一个简单运行时解密+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:}
yAYa的表哥 发表于 2016-1-21 22:21
先说第一个错误呗,他是16进制,然而并不是154次了 对吧,另外的可以自己在酌量
好吧,知道了,谢谢 dfgdf 发表于 2016-1-21 20:42
0 0,什么小错误
先说第一个错误呗,他是16进制,然而并不是154次了 对吧,另外的可以自己在酌量 坐个好位置,不过有点小错误,不碍事,还是明了!!{:1_926:} 谢谢分享 谢谢楼主分享 谢谢楼主分享 感谢分享 谢谢分享,不错不错{:1_937:} 虽然还是不懂 也来学习一下。。 感激分享