Athletics(田径) Badminton 羽毛球 javelin 标枪 Volleyball 排球 Cycling(自行车)

Athletics(ç"°å¾„) Badminton 羽毛球 javelin 标枪 Volleyball æŽ'球 Cycling(自行车)


最è¿'有一个需求,给你个地址,看看这个地址前面是不是一个CALL指令(请同学们自行è"想该需求的来源)。作为团队的æ•'火队å'˜+炮灰,这个简单的事情自然落在了æˆ'的头上。

这个事情很简单,作为一个善于站在别人肩膀上的程序å'˜æˆ'们可以考è™'使ç"¨ libdisasm;如果要考è™'x64,就试试udis86;如果需要ç"¨Python,就有Python包装好的 pydasm。不过这两个400KB+çš„åº",显然不值得为了一个CALL指令导入到编è¯'出来大小仅仅100K不到的项目代码里面。

那么就自己抽一个CALL指令解码逻è¾'出来好了。这个逻è¾'的复杂性在于,你无法知é"前面一个CALL指令有多长。因此,首先需要枚举出所有的CALL指令格式。

Intel有公开的指令集格式文档,你需要的是第二卷的上半部分,指令集从A到M。这篇文档的难度超出一般人想象,里面有众多晦涩的标识、与硬件紧密相关的介绍,拿到这后,即使直接翻到目录的Telephone call 指令一节,也不见得能够弄清楚。不相信?æˆ'们就翻到那里看看:

CALL指令格式一览表

CALLæŒ‡ä»¤æ ¼å¼ä¸€è§ˆè¡¨

虽然很明确的列出,第一列是指令的二进制形式,第二列是指令的汇编形式,但是面对着 E8 cw, FF/2这样的标识,一样不知é"究竟对åº"的二进制格式是什么样的。

那好,æˆ'们就从理解这些标识开始。文档å'前翻,有一个ä¸"门的节(3.ane.1 Educational activity Format)讲述这些标识的含义。这里抽出其中两个ç"¨å¾—着的翻è¯'一下:

表格中的“Opcode”列列出了所有的所有可能的指令对åº"的二进制格式。有可能的话,指令代码使ç"¨åå…­è¿›åˆ¶æ˜¾ç¤ºå®ƒä»¬åœ¨å†…å­˜å½"中的字节。除了这些16进制代码之外的部分使ç"¨ä¸‹é¢çš„标记:

cb, cw, cd, cp, co, ct â€" opcode后面跟着的一个1字节(cb),2字节(cw),4字节(cd),6字节 (cp),8字节(co) 或者 10字节(ct) 的值。这个值ç"¨æ¥è¡¨ç¤ºä»£ç åç§»åœ°å€ï¼Œæœ‰å¯èƒ½çš„话还包括代码段寄存器的值。

/digit â€" digit为0到7之间的数字,表示指令的 ModR/M byte 只使ç"¨ r/m字段 作为æ"ä½œæ•°ï¼Œè€Œå…¶ reg字段 作为opcode的一部分,使ç"¨digit指定的数字。

红字部分不知é"什么含义?没关系,æˆ'们先不看它。对于cb/cw之类的,基本上能够简单看明白其中的一些指令含义了:

E8 cw 的含义是:字节 0xE8 后面跟着一个2字节æ"ä½œæ•°è¡¨ç¤ºè¦è·³è½¬åˆ°çš„地址与å½"前地址的偏移量。
E8 cd 的含义是:字节 0xE8 后面跟着一个4字节的æ"ä½œæ•°è¡¨ç¤ºè¦è·³è½¬çš„地址与å½"前地址的偏移量。
9A cd 的含义是:字节 0x9A 后面跟着一个6字节的æ"ä½œæ•°è¡¨ç¤ºè¦è·³è½¬çš„地址å'Œä»£ç æ®µå¯„存器的值。

那么,同样的0xE8开头的指令,CPU如何区分后面的æ"ä½œæ•°æ˜¯2字节还是4字节?ç­"案是å'ŒCPU的模式有关,在实模式下,0xE8接受2字节æ"ä½œæ•°ï¼Œè€Œ32位保护模式下接受4个字节,64位保护模式下同样接受4字节,同时需要对该æ"ä½œæ•°è¿›è¡Œå¸¦ç¬¦å·æ‰©å±•ã€‚

因此,CALL指令的前两种格式是:E8 xx xx xx xx,å'Œ 9A xx xx xx 20 20 xx。一个是5字节长,一个是7字节长。其实E8 那种,就是æˆ'们在汇编指令里面写 CALL lable之后产ç"Ÿçš„,最常见的CALL指令。

然后是下面的FF /2。这个是0xFF字节后面跟上一个blablabla的东西。这个blablabla的东西是什么å'¢ï¼Ÿè¦è§£é‡Šè¿™ä¸ªï¼Œé¦–先需要知é"红字标出来的部分,即ModR/M是什么东西。

这个要先回到最基本的一个问题:IA32的指令格式。

IA32,64指令格式

IA-32,Intel 64æŒ‡ä»¤æ ¼å¼

其中每个部分是什么含义å'¢ï¼Ÿ

首先是指令前缀。有印象的åº"该记得å½"年学习微机原理的时候提到过得循环前缀 repnz/repne,这个前缀就是被编码在指令的前面部分的。每个前缀最多一个字节,一条指令最多4个前缀。

然后是指令代码(opcode),这部分标识了指令是什么。这个是指令å½"中å"¯ä¸€å¿…需的部分。前面例子å½"中的 0xE8,0xFF都是opcode。

再后面就是æˆ'们要重点关心的 ModR/M字段了,还有å'Œå®ƒå¯†åˆ‡ç›¸å…³çš„SIB字节。手册2.1.3å½"中有对于它们的详细描述。

许多指令需要引ç"¨åˆ°ä¸€ä¸ªåœ¨å†…å­˜å½"中的值作为æ"ä½œæ•°ï¼Œè¿™ç§æŒ‡ä»¤éœ€è¦ä¸€ä¸ªç§°ä¸ºå¯»å€æ¨¡å¼æ ‡è¯†å­—节(addressing-grade specifier byte),或者叫做ModR/M字节紧跟在主opcode后面。ModR/M字节包含下面三个部分的信息:

  • mod(模式)域,连同r/m(寄存器/内存)域共同构成了32个可能的值:8个寄存器å'Œ24个寻址模式。
  • reg/opcode(寄存器/æ"ä½œæ•°ï¼‰åŸŸæŒ‡å®šäº†8个寄存器或者额外的3个字节的opcode。究竟这三个字节ç"¨æ¥åšä»€ä¹ˆç"±ä¸»opcode指定。
  • r/m(寄存器/内存)域可以指定一个寄存器作为æ"ä½œæ•°ï¼Œæˆ–者可以å'Œmod域è"合ç"¨æ¥æŒ‡å®šå¯»å€æ¨¡å¼ã€‚有时候,它å'Œmod域一起ç"¨æ¥ä¸ºæŸäº›æŒ‡ä»¤æŒ‡å®šé¢å¤–的信息。

这一段有些晦涩。其意思解释一下是这样的:一个指令往往需要引ç"¨ä¸€ä¸ªåœ¨å†…å­˜å½"中的值,典型的就是如mov:

MOV eax, dword ptr [123456]
MOV eax, dword ptr [esi]

这其中的 123456 或者 esi 就是 MOV 指令引ç"¨çš„内存地址,而MOV关心的是这个地址å½"中的内容。这个时候,需要某种方式来为指令指定这个æ"ä½œæ•°çš„类型:是一个立即数表示的地址,还是一个存æ"¾åœ¨å¯„存器å½"中的地址,或者,就是寄存器本身。

这个ç"¨æ¥åŒºåˆ†æ"ä½œæ•°ç±»åž‹çš„指令字节就是 ModR/M,确切的说是其中的5个位,即modå'Œr/m域。剩下的三个位,可能ç"¨æ¥åšé¢å¤–的指令字节。因为,IA32的指令个数已经远超过一个字节所能表示的256个了。因此,有的指令就要复ç"¨ç¬¬ä¸€ä¸ªå­—节,然后依据ModR/Må½"中的reg/opcode域进行区分。

现在回头看前面的红字标识的部分,能不能理解 /digit 这种表示法了?

对于SIB的介绍,æˆ'们先忽略,看看对于CALL指令的枚举æˆ'们已经能做什么了。

CALL指令的表示法:FF /2,是 0xFF 后面跟着一个 /digit 表示的东西。就是说,0xFF后面需要跟一个 ModR/1000 字节,ModR/M字节使ç"¨ reg/opcode 域 = 2 。那么,reg/opcode = ii 的字节有32个,正如ModR/M的解释,这32个值代表了32种不同的寻址方式。是å"ª32种å'¢ï¼Ÿæ‰‹å†Œä¸Šé¢æœ‰å¼ è¡¨ï¼š

32字节寻址模式下的ModR/M字节

32字节寻址模式下的ModR/M字节

非常复杂的一张表。现在就看看这张表怎么读。

首先是列的定义。ç"±äºŽ reg/opcode 域可以ç"¨æ¥è¡¨ç¤ºopcode,也可以ç"¨æ¥è¡¨ç¤ºreg,因此同一个值在不同的指令å½"中可能代表不同的含义。在表å½"中,就表现为每一列的表头都有很多个不同的表示。æˆ'们需要关心的就是 opcode 这一个。注意看æˆ'ç"¨çº¢åœˆåœˆå‡ºæ¥çš„部分,这一列就是 opcode=2 的一列。而æˆ'们需要的 Call 指令,也就是在这一列å½"中,0xFF后面需要跟着的内容。

行的定义就是不同的寻址模式。正如手册所说,mod + R/M域,共5个字节,定义了32种寻址模式。0x10 – 0x17 对åº"于寄存器寻址。例如指令 Phone call dword ptr [eax] :[eax]寻址对åº"的是 0x10,因此,该指令对åº"的二进制就是 FF 10。同理, Phone call dword ptr [ebx] 是 FF 13,CALL dword ptr [esi] 是 FF 16,这些指令都是2个字节。有人也许问 CALL word ptr [eax] 是什么?抱歉,这不是一个合法的32位指令。

0x50-0x57部分需要带一个 disp8,即 8bit 立即数,也就是一个字节。这个是基地址+8位偏移量的寻址模式。例如 Phone call dword ptr [eax+10] 就是 FF 50 ten 。注意虽然表å½"中写的是 [eax] + disp8 这种形式,但是并不表示是取得 eax 指å'的地址å½"中的值再加上 disp8,而是在eax上加上disp8再进行寻址。因此写成 [eax+disp8] 更不容æ˜"引起误解。后面的disp32也是一样的。这个类型指令是3个字节。

0x90 – 0x97部分需要带 disp32,即4字节立即数。这个是基地址+32位偏移量。例如 Call dword ptr [eax+12345] 就是 FF xc 00 01 23 45。有趣的是, Phone call dword ptr [eax+10] 也可以写成 FF 90 00 00 00 10。至于汇编成å"ªä¸ªäºŒè¿›åˆ¶å½¢å¼ï¼Œè¿™æ˜¯æ±‡ç¼–器的选择。这个类型的指令是6个字节。

0xD0 – 0xD7部分则直接是寄存器。这边引ç"¨çš„寄存器的类型有很多,但是在CALL指令å½"中只能引ç"¨é€šç"¨å¯„存器,因此 Phone call eax 就是 FF D0,臭名昭è'—çš„ CALL esp 就是 FF D4。注意 CALL eax å'Œ CALL [eax] 是不一样的。这些指令也是2个字节。

ä»"细的人也许主要到了,在表å½"中,0x14, 0x15, 0x54å'Œ0x94是不一样的。0x15æ¯"较简单,这个要求 ModR/M后面跟上一个32位立即数作为地址。即常见的 CALL dword ptr [004F778e] 这种格式的,直接跳转到一个固定内存地址处存æ"¾çš„值,常见于调ç"¨Windows的导出表。对åº"的二进制是 FF fifteen 00 4F 77 8E ,有6个字节。

0x14,0x54,0x94部分是最复杂的,因为这个时候,ModR/M不足以指定寻址方式,而是需要一个额外的字节,这个字节就是指令å½"中的第4个字节,SIB。同样在手册的2.1.3,紧跟着ModR/M的定义:

某些特定的ModR/M字节需要一个后续字节,称为SIB字节。32位指令的基地址+偏移量,以及 æ¯"例*偏移量 的形式的寻址方式需要SIB字节。 SIB字节包括下列信息:

  • scale(æ¯"例)域指定了æ"¾å¤§çš„æ¯"例。
  • index(偏移)域指定了ç"¨æ¥å­˜æ"¾åç§»é‡ 的寄存器。
  • base of operations (基地址)域ç"¨æ¥æ ‡è¯†å­˜æ"¾åŸºåœ°å€çš„寄存器。

0x14, 0x54, 0x94就是这里所说的“特定的ModR/M字节。这个字节后面跟着的SIB表示了一个复杂的寻址方式,典型的见于虚函数调ç"¨ï¼š

Call dword ptr [ecx+iv*eax]

就是调ç"¨ecx指å'的虚表å½"中的第eax个虚函数。这个指令å½"中,因为没有立即数,因此FF后面的字节就是0x14,而 [ecx+4*eax] 就需要ç"¨SIB字节来表示。在这个指令å½"中,ecx就是 Base,4是Scale,eax是Index。

那么,Base, Scaleå'ŒIndex是如何确定的å'¢ï¼Ÿæ‰‹å†Œä¸ŠåŒæ ·æœ‰ä¸€å¼ è¡¨ï¼ˆåˆæ˜¯å·¨å¤§çš„表):

32位寻址模式å½"中的SIB字节

列是Base,行是Index*Scale,例如[ecx+4*eax] 就是0x81。

根据这张表,CALL dword ptr [ecx+four*eax] 就是 FF xiv 81 。ç"±æ­¤å¯è§ï¼Œå¯¹äºŽ 0x14系列的来说,CALL指令就是 3个字节。
而 0x54 带 8bit 立即数,就是对åº"于 CALL指令:CALL dword ptr [ecx+4*eax+xx],这个指令就是 FF 54 81 xx,是4个字节。
同理,0x94带32位立即数,对åº"于CALL指令:CALL dword ptr [ecx+4*eax+xxxxxxxx],这个指令就是 FF 94 81 xx xx twenty xx,是7个字节。

OK,截止到目前,æˆ'们基本上能够列出常见的CALL指令的格式了:

指令 二进制形式
Telephone call rel32 E8 xx xx 20 xx
CALL dword ptr [EAX] FF x
Call dword ptr [ECX] FF 11
CALL dword ptr [EDX] FF 12
Phone call dword ptr [EBX] FF 13
Telephone call dword ptr [REG*Scale+Base of operations] FF 14 xx
Call dword ptr [abs32] FF 15 20 xx twenty xx
Call dword ptr [ESI] FF 16
Phone call dword ptr [EDI] FF 17
CALL dword ptr [EAX+20] FF 50 xx
CALL dword ptr [ECX+xx] FF 51 xx
Call dword ptr [EDX+xx] FF 52 twenty
CALL dword ptr [EBX+20] FF 53 twenty
CALL dword ptr [REG*Scale+BASE+off8] FF 54 xx 20
Call dword ptr [EBP+20] FF 55 xx
Call dword ptr [ESI+xx] FF 56 xx
CALL dword ptr [EDI+twenty] FF 57 20
Phone call dword ptr [EAX+xxxxxxxx] FF 90 xx xx twenty xx
Call dword ptr [ECX+xxxxxxxx] FF 91 xx xx xx twenty
CALL dword ptr [EDX+xxxxxxxx] FF 92 xx xx twenty xx
Call dword ptr [EBX+xxxxxxxx] FF 93 twenty 20 xx 20
CALL dword ptr [REG*Scale+Base+off32] FF 94 twenty xx 20 xx xx
Telephone call dword ptr [EBP+xxxxxxxx] FF 95 xx xx xx xx
CALL dword ptr [ESI+xxxxxxxx] FF 96 20 xx xx twenty
Phone call dword ptr [EDI+xxxxxxxx] FF 97 xx xx 20 twenty
CALL EAX FF D0
CALL ECX FF D1
Call EDX FF D2
CALL EBX FF D3
Telephone call ESP FF D4
CALL EBP FF D5
Phone call ESI FF D6
CALL EDI FF D7
CALL FAR seg16:abs32 9A twenty xx twenty xx xx xx

有了这个列表,写一段代码来完成最初æˆ'们的需求也就不难了。

Athletics(ç"°å¾„) Badminton 羽毛球 javelin 标枪 Volleyball æŽ'球 Cycling(自行车)

Posted by: perezwerat1943.blogspot.com

0 Response to "Athletics(田径) Badminton 羽毛球 javelin 标枪 Volleyball 排球 Cycling(自行车)"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel