pwn学习-任务一:
- 安装ida;
- 安装linux虚拟机,gdb插件,ROPgadget,ropper,pwntools;
- 熟悉ida的基本使用–完成sysmagic题目。
- 学会使用markdown格式
知识储备:
看书《IDA pro 权威指南》,了解反汇编过程的基础知识及IDA基本使用,在i春秋【CTF精品实战课程】进行IDA基本操作实验。
This is an IDA pro 使用初探. 简单笔记如下:
-
反汇编器:撤销汇编过程,因此,我们可以得到汇编语言形式的输出结果(以机器语言作为输入)。需要进行反汇编的常见情况包括以下几种。分析恶意软件;分析闭源软件的漏洞;分析闭源软件的互操作性;分析编译器生成的代码,以验证编译器的性能和准确性;在调试时显示程序指令。
-
基本反汇编算法:线性扫描(linear sweep)和递归下降
(recursive descent)是两种最主要的反汇编算法。
[1] 确定进行反汇编的代码区域。
[2]知道指令的起始地址后,读取该地址(或文件偏移量)所包含的值,并执行一次表查找,将二进制操作码的值与它的汇编语言助记符对应起来。
[3]获取指令并解码任何所需的操作数后,需要对它的汇编语言等价形式进行格式化,并将其在反汇编代码中输出。
[4]输出一条指令后,继续反汇编下一条指令,并重复上述过程,直到反汇编完文件中的所有指令。 -
逆向与反汇编工具:绝不要根据文件的扩展名来确定文件的类型,这是最基本的原则。在脑子里建立起“文件扩展名并无实际意义”的印象.
[1] 分类工具:file:试图通过检查文件中的某些特定字段来确认文件的类型。file 能够识别大量的文件格式,包括数种 ASCII文本文件、各种可执行文件和数据文件。file执行的幻数检查由幻数文件(magic file)所包含的规则控制. PE Tools:一组用于分析 Windows 系统中正在运行的进程和可执行文件的工具。 PEiD:主要用于识别构建某一特定 Windows PE 二进制文件所使用的编译器,并确定任何用于模糊 Windows PE 二进制文件的工具。
[2] 摘要工具:
nm :列出目标文件每一个符号以及与符号有关的一些信息。大写字母表示全局符号,小写字母则表示局部符号。 ldd:(list dynamic dependencies),列举任何可执行文件所需的动态库。 objdump: 可用于显示以下与目标文件有关的信息(以及其他更多信息):节头部,程序文件每节的摘要信息;专用头部,程序内存分布信息,还有运行时加载器所需的其他信息,包括由 ldd 等工具生成的库列表;调试信息,提取出程序文件中的任何调试信息;符号信息,以类似 nm 的方式转储符号表信息;反汇编代码清单,objdump 对文件中标记为代码的部分执行线性扫描反汇编。 otool :可用于解析与 OS X Mach-O 二进制文件有关的信息,显示与文件的头部和符号表有关的信息,并对文件的代码部分进行反汇编。
[3] 深度检测工具:
strings: 提取文件中的字符串内容,通常,使用该工具不会受到文件格式的限制。 反汇编器:PE、ELF 和 MACH-O 文件可分别使用 dumpbin、objdump 和 otool 进行反汇编。两个用于 x86 指令集的流式反汇编器(stream disassembler):ndisasm 和 diStorm。
-
IDA使用切记:
[1] IDA 不提供撤销功能!也无法命令历史记录列表;几乎所有的操作都有其对应的菜单项、热键和工具栏按钮。 IDA提供方便的、基于上下文的鼠标右键操作菜单。
[2] IDA 对于二进制文件,IDA 不会进行任何初始反汇编,除非你至少确定了一个代码字节。
它没有可用的文件头信息区分二进制文件中的代码字节和数据字节。这时,IDA 会提醒用户指定文件中的一个地址作为入口点,告诉 IDA 将这个地址的字节转换成代码(C 是用于强制 IDA 将字节作为代码处理的热键)。
[3]IDB文件: 通常,人们说到 IDA 数据库时实际上指的是 IDB 文件。
IDA 会创建一个数据库,其组件分别保存在 4 个文件中,这些文件的名称与选定的可执行文件的名称相同,扩展名分别为.id0、.id1、.nam 和.til .id0 文件是一个二叉树形式的数据库。 .id1 文件包含描述每个程序字节的标记。 .nam 文件包含与 IDA 的 Names 窗口中显示的给定程序位置有关的索引信息。 .til 文件用于存储与一个给定数据库的本地类型定义有关的信息。 在关闭当前项目时,这 4 个文件将被存档,还可以选择将它们压缩成一个 IDB文件。
[4]加载器:根据程序文件头包含的信息,确定一个虚拟内存布局,并对数据库进行相应的配置
[5]处理器:确定位于该地址的指令的类型、长度,以及从这个地址继续执行指令的位置(例如,是当前的指令序列还是分支)。 -
pwntools:CTF框架和漏洞利用开发库,用Python开发,由rapid设计,旨在让使用者简单快速的编写exploit。 ROPgadget.
扫描二维码关注公众号,回复: 11066953 查看本文章 -
Ropper : 显示有关不同文件格式的二进制文件的信息 Ropper.
-
基本应用软件:静态分析:IDA Pro;动态调试:gdb;Exploit:pwntools(没用到)
-
逆向工程:比如你看到别人写的某个exe程序能够做出某种漂亮的动画效果,你通过反汇编、反编译和动态跟踪等方法,分析出其动画效果的实现过程,这种行为就是逆向工程;不仅仅是反编译,而且还要推倒出设计,并且文档化,逆向软件工程的目的是使软件得以维护。
-
参考博文IDA 快捷键.
解题过程:
1. checksec检测安全保护 ,发现程序是32位,并开启了RELRO和stack保护。
了解到,如果使用64位IDA Pro加载器打开32位程序,是无法正常使用反汇编功能,这也是很多新手IDA Pro使用者不能正常F5的主要原因之一。
查询:
RELRO(read only relocation):加强对 binary 数据段的保护的技术。gcc 默认编译就是 partial relro,部分区块在被动态装载(初始化)后,就被标记为只读区块。
Stack Guard:对栈溢出的保护机制,函数执行时,先在栈上放置一个随机标识符,函数返回前会先检查标识符是否被修改,如果被修改则直接触发中断来中止程序,可以有效的防止栈溢出攻击。Canary在后文解题中介绍。
PIE(position-independent executable, 地址无关可执行文件):没有开启的情况下数据段的地址是固定的。
详细介绍参考博文 二进制程序的一些保护措施.
2. 使用IDA Pro 7.0加载目标程序,找到函数 _main_0 ,然后使用快捷键 F5 反编译显示C伪代码如下:
查询:
函数setvbuf()用来设定文件流的缓冲区,其原型为: int setvbuf(FILE * stream, char * buf, int type, unsigned size);
【参数】stream为文件流指针,buf为缓冲区首地址,type为缓冲区类型,size为缓冲区内字节的数量。
了解到在打开文件流后,读取内容之前,调用setvbuf()可以用来设置文件流的缓冲区(而且必须是这样)。
参考博文IDA快捷键.
3. 双击get_flag()函数,代码前一百行左右均为变量定义,主体部分显示如下:
大致意思为:打开一文件,读取其中的随机数buf,等待输入某十进制数字v2,如果v2=buf,则进行循环异或运算。返回值的那个其实是canary的保护机制。
查询
canary是一种用来防护栈溢出的保护机制。
其原理是在一个函数的入口处,先从fs/gs寄存器中取出一个4字节(eax)或者8字节(rax)的值存到栈上,当函数结束时会检查这个栈上的值是否和存进去的值一致 。
若一致则正常退出,如果是栈溢出或者加粗样式其他原因导致canary的值发生变化,那么程序将执行___stack_chk_fail函数,继而终止程序。
在本题中保护措施在IDA中显示如下:
对应:
汇编指令,此处只列举本题出现的,详细指令参考博文 汇编指令大全.
- MOV A,B :把B的值送给A其中,A与B可是寄存器或内存地址,也可同时是两个寄存器,但不能同都是内存地址。
- CMP A,B :比较A与B其中A与B可以是寄存器或内存地址,也可同时是两个寄存器,但不能同都是内存地址。
- EAX :可以作为累加器来使用,所以它是算术运算的主要寄存器。
- EBX :一般在计算存储器地址时,它经常用作基址寄存器。
- ECX: 常用来保存计数值,如在移位指令它用来装位移量、循环和串处理指令中作隐含的计数器。
- Xor a:a异或操作,主要是用来将a清空
- 进栈指令PUSH direct ;(SP)+1 → SP ,(direct) → SP
- 退栈指令POP direct
- ADD A,Rn ;加法指令(A)+(Rn)→A
- SUB :减法指令 格式UB DST,SRC 执行的操作:(DST)<-(DST)-(SRC)
- NOP :无作用,可以用来抹去相应的语句
- 控制转移指令: JE 或JZ 若相等则跳
- 程序转移指令:CALL 过程调用
- lea:为加载有效地址(load dffective address)和mov用法一样,指令并不是从制定的位置读入数据,而是将有效地址写入到目的操作数值中。
- jne:一个条件转移指令。当ZF=0,转至标号处执行。
读懂这些指令对后面理解程序是怎样进行的有很大帮助。
4. gdb调试命令:gdb sys
可怜的英文水平迫使我一个个查询单词意思。
systemd是Linux系统最新的初始化系统(init),作用是提高系统的启动速度,尽可能启动较少的进程,尽可能更多进程并发启动。
systemd对应的进程管理命令是systemctl,systemctl命令管理systemd的资源Unit
大致就是一些服务,跟解题无关
5. gdb sysmagic,(sysmagic是本题目文件名),调试这个程序
没有找到调试符号,因为还没运行程序
6. 运行指令 r,任意输入个值,自然buf与v2不等,跳出if语句,结束程序。 在if语句之前加个断点,使程序运行到该处暂停
成功在get_flag()处设置了本程序的第一个断点(序号为1);断点处的代码地址为:0x80485a4(此值只在本次调试过程中有效)。回过头去看IDA中反汇编窗口源代码:恰好是get_flag第一个可执行语句:
将静态与动态联合起来,能很快理解题目思路。
7. 运行程序
在刚设置断点处中止了。
8. gdb指令:n
- s(单步进入): 执行一行源程序代码,如果此行代码中有函数调用,则进入该函数;
- n(单步不进入): 执行一行源程序代码,此行代码中的函数调用也一并执行。
可以看见程序向下进行了一步,继续此操作,程序一直向下进行,到等待输入数值时停止,从IDA静态调试可更方便看见程序执行情况:
此时到达scanf处,任意输入数值,程序继续运行:
观察程序:
call之前参数进栈;
scanf第一个参数是%d,第二个参数是&v2。ebp-0x7c是v2这个变量的内存地址,将这个地址压栈,然后call scanf的时候根据这个地址,将输入的数据写到这个内存地址里面。
下一步应该通过if条件,要使edx=eax即可。为方便直接明了看见该步骤前后因v2值不同导致程序执行状况的不同,再设置一断点,让程序在scanf &v2处中止.
*9. 查ebp-0x80地址,在scanf处加断点,命令为:b 0x8048712
转换为10进制数,:(在python中可一步转换)
继续运行,程序在第一个断点处中止,将十进制数输入,执行命令c,程序在第二个断点处中止。重复上述查询步骤,继续运行,输入第二次查询的十进制值,即成功。显示界面如下:
GDB查看指定内存地址:
指令:x/ <n/f/u> <addr>
n:正整数,显示内存的长度,从当前地址向后显示几个地址(units)的内容。
f:显示的格式(format)
- d (signed decimal)按十进制格式显示变量
- a (address)按十六进制格式显示地址,并显示距离前继符号的偏移量(offset)。常用于定位未知地址(变量)。
u:the unit size)从当前地址往后请求的位宽大小。如果不指定的话,GDB默认是4个bytes。
-u参数可以用下面的字符来代替,b表示单字节,h表示双字节,w表示四字 节,g表示八字节。
-当我们指定了位宽长度后,GDB会从指内存定的内存地址开始,读写指定位宽大小,并把其当作一个值取出来。
博文推荐,一好用的 gdb速查手册.
本题栈内存储:Why is my teamwork Orange so angry?
markdown格式
- 图片:
alt:显示在图片下面的文字,相当于对图片内容的解释。
title:图片的标题,当鼠标移到图片上时显示的内容。title可加可不加
center居中,left居左,right居右
列表:
- 列表内容
- 列表内容
- 列表内容
- 列表内容
- 列表内容
- 列表内容
序号- + * \跟内容之间均有空格
- 表格:
表头 | 表头 | 表头 |
---|---|---|
内容 | 内容 | 内容 |
内容 | 内容 | 内容 |
第二行分割表头和内容。文字默认居左;两边加:表示文字居中;右边加:表示文字居右。原生语法两边都要有| 。
- 代码:
() 代码... 代码... 代码... (
)
- 流程图: