Выполнение rundll32.exe с помощью CreateProcess

Я создал DLL и хотел бы выполнить одну из функций с помощью команды rundll32.exe в Windows.

Используя rundll32.exe, он работает правильно из командной строки; Тем не менее, я хотел бы назвать его (rundll32.exe) из отдельной программы. Я не могу напрямую вызвать функцию из своего кода из-за проблем совместимости 32/64 бит в используемых мной базовых библиотеках (Easyhook).

Ниже приведено то, что я использую при попытке запустить функцию 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-битной версии).

Моя библиотека выглядит следующим образом:

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 

дает ожидаемые результаты.


Обновить
настройка application в NULL и в том числе rundll32.exe в cmd, как упомянуто в комментариях, кажется, работает.

Соответствующие документы:
CreateProcess
rundll32.exe

1 ответ

Решение

В соответствии с CreateProcess()документация:

Если обаlpApplicationName а такжеlpCommandLineне NULL, строка с нулевым символом в конце, указанная lpApplicationName указывает модуль для выполнения, и строка с нулевым символом в конце, указанная lpCommandLine определяет командную строку. Новый процесс может использовать GetCommandLine чтобы получить всю командную строку. Консольные процессы, написанные на C, могут использовать argc а также argv аргументы для разбора командной строки. Так как 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, может изменить содержимое этой строки. Следовательно, этот параметр не может быть указателем на постоянную память (такую ​​как переменная const или литеральная строка). Если этот параметр является константной строкой, функция может вызвать нарушение прав доступа.

Вы могли бы рассмотреть возможность изменения 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"));

В любом случае, передавая имя файла модуля в качестве первого токена в lpCommandLine параметр, вы можете установить lpApplicationName параметр в NULL:

lpApplicationName параметр может быть НЕДЕЙСТВИТЕЛЕН. В этом случае имя модуля должно быть первым токеном с пробелами в lpCommandLine строка.

Позволять CreateProcess() установить правильную командную строку для передачи rundll32.exe для тебя:

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

BOOL cpRes = CreateProcess(NULL, cmd, ...);
Другие вопросы по тегам