《加密与解密》第三篇非明码比较分析,个人实战

所谓非明码就是软件没有在代码了直接写出与其计算出的序列号比较得出是否符合,而是通过一种绕弯的方式进行进行用户名与序列号比较,在OD或者某反汇编中难以找到正确的序列号而是通过一个等式进行判断用户是否输入正确:



K1(用户名) = K2(序列号)

在虚拟机中用OD打开例子程序serialt.exe,运行它、点Help/Register弹出一个对话框随便输入一个“Name :zhanghanyu123”,“123456789”、点击"OK"按钮弹出,在OD中点查找/所有匹配字符串、看这是一件捕获到你输入的Name和序列号了

双击这个地址来到关键代码处:


反汇编代码如下:

 
 

00401228    68 8E214000     push serialt.0040218E                    ; ASCII "ZHANGHANYU"
0040122D    E8 4C010000     call serialt.0040137E                    ; 调用计算用户名得出一个数值
00401232    50              push eax
00401233    68 7E214000     push serialt.0040217E                    ; ASCII "123456789"
00401238    E8 9B010000     call serialt.004013D8                    ; 调用计算一个输入的序列号得出数值

在0040122D这个地方下一个断点,重新跑程序,进入断点处,F7进入CALL调用的函数内部


扫描二维码关注公众号,回复: 3163313 查看本文章

具体分析如下:

0040137E    8B7424 04       mov esi,dword ptr ss:[esp+0x4]           ; esi = 压入栈中的name存放地址
00401382    56              push esi                                 ; 再次将esi压入栈中
00401383    8A06            mov al,byte ptr ds:[esi]                 ; esi的一个字节给al
00401385    84C0            test al,al                               ; 比较al是否为空
00401387    74 13           je short serialt.0040139C                ; 空的那么就跳到0040139C地址处
00401389    3C 41           cmp al,0x41                              ; 字符与41h相比较(与“A”相比较)
0040138B    72 1F           jb short serialt.004013AC                ; 如果小于A那么就不是字母跳到004013AC
0040138D    3C 5A           cmp al,0x5A                              ; 字符再次与5AH比较(与“z”比较)
0040138F    73 03           jnb short serialt.00401394               ; al不低于5Ah(“z”ASCII值)就跳转00401394
00401391    46              inc esi                                  ; esi+1指向下一个字符(字节)
00401392  ^ EB EF           jmp short serialt.00401383               ; 无条件跳到00401383处执行循环
00401394    E8 39000000     call serialt.004013D2
00401399    46              inc esi                                  ; esi+1指向下一个字符
0040139A  ^ EB E7           jmp short serialt.00401383               ; 继续循环
0040139C    5E              pop esi                                  ; esi出栈
0040139D    E8 20000000     call serialt.004013C2                    ; 跳004013C2函数处
004013A2    81F7 78560000   xor edi,0x5678                           ; edi的字符相加的值域5678h进行异或运算
004013A8    8BC7            mov eax,edi                              ; 得出的值给eax
004013AA    EB 15           jmp short serialt.004013C1               ; 跳004013C1返回函数外部指向下一行代码
004013AC    5E              pop esi
004013AD    6A 30           push 0x30
004013AF    68 60214000     push serialt.00402160                    ; ASCII "Error!  "
004013B4    68 69214000     push serialt.00402169                    ; ASCII "Incorrect!,Try Again"
004013B9    FF75 08         push dword ptr ss:[ebp+0x8]
004013BC    E8 79000000     call <jmp.&USER32.MessageBoxA>           ; 错误信息提示超出范围
004013C1    C3              retn
004013C2    33FF            xor edi,edi                              ; edi清0
004013C4    33DB            xor ebx,ebx                              ; ebx清0
004013C6    8A1E            mov bl,byte ptr ds:[esi]                 ; 拿出esi数据中一个字节给bl
004013C8    84DB            test bl,bl                               ; 判断name中还有字符吗?
004013CA    74 05           je short serialt.004013D1                ; 没有则跳到004013D1返回
004013CC    03FB            add edi,ebx                              ; 将ebx中的字符依次相加
004013CE    46              inc esi                                  ; esi+1指向下一个字符(字节)
004013CF  ^ EB F5           jmp short serialt.004013C6               ; 跳到004013C6循环次操作直到name字符没有为止
004013D1    C3              retn                                     ; 返回004013A2处
004013D2    2C 20           sub al,0x20                              ; al-20h 相当于吧小写字母变成大写字母
004013D4    8806            mov byte ptr ds:[esi],al                 ; 得到的大写字母值重新放入esi中
004013D6    C3              retn                                     ; 返回00401399处

返回外部,执行下一行代码!


F7继续执行同理下面CALL也一样,进入CALL内部

代码如下


代码具体分析如下:

004013C2    33FF            xor edi,edi                              ; edi清0
004013C4    33DB            xor ebx,ebx                              ; ebx清0
004013C6    8A1E            mov bl,byte ptr ds:[esi]                 ; 拿出esi数据中一个字节给bl
004013C8    84DB            test bl,bl                               ; 判断name中还有字符吗?
004013CA    74 05           je short serialt.004013D1                ; 没有则跳到004013D1返回
004013CC    03FB            add edi,ebx                              ; 将ebx中的字符依次相加
004013CE    46              inc esi                                  ; esi+1指向下一个字符(字节)
004013CF  ^ EB F5           jmp short serialt.004013C6               ; 跳到004013C6循环次操作直到name字符没有为止
004013D1    C3              retn                                     ; 返回004013A2处
004013D2    2C 20           sub al,0x20                              ; al-20h 相当于吧小写字母变成大写字母
004013D4    8806            mov byte ptr ds:[esi],al                 ; 得到的大写字母值重新放入esi中
004013D6    C3              retn                                     ; 返回00401399处
004013D7    C3              retn
004013D8    33C0            xor eax,eax                              ; eax清0
004013DA    33FF            xor edi,edi                              ; edi清0
004013DC    33DB            xor ebx,ebx                              ; ebx清0
004013DE    8B7424 04       mov esi,dword ptr ss:[esp+0x4]           ; 存放序列号的地址给esi
004013E2    B0 0A           mov al,0xA                               ; al=0Ah
004013E4    8A1E            mov bl,byte ptr ds:[esi]                 ; 将esi地址第一个字节(字符)给bl
004013E6    84DB            test bl,bl                               ; bl是否为空(是否全部没有)
004013E8    74 0B           je short serialt.004013F5                ; 相等则直接跳走进行异或运算
004013EA    80EB 30         sub bl,0x30                              ; bl=bl-30h code[i]-30h
004013ED    0FAFF8          imul edi,eax                             ; edi=edi*0ah相当与左移1位
004013F0    03FB            add edi,ebx                              ; 将每个字符计算出的数值加起来
004013F2    46              inc esi                                  ; esi指向下一个字符 循环
004013F3  ^ EB ED           jmp short serialt.004013E2
004013F5    81F7 34120000   xor edi,0x1234                           ; 最后结果进行异或运算
004013FB    8BDF            mov ebx,edi                              ; 值放入ebx中
004013FD    C3              retn                                     ; 返回CALL下一行代码

返回我们看见了核心的比较


代码分析如下:

00401241    3BC3            cmp eax,ebx                              ; eax(用户名的计算结果)是否等于ebx(序列号的计算结果)
00401243    74 07           je short serialt.0040124C                ; 相等跳到0040124C执行CALL
00401245    E8 18010000     call serialt.00401362
0040124A  ^ EB 9A           jmp short serialt.004011E6
0040124C    E8 FC000000     call serialt.0040134D
00401251  ^ EB 93           jmp short serialt.004011E6
0040134D具体如下:

{

0040134D    6A 30           push 0x30
0040134F    68 29214000     push serialt.00402129                    ; ASCII "Good work!"
00401354    68 34214000     push serialt.00402134                    ; ASCII "Great work!GOOD!  Now try the next CrackMe!"
00401359    FF75 08         push dword ptr ss:[ebp+0x8]
0040135C    E8 D9000000     call <jmp.&USER32.MessageBoxA>           ; 执行注册信息成功的函数

}

分析后发现这个ebx和eax使我们主要注意的数据 只要计算结果ebx和eax相等就跳转注册成功的地方那么想办法让ebx和eax相等就行了

我做了如下修改:

我在计算name值函数里面讲xor edi,0x5678 修改成 imul edi,0x0h 这样edi等于0

同理 在序列号函数里面也修改成imul edi,0x0h 

然后复制到可执行文件

在外部比较两个计算出的值相等

那么就转向注册成功!

当然你也可以直接将cmp ebx,eax 下面的je指令改为jne指令意思是不相等则跳转 直接转到注册成功!

同样可以成功!

分析完后发现这个例子程序就是利用这个等式进行软件注册的



K1(用户名) = K2(序列号)



完!


猜你喜欢

转载自blog.csdn.net/z1455841095/article/details/78152147