学破解第118天,《160个CrackerMe之002》分析
前言:
从小学到大专(计算机网络技术专业),玩过去的,所以学习成绩惨不忍睹,什么证书也没考,直到找不到工作才后悔,不知道怎么办才好。
2017年12月16日,通过19元注册码注册论坛账号,开始做伸手党,潜水一年多,上来就是找软件。(拿论坛高大上的软件出去装X)
2018年8月某一天,报名了华中科技大学网络教育本科(计算机科学与技术专业)2018级秋季。(开始提升学历)
2019年6月17日,不愿再做小菜鸟一枚,开始零基础学习破解。(感谢小糊涂虫大哥在我刚开始学习脱壳时,录制视频解答我的问题)
2020年7月7日,感谢H大对我的鼓励,拥有了第一篇获得优秀的文章。(接下来希望学习逆向,逆天改命)
坛友们,年轻就是资本,和我一起逆天改命吧,我的学习过程全部记录及学习资源:https://www.52pojie.cn/thread-1208234-1-1.html
立帖为证!--------记录学习的点点滴滴
0x1分析题目
1.打开软件,发现需要输入name和serial,然后进行验证
2.单机OK按钮会有弹窗提示正确与否。
0x2寻找爆破点
1.看到弹窗,我的第一反应就是MessageBOX,没断下来,不熟悉的VB程序真的是毫无办法啊。
2.搜字符串吧,然后定位到
0040258B . /74 58 je short Afkayas_.004025E5
0040258D . |68 801B4000 push Afkayas_.00401B80 ; UNICODE "You Get It"
00402592 . |68 9C1B4000 push Afkayas_.00401B9C ; ASCII "\r"
00402597 . |FFD7 call edi ; msvbvm50.__vbaStrCat
00402599 . |8BD0 mov edx,eax
0040259B . |8D4D E8 lea ecx,dword ptr ss:[ebp-0x18]
0040259E . |FFD3 call ebx ; msvbvm50.__vbaStrMove
004025A0 . |50 push eax
004025A1 . |68 A81B4000 push Afkayas_.00401BA8 ; UNICODE "KeyGen It Now"
004025A6 . |FFD7 call edi ; msvbvm50.__vbaStrCat
004025A8 . |8D4D 94 lea ecx,dword ptr ss:[ebp-0x6C]
004025AB . |8945 CC mov dword ptr ss:[ebp-0x34],eax
004025AE . |8D55 A4 lea edx,dword ptr ss:[ebp-0x5C]
004025B1 . |51 push ecx
004025B2 . |8D45 B4 lea eax,dword ptr ss:[ebp-0x4C]
004025B5 . |52 push edx
004025B6 . |50 push eax
004025B7 . |8D4D C4 lea ecx,dword ptr ss:[ebp-0x3C]
004025BA . |6A 00 push 0x0
004025BC . |51 push ecx
004025BD . |C745 C4 08000>mov dword ptr ss:[ebp-0x3C],0x8
004025C4 . |FF15 10414000 call dword ptr ds:[<&MSVBVM50.#rtcMsgBox_595>] ; msvbvm50.rtcMsgBox
004025CA . |8D4D E8 lea ecx,dword ptr ss:[ebp-0x18]
004025CD . |FF15 80414000 call dword ptr ds:[<&MSVBVM50.__vbaFreeStr>] ; msvbvm50.__vbaFreeStr
004025D3 . |8D55 94 lea edx,dword ptr ss:[ebp-0x6C]
004025D6 . |8D45 A4 lea eax,dword ptr ss:[ebp-0x5C]
004025D9 . |52 push edx
004025DA . |8D4D B4 lea ecx,dword ptr ss:[ebp-0x4C]
004025DD . |50 push eax
004025DE . |8D55 C4 lea edx,dword ptr ss:[ebp-0x3C]
004025E1 . |51 push ecx
004025E2 . |52 push edx
004025E3 . |EB 56 jmp short Afkayas_.0040263B
004025E5 > \68 C81B4000 push Afkayas_.00401BC8 ; UNICODE "You Get Wrong"
3.接下来不用我说也知道吧,直接把0040258B这里的je nop掉即可爆破成功。
0x3分析算法
1.messageBOX断不下你,那我就试试GetWindowTextA和GetDlgItemTextA,输入52pojie和123456,点击OK,然后定位到了
0012F14C 7404375D /CALL 到 GetWindowTextA 来自 msvbvm50.74043757
0012F150 00010708 |hWnd = 00010708 (class='ThunderRT5TextBox',parent=00010706)
0012F154 0091BE40 |Buffer = 0091BE40
0012F158 00000007 \Count = 0x7
2.此时还在系统领空,Alt+F9返回到用户代码,这应该是到了vb的用户代码处吧
00402458 . FF93 A4000000 call dword ptr ds:[ebx+0xA4] ; msvbvm50.74070D32
0040245E . 85C0 test eax,eax
00402460 . 7D 12 jge short Afkayas_.00402474
3.接下来开始单步跟,不懂的函数直接丢百度
0040246E . FF15 04414000 call dword ptr ds:[<&MSVBVM50.__vbaHresultCheckObj>] ; msvbvm50.__vbaHresultCheckObj
00402482 . FF15 5C414000 call dword ptr ds:[<&MSVBVM50.__vbaFreeStrList>] ; msvbvm50.__vbaFreeStrList
00402499 . FF15 F4404000 call dword ptr ds:[<&MSVBVM50.__vbaFreeObjList>] ; msvbvm50.__vbaFreeObjList
004024AB . 8B1D 0C414000 mov ebx,dword ptr ds:[<&MSVBVM50.__vbaObjSet>] ; msvbvm50.__vbaObjSet
......
vbaHresultCheckObj 检查结果对象?
vbaFreeStrList 释放一个字符串?
vbaFreeObjList 释放一个对象?
vbaObjSet 给对象赋值?
......
4.不瞎浪费时间,一路F8看看在哪出现我们输入的字符串吧
00402510 > \8B45 E8 mov eax,dword ptr ss:[ebp-0x18] ; 输入的serial123456
00402513 . 8B4D E4 mov ecx,dword ptr ss:[ebp-0x1C] ; 682770
00402516 . 8B3D 00414000 mov edi,dword ptr ds:[<&MSVBVM50.__vbaStrCat>] ; msvbvm50.__vbaStrCat
0040251C . 50 push eax ; 123456入栈
0040251D . 68 701B4000 push Afkayas_.00401B70 ; UNICODE "AKA-"
00402522 . 51 push ecx ; /String = "溆"
00402523 . FFD7 call edi ; \__vbaStrCat
00402525 . 8B1D 70414000 mov ebx,dword ptr ds:[<&MSVBVM50.__vbaStrMove>] ; 拼接字符串AKA-682770
0040252B . 8BD0 mov edx,eax
0040252D . 8D4D E0 lea ecx,dword ptr ss:[ebp-0x20]
00402530 . FFD3 call ebx ; msvbvm50.__vbaStrMove; <&MSVBVM50.__vbaStrMove>
00402532 . 50 push eax ; 比较两个字符串是否相等
00402533 . FF15 28414000 call dword ptr ds:[<&MSVBVM50.__vbaStrCmp>] ; msvbvm50.__vbaStrCmp
5.虽然找到了真码,可是算法在哪呢?根据一路走过来的流程,可以看到真码由AKA-拼接682770构成,那么682770从哪来的?为什么没有看到获取52pojie的地方呢?是不是还是不能用Windows API断点?算了,不要紧,反正已经定位到了关键比较函数了,在往上回溯就行了,去段首F2下断点,然后单步开始跟,看看有没有线索
00402403 . FF15 04414000 call dword ptr ds:[<&MSVBVM50.__vbaHresultCheckObj>] ; msvbvm50.__vbaHresultCheckObj
00402409 > 8B95 50FFFFFF mov edx,dword ptr ss:[ebp-0xB0]
0040240F . 8B45 E4 mov eax,dword ptr ss:[ebp-0x1C] ; 经过上面那个call,52pojie就出来了
00402412 . 50 push eax ; /String = "682770"
00402413 . 8B1A mov ebx,dword ptr ds:[edx] ; |计算长度
00402415 . FF15 E4404000 call dword ptr ds:[<&MSVBVM50.__vbaLenBstr>] ; \__vbaLenBstr
0040241B . 8BF8 mov edi,eax ; 此时eax是7,赋值给edi
0040241D . 8B4D E8 mov ecx,dword ptr ss:[ebp-0x18] ; 将52pojie赋值给ecx
00402420 . 69FF FB7C0100 imul edi,edi,0x17CFB ; name的长度7*0x17CFB=0xA6ADD
00402426 . 51 push ecx ; /String = 0000104A ???
00402427 . 0F80 91020000 jo Afkayas_.004026BE ; |如果溢出就跳转
0040242D . FF15 F8404000 call dword ptr ds:[<&MSVBVM50.#rtcAnsiValueBstr_516>] ; \rtcAnsiValueBstr
00402433 . 0FBFD0 movsx edx,ax ; 取第一个字符的值0x35给edx
00402436 . 03FA add edi,edx ; 0xA6ADD+0x35=0XA6B12
00402438 . 0F80 80020000 jo Afkayas_.004026BE ; 如果溢出就跳转
0040243E . 57 push edi ; edi入栈
0040243F . FF15 E0404000 call dword ptr ds:[<&MSVBVM50.__vbaStrI4>] ; msvbvm50.__vbaStrI4
00402445 . 8BD0 mov edx,eax ; 出栈后eax=682770
不懂的地方百度一下:
imul三操作数格式
32 位模式下的三操作数格式将乘积保存在第一个操作数中。第二个操作数可以是 16 位寄存器或内存操作数,它与第三个操作数相乘,该操作数是一个8位或16 位立即数。
IMUL 执行时,若乘积有效位被丢弃,则溢出标志位和进位标志位置 1。因此,在执行了有三个操作数的 IMUL 操作后,必须检查这些标志位中的一个。
6.0XA6B12经过0040243F这个call就变成了682770,经历过上一个CM的大坑,我这次0XA6B12直接丢电脑自带的计算器转换一下,果然就是682770,到了这里算法也就分析完毕了。
0x4注册机的编写
1.算法部分:输入的字符串长度*0x17CFB+字符串的第一个字符,然后如果没有溢出,就将结果转换成10进制数对应的字符串。
2.代码实现:
package cpyutil.xiao.cai.niao.com;
import java.util.Scanner;
public class Register {
public static void main(String[] args) {
String name;
String str1 = "AKA-";
String str2 = null;
int code;
String serial;
System.out.println("请输入name(不小于4个字符):");
Scanner sc = new Scanner(System.in);// 初始化一个输入流
name = sc.nextLine();// 从控制台读取输入的字符串
if (name == null || name.length() < 4)// 如果输入的长度小于4退出程序
System.exit(0);
sc.close();// 关闭输入流
//计算注册码后半部分
code = name.length() * 0x17CFB;
if(code < 0)//发生溢出
{
System.out.println("很抱歉,您输入的name没有对应的序列号");
}
code += name.charAt(0);
if(code < 0)//发生溢出
{
System.out.println("很抱歉,您输入的name没有对应的序列号");
}
// 将其转换成字符串
str2 = String.valueOf(code);
serial = str1 + str2;//拼接字符串
// 输出正确的serial
System.out.println("生成的serial:");
System.out.println(serial);
}
}
输出结果:
请输入name(不小于4个字符):
52pojie
生成的serial:
AKA-682770
3.当然了,这个程序其实并没有限制name不少于4个字符,别被误导了哦。
0x5总结
1.只会一点C++的皮毛,做起论坛的CM果然是好大的压力啊。
2.幸运的是VB程序可以使用GetWindowTextA,不至于又逼得我去搜索字符串了。
3.上个程序弄懂了,这个CM其实并不难,都是一样的套路,取name,计算注册码,然后把数值转换十进制,然后再转换成字符串类型。
PS:善于总结,善于发现,找到分析问题的思路和解决问题的办法。虽然我现在还是零基础的小菜鸟一枚,也许学习逆向逆天改命我会失败,但也有着成功的可能,只要还有希望,就决不放弃!