Search code examples
cwindowswinapihandle

How to run an .exe file downloaded with InternetOpenFile() in Winapi


I have a C app written using Winapi and an .exe file that I need to download and execute. My code so far is:

if (NULL == (hRequest = HttpOpenRequest(hHTTP, "GET", "/~alexandru.antochi/exe_1.exe", NULL, NULL, rgpszAcceptTypes, NULL, INTERNET_FLAG_NO_COOKIES || INTERNET_FLAG_NO_AUTH)))
        {
            _error("HttpOpenRequest error.");
        }

        if (HttpSendRequest(hRequest, NULL, NULL, NULL, NULL))
        {

            if (InternetReadFile(hRequest, &buffer, 65536, &bytesRead))
            {
                if (bytesRead == 65536)
                {
                    printf("Warning: .exe file too big. Ignoring");
                    continue;
                }
            }
        }
        else
        {
            _error("Could not send HTTP request.");
        }

        closeHandles(2, hRequest, hHTTP);

I read the file, what now? If I try to write it in a local file, it will stop at the first \0 delimiter, which is after 2 letters in my case. The file can be found at http://students.info.uaic.ro/~alexandru.antochi/exe_1.exe


Solution

  • You must save the EXE file to a local file before you can execute it. You can't execute an EXE from memory (without writing your own EXE loader, or using a 3rd party one).

    InternetReadFile() reads arbitrary amounts of data, so you need to call it in a loop until the end of the response is reached. Write each block of data that is received as-is to your local file. Your claim that your writing "will stop at the first \0 delimiter" means that you are writing the received data as null-terminated strings instead of as raw binary data. Binary files, especially executable files, contain plenty of 0x00 bytes in them. So this is a logic bug in your code that you need to fix.

    Try something more like this instead:

    HINTERNET hInternet = InternetOpen(...);
    if (!hInternet)
    {
        _error("InternetOpen error.");
    }
    
    HINTERNET hHTTP = InternetConnect(hInternet, "students.info.uaic.ro", INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
    if (!hHTTP)
    {
        InternetCloseHandle(hInternet);
        _error("InternetConnect error.");
    }
    
    const char* rgpszAcceptTypes[] = {"application/vnd.microsoft.portable-executable", "application/octet-stream", "application/x-msdownload", NULL};
    HINTERNET hRequest = HttpOpenRequest(hHTTP, "GET", "/~alexandru.antochi/exe_1.exe", NULL, NULL, rgpszAcceptTypes, NULL, INTERNET_FLAG_NO_COOKIES | INTERNET_FLAG_NO_AUTH);
    if (!hRequest)
    {
        InternetCloseHandle(hHTTP);
        InternetCloseHandle(hInternet);
        _error("HttpOpenRequest error.");
    }
    
    if (!HttpSendRequest(hRequest, NULL, NULL, NULL, NULL))
    {
        InternetCloseHandle(hRequest);
        InternetCloseHandle(hHTTP);
        InternetCloseHandle(hInternet);
        _error("Could not send HTTP request.");
    }
    
    DWORD statusCode;
    DWORD size = sizeof(statusCode), index = 0;
    if (!HttpQueryInfo(hRequest, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &statusCode, &size, &index))
    {
        InternetCloseHandle(hRequest);
        InternetCloseHandle(hHTTP);
        InternetCloseHandle(hInternet);
        _error("HttpQueryInfo error.");
    }
    
    if (statusCode != 200)
    {
        InternetCloseHandle(hRequest);
        InternetCloseHandle(hHTTP);
        InternetCloseHandle(hInternet);
        _error("HTTP request failed.");
    }
    
    HANDLE hFile = CreateFile("C:\\path to\\exe_1.exe" , GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL); 
    if (hFile == INVALID_HANDLE_VALUE)
    {
        InternetCloseHandle(hRequest);
        InternetCloseHandle(hHTTP);
        InternetCloseHandle(hInternet);
        _error("Could not create local file.");
    }
    
    BYTE buffer[1024];
    DWORD bytesRead, bytesWritten;
    
    do
    {
        if (!InternetReadFile(hRequest, buffer, sizeof(buffer), &bytesRead))
        {
            CloseHandle(hFile);
            InternetCloseHandle(hRequest);
            InternetCloseHandle(hHTTP);
            InternetCloseHandle(hInternet);
            _error("Could not read HTTP response.");
        }
    
        if (bytesRead == 0)
            break;
    
        if (!WriteFile(hFile, buffer, bytesRead, &bytesWritten))
        {
            CloseHandle(hFile);
            InternetCloseHandle(hRequest);
            InternetCloseHandle(hHTTP);
            InternetCloseHandle(hInternet);
            _error("Could not write to local file.");
        }
    }
    while (true);
    
    CloseHandle(hFile);
    InternetCloseHandle(hRequest);
    InternetCloseHandle(hHTTP);
    InternetCloseHandle(hInternet);
    
    // use EXE file as needed...
    

    Refer to MSDN documentation for more details:

    HTTP Sessions

    Downloading Resources from the WWW