硬编码入门(一) 滴水-
硬编码 目标做一个反汇引擎
百度百科:硬编码是将数据直接嵌入到程序或其他可执行对象的源代码中的软件开发实践,与从外部获取数据或在运行时生成数据不同
老师讲解+自己感悟:硬编码(数字)对应的汇编代码(英文)。加密壳可以分为二进制壳(对pe文件进行操作)和指令壳(源代码加密),以后会对pe文件进行复习,加深理解。反汇编引擎可以自动识别硬编码。
每一个指令的硬编码是有所不同的。
指令编码的结构
指令编码格式分为六个部分,其中的分为主要部分和次要部分(可以省略)。
-
InstructionPrefixes:可选的前缀指令。有4种类型的前缀指令,在一条指令指令编码中每种类型最多只能有一个。
-
Opcode:操作码,可以是1,2或3字节。
-
ModR/M:1字节,由Opcode决定是否存在。
-
SIB:1字节,由ModR/M决定是否存在。
-
DisplaceMent:可选的偏移指令,可以是1,2,4字节。是否存在以及存在的形式由ModR/M决定。
-
Immediate:可选的立即数,可以是1,2或4字节。是否存在以及存在的形式由OpCode决定的。
由此可知,每条指令编码的长度最长为15个字节,最短为1个字节。而指令的长度,很大程度上又是由操作码,也就是Opcode来决定的。所以,对操作码的解析是最重要的。
说明:最左列一列数字代表的是操作码的高4位,第一行的数字代表的是操作码的低4位,这样就可以找到不同的操作码所对应的汇编指令从而解析出指令。
前缀指令
前缀指令一共有4个类别,分别有不同的作用。
操作数据宽度的指令
这一类的前缀指令只有一个,那就是0x66。该前缀指令的作用是修改操作数的数据宽度,如下图是不包含该前缀指令的指令编码,其功能就是将32位的ebx寄存器中的内容入栈。
而在该指令前面加入前缀指令0x66的时候,此时这条指令就会变成将16位的bx入栈,也就是说前缀指令的作用就是将32位操作数的数据宽度改变为16位的。
地址宽度前缀指令
这一类指令也只有一个,那就是0x67。该前缀指令的作用是可以改变地址计算时候的宽度。在没有前缀的时候,计算地址时候是用32位寄存器ecx计算。
而当该条指令编码加上0x67前缀指令的时候,地址的计算就变成使用16位的bx和di
段前缀指令
该类指令,主要是用来改变指令操作时候的数据段。通过使用不同的前缀指令,可以指定指令运行时候使用不同的数据段,具体数值如下:
当没有使用这些前缀指令的时候,指令的运行过程中所使用的段都是默认的段,比如下面这条指令编码所使用的段就是ss段
而通过这一类的前缀指令就可以修改默认的段
LOCK和REPEAT前缀指令
这类指令一共有三种:
指令 | 数值 |
---|---|
LOCK | 0xF0 |
REPNE/REPNZ | 0XF2 |
REP/REPZ | 0xF3 |
其中LOCK指令的作用是在多核CPU情况下,保证只有一个CPU可以访问指令的指令。 |
经典定长指令(修改E某某) 一个字节指令(既包括操作码又包括操作数),这些需要背会.|
根据上面的TableA-2可以得知,高位0x4,0x5,0x7,0x9,0xB,0xC,0xE的时候,代表的就是定长指令,因为这些指令里面缩写的内容并没有像Eb,Gv这样的内容。对于表中操作码上的i64,o64,d64
1.push(oprate code)为操作码,后面的32通用位寄存器为操作数。 push为压栈的汇编指令
8个通用寄存器(最好按顺序记住 EAX ECX EDX EBX ESP EBP ESI EDI)备注:这是汇编的一些操作,需要补基础。
* 硬编码 汇编语言
* 0x50 PUSH EAX
* 0X51 PUSH ECX
* 0X52 PUSH EDX
* 0X53 PUSH EBX
* 0X54 PUSH ESP
* 0X55 PUSH EBP
* 0X56 PUSH ESI
* 0X57 PUSH EDI
2.pop (oprate code简称opcode)为操作码,后面的32通用位寄存器为操作数。POP为出栈
* 0x58 POP EAX
* 0X59 POP ECX
* 0X5A POP EDX
* 0X5B POP EBX
* 0X5C POP ESP
* 0X5D POP EBP
* 0X5E POP ESI
* 0X5F POP EDI
3.inc(increase)指令 加指令
* 0x40到0x47分别对应 EAX ECX EDX EBX ESP EBP ESI EDI
4.dec(decrease)指令 减指令
* 0x48到0x4F分别对应 EAX ECX EDX EBX ESP EBP ESI EDI
5.8位寄存器分别对应的指令编码(B0-B7) EAX:32位通用寄存器 分为16位的寄存器AX ,AX又分为8位的AH和8位的AL
* B0 00 MOV AL 0
* B1 89 MOV CL,89
* B2 E8 MOV DL,0E8
* B3 15 MOV BL,15
* B4 B1 MOV AH,0B1
* B5 B1 MOV CH,0B1
* B6 B1 MOV DH,0B1
* B7 B1 MOV BH,0B1
6.32位寄存器分别对应的指令编码(B8-BF)
* B8 0 MOV EAX,0
* B9 0 MOV ECX,0
* BA 0 MOV EDX,0
* BB 0 MOV EBX,0
* BC 0 MOV ESP,0
* BD 0 MOV EBP,0
* BE 0 MOV ESI,0
* BF 0 MOV EDI,0
7.9*系列定长指令集
* 90 NOP 相当于XCHG EAX EAX 没有什么设计意义所以nop(这个指令是空指令,nop很重要,)
* 91 XCHG EAX,ECX
* 92 XCHG EAX,EDX
* 93 XCHG EAX,EBX
* 94 XCHG EAX,ESP
* 95 XCHG EAX,ESI
* 96 XCHG EAX,EDI
为什么没有16位寄存器 因为32位寄存器跟16位寄存器可以根据指令前缀来更换
intel指令手册中描述的指令由六部分构成。
instruction prefixes opcode Mode R/M SIB|Displacement immedate
指令前缀 指令操作码 操作数类型 辅助Mode R/M,计算地址偏移 立即数
总结:
一字节指令:
push 是 从 0x50 到0x57
pop 是 从 0x58 到0x5f
inc 是 从 0x40 到0x47
DEC 是 从 0x48 到0x4F
**90位nop指令很重要**
XCHG 是 从 91 到 96
MOV(8位寄存器) 是 从 B0 到B7
MOV(32位寄存器)是 从 B8 到BF
第一天写博客,欢迎各位技术大牛来指出不足。