调试器与反编译工具

记录od,ida,windbg等的常用键~

ollydbg

快捷键

Ctrl+G 跳转到指定位置
Ctrl+E 编辑指定区域
space 编辑汇编代码
F4 执行到光标位置处
F2 Int3 断点
; 添加注释
: 添加标签名
* 返回到正在运行的地方
- 返回到上一个光标处
Enter 跟随跳转/跟入调用内部
F3 打开一个新的可执行程序
Ctrl+F2 重新运行当前调试的程序
Alt+F2 当前调试的程序
Alt+C 显示 CPU 窗口
Ctrl+P 显示补丁窗口
Alt+O 打开调试选项窗口
Alt+K 显示呼叫堆栈
Alt+B 显示断点窗口
F9 运行选定的程序进行调试
F12 暂时停止被调试程序的执行
F7 单步进入被调试程序的Call中
F8 步过被调试程序的Call
Ctrl+F11 跟入被调试程序的 Call 中
Ctrl+F12 跟踪时跳过被调试程序的 Call
Ctrl+F9 执行直到返回
Alt+L 显示记录窗口
Alt+E 显示模块窗口
Alt+M 显示内存窗口
### 断点
1. Int 3 断点:
即CC指令
2. 硬件断点:
DR0-DR3存储断点的线性地址,DR7设置断点控制,所以最多有四个:
3. 内存断点:
内存访问/写入断点是直接将其属性去除,发生异常时再比对是否是断点,由于每次发生异常都会判断,很影响速度,od只允许设置一个:
4. 内存访问一次性断点:
在显示内存布局时,可以使用F2下断点,首次读取/执行此区域会中断并清除断点:
5. 消息断点:
使窗口函数在接收到指定消息时中断,直接打开窗口界面,选定控件右键选择消息断点,指定消息类型即可:
6. 条件断点:
就是int3断点,遇到时会判断满足条件即中断:
0x1:按寄存器条件中断
eax==00000000
0x2:按存储器条件中断
[String [esp+4]]==”betamao.me”
7. 条件记录断点:
看中文意思就很明确了,不解释,实验下就知道,记录在log窗口显示:
8. Run trace:
使用 调试 打开或清除Run跟踪 即可,跟踪可以在调试选项里面设置:
它会记录所有暂停时的状态信息,使用+ -号可以前后翻动
9. Hit trace:
在所有选中部分添加int 3 断点来记录是否被执行过,实验时将所有已存在断点删除后,程序依然总是会崩溃。。。
## windbg ##
点击下载它是在WDK里面的,当然也可以单独下载,即在安装时只选择“Debugging Tools for Windows”,为方便调试,可以使用微软提供的符号文件,这样可以看到win程序的变量名和结构体定义,不必下载,可以配置为使用服务器,这样会自动匹配:srvc:\symbolshttps://msdl.microsoft.com/download/symbols
也可以放在环境变量里面,名为_NT_SYMBOL_PATH。
开启内核调试:
重启后生效,至于调试命令,需要的时候再看吧,太多了,在这里这里
调试程序,不会断在EP处,需要获取EP地址:
!dh命令用来查看PE头的,于是就可以跳转到这里了:
神奇的命令。。。就这样调试着走,不截图了,不停的走啊走,走到这里传入三个参数,然后一个规则的跳转,跟进去果然是main:
然而,看不懂主函数啊,什么鬼啊!!!!!!

qira

一个神奇的调试器,由geohot编写,安装:

1
2
3
4
cd ~/
git clone https://github.com/BinaryAnalysisPlatform/qira.git
cd qira/
./install.sh

注意,他需要Flask-SocketIO==2.9.1,将requirements.txt文件对应项改掉就行啦~
用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
usage: qira.py [-h] [-s] [-t] [--gate-trace ADDRESS] [--flush-cache] [--pin]
[--host HOST] [--web-port PORT] [--socat-port PORT] [-S]
[--engine ENGINE]
binary [args [args ...]]

Analyze binary. Like "qira /bin/ls /"

positional arguments:
binary 要分析的程序地址
args 程序参数

optional arguments:
-h, --help
-s, --server 类似使用socat搭建服务,监听4000端口
-t, --tracelibraries 跟入所有libraries
--gate-trace ADDRESS 从指定位置开始trace
--flush-cache flush all QIRA caches
--pin 用pin做后端,需要安装:./pin_build.sh
--host HOST 设置web和socat的监听地址,默认 0.0.0.0
--web-port PORT web端口,默认 3002
--socat-port PORT socat端口,默认4000
-S, --static enable static2
--engine ENGINE static engine to use with static2 (builtin or r2)

看着一脸懵逼,最简单的就是./qira /bin/ls啦,此时它会监听3002,使用浏览器打开即可(若打开为空白,结束命令再启动,多试几次就好啦):

  1. 该区域为垂直时间线,从上至下记录着整个程序从开始追踪到当前执行到的位置(若程序已经结束则指向结束位置),它本来是绿色,颜色越深代表函数调用深度越深,当数据区(下面会提,即7区域)的光标指向某个地址时,该区域也会有不同的颜色变化,亮黄色代表该地址在那个时候被读过,暗黄色代表该在那个时候被写过,而代码区(即4区域)的光标指向的地址在这里以蓝色表示。通过鼠标左键拖动选中一块时间线可以缩小查看的范围,使用z键可以恢复该区大小,另外右键双击该区域能隐藏当前进程的时间线。

  2. 该区域为内存属性区域。

  3. 该区域有四个框:

    • 第一个代表指令序号,qira会为按执行顺序为每一条执行到的指令编号,数字以蓝色标记,可以在这个框里输入数据快速跳转到相应序号处。
    • 第二个代表子线程/进程编号,数字以灰色标记,通过它可以可以切换线程编号,当然左右方向键也有此功能。
    • 第三个代表指令地址,数字以红色标记,可以在此键入地址快速跳转,当然g键也可以快速跳转。
    • 第四个代表数据地址,数字以黄色标记,可以在此键入地址快速跳转。
  4. 该区域为指令区,第一列为指令序号,前面有提,调用者与被调用者左右不对齐,可以看出明显的层次关系,第二列为指令地址,第三列为反汇编语句,可以在这个框里使用很多按键:

    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
    j -- 跳转到下次对当前指令调用的地址
    k -- 跳转到上次对当前指令调用的地址

    shift-j -- 跳转到下次对当前数据访问的地址
    shift-k -- 跳转到上次对当前数据访问的地址

    m -- 到当前函数结束处
    , -- 到当前函数开始处

    z -- 恢复垂直时间线

    left -- -1 切换前一个子进程
    right -- +1 切换后一个子进程
    up -- -1 查看前一条指令 鼠标滚轮上滑
    down -- +1 查看后一条指令 鼠标滚轮下滑

    esc -- 回到上一次光标所在位置

    shift-c -- 清除所有进程

    n -- 对指令重命名,一般用在函数入口处
    shift-n -- 对数据重命名
    : --对指令添加注释,其实就是';'符号
    shift-: -- 对数据添加注释,其实就是':'符号

    g -- 快速切换位置,可以输入地址,指令序号或者指令名
  5. 此区域为通用寄存器区域,不同的寄存器用了不同的颜色标记,里面的数据属于指令地址的用红色标记,属于数据地址的用黄色标记,其他事黑色,红色高亮的寄存器是上条指令改变的寄存器,最下行是当前指令的读写操作,暗黄色代表读,亮黄色为将右侧数据写入左侧地址。

  6. 此区域为当前所进行的系统调用。

  7. 此区域为数据dump。

另外它也支持与ida连接,由于它自己编译的插件是plw的,我这里就用ida6.8来配套使用,将./ida/bin下的windows下的两个插件放入ida的插件目录,启动ida,启动插件:

接着ida和qira就同步了,另外F5的伪代码也能定位,美滋滋:

需要注意:ida.js里面ida地址写的是localhost,若浏览器不在那台电脑上将会失败,改一下即可

gdb

Linux下首选,和windbg差不多都是命令行的,虽然有第三方的图形化界面,没用过。。。它的命令在没有冲突的情况下都可以简写,下面不特别记录了。

调试进程

在bash下可以新建也可以附加:

1
2
gdb bin
gdb -p pid

在gdb下可以新建也可以附加:

1
2
file <bin>
attach <pid>

对于附加进程,需要有权限,一般都是是root操作所以不存在问题,若普通用户需要权限可以百度。

断点

添加断点:

1
2
3
4
5
6
tbreak          //临时断点,参数同下
break [[-|+]N] //软中断
break <filename:line> //在源码文件 filename 的 line 行处打断点。
break <filename:function> //在源码文件 filename 的 function 函数入口处打断点。
break <address>
break ... if <cond> //设置条件断点

设置监视点:

1
watch [-l|-location] <expr> //-l表示表达式为地址

列出断点:

1
info breakpoints [lists...]     //list可指定断点编号

禁/启用断点:

1
2
3
4
disable [list…]                 
enable [list…]
enable once [list… ]
enable delete [list… ]

删除断点:

1
2
clear                           //用法同break作用相反
delete [list…]

执行

1
2
3
4
5
6
7
8
9
10
run                             //可使用set args <agr1 ...>设置参数
step [N] //单步步入,N可指定执行步数
reverse-step [N]
next [N] //步过
reverse-next [N]
return <expression> //直接返回函数
finish //运行到返回
until <location> //可用于过循环,location可用于指定执行到何处
continue [N] //继续执行直到下一个断点或结束
jump addr //改变eip

查看

1
2
3
4
5
6
7
8
9
10
11
12
disassemble expr,expr           //反汇编,使用 /m 可以将汇编代码与C代码结合
print /f [expr] //输出表达式值,可用于运算
print /f array[index]@num //输出数组的[index,num]元素
x/nfu <addr> //查看内存
display/fmt <addr>|<expr> //跟踪显示,当fmt为i、s时表达式被视为地址
info display
undisplay [N]
disable display [N]
enable display [N]
backtrace [full] [[+|-]n] //栈回溯
ptype typename //输出类型的定义
info something //info用于查看一些神奇的东西,例如寄存器[all-]register,signals

对于最常用到的x命令,格式如下:

n, f, 和 u 都是可选参数,用于指定要显示的内存以及如何格式化。 
addr 是要开始显示内存的地址的表达式。 
n 重复次数(默认值是 1),指定要显示多少个单位(由 u 指定)的内存值。 
f 显示格式(初始默认值是 x),显示格式是 print('x','d','u','o','t','a','c','f','s') 使用的格式之一,再加 i(机器指令)。 
u 单位大小,b 表示单字节,h 表示双字节,w 表示四字节,g 表示八字节。

信号

一般的ctf题都有定时信号

1
2
3
info signals                    //列出当前信号处理设置
handle signalname [stop|nostop]、[print|noprint]、[pass(noignore)|nopass(ignore)] //对信号所做操作
signal [signalname|signalnum] //对程序发送指定信号

设置

1
2
3
4
5
6
set var varName=varValue    //设置变量值
set print elements number-of-elements //设置print的输出限制
set print array-indexes on //打印数组时输出下标
set print pretty on //格式化输出结构体
set follow-fork-mode [child|parent] //跟踪父进程或子进程
set disassembly-flavor [intel|att] //设置汇编指令格式

这些设置在退出gdb后就会失效,若想长期生效可以将它们写入.gdbinit文件,这样在每次启动gdb时都会执行它们。

参考

[1]逆向工程核心原理
[2]黑客免杀攻防
[3]加密与解密第三版
[4]100个gdb小技巧