This is the mail archive of the cygwin mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RE: Very slow Cygwin startup on Windows 7


> > Sysinternals "ADInsight" is a 32bit only tool and, in order to work on
> > a 64bit Windows you seem to have to manually inject the DLL
> > ADInsightDll.dll (which is extracted into %TEMP%) into the target
> > (32-bit!) process.

> So, it seems ADInsight seems a non-starter - for my skill level anyway.

In case it helps you, or another reader of the list, here is a simple
program that injects a named dll into a target process.

Example of using it to examine the ldap calls for cygwin's "echo.exe":

- Compile as a 32-bit program using *32bit* cygwin (as ADInsight is a 32bit
process): g++ inject.cpp -o inject.exe
- Start ADInsight from SysInternals
- Start Windows command shell
- Invoke: inject.exe %TEMP%\ADInsightDll.dll c:\cygwin\bin\echo.exe hello

Regards,
Roger.

----- inject.cpp -----
/*
NAME
    Inject.cpp

DESCRIPTION
    Inject a DLL into another process

COPYRIGHT
    Copyright (C) 2002,2015 by Roger Orr <rogero@howzatt.demon.co.uk>

    This software is distributed in the hope that it will be useful, but
    without WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

    Permission is granted to anyone to make or distribute verbatim
    copies of this software provided that the copyright notice and
    this permission notice are preserved, and that the distributor
    grants the recipient permission for further distribution as permitted
    by this notice.

    Comments and suggestions are always welcome.
    Please report bugs to rogero@howzatt.demon.co.uk.

EXAMPLE
    Inject MyDll fred.exe
*/

#include <windows.h>

#include <string>
#include <iostream>

//////////////////////////////////////////////////////////////////////////
// Local functions
int CreateProcessHelper(char ** it, char ** end, HANDLE & hProcess,
    HANDLE & hThread);
int InjectDLL(std::string const &dllName, HANDLE hProcess);

//////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv)
{
    if (argc < 3)
    {
        std::cerr << "Syntax: inject <dllname> <progname>" << std::endl;
        return 1;
    }

    std::string const dllName = argv[1];
    std::string const progName = argv[2];

    HANDLE hProcess = 0;
    HANDLE hThread = 0;
    if (CreateProcessHelper(argv+2, argv+argc, hProcess, hThread) != 0)
    {
        return 1;
    }

    if (InjectDLL(dllName, hProcess) != 0)
    {
        TerminateProcess(hProcess, GetLastError());
        return 1;
    }

    // resume the created process once we've loaded the DLL
    if (::ResumeThread(hThread) == (DWORD)-1)
    {
        std::cout << "ResumeThread failed with " << GetLastError()
            << std::endl;
        return 1;
    }

    DWORD ret = ::WaitForSingleObject(hProcess, INFINITE);
    if (ret == WAIT_OBJECT_0)
    {
        DWORD exitCode;
        if (GetExitCodeProcess(hProcess, &exitCode))
        {
            std::cout << "Process " << progName << " terminated: "
                 "return code: " << exitCode << std::endl;
            ret = exitCode;
        }
        else
        {
            ret = GetLastError();
            std::cout << "Process terminated: return code unavailable: "
                << ret << std::endl;
        }
    }
    else if (ret == WAIT_FAILED)
    {
        std::cout << "Process wait failed: " << GetLastError() << std::endl;
    }
    else
    {
        std::cout << "Process wait failed: " << ret << std::endl;
    }

    return ret;
}

//////////////////////////////////////////////////////////////////////////
// Inject DLL 'dllName' into process 'hProcess'
int InjectDLL(std::string const &dllName, HANDLE hProcess)
{
    LPTHREAD_START_ROUTINE lpStartAddress = 0;

    // Create memory in target process
    LPVOID const chDllName = VirtualAllocEx(hProcess, 0, dllName.size() + 1,
        MEM_COMMIT, PAGE_READWRITE);
    if (chDllName == 0)
    {
        std::cerr << "VirtualAllocEx failed: " << GetLastError()
            << std::endl;
        return 1;
    }

    // Map into my process
    if (! WriteProcessMemory(hProcess, chDllName,
        dllName.c_str(), dllName.size()+1, 0))
    {
        std::cerr << "WriteProcessMemory failed: " << GetLastError()
            << std::endl;
        return 1;
    }

    lpStartAddress = (LPTHREAD_START_ROUTINE)LoadLibrary;

    // Start a remote thread, at LoadLibraryA in the target process
    // Note we assume KERNEL32 has a fixed load address
    DWORD threadId(0);
    HANDLE const hRemoteThread = CreateRemoteThread(hProcess, 0, 0,
        lpStartAddress, chDllName, 0, &threadId);
    if (hRemoteThread == 0)
    {
        std::cerr << "CreateRemoteThread failed: " << GetLastError()
            << std::endl;
        return 1;
    }

    WaitForSingleObject(hRemoteThread, 10000);
    DWORD exitCode;
    if (! GetExitCodeThread(hRemoteThread, &exitCode))
    {
        std::cerr << "GetExitCodeThread failed: " << GetLastError()
            << std::endl;
        return 1;
    }

    if (exitCode == STILL_ACTIVE)
    {
        std::cout << "Remote thread still running..." << std::endl;
        return 1;
    }
    else if (exitCode == 0)
    {
        std::cout << "Remote thread failed to load DLL" << std::endl;
        return 1;
    }

    // Tidy up the allocated memory.
    if (! VirtualFreeEx(hProcess, chDllName, 0, MEM_RELEASE))
    {
        std::cout << "Warning: unable to free memory in target process: "
            << GetLastError() << std::endl;
    }

    return 0;
}

//////////////////////////////////////////////////////////////////////////
// Wrapper for create process.
int CreateProcessHelper(
    char ** it,
    char ** end,
    HANDLE &hProcess,
    HANDLE &hThread)
{
    char * executable = *it;

    // Search for possible executable matching the program name
    char szFullName[ MAX_PATH ];
    if (0 != SearchPath(0, executable, ".exe",
        sizeof(szFullName), szFullName, 0))
        executable = szFullName;
    
    std::string cmdLine;
    for (; it != end; ++it)
    {
        std::string curr(*it);

        if (cmdLine.length())
            cmdLine += " ";

        if (curr.find(' ') != std::string::npos)
        {
            cmdLine += '"';
            cmdLine += curr;
            cmdLine += '"';
        }
        else
        {
            cmdLine += curr;
        }
    }

    STARTUPINFO startupInfo = { sizeof(startupInfo) };
    startupInfo.dwFlags = STARTF_USESHOWWINDOW;
    startupInfo.wShowWindow = SW_SHOWNORMAL; // Assist GUI programs
    PROCESS_INFORMATION procInfo;

    if (! CreateProcess(executable, const_cast<char*>(cmdLine.c_str()),
        0, 0, TRUE, CREATE_SUSPENDED, 0, 0, &startupInfo, & procInfo))
    {
        std::cout << "CreateProcess for " << executable << " failed: "
            << GetLastError() << std::endl;
        return 1;
    }

    hProcess = procInfo.hProcess;
    hThread = procInfo.hThread;
    return 0;
}
----- ends -----



--
Problem reports:       http://cygwin.com/problems.html
FAQ:                   http://cygwin.com/faq/
Documentation:         http://cygwin.com/docs.html
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]