我想从可执行文件中调用一个函数。达到该过程的唯一方法是在父进程中注入一个dll。我可以在父进程中注入一个dll但是如何从子进程调用一个函数? 像
这样的东西_asm
{
call/jmp address
}
不起作用。我希望你明白我的意思。
答案 0 :(得分: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的基础,可以使用参数NULL调用GetModuleHandle。如果您确信函数偏移量不会改变,则可以在反汇编程序或其他工具中找到偏移量后,对要调用的函数的偏移量进行硬编码。假设包含函数的exe没有被改变,那么该偏移将是恒定的。
如评论中所述,调用约定在函数typedef中很重要,请确保它与您正在调用的函数的调用约定相匹配。
答案 1 :(得分:1)
要调用函数,您需要一个地址或一个中断号。地址被加载到程序计数器寄存器中并传输执行。某些处理器允许“软件中断”,其中程序执行调用软件中断的特殊指令。这是执行功能的基础。
有两种常见的可执行文件形式:绝对寻址和相对(或位置独立代码,PIC)。在绝对寻址中,功能位于硬编码地址。功能不会移动。通常用于嵌入式系统。
在相对寻址模型中,地址相对于程序计数器寄存器中的值。例如,您的函数可能是1024字节,因此编译器将发出1024字节(离开)的相对分支指令。
许多操作系统为每次调用在不同的地方加载程序。这意味着您的可执行文件可以从地址1000开始,下一次从地址127654开始。在这些操作系统中,无法保证每次都在同一位置启动可执行文件。
在程序中执行函数很容易。链接器决定所有函数的位置,并确定如何执行它们;是使用绝对寻址,PIC还是混合。
根据上述知识,在另一个程序中执行函数存在问题:
大多数可执行文件不包含有关其功能所在位置的任何信息,因此您需要知道它的位置。您还需要知道该函数是绝对寻址还是PIC。您还需要知道该功能是否在您需要时存储在内存中,或者操作系统是否已分页该功能到硬盘驱动器。
了解功能位置是必要的。但是,如果操作系统未加载可执行文件,则该位置无用。在另一个可执行文件中调用函数之前,执行调用时需要知道它是否存在于内存中。
最后,您需要知道用于外部功能的协议。例如,寄存器传递的值是多少?他们在堆栈上吗?它们是否通过指针(地址)传递?
操作系统(OS)已经发展到允许动态共享功能。这些函数存在于动态链接库(DLL)或共享库(.SO)中。您的程序告诉操作系统将库加载到内存中,然后通过为其提供函数名称来告诉操作系统执行该函数。
需要注意的是,您所需的功能必须位于库中。如果可执行文件不使用共享库,或者您需要的功能不在库中,那么您的任务就更难了。