这里以160个CrackMe之033为例
1.工具与环境
Windows 7 sp1 64bit
吾爱破解OD
2.破解流程
首先运行一下程序了解程序功能,可以看到是一个普通的用户名+序列号方式验证的crackme程序。
尝试输入用户名和密码
输入错误后发现有弹出提示,提示文字将帮助我们找到程序流程,这个程序比较特别弹出两次文本提示框,猜测是为了混淆
在OD界面下,主线程,模块窗口点击右键----查找-----所有参考文本字串
可以看到这边有着两个 No luck there ,mate!
点击进入到该文本所在的地址,可以发现有两部分对于文本框参数进行描述的汇编代码,通过观测发现,有一块文本框参数描述的汇编代码前面有一段程序,从0040137E开始到004013C1结束
试着分析这段代码,发现是一个判断输入字符串是否是从大写A到Z的函数
函数注释如下:
0040137E /$ 8B7424 04 mov esi,dword ptr ss:[esp+0x4] ;将字符串源的偏移地址填入到esi中
00401382 |. 56 push esi ;将esi数据填入到堆栈
;以循环的方式将字符串的每一个字符进行比对以确定字符在大写的A-Z之间
00401383 |> 8A06 /mov al,byte ptr ds:[esi] ;将esi指向的数据填入到低位
00401385 |. 84C0 |test al,al ;比较AX寄存器低16位是否为0
00401387 |. 74 13 |je XCruehead.0040139C ;如果ZF寄存器为1则转移到指定地址
00401389 |. 3C 41 |cmp al,0x41 ;比较AX寄存器的低16位和0x41
0040138B |. 72 1F |jb XCruehead.004013AC ;如果小于则转移
0040138D |. 3C 5A |cmp al,0x5A ;比较AX寄存器的低16位和0x5A
0040138F |. 73 03 |jnb XCruehead.00401394 ;如果小于等于则转移
00401391 |. 46 |inc esi ;esi自加1
00401392 |.^ EB EF |jmp XCruehead.00401383 ;跳转到指定地址,这里会返回到上方进行下一次判断
00401394 |> E8 39000000 |call Cruehead.004013D2 ;调用指定地址程序
00401399 |. 46 |inc esi ;esi自加1
0040139A |.^ EB E7 \jmp XCruehead.00401383 ;跳转到指定地址,这里会返回到上方进行下一次判断
0040139C |> 5E pop esi ;从堆栈中读取最初的esi地址
0040139D |. E8 20000000 call Cruehead.004013C2 ;调用子程序
004013A2 |. 81F7 78560000 xor edi,0x5678 ;将edi和0x5678异或(仅一个1一个0时结果为1)
004013A8 |. 8BC7 mov eax,edi ;将edi赋值到eax
004013AA |. EB 15 jmp XCruehead.004013C1 ;调用子程序
004013AC |> 5E pop esi ;将堆栈中数据复制到esi中
;配置消息弹出框并将数据进行显示
004013AD |. 6A 30 push 0x30 ; 填入数据到堆栈中 /Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL
004013AF |. 68 60214000 push Cruehead.00402160 ; 填入数据到堆栈中 |Title = "No luck!"
004013B4 |. 68 69214000 push Cruehead.00402169 ; 填入数据到堆栈中|Text = "No luck there, mate!"
004013B9 |. FF75 08 push [arg.1] ; 填入数据到堆栈中 |hOwner
004013BC |. E8 79000000 call <jmp.&USER32.MessageBoxA> ; 调用消息框函数显示文字提示 \MessageBoxA
004013C1 \> C3 retn ;函数结束,返回
到这里可以判断这是一个前置判断的预处理函数,肯定是最先执行的
搜索call 0040137E,找到了调用这一函数位置,发现这边存储(放入堆栈)我们之前输入的名称和序列号
继续往下查看,可以看到在调用了先前0040137E起始的判断字符类型函数后,又调用起始位置为004013D8的函数,该函数处理我们输入的序列号数据
004013D8的函数注释如下:
之后,将把序列号和我们的用户名进行一个比较,从而判断输入的用户名序列号是否匹配
关键跳转位置在00401243处,我们将此处修改为JMP 0040124C
程序就能够正常的跳出成功提示了
3.总结
从该类简单的弹窗式名称密码校验程序算法中我们可以了解到,需要用户输入的名称和序列号在之后的验证中往往相辅相成,有所联系。
在整个流程中,先寻找文字,再寻找子函数,分析函数用途,再去追踪函数调用,最终找到关键跳转,是攻破此类程序基本的解密流程。