这两个exe都是“加密与解密”书中“调试篇”的例子,CrackMe很简单,TraceMe稍微复杂一点。
1. CrackMe
分析CrackMe无需用OD打断点跟进,该程序逻辑非常简单,仅仅从汇编代码的调用上即可判断出其内部实现。
先用IDA进行CrackMe的反汇编,在最下方可以看到关于序列号的判断:
注意刚开始是无法看到右侧“序列号不对,重新再试一次”的字样的,需要查看内存地址00403000,发现是一个字符串数组,手动转化为数组后才能看到这些汉字。
很显然,关于判断序列号是否正确的代码就是:
.text:004010BD push edx ; lpString2
.text:004010BE push eax ; lpString1
.text:004010BF call ds:lstrcmpA
.text:004010C5 test eax, eax
.text:004010C7 push 0 ; uType
.text:004010C9 jnz short loc_4010E8
.text:004010CB push offset Caption ; "OK!"
.text:004010D0 push offset Text ; "恭喜你!"
.text:004010D5 push 0 ; hWnd
.text:004010D7 call ds:MessageBoxA
这里的序列号比对是将用户输入的序列号与预设的一个值进行比较,调用lstrcmpA函数。
如果eax = 1,则test语句执行后ZF = 0,会进入飘黄的跳转部分
如果eax = 0,则test语句执行后ZF = 1,会进入下方的恭喜提示
事实上,这里的序列号是以明文的方式写在程序中。
dx中的“9981”就是正确的序列号。这个9981是直接写死在CrackMe.exe的数据区中,运行的时候再被加载到栈里边。
.data:00403034 byte_403034 db 39h ; 9
.data:00403035 db 39h ; 9
.data:00403036 db 38h ; 8
.data:00403037 db 31h ; 1
.data:00403038 byte_403038 db 0
crack的办法已经很清楚了,可以将lstrcmpA的两个参数置为相同,比如都是edx,也可以将JNZ一句替换成NOP指令。
2.TraceMe
用OD给TraceMe.exe下断,刚开始的时候下的GetWindowTextA,后来几经ctrl-F9,才回到程序领空。
这里发现一个原来还不知道的调用,实际上在GetDlgItemTextA的内部,会调用GetWindowTextA。
程序内部 ----> GetDlgItemTextA ---> GetWindowTextA
因此可以直接对GetDlgItemTextA下断。
这里的两个GetDlgItemTextA调用即是获取用户名、序列号。
004011CA . 8A4424 4C mov al, byte ptr [esp+4C] ;取首字节判断用户名是否为空
004011CE . 84C0 test al, al
004011D0 . 74 76 je short 00401248
004011D2 . 83FB 05 cmp ebx, 5
;判断用户名长度是否>=5
004011D5 . 7C 71 jl short 00401248
004011D7 . 8D5424 4C lea edx, dword ptr [esp+4C]
004011DB . 53 push ebx
004011DC . 8D8424 A00000>lea eax, dword ptr [esp+A0]
004011E3 . 52 push edx
004011E4 . 50 push eax
004011E5 . E8 56010000 call 00401340
;判断序列号是否真确
最关键的部分是call 00401340,这个函数用来验证用户输入的用户名与序列号是否匹配。
该函数调用之前需要3次压栈,可以大概看出来,这3个参数是(密码,用户名,用户名长度)
下面来看call 00401340的具体实现:
ecx 相当于用户名byte数组的下标
eax 相当于密钥byte数组
的下标
可以查看内存得知密钥是: 【 0C 0A 13 09 0C 0B 0A 08 】
看懂这段代码即可以很轻松的写出针对TraceMe的注册机。
大体上的加密算法为:
function validation(passWord,userName,length){
var keyArray = [0x0c,0x0A,0x13,0x09,0x0c,0x0B,0x0A,0x08]
var keyArrayIndex = 0
var userNameIndex = 3
var passWord2 = 0;
while(length > userNameIndex) {
if (keyArrayIndex > 7) {
keyArrayIndex = 0
}
passWord2 += userName[userNameIndex]*keyArray[keyArrayIndex]
userNameIndex++
keyArrayIndex++
}
ToString(passWord2)
if(passWord == passWord2){
return true
}
else
return false
}
举个例子:如果用户名为 “abcde”,则序列号为
“d”×0C + “e”×0A = 100 × 12 + 101 ×10 = 2210
注意最后的几句:
0040138F |. FF15 04404000 call dword ptr [<&KERNEL32.lstrcmpA>] ; \lstrcmpA
00401395 |. F7D8 neg eax
00401397 |. 1BC0 sbb eax, eax
00401399 |. 5F pop edi ; USER32.GetDlgItemTextA
0040139A |. 5E pop esi
0040139B |. 40 inc eax
0040139C |. 5D pop ebp
0040139D \. C3 retn
strcmp的结果存放在eax中
只有eax为0的时候,才可以将eax设置为1(因为最后的返回结果也要放在eax中);如果strcmp的结果eax≠0,则要将eax设置为0。
这里用了
neg eax //求补 ,0->0 (CF=0) ,1-> -1(CF=1) ,-1>1(CF=1)
sbb eax,eax // SBB结果是 -CF
inc eax
这三句来完成,精妙无比。
分享到:
相关推荐
专门适用于新手破解练手的crackme,来自看雪论坛的高人
crackme3
自己写的一个CrackMe,图一乐呵 编译后的文件在: http://bbs.pediy.com/showthread.php?t=153921
PEDIY CrackMe 2007.7z PEDIY CrackMe 2007.7z
入门级别CrackMe,仅仅去除一些常用API和字符串 破文见博文http://blog.csdn.net/betabin/article/details/7470116
百度杯CTF比赛二月第三场比赛(Reverse专题赛)的CrackMe-1题目。
我制作的《新160个CrackMe算法分析》视频的配套文件,内含全部课件及评分。
适合破解新手的160个crackme练手
160个crackme程序4
160个crackme程序2
Good for crack beginers.
一只老虎的CRACKME一只老虎的CRACKME,适合新手练习
《加密与解密》第一版附带光盘中的 crackmes.cjb.net 镜像打包中的 CFF Crackme #3已经脱壳了,拿来ollydbg直接用
这是我以前学习破解收集的几个Crackme,现在放上来大家一起研究研究...
160个crackme程序8
160个crackme程序5
160个全能用的CRACKME程序,很不错,有的和简单但是也有难的,值得一玩
crackme集合[1/2] 本crackme集合分了10个等级。由linholer[PYG]整理制作
被爆破的一个简单无壳crackme,杀毒软件会报毒。但绝对无害!
crackme.exe