首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 組合語言

組合語言技巧:利用 CALL/POP 在執行期取得當前指令位址 (EIP)

     編輯:組合語言

前言

在組合語言中,有時需要在執行期動態取得當前程式碼的位址 (如位置無關程式碼、Shellcode、動態解密)。x86 沒有直接讀取 EIP 的指令,但巧用 CALL 將返回位址壓入堆疊,再 POP 取出,即可輕鬆獲得。

核心技巧

call @f          ; 呼叫下一個標號
@@:              ; 匿名標號 (MASM/TASM/JWasm 支援)
pop ebx          ; EBX = @@ 的位址 (即 CALL 後的指令位址)

原理說明

  1. CALL rel32 執行時:將下一條指令的線性位址 (EIP) 壓入堆疊,然後跳轉。
  2. 標號 @@: 正是 CALL 後的下一條指令位置。
  3. POP EBX 彈出堆疊頂部的該位址 → EBX 現在持有 當前程式碼的執行位址。

變體與應用

1. 取得資料區位址 (相對定址)

call get_addr
get_addr:
pop ebx
; EBX = get_addr 位址
; 假設資料在程式碼後 100h 位元組
mov esi, [ebx + 100h]  ; ESI 指向資料

2. 位置無關程式碼 (PIC) 範例

start:
    call $+5         ; 呼叫下一條指令 (相對位移 0)
    pop ebp          ; EBP = 基址
    ; 後續所有記憶體存取以 EBP 為基準
    mov eax, [ebp + offset MyData - offset start]
    call [ebp + offset MyFunc - offset start]

3. 解密器殼碼常見模式

decode_loop:
    call get_key
get_key:
    pop esi          ; ESI = 密鑰位址
    lodsb            ; AL = 密鑰位元組
    xor [edi], al    ; 解密目的緩衝區
    inc edi
    loop decode_loop

不同組譯器的標號寫法

組譯器匿名標號具名標號
MASM / JWasm / UAsm@@:MyLabel:
TASM@@:MyLabel:
NASM / YASM$: 或 $$:MyLabel:
GAS (AT&T)1f: (前向) / 1b: (後向)MyLabel:

注意事項

  • 堆疊平衡:CALL/POP 不改變堆疊深度,但若在已有參數的堆疊框架中使用,需注意 EBP 相對位址偏移。
  • 64 位元模式:x64 同樣適用,CALL 壓入 RIP,POP RAX 取得。
  • DEP/ASLR:現代作業系統啟用 DEP 時,程式碼區不可寫;若需自修改程式碼,必須先 VirtualProtect 變更頁面屬性。
  • 最佳化風險:激進最佳化可能內聯或移除 CALL,建議標註 NOP 或關閉該區塊最佳化。

總結

CALL @F / POP REG 是組合語言取得執行期位址的黃金標準技巧,簡潔、高效、跨平台。掌握此技巧,即可編寫位置無關程式碼、動態解密器、Shellcode 等進階底層程式,是逆向工程、殼開發、嵌入式韌體開發的必備內功。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved