【问题标题】:Call function from executable从可执行文件调用函数
【发布时间】:2020-06-03 03:28:45
【问题描述】:

我想从可执行文件中调用一个函数。到达该进程的唯一方法是在父进程中注入一个 dll。我可以在父进程中注入 dll,但如何从子进程中调用函数? 类似的东西

_asm
{ 
call/jmp address
}

不起作用。我希望你明白我的意思。

【问题讨论】:

    标签: c++ assembly code-injection


    【解决方案1】:

    如果你在进程内部运行,你需要知道你想调用的函数相对于包含函数的模块(exe)的偏移量。然后,你只需要制作一个函数指针并调用它。

    // assuming the function you're calling returns void and takes 0 params
    typedef void(__stdcall * voidf_t)();
    
    // make sure func_offset is the offset of the function when the module is loaded
    voidf_t func = (voidf_t) (((uint8_t *)GetModuleHandle('module_name')) + func_offset);
    func(); // the function you located is called here
    

    如果您知道函数的地址,您的解决方案将适用于 32 位系统(64 位不允许内联汇编),但您需要确保正确实现调用约定。上面的代码使用 GetModuleHandle 来解析你要调用其函数的模块的当前加载基数。

    一旦你将你的模块注入到正在运行的进程中,ASLR 就不是问题了,因为你可以向 windows 询问包含你希望调用的代码的模块的基础。如果要查找运行当前进程的exe的base,可以调用GetModuleHandle,参数为NULL。如果您确信函数偏移量不会改变,您可以在反汇编程序或其他工具中找到偏移量后,对要调用的函数的偏移量进行硬编码。假设包含该函数的 exe 未更改,则该偏移量将是恒定的。

    如 cmets 中所述,调用约定在函数 typedef 中很重要,请确保它与您正在调用的函数的调用约定相匹配。

    【讨论】:

    • 您应该在指针定义中指定函数调用约定。否则约定不正确的函数调用会破坏堆栈并导致程序终止。
    【解决方案2】:

    执行基础

    要调用一个函数,你需要一个地址或一个中断号。该地址被加载到程序计数器寄存器中并转移执行。一些处理器允许“软件中断”,其中程序执行调用软件中断的特殊指令。这是执行功能的基础。

    更多背景——相对地址

    可执行文件有两种常见形式:绝对寻址和相对(或位置无关代码,PIC)。在绝对寻址中,函数位于硬编码地址。函数不会移动。通常用于嵌入式系统。

    在相对寻址模型中,地址与程序计数器寄存器中的值相关。例如,您的函数可能在 1024 字节之外,因此编译器会发出 1024 字节(距离)的相对分支指令。

    操作系统和移动目标

    许多操作系统在每次调用时将程序加载到不同的位置。这意味着您的可执行文件可能从地址 1000 开始,下一次从地址 127654 开始。在这些操作系统中,无法保证每次都在同一位置启动可执行文件

    在您的程序中执行

    在程序中执行函数很容易。链接器决定所有函数的位置并确定如何执行它们;是否使用绝对寻址、PIC 或混合寻址。

    在另一个可执行文件中执行函数

    有了以上知识,在另一个程序中执行函数存在问题:

    • 函数在外部可执行文件中的位置
    • 确定可执行文件是否处于活动状态
    • 可执行文件的调用协议

    大多数可执行文件不包含有关其功能所在位置的任何信息,因此您需要知道它在哪里。您还需要知道该功能是绝对寻址还是 PIC。您还需要知道该函数是否在您需要时在内存中,或者操作系统是否已将该函数 分页 到硬盘驱动器。

    了解函数位置是必要的。但是,如果操作系统尚未加载可执行文件,则该位置将毫无用处。在调用另一个可执行文件中的函数之前,您需要知道调用执行时它是否存在于内存中。

    最后,您需要了解用于外部函数的协议。例如,值是否通过寄存器传递?他们在堆栈上吗?它们是通过指针(地址)传递的吗?

    解决方案:共享库

    操作系统 (OS) 已经发展到允许动态共享功能。这些函数存在于动态链接库 (DLL) 或共享库 (.SO) 中。你的程序告诉操作系统将库加载到内存中,然后你告诉操作系统通过给它函数的名称来执行函数。

    需要注意的是,您需要的功能必须在库中。如果可执行文件不使用共享库或者您需要的功能不在库中,那么您的任务就比较困难。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-10-21
      • 1970-01-01
      • 2019-01-23
      • 1970-01-01
      • 1970-01-01
      • 2023-02-07
      • 1970-01-01
      • 2020-11-25
      相关资源
      最近更新 更多