本篇文章将介绍一款名为 JDPack 的加壳工具,它专门用于对 PE 文件进行加壳保护,并内置了反调试功能——当检测到 TRW 或 SoftICE 调试器时,会触发不同的响应行为。在 1.00 版中,检测到调试器仅弹出提示信息;而到了 1.01 版,系统会直接触发非法操作,导致程序异常终止。未注册版本没有时间限制,但每次运行经加壳处理后的文件时,都会弹出一个烦人的提示框,内容为“Unregistered JDPack. This file PACKED by Unregistered JDPack 1.0* from ...”。
进行脱壳操作所需的工具包括:TRW(或 SoftICE)配合 kWDSM 反汇编器。下面直接进入实战步骤讲解。
1.00版脱壳
在早期追踪 1.00 版时,由于该版本仅给出提示信息而未触发异常,因此很容易定位到关键代码位置。使用断点 bpx GetVersionExA,然后执行 g 命令运行程序,中断后先用 bc 清除该断点(后续还会出现几次 GetVersionExA 调用,但与脱壳流程无关)。在下方会出现两个 JZ 跳转指令,务必确保它们不跳转,否则会触发调试器检测提示(这里使用的是 TRW 调试器)。直接通过 r fl z 清除零标志位,随后会遇到一个 JMP 指令,按 F8 单步继续执行。后续步骤较为简单,当接近原始入口点(OEP)时会出现 POPA 和 JMP EAX 指令,最后执行 makepe 命令即可完成脱壳。
1.01版脱壳
1.01 版本的脱壳思路与 1.00 版基本一致,同样采用 bpx GetVersionExA 断点,然后 g 运行程序。断点会停在以下位置:
0187:0040E250 CALL NEAR [EBP+004031B1] //停在这里,先bc
0187:0040E256 LEA EBX,[EBP+00403449]
0187:0040E25C CMP DWORD [EBX+10],BYTE 01
0187:0040E260 JZ 0040E276 (JUMP)//下r fl z,跳的话就完了
0187:0040E262 CMP DWORD [EBX+10],BYTE 02
0187:0040E266 JZ 0040E26A
0187:0040E268 JMP SHORT 0040E284 //F8进去
0187:0040E284 MOV EDX,[EBP+00403441] //到了这里
0187:0040E28A MOV ESI,[EBP+004031D9]
0187:0040E290 ADD ESI,EDX
0187:0040E292 MOV EAX,[ESI+0C]
0187:0040E295 OR EAX,EAX
0187:0040E297 JZ NEAR 0040E3EA (NO JUMP)
0187:0040E29D ADD EAX,EDX
0187:0040E29F MOV [EBP+004031A5],EAX
0187:0040E2A5 MOV EBX,EAX
0187:0040E3EA MOV EDX,[EBP+00403441]
0187:0040E3F0 MOV EAX,[EBP+004031D5]
0187:0040E3F6 ADD EAX,EDX
0187:0040E3F8 MOV [ESP+1C],EAX
0187:0040E3FC POPA
0187:0040E3FD PUSH EAX
0187:0040E3FE RET //按F8就到OEP,直接makepe断点处中断后,首先使用 bc 清除断点。接下来会遇到两个比较指令:第一个 CMP DWORD [EBX+10], 01,如果比较结果等于 1,则跳转到 0040E276——这个跳转绝对不能发生,否则会进入反调试流程。直接通过 r fl z 清零零标志位,使其不跳转。接着是比较 02 的指令,如果等于 2 则跳转到 0040E26A,这里也是一个保护分支,不过代码随后会走到 JMP SHORT 0040E284,按 F8 直接进入该地址。到达 0040E284 后,继续向下执行,会看到 JZ NEAR 0040E3EA (NO JUMP)——注意此处不要让它跳转,直接使用 g 40E3EA 命令跳转到该地址。再往下就是 POPA、PUSH EAX、RET 指令序列,按 F8 即可返回到程序的原始入口点,最后执行 makepe 命令完成脱壳。
总结两个版本的差异:1.00 版的反调试机制相对“温和”,仅弹出提示;而 1.01 版则直接触发异常,但核心破解思路完全相同——都是通过拦截 GetVersionExA 系统调用来绕过版本检测,然后沿着正确的跳转路径直达原始入口点(OEP)。
