How to Get Remote Proc address of injected DLL into another process

1

This application is created 1) Console Application 2) InjectedDLL - DLL Project for inject into the process

1) the console application i have taken notepad.exe process id and inject my DLL into the notepad. 2) I have Created one exported method in the injected dll. 3) Now after injecting dll into notepad , i require the proc address of that exported method.

I have writted code here to get it but it's is not calling that methods and crash it.

I am attaching sample code this here. for run it only need to give full path of the dll. const WCHAR INJECTED_DLL_FULL_PATH[] = L"FULL PATH OF DLL"; Only change this path, everything else will work.

I am unable to get the proc address of the injected dll. anyone can help me on that.

/

Console Application code

/ DLLInjection.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <Windows.h>
#include <stdlib.h>
#include "RemoteOperation.h"
#include <stdio.h>
#include <tchar.h>
#include <tlhelp32.h>

BOOL InjectDLL();
void EjectDLL();
HANDLE   m_hRemoteThread;
HANDLE   m_hProcess;
void*    m_pLibRemoteAddress;
DWORD    m_dwhLibModule;
BOOL     m_bIsDLLInjected;
DWORD    m_dwProcessID;
HWND     m_hCaptureWnd;

const WCHAR INJECTED_DLL[] = L"InjectedDLL.dll";
const WCHAR INJECTED_DLL_FULL_PATH[] = L"FULL PATH OF DLL";
DWORD GetProcessIdEx(LPCWSTR szExeName);

typedef void (WINAPI *test)();
test _test = NULL;

int main()
{

    InjectDLL();

    HMODULE hDLLModule = GetRemoteModuleHandle(m_hProcess, INJECTED_DLL);
    _test = (test)GetRemoteProcAddress(m_hProcess, hDLLModule, "test");
    _test();


    EjectDLL();


    return 0;
}

DWORD GetProcessIdEx(LPCWSTR szExeName)

{
    DWORD dwRet = 0;
    DWORD dwCount = 0;

    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

    if (hSnapshot != INVALID_HANDLE_VALUE)
    {
        PROCESSENTRY32 pe = { 0 };
        pe.dwSize = sizeof(PROCESSENTRY32);

        BOOL bRet = Process32First(hSnapshot, &pe);

        while (bRet)
        {
            OutputDebugString(pe.szExeFile);
            OutputDebugString(L"\n");
            if (!wcscmp(szExeName, pe.szExeFile))
            {
                dwCount++;
                dwRet = pe.th32ProcessID;
                break;
            }
            bRet = Process32Next(hSnapshot, &pe);
        }

        if (dwCount > 1)
            dwRet = 0xFFFFFFFF;

        CloseHandle(hSnapshot);
    }

    return dwRet;
}

BOOL InjectDLL()
{

    m_hRemoteThread = NULL;
    m_hProcess = NULL;
    m_pLibRemoteAddress = NULL;
    m_dwhLibModule = 0;



    char chardllPath[MAX_PATH] = "\0";
    wcstombs(chardllPath, INJECTED_DLL_FULL_PATH, MAX_PATH);

    int Length = strlen(chardllPath);

    HMODULE hKernel32 = ::GetModuleHandle(L"Kernel32");
    LPVOID LoadLibraryPoniter = (LPVOID)GetProcAddress(hKernel32, "LoadLibraryA");

    m_dwProcessID = GetProcessIdEx(L"notepad.exe");


    m_hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, m_dwProcessID);

    // 1. Allocate memory in the remote process for szLibPath
    // 2. Write szLibPath to the allocated memory
    m_pLibRemoteAddress = 0;

    m_pLibRemoteAddress = ::VirtualAllocEx(m_hProcess, NULL, Length, MEM_COMMIT, PAGE_READWRITE);
    if (m_pLibRemoteAddress == NULL)
    {
        CloseHandle(m_hProcess);
        m_hProcess = NULL;
        return false;
    }

    ::WriteProcessMemory(m_hProcess, m_pLibRemoteAddress, (void*)chardllPath, Length, NULL);


    // Load "dll" into the remote process 
    // (via CreateRemoteThread & LoadLibrary)
    m_hRemoteThread = ::CreateRemoteThread(m_hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibraryPoniter, (LPVOID)m_pLibRemoteAddress, 0, NULL);

    m_bIsDLLInjected = true;

    ::WaitForSingleObject(m_hRemoteThread, INFINITE);



    // Get handle of loaded module
    m_dwhLibModule = 0;
    ::GetExitCodeThread(m_hRemoteThread, &m_dwhLibModule);
    ::CloseHandle(m_hRemoteThread);
    m_hRemoteThread = NULL;
    ::VirtualFreeEx(m_hProcess, m_pLibRemoteAddress, Length, MEM_RELEASE);

    m_pLibRemoteAddress = NULL;




    return true;
}

void EjectDLL()
{
    if (m_hProcess && m_bIsDLLInjected)
    {
        HMODULE hKernel32 = ::GetModuleHandle(L"Kernel32");
        LPVOID LoadFreeLibraryPoniter = (LPVOID)GetProcAddress(hKernel32, "FreeLibrary");
        HMODULE hDLLModule = GetRemoteModuleHandle(m_hProcess, INJECTED_DLL);

        if (hDLLModule)
        {
            HANDLE hThread = ::CreateRemoteThread(m_hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadFreeLibraryPoniter, (void*)hDLLModule, 0, NULL);

            ::WaitForSingleObject(hThread, INFINITE);

            // Clean up
            ::CloseHandle(hThread);
        }
    }

    if (m_hProcess)
    {
        CloseHandle(m_hProcess);
    }

    m_hProcess = NULL;

}

Remoteoperation.h

#pragma once
#define WIN32_LEAN_AND_MEAN             // Exclude rarely-used stuff from Windows headers
// Windows Header Files:
#include <windows.h>
#include <commctrl.h>

// C RunTime Header Files
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>

#ifndef REM_OPS_H
#define REM_OPS_H

HMODULE WINAPI GetRemoteModuleHandle(HANDLE hProcess, LPCWSTR lpModuleName);
FARPROC WINAPI GetRemoteProcAddress(HANDLE hProcess, HMODULE hModule, LPCSTR lpProcName, UINT Ordinal = 0, BOOL UseOrdinal = FALSE);
BOOL RemoteLibraryFunction(HANDLE hProcess, LPCSTR lpModuleName, LPCSTR lpProcName, LPVOID lpParameters, SIZE_T dwParamSize, PVOID *ppReturn);
#endif //REM_OPS_H

// RemoteOperation.cpp

#include "stdafx.h"

/* RempteOps.cpp */

#include "stdafx.h" // SDKDDKVer.h, windows.h, stdlib.h, malloc.h, memory.h, tchar.h
#include "RemoteOperation.h" // Function prototypes
#include <string>
#include <windows.h>
#include <psapi.h>

using std::string;

//-----------------------------------------------------------------------------

HMODULE WINAPI GetRemoteModuleHandle(HANDLE hProcess, LPCWSTR lpModuleName)
{
    HMODULE* ModuleArray = NULL;
    DWORD ModuleArraySize = 200;
    DWORD NumModules = 0;
    WCHAR lpModuleNameCopy[MAX_PATH] = { 0 };
    WCHAR ModuleNameBuffer[MAX_PATH] = { 0 };

    /* Make sure we didn't get a NULL pointer for the module name */
    if (lpModuleName == NULL)
        goto GRMH_FAIL_JMP;

    /* Convert lpModuleName to all lowercase so the comparison isn't case sensitive */
    for (size_t i = 0; lpModuleName[i] != '\0'; ++i)
    {
        if (lpModuleName[i] >= 'A' && lpModuleName[i] <= 'Z')
            lpModuleNameCopy[i] = lpModuleName[i] + 0x20; // 0x20 is the difference between uppercase and lowercase
        else
            lpModuleNameCopy[i] = lpModuleName[i];

        lpModuleNameCopy[i + 1] = '\0';
    }

    /* Allocate memory to hold the module handles */
    ModuleArray = new HMODULE[ModuleArraySize];

    /* Check if the allocation failed */
    if (ModuleArray == NULL)
        goto GRMH_FAIL_JMP;

    /* Get handles to all the modules in the target process */
    if (!::EnumProcessModulesEx(hProcess, ModuleArray,
        ModuleArraySize * sizeof(HMODULE), &NumModules, LIST_MODULES_ALL))
        goto GRMH_FAIL_JMP;

    /* We want the number of modules not the number of bytes */
    NumModules /= sizeof(HMODULE);

    /* Did we allocate enough memory for all the module handles? */
    if (NumModules > ModuleArraySize)
    {
        delete[] ModuleArray; // Deallocate so we can try again
        ModuleArray = NULL; // Set it to NULL se we can be sure if the next try fails
        ModuleArray = new HMODULE[NumModules]; // Allocate the right amount of memory

                                               /* Check if the allocation failed */
        if (ModuleArray == NULL)
            goto GRMH_FAIL_JMP;

        ModuleArraySize = NumModules; // Update the size of the array

                                      /* Get handles to all the modules in the target process */
        if (!::EnumProcessModulesEx(hProcess, ModuleArray,
            ModuleArraySize * sizeof(HMODULE), &NumModules, LIST_MODULES_ALL))
            goto GRMH_FAIL_JMP;

        /* We want the number of modules not the number of bytes */
        NumModules /= sizeof(HMODULE);
    }

    /* Iterate through all the modules and see if the names match the one we are looking for */
    for (DWORD i = 0; i <= NumModules; ++i)
    {
        /* Get the module's name */
        ::GetModuleBaseName(hProcess, ModuleArray[i],
            ModuleNameBuffer, sizeof(ModuleNameBuffer));

        /* Convert ModuleNameBuffer to all lowercase so the comparison isn't case sensitive */
        for (size_t j = 0; ModuleNameBuffer[j] != '\0'; ++j)
        {
            if (ModuleNameBuffer[j] >= 'A' && ModuleNameBuffer[j] <= 'Z')
                ModuleNameBuffer[j] += 0x20; // 0x20 is the difference between uppercase and lowercase
        }


        /* Does the name match? */
        if (wcsstr(ModuleNameBuffer, lpModuleNameCopy) != NULL)
        {
            /* Make a temporary variable to hold return value*/
            HMODULE TempReturn = ModuleArray[i];

            /* Give back that memory */
            delete[] ModuleArray;

            /* Success */
            return TempReturn;
        }

        /* Wrong module let's try the next... */
    }

    /* Uh Oh... */
GRMH_FAIL_JMP:

    /* If we got to the point where we allocated memory we need to give it back */
    if (ModuleArray != NULL)
        delete[] ModuleArray;

    /* Failure... */
    return NULL;
}

//-----------------------------------------------------------------------------

FARPROC WINAPI GetRemoteProcAddress(HANDLE hProcess, HMODULE hModule, LPCSTR lpProcName, UINT Ordinal, BOOL UseOrdinal)
{
    BOOL Is64Bit = FALSE;
    MODULEINFO RemoteModuleInfo = { 0 };
    UINT_PTR RemoteModuleBaseVA = 0;
    IMAGE_DOS_HEADER DosHeader = { 0 };
    DWORD Signature = 0;
    IMAGE_FILE_HEADER FileHeader = { 0 };
    IMAGE_OPTIONAL_HEADER64 OptHeader64 = { 0 };
    IMAGE_OPTIONAL_HEADER32 OptHeader32 = { 0 };
    IMAGE_DATA_DIRECTORY ExportDirectory = { 0 };
    IMAGE_EXPORT_DIRECTORY ExportTable = { 0 };
    UINT_PTR ExportFunctionTableVA = 0;
    UINT_PTR ExportNameTableVA = 0;
    UINT_PTR ExportOrdinalTableVA = 0;
    DWORD* ExportFunctionTable = NULL;
    DWORD* ExportNameTable = NULL;
    WORD* ExportOrdinalTable = NULL;

    /* Temporary variables not used until much later but easier
    /* to define here than in all the the places they are used */
    CHAR TempChar;
    BOOL Done = FALSE;

    /* Check to make sure we didn't get a NULL pointer for the name unless we are searching by ordinal */
    if (lpProcName == NULL && !UseOrdinal)
        goto GRPA_FAIL_JMP;

    /* Get the base address of the remote module along with some other info we don't need */
    if (!::GetModuleInformation(hProcess, hModule, &RemoteModuleInfo, sizeof(RemoteModuleInfo)))
        goto GRPA_FAIL_JMP;
    RemoteModuleBaseVA = (UINT_PTR)RemoteModuleInfo.lpBaseOfDll;

    /* Read the DOS header and check it's magic number */
    if (!::ReadProcessMemory(hProcess, (LPCVOID)RemoteModuleBaseVA, &DosHeader,
        sizeof(DosHeader), NULL) || DosHeader.e_magic != IMAGE_DOS_SIGNATURE)
        goto GRPA_FAIL_JMP;

    /* Read and check the NT signature */
    if (!::ReadProcessMemory(hProcess, (LPCVOID)(RemoteModuleBaseVA + DosHeader.e_lfanew),
        &Signature, sizeof(Signature), NULL) || Signature != IMAGE_NT_SIGNATURE)
        goto GRPA_FAIL_JMP;

    /* Read the main header */
    if (!::ReadProcessMemory(hProcess,
        (LPCVOID)(RemoteModuleBaseVA + DosHeader.e_lfanew + sizeof(Signature)),
        &FileHeader, sizeof(FileHeader), NULL))
        goto GRPA_FAIL_JMP;

    /* Which type of optional header is the right size? */
    if (FileHeader.SizeOfOptionalHeader == sizeof(OptHeader64))
        Is64Bit = TRUE;
    else if (FileHeader.SizeOfOptionalHeader == sizeof(OptHeader32))
        Is64Bit = FALSE;
    else
        goto GRPA_FAIL_JMP;

    if (Is64Bit)
    {
        /* Read the optional header and check it's magic number */
        if (!::ReadProcessMemory(hProcess,
            (LPCVOID)(RemoteModuleBaseVA + DosHeader.e_lfanew + sizeof(Signature) + sizeof(FileHeader)),
            &OptHeader64, FileHeader.SizeOfOptionalHeader, NULL)
            || OptHeader64.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC)
            goto GRPA_FAIL_JMP;
    }
    else
    {
        /* Read the optional header and check it's magic number */
        if (!::ReadProcessMemory(hProcess,
            (LPCVOID)(RemoteModuleBaseVA + DosHeader.e_lfanew + sizeof(Signature) + sizeof(FileHeader)),
            &OptHeader32, FileHeader.SizeOfOptionalHeader, NULL)
            || OptHeader32.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
            goto GRPA_FAIL_JMP;
    }

    /* Make sure the remote module has an export directory and if it does save it's relative address and size */
    if (Is64Bit && OptHeader64.NumberOfRvaAndSizes >= IMAGE_DIRECTORY_ENTRY_EXPORT + 1)
    {
        ExportDirectory.VirtualAddress = (OptHeader64.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]).VirtualAddress;
        ExportDirectory.Size = (OptHeader64.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]).Size;
    }
    else if (OptHeader32.NumberOfRvaAndSizes >= IMAGE_DIRECTORY_ENTRY_EXPORT + 1)
    {
        ExportDirectory.VirtualAddress = (OptHeader32.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]).VirtualAddress;
        ExportDirectory.Size = (OptHeader32.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]).Size;
    }
    else
        goto GRPA_FAIL_JMP;

    /* Read the main export table */
    if (!::ReadProcessMemory(hProcess, (LPCVOID)(RemoteModuleBaseVA + ExportDirectory.VirtualAddress),
        &ExportTable, sizeof(ExportTable), NULL))
        goto GRPA_FAIL_JMP;

    /* Save the absolute address of the tables so we don't need to keep adding the base address */
    ExportFunctionTableVA = RemoteModuleBaseVA + ExportTable.AddressOfFunctions;
    ExportNameTableVA = RemoteModuleBaseVA + ExportTable.AddressOfNames;
    ExportOrdinalTableVA = RemoteModuleBaseVA + ExportTable.AddressOfNameOrdinals;

    /* Allocate memory for our copy of the tables */
    ExportFunctionTable = new DWORD[ExportTable.NumberOfFunctions];
    ExportNameTable = new DWORD[ExportTable.NumberOfNames];
    ExportOrdinalTable = new WORD[ExportTable.NumberOfNames];

    /* Check if the allocation failed */
    if (ExportFunctionTable == NULL || ExportNameTable == NULL || ExportOrdinalTable == NULL)
        goto GRPA_FAIL_JMP;

    /* Get a copy of the function table */
    if (!::ReadProcessMemory(hProcess, (LPCVOID)ExportFunctionTableVA,
        ExportFunctionTable, ExportTable.NumberOfFunctions * sizeof(DWORD), NULL))
        goto GRPA_FAIL_JMP;

    /* Get a copy of the name table */
    if (!::ReadProcessMemory(hProcess, (LPCVOID)ExportNameTableVA,
        ExportNameTable, ExportTable.NumberOfNames * sizeof(DWORD), NULL))
        goto GRPA_FAIL_JMP;

    /* Get a copy of the ordinal table */
    if (!::ReadProcessMemory(hProcess, (LPCVOID)ExportOrdinalTableVA,
        ExportOrdinalTable, ExportTable.NumberOfNames * sizeof(WORD), NULL))
        goto GRPA_FAIL_JMP;

    /* If we are searching for an ordinal we do that now */
    if (UseOrdinal)
    {
        /* NOTE:
        /* Microsoft's PE/COFF specification does NOT say we need to subtract the ordinal base
        /* from our ordinal but it seems to always give the wrong function if we don't */

        /* Make sure the ordinal is valid */
        if (Ordinal < ExportTable.Base || (Ordinal - ExportTable.Base) >= ExportTable.NumberOfFunctions)
            goto GRPA_FAIL_JMP;

        UINT FunctionTableIndex = Ordinal - ExportTable.Base;

        /* Check if the function is forwarded and if so get the real address*/
        if (ExportFunctionTable[FunctionTableIndex] >= ExportDirectory.VirtualAddress &&
            ExportFunctionTable[FunctionTableIndex] <= ExportDirectory.VirtualAddress + ExportDirectory.Size)
        {
            Done = FALSE;
            string TempForwardString;
            TempForwardString.clear(); // Empty the string so we can fill it with a new name

                                       /* Get the forwarder string one character at a time because we don't know how long it is */
            for (UINT_PTR i = 0; !Done; ++i)
            {
                /* Get next character */
                if (!::ReadProcessMemory(hProcess,
                    (LPCVOID)(RemoteModuleBaseVA + ExportFunctionTable[FunctionTableIndex] + i),
                    &TempChar, sizeof(TempChar), NULL))
                    goto GRPA_FAIL_JMP;

                TempForwardString.push_back(TempChar); // Add it to the string

                                                       /* If it's NUL we are done */
                if (TempChar == (CHAR)'\0')
                    Done = TRUE;
            }

            /* Find the dot that seperates the module name and the function name/ordinal */
            size_t Dot = TempForwardString.find('.');
            if (Dot == string::npos)
                goto GRPA_FAIL_JMP;

            /* Temporary variables that hold parts of the forwarder string */
            string RealModuleName, RealFunctionId;
            RealModuleName = TempForwardString.substr(0, Dot - 1);
            RealFunctionId = TempForwardString.substr(Dot + 1, string::npos);

            WCHAR newModuleName[MAX_PATH] = L"\0";
            swprintf_s(newModuleName, L"%s", RealModuleName.c_str());

            HMODULE RealModule = GetRemoteModuleHandle(hProcess, newModuleName);
            FARPROC TempReturn;// Make a temporary variable to hold return value 


                               /* Figure out if the function was exported by name or by ordinal */
            if (RealFunctionId.at(0) == '#') // Exported by ordinal
            {
                UINT RealOrdinal = 0;
                RealFunctionId.erase(0, 1); // Remove '#' from string

                                            /* My version of atoi() because I was too lazy to use the real one... */
                for (size_t i = 0; i < RealFunctionId.size(); ++i)
                {
                    if (RealFunctionId[i] >= '0' && RealFunctionId[i] <= '9')
                    {
                        RealOrdinal *= 10;
                        RealOrdinal += RealFunctionId[i] - '0';
                    }
                    else
                        break;
                }

                /* Recursively call this function to get return value */
                TempReturn = GetRemoteProcAddress(hProcess, RealModule, NULL, RealOrdinal, TRUE);
            }
            else // Exported by name
            {

                /* Recursively call this function to get return value */
                TempReturn = GetRemoteProcAddress(hProcess, RealModule, RealFunctionId.c_str(), 0, FALSE);
            }

            /* Give back that memory */
            delete[] ExportFunctionTable;
            delete[] ExportNameTable;
            delete[] ExportOrdinalTable;

            /* Success!!! */
            return TempReturn;
        }
        else // Not Forwarded
        {

            /* Make a temporary variable to hold return value*/
            FARPROC TempReturn = (FARPROC)(RemoteModuleBaseVA + ExportFunctionTable[FunctionTableIndex]);

            /* Give back that memory */
            delete[] ExportFunctionTable;
            delete[] ExportNameTable;
            delete[] ExportOrdinalTable;

            /* Success!!! */
            return TempReturn;
        }
    }


    /* Iterate through all the names and see if they match the one we are looking for */
    for (DWORD i = 0; i < ExportTable.NumberOfNames; ++i) {
        string TempFunctionName;

        Done = FALSE;// Reset for next name
        TempFunctionName.clear(); // Empty the string so we can fill it with a new name

                                  /* Get the function name one character at a time because we don't know how long it is */
        for (UINT_PTR j = 0; !Done; ++j)
        {
            /* Get next character */
            if (!::ReadProcessMemory(hProcess, (LPCVOID)(RemoteModuleBaseVA + ExportNameTable[i] + j),
                &TempChar, sizeof(TempChar), NULL))
                goto GRPA_FAIL_JMP;

            TempFunctionName.push_back(TempChar); // Add it to the string

                                                  /* If it's NUL we are done */
            if (TempChar == (CHAR)'\0')
                Done = TRUE;
        }

        /* Does the name match? */
        if (TempFunctionName.find(lpProcName) != string::npos)
        {
            /* NOTE:
            /* Microsoft's PE/COFF specification says we need to subtract the ordinal base
            /*from the value in the ordinal table but that seems to always give the wrong function */

            /* Check if the function is forwarded and if so get the real address*/
            if (ExportFunctionTable[ExportOrdinalTable[i]] >= ExportDirectory.VirtualAddress &&
                ExportFunctionTable[ExportOrdinalTable[i]] <= ExportDirectory.VirtualAddress + ExportDirectory.Size)
            {
                Done = FALSE;
                string TempForwardString;
                TempForwardString.clear(); // Empty the string so we can fill it with a new name

                                           /* Get the forwarder string one character at a time because we don't know how long it is */
                for (UINT_PTR j = 0; !Done; ++j)
                {
                    /* Get next character */
                    if (!::ReadProcessMemory(hProcess,
                        (LPCVOID)(RemoteModuleBaseVA + ExportFunctionTable[i] + j),
                        &TempChar, sizeof(TempChar), NULL))
                        goto GRPA_FAIL_JMP;

                    TempForwardString.push_back(TempChar); // Add it to the string

                                                           /* If it's NUL we are done */
                    if (TempChar == (CHAR)'\0')
                        Done = TRUE;
                }

                /* Find the dot that seperates the module name and the function name/ordinal */
                size_t Dot = TempForwardString.find('.');
                if (Dot == string::npos)
                    goto GRPA_FAIL_JMP;

                /* Temporary variables that hold parts of the forwarder string */
                string RealModuleName, RealFunctionId;
                RealModuleName = TempForwardString.substr(0, Dot);
                RealFunctionId = TempForwardString.substr(Dot + 1, string::npos);


                WCHAR newModuleName[MAX_PATH] = L"\0";
                swprintf_s(newModuleName, L"%s", RealModuleName.c_str());


                HMODULE RealModule = GetRemoteModuleHandle(hProcess, newModuleName);
                FARPROC TempReturn;// Make a temporary variable to hold return value 


                                   /* Figure out if the function was exported by name or by ordinal */
                if (RealFunctionId.at(0) == '#') // Exported by ordinal
                {
                    UINT RealOrdinal = 0;
                    RealFunctionId.erase(0, 1); // Remove '#' from string

                                                /* My version of atoi() because I was to lazy to use the real one... */
                    for (size_t i = 0; i < RealFunctionId.size(); ++i)
                    {
                        if (RealFunctionId[i] >= '0' && RealFunctionId[i] <= '9')
                        {
                            RealOrdinal *= 10;
                            RealOrdinal += RealFunctionId[i] - '0';
                        }
                        else
                            break;
                    }

                    /* Recursively call this function to get return value */
                    TempReturn = GetRemoteProcAddress(hProcess, RealModule, NULL, RealOrdinal, TRUE);
                }
                else // Exported by name
                {

                    /* Recursively call this function to get return value */
                    TempReturn = GetRemoteProcAddress(hProcess, RealModule, RealFunctionId.c_str(), 0, FALSE);
                }

                /* Give back that memory */
                delete[] ExportFunctionTable;
                delete[] ExportNameTable;
                delete[] ExportOrdinalTable;

                /* Success!!! */
                return TempReturn;
            }
            else // Not Forwarded
            {

                /* Make a temporary variable to hold return value*/
                FARPROC TempReturn;

                /* NOTE:
                /* Microsoft's PE/COFF specification says we need to subtract the ordinal base
                /*from the value in the ordinal table but that seems to always give the wrong function */
                //TempReturn = (FARPROC)(RemoteModuleBaseVA + ExportFunctionTable[ExportOrdinalTable[i] - ExportTable.Base]);

                /* So we do it this way instead */
                TempReturn = (FARPROC)(RemoteModuleBaseVA + ExportFunctionTable[ExportOrdinalTable[i]]);

                /* Give back that memory */
                delete[] ExportFunctionTable;
                delete[] ExportNameTable;
                delete[] ExportOrdinalTable;

                /* Success!!! */
                return TempReturn;
            }
        }

        /* Wrong function let's try the next... */
    }

    /* Uh Oh... */
GRPA_FAIL_JMP:

    /* If we got to the point where we allocated memory we need to give it back */
    if (ExportFunctionTable != NULL)
        delete[] ExportFunctionTable;
    if (ExportNameTable != NULL)
        delete[] ExportNameTable;
    if (ExportOrdinalTable != NULL)
        delete[] ExportOrdinalTable;

    /* Falure... */
    return NULL;
}

BOOL RemoteLibraryFunction(HANDLE hProcess, LPCSTR lpModuleName, LPCSTR lpProcName, LPVOID lpParameters, SIZE_T dwParamSize, PVOID *ppReturn)
{
    LPVOID lpRemoteParams = NULL;

    LPVOID lpFunctionAddress = GetProcAddress(GetModuleHandleA(lpModuleName), lpProcName);
    if (!lpFunctionAddress) lpFunctionAddress = GetProcAddress(LoadLibraryA(lpModuleName), lpProcName);
    if (!lpFunctionAddress) goto ErrorHandler;

    if (lpParameters)
    {
        lpRemoteParams = VirtualAllocEx(hProcess, NULL, dwParamSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
        if (!lpRemoteParams) goto ErrorHandler;

        SIZE_T dwBytesWritten = 0;
        BOOL result = WriteProcessMemory(hProcess, lpRemoteParams, lpParameters, dwParamSize, &dwBytesWritten);
        if (!result || dwBytesWritten < 1) goto ErrorHandler;
    }

    HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpFunctionAddress, lpRemoteParams, NULL, NULL);
    if (!hThread) goto ErrorHandler;

    DWORD dwOut = 0;
    while (GetExitCodeThread(hThread, &dwOut)) {
        if (dwOut != STILL_ACTIVE) {
            *ppReturn = (PVOID)dwOut;
            break;
        }
    }

    return TRUE;

ErrorHandler:
    if (lpRemoteParams) 
        VirtualFreeEx(hProcess, lpRemoteParams, dwParamSize, MEM_RELEASE);

    return FALSE;
}

Injectdl DLL Expoerted methods

#define EXPORT __declspec (dllexport)
EXPORT void test();


EXPORT void test()
{
    ::MessageBox(NULL, L"test", L"", MB_OK);
}

DLL Main cpp

// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    {
        ::MessageBox(NULL, L"DLL Injected", L"", MB_OK);
    }
    break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

def file

LIBRARY InjectedDLL
EXPORTS
test @1
dll
code-injection
getprocaddress
asked on Stack Overflow Dec 11, 2019 by ginoyaha

1 Answer

0

That is a lot of code to debug. What you're having a problem with is writing an external version of GetProcAddress which walks the export table. Instead of taking the time to debug your code I will supply a code which I know works. It is not my own code but I have used it before, the original author is iPower.

#define ReCa reinterpret_cast

uintptr_t GetProcAddressEx(HANDLE hProcess, DWORD pid, const char* module, const char* function)
{
    if (!module || !function || !pid || !hProcess)
        return 0;

    uintptr_t moduleBase = GetModuleBaseEx(module, pid); //toolhelp32snapshot method

    if (!moduleBase)
        return 0;

    IMAGE_DOS_HEADER Image_Dos_Header = { 0 };

    if (!ReadProcessMemory(hProcess, ReCa<LPCVOID>(moduleBase), &Image_Dos_Header, sizeof(IMAGE_DOS_HEADER), nullptr))
        return 0;

    if (Image_Dos_Header.e_magic != IMAGE_DOS_SIGNATURE)
        return 0;

    IMAGE_NT_HEADERS Image_Nt_Headers = { 0 };

    if (!ReadProcessMemory(hProcess, ReCa<LPCVOID>(moduleBase + Image_Dos_Header.e_lfanew), &Image_Nt_Headers, sizeof(IMAGE_NT_HEADERS), nullptr))
        return 0;

    if (Image_Nt_Headers.Signature != IMAGE_NT_SIGNATURE)
        return 0;

    IMAGE_EXPORT_DIRECTORY Image_Export_Directory = { 0 };
    uintptr_t img_exp_dir_rva = 0;

    if (!(img_exp_dir_rva = Image_Nt_Headers.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress))
        return 0;

    if (!ReadProcessMemory(hProcess, ReCa<LPCVOID>(moduleBase + img_exp_dir_rva), &Image_Export_Directory, sizeof(IMAGE_EXPORT_DIRECTORY), nullptr))
        return 0;

    uintptr_t EAT = moduleBase + Image_Export_Directory.AddressOfFunctions;
    uintptr_t ENT = moduleBase + Image_Export_Directory.AddressOfNames;
    uintptr_t EOT = moduleBase + Image_Export_Directory.AddressOfNameOrdinals;

    WORD ordinal = 0;
    SIZE_T len_buf = strlen(function) + 1;
    char* temp_buf = new char[len_buf];

    for (size_t i = 0; i < Image_Export_Directory.NumberOfNames; i++)
    {
        uintptr_t tempRvaString = 0;

        if (!ReadProcessMemory(hProcess, ReCa<LPCVOID>(ENT + (i * sizeof(uintptr_t))), &tempRvaString, sizeof(uintptr_t), nullptr))
            return 0;

        if (!ReadProcessMemory(hProcess, ReCa<LPCVOID>(moduleBase + tempRvaString), temp_buf, len_buf, nullptr))
            return 0;

        if (!lstrcmpi(function, temp_buf))
        {
            if (!ReadProcessMemory(hProcess, ReCa<LPCVOID>(EOT + (i * sizeof(WORD))), &ordinal, sizeof(WORD), nullptr))
                return 0;

            uintptr_t temp_rva_func = 0;

            if (!ReadProcessMemory(hProcess, ReCa<LPCVOID>(EAT + (ordinal * sizeof(uintptr_t))), &temp_rva_func, sizeof(uintptr_t), nullptr))
                return 0;

            delete[] temp_buf;
            return moduleBase + temp_rva_func;
        }
    }
    delete[] temp_buf;
    return 0;
}
answered on Stack Overflow Dec 30, 2019 by GuidedHacking

User contributions licensed under CC BY-SA 3.0