基础知识
寄存器与系统调用
x86
名称 | 用途 |
---|---|
eax | 通用寄存器,可以存变量的值。累加器操作数和结果数据累加器,返回值运算结果一般存储在这里。 |
ebx | 通用寄存器。基地址,在内存寻址的时候存放基地址。 |
ecx | 通用寄存器。计数器,字符串和循环操作的计数器。 |
edx | 通用寄存器。用于存储部分乘法结果和部分除法被除数。 |
ebp | 基地址寄存器。用来存储当前函数状态的基地址,在函数运行时不变,可以用来索引确定函数参数或局部变量的位置。里面存放一个地址。==一般情况下,ebp和返回地址相邻。 == |
edi | 字符串操作的目标指针。 |
esp | 用来储存函数调用栈的==栈顶地址 ==,在压栈和退栈时发生变化 |
eip | 用来存储==即将 == 执行的程序指令的地址。 |
寄存器长度:
名称 | 长度 |
---|---|
RAX | 64位,8字节。 |
EAX | 32位,4字节。 |
AX | 16位,2字节。 |
AH | 高八位。1字节。 |
AL | 低八位。1字节。 |
X64
调用函数寄存器传参顺序:
x64 | x86 |
---|---|
rdi,rsi,rdx,rcx(r10),r8,r9,超过6个参数直接入栈 | 不通过寄存器传参,将参数从右向左入栈 |
x64系统调用
read(0,buf,0x100)
xor rdi,rdi
mov rsi,0x601000 //buf
mov rdx,0x100
mov eax,0
syscall
rax | 系统调用号 |
---|---|
参数 | rdi,rsi,rdx,r10,r8,r9 |
返回值 | rax |
x86_64系统调用
int execve(const char* filename,char *const argv[],char *const envp[]);
char *name[2];
name[0] = "/bin//sh";
name[1] = NULL;
int execve("/bin//sh",name,0);
xor %eax,%eax //给eax赋值为0,作为字符串的结束符入栈
pushl %eax //第三个参数入栈
push $0x68732f2f // 字符串//sh入栈
push $0x6e69622f // 字符串/bin入栈
movl %esp,%ebx //将字符串'/bin//sh'的首地址赋值给ebx
pushl %eax //第三个参数envp入栈,eax的值为0
pushl %ebx //第一参数filename入栈
movl %esp,%ecx //给第二个参数argv赋值
movb $0xb,%al //给eax的低八位赋值0xb,即系统调用号
int $0x80 //执行系统调用
syscall指令是int 0x80的64位版本,syscall是在x86_64上进入内核模式的默认方式。
int 0x80是选择eax作为系统调用编号,ebx,ecx,edx,esi,edi和ebp传递参数。
x86和x86_64的区别:
x86、x86_64主要的区别就是32位和64位的问题,x86中只有8个32位通用寄存器,eax,ebx,ecx,edx, ebp, esp, esi, edi。x86_64把这8个通用寄存器扩展成了64位的。
参考文献:X86、X64和X86_64区别 – 作者:arctic_fox
栈帧
栈帧就是一个函数的执行环境:
函数参数,函数局部变量,函数执行完后返回到哪里等。
每一个栈帧代表的就是一个未完成的函数。
x64: rbp + 0x8 = Return Address
x86: ebp + 0x4 = Return Address
汇编代码
数据存储模式
大端序 | 小端序 |
---|---|
数据高位在内存低位,数据低位在内存高位 | 数据高位在内存高位,数据低位在内存低位 |
地址0x77 66 55 44
大端序:77 66 55 44
小端序:44 55 66 77
大端序常用于ARM架构,小端序常用与x86,AMD64架构
内存的五种表现形式
形式 | 示例 |
---|---|
立即数 | 0x33333 |
寄存器 | mov ebx,0x3333; mov eax,ebx; |
寄存器+立即数 | mov ebx,0x3333; mov eax,DWORD PTR[ebx + 4] |
比例因子 | 常用于数组。[REG+REG*{1,2,4,8}] 其中,1,2,4,8分别可以对应char,short,int,long int。数组元素地址=数组元素首地址+元素索引*数组元素占用空间 |
比例因子+立即数 | mov ecx, DWORD PTR[eax+ebx*4+1] |
常用汇编指令
指令 | |
---|---|
mov | 数据传输指令(赋值)mov dst,src 将src的值传输到dst |
push | 入栈。push src 将src入栈 |
pop | 出栈。pop dst 将栈顶元素弹出,并存至dst |
add/sub | 加减法指令。add dst,src dst-src并将结果存至dst |
乘除与自增减
指令 | |
---|---|
DIV | 无符号除法。DIV OPRD。带符号数指定除法:IDIV |
MUL | 无符号乘法。MUL OPRD。带符号乘法:IMUL |
DEC | 自减指令。DEC OPRD。功能:OPRD = OPRD - 1 |
INC | 自增指令。INC OPRD。功能:OPRD = OPRD + 1 |
逻辑运算
指令 | |
---|---|
AND | 与运算。AND OPRD1,OPRD2 |
OR | 或运算。OR OPRD1,OPRD2 |
XOR | 异或运算。XOR OPRD1,OPRD2。功能:两个数相同就为0,不同就为1 |
NOT | 非运算。NOT exp。功能:按位取返。0 --> 1, 1 --> 0。 |
LOOP
循环控制指令。
格式:LOOP 标号。
功能:用ecx计数,提前初始化ecx的值,当ecx的值减为0时循环停止。
mov ecx,10
s:
add eax,ebx
loop s
JMP
将程序跳转至某一地址执行。
jmp A
等价于
mov rip,A
CALL
过程调用指令
call A
等价于
push next_rip
mov rip,nex_rip
LEAVE
还原至调用者的栈帧。
mov rsp,rbp
pop rbp
RET
返回指令
pop rip
jmp rip
DWORD PTR
DWORD PTR 表示要取四个字节长度(32位)。
同理还有:BYTE-PTR就是指定为一个字节,WORD-PTR就是指定为两个字节
mov eax,DWORD PTR[esp]
Linux的文件保护
ASLR
Address Space Layout Randomization
地址空间布局随机化
PIE
Position-Independent-Executable
ASLR 不负责代码段以及数据段的随机化工作,这项工作由 PIE 负责。但是只有在开启 ASLR 之后,PIE 才会生效。
NX
No-Execute
数据段不该有执行权限:rw-
代码段不该有写入权限:r-x
Canary
哨兵保护
RELRO
Relaocation-Read-Only