Results 1 to 1 of 1
  1. #1
    Dwar
    Dwar is offline
    Veteran Dwar's Avatar
    Join Date
    2010 Mar
    Posts
    2,222
    Thanks Thanks Given 
    211
    Thanks Thanks Received 
    2,230
    Thanked in
    292 Posts
    Rep Power
    10

    Call Exports of a Module in a Remote Process

    Here's some code you can use to call the exports of a module in a remote process. My code assumes the function prototype is:
    extern "C" void ();

    But you can easily modify it to whatever you want.

    Requires EnsureCleanup class collection posted in the utilities section. The function is a class member, but you can easily change it to a free function, it's a static member so simply removing the member qualification should do.
     // Call an exported function in a module in a remote process
    inline DWORD Injector::CallExport(DWORD ProcID, const std::string& ModuleName,
    const std::string& ExportName)
    {
    // For HCommon
    using namespace Hades;
    // For C++ Standard Library
    using namespace std;

    // Grab a new snapshot of the process
    EnsureCloseHandle Snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPMODUL E,
    ProcID));
    if (Snapshot == INVALID_HANDLE_VALUE)
    {
    throw runtime_error("Injector::CallExport: Could not get module "
    "snapshot for remote process.");
    }

    // Get the HMODULE of the desired library
    MODULEENTRY32W ModEntry = { sizeof(ModEntry) };
    bool Found = false;
    BOOL bMoreMods = Module32FirstW(Snapshot, &ModEntry);
    for (; bMoreMods; bMoreMods = Module32NextW(Snapshot, &ModEntry))
    {
    wstring ExePath(ModEntry.szExePath);
    wstring ModuleTmp(ModuleName.begin(), ModuleName.end());
    Found = (ExePath == ModuleTmp);
    if (Found) break;
    }
    if (!Found)
    {
    throw runtime_error("Injector::CallExport: Could not find module in "
    "remote process.");
    }

    // Get module base address
    PBYTE ModuleBase = ModEntry.modBaseAddr;

    // Get a handle for the target process.
    EnsureCloseHandle Process(OpenProcess(
    PROCESS_QUERY_INFORMATION |
    PROCESS_CREATE_THREAD |
    PROCESS_VM_OPERATION |
    PROCESS_VM_READ,
    FALSE, ProcID));
    if (!Process)
    {
    throw runtime_error("Injector::CallExport: Could not get handle to "
    "process.");
    }

    // Load module as data so we can read the EAT locally
    EnsureFreeLibrary MyModule(LoadLibraryExA(ModuleName.c_str(), NULL,
    DONT_RESOLVE_DLL_REFERENCES));

    // Get module pointer
    PVOID Module = static_cast<PVOID>(MyModule);

    // Get pointer to DOS header
    PIMAGE_DOS_HEADER pDosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(
    static_cast<HMODULE>(Module));
    if (!pDosHeader || pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
    {
    throw runtime_error("Injector::CallExport: DOS PE header "
    "is invalid.");
    }

    // Get pointer to NT header
    PIMAGE_NT_HEADERS pNtHeader = reinterpret_cast<PIMAGE_NT_HEADERS>
    (reinterpret_cast<PCHAR>(Module) + pDosHeader->e_lfanew);
    if (pNtHeader->Signature != IMAGE_NT_SIGNATURE)
    throw runtime_error("Injector::CallExport: NT PE header "
    "is invalid.");

    // Get pointer to image export directory
    PVOID pExportDirTemp = reinterpret_cast<PBYTE>(Module) +
    pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].
    VirtualAddress;
    PIMAGE_EXPORT_DIRECTORY pExportDir =
    reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>(pExportD irTemp);

    // Symbol names could be missing entirely
    if (pExportDir->AddressOfNames == NULL)
    {
    throw runtime_error("Injector::CallExport: Symbol names "
    "missing entirely.");
    }

    // Get pointer to export names table
    PDWORD pNamesRvas = reinterpret_cast<PDWORD>(
    reinterpret_cast<PBYTE>(Module) + pExportDir->AddressOfNames);
    // Get pointer to export ordinal table
    PWORD pNameOrdinals = reinterpret_cast<PWORD>(
    reinterpret_cast<PBYTE>(Module) + pExportDir->AddressOfNameOrdinals);
    // Get pointer to export address table
    PDWORD pFunctionAddresses = reinterpret_cast<PDWORD>(
    reinterpret_cast<PBYTE>(Module) + pExportDir->AddressOfFunctions);

    // Variable to hold the export address
    FARPROC pExportAddr = 0;

    // Walk the array of this module's function names
    for (DWORD n = 0; n < pExportDir->NumberOfNames; n++)
    {
    // Get the function name
    PSTR CurrentName = reinterpret_cast<PSTR>(
    reinterpret_cast<PBYTE>(Module) + pNamesRvas[n]);

    // If not the specified function, try the next function
    if (ExportName != CurrentName) continue;

    // We found the specified function
    // Get this function's Ordinal value
    WORD Ordinal = pNameOrdinals[n];

    // Get the address of this function's address
    pExportAddr = reinterpret_cast<FARPROC>(reinterpret_cast<PBYTE>( Module)
    + pFunctionAddresses[Ordinal]);

    // We got the func. Break out.
    break;
    }

    // Nothing found, throw exception
    if (!pExportAddr)
    {
    throw runtime_error("Injector::CallExport: Could not find "
    + ExportName + ".");
    }

    // Convert local address to remote address
    // TODO: Clean the casts. Currently working but could be simplified.
    PTHREAD_START_ROUTINE pfnThreadRtn =
    reinterpret_cast<PTHREAD_START_ROUTINE>((reinterpr et_cast<DWORD_PTR>(
    pExportAddr) - reinterpret_cast<DWORD_PTR>(Module)) +
    reinterpret_cast<DWORD_PTR>(ModuleBase));

    // Create a remote thread that calls the desired export
    EnsureCloseHandle Thread(CreateRemoteThread(Process, NULL, 0,
    pfnThreadRtn, ModEntry.modBaseAddr, 0, NULL));
    if (!Thread)
    {
    throw runtime_error("Injector::CallExport: Could not create thread in "
    "remote process.");
    }

    // Wait for the remote thread to terminate
    WaitForSingleObject(Thread, INFINITE);

    // Get thread exit code
    DWORD ExitCode = 0;
    if (!GetExitCodeThread(Thread,&ExitCode))
    {
    throw runtime_error("Injector::CallExport: Could not get thread exit "
    "code.");
    }

    // Return thread exit code
    return ExitCode;
    }

    Author: Chazwazza
    Please, post your questions on forum, not by PM or mail

    I spend my time, so please pay a little bit of your time to keep world in equilibrium

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •