Last active
May 23, 2021 06:32
-
-
Save dixyes/6761153024ed8af9e91ff91a002c87fd to your computer and use it in GitHub Desktop.
show dll load and unload
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <wchar.h> | |
#include <windows.h> | |
#include <detours.h> | |
/* common */ | |
LONG (NTAPI* LdrRegisterDllNotification)(ULONG Flags, PVOID cb, PVOID Context, PVOID *Cookie); | |
LONG (NTAPI* ZwQueryInformationProcess)(HANDLE ProcessHandle, int ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength); | |
void getkernelfuncs(void){ | |
static int fucked = 0; | |
if(fucked){ | |
return; | |
} | |
fucked = 1; | |
HANDLE hNtdll = GetModuleHandleW(L"ntdll.dll"); | |
LdrRegisterDllNotification = (LONG (__stdcall *)(ULONG,PVOID,PVOID,PVOID *))GetProcAddress(hNtdll, "LdrRegisterDllNotification"); | |
if(NULL == LdrRegisterDllNotification){ | |
printf("[common] failed getprocaddress %d\n", GetLastError()); | |
abort(); | |
} | |
ZwQueryInformationProcess = (LONG (__stdcall *)(HANDLE,int,PVOID,ULONG,PULONG))GetProcAddress(hNtdll, "ZwQueryInformationProcess"); | |
if(NULL == ZwQueryInformationProcess){ | |
printf("[common] failed getprocaddress %d\n", GetLastError()); | |
abort(); | |
} | |
} | |
/* LdrRegisterDllNotification part */ | |
typedef struct _UNICODE_STRING { | |
USHORT Length; | |
USHORT MaximumLength; | |
PWSTR Buffer; | |
} UNICODE_STRING, *PUNICODE_STRING; | |
typedef struct _LDR_DLL_UNLOADED_NOTIFICATION_DATA { | |
ULONG Flags; //Reserved. | |
const PUNICODE_STRING FullDllName; //The full path name of the DLL module. | |
const PUNICODE_STRING BaseDllName; //The base file name of the DLL module. | |
PVOID DllBase; //A pointer to the base address for the DLL in memory. | |
ULONG SizeOfImage; //The size of the DLL image, in bytes. | |
} LDR_DLL_UNLOADED_NOTIFICATION_DATA, *PLDR_DLL_UNLOADED_NOTIFICATION_DATA; | |
typedef struct _LDR_DLL_LOADED_NOTIFICATION_DATA { | |
ULONG Flags; //Reserved. | |
const PUNICODE_STRING FullDllName; //The full path name of the DLL module. | |
const PUNICODE_STRING BaseDllName; //The base file name of the DLL module. | |
PVOID DllBase; //A pointer to the base address for the DLL in memory. | |
ULONG SizeOfImage; //The size of the DLL image, in bytes. | |
} LDR_DLL_LOADED_NOTIFICATION_DATA, *PLDR_DLL_LOADED_NOTIFICATION_DATA; | |
typedef union _LDR_DLL_NOTIFICATION_DATA { | |
LDR_DLL_LOADED_NOTIFICATION_DATA Loaded; | |
LDR_DLL_UNLOADED_NOTIFICATION_DATA Unloaded; | |
} LDR_DLL_NOTIFICATION_DATA, *PLDR_DLL_NOTIFICATION_DATA; | |
typedef void (*LDR_DLL_NOTIFICATION_FUNCTION)( | |
_In_ ULONG NotificationReason, | |
_In_ const PLDR_DLL_NOTIFICATION_DATA NotificationData, | |
_In_opt_ PVOID Context | |
); | |
void CALLBACK fuckshow(ULONG NotificationReason, const PLDR_DLL_NOTIFICATION_DATA NotificationData, PVOID Context){ | |
switch(NotificationReason){ | |
case 1: // LDR_DLL_NOTIFICATION_REASON_LOADED | |
{ | |
LDR_DLL_LOADED_NOTIFICATION_DATA* pData = &NotificationData->Loaded; | |
wprintf(L"[LdrNotify] mod %s loaded from %s\n", pData->BaseDllName->Buffer, pData->FullDllName->Buffer); | |
return; | |
} | |
case 2: // LDR_DLL_NOTIFICATION_REASON_UNLOADED | |
{ | |
LDR_DLL_UNLOADED_NOTIFICATION_DATA* pData = &NotificationData->Unloaded; | |
wprintf(L"[LdrNotify] mod %s unloaded from %s\n", pData->BaseDllName->Buffer, pData->FullDllName->Buffer); | |
return; | |
} | |
default: | |
printf("[LdrNotify] ??? stange\n"); | |
abort(); | |
} | |
} | |
void fuckdll(void){ | |
static int fucked = 0; | |
if(fucked){ | |
return; | |
} | |
fucked = 1; | |
getkernelfuncs(); | |
void* registered = NULL; | |
LONG ret; | |
if(0 != (ret = LdrRegisterDllNotification(0, fuckshow, NULL, ®istered))){ | |
printf("[detour] failed LdrRegisterDllNotification %d\n", ret); | |
abort(); | |
} | |
} | |
/* peb part */ | |
typedef struct _PEB_LDR_DATA | |
{ | |
ULONG Length; | |
UCHAR Initialized; | |
PVOID SsHandle; | |
LIST_ENTRY InLoadOrderModuleList; | |
LIST_ENTRY InMemoryOrderModuleList; | |
LIST_ENTRY InInitializationOrderModuleList; | |
PVOID EntryInProgress; | |
} PEB_LDR_DATA, *PPEB_LDR_DATA; | |
typedef struct _PEB { | |
#ifdef _WIN64 | |
UINT8 _PADDING_[24]; | |
#else | |
UINT8 _PADDING_[12]; | |
#endif | |
PPEB_LDR_DATA Ldr; | |
} PEB, *PPEB; | |
typedef struct _PROCESS_BASIC_INFORMATION | |
{ | |
PVOID Reserved1; | |
PPEB PebBaseAddress; | |
PVOID Reserved2[2]; | |
ULONG_PTR UniqueProcessId; | |
PVOID Reserved3; | |
} PROCESS_BASIC_INFORMATION; | |
typedef struct _LDR_MODULE | |
{ | |
LIST_ENTRY InLoadOrderModuleList; | |
LIST_ENTRY InMemoryOrderModuleList; | |
LIST_ENTRY InInitializationOrderModuleList; | |
PVOID BaseAddress; | |
PVOID EntryPoint; | |
ULONG SizeOfImage; | |
UNICODE_STRING FullDllName; | |
UNICODE_STRING BaseDllName; | |
ULONG Flags; | |
USHORT LoadCount; | |
USHORT TlsIndex; | |
LIST_ENTRY HashTableEntry; | |
ULONG TimeDateStamp; | |
} LDR_MODULE, *PLDR_MODULE; | |
void fuckpeb(HANDLE module){ | |
getkernelfuncs(); | |
PROCESS_BASIC_INFORMATION pbi; | |
ULONG ulong = 0; | |
LONG ret; | |
HANDLE selfProcess = GetCurrentProcess(); | |
if (0 != (ret = ZwQueryInformationProcess(selfProcess, 0, &pbi, sizeof(pbi), &ulong))){ | |
printf("[PEB] ZwQueryInformationProcess failed %d\n", ret); | |
abort(); | |
} | |
PEB peb; | |
SIZE_T retlen = 0; | |
ReadProcessMemory(selfProcess, pbi.PebBaseAddress, &peb, sizeof(peb), &retlen); | |
if(sizeof(peb) != retlen){ | |
printf("[PEB] read peb failed %d\n", GetLastError()); | |
abort(); | |
} | |
PEB_LDR_DATA peb_ldr_data; | |
ReadProcessMemory(selfProcess, peb.Ldr, &peb_ldr_data, sizeof(peb_ldr_data), &retlen); | |
if(sizeof(peb_ldr_data) != retlen){ | |
printf("[PEB] read peb failed %d\n", GetLastError()); | |
abort(); | |
} | |
LDR_MODULE peb_ldr_module; | |
void *readAddr = (char*) peb_ldr_data.InLoadOrderModuleList.Flink; | |
int found = 0; | |
// Go through each modules one by one in their load order. | |
while(ReadProcessMemory(selfProcess, (void*)((char*)readAddr), &peb_ldr_module, sizeof(peb_ldr_module), &retlen)){ | |
//wprintf(L"now %p\n", readAddr); | |
// Get the reference count of the DLL | |
//int loadCount = (signed short)peb_ldr_module.LoadCount; | |
//wprintf(L"%s@%p: %d\n", peb_ldr_module.BaseDllName.Buffer, peb_ldr_module.BaseAddress, loadCount); | |
if(peb_ldr_module.BaseAddress == module){ | |
int loadCount = (signed short)peb_ldr_module.LoadCount; | |
printf("[PEB] module %p have refcount %d\n", module, loadCount); | |
found = 1; | |
break; | |
} | |
readAddr = (void *) peb_ldr_module.InLoadOrderModuleList.Flink; | |
if(readAddr == peb_ldr_data.InLoadOrderModuleList.Flink){ | |
break; | |
} | |
//wprintf(L"next %p\n", readAddr); | |
} | |
if(!found){ | |
printf("[PEB] module %p was not loaded\n", module); | |
} | |
} | |
/* detour part */ | |
static HANDLE (*origLoadLibraryA)(LPCSTR) = LoadLibraryA; | |
HANDLE WINAPI myLoadLibraryA(LPCSTR name){ | |
printf("[detour] LoadLibraryA(\"%s\") start\n", name); | |
HANDLE ret = origLoadLibraryA(name); | |
printf("[detour] LoadLibraryA(\"%s\") = %p\n", name, ret); | |
if(ret){ | |
fuckpeb(ret); | |
} | |
return ret; | |
} | |
static HANDLE (*origLoadLibraryW)(LPCWSTR) = LoadLibraryW; | |
HANDLE WINAPI myLoadLibraryW(LPCWSTR name){ | |
wprintf(L"[detour] LoadLibraryW(\"%s\") start\n", name); | |
HANDLE ret = origLoadLibraryW(name); | |
wprintf(L"[detour] LoadLibraryW(\"%s\") = %p\n", name, ret); | |
if(ret){ | |
fuckpeb(ret); | |
} | |
return ret; | |
} | |
static HANDLE (*origLoadLibraryExA)(LPCSTR, HANDLE, DWORD) = LoadLibraryExA; | |
HANDLE WINAPI myLoadLibraryExA(LPCSTR name, HANDLE hFile, DWORD flags){ | |
printf("[detour] LoadLibraryExA(\"%s\", %p, %08x) start\n", name, hFile, flags); | |
HANDLE ret = origLoadLibraryExA(name, hFile, flags); | |
printf("[detour] LoadLibraryExA(\"%s\", %p, %08x) = %p\n", name, hFile, flags, ret); | |
if(ret){ | |
fuckpeb(ret); | |
} | |
return ret; | |
} | |
static HANDLE (*origLoadLibraryExW)(LPCWSTR, HANDLE, DWORD) = LoadLibraryExW; | |
HANDLE WINAPI myLoadLibraryExW(LPCWSTR name, HANDLE hFile, DWORD flags){ | |
wprintf(L"[detour] LoadLibraryExW(\"%s\", %p, %08x) start\n", name, hFile, flags); | |
HANDLE ret = origLoadLibraryExW(name, hFile, flags); | |
wprintf(L"[detour] LoadLibraryExW(\"%s\", %p, %08x) = %p\n", name, hFile, flags, ret); | |
if(ret){ | |
fuckpeb(ret); | |
} | |
return ret; | |
} | |
static BOOL (*origFreeLibrary)(HANDLE) = FreeLibrary; | |
BOOL WINAPI myFreeLibrary(HANDLE h){ | |
wprintf(L"[detour] FreeLibrary(%p) start\n", h); | |
fuckpeb(h); | |
BOOL ret = origFreeLibrary(h); | |
wprintf(L"[detour] FreeLibrary(%p) = %s\n", h, ret ? L"TRUE" : L"FALSE"); | |
fuckpeb(h); | |
return ret; | |
} | |
void fuckdetour(void){ | |
static int fucked = 0; | |
if(fucked){ | |
return; | |
} | |
fucked = 1; | |
DetourTransactionBegin(); | |
DetourUpdateThread(GetCurrentThread()); | |
DetourAttach((void**)&origLoadLibraryA, myLoadLibraryA); | |
DetourAttach((void**)&origLoadLibraryW, myLoadLibraryW); | |
DetourAttach((void**)&origLoadLibraryExA, myLoadLibraryExA); | |
DetourAttach((void**)&origLoadLibraryExW, myLoadLibraryExW); | |
DetourAttach((void**)&origFreeLibrary, myFreeLibrary); | |
DetourTransactionCommit(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment