Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hooking IAT address is incorrect

I'm trying to locate the entry for wglGetProcAddress (OpenGl32.dll) imported in a test application. For some reason, the import whose name is "wglGetProcAddress" does point to the same function returned by calling GetModuleHandle and GetProcAddress on Opengl32.dll.

The executable file has been loaded into memory and is a process with its thread currently suspended. The following code correctly reads the names modules and their functions imported by that executable. Hence, the IAT should not contain RVAs since it has been loaded.

HMODULE h = GetModuleHandle("OPENGL32.dll");
DWORD expect_addr = (DWORD)GetProcAddress(h, "wglGetProcAddress");

PIMAGE_IMPORT_DESCRIPTOR import_desc = (PIMAGE_IMPORT_DESCRIPTOR)(pmem + import_dir);
while (import_desc->Name)
{
    PIMAGE_THUNK_DATA thunk = (PIMAGE_THUNK_DATA)(pmem + import_desc->OriginalFirstThunk);
    while (thunk->u1.Function)
    {
        PIMAGE_IMPORT_BY_NAME import = (PIMAGE_IMPORT_BY_NAME)(pmem + thunk->u1.AddressOfData);

        printf("%s 0x%X\n", import->Name, thunk->u1.Function);
        if ((DWORD)expect_addr == (DWORD)thunk->u1.Function)
        {
            printf("Found wglGetProcAddress\n");
        }
        else if (!strcmp((const char*)import->Name, "wglGetProcAddress"))
        {
            printf("Found wglGetProcAddress's import, but the function has a different value.\n");
        }
        ++thunk;
    }

    ++import_desc;
}

GetProcAddress from that original value returns the address 60XXC245 where XX varies, but thunk->u1.Function always returns 0xA46D8. Everything in thunk->u1 (Function, AddressOfData, Ordinal and ForwarderString) has the same value. The names of the import descriptors and imports correct. Does anyone see what I'm missing?

Edit: I'm trying something else: I'm scanning pmem (image of the executable in memory) for what I expect is the IAT entry, but it doesn't locate that either:

HMODULE h = GetModuleHandle("OPENGL32.dll");
DWORD expect_addr = (DWORD)GetProcAddress(h, "wglGetProcAddress");

printf("Looking for 0x%X\n", expect_addr);
for (int i = 0; i < pmem_size - sizeof(DWORD); i++)
{
    if (*(DWORD*)(pmem + i) == expect_addr)
    {
        printf("0x%X at 0x%X\n", *(DWORD*)(pmem + i), i);
    }
}

SOLVED: I didn't realize it, but calling CreateProcess with CREATE_SUSPENDED prevents the windows loader from populating FirstThunk with the actual addresses. If I let the process run for a second and then suspend the thread, it hooks the IAT address perfectly fine. Now I have to go look for a way to fix that.

like image 358
Dmi Avatar asked Oct 24 '22 05:10

Dmi


1 Answers

u1.Function represents the relative offset to the IMAGE_IMPORT_BY_NAME entry (or the ordinal entry if the IMAGE_ORDINAL_FLAG bit is set). this is why it doesn't match the value from GetProcAddress, because it isn't the address of the function, its the address of the function import entry.

When you have found the thunk matching your function, you need to use this too lookup the virtualized address altered by the linker, form the other thunk list. altering your code so it does this yeilds:

while (import_desc->Name)
{
    PIMAGE_THUNK_DATA thunk = (PIMAGE_THUNK_DATA)((DWORD)GetModuleHandle(NULL) + import_desc->OriginalFirstThunk);
    int i = 0;
    while (thunk->u1.Function)
    {
        PIMAGE_IMPORT_BY_NAME import = (PIMAGE_IMPORT_BY_NAME)((DWORD)GetModuleHandle(NULL) + thunk->u1.AddressOfData);

        void** p = (void**)((DWORD)GetModuleHandle(NULL) + import_desc->FirstThunk);
        printf("%s 0x%X\n", import->Name, p[i]);//thunk->u1.Function);
        if ((DWORD)expect_addr == (DWORD)p[i])
        {
            printf("Found wglGetProcAddress\n");
        }
        else if (!strcmp((const char*)import->Name, "wglGetProcAddress"))
        {
            printf("Found wglGetProcAddress's import, but the function has a different value.\n");
        }
        ++thunk;
    }

    ++import_desc;
}

To get the IAT entries, I do things a little differently:

inline const void** GetImportAddress(HMODULE hModule, IMAGE_IMPORT_DESCRIPTOR* pTable, size_t nThunk)
{
    const void** pAddressBlock = (const void**)((DWORD)hModule + pTable->FirstThunk);
    return &pAddressBlock[nThunk];      
}

const void** GetImport(HMODULE hModule, const char* szDll, const char* szFunction)
{
    const char* szDllName = NULL;
    IMAGE_IMPORT_DESCRIPTOR* pTable = GetImportDescriptor(hModule);
    while(pTable->Characteristics != 0 && (szDllName = GetImportTableName(hModule,pTable)) != NULL)
    {
        if(!lstrcmpiA(szDll,szDllName))
        {
            IMAGE_THUNK_DATA* pThunkData = GetThunk(hModule,pTable);
            if(pThunkData != NULL)
            {
                size_t nThunk = 0;
                while(pThunkData->u1.AddressOfData != 0)
                {
                    if(pThunkData->u1.Ordinal & IMAGE_ORDINAL_FLAG)
                    {
                        if(IMAGE_ORDINAL32(pThunkData->u1.Ordinal) == (DWORD)szFunction)
                            return GetImportAddress(hModule,pTable,nThunk);
                    }
                    else
                    {
                        IMAGE_IMPORT_BY_NAME* pImport = GetImport(hModule,pThunkData);
                        if(!lstrcmpA(szFunction,(const char*)pImport->Name))
                            return GetImportAddress(hModule,pTable,nThunk);
                    }

                    nThunk++;
                    pThunkData++;
                }
            }
        }

        pTable++;
    }

    return NULL;
}
like image 127
Necrolis Avatar answered Oct 26 '22 22:10

Necrolis