使用CreateProcess执行rundll32.exe

问题描述:

我已经创建了一个DLL,并希望在Windows上使用rundll32.exe命令执行其中一个函数。使用CreateProcess执行rundll32.exe

使用rundll32.exe,它从命令行正确运行;不过,我想从一个单独的程序中调用它(rundll32.exe)。由于我使用的基础库(Easyhook)中的32/64位兼容性问题,我无法直接从我的代码中调用该函数。

下面是我使用的尝试运行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); 

输出到我的控制台总是DLL Launched;然而,我没有看到我的DLL实际被调用的效果(当前以命令写入文件的方式被删除)。

如果我用诸如C:\\Windows\\system32\\notepad.exe之类的东西换出应用程序,程序将成功运行。

完成,这里有MyFunc身体:

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

没有任何理由的CreateProcess不能与RUNDLL32使用?在阅读本文时,我发现了几条关于LoadLibrary()DLLMain的警告,但它不是似乎就像它们与此相关。


更多的澄清:
这是当前的32位应用程序(可能)启动32位rundll32.exe(逻辑将在后面加入到调用32或64位版本)。

我的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) { ... } 

其中也有.def文件有:

EXPORTS 
    MyFunc 

运行

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

产生预期的结果。


更新
设置applicationNULL,并包括在cmd中的rundll32.exe在评论中提到似乎工作。

相关的文档:
CreateProcess
RunDll32.exe

+0

什么是COUT的'输出

+0

@NaseefUrRahman输出为[0](https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v = vs.85).aspx)。 – user5786682

+0

您试图从DLL调用的函数的确切签名是什么? –

CreateProcess()文档:

如果同时lpApplicationNamelpCommandLine非空,空结束的字符串由lpApplicationName指出,指定模块以执行,并由lpCommandLine指向的以空字符结尾的字符串指定命令行。新进程可以使用​​来检索整个命令行。用C编写的控制台进程可以使用参数argcargv来解析命令行。 由于argv[0]是模块名称,因此C程序员通常会重复模块名称作为命令行中的第一个标记。

您不重复rundll32.exe作为第一个命令行令牌。

所以,如果你继续使用lpApplicationName参数,然后更改此:

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

为了这个:

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

请注意,您目前正在编制的ANSI/MBCS(凭借您将窄字符串传递给CreateProcess())。如果你更新项目编制对Unicode,而不是使用:

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

这是因为该文件指出:

lpCommandLine [IN,OUT,可选]
...
此函数的Unicode版本CreateProcessW可以修改此字符串的内容。 因此,此参数不能是指向只读存储器(例如常量变量或文字字符串)的指针。如果此参数是一个常量字符串,则该函数可能会导致访问冲突。

你可能会考虑改变cmdTCHAR[]阵列无论如何,即使是在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")); 

无论哪种方式,通过将模块文件名作为第一个标记在lpCommandLine参数,则可以将lpApplicationName参数设置为NULL:

lpApplicationName参数可以为NULL。在这种情况下,模块名称必须是lpCommandLine字符串中第一个以空格分隔的令牌。

CreateProcess()设置正确的命令行传递给rundll32.exe你:

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

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

如果我们使用* lpApplicationName *(!= 0),我们可以添加* any *令牌给* lpCommandLine *。不是强制的完整路径。甚至没有名字。任何字符串(没有空格是好的)。所以说'@ C:\\ Projects \\ Test \\ mydll.dll,MyFunc'也可以。如果我们有*正是* * * lpApplicationName总是更好地利用它传递给'CreateProcess' – RbMm

+1

好答案整体,但如果你打算使用'TCHAR CMD建议[] = ...',那么你也应该使用'TCHAR cmd [] = TEXT(“C:\\ Windows .... \\ mydll.dll,MyFunc”);'。另一种方法是明确使用'WCHAR'和'L'前缀。 –

+0

@RbMm按照惯例,'argv [0]'应该是调用进程的完整路径。当然,你可以单独传递模块名称,但是你会打破任何需要完整路径的控制台应用程序。也许'rundll32'没有。不要冒险。 –