1、 分析环境
硬件:CPU: Pentium(R) Dual-Core CPU E5300@2.60GHZ ,内存: 2G
操作系统: Microsoft Windows XP Professional 2002 Service Pack 3
分析的软件:威步CodeMeter保护的WupiCalculator.exe。
分析工具:
OllyICE v1.10[汉化第二版],LordPE(LordPE Deluxe by youda),
Import REConstructor v1.7c,ResHacker V3.5,UltraEdit v 9.0.1.0,
CFFExplorer v7.2.0.1
2、 待分析程序
分析程序WupiCalculator.exe,程序的默认安装路径为
“C:\Documents and Settings\All Users\Documents\WIBU-SYSTEMS\Software Protection\C++\WupiCalculatorIndex\Protected\CodeMeter\WupiCalculator.exe”,该程序通过AxProtector和Ixprotector来进行保护。
AxProtector版本为8.0。
加密时采用的工程文件的默认安装路径为:C:\Documents and Settings\All Users\Documents\WIBU-SYSTEMS\Software Protection\C++\WupiCalculatorIndex\WupiCalculator-CodeMeter.WibuAxProject,该工程文件的主要的保护选项设置如图1,图2,图3,图4所示:
图 1
图 2
图 3
图 4
3、 分析过程
1. 保护前后程序的区段结构对比
原始程序的区段如图5所示。
图 5
被保护后程序的区段如图6所示。
图 6
2. 寻找OEP
程序用OD载入后报错,换了几个版本的OD均报错,报错的情况如图7所示。
图 7
用LordPE查看PE结构,没有发现异常。
用CFFExplorer查看PE文件结构,发现数据目录不能正常显示,原来被保护后的PE文件中的IMAGE_OPTIONAL_HEADER中的NumberofRvaAndSizes字段,修改为2200C4E7,如图8所示,该字段表示数据目录的项数,这个字段从WindowsNT发布以来一直是16,用CFFExplorer把这个字段修改为0x10,如图9所示。然后进行保存。
此时保存后的文件可以用OD打开。
图 8
图 9
直接运行修改后的程序报错,如图10所示,应该是有自校验功能。
图 10
用OD打开程序后,用HideOD插件将该插件提供的所有选项选中,然后重新启动程序,采用单步跟踪的方法,,在005186A3处的代码修改为jmp,如图11所示。
图 11
继续跟踪来到0051873A处,将代码修改为jmp,如图12所示。
图 12
直接运行,如图13所示。
图 13
单击确定后继续运行出错,如图14所示。
图 14
重新载入,单步跟踪来到005139DC处,修改为jmp。
图 15
后台检测功能会开新线程,为了避免在CreatehThread处下段点会被检测到,因此在call CreateRemoteThread处下断点,如图16所示。
图 16
继续运行中断后,堆栈数据如图17所示。
图 17
来到地址00514DC0处,005CCCBC地址存放校验值,将005CCCBC地址处的值修改为800000,如图18所示,这样可以跳过校验。
图 18
在OD中利用"Alt+M"打开内存映射,在区段__wibu00处下断点,如图19所示,下段后的结果如图20所示。
图 19
图 20
直接运行来到OEP处,如图21所示。
图 21
用lordpe完整转存,如图22所示,名称为dump.exe
图 22
3. 修复IAT
用Import Rec附加到WupiCalculator.exe进程,OEP处填入0002096B,依次单击AutoSearch和GetImports按钮,获取到的IAT如图23所示,从图中可以看出部分IAT被加密了。
图 23
重新载入程序,在地址0043B000处下硬件访问断点,如图24所示。
图 24
在硬件断点第二次中断后,数据窗口的数据如图25所示。
图 25
此时的EIP为0052A575,此地址的函数开头地址为00529FB0。
重新载入程序,在00529Fb0处下断点,分析IAT的处理过程。经过多次调试后,找到处理IAT加密的地方。
将0052A525处修改为jmp,禁止该处断点后,继续运行,如图26所示。
在地址0052A8BB处会将空的数据修改为005160B0,将0052A8B9处修改为jmp,如图27所示,此时已经避开IAT加密。
图 26
图 27
在函数的末尾0052A905处下断点,如图28所示。运行到此处时,还原图26和27处的magic jmp的修改,并去掉0052A905的断点。
注:修复输入表完毕后需要恢复修复IAT部分的代码中的断点,否则会被后面的自校验检测到。
图 28
继续在内存镜像的第一个区段处下断点,来到OEP处,用Import Rec获取输入表,如图29所示。单击Fix Dump按钮来修复脱壳后的数据。
图 29
4. 修复代码替换
运行修复输入表后的程序会出错,如图30所示。
图 30
运行出错地址。
00509E95 . 8B46 4C mov eax, dword ptr [esi+4C]
通过跟踪加壳后的程序和脱壳后的程序,出错的地方为0040101078,如图31所示。
通过反复跟踪加壳后的程序,壳代码中自己实现了GetProcAddress函数,此处为对InitCommonCtrolsEx的调用,分析其他调用输入表函数的地方,没有进行替换,只替换了此处。可以将00401077和00401078处的汇编语句先用NOP填充,然后修改为
call dword ptr [43B028],
修改后用OD保存修改,文件名称为dumped_fixcode.exe。
图 31
图 32
5. 修复加密的资源
运行程序继续出错。
通过单步跟踪的方法来对比加壳后的程序和脱壳后的程序,来到地址00407768处,如图33所示。
加壳后程序对话框资源0x66的的内存地址为00C0A6F0,如图34所示,脱壳后的程序的对话框资源地址为004DC620,如图35所示,该地址处的数据为加密后的资源数据。
图 33
图 34
图 35
用LordPE查看加壳后程序的对话框102资源大小为0x66E,如图36所示。
图 36
用解密后的数据替换加密后的数据。
用LordPe部分转存加壳后程序内存中的102对话框的资源数据,如图37所示。将转存的数据保存为102dlg.dmp
图 37
脱壳后程序的对话框资源102的文件偏移为0x00DC620,大小为0x66E,如图38所示。
图 38
用UltraEdit打开102dlg.dmp和脱壳后的程序,用102dlg.dmp中的数据替换掉脱壳后的程序从偏移0x00DC620到偏移0x000DCC8D处的数据,将脱壳后的程序保存为dumped_fixcode_fixres.exe。
此时可以用ResHacker打开修复好资源对话框102资源的程序,可以正确查看对话框资源,如图39所示。
图 39
附注:bp FindResourceW [esp + C]==05寻找对话框的Handle,LoadResource后就会返回对话框资源在内存中的位置。其他的资源可以利用上面的方法进行修复。
6. 处理浮点数错误
运行修复资源后的程序,报浮点数错误,如图40所示。
R6002错误原因:程序启动阶段___tmainCRTStartup函数中调用了__cinit函数,在这个函数的第一个判断是校验浮点运算初始化函数指针所处的section是否为可写,如果可写的话就跳过浮点运算初始化函数。该函数指针一般位于.rdata段。脱壳后程序的区段如图41所示,此处段名称修改为__wibu01。修改__wibu01区段的标志,将可写属性去掉,如图42所示,保存可执行文件。
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!