-
-
[原创]写了个反汇编的东西,分享出来
-
发表于:
2011-1-18 21:10
9209
-
原来写了个反汇编的函数,源代码好像也不太给力。
就大概说说原理吧:
源代码中自定义了许多表:
// 定义标志寄存器结构
typedef struct _INQUIRE_EFLAGS
{
DWORD dwUseField; // 使用下列那些字段
DWORD dwTest; // 要测试的标记,位1
DWORD dwModif; // 会影响的32位标志寄存器,位2
DWORD dwDefine; // 已定义的标记,位3
DWORD dwUndefine; // 未定义的标记,这个标记还在考虑中,位4
DWORD dwFixSet; // 确定会被置1的标记,位5
DWORD dwFixZro; // 确定会被清0的标记,位6
} INQUIRE_EFLAGS, *LPINQUIRE_EFLAGS;
这个表,用于想要知道指令是否影响标记位的。
// ModR/M32表专用宏
#define MODRM32_MEM_FREG 0x1 // 全寄存器寻址
#define MODRM32_MEM_FREG_IMM1 0x2 // 全寄存器加立即数1寻址
#define MODRM32_MEM_FREG_IMM4 0x3 // 全寄存器加立即数4寻址
#define MODRM32_MEM_IMM4 0x4 // 立即数4寻址
#define MODRM32_REG 0x5 // 寄存器作为操作数
#define MODRM32_SIB 0x6 // 存在SIB
// ModR/M32表
typedef struct _TabModRM32
{
BYTE dwModRMMode; // 寻址模式
BYTE dwMod;
BYTE dwRegOp;
BYTE dwRM;
} TabModRM32;
这个表方便Mod如何解析的,反正就255种情况,我直接用程序生成这个表,直接查表,搞的现在我自己都忘了怎么解析Mod表,写的时候还知道。
// ModR/M16表专用宏
#define MODRM16_MEM_2REG 0x1 // [bx + si], REG
#define MODRM16_MEM_1REG 0x2 // [bx + si], REG
#define MODRM16_MEM_2REG_IMM1 0x3 // [bx + si + IMM1], REG
#define MODRM16_MEM_1REG_IMM1 0x4 // [bx + si + IMM1], REG
#define MODRM16_MEM_2REG_IMM2 0x5 //[bx + si + IMM2], REG
#define MODRM16_MEM_1REG_IMM2 0x6 // [bx + si + IMM2], REG
#define MODRM16_MEM_IMM2 0x7 // [IMM2], REG
#define MODRM16_REG 0x8 // Opcode REG, REG
typedef struct _TabModRM16
{
BYTE dwModRMMode; // 寻址模式
BYTE dwMod;
BYTE dwRegOp;
BYTE dwRM;
BYTE dwReg1;
BYTE dwReg2;
} TabModRM16;
同上,这个是16位的表
// SIB表
typedef struct _TabSib
{
BYTE dwSibMode; // 寻址模式
BYTE dwScaleN; // 比例因子
BYTE dwIndex; // 索引寄存器索引
BYTE dwBase; // 基址寄存器索引
} TabSib;
SIB也建表了
#define ADDR_BIT_1REG BIT_4 // 地址中有1个寄存器
#define ADDR_BIT_2REG (BIT_3 | BIT_4) // 地址中有2个寄存器
#define ADDR_BIT_N BIT_2 // 有比例因子
#define ADDR_BIT_IMM BIT_1 // 有地址立即数
#define OPERAND_NULL 0x0 // 无操作数
// 最高位为1就是直接寻址,否则为间接寻址,直接寻址就是没有[]的
#define OPERAND_IMM (BIT_32 | ADDR_BIT_IMM) // 立即数
#define OPERAND_REG (BIT_32 | ADDR_BIT_1REG) // 寄存器
#define OPERAND_MEM_IMM ADDR_BIT_IMM// 地址立即数
#define OPERAND_MEM_REG ADDR_BIT_1REG // 地址寄存器
#define OPERAND_MEM_REGIMM (ADDR_BIT_1REG | ADDR_BIT_IMM) // [REG + IMM]
#define OPERAND_MEM_2REG ADDR_BIT_2REG// [REG1 + REG2]
#define OPERAND_MEM_2REGIMM (ADDR_BIT_2REG | ADDR_BIT_IMM) // [REG1 + REG2 + IMM]
#define OPERAND_MEM_1REGN (ADDR_BIT_1REG | ADDR_BIT_N) // [REG1 * N]
#define OPERAND_MEM_2REGN (ADDR_BIT_2REG | ADDR_BIT_N) // [REG1 + REG2 * N]
#define OPERAND_MEM_1REGNIMM (ADDR_BIT_1REG | ADDR_BIT_N | ADDR_BIT_IMM) // [REG1 * N + IMM]
#define OPERAND_MEM_2REGNIMM (ADDR_BIT_2REG | ADDR_BIT_N | ADDR_BIT_IMM)// [REG1 + REG2 * N + IMM]
// 其实2,4有符号数都是由1BYTE符号数扩展而来的
#define SIGN1IMM 0x1
#define SIGN2IMM 0x2
#define SIGN4IMM 0x3
#define UNSIGN1IMM 0x4
#define UNSIGN2IMM 0x5
#define UNSIGN4IMM 0x6
// 操作数结构
typedef struct _UnImm
{
BYTE ImmType; // 立即数类型,或地址立即数类型
union
{
CHAR cImm;
SHORT sImm;
LONG lImm;
BYTE Imm;
WORD wImm;
DWORD dwImm;
} AnyImm;
} UnImm;
// 操作数结构
typedef struct _UnOperand
{
DWORD AddrMode; // 表明本结构的意义和使用的字段
BYTE Reg1; // [base + index * n + IMM/1/4]
BYTE Reg2; //[Reg1 + Reg2 * n + IMM]
BYTE N; // 比例因子,不存在就设置为1,也用于表示立即数的大小
UnImm stImm; // 立即数类型,或地址立即数类型
} UnOperand;
自己定义的一个操作数结构,用于解析指令的参数时好做判断
最后输出怎么一个结构。
typedef struct _InstructionFrame
{
DWORD dwInstructionAddr; // 指令地址
DWORD dwInstruction; // 指令
BYTE dwInstructionLen;// 指令机器码长
BYTE arInstructionCode[INSTRUCTION_LEN]; // 机器码
DWORD dwGrp; // 指令组
DWORD dwRing; // 指令特权级
DWORD dwLock; // 是否有锁前缀
DWORD dwRep; // 是否有Rep前缀
BYTE dwAddrSize; // 地址大小
BYTE dwSegment;// 段前缀
UnOperand stOpernd[3]; // 3个参数内容
INQUIRE_EFLAGS InquireEflags; // 影响的标记位
} InstructionFrame;
把结构传入下面这个函数就可以返回指令的字符串,In_dwMnmicLen为对齐,就是质量和参数间的距离,In_dwlowerCase 为大写和小写。
DWORD Instruction(InstructionFrame *Out_InsFrame, TCHAR* Out_pMnemonic, DWORD dwLen, DWORD In_dwMnmicLen = 6, DWORD In_dwlowerCase = 0);
原理其实好简单,就是不停的查表。
一共有:
1byte指令表
2byte指令表
扩展指令表
后缀指令表
前缀指令表
9b指令表----------------这个9b好像很特别,记得我用od和ida测试了好多次
总之第一次写,理解不够深刻吧,建了怎么多表
比如 查1byte指令表先,发现时0f就跳到2byte指令表去,mod中是扩展指令,就查扩展指令表,然后有的指令,不算2byte,存在扩展指令,而且后面一个字节又可以代表一个指令,所以就有了后缀指令表(而且是先查后缀,我没记错的话),前缀指令表就主要用于0F 38 如66 0f 38,什么66 67 f2 f3原来那么多用途,我还是第一次知道。
最后就定位到一个表,然后到其中去取得解析方式就ok了
有bug就告诉我吧!
望大虾提出意见,好提高一下,如果现在让我写,我可能还会设计成这样,只是细节的一些东西可能会做的更好。
代码中用了许多goto,好纠结这个goto。
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)