从可执行文件调用函数

Call function from executable

本文关键字:函数 调用 可执行文件      更新时间:2023-10-16

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

_asm
{ 
call/jmp address
}

不行。我希望你明白我的意思。

如果你在进程内运行,你需要知道要从包含函数的模块(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 的基,可以使用参数 NULL 调用 GetModuleHandle。 如果您确信函数偏移量不会更改,则可以在反汇编器或其他工具中找到偏移量后,对要调用的函数的偏移量进行硬编码。 假设包含函数的 exe 未更改,则该偏移量将是恒定的。

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

执行基础

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

更多背景 -- 相对地址

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

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

操作系统和移动目标

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

在程序中执行

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

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

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

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

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

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

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

解决方案:共享库

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

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