手脱 tElock 0.80 加 用 FixRes.dll 手动修复举例
Target: 小牧童 的“万能五笔2002”破解版(里面还DIY了他自己的签名,呵呆了,高呀)
Tools: OllyDbg1.10,LordPE, ImportRec, PEid0.93
OS: WinXp
用 PEid0.93 查得“万能五笔2002”是 tElock 0.80 -> tE!
用我的偶像 heXer 的脱壳机 脱唔倒 应该是版本不对口
于是来手脱一下:
(来个废话:以前一直不知怎么动它,看高手是玩得很轻松,怎么这里设断,那里设保留异常,
现在,感觉有点不同,不是我技术高了很多,而是心境好了,或许煅炼了一些耐性吧 )
言归正传:
好像没有设校验
脱 tElock 第一步可以先找 OEP
很容易的
忽略全部异常,直点运行,你会发现壳留下的“我曾到此一游”的蛛丝马迹 --
这时壳的初始代码已经脱光光了,CPU窗口拉上屋顶,就能看见醒目的 JMP OEP 的字样
找到是:423E1C
接着找壳解码:
通过一点的跟踪,可以很快知道壳在解码后,会搬运代码到原程序的空间,然后释放自己申请的临时块
所以中断 VirtualFree 比较方便
重来同样忽略所有异常,he VirtualFree
点运行
中断了,取消断点,这时在返回处会见到有个41000,查看这个块已经解码了
在 GetModuleHandleA 处下断点
He GetModuleHandleA
点运行
中断后,断点取消,返回用户代码空间会来到(Iat处理):
004BEBB2 test eax,eax
004BEBB4 je 004BEEAD
004BEBBA add eax,edx
004BEBBC mov ebx,eax
004BEBBE push eax //User32.dll
004BEBBF call dword ptr ss:[ebp+409C88] //kernel32.GetModuleHandleA
004BEBC5 test eax,eax //返回此处,我们可以向下跟一下很容易就能找到
004BEBC7 jnz 004BEC59
004BEBCD push ebx
004BEBCE call dword ptr ss:[ebp+409C8C]
004BEBD4 test eax,eax
004BEBD6 jnz 004BEC59
004BEBDC mov edx,dword ptr ss:[ebp+409D2E]
004BEBE2 add dword ptr ss:[ebp+409D02],edx
004BEBE8 add dword ptr ss:[ebp+409D0E],edx
004BEBEE push 30
004BEBF0 push dword ptr ss:[ebp+409D02]
004BEBF6 push dword ptr ss:[ebp+409D0E]
004BEBFC jmp short 004BEC1E
004BEBFE mov edx,dword ptr ss:[ebp+409D2E]
004BEC04 add dword ptr ss:[ebp+409D02],edx
004BEC0A add dword ptr ss:[ebp+409D06],edx
004BEC10 push 30
004BEC12 push dword ptr ss:[ebp+409D02]
004BEC18 push dword ptr ss:[ebp+409D06]
004BEC1E push 0
004BEC20 call dword ptr ss:[ebp+409CA4]
004BEC26 mov eax,dword ptr ss:[ebp+409C90]
004BEC2C mov dword ptr ss:[esp-4],eax
004BEC30 popad
004BEC31 push 0
004BEC33 call dword ptr ss:[esp-20]
004BEC37 mov edx,dword ptr ss:[ebp+409D2E]
004BEC3D add dword ptr ss:[ebp+409D02],edx
004BEC43 add dword ptr ss:[ebp+409D12],edx
004BEC49 push 30
004BEC4B push dword ptr ss:[ebp+409D02]
004BEC51 push dword ptr ss:[ebp+409D12]
004BEC57 jmp short 004BEC1E
004BEC59 mov dword ptr ss:[ebp+409D16],eax
004BEC5F lea eax,dword ptr ss:[ebp+409810]
004BEC65 pushad
004BEC66 xor ecx,ecx
004BEC68 sub dh,dh
004BEC6A mov dl,byte ptr ds:[ebx]
004BEC6C test dl,40
004BEC6F je short 004BEC74
004BEC71 and dl,5F
004BEC74 or dl,dl
004BEC76 je short 004BEC96
004BEC78 inc ebx
004BEC79 inc dh
004BEC7B inc ecx
004BEC7C cmp dl,byte ptr ds:[eax+ecx-1]
004BEC80 je short 004BEC6A
004BEC82 cmp dl,byte ptr ds:[eax+ecx+8]
004BEC86 je short 004BEC6A
004BEC88 cmp dl,byte ptr ds:[eax+ecx+12]
004BEC8C je short 004BEC6A
004BEC8E cmp dl,byte ptr ds:[eax+ecx+1D]
004BEC92 je short 004BEC6A
004BEC94 jmp short 004BEC66
004BEC96 or dh,dh //******** 关键之一 ********//
004BEC98 popad
004BEC99 mov byte ptr ss:[ebp+4098C0],0 //这里先置不加密
004BECA0 je short 004BECA9
004BECA2 or byte ptr ss:[ebp+4098C0],1 //这里加不加密要看上面的判断了
004BECA9 xor eax,eax
004BECAB mov byte ptr ds:[ebx],al
004BECAD inc ebx
004BECAE cmp byte ptr ds:[ebx],al
004BECB0 jnz short 004BECA9 //循环做一下清洁工
004BECB2 and dword ptr ss:[ebp+409D1A],0
004BECB9 mov edx,dword ptr ss:[ebp+409D2E] //基址
004BECBF mov eax,dword ptr ds:[esi] //相对于基址的偏移值
004BECC1 test eax,eax
004BECC3 jnz short 004BECD0
004BECC5 mov eax,dword ptr ds:[esi+10]
004BECC8 test eax,eax
004BECCA je 004BEC37
004BECD0 add eax,edx
004BECD2 add eax,dword ptr ss:[ebp+409D1A] //找API的地址 = 基址 + 偏移值
004BECD8 mov ebx,dword ptr ds:[eax]
004BECDA mov edi,dword ptr ds:[esi+10]
004BECDD add edi,edx
004BECDF and byte ptr ss:[ebp+4098BF],0FF //经过一二次的跟踪,不难发现这里也是鸡觅(鸡腿打人牙架软)
004BECE6 je 004BED8F //改动改动这里,笨猪跳就是啦,顺便在OEP处下个断点先,点运行就很快到终点了
004BECEC and byte ptr ss:[ebp+4098C0],0FF
004BECF3 je 004BED8F
004BECF9 mov dword ptr ss:[ebp+409DF6],edi //下面是加密过程,不是很复杂的
004BECFF mov eax,dword ptr ss:[ebp+409DEE]
004BED05 inc eax
004BED06 je 004BED8F
004BED0C dec eax
004BED0D jnz short 004BED64
004BED0F pushad
004BED10 mov esi,edi
004BED12 sub eax,eax
004BED14 inc eax
004BED15 cmp dword ptr ds:[edi],0
004BED18 lea edi,dword ptr ds:[edi+4]
004BED1B jnz short 004BED14
004BED1D dec eax
004BED1E je short 004BED87
004BED20 mov ebx,eax
004BED22 imul eax,eax,10
004BED25 push 4
004BED27 push 1000
004BED2C push eax
004BED2D push 0
004BED2F call dword ptr ss:[ebp+409C94] //申请空间加密用 kernel32.VirtualAlloc
004BED35 test eax,eax
004BED37 je short 004BED87
004BED39 mov edi,esi
004BED3B mov ecx,ebx
004BED3D mov edi,eax
004BED3F mov dword ptr ss:[ebp+409DF2],eax
004BED45 mov ecx,ebx
004BED47 lea ebx,dword ptr ds:[edi+ecx*8]
004BED4A mov dword ptr ss:[esp],ebx
004BED4D mov ax,25FF
004BED51 stos word ptr es:[edi]
004BED53 mov dword ptr ds:[edi],ebx
004BED55 add ebx,4
004BED58 add edi,4
004BED5B loopd short 004BED51
004BED5D popad
004BED5E mov dword ptr ss:[ebp+409DEE],edi
004BED64 mov edi,dword ptr ss:[ebp+409DEE]
004BED6A mov eax,dword ptr ss:[ebp+409DF6]
004BED70 add eax,dword ptr ss:[ebp+409D1A]
004BED76 mov ecx,dword ptr ss:[ebp+409DF2] //取得加密段的 基址
004BED7C mov dword ptr ds:[eax],ecx //这里eax是写入加密的 api 地址
004BED7E add dword ptr ss:[ebp+409DF2],6
004BED85 jmp short 004BED8F
004BED87 or dword ptr ss:[ebp+409DEE],FFFFFFFF
004BED8E popad
004BED8F add edi,dword ptr ss:[ebp+409D1A]
004BED95 test ebx,ebx
004BED97 je 004BEE5C
004BED9D test ebx,80000000
004BEDA3 push 0
004BEDA5 jnz short 004BEDAD
004BEDA7 lea ebx,dword ptr ds:[ebx+edx+2]
004BEDAB jmp short 004BEDE9
004BEDAD inc dword ptr ss:[esp]
004BEDB0 mov eax,dword ptr ss:[ebp+409D16]
004BEDB6 cmp eax,dword ptr ss:[ebp+409DDE]
004BEDBC jnz short 004BEDE9
004BEDBE and ebx,7FFFFFFF
004BEDC4 mov edx,ebx
004BEDC6 lea edx,dword ptr ds:[edx*4-4]
004BEDCD mov ebx,dword ptr ss:[ebp+409D16]
004BEDD3 mov eax,dword ptr ds:[ebx+3C]
004BEDD6 mov eax,dword ptr ds:[eax+ebx+78]
004BEDDA add ebx,dword ptr ds:[eax+ebx+1C]
004BEDDE mov eax,dword ptr ds:[edx+ebx]
004BEDE1 add eax,dword ptr ss:[ebp+409D16]
004BEDE7 jmp short 004BEDFC
004BEDE9 and ebx,7FFFFFFF
004BEDEF push ebx
004BEDF0 push dword ptr ss:[ebp+409D16]
004BEDF6 call dword ptr ss:[ebp+409C84] // kernel32.GetProcAddress
004BEDFC inc eax
004BEDFD dec eax
004BEDFE jnz short 004BEE32
004BEE00 pop eax
004BEE01 stc
004BEE02 jb 004BEC37
004BEE08 inc edi
004BEE09 inc esp
004BEE0A dec ecx
004BEE0B xor esi,dword ptr ds:[edx]
004BEE0D inc esp
004BEE0F dec esp
004BEE10 dec esp
004BEE11 push ebp
004BEE12 push ebx
004BEE13 inc ebp
004BEE14 push edx
004BEE15 xor esi,dword ptr ds:[edx]
004BEE17 inc esp
004BEE19 dec esp
004BEE1A dec esp
004BEE1B push ebx
004BEE1C dec eax
004BEE1D inc ebp
004BEE1E dec esp
004BEE1F dec esp
004BEE20 xor esi,dword ptr ds:[edx]
004BEE22 inc esp
004BEE24 dec esp
004BEE25 dec esp
004BEE26 dec ebx
004BEE27 inc ebp
004BEE28 push edx
004BEE29 dec esi
004BEE2A inc ebp
004BEE2B dec esp
004BEE2C xor esi,dword ptr ds:[edx]
004BEE2E inc esp
004BEE30 dec esp
004BEE31 dec esp
004BEE32 cmp byte ptr ds:[eax],0CC //是否是CC
004BEE35 mov dword ptr ds:[edi],eax //******* 写入真正的 API 地址或加密地址 *******
004BEE37 jnz short 004BEE3F
004BEE39 cmp byte ptr ds:[eax+1],0C3 //是否是ret
004BEE3D je short 004BEE3F
004BEE3F pop eax
004BEE40 dec eax
004BEE41 je short 004BEE50
004BEE43 inc eax
004BEE44 clc
004BEE45 mov word ptr ds:[ebx-2],ax
004BEE49 mov byte ptr ds:[ebx],al
004BEE4B inc ebx
004BEE4C cmp byte ptr ds:[ebx],al
004BEE4E jnz short 004BEE49
004BEE50 add dword ptr ss:[ebp+409D1A],4
004BEE57 jmp 004BECB9
004BEE5C add esi,14
004BEE5F mov edx,dword ptr ss:[ebp+409D2E]
004BEE65 jmp 004BEBA4
004BEE6A popad
004BEE6B retn
到达入口后,用 ImportReC 填入OEP,Get之后,全部有效,Fixit 就可以投入运行了!
//顺便来个脚本吧!
//OS:忽略所有异常,OllyDbg1.10,OllySctript0.92
var VF
var GM
var oep
mov oep, xxxxxxxx //这里填你 F9 看到的 OEP,一向上拉就能看到的
gpa "VirtualFree", "Kernel32.dll"
mov VF, $RESULT
bphws VF, "x"
run
cmp eip, VF
je err
bphwc VF
gpa "GetModuleHandleA", "Kernel32.dll"
mov GM, $RESULT
bphws GM, "x"
run
cmp eip, GM
je err
bphwc GM
rtu
findop eip, #08F661#
cmp $RESULT, 0
je err
mov [$RESULT], #32F6#
bp oep
run
cmp eip, oep
jne err
msg "OK!"
ret
err:
msg "Hit a error!"
ret
减肥修正资源:
另外用 dREAMtHEATER 的 FixRes.dll 的 Demo.exe Dump 出了修复好的资源节,当然是做好了所有裁减工作后才去Dump的。好像有人说不会用 Dump 功能,下面简略说一下我的使用过程:
在“万能五笔2002”破解版到达 OEP 处 Dump 出内存后,用 ImportReC 获取 Iat 修复为 Dump_.exe,运行一下,很正常,复制一个副本待用,暂时不要关闭ImportReC。
有如下6、7个节项(770多 K)如图:Dump_.jpg:
Name VOffset VSize ROffset RSize Flags
.text 00001000 0002B000 00001000 0002B000 C0000040
.rdata 0002C000 00002000 0002C000 00002000 C0000040
.data 0002E000 00057000 0002E000 00057000 C0000040
.Share 00085000 00001000 00085000 00010000 C0000040
.rsrc 00086000 00038000 00086000 00038000 C0000040
nil(壳的) 000BE000 00002000 000BE000 00002000 C0000040
.mackt(修复的Import) 000C0000 00001000 000C0000 00001000 E0000060
小小分析(仅个人愚见,不可当真,我这里没有参考未破解版本的原程序):
由于有个 Share 节,而且只有一个DWORD(-1)内容,用 OD 加载,在那个节下内存访问断点,只中断到那个Dword处那么一个Dword上,跟变量有关哟,不能草率铲除呵。再看了看它上面的一个节,有不少 00,很想也减一下它,稳当起见,又用 OD 加载一次,在那个段下内存访问断点,中断了好几次,应该是程序在初始化或保存数据,嘿,真是见鬼,接近节末还有写的,看来该节虚拟的大小不能减。粗略浏览了一下资源表,可以发现有些图标资源分散在壳节中,dREAMtHEATER 的 FixRes.dll 当然有用啦,OK,可以动工了。
决定采用文件对齐:200,内存对齐:1000
拿出你熟悉的16进制工具,或者用LordPE的分割和合并功能,我这里用WinHex。
加载后,goto 到 85000 偏移处,将后面的部分剪去了(一共剪去了.Share、.rsrc、 nil(壳的)、.mackt),再往上看,减多少随你吧,反正从底部起是连续的OO都可以减,可我这里还是采用了对对齐200,将.data 的偏移大小改为 11400,即从文件偏移 0 处开始保留大小为 3F400 ,改了后要保存。调整了PE文件的大小,当然要用 PE 工具如 LordPE 将.data节的 Offset 大小改过来,要与之对应。
接着,.Share节,我在刚才处理的文件最后粘贴(加了)4字节FF(即原来的-1 Dword 内容),你要填200的Offset大小我也不反对,下面的修复输入表会补回来的,还会有多,不要改 RVA 大小,修正其节的Offset大小和节偏移地址。
我这里是 .Share ROffset : 0003F400 RSize : 00000004
清除节描述表里面的 .rsrc、 nil(壳的)、.mackt,逐一点擦除即可,一定要,不然下面修复输入表会出错的。
到修复输入表了,由于 ImportReC 的在PE文件自填 RVA 补Import不是很稳定(估计要1000对齐的才能OK),只好另开一个新节 .mackt。
点击刚才还没关闭的 ImportReC , 选新增一个节修复选项,点 Fix ,选中上面改好的文件,这时 ImportReC 会因为对齐,给你在上一个节与这个新节之间的文件间隙中自动补充了00。
好了,要修正资源节了。到了 FixRes.dll 出动的时候了,在经过上面的输入表修复后,我们用 LordPE 给它新增一个节,改名为 .rsrc ,意思为资源节,
该节如下:
VOffset: 0087000 //这个是我们经过上面处理,现在得到新资源表的RVA
VSize: 0000000
ROffset: 0041000
RSize: 0000000
启动 FixRes.dll 的 Demo.exe ,选择好上面的修复 “副本”,再选择 Dump 项,给出要Dump出 资源文件的文件名,在 NewRVA 处填 87000 ,FileAlgnMent 处填: 200
最后,点 Dump Resource 按钮输出修复的资源节。
把这个资源节拖入 WinHex ,全选,复制16进制节(大小:37400),粘贴到该文件的最后,保存。
用 LordPE 加载 该文件,在 .rsrc 节 VSize 处填上 38000 (内存块对齐),RSize 处填上 37400
点保存,
再选择目录,进入目录表,修正原来 的资源表入口为 RVA: 87000, 大小为: 37400
点保存即可,你可以同时删除重定位表描述。
最最后,重建一下 PE ,单独启动 LordPE ,选 重建 PE,点选文件,重建就可以运行了。
我这里大概减肥修复为 :481 K (当然可以更优,就留给你办了)
如图:Fixed.jpg
Name VOffset VSize ROffset RSize Flags
.text 00001000 0002B000 00001000 0002B000 C0000040
.rdata 0002C000 00002000 0002C000 00002000 C0000040
.data 0002E000 00057000 0002E000 00011400 C0000040
.Share 00085000 00001000 0003F400 00000004 C0000040
.mackt 00086000 00001000 00040000 00001000 E0000060
.rsrc 00087000 00038000 00041000 00037400 C0000040
当然你还可以优化得更好,就让你去办了!
感谢你可以看完到这一行,我的字要打完了,希望对你有所帮助!
Written by askformore
[课程]Linux pwn 探索篇!