dfgdf 发表于 2016-1-21 02:42

一个简单运行时解密+CRC校验的patchme分析

本帖最后由 dfgdf 于 2016-1-21 13:48 编辑

今天朋友给我发了patchme,他很多地方不懂,叫我帮他分析。
我分析完发现这个作者真是用心良苦,专为新手练习特意写的。分析完 觉得有点意思,就发出来给大家分享一下。



                                       
打开程序,很简单, 一个提示框,一个对话框,作者要求就是修改这两个字符串。







OD载入,ep代码很简单整洁,这是汇编写的吧(我猜)。





国际惯例,搜索字符串,没找到提示框和对话框的字符串,早做好心理准备肯定是搜不到的了。



既然这样我们就一句句代码来分析吧。。。。。。。


我们看到上面ep代码,就一个call,肯定进去,F8再F7进去代码如下。。。。。
004010E9/$B8 F5104000   mov eax,unpackme.004010F5
004010EE|.50            push eax
004010EF|.E8 A7FFFFFF   call unpackme.0040109B
004010F4\.C3            retn


这。。。。。压入004010F5作为参数继续Call。。。。我们还是F8 F8 F7进去call unpackme.0040109B,代码如下。。。。
0040109B/$50            push eax                                 ;unpackme.004010F5
0040109C|.8BD8          mov ebx,eax
0040109E|.B9 54010000   mov ecx,0x154
004010A3|>8033 44       /xor byte ptr ds:,0x44
004010A6|.83E9 01       |sub ecx,0x1
004010A9|.43            |inc ebx
004010AA|.83F9 00       |cmp ecx,0x0
004010AD|.^ 75 F4         \jnz short unpackme.004010A3
004010AF|.50            push eax
004010B0|.E8 08000000   call unpackme.004010BD
004010B5|.50            push eax
004010B6|.E8 7EFFFFFF   call unpackme.00401039
004010BB|.58            pop eax
004010BC\.C3            retn


代码真是非常简洁明了,一个循环两个call。。。我们先看这个循环是什么鬼。。。
0040109B/$50            push eax                                 ;F8往下走
0040109C|.8BD8          mov ebx,eax
0040109E|.B9 54010000   mov ecx,0x154                            ;循环次数,154
004010A3|>8033 44       /xor byte ptr ds:,0x44            ;ebx=004010f5,用ebx异或44,解密(4010f5~401248)区域
004010A6|.83E9 01       |sub ecx,0x1
004010A9|.43            |inc ebx
004010AA|.83F9 00       |cmp ecx,0x0
004010AD|.^ 75 F4         \jnz short unpackme.004010A3


我发现我写得好像过于详细。。。。。
知道循环是什么鬼之后就在 004010AF|.50            push eax 下段点然后F9跑过循环。
然后进入004010B0|.E8 08000000   call unpackme.004010BD
看看又是什么鬼。。。。。。
代码如下
004010BD/$50            push eax                                 ;F8走下去
004010BE|.BB 07104000   mov ebx,unpackme.00401007
004010C3|.B9 7F000000   mov ecx,0x7F                           ;循环次数7F
004010C8|>8033 07       /xor byte ptr ds:,0x7               ;ebx=401007,用ebx异或7,解密(401007~401085)区域
004010CB|.83E9 01       |sub ecx,0x1
004010CE|.43            |inc ebx
004010CF|.83F9 00       |cmp ecx,0x0
004010D2|.^ 75 F4         \jnz short unpackme.004010C8
004010D4|.8BD8          mov ebx,eax
004010D6|.B9 54010000   mov ecx,0x154                            ;又一个循环,154次
004010DB|>8033 11       xor byte ptr ds:,0x11               ;ebx=004010f5,用ebx异或11,解密(4010f5~401248)区域
004010DE|.83E9 01       sub ecx,0x1                              ;又是刚才那个区域,双重加密啊啊啊啊
004010E1|.43            inc ebx
004010E2|.83F9 00       cmp ecx,0x0
004010E5|.^ 75 F4         jnz short unpackme.004010DB
004010E7|.58            pop eax
004010E8\.C3            retn                                     ;解密完就返回


这个CALL就是分别解密(401007~401085和4010f5~401248)两个区域,弄懂走下一个call :004010B6|.E8 7EFFFFFF   call unpackme.00401039

哎呀,这个call的地址留意一下, call 00401039;之前分析的”用ebx异或7,解密(401007~401085)区域“,正好在上面xor 7解密的那个区域。
进去代码如下


00401039   $50            push eax
0040103A   .8BD8          mov ebx,eax
0040103C   .B9 54010000   mov ecx,0x154                            ;循环154次
00401041   .BA 00000000   mov edx,0x0                              ;初始化edx
00401046   >0313          add edx,dword ptr ds:               ;ebx=004010F5,又是那个双重加密的区域,将(4010f5~401248)区域累计相加,结果存edx
00401048   .83E9 01       sub ecx,0x1
0040104B   .43            inc ebx
0040104C   .83F9 00       cmp ecx,0x0
0040104F   .^ 75 F5         jnz short unpackme.00401046
00401051   .B8 4A124000   mov eax,unpackme.0040124A
00401056   .BE 80124000   mov esi,unpackme.00401280
0040105B   .50            push eax
0040105C   .56            push esi
0040105D   .E8 28000000   call unpackme.0040108A                   ;解密IAT。
00401062   .81FA B08DEB31 cmp edx,0x31EB8DB0                     ;edx和31eb8db0比较 ,这就是CRC校验,你修改过就会提示错误。
00401068   .74 19         je short unpackme.00401083               ;是否提示crc校验错误的跳转
0040106A   .6A 30         push 0x30
0040106C   .68 32104000   push unpackme.00401032                   ;Error:
00401071   .68 09104000   push unpackme.00401009                   ;CrC of this file has been modified !!!
00401076   .6A 00         push 0x0
00401078   .E8 E5010000   call unpackme.00401262
0040107D   .50            push eax
0040107E   .E8 F1010000   call unpackme.00401274
00401083   >E9 96010000   jmp unpackme.0040121E                  ;跳到程序的oep
00401088   .58            pop eax
00401089   .C3            retn


这是最简单的CRC校验了,我们继续来看OEP的代码情况,如下:

0040121E    6A 00         push 0x0
00401220    E8 55000000   call <jmp.&kernel32.GetModuleHandleA>    ; GetModuleHandleA 是取DLL的运行句柄的,在创建窗口时候用这个能给窗口赋值正确的句柄和运行id
00401225    A3 18304000   mov dword ptr ds:,eax
0040122A    6A 00         push 0x0
0040122C    68 F5104000   push unpackme.004010F5                   ; 显示对话框的过程
00401231    6A 00         push 0x0
00401233    68 24304000   push unpackme.00403024                   ; TESTWIN
00401238    FF35 18304000   push dword ptr ds:
0040123E    E8 0D000000   call <jmp.&user32.DialogBoxParamA>       ; DialogBoxParam函数根据对话框模板资源创建一个模态的对话框
00401243    50            push eax
00401244    E8 2B000000   call <jmp.&kernel32.ExitProcess>         ; 退出



代码整洁的不习惯。。。程序流程很明了,提示对话框然后退出, 看看函数DialogBoxParam第四个参数是IpDialogFunc:指向对话框过程的指针。有关更详细的关于对话框过程的信息,请参见DialogProc。
我们要分析参数是0040122C push 004010F5 ; 显示对话框的过程,所以进入004010F5 细看整个流程。没错就是那个加密两次还要crc校验的重要区域,代码如下:


004010F5   .55            push ebp
004010F6   .8BEC          mov ebp,esp
004010F8   .83C4 C0       add esp,-0x40
004010FB   .817D 0C 10010>cmp dword ptr ss:,0x110
00401102   .0F85 C8000000 jnz unpackme.004011D0
00401108   .EB 17         jmp short unpackme.00401121
0040110A   .59 6F 75 20 6>ascii "You must unpack "
0040111A   .6D 65 20 21 2>ascii "me !!!",0
00401121   >EB 1C         jmp short unpackme.0040113F
00401123   .59 6F 75 20 6>ascii "You must patch t"
00401133   .68 69 73 20 4>ascii "his NAG !!!",0
0040113F   >EB 24         jmp short unpackme.00401165
00401141   .3C 3C 3C 20 4>ascii "<<< Ap0x / Patch"
00401151   .20 26 20 55 6>ascii " & Unpack Me #1 "
00401161   .3E 3E 3E 00   ascii ">>>",0
00401165   >68 41114000   push unpackme.00401141                   ; /lParam = 0x401141
0040116A   .6A 00         push 0x0                                 ; |wParam = 0x0
0040116C   .6A 0C         push 0xC                                 ; |Message = WM_SETTEXT
0040116E   .FF75 08       push dword ptr ss:            ; |hWnd
00401171   .E8 F2000000   call <jmp.&user32.SendMessageA>          ; \SendMessageA
00401176   .68 C8000000   push 0xC8                              ; /RsrcName = 200.
0040117B   .FF35 18304000 push dword ptr ds:             ; |hInst = NULL
00401181   .E8 D6000000   call <jmp.&user32.LoadIconA>             ; \LoadIconA
00401186   .A3 20304000   mov dword ptr ds:,eax
0040118B   .FF35 20304000 push dword ptr ds:             ; /lParam = 0x0
00401191   .6A 01         push 0x1                                 ; |wParam = 0x1
00401193   .68 80000000   push 0x80                              ; |Message = WM_SETICON
00401198   .FF75 08       push dword ptr ss:            ; |hWnd
0040119B   .E8 C8000000   call <jmp.&user32.SendMessageA>          ; \SendMessageA
004011A0   .BB 01000000   mov ebx,0x1
004011A5   .68 0A114000   push unpackme.0040110A                   ; /You must unpack me !!!
004011AA   .6A 64         push 0x64                              ; |ControlID = 64 (100.)
004011AC   .FF75 08       push dword ptr ss:            ; |hWnd
004011AF   .E8 BA000000   call <jmp.&user32.SetDlgItemTextA>       ; \SetDlgItemTextA
004011B4   .6A 40         push 0x40                              ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
004011B6   .68 41114000   push unpackme.00401141                   ; |<<< Ap0x / Patch & Unpack Me #1 >>>
004011BB   .68 23114000   push unpackme.00401123                   ; |You must patch this NAG !!!
004011C0   .FF75 08       push dword ptr ss:            ; |hOwner
004011C3   .E8 9A000000   call <jmp.&user32.MessageBoxA>         ; \MessageBoxA
004011C8   .33C0          xor eax,eax
004011CA   .C9            leave
004011CB   .C2 1000       retn 0x10


终于找到我们要修改的字符串了,经过两次解密才出现的字符串,来我们开始想办法避开校验打补丁。
经过上面分析我们知道要在程序解密之后,然后CRC校验结束之后打补丁即可,正好利用原来00401083 >jmp 0040121E ; 跳到程序的oep,这条指令
这里改成JMP XXXXXX 空白区域修改完字符串再跳回OEP,有想法就开干~~~~


先找个空白区域,我经过搜索000发现00401280开始就是空白了。

首先在00401083 > E9 96010000 jmp unpackme.0040121E 改00401083   /E9 F8010000   jmp unpackme.00401280。
哎,不对,留意一下这个地址00401083,再看看上面的分析(004010C8 |> 8033 07 /xor byte ptr ds:,0x7 ; ebx=401007,用ebx异或7,解密(401007~401085)区域),正好在这个加密的区域。
所以我们的修改指令正常写下去是不行的,要加密让程序运行时解密出正确的指令,可以用 xor加密,经E9 F8010000 xor 7= EE FF060000,修改后00401083    EE            out dx,al                                       ; 跳到程序的oep
00401084    FF06            inc dword ptr ds:
00401086    0000            add byte ptr ds:,al

这个指令是未解密的,所以看不懂,解密后这个指令就会变成E9 F8010000   jmp 00401280,然后再到00401280把修改字符串的指令写上去就可以了:

00401280   .B9 0C000000   mov ecx,0x1b
00401285   .BE A8124000   mov esi,unpackme.004012A8
0040128A   .BF 23114000   mov edi,unpackme.00401123                         ;ASCII 0C,": u8 &!u%4!6"
0040128F   .F3:A4         rep movs byte ptr es:,byte ptr ds:      ;//修改提示框
00401291   .B9 09000000   mov ecx,0x15
00401296   .BE B4124000   mov esi,unpackme.004012B4
0040129B   .BF 0A114000   mov edi,unpackme.0040110A                         ;ASCII 0C,": u8 &!u ;%4"
004012A0   .F3:A4         rep movs byte ptr es:,byte ptr ds:      ;修改对话框
004012A2   .^ E9 77FFFFFF   jmp unpackme.0040121E                           ;跳回OEP
004012A7      90            nop
004012A8   .B8 C9B5F4CC   mov eax,0xCCF4B5C9                              ;用来替换提示框的字符串
004012AD   .^ E1 CA         loopde short unpackme.00401279
004012AF   .BE BFF20000   mov esi,0xF2BF
004012B4   .B5 BD         mov ch,0xBD                                       ;用来替换对话框的字符串
004012B6   .C1CB D5       ror ebx,0xD5
004012B9   .^ E2 C0         loopd short unpackme.0040127B
004012BB   .EF            out dx,eax
004012BC   .BE CDC4DCCE   mov esi,0xCEDCC4CD
004012C1   .AA            stos byte ptr es:
004012C2   .CB            retf
004012C3      F9            db F9
004012C4      D3            db D3
004012C5      FB            db FB
004012C6      CE            db CE
004012C7      AA            db AA



右键》保存》OK,过解密,过校验就是这么简单。。。。

之前我为什么说作者用心良苦,你会发现,会莫名其妙多个空白区域,然后刚好又是没加密的区域。~~~为了你们新手也是操碎了心。











我已经是非常照顾新手了!打遍文章不容易,技术含量不高也给点打字费吧,谢谢各位大爷!{:301_1007:}热心和CB不加就浪费啦,大爷们!请点击帖子下方的评分!{:301_977:}

对我来说发帖排版比分析程序还难啊!!{:301_972:}{:301_972:}{:301_972:}






dfgdf 发表于 2016-1-22 14:47

yAYa的表哥 发表于 2016-1-21 22:21
先说第一个错误呗,他是16进制,然而并不是154次了 对吧,另外的可以自己在酌量

好吧,知道了,谢谢

yAYa的表哥 发表于 2016-1-21 22:21

dfgdf 发表于 2016-1-21 20:42
0 0,什么小错误

先说第一个错误呗,他是16进制,然而并不是154次了 对吧,另外的可以自己在酌量

yAYa的表哥 发表于 2016-1-21 04:42

坐个好位置,不过有点小错误,不碍事,还是明了!!{:1_926:}

plmm20151111 发表于 2016-1-21 09:04

谢谢分享

夜航船 发表于 2016-1-21 09:19

谢谢楼主分享

lvhpxa 发表于 2016-1-21 09:42

谢谢楼主分享

1462326016 发表于 2016-1-21 10:40

感谢分享

不苦小和尚 发表于 2016-1-21 11:06

谢谢分享,不错不错{:1_937:}

逆转的华丽 发表于 2016-1-21 11:17

虽然还是不懂

soulovess 发表于 2016-1-21 11:51

也来学习一下。。

83571674 发表于 2016-1-21 13:20

感激分享
页: [1] 2 3
查看完整版本: 一个简单运行时解密+CRC校验的patchme分析