x86汇编语法
- AT&T:GNU工具(Gas:GNU汇编器、gcc、gdb)
- 前缀:%reg,$立即数
- 操作数排序:mov 源操作数,目的操作数 add $0x4,%eax
- Intel :MASM(微软汇编器)、Turbo汇编器、NASM
- add eax,0x4
.model flat,平坦模式,代码段和数据段共用一个4G段。
局部变量、
局部变量是堆栈变量。作用域是单个子程序,从子程序返回到主程序时被释放。一种规范写法是
1 | LOCAL @buffer[10]:BYTE ;LOCAL 变量名1[重复数量]:类型,变量名2[重复数量]:类型 |
LOCAL
用于为堆栈变量预留空间。
局部变量:只能在过程中用,主程序里不能用;
堆栈变量:没有初始值,只在调用时分配。C语言中的函数值传递的本质。
一些常用类型整理
1 | byte db,word dw,DWORD dd,fword df,QWORD dq,tbyte dt 1,2,4,6,8,10 |
- TYPE返回变量大小
- LENGTHOF 返回变量元素个数
1 | ;,用于表示一个变量是否结束 |
- SIZE,SIZEOF返回所占字节数=LENGTHOF*TYPR
1.=和EQU伪指令
由等号或者EQU定义的符号常量不占用存储空间。
EQU类似于等号伪指令,但是EQU伪指令不许重复定义,而等号伪指令可以(同一个常量名可重复定义多次)。
1 | presskey EQU <"Output is:"> |
2.$ 当前地址运算符
3.LEA伪指令
OFFSET和ADDR编译时起作用,LEA是指令,在运行时起作用。
1 | MOV ESI,ADDR BVAL ;相当于 |
计算堆栈(程序执行是分配)变量的偏移地址时,只能用lea。
4.PTR 操作符
按照指定类型在内存中读写值。
1 | LIST DB 12H,34H,56H,78H; |
5.ALIGN和EVEN伪指令
CPU处理偶数地址比处理奇数地址要快。 可以在一个内存访问周期内获取该数据
ALIGN 对齐 (1,2,4) 按照n个字节的边界值对齐
EVEN 使下一地址从偶数地址开始
6.TYPEDEF和TYPEDEF PTR操作符
类型自命名和定义指针的类型,不占用存储空间
7.LABEL伪指令
别名,不占用存储空间
8.基数控制伪指令RAIDX
1 | .RADIX 16;默认该指令后面的数据都是16进制数,其他进制的数据需要额外说明 |
9.ORG伪指令
10.REPT伪指令
11.ASSUME伪指令
将程序的段与逻辑段绑定。
12.SHORT伪指令
循环
1 | .while(条件) |
14.结构体和共用体
15.宏定义
16.过程
模块化代码
PROC [NEAR] 或者[FAR],默认近调用,即在ODS实模式下的一个段里(<64KB(。
1 | 主程序中 CALL {PROC_noarg_name} |
17.ENTER和LEAVE
18.RET和RETN
19.IDA的反汇编
0day 安全
文件偏移地址 = 虚拟内存地址(VA)−装载基址(Image Base)−节偏移
= RVA -节偏移
对于 栈桢可能发生移位的情况
解决办法:
一个函数返回时,esp正好指向原来存储返回地址的下一位,我们将shellcode从ret_addr的后一个位置开始填充,并将ret_addr填充为一个进程中的”jmp esp”的指令的地址,这样函数返回后就会跳到esp指向的栈顶的位置开始执行shellcode。
缓冲区组成方式,现阶段已经讲了两种:
- 将shellcode放到缓冲区,然后覆盖返回地址到缓冲区的起始地址。这种适用于缓冲区较大的场合。
将shellcode放到函数返回地址以后,然后覆盖返回地址为”jmp esp”之类的指令,使得函数返回时跳转到shellcode处执行指令。这种适用于缓冲区较小的场合。
找到程序运行的线程环境块TEB。
- TEB的起始地址偏移0x30的地方指向进程环境块PEB。
- PEB的地址偏移0x0C的地方存放指向PEB_LDR_DATA结构体的指针,该指针指向一个存放着被进程装载的动态链接库的信息的结构体。
- PEB_LDR_DATA结构体偏移位置位0x1C的地方指向模块初始化链表的头指针InInitializationOrderModuleList。
- 4中的链表存放PE被载入时初始化的模块信息,第一个链表节点时ntdll.dll,第二个位kernel32.dll。
- kernel32.dll的节点偏移0x08是kernel32.dll在内存中载入的基址。
- kernel32.dll的基址加0xe3C是PE头的地址。
- PE头偏移0x78存放着指向函数导出表的指针。
- 安照下述方法寻址:
- 导出表偏移0x1C的指针指向存储导出函数偏移地址(RVA)的列表。
- 导出表偏移0x20指针指向存储导出函数名的列表。
- 根据函数名找到我们要的函数是导出表中的第几个,然后再地址列表中找到对应RVA。
- RVA加上动态链接库的基址即是VA,这个也是我们在shellcode中需要的地址。
这里shellcode的构造为了尽可能的短,所以需要给每个API名字用一个hash去代替。
MessageBoxA:0x1e380a6a
ExitProcess:0x4fd18963
LoadLibraryA:0x0c917432
1 | push 0x1e380a6a |