小菜鸟一枚 发表于 2020-7-17 17:46

学破解第118天,《160个CrackerMe之002》学习

## 学破解第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:
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:
004025AB   . |8945 CC       mov dword ptr ss:,eax
004025AE   . |8D55 A4       lea edx,dword ptr ss:
004025B1   . |51            push ecx
004025B2   . |8D45 B4       lea eax,dword ptr ss:
004025B5   . |52            push edx
004025B6   . |50            push eax
004025B7   . |8D4D C4       lea ecx,dword ptr ss:
004025BA   . |6A 00         push 0x0
004025BC   . |51            push ecx
004025BD   . |C745 C4 08000>mov dword ptr ss:,0x8
004025C4   . |FF15 10414000 call dword ptr ds:[<&MSVBVM50.#rtcMsgBox_595>]            ;msvbvm50.rtcMsgBox
004025CA   . |8D4D E8       lea ecx,dword ptr ss:
004025CD   . |FF15 80414000 call dword ptr ds:[<&MSVBVM50.__vbaFreeStr>]            ;msvbvm50.__vbaFreeStr
004025D3   . |8D55 94       lea edx,dword ptr ss:
004025D6   . |8D45 A4       lea eax,dword ptr ss:
004025D9   . |52            push edx
004025DA   . |8D4D B4       lea ecx,dword ptr ss:
004025DD   . |50            push eax
004025DE   . |8D55 C4       lea edx,dword ptr ss:
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"
```

&emsp;&emsp;3.接下来不用我说也知道吧,直接把0040258B这里的je nop掉即可爆破成功。

### 0x3分析算法
&emsp;&emsp;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
```

&emsp;&emsp;2.此时还在系统领空,Alt+F9返回到用户代码,这应该是到了vb的用户代码处吧
```
00402458   .FF93 A4000000 call dword ptr ds:                              ;msvbvm50.74070D32
0040245E   .85C0          test eax,eax
00402460   .7D 12         jge short Afkayas_.00402474
```

&emsp;&emsp;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 给对象赋值?
......

&emsp;&emsp;4.不瞎浪费时间,一路F8看看在哪出现我们输入的字符串吧
```
00402510   > \8B45 E8       mov eax,dword ptr ss:                           ;输入的serial123456
00402513   .8B4D E4       mov ecx,dword ptr ss:                           ;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:
00402530   .FFD3          call ebx                                                ;msvbvm50.__vbaStrMove; <&MSVBVM50.__vbaStrMove>
00402532   .50            push eax                                                ;比较两个字符串是否相等
00402533   .FF15 28414000 call dword ptr ds:[<&MSVBVM50.__vbaStrCmp>]               ;msvbvm50.__vbaStrCmp
```

&emsp;&emsp;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:
0040240F   .8B45 E4       mov eax,dword ptr ss:                           ;经过上面那个call,52pojie就出来了
00402412   .50            push eax                                                ; /String = "682770"
00402413   .8B1A          mov ebx,dword ptr ds:                              ; |计算长度
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:                           ;将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 操作后,必须检查这些标志位中的一个。

&emsp;&emsp;6.0XA6B12经过0040243F这个call就变成了682770,经历过上一个CM的大坑,我这次0XA6B12直接丢电脑自带的计算器转换一下,果然就是682770,到了这里算法也就分析完毕了。

### 0x4注册机的编写
&emsp;&emsp;1.算法部分:输入的字符串长度*0x17CFB+字符串的第一个字符,然后如果没有溢出,就将结果转换成10进制数对应的字符串。

&emsp;&emsp;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

&emsp;&emsp;3.当然了,这个程序其实并没有限制name不少于4个字符,别被误导了哦。

### 0x5总结
&emsp;&emsp;1.只会一点C++的皮毛,做起论坛的CM果然是好大的压力啊。

&emsp;&emsp;2.幸运的是VB程序可以使用GetWindowTextA,不至于又逼得我去搜索字符串了。

&emsp;&emsp;3.上个程序弄懂了,这个CM其实并不难,都是一样的套路,取name,计算注册码,然后把数值转换十进制,然后再转换成字符串类型。

&emsp;&emsp;**PS:善于总结,善于发现,找到分析问题的思路和解决问题的办法。虽然我现在还是零基础的小菜鸟一枚,也许学习逆向逆天改命我会失败,但也有着成功的可能,只要还有希望,就决不放弃!**

acsecqb 发表于 2020-7-17 17:57

加油!楼主已经很棒了!

garen 发表于 2020-7-17 18:39

虽然看不懂。但的支持楼主 加油

多余呀 发表于 2020-7-17 18:59

楼主加油

gms 发表于 2020-7-17 19:27

加油,绝不放弃!

sifan785622020 发表于 2020-7-17 21:09

虽然看不懂,加油

查无此凡 发表于 2020-7-17 21:51

太欣赏楼主了,继续加油啊

咕咚陛下 发表于 2020-7-18 08:39

只要还有希望,就决不放弃

pp125109139 发表于 2020-7-18 09:59

谢谢分享~~

tpeiewjkdw4 发表于 2020-7-18 13:45

看不太懂,不过加油。比我牛掰多了
页: [1] 2 3
查看完整版本: 学破解第118天,《160个CrackerMe之002》学习