Read console arguments in a winmain (WINAPI)

1

I'm modifying a small one that 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 WinMain as 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'
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'
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
'; ::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; }
'; ::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 make the modification but I am not sure if this program will work correctly.

In this case you will pass two arguments and the assert does not understand very well so that it works since it is assumed that if it is not greater than one (the number of arguments) the program will abort.

I convert it to winmain:

#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'
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'
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
'; ::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; }
'; ::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; }

But I returned the following errors obviously for the arguments that I put them I have to read them .. using getcommandline from lpszCmdParam , but I do not know very well, errors:

%pre%     
asked by Sergio Ramos 25.03.2017 в 10:42
source

1 answer

2

No I can confirm it (I do not use windows), but, given the source, I think it's correct.

To the WinMain( ) function, the command line comes to you through its lpszCmdParam argument; to convert it into a array similar to argv , you can use the CommandLineToArgvW( )

In the example proposed, it would be more or less like this:

Modify the following:

int WINAPI WinMain(HINSTANCE hInstance, ... ) {

We turn it into

 int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) {

In addition, we do the following:

char cmd[] = "taskmgr.exe" ; // note: non-const (writeable array)
HANDLE thread = nullptr ;
auto myProc=Startpausedprocess( cmd, std::addressof(thread) ) ;

// AÑADIMOS ESTO

int argv; // <- Añadir esto.
wchar_t **argv; // <- Y esto también.

argv = CommandLineToArgvW( pCmdLine, &argc );

As of that moment, argv[] will be equivalent to the original code, except for one thing: YOU SHOULD CHANGE ALL INDEXES FOR ONE LESS .

That is, if we see, in the original code, argv[1] , we have to change it by argv[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 be argv[0] .

    
answered by 25.03.2017 / 10:52
source