목적
진행중인 x64dbg Refactoring 작업 중 C#을 이용한 코드를 이용하여 Debugee을 로드하면 Debugee의 Machine Type이 64인지 32인지 확인하여 알맞은 버전의 디버거(x64dbg 또는 x32dbg)를 실행시켜야 했다.
이에 방법을 찾아보게 되었다.
배경 및 알고가야 할 기본
윈도우에서의 실행 파일을 PE(Portable Executable)파일이라고 한다.
전체적으로 PE헤더와 PE바디 부분으로 나눠져 있다.
PE헤더를 자세히 보자면
- IMAGE_DOS_HEADER는 PE파일의 여부를 알려주는 시그니처 (MZ = 5A4D)
- IMAGE_NT_HEADERS는 파일이 실행되는 플랫폼을 나타내준다.
자세한 사항은 내가 참고한 아래 페이지를 확인하자
[ Reversing ] PE 파일 기본 구조
1. PE 파일 기본 구조 윈도우에서는 실행파일을 PE(Portable Executable)파일이라고 합니다. UNI...
blog.naver.com
구현방법
인터넷으로 찾아본 결과 실행중이 아닌 파일의 Machine Type을 C#에서 Programmatic하게 확인하는 유일한 방법은 파일의 BinaryReader을 불러 File Header를 확인하는 방법 밖에 없었다.
아래는 마이크로소프트 공식 홈페이지에서 퍼온 Machine Type 리스트이다.
IMAGE_FILE_MACHINE_UNKNOWN | 0x0 | The content of this field is assumed to be applicable to any machine type |
IMAGE_FILE_MACHINE_AM33 | 0x1d3 | Matsushita AM33 |
IMAGE_FILE_MACHINE_AMD64 | 0x8664 | x64 |
IMAGE_FILE_MACHINE_ARM | 0x1c0 | ARM little endian |
IMAGE_FILE_MACHINE_ARM64 | 0xaa64 | ARM64 little endian |
IMAGE_FILE_MACHINE_ARMNT | 0x1c4 | ARM Thumb-2 little endian |
IMAGE_FILE_MACHINE_EBC | 0xebc | EFI byte code |
IMAGE_FILE_MACHINE_I386 | 0x14c | Intel 386 or later processors and compatible processors |
IMAGE_FILE_MACHINE_IA64 | 0x200 | Intel Itanium processor family |
IMAGE_FILE_MACHINE_M32R | 0x9041 | Mitsubishi M32R little endian |
IMAGE_FILE_MACHINE_MIPS16 | 0x266 | MIPS16 |
IMAGE_FILE_MACHINE_MIPSFPU | 0x366 | MIPS with FPU |
IMAGE_FILE_MACHINE_MIPSFPU16 | 0x466 | MIPS16 with FPU |
IMAGE_FILE_MACHINE_POWERPC | 0x1f0 | Power PC little endian |
IMAGE_FILE_MACHINE_POWERPCFP | 0x1f1 | Power PC with floating point support |
IMAGE_FILE_MACHINE_R4000 | 0x166 | MIPS little endian |
IMAGE_FILE_MACHINE_RISCV32 | 0x5032 | RISC-V 32-bit address space |
IMAGE_FILE_MACHINE_RISCV64 | 0x5064 | RISC-V 64-bit address space |
IMAGE_FILE_MACHINE_RISCV128 | 0x5128 | RISC-V 128-bit address space |
IMAGE_FILE_MACHINE_SH3 | 0x1a2 | Hitachi SH3 |
IMAGE_FILE_MACHINE_SH3DSP | 0x1a3 | Hitachi SH3 DSP |
IMAGE_FILE_MACHINE_SH4 | 0x1a6 | Hitachi SH4 |
IMAGE_FILE_MACHINE_SH5 | 0x1a8 | Hitachi SH5 |
IMAGE_FILE_MACHINE_THUMB | 0x1c2 | Thumb |
IMAGE_FILE_MACHINE_WCEMIPSV2 | 0x169 | MIPS little-endian WCE v2 |
출처 : https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
테스트 코드 작성
using System.IO;
// 모든 Machine Type을 Enum으로 등록
public enum MachineType : ushort
{
IMAGE_FILE_MACHINE_UNKNOWN = 0x0,
IMAGE_FILE_MACHINE_AM33 = 0x1d3,
IMAGE_FILE_MACHINE_AMD64 = 0x8664,
IMAGE_FILE_MACHINE_ARM = 0x1c0,
IMAGE_FILE_MACHINE_EBC = 0xebc,
IMAGE_FILE_MACHINE_I386 = 0x14c,
IMAGE_FILE_MACHINE_IA64 = 0x200,
IMAGE_FILE_MACHINE_M32R = 0x9041,
IMAGE_FILE_MACHINE_MIPS16 = 0x266,
IMAGE_FILE_MACHINE_MIPSFPU = 0x366,
IMAGE_FILE_MACHINE_MIPSFPU16 = 0x466,
IMAGE_FILE_MACHINE_POWERPC = 0x1f0,
IMAGE_FILE_MACHINE_POWERPCFP = 0x1f1,
IMAGE_FILE_MACHINE_R4000 = 0x166,
IMAGE_FILE_MACHINE_SH3 = 0x1a2,
IMAGE_FILE_MACHINE_SH3DSP = 0x1a3,
IMAGE_FILE_MACHINE_SH4 = 0x1a6,
IMAGE_FILE_MACHINE_SH5 = 0x1a8,
IMAGE_FILE_MACHINE_THUMB = 0x1c2,
IMAGE_FILE_MACHINE_WCEMIPSV2 = 0x169,
}
private void button1_Click(object sender, EventArgs e)
{
//MessageBox.Show(Environment.Is64BitProcess.ToString());
var fileContent = string.Empty;
var filePath = string.Empty;
using (OpenFileDialog openFileDialog = new OpenFileDialog())
{
openFileDialog.InitialDirectory = "c:\\";
openFileDialog.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
openFileDialog.FilterIndex = 2;
openFileDialog.RestoreDirectory = true;
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
//Get the path of specified file
filePath = openFileDialog.FileName;
}
}
switch (isMachineType64(filePath))
{
case null:
MessageBox.Show("Unknown!");
break;
case true:
MessageBox.Show("64");
break;
case false:
MessageBox.Show("32");
break;
}
}
// return
// -1 if file is neither 32 nor 64
// 0 if file is 64 bit
// 1 if file is 32 bit
private static MachineType GetMachineTypeFromFile(string filePath)
{
MachineType machineType;
using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
using (var binaryReader = new BinaryReader(fileStream))
{
// if (binaryReader.BaseStream.Length == 0) = if file length is zero
// if (binaryReader.ReadUInt16() != 0x5a4d) = if it's a valid image("MZ")
if (binaryReader.BaseStream.Length == 0 || binaryReader.ReadUInt16() != 0x5a4d)
{
return 0x0; //file size is zero OR invalid image("MZ")
}
fileStream.Position = 60; // this location contains the offset for the PE header
var peOffset = binaryReader.ReadUInt32();
fileStream.Position = peOffset + 4; //contains the architecture
machineType = (MachineType) binaryReader.ReadUInt16();
}
return machineType;
}
private static bool? isMachineType64(string filePath)
{
switch (GetMachineTypeFromFile(filePath))
{
case MachineType.IMAGE_FILE_MACHINE_AMD64: // if machine type is 64
case MachineType.IMAGE_FILE_MACHINE_IA64: // if machine type is 64
return true;
case MachineType.IMAGE_FILE_MACHINE_I386: // if machine type is 32
return false;
default: // all other types
return null;
}
}
}
출처1 : https://www.neowin.net/forum/topic/732648-check-if-exe-is-x64/
출처2 : https://stackoverflow.com/questions/1001404/check-if-unmanaged-dll-is-32-bit-or-64-bit?lq=1