Ghidra对局部变量的标识

Ghidra函数中的局部变量,不是根据RBP的偏移,而是根据函数开始处RSP的偏移进行标识。

使用csaw18 pwn中的boi程序作为例子,来分析看ghidra对局部变量是如何标识。

Ghidra分析结果

                         *******************************************************
                         *                      FUNCTION                       *
                         *******************************************************
                         undefined main()
    undefined       AL:1         <RETURN>
    undefined8      Stack[-0x10  local_10                           XREF[2]:   00400659(W), 
                                                                               004006ca(R)  
    undefined4      Stack[-0x20  local_20                           XREF[1]:   00400677(W)  
    undefined8      Stack[-0x28  local_28                           XREF[1,2]: 0040066f(W), 
                                                                               0040067e(W), 
                                                                               004006a5(R)  
    undefined8      Stack[-0x30  local_30                           XREF[1]:   00400667(W)  
    undefined8      Stack[-0x38  local_38                           XREF[2]:   0040065f(W), 
                                                                               0040068f(*)  
    undefined4      Stack[-0x3c  local_3c                           XREF[1]:   00400649(W)  
    undefined8      Stack[-0x48  local_48                           XREF[1]:   0040064c(W)  
                         main                                       XREF[5]:   Entry Point(*), 
                                                                            _start:0040054d(*), 
                                                                            _start:0040054d(*), 004007b4, 
                                                                               00400868(*)  
      00400641               PUSH      RBP        # 入栈8字节
      00400642               MOV       RBP,RSP
      00400645               SUB       RSP,0x40
      00400649               MOV       dword ptr [RBP + local_3c],EDI
      0040064c               MOV       qword ptr [RBP + local_48],RSI
      00400650               MOV       RAX,qword ptr FS:[0x28]
      00400659               MOV       qword ptr [RBP + local_10],RAX
      0040065d               XOR       EAX,EAX
      0040065f               MOV       qword ptr [RBP + local_38],0x0
      00400667               MOV       qword ptr [RBP + local_30],0x0
      0040066f               MOV       qword ptr [RBP + local_28],0x0
      00400677               MOV       dword ptr [RBP + local_20],0x0
      0040067e               MOV       dword ptr [RBP + local_28+0x4],0xdeadbeef
      00400685               MOV       EDI=>s_Are_you_a_big_boiiiii??_00400764,s  = "Are you a big boiiiii??"
      0040068a               CALL      puts                                       int puts(char * __s)
      0040068f               LEA       RAX=>local_38,[RBP + -0x30]  # 此处 RAX=>local_38 是什么意思? 
      00400693               MOV       EDX,0x18
      00400698               MOV       RSI,RAX
      0040069b               MOV       EDI,0x0
      004006a0               CALL      read                                       ssize_t read(int __fd, void 
      004006a5               MOV       EAX,dword ptr [RBP + local_28+0x4]
      004006a8               CMP       EAX,0xcaf3baee
      004006ad               JNZ       LAB_004006bb
      004006af               MOV       EDI=>s_/bin/bash_0040077c,s_/bin/bash_004  = "/bin/bash"
      004006b4               CALL      run_cmd                                    undefined run_cmd()
      004006b9               JMP       LAB_004006c5
 LAB_004006bb                              XREF[1]:   004006ad(j)  
      004006bb               MOV       EDI=>s_/bin/date_00400786,s_/bin/date_004  = "/bin/date"
      004006c0               CALL      run_cmd                                    undefined run_cmd()
 LAB_004006c5                              XREF[1]:   004006b9(j)  
      004006c5               MOV       EAX,0x0
      004006ca               MOV       RCX,qword ptr [RBP + local_10]
      004006ce               XOR       RCX,qword ptr FS:[0x28]
      004006d7               JZ        LAB_004006de
      004006d9               CALL      __stack_chk_fail                           undefined __stack_chk_fail()
                         -- Flow Override: CALL_RETURN (CALL_TERMINATOR)
                         LAB_004006de                              XREF[1]:   004006d7(j)  
      004006de               LEAVE
      004006df               RET

从最上面可以看到,ghidra函数中的局部变量,直接是根据STACK进行标识,是根据函数开始处RSP的偏移。

当看到这行LEA RAX=>local_38,[RBP + -0x30]时,是获取RBP-0x30的地址,在想和local_38有什么关系?

从最上面Stack[-0x38 local_38看到,local_38 = 起始RSP-0x38

PUSH RBP MOV RBP,RSP可知,RBP=起始RSP - 0x8,那RBP-0x30 = 起始RSP-0x8-0x30=起始RSP-0x38=local_38

所以,RAX获取到的是local_38的地址。

IDA的分析结果

IDA的结果:

text:0000000000400641 ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:0000000000400641                 public main
.text:0000000000400641 main            proc near               ; DATA XREF: _start+1D↑o
.text:0000000000400641
.text:0000000000400641 var_40          = qword ptr -40h
.text:0000000000400641 var_34          = dword ptr -34h
.text:0000000000400641 buf             = qword ptr -30h
.text:0000000000400641 var_28          = qword ptr -28h
.text:0000000000400641 var_20          = qword ptr -20h
.text:0000000000400641 var_18          = dword ptr -18h
.text:0000000000400641 var_8           = qword ptr -8
.text:0000000000400641
.text:0000000000400641 ; __unwind {
.text:0000000000400641                 push    rbp
.text:0000000000400642                 mov     rbp, rsp
.text:0000000000400645                 sub     rsp, 40h
.text:0000000000400649                 mov     [rbp+var_34], edi
.text:000000000040064C                 mov     [rbp+var_40], rsi
.text:0000000000400650                 mov     rax, fs:28h
.text:0000000000400659                 mov     [rbp+var_8], rax
.text:000000000040065D                 xor     eax, eax
.text:000000000040065F                 mov     [rbp+buf], 0
.text:0000000000400667                 mov     [rbp+var_28], 0
.text:000000000040066F                 mov     [rbp+var_20], 0
.text:0000000000400677                 mov     [rbp+var_18], 0
.text:000000000040067E                 mov     dword ptr [rbp+var_20+4], 0DEADBEEFh
.text:0000000000400685                 mov     edi, offset s   ; "Are you a big boiiiii??"
.text:000000000040068A                 call    _puts
.text:000000000040068F                 lea     rax, [rbp+buf]
.text:0000000000400693                 mov     edx, 18h        ; nbytes
.text:0000000000400698                 mov     rsi, rax        ; buf
.text:000000000040069B                 mov     edi, 0          ; fd
.text:00000000004006A0                 call    _read
.text:00000000004006A5                 mov     eax, dword ptr [rbp+var_20+4]
.text:00000000004006A8                 cmp     eax, 0CAF3BAEEh
.text:00000000004006AD                 jnz     short loc_4006BB
.text:00000000004006AF                 mov     edi, offset aBinBash ; "/bin/bash"
.text:00000000004006B4                 call    run_cmd
.text:00000000004006B9                 jmp     short loc_4006C5
.text:00000000004006BB ; ---------------------------------------------------------------------------
.text:00000000004006BB
.text:00000000004006BB loc_4006BB:                             ; CODE XREF: main+6C↑j
.text:00000000004006BB                 mov     edi, offset aBinDate ; "/bin/date"
.text:00000000004006C0                 call    run_cmd
.text:00000000004006C5
.text:00000000004006C5 loc_4006C5:                             ; CODE XREF: main+78↑j
.text:00000000004006C5                 mov     eax, 0
.text:00000000004006CA                 mov     rcx, [rbp+var_8]
.text:00000000004006CE                 xor     rcx, fs:28h
.text:00000000004006D7                 jz      short locret_4006DE
.text:00000000004006D9                 call    ___stack_chk_fail

对于IDA来说,局部变量是针对RBP进行偏移的,RBP是函数调用中的栈帧的基址,并且在函数返回前不会改动,所以比较好理解。

Ghidra的问题

IDA上0x00400649地址处汇编为mov [rbp+var_34], edi,根据之前的RBP=起始RSP-0x8,转化成起始RSP-0x8-0x34起始RSP-0x3C

而该地址对应的是local_3c,但是ghidra上却是RBP + local_3c,因为local_3c的地址想对于RBP是0x34,所以ghidra使用MOV dword ptr [local_3c],EDI会比较合适。

在github上,看到了为什么ghidra会选择以stack作为偏移。链接

关闭ghidra局部变量引用

这种可以关闭,通过开始菜单上的Edit –> Tool Options –> Listing Fields –> Operands Field,将Markup Stack Variable References勾去掉就行。

graph

效果如下:

graph

关闭后效果会更好,可以直接知道每行汇编代码是针对那个局部变量进行处理,并且针对RBP的偏移也有展示。

打赏

取消

感谢您的支持!

扫码支持
扫码支持
扫码打赏,您说多少就多少

打开支付宝或微信扫一扫,即可进行扫码打赏哦