导入地址表中的 Thunk 表? [英] Thunk table in import address table?

查看:26
本文介绍了导入地址表中的 Thunk 表?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

与 EXE 文件中用于导入外部 DLL 中使用的函数的导入地址表相关的 thunk 表是什么?

What is a thunk table in relation to the import address table that's used in EXE files to import functions used in external DLLs?

这个 thunk 表只是一个包含其他函数的 'Thunks' 的表吗?

Is this thunk table just a table containing 'Thunks' to other functions?

推荐答案

Thunks 是导入表的一部分 (IMAGE_DIRECTORY_ENTRY_IMPORT) 和延迟导入表 (IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT).它们被描述 http://msdn.microsoft.com/en-us/library/ms809762.aspx.

Thunks are a part of the Import table (IMAGE_DIRECTORY_ENTRY_IMPORT) and Delay Import Table (IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT). They are described http://msdn.microsoft.com/en-us/library/ms809762.aspx.

我将查看我的旧源代码,稍后将发布一个工作代码,该代码转储包含绑定信息的两个表.

I'll look at my old source code and will post later a working code which dump both this tables inclusive binding information.

更新:

这是我在一个旧程序中喜欢的代码.它仅支持 32 位 PE,但可以轻松修改为 64 位.顺便说一下,你可以看到,它也转储绑定信息.要测试这个绑定你想要转储的 PE 与 bind.exe(例如,使用 bind.exe -u -v Test.dll).

Here is a code which I fond in one of my old program. It support only 32-bit PE, but can be easy modified to 64-bit. By the way you can see, that it dump also binding information.To test this bind the PE which you want to dump with respect of bind.exe (use for example, bind.exe -u -v Test.dll).

代码大约有 1000 行,所以我不能在这里发布.我收到一条错误消息

The code consist from about 1000 lines, so I could not post it here. I receive an error message

糟糕!无法提交您的修改,因为:

Oops! Your edit couldn't be submitted because:

  • 正文限制为 30000 个字符;您输入了 55095

所以我把它放在这里:http://www.ok-soft-gmbh.com/ForStackOverflow/PEInfo.c.我希望代码能帮助你更好地描述.

So I placed it here: http://www.ok-soft-gmbh.com/ForStackOverflow/PEInfo.c. I hope the code will help you better as a long description.

更新 2:我发现我的旧答案不适合搜索引擎.所以我在下面包含了PEInfo.c的部分代码(函数DumpImportsDumpExports):

UPDATED 2: I see that my old answer is not good for searching engine. So I includes the part of the code of PEInfo.c (the functions DumpImports and DumpExports) below:

void MakeIdent (UINT nOffset)
{
    for (; nOffset; nOffset--)
        printf ("    ");    // 4 blanks
}

void DumpDword (UINT nOffset, LPCSTR pszPrefix, DWORD dw)
{
    MakeIdent(nOffset);

    if (dw < 100)
        printf ("%s: %d
", pszPrefix, dw);
    else if (dw%(256*256) == 0)
        printf ("%s: 0x%X
", pszPrefix, dw);
    else
        printf ("%s: %d (0x%X)
", pszPrefix, dw, dw);
}

void DumpTimeDateStamp (UINT nOffset, LPCSTR pszTimeDateStampPrefix, DWORD dwTimeDateStamp)
{
    //struct tm tmTime;//= localtime_s ((time_t *)&dwTimeDateStamp);
    //errno_t err = localtime_s (&tmTime, ((time_t *)&dwTimeDateStamp));

    struct tm *ptmTime = _localtime32 ((__time32_t *)&dwTimeDateStamp);
    SYSTEMTIME stSystemTime;
    static CHAR szString[128];

    stSystemTime.wYear = (WORD)(1900 + ptmTime->tm_year);
    stSystemTime.wMonth = (WORD)(ptmTime->tm_mon + 1);
    stSystemTime.wDay = (WORD)ptmTime->tm_mday;
    stSystemTime.wDayOfWeek = (WORD)(ptmTime->tm_wday + 1);
    stSystemTime.wHour = (WORD)ptmTime->tm_hour;
    stSystemTime.wMinute = (WORD)ptmTime->tm_min;
    stSystemTime.wSecond = (WORD)ptmTime->tm_sec;
    stSystemTime.wMilliseconds = 0;

    MakeIdent(nOffset);
    printf ("%s: 0x%8X (", pszTimeDateStampPrefix, dwTimeDateStamp);

    if (GetDateFormatA (LOCALE_USER_DEFAULT, 0, &stSystemTime, NULL, 
        szString, sizeof(szString)/sizeof(TCHAR)) != 0) {
        printf (szString);
    }

    if (GetTimeFormatA (LOCALE_USER_DEFAULT, 0, &stSystemTime, NULL, 
                       szString, sizeof(szString)/sizeof(TCHAR)) != 0) {
        if (szString[0] != 0)
            printf (" ");
        printf (szString);
    }
    printf (")
");
}

void DumpImports (UINT nOffset, IMAGE_OPTIONAL_HEADER32 *pOptionalHeader, PBYTE pbyFile,
                  IMAGE_SECTION_HEADER *pSectionHeader, IMAGE_NT_HEADERS32 *pNtHeader) // header of the section, which contains export section
{
    IMAGE_IMPORT_DESCRIPTOR *pImportDescriptor = (IMAGE_IMPORT_DESCRIPTOR *)((PBYTE)pbyFile + pSectionHeader->PointerToRawData +
        pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress - pSectionHeader->VirtualAddress);
    DWORD dwBoundImportVA = pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress;
    IMAGE_BOUND_IMPORT_DESCRIPTOR *pFirstBoundImportDescriptor = NULL, *pBoundImportDescriptor;

    //DumpDword (nOffset, TEXT("Characteristics"), pImportDescriptor->Characteristics);
    if (dwBoundImportVA) {
        UINT i;
        IMAGE_SECTION_HEADER *pFirstSectionHeader = (IMAGE_SECTION_HEADER *)((PBYTE)pOptionalHeader + //sizeof(IMAGE_OPTIONAL_HEADER32));
                                                                                pNtHeader->FileHeader.SizeOfOptionalHeader);

        for (i=0; i<pNtHeader->FileHeader.NumberOfSections; i++) {
            if (pFirstSectionHeader[i].VirtualAddress <= dwBoundImportVA &&
                dwBoundImportVA < pFirstSectionHeader[i].VirtualAddress + pFirstSectionHeader[i].Misc.VirtualSize) {

                pFirstBoundImportDescriptor = (IMAGE_BOUND_IMPORT_DESCRIPTOR *)((PBYTE)pbyFile + pFirstSectionHeader[i].PointerToRawData +
                                            dwBoundImportVA - pFirstSectionHeader[i].VirtualAddress);
                break;
            }
        }
        if (i >= pNtHeader->FileHeader.NumberOfSections)
            pFirstBoundImportDescriptor = (IMAGE_BOUND_IMPORT_DESCRIPTOR *)((PBYTE)pbyFile + dwBoundImportVA);
    }

    for (;pImportDescriptor->Characteristics; pImportDescriptor++) {
        IMAGE_THUNK_DATA *pOriginalFirstThunk = (IMAGE_THUNK_DATA *)((PBYTE)pbyFile + pSectionHeader->PointerToRawData +
            pImportDescriptor->OriginalFirstThunk - pSectionHeader->VirtualAddress);
        IMAGE_THUNK_DATA *pFirstThunk = (IMAGE_THUNK_DATA *)((PBYTE)pbyFile + pSectionHeader->PointerToRawData +
            pImportDescriptor->FirstThunk - pSectionHeader->VirtualAddress);
        IMAGE_THUNK_DATA *pOriginalThunk, *pThunk;

        MakeIdent(nOffset);
        printf ("%s ", pbyFile + pSectionHeader->PointerToRawData + pImportDescriptor->Name - pSectionHeader->VirtualAddress);
        //DumpDword (nOffset, TEXT("Ordinal Base"), pExportDirectory->Base);

        if (pImportDescriptor->TimeDateStamp == 0) {
            //MakeIdent(nOffset);
            printf ("(DLL is Not bound)
");
        }
        else if (pImportDescriptor->TimeDateStamp == -1) {
            //if bound, and real date	ime stamp
            //                                    //     in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
            //MakeIdent(nOffset);
            printf ("(DLL bound with New BIND)
");
        }
        else {
            //MakeIdent(nOffset);
            printf ("(DLL bound with Old BIND) ");
            DumpTimeDateStamp (nOffset, "TimeDateStamp", pImportDescriptor->TimeDateStamp);
        }

        MakeIdent(nOffset+1);
        if (pImportDescriptor->TimeDateStamp)   // if bound
            printf (TEXT("      Ordinal          hint BoundAddrs Name
"));
        else
            printf (TEXT("      Ordinal          hint Name
"));

        for (pOriginalThunk=pOriginalFirstThunk, pThunk=pFirstThunk; pOriginalThunk->u1.AddressOfData; pOriginalThunk++, pThunk++) {
            if (IMAGE_SNAP_BY_ORDINAL32(pOriginalThunk->u1.Ordinal)) {
                MakeIdent(nOffset+1);
                // Ordinal
                if (pImportDescriptor->TimeDateStamp)
                    printf (TEXT("%4u (0x%04X)               0x%08X
"),
                            pOriginalThunk->u1.Ordinal & ~IMAGE_ORDINAL_FLAG32,
                            pOriginalThunk->u1.Ordinal^IMAGE_ORDINAL_FLAG32,
                            pThunk->u1.AddressOfData);
                else
                    // pThunk->u1.AddressOfData == pOriginalThunk->u1.Ordinal so don't print it 
                    printf (TEXT("%4u (0x%04X)
"),
                            pOriginalThunk->u1.Ordinal & ~IMAGE_ORDINAL_FLAG32,
                            pOriginalThunk->u1.Ordinal^IMAGE_ORDINAL_FLAG32);
            }
            else {
                IMAGE_IMPORT_BY_NAME *pImportByName = (IMAGE_IMPORT_BY_NAME *) (pOriginalThunk->u1.AddressOfData +
                    (PBYTE)pbyFile + pSectionHeader->PointerToRawData - pSectionHeader->VirtualAddress);

                MakeIdent(nOffset+1);
                // Hint - Index into the Export Name Pointer Table. A match is attempted first with this value.
                // If it fails, a binary search is performed on the DLL’s Export Name Pointer Table.
                if (pImportDescriptor->TimeDateStamp)   // if bound
                    printf (TEXT("%18u (0x%04X) 0x%08X %hs
"), pImportByName->Hint, pImportByName->Hint, pThunk->u1.AddressOfData,
                        pImportByName->Name);
                else
                    printf (TEXT("%18u (0x%04X) %hs
"), pImportByName->Hint, pImportByName->Hint, pImportByName->Name);
            }
        }
    }

    if (pFirstBoundImportDescriptor) {
        MakeIdent(nOffset);
        printf ("PE Header contains the following bound import information:
");

        for (pBoundImportDescriptor=pFirstBoundImportDescriptor; pBoundImportDescriptor->TimeDateStamp;
            pBoundImportDescriptor = (IMAGE_BOUND_IMPORT_DESCRIPTOR *)((PBYTE)(pBoundImportDescriptor+1) + pBoundImportDescriptor->NumberOfModuleForwarderRefs*sizeof(IMAGE_BOUND_FORWARDER_REF))) {
            PSTR pszDllName = (PSTR) ((DWORD)pFirstBoundImportDescriptor + pBoundImportDescriptor->OffsetModuleName);
            IMAGE_BOUND_FORWARDER_REF *pRef = (IMAGE_BOUND_FORWARDER_REF *)(pBoundImportDescriptor+1);

            MakeIdent(nOffset+1);
            printf ("Bound to %hs", pszDllName);
            DumpTimeDateStamp (0, "", pBoundImportDescriptor->TimeDateStamp);
            if (pBoundImportDescriptor->NumberOfModuleForwarderRefs) {
                UINT i;

                for (i=0;i<pBoundImportDescriptor->NumberOfModuleForwarderRefs;i++) {
                    PSTR pszDllName = (PSTR) ((DWORD)pFirstBoundImportDescriptor + pRef->OffsetModuleName);

                    MakeIdent(nOffset+2);
                    printf ("Contained forwarders bound to %hs", pszDllName);
                    DumpTimeDateStamp (0, "", pRef->TimeDateStamp);
                }
            }
        }
    }
}

void DumpExports (UINT nOffset, IMAGE_OPTIONAL_HEADER32 *pOptionalHeader, PBYTE pbyFile,
                  IMAGE_SECTION_HEADER *pSectionHeader) // header of the section, which contains export section
{
    UINT i;
    UINT iNames;
    PDWORD pdwAddressOfFunctions;
    PWORD pwOrdinals;
    PDWORD pdwNameRVA;
    IMAGE_EXPORT_DIRECTORY *pExportDirectory = (IMAGE_EXPORT_DIRECTORY *)((PBYTE)pbyFile + pSectionHeader->PointerToRawData +
        pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress - pSectionHeader->VirtualAddress);
    DWORD dwVAExportStart = pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
    DWORD dwVAExportEnd = pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + 
                          pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;

    DumpDword (nOffset, TEXT("Characteristics"), pExportDirectory->Characteristics);
    DumpTimeDateStamp (nOffset, "TimeDateStamp", pExportDirectory->TimeDateStamp);

    MakeIdent(nOffset);
    printf ("DllName: %s
", pbyFile + pSectionHeader->PointerToRawData + pExportDirectory->Name - pSectionHeader->VirtualAddress);
    DumpDword (nOffset, TEXT("Ordinal Base"), pExportDirectory->Base);

    MakeIdent(nOffset);
    printf (TEXT("Version: %d.%d
"), pExportDirectory->MajorVersion, pExportDirectory->MinorVersion);

    DumpDword (nOffset, TEXT("Number of exported functions"), pExportDirectory->NumberOfFunctions);
    DumpDword (nOffset, TEXT("Number of functions exported by name"), pExportDirectory->NumberOfNames);

    MakeIdent(nOffset+1);
    printf (TEXT("Ordn hint RVA      Name
"));

    pdwAddressOfFunctions = (PDWORD)(pbyFile + pSectionHeader->PointerToRawData + pExportDirectory->AddressOfFunctions - pSectionHeader->VirtualAddress);
    pwOrdinals = (PWORD)(pbyFile + pSectionHeader->PointerToRawData + pExportDirectory->AddressOfNameOrdinals - pSectionHeader->VirtualAddress);
    pdwNameRVA = (PDWORD)(pbyFile + pSectionHeader->PointerToRawData + pExportDirectory->AddressOfNames - pSectionHeader->VirtualAddress);

    for (iNames = 0; iNames < pExportDirectory->NumberOfNames; iNames++) {
        MakeIdent(nOffset+1);

        // AddressOfFunctions MUST be ouf of Export Directory. If it is not so, it is a Forwarding entry
        if (pdwAddressOfFunctions[pwOrdinals[iNames]] < dwVAExportStart ||
            pdwAddressOfFunctions[pwOrdinals[iNames]] > dwVAExportEnd)
            // AddressOfFunctions is normaly in .text section and export table in .edata or .rdata section, so
            // AddressOfFunctions must be not in Export Directory
            printf("%4u %4u %08X %s
",
                    pwOrdinals[iNames] + pExportDirectory->Base, iNames, pdwAddressOfFunctions[pwOrdinals[iNames]],
                    (pbyFile + pSectionHeader->PointerToRawData + pdwNameRVA[iNames] - pSectionHeader->VirtualAddress));
        else
            printf("%4u %4u          %s (forwarded to %s)
",
                    pwOrdinals[iNames] + pExportDirectory->Base, iNames,
                    (pbyFile + pSectionHeader->PointerToRawData + pdwNameRVA[iNames] - pSectionHeader->VirtualAddress),
                    (PSTR)(pbyFile + pSectionHeader->PointerToRawData + pdwAddressOfFunctions[pwOrdinals[iNames]] - pSectionHeader->VirtualAddress));
    }

    // print functions exported by ordinal
    for (i = 0; i < pExportDirectory->NumberOfFunctions; i++) {
        if (pdwAddressOfFunctions[i] != 0) {
            // if EXPORTS in DEF-file look like 
            //
            // EXPORTS
            //    Message1  @100
            //    Message2  @200
            //    Message3  @300
            //    Message4  @400
            //    Message5  @500
            // it will be added in export section 401 (500-100+1) entries. 5 from there with not 0 address and the rest
            // empty entries with 0
            // we will dump only not empty entries

            UINT iNames;
            WORD wOrdinal = (WORD)(i + pExportDirectory->Base);

            // try to find (i + pExportDirectory->Base) ordinal in the list of pwOrdinals
            for (iNames = 0; iNames<pExportDirectory->NumberOfNames; iNames++) {
                if (pdwAddressOfFunctions[pwOrdinals[iNames]] == pdwAddressOfFunctions[i])
                    break;
            }

            if (iNames >= pExportDirectory->NumberOfNames) {
                // if not found as exported by name, print it here
                MakeIdent(nOffset+1);
                if (pdwAddressOfFunctions[i] < pSectionHeader->VirtualAddress ||
                    pdwAddressOfFunctions[i] > pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize)
                    printf("%4u      %08X [NONAME]
", wOrdinal, pdwAddressOfFunctions[i]);
                else
                    printf("%4u               [NONAME] (forwarded to %s)
",
                           wOrdinal, (PSTR)(pbyFile + pSectionHeader->PointerToRawData + pdwAddressOfFunctions[i] - pSectionHeader->VirtualAddress));
            }
        }
    }
}

这篇关于导入地址表中的 Thunk 表?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆