做 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存储下一条执行的指令的地址

指令格式

BaseIndexScale
024
偏移地址: 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(实际不存在的)

两种汇编格式

intelAT&T
mov eax, 8movl $8, %eax
mov ebx, 0ffffhmovl $0xffff, %ebx
int 80hint $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
shortw 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