C++ 从可执行文件调用函数
我想从可执行文件调用函数。到达该进程的唯一方法是在父进程中插入dll。我可以在父进程中插入dll,但如何从子进程调用函数? 差不多C++ 从可执行文件调用函数,c++,assembly,code-injection,C++,Assembly,Code Injection,我想从可执行文件调用函数。到达该进程的唯一方法是在父进程中插入dll。我可以在父进程中插入dll,但如何从子进程调用函数? 差不多 _asm { call/jmp address } 不起作用。我希望你明白我的意思。执行基础 要调用函数,您需要一个地址或中断号。地址被加载到程序计数器寄存器中,执行被转移。一些处理器允许软件中断,其中程序执行调用软件中断的特殊指令。这是执行函数的基础。 更多背景相对地址 可执行文件有两种常见形式:绝对寻址和相对或位置无关代码PIC。在绝对寻址中,函数位于硬编码
_asm
{
call/jmp address
}
不起作用。我希望你明白我的意思。执行基础
要调用函数,您需要一个地址或中断号。地址被加载到程序计数器寄存器中,执行被转移。一些处理器允许软件中断,其中程序执行调用软件中断的特殊指令。这是执行函数的基础。
更多背景相对地址
可执行文件有两种常见形式:绝对寻址和相对或位置无关代码PIC。在绝对寻址中,函数位于硬编码地址。这些函数不会移动。通常用于嵌入式系统
在相对寻址模型中,地址与程序计数器寄存器中的值相对。例如,您的函数可能有1024字节远,因此编译器将发出1024字节远的相对分支指令
操作系统和移动目标
许多操作系统在每次调用的不同位置加载程序。这意味着您的可执行文件可能从地址1000开始,下一次从地址127654开始。在这些操作系统中,无法保证每次在同一位置启动可执行文件
在程序中执行
在程序中执行函数很容易。链接器决定所有函数的位置并决定如何执行它们;使用绝对寻址、PIC还是混合寻址
在另一个可执行文件中执行函数
根据上述知识,在另一个程序中执行函数存在问题:
函数在外部可执行文件中的位置
确定可执行文件是否处于活动状态
可执行文件的调用协议
大多数可执行文件不包含有关其函数位置的任何信息,因此您需要知道函数位置。您还需要知道函数是绝对寻址还是PIC。您还需要知道,当您需要该功能时,该功能是否在内存中,或者操作系统是否已将该功能分页到硬盘驱动器
了解功能位置是必要的。但是,如果操作系统没有加载可执行文件,则该位置没有任何用处。在调用另一个可执行文件中的函数之前,需要知道在执行调用时该函数是否存在于内存中
最后,您需要了解用于外部功能的协议。例如,值是通过寄存器传递的吗?它们在堆栈上吗?它们是通过指针地址传递的吗
解决方案:共享库
操作系统OS已经发展到允许动态共享功能。这些函数存在于动态链接库DLL或共享库.SO中。您的程序告诉操作系统将库加载到内存中,然后您通过给它函数名来告诉操作系统执行函数
需要注意的是,您想要的函数必须在库中。如果可执行文件不使用共享库,或者您需要的函数不在库中,那么您的任务将更加困难 执行基础
要调用函数,您需要一个地址或中断号。地址被加载到程序计数器寄存器中,执行被转移。一些处理器允许软件中断,其中程序执行调用软件中断的特殊指令。这是执行函数的基础。
更多背景相对地址
可执行文件有两种常见形式:绝对寻址和相对或位置无关代码PIC。在绝对寻址中,函数位于硬编码地址。这些函数不会移动。通常用于嵌入式系统
在相对寻址模型中,地址与程序计数器寄存器中的值相对。例如,您的函数可能有1024字节远,因此编译器将发出1024字节远的相对分支指令
操作系统和移动目标
许多操作系统在每次调用的不同位置加载程序。这意味着您的可执行文件可能从地址1000开始,下一次从地址127654开始。在这些操作系统中,无法保证每次在同一位置启动可执行文件
在程序中执行
在程序中执行函数很容易。链接器决定所有函数的位置并决定如何执行它们;使用绝对寻址、PIC还是混合寻址
在另一个可执行文件中执行函数
根据上述知识,在另一个程序中执行函数存在问题:
地方
外部可执行文件中函数的
确定可执行文件是否处于活动状态
可执行文件的调用协议
大多数可执行文件不包含有关其函数位置的任何信息,因此您需要知道函数位置。您还需要知道函数是绝对寻址还是PIC。您还需要知道,当您需要该功能时,该功能是否在内存中,或者操作系统是否已将该功能分页到硬盘驱动器
了解功能位置是必要的。但是,如果操作系统没有加载可执行文件,则该位置没有任何用处。在调用另一个可执行文件中的函数之前,需要知道在执行调用时该函数是否存在于内存中
最后,您需要了解用于外部功能的协议。例如,值是通过寄存器传递的吗?它们在堆栈上吗?它们是通过指针地址传递的吗
解决方案:共享库
操作系统OS已经发展到允许动态共享功能。这些函数存在于动态链接库DLL或共享库.SO中。您的程序告诉操作系统将库加载到内存中,然后您通过给它函数名来告诉操作系统执行函数
需要注意的是,您想要的函数必须在库中。如果可执行文件不使用共享库,或者您需要的函数不在库中,那么您的任务将更加困难 如果在进程内部运行,则需要知道要调用的函数从包含该函数的模块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中很重要,请确保它与正在调用的函数的调用约定相匹配。如果在进程内部运行,则需要知道要调用的函数相对于包含该函数的模块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中很重要,请确保它与正在调用的函数的调用约定相匹配。您应该在指针定义中指定函数调用约定。否则,具有不正确约定的函数调用将损坏堆栈并导致程序终止。应在指针定义中指定函数调用约定。否则,使用不正确约定的函数调用将损坏堆栈并导致程序终止。