├── README.md ├── edgegdi.cpp ├── edgegdi.hpp ├── images ├── bitblt_10.0.18363.1350.PNG ├── bitblt_10.0.19042.746.PNG └── edgegdi_exe.PNG ├── pattern.hpp └── test.cpp /README.md: -------------------------------------------------------------------------------- 1 | # edgegdi_hook 2 | 3 | Let us take a look at BitBlt in gdi32.dll... 4 | 5 | ***Windows Version 10.0.18363.1350*** 6 | ![Windows Version 10.0.18363.1350](https://github.com/0mdi/edgegdi_hook/blob/main/images/bitblt_10.0.18363.1350.PNG) 7 | 8 | ***Windows Version 10.0.19042.746 (20H2)*** 9 | ![Windows Version 10.0.19042.746](https://github.com/0mdi/edgegdi_hook/blob/main/images/bitblt_10.0.19042.746.PNG) 10 | 11 | ## Example PoC 12 | We can abuse this to hook various exported gdi32 functions with only one .data patch... 13 | ![Example PoC](https://github.com/0mdi/edgegdi_hook/blob/main/images/edgegdi_exe.PNG) 14 | 15 | 16 | -------------------------------------------------------------------------------- /edgegdi.cpp: -------------------------------------------------------------------------------- 1 | #include "edgegdi.hpp" 2 | #include "pattern.hpp" 3 | 4 | #include 5 | 6 | uintptr_t edgegdi::g_pEdgeGdi = 0; 7 | uintptr_t edgegdi::own_table[25] = { 0 }; 8 | 9 | // 10 | // Original functions 11 | edgegdi::BitBlt_t edgegdi::BitBltOrig = nullptr; 12 | edgegdi::CreateDIBSection_t edgegdi::CreateDIBSectionOrig = nullptr; 13 | edgegdi::CreateFontW_t edgegdi::CreateFontWOrig = nullptr; 14 | edgegdi::CreateFontIndirectW_t edgegdi::CreateFontIndirectWOrig = nullptr; 15 | edgegdi::CreateCompatibleDC_t edgegdi::CreateCompatibleDCOrig = nullptr; 16 | edgegdi::CreateDCW_t edgegdi::CreateDCWOrig = nullptr; 17 | edgegdi::CreateICW_t edgegdi::CreateICWOrig = nullptr; 18 | edgegdi::InternalDeleteDC_t edgegdi::InternalDeleteDCOrig = nullptr; 19 | edgegdi::InternalDeleteObject_t edgegdi::InternalDeleteObjectOrig = nullptr; 20 | edgegdi::GetObjectType_t edgegdi::GetObjectTypeOrig = nullptr; 21 | edgegdi::GetObjectW_t edgegdi::GetObjectWOrig = nullptr; 22 | edgegdi::GetStockObject_t edgegdi::GetStockObjectOrig = nullptr; 23 | edgegdi::GetTextMetricsW_t edgegdi::GetTextMetricsWOrig = nullptr; 24 | edgegdi::GetTextExtentPoint32W_t edgegdi::GetTextExtentPoint32WOrig = nullptr; 25 | edgegdi::SelectClipRgn_t edgegdi::SelectClipRgnOrig = nullptr; 26 | edgegdi::SelectObject_t edgegdi::SelectObjectOrig = nullptr; 27 | edgegdi::SetMapMode_t edgegdi::SetMapModeOrig = nullptr; 28 | edgegdi::D3DKMTOpenAdapterFromHdc_t edgegdi::D3DKMTOpenAdapterFromHdcOrig = nullptr; 29 | edgegdi::ExtCreateRegion_t edgegdi::ExtCreateRegionOrig = nullptr; 30 | edgegdi::GdiTrackHCreate_t edgegdi::GdiTrackHCreate = nullptr; 31 | 32 | 33 | int NotImplemented() 34 | { 35 | return 1; 36 | } 37 | 38 | 39 | bool edgegdi::init() 40 | { 41 | auto gdi32 = (uintptr_t)GetModuleHandleA("gdi32.dll"); 42 | if (!gdi32) 43 | return false; 44 | 45 | /* 46 | 48 89 05 ?? ?? ?? ?? E9 ?? ?? ?? ?? 47 | \x48\x89\x05\x00\x00\x00\x00\xE9\x00\x00\x00\x00, xxx????x???? 48 | */ 49 | g_pEdgeGdi = FindPattern(gdi32, 0xFF000, "\x48\x89\x05\x00\x00\x00\x00\xE9\x00\x00\x00\x00", "xxx????x????", 0); 50 | if (g_pEdgeGdi) 51 | { 52 | uint32_t offset = *(uint32_t*)(g_pEdgeGdi + 3); 53 | g_pEdgeGdi = g_pEdgeGdi + 7 + offset; 54 | } 55 | printf("g_pEdgeGdi: 0x%p\n", g_pEdgeGdi); 56 | return g_pEdgeGdi != NULL; 57 | } 58 | 59 | bool edgegdi::hook(uintptr_t BitBltHook) 60 | { 61 | auto win32u = GetModuleHandleA("win32u.dll"); 62 | auto gdi32 = GetModuleHandleA("gdi32.dll"); 63 | auto gdi32full = GetModuleHandleA("gdi32full.dll"); 64 | auto ntdll = GetModuleHandleA("ntdll.dll"); 65 | if (!gdi32full || !gdi32 || !win32u || !ntdll) 66 | return false; 67 | 68 | // 69 | // Initialize orig functions 70 | BitBltOrig = (BitBlt_t)GetProcAddress(gdi32full, "BitBlt"); 71 | CreateDIBSectionOrig = (CreateDIBSection_t)GetProcAddress(gdi32full, "CreateDIBSection"); 72 | CreateFontWOrig = (CreateFontW_t)GetProcAddress(gdi32full, "CreateFontW"); 73 | CreateFontIndirectWOrig = (CreateFontIndirectW_t)GetProcAddress(gdi32full, "CreateFontIndirectW"); 74 | CreateCompatibleDCOrig = (CreateCompatibleDC_t)GetProcAddress(gdi32full, "CreateCompatibleDC"); 75 | CreateDCWOrig = (CreateDCW_t)GetProcAddress(gdi32, "bCreateDCW"); 76 | CreateICWOrig = (CreateICW_t)CreateDCWOrig; 77 | InternalDeleteDCOrig = (InternalDeleteDC_t)GetProcAddress(gdi32, "InternalDeleteDC"); 78 | InternalDeleteObjectOrig = (InternalDeleteObject_t)GetProcAddress(gdi32, "InternalDeleteObject"); 79 | GetObjectTypeOrig = (GetObjectType_t)GetProcAddress(gdi32full, "GetObjectType"); 80 | GetObjectWOrig = (GetObjectW_t)GetProcAddress(gdi32full, "GetObjectW"); 81 | GetStockObjectOrig = (GetStockObject_t)GetProcAddress(gdi32full, "GetStockObject"); 82 | GetTextMetricsWOrig = (GetTextMetricsW_t)GetProcAddress(gdi32full, "GetTextMetricsW"); 83 | GetTextExtentPoint32WOrig = (GetTextExtentPoint32W_t)GetProcAddress(gdi32full, "GetTextExtentPoint32W"); 84 | SelectClipRgnOrig = (SelectClipRgn_t)GetProcAddress(gdi32full, "SelectClipRgnImpl"); 85 | SelectObjectOrig = (SelectObject_t)GetProcAddress(gdi32full, "SelectObjectImpl"); 86 | SetMapModeOrig = (SetMapMode_t)GetProcAddress(gdi32full, "SetMapMode"); 87 | D3DKMTOpenAdapterFromHdcOrig = (D3DKMTOpenAdapterFromHdc_t)GetProcAddress(win32u, "NtGdiDdDDIOpenAdapterFromHdc"); 88 | ExtCreateRegionOrig = (ExtCreateRegion_t)GetProcAddress(gdi32full, "NtGdiExtCreateRegion"); 89 | 90 | // 91 | // Initialize own_table 92 | own_table[0] = (uintptr_t)BitBltHook/*BitBltOrig*/; 93 | own_table[1] = (uintptr_t)CreateDIBSectionOrig; 94 | own_table[2] = (uintptr_t)CreateFontWOrig; 95 | own_table[3] = (uintptr_t)CreateFontIndirectWOrig; 96 | own_table[4] = (uintptr_t)CreateCompatibleDCOrig; 97 | own_table[5] = (uintptr_t)CreateDCWOrig; 98 | own_table[6] = (uintptr_t)CreateICWOrig; 99 | own_table[9] = (uintptr_t)InternalDeleteDCOrig; 100 | own_table[11] = (uintptr_t)InternalDeleteObjectOrig; 101 | own_table[12] = (uintptr_t)GetObjectTypeOrig; 102 | own_table[13] = (uintptr_t)GetObjectWOrig; 103 | own_table[14] = (uintptr_t)GetStockObjectOrig; 104 | own_table[15] = (uintptr_t)GetTextMetricsWOrig; 105 | own_table[16] = (uintptr_t)GetTextExtentPoint32WOrig; 106 | own_table[17] = (uintptr_t)SelectClipRgnOrig; 107 | own_table[18] = (uintptr_t)SelectObjectOrig; 108 | own_table[19] = (uintptr_t)SetMapModeOrig; 109 | own_table[22] = (uintptr_t)D3DKMTOpenAdapterFromHdcOrig; 110 | own_table[23] = (uintptr_t)NotImplemented; 111 | own_table[24] = (uintptr_t)NotImplemented; 112 | 113 | 114 | // Replace vtable ptr 115 | DWORD OldProtect; 116 | VirtualProtect((LPVOID)g_pEdgeGdi, sizeof(uintptr_t), PAGE_READWRITE, &OldProtect); 117 | *(uintptr_t**)g_pEdgeGdi = own_table; 118 | VirtualProtect((LPVOID)g_pEdgeGdi, sizeof(uintptr_t), OldProtect, &OldProtect); 119 | 120 | return true; 121 | } 122 | -------------------------------------------------------------------------------- /edgegdi.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | 6 | namespace edgegdi 7 | { 8 | extern uintptr_t g_pEdgeGdi; 9 | extern uintptr_t own_table[25]; 10 | 11 | bool init(); 12 | bool hook(uintptr_t BitBltHook); 13 | 14 | // 15 | // All original functions 16 | using BitBlt_t = BOOL(*)(HDC, int, int, int, int, HDC, int, int, DWORD); 17 | extern BitBlt_t BitBltOrig; 18 | using CreateDIBSection_t = HBITMAP(*)(HDC, BITMAPINFO*, UINT, void**, HANDLE, DWORD); 19 | extern CreateDIBSection_t CreateDIBSectionOrig; 20 | using CreateFontW_t = HFONT(*)(int, int, int, int, int, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, LPCWSTR); 21 | extern CreateFontW_t CreateFontWOrig; 22 | using CreateFontIndirectW_t = HFONT(*)(LOGFONTW*); 23 | extern CreateFontIndirectW_t CreateFontIndirectWOrig; 24 | using CreateCompatibleDC_t = HDC(*)(HDC); 25 | extern CreateCompatibleDC_t CreateCompatibleDCOrig; 26 | using CreateDCW_t = HDC(*)(LPCWSTR, LPCWSTR, LPCWSTR, DEVMODEW*); 27 | extern CreateDCW_t CreateDCWOrig; 28 | using CreateICW_t = HDC(*)(LPCWSTR, LPCWSTR, LPCWSTR, DEVMODEW*); 29 | extern CreateICW_t CreateICWOrig; 30 | using InternalDeleteDC_t = BOOL(*)(PVOID); 31 | extern InternalDeleteDC_t InternalDeleteDCOrig; 32 | using InternalDeleteObject_t = BOOL(*)(PVOID); 33 | extern InternalDeleteObject_t InternalDeleteObjectOrig; 34 | using GetObjectType_t = DWORD(*)(HGDIOBJ); 35 | extern GetObjectType_t GetObjectTypeOrig; 36 | using GetObjectW_t = int(*)(HANDLE, int, LPVOID); 37 | extern GetObjectW_t GetObjectWOrig; 38 | using GetStockObject_t = HGDIOBJ(*)(int); 39 | extern GetStockObject_t GetStockObjectOrig; 40 | using GetTextMetricsW_t = BOOL(*)(HDC, LPTEXTMETRICW); 41 | extern GetTextMetricsW_t GetTextMetricsWOrig; 42 | using GetTextExtentPoint32W_t = BOOL(*)(HDC, LPCWSTR, int, LPSIZE); 43 | extern GetTextExtentPoint32W_t GetTextExtentPoint32WOrig; 44 | using SelectClipRgn_t = int(*)(HDC, HRGN); 45 | extern SelectClipRgn_t SelectClipRgnOrig; 46 | using SelectObject_t = HGDIOBJ(*)(HDC, HGDIOBJ); 47 | extern SelectObject_t SelectObjectOrig; 48 | using SetMapMode_t = int(*)(HDC, int); 49 | extern SetMapMode_t SetMapModeOrig; 50 | using D3DKMTOpenAdapterFromHdc_t = PVOID(*)(HDC); 51 | extern D3DKMTOpenAdapterFromHdc_t D3DKMTOpenAdapterFromHdcOrig; 52 | using ExtCreateRegion_t = HRGN(*)(XFORM*, DWORD, RGNDATA*); 53 | extern ExtCreateRegion_t ExtCreateRegionOrig; 54 | using GdiTrackHCreate_t = void(*)(HDC); 55 | extern GdiTrackHCreate_t GdiTrackHCreate; 56 | } -------------------------------------------------------------------------------- /images/bitblt_10.0.18363.1350.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0mdi/edgegdi_hook/dc3013ef9d1f03e9e3d3af2ce814c66229890e54/images/bitblt_10.0.18363.1350.PNG -------------------------------------------------------------------------------- /images/bitblt_10.0.19042.746.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0mdi/edgegdi_hook/dc3013ef9d1f03e9e3d3af2ce814c66229890e54/images/bitblt_10.0.19042.746.PNG -------------------------------------------------------------------------------- /images/edgegdi_exe.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0mdi/edgegdi_hook/dc3013ef9d1f03e9e3d3af2ce814c66229890e54/images/edgegdi_exe.PNG -------------------------------------------------------------------------------- /pattern.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | bool DataCompare(const uint8_t* OpCodes, const uint8_t* Mask, const char* StrMask) 5 | { 6 | while (*StrMask) 7 | { 8 | if (*StrMask == 'x' && *OpCodes != *Mask) 9 | return false; 10 | 11 | ++StrMask; 12 | ++OpCodes; 13 | ++Mask; 14 | } 15 | 16 | return true; 17 | } 18 | 19 | uintptr_t FindPattern(uintptr_t StartAddress, uint32_t CodeLen, const char* Mask, const char* StrMask, unsigned short ignore) 20 | { 21 | uint16_t Ign = 0; 22 | uint32_t i = 0; 23 | 24 | while (Ign <= ignore) 25 | { 26 | if (DataCompare((uint8_t*)(StartAddress + i++), (uint8_t*)Mask, StrMask)) 27 | ++Ign; 28 | 29 | else if (i >= CodeLen) 30 | return 0; 31 | } 32 | 33 | return StartAddress + i - 1; 34 | } -------------------------------------------------------------------------------- /test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "edgegdi.hpp" 4 | 5 | 6 | BOOL BitBltHook(HDC hdc, int x, int y, int cx, int cy, HDC hdcSrc, int x1, int y1, DWORD rop) 7 | { 8 | auto CurrentPid = GetCurrentProcessId(); 9 | auto CurrentTid = GetCurrentThreadId(); 10 | 11 | char buf[256] = { 0 }; 12 | sprintf_s(buf, sizeof(buf), "%s (PID: %i, TID: %i) (X: %i (%i), Y: %i (%i)) (X: %i, Y: %i) (%X, %X)", 13 | __FUNCTION__, 14 | CurrentPid, CurrentTid, 15 | x, cx, y, cy, 16 | x1, y1, 17 | hdc, hdcSrc); 18 | printf(buf); 19 | 20 | return edgegdi::BitBltOrig(hdc, x, y, cx, cy, hdcSrc, x1, y1, rop); 21 | } 22 | 23 | int main() 24 | { 25 | SetConsoleTitleA("EDGEGDI.EXE"); 26 | printf("Calling BitBlt.\n"); 27 | BitBlt(nullptr, 0, 0, 0, 0, nullptr, 0, 0, 0); 28 | 29 | printf("Hooking BitBlt.\n"); 30 | if (!edgegdi::init() || !edgegdi::hook((uintptr_t)BitBltHook)) 31 | { 32 | printf("Failed to hook BitBlt.\n"); 33 | return -1; 34 | } 35 | 36 | printf("Calling BitBlt again.\n"); 37 | BitBlt((HDC)0xB16B00B5, 0, 0, 0, 0, (HDC)0xCAFEBABE, 0, 0, 0); 38 | 39 | getchar(); 40 | return 0; 41 | } --------------------------------------------------------------------------------