相关学习资源
二进制安全相关工具和教程站点
- IDA pro
- Intel汇编语言程序设计
内容体系
- 基本概念
- IA-32处理器体系结构
- 汇编语言基础
- 数据传送、寻址和算术运算
- 过程
- 条件处理
- 整数算术指令
- 高级过程
- 字符串和数组
- 结构和宏
- 32位Windows变成
- 高级语言结构
- 16位MS-DOS程序设计
- 磁盘基础知识
- BIOS程序设计
- 高级MS-DOS程序设计
- 高级主题
汇编和二进制基础知识
CPU指令的基本单位
1 byte = 8 bit 0~155 1 word = 2 byte 0~65535 1 double word = 2 word 0~4294967295 1 kilobyte = 1024 byte 1 megabyte = 1024 kbyte总线
数据总线 控制总线 地址总线地址空间
32位寄存器可以使用0-2^32-1,可对4GB内存进行寻址寄存器
80386处理器中的寄存器分为8组,每组宽度为32位通用寄存器段寄存器指令寄存器标志寄存器系统地址寄存器控制寄存器调试寄存器测试寄存器通用寄存器
EAX 累加器 在乘法和除法指令中被自动使用 EBX 基址寄存器 ECX 计数器 循环计数器 EDX 数据寄存器 ESI 源变址寄存器 EDI 目的变址寄存器 EBP 扩展基址指针寄存器 由高级语言用来引用函数参数和局部变量 ESP 栈指针寄存器
EAX EBX ECX EDX ESI EDI EBP ESP #32位
AX BX CX DX SI DI BP SP #低16位 AH BH CH DH #高8位 AL BL CL DL #低8位段寄存器:
CS:代码段(Code Segment) DS:数据段(Data Segment) ES:附加数据段(Extra Segment) SS:堆栈段(Stack Segment) FS:附加段 GS 附加段指令寄存器:
EIP 指令指针寄存器 低16位为IP(8086) 它存储的是下一条要执行指令的地址。标志寄存器:
IOPL(I/O Privilege Level) I/O特权级字段,它的宽度为2bit,它指定了I/O指令的特权级。如果当前的特权级别在数值上小于或等于IOPL,那么I/O指令可执行。否则,将发生一个保护性异常。 NT(Nested Task): 控制中断返回指令IRET,它宽度为1位。NT=0,用堆栈中保存的值恢复EFLAGS,CS和EIP从而实现中断返回;NT=1,则通过任务切换实现中断返回。 RF(Restart Flag): 重启标志,它的宽度是1位。它主要控制是否接受调试故障。RF=0接受,RF=1忽略。如果你的程序每一条指令都被成功执行,那么RF会被清0。而当接受到一个非调试故障时,处理器置RF=1。 VM(Virtual Machine): 虚拟8086模式(用软件来模拟8086的模式,所以也称虚拟机)。VM=0,处理器工作在一般的保护模式下;VM=1,工作在V8086模式下。 其它16个标志位的含义和8086一样: CF(Carry Flag): 进位标志位,由CLC,STC两标志位来控制,在无符号算数运算的结果无法容纳于目的操作数中时被设置
PF(Parity Flag): 奇偶标志位
AF(Assistant Flag): 辅助进位标志位 ZF(Zero Flag): 零标志位 SF(Singal Flag): 符号标志位 IF(Interrupt Flag): 中断允许标志位,由CLI,STI两条指令来控制 DF(Direction Flag): 向量标志位,由CLD,STD两条指令来控制 OF(Overflow Flag): 溢出标志位PSW(Program Flag)程序状态字寄存器,是一个16位寄存器,由条件码标志(flag)和控制标志构成
+---------------------------------------------------------------+ |15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 | +---------------------------------------------------------------+ |-- -- -- -- OF DF IF TF SF ZF -- AF -- PF -- CF | +---------------------------------------------------------------+OF(Overflow Flag)溢出标志。溢出时为1,否则置0
SF(Sign Flag)符号标志。结果为负时置1,否则置0 ZF(Zero Flag)零标志,运算结果为0时ZF位置1,否则置0 CF(Carry Flag)进位标志,进位时置1,否则置0 AF(Auxiliary carry Flag)辅助进位标志,记录运算时第3位(半个字节)产生的进位置。有进位时1,否则置0 PF(Parity Flag)奇偶标志。结果操作数中1的个数为偶数时置1,否则置0 DF(Direction Flag)方向标志,在串处理指令中控制信息的方向 IF(Interrupt Flag)中断标志 TF(Trap Flag)陷井标志直接标志转移
寻址方式
段基址*10H+段内偏移地址,形成20位地址 段基址是16的倍数,长度最大不超过64K数据的表示方法
汇编指令
整数
d 十进制 b 二进制 q/o 八进制 h 十六进制 r 编码实数 t 十进制(可选) y 二进制(可选)整数表达式
优先级 1 () 2 +,- 单目加减 3 *,/ 3 MOD 取模 4 +,- 加减数据传送
算术运算/逻辑运算 移位 控制转移 串操作 高级语言支持 条件字节设定 位操作 处理器控制 保护方式通用数据传送
累加器专用传送 地址传送 标志传送伪指令
.data 标识包含变量的区域 .code 标识程序中包含指令的区域 func PROC PROC标识了过程的开始,func可以是任何名字- 代码标号
target: mov ax,bx jmp target
- 数据标号
first BYTE 10
- 注释
;单行注释COMMENT ; 多行注释;
mov 赋值add 两个值相加sub 相减mul 相乘inc 加1dec 减1neg 求相反数(转换成对应的二进制补码,补码可通过将目的操作数的所有数据位取反加1)jmp 跳转到一个新位置call 调用一个过程
byte 8位无符号整数sbyte 8位有符号整数word 16位无符号整数sword 16位有符号整数dword 32位无符号整数sdword 64位有符号整数fword 48位整数qword 64位整数tbyte 80位整数real4 32位IEEE短实数real8 64位IEEE长实数real10 80位IEEE拓展精度实数
.datalist BYTE 10,20,30,40;在内存中的形态:; 0000:10; 0001:20; 0002:30; 0004:50list BYTE 10,20,30,40BYTE 50,60,70,80BYTE 81,82,83,84;定义字符串str1 BYTE 'This is a test', 0 ;str2 BYTE "This is a test ",0dh,0ah, ;CRLFBYTE "This is a test ",0dh,0ah,0 ; dup BYTE 20 DUP(0) ;20字节,全部用0填充BYTE 4 DUP("stack") ;20字节,"STACKSTACKSTACKSTACK"word1 WORD 65535 ;最大无符号字word2 WORD -32768 ;最小无符号字word3 WORD ? ;未初始化的字
push 压栈
pop 出栈 MOV 赋值 MOVZX 零拓展传送 MOVSX 符号拓展传送MOV DL,90H ;DL=90HMOVSX AX,DL ;AX=FF90HMOVZX AX,DL ;AX=0090HMOVSX ESI,DL ;ESI=FFFFFF90HMOVZX ESI,DL ;ESI=00000090H
CBW 将字节数据扩展成字,符号位扩展到AH中
CWD 将字数据扩展成双字,符号位放到DX中MOV AL,70H ;CBW ;AX=0070(2byte,1word)CWD ;DX=0000,AX=0070(4byte,2word)
XCHG 交换两个操作数的数据,支持8位、16位、32位
PUSH 入栈,支持立即数入栈 PUSHA 将8个16位通用寄存器全部入栈,顺序为AX,CX,DX,BX,SP,BP,SI,DI,然后SP指针寄存减16,内容为PUSHA指令执行前的内容 PUSHAD 将8个32位通用寄存器全部入栈,顺序为EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI,然后ESP的内容是执行指令PUSHAD之前的内容 POP 出栈 POPA 8个16位通用寄存器全部出栈,堆栈指针寄存器不是堆栈中弹出的内容,而是加16之后得到 POPAD 8个32位通用寄存器全部出栈,ESP的内容是执行指令PUSHAD之前的内容 LEA 取有效地址MOV EAX, 11111111hMOV EBX, 11111111hLEA ECX, [EAX+EBX] ;ECX = 22222222h
LDS 装入指针,目的寄存器必须是16位或32位的通用寄存器,操作数必须是内存单元,不能是立即数
LDS EAX, [1000H];将偏移地址为1000,1001h这两个字节单元的内容送给DS,将1002,1003,1004,1005这四个字节单元的内容送往EAXLDS AX,[1000H];这表明将偏移地址为1000,1001H这两个字节单元的内容送给段寄存器DS,将偏移地址1002,1003H两个字节单元的内容送往EAX
LES 同LDS,不过段寄存器是ES
LFS 同LDS,不过段寄存器是FS LGS 同LDS,不过段寄存器是GS LSS 同LDS,不过段寄存器是SSLAHF 将标志寄存器的低8位送至AH中,包括SF,ZF,ZF,PF,CF。
SAHF 与LAHF的过程恰好相反 PUSHF 将标志寄存器的EFLAGS低16位内容入栈 PUSHFD 将标志寄存器EFLAGS的内容入栈 POPF 将栈顶的一个字弹出,并将它送到标志寄存器EFLAGS的低16位 POPFD 将栈顶的两个字弹出,并将它送到标志寄存器EFLAGSOFFSET 取当前内存的地址
offset Array
EBP EBP指向栈底
ESP 指向栈区域的栈顶位置 EIP 指向下一个将会被执行的指令EAX = [AX]+[AH+AL]
db: 声明 1 byte(字节)变量
dw: 声明 2 byte(字节)变量 = 1 word dd: 声明 4 byte(字节)变量 = 2 word = 1 double wordmov eax ebxmov eax 333hmov eax [ebx]mov eax [ebx+66h]
和C语言的对比:
a = b[0x66] => mov eax [ebx+66h]数据交换:
lea edx, b ;将edx指向bmov [edx], ebx ;赋值a = bmov ebx, a ;赋值ebx = amov b,ebx ;赋值a = bmov ecx, offset a ;将ecx指向a
条件跳转:
cmp 比较结果 jx 检查条件x,有大于、小于、等于三个状态 je 相等时跳转 jne 不相等时跳转 jb、ja 比较无符号数然后决定是否跳转 jl、jg 比较有符号数然后决定是否跳转 jbe 在一个无符号数小于或者等于另一个无符号数时发生跳转 jmp 无条件跳转cmp EAX,EBX ;比较EAX和EBXjz xxx ;如果相等就跳转到xxxcafebabecmp [ECX], EDX ;比较*ECX和EDX的值JAE yyy ;如果*ECX>=EDX,就跳转到yyy
- 函数调用:
push offset, LibName ;将字符串偏移量压入堆栈call LoadLibrary ;进行函数调用mov h,EAX ;将EAX中的值传给变量h
PE、ELF基础知识
- PE文件结构: .text 二进制代码 .data 初始化的数据块 .idata 动态链接库等外来函数与文件 .rsrc 资源
文件偏移地址 = 虚拟内存地址-装载基址-节偏移
= RVA - 节偏移- 文件幻数 Windows PE File
4d 5a MZ
Jpeg Image File
ff d8 ff e0 00 10 4a 46 49 46 JFIF
Java .class file
ca fe ba be
基本工具
- PE Tools 分析Windows进程和可执行文件
- PEiD 识别构建PE文件所使用的编译器
- nm 检查中间目标文件(拓展名为.o的文件),可以显示符号、函数等信息 动态链接二进制文件,未定义的符号在C语言共享库中定义
- ldd 链接器(静态链接、动态链接) 静态链接:链接器将应用程序的目标文件和所需的库文件组合起来,可执行文件更大 动态链接:不需要复制库,方便维护,可执行文件更小
gcc -o test test.cgcc -o test test.c --static
编译好之后可以通过file参数查看类型
ldd ./test #查看库依赖(mac:otool -L windows:dumpbin)
`objdump 节头部 程序每节的摘要信息
专用头部 程序内存分布信息,还有运行时加载器所需的其他信息 调试信息 程序中的调试信息 符号信息 类似nm的方式转储符号表信息 反汇编代码清单 对文件中标记为代码的部分执行线性扫描反汇编- dumpbin 从PE文件提取符号、导入函数名、导出函数名和反汇编代码
- c++filt nm test | grep demo |c++filt 跟C++函数重载有关的操作,显示重载函数的不同形态
- strings 提取文件中的字符串内容 strings test strings -t 可显示字符串文件的偏移量信息 strings -e 可搜索更广泛的字符
反汇编器:
msfpayload linux/x86/shell_findport CPORT=4444 R >testls -l testndisasm -u test
分析网络数据包中可能包含shellcode的计算机网络攻击时,可以采用流式反汇编器来反汇编数据包中包含shellcode的部分
栈帧: 程序运行时栈中分配的内存块,专门用于特定的函数调用。
因为每个递归函数调用都有自己的栈帧,使得递归成为可能。函数调用步骤:
1.调用方将被调用方所需的参数放到该函数所采用的调用约定制定的位置 2.调用方将控制权转交给被调用方 3.如有必要,为被调用的函数配置栈指针 4.被调用方为局部变量分配空间 5.被调用函数执行操作 6.函数完成操作后,为局部变量保留的栈空间被释放。(逆向执行第4步中的操作) 7.还原寄存器值 8.被调用函数将控制权返还给调用方 9.删除栈中的参数调用约定: 通过调用函数将函数参数存入栈中,调用函数必须存储被调用函数所需的参数。
调用约定指定调用方放置函数所需参数的具体位置。 调用约定可能要求将参数放置在制定的寄存器、程序栈或者寄存器和栈中。 c调用规定。 cdecl调用约定规定: 调用方按从右到左的顺序将函数参数放入栈中。 在被调用的函数完成操作时,调用方负责从栈中清除参数。
ida基本知识
ida目录结构
- cfg 配置文件
- idc 包含内置脚本语言IDC所需的核心文件
- ids 包含一些符号文件
- loaders 在加载过程中用于识别和解析PE或ELF等一直格式的IDA拓展
- plugins 包含专门为IDA提供的附加功能
- procs 包含已安装的IDA版本所支持的处理器模块
- sig 包含IDA在各种模式匹配操作中利用的现有代码的签名
- til 包含一些类型库信息
ida基本操作
- HKEY_CURRENT_USER\Software\Hex-Rays\IDA IDA注册表项
ida数据库文件
要分析的文件为main.exe
会在目录中生成- main.id0 二叉树形式的数据库
- main.id1 包含描述每个程序字节的标记
- main.nam 包含于IDA的Names窗口中显示的给定程序位置有关的索引信息
- main.til til文件用于存储与一个给定数据库的本地类型定义有关的信息
- main.idb ida数据库文件
IDA创建数据库
从磁盘加载文件,解析文件头信息,创建包含代码或数据的程序块
编译器识别:IDA尝试确定用于创建输入文件的编译器,如果能确定,就可以扫描该编译器使用的样板代码序列 函数参数和局部变量识别: 数据类型信息:ida桌面
- IDA View-A
- Hex View-A Hex View可以右键编辑并提交
- Hex View-B
- String Window
- Names Window F:常规函数
- L:库函数,通过签名匹配算法来识别
- I:导入的名称,通常为共享库导入的函数名称。
- C:命名代码
- D:数据。已命名数据的位置通常表示全局变量。
- A:字符串数据。
- sub_xxxx:地址xxxx处的子例程
- loc_xxxx:地址xxxx出的e指令
- byte_xxx:位置xxx处的8位数据
- word_xxx:位置xxx处的16位数据
- dword_xx:位置xx处的32位数据
- unk_xxxx:位置xxxx处的大小未知的数据
ida热键
- IDA>View:
- View>Open Subviews 恢复需要的窗口
- ESC 后退(跳转到上一个)
- Ctrl+Enter 前进(跳转到下一个)
- G (GoTo) Jump To Address
加深理解-汇编指令、长度和十六进制的关系
+---------------------------------------------------------------------+
|位置:地址 指令 对应16进制指令 长度 | +---------------------------------------------------------------------+ |.text:00401010 push ebp 55 1byte | |.text:00401011 mov ebp, esp 8B EC 2byte | |.text:00401013 sub esp, 44h 83 EC 44 3byte | |.text:00401016 push ebx 53 1byte | +---------------------------------------------------------------------+