首页
论坛
课程
招聘
[原创]学习从基础自学逆向
2021-10-29 20:37 21084

[原创]学习从基础自学逆向

2021-10-29 20:37
21084

0.概述

CPU指令集(CPU微处理器架构)分为x86以及ARM

 

ASM(assembly language):汇编语言

 

在运行 Microsoft Windows 的 x86 系统中,其他一些有名的汇编器包括:TASM(Turbo 汇编器),NASM(Netwide 汇编器)和 MASM32(MASM 的一种变体)。GAS(GNU 汇编器)和 NASM 是两种基于 Linux 的汇编器。在这些汇编器中,NASM 的语法与 MASM 的最相似。

 

32 位保护模式(32-Bit Protected Mode):32 位保护模式程序运行于所有的 32 位和 64 位版本的 Microsoft Windows 系统。它们通常比实模式程序更容易编写和理解。从现在开始,将其简称为 32 位模式。

 

64 位模式(64-Bit Mode):64 位程序运行于所有的 64 位版本 Microsoft Windows 系统。

 

16 位实地址模式(16-Bit Real-Address Mode):16 位程序运行于 32 位版本 Windows 和嵌入式系统。 64 位 Windows 不支持这类程序。

 

汇编语言与机器语言是一对一(one-to-one)的关系:每一条汇编语言指令对应一条机器语言指令。

1.x86

  • 字节(Byte):8位,比如AL、BL、CL。
  • 字(word):16位,比如AX、BX、CX。
  • 双字(Double Word):32位,比如EAX、EBX、ECX。

x86可以再两种操作模式下运行:实模式保护模式

  1. 实模式:指处理器刚刚上电后只支持16位指令集的状态。
  2. 保护模式:指处理器支持虚拟内存、分页以及其他功能的状态。

x86通过一种环级别(ring level)的抽象来支持特权隔离。处理器支持4种特权级别,编号为0到3(通常不使用ring1和ring2,所以不讨论)

  1. ring0具有最高特权级别,可以修改所有的系统设置。
  2. ring3的特权级别最低,只能读取/修改部分系统设置。

因此现代操作系统通常将用户模式应用程序运行在ring3级别,内核运行在ring0级别,以此实现用户/内核特权隔离,ring级别编码于CS寄存器

通用寄存器名 作用
EAX(双字)
EBX(双字)
ECX(双字) 循环计数
EDX
EDI 字符串/内存操作的目标
ESI 字符串/内存操作的源
EBP 帧基指针
ESP 栈指针
其他寄存器 作用
EIP 存储指令指针,存储CPU当前要运行的内存地址
EFLAGS 用于存储算术运算状态以及其他运行状态(比如陷阱标志位DF)
CR0 控制分页机制的开关
CR2 保存着导致缺页异常发生的线性地址
CR3 分页数据结构的基地址
CR4 控制硬件虚拟化设置
DR0~DR7 用于设置内存断电,其中系统只支持4个内存断电(DR0~DR3),其余寄存器用于保存状态
其他寄存器 作用
指令 作用
MOVSB/MOVSW/MOVSD 指令分别以1字节,2字节或4字节为单位,在两个内存地址之间移动数据
SCAS(B/W/D) SCAS指令隐式地把(当指令为SCASB/SCASW/SCASD时)AL/AX/EAX的数值与地址为EDI的内存数值比较。根据EFLAGS中DF标志位的不同,EDI自动递增或递减。
REP 重复执行目标指令n次,比如:rep movsd ;复制4n字节(重复n次movsd),找ECX,每循环一次,ECX值减一,满足条件ECX>0
LEA
repne(repeat no equal) 不相等时重复(零标志位)ZF=0且ECX>0进行重复
repe(repeat equal) 相等是时候重复(零标志位)ZF=1且ECX>0进行重复
MUL(无符号) 只允许后面有一个操作数,比如:mul ebx ;将ebx的值与eax的值相乘,若结果存不下,则扩展为EDX:EAX。乘法运算,寄存器值与AL、AX或EAX值相乘,结果存储于AX、DX:AX或EDX:EAX 例如:mul ecx ;EDX:EAX=EAX*ECX
DIV(无符号) 只允许后面有一个操作数,比如:div ebx ;将EAX / EBX 的商放入EAX,余数放入EDX。计算得到的商和余数存储在AL/AH、AX/DX或EAX/EDX中。
IMUL(有符号) 可有多个操作数。例如:imul ebx,ecx ;若溢出,结果高位部分存到ECX,低位部分存入EBX。
指令 作用
NOP 垃圾指令,不执行任何操作
PUSHFD 对标志位进行现场保护,对标志位寄存器的压入栈
POPFD 还原标志位寄存器,从栈中弹出标志位寄存器的值到标志位寄存器
MOVSX 有符号扩展( movsx eax,bx)(movsx eax , bh(或者bl))如果bx(对应2个字节),bh/bl(对应一个字节)的值大于它所对应字节的一半+1,则复制到的存储器的高位值要变负。
MOVZX 无符号扩展( movzx eax, bx)(movzx eax, bh(或者bl))如果bx(对应2个字节),bh/bl(对应一个字节)的值大于它所对应字节的一半+1,则复制到的存储器的高位值不用变。
XCHG 值交换,将两个值交换
ADC 比如:adc eax,ebx 相当于 eax=eax+ebx+CF(进位标志位)
SBB 比如:sbb eax,ebx 相当于 eax=eax-ebx-CF
INC 递增,就是寄存器自动加1
指令 作用
DEC 递减,就是寄存器自动减1
IDIV (有符号)
XADD 例如:xadd ebx,eax ; 设ebx为3,eax为2,则执行执行这条指令,交换双方的值,ebx为2,eax为3,然后相加返回给ebx,则ebx为5。
NEG 取反指令,neg ebx ;若ebx为100,则执行此指令,ebx为-100
CMP 比较指令,比较两个寄存器的值是否想等。例如:cmp edx,eax ;其实是两个值相减,sub edx,eax比较两个值是否相等,结果并不会存到edx寄存器,若比较出来结果相等,即相减为0,则运算结果为0,ZF标志位置为1
TEST 比较指令,比较两个寄存器的值是否相等。例如:test eax,ebx;其实是两个值进行与运算,and eax,ebx;运算结果是否为0,若为0,则置ZF为1,否则置0。结果不保存到EAX寄存器上。
JMP 无条件跳转指令,不根据标志位来改变程序运行逻辑
JE/JZ 根据ZF标志位来进行跳转,如果ZF标志位为1时则跳,为0时不跳
指令 作用
JNE/JNZ 根据ZF标志位来进行跳转,ZF标志位为0时则跳,为1时则不跳
JS 如果结果为负,SF为1,根据SF标志位来进行跳转,如果SF标志位为1时则跳,为0时则不跳
JNS 根据SF标志位来进行跳转,如果SF标志位为0时则跳,为1时则不跳
JP/JPE 如果结果的低十六位含1个数为偶数时,PF为1。根据PF标志位来进行跳转,如果PF标志位为1时则跳,为0时则不跳
JNP/JPO 根据PF标志位来进行跳转,如果PF标志位为0时则跳,为1时则不跳
JO 根据OF标志位来进行跳转,如果OF标志位为1时则跳,为0时则不跳
JNO 根据OF标志位来进行跳转,如果OF标志位为0时则跳,为1时则不跳
JB (判断无符号)根据CF标志位(根据无符号进行运算,只有进位或借位,不存在有无符号)来进行跳转,如果CF标志位为1时则跳,为0时则不跳
JNB 根据CF标志位来进行跳转,如果CF标志位为0时则跳,为1时则不跳
指令 作用
JBE 根据CF或ZF标志位来进行跳转,如果CF或者ZF标志为1时则跳,为0则不跳。例如:cmp eax,ebx;若运算结果为0,ZF为1,运算结果小于0,CF为1。所以就是看eax-ebx的结果是否<=0,就是判断eax<=ebx
JNBE/JA 根据CF和ZF标志位来进行跳转,如果CF和ZF标志都为0时则跳,有一个为1时则不跳。例如:cmp eax,ebx;若运算结果不为0,ZF为0,运算结果大于0,CF为0。所以就是看eax-ebx的结果是否>0,就是判断eax>ebx
JL (判断有符号)根据SF标志位(根据有符号进行运算)来进行跳转,若SF为1,则跳,为0则不跳
JNL (判断有符号)根据SF标志位(根据有符号进行运算)来进行跳转,若SF为0,则跳,为1则不跳
CALL 函数调用,例如:call 00007FFB59C4A838 ;跳到子程序的地址执行,主程序的下个地址存入栈中,当子程序执行完后,从栈顶弹出地址赋值给EIP,然后继续执行主程序后的部分。
RET call和ret配合使用,当运行到ret时,表示子程序返回到主程序。
LOOP 根据寄存器ECX值递减至1时,则不继续循环,且ECX减为0;常见有loopd,loopb和loop是一样的 loopd使用ECX 32位计数器。loopb使用ECX 8位计数器。
 

x86独有的,支持INC或ADD指令,让内存地址中的某个数递增

根据汇编器/反汇编器的不同,x86汇编代码有两种语法记法:Intel和AT&T

  1. Intel

    mov ecx , AABBCCDDh
    mov ecx , [eax]
    mov ecx , eax

  2. AT&T

    movl $0xAABBCCDD , %ecx
    movl (%eax) , %ecx
    movl %eax , %ecx

  • AT&T记法在寄存器名前加前缀%,立即数加$。Intel记法不加前缀
  • AT&T记法加入了指示指令宽度的后缀,比如MOVL(长整形),MOVB(字节)等。而Intel记法没有这种标识
  • AT&T记法把源操作数放在目标操作数前面。而Intel记法相反

x86使用[]标识内存地址,LEA指令也使用[],但不一定指内存LEA不访问内存

1
2
3
4
5
6
7
8
9
10
11
12
mov dword ptr [eax] , 1
;把1放入EAX内存地址
mov ecx, [eax]
;访问EAX寄存器存储的地址值,并把这个地址值当做内存地址值去访问内存,把值提取出来并放入ECX寄存器
mov [eax], ebx
;把EBX寄存器里的值放入EAX内存地址
mov [esi+34h], eax
;把EAX寄存器里的值放入内存地址为(ESI+0x34)的值
mov eax, [esi+34h]
;把内存地址为(ESI+0x34)的值放入EAX寄存器
mov edx, [ecx+eax]
;把内存地址为(ECX+EAX)的值放入EDX寄存器

转化为C伪码

1
2
3
4
5
6
*eax=1;
ecx=*eax;//EAX寄存器存储了一个地址值,通*EAX访问这个地址值里的内容,并将内容赋给ECX
*eax=ebx;
*(esi+0x34)=eax;
eax=*(esi+0x34);
edx=*(ecx+eax);

dword (double word)双字 就是四个字节
ptr pointer缩写 即指针
[]里的数据是一个地址值,这个地址指向一个双字型数据
比如mov eax, dword ptr [12345678] 把内存地址12345678中的双字型(32位)数据赋给eax

 

C语言实现strlen()

1
2
3
4
5
6
7
8
xor al,al
;al置0
mov ebx,edi
;复制edi寄存器的值到ebx
repne scasb
;SCAS指令隐式地把(当指令为SCASB/SCASW/SCASD时)AL/AX/EAX的数值与地址为EDI的内存数值比较,若不同(对应repne),则重复扫描。同时EDI-1
sub edi,ebx
ebx寄存器的值减去edi寄存器的值,结果存入edi寄存器,得到扫描的字符串的长度

image-20211028140257199

 

image-20211028144511317


[2022冬季班]《安卓高级研修班(网课)》月薪三万班招生中~

上传的附件:
收藏
点赞9
打赏
分享
最新回复 (12)
雪    币: 99
活跃值: 活跃值 (472)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
China龍星 活跃值 2021-11-3 13:37
2
0
好文
雪    币: 221
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
Ram.z 活跃值 2021-11-11 11:22
3
1
不错不错
雪    币: 38
活跃值: 活跃值 (33)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
DarkFirer 活跃值 2021-11-11 13:35
4
0
好文
雪    币: 943
活跃值: 活跃值 (204)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
射到深處 活跃值 2021-11-11 16:05
5
0
内容基础值得学习
雪    币: 189
活跃值: 活跃值 (434)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lolikon 活跃值 2021-11-13 15:33
6
1
会的人不需要 不会的人傻也看不懂
雪    币: 1695
活跃值: 活跃值 (661)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
弱冠甕卿还仓 活跃值 2021-11-13 17:19
7
0
lolikon [em_19]会的人不需要 不会的人傻也看不懂
现在大部分都是这样的,教人入门门都不告诉在哪
雪    币: 1779
活跃值: 活跃值 (1632)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
fengyunabc 活跃值 1 2021-11-13 21:05
8
0
看到第一句“CPU指令集(CPU微处理器架构)分为x86以及ARM”就是错的。。。
雪    币: 549
活跃值: 活跃值 (166)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
无善无我 活跃值 2021-11-17 08:45
9
0
好文
雪    币: 0
活跃值: 活跃值 (34)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
KSKSL 活跃值 2021-11-17 16:59
10
0
表里面少了LEA的说明
雪    币: 6
活跃值: 活跃值 (43)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
任常安 活跃值 2021-11-17 17:24
11
0
文章不错呢!谢谢分享
雪    币: 21
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
芜湖 活跃值 2021-12-3 11:44
12
0
小白受益匪浅。谢谢。
雪    币: 27
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
wx_山东好汉 活跃值 2021-12-9 18:34
13
0
为什么底层代码非要用汇编呢,用Java不好吗
游客
登录 | 注册 方可回帖
返回