逆向工程入門學習(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,低16是0x4550,用字元表示是'PE‘(00004550)。
IMAGE_FILE_HEADER:IMAGE_FILE_HEADER是PE檔案頭,定義如下: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檔案中有多少個節段,也就是節表中的項數。TimeDateStamp:PE檔案的建立時間,一般有聯結器填寫。PointerToSymbolTable:COFF檔案符號表在檔案中的偏移。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官方文檔入門學習(1)overview
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語言,一定要多多練習,因此後面的文章會有大量的