我试图写,使用DLL注入方法,显示另一个程序使用的位图的应用程序,我想要得到它正在使用的GDI句柄(如GDIView.exe实用程序中的列表)的特定进程列表。 我find了关于NtQuerySystemInformation函数的文章,但是这个描述只适用于内核对象的句柄。 有人可以帮忙吗?
这是一个控制台应用程序代码,用于为给定的进程标识符转储所有的GDI句柄。 对于32位或64位应用程序以及在64位操作系统上运行的32位应用程序,它应该编译和正常工作。 它使用了很多没有记录的功能,所以不要依赖它:-)共享GDI表的结构信息发送给冯原原作。 (我不得不适应WOW64)。
以下是在记事本(64位)进程上运行时的示例输出:
[C:\Temp\EnumGdi\Debug]EnumGdi.exe 5916 DC handle:0xF20105DB Bitmap handle:0xDF05118B Font handle:0xDC0A19E0 Font handle:0xAB0A1A62 DC handle:0xA3011A63 Region handle:0xAF041B7B Brush handle:0x11101C5B Font handle:0x280A1CA1 Font handle:0xBB0A1D13 Bitmap handle:0xA3051DD8 Font handle:0xB40A1DDC Region handle:0x3A041EE4 Brush handle:0x0B101F04 Region handle:0xC6041F3D Font handle:0x2C0A2384 Brush handle:0xBA1024DA
EnumGdi.cpp:
#include "stdafx.h" #include "enumgdi.h" int _tmain(int argc, _TCHAR* argv[]) { if (argc < 2) { printf("Format is EnumGdi <process id>\n"); 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(); 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); 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(GetmoduleeHandleA("ntdll.dll"), "NtWow64QueryInformationProcess64"); err = query(hProcess, 0, &pbi, sizeof(pbi), NULL); if (err != 0) { printf("NtWow64QueryInformationProcess64 failed\n"); CloseHandle(hProcess); return -1; } // read PEB from 64-bit address space _NtWow64ReadVirtualMemory64 read = (_NtWow64ReadVirtualMemory64)GetProcAddress(GetmoduleeHandleA("ntdll.dll"), "NtWow64ReadVirtualMemory64"); err = read(hProcess, pbi.PebBaseAddress, peb, pebSize, NULL); if (err != 0) { printf("NtWow64ReadVirtualMemory64 PEB failed\n"); CloseHandle(hProcess); 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); 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); 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 ); break; case 4: printf("Region handle:0x%08X\n", gdiHandle); break; case 5: printf("Bitmap handle:0x%08X\n", gdiHandle); break; case 8: printf("Palette handle:0x%08X\n", gdiHandle); break; case 10: printf("Font handle:0x%08X\n", gdiHandle); break; case 16: printf("Brush handle:0x%08X\n", gdiHandle); break; case 48: printf("Pen handle:0x%08X\n", gdiHandle); break; default: printf("Unknown type handle:0x%08X\n", gdiHandle); 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(GetmoduleeHandleA("ntdll.dll"), "NtQueryInformationProcess"); err = query(hProcess, 0, &pbi, sizeof(pbi), NULL); if (err != 0) { printf("NtQueryInformationProcess failed\n"); CloseHandle(hProcess); return -1; } // read PEB _NtReadVirtualMemory read = (_NtReadVirtualMemory)GetProcAddress(GetmoduleeHandleA("ntdll.dll"), "NtReadVirtualMemory"); err = read(hProcess, pbi.PebBaseAddress, peb, pebSize, NULL); if (err != 0) { printf("NtReadVirtualMemory PEB failed\n"); CloseHandle(hProcess); 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); 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); 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 ); break; case 4: printf("Region handle:0x%08X\n", gdiHandle); break; case 5: printf("Bitmap handle:0x%08X\n", gdiHandle); break; case 8: printf("Palette handle:0x%08X\n", gdiHandle); break; case 10: printf("Font handle:0x%08X\n", gdiHandle); break; case 16: printf("Brush handle:0x%08X\n", gdiHandle); break; case 48: printf("Pen handle:0x%08X\n", gdiHandle); break; default: printf("Unknown type handle:0x%08X\n", gdiHandle); break; } } free(table); } CloseHandle(hProcess); }
EnumGdi.h:
#pragma once #include "stdafx.h" // defines a GDI CELL typedef struct { LPVOID pcoreelAddress; USHORT wProcessId; USHORT wCount; USHORT wUpper; USHORT wType; LPVOID pUserAddress; } GDICELL; // defines a GDI CELL for WOW64 typedef struct { PVOID64 pcoreelAddress; USHORT wProcessId; USHORT wCount; USHORT wUpper; USHORT wType; PVOID64 pUserAddress; } GDICELL_WOW64; // NtQueryInformationProcess for pure 32 and 64-bit processes typedef NTSTATUS (NTAPI *_NtQueryInformationProcess)( IN HANDLE ProcessHandle, ULONG ProcessInformationClass, OUT PVOID ProcessInformation, IN ULONG ProcessInformationLength, OUT PULONG ReturnLength OPTIONAL ); typedef NTSTATUS (NTAPI *_NtReadVirtualMemory)( IN HANDLE ProcessHandle, IN PVOID BaseAddress, OUT PVOID Buffer, IN SIZE_T Size, OUT PSIZE_T NumberOfBytesRead); // NtQueryInformationProcess for 32-bit process on WOW64 typedef NTSTATUS (NTAPI *_NtWow64ReadVirtualMemory64)( IN HANDLE ProcessHandle, IN PVOID64 BaseAddress, OUT PVOID Buffer, IN ULONG64 Size, OUT PULONG64 NumberOfBytesRead); // PROCESS_BASIC_INFORMATION for pure 32 and 64-bit processes typedef struct _PROCESS_BASIC_INFORMATION { PVOID Reserved1; PVOID PebBaseAddress; PVOID Reserved2[2]; ULONG_PTR UniqueProcessId; PVOID Reserved3; } PROCESS_BASIC_INFORMATION; // PROCESS_BASIC_INFORMATION for 32-bit process on WOW64 // The definition is quite funky, as we just lazily doubled sizes to match offsets... typedef struct _PROCESS_BASIC_INFORMATION_WOW64 { PVOID Reserved1[2]; PVOID64 PebBaseAddress; PVOID Reserved2[4]; ULONG_PTR UniqueProcessId[2]; PVOID Reserved3[2]; } PROCESS_BASIC_INFORMATION_WOW64;
首先你必须用“GDI句柄”来定义你的意思,为什么你需要知道它们,因为有不同类型的句柄。
技术上有三种主要类型的手柄:
HWND
, HDC
, HICON
,桌面句柄等 HBITMAP
, HGDIOBJ
(亚型是HRGN
, HPEN
等)。 特别是有些人在用户和GDI处理之间混淆。 并不是每个人都知道,用于绘制的HDC
实际上不是一个GDI句柄。
从实现的角度来看,用户和GDI句柄之间有很大的区别。 用户句柄是系统范围内的,它们在内核中进行管理。 因此有机会在内核模式下收集关于它们的所有信息。 OTOH GDI句柄是特定于流程的。 一些GDI对象纯粹在用户模式下进行管理(如区域和DIB)。
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(GetmoduleeHandleA("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(GetmoduleeHandleA("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(GetmoduleeHandleA("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(GetmoduleeHandleA("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; }
和GDIInquiry.h代码如下
#pragma once #include "stdafx.h" #include "Winternl.h" // defines a GDI CELL typedef struct { LPVOID pcoreelAddress; USHORT wProcessId; USHORT wCount; USHORT wUpper; USHORT wType; LPVOID pUserAddress; } GDICELL; // defines a GDI CELL for WOW64 typedef struct { PVOID64 pcoreelAddress; USHORT wProcessId; USHORT wCount; USHORT wUpper; USHORT wType; PVOID64 pUserAddress; } GDICELL_WOW64; // NtQueryInformationProcess for pure 32 and 64-bit processes typedef NTSTATUS(NTAPI *_NtQueryInformationProcess)( IN HANDLE ProcessHandle, ULONG ProcessInformationClass, OUT PVOID ProcessInformation, IN ULONG ProcessInformationLength, OUT PULONG ReturnLength OPTIONAL ); typedef NTSTATUS(NTAPI *_NtReadVirtualMemory)( IN HANDLE ProcessHandle, IN PVOID BaseAddress, OUT PVOID Buffer, IN SIZE_T Size, OUT PSIZE_T NumberOfBytesRead); // NtQueryInformationProcess for 32-bit process on WOW64 typedef NTSTATUS(NTAPI *_NtWow64ReadVirtualMemory64)( IN HANDLE ProcessHandle, IN PVOID64 BaseAddress, OUT PVOID Buffer, IN ULONG64 Size, OUT PULONG64 NumberOfBytesRead); // PROCESS_BASIC_INFORMATION for pure 32 and 64-bit processes /*typedef struct { PVOID Reserved1; PVOID PebBaseAddress; PVOID Reserved2[2]; ULONG_PTR UniqueProcessId; PVOID Reserved3; }PROCESS_BASIC_INFORMATION;*/ // PROCESS_BASIC_INFORMATION for 32-bit process on WOW64 // The definition is quite funky, as we just lazily doubled sizes to match offsets... typedef struct PROCESS_BASIC_INFORMATION_WOW64 { PVOID Reserved1[2]; PVOID64 PebBaseAddress; PVOID Reserved2[4]; ULONG_PTR UniqueProcessId[2]; PVOID Reserved3[2]; }PROCESS_BASIC_INFORMATION_WOW64;
完
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