determine if a program is 32-bit/64-bit without running it Topic is solved

Get help with using AutoHotkey and its commands and hotkeys
User avatar
jeeswg
Posts: 6469
Joined: 19 Dec 2016, 01:58
Location: UK

determine if a program is 32-bit/64-bit without running it

10 Jan 2017, 12:50

Is there a way to determine if a program is 32-bit/64-bit without running it?
In a way similar to the FileGetVersion command?

I wrote a function that can achieve this, but only when the program *is* running.

Also is there a better name for the function below, 'get bits', 'get architecture', 'get image type', 'get bitness'?
I would be grateful for any ideas and related terms.

Also, I don't really need it, but it would be good to mention for both methods, if it could be determined whether a program was 16-bit or any other n-bit.

Code: Select all

JEE_ProcessGetBits(vPID)
{
	if !A_Is64bitOS
		return "x86"

	hProc := DllCall("kernel32\OpenProcess", UInt,0x400, Int,0, UInt,vPID, Ptr)
	DllCall("kernel32\IsWow64Process", Ptr,hProc, IntP,vIsWow64Process)
	DllCall("kernel32\CloseHandle", Ptr,hProc)

	if vIsWow64Process
		return "x86"

	return "x64"
}
Last edited by jeeswg on 17 Feb 2019, 17:39, edited 1 time in total.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
qwerty12
Posts: 468
Joined: 04 Mar 2016, 04:33
GitHub: qwerty12

Re: determine if a program is 32-bit/64-bit without running it  Topic is solved

10 Jan 2017, 13:24

Maybe reading from the file's PE headers to get the value of the Machine field may work. The following is pretty much from Lexikos' code here (which is properly commented):

Code: Select all

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

IMAGE_DOS_SIGNATURE := 0x5A4D
IMAGE_NT_SIGNATURE := 0x4550

Machines := {0x014c: "IMAGE_FILE_MACHINE_I386", 0x0200: "IMAGE_FILE_MACHINE_IA64", 0x8664: "IMAGE_FILE_MACHINE_AMD64"}

if ((file := FileOpen("MinHook.x64.dll", "r"))) {
	if (file.ReadUShort() == IMAGE_DOS_SIGNATURE) {
		file.Seek(60)
		e_lfanew := file.ReadInt()
		file.Seek(e_lfanew)
		if (file.ReadUInt() == IMAGE_NT_SIGNATURE) {
			file.Seek(e_lfanew + 4)
			MsgBox % Machines[file.ReadUShort()]
		}
	}
	file.Close()
}
If you want to fill in the rest of the other valid values for the Machine field:

Code: Select all

#define IMAGE_FILE_MACHINE_UNKNOWN           0
#define IMAGE_FILE_MACHINE_TARGET_HOST       0x0001  // Useful for indicating we want to interact with the host and not a WoW guest.
#define IMAGE_FILE_MACHINE_I386              0x014c  // Intel 386.
#define IMAGE_FILE_MACHINE_R3000             0x0162  // MIPS little-endian, 0x160 big-endian
#define IMAGE_FILE_MACHINE_R4000             0x0166  // MIPS little-endian
#define IMAGE_FILE_MACHINE_R10000            0x0168  // MIPS little-endian
#define IMAGE_FILE_MACHINE_WCEMIPSV2         0x0169  // MIPS little-endian WCE v2
#define IMAGE_FILE_MACHINE_ALPHA             0x0184  // Alpha_AXP
#define IMAGE_FILE_MACHINE_SH3               0x01a2  // SH3 little-endian
#define IMAGE_FILE_MACHINE_SH3DSP            0x01a3
#define IMAGE_FILE_MACHINE_SH3E              0x01a4  // SH3E little-endian
#define IMAGE_FILE_MACHINE_SH4               0x01a6  // SH4 little-endian
#define IMAGE_FILE_MACHINE_SH5               0x01a8  // SH5
#define IMAGE_FILE_MACHINE_ARM               0x01c0  // ARM Little-Endian
#define IMAGE_FILE_MACHINE_THUMB             0x01c2  // ARM Thumb/Thumb-2 Little-Endian
#define IMAGE_FILE_MACHINE_ARMNT             0x01c4  // ARM Thumb-2 Little-Endian
#define IMAGE_FILE_MACHINE_AM33              0x01d3
#define IMAGE_FILE_MACHINE_POWERPC           0x01F0  // IBM PowerPC Little-Endian
#define IMAGE_FILE_MACHINE_POWERPCFP         0x01f1
#define IMAGE_FILE_MACHINE_IA64              0x0200  // Intel 64
#define IMAGE_FILE_MACHINE_MIPS16            0x0266  // MIPS
#define IMAGE_FILE_MACHINE_ALPHA64           0x0284  // ALPHA64
#define IMAGE_FILE_MACHINE_MIPSFPU           0x0366  // MIPS
#define IMAGE_FILE_MACHINE_MIPSFPU16         0x0466  // MIPS
#define IMAGE_FILE_MACHINE_AXP64             IMAGE_FILE_MACHINE_ALPHA64
#define IMAGE_FILE_MACHINE_TRICORE           0x0520  // Infineon
#define IMAGE_FILE_MACHINE_CEF               0x0CEF
#define IMAGE_FILE_MACHINE_EBC               0x0EBC  // EFI Byte Code
#define IMAGE_FILE_MACHINE_AMD64             0x8664  // AMD64 (K8)
#define IMAGE_FILE_MACHINE_M32R              0x9041  // M32R little-endian
#define IMAGE_FILE_MACHINE_ARM64             0xAA64  // ARM64 Little-Endian
#define IMAGE_FILE_MACHINE_CEE               0xC0EE
EDIT: There's a far better way: https://msdn.microsoft.com/en-us/librar ... s.85).aspx
Last edited by qwerty12 on 15 Feb 2017, 09:45, edited 1 time in total.
User avatar
jeeswg
Posts: 6469
Joined: 19 Dec 2016, 01:58
Location: UK

Re: determine if a program is 32-bit/64-bit without running it

10 Jan 2017, 14:33

This is great, thanks!
I've made a preliminary function to retrieve a file's bitness.

Code: Select all

JEE_FileGetBits(vPath)
{
	IMAGE_DOS_SIGNATURE := 0x5A4D
	IMAGE_NT_SIGNATURE := 0x4550

	Machines := {0x014c: "IMAGE_FILE_MACHINE_I386", 0x0200: "IMAGE_FILE_MACHINE_IA64", 0x8664: "IMAGE_FILE_MACHINE_AMD64"}

	if ((file := FileOpen(vPath, "r")))
	{
		if (file.ReadUShort() == IMAGE_DOS_SIGNATURE)
		{
			file.Seek(60)
			e_lfanew := file.ReadInt()
			file.Seek(e_lfanew)
			if (file.ReadUInt() == IMAGE_NT_SIGNATURE)
			{
				file.Seek(e_lfanew + 4)
				vOutput := Machines[file.ReadUShort()]
			}
		}
		file.Close()
	}

	return vOutput
}
Last edited by jeeswg on 17 Feb 2019, 17:41, edited 1 time in total.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
jeeswg
Posts: 6469
Joined: 19 Dec 2016, 01:58
Location: UK

Re: determine if a program is 32-bit/64-bit without running it

01 Dec 2018, 22:49

- @qwerty12: Thanks, I didn't see your post edit (15 Feb 2017) re. GetBinaryType until just now. There's a nice example using it by jNizM, here, written not long after your post edit.
is exe file x64 or x86? Howto? - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 66#p134766
- I prefer the method we have already, because it can handle exe files and dll files, GetBinaryType can only handle exe files. Possibly both methods support other file types also.

- Here are some links re. the e_lfanew approach. I wanted to understand it in full.
[IMAGE_DOS_HEADER appears in winnt.h]
struct IMAGE_DOS_HEADER
https://www.nirsoft.net/kernel_struct/v ... EADER.html
_IMAGE_NT_HEADERS | Microsoft Docs
https://docs.microsoft.com/en-us/window ... nt_headers
_IMAGE_FILE_HEADER | Microsoft Docs
https://docs.microsoft.com/en-us/window ... ile_header
Peering Inside the PE: A Tour of the Win32 Portable Executable File Format
https://msdn.microsoft.com/en-us/library/ms809762.aspx
windows - What does "e_lfanew" mean in the DOS header for the PE format? - Stack Overflow
https://stackoverflow.com/questions/477 ... -pe-format
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA

Return to “Ask For Help”

Who is online

Users browsing this forum: vsub and 204 guests