1. 程式人生 > >判斷應用程式是32位還是64位

判斷應用程式是32位還是64位

1.首先介紹PE結構

    Windows系統下的可執行檔案,是基於Microsoft設計的一種新的檔案結構,此結構被稱之為PE結構。PE的意思是Portable Executable(可移植的執行體),所有Win32執行體都是用PE檔案格式,其中包括SYS、DLL、EXE、COM、OCX等。(不管是學習逆向、破解還是安全,瞭解PE檔案格式都是非常必要的。)

    PE檔案的第一個部分是IMAGE_DOS_HEADER,大小為64B,這裡面有兩個重要的資料成員。第一個為e_magic,這個必須為MZ,即0x5A4D。當然,0x5A4D這是典型的小端格式(Little Endian);另一個重要的資料成員是最後一個成員e_lfanew,這個成員的值為IMAGE_NT_HEADERS的偏移。在IMAGE_DOS_HEADER和IMAGE_NT_HEADERS之間一個DOS Stub,這段程式用於在DOS環境中顯示一個字串,“This program cannot be run in DOS mode”,現在DOS早已滅絕,這段資料由編譯器生成,可以用0填充或者刪除(刪除的話要移動很多資料)。

IMAGE_DOS_HEADER的定義如下:

IMAGE_DOS_HEADER STRUCT
{//(注:最左邊是檔案頭的偏移量。)
+0h  WORD e_magic		//Magic DOS signature MZ(4Dh 5Ah)		      DOS可執行檔案標記
+2h  WORD e_cblp		//Bytes on last page of file  
+4h  WORD e_cp			//Pages in file
+6h  WORD e_crlc		//Relocations
+8h  WORD e_cparhdr	        //Size of header in paragraphs
+0ah WORD e_minalloc //Minimun extra paragraphs needs +0ch WORD e_maxalloc //Maximun extra paragraphs needs +0eh WORD e_ss //intial(relative)SS value DOS程式碼的初始化堆疊SS +10h WORD e_sp //intial SP value DOS程式碼的初始化堆疊指標SP +12h WORD e_csum //Checksum +14h WORD e_ip //intial IP value DOS程式碼的初始化指令入口[指標IP]
+16h WORD e_cs //intial(relative)CS value DOS程式碼的初始堆疊入口 +18h WORD e_lfarlc //File Address of relocation table +1ah WORD e_ovno //Overlay number +1ch WORD e_res[4] //Reserved words +24h WORD e_oemid //OEM identifier(for e_oeminfo) +26h WORD e_oeminfo //OEM information;e_oemid specific +29h WORD e_res2[10] // Reserved words +3ch DWORD e_lfanew //Offset to start of PE header 指向PE檔案頭 } IMAGE_DOS_HEADER ENDS

用C32Asm檢視一個EXE程式的結構: 


     PE Header 是PE相關結構NT映像頭(IMAGE_NT_HEADER)的簡稱,裡邊包含著許多PE裝載器用到的重要欄位。IMAGE_NT_HEADERS 結構的定義: 
IMAGE_NT_HEADERS STRUCT  
{  
+0h  DWORD  Signature; 
+4h  IMAGE_FILE_HEADER  FileHeader; 
+18h IMAGE_OPTIONAL_HEADER32  OptionalHeader; 
} IMAGE_NT_HEADERS ENDS 
Signature 欄位:在一個有效的 PE 檔案裡,Signature 欄位被設定為00004550h,ASCII 碼字元是“PE00”。標誌這 PE 檔案頭的開始。“PE00” 字串是 PE 檔案頭的開始,DOS 頭部的 e_lfanew 欄位正是指向這裡,如上圖所示。 

IMAGE_FILE_HEADER 結構定義: 
typedef struct _IMAGE_FILE_HEADER  

+04h 
 // 執行平臺 
+06h  WORD   NumberOfSections; // 檔案的區塊數目 
+08h  DWORD TimeDateStamp; // 檔案建立日期和時間 
+0Ch  DWORD PointerToSymbolTable;// 指向符號表(主要用於除錯) 
+10h  DWORD NumberOfSymbols; // 符號表中符號個數(同上) 
+14h  WORD   SizeOfOptionalHeader; // IMAGE_OPTIONAL_HEADER32 結構大小 
+16h  WORD   Characteristics;         // 檔案屬性 
} IMAGE_FILE_HEADER,  *PIMAGE_FILE_HEADER; 
(1)Machine:可執行檔案的目標CPU型別。 
IMAGE_FILE_MACHINE_I386 0x014c  x86 
IMAGE_FILE_MACHINE_IA64 0x0200  Intel Itanium 
IMAGE_FILE_MACHINE_AMD64 0x8664 x64 

(2)NumberOfSection: 區塊的數目。(注:區塊表是緊跟在 IMAGE_NT_HEADERS 後邊的) 
(3)TimeDataStamp: 表明檔案是何時被建立的。 
這個值是自1970年1月1日以來用格林威治時間(GMT)計算的秒數,這個值是比檔案系統(FILESYSTEM)的日期時間更加精確的指示器。 
提示:VC的話可以用_ctime 函式或者 gmtime 函式。 
(4)PointerToSymbolTable: COFF 符號表的檔案偏移位置,現在基本沒用了。 
(5)NumberOfSymbols: 如果有COFF 符號表,它代表其中的符號數目,COFF符號是一個大小固定的結構,如果想找到COFF 符號表的結束位置,則需要這個變數。 
(6)SizeOfOptionalHeader: 緊跟著IMAGE_FILE_HEADER 後邊的資料結構(IMAGE_OPTIONAL_HEADER)的大小。(對於32位PE檔案,這個值通常是00E0h;對於64位PE32+檔案,這個值是00F0h )。 
(7)Characteristics: 檔案屬性,有選擇的通過幾個值可以運算得到。( 這些標誌的有效值是定義於 winnt.h 內的 IMAGE_FILE_** 的值,具體含義見下表。普通的EXE檔案這個欄位的值一般是 0100h,DLL檔案這個欄位的值一般是 210Eh。) 

    2.然後我們通過讀取PE檔案的執行平臺欄位判斷是32位還是64位:(這裡我寫的VC++6.0是Win32控制檯應用程式)

#include <stdio.h>
#include <windows.h>
int CrnGetImageFileMachine(char* lpFileName);
int main()
{
    int n = CrnGetImageFileMachine("C:\\Users\\Administrator\\Desktop\\VS版 ADT控制卡程式 x64\\adt8948.dll");//需要檢測的可執行檔案
    if (n == 0x014C) printf("x86\n");//32位
    else if (n == 0x0200) printf("IA64\n");//純64位
    else if (n == 0x8664) printf("x64\n");//64位
    else printf("未知\n");

    return 1;
}
int CrnGetImageFileMachine(char* lpFileName)
{
    IMAGE_DOS_HEADER idh;
    FILE *f = fopen(lpFileName, "rb");
    fread(&idh, sizeof(idh), 1, f);
IMAGE_FILE_HEADER ifh;
    fseek(f, idh.e_lfanew + 4, SEEK_SET);
    fread(&ifh, sizeof(ifh), 1, f);
    fclose(f);
 
    return ifh.Machine;
}
如何判斷一個執行的程式是64位的還是32位的