本文介绍了获取帧指针用C的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

限时删除!!

我试图让FP在我的C程序中,我尝试两种不同的方式,但他们都从我所得到的,当我运行GDB不同。

我试过第一种方式,我用C做了一个协议函数汇编函数:

 为int * getEbp();

和我的code是这样的:

 为int * EBP = getEbp();
的printf(EBP:%08X \\ n,EBP); //值我得到这里是0xbfe2db58而(ESP< = EBP)
    尤 - = 4;的printf(EBP:%08X,ESP); //值我得到这里是0xbfe2daec

我的组装code

  getEbp:
    MOVL%EBP,EAX%
    RET

我试图使原型函数只是返回一个int,但也不会与我的GDB的输出匹配。我们正在使用x86汇编。

编辑:错别字,我getEsp功能长相酷似另一种:

  getEsp:
    MOVL%ESP,EAX%
    RET


解决方案

  1. 要读取寄存器,它的确是最好使用。

  2. getEbp()的样子,如果你在一个单独的文件汇编编译它,它应该工作。

  3. getEsp()是显然是不正确,因为它并不需要调用者推入帐户的返回地址。

下面是一个code片段,可获得 EBP 通过扩展的内联汇编并没有追逐帧指针堆栈展开:

 结构stack_frame {
        结构stack_frame * preV;
        无效* return_addr;
} __attribute __((包装));
typedef结构stack_frame stack_frame;无效backtrace_from_fp(无效** BUF,INT大小)
{
        INT I;
        stack_frame * FP;        __asm​​ __(MOVL %% EBP,%[FP]/ *输出* / [FP]= R(FP));        对于(i = 0; I<大小和放大器;&安培; FP = NULL;!FP = FP-GT&; preV,我++)
                BUF [I] = FP-GT&; return_addr;
}

我会告诉阅读下面的寄存器两个工作实现。纯ASM功能 get_ebp() get_esp() getbp.S 。为内联函数实现的另一组是 get_esp_inline() get_ebp_inline()在顶部测试getbp.c

getbp.S

  .section伪的.text
/ *显然招致函数调用的成本
   读寄存器是无效的* /
。全球get_ebp
get_ebp:
MOVL%EBP,EAX%
RET。全球get_esp
get_esp:
/ * 4:由主叫推返回地址* /
LEA 4(%ESP),EAX%
RET

测试getbp.c

 的#include<&stdio.h中GT;
#包括LT&;&stdint.h GT;/ *参见http://sourceware.org/systemtap/wiki/UserSpaceProbeImplementation * /
#包括LT&; SYS / sdt.h>int32_t * get_ebp(无效);
int32_t * get_esp(无效);__attribute __((always_inline))uintptr_t形式* get_ebp_inline(无效)
{
    类型uintptr_t * R;
    __asm​​__挥发性(MOVL %% EBP,%[R]/ *输出* / [R]= R(R));
    返回ř;
}__attribute __((always_inline))uintptr_t形式* get_esp_inline(无效)
{
    类型uintptr_t * R;
    __asm​​__挥发性(MOVL %% ESP,%[R]/ *输出* / [R]= R(R));
    返回ř;
}INT主(INT ARGC,字符** argv的)
{
    uintptr_t形式*基点,* SP;    / *分配堆栈上的一些随机数据只是为了好玩* /
    诠释一个[10] = {1,3,4,9};
    fprintf中(FOPEN(的/ dev / null的,R),%d个\\ N中,[3]);    STAP_PROBE(getbp,getbp); / *静态探头就像一个名为断点* /
    BP = get_ebp();
    SP = get_esp();
    的printf(ASM:%P,%P \\ N(无效*)BP,(无效*)SP);
    BP = get_ebp_inline();
    SP = get_esp_inline();
    的printf(内联:%P,%P \\ N(无效*)BP,(无效*)SP);
    返回0;
}

我们现在可以编写一个GDB脚本来倾倒 EBP 尤其同时利用了<$ C $的C> getbp >测试getbp.c 上方

测试getbp.gdb

 文件测试getbp设置断点等候
打破-p getbp
命令
无声
printf的GDB:为0x%04X,为0x%04X \\ n,$ EBP,ESP $
继续
结束跑
放弃

要验证该函数返回相同的数据GDB:

  $ GDB -x测试getbp.gdb
&LT; ...&GT;
GDB:0xffffc938,0xffffc920
ASM:0xffffc938,0xffffc920
内联:0xffffc938,0xffffc920
&LT; ...&GT;

拆卸测试getbp 的main()生产:

  0x08048370 1 + 0计算值:推%EBP
   0x08048371 1 + 1&GT ;: MOV%ESP,EBP%
   0x08048373 1 + 3计算值:推%EBX
   0x08048374 1 + 4计算值:和$ 0xfffffff0,%尤
   0x08048377 1 + 7计算值:子$为0x10,%尤
   0x0804837a 1 + 10 -10 ;: MOVL $ 0x8048584,0x4(%尤)
   0x08048382 1 + 18计算值:MOVL $ 0x8048586,(%尤)
   0x08048389 1 + 25计算值:调用0x8048360&下;的fopen @ PLT&GT;
   0x0804838e 1 + 30计算值:MOVL $ 0x9,0x8(%尤)
   0x08048396 1 + 38计算值:MOVL $ 0x8048590,0x4(%尤)
   0x0804839e 1 + 46计算值:MOV%eax中,(%尤)
   0x080483a1 1 + 49计算值:调用0x8048350&下; fprintf中@ PLT&GT;
   0x080483a6 1 + 54计算值:NOP
   0x080483a7 1 + 55计算值:调用0x80484e4&所述; get_ebp&GT;
   0x080483ac 1 + 60计算值:MOV%eax中,%EBX
   0x080483ae 1 + 62计算值:调用0x80484e7&所述; get_esp&GT;
   0x080483b3 1 + 67计算值:MOV%EBX,为0x4(%尤)
   0x080483b7 1 + 71计算值:MOVL $ 0x8048594,(%尤)
   0x080483be 1 + 78计算值:MOV%eax中,位于0x8(%尤)
   0x080483c2 1 + 82计算值:调用0x8048320&下; printf的@ PLT&GT;
   0x080483c7 1 + 87计算值:MOV%EBP,EAX%
   0x080483c9 1 + 89计算值:MOV%ESP,EDX%
   0x080483cb 1 + 91计算值:MOV%EDX,位于0x8(%尤)
   0x080483cf 1 + 95计算值:MOV EAX%,为0x4(%ESP)
   0x080483d3 1 + 99计算值:MOVL $ 0x80485a1,(%尤)
   0x080483da 1 + 106计算值:调用0x8048320&下; printf的@ PLT&GT;
   0x080483df 1 + 111 ;: XOR%EAX,EAX%
   0x080483e1 1 + 113计算值:MOV -0x4(EBP%),EBX%
   0x080483e4 1 + 116计算值:离开
   0x080483e5 1 + 117计算值:保留

NOP &lt;主+ 54&GT; 是静态的探头。看到周围的code中的两个的printf 呼吁寄存器读取如何

顺便说一句,这个循环在code觉得奇怪,我:

 而(ESP&LT; = EBP)
    尤 - = 4;

不要你的意思

 而(ESP&LT; EBP)
    ESP + = 4

I'm trying to get the FP in my C program, I tried two different ways, but they both differ from what I get when I run GDB.

The first way I tried, I made a protocol function in C for the Assembly function:

int* getEbp();

and my code looks like this:

int* ebp = getEbp();
printf("ebp: %08x\n", ebp); // value i get here is 0xbfe2db58

while( esp <= ebp )
    esp -= 4;

printf( "ebp: %08x, esp" ); //value i get here is 0xbfe2daec

My assembly code

getEbp:
    movl %ebp, %eax
    ret

I tried making the prototype function to just return an int, but that also doesn't match up with my GDB output. We are using x86 assembly.

EDIT: typos, and my getEsp function looks exactly like the other one:

getEsp:
    movl %esp, %eax
    ret
解决方案
  1. For reading a register, it's indeed best to use GCC extended inline assembly syntax.
  2. Your getEbp() looks like it should work if you compiled it in a separate assembler file.
  3. Your getEsp() is obviously incorrect since it doesn't take the return address pushed by the caller into account.

Here's a code snippet that gets ebp through extended inline asm and does stack unwinding by chasing the frame pointer:

struct stack_frame {
        struct stack_frame *prev;
        void *return_addr;
} __attribute__((packed));
typedef struct stack_frame stack_frame;

void backtrace_from_fp(void **buf, int size)
{
        int i;
        stack_frame *fp;

        __asm__("movl %%ebp, %[fp]" :  /* output */ [fp] "=r" (fp));

        for(i = 0; i < size && fp != NULL; fp = fp->prev, i++)
                buf[i] = fp->return_addr;
}

I'll show two working implementations of reading the registers below. The pure asm functions are get_ebp() and get_esp() in getbp.S. The other set implemented as inline functions are get_esp_inline() and get_ebp_inline() at the top of test-getbp.c.

In getbp.S

.section .text
/* obviously incurring the cost of a function call
   to read a register is inefficient */
.global get_ebp
get_ebp:
movl %ebp, %eax
ret

.global get_esp
get_esp:
/* 4: return address pushed by caller */
lea 4(%esp), %eax
ret

In test-getbp.c

#include <stdio.h>
#include <stdint.h>

/* see http://sourceware.org/systemtap/wiki/UserSpaceProbeImplementation */
#include <sys/sdt.h>

int32_t *get_ebp(void);
int32_t *get_esp(void);

__attribute__((always_inline)) uintptr_t *get_ebp_inline(void)
{
    uintptr_t *r;
    __asm__ volatile ("movl %%ebp, %[r]" : /* output */ [r] "=r" (r));
    return r;
}

__attribute__((always_inline)) uintptr_t *get_esp_inline(void)
{
    uintptr_t *r;
    __asm__ volatile ("movl %%esp, %[r]" : /* output */ [r] "=r" (r));
    return r;
}

int main(int argc, char **argv)
{
    uintptr_t *bp, *sp;

    /* allocate some random data on the stack just for fun */
    int a[10] = { 1, 3, 4, 9 };
    fprintf(fopen("/dev/null", "r"), "%d\n", a[3]);

    STAP_PROBE(getbp, getbp); /* a static probe is like a named breakpoint */
    bp = get_ebp();
    sp = get_esp();
    printf("asm: %p, %p\n", (void*)bp, (void*)sp);
    bp = get_ebp_inline();
    sp = get_esp_inline();
    printf("inline: %p, %p\n", (void*)bp, (void*)sp);
    return 0;
}

We can now write a GDB script to dump ebp and esp while making use of the getbp static probe defined in test-getbp.c above.

In test-getbp.gdb

file test-getbp

set breakpoint pending on
break -p getbp
commands
silent
printf "gdb: 0x%04x, 0x%04x\n", $ebp, $esp
continue
end

run
quit

To verify that the functions return the same data as GDB:

$ gdb -x test-getbp.gdb
< ... >
gdb: 0xffffc938, 0xffffc920
asm: 0xffffc938, 0xffffc920
inline: 0xffffc938, 0xffffc920
< ... >

Disassembling test-getbp main() produces:

   0x08048370 <+0>: push   %ebp
   0x08048371 <+1>: mov    %esp,%ebp
   0x08048373 <+3>: push   %ebx
   0x08048374 <+4>: and    $0xfffffff0,%esp
   0x08048377 <+7>: sub    $0x10,%esp
   0x0804837a <+10>:    movl   $0x8048584,0x4(%esp)
   0x08048382 <+18>:    movl   $0x8048586,(%esp)
   0x08048389 <+25>:    call   0x8048360 <fopen@plt>
   0x0804838e <+30>:    movl   $0x9,0x8(%esp)
   0x08048396 <+38>:    movl   $0x8048590,0x4(%esp)
   0x0804839e <+46>:    mov    %eax,(%esp)
   0x080483a1 <+49>:    call   0x8048350 <fprintf@plt>
   0x080483a6 <+54>:    nop
   0x080483a7 <+55>:    call   0x80484e4 <get_ebp>
   0x080483ac <+60>:    mov    %eax,%ebx
   0x080483ae <+62>:    call   0x80484e7 <get_esp>
   0x080483b3 <+67>:    mov    %ebx,0x4(%esp)
   0x080483b7 <+71>:    movl   $0x8048594,(%esp)
   0x080483be <+78>:    mov    %eax,0x8(%esp)
   0x080483c2 <+82>:    call   0x8048320 <printf@plt>
   0x080483c7 <+87>:    mov    %ebp,%eax
   0x080483c9 <+89>:    mov    %esp,%edx
   0x080483cb <+91>:    mov    %edx,0x8(%esp)
   0x080483cf <+95>:    mov    %eax,0x4(%esp)
   0x080483d3 <+99>:    movl   $0x80485a1,(%esp)
   0x080483da <+106>:   call   0x8048320 <printf@plt>
   0x080483df <+111>:   xor    %eax,%eax
   0x080483e1 <+113>:   mov    -0x4(%ebp),%ebx
   0x080483e4 <+116>:   leave
   0x080483e5 <+117>:   ret

The nop at <main+54> is the static probe. See the code around the two printf calls for how the registers are read.

BTW, this loop in your code seems strange to me:

while( esp <= ebp )
    esp -= 4;

Don't you mean

while (esp < ebp)
    esp +=4

?

这篇关于获取帧指针用C的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

1403页,肝出来的..

09-07 02:33