Windows Event Viewer Log (EVT)单条日志清除系列文章的第三篇,介绍删除当前系统指定时间段evt日志记录的方法和详细测试过程,说明无法修改日志数量的原因,最后开源查询日志内容和修改日志内容的实现代码
本文将要介绍以下内容:
XP系统下枚举系统所有句柄的方法
筛选日志文件句柄的条件
XP下Dll注入的实例代码
实际测试过程
无法修改日志数量的原因
日志查询的程序实现细节
日志修改的程序实现细节
之前的文章《Windows单条日志清除(五)——通过DuplicateHandle获取日志文件句柄删除当前系统单条日志记录》介绍了Win8及以上系统的实现方法:
利用NtQuerySystemInformation查询SystemHandleInformation能够获得所有进程的句柄信息
通过NtDuplicateObject获取句柄的名称和具体的数值信息
筛选出想要查找的句柄
通过DuplicateHandle复制句柄
获得修改日志文件的权限
在XP系统下,无法使用NtQuerySystemInformation查询SystemHandleInformation获得进程的句柄信息
参考processhacker的源码,寻找实现方法
代码位置:
https://github.com/processhacker/processhacker/blob/e2d793289dede80f6e3bda26d6478dc5
获得参考资料:
On Windows 8 and later,NtQueryInformationProcess with ProcessHandleInformation is the most efficient method.
On Windows XP and later, NtQuerySystemInformation with SystemExtendedHandleInformation.
Otherwise, NtQuerySystemInformation with SystemHandleInformation can be used.
尝试第二种,使用NtQuerySystemInformation查询SystemExtendedHandleInformation
注:
第二种方法支持WinXP及更高版本的系统
1、筛选出类型为文件的句柄
ObjectTypeNumber = 0x1c
注:
Win8及更高版本的系统,ObjectTypeNumber = 0x1e
WinXP和Win7系统,ObjectTypeNumber = 0x1c
2、过滤出有可能导致挂起的句柄
通过API WaitForSingleObject进行判断
否则将导致进程挂起
3、缩小范围,指定文件属性
日志文件的属性固定,handle->GrantedAccess = 0x0012019f
完整实现代码已开源,下载地址如下:
https://github.com/3gstudent/Homework-of-C-Language/blob/master/GetPIDandHandle(evt).cpp
代码实现了根据输入的关键词进行搜索,获得对应的句柄名称和Handle值
向系统进程注入dll,dll文件即可获取日志文件的句柄
接下来的操作为:
调用函数CreateFileMapping()创建一个文件映射内核对象
调用函数MapViewOfFile()将文件数据映射到进程的地址空间
修改内存中的数据,删除指定日志记录
调用函数FlushViewOfFile(),将内存数据写入磁盘
清除内存映射对象
完整的实现过程可参考之前介绍删除evtx文件单条日志的文章《Windows XML Event Log (EVTX)单条日志清除(四)——通过注入获取日志文件句柄删除当前系统单条日志记录》
xp系统下无法使用NtCreateThreadEx + LdrLoadDll的方式注入dll,可以直接调用CreateRemoteThread
实现代码可参考:
https://github.com/3gstudent/Homework-of-C-Language/blob/master/CreateRemoteThread.cpp
参考之前的文章《Windows XML Event Log (EVTX)单条日志清除(五)——通过DuplicateHandle获取日志文件句柄删除当前系统单条日志记录》
筛选出句柄后,再次调用NtDuplicateObject获得实句柄,对日志文件进行删除操作
同样,需要以下操作:
调用函数CreateFileMapping()创建一个文件映射内核对象
调用函数MapViewOfFile()将文件数据映射到进程的地址空间
修改内存中的数据,删除指定日志记录
调用函数FlushViewOfFile(),将内存数据写入磁盘
清除内存映射对象
日志删除部分可参考之前的文章《Windows Event Viewer Log (EVT)单条日志清除(二)——程序实现删除evt文件指定时间段的日志记录》
这里给出一个完整的实现代码:
https://github.com/3gstudent/Eventlogedit-evt--General/blob/master/evtDeleteRecordbyGetHandle.cpp
代码实现了删除指定evt文件中,某一时间段的多条日志,并且生成调试文件sys2.evt和sys3.evt
sys2.evt保存删除日志后的数组内容
sys3.evt保存映射到内存中的内容
程序执行后,sys2.evt和sys3.evt成功删除指定日志,但是当前系统的日志文件产生错误
为了对比测试,我将删除的时间段调整为当前日志以外的数值,即不会删除任何日志,程序执行后,当前系统的日志文件正常
更进一步,只要不改变日志的个数,修改日志的内容,当前系统的日志文件仍正常
这里得出一个结论:无法通过获得日志文件句柄修改内存数据的方式改变日志的数目
同样,通过ProcessHacker直接修改内存文件的File header也无法改变日志的数目
编写程序验证,通过API GetNumberOfEventLogRecords查询日志个数
c代码如下:
#include <windows.h> #pragma comment(lib,"Advapi32.lib") int main(int argc, char *argv[]) { HANDLE hEventLog = NULL; hEventLog = OpenEventLog(NULL, argv[1]); if (NULL == hEventLog) { printf("OpenEventLog failed with 0x%x.\n", GetLastError()); goto cleanup; } DWORD NumberOfRecords = 0; BOOL flag = GetNumberOfEventLogRecords(hEventLog, &NumberOfRecords); if (NULL == flag) { printf("GetNumberOfEventLogRecords failed with 0x%x.\n", GetLastError()); goto cleanup; } printf("%d\n", NumberOfRecords); cleanup: if (hEventLog) CloseEventLog(hEventLog); }
cmd:
GetNumberOfEventLogRecords.exe system
获得日志个数
通过ProcessHacker直接修改内存文件File header的Last (newest) record number和End of file record的Last (newest) record number
再次执行程序获得日志个数,发现获得的日志个数不变
验证结论,修改内存中的日志内容无法更改实际的日志个数
日志查询的代码如下:
https://github.com/3gstudent/Eventlogedit-evt--General/blob/master/evtQueryRecordbyGetHandle.cpp
代码实现了遍历日志,显示每个日志的信息
日志修改的代码如下:
https://github.com/3gstudent/Eventlogedit-evt--General/blob/master/evtModifyRecordbyGetHandle.cpp
代码实现了修改指定日志的信息
本文介绍了删除当前系统指指定时间段evt日志记录的两种方法:通过Dll注入和通过DuplicateHandle分别获得句柄操作权限,利用该句柄实现日志文件的修改
删除方式不是简单的覆盖,而是完全的删除某段时间的日志,evtx文件的日志删除也可以参考这种方法,只是实现上相对复杂一些,后续会更新evtx的实现代码