Enigma protector V1.31.build.2007615 加密的记事本脱壳
主程序:自己找
目标程序:自己加 XP SP2
ODIC
importrec
winhex
......
简单介绍一下我的脱壳过程,没有仔细看,某些地方说不清楚 一, 解码后dump
清除所有断点,忽略所有异常
对01001000下内存写入断点(1个字节就可以了)
咦,不用等啊等,也不慢、不狂异常了,555,不能顺便去WC了,回来后发现断在这里
00C79B59 8807 mov byte ptr [edi], al// 断在这里
00C79B5B 47 inc edi
00C79B5C 00D2 add dl, dl
00C79B5E 75 05 jnz short 00C79B65 清除内存断点,往下拉,找retn
00C79C74 5D pop ebp
00C79C75 2B7D 40 sub edi, dword ptr [ebp+40]
00C79C78 897C24 1C mov dword ptr [esp+1C], edi
00C79C7C 61 popad
00C79C7D 5D pop ebp
00C79C7E C3 retn
00C79C7F 894424 1C mov dword ptr [esp+1C], eax
00C79C83 61 popad // 你要在这里下断也行,不过很快发现出口是下面一个
00C79C84 8945 FC mov dword ptr [ebp-4], eax
00C79C87 8B45 FC mov eax, dword ptr [ebp-4]
00C79C8A 59 pop ecx
00C79C8B 5D pop ebp
00C79C8C C2 0800 retn 8 // 这里下断
上面返回
00C79AC9 8945 FC mov dword ptr [ebp-4], eax // 00FCC31C返回到这里
00C79ACC F6C3 04 test bl, 4
00C79ACF 74 0A je short 00C79ADB
00C79AD1 8B45 FC mov eax, dword ptr [ebp-4]
00C79AD4 50 push eax
00C79AD5 57 push edi
00C79AD6 E8 09000000 call 00C79AE4
00C79ADB 5F pop edi
00C79ADC 5E pop esi
00C79ADD 5B pop ebx
00C79ADE 59 pop ecx
00C79ADF 5D pop ebp
00C79AE0 C2 1400 retn 14 // F4到这里
然后
00C79A6A 8B53 05 mov edx, dword ptr [ebx+5] // 00C79AE0 返回到这里
00C79A6D 8BC6 mov eax, esi
00C79A6F E8 E48AFFFF call 00C72558
00C79A74 83C3 3D add ebx, 3D
00C79A77 837B 0D 00 cmp dword ptr [ebx+D], 0
00C79A7B ^ 75 AE jnz short 00C79A2B //这个jnz如果跳上去的话,继续去判断下面的段是否要解码
00C79A7D 5F pop edi
00C79A7E 5E pop esi
00C79A7F 5B pop ebx
00C79A80 C3 retn // F4到这里 这时F4到00FCC128 后,发现第一个区段解码了
01001000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ............... // 不过够明显,姑且先当作解码了
这时可以用 OD dump了吗?此时不dump, 后面也许就被重定位吧,先dump一个放着。 二,继续前进
解码后 alt-m 对01001000段下内存访问断点,F9运行
00C7268F F3:A5 rep movs dword ptr es:[edi], dword ptr [esi]// 断在这里
00C72691 89C1 mov ecx, eax
00C72693 83E1 03 and ecx, 3
00C72696 F3:A4 rep movs byte ptr es:[edi], byte ptr [esi]
00C72698 5F pop edi
00C72699 5E pop esi
00C7269A C3 retn//取消内存断点, F4下来 这一段不知道干嘛的,它将解码后的代码段copy其它地方去,不去管它
返回后
00C7EAD8 B8 40000000 mov eax, 40
00C7EADD 2B07 sub eax, dword ptr [edi]
00C7EADF 3BC3 cmp eax, ebx
00C7EAE1 77 23 ja short 00C7EB06
00C7EAE3 8BC8 mov ecx, eax
00C7EAE5 8B07 mov eax, dword ptr [edi]
00C7EAE7 8D90 9403CB00 lea edx, dword ptr [eax+CB0394]
00C7EAED 8BC6 mov eax, esi
00C7EAEF E8 883BFFFF call 00C7267C
00C7EAF4 B8 40000000 mov eax, 40
00C7EAF9 2B07 sub eax, dword ptr [edi]
00C7EAFB 2BD8 sub ebx, eax
00C7EAFD 03F0 add esi, eax
00C7EAFF E8 B4F6FFFF call 00C7E1B8
00C7EB04 EB 15 jmp short 00C7EB1B
00C7EB06 8B07 mov eax, dword ptr [edi]
00C7EB08 8D90 9403CB00 lea edx, dword ptr [eax+CB0394]
00C7EB0E 8BC6 mov eax, esi
00C7EB10 8BCB mov ecx, ebx
00C7EB12 E8 653BFFFF call 00C7267C
00C7EB17 011F add dword ptr [edi], ebx
00C7EB19 33DB xor ebx, ebx
00C7EB1B 85DB test ebx, ebx
00C7EB1D ^ 77 B9 ja short 00C7EAD8// 这里会跳上去,下面F4就是要跳过这里
00C7EB1F 5F pop edi
00C7EB20 5E pop esi
00C7EB21 5B pop ebx
00C7EB22 C3 retn // F4下来 继续alt-m 对01001000段下内存写入断点, F9运行
00C726A9 F3:A5 rep movs dword ptr es:[edi], dword ptr [esi]
00C726AB 89C1 mov ecx, eax
00C726AD 83E1 03 and ecx, 3
00C726B0 83C6 03 add esi, 3
00C726B3 83C7 03 add edi, 3
00C726B6 F3:A4 rep movs byte ptr es:[edi], byte ptr [esi]
00C726B8 FC cld
00C726B9 5F pop edi
00C726BA 5E pop esi
00C726BB C3 retn
不理
继续对01001000段下内存写入断点, F9
00C8B94B 8902 mov dword ptr [edx], eax // 断在这里
00C8B94D 46 inc esi
00C8B94E 4F dec edi
00C8B94F ^ 75 99 jnz short 00C8B8EA
00C8B951 43 inc ebx
00C8B952 FF0C24 dec dword ptr [esp]
00C8B955 ^ 0F85 76FFFFFF jnz 00C8B8D1
00C8B95B 5A pop edx
00C8B95C 5D pop ebp
00C8B95D 5F pop edi
00C8B95E 5E pop esi
00C8B95F 5B pop ebx
00C8B960 C3 retn 00C8B94B 8902 mov dword ptr [edx], eax 对代码段中的jmp [IAT] 的IAT地址重定位了,重定位到底地址,并且IAT里面加密了。
当前改写的第一个是
01002DFC 8B3D C4120001 mov edi, dword ptr [10012C4]
0C8B94B 8902 mov dword ptr [edx], eax 这句话过后改成了
01002DFC 8B3D 3870CE00 mov edi, dword ptr [CE7038]
CE7038中的内容对应的位置是
00CE79C0 8BFF mov edi, edi
00CE79C2 55 push ebp
00CE79C3 54 push esp
00CE79C4 5D pop ebp
00CE79C5 81EC A0040000 sub esp, 4A0
00CE79CB A1 AC113576 mov eax, dword ptr [763511AC]
00CE79D0 8B55 08 mov edx, dword ptr [ebp+8]
00CE79D3 56 push esi
00CE79D4 57 push edi
00CE79D5 8945 FC mov dword ptr [ebp-4], eax
00CE79D8 33C0 xor eax, eax
00CE79DA B9 27010000 mov ecx, 127
00CE79DF 8DBD 60FBFFFF lea edi, dword ptr [ebp-4A0]
00CE79E5 F3:AB rep stos dword ptr es:[edi]
00CE79E7 8D85 60FBFFFF lea eax, dword ptr [ebp-4A0]
00CE79ED 50 push eax
00CE79EE 8995 68FBFFFF mov dword ptr [ebp-498], edx
00CE79F4 C785 60FBFFFF 0>mov dword ptr [ebp-4A0], 1
00CE79FE E8 32BF6575 call comdlg32.76343935
00CE7A03 83BD 64FBFFFF 0>cmp dword ptr [ebp-49C], 0
00CE7A0A 8BF0 mov esi, eax
00CE7A0C - 0F84 1ECF6575 je comdlg32.76344930
00CE7A12 FFB5 64FBFFFF push dword ptr [ebp-49C]
00CE7A18 FF15 BC103276 call dword ptr [<&KERNEL32.GlobalFree>] ; kernel32.GlobalFree
00CE7A1E 8B4D FC mov ecx, dword ptr [ebp-4]
00CE7A21 5F pop edi
00CE7A22 8BC6 mov eax, esi
00CE7A24 5E pop esi
00CE7A25 E8 EB9B6375 call comdlg32.76321615
00CE7A2A C9 leave
00CE7A2B C2 0400 retn 4
显然是一个加密的API 三,记下CE7038和00CE79C0这2个地方,重来
清除所有断点,忽略所有异常
完成上面的第一部分,对CE7038下内存写入断点,哎呀,怎么无此地址啊?再试试00CE79C0,5555,怎么也没有啊,看来完成第一部分还没有分配空间。
怎么办哪?我们现在看上面的哪个API,明显是被从什么地方搬来的,于是我们随便找个API,看看壳是怎么处理的。
CTRL-G,到CloseHandle,下个内存访问断点,F9。
00C8468C 8A06 mov al, byte ptr [esi]// 断在这里
00C8468E 3D FF000000 cmp eax, 0FF
00C84693 0F87 663E0000 ja 00C884FF
00C84699 8A80 A646C800 mov al, byte ptr [eax+C846A6]
00C8469F FF2485 A647C800 jmp dword ptr [eax*4+C847A6]
跟着往下跑跑
00C8C0A9 E8 2A0AFFFF call 00C7CAD8
00C8C0AE 8D45 EC lea eax, dword ptr [ebp-14]
00C8C0B1 8BCB mov ecx, ebx
00C8C0B3 B2 04 mov dl, 4
00C8C0B5 E8 2AF4FEFF call 00C7B4E4
00C8C0BA 8D45 EC lea eax, dword ptr [ebp-14]
00C8C0BD 33D2 xor edx, edx
00C8C0BF E8 E405FFFF call 00C7C6A8
00C8C0C4 8D047F lea eax, dword ptr [edi+edi*2]
00C8C0C7 8B55 FC mov edx, dword ptr [ebp-4]
00C8C0CA 8B4D F0 mov ecx, dword ptr [ebp-10]
00C8C0CD 894C82 04 mov dword ptr [edx+eax*4+4], ecx//这一行是对地址进行的改写
00C8C0D1 47 inc edi
00C8C0D2 FF4D D0 dec dword ptr [ebp-30]
00C8C0D5 ^ 0F85 CDFAFFFF jnz 00C8BBA8 //跳上去处理下一个加密的输入表
00C8C0DB 33C0 xor eax, eax
从来,解码后到这里:
00C8C0CD 894C82 04 mov dword ptr [edx+eax*4+4], ecx 把这一行nop 掉(3个nop) 然后F4到下面的00C8C0DB
再把这3个nop恢复(撤消选择),我知道有自校验,这样做是为了不出错
这样一来,大部分被重定位的IAT中都是真实的API地址了 alt-m 对010001000段下内存写入断点
和第二部分中的一样,又到这里了
00C8B94B 8902 mov dword ptr [edx], eax//这一次到这里时[eax]中的是真实API了
00C8B94D 46 inc esi
00C8B94E 4F dec edi
00C8B94F ^ 75 99 jnz short 00C8B8EA
00C8B951 43 inc ebx
00C8B952 FF0C24 dec dword ptr [esp]
00C8B955 ^ 0F85 76FFFFFF jnz 00C8B8D1
00C8B95B 5A pop edx
00C8B95C 5D pop ebp
00C8B95D 5F pop edi
00C8B95E 5E pop esi
00C8B95F 5B pop ebx
00C8B960 C3 retn
我们只要将[eax]写入[[edx]]中,输入表就巧妙回来了
清除内存断点
申请找一块空地
在00C8B943 8B0D 40B2C900 mov ecx, dword ptr [C9B240]新建EIP,为什么这样做看代码上面的部分
修改如下:
00C8B943 - E9 B8461700 jmp 00E00000 00E00000 8B0D 40B2C900 mov ecx, dword ptr [C9B240]
00E00006 0311 add edx, dword ptr [ecx]
00E00008 60 pushad
00E00009 8B08 mov ecx, dword ptr [eax]
00E0000B 8B1A mov ebx, dword ptr [edx]
00E0000D 890B mov dword ptr [ebx], ecx
00E0000F 61 popad
00E00010 46 inc esi
00E00011 4F dec edi
00E00012 - E9 3AB9E8FF jmp 00C8B951 8B 0D 40 B2 C9 00 03 11 60 8B 08 8B 1A 89 0B 61 46 4F E9 3A B9 E8 FF 然后F4到上面的00C8B960 C3 retn 就全都处理完了,为了不出错,也把上面改的恢复回来。
然后找数据段(DATA段)吗?算了,先去OEP看看再说 四,飞向光明之颠
该做的都做完了吧,alt-m对01001000段下内存访问断点, F9,飞啊,飞向光明之颠!!!
咦,怎么程序飞了?看来这个办法飞不到光明之颠了,换个办法吧。重来,我们可以根据程序的入口特点来下API断点定位OEP,毕竟脱记事本是开卷考试。但假设现在不知道,我们换个别的办法,ALT-M,看到MSVCRT,下个内存访问断点。
77C0537C > 8BFF mov edi, edi
77C0537E 55 push ebp
77C0537F 8BEC mov ebp, esp
77C05381 8B45 08 mov eax, dword ptr [ebp+8]
77C05384 A3 BC17C377 mov dword ptr [77C317BC], eax
77C05389 5D pop ebp
77C0538A C3 retn//返回
可以看到有多少代码被搬走了,不幸的是没有变形,没有插花、插校验,没有VM。
00CF7004 6A 70 push 70
00CF7006 68 98180001 push 1001898
00CF700B E8 58053100 call notepad_.01007568
00CF7010 33DB xor ebx, ebx
00CF7012 53 push ebx
00CF7013 8B3D C435CE00 mov edi, dword ptr [CE35C4]
00CF7019 FFD7 call edi
00CF701B 66:8138 4D5A cmp word ptr [eax], 5A4D
00CF7020 0F85 30000000 jnz 00CF7056
00CF7026 8B48 3C mov ecx, dword ptr [eax+3C]
00CF7029 03C8 add ecx, eax
00CF702B 8139 50450000 cmp dword ptr [ecx], 4550
00CF7031 0F85 1F000000 jnz 00CF7056
00CF7037 0FB781 18000000 movzx eax, word ptr [ecx+18]
00CF703E 81F8 0B010000 cmp eax, 10B
00CF7044 0F84 34000000 je 00CF707E
00CF704A 81F8 0B020000 cmp eax, 20B
00CF7050 0F84 0B000000 je 00CF7061
00CF7056 899D E4FFFFFF mov dword ptr [ebp-1C], ebx
00CF705C E9 3E000000 jmp 00CF709F
00CF7061 81B9 84000000 0>cmp dword ptr [ecx+84], 0E
00CF706B ^ 0F86 E5FFFFFF jbe 00CF7056
00CF7071 33C0 xor eax, eax
00CF7073 3999 F8000000 cmp dword ptr [ecx+F8], ebx
00CF7079 E9 18000000 jmp 00CF7096
00CF707E 81B9 74000000 0>cmp dword ptr [ecx+74], 0E
00CF7088 ^ 0F86 C8FFFFFF jbe 00CF7056
00CF708E 33C0 xor eax, eax
00CF7090 3999 E8000000 cmp dword ptr [ecx+E8], ebx
00CF7096 0F95C0 setne al
00CF7099 8985 E4FFFFFF mov dword ptr [ebp-1C], eax
00CF709F 899D FCFFFFFF mov dword ptr [ebp-4], ebx
00CF70A5 6A 02 push 2
00CF70A7 FF15 8C34CE00 call dword ptr [CE348C] ; msvcrt.__set_app_type
00CF70AD 59 pop ecx ; notepad_.010000E0
00CF70AE 810D 9CAB0001 F>or dword ptr [100AB9C], FFFFFFFF
00CF70B8 810D A0AB0001 F>or dword ptr [100ABA0], FFFFFFFF
00CF70C2 FF15 8034CE00 call dword ptr [CE3480] ; msvcrt.__p__fmode
00CF70C8 8B0D B89A0001 mov ecx, dword ptr [1009AB8]
00CF70CE 8908 mov dword ptr [eax], ecx
00CF70D0 FF15 7434CE00 call dword ptr [CE3474] ; msvcrt.__p__commode
00CF70D6 8B0D B49A0001 mov ecx, dword ptr [1009AB4]
00CF70DC 8908 mov dword ptr [eax], ecx
00CF70DE 8B05 6834CE00 mov eax, dword ptr [CE3468] ; msvcrt._adjust_fdiv
00CF70E4 8B40 00 mov eax, dword ptr [eax]
00CF70E7 8905 A4AB0001 mov dword ptr [100ABA4], eax
00CF70ED E8 02053100 call notepad_.010075F4
00CF70F2 391D 08960001 cmp dword ptr [1009608], ebx
00CF70F8 0F85 0C000000 jnz 00CF710A
00CF70FE 68 F4750001 push 10075F4
00CF7103 FF15 5C34CE00 call dword ptr [CE345C] ; msvcrt.__setusermatherr
00CF7109 59 pop ecx
00CF710A E8 CE043100 call notepad_.010075DD
00CF710F 68 10900001 push 1009010
00CF7114 68 0C900001 push 100900C
00CF7119 E8 B4043100 call notepad_.010075D2 ; jmp 到 msvcrt._initterm
00CF711E 8B05 B09A0001 mov eax, dword ptr [1009AB0]
00CF7124 8985 DCFFFFFF mov dword ptr [ebp-24], eax
00CF712A 8D45 DC lea eax, dword ptr [ebp-24]
00CF712D 50 push eax
00CF712E FF35 AC9A0001 push dword ptr [1009AAC]
00CF7134 8D45 D4 lea eax, dword ptr [ebp-2C]
00CF7137 50 push eax
00CF7138 8D45 D0 lea eax, dword ptr [ebp-30]
00CF713B 50 push eax
00CF713C 8D45 CC lea eax, dword ptr [ebp-34]
00CF713F 50 push eax
00CF7140 FF15 4434CE00 call dword ptr [CE3444] ; msvcrt.__getmainargs
00CF7146 8985 C8FFFFFF mov dword ptr [ebp-38], eax
00CF714C 68 08900001 push 1009008
00CF7151 68 00900001 push 1009000
00CF7156 E8 77043100 call notepad_.010075D2 ; jmp 到 msvcrt._initterm
00CF715B 83C4 24 add esp, 24
00CF715E 8B05 3834CE00 mov eax, dword ptr [CE3438] ; msvcrt._acmdln
00CF7164 8B70 00 mov esi, dword ptr [eax]
00CF7167 89B5 E0FFFFFF mov dword ptr [ebp-20], esi
00CF716D 80BE 00000000 2>cmp byte ptr [esi], 22
00CF7174 0F85 6A000000 jnz 00CF71E4
00CF717A 46 inc esi
00CF717B 89B5 E0FFFFFF mov dword ptr [ebp-20], esi
00CF7181 8A06 mov al, byte ptr [esi]
00CF7183 3AC3 cmp al, bl
00CF7185 0F84 09000000 je 00CF7194
00CF718B 80F8 22 cmp al, 22
00CF718E ^ 0F85 E6FFFFFF jnz 00CF717A
00CF7194 80BE 00000000 2>cmp byte ptr [esi], 22
00CF719B 0F85 07000000 jnz 00CF71A8
00CF71A1 46 inc esi
00CF71A2 89B5 E0FFFFFF mov dword ptr [ebp-20], esi
00CF71A8 8A06 mov al, byte ptr [esi]
00CF71AA 3AC3 cmp al, bl
00CF71AC 0F84 09000000 je 00CF71BB
00CF71B2 80F8 20 cmp al, 20
00CF71B5 ^ 0F86 E6FFFFFF jbe 00CF71A1
00CF71BB 899D ACFFFFFF mov dword ptr [ebp-54], ebx
00CF71C1 8D45 80 lea eax, dword ptr [ebp-80]
00CF71C4 50 push eax
00CF71C5 FF15 D035CE00 call dword ptr [CE35D0] ; kernel32.GetStartupInfoA
00CF71CB F685 ACFFFFFF 0>test byte ptr [ebp-54], 1
00CF71D2 0F84 25000000 je 00CF71FD
00CF71D8 0FB785 B0FFFFFF movzx eax, word ptr [ebp-50]
00CF71DF E9 1C000000 jmp 00CF7200
00CF71E4 80BE 00000000 2>cmp byte ptr [esi], 20
00CF71EB ^ 0F86 B7FFFFFF jbe 00CF71A8
00CF71F1 46 inc esi
00CF71F2 89B5 E0FFFFFF mov dword ptr [ebp-20], esi
00CF71F8 ^ E9 E7FFFFFF jmp 00CF71E4
00CF71FD 6A 0A push 0A
00CF71FF 58 pop eax
00CF7200 50 push eax
00CF7201 56 push esi
00CF7202 53 push ebx
00CF7203 53 push ebx
00CF7204 FFD7 call edi
00CF7206 50 push eax
00CF7207 E8 2AB73000 call notepad_.01002936
00CF720C 8BF0 mov esi, eax
00CF720E 89B5 C4FFFFFF mov dword ptr [ebp-3C], esi
00CF7214 399D E4FFFFFF cmp dword ptr [ebp-1C], ebx
00CF721A 0F85 07000000 jnz 00CF7227
00CF7220 56 push esi
00CF7221 FF15 2C34CE00 call dword ptr [CE342C] ; msvcrt.exit
00CF7227 FF15 E433CE00 call dword ptr [CE33E4] ; msvcrt._cexit
00CF722D - E9 25033100 jmp notepad_.01007557
00CF7232 8B45 EC mov eax, dword ptr [ebp-14]
00CF7235 8B48 00 mov ecx, dword ptr [eax]
00CF7238 8B49 00 mov ecx, dword ptr [ecx]
00CF723B 898D D8FFFFFF mov dword ptr [ebp-28], ecx
00CF7241 50 push eax
00CF7242 51 push ecx
00CF7243 E8 7E033100 call notepad_.010075C6 ; jmp 到 msvcrt._XcptFilter
00CF7248 59 pop ecx
00CF7249 59 pop ecx
00CF724A C3 retn
00CF724B - E9 EE023100 jmp notepad_.0100753E
00CF724B - E9 EE023100 jmp notepad_.0100753E,最后这句话告诉我们原来这些代码的大概位置,然后干什么不用多说了吧。到代码段看看,发现没有什么别的动作,于是补好代码后再DUMP一个。 五,擦屁屁
到了这里,可以打开ImportIAT修输入表了,发现有几个还是加密了,但并不难, ctrl-g过去看一下就能知道是什么了,要不就取个特征码在对应的DLL找找。然后修复,运行,挂!看看ImportIAT的显示,发现有KERNEL32.DLL和MSVRT.DLL有割断,而原来不是这样的,看来还有特出的处理。 直接放开跑,到抽去的OEP代码位置,看到00CF7F8B FF15 74FBCC00 call dword ptr [CCFB74]; msvcrt._cexit,这个在ImportIAT里就没有,原来这就是特出之处,这里的填充位置有所不同,造成刚才的补丁没有处理这几个。剩下的就没啥了,先用OD往对应的地方添点东西,让ImportIAT把表连起来,然后从00C8C0CD 894C82 04 mov dword ptr [edx+eax*4+4], ecx这里找到对应API的位置,补好,修复,运行正常。
六,后记
这个壳整体上很温柔,就像OB那样,没有野蛮的ANTI,输入表的加密做的还不错,如果能再混合上代码变形,插花,插校验和自定义的VM效果会更好。主程序的脱壳流程差不多,但有VM,慢慢修吧。破解很简单,不过人家没什么限制,像这样的作者现在已经不多了,要是破了自己放着就好了,发出来只会被人拿去加木马,让作者不再放新版,这种损人不利己的事还是少做为好。最后感谢最最强大的,最最青春的XXXXXX原来的文章,让我少打了许多字,也感谢你能看完,虽然我并不认为有多好看。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课