3

I writing code in C#. My code gonna run in Any CPU mode and elevated.

My goal is enumerating all processes in the machine with Process.GetProcesses(), and for each process detect its CPU architecture: x86, x64 or IA64.

I'm implementing code injection in C# and need to detect the architecture of the target process to decide what opcodes to inject.

How to do that?

Thanks.

DxCK
  • 4,402
  • 7
  • 50
  • 89
  • 2
    If you're implementing code injection, you're probably calling a LOT of Win32 APIs? Might I suggest that using C++/CLI for that is going to be a lot easier... you end up with .NET classes just like if you wrote them in C#, but you don't have to mess with translating all the structures since the C++ compiler does that for you directly from the Win32 header files. – Ben Voigt Jan 08 '11 at 19:55
  • +1 to Ben. Also don't forget that 1.0/1.1/2.0 CLR can't host 2 runtimes in the process, so you need to figure out if process runs managed code (or if it will run different version of managed code later) and inject matching code (you'd better have at least 2.0 version of the code in addition to 4.0) – Alexei Levenkov Jan 08 '11 at 21:12
  • @Alexei: Can't the same process have .NET 4 at the same time as 1.0/1.1/2.0? So if you always injected .NET 4 code, it wouldn't matter if a CLR version was already loaded. – Ben Voigt Jan 08 '11 at 21:16
  • I'm injecting native opcodes, so i dont care of the .NET framework loaded in target process (if any). – DxCK Jan 08 '11 at 21:27

6 Answers6

2

Define:

    [DllImport("kernel32.dll")]
    internal static extern void GetNativeSystemInfo(ref SystemInfo lpSystemInfo);

    [DllImport("kernel32.dll")]
    internal static extern void GetSystemInfo(ref SystemInfo lpSystemInfo);

    [StructLayout(LayoutKind.Sequential)]
    internal struct SystemInfo
    {
        public ushort wProcessorArchitecture;
        public ushort wReserved;
        public uint dwPageSize;
        public IntPtr lpMinimumApplicationAddress;
        public IntPtr lpMaximumApplicationAddress;
        public UIntPtr dwActiveProcessorMask;
        public uint dwNumberOfProcessors;
        public uint dwProcessorType;
        public uint dwAllocationGranularity;
        public ushort wProcessorLevel;
        public ushort wProcessorRevision;
    }

    internal const ushort ProcessorArchitectureIntel = 0;
    internal const ushort ProcessorArchitectureIa64 = 6;
    internal const ushort ProcessorArchitectureAmd64 = 9;
    internal const ushort ProcessorArchitectureUnknown = 0xFFFF;

GetNativeSystemInfo will return you info about the machine you're running on. GetSystemInfo will return you info about the virtualised environment you're running within (which will be the same as GetNativeSystemInfo if there isn't one).

I.e: On 32 bit Windows, you will have wProcessorArchitecture == ProcessorArchitectureIntel always.

On 64 bit Windows, you will have wProcessorArchitecture == ProcessorArchitectureIntel for GetSystemInfo, but wProcessorArchitecture == ProcessorArchitectureAmd64 for GetNativeSystemInfo, if you are running as a 32 bit process.

They will obviously both be ProcessorArchitectureAmd64 if you're a 64 bit process on 64 bit Windows.

Alastair Maw
  • 5,373
  • 1
  • 38
  • 50
1

You have to call out to Win32 to get this information:

[System.Runtime.InteropServices.DllImport("kernel32.dll")]
public static extern bool IsWow64Process(System.IntPtr hProcess, out bool lpSystemInfo);

public bool IsWow64Process(System.Diagnostics.Process process)
{
    bool retVal = false;
    IsWow64Process(process.Handle, out retVal);
    return retVal;
}

Calling IsWow64Process(process) for each process will tell you whether is it 64-bit or not. I've not come across a method to determine whether a process is x64 or IA64, just its "bitness".

adrianbanks
  • 81,306
  • 22
  • 176
  • 206
  • IA64 processors can't run x86_64 code, can they? So the local machine architecture would differentiate those. Or find the executable corresponding to the process and inspect the PE header. – Ben Voigt Jan 08 '11 at 19:43
  • That isn't right. IsWow64Process tells you if you are in a 32 bit process running under a 64-bit OS. This will return false on 32 bit Windows for 32 bit apps, and false on 64 bit Windows for 64 bit apps. See my answer below for how to do it properly. – Alastair Maw Mar 01 '11 at 15:57
1

You could p/invoke QueryFullProcessImageName or GetProcessImageFileName and then read the PE header of the .exe file.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • 1
    I like this approach more. See here on how to get the architecture from PE header http://stackoverflow.com/questions/197951/how-can-i-determine-for-which-platform-an-executable-is-compiled – Harvey Kwok Jan 08 '11 at 21:14
  • Although, [`ImageNtHeader`](http://msdn.microsoft.com/en-us/library/ms680212.aspx) is the future-proof way to find the header. – Ben Voigt Jan 08 '11 at 21:19
  • I don't really like this. You need to support any future extension of the PE format. For example you need to understand .net headers too. And if you hit a target like "Any CPU" it gets even more complicated. – CodesInChaos Aug 07 '11 at 17:52
  • @CodeInChaos: AnyCPU code still has the standard header. You might want to use the process helper functions to find which `kernel32.dll` is loaded, and check its bitness. And if the header was changed in the future, don't you think Microsoft would update `ImageNtHeader` to understand the new format? – Ben Voigt Aug 07 '11 at 17:54
  • hmm you're right. I didn't consider that the standard header would support native endianness. But since that's the case this method isn't that bad. It still feels odd to me to query the file if you want to know properties of the process. – CodesInChaos Aug 07 '11 at 18:04
1

Alastair is right in that you cannot just call IsWow64Process, but you also dont need to call another WinApi function directly. Here's a shorter solution.

    /// <summary>
    /// TRUE if the process is running under WOW64. That is if it is a 32 bit process running on 64 bit Windows.
    /// If the process is running under 32-bit Windows, the value is set to FALSE. 
    /// If the process is a 64-bit application running under 64-bit Windows, the value is also set to FALSE.
    /// </summary>
    [DllImport( "kernel32.dll" )]
    static extern bool IsWow64Process( System.IntPtr aProcessHandle, out bool lpSystemInfo );

    /// <summary>
    /// Indicates if the process is 32 or 64 bit.
    /// </summary>
    /// <param name="aProcessHandle">process to query</param>
    /// <returns>true: process is 64 bit; false: process is 32 bit</returns>
    public static bool Is64BitProcess( System.IntPtr aProcessHandle )
    {
        bool lIs64BitProcess = false;
        if ( System.Environment.Is64BitOperatingSystem ) {
            IsWow64Process( aProcessHandle, out lIs64BitProcess );
        }
        return lIs64BitProcess;
    }
Ross K.
  • 101
  • 1
  • 2
0

I think y'all are on the right track, but the return value is missing a not operator. If you're on a 64-bit machine and the process is WOW64, then it's a 32-bit process (see comments above IsWow64Process). Also, the possibility of IsWow64Process returning an error is not being handled. Here's a fixed version:

/// <summary>
/// TRUE if the process is running under WOW64. That is if it is a 32 bit process running on 64 bit Windows.
/// If the process is running under 32-bit Windows, the value is set to FALSE. 
/// If the process is a 64-bit application running under 64-bit Windows, the value is also set to FALSE.
/// </summary>
[DllImport("kernel32.dll", SetLastError=true)]
static extern bool IsWow64Process(System.IntPtr aProcessHandle, out bool isWow64Process);

/// <summary>
/// Indicates if the process is 32 or 64 bit.
/// </summary>
/// <param name="aProcessHandle">process to query</param>
/// <returns>true: process is 64 bit; false: process is 32 bit</returns>
public static bool Is64BitProcess(System.IntPtr aProcessHandle)
{
    if (!System.Environment.Is64BitOperatingSystem)
        return false;

    bool isWow64Process;
    if (!IsWow64Process(aProcessHandle, out isWow64Process))
        throw new Win32Exception(Marshal.GetLastWin32Error());

    return !isWow64Process;
}
Jimmy
  • 41
  • 4
0

You can try to P/Invoke:

BOOL WINAPI IsWow64Process(  __in   HANDLE hProcess, __out  PBOOL Wow64Process);
Felice Pollano
  • 32,832
  • 9
  • 75
  • 115