简体   繁体   English

使用CreateProcess执行rundll32.exe

[英]Executing rundll32.exe with CreateProcess

I've created a DLL and would like to execute one of the functions using the rundll32.exe command on windows. 我创建了一个DLL,并希望在Windows上使用rundll32.exe命令执行其中一个功能。

Using rundll32.exe, it runs correctly from the command line; 使用rundll32.exe,它可以从命令行正确运行; however, I'd like to call it (rundll32.exe) from a separate program. 但是,我想从一个单独的程序中调用它(rundll32.exe)。 I cannot directly call the function from my code due to 32/64 bit compatibility issues in the underlying libraries I'm using (Easyhook). 由于我正在使用的基础库(Easyhook)中存在32/64位兼容性问题,因此我无法直接从代码中调用该函数。

Below is what I'm using in an attempt to run the dll function: 下面是我在尝试运行dll函数时使用的:

STARTUPINFO si;
PROCESS_INFORMATION pi;

ZeroMemory( &si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi));

LPCTSTR application = "C:\\Windows\\system32\\rundll32.exe";
LPTSTR cmd = "C:\\Projects\\Test\\mydll.dll,MyFunc";

BOOL cpRes = CreateProcess(application,
  cmd,
  NULL,
  NULL,
  FALSE,
  0,
  NULL,
  NULL,
  &si,
  &pi);

if(cpRes == 0) {
  cout << "ERROR\n";
  cout << GetLastError() << endl;
} else {
  cout << "DLL Launched!" << endl;
}

CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);

The output to my console is always DLL Launched ; 我的控制台的输出始终是DLL Launched however, I do not see the effects of my DLL actually being called (currently stubbed out in such a way that the command writes to a file). 但是,我看不到实际调用DLL的效果(当前以命令写入文件的方式进行存根处理)。

If I swap out the application with something such as C:\\\\Windows\\\\system32\\\\notepad.exe , the program successfully runs. 如果我用诸如C:\\\\Windows\\\\system32\\\\notepad.exe东西替换应用程序,则该程序将成功运行。

For completion, here's the body of MyFunc : 为了完成,这是MyFunc的主体:

ofstream file;
file.open("C:\\Projects\\Test\\test.txt");
file << "I wrote to a file!";
file.close();

Is there any reason CreateProcess cannot be used with rundll32? 有什么原因不能将RunProcess32与CreateProcess一起使用? While reading over this I found several warnings about LoadLibrary() and DLLMain but it doesn't seem like they're relevant to this. 在阅读此内容时,我发现了一些有关LoadLibrary()DLLMain警告,但似乎它们与此无关。


More Clarification: 更多说明:
This is currently a 32-bit application (allegedly) launching the 32-bit rundll32.exe (Logic will be added later to call the 32 or 64 bit version). 当前,这是一个32位应用程序(据说)正在启动32位rundll32.exe (稍后将添加逻辑以调用32或64位版本)。

My dll is as follows: 我的dll如下:

extern "C" __declspec(dllexport) void CALLBACK MyFunc(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow);

void CALLBACK MyFunc(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) { ... }

Which also has a .def file with: 其中也有一个.def文件,其中包含:

EXPORTS
  MyFunc

Running 运行

C:\Windows\system32\rundll32.exe C:\Projects\Test\mydll.dll,MyFunc 

produces the expected results. 产生预期的结果。


Update 更新
Setting application to NULL and including the rundll32.exe in cmd as mentioned in the comments seems to work. 如注释中所述,将application设置为NULL并在cmd中包含rundll32.exe似乎可行。

Relevant Docs: 相关文件:
CreateProcess CreateProcess的
RunDll32.exe RUNDLL32.EXE

Per the CreateProcess() documentation: 根据CreateProcess()文档:

If both lpApplicationName and lpCommandLine are non-NULL, the null-terminated string pointed to by lpApplicationName specifies the module to execute, and the null-terminated string pointed to by lpCommandLine specifies the command line. 如果lpApplicationNamelpCommandLine均为非NULL,则lpApplicationName指向的以Null终止的字符串指定要执行的模块,而lpCommandLine指向的以Null终止的字符串lpCommandLine指定命令行。 The new process can use GetCommandLine to retrieve the entire command line. 新进程可以使用GetCommandLine检索整个命令行。 Console processes written in C can use the argc and argv arguments to parse the command line. 用C编写的控制台进程可以使用argcargv参数来解析命令行。 Because argv[0] is the module name, C programmers generally repeat the module name as the first token in the command line . 由于argv[0]是模块名称,因此C程序员通常将模块名称作为命令行中的第一个标记重复

You are not repeating rundll32.exe as the first command-line token. 您没有将rundll32.exe作为第一个命令行标记重复。

So, if you continue using the lpApplicationName parameter, then change this: 因此,如果继续使用lpApplicationName参数,请更改此参数:

LPCTSTR application = "C:\\Windows\\system32\\rundll32.exe";
LPTSTR cmd = "C:\\Projects\\Test\\mydll.dll,MyFunc";

To this instead: 为此:

LPCTSTR application = TEXT("C:\\Windows\\system32\\rundll32.exe");
LPTSTR cmd = TEXT("C:\\Windows\\system32\\rundll32.exe C:\\Projects\\Test\\mydll.dll,MyFunc");

Note that you are currently compiling for ANSI/MBCS (by virtue of the fact that you are passing narrow strings to CreateProcess() ). 请注意,您当前正在针对ANSI / MBCS进行编译(因为您正在将狭窄的字符串传递给CreateProcess() )。 If you ever update the project to compile for Unicode, use this instead: 如果您曾经更新过项目以针对Unicode进行编译,请改用以下代码:

TCHAR cmd[] = TEXT("C:\\Windows\\system32\\rundll32.exe C:\\Projects\\Test\\mydll.dll,MyFunc");

This is because the documentation states: 这是因为文档指出:

lpCommandLine [in, out, optional] lpCommandLine [输入,输出,可选]
... ...
The Unicode version of this function, CreateProcessW , can modify the contents of this string. 此函数的Unicode版本CreateProcessW可以修改此字符串的内容。 Therefore, this parameter cannot be a pointer to read-only memory (such as a const variable or a literal string). 因此,该参数不能是指向只读存储器的指针 (例如const变量或文字字符串)。 If this parameter is a constant string, the function may cause an access violation. 如果此参数是常量字符串,则该函数可能会导致访问冲突。

You might consider changing cmd into a TCHAR[] array anyway, even in ANSI/MBCS, so you can do something like this: 您可能仍然考虑将cmd更改为TCHAR[]数组,即使在ANSI / MBCS中也是如此,因此您可以执行以下操作:

LPCTSTR application = TEXT("C:\\Windows\\system32\\rundll32.exe");

TCHAR cmd[(MAX_PATH*2)+10];
wsprintf(cmd, TEXT("%s %s,%s"), application, TEXT("C:\\Projects\\Test\\mydll.dll"), TEXT("MyFunc"));

Either way, by passing the module filename as the first token in the lpCommandLine parameter, you can then set the lpApplicationName parameter to NULL: 无论哪种方式,都可以通过将模块文件名作为第一个令牌传递给lpCommandLine参数,然后将lpApplicationName参数设置为NULL:

The lpApplicationName parameter can be NULL. lpApplicationName参数可以为NULL。 In that case, the module name must be the first white space–delimited token in the lpCommandLine string. 在这种情况下,模块名称必须是lpCommandLine字符串中第一个由空格分隔的标记。

Let CreateProcess() setup the correct command-line to pass to rundll32.exe for you: CreateProcess()设置正确的命令行为您传递给rundll32.exe

TCHAR cmd[] = TEXT("C:\\Windows\\system32\\rundll32.exe C:\\Projects\\Test\\mydll.dll,MyFunc");

BOOL cpRes = CreateProcess(NULL, cmd, ...);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM