//学习了一段时间的破解,前两天在论坛上看见了知心人发的160个cracking ,自己就尝试连了,一些,第一次发帖,由于技术有限,错误的地方请大牛指出,希望帮助那些和我一样的新手快速入门,尽力做的清晰明了。--大牛就可以飘过了。
目标:Afkayas Nag,Name/Serial(VB5)
保护:没有任何保护
方法:注册算法+算法注册机编写(C语言)
开始:
由于没有任何保护。所以直接OD载入,F9 跑起程序,
// VB用的是UNICODE编码,所以直接搜索UNICODE字符串 找到一些字符串,非常简单,很容易就能明白注册关键代码
中文搜索引擎
地址 反汇编 文本字符串
004085EF JNZ SHORT AfKayAs_.004085F9 (Initial CPU selection)
0040867F PUSH AfKayAs_.00406FC0 You Get It //看到这里都明白是正确消息框的意思
00408684 PUSH AfKayAs_.00406FDC \r\n // 这里两个一个是 回车 一个是换行的意思
00408697 PUSH AfKayAs_.00406FE8 Key Gen It Now //正确字符串
004086E1 PUSH AfKayAs_.00407008 You Get Wrong //如意 wrong
004086E6 PUSH AfKayAs_.00406FDC \r\n
004086F9 PUSH AfKayAs_.00407028 Try Again
双击直接定位到YOU Get It
004086D0 8D45 B4 LEA EAX,DWORD PTR SS:[EBP-0x4C]
004086D3 52 PUSH EDX
004086D4 8D4D C4 LEA ECX,DWORD PTR SS:[EBP-0x3C]
004086D7 50 PUSH EAX
004086D8 51 PUSH ECX
00408677 /74 62 JE SHORT AfKayAs_.004086DB ; 关键跳,如果ZF等于0就跳转到下面错误消息弹弹出窗口的地方 (如果是采用暴力破解程序这里直接改成JMP就可以了,)
//个人觉得暴力破解不利于以后学习,所以建议和我一样的小鸟学习的时候多分析,不用总是采用暴力破解,不然学不到多少东西。
00408679 |8B35 14B14000 MOV ESI,DWORD PTR DS:[<&MSVBVM50.__vbaSt>; MSVBVM50.__vbaStrCat // 调用一个字符串处理函数,(字符串连接用的。因为他正确消息框显示了2个字符串)
0040867F |68 C06F4000 PUSH AfKayAs_.00406FC0 ; You Get It 压入字符串到堆栈
00408684 |68 DC6F4000 PUSH AfKayAs_.00406FDC ; \r\n 压入格式控制到堆栈
00408689 |FFD6 CALL ESI // 调用(strCat)函数
0040868B |8BD0 MOV EDX,EAX // eax的值赋值给EDX eax=edx= You Get It
0040868D |8D4D E8 LEA ECX,DWORD PTR SS:[EBP-0x18] //这里将这个堆栈段的地址赋值给ECX 可以在寄存器的ECX查看一下
00408690 |FF15 94B14000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaStrMo>; MSVBVM50.__vbaStrMove //字符串分解函数
00408696 |50 PUSH EAX // EAX= you get it
00408697 |68 E86F4000 PUSH AfKayAs_.00406FE8 ; Key Gen It Now
0040869C |FFD6 CALL ESI //这个函数就是将这2个字符串在MSG消息框中以2行形式显示
0040869E |8945 CC MOV DWORD PTR SS:[EBP-0x34],EAX
004086A1 |8D45 94 LEA EAX,DWORD PTR SS:[EBP-0x6C]
004086A4 |8D4D A4 LEA ECX,DWORD PTR SS:[EBP-0x5C]
004086A7 |50 PUSH EAX
004086A8 |8D55 B4 LEA EDX,DWORD PTR SS:[EBP-0x4C]
004086AB |51 PUSH ECX
004086AC |52 PUSH EDX
004086AD |8D45 C4 LEA EAX,DWORD PTR SS:[EBP-0x3C]
004086B0 |6A 00 PUSH 0x0
004086B2 |50 PUSH EAX
004086B3 |C745 C4 0800000>MOV DWORD PTR SS:[EBP-0x3C],0x8
004086BA |FF15 24B14000 CALL DWORD PTR DS:[<&MSVBVM50.#595>] ; MSVBVM50.rtcMsgBox //根据前面的那些参数可以看出是弹出正确的MSG消息框
004086C0 |8D4D E8 LEA ECX,DWORD PTR SS:[EBP-0x18]
004086C3 |FF15 A8B14000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaFreeS>; MSVBVM50.__vbaFreeStr //释放分配的资源
004086C9 |8D4D 94 LEA ECX,DWORD PTR SS:[EBP-0x6C]
004086CC |8D55 A4 LEA EDX,DWORD PTR SS:[EBP-0x5C]
004086CF |51 PUSH ECX
004086D0 |8D45 B4 LEA EAX,DWORD PTR SS:[EBP-0x4C]
004086D3 |52 PUSH EDX
004086D4 |8D4D C4 LEA ECX,DWORD PTR SS:[EBP-0x3C]
004086D7 |50 PUSH EAX
004086D8 |51 PUSH ECX
004086D9 |EB 60 JMP SHORT AfKayAs_.0040873B
004086DB \8B35 14B14000 MOV ESI,DWORD PTR DS:[<&MSVBVM50.__vbaSt>; MSVBVM50.__vbaStrCat
004086E1 68 08704000 PUSH AfKayAs_.00407008 ; You Get Wrong
004086E6 68 DC6F4000 PUSH AfKayAs_.00406FDC ; \r\n
004086EB FFD6 CALL ESI //和上面分析一样
004086ED 8BD0 MOV EDX,EAX
004086EF 8D4D E8 LEA ECX,DWORD PTR SS:[EBP-0x18]
通过上面的调试分析 可以看出这里的代码可以分2个 分别是弹出2个消息框用C语言可以
If(x==0)
{
压入错误消息框MSG参数
弹出错误消息框。
}
Else
{
压入正确消息框MSG参数
正确消息框
}
那么怎么定位到程序调用消息窗口的函数地方呢。 1. 可以直接向上面找,通常是可以找到的。 2.可以通过设置消息断点。但是要麻烦许多,一般都会跳到系统库里面。
这里是直接向上找,就可以找到 调用函数关键代码
004085D1 50 PUSH EAX ; 压入用户密码
004085D2 FF15 74B14000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaR8Str>] ; 可能是计算正确密码
004085D8 8B4D E4 MOV ECX,DWORD PTR SS:[EBP-0x1C] ; 正确密码 ()SS:[EBP-0x1C] 0018f41c 跟紧这个地址
004085DB DD9D 1CFFFFFF FSTP QWORD PTR SS:[EBP-0xE4]
004085E1 51 PUSH ECX
004085E2 FF15 74B14000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaR8Str>] ; MSVBVM50.__vbaR8Str
004085E8 833D 00904000 0>CMP DWORD PTR DS:[0x409000],0x0 ; 关键位置 00409000不能为0
004085EF 75 08 JNZ SHORT AfKayAs_.004085F9
004085F1 DCBD 1CFFFFFF FDIVR QWORD PTR SS:[EBP-0xE4]
004085F7 EB 11 JMP SHORT AfKayAs_.0040860A
004085F9 FFB5 20FFFFFF PUSH DWORD PTR SS:[EBP-0xE0]
004085FF FFB5 1CFFFFFF PUSH DWORD PTR SS:[EBP-0xE4]
00408605 E8 888AFFFF CALL <JMP.&MSVBVM50._adj_fdivr_m64>
0040860A DFE0 FSTSW AX
0040860C A8 0D TEST AL,0xD ; AX的值与 13进行与操作 结果必须不为0
0040860E 0F85 AB010000 JNZ AfKayAs_.004087BF //这里ZF不等于0程序会错误
00408614 FF15 34B14000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaFpR8>] ; MSVBVM50.__vbaFpR8
0040861A DC1D 28104000 FCOMP QWORD PTR DS:[0x401028]
00408620 DFE0 FSTSW AX ; 把状态寄存器的值存入AX
00408622 F6C4 40 TEST AH,0x40 ; AH 必须等于40 下面才能指向正确的窗口
00408625 74 07 JE SHORT AfKayAs_.0040862E ; 关键代码(这里如果跳转成功表示用户输入密码是错误的)
00408627 BE 01000000 MOV ESI,0x1
0040862C EB 02 JMP SHORT AfKayAs_.00408630
0040862E 33F6 XOR ESI,ESI
00408630 8D55 E4 LEA EDX,DWORD PTR SS:[EBP-0x1C] // SS:[EBP-0x1C] 放置正确密码的栈段地址传递给EDX
00408633 8D45 E8 LEA EAX,DWORD PTR SS:[EBP-0x18] //用户输入密码地址传递给EAX
//就上面而言得到正确注册码很简单,甚至不用OD分析都可以达到, 直接用CE搜索下用户输入密码,在加个一级偏移可能就能找到正确注册码。但是遇到变态的程序,你在调试的时候是很难直接看见一个完整字符串密码或者注册码的。
看到正确密码的 004085D8 8B4D E4 MOV ECX,DWORD PTR SS:[EBP-0x1C] 这里大家可能都以为 上面那个估计就是计算正确密码的函数了,
其实不然, 注意这个SS:[EBP-0x1C] 0018f41c 地址这里保存了运算结果,所以一些函数必定要操作这个地址,那么简单了,我们随便输入个密码在这个计算函数前面一点下个段,然后 dd SS:[EBP-0x1C] 0018f41c 这个地址发现里面有一串数字,带入前面的账号,弹出正确消息框,那说明了什么,说明在这个函数前面就已经有了正确密码,那说明这个也不是验证码计算函数。那么我们该怎么着计算函数呢,。。其实简单, 只要跟着SS:[EBP-0x1C] 0018f41c 这个地址就可以了。我们往上面找,隔一段地址就下断看看有没有用户或者密码,或者什么关键信息。
-----这个时候耐心很重要了,我自己找的时候也跟错了很多函数。一进去乱七八糟的,分析了半天发现不是。解决办法,------打开QQ 音乐来点杀马特音乐
提前说明下注册码的计算过程 : 用户名->值A->值A+2->值B->值B+15>正确注册码
好了开了 我们继续向上面跟。
004084DF FF15 74B14000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaR8Str>] ; MSVBVM50.__vbaR8Str
004084E5 DC25 20104000 FSUB QWORD PTR DS:[0x401020] ; 把浮点数寄存器中的值减去-15 既+15得到正确注册码,这里是关键注意浮点数寄存器
004084EB 83EC 08 SUB ESP,0x8
004084EE DFE0 FSTSW AX
004084F0 A8 0D TEST AL,0xD
004084F2 0F85 C7020000 JNZ AfKayAs_.004087BF
004084F8 DD1C24 FSTP QWORD PTR SS:[ESP]
004084FB FF15 48B14000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaStrR8>] ; MSVBVM50.__vbaStrR8
00408501 8BD0 MOV EDX,EAX ; 正确的注册码
00408503 8D4D E4 LEA ECX,DWORD PTR SS:[EBP-0x1C]
00408506 FF15 94B14000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaStrMove>] ; MSVBVM50.__vbaStrMove
那么继续想上面跟,找004084E5 DC25 20104000 FSUB QWORD PTR DS:[0x401020] 中浮点数寄存器值相关的代码,
004083E3 FF15 18B14000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaHresultCheckObj>] ; MSVBVM50.__vbaHresultCheckObj
004083E9 8B8D 58FFFFFF MOV ECX,DWORD PTR SS:[EBP-0xA8]
004083EF 8B55 E8 MOV EDX,DWORD PTR SS:[EBP-0x18]
004083F2 52 PUSH EDX
004083F3 8B19 MOV EBX,DWORD PTR DS:[ECX] ; //注意右边的浮点数寄存器
004083F5 FF15 74B14000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaR8Str>] ; MSVBVM50.__vbaR8Str
004083FB DC0D 10104000 FMUL QWORD PTR DS:[0x401010] ; 这里计算出关键值用53384*3= ST0=1600152 值B
00408401 83EC 08 SUB ESP,0x8
00408404 DC25 18104000 FSUB QWORD PTR DS:[0x401018] ; 1600152减去-2 1600152与注册码计算相关数值 注意这里 值B-2
0040840A DFE0 FSTSW AX
0040840C A8 0D TEST AL,0xD
0040840E 0F85 AB030000 JNZ AfKayAs_.004087BF
00408414 DD1C24 FSTP QWORD PTR SS:[ESP]
00408417 FF15 48B14000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaStrR8>] ; MSVBVM50.__vbaStrR8
0040841D 8BD0 MOV EDX,EAX ; EAX =1600150 传递给EDX
0040841F 8D4D E4 LEA ECX,DWORD PTR SS:[EBP-0x1C] ; 这里将 533384地址传递给ECX 这个段寄存器中的值也是与注册码相关的值。
00408422 FF15 94B14000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaStrMove>] ; MSVBVM50.__vbaStrMove
00408428 899D 2CFFFFFF MOV DWORD PTR SS:[EBP-0xD4],EBX
0040842E 8B9D 58FFFFFF MOV EBX,DWORD PTR SS:[EBP-0xA8]
00408434 50 PUSH EAX ; 与正确注册码有关
00408435 8B85 2CFFFFFF MOV EAX,DWORD PTR SS:[EBP-0xD4]
0040843B 53 PUSH EBX
0040843C FF90 A4000000 CALL DWORD PTR DS:[EAX+0xA4]
继续想上面找值A+2的地方
00408322 A8 0D TEST AL,0xD
00408324 0F85 95040000 JNZ AfKayAs_.004087BF
0040832A DD1C24 FSTP QWORD PTR SS:[ESP]
0040832D FF15 48B14000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaStrR8>] ; 值A+2
00408333 8BD0 MOV EDX,EAX ; 533384
00408335 8D4D E4 LEA ECX,DWORD PTR SS:[EBP-0x1C]
00408338 FF15 94B14000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaStrMove>] ; MSVBVM50.__vbaStrMove
这里先不分析那些CALL的执行过程,只需要推测注册码怎么来的就可以了。
好了继续想上面找值A
004081E3 FF15 18B14000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaHresultCheckObj>] ; MSVBVM50.__vbaHresultCheckObj
004081E9 8B95 50FFFFFF MOV EDX,DWORD PTR SS:[EBP-0xB0]
004081EF 8B45 E4 MOV EAX,DWORD PTR SS:[EBP-0x1C] ; 压入用户名
004081F2 50 PUSH EAX ; 将用户名压入堆栈
004081F3 8B1A MOV EBX,DWORD PTR DS:[EDX]
004081F5 FF15 F8B04000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaLenBstr>] ; 计算用户名长度
004081FB 8BF8 MOV EDI,EAX ; 将用户名长度赋值给EDI
004081FD 8B4D E8 MOV ECX,DWORD PTR SS:[EBP-0x18] ; 将用户名赋值给ECX
00408200 69FF 385B0100 IMUL EDI,EDI,0x15B38 ; 15B38 10进制=88888 不知道意义何在这里
00408206 51 PUSH ECX
00408207 0F80 B7050000 JO AfKayAs_.004087C4 ; JO 表示 OF溢出标志位=1 就跳转
0040820D FF15 0CB14000 CALL DWORD PTR DS:[<&MSVBVM50.#516>] ; MSVBVM50.rtcAnsiValueBstr
00408213 0FBFD0 MOVSX EDX,AX ; 代符号扩展的传送指令
00408216 03FA ADD EDI,EDX 这里这个值很奇怪 把他转换成10进制看看 发现这里就是值A 根本计算过程
00408218 0F80 A6050000 JO AfKayAs_.004087C4
0040821E 57 PUSH EDI
0040821F FF15 F4B04000 CALL DWORD PTR DS:[<&MSVBVM50.__vbaStrI4>] ; 计算可能是出值A的函数
好了到这里基本可以推测出注册的形式了,只需要知道值A怎么来的就可以了
00408216 03FA ADD EDI,EDX 通过这里 可以知道 值A= ADD EDI,EDX 那么只需要知道EDI 和EDX就可以了 00408213 0FBFD0 MOVSX EDX,AX 这里可以看出EDX =AX 0040820D FF15 0CB14000 CALL DWORD PTR DS:[<&MSVBVM50.#516>] 这里看出 AX=用户账号第一个字符 的ansi 的编码值
00408200 69FF 385B0100 IMUL EDI,EDI,0x15B38 这里可以看出 EDI的值 = EDI*0x15b38 得出的 那继续向上面跟 EDI=EAX EAX=用户名长度值
好了进过分析总结出了注册码的计算方法,这个代码跨度还是挺大的!!。。不像C语言程序注册码计算都在一个函数里面多方便。
注册码=(用户名长度值*0x15B38+用户名字符串第一个字符串的ansi+2)*3-2+15
C语言算法注册机
# include <stdio.h>
# include <string.h>
int main()
{
char user[20];
char s;
int len;
int number;
int ansi;
printf("请输入用户名:");
scanf("%s",&user);
s=user[0];
ansi=(int)s;
len=strlen(user);
//printf("%d",ansi);
number=(len*0x15B38+ansi+2)*3-2+15;
printf("注册码为:%d",number);
return 0;
}
好了分析结束了,第一次发帖很多地方注意不到,希望大家能体谅。。。
附加里面我吧WORD文档和程序都添加了
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)