这是我的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;
}我对ESP和EBP没有问题。
user@linux:~# ./memoryAddress
0xbffff650 <= $ESP
0xbffff654 d = B
0xbffff656 c = A
0xbffff658 b = 2
0xbffff65c a = 1
0xbffff668 <= $EBP
user@linux:~# 但是,当我尝试放置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:~#这个密码怎么了?
register int k asm("eip");
printf("%#010x <= $EIP\n", k);通过C程序可以打印出EIP值吗?
如果是,请让我知道怎么做。
更新
我在这里测试过密码..。
user@linux:~/c$ lscpu
Architecture: i686
CPU op-mode(s): 32-bit
Byte Order: Little Endian感谢@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) 这是新代码
#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;
}发布于 2018-05-22 16:51:36
请首先阅读QA 直接读取程序计数器 -从这里我们可以看到没有mov命令可以直接访问EIP/RIP,因此您不能使用register asm来访问它。相反,在任何时候你都可以使用这些技巧。在64位模式下最简单,请使用
uint64_t rip;
asm volatile("1: lea 1b(%%rip), %0;": "=a"(rip));要获得64位指令(感谢Michael指出标签在这里适用于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);
}然后
% gcc -m64 rip.c -o rip; ./rip
55b7bf9e8659; 8 bytes from start of main证明它是正确的:
% 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>对于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);
}然后
% gcc -m32 eip.c -o eip; ./eip
5663754a; 29 bytes from main start证明它是正确的:
% 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(在32位版本中还有更多的lea命令,但这个命令是“在这里加载我的常量地址”,然后动态链接器将在加载exe时进行更正)。
发布于 2018-05-22 17:46:08
如果你有兴趣的话,你可以用另一个小黑客来阅读rip。这里是您的完整代码,它也读取rip:
#include <stdio.h>
#include <inttypes.h>
int main()
{
register uint64_t i asm("rsp");
printf("%" PRIx64 " <= $RSP\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 uint64_t j asm("rbp");
printf("%" PRIx64 " <= $RBP\n", j);
uint64_t rip = 0;
asm volatile ("call here2\n\t"
"here2:\n\t"
"pop %0"
: "=m" (rip));
printf("%" PRIx64 " <= $RIP\n", rip);
return 0;
}这里的黑客很有趣。你只是call下一条装配线。现在,因为返回地址是堆栈中的rip,所以可以通过堆栈中的pop指令检索它。:)
更新:
这种方法的主要原因是数据注入。见以下代码:
#include <stdio.h>
#include <inttypes.h>
int main()
{
uint64_t rip = 0;
asm volatile ("call here2\n\t"
".byte 0x41\n\t" // A
".byte 0x42\n\t" // B
".byte 0x43\n\t" // C
".byte 0x0\n\t" // \0
"here2:\n\t"
"pop %0"
: "=m" (rip));
printf("%" PRIx64 " <= $RIP\n", rip);
printf("injected data:%s\n", (char*)rip);
return 0;
}这种方法可以在代码段中注入数据(这对于代码注入是有用的)。如果编译和运行,您将看到以下输出:
400542 <= $RIP
injected data:ABC您已经使用rip作为数据的占位符。我个人喜欢这种方法,但正如评论中提到的那样,它可能会对效率产生影响。
我在64位(Linux子系统用于Windows)中测试了这两种代码,这两种代码都能工作。
更新2:
如果您需要使用此代码而不存在红色区域问题,请确保阅读有关红区的注释,您需要按以下方式编写它(来自micheal的示例):
asm volatile ("sub $128, %%rsp\n\t"
"call 1f\n\t"
".byte 0x41\n\t" // A
".byte 0x42\n\t" // B
".byte 0x43\n\t" // C
".byte 0x0\n\t" // \0
"1:\n\t"
"pop %0\n\t"
"add $128, %%rsp"
: "=r" (rip));https://stackoverflow.com/questions/50471237
复制相似问题