環境
Windows xp sp3
工具
exeinfope
ollydbg
查殼
用exeinfoe查殼
測試
可以從左下角狀態欄看出serial是無效的
直接OD載入字符串搜索
00401274 |. /75 17 jnz XChafe_1.0040128D
00401276 |. |6A 00 push 0x0 ; /Timerproc = NULL; Case 1 (WM_CREATE) of switch 0040123F
00401278 |. |6A 01 push 0x1 ; |Timeout = 1. ms
0040127A |. |68 CA0000>push 0xCA ; |TimerID = CA (202.)
0040127F |. |FF75 08 push [arg.1] ; |hWnd
00401282 |. |E8 A10200>call <jmp.&USER32.SetTimer> ; \SetTimer
00401287 |. |33C0 xor eax,eax
00401289 |. |C9 leave
0040128A |. |C2 1000 retn 0x10
0040128D |> \3D 130100>cmp eax,0x113
00401292 |. 75 50 jnz XChafe_1.004012E4
00401294 |. E8 BA0100>call Chafe_1.00401453 ; Case 113 (WM_TIMER) of switch 0040123F
00401299 |. 0FBE05 66>movsx eax,byte ptr ds:[0x403166]
004012A0 |. 3A05 6731>cmp al,byte ptr ds:[0x403167]
004012A6 |. 75 06 jnz XChafe_1.004012AE ; 這里不能相同
004012A8 |. 33C0 xor eax,eax
004012AA |. C9 leave
004012AB |. C2 1000 retn 0x10
004012AE |> A2 673140>mov byte ptr ds:[0x403167],al ; 可以看出[0x403167]的值要為0x10
004012B3 |. 83F8 10 cmp eax,0x10 ; 這里要相同
004012B6 |. 74 16 je XChafe_1.004012CE
004012B8 |. 68 653040>push Chafe_1.00403065 ; /Text = "Your serial is not valid."
004012BD |. FF35 7C31>push dword ptr ds:[0x40317C] ; |hWnd = NULL
004012C3 |. E8 660200>call <jmp.&USER32.SetWindowTextA> ; \SetWindowTextA
004012C8 |. 33C0 xor eax,eax
004012CA |. C9 leave
004012CB |. C2 1000 retn 0x10
004012CE |> 68 7F3040>push Chafe_1.0040307F ; /Text = "YES! You found your serial!!"
004012D3 |. FF35 7C31>push dword ptr ds:[0x40317C] ; |hWnd = NULL
004012D9 |. E8 500200>call <jmp.&USER32.SetWindowTextA> ; \SetWindowTextA
因為界面沒有點擊確認的按鈕,加上那個SetTimer函數,可以猜測是用程序自己檢測serial是否正確。
可以猜到[0x4012AE]里面的[0x403167]的值是根據serial是否正確才會為0x10
搜索程序,觀察哪里使得[0x403167]地址的內容發生改變
參考位于 Chafe_1:.text 到常量 403166
地址 反匯編 注釋
00401000 push 0x0 (初始 CPU 選擇)
00401093 add byte ptr ds:[0x403166],0x4 ds:[00403166]=00
004010A3 mov byte ptr ds:[0x403166],ah
00401299 movsx eax,byte ptr ds:[0x403166] ds:[00403166]=00
00401398 add byte ptr ds:[0x403166],0x4 ds:[00403166]=00
00401465 movsx eax,byte ptr ds:[0x403166] ds:[00403166]=00
00401493 add byte ptr ds:[0x403166],0x4 且字符串長度在10以內
004014AA add byte ptr ds:[0x403166],0x4 ds:[00403166]=00
004014B3 mov byte ptr ds:[0x403166],0x0 ds:[00403166]=00
可以猜出,只要實現4個add byte ptr ds:[0x403166],0x4 ,就可以使得[0x403167]的值為0x10
跟隨這4個add,查看相應的條件。
0040107B . B9 140000>mov ecx,0x14
00401080 . 2BC8 sub ecx,eax
00401082 . 8DB8 8C31>lea edi,dword ptr ds:[eax+0x40318C]
00401088 > C607 00 mov byte ptr ds:[edi],0x0
0040108B . 47 inc edi
0040108C . 49 dec ecx
0040108D .^ 75 F9 jnz XChafe_1.00401088
0040108F . 85C0 test eax,eax ; eax為輸入的name的長度
00401091 . 74 10 je XChafe_1.004010A3
00401093 . 8005 6631>add byte ptr ds:[0x403166],0x4
0040109A . C605 6831>mov byte ptr ds:[0x403168],0x0
004010A1 . EB 06 jmp XChafe_1.004010A9
不難看出,ecx為保存name的字符數組的長度,將沒有字符的部分用0填充。
所以這里的條件是只要輸入了name就能使得[0x403166]加0x4了
00401361 . 8D3D 8C31>lea edi,dword ptr ds:[0x40318C]
00401367 . 0FBE05 68>movsx eax,byte ptr ds:[0x403168]
0040136E . 03F8 add edi,eax
00401370 . FE05 6831>inc byte ptr ds:[0x403168]
00401376 . A1 883140>mov eax,dword ptr ds:[0x403188]
0040137B . 8B25 A031>mov esp,dword ptr ds:[0x4031A0]
00401381 . 40 inc eax
00401382 . FF05 8831>inc dword ptr ds:[0x403188]
00401388 . 3307 xor eax,dword ptr ds:[edi]
0040138A . A3 883140>mov dword ptr ds:[0x403188],eax
0040138F . 803D 6831>cmp byte ptr ds:[0x403168],0x10 ; 這里要使得[401368]為0x10
00401396 . 75 07 jnz XChafe_1.0040139F
00401398 . 8005 6631>add byte ptr ds:[0x403166],0x4
0040139F > C9 leave
這里可以看作是這個程序的算法核心,因為這里有一個循環,它是用來計算[0x403188]的值,具體的計算方法為:
設x0為[0x403188]的初值,有:
x1 = (x0 + 1) xor k
x2 = (x1 + 1) xor k
x3 = (x3 + 1) xor k
…
xn = (xn-1 + 1) xor k
這個xn就是在循環結束的時候[0x403188]的值。k的話是輸入的name,每次取name的4個字節,來進行異或,每次取完直接后,下一次取得4個字節會往后移動1個字節。
00401475 . 6A 00 push 0x0 ; /IsSigned = FALSE
00401477 . 8D45 FC lea eax,dword ptr ss:[ebp-0x4] ; |
0040147A . 50 push eax ; |pSuccess
0040147B . 6A 64 push 0x64 ; |ControlID = 64 (100.)
0040147D . FF35 7031>push dword ptr ds:[0x403170] ; |hWnd = 001402A8 ('TEXme v1.0',class='TEXcls')
00401483 . E8 640000>call <jmp.&USER32.GetDlgItemInt> ; \GetDlgItemInt
00401488 . A3 883140>mov dword ptr ds:[0x403188],eax
0040148D . 837D FC 0>cmp dword ptr ss:[ebp-0x4],0x0
00401491 . 74 07 je XChafe_1.0040149A ; 這里判斷輸入框是否有值,此時EAX為輸入的值得16進制,字符不計算在內
00401493 . 8005 6631>add byte ptr ds:[0x403166],0x4 ; 且字符串長度在10以內
0040149A > C9 leave
0040149B . C3 retn
這段代碼是將輸入的serial轉成數值,并且將這個值存儲到[0x403188],顯然這個就是剛剛的x0,也就是
[0x403188]的初值,這里的數值均為16進制。
0040149C . A1 883140>mov eax,dword ptr ds:[0x403188] ; 這里計算最后一步
004014A1 . 05 782411>add eax,0x9112478
004014A6 . 85C0 test eax,eax
004014A8 . 75 09 jnz XChafe_1.004014B3
004014AA . 8005 6631>add byte ptr ds:[0x403166],0x4
004014B1 . EB 07 jmp XChafe_1.004014BA
004014B3 > C605 6631>mov byte ptr ds:[0x403166],0x0
004014BA > 8B25 A031>mov esp,dword ptr ds:[0x4031A0]
004014C0 . C9 leave
004014C1 . C3 retn
這里是將循環過后計算得出的[0x403188]的值加上0x9112478,即[0x403188]+0x9112478
后面有個test,所以這里的計算結果為1 0000 0000,可以使得eax的值為0
所以程序的算法過程可以輕易的出了:
1.判斷是否輸入了name和serial,都有的話就加0x8
2.然后循環計算一個值,計算出來后加0x4
3.將計算出來的值再加上一個數,如果結果滿足條件的話就加0x4
4.如果上面的條件都滿足了,就會顯示正確的提示。
注冊機:
char c[20];unsigned int * p;unsigned int k = 0xF6EEDB88;memset(c,0,sizeof(c));scanf("%s",c);int len = strlen(c);k -= 0xf - len;for(int i=len-1;i>=0;i--){p = (unsigned int*)&c[i];k = (k-1)^*p;}printf("%u",k-1); //這里減1輸出是因為最后異或算出來的值為x0+1的值