从可执行文件中调用函数

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

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

_asm
{ 
call/jmp address
}

不工作。我希望你能理解我的意思。

c++ assembly code-injection
2个回答
3
投票

如果你在进程内部运行,你需要知道你要调用的函数从包含该函数的模块(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的基础,你可以调用GetModuleHandle,参数为NULL。 如果你确信函数的偏移量不会改变,你可以在反汇编器或其他工具中找到偏移量后,硬编码你想调用的函数的偏移量。 假设包含函数的exe没有被改变,那么这个偏移量将是不变的。

正如注释中提到的,函数typedef中的调用约定很重要,确保它与你要调用的函数的调用约定一致。


1
投票

执行基础知识

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

更多背景知识 -- 相对地址

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

在相对寻址模型中,地址与程序计数器寄存器中的值相对。 例如,你的函数可能在1024字节之外,所以编译器会发出一个相对的分支指令,地址为1024字节(远离)。

操作系统和移动目标

许多操作系统在每次调用时,都会在不同的地方加载程序,这意味着你的可执行文件可能在地址1000处启动,而下一次在地址127654处启动。 这意味着你的可执行文件可能从地址1000开始,而下一次则从地址127654开始。 在这些操作系统中。不能保证每次都能在同一地点启动可执行程序.

在您的程序中执行

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

在另一个可执行程序中执行函数

有了上述知识,在另一个程序中执行函数就会出现问题。

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

大多数可执行文件不包含任何关于其函数位置的信息,所以你需要知道它在哪里。 你还需要知道该函数是绝对寻址还是PIC。 你还需要知道当你需要它时,该函数是否在内存中,或者操作系统是否有 页状 的功能到硬盘上。

知道函数的位置是必要的。 但是,如果操作系统没有加载可执行文件,那么这个位置就没有用了。 在你调用另一个可执行文件中的函数之前,你需要知道当调用被执行时,它是否存在于内存中。

最后,你需要知道外部函数使用的协议。 例如,值是通过寄存器传递的吗? 它们是在堆栈上吗? 它们是通过指针(地址)传递的吗?

一个解决方案。共享库

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

需要注意的是,你想要的函数必须在一个库中。 如果可执行文件没有使用共享库,或者你需要的函数不在库中,那么你的任务就比较困难。

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