您的位置:首页 > 其它

逆向个人学习笔记(1)汇编

2020-08-13 16:50 99 查看

文章目录

进制

n进制:由n个符号组成,逢n进1,符号自定义

十六进制 0 1 2 3 4 5 6 7 8 9 A B C D E F
二进制 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111

进制间的计算:抛弃数字的概念,查数

进制太美妙了,没有不完美的进制,把各种进制进行转换是因为十进制更符合我们的习惯,真正的进制间计算应该抛弃数字的概念,去查数。

如八进制计算:先从0开始,依次写80个数,列出加法表、乘法表。加减乘除由查表都可以实现。

练习:三进制定义:由3个符号组成,分别是2,0,1,逢3进1

2 0 1
02 00 01
12 10 11
022 020 021

数据宽度

1.计算机什么都不认识,只存0和1。

2.存的数超过界限,会被毫不犹豫的扔掉。

3.有符号数、无符号数都是自己用的时候定义的,你说是什么就是什么。
例:4位宽度表示,假设计算机只能存储4位2进制数

无符号数:0 1 2 3 4 5 6 7 8 9 A B C D E F

有符号数

正数: 0 1 2 3 4 5 6 7

负数: -1 -2 -3 -4 -5 -6 -7 -8

​ F E D C B A 9 8

4.几个重要的计量单位

BYTE 字节 8BIT

WORD 字 16BIT 2字节

DWORD 双字 32BIT 4字节

1 KB = 1024 BYTE

1MB = 1024 KB

1GB = 1024 MB

二进制的逻辑运算

计算机只会做逻辑运算
或(or |) 只要有一个1就是1
与(and &) 两个都为1才是1
异或(xor ^) 不一样为1
非(not !)
逻辑运算的具体应用:
1. CPU如何计算2+3?
答:
X: 0010
Y: 0011
X xor Y 得 R: 0001
X and Y得 0010 左移一位 <<1 ,得 0100,不为0000,则 X = R, Y = 0100,重复如上操作。
X: 0001
Y: 0100
X xor Y 得 R: 0101
X and Y得 0000 左移一位 <<1 ,得 0000,则最终结果为R: 0101
2. 如果想获取某个值的第N位的值是多少?
如:8F第四位?
       10001111
and 00001000
——————————
       00001000
3. 简单的加密算法(两次异或结果为两次异或前的数)
要加密的数据:20
密钥:54
       00100000
xor 01010100
——————————
       01110100
加密后:74
       01110100
xor 01010100
——————————
      00100000
解密后:20

通用寄存器

1.32位通用寄存器(CPU中的容器)

2. 通用寄存器

  1. MOV的语法:
    (1)MOV r/m8,r8 r 通用寄存器
    (2)MOV r/m16,r16 m表示内存
    (3)MOV r/m32,r32 imm表示立即数
    (4)MOV r8,r/m8 r8表示8位寄存器
    (5)MOV r16,r/m16 m8表示8位内存
    (6)MOV r32,r/m32 imm8表示8位立即数
    (7)MOV r/m8,imm8
    (8)MOV r/m16,imm16
    (9)MOV r/m32,imm32
    MOV 目标操作数,源操作数
    源操作数和目标操作数不能同时为内存单元

  2. ADD加法指令

  3. SUB减法

  4. AND与:
    mov eax,2
    and eax,3
    “与”后的结果存在eax中

  5. OR或

  6. XOR异或

  7. NOT非:
    not r/m8
    not r/m16
    not r/m32

内存读写

  1. 几个重要的计量单位 BYTE 字节 8BIT WORD 字 16BIT 2字节 DWORD 双字 32BIT 4字节1 KB = 1024 BYTE1MB = 1024 KB1GB = 1024 MB
    内存编号的单位是字节
  2. 寄存器位于CPU内部,执行速度快,但比较贵
  3. 内存速度相对较慢,但成本较低,所以可以做的很大
  4. 32位计算机 32位跟寄存器的宽度没有关系,是跟它的寻址宽度有关系的。编号最大的是32位,即32个1。不考虑别的情况,内存能储存的最多信息为4G
  5. 到底怎么寻址,是操作系统自己说的算
  6. 内存格式
    每个内存单元的宽度为8,[编号]称为地址
  7. 从指定内存中写入/读取数据
    mov dword ptr ds:[0x0012FF34],0x12345678
    mov eax,dword ptr ds:[0x0012FF34]

内存地址

  1. OD反汇编窗口、寄存器窗口数据从左到右,从高位到低位,和平常在本上写的顺序是一样的。左下数据窗口中数据是倒过来的,从左到右,从低位到高位(大小端问题)。 内存里最小单位是字节,即两个16进制数字。
    举例:在OD最底下命令行里输入 db 0x12FFDC(d为查看数据,b为字节,即以字节的形式显示后面地址中的数据),敲回车,左下数据窗口显示该内存中的数据。该数据在内存中为E47CB3B6,在本子上写下来就是B6B37CE4
  2. 寻址公式
    寻找内存地址
    寻址公式一:[立即数]
    读取内存的值:mov eax,dword ptr ds:[0x0012FF34]
    向内存中写入数据:mov dword ptr ds:[0x0012FF34],0x12345678
    获取内存编号:LEA EAX,DWORD PTR DS:[0x0012FF34]
    寻址公式二:[reg] reg代表寄存器,可以是8个32位通用寄存器中的任意一个
    读取内存的值:
    mov eax,0x0012FF34
    mov ecx,dword ptr ds:[eax]
    向内存中写入数据:
    mov eax,0x0012FF34
    mov dword ptr ds:[eax],ecx
    获取内存编号:
    LEA EAX,DWORD PTR DS:[ecx]
    寻址公式三:[reg+立即数]
    寻址公式四:[reg+reg*{1,2,4,8}]
    寻址公式五:[reg+reg*{1,2,4,8}+立即数]

堆栈

windows中分配栈是从高地址向低地址分配
注意:立即数为16进制,十进制12为十六进制c
通常esp栈顶,ebp栈底
练习:

  1. 使用ebx存储栈底地址,edx存储栈顶地址,连续存储2个不同的数

  2. 分别使用栈底加偏移、栈顶加偏移的方式读取这2个数,并存储到寄存器中

  3. 弹出这2个数,恢复栈顶到原来的位置
    mov esi,dword ptr ds:[edx]
    add edx,0x4
    mov edi,dword ptr ds:[edx]
    add edx,0x4

push指令:
push r32
push r16
push m32
push m16
push imm8/imm16/imm32
若push的立即数,地址都要减4;不能push8位的寄存器或内存
pop指令:
pop r32
pop r16
pop m32
pop m16
pushad:把8个寄存器存到堆栈
popad:把8个寄存器恢复

标志寄存器

1.记住CF/PF/AF/ZF/SF/OF的位置
2.若工具没有如图所示拆开各位,可以自行拆开EFL(即将其转化为二进制)
3.进位标志CF(Carry Flag):如果运算结果的最高位产生了一个进位或借位,那么其值为1,否则为0
注: 1.要先研究其数据宽度
        2.mov不算运算,运算为加减乘除xor之类
        3.80-40(16进制)不存在向更高位借位,CF为0;80-81(16进制)存在向更高位借位,CF为1
4. 奇偶标志PF(Parity Flag):反映运算结果中“1”的个数的奇偶性。如果“1”的个数为偶数,则PF的值为1,否则为0
注:PF只看最低有效字节,即最后8位
5. 辅助进位标志AF(Auxiliary Carry Flag):
若为8个十六进制,看从右数第4个是否进位或借位,若进位或借位则为1,否则为0
若为4个十六进制,看从右数第2个是否进位或借位,若进位或借位则为1,否则为0
若为2个十六进制,看从右数第1个是否进位或借位,若进位或借位则为1,否则为0
6.零标志ZF(Zero Flag):反映运算结果是否为0。如果运算结果为0,则其值为1,否则其值为0。
注:xor eax,eax可把eax清零(xor相同为0,不同为1)
7.符号标志SF(Sign Flag):反映运算结果的符号位,它与运算结果的最高位相同。
8.溢出标志OF(Overflow Flag):反映有符号数加减运算所得结果是否溢出。如果运算结果超过当前运算位数所能表示的范围,则称为溢出,OF的值被置为1,否则,OF的值被清为0。
9.CF和OF的区别:
CF针对无符号数,OF针对有符号数
正+正 = 正 如果结果为负数,则说明有溢出
负+负 = 负 如果结果为正数,则说明有溢出
正+负永远都不会有溢出
减法:被减数与减数异号,而结果的符号与减数相同则OF = 1,否则OF = 0
(1)无符号、有符号都不溢出
mov al,0x8
add al,0x8
(2)无符号溢出、有符号不溢出
mov al 0xff
add al,2
(3)无符号不溢出、有符号溢出
mov al,0x7f
add al,2
(4)无符号、有符号都溢出
mov al,0xfe
add al,80
计算机如何判断是否溢出:
比如 80-40
mov al,80
sub al,40
相当于
mov al,80
sub al,40

1000 0000
0100 0000
——————
符号位有进位:1
最高有效数值位向符号位产生的进位:0
1 xor 0 得1,所以 OF = 1
练习:(不要小看练习,我太菜了QAQ)

  1. 写汇编指令只影响CF位的值(不能影响其他标志位)
    mov al,0xF0add al,0x11
  2. 写汇编指令只影响PF位的值(不能影响其他标志位)
    mov al,0x2add al,0x1
  3. 写汇编指令只影响AF位的值(不能影响其他标志位)
    mov al,0xF
    add al,0x1
  4. 写汇编指令只影响SF位的值(不能影响其他标志位)
    mov al,0x80
    add al,0x3
  5. 写汇编指令只影响OF位的值(不能影响其他标志位)
    mov al,0x80
    sub al,0x10

JCC

一、补充指令

  1. ADC指令:带进位加法,若CF值为1则进位,否则不进位
    格式:ADC R/M,R/M/IMM 两边不能同时为内存 宽度要一样
  2. SBB指令:带借位减法,若CF值为1则借位,否则不借位
    格式:SBB R/M,R/M/IMM 两边不能同时为内存 宽度要一样
  3. XCHG指令:交换数据
    格式:XCHG R/M,R/M 两边不能同时为内存 宽度要一样
  4. MOVS指令:移动数据 内存——内存
    BYTE/WORD/DWORD
    MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI] 简写为:MOVSB
    MOVS WORD PTR ES:[EDI],WORD PTR DS:[ESI] 简写为:MOVSW
    MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI] 简写为:MOVSD
    注:DF(Direction Flag)方向标志,DF为0时,执行完MOVSD后EDI、ESI内的值自动加4;DF为1则减4
  5. STOS指令:将AL/AX/EAX的值存储到[EDI]指定的内存单元
    STOS BYTE PTR ES:[EDI] 简写为:STOSB
    STOS WORD PTR ES:[EDI] 简写为:STOSW
    STOS DWORD PTR ES:[EDI] 简写为:STOSD
    注:DF为0时,执行完STOSD后EDI内的值自动加;DF为1则减
  6. REP指令:按计数寄存器(ECX)中指定的次数重复执行字符串指令
    mov ecx,10
    rep movsd 或 rep stosd
    练习:
    (1)用movs指令分别移动5个字节,5个字,5个双字
    (2)用stos指令分别移动5个字节,5个字,5个双字
    (3)使用rep指令重写第1,2题

二、JMP指令

  1. JMP指令:只修改EIP的值
    格式:JMP 寄存器/立即数
  2. call指令:修改eip的值;把call下一行指令的地址push进栈
    注:call和ret成对出现,call一定要回来
    ret相当于pop eip

三、比较指令

  1. cmp指令
    格式:CMP R/M,R/M/IMM 两边不能同时为内存 宽度要一样
    相当于sub指令,但相减后的结果不保存到第一个容器里
    当两个操作数相等时,零标志ZF为1
    mov eax,0x100
    mov ecx,0x200
    cmp eax,ecx 观察sf,由于第一个数小于第二个数,sf为1
  2. test指令
    格式:CMP R/M,R/M/IMM 两边不能同时为内存 宽度要一样
    相当于and与指令,但与后的结果不保存到第一个容器里
    常见用法:用这个指令,可以确定某寄存器是否为0
    如test eax,eax 观察zf位

四、JCC指令
练习:

  1. CALL执行时堆栈有什么变化?EIP有变化吗?
  2. RET执行时堆栈有什么变化?EIP有变化吗?
  3. 使用汇编指令修改标志寄存器中的某个位的值,实现JCC的十六种跳转。不允许在OD中通过双击的形式修改标志寄存器,要通过汇编指令的执行去影响标志位,能用CMP和TEST实现的优先考虑。

堆栈图

  1. 函数:计算机的函数,是一个固定的一个程序段,或称其为一个子程序,它在可以实现固定运算功能的同时还带有一入口和一个出口,所谓的入口,就是函数所带的各个参数,我们可以通过这个入口,把函数的参数值代入子程序,供计算机处理,所谓出口,就是指函数的计算结果,也称为返回值,在计算机求得之后,由此口带回给调用它的程序。
  2. 入口:可把外面的值(参数)传进来,可以通过寄存器或者内存
  3. 出口:传出返回值,可以通过寄存器或者内存。
  4. Windows堆栈的特点:(1)先进后出(2)向低地址扩展
  5. 堆栈平衡:一个程序执行后,栈顶栈底和程序执行前一样
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: