通过增加MD5 验证防止Crack 爆破判断的一种思路
LCatro2015/07/24软件综合 IP:广东

  爆破程序验证判断的原理


  首先大家来看一段代码:

3:#include
<stdio.h>


4:void main(void) {
5:        int input=0;
00401028   mov        
dword ptr [ebp-4],0

6:        scanf("%d",&input);
0040102F   lea        
eax,[ebp-4]

00401032   push      
eax

00401033   push      
offset string "%d" (00425028)

00401038   call      
scanf (00401110)

0040103D   add        
esp,8

7:        if (input==100)
00401040   cmp        
dword ptr [ebp-4],64h    
把变量input 对比0x64(十进制100)
00401044   jne        
main+45h (00401055)    
如果不等于100 的话条转到地址0x401055
8:            printf("OK!");
00401046   push      
offset string "OK!" (00425024)

0040104B   call      
printf (00401090)

00401050   add        
esp,4

9:        else
00401053   jmp        
main+52h (00401062)    
直接跳到地址0x401062
10:           printf("ERR!");
00401055   push      
offset string "ERR!" (0042501c)

0040105A   call      
printf (00401090)

0040105F   add        
esp,4

11:   }


  标记为红色的代码就是if 判断的主要结构代码.执行的流程如下:
QQ图片20150531215935.png


  转换成汇编代码版就是这样
QQ图片20150531215953.png



  现在我们知道了if 的结构,那么人家破解程序的原理是怎么样的呢?其实道理很简单,只需要把代码:
00401044  jne         main+45h (00401055)


  改写成
00401044  nop
00401044  nop


  就可以随意输入任何数字都能够成功输出字符串”OK!”

PS:什么是nop ?

  nop 指令是空指令,它本身没有任何意义,也就是说当处理器执行到这条指令时不会做任何的事情.


  那么我们破解成功的原理是什么呢?还是用图片来表达吧.
QQ图片20150531215959.png


  可能大家会感到奇怪,为什么这个地方即使输入错误都不会跳转呢?聪明的你可能明白,当程序执行完cmp 对比指令之后,接下来就是要根据对比的结果来进行跳转,问题是现在没有跳转指令,空指令把原来的跳转指令覆盖了,所以处理器只执行两条空指令,什么都不做,然后就输出字符串”OK!” ,最后跳出if 判断语句块.这个就是爆破的原理.


  如何使用验证实现


  上面已经演示出如何把判断结构通过修改指令的形式来使它按照我们的意愿来执行代码流.在一些需要验证密码的程序中,一旦被攻破掉验证这重防御将会使索要所有的数据都变得不安全,于是提出一种防止爆破的思路:通过密码解密数据,然后验证数据签名是否为加密之前的签名,如果相同的话则解密成功

  加密过程图解:
QQ图片20150724211242.png


  解密过程图解:
QQ图片20150724211247.png


  大家也许会有疑问,假如把判断数据签名的判断结构给爆破掉了是不是就可以达到破解验证的效果呢?其实是不会的,因为程序使用输入的密码来使整一块数据进行运算,即使是让程序跳过了数据验证,运算出来的数据还是错误的,只要密码不正确,那么解密数据的运算得出的数据就永远不会正确.


  在文件加解密程序的应用


  程序代码如下:


Encrypt:


<code class="lang-cpp">#include <malloc.h>
#include <memory.h>
#include <stdio.h>
#include <string.h>
  
#include "encoder_md5.h"
#include "encoder_xor.h"
  
void main(int argc,char** argv) {
    
if (3==argc) {
        
FILE* file=fopen(argv[1],"r");
        
if (NULL!=file) {
            
fseek(file,0,SEEK_END);
            
unsigned long file_size=ftell(file);
            
fseek(file,0,SEEK_SET);
  
            
char* buffer=(char*)malloc(file_size+LENGTH_MD5);
            
if (NULL!=buffer) {
                
fread(buffer+LENGTH_MD5,1,file_size,file);
                fclose(file);
  
                char*
md5=calcu_md5(&buffer[LENGTH_MD5],file_size);
                memcpy(buffer,md5,LENGTH_MD5);
                encoder_xor((unsigned
char*)buffer,file_size+LENGTH_MD5,(unsigned char*)argv[2],strlen(argv[2]));
  
            
    file=fopen(argv[1],"w+");
                
fwrite(buffer,1,file_size+LENGTH_MD5,file);
                fclose(file);
                free(buffer);
            
} else
                printf("Alloc Memory ERROR!");
        
} else
            
printf("Open ERROR!");
    }
}
</string.h></stdio.h></memory.h></malloc.h></code>



Decrypt:

<code class="lang-cpp">#include <malloc.h>
#include <memory.h>
#include <stdio.h>
#include <string.h>
  
#include "encoder_md5.h"
#include "encoder_xor.h"
  
void main(int argc,char** argv) {
    
if (3==argc) {
        
FILE* file=fopen(argv[1],"r");
        
if (NULL!=file) {
            
fseek(file,0,SEEK_END);
            
unsigned long file_size=ftell(file);
            
fseek(file,0,SEEK_SET);
  
            
char* buffer=(char*)malloc(file_size);
            
if (NULL!=buffer) {
                fread(buffer,1,file_size,file);
                fclose(file);
  
                encoder_xor((unsigned
char*)buffer,file_size,(unsigned char*)argv[2],strlen(argv[2]));
                char*
md5=calcu_md5(&buffer[LENGTH_MD5],file_size-LENGTH_MD5);
                char
sorc_md5[LENGTH_MD5+1]={0};
                char
dest_md5[LENGTH_MD5+1]={0};
                
memcpy(sorc_md5,buffer,LENGTH_MD5);
                
memcpy(dest_md5,md5,LENGTH_MD5);
                if (!strcmp(sorc_md5,dest_md5))
{
                    file=fopen(argv[1],"w+");
                    
fwrite(&buffer[LENGTH_MD5],1,file_size-LENGTH_MD5,file);
                    fclose(file);
                } else
                    printf("ERROR
Password!");
  
                free(buffer);
            } else
                printf("Alloc Memory
ERROR!");
        
} else
            
printf("Open ERROR!");
    }
}</string.h></stdio.h></memory.h></malloc.h></code>


  测试:

  Encrypt 下建立test.txt ,随意输入一些数据

QQ图片20150724211020.png


  在控制台中加密文件

QQ图片20150724210958.jpg


  查看test.txt 文件的数据

QQ图片20150724211004.png


  解密时输入错误密码

QQ图片20150724211009.jpg


  输入正确密码

QQ图片20150724211014.jpg


  数据正常恢复


QQ图片20150724211020.png


  输入密码错误时堆的数据情况

QQ截图20150724211611.png
QQ图片20150724210948.png
来自:计算机科学 / 软件综合
8
 
已屏蔽 原因:{{ notice.reason }}已屏蔽
{{notice.noticeContent}}
~~空空如也
坚定的潜水党
9年5个月前 IP:江苏
781104
= =
同时爆破验证和签名
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
LCatro作者
9年5个月前 IP:广东
781116
签名是MD5 的,不可能做到爆破,密码长度也可以随意设置,就像RSA P/S Key 一样选择512 或者1024 位密码来加密..
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
smith
9年5个月前 IP:广东
781917
破解程序和破解数据加密的场景搞混了吧。
破解程序如破解正版软件,改跳转指令确实是常用的方法。这个时候攻击的目标是程序自身
但楼主的程序是数据加密的场景,如解压一个winrar压缩包,要提供密钥才能解压。这个时候攻击的是加密的算法和密钥,如果这个时候去攻击winrar这个软件是徒劳无功的。因为winrar自己也不知道密钥。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
那抹余辉
9年5个月前 IP:浙江
781963
#include "encoder_md5.h"

#include "encoder_xor.h"
我是新手、缺少这两个头文件,怎么办 encrypt.png
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
LCatro作者
9年5个月前 IP:广东
782128
引用 smith:
破解程序和破解数据加密的场景搞混了吧。
破解程序如破解正版软件,改跳转指令确实是常用的方法。这个时候攻击的目标是程序自身
但楼主的程序是数据加密的场景,如解压一个winrar压缩包,要提供密钥才能解压。这个时候攻击的是加密的算法和密钥,如果...
是这样的,在数据加密验证的时候Crack 了那个特定的判断就可以输入任意密码绕过验证,之前写过一个类Winrar 的程序,过了很久自己把关键的判断给破解就可以绕过密码的输入验证..
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
phpskycn
9年5个月前 IP:浙江
783286
同样没看明白LZ想实现什么。
如果从数据加密/解密的角度,增加的验证环节基本没有价值,因为它发生在数据解密之后,其加密的强度依旧取决于加密算法本身,没有任何改变。
从程序破解/反破解的角度,这个方法也没用什么作用
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
zx-16533
9年5个月前 IP:广东
783289
引用 LCatro:
是这样的,在数据加密验证的时候Crack 了那个特定的判断就可以输入任意密码绕过验证,之前写过一个类Winrar 的程序,过了很久自己把关键的判断给破解就可以绕过密码的输入验证..
对于数据加密来说破解掉输入验证没有价值吧。去掉判断以后用来解密的密码仍然是错误的密码,解密出来的仍然是错误的数据(假设此时仍能够成功解密,比如解密之后没有校验明文之类的)。另外貌似一般都是解密完之后校验明文是否正确而不是解密之前先判断密码的吧。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论

想参与大家的讨论?现在就 登录 或者 注册

所属专业
上级专业
同级专业
文件下载
加载中...
{{errorInfo}}
{{downloadWarning}}
你在 {{downloadTime}} 下载过当前文件。
文件名称:{{resource.defaultFile.name}}
下载次数:{{resource.hits}}
上传用户:{{uploader.username}}
所需积分:{{costScores}},{{holdScores}}下载当前附件免费{{description}}
积分不足,去充值
文件已丢失

当前账号的附件下载数量限制如下:
时段 个数
{{f.startingTime}}点 - {{f.endTime}}点 {{f.fileCount}}
视频暂不能访问,请登录试试
仅供内部学术交流或培训使用,请先保存到本地。本内容不代表科创观点,未经原作者同意,请勿转载。
音频暂不能访问,请登录试试
支持的图片格式:jpg, jpeg, png
插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

加载中...
详情
详情
推送到专栏从专栏移除
设为匿名取消匿名
查看作者
回复
只看作者
加入收藏取消收藏
收藏
取消收藏
折叠回复
置顶取消置顶
评学术分
鼓励
设为精选取消精选
管理提醒
编辑
通过审核
评论控制
退修或删除
历史版本
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}