EBX寄存器用于内存访问的这种模式是什么? [英] What is this pattern where the EBX register is used for memory access?

查看:353
本文介绍了EBX寄存器用于内存访问的这种模式是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在学习逆向工程的基础。在逆转破解时,我碰巧在几乎每个函数的开头都看到了这种模式:

I'm learning the basis of reverse engineering. While reversing a crackme it happened to me to see this pattern at the beginning of almost every function:

pushl %ebp                            
movl  %esp, %ebp              
pushl %ebx              # because ebx is a callee-saved register
subl  $0x14,%esp        # of course $0x14 changes depending on the function
calll 0x08048766
addl  $0x1a5f, %ebx     # also this value sometime changes depending on the function

而变化 0x08048766 有一个函数可以执行以下操作:

Where at 0x08048766 there is a function that does just this:

movl 0(%esp), %ebx         
retl 

首先初始化寄存器 ebp esp 。然后将寄存器 ebx 推入堆栈,这也是完全可以理解的,因为 ebx 是已保存被调用者的寄存器并且稍后在函数中使用它来引用一些静态数据(来自 .rodata ),例如:

So basically, as it is normal, every function first initialize the registers ebp and esp. Then the register ebx is pushed into the stack, and this also is totally understandable as ebx is a callee-saved register and it is used later in the function to reference some static data (from .rodata), for example:

leal  -0x17b7(%ebx), %eax
movl  %eax, 0(%esp) 
calll printf   

现在最有趣(对我来说晦涩)的部分:如果我正确理解, ebx 是首先用 esp 指向的值初始化(使用 0x08048766 的函数),为什么?里面有什么?

Now the most interesting (and to me obscure) part: If I have understood correctly, ebx is first initialized with the value pointed by esp (this using the function at 0x08048766), why? What's inside there? Isn't it an uninitialized point down into the stack?

然后将另一个值添加到 ebx 中。这个值代表什么?

Then another value is added to ebx. What does this value represent?

我想更好地理解在这种情况下如何使用寄存器 ebx ,以及如何计算指向的地址。

I would like to understand better how the register ebx is used in this case, and how to calculate the address it is pointing to.

您可以查看完整的程序此处,但不幸的是,没有可用的C源代码。

You can have a look to the complete program here, but unfortunately there isn't any C source code available.

推荐答案

该代码似乎已经使用 -fPIC 进行了编译。 PIC代表位置无关的代码,这意味着它可以加载到任何地址,并且仍然能够访问其全局变量。

This code appears to have been compiled with -fPIC. PIC stands for "position-independent code", meaning it can be loaded to any address and is still able to access it's global variables.

在这种情况下, ebx 被称为PIC寄存器,它用于指向GOT(全局偏移表)的末尾。 GOT对每个正在使用的全局变量都有一个偏移量(从程序的基地址*开始)。

In this case ebx is known as the PIC register, and it's used to point to the end of the GOT (the global offset table). The GOT has offsets (from the program's base address*) to each global variable being used.

很多时候,了解这些东西的最好方法是编译自己编写一些代码,然后查看输出。

Many times, the best way to learn about these kinds of things are to compile some code yourself, and look at the output. It especially makes it easier when you have your symbols to look at.

让我们做一个实验:

pic.c

int global;

int main(void)
{
    global = 4;
    return 0;
}

编译

$ gcc -v
...
gcc version 5.3.1 20160406 (Red Hat 5.3.1-6) (GCC)

$ gcc -m32 -Wall -Werror -fPIC -o pic pic.c

部分(缩写)

$ readelf -S pic
Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [13] .text             PROGBITS        080482f0 0002f0 000182 00  AX  0   0 16
  [15] .rodata           PROGBITS        08048488 000488 00000c 00   A  0   0  4
  [22] .got              PROGBITS        08049ffc 000ffc 000004 04  WA  0   0  4
  [23] .got.plt          PROGBITS        0804a000 001000 000014 04  WA  0   0  4
  [24] .data             PROGBITS        0804a014 001014 000004 00  WA  0   0  1
  [25] .bss              NOBITS          0804a018 001018 000008 00  WA  0   0  4

反汇编(英特尔语法,因为AT& T让我发疯了)

Disassemble (Intel syntax because AT&T drives me nuts)

$ objdump -Mintel -d --no-show-raw-insn pic

080483eb <main>:
 80483eb:   push   ebp
 80483ec:   mov    ebp,esp
 80483ee:   call   804840b <__x86.get_pc_thunk.ax> ; EAX = EIP + 5
 80483f3:   add    eax,0x1c0d            ; EAX = 0x804a000 (.got.plt, end of .got)
 80483f8:   lea    eax,[eax+0x1c]        ; EAX = 0x804a01C (.bss + 4)

 80483fe:   mov    DWORD PTR [eax],0x4   ; set `global` to 4
 8048404:   mov    eax,0x0
 8048409:   pop    ebp
 804840a:   ret    

0804840b <__x86.get_pc_thunk.ax>:
 804840b:   mov    eax,DWORD PTR [esp]
 804840e:   ret    
 804840f:   nop

说明

在这种情况下,我的GCC决定使用 eax 作为PIC寄存器而不是 ebx

In this case, my GCC decided to use eax as the PIC register instead of ebx.

另外,请注意编译器(GCC 5.3.1)在这里做了一些有趣的事情。它不是通过GOT访问变量,而是将GOT用作锚,而是直接偏移到 .bss 部分中的变量。

Also, note that the compiler (GCC 5.3.1) did something interesting here. Instead of accessing the variable via the GOT, it essentially used the GOT as an "anchor", and instead offsetted directly to the variable in the .bss section.

返回您的代码:

pushl %ebp                            
movl %esp, %ebp              
pushl %ebx             ; because ebx is a callee-saved register
subl $0x14,%esp        ; end of typical prologue 

calll 0x08048766       ; __i686_get_pc_thunk_bx
                       ; Gets the current value of EIP after this call into EBX.
                       ; There is no other way to do this in x86 without a call

addl $0x1a5f, %ebx     ; Add the displacement to the end of the GOT.
                       ; This displacement of course changes depending on 
                       ; where the function is.
                       ; EBX now points to the end of the GOT.

leal -0x17b7(%ebx), %eax    ; EAX = EBX - 0x17b7
movl %eax, 0(%esp)          ; Put EAX on stack (arg 0 to printf)
                            ; EAX should point to some string
calll printf   

在您的代码中,它也没有实际上使用了GOT(否则我们将看到第二个内存取消引用);它用它作为字符串的锚点,可能是在GOT之前的只读数据部分( .rodata )中。

In your code also, it didn't actually "use" the GOT (otherwise we would see a second memory de-reference); it used it as an anchor to the string, probably in the read-only data section (.rodata) which also came before the GOT.

如果您查看 0x08048766 处的函数,则会看到类似以下的内容:

If you look at the function at 0x08048766, you'll see it looks something like this:

mov    (%esp),%eax  ; Put return address (pushed onto stack by call insn)
                    ; in eax
ret                 ; Return

这篇关于EBX寄存器用于内存访问的这种模式是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆