Detect Target CPU

StewartBW 1,805 Reputation points
2025-06-09T13:34:03.0666667+00:00

Hi experts,

I asked AI to write a code to detect different PE executable types, ie x64 x86 Itanium Arm etc...

Here's the code which seems to be fine with one exception, for processor neutral apps (like if in Visual Studio we select Target CPU: Any CPU) they are detected as x86 too, while they run as x64 in 64-bit Windows!

Possible to detect processor neutral too?

Thanks all :)

Try
    Using MyBinaryReader As New BinaryReader(New H(InputStream), Encoding.ASCII)
        If MyBinaryReader.ReadUInt16() <> &H5A4D Then Return False 'Check MZ signature "MZ" Little Endian
        InputStream.Seek(&H3C, SeekOrigin.Begin) 'Seek 2 PE Header Offset (e_lfanew is at offset 0x3C)
        InputStream.Seek(MyBinaryReader.ReadUInt32(), SeekOrigin.Begin) 'Seek 2 PE Header
        If MyBinaryReader.ReadUInt32() <> &H4550 Then Return False 'Check PE Signature "PE\0\0"
        'Read Machine Architecture (2 Bytes After PE Signature)
        Dim MyMachine As UShort = MyBinaryReader.ReadUInt16()
        Select Case MyMachine
            Case &H14C
                Architecture = "Intel386 (x86)"
            Case &H8664
                Architecture = "AMD64 (x64)"
            Case &H1C0
                Architecture = "ARM"
            Case &HAA64
                Architecture = "ARM64"
            Case &H200
                Architecture = "Intel Itanium"
            Case Else
                Architecture = MyMachine.ToString("X4")
        End Select
        Return True
    End Using
Catch Exception As Exception
    Return False
End Try
Developer technologies VB
0 comments No comments
{count} votes

Accepted answer
  1. Castorix31 90,521 Reputation points
    2025-06-10T11:57:04.8533333+00:00

    The test I did with BinaryReader with help of AI (click on a Button, change sPath variable) =>

    Imports System.IO
    
    Public Class Form1
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    
            ' Test C# or VB.NET app
            Dim sPath As String = "E:\Sources\CSharp_Test5\bin\Debug\CSharp_Test5.exe"
            'Dim sPath As String = "E:\Sources\VB_ReadPE\bin\x86\Debug\VB_ReadPE.exe"
    
            System.Diagnostics.Debug.WriteLine($"Executable : {sPath}")
            Dim nCpuType = AssemblyCpuChecker.GetCpuType(sPath)
            System.Diagnostics.Debug.WriteLine($"Target : {nCpuType}")
        End Sub
    End Class
    
    Public Class AssemblyCpuChecker
    
        ' https//sushihangover.github.io/ms-corflags-showing-incorrect-flags/
    
        ' CorFlags
        ' Developer Command Prompt for VS 2022
        ' E:\Program Files\Microsoft Visual Studio\2022\Enterprise>CorFlags "E:\Sources\CSharp_Test5\bin\Debug\CSharp_Test5.exe"
    
        'Version: v4.0.30319
        'CLR Header :  2.5
        'PE: PE32
        'CorFlags: 0x20003
        'ILONLY: 1
        '32BITREQ  : 0
        '32BITPREF : 1
        'Signed: 0
    
        Public Const COMIMAGE_FLAGS_ILONLY As Integer = &H1
        Public Const COMIMAGE_FLAGS_32BITREQUIRED As Integer = &H2
        Public Const COMIMAGE_FLAGS_IL_LIBRARY As Integer = &H4
        Public Const COMIMAGE_FLAGS_STRONGNAMESIGNED As Integer = &H8
        Public Const COMIMAGE_FLAGS_NATIVE_ENTRYPOINT As Integer = &H10
        Public Const COMIMAGE_FLAGS_TRACKDEBUGDATA As Integer = &H10000
        Public Const COMIMAGE_FLAGS_32BITPREFERRED As Integer = &H20000
    
        Public Enum CpuType
            Unknown
            x86
            x64
            AnyCPU
            AnyCPU_Prefer32Bit
        End Enum
    
        ' Some parts generated with Copilot + ChatGPT, then fixed...
        Public Shared Function GetCpuType(filePath As String) As CpuType
            Using fs As New FileStream(filePath, FileMode.Open, FileAccess.Read)
                Using br As New BinaryReader(fs)
                    fs.Seek(&H3C, SeekOrigin.Begin)
                    Dim nPEHeaderOffset As Integer = br.ReadInt32()
    
                    fs.Seek(nPEHeaderOffset + 4, SeekOrigin.Begin) ' Skip "PE\0\0"
                    Dim nMachine As UShort = br.ReadUInt16()
                    Dim nNumberOfSections As UShort = br.ReadUInt16()
                    fs.Seek(16, SeekOrigin.Current) ' skip rest of COFF header
    
                    Dim nOptionalHeaderStart As Long = fs.Position
                    Dim nOptionalHeaderMagic As UShort = br.ReadUInt16()
                    Dim bPE32 As Boolean = (nOptionalHeaderMagic = &H10B)
    
                    Dim nDataDirectoryOffset As Integer = If(bPE32, &H60 + 8 * 14, &H70 + 8 * 14)
                    Dim nCLRDirOffset As Long = nOptionalHeaderStart + nDataDirectoryOffset
    
                    fs.Seek(nCLRDirOffset, SeekOrigin.Begin)
                    Dim nCLRHeaderRVA As UInteger = br.ReadUInt32()
                    Dim nCLRHeaderSize As UInteger = br.ReadUInt32()
    
                    If nCLRHeaderRVA = 0 Then
                        Return CpuType.Unknown ' Not a .NET assembly
                    End If
    
                    ' Section table comes after optional header
                    Dim nOptionalHeaderSize As Integer = If(bPE32, 224, 240)
                    Dim nSectionTableStart As Long = nOptionalHeaderStart + nOptionalHeaderSize
    
                    Dim nCLRHeaderFileOffset As UInteger = 0
                    For i As Integer = 0 To nNumberOfSections - 1
                        fs.Seek(nSectionTableStart + i * 40 + 8, SeekOrigin.Begin)
                        Dim nVirtualSize As UInteger = br.ReadUInt32()
                        Dim nVirtualAddress As UInteger = br.ReadUInt32()
                        Dim nSizeOfRawData As UInteger = br.ReadUInt32()
                        Dim nPointerToRawData As UInteger = br.ReadUInt32()
                        Dim nSectionSize As UInteger = Math.Max(nVirtualSize, nSizeOfRawData)
    
                        If nCLRHeaderRVA >= nVirtualAddress AndAlso nCLRHeaderRVA < nVirtualAddress + nSectionSize Then
                            nCLRHeaderFileOffset = nPointerToRawData + (nCLRHeaderRVA - nVirtualAddress)
                            Exit For
                        End If
                    Next
    
                    If nCLRHeaderFileOffset = 0 Then
                        Return CpuType.Unknown
                    End If
    
                    fs.Seek(nCLRHeaderFileOffset + 16, SeekOrigin.Begin)
                    Dim nCorFlags As UInteger = br.ReadUInt32()
                    ' 131075 = 0x20003
    
                    System.Diagnostics.Debug.WriteLine($"CorFlags : 0x{nCorFlags:X} ({nCorFlags})")
                    System.Diagnostics.Debug.WriteLine($"ILONLY : {((nCorFlags And COMIMAGE_FLAGS_ILONLY) <> 0)}")
                    System.Diagnostics.Debug.WriteLine($"32BITREQUIRED : {((nCorFlags And COMIMAGE_FLAGS_32BITREQUIRED) <> 0)}")
                    System.Diagnostics.Debug.WriteLine($"32BITPREFERRED : {((nCorFlags And COMIMAGE_FLAGS_32BITPREFERRED) <> 0)}")
                    System.Diagnostics.Debug.WriteLine($"Machine : 0x{nMachine:X}")
    
                    If (nCorFlags And COMIMAGE_FLAGS_32BITPREFERRED) <> 0 Then
                        Return CpuType.AnyCPU_Prefer32Bit
                    End If
                    If (nCorFlags And COMIMAGE_FLAGS_32BITREQUIRED) <> 0 Then
                        Return CpuType.x86
                    End If
                    If (nMachine = &H8664) Then
                        Return CpuType.x64
                    End If
                    If (nCorFlags And COMIMAGE_FLAGS_ILONLY) <> 0 Then
                        Return CpuType.AnyCPU
                    End If
                    Return CpuType.Unknown
                End Using
            End Using
        End Function
    End Class
    
    
    1 person found this answer helpful.

1 additional answer

Sort by: Most helpful
  1. RLWA32 49,536 Reputation points
    2025-06-09T13:50:22.0366667+00:00

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.