I am modifying a small one which works only by console and requires console arguments. But now I wanted to pass it to winmain(form) and get those arguments using GetCommandLine
and use them in a WinMain
just like I did in console. The program is as follows:
#include "stdafx.h"
int wmain(int argc, wchar_t* argv[]) {
assert(argc > 1);
// build command line
wchar_t commandLine[MAX_PATH * 2];
::lstrcpyW(commandLine, argv[1]);
if (argc > 2) {
::lstrcatW(commandLine, L" ");
::lstrcatW(commandLine, argv[2]);
}
PROCESS_INFORMATION pi;
STARTUPINFO si = { sizeof(si) };
// create the actual process with the debug flag to avoid an infinite loop
BOOL bCreated = ::CreateProcessW(nullptr, commandLine, nullptr, nullptr, FALSE, DEBUG_PROCESS, nullptr, nullptr, &si, &pi);
if (bCreated) {
WCHAR path[MAX_PATH];
::GetModuleFileName(nullptr, path, MAX_PATH);
*::wcsrchr(path, L'\\') = L'\0';
::wcscat_s(path, MAX_PATH, L"\\dllmain.Dll");
// create a semaphore which count represents the main thread ID
HANDLE hSemaphore = ::CreateSemaphore(nullptr, pi.dwThreadId - 1, pi.dwThreadId, L"InjectedMainThread");
assert(hSemaphore);
// duplicate in the injected process so the semaphore survives after the injected process goes away
HANDLE hTarget = nullptr;
::DuplicateHandle(::GetCurrentProcess(), hSemaphore, pi.hProcess, &hTarget, 0, FALSE, DUPLICATE_SAME_ACCESS);
assert(hTarget);
// allocate buffer for the DLL path name
void* pPathBuffer = ::VirtualAllocEx(pi.hProcess, nullptr, MAX_PATH * sizeof(WCHAR), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
assert(pPathBuffer);
// write the path
SIZE_T written;
::WriteProcessMemory(pi.hProcess, pPathBuffer, path, MAX_PATH * sizeof(WCHAR), &written);
// create a remote thread to load the DLL
HANDLE hRemoteThread = ::CreateRemoteThread(pi.hProcess, nullptr, 0,
(PTHREAD_START_ROUTINE)::GetProcAddress(::GetModuleHandle(L"kernel32"), "LoadLibraryW"),
pPathBuffer, 0, nullptr);
// allow the process to continue after this one exits
::DebugSetProcessKillOnExit(FALSE);
// close handles (not really needed as we're existing)
::CloseHandle(hRemoteThread);
::CloseHandle(pi.hProcess);
::CloseHandle(pi.hThread);
::CloseHandle(hSemaphore);
}
return 0;
}
I ask because I need help from an expert since I can do the modification but I am not sure if this program will work correctly.
In this case, two arguments will be passed and I don't really understand why the assert works since it is supposed that if it is not greater than one (the number of arguments) the program will abort.
I convert it to winmain:
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpszCmdParam,
int nCmdShow)
{
//int wmain(int argc, wchar_t* argv[]) {
assert(argc > 1);
// build command line
wchar_t commandLine[MAX_PATH * 2];
::lstrcpyW(commandLine, argv[1]);
if (argc > 2) {
::lstrcatW(commandLine, L" ");
::lstrcatW(commandLine, argv[2]);
}
PROCESS_INFORMATION pi;
STARTUPINFO si = { sizeof(si) };
// create the actual process with the debug flag to avoid an infinite loop
BOOL bCreated = ::CreateProcessW(nullptr, commandLine, nullptr, nullptr, FALSE, DEBUG_PROCESS, nullptr, nullptr, &si, &pi);
if (bCreated) {
WCHAR path[MAX_PATH];
::GetModuleFileName(nullptr, path, MAX_PATH);
*::wcsrchr(path, L'\\') = L'\0';
::wcscat_s(path, MAX_PATH, L"\\Injected.Dll");
// create a semaphore which count represents the main thread ID
HANDLE hSemaphore = ::CreateSemaphore(nullptr, pi.dwThreadId - 1, pi.dwThreadId, L"InjectedMainThread");
assert(hSemaphore);
// duplicate in the injected process so the semaphore survives after the injected process goes away
HANDLE hTarget = nullptr;
::DuplicateHandle(::GetCurrentProcess(), hSemaphore, pi.hProcess, &hTarget, 0, FALSE, DUPLICATE_SAME_ACCESS);
assert(hTarget);
// allocate buffer for the DLL path name
void* pPathBuffer = ::VirtualAllocEx(pi.hProcess, nullptr, MAX_PATH * sizeof(WCHAR), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
assert(pPathBuffer);
// write the path
SIZE_T written;
::WriteProcessMemory(pi.hProcess, pPathBuffer, path, MAX_PATH * sizeof(WCHAR), &written);
// create a remote thread to load the DLL
HANDLE hRemoteThread = ::CreateRemoteThread(pi.hProcess, nullptr, 0,
(PTHREAD_START_ROUTINE)::GetProcAddress(::GetModuleHandle(L"kernel32"), "LoadLibraryW"),
pPathBuffer, 0, nullptr);
// allow the process to continue after this one exits
::DebugSetProcessKillOnExit(FALSE);
// close handles (not really needed as we're existing)
//::CloseHandle(hRemoteThread);
//::CloseHandle(pi.hProcess);
//::CloseHandle(pi.hThread);
//::CloseHandle(hSemaphore);
}
return 0;
}
But it returns me the following errors, obviously because of the arguments that I gave them, I have to read them... using getcommandline from lpszCmdParam
, but I don't know very well how, errors:
C2065: 'argc': undeclared identifier
C2065: 'argv': undeclared identifier
C2660: 'lstrcpyW': function does not take 1 arguments
C2065: 'argc': undeclared identifier
C2065: 'argv': undeclared identifier
C2660: 'lstrcatW': function does not take 1 arguments
I can't confirm it (I don't use windows), but, given the source, I think it's correct.
The function
WinMain( )
is served by the command line via its argumentlpszCmdParam
; to convert it to an array similar toargv
, you can use the functionCommandLineToArgvW( )
In the proposed example, it would be more or less like this:
Modify the following:
we turn it into
In addition, we do the following:
From then on, it
argv[]
will be equivalent to the original code, except for one thing: ALL INDICES MUST BE CHANGED TO ONE LESS .That is, if we see, in the original code
argv[1]
, we have to change it toargv[0]
. And so in all cases .This is because, in the value returned by
CommandLineToArgvW( )
, the path to the executable has been omitted ; what would beargv[0]
.