32/64 位 ReadProcessMemory 问题
32/64-bit ReadProcessMemory issues
我一直在 x86 机器上使用这段代码没有问题:
PIDHandle:= OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_OPERATION or
PROCESS_VM_READ, false, Struct.th32ProcessID);
if (PIDHandle <> 0)
ScanMemory(PIDHandle, Struct.szExeFile);
procedure TForm1.ScanMemory(PIDHandle: THandle; const ProcessName: string);
var
MemStart, ReceivedBytes: SIZE_T;
MemInfo: MEMORY_BASIC_INFORMATION;
begin
MemStart:= 0;
while (VirtualQueryEx(PIDHandle, Pointer(MemStart), MemInfo, SizeOf(MemInfo)) <> 0) do
begin
if ((MemInfo.State = MEM_COMMIT) and (not (MemInfo.Protect = PAGE_GUARD)
or (MemInfo.Protect = PAGE_NOACCESS)) and (MemInfo.Protect = PAGE_READWRITE)) then
begin
SetLength(Buff, MemInfo.RegionSize);
if (ReadProcessMemory(PIDHandle, MemInfo.BaseAddress, Buff,
MemInfo.RegionSize, ReceivedBytes)) then
begin
//do particular stuff with memory
end; //if readprocessmemory
end; //if mempages
MemStart:= MemStart + MemInfo.RegionSize;
end;
end;
现在我编译了一个 x64 二进制文件,它在一些随机进程中停止响应,我不确定它们是否 x86/x64...
从 x64 bin 到 x86 进程的 运行 ReadProcessMemory 是否存在任何已知问题?
真的有必要保留一个 x86 bin 来读取其他 x86 进程的内存和一个 x64 bin 来读取 x64 进程吗?或者有什么解决方法?
问题不在于 ReadProcessMemory()
,而是在于 VirtualQueryEx()
。
To enable a debugger to debug a target that is running on a different architecture (32-bit versus 64-bit), use one of the explicit forms of this structure.
typedef struct _MEMORY_BASIC_INFORMATION32 {
DWORD BaseAddress;
DWORD AllocationBase;
DWORD AllocationProtect;
DWORD RegionSize;
DWORD State;
DWORD Protect;
DWORD Type;
} MEMORY_BASIC_INFORMATION32, *PMEMORY_BASIC_INFORMATION32;
typedef struct DECLSPEC_ALIGN(16) _MEMORY_BASIC_INFORMATION64 {
ULONGLONG BaseAddress;
ULONGLONG AllocationBase;
DWORD AllocationProtect;
DWORD __alignment1;
ULONGLONG RegionSize;
DWORD State;
DWORD Protect;
DWORD Type;
DWORD __alignment2;
} MEMORY_BASIC_INFORMATION64, *PMEMORY_BASIC_INFORMATION64;
因此,查询32位进程时使用MEMORY_BASIC_INFORMATION32
,查询64位进程时使用MEMORY_BASIC_INFORMATION64
。但是,Delphi 不会声明这些记录类型,因此您必须在代码中手动声明。
Delphi 在 Windows
单元中对 MEMORY_BASIC_INFORMATION
的声明仿照旧的 32 位版本:
typedef struct _MEMORY_BASIC_INFORMATION {
PVOID BaseAddress;
PVOID AllocationBase;
DWORD AllocationProtect;
SIZE_T RegionSize;
DWORD State;
DWORD Protect;
DWORD Type;
} MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION;
PMemoryBasicInformation = ^TMemoryBasicInformation;
_MEMORY_BASIC_INFORMATION = record
BaseAddress : Pointer;
AllocationBase : Pointer;
AllocationProtect : DWORD;
RegionSize : SIZE_T;
State : DWORD;
Protect : DWORD;
Type_9 : DWORD;
end;
{$EXTERNALSYM _MEMORY_BASIC_INFORMATION}
TMemoryBasicInformation = _MEMORY_BASIC_INFORMATION;
MEMORY_BASIC_INFORMATION = _MEMORY_BASIC_INFORMATION;
{$EXTERNALSYM MEMORY_BASIC_INFORMATION}
这个只在32位调用进程中使用有效,64位调用进程中无效
使用IsWow64Process()
检查PIDHandle
是否是32位或64位进程的句柄,然后使用适当的记录类型扫描其内存,例如:
// 32-bit and 64-bit processes can scan the full address space of a 32-bit process,
// but a 32-bit process cannot scan the full address space of a 64-bit process
type
PMEMORY_BASIC_INFORMATION32 = ^MEMORY_BASIC_INFORMATION32;
MEMORY_BASIC_INFORMATION32 = record
BaseAddress: DWORD;
AllocationBase: DWORD;
AllocationProtect: DWORD;
RegionSize: DWORD;
State: DWORD;
Protect: DWORD;
_Type: DWORD;
end;
{$IFDEF WIN64}
PMEMORY_BASIC_INFORMATION64 = ^MEMORY_BASIC_INFORMATION64;
{$ALIGN 16}
MEMORY_BASIC_INFORMATION64 = record
BaseAddress: ULONGLONG;
AllocationBase: ULONGLONG;
AllocationProtect: DWORD;
_alignment1: DWORD;
RegionSize: ULONGLONG;
State: DWORD;
Protect: DWORD;
_Type: DWORD;
_alignment2: DWORD;
end;
{$ENDIF}
function VirtualQueryEx32(hProcess: THandle; lpAddress: Pointer; var lpBuffer: MEMORY_BASIC_INFORMATION32; dwLength: SIZE_T): SIZE_T; stdcall; external 'kernel32' name 'VirtualQueryEx';
{$IFDEF WIN64}
function VirtualQueryEx64(hProcess: THandle; lpAddress: Pointer; var lpBuffer: MEMORY_BASIC_INFORMATION64; dwLength: SIZE_T): SIZE_T; stdcall; external 'kernel32' name 'VirtualQueryEx';
{$ENDIF}
procedure TForm1.DoSomethingWithBuff(const ProcessName: string);
begin
// do particular stuff with Buff
end;
procedure TForm1.ScanMemory32(PIDHandle: THandle; const ProcessName: string);
var
MemStart: DWORD;
ReceivedBytes: SIZE_T;
MemInfo: MEMORY_BASIC_INFORMATION32;
begin
MemStart := 0;
while (VirtualQueryEx32(PIDHandle, Pointer(MemStart), MemInfo, SizeOf(MemInfo)) <> 0) do
begin
if ((MemInfo.State = MEM_COMMIT) and (not (MemInfo.Protect = PAGE_GUARD)
or (MemInfo.Protect = PAGE_NOACCESS)) and (MemInfo.Protect = PAGE_READWRITE)) then
begin
SetLength(Buff, MemInfo.RegionSize);
if (ReadProcessMemory(PIDHandle, Pointer(MemInfo.BaseAddress), Buff,
MemInfo.RegionSize, ReceivedBytes)) then
begin
DoSomethingWithBuff(ProcessName);
end;
end;
Inc(MemStart, MemInfo.RegionSize);
end;
end;
{$IFDEF WIN64}
procedure TForm1.ScanMemory64(PIDHandle: THandle; const ProcessName: string);
var
MemStart: ULONGLONG;
ReceivedBytes: SIZE_T;
MemInfo: MEMORY_BASIC_INFORMATION64;
begin
MemStart := 0;
while (VirtualQueryEx64(PIDHandle, Pointer(MemStart), MemInfo, SizeOf(MemInfo)) <> 0) do
begin
if ((MemInfo.State = MEM_COMMIT) and (not (MemInfo.Protect = PAGE_GUARD)
or (MemInfo.Protect = PAGE_NOACCESS)) and (MemInfo.Protect = PAGE_READWRITE)) then
begin
SetLength(Buff, MemInfo.RegionSize);
if (ReadProcessMemory(PIDHandle, Pointer(MemInfo.BaseAddress), Buff,
MemInfo.RegionSize, ReceivedBytes)) then
begin
DoSomethingWithBuff(ProcessName);
end;
end;
Inc(MemStart, MemInfo.RegionSize);
end;
end;
{$ENDIF}
procedure TForm1.ScanMemory(PIDHandle: THandle; const ProcessName: string);
var
Is32Bit: BOOL;
begin
if not IsWow64Process(PIDHandle, @Is32Bit) then
RaiseLastOSError;
if Is32Bit then begin
ScanMemory32(PIDHandle, ProcessName);
end
{$IFDEF WIN64}
else begin
ScanMemory64(PIDHandle, ProcessName);
end
{$ENDIF};
end;
我一直在 x86 机器上使用这段代码没有问题:
PIDHandle:= OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_OPERATION or
PROCESS_VM_READ, false, Struct.th32ProcessID);
if (PIDHandle <> 0)
ScanMemory(PIDHandle, Struct.szExeFile);
procedure TForm1.ScanMemory(PIDHandle: THandle; const ProcessName: string);
var
MemStart, ReceivedBytes: SIZE_T;
MemInfo: MEMORY_BASIC_INFORMATION;
begin
MemStart:= 0;
while (VirtualQueryEx(PIDHandle, Pointer(MemStart), MemInfo, SizeOf(MemInfo)) <> 0) do
begin
if ((MemInfo.State = MEM_COMMIT) and (not (MemInfo.Protect = PAGE_GUARD)
or (MemInfo.Protect = PAGE_NOACCESS)) and (MemInfo.Protect = PAGE_READWRITE)) then
begin
SetLength(Buff, MemInfo.RegionSize);
if (ReadProcessMemory(PIDHandle, MemInfo.BaseAddress, Buff,
MemInfo.RegionSize, ReceivedBytes)) then
begin
//do particular stuff with memory
end; //if readprocessmemory
end; //if mempages
MemStart:= MemStart + MemInfo.RegionSize;
end;
end;
现在我编译了一个 x64 二进制文件,它在一些随机进程中停止响应,我不确定它们是否 x86/x64...
从 x64 bin 到 x86 进程的 运行 ReadProcessMemory 是否存在任何已知问题? 真的有必要保留一个 x86 bin 来读取其他 x86 进程的内存和一个 x64 bin 来读取 x64 进程吗?或者有什么解决方法?
问题不在于 ReadProcessMemory()
,而是在于 VirtualQueryEx()
。
To enable a debugger to debug a target that is running on a different architecture (32-bit versus 64-bit), use one of the explicit forms of this structure.
typedef struct _MEMORY_BASIC_INFORMATION32 { DWORD BaseAddress; DWORD AllocationBase; DWORD AllocationProtect; DWORD RegionSize; DWORD State; DWORD Protect; DWORD Type; } MEMORY_BASIC_INFORMATION32, *PMEMORY_BASIC_INFORMATION32; typedef struct DECLSPEC_ALIGN(16) _MEMORY_BASIC_INFORMATION64 { ULONGLONG BaseAddress; ULONGLONG AllocationBase; DWORD AllocationProtect; DWORD __alignment1; ULONGLONG RegionSize; DWORD State; DWORD Protect; DWORD Type; DWORD __alignment2; } MEMORY_BASIC_INFORMATION64, *PMEMORY_BASIC_INFORMATION64;
因此,查询32位进程时使用MEMORY_BASIC_INFORMATION32
,查询64位进程时使用MEMORY_BASIC_INFORMATION64
。但是,Delphi 不会声明这些记录类型,因此您必须在代码中手动声明。
Delphi 在 Windows
单元中对 MEMORY_BASIC_INFORMATION
的声明仿照旧的 32 位版本:
typedef struct _MEMORY_BASIC_INFORMATION {
PVOID BaseAddress;
PVOID AllocationBase;
DWORD AllocationProtect;
SIZE_T RegionSize;
DWORD State;
DWORD Protect;
DWORD Type;
} MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION;
PMemoryBasicInformation = ^TMemoryBasicInformation;
_MEMORY_BASIC_INFORMATION = record
BaseAddress : Pointer;
AllocationBase : Pointer;
AllocationProtect : DWORD;
RegionSize : SIZE_T;
State : DWORD;
Protect : DWORD;
Type_9 : DWORD;
end;
{$EXTERNALSYM _MEMORY_BASIC_INFORMATION}
TMemoryBasicInformation = _MEMORY_BASIC_INFORMATION;
MEMORY_BASIC_INFORMATION = _MEMORY_BASIC_INFORMATION;
{$EXTERNALSYM MEMORY_BASIC_INFORMATION}
这个只在32位调用进程中使用有效,64位调用进程中无效
使用IsWow64Process()
检查PIDHandle
是否是32位或64位进程的句柄,然后使用适当的记录类型扫描其内存,例如:
// 32-bit and 64-bit processes can scan the full address space of a 32-bit process,
// but a 32-bit process cannot scan the full address space of a 64-bit process
type
PMEMORY_BASIC_INFORMATION32 = ^MEMORY_BASIC_INFORMATION32;
MEMORY_BASIC_INFORMATION32 = record
BaseAddress: DWORD;
AllocationBase: DWORD;
AllocationProtect: DWORD;
RegionSize: DWORD;
State: DWORD;
Protect: DWORD;
_Type: DWORD;
end;
{$IFDEF WIN64}
PMEMORY_BASIC_INFORMATION64 = ^MEMORY_BASIC_INFORMATION64;
{$ALIGN 16}
MEMORY_BASIC_INFORMATION64 = record
BaseAddress: ULONGLONG;
AllocationBase: ULONGLONG;
AllocationProtect: DWORD;
_alignment1: DWORD;
RegionSize: ULONGLONG;
State: DWORD;
Protect: DWORD;
_Type: DWORD;
_alignment2: DWORD;
end;
{$ENDIF}
function VirtualQueryEx32(hProcess: THandle; lpAddress: Pointer; var lpBuffer: MEMORY_BASIC_INFORMATION32; dwLength: SIZE_T): SIZE_T; stdcall; external 'kernel32' name 'VirtualQueryEx';
{$IFDEF WIN64}
function VirtualQueryEx64(hProcess: THandle; lpAddress: Pointer; var lpBuffer: MEMORY_BASIC_INFORMATION64; dwLength: SIZE_T): SIZE_T; stdcall; external 'kernel32' name 'VirtualQueryEx';
{$ENDIF}
procedure TForm1.DoSomethingWithBuff(const ProcessName: string);
begin
// do particular stuff with Buff
end;
procedure TForm1.ScanMemory32(PIDHandle: THandle; const ProcessName: string);
var
MemStart: DWORD;
ReceivedBytes: SIZE_T;
MemInfo: MEMORY_BASIC_INFORMATION32;
begin
MemStart := 0;
while (VirtualQueryEx32(PIDHandle, Pointer(MemStart), MemInfo, SizeOf(MemInfo)) <> 0) do
begin
if ((MemInfo.State = MEM_COMMIT) and (not (MemInfo.Protect = PAGE_GUARD)
or (MemInfo.Protect = PAGE_NOACCESS)) and (MemInfo.Protect = PAGE_READWRITE)) then
begin
SetLength(Buff, MemInfo.RegionSize);
if (ReadProcessMemory(PIDHandle, Pointer(MemInfo.BaseAddress), Buff,
MemInfo.RegionSize, ReceivedBytes)) then
begin
DoSomethingWithBuff(ProcessName);
end;
end;
Inc(MemStart, MemInfo.RegionSize);
end;
end;
{$IFDEF WIN64}
procedure TForm1.ScanMemory64(PIDHandle: THandle; const ProcessName: string);
var
MemStart: ULONGLONG;
ReceivedBytes: SIZE_T;
MemInfo: MEMORY_BASIC_INFORMATION64;
begin
MemStart := 0;
while (VirtualQueryEx64(PIDHandle, Pointer(MemStart), MemInfo, SizeOf(MemInfo)) <> 0) do
begin
if ((MemInfo.State = MEM_COMMIT) and (not (MemInfo.Protect = PAGE_GUARD)
or (MemInfo.Protect = PAGE_NOACCESS)) and (MemInfo.Protect = PAGE_READWRITE)) then
begin
SetLength(Buff, MemInfo.RegionSize);
if (ReadProcessMemory(PIDHandle, Pointer(MemInfo.BaseAddress), Buff,
MemInfo.RegionSize, ReceivedBytes)) then
begin
DoSomethingWithBuff(ProcessName);
end;
end;
Inc(MemStart, MemInfo.RegionSize);
end;
end;
{$ENDIF}
procedure TForm1.ScanMemory(PIDHandle: THandle; const ProcessName: string);
var
Is32Bit: BOOL;
begin
if not IsWow64Process(PIDHandle, @Is32Bit) then
RaiseLastOSError;
if Is32Bit then begin
ScanMemory32(PIDHandle, ProcessName);
end
{$IFDEF WIN64}
else begin
ScanMemory64(PIDHandle, ProcessName);
end
{$ENDIF};
end;