测试环境是x86

main

#include <iostream>
#include <Windows.h>
#include <TlHelp32.h>
#include <string.h> using namespace std; const string processName = "game2.exe";
const string dllName = "kernel32.dll";
const string exportFunName = "LoadLibraryA"; // 获取PID
DWORD getPID(string name)
{
DWORD pid = 0;
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnap != INVALID_HANDLE_VALUE)
{
PROCESSENTRY32 pe;
pe.dwSize = sizeof(pe);
if (Process32First(hSnap, &pe))
{
do {
if (!_wcsicmp(pe.szExeFile, wstring(name.begin(), name.end()).c_str())) {
pid = pe.th32ProcessID;
break;
}
} while (Process32Next(hSnap, &pe));
}
}
CloseHandle(hSnap);
return pid;
} // 获取模块基址
uintptr_t getModuleBaseAddress(DWORD pid, const wchar_t* modName)
{
uintptr_t modBaseAddr = 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, modName)) {
modBaseAddr = (uintptr_t)me.modBaseAddr;
break;
}
} while (Module32Next(hSnap, &me));
}
}
CloseHandle(hSnap);
return modBaseAddr;
} // 读取字节集中的ASCII
void ReadASCII(BYTE* addr, size_t offset, char r[])
{
size_t i = 0;
char c;
while (true)
{
c = *(addr + offset + i);
r[i] = c; // 需要把最后一个0写进去
if (!c) break;
i++;
}
} void* MyGetProcAddress(string gameProcessName, string modName, string exportFunName)
{
DWORD pid = getPID(processName);
if (!pid) return nullptr; HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if (!hProcess) return nullptr; uintptr_t kernel32BaseAddr = getModuleBaseAddress(pid,
wstring(modName.begin(), modName.end()).c_str()); printf("kernel32BaseAddr: %x\n", kernel32BaseAddr); auto RVA2VA = [&](DWORD rva) -> DWORD
{
return kernel32BaseAddr + rva;
}; // 储存headers+节表 对齐后
BYTE peHeader[0x1000];
ReadProcessMemory(hProcess, (LPVOID)kernel32BaseAddr, peHeader, sizeof(peHeader), 0); IMAGE_DOS_HEADER* dosHeader = (IMAGE_DOS_HEADER*)peHeader; // nt头可以分为PE头,标准头,可选头
IMAGE_NT_HEADERS* ntHeader = (IMAGE_NT_HEADERS*)(kernel32BaseAddr + dosHeader->e_lfanew); IMAGE_DATA_DIRECTORY* exportEntry = (IMAGE_DATA_DIRECTORY*)&ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
if (!exportEntry->Size)
{
// 没有导出表
return nullptr;
} BYTE* exportDirData = new BYTE[exportEntry->Size];
ReadProcessMemory(hProcess, (LPVOID)RVA2VA(exportEntry->VirtualAddress),
exportDirData, exportEntry->Size, 0); IMAGE_EXPORT_DIRECTORY* exportDir = (IMAGE_EXPORT_DIRECTORY*)exportDirData; // 函数数量
printf("NumberOfFunctions: %d\n", exportDir->NumberOfFunctions); // 以函数名导出的数量
printf("NumberOfNames: %d\n", exportDir->NumberOfNames); // 获取fun name表的VA地址
// 每个大小是DWORD,一共有NumberOfNames个,并且表里面存的都是RVA值
DWORD* AddressOfNamesVA = (DWORD*)RVA2VA(exportDir->AddressOfNames); DWORD itRVA = 0;
uintptr_t itVA = 0;
char funName[1024];
size_t funNameIndex = 0;
for (; funNameIndex < exportDir->NumberOfNames; funNameIndex++)
{
itRVA = *(AddressOfNamesVA + funNameIndex);
itVA = kernel32BaseAddr + itRVA;
ReadASCII((BYTE*)itVA, 0, funName);
// printf("%s\n", funName);
if (!strcmp(funName, exportFunName.c_str()))
{
break;
}
}
printf("funName: %s\n", funName);
printf("funNameIndex: %d\n", funNameIndex); // 拿到索引后去AddressOfNameOrdinals表,找到对应的索引中的值,取出来的值是
// AddressOfFunctions的索引,里面存的就是地址 // 获取AddressOfNameOrdinals表的VA地址,每个大小是WORD
WORD* AddressOfNameOrdinalsVA = (WORD*)RVA2VA(exportDir->AddressOfNameOrdinals);
WORD AddressOfFunctionsIndex = *(AddressOfNameOrdinalsVA + funNameIndex); // 获取AddressOfFunctions表的VA地址,每个大小是DWORD
DWORD* AddressOfFunctionsVA = (DWORD*)RVA2VA(exportDir->AddressOfFunctions); // 每个函数地址存的是RVA地址,需要转为VA使用
DWORD funAddrVA = *(AddressOfFunctionsVA + AddressOfFunctionsIndex);
printf("funName Addr RVA: %x\n", RVA2VA(funAddrVA)); delete[] exportDirData;
CloseHandle(hProcess); return (VOID*)RVA2VA(funAddrVA);
} int main()
{
void* loadlibrary_a = MyGetProcAddress(processName, dllName, exportFunName);
printf("loadlibrary_a: %p\n", loadlibrary_a);
return 0;
}
kernel32BaseAddr: 77a80000
NumberOfFunctions: 1603
NumberOfNames: 1603
funName: LoadLibraryA
funNameIndex: 961
funName Addr RVA: 77aa2990
loadlibrary_a: 77AA2990

c++ 动态解析PE导出表的更多相关文章

  1. 解析PE文件

    最近在自学解析PE文件,根据小辣椒(CFF Explorer)以及各论坛上大佬的帖子,做了个黑屏打印PE文件的,历时7天完成,在此想跟有相关需要的同学们分享下思路,有不足之处也希望大家不吝赐教,指点出 ...

  2. 使用Newtonsoft.Json.dll(JSON.NET)动态解析JSON、.net 的json的序列化与反序列化(一)

    在开发中,我非常喜欢动态语言和匿名对象带来的方便,JSON.NET具有动态序列化和反序列化任意JSON内容的能力,不必将它映射到具体的强类型对象,它可以处理不确定的类型(集合.字典.动态对象和匿名对象 ...

  3. 理解AngularJS生命周期:利用ng-repeat动态解析自定义directive

    ng-repeat是AngularJS中一个非常重要和有意思的directive,常见的用法之一是将某种自定义directive和ng-repeat一起使用,循环地来渲染开发者所需要的组件.比如现在有 ...

  4. 开源一个动态解析protobuf的工具

    好久没写博客了,主要是这一年技术没啥长进都打杂了,还有就是生活琐事越来越多,人也越来越懒了…… 之前项目中用到了Protobuf,然后测试发现这玩意不好测,总不能每次定个协议或者改下都要编译Java代 ...

  5. Protobuf动态解析那些事儿

    需求背景 在接收到 protobuf 数据之后,如何自动创建具体的 Protobuf Message 对象,再做反序列化.“自动”的意思主要有两个方面:(1)当程序中新增一个 protobuf Mes ...

  6. jsoncpp动态解析节点类型

    在互联网无处不在的今天,JSON作为轻量级数据存储格式,被广泛应用到互联网数据传输中.众所周知,JSON由键/值对.对象.数组组成,其中键/值对的值包括以下几种类型: enum ValueType { ...

  7. Protobuf动态解析在Java中的应用 包含例子程序

    最近在做ProtoBuf相关的项目,其中用到了动态解析,网上看了下相关资料和博文都比较少,自己来写一个记录一下学习过程.   Protocol Buffers是结构化数据格式标准,提供序列化和反序列方 ...

  8. 在C#中,Newtonsoft.Json + dynamic动态解析jsonString,jsonString转实体

    记录一下 引用 using Newtonsoft.Json; using Newtonsoft.Json.Linq; var jsonString = "{\"ApiResourc ...

  9. C#匿名类型和动态解析减少定义传输类模板

    C#作为强类型语言,在序列化和反序列化(json)场景中对字符串解析常常需要定义强类型模板,造成编码上的繁琐.其实可以使用匿名类型和动态解析减少json序列化时候的数据模板定义: string a = ...

随机推荐

  1. LOJ10077

    题目描述给出一个 N 个顶点 M 条边的无向无权图,顶点编号为 1∼N.问从顶点 1 开始,到其他每个点的最短路有几条. 输入格式第一行包含 2 个正整数 N,M,为图的顶点数与边数. 接下来 M行, ...

  2. 在 WebAssembly 中实现回调的方式

    本文将介绍在 C++ 中实现 js 回调的几种方式. 在使用 wasm 的过程中, 避免不了要从 C++ 回调 js 的函数来实现异步交互. 官网文档 https://emscripten.org/d ...

  3. eclipse 断点调试方法

    1 Debug视图 1.1 线程堆栈视图 线程堆栈视图表示当前线程的堆栈,从中可以看出在运行哪些代码,并且整个调用过程,以及代码行号.分别介绍一下这几个按钮的含义.从左至右分别为: 1.表示当前实现继 ...

  4. Grafana Prometheus系统监控Redis服务

    Grafana Prometheus系统监控Redis服务 一.Grafana Prometheus系统监控Redis服务 1.1流程 1.2安装redis_exporter 1.3配置prometh ...

  5. SQL操作数据——SQL组成,查询基础语法,where,Oracle常用函数等

    SQL组成 DML数据操作语言 DCL数据控制语言 DQL数据查询语言 DDL数据定义语言 查询基础语法 记录筛选 where 子句 记录筛选 where 子句 实例练习 实例练习 Select语句中 ...

  6. 彻底搞懂Cookie、Session、Token到底是什么

    洛:大爷,楼上322住的是马冬梅家吧? 大爷:马都什么? 夏洛:马冬梅. 大爷:什么都没啊? 夏洛:马冬梅啊. 大爷:马什么没? 夏洛:行,大爷你先凉快着吧. 在了解这三个概念之前我们先要了解HTTP ...

  7. 在eclipse完成对Java_web项目里面资源文件的读取

    Java_web项目的资源文件一般有两种: 一种是存放数据之间有联系的文件,使用xml文件 另一种是存放数据之间没有联系的文件,使用properties文件 这里我们对properties文件读写做示 ...

  8. 2019HDU多校 Round10

    Solved:3 Rank:214 08 Coin 题意:n组硬币 每组有两个 分别有自己的价值 每组的第一个被拿了之后才能拿第二个 问拿1,2....2n个硬币的最大价值 题解:之前贪心带反悔的做法 ...

  9. hdu1394Minimum Inversion Number

    Problem Description The inversion number of a given number sequence a1, a2, ..., an is the number of ...

  10. 【noi 2.6_2988】计算字符串距离(DP)

    题意: 给两个字符串,可以增.删.改,问使这两个串变为相同的最小操作数. 解法:(下面2种的代码主要区别在初始化和,而状态转移方程大家可挑自己更容易理解的方法打) 1.f[i][j]表示a串前i个和b ...