看代码
#include <stdio.h>
#include "windows.h"
#define PASSWORD "1234567"
int verify_password(char *password)
{
int authenticated;
char buffer[8];
authenticated=strcmp(password,PASSWORD);
strcpy(buffer,password);
return authenticated;
}
int main()
{
int valid_flag=0;
char password[1024];
while (1)
{
printf("请输入密码:");
scanf("%s",password);
valid_flag=verify_password(password);
if (valid_flag)
{
printf("错误!\n");
}
else
{
printf("正确!\n");
break;
}
}
return 0;
}
会点C语言就能看懂吧,有个验证密码是否正确的函数
要注意的一点是要关闭编译时的GZ选项,VC6以上版本关闭GS编译选项
具体方式:vc6工程-设置-c/c++-工程选项里面去掉GZ
vs C/C++ 代码生成 缓冲区安全检查 否
生成程序输入密码,当输入的为8位但是数值比1234567大时均会通过验证,这是为什么呢?
拿到OD中看下
当输入12345678时,堆栈中如下所示
0012FB18 34333231 ;4321
0012FB1C 38373635 ;8765
0012FB20 00000000; ;authenticated
0012FB24 /0012FF80; ;ebp
当我们输入01234567时,因为比1234567小,所以strcmp会返回-1.补码为0xFFFFFFFF,OD中看下
0012FB18 33323130 ;3210
0012FB1C 37363534 ;7654
0012FB20 FFFFFF00 ;authenticated
0012FB24 /0012FF80 ;ebp
authenticated为FFFFFF,所以还是不会通过验证的
另外问下为什么我OD中那些像strcpy什么的函数都识别不出来,CALL的都是一个模块内的地址
是不是符号的问题?
下面我们再换种方式
#include <stdio.h>
#include "windows.h"
#define PASSWORD "1234567"
char *p={
"\x12\x12\x12\x12\x12\x12\x12\x12"//buffer
"\x34\x34\x34\x34"//authenticated
"\xaa\xaa\xaa\xaa"//ebp
"\xbb\xbb\xbb\xbb"//eip
};
int verify_password(char *password)
{
int authenticated;
char buffer[8];
authenticated=strcmp(password,PASSWORD);
strcpy(buffer,password);
return authenticated;
}
int main()
{
int valid_flag=0;
char password[1024];
while (1)
{
printf("请输入密码:");
scanf("%s",password);
valid_flag=verify_password(p);
if (valid_flag)
{
printf("错误!\n");
}
else
{
printf("正确!\n");
break;
}
}
return 0;
}
为了方便测试直接在程序内定义一个字符串,这样编译运行后会弹出一个引用的0xbbbbbbbb内存不能 为read错误,原因就不多说了。
我们把这个0xxbbbbbbbb改为输出正确的分支就可以,拖到OD中找到输出正确的地址,是0x00401106,替换掉就OK 。
运行下就会输出正确了,不过程序之后会崩溃掉,因为栈内EBP被覆盖为无效值,使得程序在退出时堆栈无法平衡。