接上文: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;
}