0x00. 分析
入口
00401288 > [ DISCUZ_CODE_5 ]nbsp; 6A 00 push 0
0040128A E8 db E8
0040128B EF db EF
0040128C FF db FF
0040128D FF db FF
0040128E FF db FF
0040128F A3 db A3
00401290 30314000 dd ReverseM.00403130
00401294 . BF 11104000 mov edi, 00401011
00401299 . E8 71000000 call 0040130F
0040129E > E8 6EFDFFFF call
入口处指令需要去除分析,或者调试窗口-取消勾选自动对主模块进行分析。
00401288 > 6A 00 push 0
0040128A E8 EFFFFFFF call <jmp.&KERNEL32.GetModuleHandleA>
0040128F A3 30314000 mov dword ptr [403130], eax
00401294 BF 11104000 mov edi, 00401011
00401299 E8 71000000 call 0040130F
0040129E E8 6EFDFFFF call 00401011
004012A3 33C0 xor eax, eax
第1次解密
进入call 0040130F调用。
0040130F B8 00104000 mov eax, 00401000
00401314 8030 5A xor byte ptr [eax], 5A
00401317 40 inc eax
00401318 3D 18124000 cmp eax, <jmp.&USER32.BeginPaint>
0040131D ^ 7C F5 jl short 00401314
0040131F C3 retn
;信息面板
00401218=<jmp.&USER32.BeginPaint>
eax=00401002 (ReverseM.00401002)
这次调用是将0x00401000 ~ 0x00401218处的数据与0x5A异或。
第2次解密
进入call 00401011调用。
00401011 33C0 xor eax, eax ; ReverseM.00401218
00401013 66:C707 6A00 mov word ptr [edi], 6A
00401018 83C7 02 add edi, 2
0040101B C707 687D3040 mov dword ptr [edi], 40307D68
00401021 83C7 04 add edi, 4
00401024 C607 00 mov byte ptr [edi], 0
00401027 47 inc edi
00401028 C707 68343040 mov dword ptr [edi], 40303468
0040102E 83C7 04 add edi, 4
00401031 C607 00 mov byte ptr [edi], 0
00401034 47 inc edi
00401035 66:C707 6A00 mov word ptr [edi], 6A
0040103A 83C7 02 add edi, 2
0040103D C707 E8300200 mov dword ptr [edi], 230E8
00401043 83C7 04 add edi, 4
00401046 C607 00 mov byte ptr [edi], 0
00401049 47 inc edi
0040104A 66:C707 EB44 mov word ptr [edi], 44EB ; 0x15 bytes at all
0040104F 83EF 24 sub edi, 24
00401052 FFD7 call edi
00401054 E8 C7020000 call 00401320
00401059 E8 64020000 call 004012C2
0040105E EB 15 jmp short 00401075
在第一次解密之前的入口部分,就有mov edi, 00401011,所以,第二次调用是将0x00401011 ~ 0x0x00401025部分解密,与第一次异或不同,这一次是纯替换。 而且,这部分代码其实是自己本身。
下面是解密后内容指令。可以看到弹窗的标题和文本参数为乱码,这一部分后面应该还会解密。
00401011 nbsp; 6A 00 push 0 ; /Style = MB_OK|MB_APPLMODAL
00401013 . 68 7D304000 push 0040307D ; |Title = 乱码
00401018 . 68 34304000 push 00403034 ; |Text = 乱码
0040101D . 6A 00 push 0 ; |hOwner = NULL
0040101F . E8 30020000 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
00401024 . /EB 44 jmp short 0040106A
00401026 |00 db 00
00401027 . |47 inc edi
00401028 . |C707 68343040 mov dword ptr [edi], 40303468
0040102E . |83C7 04 add edi, 4
00401031 . |C607 00 mov byte ptr [edi], 0
00401034 . |47 inc edi
00401035 . |66:C707 6A00 mov word ptr [edi], 6A
0040103A . |83C7 02 add edi, 2
0040103D . |C707 E8300200 mov dword ptr [edi], 230E8
00401043 . |83C7 04 add edi, 4
00401046 . |C607 00 mov byte ptr [edi], 0
00401049 . |47 inc edi
0040104A . |66:C707 EB44 mov word ptr [edi], 44EB
0040104F . |83EF 24 sub edi, 24
00401052 . |FFD7 call edi
00401054 . |E8 C7020000 call 00401320
00401059 . |E8 64020000 call 004012C2
0040105E . |EB 15 jmp short 00401075
进入0x00401052处的call edi调用,是第一次解密得到的指令。此时edi减去0x24后为0x00401000,
第3次解密
00401000 > /B8 00304000 mov eax, 00403000
00401005 > |8030 B3 xor byte ptr [eax], 0B3
00401008 . |40 inc eax
00401009 . |3D 28314000 cmp eax, 00403128
0040100E .^|7C F5 jl short 00401005
00401010 . |40 inc eax
00401011 nbsp; 6A 00 push 0 ; /Style = MB_OK|MB_APPLMODAL
00401013 . 68 7D304000 push 0040307D ; |Title = 乱码
00401018 . 68 34304000 push 00403034 ; |Text = 乱码
0040101D . 6A 00 push 0 ; |hOwner = NULL
0040101F . E8 30020000 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
00401024 . |EB 44 jmp short 0040106A
这一次是解密0x00403000 ~ 0x00403127的数据,而MessageBoxA()的标题和文本参数就在这一范围内。
这一过程可以在数据窗口中观察。
00403000 E1 D6 C5 D6 C1 C0 D6 FE D6 E7 C6 C7 DC C1 DA D2 嶂胖晾筑昼魄芰谝
00403010 DF B3 E1 D6 C5 D6 C1 C0 D6 FE D6 E7 C6 C7 DC C1 叱嶂胖晾筑昼魄芰
00403020 DA D2 DF 89 93 E1 D6 DE DC C5 D6 93 C7 DB D6 93 谝邏撫洲芘謸芹謸
00403030 DD D2 D4 B3 EA DC C6 93 DD D6 D6 D7 93 C7 DC 93 菀猿贶茡葜肿撉軗
00403040 C1 D6 DE DC C5 D6 93 C7 DB D6 93 DD D2 D4 BE B9 林捃胖撉壑撦以竟
00403050 E7 C1 CA 93 C7 DC 93 D7 DC 93 DA C7 93 DA DD 93 缌蕮擒撟軗谇撢輷
解密后:
00403000 52 65 76 65 72 73 65 4D 65 54 75 74 6F 72 69 61 ReverseMeTutoria
00403010 6C 00 52 65 76 65 72 73 65 4D 65 54 75 74 6F 72 l.ReverseMeTutor
00403020 69 61 6C 3A 20 52 65 6D 6F 76 65 20 74 68 65 20 ial: Remove the
00403030 6E 61 67 00 59 6F 75 20 6E 65 65 64 20 74 6F 20 nag.You need to
00403040 72 65 6D 6F 76 65 20 74 68 65 20 6E 61 67 0D 0A remove the nag..
00403050 54 72 79 20 74 6F 20 64 6F 20 69 74 20 69 6E 20 Try to do it in
00401010 . 40 inc eax ; ReverseM.00403128
00401011 nbsp; 6A 00 push 0 ; /Style = MB_OK|MB_APPLMODAL
00401013 . 68 7D304000 push 0040307D ; |Title = "TutorialNag"
00401018 . 68 34304000 push 00403034 ; |Text = "You need to remove the nag",CR,LF,"Try to do it in a two byte patch. ",CR,LF,"Regards!"
0040101D . 6A 00 push 0 ; |hOwner = NULL
0040101F . E8 30020000 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
00401024 . EB 44 jmp short 0040106A
往下执行,就可以弹出第一个NAG窗口了。
第1次加密
`0x00401024`处`jmp short 0040106A`后,`edi`值仍为`0x00401000`,指令如下:
0040106A > 83C7 11 add edi, 11
0040106D . 66:C707 6A0A mov word ptr [edi], 0A6A
00401072 . 83C7 02 add edi, 2
00401075 > C707 FF353431 mov dword ptr [edi], 313435FF
0040107B . 83C7 04 add edi, 4
0040107E . 66:C707 4000 mov word ptr [edi], 40
00401083 . 83C7 02 add edi, 2
00401086 . 66:C707 6A00 mov word ptr [edi], 6A
0040108B . 83C7 02 add edi, 2
0040108E . C707 FF353031 mov dword ptr [edi], 313035FF
00401094 . 83C7 04 add edi, 4
00401097 . 66:C707 4000 mov word ptr [edi], 40
0040109C . 83C7 02 add edi, 2
0040109F . C707 E8900000 mov dword ptr [edi], 90E8
004010A5 . 83C7 04 add edi, 4
004010A8 . C607 00 mov byte ptr [edi], 0
004010AB . 47 inc edi
004010AC . 66:C707 EB2C mov word ptr [edi], 2CEB ;0x17 bytes at all
004010B1 . 83EF 15 sub edi, 15
004010B4 . FFD7 call edi
这一部分是将`0x00401011 ~ 0x00401027`的指令加密。
最后`call edi`时,减去`0x15`,`edi`的值又变回`0x00401011`。
00401011 nbsp; 6A 0A push 0A
00401013 . FF35 34314000 push dword ptr [403134]
00401019 . 6A 00 push 0
0040101B . FF35 30314000 push dword ptr [403130] ; ReverseM.00400000
00401021 . E8 90000000 call 004010B6
00401026 . EB 2C jmp short 00401054
执行后,弹出了第2个NAG窗口,然后跳到`0x00401054`。
第2次加密
00401054 > E8 C7020000 call 00401320
00401059 . E8 64020000 call 004012C2
0040105E . EB 15 jmp short 00401075
上面的指令是第1,2次解密得到的。
00401320 /nbsp; B8 00304000 mov eax, 00403000 ; ASCII "ReverseMeTutorial"
00401325 |> 8030 8D /xor byte ptr [eax], 8D
00401328 |. 40 |inc eax
00401329 |. 3D 28314000 |cmp eax, 00403128
0040132E |.^ 7C F5 \jl short 00401325
00401330 \. C3 retn
加密`0x00403000 ~ 0x00403127`的数据,注意我们第2次解密的时候是与`0xB3`异或。
退出
上一次加密后返回,调用`0x004012c2`。
004012C2 /nbsp; 50 push eax ; /ExitCode = 403128
004012C3 \. E8 B0FFFFFF call <jmp.&KERNEL32.ExitProcess> ; \ExitProcess
整体流程
1. 0040130F:解密`0x00401000 ~ 0x00401218`(XOR 0x5A)
2. 00401011 :解密`0x00401011 ~ 0x0x00401025`
3. 00401000:解密`0x00403000 ~ 0x00403127`(含窗口标题和文本)
4. 0040106A:加密`0x00401011 ~ 0x00401027`
5. 00401320:加密`0x00403000 ~ 0x00403127`
0x01. 打补丁
我们的目的是把第一个NAG去掉,即由第2次解密得到、第3次解密之后马上执行的`0x0040101F`处的`call`指令。
第1种方法
一个方法是使`MessageBoxA()`的第一个参数`hOwner`即父句柄无效:`6A 00 | push 0x0`改为`6A 0A | push 0x1`。
这句参数入栈的指令是由第2次解密时的这一句得到的。
00401035 66:C707 6A00 mov word ptr [edi], 6A
直接改为mov word ptr [edi], 0x016A是行不通滴,因为66:C707 6A00这一句指令又是由第一次解密时与`0x5A`异或得到哒 (- 。-)! 我们需要算一下与`0x5A`异或后得到`0x01`的字节。
`0x01 ^ 0x5A == 0x5B`,那么在运行前改把00401039的`0x5A`为`5B`就行了。
00401034 1D 3C9D5D30 sbb eax, 305D9D3C
00401039 5B pop ebx
保存后执行,成功地直接显示第二个NAG窗口。
第2种方法
在弹窗之前,直接执行下面的跳转。
00401011 6A 00 push 0
00401013 |68 7D304000 push 0040307D ; ASCII "TutorialNag"
00401018 |68 34304000 push 00403034 ; ASCII "You need to remove the nag",CR,LF,"Try to do it in a two byte patch. ",CR,LF,"Regards!"
0040101D |6A 00 push 0
0040101F |E8 30020000 call <jmp.&USER32.MessageBoxA>
修改后:00401011 EB 57 jmp short 0040106A
EB 57 XOR 5A == B1 0D ,所以回到找到第2次解密中对应的指令。
00401013 66:C707 6A00 mov word ptr [edi], 6A
00401018 83C7 02 add edi, 2
回到运行前的`00401016`。
00401016 305A D9 xor byte ptr [edx-27], bl
这里验证一下,30 5A XOR 5A == 6a 00,那么动手:
00000416 B1 0D mov cl, 0D
保存到执行文件,备份,成功去除第一个NAG。
|