首页
社区
课程
招聘
[原创]打造自己的反汇编引擎——Intel指令编码学习报告(八)
发表于: 2008-12-1 23:42 23130

[原创]打造自己的反汇编引擎——Intel指令编码学习报告(八)

2008-12-1 23:42
23130
switch(opcode)
{
    case 0xXX:
    {
       /* 这里相当于已经知道了指令定义(什么指令,有些什么格式的参数),调用指令格式的各个解析部分,传入相应的参数就可以很容易解决了 */

       Mnemonic = "";
       operand1 = ParseModeRM(...)
       ....

       break;
    }

   default:
   {
      Mnemonic = "undefined";
   }
}
const char *ArithmeticMnemonic[] = {"add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" };
case 0x00: case 0x01: case 0x02: case 0x03: 
case 0x08: case 0x09: case 0x0A: case 0x0B: 
case 0x10: case 0x11: case 0x12: case 0x13: 
case 0x18: case 0x19: case 0x1A: case 0x1B: 
case 0x20: case 0x21: case 0x22: case 0x23: 
case 0x28: case 0x29: case 0x2A: case 0x2B: 
case 0x30: case 0x31: case 0x32: case 0x33: 
case 0x38: case 0x39: case 0x3A: case 0x3B: 
{
	Instruction->Opcode = *currentCode;
	Instruction->dFlag = (*currentCode >> 1) & 1;
	Instruction->wFlag = (*currentCode) & 1;

	sprintf(mnemonic, ArithmeticMnemonic[(*currentCode >> 3) & 0x1F]);
			
	currentCode++;
	currentCode = ParseRegModRM(currentCode, Instruction, operand1, operand2);
			
	break;
}

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 7
支持
分享
最新回复 (18)
雪    币: 233
活跃值: (15)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
2
学习啊,等这一篇很久啦
2008-12-1 23:44
0
雪    币: 561
活跃值: (124)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
学习下
2008-12-1 23:49
0
雪    币: 202
活跃值: (57)
能力值: ( LV9,RANK:370 )
在线值:
发帖
回帖
粉丝
4
code的识别好象是最难的了,因为CPU中有几个个code,要对这些code进行识别的确不容易,而且CPU中的code还一直呈现出增长趋势,而且每个code对应不同的操作数个数,这些操作数的寻址方式也各异......

如果你的"计算机体系结构"知识还没有还给老师的话,你应该知道,CPU在设计时,为了提高比特位的利用率,也为了保证一个code不是另一个code的前缀(否则CPU也无法译码),code的编码采用的是哈夫曼算法。利用这个特性,code及其后继的操作数等信息的识别,应该很容易了吧。

code的最大长度是3个字节,当然可以是1个字节,也可以是2个字节,另外,对于某些特定的code,还有3个比特的信息也会用来表示code.这3比特在ModR/M的3、4和5位。当然每个code也最多只能有三个operand哦。

对code的识别一般都是采用二维表格来驱动的。二维表格中记录了给各code的详细信息。这样code的识别就变成了查表,爽吧。这个表格建的怎么样,取决于你的需求。

下面举一个例子来说明表格的信息,及其code的识别过程(拿call指令为例):

查看Intel官方手册(A-M卷),你会发现call指令有四个code,手册列出分别为:
E8 cw call re/16
E8 cd call re/32
F2 /2 call re/m16
F2 /2 call re/m32
F2 /2 call re/m64
9A cd call ptr16:16
9A cp call ptr16:32
FF /3 call m16:16
FF /3 call m16:32
关于它们的详细信息请查看Intel的官方手册,上面所列表明call的code占用一个字节,并且指令只有一个操作数,在手册上详细说明了E8是后面的操作数表示相对于下条指令的偏移,F2、FF和9A后面带的操作数是要调用的绝对地址。
根据code的编码规则以及Intel的手册信息,可以用如下结构体来组织数据:
typedef tagCodeInfo
{
long lMask; //掩码
long lCode; //code
int nCodeLen; //code的长度
int nBitFeature; //特殊code标识
int nArg0; //第一个operand的寻址方式,这个地方用enum来定义最好,这里只是为了说明算法,就用int来定义了
int nArg1; //第二个operand的寻址方式,用0表示没有这个operand
int nArg2; //第三个operand的寻址方式
std::string strCodeName; //code的助记符
}CodeInfo, *PCodeInfo;

通过上面的结构体定义,可以很容易得到4个call的code对应的结构体数据定义了,如下:

{ 0x0000FF, 0x0000E8, 1, 0, 1, 0, 0, "call" },
{ 0x0038FF, 0x0010FF, 1, 0, 2, 0, 0, "call" },
{ 0x0000FF, 0x00009A, 1, 0, 3, 0, 0, "call" },
{ 0x0038FF, 0x0018FF, 1, 0, 4, 0, 0, "call" },

上面4个{}里的第一项和第二项看晕了吧,在说明这个问题时,先说说用这个数据结构是怎么进行code的识别的,设传进来要识别的code为 opCode,那么用这个计算公式可以识别code,(opCode ^ lCode) & lMask,只要这个家伙不为zero,就是我们千辛万苦要找的东东了。这里说下上面opCode的求法,opCode并不是传进来的buffer,因为每个code最多只有三个字节,而我们定义的结构体中用long来表示mask这些信息了,所以我们的opCode也要是long型的,很简单,只要传进来的buffer够长的话,用memcpy((char *)&opCode, buffer, 3),如果不够3个字节了,有几个字节就把几个字节copy到(char *)&opCode处,另外说明的是,repeat prefixes是比较讨厌的,如果有这个东西在带反汇编的机器码中,opCode的求法还要加个opCode = (opCode << 8) | repeat prefixes。
下面说那两个项是怎么计算的了。
mask的计算方法:有指令的地方用FF,如果这个code用到了ModR/M中的那3个比特位,这ModR/M对应字节用38.
lCode的计算方法:它对应的code照搬,如果这个code用到了ModR/M中的那3个比特位,/2和/3应该看到了吧,这它们乘以8 放ModR/M对应字节,为什么是8,是因为它ModR/M字节中表示code信息的那3个bits后面还有3个bits.

到这里code就识别完了,通过以上的那个结构体,我们连code对应的每个operand的寻址方式的求出来了,后面那几个域的识别就方便了,没有难度了。

上面的是网络上的关于od用的那个反汇编引擎指令表的构建部分的知识。本打算对已有反汇编引擎的指令表设计方式总结一下的,但是水平实在有限。

目前,正在尽自己最大的努力打造一个“好”反汇编引擎,倒不是为了重新造轮子,只是觉得好玩而已,希望能弄出来。使用的话,目前的反汇编引擎已经很多了,“好”的也不少
2008-12-1 23:49
0
雪    币: 723
活跃值: (81)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
5
你图中用红圈标识的有误

纵向是高4位,横向是低4位
2008-12-1 23:54
0
雪    币: 202
活跃值: (57)
能力值: ( LV9,RANK:370 )
在线值:
发帖
回帖
粉丝
6
呵呵,犯糊涂了,已经修改了,谢谢!
2008-12-2 10:10
0
雪    币: 116
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
要是写完这些学习报告后,楼主能把OD的反汇编引擎搞个源代码分析就好了
2008-12-2 10:26
0
雪    币: 200
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
8
我还看不懂先收藏!
2008-12-2 13:19
0
雪    币: 2575
活跃值: (502)
能力值: ( LV2,RANK:85 )
在线值:
发帖
回帖
粉丝
9
等这一篇很久
2008-12-2 18:26
0
雪    币: 217
活跃值: (41)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
10
顶了你 我再慢慢看 啊 哈哈  等你好久了

^_^
2008-12-3 16:46
0
雪    币: 34
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
我建了驱动开发群,群号:67181435
2008-12-4 11:04
0
雪    币: 190
活跃值: (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
12
大爷能不能总结到一个帖子????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
2008-12-5 22:03
0
雪    币: 349
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
俺还不懂,楼主辛苦了
2008-12-6 09:32
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
学习了,好东西呀,谢谢楼主
2008-12-6 17:40
0
雪    币: 359
活跃值: (445)
能力值: ( LV9,RANK:150 )
在线值:
发帖
回帖
粉丝
15
从7到8,有一段时间了,呵呵,持续关注中…………

谢谢楼主
2008-12-6 20:46
0
雪    币: 205
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
本人想实现一个linux运行简单dos程序的模拟器,现在只是在头脑中有个大概的想法,首先要有加载模块,然后是命令解释模块,命令解释模块会参考楼主的这个反汇编引擎 ,不过后面还有很多问题要考虑,比如中断什么的,不知道大家有什么建议。
2008-12-8 14:41
0
雪    币: 29
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
偶然看到此帖,大有裨益,神作啊
2011-6-15 19:55
0
雪    币: 14
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
拜读完毕,开始整理知识和思路,自己也构建个简单的。
2011-10-20 16:56
0
雪    币: 166
活跃值: (230)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
看完了,本来还想debug几只虫子的,算了算了...
谢谢楼主,楼主辛苦了...
2012-12-25 15:04
0
游客
登录 | 注册 方可回帖
返回
// // 统计代码