测试环境是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. 分布式缓存 — redis

    redis是一种支持Key-Value等多种数据结构的存储系统.可用于缓存,事件发布或订阅,高速队列等场景.该数据库使用ANSI C语言编写,支持网络,提供字符串,哈希,列表,队列,集合结构直接存取, ...

  2. MTO1804无刷电机引发的悲惨经历之二:电调固件刷新与优化

    前言 原创文章,转载引用请务必注明链接,水平有限,如有疏漏,欢迎指正. 书接上回,我们总算是基本确认了黑衣神秘电调的身份,本文就尝试对电调固件进行一番设置,来个免费优化. 1.刷新固件 关于电调的固件 ...

  3. Excel 一张表最多能装下多少行多少列数据?

    一个工作簿可以装下255张,那么每张工作表可以装下多少行多少列数据呢? 1.任意打开或新建一个Excel文档. 2.在文档中,找到其左上角的"文件"按钮,点击选择"选项& ...

  4. Java 操作 HBase 教程

    Java 操作 HBase 教程 一.简介 二.hbase-client 引入 三.连接操作 四.表操作 五.运行测试 相关博文原文地址: 博客园:美码师:HBase(2) Java 操作 HBase ...

  5. Spring框架——事务管理方式搭建一个小的项目

    学习Spring框架,通过事务管理的方式搭建一个小的项目,该项目可以查询对数据库中的图书库存数量进行修改. 首先,使用MVC分层的设计模式思想搭建项目目录结构. 此部分代码源码之中都有相关注释,所以尽 ...

  6. maven基础学习-为什么要用maven,帮助解决了什么问题,怎么解决的,希望以后学习每个知识点都可以这样问下自己

    maven基础学习 第1章 Maven介绍 1.1 什么是Maven 1.1.1 什么是Maven Maven 的正确发音是[ˈmevən],而不是"马瘟"以及其他什么瘟.Mave ...

  7. 5.2 spring5源码--spring AOP源码分析二--切面的配置方式

    目标: 1. 什么是AOP, 什么是AspectJ 2. 什么是Spring AOP 3. Spring AOP注解版实现原理 4. Spring AOP切面原理解析 一. 认识AOP及其使用 详见博 ...

  8. Centos根目录100%解决思路

    Centos 7 根目录(爆满)100%解决思路,下面以宝塔面板环境为例 1.首先远程到服务器,在~下输入df -h ,看下根目录下文件夹使用情况 [root@localhost~]# df -h F ...

  9. [The Preliminary Contest for ICPC Asia Shanghai 2019] B-Light bulbs(差分+思维)

    前言 最近有很多算不上事的事,搞得有点心烦,补题难免就很水,没怎么搞,自我检讨一番~~ 说实话网络赛题目的质量还是挺高的,题目都设计的挺好的,很值得学习.这场比赛那会只有我们大二的在做,其他人去参加$ ...

  10. 2019牛客暑期多校训练营(第四场)A-meeting(树的直径)

    >传送门< 题意:n给城市有n-1条路相连,每两个城市之间的道路花费为1,有k个人在k个城市,问这k个人聚集在同一个城市的最小花费 思路:(官方给的题解写的挺好理解的) 考虑距离最远的两个 ...