[Opcode]JMP如何轉成機械碼的呢?
JMP一個指令,根據跳轉目的地遠近分成短跳轉(Short jump)、近跳轉(Near jump)、遠跳轉(Far jump)。
引用Intel指令手冊(Intel® 64 and IA-32 Architectures Software Developer’s Manual)裡面一些對於JMP的敘述:
- Short jump—A near jump where the jump range is limited to –128 to +127 from the current EIP value.
- Near jump—A jump to an instruction within the current code segment (the segment currently pointed to by the CS register), sometimes referred to as an intrasegment jump.
- Far jump—A jump to an instruction located in a different segment than the current code segment but at the same privilege level, sometimes referred to as an intersegment jump.
它們主要就是以所要跳的目的地位址與現在的IP(instruction pointer)位址差值來區分:
- 短跳轉:差值在 -128 ~ +127 (8-bit) 之內。
- 近跳轉:目的地在同一個區段內,且差值在 32-bit 可以表示的範圍內,又稱段內跳轉。
- 遠跳轉:目的地在別的區段,又稱段間跳轉。
雖然在組合語言都是以JMP來實現跳轉,但在組譯轉成機械碼(opcode)時翻譯出來的卻不一樣,短跳轉(EB)、近跳轉(E9)、遠跳轉(EA)。當然,機械碼不一樣就代表是不同的指令,其後的參數要怎麼給是該瞭解的事情。參考手冊說明摘要如下:
Opcode |
Instruction
| |
Short Jump
| EB cb | JMP rel8 |
Near Jump
| E9 cw/cd | JMP rel16/rel32 |
Far Jump
| EA cd/cp | JMP ptr16:16/ptr16:32 |
其中一些參數解釋:
- rel8/rel16/rel32:偏移量(也就是上面說的差值)能用有號 8/16/32-bit 來表示的相對位址。
- ptr16:16/ptr16:32:一個相對遠的指標(pointer),通常與IP不同區段,前面的16/16表示 16-bit 的區段暫存器,後面的16/32表示目的地在那個區段的偏移量。
- cb, cw, cd, cp:用來描述代碼的偏移量和新的區段暫存器的值,分別為 1-byte、2-byte、4-byte、6-byte。
有概念之後,看程式來對上面敘述做驗證吧:
- 短跳轉:
- 近跳轉:
- 遠跳轉:
位址 | Opcode |
Instruction
|
003F1010
| EB 06 | jmp 003F1018 |
003F1012
| EB 04 | jmp 003F1018 |
003F1014
| EB 02 | jmp 003F1018 |
因為指令位址距目的很近,所以為短跳轉(EB), EB 後的數字為目的地與 EIP 的偏移量,但可能有人會問,為什麼對不起來?像是第一個的
偏移量 = 003F1018h - 003F1010h = 08h
結果不是 EB 08,而是 EB 06 。這是因為 CPU 在運作時,看到 EB 06 知道要跳轉,也由於它已經讀了這一行指令, EIP 會再加 2 指向下一行,並執行 EB 06 這個指令。可以看得出關鍵嗎?在執行 EB 06 時 EIP 已經又加 2 了,實際上的算法應為
偏移量 = 003F1018h - (003F1010h + opcode的長度) = 06h
位址 | Opcode |
Instruction
|
013D1035
| E9 85 00 00 00 |
jmp 013D10BF
|
013D103A
| E9 80 00 00 00 | jmp 013D10BF |
013D103F
|
EB 7E
| jmp 013D10BF |
想到再說
留言
張貼留言