1

I want to implement a full blown import reconstructor into my app without any external dll's or Shell Executes to EXEs. I want to just have the ability to get IAT Import addresses to certain imported DLL's by name or Ordinal. So I can easily patch the IAT to do hacks. At the moment I do this all by hand and have to rely on updating the IAT addresses for every function I am hooking I want this to be automatic by putting in dll name and dll import name and get the import addresses. If I hook using anything other then IAT.. like (DWORD)GetProcAddress("dllname", "import name"); it will be detected because it's hooking inside of a DLL that's outside the main game.. even though the anticheat also cares about editing the CODE of the Game itself same as it does for DLL's it doesn't seem to care about memory edits which is what IAT hooking does.

I tried a bunch of solutions such as PE-Sieve and libpeconv both don't handle packed IAT's..

I was going to make my own Auto Import Scanner.. but its too much work.. i need to first find a small x86 disasm and opcode length counter then I could loop the whole game EXE and scan for absolute addresses and double check them with *(DWORD*) against (DWORD)GetProcAddress("dllname", "import name"); if any of the addresses match then I found my IAT addresses.

– 8B0D MOV ECX,[ADDRESS]
– 8B15 MOV EDX,[ADDRESS]
– 8B1D MOV EBX,[ADDRESS]
– 8B25 MOV ESP,[ADDRESS]
– 8B2D MOV EBP,[ADDRESS]
– 8B35 MOV ESI,[ADDRESS]
– 8B3D MOV EDI,[ADDRESS]
– A1 MOV EAX,[ADDRESS]
- FF15 CALL [ADDRESS]
– FF25 JMP [ADDRESS]
– FF35 PUSH [ADDRESS]

Anyone got a code that already do this? or anything similar to this.. i would really appreciate it.

Here is what I got so far.. it kinda works gets 80-85% of all imports.. but the ones that are double jumped and some with crap instructions that needs a re-pass I'm still working on that anyone got these patterns complete?

#define ResolveRVA(base,rva) (( (uint8_t*)base) +rva)
#define RVA2VA(type, base, rva) (type)((ULONG_PTR) base + rva)

BOOL SnapShotModules(DWORD dwPID)
{
    BOOL           bRet = TRUE;

    // Get all modules for this process:
    std::vector<HMODULE> hModules;
    const HMODULE hSelf = GetModuleHandle(NULL);
    {
        DWORD nModules;
        EnumProcessModules(GetCurrentProcess(), NULL, 0, &nModules);
        hModules.resize(nModules);
        EnumProcessModules(GetCurrentProcess(), &hModules[0], nModules, &nModules);
    }

    if (!hSelf)
    {
        printf("Invalid Process Handle\n");
        return FALSE;
    }

    gs_ModuleList.clear();

    IAT_Module_Info modulefullInfo = { 0 };
    MODULEINFO modinfo = { 0 };
    char moduleName[256] = { 0 };
    char moduleFileName[1000] = { 0 };

    char myProcessFilePath[1000] = { 0 };
    GetModuleFileNameExA(GetCurrentProcess(), NULL, myProcessFilePath, 1000);
    LPCSTR MyProcessFileName = PathFindFileName(myProcessFilePath);
    for (auto hModule : hModules) {
        if (hModule == hSelf)
            continue;

        GetModuleInformation(GetCurrentProcess(), hModule, &modinfo, sizeof(modinfo));
        GetModuleBaseName(GetCurrentProcess(), hModule, moduleName, sizeof(moduleName) / sizeof(char));
        GetModuleFileName(hModule, moduleFileName, sizeof(moduleFileName) / sizeof(char));
        if (_strcmpi(moduleName, MyProcessFileName) == 0) continue;
        strcpy(modulefullInfo.DllName, moduleName);
        modulefullInfo.ImageSize = modinfo.SizeOfImage;
        modulefullInfo.ImageBase = (DWORD)modinfo.lpBaseOfDll;
        modulefullInfo.EntryPoint = (BYTE*)modinfo.EntryPoint;
        strcpy(modulefullInfo.DllFileName, moduleFileName);
        gs_ModuleList.push_back(modulefullInfo);
    }

    return TRUE;
}

/************************************************************************/
/*
Function : Retrieve API info by its addr and the module it belongs to
Params   : pBuf points to the image mapped to our space*/
/************************************************************************/
void GetAPIInfo(DWORD ptrAPI, const IAT_Module_Info *iat_module_info, DWORD ptrAPIObfuscated = NULL)
{
    //try to load the dll into our space
    HMODULE hDll = NULL;
    if(iat_module_info)
        hDll = LoadLibrary(iat_module_info->DllFileName);

    if (NULL == hDll)
        return;

    //now ask for info from Export
    PIMAGE_DOS_HEADER pDOSHDR = (PIMAGE_DOS_HEADER)hDll;
    PIMAGE_NT_HEADERS pNTHDR = (PIMAGE_NT_HEADERS)((BYTE *)pDOSHDR + pDOSHDR->e_lfanew);
    if (pNTHDR->OptionalHeader.NumberOfRvaAndSizes < IMAGE_DIRECTORY_ENTRY_EXPORT + 1)
        return;

    PIMAGE_EXPORT_DIRECTORY pExpDIR = (PIMAGE_EXPORT_DIRECTORY)
        ((BYTE *)pDOSHDR
            + pNTHDR->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
    DWORD dwFunctions = pExpDIR->NumberOfFunctions;
    DWORD *ptrAddrFunc = (DWORD *)((BYTE *)pDOSHDR + pExpDIR->AddressOfFunctions);
    DWORD i = 0;

    //get index by address
    for (i = 0; i < dwFunctions; i++)
    {
        if (ptrAPIObfuscated && ((DWORD)pDOSHDR + ptrAddrFunc[i]) == ptrAPIObfuscated)
            break;
        if (!ptrAPIObfuscated && ((DWORD)pDOSHDR + ptrAddrFunc[i]) == *(DWORD*)ptrAPI)
            break;
    }

    //not match
    if (i == dwFunctions)
        return;

    //get name and ordinal
    DWORD dwNames = pExpDIR->NumberOfNames;
    DWORD *pNames = (DWORD *)((BYTE *)pDOSHDR + pExpDIR->AddressOfNames);
    WORD *pNameOrd = (WORD *)((BYTE *)pDOSHDR + pExpDIR->AddressOfNameOrdinals);
    DWORD j = 0;
    char *pszName = NULL;
    SIZE_T nLen = 0;
    for (j = 0; j < dwNames; j++)
    {
        if (pNameOrd[j] == i)
        {
            pszName = (char *)pDOSHDR + pNames[j];
            nLen = strlen(pszName);
            /*printf("%X\t%04X\t%s\n",
                *(DWORD *)ptrAPI,
                j,
                pszName
            );*/

            //Save information
            IAT_Import_Information iat_found = { 0 };
            iat_found.IATAddress = ptrAPI;
            strcpy(iat_found.IATFunctionName, pszName);
            strcpy(iat_found.IATModuleName, iat_module_info->DllName);
            listOfIATImports.push_back(iat_found);
            if(ptrAPIObfuscated)
                printf("Added Obfuscated %X %X, %s -> %s\n", ptrAPI, ptrAPIObfuscated, iat_module_info->DllName, pszName);
            else
                printf("Added %X %X, %s -> %s\n", ptrAPI, *(DWORD*)ptrAPI, iat_module_info->DllName, pszName);
        }
    }
}

/************************************************************************/
/*
Function : rebuild Import Info according to IAT
Params   : ptrIAT point to the page where IAT in
ppBuf [IN/OUT] is the memory space for the exe, may be updated
dwImageSize is the exe's image size                                                                  */
/************************************************************************/
void FixImport(DWORD dwPID, DWORD ptrIAT, DWORD ptrIATEnd, DWORD dwImageSize)
{
    if (gs_ModuleList.size() == 0) {
        printf("No Modules loaded, can't fix anything\n");
        return;
    }

    //now verify every DWORD item is a valid FuncPtr with some dll.
    //we need to snapshot the process.
    std::list<IAT_Module_Info>::iterator it;
    IAT_Module_Info iat_module_info;
    printf("ptrIAT = %X ptrIATEnd = %X\n", ptrIAT, ptrIATEnd);

    DWORD ptrIndex = ptrIAT;
    DWORD dwModBase = NULL;  //????????????
    DWORD dwModSize = NULL;
    DWORD dwModHit = NULL;
    while (TRUE)
    {
        //thz should always continue, even if BadPtr or invalid funcptr
        if (ptrIndex <= ptrIATEnd
            && IsBadReadPtr((const void *)*(DWORD *)ptrIndex, sizeof(DWORD)))
        {
            ptrIndex += sizeof(DWORD);
            continue;
        }

        //now we may end, be careful
        if (ptrIndex > ptrIATEnd
            && (NULL == *(DWORD*)ptrIndex)
            && (NULL == *(DWORD*)(ptrIndex + sizeof(DWORD))))
        {
            break;
        }

        if (ptrIndex > ptrIATEnd
            && IsBadReadPtr((const void *)*(DWORD *)ptrIndex, sizeof(DWORD))
            )
        {
            ptrIndex += sizeof(DWORD);
            continue;
        }

        //////////////////////////////////////////////////////////////////////////
        //whether in a module range
        dwModHit = NULL;

        //??????????
        if (*(DWORD *)ptrIndex >= dwModBase
            && *(DWORD *)ptrIndex < dwModBase + dwModSize)
        {
            dwModHit = dwModBase;
        }

        //have to loop every module
        if (dwModHit == NULL)
        {
            for (it = gs_ModuleList.begin(); it != gs_ModuleList.end(); it++)
            {
                iat_module_info = *it;
                dwModBase = (DWORD)iat_module_info.ImageBase;
                dwModSize = (DWORD)iat_module_info.ImageSize;

                if (*(DWORD *)ptrIndex >= dwModBase
                    && *(DWORD *)ptrIndex < dwModBase + dwModSize)
                {
                    //printf("ptrIndex %X %X, Mod: %X, Size: %X\n", *(DWORD *)ptrIndex, ptrIndex, dwModBase, dwModSize);
                    //printf("Module: %s\n", iat_module_info.DllName);
                    break;
                }
                memset(&iat_module_info, 0, sizeof(IAT_Module_Info));
            }//end for(
        }//end if(NULL == 

        if (iat_module_info.ImageBase == 0 && iat_module_info.ImageSize == 0) {
            bool passDone = false;
            DWORD deObfuscatedAddress = *(DWORD*)ptrIndex;
            retryPass:
            printf("%X %X\n", (BYTE)deObfuscatedAddress, *(BYTE*)deObfuscatedAddress);
            if (*(BYTE*)deObfuscatedAddress == 0xE9) //JMP relative
                deObfuscatedAddress = (*(DWORD*)(deObfuscatedAddress + 1)) + deObfuscatedAddress + 5;
            else if (*(BYTE*)deObfuscatedAddress == 0x68) { //PUSH
                printf("PUSH = %X %X\n", deObfuscatedAddress, *(DWORD*)(deObfuscatedAddress + 1));
                deObfuscatedAddress = *(DWORD*)(deObfuscatedAddress + 1);
            }
            else if ((BYTE)deObfuscatedAddress == 0xC0) { //shl (invalid opcode)
                printf("invalid = %X %X %X\n", ptrIndex, deObfuscatedAddress, (DWORD*)deObfuscatedAddress);
                deObfuscatedAddress = *(DWORD*)(ptrIndex + insn_len((void*)ptrIndex));
                printf("invalid = %X %X %X\n", ptrIndex, deObfuscatedAddress, (DWORD*)deObfuscatedAddress);
                passDone = true;
                goto retryPass;
            } else if ((BYTE)deObfuscatedAddress == 0xC8) { //enter (invalid opcode)
                printf("invalid = %X %X %X\n", ptrIndex, deObfuscatedAddress, (DWORD*)deObfuscatedAddress);
                deObfuscatedAddress = *(DWORD*)(ptrIndex + insn_len((void*)ptrIndex));
                printf("invalid = %X %X %X\n", ptrIndex, deObfuscatedAddress, (DWORD*)deObfuscatedAddress);
                passDone = true;
                goto retryPass;
            } else {
                if (passDone) goto continueGo;
                printf("b unknown deob %X %X %X %X\n", ptrIndex, *(BYTE*)ptrIndex, *(DWORD*)ptrIndex, deObfuscatedAddress);
                deObfuscatedAddress += insn_len((void*)deObfuscatedAddress);
                printf("a unknown deob %X %X %X %X\n", ptrIndex, *(BYTE*)ptrIndex, *(DWORD*)ptrIndex, deObfuscatedAddress);
                passDone = true;
                goto retryPass;
            }
            continueGo:
            for (it = gs_ModuleList.begin(); it != gs_ModuleList.end(); it++)
            {
                iat_module_info = *it;
                dwModBase = (DWORD)iat_module_info.ImageBase;
                dwModSize = (DWORD)iat_module_info.ImageSize;

                if (deObfuscatedAddress >= dwModBase
                    && deObfuscatedAddress < dwModBase + dwModSize)
                {
                    //printf("ptrIndex %X %X, Mod: %X, Size: %X\n", deObfuscatedAddress, ptrIndex, dwModBase, dwModSize);
                    //printf("Module: %s\n", iat_module_info.DllName);
                    break;
                }
                memset(&iat_module_info, 0, sizeof(IAT_Module_Info));
            }
            GetAPIInfo(ptrIndex, &iat_module_info, deObfuscatedAddress);
            ptrIndex += sizeof(DWORD);
            memset(&iat_module_info, 0, sizeof(IAT_Module_Info));
            continue;
        }

        //now *ptrIndex in dwModBase
        //now retrieve API info (Hint, name) from the module's export
        //printf("ptrIndex %X %X, Mod: %X, Size: %X\n", *(DWORD *)ptrIndex, ptrIndex, dwModBase, dwModSize);
        GetAPIInfo(ptrIndex, &iat_module_info);
        ptrIndex += sizeof(DWORD);
    }
}

/************************************************************************/
/*
Function : Get AddressOfEntryPoint  (or Original Entry Point)
Params   : lpAddr is the Base where the exe mapped into
Return   : OEP (RVA)             */
/************************************************************************/
DWORD GetOEP(LPVOID lpAddr)
{
    PIMAGE_DOS_HEADER pDOSHDR = (PIMAGE_DOS_HEADER)lpAddr;
    PIMAGE_NT_HEADERS pNTHDR = (PIMAGE_NT_HEADERS)((unsigned char *)pDOSHDR + pDOSHDR->e_lfanew);
    return pNTHDR->OptionalHeader.AddressOfEntryPoint;
}

/************************************************************************/
/*
Function : Retrieve a process's Import Info only by IAT
Param    : lpAddr is the address the exe mapped into (within our space)
ptrIATEnd [out] used to receive the 1st IAT we found (FF25 XXXX, FF15YYYY)
Return   : the beginning of the page where IAT in
Search for FF25 XXXX,  or FF15 yyyy
HelloWorld.exe
004001E0 > .  EA07D577      DD USER32.MessageBoxA
004001E4      00000000      DD 00000000
004001E8 >/$  6A 00         PUSH 0                                   ; /Style = MB_OK|MB_APPLMODAL
004001EA  |.  6A 00         PUSH 0                                   ; |Title = NULL
004001EC  |.  6A 00         PUSH 0                                   ; |Text = NULL
004001EE  |.  6A 00         PUSH 0                                   ; |hOwner = NULL
004001F0  |.  E8 01000000   CALL <JMP.&USER32.MessageBoxA>           ; \MessageBoxA
004001F5  \.  C3            RETN
004001F6   $- FF25 E0014000 JMP DWORD PTR DS:[<&USER32.MessageBoxA>] ;  USER32.MessageBoxA
Notepad.exe
0100740B   .  FF15 38130001      CALL DWORD PTR DS:[<&msvcrt.__set_app_ty>;  msvcrt.__set_app_type
MSPaint.exe
1000CA65    8B35 58D10110   MOV ESI,DWORD PTR DS:[<&KERNEL32.LCMapSt>; kernel32.LCMapStringW
*/
/************************************************************************/

/*
Need to check all of these
– 8B0D MOV ECX,[ADDRESS]
– 8B15 MOV EDX,[ADDRESS]
– 8B1D MOV EBX,[ADDRESS]
– 8B25 MOV ESP,[ADDRESS]
– 8B2D MOV EBP,[ADDRESS]
– 8B35 MOV ESI,[ADDRESS]
– 8B3D MOV EDI,[ADDRESS]
– A1 MOV EAX,[ADDRESS]
- FF15 CALL [ADDRESS]
– FF25 JMP [ADDRESS]
– FF35 PUSH [ADDRESS]
*/

DWORD SearchIAT(LPVOID lpAddr, DWORD dwImageSize, DWORD pImageBase, DWORD dwMaxIATImageSize, DWORD *ptrIATEnd)
{
    DWORD pImageSectionStart = 0;
    DWORD instruction_length;
    DWORD *ptrFuncAddr = NULL;     //like xxx in JMP DWORD PTR DS:[XXXX]
    DWORD ptrFuncAddrHighest = NULL;
    DWORD dwOEP = NULL;
    BYTE *pCode = NULL;
    DWORD i = NULL;
    WORD  wJMP = 0x25FF;
    WORD  wCALL = 0x15FF;

    dwOEP = GetOEP(lpAddr);
    i = dwOEP;
    pCode = (BYTE *)((BYTE *)lpAddr + dwOEP);

    // get the location of the module's IMAGE_NT_HEADERS structure
    IMAGE_NT_HEADERS *pNtHdr = ImageNtHeader(lpAddr);
    // section table immediately follows the IMAGE_NT_HEADERS
    IMAGE_SECTION_HEADER *pSectionHdr = (IMAGE_SECTION_HEADER *)(pNtHdr + 1);

    bool got = false;
    for (int scn = 0; scn < pNtHdr->FileHeader.NumberOfSections; ++scn)
    {
        char *name = (char*)pSectionHdr->Name;
        DWORD SectionStart = (DWORD)lpAddr + pSectionHdr->VirtualAddress;
        DWORD SectionEnd = (DWORD)lpAddr + pSectionHdr->VirtualAddress + pSectionHdr->Misc.VirtualSize - 1;

        if (got) {
            pImageSectionStart = SectionStart;
            break;
        }

        if (SectionStart == pImageBase + dwOEP && SectionEnd < dwImageSize) {
            got = true;
            //next one is imports.
            ++pSectionHdr;
            continue;
        }
        ++pSectionHdr;
    }

    if (!pImageSectionStart)
        pImageSectionStart = dwImageSize;

    printf("Found OEP at %X, ImageSize = %X,%X\n", dwOEP, dwImageSize, pImageSectionStart);

    //search for FF 25 XXXX, FF 15 YYYY from OEP, had better use Disasm engine 
    //but we just do it simply
    while (i < pImageSectionStart)
    {
        if (memcmp(pCode, &wJMP, sizeof(WORD))
            && memcmp(pCode, &wCALL, sizeof(WORD)))
        {
            //
            instruction_length = insn_len(pCode);
            pCode += instruction_length;
            i += instruction_length;
            continue;
        }

        //check illegal, *ptrFuncAddr > pImageBase  && *ptrFuncAddr <= pImageBase + dwImageSize
        ptrFuncAddr = (DWORD *)(pCode + sizeof(WORD));
        if (*ptrFuncAddr < (DWORD)pImageBase || *ptrFuncAddr >= (DWORD)pImageBase + dwImageSize)
        {
            instruction_length = insn_len(pCode);
            pCode += instruction_length;
            i += instruction_length;
            continue;
        }

        //need to fix relocation
        *(DWORD *)ptrFuncAddr = (long)lpAddr + *(long *)ptrFuncAddr - (long)pImageBase;
        //now found one item that may belongs to IAT
        ptrFuncAddr = (DWORD *)*ptrFuncAddr;

        if ((DWORD)ptrFuncAddr > ptrFuncAddrHighest) {
            ptrFuncAddrHighest = (DWORD)ptrFuncAddr;
            printf("highest = %X\n", ptrFuncAddrHighest);
        }

        //recheck illegal, 
        //for system dlls, what about user dlls? well, whatever, there must be system dlls
        //what if we found IAT for system dlls, so we found the user dlls.
        //What if the IAT tables are not continous????????
        if (*ptrFuncAddr < dwMaxIATImageSize)
        {
            instruction_length = insn_len(pCode);
            pCode += instruction_length;
            i += instruction_length;
            continue;
        }
        break;
    }

    //now it seems ptrFuncAddr points some item in IAT, 
    //make ptrFuncAddr point to the beginning of the page
    //we use 0xFFFEFFFF, because ptrFuncAddr is the memory addr we allocated, not by loadlibrary
    *ptrIATEnd = (DWORD)ptrFuncAddrHighest;
    ptrFuncAddr = (DWORD*)(((DWORD)ptrFuncAddr & 0xFFFFF000)
        + ((DWORD)lpAddr & 0x0FFF)
        );
    return (DWORD)ptrFuncAddr;

    //return NULL;
}

unsigned long Get_Import_Address(char* DLL, char* Library, char* Import, int ordinal = -1)
{
    HMODULE mhLoadedDLL = NULL;
    do
    {
        if (!DLL)
            mhLoadedDLL = GetModuleHandle(NULL);
        else
            mhLoadedDLL = GetModuleHandle(DLL);
        Sleep(100);
    } while (!mhLoadedDLL);

    MODULEINFO modinfo;
    GetModuleInformation(GetCurrentProcess(), mhLoadedDLL, &modinfo, sizeof(MODULEINFO));
    DWORD ModuleSize = (unsigned long)modinfo.SizeOfImage;

    PIMAGE_DOS_HEADER DosHeader = (PIMAGE_DOS_HEADER)mhLoadedDLL;
    PIMAGE_NT_HEADERS NtHeader;
    PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
    UINT Index = 0;


    NtHeader = (PIMAGE_NT_HEADERS)(((PBYTE)DosHeader) + DosHeader->e_lfanew);
    if (NtHeader->Signature != IMAGE_NT_SIGNATURE)
        return 0;

    ImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(((PBYTE)DosHeader) + NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);

    if (mhLoadedDLL) {
        ULONG Sz;
        ImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToDataEx(mhLoadedDLL, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &Sz, nullptr);
    }

    __try {
        //
        // Iterate over import descriptors/DLLs.
        //
        for (Index = 0; (ImportDescriptor[Index].Characteristics != 0 || ImportDescriptor[Index].Name); Index++) {
            PSTR dllName = (PSTR)(((PBYTE)DosHeader) + ImportDescriptor[Index].Name);

            if (_strcmpi(dllName, Library) == 0) {
                // This the DLL we are after.
                PIMAGE_THUNK_DATA Thunk;
                PIMAGE_THUNK_DATA OrigThunk;

                Thunk = (PIMAGE_THUNK_DATA)(((PBYTE)DosHeader) + ImportDescriptor[Index].FirstThunk);
                OrigThunk = (PIMAGE_THUNK_DATA)(((PBYTE)DosHeader) + ImportDescriptor[Index].OriginalFirstThunk);

                //Reset
                Thunk = (PIMAGE_THUNK_DATA)(((PBYTE)DosHeader) + ImportDescriptor[Index].FirstThunk);
                OrigThunk = (PIMAGE_THUNK_DATA)(((PBYTE)DosHeader) + ImportDescriptor[Index].OriginalFirstThunk);

                for (; OrigThunk->u1.Function != NULL; OrigThunk++, Thunk++)
                {
                    if (ordinal != -1) {
                        if ((OrigThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG) && IMAGE_ORDINAL(OrigThunk->u1.Ordinal) == ordinal) //send ordinal
                            return (DWORD)Thunk; //Address of import returns.
                    }

                    if (OrigThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG) { // Ordinal import - we can handle named imports only, so skip it.
                        continue;
                    }

                    PIMAGE_IMPORT_BY_NAME importt = (PIMAGE_IMPORT_BY_NAME)(((PBYTE)DosHeader) + OrigThunk->u1.AddressOfData);

                    if (_strcmpi(Import, (char*)importt->Name) == 0) {
                        return (DWORD)Thunk; //Address of import returns.
                    }
                }

                unsigned long ptrFuncsIndex = (unsigned long)ImportDescriptor[Index].FirstThunk + (DWORD)mhLoadedDLL;
                DWORD impAddress = (DWORD)GetProcAddress(GetModuleHandle(Library), Import);

                //First get all modules loaded, so you can find the maximum ImageBase+ImageSize for IAT Max Size calculation.
                if (gs_ModuleList.size() == 0) {
                    BOOL bRet = SnapShotModules((DWORD)GetCurrentProcess());
                    if (!bRet)
                    {
                        printf("Failed to get Modules\n");
                        return 0;
                    }
                }

                DWORD dwMaxIATImageSize = 0x70000000;
                if (gs_ModuleList.size() > 0) {
                    auto max_it = std::max_element(gs_ModuleList.begin(), gs_ModuleList.end(), [](const IAT_Module_Info& l, const IAT_Module_Info& h) {
                        return l.ImageBase < h.ImageBase;
                    });

                    if (max_it->ImageBase > 0)
                        dwMaxIATImageSize = (DWORD)max_it->ImageBase + max_it->ImageSize;

                    printf("Highest Imported DLL = %X %s\n", max_it->ImageBase, max_it->DllName);
                }
                //now we do more, retrieve the Page where IAT in
                DWORD ptrIATEnd = NULL;
                DWORD ptrIAT = SearchIAT(mhLoadedDLL, ModuleSize, NtHeader->OptionalHeader.ImageBase, dwMaxIATImageSize, &ptrIATEnd);

                printf("Rebuilding IAT,Found IAT in page %X, IAT End %X\n", ptrIAT, ptrIATEnd);
                if(listOfIATImports.size() == 0)
                    FixImport((DWORD)GetCurrentProcess(), ptrIAT, ptrIATEnd, ModuleSize);

                if (listOfIATImports.size() > 0) {
                    auto match = std::find_if(listOfIATImports.cbegin(), listOfIATImports.cend(), [Library, Import](const IAT_Import_Information& s) {
                        return _strcmpi(s.IATModuleName, Library) == 0 && _strcmpi(s.IATFunctionName, Import) == 0;
                    });

                    if (match != listOfIATImports.cend()) {
                        printf("Found IAT = %X, %s %s\n", match->IATAddress, match->IATModuleName, match->IATFunctionName);
                    }

                    std::list<IAT_Import_Information>::iterator i;
                    for (i = listOfIATImports.begin();
                        i != listOfIATImports.end();
                        i++)
                    {
                        printf("Module: %s Import: %s Address: %X\n", i->IATModuleName, i->IATFunctionName, i->IATAddress);
                    }

                } else {
                    printf("Couldn't find module %s, import %s\n", Library, Import);
                }

            }
        }
    }
    __except (1) {
        printf("Exception hit parsing imports\n");
    }
    return 0;
}

1 Answer 1

1

Here is my final code.. it works.. gets all imports except a missing a few like 10 at most.. which are hardly important anyways. It misses GetCurrentProcessId(),GetCurrentProcess(),LoadLibrary. It misses them because I have no idea how to decode 0xA1 (MOV EAX, [XXXXXX]) opcode or 0xFF35 opcode (push [XXXXXX]). Although this library is very useful to me and it will help me in many projects to come.. I will release it on github now.

imports address revolver file contains this

#include <psapi.h> //GetModuleInformation IAT
#include <tlhelp32.h> //MODULEENTRY32 IAT
#include <shlwapi.h> //PathFindFileName IAT
#include <DbgHelp.h> //detours, GetImports, PE information BaseAddressStart/End etc.
#include <unordered_set> //std::unordered_set<DWORD>
#include <unordered_map> //std::map
#include <string>
#include <algorithm>
#include <iterator>
#include <vector>

#pragma comment(lib, "dbghelp.lib")
#pragma comment(lib, "psapi.lib") //GetModuleInformation IAT
#pragma comment(lib, "Shlwapi.lib") //PathFindFileName IAT

struct IAT_Module_Info
{
    DWORD ImageBase;
    DWORD ImageSize;
    BYTE* EntryPoint;
    char DllName[256];
    char DllFileName[1000];
};

static std::list<IAT_Module_Info> gs_ModuleList;

struct IAT_Import_Information
{
    DWORD IATAddress;
    char IATModuleName[256];
    char IATFunctionName[256];
};

static std::list<IAT_Import_Information> listOfIATImports;


BOOL SnapShotModules(DWORD dwPID)
{
    BOOL           bRet = TRUE;

    // Get all modules for this process:
    std::vector<HMODULE> hModules;
    const HMODULE hSelf = GetModuleHandle(NULL);
    {
        DWORD nModules;
        EnumProcessModules(GetCurrentProcess(), NULL, 0, &nModules);
        hModules.resize(nModules);
        EnumProcessModules(GetCurrentProcess(), &hModules[0], nModules, &nModules);
    }

    if (!hSelf)
    {
        printf("Invalid Process Handle\n");
        return FALSE;
    }

    gs_ModuleList.clear();

    IAT_Module_Info modulefullInfo = { 0 };
    MODULEINFO modinfo = { 0 };
    char moduleName[256] = { 0 };
    char moduleFileName[1000] = { 0 };

    char myProcessFilePath[1000] = { 0 };
    GetModuleFileNameExA(GetCurrentProcess(), NULL, myProcessFilePath, 1000);
    LPCSTR MyProcessFileName = PathFindFileName(myProcessFilePath);
    for (auto hModule : hModules) {
        if (hModule == hSelf)
            continue;

        GetModuleInformation(GetCurrentProcess(), hModule, &modinfo, sizeof(modinfo));
        GetModuleBaseName(GetCurrentProcess(), hModule, moduleName, sizeof(moduleName) / sizeof(char));
        GetModuleFileName(hModule, moduleFileName, sizeof(moduleFileName) / sizeof(char));
        if (_strcmpi(moduleName, MyProcessFileName) == 0) continue;
        strcpy(modulefullInfo.DllName, moduleName);
        modulefullInfo.ImageSize = modinfo.SizeOfImage;
        modulefullInfo.ImageBase = (DWORD)modinfo.lpBaseOfDll;
        modulefullInfo.EntryPoint = (BYTE*)modinfo.EntryPoint;
        strcpy(modulefullInfo.DllFileName, moduleFileName);
        gs_ModuleList.push_back(modulefullInfo);
    }

    return TRUE;
}

/************************************************************************/
/*
Function : Retrieve API info by its addr and the module it belongs to
Params   : pBuf points to the image mapped to our space*/
/************************************************************************/
void GetAPIInfo(DWORD ptrAPI, const IAT_Module_Info *iat_module_info, DWORD ptrAPIObfuscated = NULL)
{
    //try to load the dll into our space
    HMODULE hDll = NULL;
    if(iat_module_info)
        hDll = LoadLibrary(iat_module_info->DllFileName);

    if (NULL == hDll)
        return;

    //now ask for info from Export
    PIMAGE_DOS_HEADER pDOSHDR = (PIMAGE_DOS_HEADER)hDll;
    PIMAGE_NT_HEADERS pNTHDR = (PIMAGE_NT_HEADERS)((BYTE *)pDOSHDR + pDOSHDR->e_lfanew);
    if (pNTHDR->OptionalHeader.NumberOfRvaAndSizes < IMAGE_DIRECTORY_ENTRY_EXPORT + 1)
        return;

    PIMAGE_EXPORT_DIRECTORY pExpDIR = (PIMAGE_EXPORT_DIRECTORY)
        ((BYTE *)pDOSHDR
            + pNTHDR->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
    DWORD dwFunctions = pExpDIR->NumberOfFunctions;
    DWORD *ptrAddrFunc = (DWORD *)((BYTE *)pDOSHDR + pExpDIR->AddressOfFunctions);
    DWORD i = 0;

    //get index by address
    for (i = 0; i < dwFunctions; i++)
    {
        if (ptrAPIObfuscated && ((DWORD)pDOSHDR + ptrAddrFunc[i]) == ptrAPIObfuscated)
            break;
        if (!ptrAPIObfuscated && ((DWORD)pDOSHDR + ptrAddrFunc[i]) == *(DWORD*)ptrAPI)
            break;
    }

    //not match
    if (i == dwFunctions)
        return;

    //get name and ordinal
    DWORD dwNames = pExpDIR->NumberOfNames;
    DWORD *pNames = (DWORD *)((BYTE *)pDOSHDR + pExpDIR->AddressOfNames);
    WORD *pNameOrd = (WORD *)((BYTE *)pDOSHDR + pExpDIR->AddressOfNameOrdinals);
    DWORD j = 0;
    char *pszName = NULL;
    SIZE_T nLen = 0;
    for (j = 0; j < dwNames; j++)
    {
        if (pNameOrd[j] == i)
        {
            pszName = (char *)pDOSHDR + pNames[j];
            nLen = strlen(pszName);
            /*printf("%X\t%04X\t%s\n",
                *(DWORD *)ptrAPI,
                j,
                pszName
            );*/

            //Save information
            IAT_Import_Information iat_found = { 0 };
            iat_found.IATAddress = ptrAPI;
            strcpy(iat_found.IATFunctionName, pszName);
            strcpy(iat_found.IATModuleName, iat_module_info->DllName);
            listOfIATImports.push_back(iat_found);
            if(ptrAPIObfuscated)
                printf("Added Obfuscated %X %X, %s -> %s\n", ptrAPI, ptrAPIObfuscated, iat_module_info->DllName, pszName);
            else
                printf("Added %X %X, %s -> %s\n", ptrAPI, *(DWORD*)ptrAPI, iat_module_info->DllName, pszName);
        }
    }
}

/************************************************************************/
/*
Function : rebuild Import Info according to IAT
Params   : ptrIAT point to the page where IAT in
ppBuf [IN/OUT] is the memory space for the exe, may be updated
dwImageSize is the exe's image size                                                                  */
/************************************************************************/
void FixImport(DWORD dwPID, DWORD ptrIAT, DWORD ptrIATEnd, DWORD dwImageSize)
{
    if (gs_ModuleList.size() == 0) {
        printf("No Modules loaded, can't fix anything\n");
        return;
    }

    //now verify every DWORD item is a valid FuncPtr with some dll.
    //we need to snapshot the process.
    std::list<IAT_Module_Info>::iterator it;
    IAT_Module_Info iat_module_info;
    printf("ptrIAT = %X ptrIATEnd = %X\n", ptrIAT, ptrIATEnd);

    DWORD ptrIndex = ptrIAT;
    DWORD dwModBase = NULL;  //利用局部性原理,减少比较
    DWORD dwModSize = NULL;
    DWORD dwModHit = NULL;
    while (TRUE)
    {
        //thz should always continue, even if BadPtr or invalid funcptr
        if (ptrIndex <= ptrIATEnd
            && IsBadReadPtr((const void *)*(DWORD *)ptrIndex, sizeof(DWORD)))
        {
            ptrIndex += sizeof(DWORD);
            continue;
        }

        //now we may end, be careful
        if (ptrIndex > ptrIATEnd
            && (NULL == *(DWORD*)ptrIndex)
            && (NULL == *(DWORD*)(ptrIndex + sizeof(DWORD))))
        {
            break;
        }

        if (ptrIndex > ptrIATEnd
            && IsBadReadPtr((const void *)*(DWORD *)ptrIndex, sizeof(DWORD))
            )
        {
            ptrIndex += sizeof(DWORD);
            continue;
        }

        //////////////////////////////////////////////////////////////////////////
        //whether in a module range
        dwModHit = NULL;

        //局部性原理,减少遍历
        if (*(DWORD *)ptrIndex >= dwModBase
            && *(DWORD *)ptrIndex < dwModBase + dwModSize)
        {
            dwModHit = dwModBase;
        }

        //have to loop every module
        if (dwModHit == NULL)
        {
            for (it = gs_ModuleList.begin(); it != gs_ModuleList.end(); it++)
            {
                iat_module_info = *it;
                dwModBase = (DWORD)iat_module_info.ImageBase;
                dwModSize = (DWORD)iat_module_info.ImageSize;

                if (*(DWORD *)ptrIndex >= dwModBase
                    && *(DWORD *)ptrIndex < dwModBase + dwModSize)
                {
                    //printf("ptrIndex %X %X, Mod: %X, Size: %X\n", *(DWORD *)ptrIndex, ptrIndex, dwModBase, dwModSize);
                    //printf("Module: %s\n", iat_module_info.DllName);
                    break;
                }
                memset(&iat_module_info, 0, sizeof(IAT_Module_Info));
            }//end for(
        }//end if(NULL == 

        if (iat_module_info.ImageBase == 0 && iat_module_info.ImageSize == 0) {
            bool passDone = false;
            bool Found = false;
            IAT_Module_Info iat_module_info_temp;

            DWORD deObfuscatedAddress = *(DWORD*)ptrIndex;
            retryPass:
            printf("Check = %X %X %X\n", deObfuscatedAddress, (BYTE)deObfuscatedAddress, *(BYTE*)deObfuscatedAddress);

            for (it = gs_ModuleList.begin(); it != gs_ModuleList.end(); it++)
            {
                iat_module_info_temp = *it;
                dwModBase = (DWORD)iat_module_info_temp.ImageBase;
                dwModSize = (DWORD)iat_module_info_temp.ImageSize;

                if (deObfuscatedAddress >= dwModBase
                    && deObfuscatedAddress < dwModBase + dwModSize)
                {
                    //printf("ptrIndex %X %X, Mod: %X, Size: %X\n", deObfuscatedAddress, ptrIndex, dwModBase, dwModSize);
                    //printf("Module: %s\n", iat_module_info.DllName);
                    Found = true;
                    break;
                }
            }
            if (Found) {
                printf("Found Check = %X\n", deObfuscatedAddress);
                GetAPIInfo(ptrIndex, &iat_module_info_temp, deObfuscatedAddress);
                ptrIndex += sizeof(DWORD);
                continue;
            } else if (!passDone) {
                passDone = true;
                if (*(BYTE*)deObfuscatedAddress == 0xE9) //JMP relative
                    deObfuscatedAddress = (*(DWORD*)(deObfuscatedAddress + 1)) + deObfuscatedAddress + 5;
                else if (*(BYTE*)deObfuscatedAddress == 0x68 && *(BYTE*)(deObfuscatedAddress + 5) == 0xC3) { //PUSH
                    printf("PUSH = %X %X +5[%X]\n", deObfuscatedAddress, *(DWORD*)(deObfuscatedAddress + 1), *(BYTE*)(deObfuscatedAddress + 5));
                    deObfuscatedAddress = *(DWORD*)(deObfuscatedAddress + 1);
                } else if (*(BYTE*)deObfuscatedAddress == 0xA1 && *(BYTE*)(deObfuscatedAddress + 5) == 0xC3) { //A1 MOV EAX, [XXXXXX]
                    printf("A1 = %X %X +5[%X]\n", deObfuscatedAddress, *(DWORD*)(deObfuscatedAddress + 1), *(BYTE*)(deObfuscatedAddress + 5));
                    deObfuscatedAddress = *(DWORD*)(deObfuscatedAddress + 1);
                } else if (*(BYTE*)deObfuscatedAddress == 0xFF && *(BYTE*)(deObfuscatedAddress + 1) == 0x35 && *(BYTE*)(deObfuscatedAddress + 6) == 0x58) { //push [XXXXXX]
                    printf("PUSH2 = %X %X\n", deObfuscatedAddress, *(DWORD*)(deObfuscatedAddress + 2));
                    deObfuscatedAddress = *(DWORD*)(deObfuscatedAddress + 2);
                } else if ((BYTE)deObfuscatedAddress == 0xC8) { //enter (invalid opcode)
                    printf("invalid 0xC8 = %X %X %X\n", ptrIndex, deObfuscatedAddress, (DWORD*)deObfuscatedAddress);
                    deObfuscatedAddress = *(DWORD*)(ptrIndex + insn_len((void*)ptrIndex));
                    printf("invalid 0xC8 = %X %X %X\n", ptrIndex, deObfuscatedAddress, (DWORD*)deObfuscatedAddress);
                    passDone = false;
                }
                goto retryPass;
            } else {
                printf("not found import :(\n");
                ptrIndex += sizeof(DWORD);
                continue;
            }
        }

        //now *ptrIndex in dwModBase
        //now retrieve API info (Hint, name) from the module's export
        //printf("ptrIndex %X %X, Mod: %X, Size: %X\n", *(DWORD *)ptrIndex, ptrIndex, dwModBase, dwModSize);
        GetAPIInfo(ptrIndex, &iat_module_info);
        ptrIndex += sizeof(DWORD);
    }
}

/************************************************************************/
/*
Function : Get AddressOfEntryPoint  (or Original Entry Point)
Params   : lpAddr is the Base where the exe mapped into
Return   : OEP (RVA)             */
/************************************************************************/
DWORD GetOEP(LPVOID lpAddr)
{
    PIMAGE_DOS_HEADER pDOSHDR = (PIMAGE_DOS_HEADER)lpAddr;
    PIMAGE_NT_HEADERS pNTHDR = (PIMAGE_NT_HEADERS)((unsigned char *)pDOSHDR + pDOSHDR->e_lfanew);
    return pNTHDR->OptionalHeader.AddressOfEntryPoint;
}

/************************************************************************/
/*
Function : Retrieve a process's Import Info only by IAT
Param    : lpAddr is the address the exe mapped into (within our space)
ptrIATEnd [out] used to receive the 1st IAT we found (FF25 XXXX, FF15YYYY)
Return   : the beginning of the page where IAT in
Search for FF25 XXXX,  or FF15 yyyy
HelloWorld.exe
004001E0 > .  EA07D577      DD USER32.MessageBoxA
004001E4      00000000      DD 00000000
004001E8 >/$  6A 00         PUSH 0                                   ; /Style = MB_OK|MB_APPLMODAL
004001EA  |.  6A 00         PUSH 0                                   ; |Title = NULL
004001EC  |.  6A 00         PUSH 0                                   ; |Text = NULL
004001EE  |.  6A 00         PUSH 0                                   ; |hOwner = NULL
004001F0  |.  E8 01000000   CALL <JMP.&USER32.MessageBoxA>           ; \MessageBoxA
004001F5  \.  C3            RETN
004001F6   $- FF25 E0014000 JMP DWORD PTR DS:[<&USER32.MessageBoxA>] ;  USER32.MessageBoxA
Notepad.exe
0100740B   .  FF15 38130001      CALL DWORD PTR DS:[<&msvcrt.__set_app_ty>;  msvcrt.__set_app_type
MSPaint.exe
1000CA65    8B35 58D10110   MOV ESI,DWORD PTR DS:[<&KERNEL32.LCMapSt>; kernel32.LCMapStringW
*/
/************************************************************************/

/*
Need to check all of these
– 8B0D MOV ECX,[ADDRESS]
– 8B15 MOV EDX,[ADDRESS]
– 8B1D MOV EBX,[ADDRESS]
– 8B25 MOV ESP,[ADDRESS]
– 8B2D MOV EBP,[ADDRESS]
– 8B35 MOV ESI,[ADDRESS]
– 8B3D MOV EDI,[ADDRESS]
– A1 MOV EAX,[ADDRESS]
- FF15 CALL [ADDRESS]
– FF25 JMP [ADDRESS]
– FF35 PUSH [ADDRESS]
*/

DWORD SearchIAT(LPVOID lpAddr, DWORD dwImageSize, DWORD pImageBase, DWORD dwMaxIATImageSize, DWORD *ptrIATEnd)
{
    DWORD pImageSectionStart = 0;
    DWORD instruction_length;
    DWORD *ptrFuncAddr = NULL;     //like xxx in JMP DWORD PTR DS:[XXXX]
    DWORD ptrFuncAddrHighest = NULL;
    DWORD dwOEP = NULL;
    BYTE *pCode = NULL;
    DWORD i = NULL;
    WORD  wJMP = 0x25FF;
    WORD  wCALL = 0x15FF;

    dwOEP = GetOEP(lpAddr);
    i = dwOEP;
    pCode = (BYTE *)((BYTE *)lpAddr + dwOEP);

    // get the location of the module's IMAGE_NT_HEADERS structure
    IMAGE_NT_HEADERS *pNtHdr = ImageNtHeader(lpAddr);
    // section table immediately follows the IMAGE_NT_HEADERS
    IMAGE_SECTION_HEADER *pSectionHdr = (IMAGE_SECTION_HEADER *)(pNtHdr + 1);

    bool got = false;
    for (int scn = 0; scn < pNtHdr->FileHeader.NumberOfSections; ++scn)
    {
        char *name = (char*)pSectionHdr->Name;
        DWORD SectionStart = (DWORD)lpAddr + pSectionHdr->VirtualAddress;
        DWORD SectionEnd = (DWORD)lpAddr + pSectionHdr->VirtualAddress + pSectionHdr->Misc.VirtualSize - 1;

        if (got) {
            pImageSectionStart = SectionStart;
            break;
        }

        if (SectionStart == pImageBase + dwOEP && SectionEnd < dwImageSize) {
            got = true;
            //next one is imports.
            ++pSectionHdr;
            continue;
        }
        ++pSectionHdr;
    }

    if (!pImageSectionStart)
        pImageSectionStart = dwImageSize;

    printf("Found OEP at %X, ImageSize = %X,%X\n", dwOEP, dwImageSize, pImageSectionStart);

    //search for FF 25 XXXX, FF 15 YYYY from OEP, had better use Disasm engine 
    //but we just do it simply
    while (i < pImageSectionStart)
    {
        if (memcmp(pCode, &wJMP, sizeof(WORD))
            && memcmp(pCode, &wCALL, sizeof(WORD)))
        {
            //
            instruction_length = insn_len(pCode);
            pCode += instruction_length;
            i += instruction_length;
            continue;
        }

        //check illegal, *ptrFuncAddr > pImageBase  && *ptrFuncAddr <= pImageBase + dwImageSize
        ptrFuncAddr = (DWORD *)(pCode + sizeof(WORD));
        if (*ptrFuncAddr < (DWORD)pImageBase || *ptrFuncAddr >= (DWORD)pImageBase + dwImageSize)
        {
            instruction_length = insn_len(pCode);
            pCode += instruction_length;
            i += instruction_length;
            continue;
        }

        //need to fix relocation
        *(DWORD *)ptrFuncAddr = (long)lpAddr + *(long *)ptrFuncAddr - (long)pImageBase;
        //now found one item that may belongs to IAT
        ptrFuncAddr = (DWORD *)*ptrFuncAddr;

        if ((DWORD)ptrFuncAddr > ptrFuncAddrHighest) {
            ptrFuncAddrHighest = (DWORD)ptrFuncAddr;
            printf("highest = %X\n", ptrFuncAddrHighest);
        }

        //recheck illegal, 
        //for system dlls, what about user dlls? well, whatever, there must be system dlls
        //what if we found IAT for system dlls, so we found the user dlls.
        //What if the IAT tables are not continous????????
        if (*ptrFuncAddr < dwMaxIATImageSize)
        {
            instruction_length = insn_len(pCode);
            pCode += instruction_length;
            i += instruction_length;
            continue;
        }
        break;
    }

    //now it seems ptrFuncAddr points some item in IAT, 
    //make ptrFuncAddr point to the beginning of the page
    //we use 0xFFFEFFFF, because ptrFuncAddr is the memory addr we allocated, not by loadlibrary
    *ptrIATEnd = (DWORD)ptrFuncAddrHighest;
    ptrFuncAddr = (DWORD*)(((DWORD)ptrFuncAddr & 0xFFFFF000)
        + ((DWORD)lpAddr & 0x0FFF)
        );
    return (DWORD)ptrFuncAddr;

    //return NULL;
}

unsigned long Get_Import_Address(char* DLL, char* Library, char* Import, int ordinal = -1)
{
    HMODULE mhLoadedDLL = NULL;
    do
    {
        if (!DLL)
            mhLoadedDLL = GetModuleHandle(NULL);
        else
            mhLoadedDLL = GetModuleHandle(DLL);
        Sleep(100);
    } while (!mhLoadedDLL);

    MODULEINFO modinfo;
    GetModuleInformation(GetCurrentProcess(), mhLoadedDLL, &modinfo, sizeof(MODULEINFO));
    DWORD ModuleSize = (unsigned long)modinfo.SizeOfImage;

    PIMAGE_DOS_HEADER DosHeader = (PIMAGE_DOS_HEADER)mhLoadedDLL;
    PIMAGE_NT_HEADERS NtHeader;
    PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
    UINT Index = 0;


    NtHeader = (PIMAGE_NT_HEADERS)(((PBYTE)DosHeader) + DosHeader->e_lfanew);
    if (NtHeader->Signature != IMAGE_NT_SIGNATURE)
        return 0;

    ImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(((PBYTE)DosHeader) + NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);

    if (mhLoadedDLL) {
        ULONG Sz;
        ImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToDataEx(mhLoadedDLL, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &Sz, nullptr);
    }

    __try {
        //
        // Iterate over import descriptors/DLLs.
        //
        for (Index = 0; (ImportDescriptor[Index].Characteristics != 0 || ImportDescriptor[Index].Name); Index++) {
            PSTR dllName = (PSTR)(((PBYTE)DosHeader) + ImportDescriptor[Index].Name);

            if (_strcmpi(dllName, Library) == 0) {
                // This the DLL we are after.
                PIMAGE_THUNK_DATA Thunk;
                PIMAGE_THUNK_DATA OrigThunk;

                Thunk = (PIMAGE_THUNK_DATA)(((PBYTE)DosHeader) + ImportDescriptor[Index].FirstThunk);
                OrigThunk = (PIMAGE_THUNK_DATA)(((PBYTE)DosHeader) + ImportDescriptor[Index].OriginalFirstThunk);

                //Reset
                Thunk = (PIMAGE_THUNK_DATA)(((PBYTE)DosHeader) + ImportDescriptor[Index].FirstThunk);
                OrigThunk = (PIMAGE_THUNK_DATA)(((PBYTE)DosHeader) + ImportDescriptor[Index].OriginalFirstThunk);

                for (; OrigThunk->u1.Function != NULL; OrigThunk++, Thunk++)
                {
                    if (ordinal != -1) {
                        if ((OrigThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG) && IMAGE_ORDINAL(OrigThunk->u1.Ordinal) == ordinal) //send ordinal
                            return (DWORD)Thunk; //Address of import returns.
                    }

                    if (OrigThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG) { // Ordinal import - we can handle named imports only, so skip it.
                        continue;
                    }

                    PIMAGE_IMPORT_BY_NAME importt = (PIMAGE_IMPORT_BY_NAME)(((PBYTE)DosHeader) + OrigThunk->u1.AddressOfData);

                    if (_strcmpi(Import, (char*)importt->Name) == 0) {
                        return (DWORD)Thunk; //Address of import returns.
                    }
                }

                unsigned long ptrFuncsIndex = (unsigned long)ImportDescriptor[Index].FirstThunk + (DWORD)mhLoadedDLL;
                DWORD impAddress = (DWORD)GetProcAddress(GetModuleHandle(Library), Import);

                //First get all modules loaded, so you can find the maximum ImageBase+ImageSize for IAT Max Size calculation.
                if (gs_ModuleList.size() == 0) {
                    BOOL bRet = SnapShotModules((DWORD)GetCurrentProcess());
                    if (!bRet)
                    {
                        printf("Failed to get Modules\n");
                        return 0;
                    }
                }

                DWORD dwMaxIATImageSize = 0x70000000;
                if (gs_ModuleList.size() > 0) {
                    auto max_it = std::max_element(gs_ModuleList.begin(), gs_ModuleList.end(), [](const IAT_Module_Info& l, const IAT_Module_Info& h) {
                        return l.ImageBase < h.ImageBase;
                    });

                    if (max_it->ImageBase > 0)
                        dwMaxIATImageSize = (DWORD)max_it->ImageBase + max_it->ImageSize;

                    printf("Highest Imported DLL = %X %s\n", max_it->ImageBase, max_it->DllName);
                }
                //now we do more, retrieve the Page where IAT in
                DWORD ptrIATEnd = NULL;
                DWORD ptrIAT = SearchIAT(mhLoadedDLL, ModuleSize, NtHeader->OptionalHeader.ImageBase, dwMaxIATImageSize, &ptrIATEnd);

                printf("Rebuilding IAT,Found IAT in page %X, IAT End %X\n", ptrIAT, ptrIATEnd);
                if(listOfIATImports.size() == 0)
                    FixImport((DWORD)GetCurrentProcess(), ptrIAT, ptrIATEnd, ModuleSize);

                if (listOfIATImports.size() > 0) {
                    auto match = std::find_if(listOfIATImports.cbegin(), listOfIATImports.cend(), [Library, Import](const IAT_Import_Information& s) {
                        return _strcmpi(s.IATModuleName, Library) == 0 && _strcmpi(s.IATFunctionName, Import) == 0;
                    });

                    if (match != listOfIATImports.cend()) {
                        printf("Found IAT = %X, %s %s\n", match->IATAddress, match->IATModuleName, match->IATFunctionName);
                    }

                    std::list<IAT_Import_Information>::iterator i;
                    for (i = listOfIATImports.begin();
                        i != listOfIATImports.end();
                        i++)
                    {
                        printf("Module: %s Import: %s Address: %X\n", i->IATModuleName, i->IATFunctionName, i->IATAddress);
                    }

                } else {
                    printf("Couldn't find module %s, import %s\n", Library, Import);
                }

            }
        }
    }
    __except (1) {
        printf("Exception hit parsing imports\n");
    }
    return 0;
}

Another include which is needed is x86_instruction_length.h can https://pastebin.com/raw/YMSxjPvL

Usage:

DWORD GetTickCountx = Get_Import_Address(NULL, "kernel32.dll", "GetTickCount");
if(GetTickCountx) {
    if (!VirtualProtect((LPVOID)GetTickCountx , 4, new_rights, &old_rights))
        return 0;
    *(DWORD*)(GetTickCountx) = (DWORD)(NewTickCount);
    VirtualProtect((LPVOID)GetTickCountx , 4, old_rights, &new_rights);
}


https://github.com/fatrolls/IAT-Imports-Finder

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.