EXTERN_C PVOID NTAPI RtlFindExportedRoutineByName( _In_ PVOID ImageBase, _In_ PCCH RoutineName);
PULONG W32pServiceTable = NULL;
typedef struct _LDR_DATA_TABLE_ENTRY {
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
LIST_ENTRY HashLinks;
PVOID SectionPointer;
ULONG CheckSum;
ULONG TimeDateStamp;
} LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY;
PVOID GetSystemRoutineAddress(PCWSTR routine_name) {
UNICODE_STRING name;
RtlInitUnicodeString(&name, routine_name);
return MmGetSystemRoutineAddress(&name);
}
PVOID GetSystemModuleBase(LPCWSTR module_name) {
PLIST_ENTRY module_list = reinterpret_cast<PLIST_ENTRY>(GetSystemRoutineAddress(L"PsLoadedModuleList"));
if (!module_list) {
return NULL;
}
for (PLIST_ENTRY link = module_list; link != module_list->Blink; link = link->Flink) {
LDR_DATA_TABLE_ENTRY* entry = CONTAINING_RECORD(link, LDR_DATA_TABLE_ENTRY, InLoadOrderModuleList);
UNICODE_STRING name;
RtlInitUnicodeString(&name, module_name);
if (RtlEqualUnicodeString(&entry->BaseDllName, &name, TRUE)) {
return entry->DllBase;
}
}
return NULL;
}
ULONG64 GetShadowSSDTFuncCurAddr(ULONG id) {
LONG dwtmp = 0;
PULONG ServiceTableBase = NULL;
ServiceTableBase = W32pServiceTable;
dwtmp = ServiceTableBase[id];
dwtmp = dwtmp >> 4;
return (LONGLONG)dwtmp + (ULONGLONG)ServiceTableBase;
}
NTSTATUS GetPEPPocess(const char* process_name, PEPROCESS* process) {
PEPROCESS sys_process = PsInitialSystemProcess;
PEPROCESS curr_entry = sys_process;
char image_name[15];
do {
RtlCopyMemory((PVOID)(&image_name), (PVOID)((uintptr_t)curr_entry + 0x5a8), sizeof(image_name));
if (strstr(image_name, process_name)) {
ULONG active_threads;
RtlCopyMemory((PVOID)&active_threads, (PVOID)((uintptr_t)curr_entry + 0x5F0), sizeof(active_threads));
if (active_threads) {
*process = curr_entry;
return STATUS_SUCCESS;
}
}
PLIST_ENTRY list = (PLIST_ENTRY)((uintptr_t)(curr_entry)+0x448);
curr_entry = (PEPROCESS)((uintptr_t)list->Flink - 0x448);
} while (curr_entry != sys_process);
return STATUS_NOT_FOUND;
}
VOID EnumShadowSSDT() {
PEPROCESS winlogon = NULL;
KAPC_STATE apc_state;
NTSTATUS status = STATUS_UNSUCCESSFUL;
status = GetPEPPocess(("winlogon.exe"), &winlogon);
KeStackAttachProcess(winlogon, &apc_state);
PVOID Win32KBase = GetSystemModuleBase(L"win32k.sys");
W32pServiceTable = (PULONG)RtlFindExportedRoutineByName(Win32KBase,"W32pServiceTable");
DbgPrintEx(77, 0, "[%s] Win32k.sys = 0x%llx\n", __FUNCTION__, Win32KBase);
DbgPrintEx(77, 0, "[%s] W32pServiceTable = 0x%llx\n", __FUNCTION__, W32pServiceTable);
PIMAGE_DOS_HEADER lpDosHeader = (PIMAGE_DOS_HEADER)Win32KBase;
PIMAGE_NT_HEADERS64 lpNtHeader = (PIMAGE_NT_HEADERS64)((ULONG64)Win32KBase + lpDosHeader->e_lfanew);
if (!lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size) {
return;
}
if (!lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress) {
return;
}
PIMAGE_EXPORT_DIRECTORY lpExports = (PIMAGE_EXPORT_DIRECTORY)((ULONG64)Win32KBase + (ULONG64)lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
PULONG lpdwFunName = (PULONG)((ULONG64)Win32KBase + (ULONG64)lpExports->AddressOfNames);
PUSHORT lpword = (PUSHORT)((ULONG64)Win32KBase + (ULONG64)lpExports->AddressOfNameOrdinals);
PULONG lpdwFunAddr = (PULONG)((ULONG64)Win32KBase + (ULONG64)lpExports->AddressOfFunctions);
for (ULONG i = 0; i <= lpExports->NumberOfNames - 1; i++) {
char* pFunName = (char*)(lpdwFunName[i] + (ULONG64)Win32KBase);
if(strstr(pFunName,"__win32kstub_"))
{
PVOID _FunctionAddress = (PVOID)(lpdwFunAddr[lpword[i]] + (ULONG64)Win32KBase);
char* FunctionName = strstr(pFunName, "Nt");
ULONG lFunctionIndex = *(ULONG*)((PUCHAR)_FunctionAddress + 1);
ULONG64 FunctionAddress = GetShadowSSDTFuncCurAddr(lFunctionIndex);
DbgPrintEx(77, 0, "[%s] \nIndex: %d \nAddress: 0x%llx \n", FunctionName, lFunctionIndex, FunctionAddress);
}
}
KeUnstackDetachProcess(&apc_state);
}
VOID DriverUnload(PDRIVER_OBJECT drv_obj [[maybe_unused]] ) {
}
EXTERN_C NTSTATUS DriverEntry(PDRIVER_OBJECT drv_obj [[maybe_unused]], PUNICODE_STRING reg_path [[maybe_unused]] ) {
EnumShadowSSDT();
drv_obj->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}