【破解作者】 wildbug
【作者邮箱】 :)
【作者主页】 :)
【使用工具】 OD, PEiD,ASCII码转换,windows计算器
【破解平台】 Win98
【软件名称】 题目为“Splish,Splash”的crackme
【下载地址】 看雪论坛精华5-序列号-splish
【软件简介】 一个crackme,有3个输入框,第一个为Hard Coded,输入,下面有Check HardCoded按钮,第二、三是输入Name和
Serial的,下面有Name/Serial Check按钮。
【软件大小】 232KB
【加壳方式】 无
【破解声明】 献给和我一样看到无明码就想爆破的兄弟:)
--------------------------------------------------------------------------------
【破解内容】
初步分析:
此Crackme分2步,第一步是输入“HardCoded”,第2步是输入注册名和注册码。用 PEiD查壳,为MASM32 / TASM32,
嘿嘿,无壳好啊。实验下,随便在“HardCoded”输入1234,有提示“sorry,please try again”,在Name/Serial处
输入Name:wildbug,Serial:987654321,也有同样提示:“sorry,please try again”,嘿嘿,有提示就好办了。
破解过程:
用od载入,超级字符串查找“sorry,please try again”。在004013D9和004016E9各有1个,双击004013D9,往上找
到这里:
00401353 |. 48 61 72 64 4>ASCII "HardCoded",0
0040135D |> 6A 20 PUSH 20 ; /Count = 20 (32.)
0040135F |. 68 15324000 PUSH SPLISH.00403215 ; |Buffer = SPLISH.00403215
00401364 |. FF35 90344000 PUSH DWORD PTR DS:[403490] ; |hWnd = 00000D1C
(class='Edit',wndproc=8057DB36,parent=00000D7C)
0040136A |. E8 BB030000 CALL <JMP.&USER32.GetWindowTextA> ; \GetWindowTextA
0040136F |. 8D05 53134000 LEA EAX,DWORD PTR DS:[401353]-----------------F2下断
00401375 |. 8D1D 15324000 LEA EBX,DWORD PTR DS:[403215]
在GetWindowTextA下面的0040136F下断,运行程序,在HardCoded处输入“1234”,点Check HardCoded按钮,在
od中断下,
0040136F |. 8D05 53134000 LEA EAX,DWORD PTR DS:[401353]----断在这里,把401353处字符放到eax
00401375 |. 8D1D 15324000 LEA EBX,DWORD PTR DS:[403215] 把403215中的输入的“1234”放到ebx
0040137B |> 8038 00 /CMP BYTE PTR DS:[EAX],0 比较完了吗?
0040137E |. 74 0C |JE SHORT SPLISH.0040138C 完了就跳转,也就是胜利了
00401380 |. 8A08 |MOV CL,BYTE PTR DS:[EAX] eax中第一个字符放到CL,
00401382 |. 8A13 |MOV DL,BYTE PTR DS:[EBX] ebx中第一个字符放到DL
00401384 |. 38D1 |CMP CL,DL 比较是否一样
00401386 |. 75 4A |JNZ SHORT SPLISH.004013D2 不一样就跳到失败
00401388 |. 40 |INC EAX eax中的下一个字符
00401389 |. 43 |INC EBX ebx中的下一个字符
0040138A |.^ EB EF \JMP SHORT SPLISH.0040137B 循环
0040138C |> EB 2F JMP SHORT SPLISH.004013BD 到胜利处
0040138E |. 43 6F 6E 67 7>ASCII "Congratulations,"
0040139E |. 20 79 6F 75 2>ASCII " you got the har"
004013AE |. 64 20 63 6F 6>ASCII "d coded serial",0
004013BD |> 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
004013BF |. 68 0A304000 PUSH SPLISH.0040300A ; |splish, splash
004013C4 |. 68 8E134000 PUSH SPLISH.0040138E ; |congratulations, you got the hard coded
serial
004013C9 |. 6A 00 PUSH 0 ; |hOwner = NULL
004013CB |. E8 78030000 CALL <JMP.&USER32.MessageBoxA> ; \MessageBoxA
004013D0 |. EB 13 JMP SHORT SPLISH.004013E5
004013D2 |> 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
004013D4 |. 68 0A304000 PUSH SPLISH.0040300A ; |splish, splash
004013D9 |. 68 67304000 PUSH SPLISH.00403067 ; |sorry, please try again.
004013DE |. 6A 00 PUSH 0 ; |hOwner = NULL
004013E0 |. E8 63030000 CALL <JMP.&USER32.MessageBoxA> ; \MessageBoxA
我很菜的,只要看到算法分析,没有明码的第一感觉就是“爆”,这次呢,看到这里,有了点信心,感觉就是输入
的字符和“HardCoded”比较么,我试下,输入“HardCoded”,果然成功了。嘿嘿,对往下继续有了点期待。
在字符串参考中的004016E9处双击,往上找,有2处连在一起的GetWindowTextA,嘿嘿,就是这里了,在第2处下面
下断,输入Name:wildbug,Serial:987654321,点Name/Serial Check按钮,断在这里
0040160D |. E8 18010000 CALL <JMP.&USER32.GetWindowTextA> ; \GetWindowTextA
00401612 |. 85C0 TEST EAX,EAX --F2下断,断下,测试name输入没,
00401614 |. 74 68 JE SHORT SPLISH.0040167E 没有就跳走
00401616 |. A3 63344000 MOV DWORD PTR DS:[403463],EAX
0040161B |. 33C9 XOR ECX,ECX
0040161D |. 33DB XOR EBX,EBX
0040161F |. 33D2 XOR EDX,EDX
00401621 |. 8D35 36324000 LEA ESI,DWORD PTR DS:[403236] 把输入的name放到esi
00401627 |. 8D3D 58324000 LEA EDI,DWORD PTR DS:[403258]
0040162D |. B9 0A000000 MOV ECX,0A
00401632 |> 0FBE041E /MOVSX EAX,BYTE PTR DS:[ESI+EBX]name第一位转成16进制,放到eax
00401636 |. 99 |CDQ 扩展
00401637 |. F7F9 |IDIV ECX eax除以ecx,dl=余数=edx
00401639 |. 33D3 |XOR EDX,EBX 余数和当前位数-1进行xor
0040163B |. 83C2 02 |ADD EDX,2 edx加2
0040163E |. 80FA 0A |CMP DL,0A 比较dl和0a
00401641 |. 7C 03 |JL SHORT SPLISH.00401646 比oa小的话就跳转
00401643 |. 80EA 0A |SUB DL,0A 比oa大的话就减去0a
00401646 |> 88141F |MOV BYTE PTR DS:[EDI+EBX],DL 把算出的DL放到EDI+EBX,第一个是403258
00401649 |. 43 |INC EBX ebx加1,算出一个就加1
0040164A |. 3B1D 63344000 |CMP EBX,DWORD PTR DS:[403463] 403463放的是name的长度,和已经计算过的比较
00401650 |.^ 75 E0 \JNZ SHORT SPLISH.00401632 没有计算完就继续计算。
00401652 |. 33C9 XOR ECX,ECX
00401654 |. 33DB XOR EBX,EBX
00401656 |. 33D2 XOR EDX,EDX
00401658 |. 8D35 42324000 LEA ESI,DWORD PTR DS:[403242] 把输入注册码放到esi
0040165E |. 8D3D 4D324000 LEA EDI,DWORD PTR DS:[40324D]
00401664 |. B9 0A000000 MOV ECX,0A
00401669 |> 0FBE041E /MOVSX EAX,BYTE PTR DS:[ESI+EBX]把注册码的第一位转成16进制
0040166D |. 99 |CDQ 扩展
0040166E |. F7F9 |IDIV ECX 除以ecx
00401670 |. 88141F |MOV BYTE PTR DS:[EDI+EBX],DL 把dl放到EDI+EBX 第一位是40324d
00401673 |. 43 |INC EBX ebx加1记数
00401674 |. 3B1D 67344000 |CMP EBX,DWORD PTR DS:[403467] 注册码计算完了吗?
0040167A |.^ 75 ED \JNZ SHORT SPLISH.00401669 没有就继续计算
0040167C |. EB 2A JMP SHORT SPLISH.004016A8 算好了就跳转
0040167E |> 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
00401680 |. 68 0A304000 PUSH SPLISH.0040300A ; |splish, splash
00401685 |. 68 A0304000 PUSH SPLISH.004030A0 ; |please enter your name.
0040168A |. 6A 00 PUSH 0 ; |hOwner = NULL
0040168C |. E8 B7000000 CALL <JMP.&USER32.MessageBoxA> ; \MessageBoxA
00401691 |. EB 62 JMP SHORT SPLISH.004016F5
00401693 |> 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
00401695 |. 68 0A304000 PUSH SPLISH.0040300A ; |splish, splash
0040169A |. 68 B8304000 PUSH SPLISH.004030B8 ; |please enter your serial number.
0040169F |. 6A 00 PUSH 0 ; |hOwner = NULL
004016A1 |. E8 A2000000 CALL <JMP.&USER32.MessageBoxA> ; \MessageBoxA
004016A6 |. EB 4D JMP SHORT SPLISH.004016F5
004016A8 |> 8D35 4D324000 LEA ESI,DWORD PTR DS:[40324D] 跳到这里,把注册码算好的数放到esi
004016AE |. 8D3D 58324000 LEA EDI,DWORD PTR DS:[403258] 把用name算好的数放到edi
004016B4 |. 33DB XOR EBX,EBX
004016B6 |> 3B1D 63344000 /CMP EBX,DWORD PTR DS:[403463] 比较几次?和name的位数相同,这里是7次。
004016BC |. 74 0F |JE SHORT SPLISH.004016CD 比较完了就成功了
004016BE |. 0FBE041F |MOVSX EAX,BYTE PTR DS:[EDI+EBX]把注册码算好的数的第一位放到eax
004016C2 |. 0FBE0C1E |MOVSX ECX,BYTE PTR DS:[ESI+EBX]把用name算好的数的第一位放到ecx
004016C6 |. 3BC1 |CMP EAX,ECX 一位一位比较
004016C8 |. 75 18 |JNZ SHORT SPLISH.004016E2 不相等就结束,失败。
004016CA |. 43 |INC EBX 下一位。
004016CB |.^ EB E9 \JMP SHORT SPLISH.004016B6 循环。
004016CD |> 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
004016CF |. 68 0A304000 PUSH SPLISH.0040300A ; |splish, splash
004016D4 |. 68 42304000 PUSH SPLISH.00403042 ; |good job, now keygen it.
004016D9 |. 6A 00 PUSH 0 ; |hOwner = NULL
004016DB |. E8 68000000 CALL <JMP.&USER32.MessageBoxA> ; \MessageBoxA
004016E0 |. EB 13 JMP SHORT SPLISH.004016F5
004016E2 |> 6A 00 PUSH 0 ; /Style = MB_OK|MB_APPLMODAL
004016E4 |. 68 0A304000 PUSH SPLISH.0040300A ; |splish, splash
004016E9 |. 68 67304000 PUSH SPLISH.00403067 ; |sorry, please try again.
004016EE |. 6A 00 PUSH 0 ; |hOwner = NULL
004016F0 |. E8 53000000 CALL <JMP.&USER32.MessageBoxA> ; \MessageBoxA
004016F5 |> C9 LEAVE
004016F6 \. C2 0800 RETN 8
晕,第一次搞算法,头都晕了,还好可以看内存窗口做参考:
0040324D 04050607
00403251 00010203 .
00403255 01000009 ...
00403259 04050206
0040325D 00000704 ..
这里就是比较的地方和比较的数字。
这个Crackme的算法是这样的,
1.把输入的name每一位转换成16进制,再除以0a,余数和位数xor,再加2,如果比0a大,就减去0a。
2.再把输入的注册码的每一位转换成16进制,再除以0a。
以输入的name的长度为比较次数,把1和2的计算结果一位一位的比较,有一位不相等就失败,达到比较次数就成功了。
比如第一位为w,ASCII为77,77 IDIV 0a,余数为09,09 xor 0,得09,09 add 2,得0b,0b大于0a,0b sub 0a,得01
所以算出的结果为01。
ASCII码表可输入数字从30-39(即0-9),32(即2)除以0A,余数为0,我用这个32做为基数来计算。
所以余数为1的是32+1=33,即相对的注册码数字为3。
同样可以算出:i算出的结果为06,相对的注册码为32+6=38,就是数字8。
......
g算出的结果为07,相对的注册码为32+7=39,就是数字9。
w i l d b u g ------注册的name
77 69 6C 64 62 75 67 ------转换的16进制
0 1 2 3 4 5 6 ------转换后的所在位数
01 06 02 05 04 04 07 ------注册name计算的结果
------------------------------全加上32(原因见上文)
33 38 34 37 36 36 39 ------注册Serial的16进制
3 8 4 7 6 6 9 ------呵呵,这就是注册Serial
一个可以用的注册码:
HardCoded:HardCoded
Name:wildbug
Serial:3847669
谢谢斑竹鼓励,呵呵 我可以上传附件了。
--------------------------------------------------------------------------------
【破解总结】
感觉这个crackme写的太好了,非常适合我们这些看到算法就想爆破的菜鸟学习,如果不是第一部分的破解给了我信心的话,我也
不会去继续分析第二部分的算法。建议每个想从爆破、找明码提高到分析算法,最终写出注册机的兄弟都去破下这个crackme。
--------------------------------------------------------------------------------
【版权声明】 本文纯属技术交流, 转载请注明作者并保持文章的完整, 谢谢!
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课