|
发表于 2020-5-4 10:06:52
|
查看: 7708 |
回复: 2
今天朋友给我发了patchme,他很多地方不懂,叫我帮他分析。
我分析完发现这个作者真是用心良苦,专为新手练习特意写的。分析完 觉得有点意思,就发出来给大家分享一下。
一个简单运行时解密+CRC校验的patchme分析
一个简单运行时解密+CRC校验的patchme分析
打开程序,很简单, 一个提示框,一个对话框,作者要求就是修改这两个字符串。
一个简单运行时解密+CRC校验的patchme分析
OD载入,ep代码很简单整洁,这是汇编写的吧(我猜)。
一个简单运行时解密+CRC校验的patchme分析
国际惯例,搜索字符串,没找到提示框和对话框的字符串,早做好心理准备肯定是搜不到的了。
既然这样我们就一句句代码来分析吧。。。。。。。
我们看到上面ep代码,就一个call,肯定进去,F8再F7进去代码如下。。。。。
[Asm] 纯文本查看 复制代码
[pre]004010E9 /$ B8 F5104000 mov eax,unpackme.004010F5
004010EE |. 50 push eax
004010EF |. E8 A7FFFFFF call unpackme.0040109B
004010F4 \. C3 retn
[/pre]
这。。。。。压入004010F5作为参数继续Call。。。。我们还是F8 F8 F7进去call unpackme.0040109B,代码如下。。。。
[Asm] 纯文本查看 复制代码
[pre]0040109B /$ 50 push eax ; unpackme.004010F5
0040109C |. 8BD8 mov ebx,eax
0040109E |. B9 54010000 mov ecx,0x154
004010A3 |> 8033 44 /xor byte ptr ds:[ebx],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
[/pre]
代码真是非常简洁明了,一个循环两个call。。。我们先看这个循环是什么鬼。。。
[Asm] 纯文本查看 复制代码
[pre]0040109B /$ 50 push eax ; F8往下走
0040109C |. 8BD8 mov ebx,eax
0040109E |. B9 54010000 mov ecx,0x154 ; 循环次数,154
004010A3 |> 8033 44 /xor byte ptr ds:[ebx],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
[/pre]
我发现我写得好像过于详细。。。。。
知道循环是什么鬼之后就在 004010AF|.50 push eax 下段点然后F9跑过循环。
然后进入004010B0|.E8 08000000 call unpackme.004010BD
看看又是什么鬼。。。。。。
代码如下
[Asm] 纯文本查看 复制代码
[pre]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:[ebx],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:[ebx],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 ; 解密完就返回
[/pre]
这个CALL就是分别解密(401007~401085和4010f5~401248)两个区域,弄懂走下一个call :004010B6|.E8 7EFFFFFF call unpackme.00401039
哎呀,这个call的地址留意一下, call 00401039;之前分析的”用ebx异或7,解密(401007~401085)区域“,正好在上面xor 7解密的那个区域。
进去代码如下
[Asm] 纯文本查看 复制代码
[pre]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] ; 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
[/pre]
这是最简单的CRC校验了,我们继续来看OEP的代码情况,如下:
[Asm] 纯文本查看 复制代码
[pre]0040121E 6A 00 push 0x0
00401220 E8 55000000 call <jmp.&kernel32.GetModuleHandleA> ; GetModuleHandleA 是取DLL的运行句柄的,在创建窗口时候用这个能给窗口赋值正确的句柄和运行id
00401225 A3 18304000 mov dword ptr ds:[0x403018],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:[0x403018]
0040123E E8 0D000000 call <jmp.&user32.DialogBoxParamA> ; DialogBoxParam函数根据对话框模板资源创建一个模态的对话框
00401243 50 push eax
00401244 E8 2B000000 call <jmp.&kernel32.ExitProcess> ; 退出
[/pre]
代码整洁的不习惯。。。程序流程很明了,提示对话框然后退出, 看看函数DialogBoxParam第四个参数是IpDialogFunc:指向对话框过程的指针。有关更详细的关于对话框过程的信息,请参见DialogProc。
我们要分析参数是0040122C push 004010F5 ; 显示对话框的过程,所以进入004010F5 细看整个流程。没错就是那个加密两次还要crc校验的重要区域,代码如下:
[Asm] 纯文本查看 复制代码
[pre]004010F5 . 55 push ebp
004010F6 . 8BEC mov ebp,esp
004010F8 . 83C4 C0 add esp,-0x40
004010FB . 817D 0C 10010>cmp dword ptr ss:[ebp+0xC],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:[ebp+0x8] ; |hWnd
00401171 . E8 F2000000 call <jmp.&user32.SendMessageA> ; \SendMessageA
00401176 . 68 C8000000 push 0xC8 ; /RsrcName = 200.
0040117B . FF35 18304000 push dword ptr ds:[0x403018] ; |hInst = NULL
00401181 . E8 D6000000 call <jmp.&user32.LoadIconA> ; \LoadIconA
00401186 . A3 20304000 mov dword ptr ds:[0x403020],eax
0040118B . FF35 20304000 push dword ptr ds:[0x403020] ; /lParam = 0x0
00401191 . 6A 01 push 0x1 ; |wParam = 0x1
00401193 . 68 80000000 push 0x80 ; |Message = WM_SETICON
00401198 . FF75 08 push dword ptr ss:[ebp+0x8] ; |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:[ebp+0x8] ; |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:[ebp+0x8] ; |hOwner
004011C3 . E8 9A000000 call <jmp.&user32.MessageBoxA> ; \MessageBoxA
004011C8 . 33C0 xor eax,eax
004011CA . C9 leave
004011CB . C2 1000 retn 0x10
[/pre]
终于找到我们要修改的字符串了,经过两次解密才出现的字符串,来我们开始想办法避开校验打补丁。
经过上面分析我们知道要在程序解密之后,然后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:[ebx],0x7 ; ebx=401007,用ebx异或7,解密(401007~401085)区域),正好在这个加密的区域。
所以我们的修改指令正常写下去是不行的,要加密让程序运行时解密出正确的指令,可以用 xor加密,经E9 F8010000 xor 7= EE FF060000,修改后[Asm] 纯文本查看 复制代码
[pre]00401083 EE out dx,al ; 跳到程序的oep
00401084 FF06 inc dword ptr ds:[esi]
00401086 0000 add byte ptr ds:[eax],al
[/pre]
这个指令是未解密的,所以看不懂,解密后这个指令就会变成E9 F8010000 jmp 00401280,然后再到00401280把修改字符串的指令写上去就可以了:
[Asm] 纯文本查看 复制代码
[pre]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:[edi],byte ptr ds:[esi] ; //修改提示框
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:[edi],byte ptr ds:[esi] ; 修改对话框
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:[edi]
004012C2 . CB retf
004012C3 F9 db F9
004012C4 D3 db D3
004012C5 FB db FB
004012C6 CE db CE
004012C7 AA db AA
[/pre]
右键》保存》OK,过解密,过校验就是这么简单。。。。
之前我为什么说作者用心良苦,你会发现,会莫名其妙多个空白区域,然后刚好又是没加密的区域。~~~为了你们新手也是操碎了心。
|
温馨提示:
1.如果您喜欢这篇帖子,请给作者点赞评分,点赞会增加帖子的热度,评分会给作者加学币。(评分不会扣掉您的积分,系统每天都会重置您的评分额度)。
2.回复帖子不仅是对作者的认可,还可以获得学币奖励,请尊重他人的劳动成果,拒绝做伸手党!
3.发广告、灌水回复等违规行为一经发现直接禁言,如果本帖内容涉嫌违规,请点击论坛底部的举报反馈按钮,也可以在【 投诉建议】板块发帖举报。
|