我有第三方控制台应用程序。我需要从我的应用程序运行它,但我不能将它作为一个单独的进程运行(因为我需要使用它的依赖项:手动填充导入表,设置挂钩等)。所以我可能应该手动调用此可执行文件的main
函数。以下是我尝试这样做的方法:
auto hMod = LoadLibrary("console_app.exe")
我坚持到最后一步。
以下是我试图调用入口点的方法:
void runMain(HINSTANCE hInst)
{
typedef BOOL(WINAPI *PfnMain)(int, char*[]);
auto imageNtHeaders = ImageNtHeader(hInst);
auto pfnMain = (PfnMain)(DWORD_PTR)(imageNtHeaders->OptionalHeader.AddressOfEntryPoint + (DWORD_PTR)hInst);
char* args[] = { R"(<console_app_path>)", R"(arg1)", R"(arg2)" };
pfnMain(3, args);
}
有效。但它的工作方式就像没有参数一样。
我哪里错了?如何使用参数在我的进程中运行 可执行文件?感谢。
我已经调查了我的特定第三方exe 如何获取cmd参数并发现:
答案 0 :(得分:11)
您正在调用应用程序的入口点,而不是int main(int, char**)
。现在您可能已经读过C ++程序的入口点是int main(int, char**)
但这只是一个C ++透视图。
Win32视角不同;入口点是int (*)(void);
。 Visual Studio链接器查找int mainCRTStartup(void);
并使用它,除非您使用/ENTRY
指定另一个入口点。在调用mainCRTStartup
之前,GetCommandLine()
的默认实现会调用argv[]
来填充main(argc,argv)
。您可能希望在mainCRTStartup
中发生其他事情:运行全局ctors,初始化CRT状态,......
当然,假设其他程序是使用Visual C ++编译的,但无论编写什么语言,都必须调用GetCommandLine
。
现在,对于您的问题,这是一个有趣的观察:GetCommandLine()
返回可写指针。您可以覆盖现有的命令行。当然,如果你控制导入表,则决定GetCommandLine
的含义。 (请记住,像往常一样有A和W变体)。
一个警告:MSVCRT不是设计为初始化两次,既不是静态版本也不是DLL版本。所以实际上你不能使用它,这会伤害你。
<强> [编辑] 强>
您的更新会显示对_initterm
的来电。这是一个MSVCRT功能,正如我已经暗示过的那样。具体地,
/***
*crtexe.c - Initialization for console EXE using CRT DLL
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
...
/*
* routine in DLL to do initialization (in this case, C++ constructors)
*/
extern int __cdecl _initterm_e(_PIFV *, _PIFV *);
extern void __cdecl _initterm(_PVFV *, _PVFV *);
MSVCRT DLL代表EXE调用GetCommandLine()
。
答案 1 :(得分:2)
可执行文件(EP
)的入口点没有参数 - 因此您无法使用参数直接调用它。
通常的应用程序通过解析命令行获得参数。 [w]mainCRTStartup
执行此操作 - 如果您将控制台应用程序链接到c / c ++运行时 - 这是真实的EP
。
所以如果你Fill Import table of this exe manually
- 为GetCommandLineA
和GetCommandLineW
函数设置例外 - 将其重定向到自我实现并返回自定义命令行。
但如果应用非静态关联CRT
,则可以导入__getmainargs
或__wgetmainargs
甚至_acmdln
或_wcmdln
来自msvcrt.dll
- 所以任务已经变得复杂了。
并假设relocs退出EXE
,如果存在,则不处理TLS
,不处理应用程序清单,可能的dl重定向等。
但我无法将其作为单独的流程运行
这不是真的。您可以而且必须将其作为单独的流程运行 - 这是最佳解决方案。
使用CREATE_SUSPENDED
标记CreateProcess
执行您的应用。在这里,您可以轻松设置您需要的任何CommandLine。您不需要手动而不是完全正确加载EXE
,但系统会为您执行此任务。
创建流程后,您需要使用QueueUserAPC
(但不是DLL
!!)向自己注入CreateRemoteThread
,最后调用ResumeThread
结果,您的DLL
将在应用EXE
之前的第一个EP
主题中加载并执行 - 此处您可以执行所有必需的任务