大白兔联盟

文章搜索
搜索
当前位置:首页 > 前沿技术 > 逆向汇编 > 文章详情

[C++]反射式注入(ManualMap Inject) 3

大白兔    2023-4-11  311  0评论

接上文:https://www.dabaitulm.com/nxhb/1069.html

对于GetProcAddress的替代方案,大致的步骤为通过快照扫描到具体需要的模块地址,然后通过函数的导出表以及二分查找找出需要的函数,对于系统函数一般不必担心会出现找不到的情况,但是如果要调用进程内函数,可能会出现没有导出表的情况,以下为一个示例:

HINSTANCE _GetModuleHandleEx(HANDLE hTargetProc, const TCHAR* lpModuleName)
{
    MODULEENTRY32 ME32{ 0 };
    ME32.dwSize = sizeof(ME32);

    HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetProcessId(hTargetProc));
    if (hSnap == INVALID_HANDLE_VALUE)
    {
        while (GetLastError() == ERROR_BAD_LENGTH)
        {
            hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetProcessId(hTargetProc));
            if (hSnap != INVALID_HANDLE_VALUE) {
                break;
            }
        }
    }

    if (hSnap == INVALID_HANDLE_VALUE) {
        return NULL;
    }

    BOOL bRet = Module32First(hSnap, &ME32);
    do {
        if (!_tcsicmp(lpModuleName, ME32.szModule)) {
            break;
        }
        bRet = Module32Next(hSnap, &ME32);
    } while (bRet);

    CloseHandle(hSnap);

    if (!bRet) {
        return NULL;
    }

    return ME32.hModule;
}

PVOID GetProcAddressEx(HANDLE hTargetProc, const TCHAR* lpModuleName, const char* lpProcName)
{
    BYTE* modBase = (BYTE*)_GetModuleHandleEx(hTargetProc, lpModuleName);
    if (!modBase) {
        return nullptr;
    }

    BYTE* pe_header = new BYTE[0x1000];
    if (pe_header) {
        return nullptr;
    }

    if (!ReadProcessMemory(hTargetProc, modBase,
        pe_header, 0x1000, nullptr)) {
        delete[] pe_header;
        return nullptr;
    }

    IMAGE_NT_HEADERS* pNT = (IMAGE_NT_HEADERS*)(pe_header + ((IMAGE_DOS_HEADER*)pe_header)->e_lfanew);
    IMAGE_DATA_DIRECTORY* pExportEntry = &pNT->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
    if (!pExportEntry->Size) {
        delete[] pe_header;
        return nullptr;
    }

    BYTE* export_data = new BYTE[pExportEntry->Size];
    if (!export_data) {
        delete[] pe_header;
        return nullptr;
    }

    if (!ReadProcessMemory(hTargetProc, modBase + pExportEntry->VirtualAddress,
        export_data, pExportEntry->Size, nullptr)) {
        delete[] export_data;
        delete[] pe_header;
        return nullptr;
    }

    BYTE* localBase = export_data - pExportEntry->VirtualAddress;
    auto* pExportDir = (IMAGE_EXPORT_DIRECTORY*)(export_data);

    auto Forward = [&](DWORD FuncRVA) -> void*
    {
        char pFullExport[MAX_PATH + 1]{ 0 };
        auto Len = strlen((char*)(localBase + FuncRVA));
        if (!Len) {
            return nullptr;
        }

        memcpy(pFullExport, localBase + FuncRVA, Len);
        char* pFuncName = strchr(pFullExport, '.');
        *(pFuncName++) = 0;
        if (*pFuncName == '#')
        {
            pFuncName = (char*)(LOWORD(atoi(++pFuncName)));
        }
        return GetProcAddressEx(hTargetProc, pFullExport, pFuncName);
    };
    /*
    在 Windows 中,当编译器编译一个程序时,
    如果导出的函数没有使用 __declspec(dllexport) 或 .def 文件等手段明确指定函数名称和序号,
    那么编译器将使用一个默认的命名方案,该方案将给每个导出函数分配一个序号。
    这些序号从 1 开始,并按照它们在源代码中出现的顺序进行分配
    */
    if ((((UINT_PTR)lpProcName) & 0xffffff) <= MAXWORD)
    {
        WORD Base = LOWORD(pExportDir->Base - 1);
        WORD Ordinal = LOWORD(lpProcName) - Base;
        DWORD FuncRVA = ((DWORD*)(localBase + pExportDir->AddressOfFunctions))[Ordinal];

        delete[] export_data;
        delete[] pe_header;

        if (FuncRVA >= pExportEntry->VirtualAddress &&
            FuncRVA < pExportEntry->VirtualAddress + pExportEntry->Size) {
            return Forward(FuncRVA);
        }

        return modBase + FuncRVA;
    }

    DWORD max = pExportDir->NumberOfNames - 1;
    DWORD min = 0;
    DWORD FuncRVA = 0;
    // 二分查找
    while (min <= max)
    {
        DWORD mid = (min + max) / 2;
        DWORD CurrNameRVA = ((DWORD*)(localBase + pExportDir->AddressOfNames))[mid];
        char* szName = (char*)(localBase + CurrNameRVA);

        int cmp = strcmp(szName, lpProcName);
        if (cmp < 0) 
        {
            min = mid + 1;
        }
        else if (cmp > 0) 
        {
            max = mid + 1;
        }
        else
        {
            WORD Ordinal = ((WORD*)(localBase + pExportDir->AddressOfNameOrdinals))[mid];
            FuncRVA = ((DWORD*)(localBase + pExportDir->AddressOfFunctions))[Ordinal];
            break;
        }
    }

    delete[] export_data;
    delete[] pe_header;

    if (!FuncRVA) {
        return nullptr;
    }

    if (FuncRVA >= pExportEntry->VirtualAddress &&
        FuncRVA < pExportEntry->VirtualAddress + pExportEntry->Size) {
        return Forward(FuncRVA);
    }

    return modBase + FuncRVA;
}

免责声明

本站提供的一切软件、教程和内容信息仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络收集整理,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。如果您喜欢该程序和内容,请支持正版,购买注册,得到更好的正版服务。我们非常重视版权问题,如有侵权请邮件与我们联系处理。敬请谅解!

挤眼 亲亲 咆哮 开心 想想 可怜 糗大了 委屈 哈哈 小声点 右哼哼 左哼哼 疑问 坏笑 赚钱啦 悲伤 耍酷 勾引 厉害 握手 耶 嘻嘻 害羞 鼓掌 馋嘴 抓狂 抱抱 围观 威武 给力
提交评论

清空信息
关闭评论