1. 程式人生 > >逆向工程入門學習(FreeBuf)

逆向工程入門學習(FreeBuf)

逆向工程(二):從一個簡單的例項來了解PE檔案


文中RegisterMe及原視訊下載地址:http://pan.baidu.com/s/1bnqOgnt開啟這個RegisterMe.exe程式,會出現如下煩人的訊息框:

引入

目標:去掉煩人的訊息框

工具:Ollydbg

1.載入程式,由圖可以看出呼叫了兩個MessageBox,當程式執行到這裡的時候分別會有上述訊息框彈出。 

2.觀察 cmp eax,0×0

這裡判斷eax是否等於0

je(如果相等就跳轉 – ZF=1  

由於eax等於40000

所以這一個跳轉永遠不會成立,所以一定會執行這個煩人的MessageBox。

那麼我們就可以想辦法使它跳轉。

3.我們嘗試改變ZF標記值(je跳轉根據ZF標記判斷)

如圖,此時ZF標記為0,我們雙擊這個0,使其標記為1

再觀察:

跳轉實現了,我們成功跳過了訊息視窗!!

不過這樣每次要改變ZF標記很麻煩,我們可不可以讓它直接跳轉不進行判斷呢?所以我們可以雙擊編輯je short 00401024為jmp short 00401024

成功跳過了MessageBox!!

我們想使用一種更加完美的方法來跳過這個訊息框。。。。

假如我們把程式入口設定成00401024不就直接跳過了MessageBox了嗎?在這之前,我需要解釋一些PE的知識(請耐心地閱讀,這才是本文所要講的重點,而不是如何破解這個程式!!) 

下面標有紅色的代表重點,如果你時間緊迫,可以只看有下劃線的文字

深入的必經之路:

PE(Portable Executable)檔案簡介

PE(Portable Executable)檔案是Windows作業系統下使用的可執行檔案格式。它是微軟在UNIX平臺的COFF(通用物件檔案格式)基礎上製作而成。最初設計用來提高程式在不同作業系統上的移植性,但實際上這種檔案格式僅用在Windows系列作業系統下。

PE檔案是指32位可執行檔案,也稱為PE32。64位的可執行檔案稱為PE+或PE32+,是PE(PE32)的一種擴充套件形式(請注意不是PE64)。

PE檔案結構一般如上圖所示。

當一個PE檔案被執行時,PE裝載器首先檢查DOS header裡的PE header的偏移量。如果找到,則直接跳轉到PE header的位置。

當PE裝載器跳轉到PE header後,第二步要做的就是檢查PE header是否有效。如果該PE header有效,就跳轉到PE header的尾部。

緊跟PE header尾部的是節表。PE裝載器執行完第二步後開始讀取節表中的節段資訊,並採用檔案對映(在執行一個PE檔案的時候,Windows並不在一開始就將整個檔案讀入記憶體,而是採用與記憶體對映的機制,也就是說,Windows裝載器在裝載的時候僅僅建立好虛擬地址和PE檔案之間的對映關係,只有真正執行到某個記憶體頁中的指令或者訪問某一頁中的資料時,這個頁面才會被從磁碟提交到實體記憶體,這種機制使檔案裝入的速度和檔案大小沒有太大的關係)的方法將這些節段對映到記憶體,同時附上節表裡指定節段的讀寫屬性。

PE檔案對映入記憶體後,PE裝載器將繼續處理PE檔案中類似 import table (輸入表)的邏輯部分

這四個步驟便是PE檔案的執行順序,具體細節讀者可以參考相關文件。

(以上四個步驟摘自《黑客破解精通》) 

下面用我們要破解程式進行簡單說明:

首先用WinHex 開啟破解程式。上圖是程式的起始部分,也是PE檔案的頭部分。檔案執行需要的所有資訊就儲存在這個PE標頭檔案中。所以,學習PE檔案格式就是學習PE頭中的結構體。

 

事情根本沒有這麼簡單:

上圖描述了檔案載入到記憶體的情形,包含了許多內容,我們逐一學習。

檔案中使用偏移(offset),記憶體中使用VA(Virtual Address,虛擬地址)來表示位置。

VA指程序虛擬記憶體的絕對地址,RVA(Relative Virtual Address,相對虛擬地址)是指從某基準位置(ImageBase)開始的相對地址。VA與RVA滿足下面的換算關係:

RVA+ImageBase=VA

PE頭內部資訊大多是RVA形式存在。原因在於(主要是DLL)載入到程序虛擬記憶體的特定位置時,該位置可能已經載入了其他的PE檔案(DLL)。此時必須通過重定向(Relocation)將其載入到其他空白的位置,若PE頭資訊使用的是VA,則無法正常訪問。因此使用RVA來重定向資訊,即使發生了重定向,只要相對於基準位置的相對位置沒有變化,就能正常訪問到指定資訊,不會出現任何問題。

當PE檔案被執行時,PE裝載器會為程序分配4CG的虛擬地址空間,然後把程式所佔用的磁碟空間作為虛擬記憶體對映到這個4GB的虛擬地址空間中。一般情況下,會對映到虛擬地址空間中的0X400000的位置。

PE頭:

DOS頭

typedefstruct _IMAGE_DOS_HEADER {// DOS的.EXE頭部
  USHORT e_magic;// DOS簽名“MZ-->Mark Zbikowski(設計了DOS的工程師)”
  USHORT e_cblp;// 檔案最後頁的位元組數
  USHORT e_cp;// 檔案頁數
  USHORT e_crlc;// 重定義元素個數
  USHORT e_cparhdr;// 頭部尺寸,以段落為單位
  USHORT e_minalloc;// 所需的最小附加段
  USHORT e_maxalloc;// 所需的最大附加段
  USHORT e_ss;// 初始的SS值(相對偏移量)
  USHORT e_sp;// 初始的SP值
  USHORT e_csum;// 校驗和
  USHORT e_ip;// 初始的IP值
  USHORT e_cs;// 初始的CS值(相對偏移量)
  USHORT e_lfarlc;// 重分配表文件地址
  USHORT e_ovno;// 覆蓋號
  USHORT e_res[4];// 保留字
  USHORT e_oemid;// OEM識別符號(相對e_oeminfo)
  USHORT e_oeminfo;// OEM資訊
  USHORT e_res2[10];// 保留字
  LONG e_lfanew;// 指示NT頭的偏移(根據不同檔案擁有可變值)} IMAGE_DOS_HEADER,*PIMAGE_DOS_HEADER;

其中比較重要的有e_magic和e_lfanew,由圖可知

e_magic的值為4D5A,e_lfanew的值為000000C0(注意不是C0000000,詳見我的上一篇文章)

WORD佔2個位元組,LONG佔4個位元組,剛好是30個WORD和1個LONG,從00000000到0000003F 

DOS存根:

即使沒有DOS存根,檔案也能正常執行

NT頭(PE最重要的頭):

其定義如下:

typedefstruct _IMAGE_NT_HEADERS { 
        DWORD Signature; 
        IMAGE_FILE_HEADER FileHeader; 
        IMAGE_OPTIONAL_HEADER32 OptionalHeader;} IMAGE_NT_HEADERS32,*PIMAGE_NT_HEADERS32;Signature:類似於DOS頭中的e_magic,其高16位是0,低160x4550,用字元表示是'PE‘(00004550)。
IMAGE_FILE_HEADERIMAGE_FILE_HEADERPE檔案頭,定義如下:typedefstruct _IMAGE_FILE_HEADER { 
        WORD    Machine; 
        WORD    NumberOfSections; 
        DWORD   TimeDateStamp; 
        DWORD   PointerToSymbolTable; 
        DWORD   NumberOfSymbols; 
        WORD    SizeOfOptionalHeader; 
        WORD    Characteristics;} IMAGE_FILE_HEADER,*PIMAGE_FILE_HEADER;

 

其中有4個重要的成員(若設定不正確,將會導致檔案無法正常執行)

#1.Machine

每個CPU擁有唯一的Machine碼,相容32位Intel X86晶片的Machine碼為14C(如圖)。以下是定義在winnt.h檔案中的Machine碼:

#define IMAGE_FILE_MACHINE_UNKNOWN           0#define IMAGE_FILE_MACHINE_I386              0x014c// Intel 386. #define IMAGE_FILE_MACHINE_R3000             0x0162// MIPS little-endian, 0x160 big-endian #define IMAGE_FILE_MACHINE_R4000             0x0166// MIPS little-endian #define IMAGE_FILE_MACHINE_R10000            0x0168// MIPS little-endian #define IMAGE_FILE_MACHINE_WCEMIPSV2         0x0169// MIPS little-endian WCE v2 #define IMAGE_FILE_MACHINE_ALPHA             0x0184// Alpha_AXP #define IMAGE_FILE_MACHINE_SH3               0x01a2// SH3 little-endian #define IMAGE_FILE_MACHINE_SH3DSP            0x01a3#define IMAGE_FILE_MACHINE_SH3E              0x01a4// SH3E little-endian #define IMAGE_FILE_MACHINE_SH4               0x01a6// SH4 little-endian #define IMAGE_FILE_MACHINE_SH5               0x01a8// SH5 #define IMAGE_FILE_MACHINE_ARM               0x01c0// ARM Little-Endian #define IMAGE_FILE_MACHINE_THUMB             0x01c2#define IMAGE_FILE_MACHINE_AM33              0x01d3#define IMAGE_FILE_MACHINE_POWERPC           0x01F0// IBM PowerPC Little-Endian #define IMAGE_FILE_MACHINE_POWERPCFP         0x01f1#define IMAGE_FILE_MACHINE_IA64              0x0200// Intel 64 #define IMAGE_FILE_MACHINE_MIPS16            0x0266// MIPS #define IMAGE_FILE_MACHINE_ALPHA64           0x0284// ALPHA64 #define IMAGE_FILE_MACHINE_MIPSFPU           0x0366// MIPS #define IMAGE_FILE_MACHINE_MIPSFPU16         0x0466// MIPS #define IMAGE_FILE_MACHINE_AXP64             IMAGE_FILE_MACHINE_ALPHA64 
    #define IMAGE_FILE_MACHINE_TRICORE           0x0520// Infineon #define IMAGE_FILE_MACHINE_CEF               0x0CEF#define IMAGE_FILE_MACHINE_EBC               0x0EBC// EFI Byte Code #define IMAGE_FILE_MACHINE_AMD64             0x8664// AMD64 (K8) #define IMAGE_FILE_MACHINE_M32R              0x9041// M32R little-endian#define IMAGE_FILE_MACHINE_CEE               0xC0EE

#2.NumberOfEsctions

PE檔案把程式碼,資料,資源等依據屬性分類到各節中儲存。

NumberOfEsctions指檔案中存在的節段(又稱節區)數量,也就是節表中的項數。該值一定要大於0,且當定義的節段數與實際不符時,將發生執行錯誤。

#3.SizeOfOptionalHeader

IMAGE_NT_HEADERS結構最後一個成員IMAGE_OPTIONAL_HEADER32。

SizeOfOptionalHeader用來指出IMAGE_OPTIONAL_HEADER32結構體的長度。PE裝載器需要檢視SizeOfOptionalHeader的值,從而識別IMAGE_OPTIONAL_HEADER32結構體的大小。

PE32+格式檔案中使用的是IMAGE_OPTIONAL_HEADER64結構體,這兩個結構體尺寸是不相同的,所以需要在SizeOfOptionalHeader中指明大小。

#4.Characteristics

該段用於標識檔案的屬性,檔案是否是可執行的狀態,是否為DLL檔案等資訊。

#define IMAGE_FILE_RELOCS_STRIPPED           0x0001// Relocation info stripped from file. #define IMAGE_FILE_EXECUTABLE_IMAGE          0x0002// File is executable  (i.e. no unresolved externel references). #define IMAGE_FILE_LINE_NUMS_STRIPPED        0x0004// Line nunbers stripped from file. #define IMAGE_FILE_LOCAL_SYMS_STRIPPED       0x0008// Local symbols stripped from file. #define IMAGE_FILE_AGGRESIVE_WS_TRIM         0x0010// Agressively trim working set #define IMAGE_FILE_LARGE_ADDRESS_AWARE       0x0020// App can handle >2gb addresses #define IMAGE_FILE_BYTES_REVERSED_LO         0x0080// Bytes of machine word are reversed. #define IMAGE_FILE_32BIT_MACHINE             0x0100// 32 bit word machine. #define IMAGE_FILE_DEBUG_STRIPPED            0x0200// Debugging info stripped from file in .DBG file #define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP   0x0400// If Image is on removable media, copy and run from the swap file. #define IMAGE_FILE_NET_RUN_FROM_SWAP         0x0800// If Image is on Net, copy and run from the swap file. #define IMAGE_FILE_SYSTEM                    0x1000// System File. #define IMAGE_FILE_DLL                       0x2000// File is a DLL. #define IMAGE_FILE_UP_SYSTEM_ONLY            0x4000// File should only be run on a UP machine #define IMAGE_FILE_BYTES_REVERSED_HI         0x8000// Bytes of machine word are reversed.

為方便理解,上述程式的NT頭內容如下:

(成員功能概述)

NumberOfSections:該PE檔案中有多少個節段,也就是節表中的項數。TimeDateStampPE檔案的建立時間,一般有聯結器填寫。PointerToSymbolTableCOFF檔案符號表在檔案中的偏移。NumberOfSymbols:符號表的數量。SizeOfOptionalHeader:緊隨其後的可選頭的大小。Characteristics:可執行檔案的屬性。

IMAGE_OPTIONAL_HEADER32:

其定義如下: 

typedefstruct _IMAGE_OPTIONAL_HEADER { 
        WORD    Magic; 
        BYTE    MajorLinkerVersion; 
        BYTE    MinorLinkerVersion; 
        DWORD   SizeOfCode; 
        DWORD   SizeOfInitializedData; 
        DWORD   SizeOfUninitializedData; 
        DWORD   AddressOfEntryPoint; 
        DWORD   BaseOfCode; 
        DWORD   BaseOfData; 
        DWORD   ImageBase; 
        DWORD   SectionAlignment; 
        DWORD   FileAlignment; 
        WORD    MajorOperatingSystemVersion; 
        WORD    MinorOperatingSystemVersion; 
        WORD    MajorImageVersion; 
        WORD    MinorImageVersion; 
        WORD    MajorSubsystemVersion; 
        WORD    MinorSubsystemVersion; 
        DWORD   Win32VersionValue; 
        DWORD   SizeOfImage; 
        DWORD   SizeOfHeaders; 
        DWORD   CheckSum; 
        WORD    Subsystem; 
        WORD    DllCharacteristics; 
        DWORD   SizeOfStackReserve; 
        DWORD   SizeOfStackCommit; 
        DWORD   SizeOfHeapReserve; 
        DWORD   SizeOfHeapCommit; 
        DWORD   LoaderFlags; 
        DWORD   NumberOfRvaAndSizes; 
        IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];} IMAGE_OPTIONAL_HEADER32,*PIMAGE_OPTIONAL_HEADER32;

 

我們需要關注下列成員,這些事執行程式必需的,設定錯誤將導致程式無法正常執行。

#1.Magic

為IMAGE_OPTIONAL_HEADER32時,magic碼為10B,為IMAGE_OPTIONAL_HEADER64時,magic碼為20B

#2.AddressOfEntryPoint

AddressOfEntryPoint持有EP的RVA值。該值指出程式最先執行的程式碼起始地址,相當重要。

#3.ImageBase

一般來說,使用開發工具(VB/VC++/Delphi)建立好EXE檔案後,其ImageBase值為00400000,DLL檔案的ImageBase值為10000000(當然也可以指定其他值)。

執行PE檔案時,PE裝載器先建立程序,再將檔案載入記憶體,然後把EIP暫存器的值設定為ImageBase+AddressOfEntryPoint

#4.SectionAlignment,FileAlignment

PE檔案的Body部分被劃分成若干節段,這些節段儲存著不同類別的資料。FileAlignment指定了節段在磁碟檔案中的最小單位,而SectionAlignment則指定了節區在記憶體中的最小單位(SectionAlignment必須大於或者等於FileAlignment)

#5.SizeOfImage

當PE檔案載入到記憶體時,SizeOfImage指定了PE Image在虛擬記憶體中所佔用的空間大小,一般檔案大小與載入到記憶體中的大小是不同的(節段頭中定義了各節裝載的位置與佔有記憶體的大小,後面會講到)

#6.SizeOfHeader

SizeOfHeader用來指出整個PE頭大小。該值必須是FileAlignment的整數倍。第一節段所在位置與SizeOfHeader距檔案開始偏移的量相同。

#7.Subsystem

Subsystem值用來區分系統驅動檔案(*.sys)與普通可執行檔案(*.exe,*.dll)。

Subsystem成員可擁有值如下:

#define IMAGE_SUBSYSTEM_UNKNOWN              0// Unknown subsystem.  #define IMAGE_SUBSYSTEM_NATIVE               1// Image doesn't require a subsystem.   系統驅動#define IMAGE_SUBSYSTEM_WINDOWS_GUI          2// Image runs in the Windows GUI subsystem.  視窗應用程式#define IMAGE_SUBSYSTEM_WINDOWS_CUI          3// Image runs in the Windows character subsystem.  控制檯應用程式#define IMAGE_SUBSYSTEM_OS2_CUI              5// image runs in the OS/2 character subsystem.  #define IMAGE_SUBSYSTEM_POSIX_CUI            7// image runs in the Posix character subsystem.  #define IMAGE_SUBSYSTEM_NATIVE_WINDOWS       8// image is a native Win9x driver.  #define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI       9// Image runs in the Windows CE subsystem.  #define IMAGE_SUBSYSTEM_EFI_APPLICATION      10
            
           

相關推薦

逆向工程入門學習FreeBuf

逆向工程(二):從一個簡單的例項來了解PE檔案 文中RegisterMe及原視訊下載地址:http://pan.baidu.com/s/1bnqOgnt開啟這個RegisterMe.exe程式,會出現如下煩人的訊息框:

java入門學習3—循環,選擇,基礎算法,API概念

思想 冒泡 方法 就是 最大的 接口 兩個 循環控制 得到 1、順序結構:也就是順著程序的前後關系,依次執行。2、選擇分支:利用if..else , / switch(){case [ 這個必須是常量]:}; / if..else if….. ….else..等語句讓程序在

java入門學習2—基本數據類型

堆內存 類指針 erl 相互 lean 就是 沒有初始化 true ++ 1、變量:定義變量:【數據類型】 變量名 = 賦值(這樣定義的變量一般屬於局部變量,放置在棧內存中); 2、標識符:可以有字母(可以使任意文字),數字,下劃線,$等組成;但是不能以數字開頭,不能是保留

Django2.0官方文檔入門學習1overview

djang view site 屬性 -c .site views call data object-relational mapper:對象關系映射 data-model syntax:數據模型關系 migrate:負責申請和取消申請遷移 makemigrations

VueJS入門學習

try pre 發的 沒有 cnpm lan light install 上一個   剛剛接觸VueJs的時候,還不懂NodeJs是什麽,單頁面應用是什麽?隨著慢慢的深入慢慢的理解了這些東西。簡單介紹一些VueJs,一個頁面一個Vue實例,包含了頁面中控件所需要的方法,事件

linux入門學習:linux圖形化界面與命令行界面之間的切換,以及一些系統命令

之間 linu 鏡像 pan ctr 安裝 linux -- linux鏡像 一、linux圖形化界面與命令行界面之間的切換 註意:前提是你安裝的 linux鏡像ios 必須具備圖形化功能。 1)  圖形化界面--->命令行界面:       ctrl + alt +

NodeJS簡易部落格系統NodeJS入門學習

一、網路程式設計 1、小試牛刀 NodeJS本來的用途是編寫高效能Web伺服器。首先在這裡重複一下官方文件裡的例子,使用NodeJS內建的http模組簡單實現一個HTTP伺服器。 var http = require('http'); http.createSe

NodeJS簡易部落格系統NodeJS入門學習

一、模組 在NodeJS中,一般將程式碼合理拆分到不同的JS檔案中,每一個檔案就是一個模組,而檔案路徑就是模組名。在編寫每個模組時,都有require、exports、module三個預先定義好的變數可供使用。 1、require require函式用於在當前模組中載入和使用別的模組,傳

NS3入門學習之指令碼執行例項

 ns3中使用的編譯系統是waf,所有的c++工程都需要經過waf編譯後執行,除錯時也需要waf的。 在3.1.3中還是使用C++寫指令碼,在/ns-3.1.3/examples/tutorial/的second.cc指令碼中可以看出來,在3.2.6以上版本中已經增加了python

NS2入門學習之分裂物件模型和TclCL

 TclCL其實就是連線C++與Otcl,實現兩者的互相操作和兩者之間類的對應. NS中使用兩種語言原因: C++執行速度較快,是強制型別語言(進行嚴格的資料型別檢查),容易實現複雜的資料型別和精確/複雜的演算法。但是修改/debug和重新編譯時間較長,所以適合完成網路協

NS2入門學習之Otcl知識點

面向物件的Tcl語言,物件和類的概念同C++類似。 1.類和物件的定義 % Class  Animal #定義類名 % Animal animal_1#產生類的物件 animal info class =>Animal

NS2入門學習之Tcl知識點

1、基本命令格式換(如下總結一些易錯的知識點) “#”:註釋 ";"或者"換行"作為語句的結束 2、變數 變數不需要事先宣告; 在使用變數時要在變數名前加$,如$var; set  var 3,set命令用來給變數賦值;   unset var,u

Pandas入門學習2

文章目錄 Pandas 基本功能 1、Series 基本屬性 axes 示例 empty 示例 ndim 示例 size 示例 values 示例 head() 和 tail()

Pandas入門學習1

文章目錄 Pandas入門學習 1、Series Series的構造 建立Series ndarray建立Series dict建立Series 標量建立Series

Pandas入門學習3

文章目錄 Pandas 常用功能 1、Pandas 迭代 迭代 DataFrame iteritems()示例 iterrows()示例 itertuples()示例 2、Panda

Spring Boot入門學習0

Spring Boot是在Spring 的框架基礎上建立的一個全新框架,其設計目的是簡化Spring應用的搭建和開發過程,它不但具有Spring的所有優秀特性,而且具有如下顯著的特點: 為Spring開發提供更加簡單的使用和快速開發的技巧 具有開箱即用的預設配置功能,能

Python入門學習4

刪除包含特定值得所有列表元素 pets = ['cat','dog','goldfish','cat','rabit','cat'] print(pets) while 'cat' in pets: pets.remove('cat') print(pets)

Python入門學習3

操作列表 1.使用for迴圈來列印魔術師列表中的所有名字: magicians = ['alice','david','carolina'] for magician in magicians: print(magician) 在for迴圈中,想包含多少

C語言入門學習02——HelloWorld程式分析&printf函式的用法

  接著上一篇 C語言入門學習(01)——C程式設計環境的搭建及HelloWorld程式 繼續 //本文不是最終版本,該教程還在編寫整理中。 目錄 Part_2.1:HelloWorld程式的解釋 Part_2.2:printf函式的用法 P

C語言入門學習01——C程式設計環境的搭建及HelloWorld程式

博主是大二學生,接觸C語言也有兩年了,這兩年期間參加過不少的專案和比賽,也都拿到了還不錯的成績,暑假計劃寫一個C語言完全零基礎入門教程,對自己的C語言學習做一個總結。同時如果自己所寫的內容能幫到初學C語言的人,那真的是一件很開心的事情。 想學好C語言,一定要多多練習,因此後面的文章會有大量的