Таблицы экспорта и импорта

 
0
 
C++
ava
Alexey68 | 12.04.2013, 01:07
Здравствуйте, прошу объяснить как получить список экспортируемых и импортируемых функций?

#include <windows.h>
#include <stdio.h>
#include <winnt.h>

int main()
{
HANDLE hFile;
BYTE *BaseAddress;
WORD x;
DWORD FileSize, BR, PE, OEP, Export_RVA ;
int i;

IMAGE_DOS_HEADER *ImageDosHeader;
IMAGE_NT_HEADERS32 *ImageNtHeaders;
IMAGE_OPTIONAL_HEADER32 *ImageOptionalHeader;
IMAGE_DATA_DIRECTORY *ImageDataDirectory;
IMAGE_EXPORT_DIRECTORY *ImageExportDirectory;
IMAGE_SECTION_HEADER *ImageSectionHeader;


char FileName[MAX_PATH];
//char FileName []="test.exe";
char SectionName[9] = { 0 };


printf("%s\n","Enter filename...");
scanf("%s", FileName);

printf("%s\n","Open file...");

hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, 0,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);

if (hFile == INVALID_HANDLE_VALUE)
{
printf("%s\n","Cannot open file...");
return 0;
}

FileSize = GetFileSize(hFile, NULL);
BaseAddress = (BYTE *) malloc(FileSize);

if (!ReadFile(hFile, BaseAddress, FileSize, &BR, NULL))
{
printf("Cannot read file...\n");
free(BaseAddress);
CloseHandle(hFile);
return 0;
}

ImageDosHeader = (IMAGE_DOS_HEADER *) BaseAddress;



if (ImageDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
{
printf("Invalid Dos Header\n");
free(BaseAddress);
CloseHandle(hFile);
return -1;
}

ImageNtHeaders = (IMAGE_NT_HEADERS *)
(ImageDosHeader->e_lfanew + (DWORD) ImageDosHeader);

printf("This PE Signature - %x\n ", ImageNtHeaders->Signature);


//Как получить экспортируемые функции?
Export_RVA = IMAGE_DATA_DIRECTORY[IMAGE_DIRECTORY_ENTRY_EXPORT];


//

free(BaseAddress);
CloseHandle(hFile);

system("pause");

return 0;
}
С Уважением Алексей. 
Comments (9)
ava
DarthTon | 12.04.2013, 12:23 #
Касательно теории рекомендую почитать оригинальную спецификацию PE формата MSDN или же что-нибудь вроде этого RSDN.

Практическая реализация:

Мой старый код для получения адреса экспортируемой функции модуля. Работает с уже отмапленым в память образом. Чтобы заработало для данных из файла необходимо подправить соответствующие виртуальные адреса, либо же подгрузить файл в память как PE образ (CreateFileMapping + SEC_IMAGE).


#include <windows.h>
#include <winternl.h>
#include <string>
#include <stdint.h>

FARPROC GetProcAddressEx(HMODULE hMod, LPCSTR pSearchName)
{
    IMAGE_DOS_HEADER       *phdrDos  = {0};
    IMAGE_NT_HEADERS       *phdrNt32 = {0};
    uint8_t                *pExpDir  = nullptr;
    void                   *pFunc    = nullptr;

    //
    // Sanity checks
    //
    phdrDos  = (IMAGE_DOS_HEADER*)hMod;
    if(phdrDos->e_magic != IMAGE_DOS_SIGNATURE)
        return nullptr;

    phdrNt32 = (IMAGE_NT_HEADERS*)((size_t)hMod + phdrDos->e_lfanew);
    if(phdrNt32->Signature != IMAGE_NT_SIGNATURE)
        return nullptr;

    pExpDir  = (uint8_t*)phdrNt32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;

    // Exports are present
    if(pExpDir != nullptr)
    {
        IMAGE_EXPORT_DIRECTORY *pExpData = (IMAGE_EXPORT_DIRECTORY*)(pExpDir + (size_t)hMod);
        size_t expSize = phdrNt32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;

        WORD  *pAddressOfOrds   = (WORD*) (pExpData->AddressOfNameOrdinals + (size_t)hMod); 
        DWORD *pAddressOfNames  = (DWORD*)(pExpData->AddressOfNames        + (size_t)hMod);
        DWORD *pAddressOfFuncs  = (DWORD*)(pExpData->AddressOfFunctions    + (size_t)hMod);

        for( DWORD i = 0; i < pExpData->NumberOfFunctions; ++i )
        {
            WORD OrdIndex   = 0xFFFF;
            char *pName     = nullptr;

            if(i < pExpData->NumberOfNames)
            {
                pName       = (char*)(pAddressOfNames[i]);
                OrdIndex    = (WORD)pAddressOfOrds[i];
            }
            else
            {
                OrdIndex    = (WORD)i;
            }

            // Check by ordinal or by name
            if(((size_t)pSearchName < 0xFFFF && (WORD)pSearchName == (OrdIndex + (WORD)pExpData->Base)) ||
                ((size_t)pSearchName > 0xFFFF && pName && strcmp(pSearchName, pName + (size_t)hMod) == 0))
            {
                pFunc = (void*)(pAddressOfFuncs[OrdIndex]);

                // Invalid function pointer
                if(pFunc == nullptr)
                    continue;

                // Check chained export(function address belongs to export directory address range)
                if((size_t)pFunc >= (size_t)pExpDir && (size_t)pFunc <= (size_t)pExpDir + expSize)
                {
                    std::string chainExp((char*)pFunc + (size_t)hMod);

                    std::string strDll  = chainExp.substr(0, chainExp.find(".")) + ".dll";
                    std::string strName = chainExp.substr(chainExp.find(".") + 1, strName.npos);

                    // Load target dll
                    HMODULE hChainMod = (HMODULE)GetModuleHandleA(strDll.c_str());

                    if(hChainMod == NULL)
                        hChainMod = LoadLibraryA(strDll.c_str());

                    return GetProcAddressEx(hChainMod, strName.c_str());
                }

                return (FARPROC)((size_t)pFunc + (size_t)hMod);
            }
        }
    }

    return nullptr;
}


Аналог для импорта (Код выдран из функции класса поэтому надо допилить немного). Так же требует проекции файла как PE образа.


const IMAGE_SECTION_HEADER      *pSection   = nullptr;
const IMAGE_IMPORT_DESCRIPTOR   *pImportTbl = nullptr;

if(!pFileBase)
    return false;

// Get DOS header
m_pFileBase = pFileBase;
m_pDosHdr   = (const IMAGE_SECTION_HEADER*)m_pFileBase;

// File not a valid PE file
if(m_pDosHdr->e_magic != IMAGE_DOS_SIGNATURE)
    return false;

// Get image header
m_pImageHdr = (const IMAGE_IMPORT_DESCRIPTOR*)((uint8_t*)m_pDosHdr + m_pDosHdr->e_lfanew);

// File not a valid PE file
if(m_pImageHdr->Signature != IMAGE_NT_SIGNATURE)
    return false;

// Import base
uint8_t* pImportBase  = (uint8_t*)m_pImageHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;

// No import section
if(pImportBase == nullptr)
    return false;

pImportTbl = (const IMAGE_IMPORT_DESCRIPTOR*)((size_t)m_pFileBase + pImportBase);

// Imports
for (; pImportTbl->Name; ++pImportTbl)
{
    IMAGE_THUNK_DATA* rva   = {0};

    // Name of import DLL
    std::string strDllName((char*)m_pFileBase + pImportTbl->Name);

    // Choose appropriate thunk
    if (pImportTbl->OriginalFirstThunk)
        rva = (IMAGE_THUNK_DATA*)((size_t)m_pFileBase + pImportTbl->OriginalFirstThunk);
    else
        rva = (IMAGE_THUNK_DATA*)((size_t)m_pFileBase + pImportTbl->FirstThunk);

    while (rva->u1.AddressOfData)
    {
        void* addr                           = 0;   // Function address
        IMAGE_IMPORT_BY_NAME* pAddressTable  = (IMAGE_IMPORT_BY_NAME*)((uint8_t*)m_pFileBase + rva->u1.AddressOfData);
        HMODULE hMod                         = GetModuleHandleA(strDllName.c_str());

        if(!hMod)
            hMod = LoadLibraryA(strDllName.c_str());

        // import by name
        // sizeof(size_t) * 8 - 1 = 0x80000000 (x86) or 0x8000000000000000 (x64)
        if ((size_t)pAddressTable < (1LL << (sizeof(size_t) * 8 - 1) ) && pAddressTable->Name[0])
        {
            addr = GetProcAddress(hMod, pAddressTable->Name);
        }
        // import by ordinal
        else
        {
            addr = GetProcAddress(hMod, (char*)((USHORT)pAddressTable & 0xFFFF));
        }

        rva++;
    }
}
ava
Alexey68 | 12.04.2013, 22:45 #
Спасибо, попробую...
ava
DarthTon | 15.04.2013, 15:47 #

#include <tchar.h>
#include <windows.h>
#include <DbgHelp.h>

#pragma comment(lib, "dbghelp.lib")

void Parse(const TCHAR *pszFile)
{
    if(!pszFile)
        return;

    HANDLE hFile = CreateFile(pszFile, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);

    if(hFile != INVALID_HANDLE_VALUE)
    {
        IMAGE_DOS_HEADER        *pDosHdr = NULL;
        IMAGE_NT_HEADERS        *pNtHdr  = NULL;
        IMAGE_IMPORT_DESCRIPTOR *pImport = NULL;
        IMAGE_EXPORT_DIRECTORY  *pExport = NULL;

        DWORD size    = GetFileSize(hFile, NULL);
        DWORD dwBytes = 0;
        DWORD expSize = 0;
        DWORD expPtr  = 0;
        DWORD impPtr  = 0;
        BYTE* pData   = (BYTE*)malloc(size);

        if(!pData)
        {
            CloseHandle(hFile);
            return;
        }

        if(!ReadFile(hFile, pData, size, &dwBytes, NULL) || dwBytes != size)
            goto clean;

        pDosHdr = (IMAGE_DOS_HEADER*)pData;
        if(pDosHdr->e_magic != IMAGE_DOS_SIGNATURE)
            goto clean;

        pNtHdr = (IMAGE_NT_HEADERS*)(pData + pDosHdr->e_lfanew);
        if(pNtHdr->Signature != IMAGE_NT_SIGNATURE)
            goto clean;

        //
        // Import
        //
        impPtr = pNtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;

        if(impPtr != 0)
        {
            pImport = (IMAGE_IMPORT_DESCRIPTOR*)ImageRvaToVa(pNtHdr, pData, impPtr, NULL);

            for (; pImport->Name; ++pImport)
            {
                IMAGE_THUNK_DATA *pRVA = NULL;

                // Name of import DLL
                char *pDllName = (char*)ImageRvaToVa(pNtHdr, pData, (ULONG)pImport->Name, NULL);

                // Choose appropriate thunk
                if (pImport->OriginalFirstThunk)
                    pRVA = (IMAGE_THUNK_DATA*)ImageRvaToVa(pNtHdr, pData, (ULONG)pImport->OriginalFirstThunk, NULL);
                else
                    pRVA = (IMAGE_THUNK_DATA*)ImageRvaToVa(pNtHdr, pData, (ULONG)pImport->FirstThunk, NULL);

                while (pRVA->u1.AddressOfData)
                {
                    void* addr                           = 0;   // Function address
                    IMAGE_IMPORT_BY_NAME* pAddressTable  = (IMAGE_IMPORT_BY_NAME*)ImageRvaToVa(pNtHdr, pData, (ULONG)pRVA->u1.AddressOfData, NULL);
                    HMODULE hMod                         = GetModuleHandleA(pDllName);

                    if(!hMod)
                        hMod = LoadLibraryA(pDllName);

                    // Import by name (most significant bit is 0)
                    if ((size_t)pAddressTable < ((size_t)1 << (sizeof(size_t) * 8 - 1)) && pAddressTable->Name[0])
                    {
                        addr = GetProcAddress(hMod, pAddressTable->Name);
                    }
                    // Import by ordinal
                    else
                    {
                        addr = GetProcAddress(hMod, (char*)((USHORT)pAddressTable & 0xFFFF));
                    }

                    pRVA++;
                }
            }
        }

        //
        // Export
        //
        expPtr = pNtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;

        if(expPtr != 0)
        {
            pExport = (IMAGE_EXPORT_DIRECTORY*)ImageRvaToVa(pNtHdr, pData, expPtr, NULL);
            expSize = pNtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;

            WORD  *pAddressOfOrds   = (WORD*) ImageRvaToVa(pNtHdr, pData, pExport->AddressOfNameOrdinals, NULL); 
            DWORD *pAddressOfNames  = (DWORD*)ImageRvaToVa(pNtHdr, pData, pExport->AddressOfNames,        NULL);
            DWORD *pAddressOfFuncs  = (DWORD*)ImageRvaToVa(pNtHdr, pData, pExport->AddressOfFunctions,    NULL);

            for( DWORD i = 0; i < pExport->NumberOfFunctions; ++i )
            {
                WORD OrdIndex   = 0xFFFF;
                char *pName     = NULL;

                // Export by name
                if(i < pExport->NumberOfNames)
                {
                    pName       = (char*)(pAddressOfNames[i]);
                    OrdIndex    = (WORD)pAddressOfOrds[i];
                }
                // Export by index
                else
                {
                    OrdIndex    = (WORD)i;
                }

                // Function rva
                size_t pFunc = pAddressOfFuncs[OrdIndex];

                // Invalid function pointer
                if(pFunc == NULL)
                    continue;

                // Check chained export(function address belongs to export directory address range)
                if(pFunc >= expPtr && pFunc <= expPtr + expSize)
                {
                    char* chainExp = (char*)ImageRvaToVa(pNtHdr, pData, (ULONG)pFunc, NULL);
                    char *strDll   = 0;
                    char *strName  = 0;

                    strDll = strtok_s(chainExp, ".", &strName);

                    // Load target dll
                    HMODULE hChainMod = (HMODULE)GetModuleHandleA(strDll);
                    if(hChainMod == NULL)
                        hChainMod = LoadLibraryA(strDll);

                    pFunc = (size_t)GetProcAddress(hChainMod, strName);
                }
                else
                    pFunc = (size_t)ImageRvaToVa(pNtHdr, pData, (ULONG)pFunc, NULL);
            }
        }

    clean:
        free(pData);
        CloseHandle(hFile);
    }
}
ava
Alexey68 | 15.04.2013, 20:59 #
компилятор выдаёт:
[ILINK32 Error] Error: Unresolved external '_strtok_s' referenced from C:\DOCUMENTS AND SETTINGS\ADMIN\¦L+++Lг TT+T\C_AND_ASM\PE_INFO_C_IMPORT_MAIN\DEBUG\MAIN.OBJ
ava
DarthTon | 16.04.2013, 10:35 #
Замените

strDll = strtok_s(chainExp, ".", &strName);

на

strDll  = strtok(chainExp, ".");
strName = strDll + strlen(strDll) + 1; 
ava
Alexey68 | 18.04.2013, 23:50 #
спасибо большое за помощь, при попытке получить список экспортируемых функций, ординалов,
программа ничего не выводит и правильно ли я расставил для вывода
функцию printf
// Export by name
                if(i < pExport->NumberOfNames)
                {
                    pName       = (char*)(pAddressOfNames[i]);
                    OrdIndex    = (WORD)pAddressOfOrds[i];
                    printf("%x\n", pName);

                }
                // Export by index
                else
                {
                    OrdIndex    = (WORD)i;
                    printf("%x\n", OrdIndex);
                }
                // Function rva
                pFunc = pAddressOfFuncs[OrdIndex];
                printf("%x\n", pFunc);
                // Invalid function pointer
                if(pFunc == 0)
                    continue;
                // Check chained export(function address belongs to export directory address range)
                if(pFunc >= expPtr && pFunc <= expPtr + expSize)
                {
                    HMODULE hChainMod = NULL;
                    char* chainExp = (char*)ImageRvaToVa(pNtHdr, pData, (ULONG)pFunc, NULL);
                    char *strDll   = 0;
                    char *strName  = 0;
                    strDll  = strtok(chainExp, ".");
                    strName = strDll + strlen(strDll) + 1;
                    printf("%s\n", strName);
                    // Load target dll
                    hChainMod = (HMODULE)GetModuleHandleA(strDll);
                    if(hChainMod == NULL)
                        hChainMod = LoadLibraryA(strDll);
                    pFunc = (size_t)GetProcAddress(hChainMod, strName);

                    printf("%x\n", pFunc);
                }
                else
                    pFunc = (size_t)ImageRvaToVa(pNtHdr, pData, (ULONG)pFunc, NULL);
                    printf("%x\n", pFunc);
            }
        }
    clean:
ava
DarthTon | 19.04.2013, 10:21 #
Ну printf'ы правильные. Может у анализируемого файла нету таблицы экспорта?   smile 
ava
Alexey68 | 19.04.2013, 17:25 #
пробую подгрузить файлы из system32, например regedit и выскакивает исключение на
строку:
if((size_t)pAddressTable < ((size_t)1 << (sizeof(size_t) * 8 - 1)) && pAddressTable->Name[0])
при получении списка импортируемых функций...
ava
DarthTon | 19.04.2013, 19:08 #
Вы, вероятно, грузите x64 dll. Или соберите сам код под х64, или поправьте стуруктуры на их 64 битные версии.
Please register or login to write.
Firm of day
Вы также можете добавить свою фирму в каталог IT-фирм, и публиковать статьи, новости, вакансии и другую информацию от имени фирмы.
Подробнее
Contributors
advanced
Submit