首页
课程
问答
CTF
社区
招聘
峰会
发现
排行榜
知识库
工具下载
看雪20年
看雪商城
证书查询
登录
注册
首页
社区
课程
招聘
发现
问答
CTF
排行榜
知识库
工具下载
峰会
看雪商城
证书查询
社区
加壳脱壳
发新帖
0
1
[原创] 某网游加速器程序UPX 脱壳后续,让它跑起来!
发表于: 2026-8-15 20:01
721
[原创] 某网游加速器程序UPX 脱壳后续,让它跑起来!
cendart
2026-8-15 20:01
721
> 接上篇《某网游加速器程序 UPX 加壳分析与手工脱壳》。 > 上篇按 stub 逐指令复刻,把 52MB 的 Go 镜像解压、反过滤、恢复导入/重定位、重建 PE,静态验证全过。 > 结果一运行就 0xc0000005。这篇记录从"静态对、运行崩"到定位到解码器一个字节的初始化错误的全过程。 > 声明:本文仅用于安全研究与学习交流,请勿用于非法用途。 ## 0x0 静态全对,一跑就崩 上篇做出来的镜像(ImageBase 0x400000,SizeOfImage 0x36bf000),`file` 和 `objdump` 都正常: ```bash $ file unpacked.exe PE32 executable (console) Intel 80386 (stripped to external PDB), for MS Windows $ objdump -h unpacked.exe # 10 个节、导入表、.reloc 全部合法 ``` pefile 校验 PE 头、节表、数据目录全部通过,节无重叠。但双击直接崩溃: ``` 0xc0000005 (Access Violation),发生在加载器初始化阶段 ``` 注意,崩的是"加载器初始化",不是程序自己 —— 说明问题出在镜像里**加载器要读的那几块元数据**(TLS、.CRT、重定位结果),而不是 Go 运行时本身的逻辑。这个判断基本决定了后面的排查方向。 ## 0x1 四层崩溃,一层一层剥 每修一层,崩溃就往前推一层,一路剥了四层: 1. 启动即 AV:ntdll `LdrpInitializeProcess` 读 TLS 目录时 READ fault @ `0x81fc5c03` 2. 报缺 `nfapi.dll`(目录中的一个 netfilter 库),拷过来就好 —— 这个只是环境问题 3. 又 AV:msvcrt `initterm` 遍历 .CRT 表,表内指针被重定位成了 2.9GB 的垃圾地址 4. 又 AV,EIP 停在 RVA 0x11d9:RVA 0x13bf 处一条 `jmp` 的目标差 1 字节,落进了指令中间 到第四层就明白了:这是系统性 bug,点修一处下一处必崩。 ### TLS 目录是垃圾 TLS 目录 DD[9] 指向 `VA 0x310b9a4 / Size 0x18`,结构体内容: ``` StartAddressOfRawData = 0x9f300001 EndAddressOfRawData = 0x9f300403 AddressOfIndex = 0x9efc5c03 <- 注意高字节 0x9 AddressOfCallBacks = 0x9f201c03 SizeOfZeroFill = 3 ``` 全是垃圾。ntdll 初始化线程局部存储时按 `AddressOfIndex` 去读,高字节 `0x9` 直接指向未映射地址,READ fault。 先清零 DD[9] 顶着(Go 运行时用的是 Win32 `TlsAlloc`,不依赖 PE TLS 目录,安全)。 ### .CRT 表被错位重定位 过了 TLS 又崩在 `initterm`。.CRT 节(VA 0x35f2000 / VSize 0x30)本应是 `__xi_a/__xi_z`、`__xc_a/__xc_z` 的函数指针表,文件里却是: ``` +0x04 = 0x40112000 +0x10 = 0x40101000 +0x1c = 0x27976000 +0x20 = 0x27971001 ``` 运行时被重定位成 `0xAD112000 / 0xAD101000 / 0x94976000 / 0x94971001`。delta=0x6D000000,是镜像 delta 0x6D0000 的 256 倍,明显不对。 查 `.reloc` 表发现这 4 条 HIGHLOW 条目全部**错位 +1 字节**:条目落在 `0x35f2005 / 0x35f2011 / 0x35f201d / 0x35f2021`,而指针在 -1 处。加完 delta,本该是 `0x401120` 的指针变成了 2.9GB,`initterm` 顺着它 call 过去就炸了。先清零 4 个指针 + 4 条错位重定位改 ABSOLUTE。 ### jmp 位移差 1,警报拉响 又崩,EIP=RVA 0x11d9。反汇编看现场: ```nasm 4011d0: c7 05 08 00 51 03 01 00 00 00 mov dword ptr [0x03510008], 1 ; 10 字节, 0x11d0-0x11d9 4013bf: e9 15 fe ff ff jmp -0x1eb ; -> 0x4011D9 !! ``` `jmp` 目标 `0x4011D9` 正好落在上面那条 `mov` 的最后一个字节 `00` 上,从那儿执行到 `add [ecx+...], ah` 写非法地址 → AV。 差 1 字节。而且同一条代码路径里 call 全对,就这一条 jmp 错 1 —— 这已经不是某一处坏了,是整体有问题。点修到此为止。 ## 0x2 转机:拿 running 的 packed 进程当 ground truth 原版 packed exe 是能跑的,产品本身没坏。stub 运行时把 Go 镜像解压进内存,这份内存就是**权威解压结果**。 用调试器把 packed exe 跑起来,6 秒后 dump 完整镜像(54MB),跟脱壳文件逐字节对: | 位置 | 内存(权威) | 脱壳文件 | |---|---|---| | RVA 0x13bf | `e9 16 fe ff ff` → **0x4011DA** | `e9 15 fe ff ff` → 0x4011D9 | | .text 起始 | `c3 8d b4 26 00 00 00 00 8d b4 26 00 00 00 00 90` | `c3 8d b4 26 00 00 00 00 00 b4 26 00 00 00 00 00` | 看到 `.text` 起始那两行,问题基本就锁定了。 ## 0x3 首分歧:不是 E8/E9,是第一个 match 多吐了一个字节 逐字节对齐后,第一个分歧根本不在任何 call/jmp 上,而在 `.text` 最开头: ``` RVA 0x1000..0x1007 rec == gt (c3 8d b4 26 00 00 00 00) 前 8 字节完全一致 RVA 0x1008..0x100f rec = 00 b4 26 00 00 00 00 00 (8 字节!) gt = 8d b4 26 00 00 00 00 (7 字节) RVA 0x1010 起 rec == gt (90 83 ec 1c ...) 从此全部错位 1 字节 ``` 解码出来是这样的: - 正确:`c3`(ret) + 两个 7 字节 lea-padding `8d b4 26 00 00 00 00`(第二个是回引第一个的 match) - 错误:`c3` + `8d b4 26 00 00 00 00` + `00 b4 26 00 00 00 00` + 多余一个 `00` 也就是解压器在**第一个 match 处多插了 1 个字节**,且首字节 `00` 应为 `8d`。这一个字节让之后所有字节位置偏移 +1 —— E8/E9 位移、TLS/.CRT 指针"普遍差 1"全是它的连锁反应,0x0/0x1 里看到的三个症状同源。 复盘一下,之前全量 diff 得出"9.2M 个 4 字节不匹配"、"shift=-1 最优对齐",都是被这个单字节插入骗了。那不是恒定偏移,而是从插入点之后整体漂移 1 字节。一开始就该先找首分歧,而不是看统计数字。 ## 0x4 根因:初始 `ebp` 少了 `or ebp, -1` 对照 stub 反汇编把解码器的每个分支(m_off / m_len / getbit / `cmp ebp,-0x500; adc ecx,2`)逐条核了一遍,全都对得上,最后盯住了**寄存器初值**: ```nasm 037274ac: 83 cd ff or ebp, -1 ; <- stub 入口把 ebp 置成 -1 ``` 而我解码器里的初始化是: ```python ecx = eax = ebp = edi = edx = 0 # ebp = 0,错! ``` `ebp` 是"上一次匹配偏移"。当某个 match 走 **reuse-offset 路径**(m_off 解出 `eax < 3`,即小偏移复用上一次值)时,用的就是初始 `ebp`。第一个 match 恰好是小偏移: | | 初始 ebp | 行为 | 输出 | |---|---|---|---| | 我 | 0 | 源偏移 0 → 非法、走 copy4、len=4 | `00 00 00 00`(多 1 字节) | | stub | -1 (0xFFFFFFFF) | 源偏移 1 → 指回上一字节 00、走 copy1、len=3 | `00 00 00`(正确) | 差这 1 字节的原因:`ebp=-1` 时源指针 `edx = edi + ebp = 输出位置 - 1`,正好回指到刚写入的最后一个字节(00),`len=3` 恰好补出 `00 00 00`;`ebp=0` 时 `edx = 输出位置`(还没写数据),copy4 读出一串 0 还多写 1 字节。另外 `cmp ebp,-0x500` 对 `-1` 和 `0` 的 CF 也不同(`-1` 的 `0xFFFFFFFF` 不比 `0xFFFFFB00` 小 → `ecx+=2`;`0` 则 `ecx+=3`),长度也跟着差 1。两个症状同一个错误初值产生,全对上了。 ## 0x5 修复与验证 改一行: ```python ecx = eax = edi = edx = 0 ebp = 0xFFFFFFFF # stub: or ebp, -1 ``` 重跑整条流水线,后面全部变正常: | 项 | 修复前 | 修复后 | |---|---|---| | 解压输出 | 57,824,366 B | 57,824,365 B(少 1 字节 = 插入的那字节) | | extra_info PE 签名 | `0x37251d5`(错位) | `0x37251d4`(正确) | | .text 起始 16 B | `c3 8d b4 26 00 00 00 00 00 b4 26 00 00 00 00 00` | 与内存一致 | | E8/E9 位移 | 大量差 +1 | 反汇编 325,995 条真实 call/jmp,0 条不一致 | | TLS 目录 | 垃圾(AddressOfIndex=0x9efc5c03) | 正常(0x039efc5c,.reloc 4 字段全有 HIGHLOW 覆盖) | | .CRT 表 | 4 指针 2.9GB 垃圾 | 正常(+04=0x401120 等合法函数指针) | 验证时有个比 diff 更干净的判据:E8/E9 的相对位移不随加载基址变化,逐条比对是纯代码正确性的最强信号。 跑起来: ```bash $ ./unpacked_fixed.exe & # 52 MB $ ps # 进程存活, 多线程(Go runtime 特征), 无 0xc0000005 ``` 再附加调试器确认了一下:主线程 RIP 停在 WOW64 的 syscall 跳板(正常的等待点),不是异常现场。 ## 0x6 总结 | 组件 | 上篇结论 | 本篇补充 | |---|---|---| | NRV2B 常量 | `cmp -0x500; adc 2` | 初始 `ebp = -1`(`or ebp,-1`),转写时漏设 | | 运行 | 能否运行存疑 | 修复后可直接运行 | 几点教训: 1. "静态验证全过"不等于"能运行"。导入表、重定位、PE 头全对,只要加载器要读的元数据(TLS/.CRT)差一字节就崩; 2. 逐指令复刻解码器时,**寄存器初值也是指令**。`or ebp,-1` 这种初始化最容易漏,而且只在首条 reuse-offset 匹配时才暴露; 3. 拿运行中的 packed 进程当 ground truth 是验证后面是不是全修好的捷径,相对位移(E8/E9)是不受基址影响的纯代码正确性判据; 4. 单字节插入会伪装成"全局 shift=-1"。先找首分歧再下结论,别被全量 diff 的统计数字带偏。 修复只动了解码器一处初始化(`ebp = 0xFFFFFFFF`,对应 stub 的 `or ebp,-1`),重跑一遍后镜像、导入表、重定位、TLS/.CRT 就都正常了。
传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!!
最后于
2026-8-15 20:14 被cendart编辑 ,原因: 去掉目标程序商业名称
上传的附件:
unpack_upx.py
(27.62kb,2次下载)
收藏
・
0
点赞
・
1
打赏
分享
分享到微信
分享到QQ
分享到微博
赞赏记录
参与人
雪币
留言
时间
maxwudi
为你点赞!
2天前
查看更多
赞赏
×
1 雪花
5 雪花
10 雪花
20 雪花
50 雪花
80 雪花
100 雪花
150 雪花
200 雪花
支付方式:
微信支付
赞赏留言:
快捷留言
感谢分享~
精品文章~
原创内容~
精彩转帖~
助人为乐~
感谢分享~
最新回复
(
0
)
游客
登录
|
注册
方可回帖
回帖
表情
雪币赚取及消费
高级回复
返回
cendart
4
发帖
4
回帖
10
RANK
关注
私信
他的文章
[原创] 某网游加速器程序UPX 脱壳后续,让它跑起来!
721
[原创] 某网游加速器程序 UPX 加壳分析与手工脱壳
924
关于我们
联系我们
企业服务
看雪公众号
专注于PC、移动、智能设备安全研究及逆向工程的开发者社区
谁下载
×
huangyalei
mb_heqvlbnm
看原图
赞赏
×
雪币:
+
留言:
快捷留言
为你点赞!
返回
顶部