2 Eylül 2017 Cumartesi

PE-x86 Architecture-[ Portable Executable ]- Formatı

PE  dosya formatı nedir ?
~~~~~~~~~~~~~~~~~~~~~~~~
PE dosya formatı Windows işletim sisteminin kullandığı çalıştırılabilir,icra edilebilir dosya formatıdır. PE, Portable Executable’ın kısaltılmış halidir.

Bu yazının amacı Windows işletim sistemi altında çalışan PE formatının yapısını anlamaktır. 



PE Genel Yapısı
~~~~~~~~~~~~~~~~~~~~~~~~

PE dosya formatının yapısı aşağıdaki resimde görülmektedir.


PE dosyasının belleğe maplenişi(haritalanması) aşağıdaki resimde görülmektedir.




Disk üzerindeki sectionlar belleğe 4K şeklinde hizalanırlar.  PE dosyası Windows loader tarafından belleğe yüklendikten sonra , bellekteki bu yapı artık MODULE olarak adlandırılır.

DOS MZ Header & DOS stub
~~~~~~~~~~~~~~~~~~~~~~~~
PE  dosyası DOS işletim sistemi altında çalıştırılmak istenildiğinde DOS işletim sistemi tarafından PE dosyasının tanınması için PE dosyalarında bu başlık bulunur. 64 bayt uzunluğundaki bu başlığın hemen ardından linkerlar tarafından otomatik olarak yerleştirilen DOS Stub mevcuttur. DOS Stub, PE dosyasının DOS işletim sistemi tarafından çalıştırılamayacağını belirten bir mesajı ekrana basar.



PE dosyasını DOS işletim sistemi altında çalıştırmak istediğinizde DOS Stub tarafından yukaridaki mesajı  alırsınız.



DOS başlığının ilk 2 baytı Magic number olarak bilinir  ve Magic number  “MZ” string değerini içerir.

Bu başlığın son elemanı  e_lfanew ise PE Header başlığının dosya üzerinde nerede olduğunu belirten offset bilgisini barındırır.


Yukarıdaki resimde e_lfanew0x000000f8 (little endian formatta saklandığından tersten okumanız gerekmektedir.)  değerini göstermektedir. Bu offset değeri  PE Headerın başlangıcını göstermektedir.

PE Header
~~~~~~~~~~~~~~
Bu  başlık winnt.h başlığı içerisinde IMAGE_NT_HEADERS olarak tanımlıdır. Windows loader tarafından kullanılacak gerekli bilgiler bu başlıkta bulunur.



Signature , 4 baytlık alan işgal eder ve “PE” stringini içerir. PE başlığının 
Signature değeri  bir önceki resimde altı kırmızı ile çizilmişti.

FileHeader ve OptionalHeader ayrı başlıklar altında inceleyerek  yazımıza devam edelim.

OptionalHeader, FileHeader içerisinde belirt baytlık bir alanı işgal eder.

IMAGE FILE HEADER– [ FileHeader ]-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

FileHeader, 20 baytlık bir alanı işgal eder.



FileHeader, IMAGE_FILE_HEADER structının kendisidir ve yukarıdaki resim   IMAGE_FILE_HEADER yapısını açıklar. Bu structın bazı elemanları açıklayalım.

Machine , Mimari bilgisini içerir. örneğin  x86 mimari için Machine elemanı  0x014c değerine  ve x64 mimari için 0x8664 değerine sahiptir.

NumberOfSections , PE dosyasındaki section sayısını verir.  Sectionlar bir PE dosyasını kod,data gibi bilgileri içeren bölümlere ayırır. Windows loader tarafından bu sectionlar belleğe Page tabanlı / Page Hizalamalı bir şekilde yüklenir.

PointerToSymbolTable, PE(Portable Executable) dosyalar için buranın bir anlamı yok bu yüzden burası 0 değerine sahiptir. Fakat Windows tarafında COFF/Object dosyaları(linkerlar tarafından  input olarak kullanılabilirker ve  bir çok object dosyası bir araya getirilerek istenilirse PE executable dosya oluşturulabilir ) için burası dosya içerisindeki sembol tablosunun offsetini belirtir. Tekrardan belirtelim  PointerToSymbolTable COFF(Windows işletim sisteminin  Object dosyaları için kullandığı format )  için anlamlıdır.

NumberOfSymbols, COFF formatı için sembol tablosundaki sembollerin sayısını verir. Windows PE/Çalıştırılabilir dosyaları için anlamsız ve bu yüzden 0 değerine sahiptir.

SizeOfOptionalHeader, OptionalHeaderın uzunluğunu bayt cinsiden belirtir.

Characteristics, PE formatına ilişkin bazı önemli bilgiler bu alanda bitsel olarak kodlanmıştır. Her bir bit belli bir özelliği belirtmektedir. Örneğin ; dosyanın executable bir dosya olduğunu veya dll dosyası olduğunu , dosyanın 32-bitlik bir işlemci üzerinde çalışacağı , PE dosyasının 2 GB dan daha fazla bir alanı kullanacağı gibi  buna benzer  bilgiler burada belirtilir.

IMAGE OPTIONAL HEADER -[ OptionalHeader ]-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
PE dosya formatında kesinlikle bulunması gereken bir başlıktır. Yukarıda bahsettiğimiz üzere  Windows işletim sisteminin kullandığı Object dosya formatı COFF  bu başlığı içermez.


Bu başlık içerisindeki bazı elemanları açıklayalım.

SizeOfCode, PE dosyasında bulunan kod sectionın uzunluğunu belirtir.

SizeOfInitializedData, PE dosyasında bulunan data sectionın(ilk değer ataması yapılmış global ve static değişkenlerin değerlerinin tutulduğu yer)  uzunluğunu belirtir.

SizeOfUninitializedData, PE dosyasında bulunan ilk değer ataması gerçekleştirilmemiş   global ve statik değişkenlerin   uzunluğunu belirtir. 

Bu sayede Windows loader startup aşamasında bellekte bu elemanın belirttiği kadar bir yer ayırır ve bu alana ilk değer olarak 0 ataması yapılır.

ImageBase, Windows PE loader tarafından PE dosyası ImageBase tarafından belirtilen adresten itibaren yüklenmeye başlanır.  Executable dosyaların  ImageBase  elemanı  0x00400000 adresini, DLL dosyaların   ise 0x10000000 adresini gösterir. Burada bu adreslerin öncelikli adresler olması DLL veya Executable dosyanın ImageBase tarafından belirtilen adrese yükleneceğini garanti etmez. ImageBase içerisinde belirtilen adresin dolu olması durumunda Windows Loader , PE dosyasını başka bir adresten itibaren yüklemeye başlayacaktır.

AddressOfEntryPoint, PE dosyası belleğe yüklendikten ve çalıştırılmaya hazır hale getirildikten sonra AddressOfEntryPoint elemanının belirttiği adrese sıçrama yapılacak ve buradan itibaren PE dosyası çalıştırılmaya başlanacaktır. Buradaki adres göreceli sanal adres ( Relative Virtual Address) olarak bilinir. ImageBase adresi ile RVA(Relative Virtual Address) toplanarak Sanal Adres/Virtual Adress elde edilir.

(*) Bir X adresinin Göreceli  Sanal Adres  olması demek , X adresinin 
ImageBase’den   X kadar uzak olması demektir.

BaseOfCodekod bölümünün başlangıcını belirten göreceli sanal adresi(RVA) içerir.

BaseOfData, data bölümünün başlangıcını belirten göreceli sanal adresi(RVA) içerir.

SectionAligmentSectionlar/Bölümler belleğe yüklenirken burada belirtilen değerin katları şeklinde yüklenir/hizalanır. Örneğin;ilk section Windows loader tarafından   ve sectionın uzunluğu 28 bayt olsun. İkinci section yüklenirken Windows loader 28.bayttan hemen sonra ikinci sectionı belleğe yüklemez. 

SectionAligment’ın  belirttiği değere göre ikinci sectionı hizalar. Eğer 
SectionAligment’ın değeri 4096(4K,varsayılan olarak böyledir) ise bu durumda 2.section 4096.bayttan itibaren yüklenmeye başlanacaktır.

FileAligment, PE dosyasındaki bölümlerin disk üzerindeki hizalanışını ise FileAligment belirler. Varsayılan olarak bu değer 512((1 sektör) değerine sahiptir. Bu durumda bölümler disk üzerinde 512 nin katı şeklinde hizalanır.

SizeOfImage, PE dosyasının bellekteki boyutunu belirtir.

SizeOfHeaders, Tüm headerların(IMAGE_DOS_HEADER,IMAGE_FILE_HEADER,IMAGE_OPTONAL_HEADER)  ile  section headerlarının(kısacası section tablosunun)  toplamı,  FileAligment elemanın belirttiği değerin katına yuvarlanarak bu eleman içerisine yazılır.

Subsystem, PE dosyasının  Windows  uygulamasımı, Konsol uygulamasımı , Mobil uygulamamı veya bir Windows sürücüsü olup olmadığı gibi alt sisteme ilişkin bilgiler buranın yorumlanması ile elde edilir. Subsytem değerlerini yorumlamacak için internet üzerinden kısa bir araştırma yapabilirsiniz.(MSDN bununla ilgili geniş dökümana sahip)

DllCharacteristics, DLL karakterestiğine ilişkin bilgilerin bitsel olarak kodlandığı alandır. DllCharacteristics elemanının değerlerine ilişkin tabloya  MSDN üzerinden göz atabilirsiniz.

SizeOfStackReserve, Prosesin kullanacağı stack alanın miktarını belirtir. Bir process veya thread yaratılırken stack alanın miktarı  bu değere göre belirlenir. Default olarak bu değer   1 MB değerine setlenmiştir.

SizeOfStackCommit , Yukarıda belirttiğimiz SizeOfStackReserve    aslında prosesin sanal adresinde alan yaratmaktatır. Bu yüzden prosesin/threadin stack gereksinimi fiziksel olarak ram’den karşılanması gerekir.  Fakat bu alan SizeOfStackReserve’ün belirttiği kadar değil SizeOfStackCommit’in belirttiği kadar ile karşılanır ve prosesin adres alanına maplenir. İlerde ihtiyaç olması halinde ve SizeOfReserve aşılmadığı müddetçe  Fiziksel alandan bu gereksinim SizeOfStackCommit’lik bir alan ile  karşılanmaya devam edilir. 

SizeOfHeapReserve, prosesin heap alanın boyutunu/miktarını belirtir.

SizeOfHeapCommit, proses ilk oluşturulduğunda commit edilecek olan alanın miktarını belirtir. Yukarıda Commit ve Reserve arasındaki farktan bahsettiğimizden tekrardan burada neden böyle bir ayrım yapıldığından bahsetmeye gerek yok.

LoaderFlags, ilerde kullanmak için rezerve edilmiştir.

NumberOfRvaAndSizes,  bir sonraki IMAGE_DATA_DIRECTORY türündeki DataDirectory yapısının kaç elemanı olduğu bilgisi burada tutulur.

IMAGE DATA DIRECTORY – [ DataDirectory ] –
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
IMAGE_OPTIONAL_HEADER yapısının son elemanı olan IMAGE_DATA_DIRECTORY türündeki DataDirectory bir veri dizinidir. 

DataDirectory yapı dizisi içerisinde çeşitli tablo ve dizinler hakkında bilgi barındırır.


DataDirectory’e ait kayıtlar yukarıdaki resimde görülmektedir. Biz bu yazıda Export Directory, Import Directory ve Import Address Table hakkında konuşacağız.

DataDirectory dizisinin elemanı olan Directory kayıtlarına ilişkin yapı aşağıdaki resimde görülmektedir.


VirtualAdress, ilgili tablonun veya  dizinin kendisini işaret eden RVA adresidir.

Size, ilgili tablonun veya  dizinin uzunluğunu bayt cinsinden belirtir.

Bu DataDirectory tablosuna lord-pe programı ile kolayca göz atabilirsiniz.



(*) Yazının ilerleyen kısımlarında IAT,Import Table ve Export Table directorylerinden bahsedeceğiz.

Yazının buraya kadar ki kısmında DOS MZ Header, DOS Stub, PE Header kısımlarını tamamladık. Section Tablosunu inceleyerek devam edelim.

[---- Section Table  ----]
~~~~~~~~~~~~~~~~~~~~
Önceki kısımlarda da belirttiğimiz gibi sectionlar disk üzerinde dosyanın mantıksal olarak bölümlere ayrılmış halidir. Örneğin; Kod sectionında/bölümünde makine diline ait kodlar bulunmaktadır. PE dosyası belirli sectionlara ayrılmıştır.

PE dosyalarını incelerken  .text, .data gibi sectionlara karşı geliceksiniztir. Fakat biz sectionların detayına girmeyeceğiz dilerseniz onları araştırabilirsiniz. Bizim burada section  ile  ilgili bilmemiz gereken  disk üzerindeki dosyamızı mantıksal olarak bölümlediğimizdir.

PE dosyası içerisinde sectionlara ait bilgiler section tablolarında kayıtlar halinde tutulur. Her bir kayıt ilgili sectionın kendisi hakkında bilgiye sahiptir. Windows loader belleğe PE dosyasını maplerken bu bilgilerden faydalanır.



Section Tablosundaki her bir kayıt yukarıdaki IMAGE_SECTION_HEADER  yapısı ile tanımlanmıştır.

Name, 8 bayt uzunluğundadır ve sectionın ismini belirtir.ASCII string olmadığından dolayı null(0)  karakteri ile bitmek zorunda değildir.

VirtualSize, Sectionın bellekteki uzunluğunu  bayt cinsinden belirtir.

VirtualAddress, Sectionın RVA değeri. Örneğin ;  VirtualAddress 0x1000 ise ve ImageBase 0x400000 ise bu durumda Windows pe loaderı bu sectionı  0x401000 adresinden itibaren yüklemeye başlayacaktır.

SizeOfRawData,  Sectionın disk üzerindeki boyutunu ifade eder. Bu elemanın değeri  FileAligment elemanın katına yuvarlanmıştır.

(*) Eğer SizeOfRawData elemanın değeri VirtualSize elemanın değerinden daha küçükse bu durumda geriye kalan alan bellekte 0 değerine setlenir.

PointerToRawData, Sectionın başlangıc offset değerini belirtir. Windows loader sectionların dosya üzerinde nerede olduğunu buraya bakarak bulmaktadır.

PointerToRelocations , PointerToLinenumbers, NumberOfRelocations, NumberOfLinenumbers .

Bu elemanlardan PointerToRelocations ve NumberOfRelocations elemanları relocation işlemi gerçekleştirileceği zaman kullanılmaktadır. 

Windows PE Loader eğer IMAGEBASE adresine PE dosyasını yükleyemezse PE dosyasını uygun bir adrese yükler ve ardından .reloc sectionındaki bilgileri kullanarak PE dosyası üzerinde  gerekli düzeltmeleri gerçekleştirir. 

Characteristics , Sectionın karakteristiğine ilişkin bilgileri tutar.
Örneğin ; ilgili sectionın yazılabilir,okunabilir, çalıştırılabilir olup olmadığı gibi bilgiler buradan öğrenilir.

Export ve DLL Dosyaları
~~~~~~~~~~~~~~~~~~~

DLL dosyaları Windows OS tarafından direk olarak çalıştırılabilir olan dosyalar değildir. EXE dosyaları tarafından bu DLL dosyaları ateşlenebilir  veya daha düzgün ifade ile DLL içerisinde barındırılan fonksiyonlar EXE dosyaları tarafından çağrılabilir/icra edilebilir.


DLL dosyası da tıpkı EXE dosyaları gibi aynı PE formatına sahiptirler. DLL dosyalarının fonksiyonlarına bir başka modül tarafından(bellekteki executable/dll dosyalarına modül denilmektedir )  arka planda nasıl erişilebildiğini anlamaya çalışalım.

DLL dosyalarındaki fonksiyonlara diğer modüller ya fonksiyon ismi ile ya da ordinal numaraları ile 2  farklı şekilde erişebilirler. Ordinal numarası DLL içerisindeki fonksiyonlara özel 16-bitlik bir numaradır. Bu numaralar sayesinde DLL içerisindeki her bir fonksiyon birbirinden ayrılmış olur.

Yazının önceki kısımlarında PE dosya formatının DataDirectory  dizisinden bahsetmiştik. Bu dizinin elemanlarından birisi ve ilk elemanı da Export Directory. 


Export Directory yapısı aşağıdaki resimde görülmektedir.




Buradaki elemanlardan bizim için önemli olanlara göz atalım.

Name, Modülün ismini belirtir.

Base, Başlangıc ordinal numarasıdır.

NumberOfFunctions , export edilmiş(dışarıdan erişilebilmesi için) fonksiyonların sayısını belirtir.

NumberOfNames, isim ile export edilmiş fonksiyonların sayısını belirtir. Tüm export edilmiş fonksiyonların sayısını belirtmez.

(*) Yukarıda belirttiğimiz üzere bir DLL dosyası ismi ve ordinal numarası ile fonksiyonlarını export edebilir.

AddressOfFunctions, Export Address Tablosunu ( EAT )  işaret eden RVA değerini içerir. Bu Tablo export edilmiş fonksiyonların RVA değerlerini içerir. Kısacası export edilmiş fonksiyonların adreslerinin bir tabloda tutulduğunu düşünelim , Bu durumda AddressOfFunctions bu tablonun başını gösteren bir pointer olarak düşünebiliriz.

AddressOfNames, Export Name Tablosunu (ENT)  işaret eden RVA değerini içerir. Bu tablo export edilmiş fonksiyonların ismini içerir.

AddressOfNameOrdinals, Export Ordinal Tablosunu(EOT) işaret eden RVA değerini içerir. Bu tablo isim ile export edilmiş fonksiyonların ordinal değerlerini içerir.


Tüm bunları bir resim ile özetlemek isteseydik , kaynak olarak da belirteceğim makaledeki gibi çizimlerdik.



Resimde anlatılmak isteneni bir örnek ile açıklayalım.

Bir DLL dosyası 20 tane fonksiyonu  export etmiş olsun. Bu durumda AddressOfFunction elemanın işaret ettiği Export Address Tablosunda 20 adres olacaktır aynı şekilde  NumberOfFunctions elemanın değeri de 20 olacaktır.

Bu durumda bir fonksiyonu ismi ile bulmaya çalışalım. Windows işletim sistemi öncelikle Export Directory içerisindeki NumberofNames ve NumberOfFunctions değerlerine elde edecektir.Ardından AddressofNames elemanın işaret ettiği Export Name Tablosunda bu fonksiyonu  arayacaktır. Bu aramayı gerçekleştirirken aynı zamanda Export Ordinal Tablosunda da paralel olarak ilerleyecektir. Fonksiyonu Export Name Tablosu içerisinde bulması durumunda bu isme karşı düşen Ordinal değerini Export Ordinal Tablosundan elde edecektir. Bu Ordinal numarasını Export Addres Tablosuna index olarak kullanarak ilgili fonksiyonun Adresini elde edecektir.

20-fonksiyonlu-DLL dosyamızda aradığımız fonksiyon eğer Export Name Tablosunda 13.sırada bulunan   topla() isimli bir fonksiyon ise bu durumda Export Ordinal Tablosunda 13. sıradaki ordinal numarasını alırız ve  Export Address Tablosuna index olarak verip, topla() fonksiyonunun adresi elde etmiş oluruz.

Eğer elinizde zaten topla() isimli fonksiyona ait ordinal numarası varsa bu durumda direk Export Address Tablosundan topla() fonksiyonunun adres değerini elde edebilirsiniz. Gerçekte Ordinal numarasını kullanarak fonksiyona ulaşmak isim ile o fonksiyona ulaşmaktan daha hızlıdır. Fakat bunun dezavantajı yazılımcının DLL dosyasına yeni fonksiyonlar eklemesi durumunda ve  DLL dosyasının güncellenmesi durumunda Ordinal numaralarının değişmesi durumudur. Bu durumda topla() isimli fonksiyonuna ait X ordinal numarası güncelleştirilmiş DLL de Y isimli bir fonksiyona ait olabilir.

Import Section ve Executable Dosyaları
~~~~~~~~~~~~~~~~~~~


Windows Executable dosyaları ihtiyaç duydukları DLL dosyalarını kullanırlar. Executable dosyaların kullandıkları her bir DLL ve onlara ait fonksiyonların bilgisini Windows PE Loader Import Directory aracılığı ile öğrenir. Bu başlık Executable dosyaların kullandığı bu yapıyı açıklamaya çalışacağız.


Executable dosyaları tarafından importlanan/ithal edilen DLL dosyaların her biri IMAGE_IMPORT_DESCRIPTOR yapısı ile tanımlanmıştır.


Eğer Executable dosyamız 10 tane farklı DLL dosyasını import edecekse bu durumda 10 tane IMAGE_IMPORT_DESCRIPTOR yapısı Import Directory içerisinde bulunacaktır.

 Bu yapıda önemli olan elemanları açıklayalım.

OriginalFirstThunk, IMAGE_THUNK_DATA yapısını işaret eden RVA değerini içerir.


Name, DLL dosyasının isminin belirten RVA değerini içerir. 

FirstThunk, IMAGE_THUNK_DATA yapısını işaret eden RVA değerini içerir.

IMAGE_THUNK_DATA yapısı ;



Disk üzerindeki dosyada IMAGE_THUNK_DATA yapısı importlanmış fonksiyonun ordinal numarasını ya da IMAGE_IMPORT_BY_NAME yapısını işaret eden RVA değerini içerir.

Ordinal Numarasını bu yapının Ordinal elemanı belirtiken, IMPORT_BY_NAME yapısını AddressOfData elemanı işaret eder.

Bu yüzden importlanan fonksiyonlara 2 türlü erişim sağlanabilir tıpkı bir önceki export ile ilgili başlıkta bahsettiğimiz gibi. Öncelikle IMAGE_IMPORT_BY_NAME yapısını açıklayalım.

IMAGE_IMPORT_BY_NAME yapısı ;




Hint, fonksiyonu içeren DLL dosyasının Export Tablosunda index olarak kullanılır. Fakat kimi zaman bu değer 0 olabilir bu durumda PE loader bu değer ile ilgilenmez.

Name, importlanmış fonksiyonun ismini belirtir.

Daha önce de belirttiğimiz gibi eğer bir DLL executable dosyasına import edilmişse bu durumda executable dosyanın Import Directory içerisinde bu DLL  IMAGE_IMPORT_DESCRIPTOR yapısı ile ifade edilir.

Bu yüzden PE Loader Executable dosyasının çalışma anında ihtiyaç duyacağı tüm DLL dosyalarını Import Directory dizisine göz atarak prosesin sanal adres alanına yükler.

Bu işlemin nasıl gerçekleştiğini anlatalım. 

IMAGE_IMPORT_DESCRIPTOR yapısının elemanı olan OriginalFirstThunk, IMAGE_THUNK_DATA yapısından oluşmuş diziyi işaret eder.  Bu dizinin boyu DLL dosyasından import edilen fonksiyonların adeti kadardır. IMAGE_IMPORT_DESCRIPTOR yapısının FirstThunk elemanı ise tıpkı OriginalFirstThunk elemanı gibi IMAGE_THUNK_DATA yapısına ait bir diziyi işaret eder. Başlangıc aşamasında bu iki dizi birbirinin aynısıdır. Bu dizilerdeki   IMAGE_THUNK_DATA yapısının her biri yine IMAGE_IMPORT_BY_NAME yapılarını işaret eder. Bu yapılar Import edilmiş Fonksiyonların isimleri tutarlar. Burada bulunan fonksiyonların isimleri belirtilen DLL dosyası içerisinde bulunur. Bulunan fonksiyonların adresleri FirstThunk ile işaret edilmiş dizinin ilgili elemanına yerleştirilir. Bu şekilde FirstThunk ile işaret edilen dizi artık executable tarafından import edilmiş olan tüm fonksiyonların adreslerini içeren tablo haline gelmiş olur. Bu tabloya IMPORT ADDRESS TABLE  denilmektedir. OriginalFirstThunk tarafından işaret edilen diziye ise IMPORT NAME TABLE denimektedir. Bu arada belki dikkatinizi çekmiştir herhangi bir şekilde Import Directory eleman sayısını belirten herhangi bir eleman PE dosyasında belirtilmemiştir bu durumda Loader kaç tane Executable dosya tarafından DLL importlandığını bilemez. Bu yüzden Import Directory dizisinin son elemanı 0 değeri ile setlenmiştir.

(*) Bu anlattıklarımızı bir resim ile özetleyecek olursak işte şöyle olurdu. Bu resim kaynak olarak belirtilen yazı/yazılardan alınmıştır.



Burada bahsetmiş olduğumuz importlama aslında fonksiyonların isimlerine göredir. Kimi durumlarda bu ordinal ile de gerçekleştirilebilir. Bu durumda IMAGE_THUNK_DATA yapısına ait dizinin her bir eleman IMAGE_IMPORT_BY_NAME yapılarını işaret etmez. Bunun yerine Ordinal numaraları taşırlar.Yukarıda IMAGE_THUNK_DATA yapısına göz atarsanız bu yapının Ordinal elemanını göreceksiniz. Bu sefer PE Loader Ordinal numarasını baz alarak DLL içerisinde fonksiyonun adresine ilişkin arama gerçekleştirecektir(DLL içerisinde fonksiyonları arama işlemi bir önceki yazıda belirtilmiştir).


Peki PE Loader IMAGE_THUNK_DATA dizisindeki her bir elemanın bir IMAGE_IMPORT_BY_NAME yapısını mı işaret ettiğini yoksa Ordinal numarası mı saklı tuttuğunu nasıl bilebiliyor. Bunun cevabı IMAGE_THUNK_DATA dizisindeki her bir elemanın en anlamlı bitinde saklıdır.

IMAGE_THUNK_DATA dizisindeki her bir elemanın en anlamlı bitine bakılır. Eğer en anlamlı bit 0 ise bu durumda importlamanın isim ile olduğunu eğer 1 ise bu durumda importlamanın Ordinal ile yapılacağını anlar.

Kaynaklar : 

Portable Executable File Format – A Reverse Engineer View , Goppit
January 2006

EOF

1 yorum: