【文章标题】: 一个入门级的CrackMe分析(适合新手)
【文章作者】: petnt
【作者邮箱】: petnt@sohu.com
【下载地址】: 见附件
【操作平台】: XPsp2
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
随便下载的一个CrackMe,简介如下:
1. NO PATCHING
2. Find Serial
3. Write Keygen
4. ;) Enjoy
Difficulty: 2 - Needs a little brain (or luck)
Platform: Windows
Language: Assembler
简单分析了一下,好像就是一个入门级的CrackMe,难道我碰到了传说中的luck。:),不管他,进入正题。
既然是入门级,主要供我等菜鸟交流,大侠请飘过。
首先运行一下,随便输入试试,有错误提示。(用户名不符合条件也有提示)
可能有人要问为什么这样做(这是我等菜鸟的通病)?我的理解为这是为我们的目标搜集第一手资料。如:他是通过什么方式来注册的,有没有错误提示等等。这些蛛丝马迹有时将成为我们下手的线索,如本例。
OD载入,入口有些像VC,不管这些,找一下参考字串。幸运来了,我们发现了“Bad Boy”,错误提示的标题。双击字符串,OD就把我们带到了关键之处。
一个典型的消息处理函数。OD已经给出了足够多的注释。(带颜色注释为本人所加)
00401000 /. 55 push ebp
00401001 |. 8BEC mov ebp, esp
00401003 |. 51 push ecx
00401004 |. 8B45 0C mov eax, dword ptr [ebp+C]
00401007 |. 53 push ebx
00401008 |. 56 push esi
00401009 |. 48 dec eax ; Switch (cases 1..111)
0040100A |. 57 push edi
0040100B |. 0F84 56010000 je 00401167
00401011 |. 83E8 0F sub eax, 0F
00401014 |. 0F84 40010000 je 0040115A
0040101A |. 2D 01010000 sub eax, 101
0040101F |. 74 07 je short 00401028
00401021 |. 33C0 xor eax, eax ; Default case of switch 00401009
00401023 |. E9 5B010000 jmp 00401183
00401028 |> 0FB745 10 movzx eax, word ptr [ebp+10] ; Case 111 (WM_COMMAND) of switch 00401009
0040102C |. 48 dec eax ; Switch (cases 1..3E9)
0040102D |. 0F84 27010000 je 0040115A ; 跳向按钮 Exit 的处理过程
00401033 |. 48 dec eax
00401034 |. 0F84 03010000 je 0040113D ; 跳向按钮 About 的处理过程
0040103A |. 2D E7030000 sub eax, 3E7
0040103F |. 0F85 3B010000 jnz 00401180 ; 下面就是按钮 OK 的处理过程
00401045 |. 8B35 A0404000 mov esi, dword ptr [<&USER32.GetDlgI>; USER32.GetDlgItem; Case 3E9 of switch 0040102C
0040104B |. 68 E8030000 push 3E8 ; /ControlID = 3E8 (1000.)
00401050 |. FF75 08 push dword ptr [ebp+8] ; |hWnd
00401053 |. FFD6 call esi ; \GetDlgItem
00401055 |. 50 push eax ; /hWnd
00401056 |. FF15 9C404000 call dword ptr [<&USER32.GetWindowTex>; \GetWindowTextLengthA
0040105C |. BF EA030000 mov edi, 3EA
00401061 |. 8BD8 mov ebx, eax
00401063 |. 57 push edi ; /ControlID => 3EA (1002.)
00401064 |. FF75 08 push dword ptr [ebp+8] ; |hWnd
00401067 |. FFD6 call esi ; \GetDlgItem
00401069 |. 50 push eax ; /hWnd
0040106A |. FF15 9C404000 call dword ptr [<&USER32.GetWindowTex>; \GetWindowTextLengthA
00401070 |. 83FB 04 cmp ebx, 4 ;
00401073 |. 8945 14 mov dword ptr [ebp+14], eax
00401076 |. 0F8E B0000000 jle 0040112C ; 用户名<=4?
0040107C |. 8B35 08404000 mov esi, dword ptr [<&KERNEL32.Globa>; kernel32.GlobalAlloc
00401082 |. 8D43 01 lea eax, dword ptr [ebx+1]
00401085 |. 50 push eax ; /MemSize
00401086 |. 6A 40 push 40 ; |Flags = GPTR
00401088 |. C745 0C 08190>mov dword ptr [ebp+C], 1908 ; |
0040108F |. FFD6 call esi ; \GlobalAlloc
00401091 |. 8945 10 mov dword ptr [ebp+10], eax
00401094 |. 8B45 14 mov eax, dword ptr [ebp+14]
00401097 |. 40 inc eax
00401098 |. 50 push eax ; /MemSize
00401099 |. 6A 40 push 40 ; |Flags = GPTR
0040109B |. 8945 FC mov dword ptr [ebp-4], eax ; |
0040109E |. FFD6 call esi ; \GlobalAlloc
004010A0 |. 8945 14 mov dword ptr [ebp+14], eax
004010A3 |. 8D43 01 lea eax, dword ptr [ebx+1]
004010A6 |. 50 push eax ; /Count
004010A7 |. 8B35 A8404000 mov esi, dword ptr [<&USER32.GetDlgI>; |USER32.GetDlgItemTextA
004010AD |. FF75 10 push dword ptr [ebp+10] ; |Buffer
004010B0 |. 68 E8030000 push 3E8 ; |ControlID = 3E8 (1000.)
004010B5 |. FF75 08 push dword ptr [ebp+8] ; |hWnd
004010B8 |. FFD6 call esi ; \GetDlgItemTextA
004010BA |. FF75 FC push dword ptr [ebp-4] ; /Count
004010BD |. FF75 14 push dword ptr [ebp+14] ; |Buffer
004010C0 |. 57 push edi ; |ControlID => 3EA (1002.)
004010C1 |. FF75 08 push dword ptr [ebp+8] ; |hWnd
004010C4 |. FFD6 call esi ; \GetDlgItemTextA
004010C6 |. 33C0 xor eax, eax
004010C8 |. 85DB test ebx, ebx ; 循环变换用户名
004010CA |. 7E 17 jle short 004010E3
004010CC |> 8B4D 10 /mov ecx, dword ptr [ebp+10]
004010CF |. 8B55 0C |mov edx, dword ptr [ebp+C] ; 初始值1908h
004010D2 |. 03D3 |add edx, ebx ; 1908h+LofU
004010D4 |. 0FBE0C08 |movsx ecx, byte ptr [eax+ecx] ; U[i]
004010D8 |. 0FAFCA |imul ecx, edx ; ;[1908h+Lofu]*U[i]
004010DB |. 40 |inc eax
004010DC |. 894D 0C |mov dword ptr [ebp+C], ecx ; 新值写入1908h所在处
004010DF |. 3BC3 |cmp eax, ebx
004010E1 |.^ 7C E9 \jl short 004010CC
004010E3 |> FF75 14 push dword ptr [ebp+14] ; 序列号入栈
004010E6 |. E8 8D010000 call 00401278 ; 序列号变换函数(D to H)
004010EB |. 59 pop ecx
004010EC |. 8B4D 0C mov ecx, dword ptr [ebp+C]
004010EF |. 6A 00 push 0
004010F1 |. 81F1 FAF9A900 xor ecx, 0A9F9FA
004010F7 |. 3BC8 cmp ecx, eax ; 关键比较(喜欢爆破的同志请在此装药)
004010F9 |. 75 0C jnz short 00401107
004010FB |. 68 98504000 push 00405098 ; good boy!
00401100 |. 68 7C504000 push 0040507C ; terima kasih kerana mencuba
00401105 |. EB 0A jmp short 00401111
00401107 |> 68 70504000 push 00405070 ; bad boy! <--- 就是他把我们带到了这里。
0040110C |. 68 4C504000 push 0040504C ; tidak tepat, sila cuba sekali lagi
00401111 |> FF75 08 push dword ptr [ebp+8] ; |hOwner
00401114 |. FF15 AC404000 call dword ptr [<&USER32.MessageBoxA>>; \MessageBoxA
0040111A |. FF75 10 push dword ptr [ebp+10] ; /hMem
0040111D |. 8B35 04404000 mov esi, dword ptr [<&KERNEL32.Globa>; |kernel32.GlobalFree
00401123 |. FFD6 call esi ; \GlobalFree
00401125 |. FF75 14 push dword ptr [ebp+14] ; /hMem
00401128 |. FFD6 call esi ; \GlobalFree
0040112A |. EB 54 jmp short 00401180
0040112C |> 68 30504000 push 00405030 ; /masukkan at least 5 huruf <--用户名小于等于4的跳入点
00401131 |. 57 push edi ; |ControlID
00401132 |. FF75 08 push dword ptr [ebp+8] ; |hWnd
00401135 |. FF15 A4404000 call dword ptr [<&USER32.SetDlgItemTe>; \SetDlgItemTextA
0040113B |. EB 43 jmp short 00401180
0040113D |> 6A 00 push 0 ; /lParam = NULL; ;<-- 按钮About的处理跳入点
0040113F |. 68 8A114000 push 0040118A ; |DlgProc = zugo.0040118A
00401144 |. FF75 08 push dword ptr [ebp+8] ; |hOwner
00401147 |. 6A 67 push 67 ; |pTemplate = 67
00401149 |. 6A 00 push 0 ; |/pModule = NULL
0040114B |. FF15 58404000 call dword ptr [<&KERNEL32.GetModuleH>; |\GetModuleHandleA
00401151 |. 50 push eax ; |hInst
00401152 |. FF15 B4404000 call dword ptr [<&USER32.DialogBoxPar>; \DialogBoxParamA
00401158 |. EB 26 jmp short 00401180
0040115A |> 6A 00 push 0 ; /Result = 0; <-- 按钮 Exit的处理跳入点。
0040115C |. FF75 08 push dword ptr [ebp+8] ; |hWnd
0040115F |. FF15 B8404000 call dword ptr [<&USER32.EndDialog>] ; \EndDialog
00401165 |. EB 19 jmp short 00401180
00401167 |> 8B45 14 mov eax, dword ptr [ebp+14] ; Case 1 (WM_CREATE) of switch 00401009
0040116A |. 6A 6E push 6E ; /RsrcName = 110.
0040116C |. 8B40 04 mov eax, dword ptr [eax+4] ; |
0040116F |. 50 push eax ; |hInst
00401170 |. A3 BC564000 mov dword ptr [4056BC], eax ; |
00401175 |. FF15 B0404000 call dword ptr [<&USER32.LoadIconA>] ; \LoadIconA
0040117B |. A3 10554000 mov dword ptr [405510], eax
00401180 |> 6A 01 push 1 ; Default case of switch 0040102C
00401182 |. 58 pop eax
00401183 |> 5F pop edi
00401184 |. 5E pop esi
00401185 |. 5B pop ebx
00401186 |. C9 leave
00401187 \. C2 1000 retn 10
下面给出OK按钮的简单处理流程:
1、获取两个编辑框内容的长度;
2、判断用户名是否>4(大于4才符合注册条件);
3、根据获得的两个长度分配空间;
4、获取两个编辑框的内容;
5、对用户名进行变换;
6、对序列号进行变换(十进制转换成十六进制);
7、对用户名变换后的数据再次变换(Xor 0A9f9fA),然后于序列号的变换值进行比较。
8、对比较结果给出相应的提示。
下面给出5中的算法:
设 U=用户名(字符数组) LofU=用户名长度 S=变换结果 ,则:
S=1908H
for (i=0;i++;i<LofU)
{
S=(S+LofU)*U[i];
}
汇编语言注册机:
GenKey proc uses edi, lpUserName:DWORD,nU:DWORD ;生成序列号函数,参数分别为:指向用户名的指针,用户名字符数
.if nU<5
mov eax,offset szUserName
ret
.endif
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
xor ecx,ecx
mov ebx,1908h
mov edi,lpUserName
.while ecx<nU
movzx eax,byte ptr[edi+ecx]
add ebx,nU
imul ebx,eax
inc ecx
.endw
xor ebx,0A9F9FAh
invoke wsprintf,offset szSerial,offset szFormat2 ,ebx
mov eax,offset szSerial
ret
GenKey endp
没什么技术含量,CrackMe and KeyGen见附件,仅供参考。
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)