IDA实操技巧:深度剖析Dridex家族木马分析
字数 3741
更新时间 2026-04-02 13:36:18
Dridex 木马逆向分析与配置提取深度教学
一、 木马概述
Dridex 是一种起源于 2014 年的银行木马,是 GameOver Zeus 的继承者。其主要目标是窃取在线银行用户的登录凭证、银行账户信息,并实施金融欺诈。该木马主要通过包含恶意 Office 宏、PDF 或嵌套可执行文件的钓鱼邮件进行传播。
二、 核心分析目标
- 配置提取:木马通常配置多个 C2 服务器。动态分析可能无法捕获全部 C2 地址。通过静态提取配置,可一次性获取完整的 C2 列表,用于封锁和监测。
- 功能分析:深入理解其加载、解密、注入和执行流程。
分析样本哈希:c7990f1e72fdfa84552f02f9d11cabb74251b0508291af5366fefcee646f9c91
三、 静态分析实战
阶段一:Shellcode 提取与分析
-
初步检查:
- 确认样本为 32 位 PE 文件。
-
IDA 初步分析:
- 用 IDA 打开样本,发现字符串隐藏、函数符号混淆处理得非常彻底,增加了分析难度。
- 在浏览时,发现函数
sub_55303C频繁出现,其特征是带有两个 16 进制参数。
-
关键技巧:IDA 设置优化:
- 问题:IDA 默认以十进制显示数字,对包含大量硬编码常量的恶意代码分析不便。
- 解决:在 Hex-Rays 反编译器插件设置中,将
Default radix修改为 16,使所有数字以十六进制显示。
-
识别 API 哈希解析:
- 进入
sub_55303C函数,发现大量操作 PEB (Process Environment Block) 的代码,这是典型的 API Hashing 手法(用于隐藏 API 函数名,规避静态检测)。 - 使用 HashDB 插件进行识别。对参数执行 “HashDB Hunt Algorithm”。
- 常见问题:首次 Hash 可能无法找到正确算法,原因通常是未设置正确的 XOR Key。
- 解决:在函数
sub_5503C4中发现异或密钥0x7AF3DA47。在 HashDB 中右键设置此值为 Xor Key,再次执行 Hash 搜索。 - 结果:成功识别出 CRC32 算法。随后可使用
m键为参数重命名为具体的 API 函数名。 - 遗留问题:像
V5这类变量需要手动赋值具体的 API 函数指针,此过程可考虑编写脚本自动化,后续探讨。
- 进入
-
自动化辅助分析:使用 CAPA 插件:
- 鉴于样本极其复杂,需借助工具快速定位关键功能。使用 FLARE capa explorer IDA 插件。
- 安装:
- 在 IDA 的 Python 环境中安装
flare-capa库。 - 将
capa_explorer.py脚本放入 IDA 插件目录。 - 重启 IDA,在插件菜单中找到 “FLARE capa explorer”。
- 在 IDA 的 Python 环境中安装
- 使用:加载与
flare-capa版本对应的规则库(capa-rules)。成功加载后,插件会高亮显示敏感功能,如:- RC4 加密算法
- aPlib 压缩算法
- XOR 异或操作
- 根据经验,加密算法附近常存在待解密的数据。通过交叉引用向上回溯,定位到函数
sub_552154,其附近存在可疑数据块。
-
数据定位与导出:
- 在数据段(如
.data节)发现多处加密数据块,例如:0055A0600055AF800055B8400055B9800055C5600055C660
- 使用 IDA 的
Edit -> Export data功能,以十六进制格式导出选中数据。
- 在数据段(如
阶段二:数据解密流程推演
- 数据存储结构假设:经验表明,此类木马常采用 “密钥+数据” 的拼接存储方式,密钥位于数据块起始部分。
- 密钥提取:对每个加密数据块,取前
0x30(48) 个字节,进行字节反转(Reverse) 后作为 RC4 算法的密钥。剩余部分为密文。 - 解密验证:
- 使用 CyberChef 或编写 Python 脚本进行验证。
- 步骤:
- 截取数据前 96 个十六进制字符(即 48 字节),进行反转。
- 将反转后的密钥与后续密文,送入 RC4 解密算法。
- 解密输出多为 Base64 编码的字符串。
- 完整流程猜想:结合附近存在的
mw_aplib函数引用,推断完整的数据处理链为:
原始数据 → RC4解密 → Base64解码 → aPlib解压 → Shellcode
阶段三:核心功能逆向
- 定位注入逻辑:函数
sub_5479A4包含大量与进程注入相关的 API 调用,是分析重点。 - 结构体分析:许多函数操作一个
this指针。为提高可读性,应为其创建结构体(struct),并合理定义成员变量。 - API 类型标准化:使用 ApplyCalleeType 插件,输入 API 名称,可自动应用正确的函数原型,极大提升反编译代码的可读性。
- 关键函数符号恢复:
sub_5502D4->mw_get_api_by_hash_v2sub_54201C->mw_get_inject_apisub_54C2C4->mw_wrap_GetHandleInformationsub_5510C8->mw_get_integrity_level(获取进程完整性级别)sub_553998->mw_time_operator(时间操作)sub_5521F8->mw_get_proc_info(获取进程信息)sub_5520FC->mw_get_proc_bit(判断进程位数 32/64)sub_54FB80->mw_wrap_get_proc_bitsub_54F6E4->mw_base64_decode
- 逻辑串联:通过分析
sub_54FB80的交叉引用,发现其根据当前进程位数(32/64位),选择不同的加密数据块(如0055A060或0055A6C0)进行解密,最终将解密出的 Shellcode 注入到目标进程。
阶段四:编写完整解密脚本
- RC4 解密函数:
def rc4_decrypt(key: bytes, data: bytes) -> bytes: S = list(range(256)) j = 0 out = bytearray() # KSA for i in range(256): j = (j + S[i] + key[i % len(key)]) % 256 S[i], S[j] = S[j], S[i] # PRGA i = j = 0 for byte in data: i = (i + 1) % 256 j = (j + S[i]) % 256 S[i], S[j] = S[j], S[i] out.append(byte ^ S[(S[i] + S[j]) % 256]) return bytes(out) - aPlib 解压:使用标准的 aPlib 解压库(如
github.com/snemes/aplib)。 - 完整解密步骤:
- 读取加密数据。
- 取前 48 字节,反转后作为 RC4 密钥。
- 用 RC4 解密剩余数据。
- 对解密结果进行 Base64 解码。
- 注意:解码后的数据前 4 字节可能是压缩数据长度,实际解压时需要跳过这4个字节:
decompressed_data = decompress(decoded_data[4:])。 - 最终得到可执行的 Shellcode 二进制数据。
阶段五:自动化提取 C2 配置
- 寻找 C2 解密函数:定位到函数
sub_5513A4(mw_rc4_decrypt),查看其所有交叉引用,找到解密网络相关字符串(如 "GET"/"POST")和 C2 地址的地方。 - 定位 C2 数据结构:在数据段(如
0055D02C)附近,可发现 IP:Port 格式的数据。特征数字0x1BB(443) 指示 HTTPS 端口。 - 提取特征码:
- 在引用 C2 数据表的代码处提取机器码特征:
\xbb\x20\xd0\x55\x00\x89\x45\x00\x0f\xb7\x53\x04\x89\x10\x0f\xb6\x4b\x0b\x83\xf9\x0a\x7f\x03\x8a\x53\x0b\x0f\xb6\x53\x0b\x85\xd2\x7e\xb9\x8d\x74\x24\x0c - 特征中
\xbb后的4字节(小端序)为 C2 数据表的虚拟地址(VA)。
- 在引用 C2 数据表的代码处提取机器码特征:
- 编写提取脚本:
import re, pefile, struct def extract_c2(file_data): ip_parse_egg = rb'\xbb(....)\x89\x45\x00\x0f\xb7\x53\x04\x89\x10\x0f\xb6\x4b\x0b\x83\xf9\x0a' pe = pefile.PE(data=file_data) match = re.search(ip_parse_egg, file_data, re.DOTALL) if not match: return [] # 获取C2表地址 table_addr = struct.unpack('<I', match.group(1))[0] # 转换VA为文件偏移 table_offset = pe.get_offset_from_rva(table_addr - pe.OPTIONAL_HEADER.ImageBase) ip_table_offset = table_offset + 0xb # 读取C2数量 ip_table_length = file_data[ip_table_offset] ip_table_offset += 1 c2_list = [] for _ in range(ip_table_length): ip = '.'.join(map(str, file_data[ip_table_offset:ip_table_offset+4])) port = struct.unpack('<H', file_data[ip_table_offset+4:ip_table_offset+6])[0] c2_list.append(f"{ip}:{port}") ip_table_offset += 6 return c2_list - 执行结果:运行脚本即可输出所有 C2 服务器的 IP 地址和端口。
四、 总结与关键点
- 对抗技巧:Dridex 综合使用了 API Hashing、字符串加密、多段加密 Shellcode、aPlib 压缩等多种反分析技术。
- 分析方法:
- 环境配置:设置 IDA 以十六进制显示常量。
- 工具链:结合 HashDB 识别 API 哈希,使用 CAPA 快速定位功能代码,利用 ApplyCalleeType 规范化类型。
- 结构体重建:为频繁操作的
this指针创建结构体,是理解复杂逻辑的关键。 - 猜证结合:基于经验假设(如密钥位置、数据格式),并通过编写脚本快速验证。
- 自动化提取:核心配置(如 C2)通常以加密形式存储在
.data等节区。通过定位解密函数、分析数据引用模式、提取特征码,可以编写脚本实现配置的批量、自动化提取,极大提升分析效率。 - 纵深分析:从简单的字符串解密,到理解进程位数判断、数据选择、解密链、最终注入执行的完整逻辑,体现了对复杂木马进行系统性逆向工程的完整思路。
相似文章
相似文章