12

Is there some simple method for determining if a DOS (or OS/2, or Windows etc.) binary (.exe or .dll) is 16-bit or 32-bit? The Linux file command just says "executable".

I want to distinguish between programs that run on any "x86" processor, and those that "require a 386", in a way that is simpler than setting up two environments and attempting to run the program.

And what I want is a tool, like the file command, not primarily more detailed technical explanations.

Tomas By
  • 2,082
  • 2
  • 15
  • 35

6 Answers6

48

Plain DOS executables, in either COM or MZ format, don’t provide this information in their headers (when there is one — COM format doesn’t have a header). The only reliable way to determine whether a program requires a given CPU is to try running it on some less capable system (or emulation, e.g. with PCem which has accurate emulations of different x86 processors), and rely on either the program checking that the CPU is good enough for it, or on it crashing with an invalid opcode (on a 186 or later). Alternatively, you could try disassembling the program and looking for 386+ opcodes; but that’s only as reliable as the disassembly process, and will give inconsistent results on programs which adapt to the CPU (running 8086 code only on 8086s, 386 code on 386s, etc.).

For protected-mode executables specifically, you could look for one of the common 32-bit DOS extenders or stubs, e.g. DOS/4G, 32RTM... A program using one of these will require a 386. (There are also 286 extenders.) See Are .COM executable binaries real mode or protected mode? for more discussion of how DOS programs start (but real- v. protected-mode is only one aspect of instruction set usage; programs can use 286, 386, 486, Pentium etc. instructions even in real mode).

Many post-MZ executable formats encode this information; for example, 16-bit Windows and OS/2 executables are “new executables”, with a flag indicating which CPU is required. 32-bit OS/2 executables are “linear executables”, identified by an LX header following the MZ stub, and specify their target CPU and operating system. Likewise, 32-bit Windows programs are “portable executables”, and the PE header identifies the target CPU. file knows about these and will identify them correctly. However, it’s worth checking the details of the MZ stub too, since LX or PE executables can contain a 16-bit variant in their MZ stub, and would therefore be capable of running on a 16-bit CPU.

Stephen Kitt
  • 121,835
  • 17
  • 505
  • 462
  • 3
    Yes, I understand you’re after a simple tool, but AFAIK there isn’t one. There are emulators of only 16-bit PCs; for example PCem has to be configured with a given CPU, and if set to a 286 it won’t emulate any 386 instructions. – Stephen Kitt Feb 14 '21 at 16:39
  • 7
    WRT running under emulation - to be really sure there are no 32-bit instructions, one would need to execute every possible code path under that emulation. I think it's clear that file doesn't want to solve the Halting Problem. – Toby Speight Feb 15 '21 at 14:57
  • 2
    @Toby not necessarily – you don’t want to run the code paths on the 32-bit side after a CPU check, if there’s a 16-bit side ;-). But yes, I agree it’s impossible to get a definitive statement, and one ends up relying on the realities of computers at the time: a program which crashed with an invalid opcode when run on a 286, because it didn’t bother checking it was running on a 386, wouldn’t be too popular. – Stephen Kitt Feb 15 '21 at 15:00
  • 3
    I'd argue that the 32-bit side of a test isn't a possible code path in the emulated environment! But, especially in early personal computers, programmers tended to play fast and loose with self-modifying code (such as self-uncompressing binaries) and worse. I think we're in violent agreement - it's really not possible by mere inspection. – Toby Speight Feb 15 '21 at 15:08
  • 2
    @Toby oh yes I agree we’re in violent agreement, I was being facetious. I have a program somewhere which does code-path analysis to try to determine the type of CPU required, but even then the only thing it claims is to attempt to determine the maximum CPU which may be required, not the minimum. – Stephen Kitt Feb 15 '21 at 15:15
17

There is no easy way.

The original DOS "MZ" type executable header do not contain such information about what kind of code it contains or what CPU type it needs. It just contains a binary image that is loaded to memory and information about how to start it in real mode, so there are no separate 16-bit or 32-bit binaries.

The binary image may contain any real mode opcodes that are available for a given type of CPU, but if it does contain 32-bit protected mode code, there will be a real mode loader stub to switch to protected mode and jump to run the 32-bit image contained in the executable file.

So DOS cannot know what the executable contains, DOS simply loads the executable binary into memory, does the relocations, and jumps to run the code at the entry point given in the headers. It is up to the executable what opcodes it contains, and for example if it needs a certain type of CPU to run certain opcodes, it can perform the CPU type detection if it is suitable for running the rest of the program. The executable might for example contain a stub to put the 386 CPU into 32-bit protected mode and then execute most of the program in that mode instead of 16-bit real mode.

So in order to detect what type of CPU is needed, the program has to be for example run in a virtual machine that sees what opcodes are executed. A disassembler can also be used to see what opcodes there is in the binary. While there might be standard compiler startup codes that could be detected by a tool analyzing the generated binary, there are also infinitely many other ways to make a program that does not use standard compilers or libraries, or that can make the disassembler to not be able to follow each and every code path, for example by dynamically generating a pointer where to go execute code.

So, it is not impossible. It is just not easy.

Justme
  • 31,506
  • 1
  • 73
  • 145
  • 6
    Why not? If I just add because of what I said, there is no easy way to determine if the executable contains 32-bit code or not, without disassembling it or running it under an emulator to figure it out? – Justme Feb 14 '21 at 15:05
  • Well, I think there should be, as various parameters will be two versus four bytes etc. – Tomas By Feb 14 '21 at 15:06
  • It is not that simple, like I said, the whole binary would need to be analyzed by running or disassembling if it contains instructions that are only available on a 386 or before it. And then you added the clarification and changed the question to include OS/2 so I will delete my answer, it is not relevant any more. – Justme Feb 14 '21 at 15:16
  • No I don't think that would be necessary. The OS seems to be able to tell pretty quickly, as I have never heard of a program that run for a little while and then fail because of the register size. You get an instant error message. – Tomas By Feb 14 '21 at 15:20
  • 8
    You are asking about DOS executables. DOS cannot know what the executable contains, DOS simply loads the executable binary into memory and jumps to run the code at the given entry point. It is up to the executable what opcodes it contains, and for example detect the CPU type if it is suitable for running the rest of the program. The executable might for example contain a stub to put the 386 CPU into 32-bit protected mode and then execute most of the program in that mode instead of 16-bit real mode. – Justme Feb 14 '21 at 15:25
  • Then you could look for those stubs? It doesn't seem so impossible. – Tomas By Feb 14 '21 at 15:28
  • @TomasBy: That’s exactly what I’ve had happen on modern systems. A program I wanted to use crashed with SIGSEGV because it was compiled with SSE2 instructions, which my CPU did not support. – user3840170 Feb 14 '21 at 15:28
  • Okay, but I have never heard of it happening with DOS or OS/2. – Tomas By Feb 14 '21 at 15:29
  • Because back then programs usually detected the CPU at startup, as part of the program code itself. But it was never mandatory to include it. – user3840170 Feb 14 '21 at 15:30
  • 2
    @Justme - re there is no easy way... IMO if you added that to your answer, it would be complete. One can infer that as it stands, but explicit is better. – dave Feb 14 '21 at 15:45
  • 2
    "Then you could look for those stubs?" You can try, but there is no limit to the number of different possible stubs. For example, you can consider my test programs in https://hg.ulukai.org/ecm/dpmitest which all have their own custom Real/Virtual 86 Mode "stubs" to switch to 32-bit Protected Mode. – ecm Feb 14 '21 at 16:21
  • Typically, such a program would attempt to switch to protected mode and if that is not possible continue in real mode. So strictly speaking, the executable does not require protected mode - even though the behaviour of the successfully running real mode branch would usually simply amount to a text being printed: "This program requires 32bit protected mode" . Nevertheless, this counts as a successful run of the executable ... – Hagen von Eitzen Feb 14 '21 at 16:46
  • @Tomas By: No, those are 26 revisions of 4 tests as seen here. But the point isn't that I made 4 different tests, it's that there is no standard or limit to the ways a program can implement the mode switch. So you can add my 4 tests and the stubs generated by, say, Open Watcom and DJGPP, and you'd be covering a bunch of programs, but not all possible variations. As others have written you need to run / analyse the program in an emulator or such to detect the program's own behaviour (which may in turn include detection of the CPU). – ecm Feb 14 '21 at 17:57
  • I still don't think it is necessary to analyse/emulate the whole thing. I'm sure there are various instruction/parameter combinations that are clear indications of one or the other etc. This is what the file command ought to do. – Tomas By Feb 14 '21 at 18:00
  • 6
    No, simply stop at the first 386-specific instruction. The ones that are not 386-specific instructions, the same opcode work differently in different CPU modes. The same data move opcode will move 16 bits in real mode, and 32 bits in protected mode. The file command does not include a heuristic x86 disassembler to determine it. That is almost same as if the file command could determine if a JPG file contains a picture of a cat or a dog. – Justme Feb 14 '21 at 18:04
  • @Justme I'm fairly sure that is not at all the same thing. Won't that data move opcode take two bytes in one case and four in the other? Okay maybe that is not helpful, as you can't tell the difference. But looking for tests should be practical. – Tomas By Feb 14 '21 at 18:13
  • It depends on what kind of move it is. But the DOS executable would start with 16-bit code as the CPU is in 16-bit mode, so unless there are 386 opcodes present, to either a) go into 32-bit mode permanently, or b) prefix the opcode to toggle the data and/or addressing length for currently executing opcode, all instructions are 16-bit. Sure, it would look nonsense to a human to decode 16-bit code in 32-bit mode, or decode 32-bit code in 16-bit mode, but you need to look at it which one makes more sense. A random detection program looking at a single opcode would not know which mode to use. – Justme Feb 14 '21 at 21:36
  • 6
    @Justme To add more complications: many programs were compressed and unpacked after loading (either to save disk space and/or to make tampering more difficult). A simple "file scan" wouldn't even see the op-codes of the main program, only of the unpacker. – TripeHound Feb 14 '21 at 23:42
  • Haha, good point. – Tomas By Feb 15 '21 at 05:33
  • @TripeHound Exactly. Which is why analysis without actually executing the code is even more complex subject, as there are dozens of standard and custom executable packers. And a proper executable wanting to run 386 opcodes would try to detect the CPU and if it can determine it is not a 386 then no 386 opcodes are run, and program exits with a message that it can't run, so the execution path containing 386 opcodes is never taken. – Justme Feb 15 '21 at 08:26
  • 1
    And to find the 386 instructions, you need the whole instruction decoder anyway - it's not enough to just search for some string. And even that isn't enough, even without compression, since you don't know what is code and what is data. And then you get into proper self-modifying code (and just to rub salt in the wound, that code might even be there to e.g. offer limited support for the 286 even though the application is primarily designed for 386+). And figuring out the type of a file by attempting to execute it (even in an emulator) is just begging for trouble. – Luaan Feb 15 '21 at 08:34
  • 1
    @Luaan: The debugger fork that I maintain does in fact run on both pre-386 and 386+ machines. It patches its own code section to either make use of 386 features or not. (Besides, the entire application can be compressed too.) – ecm Feb 15 '21 at 08:53
  • 2
    @TomasBy: Won't that data move opcode take two bytes in one case and four in the other? - yes, that's why even finding instruction boundaries requires knowing what mode to decode in. x86 machine code is a byte-stream that's not self-synchronizing. You need to know the right starting point to decode (so jumps are potentially problematic, especially indirect jumps), and you need to know what mode some bytes will be decoded in to disassemble it correctly. (i.e. your idea has run into a catch-22). e.g. B8+reg id/iw is the same opcode for mov imm16 or 32 https://www.felixcloutier.com/x86/mov – Peter Cordes Feb 15 '21 at 10:19
  • 2
    @Justme: It's possible (but not easy) in practice, but for any detection algorithm based on running the program, there exists a binary that can fool it (just like the halting problem). e.g. by running indefinitely long with only 286-compatible instructions, or only running 386 instructions with certain options or problem-sizes. (That's actually plausible: working with large numbers using mul r32 in 16-bit mode in a program that runs in real-mode. Or carelessly uses movzx ax, cl (386 new opcode that works in 16-bit mode) in one random function in a program intended but not tested for 186.) – Peter Cordes Feb 15 '21 at 10:29
  • @PeterCordes yes, that's what I meant by you can't tell the difference. there could still be patterns, though. e.g. ABC more common than DEF indicates 16-bit or vice versa. – Tomas By Feb 15 '21 at 10:36
  • 2
    @TomasBy: It's pretty hard to tell if "nonsense" disassembly is due to disassembling in the wrong mode, or because you merely got mixed up and are disassembling from a wrong starting offset. There might be some kind of heuristic you could build, especially given the differences in ModRM addressing modes for 16-bit address size vs. ModRM [+ SIB] for 32-bit address-size. But for non-memory, it's normal for the same sequence of instruction bytes to do the same thing (with different operand-size) in both (or all 3) modes, like many of my code-golf.SE answers (which do typically avoid immed...). – Peter Cordes Feb 15 '21 at 11:12
  • 1
    @PeterCordes exactly, that is the whole point of my answer. Most people seem to agree with this that there is no easy and simple way. It is also not impossible either, it could be done, but it is hard and complex, and result may not be good. If it were simple and easy, at least somene would have said so and presented it. – Justme Feb 15 '21 at 11:47
  • 2
    @Justme: My comment got long enough to obscure what I meant to say. Your answer says: So, it is not impossible. But in the general case, it is impossible to fully solve, just like the halting problem. So I guess this nitpick is to ask for a weasel word in that last sentence, like "So, it is not impossible for typical programs." – Peter Cordes Feb 15 '21 at 11:52
9

Is there some simple method for determining if a DOS binary (.exe or .dll) is 16-bit or 32-bit?

For one, DOS doesn't know about 32 bit, it's a strict 16 bit system. Second, .DLL are not DOS executables but Windows libraries.

The Linux file command just says "executable".

Because all EXE start out as 16 bit programs, marked by the magic number "MZ" in the first two bytes. DLLs as well, as they carry a stub header of a 16 Bit EXE. This is done to enable a warning (*1) in case someone tries hard enough to start it under DOS. So for all practical purpose they are 16 bit executables.

Clarification: I want to distinguish between programs that run on any "x86" processor, and those that "require a 386", in a way that is simpler than setting up the two environments and attempting to run the program.

For real DOS programs, that is not windows programs, there is no simple to detect such, as DOS does simply not support 32 Bit. Any DOS program starts out as a 16 bit program, marked an MZ header. 32 Bit usage under DOS is custom made by the program itself and invisible to DOS. Of course, one could search for signatures of common DOS extenders, but that would still only cover part of all 32 Bit programs. Nor would it be decisive, as programs may include 32 bit support for memory access, but not being 32 bit themself.

Now, if this is about a 32 bit Windows EXE programs. Here, much like with DLL or any other file for Windows containing code, the file starts out with a PE-Header - which in turn starts out with a 16 bit EXE stub able to issue a warning (*1) if started under DOS.

Any detector looking for a (16 Bit) DOS program will find that EXE files as well as DLLs are exactly that, a DOS program.

After that stub (*2), the PE header contains several sections, foremost the COFF (Common Object File Format) chunk, which, after it's magic number, contains a machine type, telling what machine the code is intended for. Common values are

  • 00000h for 16 bit
  • 0014Ch for 32 Bit (Decimal 332 for 386-32)
  • 08664h for 64 bit

This is followed by more fields defining other characteristics, including word size and so on. For all practical purpose a machine type of 0014Ch is the most significant indicator for 32 Bit Windows applications. This is followed by an optional PE+ header, denoting different formats for headers in 64 bit versions.

Last but not least Windows DLL work exactly like Windows EXE featuring the same PE header.

While the PE format is nowadays the most common one, there are some variations. The most common are

  • New Executable (NE), introduced by Windows 1.0 / MSDOS, 16 bit
  • Linear Executable (LE), for mixed 16/32 bit in Windows 9x, OS2 and some DOS extenders
  • Linear Executables for OS2 2.0 (LX)
  • MP used with Phar Lap DOS extender.

*1 - The well known "This program cannot be run in DOS mode" message.

*2 - Consisting of the DOS header, a pointer to the PE header and the stub itself. Ignoring the pointer is a common error of programs trying to decode a PE format.

Raffzahn
  • 222,541
  • 22
  • 631
  • 918
  • Well, yes, I meant "DOS or OS/2 in shell or Win in shell or ...", i.e. anything that behaves like a DOS program from the user p.o.v. – Tomas By Feb 14 '21 at 17:14
  • 1
    @TomasBy Not sure what _' "DOS or OS/2 in shell or Win in shell or ...", i.e. anything that behaves like a DOS program from the user p.o.v.'_that is meant to say. A windows console program is still a windows program, tot a DOS program. – Raffzahn Feb 14 '21 at 17:16
  • 7
    @TomasBy Windows programs do not have to have a GUI, Windows sppots as well CLI programs - still, they are not DOS programs, but Windows programs. They can use all Windows resources and functions. There is no way to distinguish a Windows CLI program form a Windows GUI program - well, no except missing runtime calls to the GUI. Bottom line, a Windows program not using the Windows GUI is not a DOS program, but stays a Windows program. – Raffzahn Feb 14 '21 at 17:37
  • 1
    @TomasBy As mentioned, by looking at the headers. NE and PE is for Windows or compatible, LE are for Win9x and OS/2, LX are OS2 only, PE and Machine type distinguishs between 16/32/64 bit code. – Raffzahn Feb 14 '21 at 17:47
  • 1
    @TomasBy Of course. How else should 16 bit windows have been made? After all, original Windows is just a collection of DLL containing ever service offered. 16 Bit DLL are at the very base of everything.. – Raffzahn Feb 14 '21 at 17:48
  • 2
    @TomasBy ‘Some are DOS, some are Win or OS/2. How do you quickly tell them apart’ – that’s a different question from what you have asked in your original post. – user3840170 Feb 14 '21 at 17:51
  • @user3840170 no it is 16 vs. 32 I am interested in. DLLs are not DOS, that much is clear. – Tomas By Feb 14 '21 at 17:52
  • @TomasBy The answer is yes - 16 vs.32 bit can be detected as described above. – Raffzahn Feb 14 '21 at 17:54
  • 3
    You know the Windows command prompt (cmd.exe) is nothing to do with DOS, right? It just started life by implementing a very similar set of commands. FWIW, I spent a few years writing programs that ran on 32-bit Windows NT, which programs almost never had a GUI. – dave Feb 14 '21 at 21:41
  • 1
    Question intended for @TomasBy not you - sorry, I neglected to tag it. – dave Feb 14 '21 at 22:41
  • @another-dave I changed to "DOS-looking" in the title (some time ago). – Tomas By Feb 14 '21 at 22:49
  • 2
    Yeah, I don't know what that means to you. Suppose I type sc start foo at a cmd prompt. Is that "DOS-looking" even though what it's doing is sending an RPC to the service controller? – dave Feb 14 '21 at 22:55
  • 1
    If it's a matter of "there's a exe file on the disk, what is it?" then you have to look at the file header. See this info – dave Feb 14 '21 at 23:04
  • @another-dave I have tried to explain many times now that I am not looking for technical information but a practical tool. the file command should do this. – Tomas By Feb 14 '21 at 23:48
  • @TomasBy In that case, why don't you simply state that in your question? One clear sentence, that you do not want to gain knowledge but looking for a tool? As of now your question is about "how to do it", not "which tool can be used". – Raffzahn Feb 15 '21 at 00:08
  • 5
    @TomasBy - I'm sincerely attempting to help; but you have been using imprecise language, thus the "what do you mean by X?" questions. You may know what you mean, but we perhaps do not. – dave Feb 15 '21 at 00:40
  • Some 16-bit Windows programs actually had nontrivial DOS stubs, for example I believe early versions of Excel would start Windows for you if you tried to run them from DOS. On Windows 95 they did the reverse; XCOPY was a DOS program but if it detected NTVDM then it would attempt to run XCOPY32. – Neil Feb 15 '21 at 00:50
  • @Neil True. There were some, although, not really many. But what to classify them? In them self they are as well working DO programs (if only starting a Windows one) as well as complete Windows programs. Tough decision, isn't it? – Raffzahn Feb 15 '21 at 01:48
  • @Raffzahn I said "simple method" from the beginning, and I mentioned the file command. – Tomas By Feb 15 '21 at 05:39
  • https://docs.microsoft.com/en-us/windows/win32/sysinfo/image-file-machine-constants lists 0 as meaning ‘unknown’. Portable Executable files are never 16-bit. It would have been silly to use PE for 16-bit executables, as it is based on the very 32-bit COFF format. – user3840170 Feb 15 '21 at 08:08
  • @Neil: MSWindows 9x xcopy is indeed a dual-mode program, but the DOS boxes of the MSW 4.x line aren't NTVDM. NTVDM is the SoftPC-based VM used by MSW NT line operating systems. – ecm Feb 15 '21 at 08:57
  • @ecm Yeah you're right, I meant DOS box. (But it's not really a dual-mode program, since XCOPY32 is the 32-bit version for 9x.) – Neil Feb 15 '21 at 11:12
2

Even within "16-bit mode", various 8086-compatible processors that have appeared over the years have extended the 8086 instruction set with instructions that weren't supported by earlier processors. Programs that only need to run on the later processors may exploit such instructions to perform various tasks more easily and efficiently than would otherwise have been possible. For example, on the 8086, if code wants to shift a 16-bit value right by five places, it would either have to load CL with 5 and then use the rotate-right-by-CL instruction, or else use the rotate-right-by-1 instruction five times. On later processors, however, one could simply use a rotate-right-by-immediate-value instruction with an immediate value of 5. Code which uses the latter instruction would be faster than code that uses the other approaches when run on later processors, but behave in meaningless fashion if run on an 8088 or 8086.

DOS has no clue about what particular instructions any particular program might use, and there is no standard way of marking programs to indicate that. While most programs that require an 80386 or later happen to make use of 32-bit registers, the only time an OS would need to care about that would be if it tries to multi-task two or more programs that both make use of 32-bit registers simultaneously. If two or more programs which use 32-bit registers are run simultaneously and a multi-tasker doesn't know how to save and restore such registers on a context switch, each program would be likely to trash register contents upon which the other would be relying. If only one program at a time uses 32-bit registers, however, this would be a non-issue. Whenever code switched away from that program, the system would save the bottom halves of 32-bit registers without saving the top halves, but since nothing else in the system would access the top halves of those registers, they would still hold the proper values once control returns to the only program that cares about them.

While it's possible for DOS programs to switch to 32-bit modes, many programs which make use of 32-bit registers do so without ever leaving "16-bit" mode, using instruction codes that had no assigned meaning on the 8086. Because DOS processes such programs just like any other, it neither knows nor cares about whether they use instructions that only have meaning on certain processors, and doesn't define any means by which programs can indicate what CPU is required.

supercat
  • 35,993
  • 3
  • 63
  • 159
1

There is in the windows nt resource kit, a program called 'exetype'. The 3.1 version is a DOS program, while liter ones, like 3.51, is a win32 program. You type exetype filename.ext to get its type. It even tells you whether it's a vio (command line), or PM program.

wendy.krieger
  • 712
  • 3
  • 6
  • It does not seem to be perfect. I have (probably 16-bit) OS/2 programs that it identified as DOS. – Tomas By Jul 27 '21 at 19:22
  • @user3840170 it lists 16 bit and 32 bit options (check the .ini file below). – Tomas By Jul 28 '21 at 21:43
  • @TomasBy does it distinguish 16- and 32-bit DOS executables? – Stephen Kitt Sep 06 '21 at 18:34
  • 1
    Ah, I see, it’s similar to file but with a very brief magic database. – Stephen Kitt Sep 06 '21 at 18:39
  • Of course, DOS 16 vs 32, is implemented by DOS extenders. DOS makes use of OVL files rather than DLL, which means additional functional can overlay part of the loaded one. Windows 98 xcopy32.mod might look like one, but it's just xcopy.exe renamed. On the other hand, programs like XTree, do use overlays. The programs like requires.exe (PC-Mag for Windows 3.1), or depend.exe (WinXP PE kit), do indeed allow you to list called modules. CHK4DLL32 i think is the OS/2 version.
    One runs a proggue, and says 'this program requires "Microsoft Bob" to see what is else needed.
    – wendy.krieger Sep 08 '21 at 10:18
  • @wendy.krieger why “of course”? It’s very easy to write a DOS program requiring a 32-bit CPU without relying on a DOS extender or overlays, and it’s also not all that complicated to write a DOS program with its own, embedded, DOS extender. Note too that nothing in DOS prevents using DLLs; see the HX extender for example. – Stephen Kitt Oct 06 '21 at 13:07
1

For reference, I am posting the .txt and .ini files from the exetype program.

*********************************************************************
EXETYPE 1.0 is a tool to determine the nature of an executable file.
Syntax: EXETYPE <filename>

NOTE: EXETYPE does not yet support file wildcards.

It is necessary to have the EXETYPE.INI file somewhere in your PATH 
(if unsure, type PATH).  
The format of EXETYPE.INI is as follows:

[entry1]         
TYPE    &lt;string&gt;
ADDRESS &lt;hex value&gt; or **
OFFSET  &lt;hex value&gt;
MASK    &lt;hex value&gt;
VALUE   &lt;hex value&gt; or !&lt;hex value&gt;
ADDRESS &lt;hex value&gt; or **
OFFSET  &lt;hex value&gt;
MASK    &lt;hex value&gt;
VALUE   &lt;hex value&gt; or !&lt;hex value&gt;
.
.
.

[entry2]         
TYPE    &lt;string&gt;
HEADER  &lt;hex value&gt; or **
OFFSET  &lt;hex value&gt;
MASK    &lt;hex value&gt;
VALUE   &lt;hex value&gt; or !&lt;hex value&gt;
.
.
.


Each Entry has one TYPE field and from 1 to 5 groups of 
ADDRESS, OFFSET, MASK and VALUE fields.      

NOTE: All hex values must have an even number of characters (we're working 
  with byte values here.  If an odd number of nybbles is needed, please 
  pad with zeros. 

A description of each entry follows:
 [entry] -  This denotes the start of a new entry.  80 characters maximum.
 TYPE        -  A description of the file type, 80 characters maximum.
 ADDRESS     -  Microsoft EXE files have the address of the header at a certain 
        location.  This value is kept at offset 3c from the beginning
        of the file.  If your entry does not use this, put in ** and it 
        will be ignored.
 OFFSET      -      This hex value denotes the offset from the beginning of the 
        header.  
 MASK        -      This bitmask lets you screen which bits of the bytes you want
        to look at.
 VALUE       -  This is the actual value you are comparing to the value of the
        bits at OFFSET strained through MASK.  If it is preceded by a &quot;!&quot;, the 
        criterion is that the two values do NOT match.                     

The entries:

[DOS]
TYPE    DOS Executable 
ADDRESS **
OFFSET  00
MASK    FFFF
VALUE   4d5a 
ADDRESS 3c 
OFFSET  00
MASK    FFFF
VALUE   !4e45

[WIN] TYPE Windows Executable ADDRESS 3c OFFSET 00 MASK FFFF VALUE 4e45 ADDRESS 3c OFFSET 36 MASK FF VALUE 02

[OS/2] TYPE OS/2 Executable ADDRESS 3c OFFSET 00 MASK FFFF VALUE 4e45 ADDRESS 3c OFFSET 36 MASK FF VALUE 01

[OS2_Bound] TYPE Bound to run under DOS (or has a DOS stub) ADDRESS ** OFFSET 40 MASK FF VALUE 00 ADDRESS 3c OFFSET 00 MASK FFFF VALUE 4e45 ADDRESS 3c OFFSET 36 MASK FF VALUE 01

[OS2_Real] TYPE Runs in real mode or protected mode ADDRESS 3c OFFSET 00 MASK FFFF VALUE 4e45 ADDRESS 3c OFFSET 36 MASK FF VALUE 01 ADDRESS 3c OFFSET 0c MASK 08 VALUE 00

[OS2_Protect] TYPE Runs only in protected mode ADDRESS 3c OFFSET 00 MASK FFFF VALUE 4e45 ADDRESS 3c OFFSET 36 MASK FF VALUE 01 ADDRESS 3c OFFSET 0c MASK 08 VALUE 08

[OS2_or_Win_DLL] TYPE Dynamic link library or driver ADDRESS 3c OFFSET 00 MASK FFFF VALUE 4e45 ADDRESS 3c OFFSET 0d MASK 80 VALUE 80

[OS2_Full] TYPE Full screen application ADDRESS 3c OFFSET 00 MASK FFFF VALUE 4e45 ADDRESS 3c OFFSET 36 MASK FF VALUE 01 ADDRESS 3c OFFSET 0d MASK 07 VALUE 01

[OS2_VIO] TYPE VIO application (can run in a window) ADDRESS 3c OFFSET 00 MASK FFFF VALUE 4e45 ADDRESS 3c OFFSET 36 MASK FF VALUE 01 ADDRESS 3c OFFSET 0d MASK 07 VALUE 02

[OS2_PM] TYPE Presentation Manager application ADDRESS 3c OFFSET 00 MASK FFFF VALUE 4e45 ADDRESS 3c OFFSET 36 MASK FF VALUE 01 ADDRESS 3c OFFSET 0d MASK 07 VALUE 03

[NT] TYPE Windows NT ADDRESS 3c OFFSET 00 MASK FFFFFFFF VALUE 50450000

[NT_16bit] TYPE 16 bit machine ADDRESS 3c OFFSET 16 MASK 4001 VALUE 4000 ADDRESS 3c OFFSET 00 MASK FFFFFFFF VALUE 50450000

[NT_32bit] TYPE 32 bit machine ADDRESS 3c OFFSET 16 MASK 4001 VALUE 0001 ADDRESS 3c OFFSET 00 MASK FFFFFFFF VALUE 50450000

[NT_DLL] TYPE Dynamic Link Library ADDRESS 3c OFFSET 16 MASK 0020 VALUE 0020 ADDRESS 3c OFFSET 00 MASK FFFFFFFF VALUE 50450000

[NT_SYSTEM] TYPE System File ADDRESS 3c OFFSET 16 MASK 0010 VALUE 0010 ADDRESS 3c OFFSET 00 MASK FFFFFFFF VALUE 50450000

[NT_i386] TYPE Built for the Intel 80386 processor ADDRESS 3c OFFSET 04 MASK FFFF VALUE 4c01 ADDRESS 3c OFFSET 00 MASK FFFFFFFF VALUE 50450000

[NT_i486] TYPE Built for the Intel 80486 processor ADDRESS 3c OFFSET 04 MASK FFFF VALUE 4d01 ADDRESS 3c OFFSET 00 MASK FFFFFFFF VALUE 50450000

[NT_MARK3] TYPE Built for the R4000 (MIPS) processor ADDRESS 3c OFFSET 04 MASK FFFF VALUE 6601 ADDRESS 3c OFFSET 00 MASK FFFFFFFF VALUE 50450000

[NT_iPentium] TYPE Built for the Intel Pentium processor ADDRESS 3c OFFSET 04 MASK FFFF VALUE 4e01 ADDRESS 3c OFFSET 00 MASK FFFFFFFF VALUE 50450000

[NT_Alpha] TYPE Built for the DEC Alpha processor ADDRESS 3c OFFSET 04 MASK FFFF VALUE 8401 ADDRESS 3c OFFSET 00 MASK FFFFFFFF VALUE 50450000

[NT_PowerPC] TYPE Built for the PowerPC processor ADDRESS 3c OFFSET 04 MASK FFFF VALUE F001 ADDRESS 3c OFFSET 00 MASK FFFFFFFF VALUE 50450000

[NT_NO_SUB] TYPE Requires no subsystem to run (Native to Windows NT) ADDRESS 3c OFFSET 5c MASK 0F VALUE 01 ADDRESS 3c OFFSET 00 MASK FFFFFFFF VALUE 50450000

[NT_WIN_GUI_SUB] TYPE Runs under the Windows GUI subsystem ADDRESS 3c OFFSET 5c
MASK 0F VALUE 02 ADDRESS 3c OFFSET 00 MASK FFFFFFFF VALUE 50450000

[NT_WIN_CUI_SUB] TYPE Runs under the Windows character-based subsystem ADDRESS 3c OFFSET 5c
MASK 0F VALUE 03 ADDRESS 3c OFFSET 00 MASK FFFFFFFF VALUE 50450000

[NT_OS2_SUB] TYPE Runs under the OS/2 subsystem ADDRESS 3c OFFSET 5c MASK 0F VALUE 05 ADDRESS 3c OFFSET 00 MASK FFFFFFFF VALUE 50450000

[NT_POSIX_SUB] TYPE Runs under the POSIX subsystem ADDRESS 3c OFFSET 5c
MASK 0F VALUE 07 ADDRESS 3c OFFSET 00 MASK FFFFFFFF VALUE 50450000

Tomas By
  • 2,082
  • 2
  • 15
  • 35