为什么允许我使用ret退出main?

问题描述 投票:0回答:2

我将弄清楚如何正确设置程序堆栈。我知道使用[]调用函数

call pointer;

实际上与:相同

mov register, pc ;programcounter
add register, 1 ; where 1 is one instruction not 1 byte ...
push register
jump pointer

但是,这意味着当Unix内核调用main函数时,堆栈库应该指向重新进入调用main的内核函数。

因此,在C代码中跳转“ * rbp-1”应重新输入主要功能。

但是,以下代码中不会发生这种情况:

#include <stdlib.h>
#include <unistd.h>

extern void ** rbp(); //pointer to stack pointing to function
int main() {
   void ** p = rbp();
   printf("Main: %p\n", main);
   printf("&Main: %p\n", &main); //WTF
   printf("*Main: %p\n", *main); //WTF
   printf("Stackbasepointer: %p\n", p);
   int (*c)(void) = (*p)-4;
   asm("movq %rax, 0");
   c();

   return 0;        //should never be executed...

}

汇编文件:rsp.asm

...

.intel_syntax

.text:

.global _rbp

_rbp:
  mov rax, rbp
  ret;

毫不奇怪,这是不允许的,也许是因为此时的指令不完全是64位,也许是因为UNIX不允许这样做...

但是

不允许此呼叫:
   void (*c)(void) = (*p);
   asm("movq %rax, 0"); //Exit code is 11, so now it should be 0
   c(); //this comes with stack corruption, when successful

这意味着我没有义务退出主调用函数。

然后我的问题是:为什么我在每个GCC主函数的末尾都使用ret时会使用ret?这应该与上面的代码有效地做同样的事情。 Unix-系统如何有效地检查此类尝试...我希望我的问题很清楚...

谢谢。附注:代码只能在macOS上编译,请更改Linux的程序集]

我将弄清楚如何正确设置程序堆栈。我了解到使用调用指针来调用函数;实际上与:mov register,pc; programcounter add ...

c security assembly
2个回答
0
投票

但是,这意味着当Unix内核调用main函数时,堆栈库应该指向重新进入调用main的内核函数。


0
投票

所以我认为您在这里有很多误解。首先,main不是内核调用的内容。内核分配一个进程并将二进制文件加载到内存中。如果使用的是基于UNIX的操作系统,则通常来自ELF文件。该ELF文件包含所有需要映射到内存中的部分,以及一个地址,该地址是ELF中代码的“入口点”(除其他外)。 ELF可以指定加载程序要跳转到的任何地址,以开始启动程序。在使用GCC构建的应用程序中,这是一个名为“ _start”的函数,“ _ start”然后设置堆栈并在调用“ main”之前执行其所需的任何其他初始化。

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