如何在C中打印EIP地址?

Sab*_*ina 2 c linux memory x86 assembly

这是我的C程序......我试图打印ESP,EBP和EIP.

#include <stdio.h>
int main() {

    register int i asm("esp");
    printf("%#010x <= $ESP\n", i);

    int a = 1;
    int b = 2;
    char c[] = "A";
    char d[] = "B";

    printf("%p d = %s \n", &d, d);
    printf("%p c = %s \n", &c, c);
    printf("%p b = %d \n", &b, b);
    printf("%p a = %d \n", &a, a);

    register int j asm("ebp");
    printf("%#010x <= $EBP\n", j);

    //register int k asm("eip");
    //printf("%#010x <= $EIP\n", k);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我没有ESP和EBP的问题.

user@linux:~# ./memoryAddress 
0xbffff650 <= $ESP
0xbffff654 d = B 
0xbffff656 c = A 
0xbffff658 b = 2 
0xbffff65c a = 1 
0xbffff668 <= $EBP
user@linux:~# 
Run Code Online (Sandbox Code Playgroud)

但是当我尝试输入EIP代码时,我在编译时遇到以下错误.

user@linux:~# gcc memoryAddress.c -o memoryAddress -g
memoryAddress.c: In function ‘main’:
memoryAddress.c:20:15: error: invalid register name for ‘k’
  register int k asm("eip");
               ^
user@linux:~#
Run Code Online (Sandbox Code Playgroud)

这段代码出了什么问题?

register int k asm("eip");
printf("%#010x <= $EIP\n", k);
Run Code Online (Sandbox Code Playgroud)

是否可以通过C编程打印出EIP值?

如果是,请告诉我如何操作.

更新

我在这里测试了代码......

user@linux:~/c$ lscpu
Architecture:        i686
CPU op-mode(s):      32-bit
Byte Order:          Little Endian
Run Code Online (Sandbox Code Playgroud)

感谢@Antti Haapala和其他人的帮助.代码有效...但是,当我将其加载到GDB时,EIP值是不同的.

(gdb) b 31
Breakpoint 1 at 0x68f: file eip.c, line 31.
(gdb) i r $eip $esp $ebp
The program has no registers now.
(gdb) r
Starting program: /home/user/c/a.out 
0x00000000 <= Low Memory Address
0x40055d   <= main() function
0x4005a5   <= $EIP 72 bytes from main() function (start)
0xbffff600 <= $ESP (Top of the Stack)
0xbffff600 d = B 
0xbffff602 c = A 
0xbffff604 b = 2 
0xbffff608 a = 1 
0xbffff618 <= $EBP (Bottom of the Stack)
0xffffffff <= High Memory Address

Breakpoint 1, main () at eip.c:31
31              return 0;
(gdb) i r $eip $esp $ebp
eip            0x40068f 0x40068f <main+306>
esp            0xbffff600       0xbffff600
ebp            0xbffff618       0xbffff618
(gdb) 
Run Code Online (Sandbox Code Playgroud)

这是新代码

#include <stdio.h>
#include <inttypes.h>

int main() {

    register int i asm("esp");
    printf("0x00000000 <= Low Memory Address\n");
    printf("%p   <= main() function\n", &main);

    uint32_t eip;
    asm volatile("1: lea 1b, %0;": "=a"(eip));
    printf("0x%" PRIx32 "   <= $EIP %" PRIu32 " bytes from main() function (start)\n",
    eip, eip - (uint32_t)main);

    int a = 1;
    int b = 2;
    char c[] = "A";
    char d[] = "B";

    printf("%#010x <= $ESP (Top of the Stack)\n", i);

    printf("%p d = %s \n", &d, d);
    printf("%p c = %s \n", &c, c);
    printf("%p b = %d \n", &b, b);
    printf("%p a = %d \n", &a, a);

    register int j asm("ebp");
    printf("%#010x <= $EBP (Bottom of the Stack)\n", j);
    printf("0xffffffff <= High Memory Address\n");

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

Ant*_*ala 7

请先直接阅读QA 阅读程序计数器 - 从那里我们可以看到没有 mov命令可以EIP/RIP直接访问,因此您无法使用register asm它来访问它.相反,在任何时候你都可以使用这些技巧.使用时,它在64位模式下最简单

uint64_t rip;
asm volatile("1: lea 1b(%%rip), %0;": "=a"(rip));
Run Code Online (Sandbox Code Playgroud)

得到64位指令(感谢Michael Petch指出标签适用于lea此处.

示范:

#include <stdio.h>
#include <inttypes.h>

int main(void) {
    uint64_t rip;
   asm volatile("1: lea 1b(%%rip), %0;": "=a"(rip));
    printf("%" PRIx64 "; %" PRIu64 " bytes from main start\n",
           rip, rip - (uint64_t)main);
}
Run Code Online (Sandbox Code Playgroud)

然后

% gcc -m64 rip.c -o rip; ./rip
55b7bf9e8659; 8 bytes from start of main
Run Code Online (Sandbox Code Playgroud)

证明它是正确的:

% gdb -batch -ex 'file ./rip' -ex 'disassemble main'
Dump of assembler code for function main:
   0x000000000000064a <+0>:     push   %rbp
   0x000000000000064b <+1>:     mov    %rsp,%rbp
   0x000000000000064e <+4>:     sub    $0x10,%rsp
   0x0000000000000652 <+8>:     lea    -0x7(%rip),%rax        # 0x652 <main+8>
Run Code Online (Sandbox Code Playgroud)

对于32位代码,似乎可以使用lea标签 - 但这对64位代码不起作用.

#include <stdio.h>
#include <inttypes.h>

int main(void) {
    uint32_t eip;
    asm volatile("1: lea 1b, %0;": "=a"(eip));
    printf("%" PRIx32 "; %" PRIu32 " bytes from main start\n",
           eip, eip - (uint32_t)main);
}
Run Code Online (Sandbox Code Playgroud)

然后

% gcc -m32 eip.c -o eip; ./eip
5663754a; 29 bytes from main start
Run Code Online (Sandbox Code Playgroud)

证明它是正确的:

% gdb -batch -ex 'file ./eip' -ex 'disassemble main'  
Dump of assembler code for function main:
   0x0000052d <+0>:     lea    0x4(%esp),%ecx
   0x00000531 <+4>:     and    $0xfffffff0,%esp
   0x00000534 <+7>:     pushl  -0x4(%ecx)
   0x00000537 <+10>:    push   %ebp
   0x00000538 <+11>:    mov    %esp,%ebp
   0x0000053a <+13>:    push   %ebx
   0x0000053b <+14>:    push   %ecx
   0x0000053c <+15>:    sub    $0x10,%esp
   0x0000053f <+18>:    call   0x529 <__x86.get_pc_thunk.dx>
   0x00000544 <+23>:    add    $0x1a94,%edx
   0x0000054a <+29>:    lea    0x54a,%eax
Run Code Online (Sandbox Code Playgroud)

(在32位版本中有更多lea命令,但这一个是"在这里加载我的常量地址",然后在加载exe时由动态链接器更正).