Распечатка имен неявно связанных DLL из секции .idata в переносимом исполняемом файле - PullRequest
1 голос
/ 11 марта 2012

Я пытаюсь написать код, который должен распечатать имена всех импортированных dll-файлов в exe, используя поле 'name' структуры IMAGE_IMPORT_DESCRIPTOR в разделе .idata exe, но программа кажется застрять в бесконечном цикле. Может кто-нибудь подскажите, пожалуйста, как правильно распечатать имена ...

    #include<iostream>
    #include<Windows.h>
    #include<stdio.h>
    #include<WinNT.h>

    int main()
    {
        FILE *fp; 
        int i;

        if((fp = fopen("c:\\Linked List.exe","rb"))==NULL)
            std::cout<<"unable to open";


        IMAGE_DOS_HEADER imdh;
        fread(&imdh,sizeof(imdh),1,fp);
        fseek(fp,imdh.e_lfanew,0);

        IMAGE_NT_HEADERS imnth;
        fread(&imnth,sizeof(imnth),1,fp);

        IMAGE_SECTION_HEADER *pimsh;
        pimsh = (IMAGE_SECTION_HEADER *)malloc(sizeof(IMAGE_SECTION_HEADER) * imnth.FileHeader.NumberOfSections);

        long t;

        fread(pimsh,sizeof(IMAGE_SECTION_HEADER),imnth.FileHeader.NumberOfSections,fp);

        for(i=0;i<imnth.FileHeader.NumberOfSections;i++)
        {
            if(!strcmp((char *)pimsh->Name,".idata"))
                t = pimsh->PointerToRawData;
            pimsh++;
        }

        fseek(fp,t,0);

        IMAGE_IMPORT_DESCRIPTOR iid;
        char c;

        while(1)
        {
            fread(&iid,sizeof(iid),1,fp);

            if(iid.Characteristics == NULL)
                break;

            t = ftell(fp);

            fseek(fp,(long)iid.Name,0);

            while(c=fgetc(fp))
                printf("%c",c);
            printf("\n");

            fseek(fp,t,0);

        }
    }

Ответы [ 2 ]

4 голосов
/ 11 марта 2012

Есть несколько проблем.

  • Вы не можете предполагать, что раздел импорта называется ".idata". Вы должны найти импорт, используя IMAGE_OPTIONAL_HEADER.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].

  • Большинство смещений в PE-файле - это относительные виртуальные адреса (RVA), а не смещения файла. Чтобы преобразовать RVA в смещение, необходимо определить, в каком разделе находится виртуальный адрес, а затем рассчитать смещение на основе расположения этого раздела в файле. В частности, поле IMAGE_IMPORT_DESCRIPTOR.Name содержит RVA, а не смещение файла.

  • Ваш код будет намного проще (и быстрее), если вы будете использовать отображенный в памяти файл вместо файлового ввода-вывода.

В этой статье MSDN описываются RVA, каталог данных и т. Д. Он также включает pedump, приложение с полным исходным кодом для выгрузки PE-файлов, которое является полезным справочным материалом.

2 голосов
/ 14 марта 2012

Ответ по mox правильный во всех точках, однако я также хотел бы добавить другое решение - загрузить файл в виде изображения для чтения данных.
Это достигается очень просто, используя LoadLibraryEx только с одной строкой кода.

Base = LoadLibraryEx("c:\Linked List.exe", 0, DONT_RESOLVE_DLL_REFERENCES);

Это загружает и отображает ваш исполняемый файл как изображение, поэтому нет необходимости открывать / читать / отображать или преобразовывать rva в необработанные смещения.

С флагом DONT_RESOLVE_DLL_REFERENCES изображение неинициализировано, поэтому все данные импорта не затрагиваются, а код точки входа не выполняется.Исполняемый файл просто отображается в памяти.

Вы можете просто использовать Base + Rva , чтобы найти импортированное имя DLL - или любой другой тип информации PE.
Освободить исполняемый образ после использования с FreeLibrary (Base)

...