C++ Win32 ReadProcessMemory API的问题
我正在编写一个简单的应用程序来执行进程空洞化,该程序启动一个64位进程,然后应用程序使用NtQueryInformationProcess获取PebBaseAddress,我尝试获取Peb的第6个成员,即BaseAddressofImage,但我得到返回的这个奇怪的地址不正确: pebImageBaseOffset为:0000000000000000 以下是我正在使用的代码:C++ Win32 ReadProcessMemory API的问题,c++,c,winapi,C++,C,Winapi,我正在编写一个简单的应用程序来执行进程空洞化,该程序启动一个64位进程,然后应用程序使用NtQueryInformationProcess获取PebBaseAddress,我尝试获取Peb的第6个成员,即BaseAddressofImage,但我得到返回的这个奇怪的地址不正确: pebImageBaseOffset为:0000000000000000 以下是我正在使用的代码: #include <iostream> #include <Windows.h> #includ
#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();
}
#包括
#包括
#包括
#包括
#pragma注释(lib,“ntdll”)
int main()
{
//创建目标进程-这是要挖空的进程
LPSTARTUPINFOA si=新的STARTUPINFOA();
LPPROCESS_INFORMATION pi=新流程_INFORMATION();
流程基本信息*pbi=新流程基本信息();
DWORD returnLenght=0;
CreateProcessA(NULL,(LPSTR)“c:\\windows\\system32\\calc.exe”,NULL,NULL,TRUE,创建挂起,NULL,NULL,si,pi);
HANDLE destProcess=pi->hProcess;
//从PEB获取目标imageBase偏移地址
NtQueryInformationProcess(destProcess、ProcessBasicInformation、pbi、sizeof(流程基本信息)和ReturnLength);
DWORD pebImageBaseOffset=(DWORD)pbi->PebBaseAddress+8;
//获取目标imageBaseAddress
LPVOID desimagebase=0;
SIZE\u T bytesRead=NULL;
ReadProcessMemory(destProcess,(LPCVOID)pebImageBaseOffset和destmagebase,4和bytesRead);
std::cout我遵循了上面的@Strive Sun-MSFT答案,得到了下面显示的代码。但是,我注意到,该代码仅在使用某些可执行文件时有效,例如,如果我从C:\Windows\System32中将calc.exe替换为cmd.exe,则会失败,当我在3个文件上运行file实用程序时,cmd.exe看起来确实略有不同与其他文件不同,这可能解释了它失败的原因,如果任何阅读本文的人确切知道这两个文件不兼容的原因,请让我知道
我怀疑这与:
“为了最大化兼容性,源图像的子系统应该设置为Windows。编译器应该使用运行库的静态版本来消除对Visual C++运行时DLL的依赖。这可以通过使用/MT或/MTD编译器选项来实现。源映像的地址必须与目标映像的地址匹配,或者源必须包含重定位表,并且需要将映像重定基址到目标的地址。出于兼容性原因,首选重定基址路由。/DYNAMICBASE或/FIXED:不能使用任何链接器选项来生成重定基址表…”
这是我最终使用的代码,但是@Straive 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;
}
#包括
#包括
#包括
#包括
#包括“ntstatus.h”
#pragma注释(lib,“ntdll”)
使用NtUnmapViewOfSection=NTSTATUS(WINAPI*)(句柄,PVOID);
typedef NTSTATUS(NTAPI*pfnNtQueryInformationProcess)(
在handleprocesshandle中,
在PROCESSINFOCLASS ProcessInformationClass中,
输出PVOID进程信息,
在ULONG长度中,
出普隆返回长度可选
);
typedef结构基本块{
德沃德地址;
DWORD块大小;
}基地搬迁区、*基地搬迁区;
typedef结构基础\u重新定位\u条目{
USHORT偏移量:12;
乌舒特型:4;
}基地搬迁项目,*PBASE搬迁项目;
UINT_PTR GetPEBLocation(HANDLE hProcess)
{
ULONG RequiredLen=0;
UINT_PTR PebAddress=NULL;
进程基本信息myProcessBasicInformation[5]={0};
if(NtQueryInformationProcess(HPProcess、ProcessBasicInformation、myProcessBasicInformation、sizeof(PROCESS\u BASIC\u INFORMATION),&RequiredLen)=状态\u成功)
{
PebAddress=(UINT_PTR)myProcessBasicInformation->PebBaseAddress+16;
}
其他的
{
if(NtQueryInformationProcess(HPProcess、ProcessBasicInformation、myProcessBasicInformation、RequiredLen和RequiredLen)=状态\u成功)
{
PebAddress=(UINT_PTR)myProcessBasicInformation->PebBaseAddress+16;
}
}
返回地面;
}
int main()
{
//创建目标进程-这是要挖空的进程
LPSTARTUPINFOA si=新的STARTUPINFOA();
LPPROCESS_INFORMATION pi=新流程_INFORMATION();
流程基本信息*pbi=新流程基本信息();
CreateProcessA(NULL,(LPSTR)“c:\\windows\\system32\\cleanmgr.exe”,NULL,NULL,TRUE,CREATE\u SUSPENDED,NULL,NULL,si,pi);
HANDLE destProcess=pi->hProcess;
LPVOID destProcessImageBase=(LPVOID)GetPEBLocation(destProcess);
std::cout OptionalHeader.AddressOfEntryPoint;
context->Rcx=patchedEntryPoint;
SetThreadContext(pi->hThread,context);
恢复线程(pi->hThread);
std::cin.get();
返回0;
}
第一个代码示例:在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();
}
绝对没有错误处理。这不是一个了解程序失败原因的好方法。好吧,这不是完全正确的。有两个调用GetLastError
。但它们都返回不确定的值。为什么要将PebBaseAddress
转换为DWORD以获得64位exe?@JonathanPotter,我尝试转换为未签名的long long相反,但这并没有真正的帮助…您的代码中还有其他类型转换,它们在64位中没有任何意义。从某处复制代码是可以的,但您应该亲自检查并尝试理解它。第一步,添加错误检查这是正确的,尽管您缺少代码的结尾…检查下面的“我的代码”并编辑您的代码因为它有更多的投票,谢谢你的支持
#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;
}
#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();
}
#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;
}