0

我创建了一个 DLL,并希望在 Windows 上使用 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()在阅读本文时,我发现了几个关于and的警告,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包括rundll32.exein cmd 似乎有效。

相关文档:
CreateProcess
RunDll32.exe

4

1 回答 1

3

根据CreateProcess()文档:

如果lpApplicationNamelpCommandLine都是非NULL,则指向的以空结尾的字符串lpApplicationName指定要执行的模块,指向的以空结尾的字符串lpCommandLine指定命令行。新进程可用于GetCommandLine检索整个命令行。用 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, optional]
...
这个函数的Unicode版本CreateProcessW,可以修改这个字符串的内容。因此,此参数不能是指向只读内存的指针(例如 const 变量或文字字符串)。如果此参数是一个常量字符串,该函数可能会导致访问冲突。

无论如何,您可能会考虑更改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, ...);
于 2017-09-26T20:42:32.797 回答