Win32 ReadProcessMemory API 的问题
Posted
技术标签:
【中文标题】Win32 ReadProcessMemory API 的问题【英文标题】:Issues with Win32 ReadProcessMemory API 【发布时间】:2020-06-30 21:05:30 【问题描述】:我正在编写一个简单的应用程序来执行进程空心化,它启动一个 64 位进程,然后应用程序使用 NtQueryInformationProcess 获取 PebBaseAddress,我尝试获取 Peb 的第 6 个成员,即 BaseAddressofImage 但我得到了返回的这个奇怪的地址不正确:
pebImageBaseOffset 为:0000000000000000
这是我正在使用的代码:
#include <iostream>
#include <Windows.h>
#include <winternl.h>
#include <tchar.h>
#pragma comment(lib, "ntdll")
int main()
// create destination process - this is the process to be hollowed out
LPSTARTUPINFOA si = new STARTUPINFOA();
LPPROCESS_INFORMATION pi = new PROCESS_INFORMATION();
PROCESS_BASIC_INFORMATION *pbi = new PROCESS_BASIC_INFORMATION();
DWORD returnLenght = 0;
CreateProcessA(NULL, (LPSTR)"c:\\windows\\system32\\calc.exe", NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, NULL, si, pi);
HANDLE destProcess = pi->hProcess;
// get destination imageBase offset address from the PEB
NtQueryInformationProcess(destProcess, ProcessBasicInformation, pbi, sizeof(PROCESS_BASIC_INFORMATION), &returnLenght);
DWORD pebImageBaseOffset = (DWORD)pbi->PebBaseAddress + 8;
// get destination imageBaseAddress
LPVOID destImageBase = 0;
SIZE_T bytesRead = NULL;
ReadProcessMemory(destProcess, (LPCVOID)pebImageBaseOffset, &destImageBase, 4, &bytesRead);
std::cout << "pebImageBaseOffset is: " << destImageBase << std::endl;
std::cin.get();
此代码被编译并链接为 64 位 PE 可执行文件。我在哪里错了?我知道 calc.exe 映像的实际基地址是 0x7ff7ab750000。
如果此代码被编译并链接为 32 位 PE 可执行文件,它可以工作,所以我认为我的问题与指针大小和指针运算有关,但我不是一个经验丰富的 C++ 程序员,我必须监督一些事情。
我尝试复制以下代码,但无法让它与 64 位可执行文件一起使用,这可能是因为指针截断相关问题:
#include <iostream>
#include <Windows.h>
#include <winternl.h>
#pragma comment(lib, "ntdll")
using NtUnmapViewOfSection = NTSTATUS(WINAPI*)(HANDLE, PVOID);
typedef struct BASE_RELOCATION_BLOCK
DWORD PageAddress;
DWORD BlockSize;
BASE_RELOCATION_BLOCK, *PBASE_RELOCATION_BLOCK;
typedef struct BASE_RELOCATION_ENTRY
USHORT Offset : 12;
USHORT Type : 4;
BASE_RELOCATION_ENTRY, *PBASE_RELOCATION_ENTRY;
int main()
// create destination process - this is the process to be hollowed out
LPSTARTUPINFOA si = new STARTUPINFOA();
LPPROCESS_INFORMATION pi = new PROCESS_INFORMATION();
PROCESS_BASIC_INFORMATION *pbi = new PROCESS_BASIC_INFORMATION();
DWORD returnLenght = 0;
CreateProcessA(NULL, (LPSTR)"c:\\windows\\syswow64\\notepad.exe", NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, NULL, si, pi);
HANDLE destProcess = pi->hProcess;
// get destination imageBase offset address from the PEB
NtQueryInformationProcess(destProcess, ProcessBasicInformation, pbi, sizeof(PROCESS_BASIC_INFORMATION), &returnLenght);
DWORD pebImageBaseOffset = (DWORD)pbi->PebBaseAddress + 8;
// get destination imageBaseAddress
LPVOID destImageBase = 0;
SIZE_T bytesRead = NULL;
ReadProcessMemory(destProcess, (LPCVOID)pebImageBaseOffset, &destImageBase, 4, &bytesRead);
// read source file - this is the file that will be executed inside the hollowed process
HANDLE sourceFile = CreateFileA("C:\\temp\\regshot.exe", GENERIC_READ, NULL, NULL, OPEN_ALWAYS, NULL, NULL);
DWORD sourceFileSize = GetFileSize(sourceFile, NULL);
LPDWORD fileBytesRead = 0;
LPVOID sourceFileBytesBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sourceFileSize);
ReadFile(sourceFile, sourceFileBytesBuffer, sourceFileSize, NULL, NULL);
// get source image size
PIMAGE_DOS_HEADER sourceImageDosHeaders = (PIMAGE_DOS_HEADER)sourceFileBytesBuffer;
PIMAGE_NT_HEADERS sourceImageNTHeaders = (PIMAGE_NT_HEADERS)((DWORD)sourceFileBytesBuffer + sourceImageDosHeaders->e_lfanew);
SIZE_T sourceImageSize = sourceImageNTHeaders->OptionalHeader.SizeOfImage;
// carve out the destination image
NtUnmapViewOfSection myNtUnmapViewOfSection = (NtUnmapViewOfSection)(GetProcAddress(GetModuleHandleA("ntdll"), "NtUnmapViewOfSection"));
myNtUnmapViewOfSection(destProcess, destImageBase);
// allocate new memory in destination image for the source image
LPVOID newDestImageBase = VirtualAllocEx(destProcess, destImageBase, sourceImageSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
destImageBase = newDestImageBase;
// get delta between sourceImageBaseAddress and destinationImageBaseAddress
DWORD deltaImageBase = (DWORD)destImageBase - sourceImageNTHeaders->OptionalHeader.ImageBase;
// set sourceImageBase to destImageBase and copy the source Image headers to the destination image
sourceImageNTHeaders->OptionalHeader.ImageBase = (DWORD)destImageBase;
WriteProcessMemory(destProcess, newDestImageBase, sourceFileBytesBuffer, sourceImageNTHeaders->OptionalHeader.SizeOfHeaders, NULL);
// get pointer to first source image section
PIMAGE_SECTION_HEADER sourceImageSection = (PIMAGE_SECTION_HEADER)((DWORD)sourceFileBytesBuffer + sourceImageDosHeaders->e_lfanew + sizeof(IMAGE_NT_HEADERS32));
PIMAGE_SECTION_HEADER sourceImageSectionOld = sourceImageSection;
int err = GetLastError();
// copy source image sections to destination
for (int i = 0; i < sourceImageNTHeaders->FileHeader.NumberOfSections; i++)
PVOID destinationSectionLocation = (PVOID)((DWORD)destImageBase + sourceImageSection->VirtualAddress);
PVOID sourceSectionLocation = (PVOID)((DWORD)sourceFileBytesBuffer + sourceImageSection->PointerToRawData);
WriteProcessMemory(destProcess, destinationSectionLocation, sourceSectionLocation, sourceImageSection->SizeOfRawData, NULL);
sourceImageSection++;
// get address of the relocation table
IMAGE_DATA_DIRECTORY relocationTable = sourceImageNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
// patch the binary with relocations
sourceImageSection = sourceImageSectionOld;
for (int i = 0; i < sourceImageNTHeaders->FileHeader.NumberOfSections; i++)
BYTE* relocSectionName = (BYTE*)".reloc";
if (memcmp(sourceImageSection->Name, relocSectionName, 5) != 0)
sourceImageSection++;
continue;
DWORD sourceRelocationTableRaw = sourceImageSection->PointerToRawData;
DWORD relocationOffset = 0;
while (relocationOffset < relocationTable.Size)
PBASE_RELOCATION_BLOCK relocationBlock = (PBASE_RELOCATION_BLOCK)((DWORD)sourceFileBytesBuffer + sourceRelocationTableRaw + relocationOffset);
relocationOffset += sizeof(BASE_RELOCATION_BLOCK);
DWORD relocationEntryCount = (relocationBlock->BlockSize - sizeof(BASE_RELOCATION_BLOCK)) / sizeof(BASE_RELOCATION_ENTRY);
PBASE_RELOCATION_ENTRY relocationEntries = (PBASE_RELOCATION_ENTRY)((DWORD)sourceFileBytesBuffer + sourceRelocationTableRaw + relocationOffset);
for (DWORD y = 0; y < relocationEntryCount; y++)
relocationOffset += sizeof(BASE_RELOCATION_ENTRY);
if (relocationEntries[y].Type == 0)
continue;
DWORD patchAddress = relocationBlock->PageAddress + relocationEntries[y].Offset;
DWORD patchedBuffer = 0;
ReadProcessMemory(destProcess,(LPCVOID)((DWORD)destImageBase + patchAddress), &patchedBuffer, sizeof(DWORD), &bytesRead);
patchedBuffer += deltaImageBase;
WriteProcessMemory(destProcess, (PVOID)((DWORD)destImageBase + patchAddress), &patchedBuffer, sizeof(DWORD), fileBytesRead);
int a = GetLastError();
// get context of the dest process thread
LPCONTEXT context = new CONTEXT();
context->ContextFlags = CONTEXT_INTEGER;
GetThreadContext(pi->hThread, context);
// update dest image entry point to the new entry point of the source image and resume dest image thread
DWORD patchedEntryPoint = (DWORD)destImageBase + sourceImageNTHeaders->OptionalHeader.AddressOfEntryPoint;
context->Eax = patchedEntryPoint;
SetThreadContext(pi->hThread, context);
ResumeThread(pi->hThread);
return 0;
【问题讨论】:
绝对没有错误处理。这不是一个学习的好方法,为什么你的程序会失败。好吧,这并不完全正确。有 次调用GetLastError
。但它们都返回不确定的值。
为什么要将 PebBaseAddress
转换为 64 位 exe 的 DWORD?
@JonathanPotter,我尝试转换为 unsigned long long ,但这并没有真正帮助......
您的代码中还有其他类型的转换,这在 64 位中没有任何意义。从某个地方复制代码是可以的,但您应该仔细阅读并尝试自己理解它。
第一步,添加错误检查
【参考方案1】:
第一个代码示例:在x64
下运行时,请改用ULONG_PTR
,只要指针不被截断即可。并且需要将偏移量更改为 16(ImageBaseAddress
在 x86 中为 PEB+8,在 x64 中为 PEB+16)。
在ReadProcessMemory
中,需要将4改为8,即x64下ULONG_PTR
的大小。
x64 下,
#include <iostream>
#include <Windows.h>
#include <winternl.h>
#include <tchar.h>
#pragma comment(lib, "ntdll")
int main()
// create destination process - this is the process to be hollowed out
LPSTARTUPINFOA si = new STARTUPINFOA();
LPPROCESS_INFORMATION pi = new PROCESS_INFORMATION();
PROCESS_BASIC_INFORMATION* pbi = new PROCESS_BASIC_INFORMATION();
ULONG returnLenght = 0;
CreateProcessA(NULL, (LPSTR)"c:\\windows\\system32\\calc.exe", NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, NULL, si, pi);
HANDLE destProcess = pi->hProcess;
// get destination imageBase offset address from the PEB
NtQueryInformationProcess(destProcess, ProcessBasicInformation, pbi, sizeof(PROCESS_BASIC_INFORMATION), &returnLenght);
ULONG_PTR pebImageBaseOffset = (ULONG_PTR)pbi->PebBaseAddress + 16;
// get destination imageBaseAddress
LPVOID destImageBase = 0;
SIZE_T bytesRead = NULL;
ReadProcessMemory(destProcess, (LPCVOID)pebImageBaseOffset, &destImageBase, 8, &bytesRead);
std::cout << "pebImageBaseOffset is: " << destImageBase << std::endl;
std::cin.get();
第二个代码示例。 x64下,除了上面提到的修改外,还需要将IMAGE_NT_HEADERS32
改为_IMAGE_NT_HEADERS64
。
#include <iostream>
#include <Windows.h>
#include <winternl.h>
#pragma comment(lib, "ntdll")
using NtUnmapViewOfSection = NTSTATUS(WINAPI*)(HANDLE, PVOID);
typedef struct BASE_RELOCATION_BLOCK
DWORD PageAddress;
DWORD BlockSize;
BASE_RELOCATION_BLOCK, * PBASE_RELOCATION_BLOCK;
typedef struct BASE_RELOCATION_ENTRY
USHORT Offset : 12;
USHORT Type : 4;
BASE_RELOCATION_ENTRY, * PBASE_RELOCATION_ENTRY;
int main()
// create destination process - this is the process to be hollowed out
LPSTARTUPINFOA si = new STARTUPINFOA();
LPPROCESS_INFORMATION pi = new PROCESS_INFORMATION();
PROCESS_BASIC_INFORMATION* pbi = new PROCESS_BASIC_INFORMATION();
ULONG returnLenght = 0;
CreateProcessA(NULL, (LPSTR)"c:\\windows\\syswow64\\notepad.exe", NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, NULL, si, pi);
HANDLE destProcess = pi->hProcess;
// get destination imageBase offset address from the PEB
NtQueryInformationProcess(destProcess, ProcessBasicInformation, pbi, sizeof(PROCESS_BASIC_INFORMATION), &returnLenght);
ULONG_PTR pebImageBaseOffset = (ULONG_PTR)pbi->PebBaseAddress + 16;
// get destination imageBaseAddress
LPVOID destImageBase = 0;
SIZE_T bytesRead = NULL;
ReadProcessMemory(destProcess, (LPCVOID)pebImageBaseOffset, &destImageBase, sizeof(ULONG_PTR), &bytesRead);
// read source file - this is the file that will be executed inside the hollowed process
HANDLE sourceFile = CreateFileA("c:\\windows\\system32\\calc.exe", GENERIC_READ, NULL, NULL, OPEN_ALWAYS, NULL, NULL);
ULONG_PTR sourceFileSize = GetFileSize(sourceFile, NULL);
SIZE_T fileBytesRead = 0;
LPVOID sourceFileBytesBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sourceFileSize);
ReadFile(sourceFile, sourceFileBytesBuffer, sourceFileSize, NULL, NULL);
// get source image size
PIMAGE_DOS_HEADER sourceImageDosHeaders = (PIMAGE_DOS_HEADER)sourceFileBytesBuffer;
PIMAGE_NT_HEADERS sourceImageNTHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)sourceFileBytesBuffer + sourceImageDosHeaders->e_lfanew);
SIZE_T sourceImageSize = sourceImageNTHeaders->OptionalHeader.SizeOfImage;
// carve out the destination image
NtUnmapViewOfSection myNtUnmapViewOfSection = (NtUnmapViewOfSection)(GetProcAddress(GetModuleHandleA("ntdll"), "NtUnmapViewOfSection"));
myNtUnmapViewOfSection(destProcess, destImageBase);
// allocate new memory in destination image for the source image
LPVOID newDestImageBase = VirtualAllocEx(destProcess, destImageBase, sourceImageSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
destImageBase = newDestImageBase;
// get delta between sourceImageBaseAddress and destinationImageBaseAddress
ULONG_PTR deltaImageBase = (ULONG_PTR)destImageBase - sourceImageNTHeaders->OptionalHeader.ImageBase;
// set sourceImageBase to destImageBase and copy the source Image headers to the destination image
sourceImageNTHeaders->OptionalHeader.ImageBase = (ULONG_PTR)destImageBase;
WriteProcessMemory(destProcess, newDestImageBase, sourceFileBytesBuffer, sourceImageNTHeaders->OptionalHeader.SizeOfHeaders, NULL);
// get pointer to first source image section
PIMAGE_SECTION_HEADER sourceImageSection = (PIMAGE_SECTION_HEADER)((ULONG_PTR)sourceFileBytesBuffer + sourceImageDosHeaders->e_lfanew + sizeof(_IMAGE_NT_HEADERS64)); //IMAGE_NT_HEADERS32
PIMAGE_SECTION_HEADER sourceImageSectionOld = sourceImageSection;
// copy source image sections to destination
for (int i = 0; i < sourceImageNTHeaders->FileHeader.NumberOfSections; i++)
PVOID destinationSectionLocation = (PVOID)((ULONG_PTR)destImageBase + sourceImageSection->VirtualAddress);
PVOID sourceSectionLocation = (PVOID)((ULONG_PTR)sourceFileBytesBuffer + sourceImageSection->PointerToRawData);
WriteProcessMemory(destProcess, destinationSectionLocation, sourceSectionLocation, sourceImageSection->SizeOfRawData, NULL);
sourceImageSection++;
// get address of the relocation table
IMAGE_DATA_DIRECTORY relocationTable = sourceImageNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
// patch the binary with relocations
sourceImageSection = sourceImageSectionOld;
for (int i = 0; i < sourceImageNTHeaders->FileHeader.NumberOfSections; i++)
BYTE* relocSectionName = (BYTE*)".reloc";
if (memcmp(sourceImageSection->Name, relocSectionName, 5) != 0)
sourceImageSection++;
continue;
ULONG_PTR sourceRelocationTableRaw = sourceImageSection->PointerToRawData;
ULONG_PTR relocationOffset = 0;
while (relocationOffset < relocationTable.Size)
PBASE_RELOCATION_BLOCK relocationBlock = (PBASE_RELOCATION_BLOCK)((ULONG_PTR)sourceFileBytesBuffer + sourceRelocationTableRaw + relocationOffset);
relocationOffset += sizeof(BASE_RELOCATION_BLOCK);
ULONG_PTR relocationEntryCount = (relocationBlock->BlockSize - sizeof(BASE_RELOCATION_BLOCK)) / sizeof(BASE_RELOCATION_ENTRY);
PBASE_RELOCATION_ENTRY relocationEntries = (PBASE_RELOCATION_ENTRY)((ULONG_PTR)sourceFileBytesBuffer + sourceRelocationTableRaw + relocationOffset);
for (ULONG_PTR y = 0; y < relocationEntryCount; y++)
relocationOffset += sizeof(BASE_RELOCATION_ENTRY);
if (relocationEntries[y].Type == 0)
continue;
ULONG_PTR patchAddress = relocationBlock->PageAddress + relocationEntries[y].Offset;
ULONG_PTR patchedBuffer = 0;
ReadProcessMemory(destProcess, (LPCVOID)((ULONG_PTR)destImageBase + patchAddress), &patchedBuffer, sizeof(ULONG_PTR), &bytesRead);
patchedBuffer += deltaImageBase;
WriteProcessMemory(destProcess, (PVOID)((ULONG_PTR)destImageBase + patchAddress), &patchedBuffer, sizeof(ULONG_PTR), &fileBytesRead);
return 0;
【讨论】:
这是正确的,虽然你错过了代码的结尾...检查我的代码并编辑你的代码,因为它有更多的赞成票,谢谢你的帮助! 我不敢相信你为 64 位编写了另一个函数!使用 IMAGE_NT_HEADERS 而不是 IMAGE_NT_HEADERS32 或 IMAGE_NT_HEADERS64,您可以轻松编写一个适用于 32 位和 64 位的函数。如果 32 和 64 之间仍有不同之处,请使用 #ifdef WIN64 ... #else ... #endif。您可以使用 sizeof(ULONG_PTR) 而不是将硬编码的 4 更改为 8,它适用于两种位数。【参考方案2】:我关注了@Strive Sun - 上面的 MSFT 回答,并得到了下面显示的代码。但是,我注意到该代码仅在使用某些可执行文件时才有效,例如,如果我将 calc.exe 替换为 C:\Windows\System32\ 中的 cmd.exe 它失败,当我对 3 个文件运行文件实用程序时,它似乎 cmd.exe 与其他文件略有不同,这可能解释了它失败的原因,如果有人阅读本文确切知道为什么这两个文件不兼容,请告诉我。
我怀疑它与this有关:
cmd.exe: PE32+ executable (console) x86-64, for MS Windows
calc.exe: PE32+ executable (GUI) x86-64, for MS Windows
cleanmgr.exe: PE32+ executable (GUI) x86-64, for MS Windows
"...为了最大化兼容性,源图像的子系统应该设置为windows。编译器应该使用静态版本的运行库来去除对Visual C++运行时DLL的依赖。这样可以实现通过使用 /MT 或 /MTd 编译器选项。源映像的首选基地址(假设它有一个)必须与目标映像的基地址匹配,或者源必须包含重定位表并且映像需要重新定位到目标地址。出于兼容性原因,首选变基路由。/DYNAMICBASE 或 /FIXED:NO 链接器选项可用于生成重定位表..."
这是我最终使用的代码,但@strive sun 的解决方案基本上也是我最终做的。
#include <iostream>
#include <Windows.h>
#include <winternl.h>
#include <tchar.h>
#include "ntstatus.h"
#pragma comment(lib, "ntdll")
using NtUnmapViewOfSection = NTSTATUS(WINAPI*)(HANDLE, PVOID);
typedef NTSTATUS(NTAPI *pfnNtQueryInformationProcess)(
IN HANDLE ProcessHandle,
IN PROCESSINFOCLASS ProcessInformationClass,
OUT PVOID ProcessInformation,
IN ULONG ProcessInformationLength,
OUT PULONG ReturnLength OPTIONAL
);
typedef struct BASE_RELOCATION_BLOCK
DWORD PageAddress;
DWORD BlockSize;
BASE_RELOCATION_BLOCK, *PBASE_RELOCATION_BLOCK;
typedef struct BASE_RELOCATION_ENTRY
USHORT Offset : 12;
USHORT Type : 4;
BASE_RELOCATION_ENTRY, *PBASE_RELOCATION_ENTRY;
UINT_PTR GetPEBLocation(HANDLE hProcess)
ULONG RequiredLen = 0;
UINT_PTR PebAddress = NULL;
PROCESS_BASIC_INFORMATION myProcessBasicInformation[5] = 0 ;
if (NtQueryInformationProcess(hProcess, ProcessBasicInformation, myProcessBasicInformation, sizeof(PROCESS_BASIC_INFORMATION), &RequiredLen) == STATUS_SUCCESS)
PebAddress = (UINT_PTR)myProcessBasicInformation->PebBaseAddress + 16;
else
if (NtQueryInformationProcess(hProcess, ProcessBasicInformation, myProcessBasicInformation, RequiredLen, &RequiredLen) == STATUS_SUCCESS)
PebAddress = (UINT_PTR)myProcessBasicInformation->PebBaseAddress + 16;
return PebAddress;
int main()
// create destination process - this is the process to be hollowed out
LPSTARTUPINFOA si = new STARTUPINFOA();
LPPROCESS_INFORMATION pi = new PROCESS_INFORMATION();
PROCESS_BASIC_INFORMATION *pbi = new PROCESS_BASIC_INFORMATION();
CreateProcessA(NULL, (LPSTR)"c:\\windows\\system32\\cleanmgr.exe", NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, NULL, si, pi);
HANDLE destProcess = pi->hProcess;
LPVOID destProcessImageBase = (LPVOID)GetPEBLocation(destProcess);
std::cout << "PEB image base address is at: " << destProcessImageBase << std::endl;
// get destination imageBaseAddress
LPVOID destImageBase = NULL;
SIZE_T bytesRead = NULL;
ReadProcessMemory(destProcess, (LPVOID)destProcessImageBase, &destImageBase, 8, &bytesRead);
std::cout << "Image base address is at: " << destImageBase << std::endl;
// read source file - this is the file that will be executed inside the hollowed process
HANDLE sourceFile = CreateFileA("c:\\windows\\system32\\calc.exe", GENERIC_READ, NULL, NULL, OPEN_ALWAYS, NULL, NULL);
SIZE_T sourceFileSize = GetFileSize(sourceFile, NULL);
LPVOID sourceFileBytesBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sourceFileSize);
ReadFile(sourceFile, sourceFileBytesBuffer, sourceFileSize, NULL, NULL);
// get source image size
PIMAGE_DOS_HEADER sourceImageDosHeaders = (PIMAGE_DOS_HEADER)sourceFileBytesBuffer;
PIMAGE_NT_HEADERS sourceImageNTHeaders = (PIMAGE_NT_HEADERS)((ULONGLONG)sourceFileBytesBuffer + sourceImageDosHeaders->e_lfanew);
SIZE_T sourceImageSize = sourceImageNTHeaders->OptionalHeader.SizeOfImage;
std::cout << "LPVOID is: " << sizeof(LPVOID) << " DWORD is " << sizeof(DWORD) << " ULONGLONG is " << sizeof(ULONGLONG) << std::endl;
// carve out the destination image
NtUnmapViewOfSection myNtUnmapViewOfSection = (NtUnmapViewOfSection)(GetProcAddress(GetModuleHandleA("ntdll"), "NtUnmapViewOfSection"));
myNtUnmapViewOfSection(destProcess, destImageBase);
// allocate new memory in destination image for the source image
LPVOID newDestImageBase = VirtualAllocEx(destProcess, destImageBase, sourceImageSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
destImageBase = newDestImageBase;
// get delta between sourceImageBaseAddress and destinationImageBaseAddress
ULONGLONG deltaImageBase = (ULONGLONG)destImageBase - sourceImageNTHeaders->OptionalHeader.ImageBase;
// set sourceImageBase to destImageBase and copy the source Image headers to the destination image
sourceImageNTHeaders->OptionalHeader.ImageBase = (ULONGLONG)destImageBase;
WriteProcessMemory(destProcess, newDestImageBase, sourceFileBytesBuffer, sourceImageNTHeaders->OptionalHeader.SizeOfHeaders, NULL);
// get pointer to first source image section
PIMAGE_SECTION_HEADER sourceImageSection = (PIMAGE_SECTION_HEADER)((ULONGLONG)sourceFileBytesBuffer + sourceImageDosHeaders->e_lfanew + sizeof(IMAGE_NT_HEADERS64));
PIMAGE_SECTION_HEADER sourceImageSectionOld = sourceImageSection;
std::cout << "LPDWORD is: " << sizeof(LPDWORD) << std::endl;
std::cout << "SIZE_T is: " << sizeof(SIZE_T) << std::endl;
// copy source image sections to destination
for (int i = 0; i < sourceImageNTHeaders->FileHeader.NumberOfSections; i++)
PVOID destinationSectionLocation = (PVOID)((ULONGLONG)destImageBase + sourceImageSection->VirtualAddress);
PVOID sourceSectionLocation = (PVOID)((ULONGLONG)sourceFileBytesBuffer + sourceImageSection->PointerToRawData);
WriteProcessMemory(destProcess, destinationSectionLocation, sourceSectionLocation, sourceImageSection->SizeOfRawData, NULL);
sourceImageSection++;
// get address of the relocation table
IMAGE_DATA_DIRECTORY relocationTable = sourceImageNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
// patch the binary with relocations
sourceImageSection = sourceImageSectionOld;
for (int i = 0; i < sourceImageNTHeaders->FileHeader.NumberOfSections; i++)
BYTE* relocSectionName = (BYTE*)".reloc";
if (memcmp(sourceImageSection->Name, relocSectionName, 5) != 0)
sourceImageSection++;
continue;
ULONGLONG sourceRelocationTableRaw = sourceImageSection->PointerToRawData;
DWORD relocationOffset = 0;
while (relocationOffset < relocationTable.Size)
PBASE_RELOCATION_BLOCK relocationBlock = (PBASE_RELOCATION_BLOCK)((ULONGLONG)sourceFileBytesBuffer + sourceRelocationTableRaw + relocationOffset);
relocationOffset += sizeof(BASE_RELOCATION_BLOCK);
DWORD relocationEntryCount = (relocationBlock->BlockSize - sizeof(BASE_RELOCATION_BLOCK)) / sizeof(BASE_RELOCATION_ENTRY);
PBASE_RELOCATION_ENTRY relocationEntries = (PBASE_RELOCATION_ENTRY)((ULONGLONG)sourceFileBytesBuffer + sourceRelocationTableRaw + relocationOffset);
for (DWORD y = 0; y < relocationEntryCount; y++)
relocationOffset += sizeof(BASE_RELOCATION_ENTRY);
if (relocationEntries[y].Type == 0)
continue;
ULONGLONG patchAddress = relocationBlock->PageAddress + relocationEntries[y].Offset;
ULONGLONG patchedBuffer = 0;
ReadProcessMemory(destProcess, (LPCVOID)((ULONGLONG)destImageBase + patchAddress), &patchedBuffer, sizeof(ULONGLONG), &bytesRead);
patchedBuffer += deltaImageBase;
WriteProcessMemory(destProcess, (PVOID)((ULONGLONG)destImageBase + patchAddress), &patchedBuffer, sizeof(ULONGLONG),NULL);
int a = GetLastError();
// get context of the dest process thread
LPCONTEXT context = new CONTEXT();
context->ContextFlags = CONTEXT_INTEGER;
GetThreadContext(pi->hThread, context);
// update dest image entry point to the new entry point of the source image and resume dest image thread
ULONGLONG patchedEntryPoint = (ULONGLONG)destImageBase + sourceImageNTHeaders->OptionalHeader.AddressOfEntryPoint;
context->Rcx = patchedEntryPoint;
SetThreadContext(pi->hThread, context);
ResumeThread(pi->hThread);
std::cin.get();
return 0;
【讨论】:
嗨,很抱歉恢复旧线程。在这种情况下SetThreadContext
不会失败吗?我也在尝试这样的事情,但我无法在 x64 上设置易失性寄存器。
这段代码在 x64/Windows 10 上确实为我工作,我能够空出一个进程并且没有得到你提到的问题......你有错误吗?如果没有,请尝试使用不同的二进制文件...我记得我遇到了我认为与目标子系统有关的问题。
我实际上正在尝试使用您正在使用的相同可执行文件,但很可能我可能做错了其他事情。我只是担心这个其他线程***.com/questions/25004311/…以上是关于Win32 ReadProcessMemory API 的问题的主要内容,如果未能解决你的问题,请参考以下文章
A log about Reading the memroy of Other Process in C++/WIN API--ReadProcessMemory()
使用 ReadProcessMemory 获取字符串值的访问冲突
delphi XE Berlin ReadProcessMemory WriteProcessMemory