Skip to content

Instantly share code, notes, and snippets.

@dixyes
Last active May 23, 2021 06:32
Show Gist options
  • Save dixyes/6761153024ed8af9e91ff91a002c87fd to your computer and use it in GitHub Desktop.
Save dixyes/6761153024ed8af9e91ff91a002c87fd to your computer and use it in GitHub Desktop.
show dll load and unload
#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, &registered))){
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