c++ 动态解析PE导出表
测试环境是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
- http://www.openrce.org/reference_library/files/reference/PE Format.pdf
- https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
- 上面的代码没进过严格测试,绝对有问题
c++ 动态解析PE导出表的更多相关文章
- 解析PE文件
最近在自学解析PE文件,根据小辣椒(CFF Explorer)以及各论坛上大佬的帖子,做了个黑屏打印PE文件的,历时7天完成,在此想跟有相关需要的同学们分享下思路,有不足之处也希望大家不吝赐教,指点出 ...
- 使用Newtonsoft.Json.dll(JSON.NET)动态解析JSON、.net 的json的序列化与反序列化(一)
在开发中,我非常喜欢动态语言和匿名对象带来的方便,JSON.NET具有动态序列化和反序列化任意JSON内容的能力,不必将它映射到具体的强类型对象,它可以处理不确定的类型(集合.字典.动态对象和匿名对象 ...
- 理解AngularJS生命周期:利用ng-repeat动态解析自定义directive
ng-repeat是AngularJS中一个非常重要和有意思的directive,常见的用法之一是将某种自定义directive和ng-repeat一起使用,循环地来渲染开发者所需要的组件.比如现在有 ...
- 开源一个动态解析protobuf的工具
好久没写博客了,主要是这一年技术没啥长进都打杂了,还有就是生活琐事越来越多,人也越来越懒了…… 之前项目中用到了Protobuf,然后测试发现这玩意不好测,总不能每次定个协议或者改下都要编译Java代 ...
- Protobuf动态解析那些事儿
需求背景 在接收到 protobuf 数据之后,如何自动创建具体的 Protobuf Message 对象,再做反序列化.“自动”的意思主要有两个方面:(1)当程序中新增一个 protobuf Mes ...
- jsoncpp动态解析节点类型
在互联网无处不在的今天,JSON作为轻量级数据存储格式,被广泛应用到互联网数据传输中.众所周知,JSON由键/值对.对象.数组组成,其中键/值对的值包括以下几种类型: enum ValueType { ...
- Protobuf动态解析在Java中的应用 包含例子程序
最近在做ProtoBuf相关的项目,其中用到了动态解析,网上看了下相关资料和博文都比较少,自己来写一个记录一下学习过程. Protocol Buffers是结构化数据格式标准,提供序列化和反序列方 ...
- 在C#中,Newtonsoft.Json + dynamic动态解析jsonString,jsonString转实体
记录一下 引用 using Newtonsoft.Json; using Newtonsoft.Json.Linq; var jsonString = "{\"ApiResourc ...
- C#匿名类型和动态解析减少定义传输类模板
C#作为强类型语言,在序列化和反序列化(json)场景中对字符串解析常常需要定义强类型模板,造成编码上的繁琐.其实可以使用匿名类型和动态解析减少json序列化时候的数据模板定义: string a = ...
随机推荐
- PowerBI数据建模时的交叉连接问题
方案一.在PowerPivot中,将其中一张表复制多份,分别与另一张表做链接. 方案二.在PowerQuery中,做多次合并查询,把所有数据集中在一张表中,方便后面的数据分析. 思考:不仅仅是在Pow ...
- 七:SpringBoot-集成Redis数据库,实现缓存管理
SpringBoot-集成Redis数据库,实现缓存管理 1.SpringBoot集成Redis 1.1 核心依赖 1.2 配置文件 1.3 简单测试案例 1.4 自定义序列化配置 1.5 序列化测试 ...
- MySql(一)表类型(存储引擎)
MySql(一)表类型(存储引擎) 一.MYSQL存储引擎概述 二.存储引擎的特性对比 2.1 MyISAM 2.2 InnoDB 2.2.1 自动增长列 2.2.2 外键约束 2.2.3 存储方式 ...
- Java IO--字节流与字符流OutputStream/InputStream/Writer/Reader
流的概念 程序中的输入输出都是以流的形式保存的,流中保存的实际上全都是字节文件. 字节流与字符流 内容操作就四个类:OutputStream.InputStream.Writer.Reader 字节流 ...
- 烧录失败导致boot无法加载的解决措施,再也不怕烧成砖了
目录: 1.usb烧录时出现的问题截图 2.重新擦除boot发现失败的情况 3.解决措施 烧录失败导致boot无法加载的解决措施在烧录系统的时候经常会遇到烧录失败的情况,如果能通过再次执行烧录能烧上肯 ...
- Codeforces Round #652 (Div. 2) D. TediousLee(dp)
题目链接:https://codeforces.com/contest/1369/problem/D 题意 最初有一个结点,衍生规则如下: 如果结点 $u$ 没有子结点,添加 $1$ 个子结点 如果结 ...
- Codeforces Round #628 (Div. 2) A. EhAb AnD gCd(LCM & GCD)
题意: GCD(a,b) + LCM(a,b) = n,已知 n ,求 a,b. 思路: 设 gcd(a, b) = k, a = xk, b = yk , k + ab / k = n xy = n ...
- 【uva 1312】Cricket Field(算法效率--技巧枚举)
题意:一个 L*R 的网格里有 N 棵树,要求找一个最大空正方形并输出其左下角坐标和长.(1≤L,R≤10000, 0≤N≤100) 解法:枚举空正方形也就是枚举空矩阵,先要固定一个边,才好继续操作. ...
- 【noi 2.6_9267】核电站(DP)
题意:n个数中不能同时选连续m个或以上,问方案数. 解法:f[i][j]表示从前i个中选,到第i个已经连续选了j个.j!=0时, =f[i-1][j-1] ; j=0时, =f[i-1][0~m-1 ...
- How many integers can you find HDU - 1796 容斥原理
题意: 给你一个数n,找出来区间[1,n]内有多少书和n不互质 题解: 容斥原理 这一道题就让我真正了解容斥原理的实体部分 "容斥原理+枚举状态,碰到奇数加上(n-1)/lcm(a,b,c. ...