学破解第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"
```
  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: ;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: ;输入的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
```
  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 操作后,必须检查这些标志位中的一个。
  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:善于总结,善于发现,找到分析问题的思路和解决问题的办法。虽然我现在还是零基础的小菜鸟一枚,也许学习逆向逆天改命我会失败,但也有着成功的可能,只要还有希望,就决不放弃!** 加油!楼主已经很棒了! 虽然看不懂。但的支持楼主 加油 楼主加油 加油,绝不放弃! 虽然看不懂,加油 太欣赏楼主了,继续加油啊 只要还有希望,就决不放弃 谢谢分享~~ 看不太懂,不过加油。比我牛掰多了