讲师中心 微信公众号
AI工具推荐 视频效率加速

c++怎么通过读取PE文件导入表检测程序依赖的DLL列表【进阶】

小敏大大_3564

小敏大大_3564

发布时间:2026-04-12 23:01:29

|

900人浏览过

|

来源于php中文网

原创

PE文件导入表通过OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]获取RVA和大小,需校验非零后经节表映射为FOA;Name和INT中的字符串须按\0截断,OriginalFirstThunk比FirstThunk更可靠,所有RVA须边界检查。

c++怎么通过读取pe文件导入表检测程序依赖的dll列表【进阶】

怎么定位PE文件的导入表(IMAGE_IMPORT_DESCRIPTOR数组)

PE文件的导入表不是固定位置,得先解析DOS头、NT头、可选头,再从OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]拿到导入表RVA和大小。这个目录项可能为空(比如纯静态链接的exe),所以读之前必须校验VirtualAddress是否非零、Size是否大于0。

拿到RVA后要转成文件偏移:用IMAGE_NT_HEADERS里的OptionalHeader.ImageBase不能直接减——它只是建议加载基址;正确做法是靠节表(IMAGE_SECTION_HEADER)做RVA→FOA映射。常见错误是硬算RVA - Section.VirtualAddress + Section.PointerToRawData却没检查RVA落在哪个节里,导致读到乱码甚至越界。

  • 用ImageNtHeader()和ImageRvaToVa()(Windows SDK)可省去手动节表遍历,但需确保传入的是映射后的内存地址,不是文件映射视图起始地址
  • 若自己解析,注意节名可能被截断(8字节+null)、VirtualSize和SizeOfRawData可能不等,取小值做边界判断更安全
  • 导入表末尾以全0的IMAGE_IMPORT_DESCRIPTOR结构结束,不能只按DataDirectory.Size循环,否则可能越界读到其他数据区

怎么从IAT/INT中提取DLL名称字符串

IMAGE_IMPORT_DESCRIPTOR里的Name字段是RVA,指向DLL名字的ASCII/UTF-8字符串(如"kernel32.dll")。这个RVA同样要转FOA,且字符串以\0结尾——但PE规范没保证后面没垃圾字节,所以必须逐字节读直到\0,不能直接按长度memcpy。

真正容易出错的是路径处理:Name指向的只是文件名,不含路径,但有些打包工具或loader会写入相对路径(如"./lib/vcruntime140.dll"),此时字符串里含斜杠。Windows加载器本身只认文件名部分,但检测依赖时应原样保留整个字符串,否则会漏报。

立即学习“C++免费学习笔记(深入)”;

C++ Code Review Master
C++ Code Review Master

组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。

下载
  • 不要假设字符串一定是小写——实际有大写(如"USER32.DLL"),比较DLL白名单时建议用_stricmp或std::equal配std::toupper
  • 某些加壳程序会把Name RVA 指向重定位区或加密区,读出来是乱码,此时需结合FirstThunk和OriginalFirstThunk的非空性交叉验证
  • 64位PE的Name RVA 是8字节对齐,32位是4字节,用sizeof(ULONG_PTR)动态判断更稳妥

为什么OriginalFirstThunk比FirstThunk更可靠

导入表里有两个并行的函数指针数组:运行时用的FirstThunk(IAT),和编译时存的OriginalFirstThunk(INT)。前者在ASLR启用或DLL重定位后会被系统覆写为真实函数地址,后者始终不变,存的是IMAGE_THUNK_DATA结构,低32位(或64位)是函数名称的RVA或序号。

直接读FirstThunk内容来反推函数名是危险的:如果进程已加载,IAT里全是有效地址,无法还原原始名称;如果文件未加载,IAT可能全0(取决于链接器设置)。而OriginalFirstThunk只要存在,就一定能拿到原始导入信息。

  • 当OriginalFirstThunk == 0时,退化为用FirstThunk,但此时只能认为该DLL是“延迟导入”或“绑定导入”,需单独标记
  • IMAGE_THUNK_DATA的最高位(bit 31或63)为1表示这是序号导入(如#123),此时剩余位是序号值,不是RVA,别当成指针去解引用
  • 有些编译器(如MSVC /DELAYLOAD)会在导入表末尾额外加一个IMAGE_DELAYLOAD_DESCRIPTOR,它有自己的DllNameRVA,必须单独扫描,否则漏掉延迟加载DLL

如何处理导入名称表(INT)中的函数名结构

每个函数名在INT中由IMAGE_IMPORT_BY_NAME结构表示:前2字节是Hint(提示序号,可忽略),后续是变长ASCII字符串。这个结构没有长度字段,必须靠Hint之后第一个\0确定结尾。但实际文件中,\0之后可能紧跟下一个IMAGE_IMPORT_BY_NAME,也可能有填充字节——所以不能简单按sizeof(IMAGE_IMPORT_BY_NAME)步进。

更麻烦的是Unicode支持:极少数PE(主要是驱动或旧版工具链生成)会用IMAGE_IMPORT_BY_NAME的宽字符变体,但PE规范未定义,Windows loader也不支持,检测时遇到非ASCII字节且后续无\0,大概率是损坏或混淆,应跳过该条目而非崩溃。

  • 读IMAGE_IMPORT_BY_NAME前先检查RVA是否在节范围内,避免访问未映射内存
  • Hint字段不可信——它只是链接器的优化提示,实际调用仍靠函数名字符串匹配,有些UPX加壳会故意填错Hint来干扰分析
  • 函数名字符串可能含非法字符(如控制符、路径分隔符),输出时建议过滤不可见ASCII( 126),防止日志污染

实际跑通的关键在于:别信任任何单一字段,所有RVA都要做节边界检查,所有字符串都要找\0终止,所有指针都要判空。导入表结构看着线性,但PE文件里它散落在不同节、可能被对齐填充、还受加壳干扰——最稳的方式是把每个字段都当作需要独立验证的输入,而不是流程化的步骤。

相关文章

c++速学教程(入门到精通)
c++速学教程(入门到精通)

c++怎么学习?c++怎么入门?c++在哪学?c++怎么学才快?不用担心,这里为大家提供了c++速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

c++

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

讯飞绘文

讯飞绘文是一款由科大讯飞推出的一站式 AIGC 内容运营平台。

墨刀AI
墨刀AI Hot

一款AI图像与设计工具,主要用于产品经理的专属智能体,适合需要提升相关任务效率的用户。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

超级简历WonderCV

一款AI办公效率工具,主要用于免费求职简历模版下载制作,应届生职场人必备简历制作神器,适合需要提升相关任务效率的用户。

立刻MV
立刻MV Hot

立刻MV是一款AI文本写作工具,AI 音乐视频(MV)创作工具。

PixPix
PixPix Hot

PixPix是一款面向电商视觉生产的AI商品图生成工具。

咔片AIPPT

一款在线AI演示文稿制作工具,可根据主题和内容需求辅助生成PPT结构与页面,提高演示材料制作效率。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

相关专题

更多
c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

529

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

1658

2024.03.01

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

1578

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

2344

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

5844

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

5009

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

6734

2024.03.22

php中定义字符串的方式
php中定义字符串的方式

php中定义字符串的方式:单引号;双引号;heredoc语法等等。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

9174

2024.04.29

LLVM自定义Pass怎么写
LLVM自定义Pass怎么写

本专题聚焦LLVM自定义Pass开发,整理Pass类结构、run()方法、PreservedAnalyses、CMake构建、插件注册、-load-pass-plugin加载和测试用例编写流程。

0

2026.09.30

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Conan 2 Essentials 免费课程
Conan 2 Essentials 免费课程

共0课时 | 0人学习

CMake 与 Conan 集成实践
CMake 与 Conan 集成实践

共0课时 | 0人学习

Conan 2 高级依赖模型介绍
Conan 2 高级依赖模型介绍

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn