汇编指令之OpCode快速入门

作者:A1Pass
时间:2010-05-20
来源:黑客反病毒 (http://bbs.hackav.com)
出处:看雪论坛    (http://bbs.pediy.com)

 

注意:转载请务必附带本组信息,否则侵权必究!

 

转载自:http://bbs.pediy.com/thread-113402.htm

    最近一直被一些初学者问及有关于汇编指令的长度问题,因此为此专门撰写本文,以求为不知OpCode为何物,或者正为汇编长短不一的指令而烦恼的朋友一个最为快速的指引。
    其实,OpCode并不复杂,在本文中我不打算细致入微的告诉大家OpCode的原理,不会为大家带来一大堆有关于什么是定长指令、什么是变长指令的理论知识,更不会带着各位读者玩OpCode Hacking,我只会告诉你“怎么了”、“为什么”以及“如何解决”。

1、我的汇编指令怎么了?
    ;哦,天啊!怎么我今天突然发现汇编指令竟然是长短不一的!你还没发现吗?那么请过目:

 

1

2

3

4

5

6

E8 31880000      CALL 00430B86

E9 17FEFFFF      JMP 00428171

8B4424 04        MOV EAX, DWORD PTR SS:[ESP+4]

85C0             TEST EAX, EAX

56               PUSH ESI

8BF1             MOV ESI, ECX


    我们可以看见“CALL 00430B86”这条汇编指令竟然占用了5个字节,而“PUSH ESI”则只占用了1个字节,汇编指令的脾气犹如一只滑头的猴子一样让你摸不到头脑,它很明显的告诉了你“嘿!兄弟,你别想搞懂我!”你也许会感到很郁闷,但是我并不这么想,因为如果我要想自己搞一个反汇编引擎,或者是我要在我的壳里加上代码混淆功能……嗯,算了,就算是我想娱乐一下搞搞免杀吧,那么我终归是要搞懂它的,为什么?因为如果不能搞懂它的话,那么我就没办法做到这些!
    很明显我们的汇编指令继承了Intel工程师的狡猾本质,为了尽可能的减少体积,所以它们的体积被设计的不尽相同。
    哇哦!很多读者此时似乎已经想明白是怎么回事了,肯定是不同的指令对应的字节数不一样,恩……这样只要我们搞到一张表就可以了!不是吗?一张可以描述每个指令所用二进制码的表格,然后我们就万事大吉了。
    但是很不幸,我在初次接触OpCode时也想出了这个“超级点子”,但是很可惜我的“超级点子”与各位读者的一样,并没有为我解决任何问题,请过目:

 

 

1

2

3

B8 01000000   MOV EAX, 1

8BC3          MOV EAX, EBX

8BC7          MOV EAX, EDI


    看到了吗,一样的指令,一样的目的操作数,得到的确是完全不同的二进制码……

2、这是为什么?
    嗯,我想这个问题是很明显的,源操作数如果是一个寄存器的话,那么能有几种可能呢?按照规则来讲貌似只有不超过50种可能,那么如果被操作数是一个数值呢?你想想,32位能表示多少数,将其乘以2就是最终的可能性了,这么多的可能性一定不是区区两个16位数就能表示过来的。
    所以说我们的OpCode的长度不是一成不变是有道理的,那么既然如此,那么既然CPU可以正确时识别它,这里面肯定有什么方法是可以计算这些的,没错!这些确实是可以计算的,而且正像我们上面所设想的那样,Intel也确实为我们准备了表格,只不过不是一张,只不过有些复杂……
    首先,我们要现拥有这些,以下是我提供的一些连接,因为我们需要这些,请你下载他们:
      zip附件上传限制1000KB,而且不能上传分卷,所以大家还是到以下下载方便些:
http://bbs.hackav.com/thread-1641-1-1.html
      拥有了这些文档后,我们就可以开始“破译”它了,现在加入我们要“破译”的是“ADD EAX,1”这条指令,请各位读者跟我一起做:
    我们先打开《处理器指令参考》手册(x86eas.hlp),找到汇编指令ADD,我满看到了如下解释:

 

 

注:前面的标号是笔者为了大家方便阅读而加上去的。     Opcode    Instruction  Description 01  04 ib    ADD AL,imm8  Add imm8 to AL 02  05 iw    ADD AX,imm16  Add imm16 to AX 03  05 id    ADD EAX,imm32  Add imm32 to EAX 04  80 /0 ib    ADD r/m8,imm8  Add imm8 to r/m8 05  81 /0 iw    ADD r/m16,imm16  Add imm16 to r/m16 06  81 /0 id    ADD r/m32,imm32  Add imm32 to r/m32  07  83 /0 ib    ADD r/m16,imm8  Add sign-extended imm8 to r/m16 08  83 /0 ib    ADD r/m32,imm8  Add sign-extended imm8 to r/m32 09  00 /r    ADD r/m8,r8  Add r8 to r/m8 10  01 /r    ADD r/m16,r16  Add r16 to r/m16 11  01 /r    ADD r/m32,r32  Add r32 to r/m32 12  02 /r    ADD r8,r/m8  Add r/m8 to r8 13  03 /r    ADD r16,r/m16  Add r/m16 to r16 14  03 /r    ADD r32,r/m32  Add r/m32 to r32 解释: imm是立即数的意思,而imm8就是指8个比特大小的立即数,下面将一一对上面的简写作出解释 imm:立即数,例如01、123、0FAB等 r:寄存器,如r16就代表ax、cx等,r32就代表eax、ebx等 m:内存地址,如[01]、[123]、[0FFFF]等 r/m:寄存器或内存 ib:代表OpCode后面跟着一个byte型数值 iw:代表OpCode后面跟着一个word型数值 id:代表OpCode后面跟着一个dword型数值 /0:代表此OpCode存在ModR/M结构(后面有讲) /r:代表此OpCode存在ModR/M结构(后面有讲)


    这是什么意思呢?我们以第一条信息为例,它的意思是,如果OpCode的表现形式为04后面在跟一个字节,那么它的指令格式(Description)必然是“ADD AL,8位立即数”,例如“ADD AL,11”。
    啊哈,那么问题到这就解决了,我们上面的“ADD EAX,1”符合第8行的“ADD r/m32,imm8”,那么它的OpCode就应该是“83 01”了吧……
    结果估计大家已经猜到了“事情没那么简单”,实际上我们的汇编指令“ADD EAX,1”所对应的OpCode是如下玩意:

 

 

1

83C0 01       ADD EAX, 1


      我们可以看到它很神奇的多出来个“C0”不知道是干什么的,这让我们很郁闷!

3、我们如何解决这个问题?
    到这里,我们就要步入正轨了,通过这一节我们要搞明白那个“C0”究竟是怎么出来的。
    既然要步入正轨,我们就要了解一下Intel的指令结构(在24319102.PDF的第31页),具体情况如下:

Prefixes:前缀(最多4个前缀,每个1字节,并不是必需的)
code:主操作码(1-3字节不等)
ModR/M:固定1字节大小,并不是必需的
SIB:固定1字节大小,并不是必需的
Displacement:偏移量(1、2、4字节,并不是必需的)
Immediate:立即数(1、2、4字节,并不是必需的)

    由上可见,其实Intel指令格式中只有一个是必须存在的,就是“主操作码”,也就是我们在上一节查到的那堆东西。不过其他结构索然是可有可无,但是往往在某些时候它们当中的某些结构是必须添加上去的,例如上个例子中的“ADD EAX,1”就是如此。
    在我们讲解Prefixes之前,首先请大家务必牢记一件事,就是OpCode的结构是绝对不能被打乱的,例如Prefixes肯定是要在code前面,而Immediate肯定是在最后面。
    好了,记住上面的基本原则后,我就为大家简单讲解一下这个前缀(Prefixes)究竟做了些什么,非要把指令结构搞得这么复杂,我在24319102.PDF的第31页下面找到了这些信息:

—F0H—LOCK prefix.
—F2H—REPNE/REPNZ prefix (used only with string instructions)
—F3H—REP prefix (used only with string instructions).
—F3H—REPE/REPZ prefix (used only with string instructions).
—F3H—Streaming SIMD Extensions prefix.

    这都是什么意思呢?我们拿第一个来说,Intel对它的解释是锁定前缀,首先各位的汇编语言要过关,所谓的锁定就是将我们的指令变为原子指令,具体例子如下:

 

 

 

1

2

F0:8300 01    LOCK ADD DWORD PTR DS:[EAX], 1           ;  锁定前缀

F0:0FB10A     LOCK CMPXCHG DWORD PTR DS:[EDX], ECX     ;  锁定前缀

 


    这两条指令前都多了个“LOCK”,但是请注意,这只是一个特例,并不是所有的前缀都会导致汇编指令前非要加些什么,这点一定要注意。
    Intel手册给了我们很多其他的前缀,功能也各不相同,本文中作者不可能对其一一进行解释,因此深入的学习就要靠各位自己的努力了。
    而关于操作码,我们在上一节中已经讲了,这里不再多说,因此直接入“ModR/M”与“SIB”中。
    关于“ModR/M”,我认为它在汇编指令中应该是最难的了(虽然只是简单的查表,不过我说的是编程实现),有关于ModR/M的表格在Intel指令手册24319102.PDF的第36页,读到这里的朋友不妨先去看看。
    看完后千万不要头大,我们那一条指令解释一下,就什么都清楚了,其实很简单的,我们仍然拿“add EAX,1”为例吧。
    我在倒数第8行找到了目的操作数,Intel在表中描述如下:

 

 

 

 

Effective Address   Mod  R/M EAX/AX/AL/MM0/XMM0  11   000

 


    但是我们的源操作数要怎么找呢?上面一行似乎并没有符合的,这就要看我们此条汇编语句在定义时指定了那里,还记得我们在上一节中查到的信息吗:

83 /0 ib  ADD r/m32,imm8  Add sign-extended imm8 to r/m32

    在上一节我仅告诉各位“/0”是代表此OpCode里存在ModR/M结构,但并没有多说什么,其实这里的“/0”就是代表此表中竖排(列)中第一排,其内容如下:

 

 

 

 

r8(/r)    AL r16(/r)    AX r32(/r)    EAX mm(/r)    MM0 xmm(/r)    XMM0 /digit (Opcode)  0 REG =    000


     到这里,其实我们的“ModR/M”已经出来了,我们将其以“Mod”“R/M”“/digit”“REG”的方式组合到一起后,正好组合为如下数值:

 

 

 

/digit REG Mod R/M    0     000 11  000 = 000011000 = C0h


    其实在他们的交汇处我们可以看到Intel已经帮我们算好了,真实一张贴心的表呀。
    “ModR/M”解决了,还剩最后的“SIB”了,要想学习“SIB”,我们先要搞明白他什么时候会出现,因此我找到了第36页下面的注释:

 

 

NOTES: 1.The [--][--] nomenclature means a SIB follows the ModR/M byte. 2.……


    注释一的大致意思是“[--][--]”表示ModR/M 后跟随有一个SIB字节,因此我们现在创造一个带有“SIB”结构的汇编指令:

 

 

1

01048E  ADD DWORD PTR DS:[ESI+ECX*4], EAX


    我们重新回顾一下所学知识,首先我们分析它的指令格式如下:

 

 

01 /r    ADD r/m32,r32  Add r32 to r/m32


    根据“/r”我们可以得知这是一个有“ModR/M”结构的OpCode,因此查表得出其“ModR/M”信息如下:

 

 

横排 Effective Address  Mod  R/M [--][--]            00  100 竖列 r8(/r)    AL r16(/r)    AX r32(/r)    EAX mm(/r)    MM0 xmm(/r)    XMM0 /digit (Opcode)  0 REG =    000 结果 /digit REG Mod R/M   0      000 00  100 = 000000100 = 04h


    根据“Effective Address”的“[--][--]”可知此OpCode还存在“SIB”结构,于是继续查位于Intel指令手册24319102.PDF第37页的表格。
    这里我们要着重分解目的操作数“[ESI+ECX*4]”里的内容,我们可以将其分为两部分,既索引与倍率因子(或叫做比率因子)。
    索引指的是基址,本例中就是ESI了,而倍率因子在本例中则是“ECX*4”,我们先从横排取得倍率因子信息如下:

 

 

Scaled Index  SS  Index [ECX*4]       10  001     而后由竖排取得索引信息如下: r32  ESI Base=  6 Base=  110     将其组合起来就是: SS  Index  Base 10  001    110  = 10001110 = 8Eh


    由此,我们便成功的解析了汇编指令“ADD DWORD PTR DS:[ESI+ECX*4], EAX”。
    到了这里本文也该结束了,但是各位读者需要注意的是,本文的责任就像是标题所体现的一样,只是带领大家快速入门,因此有关于很多OpCode的细节本文并没有体现出来,如果你需要深入了解的话,建议各位还是以Intel手册为蓝本手动试验,慢慢摸索。

 

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: MIPS汇编指令在线转换机器码是一种在互联网上提供的工具,可以将MIPS汇编语言指令转换为对应的机器码。 MIPS汇编指令是一种低级语言,用于编写基于MIPS体系结构的计算机程序。它使用助记符和操作数来表示不同的指令,以便程序员更容易地理解和编写代码。然而,计算机硬件只能理解机器码,即由二进制数字表示的指令。 在线转换工具通过解析输入的MIPS汇编指令,将其转换为机器码,以便计算机能够执行相应的操作。转换的过程涉及到识别和解析指令中的助记符和操作数,并根据MIPS指令集架构的规则将其转化为对应的机器码表示。 通过在线转换机器码的工具,程序员可以验证他们编写的汇编代码是否正确,并且可以理解每条指令在计算机内部的表示形式。此外,这个工具还可以帮助初学者学习和理解MIPS汇编语言的基本知识,并且能够快速转换并输出机器码。 总之,MIPS汇编指令在线转换机器码是一种方便的工具,可以将MIPS汇编指令转换为计算机能够理解和执行的机器码。它有助于程序员验证代码的正确性,并促进对MIPS汇编语言的学习和理解。 ### 回答2: MIPS(Microprocessor without Interlocked Pipeline Stages)汇编语言是一种基于RISC(Reduced Instruction Set Computer)架构的指令集,常用于嵌入式系统和计算机体系结构的学习中。MIPS汇编指令集较为简洁,有助于理解计算机底层的工作原理。 将MIPS汇编指令转换为机器码是让计算机能够理解和执行指令的过程。通常,在进行这种转换时,需要参考MIPS指令集手册来确定每个指令的操作码(Opcode)、寄存器操作数(Register Operand)和立即数(Immediate Operand),以及一些其他可能的参数。 转换MIPS汇编指令为机器码的过程可以分为以下几个步骤: 1. 根据指令的类(例如,存储、加载、运算等),确定操作码。每个操作码对应一个特定的指令。 2. 根据指令中包含的寄存器操作数和立即数,确定相应的二进制表示。 3. 将操作码和操作数转换为二进制,并按照特定的顺序排列这些位。 4. 组合确定指令格式的各个部分,生成完整的二进制机器码。 以MIPS的ADD(加法)指令为例,其汇编语言表示为"ADD r1, r2, r3",其中r1、r2和r3是寄存器。根据MIPS指令集手册,ADD指令的操作码是"000000",而r1、r2和r3分别对应于不同的寄存器编号,例如,r1为"00001"、r2为"00010"和r3为"00011"。因此,将ADD指令转换为机器码时,操作码为"000000",寄存器操作数为"00001"、"00010"和"00011",其二进制表示为"000000 00001 00010 00011"。 如此类推,可以通过查找MIPS指令集手册中每个指令的相关信息,并遵循规定的转换流程,将所有MIPS汇编指令转换为对应的机器码。这样,计算机就能够根据转换后的机器码执行相应的指令,完成特定的任务。 ### 回答3: MIPS(Microprocessor without Interlocked Pipelined Stages)是一种常用的RISC(Reduced Instruction Set Computer)架构的计算机处理器。MIPS汇编语言是一种常用的底层编程语言,主要用于编写MIPS指令集架构的程序。 要将MIPS汇编指令转换为机器码,可以使用在线工具或软件来实现。这些工具通常提供一个用户界面,让用户输入MIPS指令,并自动将其转换为相应的机器码。 在在线转换机器码的过程中,用户需要提供MIPS指令的正确写法和语法。例如,用户可以输入“add $t0, $t1, $t2”来表示将$t1和$t2寄存器中的值相加,并将结果存储在$t0寄存器中。转换工具会根据MIPS指令的操作码、寄存器编号等信息来生成相应的机器码。例如,对于上述的add指令,其对应的机器码可能是“000000 01001 01010 01000 00000 100000”。 在线转换机器码的工具通常支持多种类的MIPS指令,包括算术操作指令、逻辑操作指令、数据传输指令等。用户可以根据自己的程序需求,在工具中选择相应的指令,并提供相应的操作数和操作码。 需要注意的是,在在线转换机器码之前,用户应该确保输入的MIPS指令是正确的,并符合MIPS指令集的规范。否则,转换过程可能会出现错误或生成无效的机器码。 总之,通过使用在线工具或软件,可以方便地将MIPS汇编指令转换为机器码。这样的工具为开发人员提供了一种快速和准确地生成MIPS指令对应机器码的方法,有助于在MIPS架构的计算机处理器上编写和运行程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值