二进制安全-汇编基础

进制的定义

二进制:由两个符号组成,分别是0 、1

八进制:由八个符号组成,分别是0、1、2、3、4、5、6、7

十进制:由十个符号组成,分别是0、1、2、3、4、5、6、7、8、9

十六进制:由十六个符号组成,分别是0、1、2、3、4、5、6、7、8、9、A、B、C、D、E、F

度量单位:

1byte 字节 = 8 bit 比特 char

WORD = 2 BYTE = 16 bit short int

DWORD = 4 BYTE = 32 bit

QWORD = 8 BYTE = 64 bit

1kb = 1024 byte = 8192 bit

1mb = 1024 kb

1gb = 1024 mb

1tb = 1024 gb

有符号 无符号
byte -128-127 0-255
word -32768-32767 0-65535
DWORD
qword

16位汇编:实模式,16位处理器内的内部,最多可以处理存储的长度为16位。

32位汇编:保护模式,32位处理器内的内部,最多可以处理存储的长度为32位。

64位汇编:保护模式,64位处理器的内部,最多可以处理存储的长度位64位。

位数 通用寄存器 扩展
16位通用寄存器 AX、BX、 CX、 DX、 SI、 DI、 BP、 SP R8W、R9W、R10W、R11W、R12W、 R13W、R14W、R15W
32位通用寄存器 EAX、EBX、ECX、EDX、ESI、EDI、EBP、ESP R8D、R9D、R10D、R11D、R12D、 R13D、R14D、R15D
64位通用寄存器 RAX、RBX、RCX、RDX、RSI、RDI、RBP、RSP R8、R9、R10、R11、R12、 R13、R14、R15

32位 常用寄存器

8个通用寄存器

二进制安全-汇编基础_第1张图片

8个通用寄存器:

EAX 是"累加器"(accumulator),操作数和结果数据累加器,返回值运算结果一般都存储在这里

EBX 是"基地址"(base)寄存器, 在内存寻址时存放基地址。

ECX 是计数器(counter), 是重复(REP)前缀指令和LOOP指令的内定计数器。

EDX 是(destination) 用于存储部分乘法结果和部分除法被除数

edi 目标索引寄存器(destination index): 字符串操作的目标指针,ES段的数据指针

esi 源索引寄存器(source index):字符串操作的源指针,SS段的数据指针

ESP:栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永远指向
系统栈最上面一个栈帧的栈顶。
EBP:基址指针寄存器(extended base pointer),其内存放着一个指针,该指针永远指向
系统栈最上面一个栈帧的底部

其中一部分还可以拆开处理

二进制安全-汇编基础_第2张图片

EIP:指令寄存器(Extended Instruction Pointer),其内存放着一个指针,该指针永远指向下
一条等待执行的指令地址

可以说如果控制了 EIP 寄存器的内容,就控制了进程——我们让 EIP 指向哪里,CPU 就会
去执行哪里的指令

XMM寄存器:(浮点寄存器)

二进制安全-汇编基础_第3张图片

EFLAGS寄存:包含了独立的二进制位,用于控制CPU操作,或是反应一些CPU操作的结果。有些指令可以测试和控制这些单独的处理器标识位。

EFLAGS寄存器的状态标志(0、2、4、6、7以及11位)指示算术指令(如ADD, SUB, MUL以及DIV指令)的结果,这些状态标志的作用如下:

内部数据类型

整数

  • BYTE 8位
  • SBYTE 8位 有符号
  • WORD 16位 符号
  • SWORD 16位 有符号
  • DWORD 32位 符号
  • SDWORD 32位 有符号
  • FWORD 48位 保护模式的远指针
  • QWORD 64位 整数
  • TBYTE 80位 整数

实数

  • REAL4 32位 短实数
  • REAL8 64位 长实数
  • REAL10 80位 扩展实数

伪指令

  • db 8位整数 =char 可以保持ascll码
  • dw 16位整数
  • dd 32位整数

大端序和小端序

首先还是先看下基本概念:

1、大端模式:高字节保存在内存的低地址

2、小端模式:高字节保存在内存的高地址

mov arr,01234567h

存储

大端序:01 23 45 67

小端序:67 45 23 01

指令集

算数运算

格式:ADD OPRD1,OPRD2

功能:两数相加

加法指令运算的结果对CF、SF、OF、PF、ZF、AF都会有影响

不允许OPRD1与OPRD2同时为存储器

————————————————————————————————

带进位加法指令ADC

格式:ADC OPRD1,OPRD2

功能:OPRD1 = OPRD1 + OPRD2 + CF

减法指令SUB
格式:SUB OPRD1,OPRD2

功能:两个操作数的相减,即从OPRD1减去OPRD2,其结果放在OPRD1中,指令的类型及标识位的影响与ADD指令相同,注意立即数不能用于目的操作数,两个存储器操作数之间不能直接相减,操作数可为8位或16位的无符号数或符号数

————————————————————————————————

带错位减法指令SBB

格式:SBB OPRD1,OPRD2

功能:进行两个操作数的相减再减去CF进位标志位,即从OPRD1 = OPRD1 - OPRD2 - CF,其结果放在OPRD1中

无符号数指令MUL

格式:MUL OPRD

两个相乘数,要么都是8位,要么都是16位。 8位乘法,16位乘法。

如果是8位,一个数字默认存放在al中,另外一个数字存放在其他8位寄存器中或者字节型内存单元中。

mul 8位寄存器 ;结果存放在ax中

如果是16位,一个数字默认存放在ax中,另外一个数字存放在其他16位寄存器中或者字型内存单元中。

mul 16位寄存器 ;结果存放在dx, ax中

8位乘法,得到一个16位数, 结果存放在ax中

16位乘法,得到一个32位数, 低16位存放在ax中,高16位存放在dx中————————————————————————————————
带符号数指令IMUL

功能:乘法操作

OPRD为通用寄存器或存储器操作数

本指令会影响标志位CF及OF

无符号数除法指令DIV

格式:DIV OPRD

功能:实现两个无符号二进制数除法运算

div指令是除法指令。100001/100,100001是被除数,100是除数。一般格式为:div reg或div 内存单元,reg和内存单元存放的是除数,除数可分为8位和16为2种。

被除数:默认放在AX或DX和AX,如果除数为8位,被除数则为16位,默认在AX中存放;如果除数 为16位,被除数则为32位,在DX和AX中存放,DX存放高16位,AX存放低16位。

————————————————————————————————

带符号数除法指令IDIV

格式:IDIV OPRD

功能:实现两个带符号数的二进制除法运算

比如16bit 的被除数,分别存在2个8bit寄存器AH:AL,商放在AL,余数在AH

比如32bit 的被除数,分别存在16个8bit寄存器DX:AX,商放在AX,余数在DX

比如64bit 的被除数,分别存在32个8bit寄存器EDX:EAX,商放在RAX,余数在EDX

比如128bit 的被除数,分别存在64个8bit寄存器RDX:RAX,商放在RAX,余数在RDX

自增

加1指令INC(INCrement by 1)

格式:INC OPRD

自减

减一指令DEC(Decrement by 1)

格式:DEC OPRD

LOOP

循环控制指令LOOP

格式:loop 标号

功能:相当于

dec cx
Jnz
即先对cx减1,然后判cx是否为0,不为0,转后面给出标号所指的入口,为0,顺序执行

MOV指令

数据传送指令 MOV

格式:MOV OPRD1,OPRD2

功能:将一个源操作数送到目的操作数中,即OPRD1<–OPRD2

说明:

OPRD1为目的操作数,可以说寄存器、存储器、累加器

OPRD2为源操作数,可以数寄存器、存储器、累加器和立即数。

MOVS(move string)

movs指令是汇编少有的两边都可以是memory的指令,MOVS在开发中通常极有可能是一串字符串的复制

字符串传送指令MOVS

格式:MOVS OPRD1,OPRD2

功能:OPRD1<—OPRD2

说明: 其中OPRD2为源串符号地址,OPRD1为目的串符号地址

LEA

有效地址传送指令

格式:LEA OPRD1,OPRD2

功能:将源操作数给出的有效地址传送到指定的寄存器中

OPRD1必须是寄存器

XCHG

数据交换指令

格式:XCHG OPRD1,OPRD2,其中OPRD1为目的操作数,OPRD2为源操作数

功能:将两个操作数相互交换位置,该指令把源操作数OPRD2与目的操作数OPRD1交换

TEST

格式:TEST OPRD1,OPRD2

功能:其中OPRD1、OPRD2的含义同AND指令一样,也是对两个操作数进行按位的‘与‘运算

不同之处:是不讲’与‘的结果送目的操作数,即本指令对两个操作数的内容均不进行修改,仅数载逻辑与操作后,对标志位重新置位

CALL指令

过程调用指令

格式:CALL OPRD

功能:过程调用指令

相当于:

push eip

amp OPRD

RETN指令

返回指令,相当于:

pop eip

jmp eip

常用的JCC指令

JMP:无条件跳转

JZ/JE:ZF = 1(jump When Zero和jump When Equal) 等于0或相等

JNZ(jump no Zero)与JNE(jump no Equals ) ZF=0 不等于0或者不相等

比较两个有符号数,高低用greater和less表示:

JG 前>后 Jump if greater
JL 前<后 Jump if less

JL=JNGE(jump if less,or not greater equal)

JGB和JLE是用于比较带符号数的转移指专令:

JGE 转移条件(Jump if greater or equal):JGE al, bl ;al里的带符号内容大于或等于bl时跳转。

JLE 转移条件 (Jump if less or equal):JLE al, bl ;al里的带符号内容小于或等于属bl时跳转。

比较两个无符号数,高低用below或者above表示:

JBE/JNA(jump if below or equal,or not above)比较结果为<=时转移

JBE/JNA:CF = 1/ZF = 1 低于等于或者不高于跳转

JNBE/JA(jump if not below or equal,or above)

JNBE/JA:CF = 0 / ZF = 0 不低于等于/高于跳转

JL/JNGE:SF != OF 小于/不大于等于跳转

JNL/JGE:SF = OF 不小于/大于等于跳转

二进制安全-汇编基础_第4张图片

栈操作指令

PUSH:压栈指令,32位汇编首先ESP-4,留出一个空间,然后把要压入栈中的内容压入

POP:出栈指令,32位汇编首先将栈顶的数据弹出给指定的目标,然后ESP+4,清掉空间

在函数栈帧中,一般包含以下几类重要信息。
(1)局部变量:为函数局部变量开辟的内存空间。
(2)栈帧状态值:保存前栈帧的顶部和底部(实际上只保存前栈帧的底部,前栈帧的顶部
可以通过堆栈平衡计算得到),用于在本帧被弹出后恢复出上一个栈帧。
(3)函数返回地址:保存当前函数调用前的“断点”信息,也就是函数调用前的指令位置,
以便在函数返回时能够恢复到函数被调用前的代码区中继续执行指令。

函数调用

函数调用大致包括以下几个步骤。

(1)参数入栈:将参数从右向左依次压入系统栈中。
(2)返回地址入栈:将当前代码区调用指令的下一条指令地址压入栈中,供函数返回时继 续执行。
(3)代码区跳转:处理器从当前代码区跳转到被调用函数的入口处。
(4)栈帧调整:具体包括。
保存当前栈帧状态值,已备后面恢复本栈帧时使用(EBP 入栈);
将当前栈帧切换到新栈帧(将 ESP 值装入 EBP,更新栈帧底部);
给新栈帧分配空间(把 ESP 减去所需空间的大小,抬高栈顶);
对于__stdcall 调用约定,函数调用时用到的指令序列大致如下

;func(a,b,c)
;假设该函数有 3 个参数,将从右向左依次入栈  

push 参数 c 
push 参数 b 
push 参数 a 
call 函数地址

;call 指令将同时完成两项工作:
;1)向栈中压入当前指令在内存中的位置,即保存返回地址。
;2)跳转到所调用函数的入口地址函数入口处

;下面是进入函数call之后:
push ebp 
;保存旧栈帧的底部
mov ebp,esp 
;设置新栈帧的底部(栈帧切换)
sub esp,xxx 
;设置新栈帧的顶部(抬高栈顶,为新栈帧开辟空间)

函数返回的步骤如下

三步:

(1)保存返回值:通常将函数的返回值保存在寄存器 EAX 中。

(2)弹出当前栈帧,恢复上一个栈帧。

具体包括: 

在堆栈平衡的基础上,给 ESP 加上栈帧的大小,降低栈顶,回收当前栈帧的空间。 

将当前栈帧底部保存的前栈帧 EBP 值弹入 EBP 寄存器,恢复出上一个栈帧。 

将函数返回地址弹给 EIP 寄存器。

(3)跳转:按照函数返回地址跳回母函数中继续执行。

理解图示:

二进制安全-汇编基础_第5张图片

汇编练习,弹个框框

基础知识----汇编代码结构

.586    代表指令集
.MODEL flat,stdcall    调用约定 内存 常用win32        


includelib  user32.lib


.data  已经定义数据段 可读可写
.data?  未定义的数据段 可读可写
.code	 代码段
.const  常量数据段
.stack  堆栈段 自动分配 可读可写可执行

.data
Number DWORD 0
.586
.MODEL flat,stdcall
option casemap:none

include windows.inc
include user32.inc
include kernel32.inc
includelib user32.lib
includelib kernel32.lib

.data
text db "zeo",0

.code
main proc
	INVOKE MessageBox,0,offset text,0,0
	INVOKE ExitProcess,0
main ENDP
END main

二进制安全-汇编基础_第6张图片

格式化输入输出(printf scanf)

.586
.MODEL flat,stdcall
option casemap:none

include windows.inc
include user32.inc
include kernel32.inc
include msvcrt.inc

includelib user32.lib
includelib kernel32.lib
includelib msvcrt.lib
 
.data
text db "zeo",0
Hello db "HelleWord!",0
szformat db "%s",0

.code
main proc
	lea eax,Hello
	push eax
	push offset szformat
	call crt_scanf
	add esp,8
	push offset Hello
	;push offset szformat
	call crt_printf
	add esp,4
	call ExitProcess
	add esp,4
main ENDP
END main

你可能感兴趣的:(二进制安全研究)