5.8 KiB
5.8 KiB
name, description, capabilities
| name | description | capabilities | ||
|---|---|---|---|---|
| re-imports | 导入导出表与库指纹:IAT/EAT、DLL/so 指纹、FLIRT 思路。 触发词:导入表、IAT、库指纹、链接了哪些库 |
|
导入导出表与库指纹
何时使用 / 何时不用
- 用:判断程序链接了哪些库/API;按导入特征匹配编译器与库版本;定位可疑导入(注入/网络/加密 API);分析插件与 DLL 的导出接口
- 不用:只需函数内部逻辑(直接反编译技能)
- 不用:壳静态隐藏导入时(动态解析的 API 不在 IAT 里——配合 re-tracing / re-memdump 从内存取)
工具准备
参考 re-analyze/platform-tips——导入表分析为静态步骤,免沙箱;涉及运行(验证动态解析 API)按最高原则进沙箱。
objdump / readelf(binutils)
- Linux:
apt install binutils/dnf install binutils/pacman -S binutils - macOS:
brew install binutils(gobjdump);Mach-O 用otool -L+nm -u - WSL: Linux 版
- 验证:
objdump -V
pefile(Python)
- 全平台:
pip install pefile - 验证:
python3 -c "import pefile; print(pefile.__version__)"
rizin / rz-bin
- 安装矩阵见 re-radare2,安装后以
rizin -v验证 - Windows: 官方 release 解压即用;radare2 用户可
choco install radare2作兼容(命令见下) - 验证:
rz-bin -V
Ghidra FLIRT 插件(ghidra_flirt)
- 全平台:
git clone https://github.com/nneonneo/ghidra_flirt && cd ghidra_flirt && make(需 Ghidra 已装,见 re-ghidra) - 验证: Ghidra 内出现 ghidra_flirt 扩展
操作步骤
-
列出导入函数:
- PE:
objdump -p sample.exe | grep 'DLL Name' -A3 | head -30import pefile pe = pefile.PE('sample.exe') for e in pe.DIRECTORY_ENTRY_IMPORT: print(e.dll, [i.name for i in e.imports if i.name][:15]) - ELF:
objdump -T sample | grep UND # 未定义符号 = 导入 readelf -s sample | grep -i ' UND ' - Mach-O:
otool -L sample # 依赖 dylib 列表 nm -u sample # 未定义符号 = 导入
- PE:
-
按导入特征匹配库/编译器(FLIRT 思路):
- FLIRT 签名: IDA
File > Load file > FLIRT signature file...(自带 sig 目录)自动标注库函数;Ghidra 用 ghidra_flirt 插件(工具准备) - libc 版本指纹:
readelf -s sample | grep -c ''配合strings sample | grep -E 'GLIBC_[0-9.]+'(GLIBC 符号版本号);strings libc.so.6 | grep -m1 version对运行库侧 - 语言指纹: Go(
runtime.main/go1.2x串)、Rust(_ZN/__rust_*)、C++(_Zmangled)、Delphi(@System@)、.NET(mscoree + metadata) - Rich Header(PE)交叉验证编译器版本,见 re-format-pe
- FLIRT 签名: IDA
-
定位可疑导入:
- 进程注入类:
OpenProcess+VirtualAllocEx+WriteProcessMemory+CreateRemoteThread(kernel32);NtCreateThreadEx(ntdll) - 网络回连类:
WSAStartup/socket/connect/HttpSendRequestA/WinHttpOpen - 加密/窃密类:
CryptEncrypt/CryptDecrypt/BCryptEncrypt/CryptExportKey(导出密钥) - 反调试类:
IsDebuggerPresent/NtQueryInformationProcess/OutputDebugStringA(异常触发检测) - ELF 侧:
ptrace/socket/execve/dlopen/fork;Mach-O 侧:task_for_pid/_dyld_* - 命中即标注到分析笔记,下一步去反编译技能定位调用点
- 进程注入类:
-
导出表分析(插件/服务类样本):
- PE:
objdump -p sample.dll | grep -A30 'Export Table'import pefile pe = pefile.PE('sample.dll') for exp in pe.DIRECTORY_ENTRY_EXPORT.symbols: print(hex(exp.address), exp.name) - ELF
.so:readelf -s sample.so | grep -v UND | grep FUNC(导出的全局函数) - Mach-O dylib:
nm -gU sample.dylib - 插件类样本导出接口名揭示功能(如 AV/注入器/工具集的内部命令)
- PE:
-
对照系统库验证(判断是否系统 API 混入可疑参数):
strings sample.exe | grep -iE '\.dll|\.so|\.dylib' # 附加库路径线索
跨域联合
- re-binary-core:工作流第 4 步固定调用
- re-malware:恶意导入特征(注入/窃密/回连)筛选
- re-cracking:找校验/注册相关 API 调用点
- 与 re-format-pe / re-format-elf / re-format-macho 衔接;壳隐藏导入时转 re-anti-analysis + re-memdump
常见坑与陷阱
- 导入表被壳重定向/加密:静态读到的 IAT 是壳的占位/已加密——真实导入要等运行后从内存取(re-memdump)
- 动态解析的 API 不在 IAT 里:
GetProcAddress/dlopen+dlsym运行时才解析,静态导入表查不到——配合 re-tracing 观察 - 字符串比对库版本更可靠:符号可被 strip/混淆,但 Go/OpenSSL 的版本串(
go1.21、OpenSSL 3.0.x)在字符串里 - 按序数(ordinal)导入的函数只有序号没有名字——需对照微软序号表或运行库导出表
- 运行时的 GOT/IAT 可能已被构造器改写:现象——静态导入表干净,运行后却调用异常函数;原因——恶意构造器(
.init_array/TLS 回调)在入口之前覆写 GOT/IAT 条目(如strcmp@GOT)装 hook,静态视图看不到;对策——导入结论与运行内存视图对照(re-memdump/re-tracing),样本带初始化回调时先把回调列出来再下结论 - 家族聚类用 imphash 而非导入名列表:现象——同家族变种导入名差异大,按名字聚类失败;原因——导入名列表对链接器版本/加壳敏感;对策——用 pefile 的
imphash(导入函数归一化后哈希)做指纹;注意 IAT 被壳接管的样本 imphash 失真,先脱壳再算