Murat ERDEM - Personal Research Blog




PE Files - 0x05

August 2, 2020

En son File Header alanındaki verilere ulaşmıştık, şimdi ise Optional Header alanı içerisindeki verilerden söz edeceğiz.

Öncelikle bu alan içerisinde önemli verilerin tutulduğu alanlardan birisidir. Optional Header içerisinde işletim sistemi sürümü ve programın entry pointi gibi verileri bulundurur. bu alanın bilgilerini almak için kullanacağımız yapı IMAGE_OPTIONAL_HEADER yapısıdır.

Bu alan içerisinde ikiye ayrılır. standart kısmı executable dosyaların ortak kullandığı Ortak Nesne Dosya Biçimi (COFF) için ortak alanlardır. Bu alanlar içerisinde en önemli olanı AddressOfEntryPoint değerini bu değer bir programın ilk nereden çalıştırılmaya başlayacağını gösterir.

Ek alanlar ise yazmış olduğumuz executable dosyalara ek özellikler kazandırmayı sağlar buradaki değerleri biraz açıklayacak olursak bunların önemini daha iyi anlayabiliriz.

Imagebase

Bu alan bildiğimiz gibi dosyanın memory üzerinde yükleneceği adresi belirtir ve default değer olarak 0x00400000 alır.

SectionAlignment

Bu değer dosyamızdaki section boyutlarının tutarak bellek üzerinde fazla yer ayrılıp gereksiz performans kaybı yaşanmasını engeller.

MajorOperationSystemVersion

İşletim sisteminin majör versiyonunu gösterir.

MinorOperationSystemVersion

İşlerim sisteminin minör versiyonunu gösterir.

Majör ve minör versiyonlar kullanılarak bir işletim sisteminin versiyonu belirlenebilir. Örnek olarak 6.3.9600 olarak gösterilen bir işletim sistemi versiyonunda majör id 6, minor id 3, ve build id 9600 olarak gösterilebilir. Aşağıdaki tablodan ise bu sistemin bir windows 8.1 olduğunu görebiliriz.

SizeOfImage

Bu değer PE dosyasının mermory üzerindeki kapladığı alan boyutunu tutar.

SizeOfHeader

Bu alanda PE file header, Optional header gibi header ile ilgili bölümler bulunur.

Subsystem

Hangi işletim sistemi üzerinde çalışacağını belirtir.

DLLCharacteristics

Bu değer program içerisinde kullanılmak üzre import edilen DLL dosyalarının başlangıç ve bitiş adreslerini tutar.

LoaderFlags

Bu flag değerleri dosyanın debug,default yada break olarak hangi amaç ile yükleneceğini belirtir.

DataDrectory

Bu alan bizim için oldukça önemlidir. Executable dosyalar için import edilen önemli dosya bileşenlerin import yolunu gösterir. PE dosyamız dışarıdan bir dosyaya erişmek istediğin de bu yollar üzerinden ulaşır. bu alanın içerisindeki bilgilere erişmek için IMAGE_DATA_DIRECTORY yapısı kullanılabilir.

Bu alan aslında bir dizi şeklinde sıralanmıştır. İçerisindeki verilere erişim için indekslerini kullanmamız gerekmektedir. Bu indeks sayısı IMAGE_NUMBEROF_DIRECTORY_ENRIES olarak tanımlanır. ve indekse karşılık gelen veri yolu aşağıdaki gibidir.

(Yukarıdan aşağı sıralı şekilde gösterilmiştir.)

Bu alanın önemini yeterince anladıysak kodlama kısmında bu alanların ansıl elde edildiğine bakalım öncelikle Optional Header bilgilerini elde etmemiz gerekiyor bunun için aşağıdaki kodu kullanabiliriz.

    
        IMAGE_OPTIONAL_HEADER optionalHeader = (IMAGE_OPTIONAL_HEADER)ntheader->OptionalHeader;
        optionalHeaderWriter(optionalHeader);
    

Burada tanımladığımız optionalHeaderWriter fonksiyonu gerekli bilgileri ekrana yazmak için kullanıyoruz. Bu fonksiyon içeriği aşağıdaki gibidir.

    
        void optionalHeaderWriter(IMAGE_OPTIONAL_HEADER optionalHeader) {
            cout << endl << "______PIMAGE_OPTIONAL_HEADER______" << endl;
            cout << "Magic : " << hex << optionalHeader.Magic << endl;
            cout << "MajorLinkerVersion : " << hex << setw(2) << setfill('0') << (int)optionalHeader.MajorLinkerVersion << endl;
            cout << "MinorLinkerVersion : " << hex << setw(2) << setfill('0') << (int)optionalHeader.MinorLinkerVersion << endl;
            cout << "SizeOfCode : " << hex << optionalHeader.SizeOfCode << endl;
            cout << "SizeOfInitializedData : " << hex << optionalHeader.SizeOfInitializedData << endl;
            cout << "SizeOfUninitializedData : " << hex << optionalHeader.SizeOfUninitializedData << endl;
            cout << "AddressOfEntryPoint : " << hex << optionalHeader.AddressOfEntryPoint << endl;
            cout << "BaseOfCode : " << hex << optionalHeader.BaseOfCode << endl;
            cout << "BaseOfData : " << hex << optionalHeader.BaseOfData << endl;
            cout << "--------------------------------" << endl;
            cout << "ImageBase : " << hex << optionalHeader.ImageBase << endl;
            cout << "SectionAlignment : " << hex << optionalHeader.SectionAlignment << endl;
            cout << "MajorOperatingSystemVersion : " << hex << optionalHeader.MajorOperatingSystemVersion << endl;
            cout << "MinorOperatingSystemVersion : " << hex << optionalHeader.MinorOperatingSystemVersion << endl;
            cout << "MajorImageVersion : " << hex << optionalHeader.MajorImageVersion << endl;
            cout << "MinorImageVersion : " << hex << optionalHeader.MinorImageVersion << endl;
            cout << "MajorSubsystemVersion : " << hex << optionalHeader.MajorSubsystemVersion << endl;
            cout << "MinorSubsystemVersion : " << hex << optionalHeader.MinorSubsystemVersion << endl;
            cout << "Win32VersionValue : " << hex << optionalHeader.Win32VersionValue << endl;
            cout << "SizeOfImage : " << hex << optionalHeader.SizeOfImage << endl;
            cout << "SizeOfHeaders : " << hex << optionalHeader.SizeOfHeaders << endl;
            cout << "CheckSum : " << hex << optionalHeader.CheckSum << endl;
            cout << "Subsystem : " << hex << optionalHeader.Subsystem << endl;
            cout << "DllCharacteristics : " << hex << optionalHeader.DllCharacteristics << endl;
            cout << "SizeOfStackReserve : " << hex << optionalHeader.SizeOfStackReserve << endl;
            cout << "SizeOfStackCommit : " << hex << optionalHeader.SizeOfStackCommit << endl;
            cout << "SizeOfHeapReserve : " << hex << optionalHeader.SizeOfHeapReserve << endl;
            cout << "SizeOfHeapCommit : " << hex << optionalHeader.SizeOfHeapCommit << endl;
            cout << "LoaderFlags : " << hex << optionalHeader.LoaderFlags << endl;
            cout << "NumberOfRvaAndSizes : " << hex << optionalHeader.NumberOfRvaAndSizes << endl;
            cout << "--------------------------------" << endl;
            for (int i = 0; i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; i++) {
                IMAGE_DATA_DIRECTORY dataDirectory = (IMAGE_DATA_DIRECTORY)optionalHeader.DataDirectory[i];
                int size = dataDirectory.Size;
                if (size != 0) {
                    cout << "-------" << i << "------------" << endl;
                    cout << "VirtualAddress : " << hex << dataDirectory.VirtualAddress << endl;
                    cout << "Size : " << hex << dataDirectory.Size << endl << endl;
                }
            }
            cout << endl << endl << endl;
        }
    

Bu fonksiyonda MajorLinkerVersion ve MinorLinkerVersion veri tipleri byte olduğu için bazı eklemeler yapmam gerekti ve bu eklemeleri kullanabilmek için iomanip kütüphanesini projeme dahil ettim. Bu fonksiyon içerisinde dahil edilen dosya yollarının bulunduğu değerleri indeks değeri ile birlikte yazdırmış olduk. Bu programı çalıştırıp çıktısına bakacak olursak aşağıdaki gibi olacaktır.