作者descent (「雄辩是银,沉默是金」)
看板ASM
标题[心得] x86 machine code
时间Thu May 8 19:51:42 2014
从来没想过我会学习 machine code, 而且 x86 machine code 实在太复杂, 花了很多心
力才有点进展。本来直接拿起 intel 那令人害怕的手册硬 K, 果然不行, 有看没有懂,
再看 ref 3, 还是看不懂。而在阅读了 ref 1, 2 後, 我如获至宝, 看懂之後再翻阅
ref 3, 终於有了进展。当能看懂时, 心中的兴奋之情, 恐怕只有和我一样在 machine
code 里头挣扎的同好才能理解。
不过 x86 machine code 实在太复杂, 我并没能搞懂所有格式。
为什麽要研究 machine code 呢?因为要改写执行档的位址, 做类似 dynamic
loader/linker 的事情, 会看这篇文章的朋友, 难道你对於 dynamic loader/linker 的
原理没有兴趣吗?不会想个方法来实验这件事情吗?Binary Hacks--骇客秘传技巧一百招
#72 就在谈这个。
让我们从 intel memory address 开始。intel 着名的 segmentation memory address,
将记忆体位址分为 segment part, offset part, 本文章重点摆在 offset part。而台湾
翻译的基底/索引定址法 (中国的翻译则是 ...) 则为 base/index。
offset part 有三个栏位:
base register
index register multiplied 1, 2, 4, 8 (1, 2, 4, 8 被称为 scale factor)
displacement
base + index * scale + displacement = offset part
ex:
at&t syntax add 0x12345678(%eax, %esi, 4), %esi
intel syntax add esi, [eax+esi*4+0x12345678]
本篇文章大量参考 Programming THE 80386 (instruction encoding - p59):
(
http://goo.gl/jr50sq )
这是 1987 年的书 (我写这篇文章的时间是 20130612), 在电脑界这麽快速更新的时代,
照理说应该是过期的书籍, 不过由於相容性的缘故, 里头提到的东西到现在都还是可以用
的, 而且简单不少 (也没有 64 bit mode), intel 手册已经变得又厚又硬难以阅读, 而
这本书讲的比较好理解。有些术语和最新的 intel 手册有些不同, 不过不影响理解。
之前在阅读 IBM 80X86 组合语言实务 (
http://goo.gl/Tmr1Pp )被其复杂的定址模式搞
得我好乱, 现在一次把它搞懂。这些复杂的 address mode 是针对 offset part 而来,
大概就是 base register 和 index register mode 这两种比较复杂。而 16 bit 和 32
bit 又有点不同, 64 bit 没研究, 就不提了。
16 bit 和 32 bit 可用来当 base/index register 的暂存器有些不同。为什麽呢?读懂
machine code 就可以回答这问题。
x86 machine code 顺序, 後面的数字是 byte 数目:
prefix 0-4
opcode 1-2
modrm 0-2
displacement 0-4
immediate 0-4
这是这本书的解释, 和目前的 intel 手册有些不同, 目前的 intel 手册把 modrm 分为
modrm + sib, 不过没关系, 原则都是一样的。我建议先看过 ref 1, ref 2 再看这篇,
如果真的没时间至少也要看过 ref 2, 因为他们提到的东西, 我不会特别说明, 请花点时
间看, 若你真想理解这玩意, 应该有觉悟要占去你不少休闲时间。
address_mode.S
1 # practice x86 machine code
2 .code16
3 #.code32
4 .text
5 .global begin
6 begin:
7 add (%bx), %ax
看看 L7 的组语, 这使用了 base register address mode。
objdump -d -m i8086 address_mode.elf
1 descent@w-linux:x86_machine_code$ objdump -d -m i8086 address_mode.elf
2
3 address_mode.elf: file format elf32-i386
4
5
6 Disassembly of section .text:
7
8 00000100 <_text>:
9 100: 03 07 add (%bx),%ax
由於 intel cpu 有 16/32/64 bit mode, 所以我们得选择要让组译器用那种 bit mode
来翻译出 machine code, 这个例子是 16 bit (ref address_mode.S L2, L3)。
03 07 是 machine code, 对应到 opcode modrm 这两栏, 没有 prefix, displacement,
immediate 这些部份。
来看看 add 的 opcode:
http://css.csail.mit.edu/6.858/2011/readings/i386/ADD.htm (
http://goo.gl/onPA8d )
有好几个, 看以下这个:
03 /r ADD r16,r/m16 2/6 Add r/m word to word register
clock 那栏我看不懂, 有请大大解惑。
所以 03 是 opcode, 03 搞定, 那 07 是什麽?
07 是 modrm 这栏, 再细分解为 2:3:3 栏位,
0000 0111 -> 00 000 111
mod: 00
reg: 000
r/m: 111
把 mod, r/m 拿来查表。
mod = 00 时的对照表 (16 bit)
Effective Addressr/m
[BX+SI] 000
[BX+DI] 001
[BP+SI] 010
[BP+DI] 011
[SI] 100
[DI] 101
disp16 110
[BX] 111
得到 [BX], 这是 base register address mode
reg: 000 代表 ax register
register table
REGRegister
000EAX/AX
001ECX/CX
010EDX/DX
011EBX/BX
100ESP/SP
101EBP/BP
110ESI/SI
111EDI/DI
得到 add ax, [bx] (intel syntax), 恭喜, 终於看懂 machine code 了。但是要从
add ax, [bx] 得到 03 07 就比较难了。
这在 intel 术语称为: one-byte address mode encoding。
这篇好像有点长了, 不过打铁趁热, 来看看 prefix 的例子。
address_mode1.S
1 # practice x86 machine code
2 .code16
3 #.code32
4 .text
5 .global begin
6 begin:
7 add (%bx), %eax
和 address_mode.S 的差别仅在 %eax, %ax 改成 %eax。我一直被 16 bit 程式码可以使
用 32 bit register 所疑惑, 这样的程式码倒底是 16 bit 还是 32 bit? 当然是 16
bit, 那你和我觉得疑惑可以使用 32 bit register 吗?让我们透过 prefix 解除这疑惑
。
objdump -d -m i8086 address_mode.elf
1 descent@w-linux:x86_machine_code$ objdump -d -m i8086 address_mode.elf
2
3 address_mode.elf: file format elf32-i386
4
5
6 Disassembly of section .text:
7
8 00000100 <_text>:
9 100: 66 03 07 add (%bx),%eax
machine code 则多了一个 66, 这就是 prefix, 用来切换 operand size, 这里的例子是
从 16 bit 切换成 32 bit, 本程式执行在 16 bit 下, 而 %eax 是 32 bit operand, 所
以要加上 prefix 0x66, 就这麽简单。
想想看:
什麽是 32 bit 执行环境?
A: ...
若在 32 bit 执行环境执行这个 machine code 又是什麽意思?
A:
.code32
.text
.global begin
begin:
add (%edi), %ax
很有意思吧, x86 就是这麽讨厌又让人喜爱。
好用的组译器:
http://radare.org/y/?p=examples&f=rasm (
http://goo.gl/7m3UXy )
玩 machine code 的朋友一定要试试。
某聚会上我的分享, 就是以这篇为主。
ref:
x86/x64 指令幕(适用于 AMD/Intel):
http://www.mouseos.com/x64/index.html (
http://goo.gl/D7kzHb )
OpCode:
http://www.luocong.com/learningopcode.htm (
http://goo.gl/4fAo5p )
Programming THE 80386
http://ref.x86asm.net/coder32.html (
http://goo.gl/311CF )
// 本文使用 Blog2BBS 自动将Blog文章转成缩址的BBS纯文字
http://goo.gl/TZ4E17 //
原文 blog
descent-incoming.blogspot.tw/2013/06/x86-machine-code-0-base-register.html
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 58.114.150.244
※ 文章网址: http://webptt.com/cn.aspx?n=bbs/ASM/M.1399549919.A.C6F.html
1F:推 soheadsome:推 05/08 22:53
2F:推 wgst88w:第二个连结"OpCode"那个网页有木马! 05/09 12:05
http://www.luocong.com/learningopcode/index.htm
这就应该没问题, 是纯 html 网页
3F:推 kingstong:加油给推!只有X86架构才是王道.不需DOSBOX直接DOS就能用 05/09 21:38
4F:推 et84121:推一个 05/10 01:39
※ 编辑: descent (111.184.191.166), 05/10/2014 22:04:00
5F:推 merckhung: Intel 有 release 一个叫 XED2 的东西, 可以帮助解码. 09/24 04:53