0x01 PWN

checksec下载安装

git clone https://github.com/slimm609/checksec.sh.git
sudo ln -s /xx/xx/checksec /usr/local/bin/checksec  #建立软链接,源地址需要是绝对路径

ida

F5/tab 查看伪代码
空格 查看汇编代码
视图->打开子视图->字符串 :查看所有字符串
编辑->修补程序 :修改程序 修改完后点击修补程序应用到输入文件即可保存修改
一些信息 HKEY_CURRENT_USER\Software\Hex-Rays\IDA\History 通过注册表查看

1、如何找到使用.rodata里数据的汇编行
选中字符串后鼠标右键点击交叉引用列表
image.png
2、查看二进制里所有的字符串
视图->子视图->字符串
image.png

2、ida联合gdb进行远程调试
F8单步调试,F9单步进入函数
https://uuzdaisuki.com/2020/02/04/ida%E8%BF%9C%E7%A8%8B%E8%B0...

3、ida远程调试之动态库
windows上加载你要调试的动态库,远程配置如下图所示。应用程序选择加载该动态库的应用程序,输入文件是该动态库。
image.png

4、反汇编报错positive sp value has found
https://blog.csdn.net/u010334666/article/details/82937413
在选项-常规勾选堆栈指针
image.png
可以看到堆栈指针
image.png
把出现负数的上一行改成和负数一样的值
image.png

5、给汇编代码添加描述
image.png

汇编显示机器码
image.png

6、规则
str R0,[sp,#0x428+var_420] 把R0的值存在sp+0x428-0x420所在地址里

python pwntools

安装 :pip install pwntools
环境:ubuntu python64位
调试:context(os='linux', arch='amd64', log_level='debug') 32位时改为i386
导入外部lib:from ctypes import *
ex:使用c的rand函数
libc = cdll.LoadLibrary('/lib/x86_64-linux-gnu/libc.so.6')
libc.srand(1)
libc.rand()
  • sendlineafter("在什么字符串后面发送数据",要发送的数据)
  • ljust(num,b'a') 补全payload,使长度为num字节
  • recvlineuntil() 可以截取收到内容中想要的数据
  • asm(shellcraft.sh()) 生成shell,使用前需要用context声明环境
  • elf=ELF(filepath) 解析elf文件,输出checksec数据
  • 使用p32等 from pwnlib.util.packing import p32

pwn

汇编转机器码
from pwn import *
context.arch='i386' #指定架构
print(asm('mov eax, 0'))

gdb

  • gdb filename :调试某个文件
  • info reg 查看寄存器的值
  • info args:打印当前函数参数名机值
  • info frame:打印当前函数的栈信息
  • info locals:打印当前函数所有局部变量及值
  • info functions: 打印所有函数
  • info files: 查看加载的可执行文件的信息,包括基地址。
  • info proc mappings 查看内存映射
  • info threads 查看线程 thread 3 选择3号线程
  • c(continue):继续执行/n(next):单步跟踪/s(step):步入
  • ni/si都是汇编级别的断点定位。si会进入汇编和C函数内部,ni不会。
  • finish 步出当前函数
  • start:重新启动程序
  • x /8gx:以16进制 输出8个64位数
  • x /4wx:以16进制 展示4个32位数
    x /10x $sp:输出当前堆栈栈顶往下10个栈里的值
    x/sh $rdi 以字符串形式查看
  • set $edx=0x12 修改寄存器的值
  • set args in/test.mp3 设置程序的参数
    show args 显示设置的参数
  • 直接gdb带参数运行
    gdb -q --args /opt/kingsoft/wps-office/office6/et -shield test2.xlsx
  • r < test.txt 从标准输入进行读取,先创建一个文件
    r 直接带上参数 ex: run -shield test.xx
  • p 变量名 查看变量在内存中的位置及值
    p/x $rax 查看rax寄存器里的值
  • disa main 查看main函数的反汇编代码
  • disassemble 0xxxx,0xxxx 查看指定位置的反汇编
  • bt 查看调用栈
  • gdb ./test core 调试core文件
  • catch load libtest.so 在目标程序加载共享库时设置断点
  • thread apply all bt 查看所有线程的调用栈
  • watch $ecx if $ecx == 0xffff 当ecx寄存器等于某值时停止
  • layout asm 展示汇编,layout src 展示源码。退出 layout 先ctrl+x 再按a; ctrl+x 按1/2 单窗口/双窗口模式
    layout下使用ctrl+p /ctrl+n查看历史命令,ctrl+b/ctrl+f 光标前后移动
    使用fs next 切换窗口/ctrl+x o
    ctrl+L 刷新窗口 /refresh
    - layout快捷键
    当前运行到的行被高亮且前面有一个 > 标记.

    前面第一个标记的含义
    B: 至少被触发过 1 次的断点.
    b: 还没有被触发过的断点.
    H: 至少被触发过 1 次的硬件断点.
    h: 还没有被触发过的硬件断点.
    前面第二个标记的含义
    +: 被启用的断点.
    -: 未被启用的断点.
  • tui new-layout test {-horizontal asm 1 regs 1} 2 status 0 cmd 1 创建一个布局,使用layout test使用它
    https://www.chuxin911.com/GDB_note_2_tui_20220708/
  • find 0x400000,0x3b85fff,"Syntax error" 搜索字符串位置,需要注意的是后面的地址通过info proc map 查看得到的0x3b86000不是结束地址。它是没有被映射的第一个字节!在查找命令中使用这个地址会报错,因为它超出了内存映射的范围。所以,需要后退一个字节,到 0x3b85fff
  • set debug remote 1 显示远程调试信息
  • detach 脱离gdbserver
  • print $sp+0x12 直接在gdb里面进行计算
  • gdb 卡住怎么办,attach一下卡住的进程,看看卡在哪 https://blog.csdn.net/Dong_HFUT/article/details/125816152
设置断点 
1、b *0x111111  : 在0x11111处下断点,记得前面要加*
2、b func_name
3、b /src/codefile.cc:81。gdb将在运行到源码文件/src/codefile.cc的第81行中断
删除断点
delete [断点编号]
查看断点
info break
使断点生效/失效
enable/disable 断点编号

pwndbg

git clone https://github.com/pwndbg/pwndbg
cd pwndbg
sudo #./setup.sh

命令

  • parseheap 展示堆结构
  • fastbins fastbins指针

pwn

  • 将汇编转成机器码
    from pwn import *
    context.arch='i386' #指定架构
    print(asm('mov eax, 0'))

questions

  • 遇到执行elf文件提示没有那个目录或文件
    解决:
    Ubuntu 32位库的安装:
    ubuntu64位默认没有32位的库,所以32位的ELF文件无法执行,会提示找不到文件或者文件夹,所以需要手动安装32位的库。
    sudo apt install libc6-dev-i386
    sudo apt-get install lib32z1
  • 实验不同版本的glibc,patchelf和glibc-all-in-one
    https://blog.csdn.net/qq_41560595/article/details/114597342

0x02 reverse

elf文件upx脱壳 :kali下 upx -d 源文件 -o 目标文件

0x03 汇编知识点

1、32位计算机常用寄存器
image.png

2、x86-64位架构中的寄存器
寄存器 描述
RAX 通用寄存器,可用于存储整数数据或指针
RBX 通用寄存器,可用于存储整数数据或指针
RCX 通用寄存器,可用于存储整数数据或指针
RDX 通用寄存器,可用于存储整数数据或指针
RDI 存储函数参数
RSI 存储函数参数
RBP 存储函数局部变量
RSP 存储函数栈指针
R8-R15 存储函数参数或临时数据
RIP 存储下一条要执行的指令的地址
RFLAGS 存储处理器状态信息,例如进位标志、零标志和符号标志等
XMM0-XMM15 扩展多媒体寄存器,可用于存储浮点数和矢量数据

3、 入参规则
在32位系统下,函数参数通常通过栈来传递。而在64位系统下,函数参数则主要通过寄存器进行传递。

在32位系统下,函数参数通常按照从右向左的顺序依次入栈,使用ESP寄存器作为栈指针。常用的参数传递寄存器包括:

EAX:用于存放函数的返回值,同时也可以作为第一个整型参数。
EBX、ECX、EDX:作为普通整型参数的通用寄存器。
ESP、EBP:ESP作为栈指针,EBP作为帧指针,用于访问函数局部变量和参数。
ESI、EDI:作为指针参数或字符串操作的源地址和目的地址。
在64位系统下,函数参数则主要通过寄存器进行传递,寄存器的使用方式如下:

RDI、RSI、RDX、RCX、R8、R9:用于传递前6个整型参数。
XMM0-7:用于传递浮点参数。
RAX:用于存放函数的返回值。
RBX、RSP、RBP、R12-R15:作为通用寄存器和保存上下文的寄存器。

4、标识寄存器
image.png

5、syscall命令
syscall 指令用于在 x86-64 架构的 64 位模式下将控制权从用户空间代码转移到内核。当执行 syscall 时,处理器将当前 RIP(指令指针)保存在 RCX 寄存器中,将当前的 RFLAGS 寄存器保存在 R11 寄存器中。系统调用号加载到 RAX 寄存器中,而系统调用参数依次放置在 RDI、RSI、RDX、R10、R8 和 R9 寄存器中。

系统调用完成后,返回值存储在 RAX 寄存器中。R11 寄存器包含系统调用返回时的 RFLAGS 值,RCX 寄存器包含保存的 RIP 值。内核通过执行 iretq 指令将控制权返回给用户空间代码,该指令恢复保存的 RIP 和 RFLAGS 值,并切换回用户模式执行。

6、标志寄存器 https://en.wikipedia.org/wiki/FLAGS_register
image.png

7、32位和64位的内存空间
cat /proc/pid/maps查看某进程的实际虚拟内存布局
32位
image.png
32位Linux系统下,从0地址开始的内存区域不直接就是代码段区域,而是一段不可访问的保留区。因为大多数系统里,较小数值的地址不是个合法地址,如在C代码里会将无效指针赋为NULL。因此,这里会出现一段不可访问的内存保留区,防止程序因bug,导致读或写了一些小内存地址的数据,而使程序跑飞。

代码段从0x08048000开始排布(以上地址需gcc编译时不开启pie选项)。代码段、数据段都是从可执行文件映像中装载到内存中;BSS段则根据BSS段所需大小,在加载时生成一段0填充的内存空间。

64位系统
0x0 - 0x00007fffffffffff 将低128T划为用户空间
0xffff800000000000 - 0xffffffffffffffff 高128T划分为内核空间
image.png

用户空间、内核空间之间有个巨大内存空洞,这块空间不可访问,由CPU保证(这里的地址都不满足Intel 64 Canonical form)。

64位程序,查看/proc/pid/maps会发现代码段跟数据段的中间还有段不可读写的保护段,防止程序在读写数据段的时候越界访问到代码段,这保护段可让越界访问行为直接崩溃,防止它继续往下运行。

8、arm寄存器
ARM 处理器一般共有 37 个寄存器,其中包括:
1) 31 个通用寄存器,包括 PC(程序计数器)在内,都是 32 位的寄存器。
2) 6 个状态寄存器,都是 32 位的寄存器。
ARM 处理器共有 7 种不同的处理器模式:
(1)USR(10000):正常用户模式,程序正常执行模式。
(2)FIQ(10001):快速中断模式,以处理快速情况,支持高速数据传输或通道处理。
(3)IRQ(10010):外部中断模式,普通中断处理
(4)SVC(10011):操作系统保护模式(管理模式),即操作系统使用的特权模式(内核),处理软件中断swi reset
(5)abt(10111):数据访问中止模式,用于 虚拟存储器 和 存储器 保护
(6)und(11011):未定义指令终止模式,用于支持通过软件仿真硬件的协处理器
(7)sys(11111):系统模式,用于运行特权级的操作系统任务( armv4 以上版本才具有)
在所有的寄存器中,有些是各模式共用同一个物理寄存器,有些寄存器是各个模式自己拥有独立的物理寄存器

r0~r3 主要用于子程序间传递参数
r4~r11 主要用于保存局部变量,但在 Thumb 程序中,通常只能使用 r4~r7 来保存局部变量
r12 用作子程序间scratch 寄存器,即 ip 寄存器
r13 通常用做栈指针,即 sp
r14 寄存器又被称为连接寄存器(lr),用于保存子程序以及中断的返回地址
r15 用作程序计数器(pc),由于 ARM 采用了流水线机制,当正确读取了 PC 的值后,该值为当前指令地址加 8 个字节,即 PC 指向当前指令的下两条指令地址。
CPSR和SPSR都是程序状态寄存器,其中SPSR是用来保存中断前的CPSR中的值,以便在中断返回之后恢复处理器程序状态。
image.png

PC指针(r15)

R15用作程序计数器(PC)对应一个物理寄存器,由于ARM体系结构采用了多级流水线技术,对于ARM指令集而言,PC总是指向当前指令的下两条指令的地址,即PC的值为当前指令的地址值加8个字节程序状态寄存器。

CPSR
image.png
下面介绍其中几个比较重要的位,其他位,大家可以参考官方手册:

N: 当两个表示的有符号整数运算时,1表示运算结果为负数,0表示结果为正或零。
Z:1表示运算的结果为零,0表示运算的结果不为零。对于CMP指令,1表示进行比较的两个数大小相等。
C:下面分四种情况讨论C的设置方法:
a) 加法运算(包括比较指令CMN):当运算产生了进位时(无符号数溢出),C=1,否则C=0。
b) 减法运算(包括比较指令CMP):当运算时产生了借位(无符号数溢出),C=0,否则C=1。
c) 对于包含移位操作的非加/减运算指令,C为移出值的最后一位。
d) 对于其他的非加/减运算指令,C的值通常不改变。
V:下面分两种情况讨论V的设置方法
a) 对于加/减法运算指令,当操作数和运算结果为二进制的补码表示的带符号数时,V=1表示符号位溢出。
b) 对于其他的非加/减运算指令,C的值通常不改变。
I:1 表示禁止外部(硬件)中断(IRQ)
F:1 表示禁止快速中断(FIQ)
T:1表示为thumb状态0为arm状态
M[4:0]:用来设置处理器的工作模式具体数据见本文开始的介绍。

SPSR

SPSR 除usr、sys外,对应用于异常保护的CPSR的备份,异常时,保存CPSR值,异常退出时,将该值恢复到CPSR,以保证程序的正常运行,每一中异常运行模式(除usr和sys)有各自的物理寄存器。

内存空间分配
Linux内核一般将处理器的虚拟地址空间分成两部分,在32系统上,地址空间在用户进程和内核之间划分的典型比例为3:1,在给出的4GB的虚拟地址空间中,0 ~ 3GB将用于用户空间而3GB ~ 4GB将用于内核空间,内核提供了相关的配置项来修改该比例,也就是说Kernel最多寻址1GB的虚拟地址空间。

arm32位
image.png
arm64位
image.png

0x04 深度拓展

gdb原理

https://mp.weixin.qq.com/s/teERWh9IRMuO6tieOZNNng
1、gdb ./a.out

以这种方式直接运行时,首先,gdb解析a.out文件的符号。接下来我们输入 run 命令,gdb通过 fork() 一个新进程,然后通过 ptrace(PTRACE_TRACEME, 0, NULL, NULL); 设置traceme模式。最后执行 exec 启动加载要调试的文件。

2、attach pid

在调试PWN题时,通过attach pid来追踪要调试的进程。gdb通过执行 ptrace(PTRACE_ATTACH,pid, 0, 0) 来对目标进程进行追踪。

3、gdb server的target remote

在gdb+qemu调试内核时,经常用到target remote来attach到qemu上对vmlinux进行调试。二者之间有特殊的定义好的数据信息通信的格式,进行通信。

4、汇编转化成机器码 调试测试写好的汇编
https://www.cnblogs.com/ZIKH26/articles/15845766.html


白风之下
10 声望3 粉丝