【问题标题】:Calling a function through its address in memory in c / c++在c / c ++中通过其在内存中的地址调用函数
【发布时间】:2012-02-13 12:09:33
【问题描述】:

如果知道函数的原型及其在内存中的地址,是否可以从另一个进程或只知道原型和内存地址的某些代码中调用此函数?如果可能,如何在代码中处理返回的类型?

【问题讨论】:

  • 在 C++ 中没有进程。如果您需要帮助,您需要指定您的平台。
  • 来自另一个进程?这是一个非常特殊的情况。你真的需要那个吗?
  • @ddriver - 听起来您想研究进程间通信,而不是函数指针。除非您尝试编写调试器,否则您将面临很多障碍。
  • @ddriver 如果您正在谈论从不同的进程调用,您确实需要指定平台。在大多数现代操作系统中,一个进程拥有的内存不能被另一个进程任意读取或写入。如果两个进程想要共享一个内存区域,它们必须明确设置。这通常是一件好事,因为它可以防止一个进程中的错误指针或其他错误影响其他进程,甚至整个操作系统。
  • @Caleb:你想解决什么问题?一般来说,进程如何交互存在很多限制,并且从其他进程调用原始函数非常难以安全可靠地完成。试着退后一步,向我们解释最终目标是什么,因为听起来你现在走错了路

标签: c++ c function-call memory-address


【解决方案1】:

在现代操作系统上,每个进程都有自己的地址空间,并且地址仅在进程内有效。如果您想在其他进程中执行代码,则必须注入共享库将您的程序附加为调试器

一旦您进入其他程序的地址空间,此代码在任意地址调用函数

typedef int func(void);
func* f = (func*)0xdeadbeef;
int i = f();

【讨论】:

  • 感谢@R.Martinho 提供better style to typedef function prototypes。我什至不知道这个作品!
  • AFAIK,没有办法在新操作系统的其他程序地址空间中写入内存,这会导致 SEGFAULT。但是没有什么可以阻止程序读取任何内存位置(因此,OpenSSL 中的心脏出血错误很可怕,因为您可以使用它读取内存中的任何内容)。那么,您能否解释一下为什么我无法访问其他程序的地址空间并需要共享库或调试器?
  • @TheQuantumPhysicist:因为每个进程都有自己的虚拟内存空间。你的过程'0xdeadbeef 是你的,我的过程'是我的。它们位于物理内存的不同地址。
  • @abi 仅当计算机具有 MMU 时。如果没有操作系统,计算机甚至可能没有进程......
【解决方案2】:

是的 - 你正在描述一个函数指针。这是一个简单的例子;

int (*func)(void) = (int (*)(void))0x12345678;
int x = func();

它可能无法在进程之间工作 - 在大多数操作系统中,进程无法访问彼此的内存。

【讨论】:

  • 为什么要转换为 void ()(void) 来分配一个 int()(void) ?这很不合逻辑不是吗?
【解决方案3】:

当您需要直接呼叫时:

((void(*)(void))0x1234)();

【讨论】:

    【解决方案4】:

    以前的所有答案都很好,但太长了:

    int i = ((int (*)(void))0xdeadbeef)();
    //                      ==========     --> addr of the function to call
    //        =============                --> type of the function to call
    //       =========================     --> ... we get a ptr to that fct
    //      =============================  --> ... and we call the function
    

    【讨论】:

    • 不,他们很棒。另一方面,你的情况很差。完全没有解释。
    【解决方案5】:

    在大多数 OP 中,每个进程都有自己的内存,所以你不能。

    示例代码: 交流:

    #include <stdio.h>
    
    int r() {return 2;}
    int main() {
        printf("%p\n",r);
        while(1);
    }
    

    b.c:

    #include <stdio.h>
    
    int main() {
    int a,(*b)();
    scanf("%p",&b);
    a=b();
    printf("%d\n",a);
    return 0;
    }
    

    这会导致分段错误。

    【讨论】:

    • 在 c c++ 中,你可以访问任何你想要的内存位置,无论好坏
    • @ddriver:C++ 允许您访问任何虚拟内存位置。但是,许多操作系统为每个进程提供了自己的虚拟内存,因此它们不会相互影响。不过,您可以进行/使用特定于操作系统的调用来影响另一个进程的内存。
    • @ddriver - 不,你不能。您只能访问操作系统允许您访问的内存位置。你的程序只知道它运行的虚拟内存环境,它通常与物理现实几乎没有关系。
    【解决方案6】:

    这绝对是可能的,但有一些限制。每个进程都有自己的内存块,其他进程无法干扰。现在,你会注意到,我写的肯定是有可能的,这是通过 DLL 注入(或代码注入)。

    我们可以使用 typedef 关键字来实现这一点。现在,我看到您已将答案标记为“已回答”,而且您似乎一切顺利,这只是给可能感兴趣的任何人的通知。

    【讨论】:

    • 这取决于你的操作系统——如果你有的话。有些计算机没有硬件 MMU,因此没有内存屏障 - 因此即使有操作系统,进程也可以写入彼此的内存。
    猜你喜欢
    • 2019-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-25
    • 1970-01-01
    • 1970-01-01
    • 2020-12-03
    • 2020-10-01
    相关资源
    最近更新 更多