首页
社区
课程
招聘
[原创]一个Crick的完整分析,以及算法函数的寻找+实现过程!
发表于: 2014-8-4 19:57 7304

[原创]一个Crick的完整分析,以及算法函数的寻找+实现过程!

2014-8-4 19:57
7304

//学习了一段时间的破解,前两天在论坛上看见了知心人发的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期)

上传的附件:
收藏
免费 3
支持
分享
最新回复 (9)
雪    币: 193
活跃值: (1215)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
好好好,mark一下,有恐学习一下
2014-8-4 20:04
0
雪    币: 517
活跃值: (35)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
3
对VB函数的理解可能有些人存在较大误差。
2014-8-4 22:38
0
雪    币: 83
活跃值: (158)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
4
嗯是 这样的,VB 程序代码是直接写在事件里面的,所以一些人可能会找错地方。
2014-8-5 00:25
0
雪    币: 435
活跃值: (14)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
前排支持。不错不错,新手学习了。哈哈哈。
2014-8-5 00:32
0
雪    币: 47147
活跃值: (20450)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
6
帖子移 『CrackMe&ReverseMe』版块。
恭喜楼主功力又提升了一级!
2014-8-12 15:43
0
雪    币: 11
活跃值: (80)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
感谢分享
2014-8-12 16:51
0
雪    币: 83
活跃值: (158)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
8
感谢版主。推荐精华,
2014-8-12 18:00
0
雪    币: 309
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
支持。不错不错,新手学习了。
2014-8-14 23:20
0
雪    币: 354
活跃值: (30)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
10
好文章,学习,感谢
2014-8-15 22:23
0
游客
登录 | 注册 方可回帖
返回
//