这是 x86 和 x64 上的通用代码。如果你的目标程序是x86/x64,那么你的程序也需要编译成x86/x64。我测试了几个程序都可以正常工作。
uintptr_t pMessageBoxA = GetProcAddressEx(gc.hProcess, "user32.dll", "MessageBoxA");
if (!pMessageBoxA)
{
printf("target not find MessageBoxA\n");
return 0;
}
printf("pMessageBoxA: %lp\n", pMessageBoxA);
const char* title = "hello";
const char* content = "world";
size_t titleLen = strlen(title) + 1;
size_t contentLen = strlen(content) + 1;
BYTE* newmem = (BYTE*)VirtualAllocEx(gc.hProcess, 0, 1024, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
printf("newmem: %x\n", newmem);
uintptr_t titleAddr = (uintptr_t)newmem;
uintptr_t contentAddr = titleAddr + titleLen;
uintptr_t funAddr = contentAddr + contentLen + 8;
printf("funAddr: %x\n", funAddr);
WriteProcessMemory(gc.hProcess, (LPVOID)titleAddr, (LPCVOID)title, titleLen, 0);
WriteProcessMemory(gc.hProcess, (LPVOID)contentAddr, (LPCVOID)content, contentLen, 0);
#ifdef _WIN64
/*
0000- 55 - push rbp
0001- 48 8B EC - mov rbp,rsp
0004- 48 83 EC 20 - sub rsp,20
0008- 48 B9 0000000000000000 - mov rcx,0000000000000000
0012- 48 BA 0000000000000000 - mov rdx,0000000000000000
001C- 49 B8 0000000000000000 - mov r8,0000000000000000
0026- 49 B9 0000000000000000 - mov r9,0000000000000000
0030- 48 B8 E02C643FFD7F0000 - mov rax,user32.MessageBoxA
003A- FF D0 - call rax
003C- 48 83 C4 20 - add rsp,20
0040- 48 8B E5 - mov rsp,rbp
0043- 5D - pop rbp
0044- C3 - ret
*/
BYTE funcode[] = {
0x55,
0x48, 0x8B, 0xEC,
0x48, 0x83, 0xEC, 0x20,
0x48, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x48, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x49, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x49, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xD0,
0x48, 0x83, 0xC4, 0x20,
0x48, 0x8B, 0xE5,
0x5D,
0xC3,
};
memcpy_s(funcode + 0x14, sizeof(uintptr_t), &contentAddr, sizeof(uintptr_t)); // rdx
memcpy_s(funcode + 0x1E, sizeof(uintptr_t), &titleAddr, sizeof(uintptr_t)); // r8
memcpy_s(funcode + 0x32, sizeof(uintptr_t), &pMessageBoxA, sizeof(uintptr_t)); // rax
WriteProcessMemory(gc.hProcess, (LPVOID)funAddr, funcode, sizeof(funcode), 0);
#else
/*
3 00000000 6A00 push 0
4 00000002 6878563412 push 0x12345678
5 00000007 6878563412 push 0x12345678
6 0000000C 6A00 push 0
7 0000000E E800000000 call MessageBoxA
8 00000013 C3 ret
*/
BYTE funcode[] = {
0x6A, 0x00,
0x68, 0x00,0x00,0x00,0x00,
0x68, 0x00,0x00,0x00,0x00,
0x6A, 0x00,
0xE8, 0x00,0x00,0x00,0x00,
0xC3
};
DWORD MessageBoxA = pMessageBoxA - (funAddr + 0xE) - 5;
memcpy_s(funcode + 0x3, sizeof(DWORD), &titleAddr, sizeof(DWORD));
memcpy_s(funcode + 0x8, sizeof(DWORD), &contentAddr, sizeof(DWORD));
memcpy_s(funcode + 0xF, sizeof(DWORD), &MessageBoxA, sizeof(DWORD));
WriteProcessMemory(gc.hProcess, (LPVOID)funAddr, funcode, sizeof(funcode), 0);
#endif // _WIN64
HANDLE hThread = CreateRemoteThread(gc.hProcess, 0, 0, (LPTHREAD_START_ROUTINE)funAddr, 0, 0, 0);
WaitForSingleObject(hThread, INFINITE);
VirtualFreeEx(gc.hProcess, newmem, 0, MEM_RELEASE);
CloseHandle(hThread);
GetProcAddressEx:
uintptr_t GetProcAddressEx(HANDLE hProcess, string modName, string exportFunName)
{
MODULEINFO mi = GetModuleBase(modName, GetProcessId(hProcess));
uintptr_t moduleBaseAddr = (uintptr_t)mi.lpBaseOfDll;
// is PE FILE ?
WORD e_magic = 0;
ReadProcessMemory(hProcess, (LPCVOID)moduleBaseAddr, &e_magic, sizeof(WORD), 0);
if (e_magic != 0x5A4D)
{
printf("not PE file.\n");
return 0;
}
// get ntHeader offset
DWORD e_lfanew = 0;
ReadProcessMemory(hProcess, (LPCVOID)(moduleBaseAddr + 0x3C), &e_lfanew, sizeof(DWORD), 0);
uintptr_t ntHeaderAddr = moduleBaseAddr + e_lfanew;
uintptr_t fileHeaderAddr = ntHeaderAddr + sizeof(DWORD);
// x86 is 0xE0, x64 is 0xF0
WORD optHeaderSize = 0;
ReadProcessMemory(hProcess, (LPCVOID)(fileHeaderAddr + 0x10), &optHeaderSize, sizeof(WORD), 0);
// tables
uintptr_t DataDirectoryAddr = fileHeaderAddr + sizeof(IMAGE_FILE_HEADER) + optHeaderSize - sizeof(IMAGE_DATA_DIRECTORY) * 16;
// tables[0] is export table
IMAGE_DATA_DIRECTORY exportEntry;
ReadProcessMemory(hProcess, (LPCVOID)DataDirectoryAddr, &exportEntry, sizeof(IMAGE_DATA_DIRECTORY), 0);
if (!exportEntry.Size)
{
printf("not export table. \n");
return 0;
}
auto RVA2VA = [&](uintptr_t rva) -> uintptr_t
{
return moduleBaseAddr + rva;
};
uintptr_t exportDirDataAddr = RVA2VA(exportEntry.VirtualAddress);
// the number of use name export function
DWORD NumberOfNames = 0;
ReadProcessMemory(hProcess, (LPCVOID)(exportDirDataAddr + 0x18), &NumberOfNames, sizeof(DWORD), 0);
DWORD AddressOfFunctions = 0;
ReadProcessMemory(hProcess, (LPCVOID)(exportDirDataAddr + 0x1C), &AddressOfFunctions, sizeof(DWORD), 0);
DWORD* AddressOfFunctionsVA = (DWORD*)RVA2VA(AddressOfFunctions);
// function name table
DWORD AddressOfNames = 0;
ReadProcessMemory(hProcess, (LPCVOID)(exportDirDataAddr + 0x20), &AddressOfNames, sizeof(DWORD), 0);
DWORD* AddressOfNamesVA = (DWORD*)RVA2VA(AddressOfNames);
DWORD AddressOfNameOrdinals = 0;
ReadProcessMemory(hProcess, (LPCVOID)(exportDirDataAddr + 0x24), &AddressOfNameOrdinals, sizeof(DWORD), 0);
WORD* AddressOfNameOrdinalsVA = (WORD*)RVA2VA(AddressOfNameOrdinals);
auto readASCII = [&](uintptr_t addr, char* name) -> void
{
size_t i = 0;
char c;
while (true)
{
ReadProcessMemory(hProcess, (LPCVOID)(addr + i), &c, sizeof(BYTE), 0);
name[i] = c;
if (!c) break;
i++;
}
};
DWORD itRVA = 0;
char funName[1024];
size_t funNameIndex = 0;
for (; funNameIndex < NumberOfNames; funNameIndex++)
{
ReadProcessMemory(hProcess, AddressOfNamesVA + funNameIndex, &itRVA, sizeof(DWORD), 0);
readASCII(moduleBaseAddr + itRVA, funName);
if (!strcmp(funName, exportFunName.c_str()))
break;
}
if (strlen(funName) == 0)
{
return 0;
}
// get function address index
WORD AddressOfFunctionsIndex = 0;
ReadProcessMemory(hProcess, AddressOfNameOrdinalsVA + funNameIndex, &AddressOfFunctionsIndex, sizeof(WORD), 0);
// get function address
DWORD funAddrRVA = 0;
ReadProcessMemory(hProcess, AddressOfFunctionsVA + AddressOfFunctionsIndex, &funAddrRVA, sizeof(DWORD), 0);
return RVA2VA(funAddrRVA);
}
GetModuleBase:
MODULEINFO GetModuleBase(string moduleName, DWORD pid)
{
MODULEINFO mi{ 0 };
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, pid);
if (hSnap != INVALID_HANDLE_VALUE)
{
MODULEENTRY32 me;
me.dwSize = sizeof(me);
if (Module32First(hSnap, &me))
{
do {
if (!_wcsicmp(me.szModule, toWstring(moduleName).c_str()))
{
mi.lpBaseOfDll = me.modBaseAddr;
mi.SizeOfImage = me.modBaseSize;
break;
}
} while (Module32Next(hSnap, &me));
}
}
CloseHandle(hSnap);
return mi;
}
与硬编码相比,这更复杂。
如果要获取CreateRemoteThread传递的参数
BYTE* lpParam = (BYTE*)VirtualAllocEx(gc.hProcess, 0, 8, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
DWORD p1 = 1;
DWORD p2 = 2;
WriteProcessMemory(gc.hProcess, lpParam, &p1, sizeof(DWORD), 0);
WriteProcessMemory(gc.hProcess, lpParam + 4, &p2, sizeof(DWORD), 0);
printf("lpParam: %lp\n", lpParam);
HANDLE hThread = CreateRemoteThread(gc.hProcess, 0, 0, (LPTHREAD_START_ROUTINE)funAddr, lpParam, 0, 0);
- 如果目标程序是x86,那么你可以在
[esp+4]中得到lpParam
- 如果目标程序是x64,那么你可以在
rcx中得到lpParam