缓冲区溢出实验

实验目的

  1. 读懂并能够独立编写密码验证的小程序。
  2. 运行 Ollydbg,并学习用其调试密码验证小程序。
  3. 通过修改汇编语句来修改程序的判断条件,改变程序的运行路线。

理解程序

阅读并理解代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>
#include <string>
#define PASSWORD "1234567"
int verify_password (char *password)
{
int authenticated;
authenticated=strcmp(password,PASSWORD);
return authenticated;
}

int main()
{
int valid_flag=0;
char password[1024];
while(1)
{
printf("please input password: ");
scanf("%s",password);
valid_flag = verify_password(password);
if(valid_flag)
{
printf("incorrect password!\n\n");
}
else
{
printf("Congratulation! You have passed the verification!\n");
break;
}
}
return 0;
}
  1. 在主函数内输入密码password
  2. 跳转到子函数verify_password()判断输入的密码是否正确即判断输入的密码password与正确的密码PASSWORD是否相等,如果相等则子函数返回0,否则返回非0;
  3. 主函数在判断子函数verify_password()返回值:如果是0,则输出Congratulation! You have passed the verification!,结束程序,否则输出incorrect password!,继续输入密码password重复上述过程。

1565795262719

调试程序

  1. 使用Ollydbg打开程序

    1565795381042

  2. 同时按下AltF9执行到用户代码如下图:在地址为00401614CALL test.00401014

    1565795418251

  3. 找到地址00401014JMP test.main,即此处向下为用户代码

    1565795448209

  4. 分析用户代码,发现004010300040106F为子函数verify_password()反汇编代码,004010800040111Cmain函数的反汇编代码

    1565795482563

    1565795488088

  5. 分析反汇编代码,发现在004010E1处,出现指令CMP 比较子函数的返回值与0,如果等于0,则执行接下来的004010E5JE SHORT test.00401105处的指令,即打印Congratulation! You have passed the verification!;否则打印incorrect password!

    1565795609568

  6. 程序运行的结构图如下

    1565795720516

修改程序

已知:

编码 功能
JE 等于则跳转
JNZ 不等于则跳转

地址004010E5处指令JE SHORT test.00401105表示CMP指令比较的两个数相同则跳转到地址00401105处,即打印Congratulation! You have passed the verification!,否则按地址顺序执行,即打印incorrect password!

为此,我们将JE修改为JNZ并执行程序

  1. 右键点击JE、找到二进制、点击编辑,或直接Ctrl+E,编辑代码,将74改成75,因为74代表JE75代表JNZ,或直接双击JE更改该汇编语言由JEJNZ

    1565797357774

    1565797362376

  2. 再次运行,当输入密码为1234567时显示incorrect password!,输入其它内容时直接退出程序。

    1565797406931

  3. 修改成功,即把结构中的选择语句中的N和Y调换位置

    1565797422793

思考题

破解crackme.exe程序,要求通过修改程序代码的方式绕过crackme.exe的密码验证逻辑,至少采用2种破解方式方法。

  1. Ollydbg打开crackme.exe文件

    1565797561858

  2. 右键→查找→所有参考文本字串

    1565797574854

    1565797587429

  3. 双击ASCII ‘crackmepassword’,跳转到文件汇编语言crackmepassword处找到四个条件选择语句

  4. 利用IDA打开crackme.exe文件,搜索字符串同样双击ASCII ‘crackmepassword’得到如下结果

    1565797649027

    1565797665901

    1565797680979

    1565797701037

  5. 分析汇编指令可知必须让程序执行00401616处的指令而不能执行00401637处的指令。而在不知道密码的情况下会执行0040161E处的指令进行跳转,故要实现绕过密码登录就有需要不进行跳转,可以0040161EJNZ指令改为JE指令实现不跳转,该方法为方法一。

  6. 通过分析四条选择语句,得到结论如下

    地址 是否跳转
    004015F1 JE不跳转
    004015F5 JE不跳转
    00401601 JNZ跳转
    0040160B JNZ跳转

    再次分析该部分程序只有程序在004015F1处不跳转、在004015F5跳转时,根据寄存器的值才能判断出程序在0040161E处不跳转即不执行00401637处指令,故方法二是004015F1JNZ指令改为JE指令,将004015F5JE指令改为JNZ指令

  7. 执行结果

    • 方法一

      1. JNZ指令改为JE指令

        1565798121426

      2. 右键单击→复制到可执行文件→所有修改→全部复制→右键单击→保存文件→选择文件路径,将更改后的文件保存为crackme1.exe

        1565798154333

      3. 打开crackme1.exe,随便输入一个用户名和密码点击注册,显示注册成功

        1565798200923

        1565798191459

    • 方法二

      1. 004015F1JNZ指令改为JE指令,将004015F5JE指令改为JNZ指令

        1565798278535

      2. 与方法一相同,将更改后的文件保存为crackme2.exe

        1565798297876

      3. 打开crackme1.exe,随便输入一个用户名和密码点击注册,显示注册成功

        1565798319089

        1565798324932