反匯編


反匯編

  • 反匯編:把目標代碼轉為匯編代碼的過程。 通常,編寫程序是利用高級語言如C,Pascal等高級語言進行編程的,然后再經過編譯程序生成可以被計算機系統直接執行的文件。反匯編即是指將這些執行文件反編譯還原成匯編語言或其他高級語言。但通常反編譯出來的程序與原程序會存在許多不同,雖然執行效果相同.
  • gdb相關操作:
    b linenumber 設置斷點
    run 運行
    disassemble 獲取匯編代碼
    用i(nfo) r(egisters)查看各寄存器的值
    用x查看內存地址中的值
  • 具體步驟:
    設置斷點在main函數調用f函數的位置gdb> b main
    gdb> run運行
    gdb> disassemble反匯編
    display /i $pc
    i r
    x查看內存中的內容
    si執行下一條匯編
  • 反匯編:
    使用gcc - g example.c -o example -m32指令在64位的機器上產生32位匯編,然后使用gdb example指令進入gdb調試器:
  • 用gcc在64位機器上編譯一個32位的程序,遇到報錯,具體如下圖:
    32位錯誤
  • 這是因為編譯64位Linux版本32位的二進制文件,需要安裝一個庫,使用指令
    sudo apt-get install libc6-dev-i386

開始gdb

  • 進入之后先在main函數處設置一個斷點,再run一下,使用disassemble指令獲取匯編代碼,用i(info) r(registers)指令查看各寄存器的值:

獲取匯編代碼
查看寄存器的值

  • 可見此時主函數的棧基址為0xffffd1e8,用x(examine)指令查看內存地址中的值,但目前%esp所指堆棧內容為0,%ebp所指內容也為0
    x 0ffffd1e8
    以上為入門小練習,接下來讓我們直接進入f函數中,查看f函數的每一步匯編代碼
    “display /i $pc”
        其中 $pc 代表當前匯編指令,/i 表示以十六進行顯示。當需要關心匯編代碼時,此命令相當有用。這樣在每次執行下一條匯編語句時,都會顯示出當前執行的語句。下面展示每一步時%esp、%ebp、%eip、%eax和堆棧內容的變化:

f

ebp esp
eip
eax

匯編代碼

  • movl 指令:把值0x1b存在%ebp-0x4中

下一條指令

ebp esp eip eax

棧值2a

  • 將上一個函數的地址入棧,以%ebp+0x8作為基址 待考證

下一條指令

ebp esp eip eax

棧值3a

  • call指令將下一條指令的地址入棧

下一條指令

ebp esp eip eax

棧值4a

  • endbr32

這是Intel 為 CONTROL-FLOW ENFORCEMENT TECHNOLOGY 新加的指令:

The ENDBRANCH (see Section 73 for details) is a new instruction that is used to mark valid jump target addresses of indirect calls and jumps in the program. This instruction opcode is selected to be one that is a NOP on legacy machines such that programs compiled with ENDBRANCH new instruction continue to function on old machines without the CET enforcement. On processors that support CET the ENDBRANCH is still a NOP and is primarily used as a marker instruction by the processor pipeline to detect control flow violations. The CPU implements a state machine that tracks indirect jmp and call instructions. When one of these instructions is seen, the state machine moves from IDLE to WAIT_FOR_ENDBRANCH state. In WAIT_FOR_ENDBRANCH state the next instruction in the program stream must be an ENDBRANCH. If an ENDBRANCH is not seen the processor causes a control protection exception (#CP), else the state machine moves back to IDLE state.

給技術要求相對跳轉的目標地址一定是一條 endbr32 或 endbr64 指令,否則就會異常。該指令並不執行任何操作,只是用於驗證目標地址是期望的跳轉目標。

下一條指令

ebp esp eip eax

棧值5a

下一條指令

ebp esp eip eax

棧值6a

  • 將上一個函數的基址入棧,從當前%esp開始作為新基址

下一條指令

ebp esp eip eax

  • 此處棧底地址改變,下圖是新地址與原始地址的對比圖:

棧值7a

  • call下一條指令入棧

下一條指令

ebp esp eip eax

棧值8a

  • 將%esp指向的地址中的值賦給%eax寄存器

下一條指令

ebp esp eip eax

棧值9a

  • ret指令將棧頂彈給%eip

下一條指令

ebp esp eip eax

棧值10a

將$0x2e23寄存器中的值與%eax寄存器中的值相加,存在$0x2e23寄存器中

下一條指令

ebp esp eip eax

棧值11a

  • 將%eax寄存器中的值存到0x8+%ebp地址中,也就是堆棧中
    存的值

下一條指令

ebp esp eip eax

棧值12a

  • %eax寄存器的值與$0x3寄存器的值相加后的值存到$0x3寄存器中

下一條指令

ebp esp eip eax

  • pop %ebp指令將棧頂彈到%ebp中,同時%esp增加4字節

下一條指令

ebp esp eip eax

  • ret指令將棧頂彈給%eip

  • leave

在32位匯編下相當於:
mov esp,ebp;//將ebp指向(ebp內部應當保存一個地址,所謂指向即這個地址對應的空間)的值賦給esp
pop ebp

/* leave指令將EBP寄存器的內容復制到ESP寄存器中,
以釋放分配給該過程的所有堆棧空間。然后,它從堆棧恢復EBP寄存器的舊值。*/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM