Sto provando a scrivere, utilizzando il metodo di iniezione DLL, l'applicazione che mostra le bitmap utilizzate da un altro programma e voglio ottenere questo elenco di GDI Handles specifico che sta usando (lista come nell'utilità GDIView.exe). Ho trovato un articolo sulla funzione NtQuerySystemInformation, ma questa descrizione funziona solo con gli handle per gli oggetti del kernel. Qualcuno può aiutare?Come ottenere l'elenco delle maniglie GDI
risposta
Ecco un codice dell'applicazione della console che esegue il dump di tutti gli handle GDI per un determinato identificativo di processo. Dovrebbe essere compilato e funzionante per applicazioni a 32 o 64 bit, nonché per applicazioni a 32 bit in esecuzione su sistemi operativi a 64 bit. Utilizza molte funzioni non documentate quindi non fare affidamento su di esso :-) I crediti sulle strutture per la tabella GDI condivisa vanno al lavoro originale Feng Yuan. (Ho dovuto adattarlo per WOW64).
Ecco un esempio di output quando eseguito su un blocchetto (64 bit) processo:
[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(GetModuleHandleA("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(GetModuleHandleA("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(GetModuleHandleA("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(GetModuleHandleA("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 pKernelAddress;
USHORT wProcessId;
USHORT wCount;
USHORT wUpper;
USHORT wType;
LPVOID pUserAddress;
} GDICELL;
// defines a GDI CELL for WOW64
typedef struct
{
PVOID64 pKernelAddress;
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;
Probabilmente dovresti documentare su quali versioni di Windows è noto che funzionino. –
Finora è noto lavorare su Windows 7, l'unico che ho a portata di mano :-). Ma è stato progettato per funzionare su XP e versioni successive. –
Per prima cosa devi definire cosa intendi esattamente con "Gestisci GDI" e perché devi conoscerli, perché esistono diversi tipi di handle.
Tecnicamente Ci sono 3 principali tipi di maniglie:
- kernel gestisce. Esempi: handle di file, oggetti di sincronizzazione (eventi, mutex, ecc.), Mappature di file e così via.
- Gestione utenti. Esempi:
HWND
,HDC
,HICON
, maniglie del desktop e così via. - Handle GDI. Esempi:
HBITMAP
,HGDIOBJ
(i sottotipi sonoHRGN
,HPEN
e così via).
In particolare alcune persone confondono tra gli handle utente e GDI. Non tutti sanno che HDC
utilizzato per il disegno è in realtà non un handle GDI.
Dal punto di vista dell'implementazione c'è una grande differenza tra gli handle utente e GDI. Gli handle utente sono a livello di sistema, sono gestiti nel kernel. Quindi c'è la possibilità di raccogliere tutte le informazioni su di loro nella modalità kernel. Gli handle OTOH GDI sono specifici del processo. Alcuni oggetti GDI sono gestiti esclusivamente in modalità utente (come regioni e DIB).
Sono interessato in particolare agli HBITMAP. GDIView indica l'indirizzo del kernel per questo tipo di handle, quindi penso che sia gestito in modalità kernel. – cadaver
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;
}
e GDIInquiry.h codice è indicato sotto
#pragma once
#include "stdafx.h"
#include "Winternl.h"
// defines a GDI CELL
typedef struct
{
LPVOID pKernelAddress;
USHORT wProcessId;
USHORT wCount;
USHORT wUpper;
USHORT wType;
LPVOID pUserAddress;
} GDICELL;
// defines a GDI CELL for WOW64
typedef struct
{
PVOID64 pKernelAddress;
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;
Fine
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
Se vuoi l'accesso a oggetti GDI di un'altra applicazione, è necessario coordinare con tale applicazione. Altrimenti non sai se l'altra app distruggerà l'oggetto mentre lo stai usando. Semplicemente non esiste un modo affidabile per farlo senza la cooperazione con l'altra app. –