0x00 前言

Windows Event Viewer Log (EVT)单条日志清除系列文章的第三篇,介绍删除当前系统指定时间段evt日志记录的方法和详细测试过程,说明无法修改日志数量的原因,最后开源查询日志内容和修改日志内容的实现代码


0x01 简介

本文将要介绍以下内容:

  • XP系统下枚举系统所有句柄的方法

  • 筛选日志文件句柄的条件

  • XP下Dll注入的实例代码

  • 实际测试过程

  • 无法修改日志数量的原因

  • 日志查询的程序实现细节

  • 日志修改的程序实现细节


0x02 XP系统下枚举系统所有句柄

之前的文章《Windows单条日志清除(五)——通过DuplicateHandle获取日志文件句柄删除当前系统单条日志记录》介绍了Win8及以上系统的实现方法:

  1. 利用NtQuerySystemInformation查询SystemHandleInformation能够获得所有进程的句柄信息

  2. 通过NtDuplicateObject获取句柄的名称和具体的数值信息

  3. 筛选出想要查找的句柄

  4. 通过DuplicateHandle复制句柄

  5. 获得修改日志文件的权限


在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及更高版本的系统



0x03 筛选出指定日志文件的句柄

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值


0x04 日志删除的实现方法1:通过Dll注入获得句柄操作权限

向系统进程注入dll,dll文件即可获取日志文件的句柄

接下来的操作为:

  1. 调用函数CreateFileMapping()创建一个文件映射内核对象

  2. 调用函数MapViewOfFile()将文件数据映射到进程的地址空间

  3. 修改内存中的数据,删除指定日志记录

  4. 调用函数FlushViewOfFile(),将内存数据写入磁盘

  5. 清除内存映射对象


完整的实现过程可参考之前介绍删除evtx文件单条日志的文章《Windows XML Event Log (EVTX)单条日志清除(四)——通过注入获取日志文件句柄删除当前系统单条日志记录》


xp系统下无法使用NtCreateThreadEx + LdrLoadDll的方式注入dll,可以直接调用CreateRemoteThread


实现代码可参考:

https://github.com/3gstudent/Homework-of-C-Language/blob/master/CreateRemoteThread.cpp


0x05 日志删除的实现方法2:通过DuplicateHandle获得句柄操作权限

参考之前的文章《Windows XML Event Log (EVTX)单条日志清除(五)——通过DuplicateHandle获取日志文件句柄删除当前系统单条日志记录》


筛选出句柄后,再次调用NtDuplicateObject获得实句柄,对日志文件进行删除操作

同样,需要以下操作:

  1. 调用函数CreateFileMapping()创建一个文件映射内核对象

  2. 调用函数MapViewOfFile()将文件数据映射到进程的地址空间

  3. 修改内存中的数据,删除指定日志记录

  4. 调用函数FlushViewOfFile(),将内存数据写入磁盘

  5. 清除内存映射对象


日志删除部分可参考之前的文章《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

再次执行程序获得日志个数,发现获得的日志个数不变

验证结论,修改内存中的日志内容无法更改实际的日志个数

0x06 日志查询和日志修改的程序实现细节

日志查询的代码如下:

https://github.com/3gstudent/Eventlogedit-evt--General/blob/master/evtQueryRecordbyGetHandle.cpp


代码实现了遍历日志,显示每个日志的信息

日志修改的代码如下:

https://github.com/3gstudent/Eventlogedit-evt--General/blob/master/evtModifyRecordbyGetHandle.cpp

代码实现了修改指定日志的信息


0x07 小结

本文介绍了删除当前系统指指定时间段evt日志记录的两种方法:通过Dll注入和通过DuplicateHandle分别获得句柄操作权限,利用该句柄实现日志文件的修改

删除方式不是简单的覆盖,而是完全的删除某段时间的日志,evtx文件的日志删除也可以参考这种方法,只是实现上相对复杂一些,后续会更新evtx的实现代码



源链接

Hacking more

...