【pwn入门】基础知识

声明

本文是B站你想有多PWN星盟安全学习的笔记,包含一些视频外的扩展知识。

工具和命令

常见的工具

  1. pwntools安装
  2. checksec安装
  3. pwndbg的安装和gdb使用
  4. ubuntu没有使用全部磁盘空间
sudo lvextend -l +100%FREE /dev/mapper/ubuntu--vg-ubuntu--lv
sudo resize2fs /dev/mapper/ubuntu--vg-ubuntu--lv
  1. one_gadget 下载 安装 与使用
  2. LibcSearcher-ng
  3. ubuntu 64上的GCC如何编译32位程序
sudo apt-get install build-essential module-assistant  
sudo apt-get install gcc-multilib g++-multilib  
gcc -m32 hello.c -o hello
  1. 关闭安全编译选项
gcc -m32 overflow.c -o overflow -z execstack -z norelro -fno-pie -no-pie -fno-stack-protector

常见命令

file
1.功能:查看文件的类型信息
2.案例:
在这里插入图片描述
3. 详细教程

ldd
1.功能:用于打印程序或者库文件所依赖的共享库列表
2.案例
在这里插入图片描述
3.详细教程
nm
1.功能:该命令用来列出指定文件中的符号
2.案例
在这里插入图片描述
3.详细教程
hexdump
1.功能:hexdump是Linux下的一个二进制文件查看工具,它可以将二进制文件转换为ASCII、八进制、十进制、十六进制格式进行查看。
2.案例
在这里插入图片描述

3.详细教程

readelf
1.功能:用于显示 elf 格式文件的信息
2.案例
在这里插入图片描述
3.详细教程
objdump
1.功能:对二进制进行反汇编
2.案例:
在这里插入图片描述
3.详细教程

gcc
1.功能:对源码进行编译
2.案例
在这里插入图片描述
3.详细教程

寄存器

通用寄存器

在这里插入图片描述
32位寄存器
eax:通常用来存放函数调用的返回值
esp:栈顶指针,指向栈的顶部
ebp:栈底指针,指向栈的底部,通常用ebp+偏移量的形式来定位函数存放在栈中的局部变量
eip:指针寄存器(instruction pointer) 这个寄存器保持着下一条要执行的指令的地址
ebx:数据存取
ecx:通常用作计数器,比如for循环
edx:暂不清楚
edi:字符串操作时,用于存放数据源的地址
esi:字符串操作时,用于存放目的地址的,和edi两个经常搭配一起使用,执行字符串的复制等操作
64位寄存器
rax:通常用于存储函数调用返回值
rsp:栈顶指针,指向栈的顶部
rbp:存放当前栈帧的栈底地址
rip:指针寄存器(instruction pointer) 这个寄存器保持着下一条要执行的指令的地址
rdi:第一个入参
rsi:第二个入参
rdx:第三个入参
rcx:第四个入参
r8:第五个入参
r9:第六个入参
rbx:数据存储,遵循Callee Save原则
r12~r15:数据存储,遵循Callee Save原则
r10~r11:数据存储,遵循Caller Save原则
参考资料

汇编基础

常见的汇编指令

数据传输指令

  1. MOV
MOV DEST, SRC // 把源操作数传送给目标
MOV EAX,1234H // 执行结果(EAX) = 1234H
MOV EBX, EAX 
MOV EAX, [00404011H] // [ ] 表示取地址内的值
MOV EAX, [ESI]  

  1. PUSH
PUSH VALUE //  把目标值压栈,同时SP指针-1字长
PUSH 1234H 
PUSH EAX
  1. POP
POP DEST // 将栈顶的值弹出至目的存储位置,同时SP指针+1字长
POP EAX

算术运算指令

  1. ADD
  2. SUB
  3. LEA
LEA REG, SRC //  把源操作数的有效地址送给指定的寄存器
LEA EBX, ASC  //  取 ASC 的地址存放至 EBX 寄存器中
LEA EAX, 6[ESI] //  把 ESI+6 单元的32位地址送给 EAX 
LEA RAX,[RBP-0X18] // RAX = RBP-0X18, 加方括号就代表把括号里运算的结果送到寄存器当中

逻辑运算指令

  1. NOT 取反运算指令 NOT dest 把操作数dest按位取反

  2. AND 与运算指令 AND dest, src 把dest和src进行与运算之后送回dest

  3. OR 或运算指令 OR dest, src 把dest和src进行或运算之后送回dest

  4. XOR 异或运算 XOR dest, src 把dest和src进行异或运算之后送回dest

xor ebx, ebx // ebx = 0

转移指令

  1. CMP
    比较整数
CMP destination,source // 实际就是destination - source,作差的值用来给JMP指令作为输入
  1. JMP
    无条件转移指令 JMP lable 无条件地转移到标号为label的位置
  2. J[Condition] JCC
    有条件转移指令
  3. CALL
    过程调用指令 CALL labal 直接调用label
  4. LEAVE
    在函数返回时,恢复父函数栈帧的指令,等效于:
MOV ESP, EBP
POP EBP
  1. RET
    在函数返回时,控制程序执行流返回父函数的指令,等效于:
POP RIP // 这条指令实际是不存在的,不能直接向RIP寄存器传送数据

参考资料
7.test

test eax,eax // 等价于cmp eax,0。eax&eax,与的结果用来作为跳转的判断条件,并不会把操作的结果赋值给eax

从C源代码到可执行文件的生成过程

编译:由C语言代码生成汇编代码
汇编:由汇编代码生成机器码
链接:将多个机器码的目标文件链接成一个可执行文件
在这里插入图片描述

两种汇编格式

在这里插入图片描述

GDB调试

常见的命令

gdb program // 启动进程,不带参数
run[r]	// 运行程序。可搭配参数使用
start	// 运行程序,停在第一条执行语句。可搭配参数使用
list[l]	// 查看程序源码
break[b]	// 设置断点。可指定文件名、函数名和行号等参数来设置断点
delete	// 删除断点等。可用于删除断点、监视点、display 等
continue[c]	// 继续执行程序。让程序继续执行,到下一个断点或程序结束
next[n]	// 单步执行程序,跳过函数调用
step[s]	// 单步执行程序,进入函数调用
ni // 指令级单步
si // 指令级进入
finish	// 结束当前函数。返回到函数调用点,就是通常意义上的步出。
b *0x000000000000123 // 对某个地址打断点
info r // 查看寄存器的信息
info b // 查看断点信息

参考资料

神级命令

1.x命令
1)一次显示个数
x/20b *0x000000000000123 // 打印内存地址中的值,以Byte的形式显示

x/20g *0x000000000000123 // 打印内存地址中的值,以8个Byte的形式显示

x/20w *0x000000000000123 // 打印内存地址中的值,以4个Byte的形式显示

2)显示形式
x/20x *0x000000000000123 // 打印内存地址中的值,以十六进制的形式显示,默认以十六进制显示

x/20d *0x000000000000123 // 打印内存地址中的值,以十进制的形式显示

x/20s *0x000000000000123 // 打印内存地址中的值,以字符串的形式显示

x/20i *0x000000000000123 // 打印内存地址中的值,以汇编的形式显示
2.set命令
set *0x000000000000123=0x61 // 将地址内存中的值设为0x61
set *((unsigned int)$ebp)=0x61 // 将寄存器中地址内存中的值设为0x61

3.断点使能命令
让断点失效和生效
在这里插入图片描述

其他知识

  1. 汇编中的长度
    BYTE 8bit
    WORD 16bit
    DWORD 32bit
    QWORD 64bit

字节序

小端序
低地址存放数据低位、高地址存放数据高位,我们所主要关注的格式。(助记:小跟班守规矩,低放低,高放高)
在这里插入图片描述
大端序
低地址存放数据高位、高地址存放数据低位。(助记:大领导不守规矩,高低错位)
在这里插入图片描述

程序结构

磁盘中的文件

ELF文件头表(ELF header)
记录了ELF文件的组织结构

程序头表/段表(Program header table)
告诉系统如何创建进程
生成进程的可执行文件必须拥有此结构
重定位文件不一定需要

节头表(Section header table)
记录了ELF文件的节区信息
用于链接的目标文件必须拥有此结构
其它类型目标文件不一定需要
在这里插入图片描述

内存中进程

Kernel Space:内核空间
Stack:栈 ,存储局部、临时变量,函数调用时,存储函数的返回指针,用于控制函数的调用和返回。在程序块开始时自动分配内存,结束时自动释放内存,其操作方式类似于数据结构中的栈。
Heap:堆,存储动态内存分配,需要程序员手工分配,手工释放.注意它与数据结构中的堆是两回事,分配方式类似于链表。
BSS Segment:未初始化过的数据,在程序运行初未对变量进行初始化的数据。
Data Segment:初始化过的数据,在程序运行初已经对变量进行初始化的数据。
Text Segment:程序段,程序代码在内存中的映射,存放函数体的二进制代码。
在这里插入图片描述

进程地址空间中最顶部的段是栈,大多数编程语言将之用于存储函数参数和局部变量。调用一个方法或函数会将一个新的栈帧(stack frame)压入到栈中,这个栈帧会在函数返回时被清理掉。由于栈中数据严格的遵守FIFO的顺序,这个简单的设计意味着不必使用复杂的数据结构来追踪栈中的内容,只需要一个简单的指针指向栈的顶端即可,因此压栈(pushing)和退栈(popping)过程非常迅速、准确。进程中的每一个线程都有属于自己的栈。

与栈一样,堆用于运行时内存分配;但不同的是,堆用于存储那些生存期与函数调用无关的数据。大部分语言都提供了堆管理功能。在C语言中,堆分配的接口是malloc()函数。如果堆中有足够的空间来满足内存请求,它就可以被语言运行时库处理而不需要内核参与,否则,堆会被扩大,通过brk()系统调用来分配请求所需的内存块。堆管理是很复杂的,需要精细的算法来应付我们程序中杂乱的分配模式,优化速度和内存使用效率。处理一个堆请求所需的时间会大幅度的变动。实时系统通过特殊目的分配器来解决这个问题。
在这里插入图片描述
参考资料

磁盘和内存的映射

一个段(segment)包含多个节(section),段视图用于进程的内存区域的 rwx权限划分,节视图用于ELF文件编译链接时与在磁盘上存储时 的文件结构的组织

代码段(Text segment)包含了代码与只读数据
.text 节
.rodata 节
.hash 节
.dynsym 节
.dynstr 节
.plt 节
.rel.got 节
……
数据段(Data segment)包含了可读可写数据
.data 节
.dynamic 节
.got 节
.got.plt 节
.bss 节
……
栈段(Stack segment)

在这里插入图片描述
在这里插入图片描述

程序数据是如何在内存中组织的

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值