Magic
เขตของIMAGE_OPTIONAL_HEADER
(แม้ว่าจะมีอะไรที่ไม่จำเป็นเกี่ยวกับส่วนหัวใน Windows ภาพปฏิบัติการ (ไฟล์ DLL / EXE)) จะบอกคุณสถาปัตยกรรมของ PE ที่
นี่คือตัวอย่างของการดึงสถาปัตยกรรมจากไฟล์
public static ushort GetImageArchitecture(string filepath) {
using (var stream = new System.IO.FileStream(filepath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
using (var reader = new System.IO.BinaryReader(stream)) {
//check the MZ signature to ensure it's a valid Portable Executable image
if (reader.ReadUInt16() != 23117)
throw new BadImageFormatException("Not a valid Portable Executable image", filepath);
// seek to, and read, e_lfanew then advance the stream to there (start of NT header)
stream.Seek(0x3A, System.IO.SeekOrigin.Current);
stream.Seek(reader.ReadUInt32(), System.IO.SeekOrigin.Begin);
// Ensure the NT header is valid by checking the "PE\0\0" signature
if (reader.ReadUInt32() != 17744)
throw new BadImageFormatException("Not a valid Portable Executable image", filepath);
// seek past the file header, then read the magic number from the optional header
stream.Seek(20, System.IO.SeekOrigin.Current);
return reader.ReadUInt16();
}
}
ค่าคงที่สถาปัตยกรรมสองอย่างในขณะนี้คือ:
0x10b - PE32
0x20b - PE32+
ไชโย
อัปเดต
เป็นเวลานานแล้วที่ฉันโพสต์คำตอบนี้ แต่ฉันก็ยังเห็นว่ามันได้รับการโหวตเพิ่มขึ้นไม่กี่ครั้งแล้วครั้งเล่าดังนั้นฉันจึงคิดว่ามันคุ้มค่าที่จะอัปเดต ฉันเขียนวิธีรับสถาปัตยกรรมของPortable Executable
รูปภาพซึ่งจะตรวจสอบด้วยว่าคอมไพล์เป็นAnyCPU
ไฟล์. น่าเสียดายที่คำตอบอยู่ใน C ++ แต่ไม่ควรยากเกินไปที่จะพอร์ตไปยัง C # หากคุณมีเวลาไม่กี่นาทีในการค้นหาโครงสร้างในWinNT.h
. หากผู้คนสนใจฉันจะเขียนพอร์ตใน C # แต่ถ้าไม่มีคนต้องการจริงๆฉันจะไม่ใช้เวลากับมันมากนัก
#include <Windows.h>
#define MKPTR(p1,p2) ((DWORD_PTR)(p1) + (DWORD_PTR)(p2))
typedef enum _pe_architecture {
PE_ARCHITECTURE_UNKNOWN = 0x0000,
PE_ARCHITECTURE_ANYCPU = 0x0001,
PE_ARCHITECTURE_X86 = 0x010B,
PE_ARCHITECTURE_x64 = 0x020B
} PE_ARCHITECTURE;
LPVOID GetOffsetFromRva(IMAGE_DOS_HEADER *pDos, IMAGE_NT_HEADERS *pNt, DWORD rva) {
IMAGE_SECTION_HEADER *pSecHd = IMAGE_FIRST_SECTION(pNt);
for(unsigned long i = 0; i < pNt->FileHeader.NumberOfSections; ++i, ++pSecHd) {
// Lookup which section contains this RVA so we can translate the VA to a file offset
if (rva >= pSecHd->VirtualAddress && rva < (pSecHd->VirtualAddress + pSecHd->Misc.VirtualSize)) {
DWORD delta = pSecHd->VirtualAddress - pSecHd->PointerToRawData;
return (LPVOID)MKPTR(pDos, rva - delta);
}
}
return NULL;
}
PE_ARCHITECTURE GetImageArchitecture(void *pImageBase) {
// Parse and validate the DOS header
IMAGE_DOS_HEADER *pDosHd = (IMAGE_DOS_HEADER*)pImageBase;
if (IsBadReadPtr(pDosHd, sizeof(pDosHd->e_magic)) || pDosHd->e_magic != IMAGE_DOS_SIGNATURE)
return PE_ARCHITECTURE_UNKNOWN;
// Parse and validate the NT header
IMAGE_NT_HEADERS *pNtHd = (IMAGE_NT_HEADERS*)MKPTR(pDosHd, pDosHd->e_lfanew);
if (IsBadReadPtr(pNtHd, sizeof(pNtHd->Signature)) || pNtHd->Signature != IMAGE_NT_SIGNATURE)
return PE_ARCHITECTURE_UNKNOWN;
// First, naive, check based on the 'Magic' number in the Optional Header.
PE_ARCHITECTURE architecture = (PE_ARCHITECTURE)pNtHd->OptionalHeader.Magic;
// If the architecture is x86, there is still a possibility that the image is 'AnyCPU'
if (architecture == PE_ARCHITECTURE_X86) {
IMAGE_DATA_DIRECTORY comDirectory = pNtHd->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR];
if (comDirectory.Size) {
IMAGE_COR20_HEADER *pClrHd = (IMAGE_COR20_HEADER*)GetOffsetFromRva(pDosHd, pNtHd, comDirectory.VirtualAddress);
// Check to see if the CLR header contains the 32BITONLY flag, if not then the image is actually AnyCpu
if ((pClrHd->Flags & COMIMAGE_FLAGS_32BITREQUIRED) == 0)
architecture = PE_ARCHITECTURE_ANYCPU;
}
}
return architecture;
}
ฟังก์ชั่นนี้ยอมรับตัวชี้ไปยังภาพ PE ในหน่วยความจำ (เพื่อให้คุณสามารถเลือกพิษของคุณว่าจะรับมันอย่างไรการทำแผนที่หน่วยความจำหรืออ่านสิ่งทั้งหมดลงในหน่วยความจำ ... อะไรก็ได้)