做 pwn 或者 reverse 的一些基础
程序的编译与链接
编译:由C语言代码生成汇编代码
汇编:由汇编代码生成机器码
链接:将多个机器码的目标文件链接成一个可执行文件
Linux下的可执行文件格式ELF
可执行文件:.out
动态链接库:.so
静态链接库:.a
Windows下的可执行文件格式PE
可执行文件:.exe
动态链接库:.dll
静态链接库:.lib
ELF文件结构
节视图(磁盘中划分程序)、段视图(内存中)
32位系统虚拟内存大小为4GB(2的32次方)
并且内核空间(kernal)共享,下面的用户空间为3GB,上面的内核空间为1GB
操作系统(arch为例):1. linux内核(不同发行版都一样)。 2. 软件是由GUN开发的(ls, cd等) 3. arch提供软件源 4. 桌面环境也是一个用户态程序(也是一个软件)
内核是用于管理硬件的, 所以内核只要在内存中装载一份,复用的思想
glic动态链接库在内存中也只有一份
64位操作系统256TB, 内核128TB, 用户128TB
内存从低位向高位写
进程虚拟地址空间
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 27 28 29 30 31 32 33 34 35
| 用户空间中分为(从上往下地址由高到低) 内核空间 栈空间(Stack):动态存储区, 控制程序流 Memory Mapping Region:映射一个虚拟空间(glic) 堆空间(heap):动态存储区, 满足用户动态内存申请(malloc) data段:静态存储区 code段:静态存储区 堆空间从低地址向高地址增长 栈空间从高地址向低地址增长
段和节:
·代码段包含了代码和只读数据 .test节(用户的代码实现) .rodata节 .hash节 .dynsym节 .dynstr节 .plt节 .rel.got节 ...... ·数据段包含了可读可写数据 .data节(一般性数据) .dynamic节(动态链接所需要的结构) .got节 .got.plt节 .bss节(全局偏移量的地址) ...... ·栈段
·一个段包含多个节(意思是从磁盘到内存,一个段会变为多个节) ·段视图用于进程的内存区域的rwx权限划分 ·节视图用于ELF文件 编译链接时 与 在磁盘上存储时 的文件结构的组织
|
程序的装载与进程的执行
磁盘上的可执行文件要先到内存,才能被CPU执行
从程序变为虚拟内存中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| int glb; char* str = "Hello world";
int sum(int x, int y) { int t = x + y; }
int main { sum(1, 2); (调用函数消耗的内存空间在栈中) void* ptr = malloc(0x100); read(0, ptr, 0x100); // input "deadbeef" return 0; }
|
编译链接执行
载入内存
1 2 3 4 5 6 7 8 9 10 11 12
| Kernel: Stack: t、ptr (程序进程执行栈) Shared libraries: Heap: "deadbeef" (存放堆分配的空间) Bss: glb (存放未初始化的全局变量)(不占用磁盘空间但是占用内存空间) Data: str (保存只读、不可写、不可执行的数据) Text: main、sum、"Hello world!" (以机器码的形式存放函数) Unused:
型参x、y的: amd64: CPU寄存器中 x86: Stack中
|
1 2 3 4 5 6 7
| 大端序和小端序
小端序(LSB): ·低地址存放数据低位、高地址存放数据高位(高"ABC"低, 内存中低到高: CBA) ·主要关注 大端序(MSB): ·低地址存放数据高位、高地址存放数据低位(高"ABC"低, 内存中低到高: ABC)
|
1 2 3 4 5 6 7 8 9 10 11 12
| amd64寄存器结构 rax: 8Bytes (rax表示64bits(8Bytes)长的寄存器) 64位 eax: 4Bytes (eax表示32bits(4Bytes)长的寄存器, 取rax的低四字节来操作) 32位 ax: 2Bytes (rx的低二字节) 16位 ah: 1Bytes (ax中的高一位字节) al: 1Bytes (ax中的第一位字节)
部分寄存器的功能 RIP: PC, 存放下一条指令的偏移地址 RSP: 存放当前栈帧的栈顶偏移地址 RBP: 存放当前栈帧的栈底偏移地址 RAX: 通用寄存器或存放函数返回值
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| 静态链接的程序的执行过程
user mode $ ./binary frok() execve("./binary", *argv[], *envp[]) kernel mode ----------------------------------- sys_execve() do_execve() search_binary_handler() load_elf_binary() ----------------------------------- user mode _start main()
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| 动态链接的程序的执行过程
user mode $ ./binary frok() execve("./binary", *argv[], *envp[]) kernel mode ----------------------------------- sys_execve() do_execve() search_binary_handler() load_elf_binary() ----------------------------------- user mode ld.so //库函数偏移地址 _start __libc_start_main() _init main()
|
x86&amd64汇编基础简述
函数状态涉及到: esp, ebp, eip
esp存储函数调用栈的栈顶地址
ebp存储当前函数状态的基地址
eip存储下一条执行的指令的地址
指令格式
Base | Index | Scale |
---|
0 | 2 | 4 |
偏移地址: 0+2*4 = 8 | | |
假设位移为: 0x10
则地址为: 0+2*4+0x10 = 24
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 27 28 29 30 31 32 33 34 35 36
| ·MOV: MOV DEST SRC 把源操作数传给目标(源操作数和被操作数不能同时是内存) ·LEA: 把源操作数的有效地址送给指定的寄存器 LEA EBX ASC: 取ASC的地址存放至EBX寄存器中 ·ADD/SUB: 目的操作数 +/- 源操作数 -> 目的操作数地址
·PUSH: 将一个寄存器中的数据入栈,然后RSP减一个字节 例如: push $2 分解为: sub 长度 %rsp mov $2 (%rsp) ·POP: 出栈用一个寄存器接受数据, 然后RSP减一个字节 例如: pop 目的地址 分解为: mov (%rsp) 目的地址 add 长度 %rsp ·CMP 目的操作数减去源操作数 ·JMP ·J[Condition]: ·CALL: 将目标地址压栈, 然后JMP 例如: call reg 分解为: push RIP JMP reg ·LEAVE: 函数返回时, 回复父函数栈帧的指令 MOV ESP, EBP POP EBP ·RET: 在函数返回时, 控制程序执行流返回父函数的指令 POP RIP(实际不存在的)
|
两种汇编格式
intel | AT&T |
---|
mov eax, 8 | movl $8, %eax |
mov ebx, 0ffffh | movl $0xffff, %ebx |
int 80h | int $0x80 |
mov eax, [ecx] | movl (%ecx), %eax |
[ ]: 取目的地址中的数值
intel
操作符重载
intel 汇编格式
1 2 3 4
| [base+index*scale]Disp
byte ptr mov qword ptr [rsp], 0xfffff
|
1 2 3 4 5 6 7 8
| sum: push ebp mov ebp, esp mov eax, [ebp+12] add eax, [ebp+8] pop ebp retn
|
AT&T
在操作符后面会加上操作数的大小描述
AT&T 汇编格式
1 2 3
| Disp(base, index, scale)
movq $0xffff, (%rsp)
|
C语言 | 数据类型 | 汇编代码后缀 |
---|
char | 字节 | b byte |
short | 字 | w word |
int | 双字 | l |
long int | 双字 | l |
long long int | 无 | 无 |
char* | 双字 | l |
float | 单精度 | s |
double | 双精度 | l |
long double | 扩展精度 | t |
1 2 3 4 5 6 7
| sum: pushl %ebp movl %esp, %ebp movl 12(%ebp), %eax addl 8(%ebp), %eax popl %ebp ret
|