c 获取函数的真实地址
获取函数的真实地址
在c注入汇编到其他程序时,由于会使用到一些变量,无法直接将汇编事先给出来。
例如,现在需要注入一条命令
mov [game.exe+1213],100
但是,game.exe这个模块的基地址需要程序使用 EnumProcessModulesEx 这个函数找到。存到一个变量addr中。
那么用c注入时可以先,在c的程序中写asm汇编,由于这个地方我们能用变量,所以就相当于自动生成我们需要的汇编代码了。
mov [addr+1213],100
再去读取这个这个函数中生成的汇编代码即可获取到我们需要的汇编。
但是不能通过这个函数的函数指针直接找到这个函数的真实地址。
函数指针找到是一个jmp命令,他会跳转到真实的函数地址。
命令大致类似与:
jmp 0x7175
对应的你找到的jmp的16进制应该是:
e975710000
这个jmp后边跟的就是 jmp这个命令的地址到真实的函数地址的偏移量。
我们只需要使用 jmp的地址 jmp_addr,加上偏移 jmp_addr+0x7175 就可以获得真实的函数地址。
jmp指令会占用5个字节(对32位程序)
所以jmp_addr = addr+5
总结起来就是:
使用函数指针addr,加上jmp的大小,获得jmp的地址,jmp_addr = addr+5.
然后读取jmp后边的偏移offset。
再得到函数的真实地址 true_addr = jmp_addr+offset
下面是一个测试的例子:
为了不必要的编译错误,请使用visual studio编译运行。
test.cpp
#include"stdafx.h"
#include <windows.h>
#include <tlhelp32.h>
#include <tchar.h>
#include <stdio.h>
#include <iostream>
#include <string>
using namespace std;
//将string转换成wstring
wstring string2wstring(string str)
{
wstring result;
//获取缓冲区大小,并申请空间,缓冲区大小按字符计算
int len = MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), NULL, 0);
TCHAR* buffer = new TCHAR[len + 1];
//多字节编码转换成宽字节编码
MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), buffer, len);
buffer[len] = '\0'; //添加字符串结尾
//删除缓冲区并返回值
result.append(buffer);
delete[] buffer;
return result;
}
//将wstring转换成string
string wstring2string(wstring wstr)
{
string result;
//获取缓冲区大小,并申请空间,缓冲区大小事按字节计算的
int len = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), wstr.size(), NULL, 0, NULL, NULL);
char* buffer = new char[len + 1];
//宽字节编码转换成多字节编码
WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), wstr.size(), buffer, len, NULL, NULL);
buffer[len] = '\0';
//删除缓冲区并返回值
result.append(buffer);
delete[] buffer;
return result;
}
int FindPID(string ProcessName)
{
int pid = -1;
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(pe32);
HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnap == INVALID_HANDLE_VALUE) {
cout << "CreateToolhelp32Snapshot Error!" << endl;;
return false;
}
BOOL bResult = Process32First(hProcessSnap, &pe32);
int num(0);
while (bResult)
{
if (wstring2string(wstring(pe32.szExeFile)) == ProcessName)
{
pid = pe32.th32ProcessID;
break;
}
bResult = Process32Next(hProcessSnap, &pe32);
}
CloseHandle(hProcessSnap);
return pid;
}
HANDLE get_handle(int pid)
{
HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
return handle;
}
int* read_memory(DWORD pid, uintptr_t addr, int bytes)
{
HANDLE handle = get_handle(pid);
int* t = (int*)malloc(bytes);
bool state = ReadProcessMemory(handle, (LPVOID)addr, t, bytes, NULL);
if (!state)
{
free(t);
t = NULL;
}
CloseHandle(handle);
return t;
}
int f1()
{
return 1;
}
int f2()
{
return 2;
}
void run(int(*f)())
{
int a = f();
printf("%x\n", (unsigned int)f);
printf("%d\n", a);
}
void* read_true_process_address(DWORD pid, void* p)
{
uintptr_t true_address = (uintptr_t)p;
printf("%x\n", true_address);
int* jmp_content = read_memory(pid, true_address, 5);
uint8_t *tp = (uint8_t*)jmp_content;
tp += 1;
uint32_t offset = *(uint32_t*)tp;
printf("%x\n", offset);
true_address = true_address + 5 + offset;
printf("%x\n", true_address);
free(jmp_content);
return (void*)true_address;
}
int main()
{
DWORD pid = FindPID("test.exe");
void *addr = read_true_process_address(pid, f1);
return 0;
}
运行结果:
751686
7175
758800
注:
显示内存和显示反汇编都可以在 调试->窗口 中找到