0x00 Preface
---
The fourth article in the Windows XML Event Log (EVTX) single log entry deletion series introduces the second method for deleting a single log record from the current system: obtaining the handle to a specified log file in the Eventlog service process, acquiring operational permissions for that handle via DLL injection, and using the handle to modify the log file.
0x01 Introduction
---
This article will cover the following topics:
- Exploitation Approach
- Program Implementation
- Enumerating all handles in the Eventlog service process to obtain the handle for a specified log file
- Acquiring operational permissions for the handle via DLL injection
- Methods for inter-process message passing
0x02 Exploitation Approach
---
After the system starts the Eventlog service, it opens log files in exclusive mode, preventing other processes from opening and modifying these log files.
So, if we enter the process memory through DLL injection and then obtain the handle to the specified log file, can we gain operational permissions for that log file?
0x03 Enumerate all handles of the Eventlog service process to obtain the handle to the specified log file
---
1. Use the tool Process Hacker to obtain the handle to the specified log file
Download link:
https://processhacker.sourceforge.io/
(1) Obtain the PID of the Eventlog service process
Execute the following PowerShell code:
Get-WmiObject -Class win32_service -Filter "name = 'eventlog'" | select -exp ProcessId |
(2) Run Process Hacker
Locate the process by PID and view Properties->Handles
This allows you to obtain all handle information for the current process
As shown in the figure below

You can see that the handle value for C:\Windows\System32\winevt\Logs\Security.evtx is 0x1c8
2. Obtain the handle of a specified log file through a C++ program
Review the source code of Process Hacker to find the implementation method
Code location:
https://github.com/processhacker/processhacker/blob/e2d793289dede80f6e3bda26d6478dc58b20b7f8/ProcessHacker/hndlprv.c#L307
Reference materials obtained:
* 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.
Therefore, choose the third method for implementation
Note:
Testing shows that the third method is applicable to Windows 7 and later operating systems
Using NtQuerySystemInformation to query SystemHandleInformation can obtain handle information for all processes
Select all handles in the log process
Then use NtDuplicateObject to obtain the handle's name and specific numerical information
Finally, filter out the desired handle and output the Handle value
The complete implementation code has been open-sourced, download link is as follows:
An open-source project).cpp
The code implements searching based on input keywords to obtain corresponding handle names and Handle values
Test as shown below

Successfully obtained the pid of the Eventlog service process corresponding to the log, and the Handle value for security.evtx is 0x1c8
0x04 Obtain operation permissions for this handle through DLL injection
---
Code for DLL injection via NtCreateThreadEx + LdrLoadDll can be referenced from:
An open-source project
Note:
FreeDll is required after successful injection
After successful injection, use the obtained Handle value as the first parameter of the function CreateFileMapping() to create a file mapping kernel object
Then call the function MapViewOfFile() to map the file data into the process's address space
Next, modify the data in memory to delete a single log record
Finally call the function FlushViewOfFile() to write memory data to disk
0x05 Methods for Inter-Process Message Passing
---
In practical use, the entire code implementing the log deletion function must be placed in a DLL. Since CreateRemoteThread cannot pass parameters to the DLL, this makes it impossible to delete logs with a specified EventlogRecordId
Here, inter-process message passing can be utilized
There are multiple implementation methods, such as signals, pipes, message queues, shared memory, or even reading and writing files
Since in0x04the function CreateFileMapping() was used to create a file mapping kernel object, inter-process message passing also employs the memory mapping method
Create a shared memory, code can be referenced from:
An open-source project
The code creates two memory mapping objects and specifies the access permission for the function CreateFileMapping() to allow anyone to access the object, i.e., the second parameter of the function CreateFileMapping()
Typically, this value is set to NULL, indicating default access permissions. However, in the injected DLL, it must be set to allow anyone to access the object; otherwise, an access denied error will occur
The reason is as follows:
After the DLL is injected into svchost.exe, the permissions are System. Default access permissions cannot access the memory-mapped file object created by the user, so it must be specified to allow anyone to access the object
Of course, if it is message passing between two user-privileged processes, the second parameter of the function CreateFileMapping() can be set to NULL.
To read the specified shared memory, the code can be referenced as follows:
An open-source project
In the code, reading these two memory-mapped objects adds the functionality of data type conversion (string to int).
0x06 Program Implementation Process
---
1. Parse the format yourself to implement log deletion.
The key code for deletion is as follows:
`An open-source project
The code implements the deletion of a log (EventRecordID=14) from the file c:\test\Setup.evtx, with the new file saved as c:\test\SetupNew.evtx.
The entire implementation process is divided into two parts:
- Start the program
- Injected DLL
1. Start the program (Loader-rewriting.cpp)
Code address:
`An open-source project
The process is as follows:
- Obtain the pid of the process corresponding to the Eventlog logging service
- Enumerate all handles of the process corresponding to the Eventlog logging service to obtain the handle of the specified log file
- Create two memory mappings to pass the log file handle and the EventRecordID of the log to be deleted to the DLL
- Inject a DLL into the process corresponding to the Eventlog logging service
- Release the DLL
- Close the memory mappings
2. The injected DLL (Dll-rewriting.cpp)
Code address:
`An open-source project
The process is as follows:
- Read messages from the two memory mappings separately, convert the read content from string to int type to obtain the log file handle and the EventRecordID of the log to be deleted
- Call the function CreateFileMapping(), passing the log file handle to create a file mapping kernel object
- Call the function MapViewOfFile() to map the file data into the process's address space
- Modify memory data to delete specified logs
- Call the function FlushViewOfFile() to write memory data to disk
- Close the memory mapping of the log file
Test as shown in the image below

2. Use WinAPI EvtExportLog to filter out the content to be deleted
Reference code:
https://github.com/360-A-Team/EventCleaner/blob/master/EventCleaner/EventCleaner.cpp#L528
The code I wrote following this approach:
`An open-source project
The code implements calling the Windows API EvtExportLog to filter log files, remove specified logs, and save the remaining log content as a new file temp.evtx
The entire implementation process is divided into three parts:
- Log deletion program
- Startup program
- Injected DLL
1. Log Deletion Program (DeleteRecord-EvtExportLog.cpp)
Code Location:
`An open-source project
Process as follows:
- Specify the log file and the EventRecordID of the log to be deleted
- Generate a new log file temp.evtx
2. Launcher Program (Loader-EvtExportLog.cpp)
Code Location:
`An open-source project
Process as follows:
- Obtain the pid of the process corresponding to the Eventlog service
- Enumerate all handles of the process corresponding to the Eventlog service to obtain the handle of the specified log file
- Create three memory mappings to pass the handle of the log file, the length of the new log file, and the content of the new log file to the DLL
- Inject DLL into the process corresponding to the Eventlog service
- Release the DLL
- Close memory mapping
3. Injected Dll (Dll-EvtExportLog.cpp)
Code address:
`An open-source project
Process is as follows:
- Obtain the handle of the log file from the first memory mapping, convert the read content from string to int type
- Obtain the length of the new log file from the second memory mapping
- Adjust the read length of the memory mapping based on the length of the new log file, obtain the content of the new log file from the third memory mapping
- Call the function CreateFileMapping(), pass in the handle of the log file, create a file mapping kernel object
- Call the function MapViewOfFile() to map the file data into the process's address space
- Modify the memory data, overwrite with the content of the new log file
- Call the function FlushViewOfFile() to write the memory data to disk
- Close the memory mapping of the log file
Test as shown in the figure below

Note:
For the above two methods, deleting setup.evtx is not problematic, but deleting system.evtx and security.evtx may fail due to race conditions.
0x07 Summary
---
This article introduced the second method for deleting a single log record in the current system: obtaining the handle of the specified log file in the Eventlog service process, gaining permissions through DLL injection, and using that handle to modify the log file.
In some cases, DLL injection may fail. So, is there another method for deleting a single log record in the current system? The next article will introduce it.