匯編入門你應該知道的知識
160個CrackMe-001 首先運行程序,發現程序是個注冊機,輸入用戶名與注冊碼。
點擊Check it Baby!會檢測注冊碼是否正確,并且多次嘗試發現提示語句相同
拉進OD進行分析,當彈出提示時不著急點確定,回到OD點擊暫停運行按鈕
點擊堆棧(crlt+k)或者小圖標K
找到地址為0042a1ae的MessageBoxA的函數,該函數為win32的彈窗函數,并且距離用戶代碼的入口點00401000非常接近
右鍵->顯示函數調用過程,觀察那個函數調用了此函數,找到相關函數,可以發現這是MessageBox調用的過程,那么在堆棧區找到返回函數,觀察該函數執行完會返回到哪個函數
打下斷點,運行到此處,在右下角的堆棧窗口查看返回地址,在堆棧窗口中右鍵->地址->相對于EBP,找到EBP+4的地址,對應的地址為返回地址,右鍵該地址,反匯編窗口跟隨
找到關鍵的跳轉,該跳轉會執行錯誤彈框信息。

方法一:暴力破解
由于該跳轉是用JNZ實現的,那么將跳轉改為JE或者NOP掉改變程序的執行流程
(1)修改為JE,右鍵關鍵跳轉語句->選擇匯編
此時成功信息彈出
(2)用NOP填充,由于在關鍵的跳轉語句下有個調用彈框函數,因此猜測該函數為成功的執行流。 右鍵關鍵跳轉,選擇NOP填充
同樣彈出成功消息

方法二:注冊機算法
發現在關鍵跳轉前有個call調用,打下斷點觀察下寄存器的值
在執行到該調用語句時,觀察右上角的寄存器窗口,發現了疑似注冊碼的值,以及我們手動輸入的注冊碼,兩者進行比較若不相同則直接跳轉到錯誤彈窗。
將疑似注冊碼輸入,發現成功彈窗,因此驗證了這個就是注冊碼的值,那么在call語句實現之前則注冊碼已經生成

0042FAF3的調用沒有什么特殊的,跟進去0042FAE5的調用
(0042FAE5調用)匯編代碼 此時可以看到,
在進入0042FAE5調用之前,激活碼已經生成完畢,在該函數調用只是進行了字符串的替換,將我們輸入的name值分部分替換為激活碼。
004039AC $ 53 PUSH EBX
004039AD . 56 PUSH ESI
004039AE . 52 PUSH EDX
004039AF . 50 PUSH EAX
004039B0 . 89D3 MOV EBX,EDX
004039B2 . 31C0 XOR EAX,EAX
004039B4 > 8B4C94 10 MOV ECX,DWORD PTR SS:[ESP+EDX*4+0x10] ; 讀取注冊碼各部分的字符串
004039B8 . 85C9 TEST ECX,ECX
004039BA . 74 03 JE SHORT Acid_bur.004039BF
004039BC . 0341 FC ADD EAX,DWORD PTR DS:[ECX-0x4]
004039BF > 4A DEC EDX 004039C0 .^75 F2 JNZ SHORT Acid_bur.004039B4
004039C2 . E8 69FDFFFF CALL Acid_bur.00403730 ; 獲取name值
004039C7 . 50 PUSH EAX ; 將name壓入棧中
004039C8 . 89C6 MOV ESI,EAX 004039CA > 8B449C 14 MOV EAX,DWORD PTR SS:[ESP+EBX*4+0x14] ; Acid_bur.0042FBC8
004039CE . 89F2 MOV EDX,ESI
004039D0 . 85C0 TEST EAX,EAX
004039D2 . 74 0A JE SHORT Acid_bur.004039DE
004039D4 . 8B48 FC MOV ECX,DWORD PTR DS:[EAX-0x4]
004039D7 . 01CE ADD ESI,ECX ; 計算當前部分激活碼的長度
004039D9 . E8 66EDFFFF CALL Acid_bur.00402744 ; 將部分name值替換為激活碼
004039DE > 4B DEC EBX 004039DF .^75 E9 JNZ SHORT Acid_bur.004039CA
004039E1 . 5A POP EDX
004039E2 . 58 POP EAX
004039E3 . 85D2 TEST EDX,EDX
004039E5 . 74 03 JE SHORT Acid_bur.004039EA
004039E7 . FF4A F8 DEC DWORD PTR DS:[EDX-0x8]
004039EA > E8 D5FCFFFF CALL Acid_bur.004036**
004039EF . 5A POP EDX
004039F0 . 5E POP ESI
004039F1 . 5B POP EBX
004039F2 . 58 POP EAX
004039F3 . 8D2494 LEA ESP,DWORD PTR SS:[ESP+EDX*4]
004039F6 . FFE0 JMP EAX 004039F8 . C3 RETN 將斷點斷在函數的起始部分,單步跟蹤查看

匯編代碼部分
可以看到,程序會先計算name的長度,若長度小于4則直接彈出錯誤信息窗口。
程序會取出我們輸入的name的第一個字節,這里簡稱為name[0]
將name[0]的值乘以0x29再乘以0x2即為部分注冊碼的值,例如我們輸入的name為123456789,name[0]=1,這個1為字符串1,它的ASCII碼值為0x31,則0x31*0x29*0x2 = 4018,通過剛剛的寄存器窗口可以看到我們的注冊碼為CW-4018-CRACKED,即中間數字部分的注冊碼已經求出
0042FA1E |. E8 35B0FEFF CALL Acid_bur.0041AA58 ; 用于計算name的長度
0042FA23 |. 8B45 F0 MOV EAX,DWORD PTR SS:[EBP-0x10]
0042FA26 |. 0FB640 03 MOVZX EAX,BYTE PTR DS:[EAX+0x3]
0042FA2A |. 6BF0 0B IMUL ESI,EAX,0xB
0042FA2D |. 8D55 EC LEA EDX,DWORD PTR SS:[EBP-0x14]
0042FA30 |. 8B83 DC010000 MOV EAX,DWORD PTR DS:[EBX+0x1DC]
0042FA36 |. E8 1DB0FEFF CALL Acid_bur.0041AA58
0042FA3B |. 8B45 EC MOV EAX,DWORD PTR SS:[EBP-0x14]
0042FA3E |. 0FB640 02 MOVZX EAX,BYTE PTR DS:[EAX+0x2]
0042FA42 |. 6BC0 0E IMUL EAX,EAX,0xE
0042FA45 |. 03F0 ADD ESI,EAX
0042FA47 |. 8935 58174300 MOV DWORD PTR DS:[0x431758],ESI
0042FA4D |. A1 6C174300 MOV EAX,DWORD PTR DS:[0x43176C]
0042FA52 |. E8 D96EFDFF CALL Acid_bur.00406930
0042FA57 |. 83F8 04 CMP EAX,0x4 ; 判斷name長度是否大于4
0042FA5A |. 7D 1D JGE SHORT Acid_bur.0042FA79
0042FA5C |. 6A 00 PUSH 0x0
0042FA5E |. B9 74FB4200 MOV ECX,Acid_bur.0042FB74 ; ASCII 54,"ry Again!"
0042FA63 |. BA 80FB4200 MOV EDX,Acid_bur.0042FB80 ; ASCII 53,"orry , The serial is incorect !"
0042FA68 |. A1 480A4300 MOV EAX,DWORD PTR DS:[0x430A48]
0042FA6D |. 8B00 MOV EAX,DWORD PTR DS:[EAX]
0042FA6F |. E8 FCA6FFFF CALL Acid_bur.0042A170
0042FA74 |. E9 BE000000 JMP Acid_bur.0042FB37
0042FA79 |> 8D55 F0 LEA EDX,DWORD PTR SS:[EBP-0x10] ; EBP-0x10存儲著name值,并賦值給EDX
0042FA7C |. 8B83 DC010000 MOV EAX,DWORD PTR DS:[EBX+0x1DC]
0042FA82 |. E8 D1AFFEFF CALL Acid_bur.0041AA58
0042FA87 |. 8B45 F0 MOV EAX,DWORD PTR SS:[EBP-0x10]
0042FA8A |. 0FB600 MOVZX EAX,BYTE PTR DS:[EAX] ; 取第一個字節到EAX中
0042FA8D |. F72D 50174300 IMUL DWORD PTR DS:[0x431750] ; 乘以0x29
0042FA93 |. A3 50174300 MOV DWORD PTR DS:[0x431750],EAX
0042FA98 |. A1 50174300 MOV EAX,DWORD PTR DS:[0x431750]
0042FA9D |. 0105 50174300 ADD DWORD PTR DS:[0x431750],EAX ; 乘以2
0042FAA3 |. 8D45 FC LEA EAX,DWORD PTR SS:[EBP-0x4]
0042FAA6 |. BA ACFB4200 MOV EDX,Acid_bur.0042FBAC
0042FAAB |. E8 583CFDFF CALL Acid_bur.00403708
0042FAB0 |. 8D45 F8 LEA EAX,DWORD PTR SS:[EBP-0x8]
0042FAB3 |. BA B8FB4200 MOV EDX,Acid_bur.0042FBB8
0042FAB8 |. E8 4B3CFDFF CALL Acid_bur.00403708
0042FABD |. FF75 FC PUSH DWORD PTR SS:[EBP-0x4]
0042FAC0 |. 68 C8FB4200 PUSH Acid_bur.0042FBC8 ; UNICODE "-",注冊碼用"-"字符串隔開
0042FAC5 |. 8D55 E8 LEA EDX,DWORD PTR SS:[EBP-0x18]
0042FAC8 |. A1 50174300 MOV EAX,DWORD PTR DS:[0x431750]
0042FACD |. E8 466CFDFF CALL Acid_bur.00406718
0042FAD2 |. FF75 E8 PUSH DWORD PTR SS:[EBP-0x18]
0042FAD5 |. 68 C8FB4200 PUSH Acid_bur.0042FBC8 ; UNICODE "-",注冊碼用"-"字符串隔開 通過輸入不同的注冊碼,我們可以發現注冊碼的形式為CW-*****-CRACKED即只有中間部分的注冊碼是通過name值變換得來,而其他部分的注冊碼則是固定不變的,因此生成注冊碼的代碼為,代碼寫的較為稀爛。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main() {
char flag[20];
char text[20];
int i = 0;
scanf("%s",flag);
while(flag[i]!='') {
i++;
if(i>4)
break;
}
if(i<4) {
printf("長度需要大于4!\n");
exit(-1); } i = flag[0]*0x29*2;
printf("CW-%d-CRACKED\n",i);
return 1;
}
補充
當我們看到這些間接尋址時,可能因為代碼太多已經忘記此時里面的值,可以點擊數據窗口->Crtl+G輸入你想看的地址,例如我輸入了0x43176c則可以看到該段里面的值
可以看到存儲的值即我輸入的name值012345678,這樣可以隨時查看段地址里存儲的值,方便閱讀匯編代碼 
總結
雖然程序不是十分復雜,但是可以幫助我們去熟悉OD的使用以及對匯編的應用,我也是通過該程序學到了很多,希望能夠幫助到大家