Compilable and Buildable //Lets name it GDIInquiry.cpp #pragma once #include "stdafx.h" #include "StdAfx.h" #include <tchar.h> #include <stdio.h> #include <malloc.h> #include <dbghelp.h> #include <shlwapi.h> #include <ShlObj.h> #include "GDIInquiry.h" int _tmain(int argc, _TCHAR* argv[]) { if (argc < 2) { printf("Format is EnumGdi <process id>\n"); system("pause"); return 0; } // get process identifier DWORD dwId = _wtoi(argv[1]); // open the process HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwId); DWORD err = 0; if (hProcess == NULL) { printf("OpenProcess %u failed\n", dwId); err = GetLastError(); system("pause"); return -1; } // determine if 64 or 32-bit processor SYSTEM_INFO si; GetNativeSystemInfo(&si); // NOTE: as this is undocumented, it *may vary* depending on bitness (32/64) and on Windows version. // use WinDbg "dt ntdll!_PEB" command and search for GdiSharedHandleTable offset to find the truth out DWORD GdiSharedHandleTableOffset = si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ? 0xF8 : 0x94; DWORD tableCount = 16384; // count of GDI table cells // determine if this process is running on WOW64 BOOL wow; IsWow64Process(GetCurrentProcess(), &wow); // read basic info to get PEB address, we only need the beginning of PEB DWORD pebSize = GdiSharedHandleTableOffset + 8; LPBYTE peb = (LPBYTE)malloc(pebSize); ZeroMemory(peb, pebSize); int nDCHandle, nRegionHandle, nBitmapHandle, nPaletteHandle, nFontHandle, nPenHandle, nBrushHandle, nOtherHandle; nDCHandle = nRegionHandle = nBitmapHandle = nPaletteHandle = nFontHandle = nPenHandle = nBrushHandle = nOtherHandle = 0; if (wow) { // we're running as a 32-bit process in a 64-bit process PROCESS_BASIC_INFORMATION_WOW64 pbi; ZeroMemory(&pbi, sizeof(pbi)); // get process information from 64-bit world _NtQueryInformationProcess query = (_NtQueryInformationProcess)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtWow64QueryInformationProcess64"); err = query(hProcess, 0, &pbi, sizeof(pbi), NULL); if (err != 0) { printf("NtWow64QueryInformationProcess64 failed\n"); CloseHandle(hProcess); system("pause"); return -1; } // read PEB from 64-bit address space _NtWow64ReadVirtualMemory64 read = (_NtWow64ReadVirtualMemory64)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtWow64ReadVirtualMemory64"); err = read(hProcess, pbi.PebBaseAddress, peb, pebSize, NULL); if (err != 0) { printf("NtWow64ReadVirtualMemory64 PEB failed\n"); CloseHandle(hProcess); system("pause"); return -1; } // get GDI table ptr from PEB GDICELL_WOW64* gdiTable = (GDICELL_WOW64*)*(LPVOID*)(peb + GdiSharedHandleTableOffset); // address in remote process adress space if (gdiTable == NULL) { printf("GDI32.DLL is not loaded in the process\n"); CloseHandle(hProcess); system("pause"); return -1; } free(peb); DWORD tableSize = sizeof(GDICELL_WOW64)* tableCount; // size of GDI table GDICELL_WOW64* table = (GDICELL_WOW64*)malloc(tableSize); // local table copied over to our address space // copy GDI table err = read(hProcess, gdiTable, table, tableSize, NULL); if (err != 0) { printf("NtWow64ReadVirtualMemory64 GdiTable failed\n"); free(table); CloseHandle(hProcess); system("pause"); return -1; } for (DWORD i = 0; i < tableCount; i++) { GDICELL_WOW64 cell = table[i]; if (cell.wProcessId != dwId) continue; HGDIOBJ gdiHandle = (HGDIOBJ)((cell.wUpper << 16) + i); WORD type = cell.wType & 0x7F; switch (type) { case 1: //printf("DC handle:0x%08X\n", gdiHandle); nDCHandle++; break; case 4: //printf("Region handle:0x%08X\n", gdiHandle); nRegionHandle++; break; case 5: //printf("Bitmap handle:0x%08X\n", gdiHandle); nBitmapHandle++; break; case 8: //printf("Palette handle:0x%08X\n", gdiHandle); nPaletteHandle++; break; case 10: //printf("Font handle:0x%08X\n", gdiHandle); nFontHandle++; break; case 16: //printf("Brush handle:0x%08X\n", gdiHandle); nPenHandle++; break; case 48: //printf("Pen handle:0x%08X\n", gdiHandle); nBrushHandle++; break; default: //printf("Unknown type handle:0x%08X\n", gdiHandle); nOtherHandle++; break; } } free(table); } else { // we're running as a 32-bit process in a 32-bit OS, or as a 64-bit process in a 64-bit OS PROCESS_BASIC_INFORMATION pbi; ZeroMemory(&pbi, sizeof(pbi)); // get process information _NtQueryInformationProcess query = (_NtQueryInformationProcess)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQueryInformationProcess"); err = query(hProcess, 0, &pbi, sizeof(pbi), NULL); if (err != 0) { printf("NtQueryInformationProcess failed\n"); CloseHandle(hProcess); system("pause"); return -1; } // read PEB _NtReadVirtualMemory read = (_NtReadVirtualMemory)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtReadVirtualMemory"); err = read(hProcess, pbi.PebBaseAddress, peb, pebSize, NULL); if (err != 0) { printf("NtReadVirtualMemory PEB failed\n"); CloseHandle(hProcess); system("pause"); return -1; } // get GDI table ptr GDICELL* gdiTable = (GDICELL*)*(LPVOID*)(peb + GdiSharedHandleTableOffset); // address in remote process adress space if (gdiTable == NULL) { printf("GDI32.DLL is not loaded in the process\n"); CloseHandle(hProcess); system("pause"); return -1; } free(peb); DWORD tableSize = sizeof(GDICELL)* tableCount; // size of GDI table GDICELL* table = (GDICELL*)malloc(tableSize); // local table copied over to our address space // read GDI table err = read(hProcess, gdiTable, table, tableSize, NULL); if (err != 0) { printf("NtReadVirtualMemory GdiTable failed\n"); free(table); CloseHandle(hProcess); system("pause"); return -1; } for (DWORD i = 0; i < tableCount; i++) { GDICELL cell = table[i]; if (cell.wProcessId != dwId) continue; HGDIOBJ gdiHandle = (HGDIOBJ)((cell.wUpper << 16) + i); WORD type = cell.wType & 0x7F; switch (type) { case 1: //printf("DC handle:0x%08X\n", gdiHandle); nDCHandle++; break; case 4: //printf("Region handle:0x%08X\n", gdiHandle); nRegionHandle++; break; case 5: //printf("Bitmap handle:0x%08X\n", gdiHandle); nBitmapHandle++; break; case 8: //printf("Palette handle:0x%08X\n", gdiHandle); nPaletteHandle++; break; case 10: //printf("Font handle:0x%08X\n", gdiHandle); nFontHandle++; break; case 16: //printf("Brush handle:0x%08X\n", gdiHandle); nPenHandle++; break; case 48: //printf("Pen handle:0x%08X\n", gdiHandle); nBrushHandle++; break; default: //printf("Unknown type handle:0x%08X\n", gdiHandle); nOtherHandle++; break; } } free(table); } CloseHandle(hProcess); int nTotalGDI = nDCHandle + nRegionHandle + nBitmapHandle + nPaletteHandle + nFontHandle + nPenHandle + nBrushHandle + nOtherHandle; printf("Bitmap:%d\n", nBitmapHandle); printf("Brush:%d\n", nPenHandle); printf("DeviceContext:%d\n", nDCHandle); printf("Font:%d\n", nFontHandle); printf("Palette:%d\n", nPaletteHandle); printf("Pen:%d\n", nBrushHandle); printf("Region:\%d\n", nRegionHandle); printf("Unknown:%d\n", nOtherHandle); printf("GDITotal:%d\n", nTotalGDI); return 1; }
and GDII inquiry.h code below
#pragma once #include "stdafx.h" #include "Winternl.h"
Done
Run commands: ..\..\GDIInquiry\Debug GDIInquiry.exe PID Sample Output: cmd Microsoft Windows [Version 6.1.7601] Copyright (c) 2009 Microsoft Corporation. All rights reserved. ..\..\GDIInquiry\Debug>GDIInquiry.exe 6772 Bitmap:302 Brush:139 DeviceContext:133 Font:75 Palette:1 Pen:0 Region:11 Unknown:0 GDITotal:661