2017-09-26 172 views
0

我已經創建了一個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的'輸出<< GetLastError函數()<< ENDL;'如果沒有正確啓動DLL ? –

+0

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

+0

您試圖從DLL調用的函數的確切簽名是什麼? –

回答

1

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'沒有。不要冒險。 –