- UID
- 59926
注册时间2009-3-1
阅读权限20
最后登录1970-1-1
以武会友
TA的每日心情 | 擦汗 2019-5-7 09:43 |
---|
签到天数: 28 天 [LV.4]偶尔看看III
|
楼主 |
发表于 2009-3-10 23:10:34
|
显示全部楼层
答案:
破文标题】 CrackMe之chap203 破解分析
【使用工具】 peid,olldbg
【破解平台】 Win2000/XP
【软件名称】 chap203
【软件大小】 12KB
【编程语言】 MASM32/TASM32
【软件简介】 加密和解密第一版第二章第三个CrackMe。
【破解目的】 从头学起,打好基础。
【破解声明】 我是一只小菜鸟,偶得一点心得,愿与大家分享:)
------------------------------------------------------------
首先 Peid 检测程序编程语言是MASM32 / TASM32,运行程序。
没输入或错误注册码提示
"Your registration info is invalid... Note that most of the special chars may raise registration problems!"
这次W32Dasm败下阵来了,看不到任何字符参考。
这次OD直接披挂上阵。
载入程序,点右键-搜索-字符参考。
004010E1 push chap203.00402061 ASCII "Congratulations! Please send your keygen (working one) to [email protected]!"
00401224 push chap203.004020AE ASCII "Your registration info is invalid... Note that most of the special chars may raise registration problems!"
//先双击00401224 到失败处代码段看看。
这两句让我们感兴趣。
0040121A > \68 00200000 push 2000 //这句有个>箭头表示从某处跳转过来,根据OD的红线向上找。
0040121F . 68 01204000 push chap203.00402001 ; |Title = "Duelist's Crackme #4"
00401224 . 68 AE204000 push chap203.004020AE ; |Text = "Your registration info is invalid... Note that most of the special chars may raise registration problems!"
00401229 . 6A 00 push 0 ; |hOwner = NULL
0040122B . E8 36010000 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
...........................................................................
于是截取了一段关键代码。
填入用户
Mr.David
注册码
123456789
这个程序不是用 GetDlgItemTextA 或 GetWindowTextA 获取字符,而是用消息函数SendDlgItemMessageA 获取字符信息,我们把断点下在00401127处,点Check按钮立即中断。注意用Alt+F5前台显示切换便于调试。
004010D7 > /68 00200000 push 2000 ; /Style = MB_OK|MB_TASKMODAL
004010DC . |68 01204000 push chap203.00402001 ; |Title = "Duelist's Crackme #4"
004010E1 . |68 61204000 push chap203.00402061 ; |Text = "Congratulations! Please send your keygen (working one) to [email protected]!"
004010E6 . |6A 00 push 0 ; |hOwner = NULL
004010E8 . |E8 79020000 call <jmp.&USER32.MessageBoxA> ; \MessageBoxA
004010ED . |B8 01000000 mov eax, 1
004010F2 . |EB 25 jmp short chap203.00401119
004010F4 > |817D 0C 11010>cmp dword ptr ss:[ebp+C], 111
004010FB . |0F84 FA000000 je chap203.004011FB
00401101 . |817D 0C 10010>cmp dword ptr ss:[ebp+C], 110
00401108 . |74 16 je short chap203.00401120
0040110A . |837D 0C 10 cmp dword ptr ss:[ebp+C], 10
0040110E . |0F84 F7000000 je chap203.0040120B
00401114 . |B8 00000000 mov eax, 0
00401119 > |5F pop edi
0040111A . |5E pop esi
0040111B . |5B pop ebx
0040111C . |C9 leave
0040111D . |C2 1000 retn 10
00401120 > |B8 01000000 mov eax, 1
00401125 .^|EB F2 jmp short chap203.00401119
00401127 > |6A 00 push 0 ; /lParam = 0
00401129 . |6A 00 push 0 ; |wParam = 0
0040112B . |6A 0E push 0E ; |Message = WM_GETTEXTLENGTH
0040112D . |6A 03 push 3 ; |ControlID = 3
0040112F . |FF75 08 push dword ptr ss:[ebp+8] ; |hWnd
00401132 . |E8 41020000 call <jmp.&USER32.SendDlgItemMessageA> ; \SendDlgItemMessageA
00401137 . |A3 AF214000 mov dword ptr ds:[4021AF], eax //eax返回用户字符数目5
0040113C . |83F8 00 cmp eax, 0 //比较eax是否为0
0040113F . |0F84 D5000000 je chap203.0040121A //是则跳走Over。
00401145 . |83F8 08 cmp eax, 8 //比较eax是否大于8个字符。
00401148 . |0F8F CC000000 jg chap203.0040121A //是则跳走Over。
0040114E . |8BF0 mov esi, eax
00401150 . |6A 00 push 0 ; /lParam = 0
00401152 . |6A 00 push 0 ; |wParam = 0
00401154 . |6A 0E push 0E ; |Message = WM_GETTEXTLENGTH
00401156 . |6A 04 push 4 ; |ControlID = 4
00401158 . |FF75 08 push dword ptr ss:[ebp+8] ; |hWnd
0040115B . |E8 18020000 call <jmp.&USER32.SendDlgItemMessageA> ; \SendDlgItemMessageA
00401160 . |83F8 00 cmp eax, 0 //直接比较eax返回注册码字符数目9是否为0
00401163 . |0F84 B1000000 je chap203.0040121A //是则跳走Over。
00401169 . |3BF0 cmp esi, eax //比较用户名和注册码的长度是否相同。
0040116B . |0F85 A9000000 jnz chap203.0040121A //不同跳走Over。
这里修改用户名
David
注册码
12345
再次来到这里。
00401171 . |68 60214000 push chap203.00402160 ; /lParam = 402160
00401176 . |6A 08 push 8 ; |wParam = 8
00401178 . |6A 0D push 0D ; |Message = WM_GETTEXT
0040117A . |6A 03 push 3 ; |ControlID = 3
0040117C . |FF75 08 push dword ptr ss:[ebp+8] ; |hWnd
0040117F . |E8 F4010000 call <jmp.&USER32.SendDlgItemMessageA> ; \SendDlgItemMessageA
00401184 . |68 79214000 push chap203.00402179 ; /lParam = 402179
00401189 . |6A 10 push 10 ; |wParam = 10
0040118B . |6A 0D push 0D ; |Message = WM_GETTEXT
0040118D . |6A 04 push 4 ; |ControlID = 4
0040118F . |FF75 08 push dword ptr ss:[ebp+8] ; |hWnd
00401192 . |E8 E1010000 call <jmp.&USER32.SendDlgItemMessageA> ; \SendDlgItemMessageA
00401197 . |B9 FFFFFFFF mov ecx, -1
0040119C > |41 inc ecx
0040119D . |0FBE81 602140>movsx eax, byte ptr ds:[ecx+402160] //逐位取用户名的16进制。
004011A4 . |83F8 00 cmp eax, 0 比较是否为0,判断输入是否是字符。
004011A7 . |74 32 je short chap203.004011DB //不是则跳走Over。
004011A9 . |BE FFFFFFFF mov esi, -1
004011AE . |83F8 41 cmp eax, 41 //比较eax是否小于41(A)
004011B1 . |7C 67 jl short chap203.0040121A //小于over,不能是数字等字符。
004011B3 . |83F8 7A cmp eax, 7A //比较eax是否大于7A(z)
004011B6 . |77 62 ja short chap203.0040121A //大于over,不能是数字等字符。
004011B8 . |83F8 5A cmp eax, 5A //比较eax是否大于5A(Z)
004011BB . |7C 03 jl short chap203.004011C0 //小于则跳走,不处理。
004011BD . |83E8 20 sub eax, 20 //将小写字符转为大写。
004011C0 > 46 inc esi
004011C1 . |0FBE96 172040>movsx edx, byte ptr ds:[esi+402017] //计算序列号的原始字串。
004011C8 . |3BC2 cmp eax, edx //判断当前字符串是否等于edx。
004011CA .^|75 F4 jnz short chap203.004011C0 //不等则循环。
004011CC . |0FBE86 3C2040>movsx eax, byte ptr ds:[esi+40203C] //如相等则eax=正确字符。
004011D3 . |8981 94214000 mov dword ptr ds:[ecx+402194], eax //将字符存贮在00402194
004011D9 .^|EB C1 jmp short chap203.0040119C //循环。
004011DB > |FF35 AF214000 push dword ptr ds:[4021AF] //序列号数目5进堆栈。
004011E1 . |68 94214000 push chap203.00402194 //真码进入堆栈。
004011E6 . |68 79214000 push chap203.00402179 //假码入堆栈。
004011EB . |E8 54000000 call chap203.00401244 //比较Call,跟进。
004011F0 . |83F8 01 cmp eax, 1 //EAX=1则注册正确。
004011F3 .^\0F84 DEFEFFFF je chap203.004010D7 //跳到注册成功对话框处。
004011F9 . EB 1F jmp short chap203.0040121A
004011FB > 837D 10 01 cmp dword ptr ss:[ebp+10], 1 ; |
004011FF .^ 0F84 22FFFFFF je chap203.00401127 ; |
00401205 . 837D 10 02 cmp dword ptr ss:[ebp+10], 2 ; |
00401209 . 75 2F jnz short chap203.0040123A ; |
0040120B > E8 B4000000 call <jmp.&KERNEL32.ExitProcess> ; \ExitProcess
00401210 . B8 01000000 mov eax, 1
00401215 .^ E9 FFFEFFFF jmp chap203.00401119
0040121A > 68 00200000 push 2000 ; /Style = MB_OK|MB_TASKMODAL; Default case of switch 004011A4
0040121F . 68 01204000 push chap203.00402001 ; |Title = "Duelist's Crackme #4"
00401224 . 68 AE204000 push chap203.004020AE ; |Text = "Your registration info is invalid... Note that most of the special chars may raise registration problems!"
00401229 . 6A 00 push 0 ; |hOwner = NULL
0040122B . E8 36010000 call <jmp.&USER32.MessageBoxA> //错误提示。
.....................................................................
转存信息
00402017 41 31 4C 53 4B 32 44 4A A1LSK2DJ
0040201F 46 34 48 47 50 33 51 57 F4HGP3QW
00402027 4F 35 45 49 52 36 55 54 O5EIR6UT
0040202F 59 5A 38 4D 58 4E 37 43 YZ8MXN7C
00402037 42 56 39 00 20 53 55 37 BV9. SU7
0040203F 43 53 4A 4B 46 30 39 4E CSJKF09N
00402047 43 53 44 4F 39 53 44 46 CSDO9SDF
0040204F 30 39 53 44 52 4C 56 4B 09SDRLVK
00402057 37 38 30 39 53 34 4E 46 7809S4NF
004011EB . |E8 54000000 call chap203.00401244 //比较Call,跟进。
00401244 /$ C8 000000 enter 0, 0
00401248 |. B8 01000000 mov eax, 1
0040124D |. 8B7D 08 mov edi, dword ptr ss:[ebp+8]
00401250 |. 8B75 0C mov esi, dword ptr ss:[ebp+C]
00401253 |. 8B4D 10 mov ecx, dword ptr ss:[ebp+10] //esi 存放真码 KSN0K
00401256 |. F3:A6 repe cmps byte ptr es:[edi], byte ptr ds>
00401258 |. 67:E3 05 jcxz short chap203.00401260
0040125B |. B8 00000000 mov eax, 0
00401260 |> C9 leave
00401261 \. C2 0C00 retn 0C
注册码算法
取地址
[esi+402017] 处的字符与注册码第一位比较,不相等则esi加1,直到两者相同为止。
然后取[esi+40203C] 算出注册码第一位。
后面位数的一样。
【内存注册机】
修改内存
修改地址
401148
修改长度
6
原始指令
0F8FCC000000
修改指令
909090909090
添加
修改地址
40116B
修改长度
6
原始指令
0F85A9000000
修改指令
909090909090
添加
中断地址
4011EB
中断次数 1
第一字节 E8
指令长度 5
继续添加
中断地址
401256
中断次数 1
第一字节 F3
指令长度 2
最后内存方式寄存器 Esi
[ 本帖最后由 jzyjd 于 2009-3-10 23:14 编辑 ] |
|