《0day安全:软件漏洞分析技术 第二版》第一章 基础知识 —— 学习笔记

一. 二进制文件概述

1.1 PE文件格式

  • PE文件格式把可执行文件分成若干个数据节(section),分别如下:
    • .text: 由编译器产生,存放着二进制的机器代码,也是反汇编和调试的对象
    • .data: 初始化的数据块,如宏定义、全局变量、静态变量等
    • .idata: 可执行文件所使用的动态链接库等外来函数与文件的信息
    • .rsrc: 存放程序的资源,如图标、菜单等
    • 除上以外,还可能有: .reloc、.edata、.tls、.rdata。

如果可执行文件经过了"加壳"处理,PE的节信息将变得非常"古怪"。

1.2 虚拟内存

Windows的内存被分为两个层面:物理内存和虚拟内存。在用户模式下看到的内存均为虚拟内存。

进程所拥有的虚拟内存中包含了程序运行时所必须的资源,比如代码、栈空间、堆空间、资源区、动态链接库等。

1.3 PE文件与虚拟内存之间的映射

1.3.1 文件偏移地址(File Offset)

数据在PE文件中的地址叫文件偏移地址(有时叫文件地址更加准确)。这是文件在磁盘上存放时相对于文件开头的偏移。

1.3.2 装载基址(Image Base)

PE装入内存时的基地址。默认情况下,EXE文件在内存中的基地址是0x00400000,DLL文件0x10000000。这些位置可以通过修改编译选项更改。

1.3.3. 虚拟内存地址(Virtual Address, VA)

PE文件中的指令被装入内存后的地址

1.3.4. 相对虚拟地址(Relative Virtual Address, RVA)

相对虚拟地址是内存地址相对于映射基址的偏移量

1.3.5. 节偏移

由存储单位差异引起的节基址差。

1.3.6. 必记公式

  • VA = Image Base + RVA

  • 文件偏移地址 = 虚拟内存地址(VA)−装载基址(Image Base)−节偏移

    ​ = RVA -节偏移

二 必备工具

2.1 书中要求的必备工具

  • LordPE: 可以方便地查看 PE 文件中的节信息,也可以方便地换算虚拟内存地址,文件偏移地址和 RVA。

  • OllyDbg: 一个集成了反汇编分析、十六进制编辑、动态调试等多种功能于一身的功能强

    大的调试器。

快捷键功能说明
F8单步执行遇到函数条用指令不会跟进(Step over)
F7单步执行遇到函数调用指令跟入(Step in)
F2设置断点在一条指令上按 F2 键将设置断点,再按一次将取消断点
F4执行到当前光标所选中的指令在遇到循环时可以方便地用 F4 键执行到循环结束后的指令
F9运行程序运行程序直到遇到断点
Ctrl+G查看任意位置的数据这个功能键非常有用,在指令区、栈区、内存区都可以使用,能方便地查看任意位置的指令和数据
  • SoftICE: 工作在 ring0 级,所以可调试驱动等内核对象。会独占 CPU,中断一切进程和消息。慎用!!!反正我是没敢装这个软件~~
  • WinDbg: 它可以调试内核,但却不像 SoftICE 那么暴力,总是中断操作系统;它保留了一部分 Visual Studio 中常用的快捷按钮,也保留了和 SoftICE 一样丰富的调试命令。这个我装了~

ctrl + 左键 打开WinDbg常用命令

  • IDA Pro: 是当今最强大的反汇编软件
快捷键功能
;为当前指令添加全文交叉引用的注释
n定义或修改名称,通常用来标注函数名
g跳转到任意地方观察代码
Esc返回到跳转前的位置
D分别按字节、字(双字节)、双字(四字节)的形式显示数据
A按照 ASCII 形式显示数据
  • UltraEdit: 二进制编辑器, 用它可以方便地完成机器代码的修改或者 shellcode的编辑。除了这个以外还有Hex Workshop、WinHex和010 editor,个人觉得UE是比较符合当前审美的(有点颜值要求~),我安装了两个,分别是UE和010 Editor

  • Python解释器,这里书中安装的是Python2,由于本人觉得看书应该有所进步,所以就换成了Python3,后面如果不行再换成Python2吧~

2.2 个人环境

环境名环境版本
系统环境Windows10 Professional 64位(内部版本21H2)
IDEVisual Studio Professional 2017
调试器OllyDbg 1.10、WinDbg、x64Dbg
反编译器IDA Pro 7.6
编辑器UltraEdit 28、010 Editor 12.0.1

三. Crack小实验

3.1 实验源码(C语言版哦)

#include <stdio.h>
#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("请输入密码: ");
		scanf("%s", password);
		valid_flag = verify_password(password);
		if (valid_flag)
		{
			printf("密码错误!\n");
		}
		else
		{
			printf("密码正确!\n");
			break;
		}
	}
	return 0;
}

3.2 实验源码分析与破解思路

上面代码的逻辑是程序运行后提示用户输入密码,用户输入密码后调用函数进行比较,并将比较的值返回,再用此值进行判断,错误再次执行流程,正确跳出循环并结束程序。程序流程图如下:
图一
从流程图可以看出结束程序的关键在判断的地方,如果能改变if语句,那么即使输入的密码是错误的,也能通过验证,这种方法被叫做软件破解,也称为爆破。

3.3 实验步骤

步骤一: 编写代码并生成

首先你需要在VS2017中敲入第一节中的实验源码,如果直接生成会导致错误,这时候你在VS2017中改下面的设置:

  • 首先将你的build版本从Debug改为Release, 保持x86即可;

  • 然后依次点击"项目" --> “‘你的项目名’ 属性” --> “C/C++” --> “优化”, 进入后改成如下图所示的样子:
    图二

  • 其次点击"C/C++" --> “代码生成”, 进入后改成如下图所示的样子:
    图三

  • 最后F7或者手动点击生成代码,待成功后在项目文件中将得到一个Crack.exe,当然名字和我可能不一样哦~

步骤二: IDA分析

打开IDA,并使用IDA打开步骤一生成的.exe文件,他将自动识别main函数,如下图:
图四
此时他自动跳到了main函数处,如果想看反编译的代码可以在右边显示图像的窗口中右键选择"Text view"即可调转到反编译的界面。如下图:
图五
同时在右侧也会有它自动分析出来的函数,一般而言他会在函数前面加上下划线。

现在开始分析下这个反编译出来的汇编代码吧,首先需要知道的是***call命令,在调用函数的时候就会执行call命令,不区分调用的函数是否为内置函数还是自定义函数***,仔细分析可以找到以下几个有用的call指令地方:
图六
这五个call刚好对应了代码中的几个调用函数的地方,根据编写的逻辑知道if语句肯定是位于调用_verify_password函数之后的,那么再把上面的代码缩减一下,如下图:
图七
注意到上面的两个红框中的内容是否大致一样?所以他们绝对不是if语句反编译出来的汇编代码,除此以外只剩四个指令,add指令表示加;mov指令类似C语言中的赋值符,即“=”;cmp指令表示比较,通过排除法就能知道***jz指令就是所谓的判断指令,该指令的运行方式为前面的结果为0则跳转,反之不会跳转(不跳转的结果就是执行jz指令的后一条语句)***,而两个红框就是它的分支。知道了这一点之后,这个程序也就没有分析的必要了。

Tips: 一个更好的找判断指令的方法

直接看最初的图形视图,会发现在下面其实就相当于将程序流程图画出来了,此处不再分析。
图八
不管怎么分析,最终我们需要知道并记住的是在该程序中jz指令对应的虚拟内存地址(VA)。我这里是0x00401070,如下图:
图九

步骤三: 使用OllyDbg破解程序

关闭IDA,如果你是在IDA中做的笔记请保存,否则如果想我一样在Typora中做的笔记可以直接不保存(对于大型软件的分析建议保存)。

打开OllyDbg,依次点击"文件" --> “打开"选择.exe文件并打开,如下图:
图十
可以看到这时候的地址只有后四位是一样的了,前面都不一样了,这是为啥呢?这是因为在生成程序的时候选择了随机基址,使用VS打开源程序,将"属性” --> “链接器” --> "高级"中的随机基址设置为否,再次生成,之后用OllyDbg打开,这次和IDA中一样咯,如下图:
图十一
Ctrl + G输入在IDA中找到的if语句地址,即可调转到目的地址。

双击汇编代码"je short xxx",修改前面的je为jne,之后点击"汇编",如下图:
图十二
仔细观察前面的机器码,之前是74 0F,在改完之后变成了75 0F,这一字之差即可改变整个程序走向,点击OllyDbg工具栏的"三角"按钮运行程序。你会发现此时程序完全不按照原先的逻辑运行了,输入正确的密码反而提示错误,输入错误的密码反而提示正确。如下图:
图十三
这是因为JNE指令在起作用,JNE指令恰恰与JE指令相反,如果上一步是0则不跳转,反之跳转。现在只是在OllyDbg上实现了这个功能,那么如何直接修改程序本身呢?这就需要用到神器UltraEdit(以后简称UE)。

步骤四: 从根本破解程序

首先使用UE打开.exe程序,当然在此之前也得关闭OllyDbg哦,如下图所示:
图十四
从步骤三可以知道,需要将一个74 0F改成75 0F,但是在这个里面想要找到这两个可不太容易~所以需要借助前面的公式来计算文件偏移地址,而计算它需要知道虚拟内存地址(VA)、转载基址(Image Base)、节偏移。

这里我们知道的有VA = 0x00401070,Image Base = 0x00400000,最后的节偏移地址需要使用LordPE进行查看,使用LordPE打开.exe文件,如下图:
图十五
节偏移 = 节在内存中的偏移量(VOffset) - 节在文件中的偏移量(ROffset)

​ = 0x00001000 - 0x00000400

​ = 0x00000C00

Tips: 这个地方需要注意的是因为在IDA中已经知道需要修改的if语句指令所在的节在.text中,所以才使用上图中"Section Table"窗口中的第一个VOffset和ROffset,请根据实际情况进行更改

直到此时我们终于凑齐了所有的数据,现在计算出结果:

文件偏移地址 = 虚拟内存地址(VA)−装载基址(Image Base)−节偏移

​ = 0x00401070 - 0x00400000 - (0x00001000 - 0x00000400)

​ = 0x00401070 - 0x00400000 - 0x00000C00

​ = 0x00000470

最后用UE打开.exe文件,按Ctrl + G输入上面计算出来的结果地址转到指定地点,如下图:
图十六
将上面的74改成75吧!之后保存,现在再次运行程序,如下图:
图十七
成功!

四. 总结

还记得自己两年前左右刚开始看这本书时自我膨胀,把环境搭建得特别新潮,结果愣是没复现出现这个,百度多时未果,也是一度想要放弃。现在慢慢学习之后也终于完成了当年的那个夙愿,终于把环境升级了,哈哈哈,如果想要详细的讲解可以去百度搜一搜关键词"SEVEN 漏洞",应该还能搜到这个小实验的详细讲解~
还请大佬们不喜勿喷,若有错误请指点~

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

g_pSeven

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值