这两个题目中规中矩,只要分析好作者的意图即可。
023:
首先,点击About,作者不让爆破,即让分析keygen。
pe装载发现是纯汇编,666。
od载入调试,我们跟到关键处:
004012AE |> \A2 67314000 mov byte ptr ds:[0x403167],al
004012B3 |. 83F8 10 cmp eax,0x10
004012B6 |. 74 16 je short Chafe_1.004012CE
004012B8 |. 68 65304000 push Chafe_1.00403065 ; /Text = "Your serial is not valid."
004012BD |. FF35 7C314000 push dword ptr ds:[0x40317C] ; |hWnd = 00031230 ('Your serial is not valid.',class='Edit',parent=00071162)
004012C3 |. E8 66020000 call <jmp.&USER32.SetWindowTextA> ; \SetWindowTextA
004012C8 |. 33C0 xor eax,eax
004012CA |. C9 leave
004012CB |. C2 1000 retn 0x10
004012CE |> 68 7F304000 push Chafe_1.0040307F ; /Text = "YES! You found your serial!!"
004012D3 |. FF35 7C314000 push dword ptr ds:[0x40317C] ; |hWnd = 00031230 ('Your serial is not valid.',class='Edit',parent=00071162)
004012D9 |. E8 50020000 call <jmp.&USER32.SetWindowTextA> ; \SetWindowTextA
004012DE |. 33C0 xor eax,eax
004012E0 |. C9 leave
004012E1 |. C2 1000 retn 0x10
我们分析代码之后,发现这是一个教科书的windows窗口过程。但这与我们破解无关,通过Yes! You found your serial 之后我们可以跟到判断的关键处。
00401294 |. E8 BA010000 call Chafe_1.00401453 ; Case 113 (WM_TIMER) of switch 0040123F
00401299 |. 0FBE05 663140>movsx eax,byte ptr ds:[0x403166]
004012A0 |. 3A05 67314000 cmp al,byte ptr ds:[0x403167]
004012A6 |. 75 06 jnz short Chafe_1.004012AE
004012A8 |. 33C0 xor eax,eax
004012AA |. C9 leave
004012AB |. C2 1000 retn 0x10
004012AE |> A2 67314000 mov byte ptr ds:[0x403167],al
004012B3 |. 83F8 10 cmp eax,0x10
004012B6 |. 74 16 je short Chafe_1.004012CE
比较byte ptr ds:[0x403166]是否等于0x10,我们去跟踪一下有多少地方对这个地址进行了操作。
正好发现有四个add * 0x04,这不告诉我们只要满足这四个条件就可以了么。
第一个:
0040146F . 8B25 A0314000 mov esp,dword ptr ds:[0x4031A0]
00401475 . 6A 00 push 0x0 ; /IsSigned = FALSE
00401477 . 8D45 FC lea eax,dword ptr ss:[ebp-0x4] ; |
0040147A . 50 push eax ; |pSuccess = 0000000C
0040147B . 6A 64 push 0x64 ; |ControlID = 64 (100.)
0040147D . FF35 70314000 push dword ptr ds:[0x403170] ; |hWnd = 00071162 ('TEXme v1.0',class='TEXcls')
00401483 . E8 64000000 call <jmp.&USER32.GetDlgItemInt> ; \GetDlgItemInt
00401488 . A3 88314000 mov dword ptr ds:[0x403188],eax
0040148D . 837D FC 00 cmp dword ptr ss:[ebp-0x4],0x0
00401491 . 74 07 je short Chafe_1.0040149A
00401493 . 8005 66314000>add byte ptr ds:[0x403166],0x4
0040149A > C9 leave
0040149B . C3 retn
0040149C . A1 88314000 mov eax,dword ptr ds:[0x403188]
004014A1 . 05 78241109 add eax,0x9112478
004014A6 . 85C0 test eax,eax
004014A8 . 75 09 jnz short Chafe_1.004014B3
004014AA . 8005 66314000>add byte ptr ds:[0x403166],0x4
004014B1 . EB 07 jmp short Chafe_1.004014BA
004014B3 > C605 66314000>mov byte ptr ds:[0x403166],0x0
004014BA > 8B25 A0314000 mov esp,dword ptr ds:[0x4031A0]
004014C0 . C9 leave
004014C1 . C3 retn
GetDlgItemInt,说明需要满足我们输入的serial为纯数字,那么一定会+4的,
第二个+4来自于GetWindowText,也是一定会+4,
第三个+4来自于下面的代码:
00401361 . 8D3D 8C314000 lea edi,dword ptr ds:[0x40318C]
00401367 . 0FBE05 683140>movsx eax,byte ptr ds:[0x403168]
0040136E . 03F8 add edi,eax
00401370 . FE05 68314000 inc byte ptr ds:[0x403168]
00401376 . A1 88314000 mov eax,dword ptr ds:[0x403188]
0040137B . 8B25 A0314000 mov esp,dword ptr ds:[0x4031A0]
00401381 . 40 inc eax
00401382 . FF05 88314000 inc dword ptr ds:[0x403188]
00401388 . 3307 xor eax,dword ptr ds:[edi]
0040138A . A3 88314000 mov dword ptr ds:[0x403188],eax
0040138F . 803D 68314000>cmp byte ptr ds:[0x403168],0x10
00401396 . 75 07 jnz short Chafe_1.0040139F
00401398 . 8005 66314000>add byte ptr ds:[0x403166],0x4
0040139F > C9 leave
004013A0 . C3 retn
发现这里一定会循环17次,然后+4,所以通过这三部分一定会+12,所以最后那个+4才是关键的点,这里明显是个算法,认真分析,代码如下:
from ctypes import *
name = "1234"
namevalue = ((ord(name[3])<< 24) + (ord(name[2])<<16) +(ord(name[1])<<8) + (ord(name[0])<<0))
serial = 1111
for i in range(0,16):
serial += 1
serial = (serial) ^ namevalue
namevalue = c_uint(namevalue >> 8).value
print hex(serial)
#f6eedb88
那么分析第四个+4代码如下:
0040149C . A1 88314000 mov eax,dword ptr ds:[0x403188]
004014A1 . 05 78241109 add eax,0x9112478
004014A6 . 85C0 test eax,eax
004014A8 . 75 09 jnz short Chafe_1.004014B3
004014AA . 8005 66314000>add byte ptr ds:[0x403166],0x4
004014B1 . EB 07 jmp short Chafe_1.004014BA
004014B3 > C605 66314000>mov byte ptr ds:[0x403166],0x0
004014BA > 8B25 A0314000 mov esp,dword ptr ds:[0x4031A0]
004014C0 . C9 leave
看出,之前算出的结果和0x9112478相加得到0就能通过了。
那么我们逆思路回去,输入name为1,1比较好算啦,,,,不再写keygen了,得出serial结果为4142848839,输入之后通过。
024
这个题目还是比较有趣的,通过改变text段的代码,然后进行跳转成功页面:
分析如下:
我们看到代码片段如下:
004012D9 54 push esp
004012DA 45 inc ebp
004012DB 58 pop eax ; kernel32.76D38744
004012DC 00 db 00
这段代码通过上面的一条语句004012C4 . 66:2905 D9124>sub word ptr ds:[0x4012D9],ax
进行修改。
我们在往下看到如下语句:
004012D0 . B9 3E000000 mov ecx,0x3E
...
004012DD > AD lods dword ptr ds:[esi]
004012DE . |33D8 xor ebx,eax
004012E0 . |49 dec ecx ; Chafe_2.<ModuleEntryPoint>
004012E1 .^\75 FA jnz short Chafe_2.004012DD
004012E3 . 81FB FBCFFCAF cmp ebx,0xAFFCCFFB
从dword ptr ds:[esi]处进行0x3e异或循环,如果等于0xaffccffb,那么进行跳转
这些异或数据中,其他的都是固定的,只有上述的四个字节可控,所以我们控制这四个字节的值就能达到跳转的效果。
异或这个运算还是比较有趣的,分析一下:
如果有a^b^c^d=e
那么a=b^c^d^e
b=a^c^d^e…具有叫什么性质,,,额,可交换性,姑且这么讲吧。
所以我们很容易去得到这四个字节的值,因为写博客和分析的时间间隔比较久远,具体是啥也不太清楚了,但是一定会有个je 跳转的指令之类将其跳转到成功的弹窗代码处。完成程序的注册。