本文中指令标点不全为英文。
Part1 二进制基础
Linux一些pwn常用的命令
file 文件名
显示有关文件的信息readelf -a 可执行文件 | less
查看可执行文件信息(-a是全部,| less可以从前往后看,可以去除试试有什么不一样)ldd 可执行文件
可以看到使用的库函数所在位置(ldd很常用)objdump -d 可执行文件 -M intel |less
查看intel下的汇编指令(objdump可以反汇编出,ida之前一些小的题可以用它来做,现在很少用,除非没网了)gcc test.c -o text
:正常编译(主要查看rip寄存器)gcc test.c -o text_x86
:编译为x86形式gcc -m32 test.c -o test
:编译为32位(主要查看eip寄存器)
常用汇编指令
格式
操作指令 操作数(例:push rbp)
或者
操作指令 目的操作数,源操作数(例:mov rbp,rsp)
mov
:赋值movzx
: 例:movzx eax,BYTE PTR [rbp-0x10]
把rbp减0x10地址的信息的第一个位给eax(PTR:指针)
关于上面的BYTE
字长 | 8 | 16 | 32 | 64 |
---|---|---|---|---|
名字 | BYTE | WORD | DWORD | QWORD |
lea
:载入地址(现在的编译器不用它来载入地址,现在这样用:例:lea rax,[rbp-0x18]
:将rbp的值减0x18后赋值给rax,好处:短)add/sub
:加减push
:入栈pop
:出栈cmp
:与sub作用相似,不同之处在于cmp计算结果不赋值,通常与jcc系列一起用- jum
j[comdition]
jcc系列:满足一定条件就跳转,(遇到了去查)
- call:调用函数
- leave
- ret
xor
:异或(如果a和b两个数值不相等,异或值为1,如果a和b;两个数值相等,异或值为0例:xor ebx,ebx
作用:ebx=0,好处:短)
gcc也可以编译出汇编指令
指令gcc -S c源文件
gdb
-
运行
start
:运行至程序的入口点
run
:将程序完全运行 -
步入、步过、步出、步止(设置断点,运行程序到断点)
步入:si
进入c函数或汇编内部
步过:ni
不会进入
步出:finish
退出函数内部
步止:c
执行到断点为止 -
断点(设置、删除、显示)
设置:b *地址
或者b 函数名
显示:i b
删除:d 断点编号
关闭断点(不删除):disable b 断点编号
打开断点:enable b 断点编号
-
查看内存、寄存器、各种参数
-
设置内存、寄存器、各种参数(加载文件)
-
远程调试
-
其他指令
r i
:查看当前寄存器的值(start之后)
disassemble main
: 反编译以下main函数
disassemble $rip
:反编译rip所在位置
p $寄存器
:打印寄存器的值
也可p $ 寄存器-0x10
:打印寄存器-0x10地址的值
x/20i $rip
:从rip开始编译20行,显示汇编指令
x/20b 地址
:以bety的形式查看从地址开始的内容
x/20g 地址
:以四个字节的形式显示
x后面的参数 | 作用 |
---|---|
i | 以汇编指令显示 |
b | 以beyt的形式显示 |
g | 以八个字节显示 |
w | 以四个字节显示 |
d | 以十进制来显示 |
x | 以十六进制显示 |
s | 以字符串形式显示 |
可以两个参数一起用
set *地址=0x61
:修改地址处的内容位0x61
x和set是很重要的指令
寄存器
(除了pc机外寄存器名字为r0~r31)
- 约定俗成的:
- rbp和rsp这两个寄存器是保护栈的
- rax:存储程序的返回值
amd64寄存器结构: - rax类:8Bytes(64位0~63)
- eax类:4Bytes(它是rax的前32位0~31,其他寄存器也有类似的,但并不是所有的寄存器都是这样,r8,r9之类叫r8d,r9d)
- ax:2Bytes(eax类再取一半,前十六个:0~15)
- ah类:1Bytes(ax~dx再取一半,后八个:8到15,不常用)
- al类:1Bytes(ax类再取一半,前八个:0到7)这些l们很常用
- 部分寄存器功能
- RIP:存放当前指令的指令地址
- RSP:存放当前栈帧的栈顶地址
- RBP:存放当前栈帧的栈底地址
- PAX:通用寄存器。存放函数返回值
寄存器数量有限,当变量数目很多时,寄存器会把变量的值存在内存里(虚拟内存),在使用时取出