NE-Executable | Segmented EXE Format New executable

The NE (fully “New executable”) is a 16-bit executable file format was designed by Microsoft for 16-bit Windows 1.x - Windows 3.x, Windows 9x, OS/2 1.x, multitasking MS-DOS 4.0 and the OS/2 sunset of Windows NT up to version 5.0 (Windows 2000).

This Segmented EXE format provides support for:

  • Segmented memory model;
  • Protected Mode (I286+) operation;
  • Dynamic linking;
  • Resource management;
  • Shared code between programs.

Overview

NE segmented program or library always starts like MZ-Executable. Means image has MZheader structure. Last field in structure - e_lfanew is a pointer to next NE header structure.

The NE header is an important detail which describes the entire subsequent structure of the image. An NE segmented executable typically contains about 7 tables (or unsafe structures) and segments which contain program’s code.

                    | DOS stub            |
                    +---------------------+
  relative offset   | ...                 |
  [1,24,6...]<------+ Module references   |
              +-----+ Importing names     | relative offset
relative offset     | Entry Table         +------------> [#1{...}][#2{...}...]
[...]<--------+     | Resident names      +-------+
                    | Not resident names  +----+  | relative offset
        +-----------+ Segments Table      |    |  +-----> [...]
        |           | Per-segment fixups  |    | absolute offset
        |           | Resources table     |    +--------> [...]
        |           ...                   |
 +------+--------------------+            |
 | #1 .CODE 0xBABE no_relocs |            |
 | #2 .CODE 0xFEED           +------>[#2 fixups table]
 | ...                       |            |
 +-------------+-------------+            |
              ||    |                     |
              ||    |                     |
              |+--->+---------------------+
              |     | #1 .CODE bytes      |
              +---->+---------------------+
                    | #2 .CODE bytes      |
                    | ...                 |
                    +---------------------+
                    | Resource #1         |
                    | Resource #2         |
                    | Resource #3         |
                    | ...
                    EOF
                    

NE Header

The NE header is a packed structure. Starts with ASCII fixed string [E, N] (little endian reinterpretation) or [N, E] (big endian reinterpretation). This is a main sign which indicates that the following values describe 16-bit Windows or OS/2 program.

#[derive(Debug, Clone, Copy, PartialEq, Eq, Pod, Zeroable)]
#[repr(C)]
pub struct NeHeader {
    pub e_magic: [u8; 2],
    pub e_ver: u8,        // LINK.EXE major version
    pub e_rev: u8,        // LINK.EXE minor version
    pub e_enttab: u16,
    pub e_cbent: u16,     // Count of entry bundles
    pub e_crc: u32,
    pub e_flags: u16,     // [program_flags][app_flags]
    pub e_autodata: u16,  // automatic DS (data segment) index
    pub e_heap: u16,      // Initial heap size
    pub e_stack: u16,     // Initial stack size 
    pub e_cs_ip: u32,     // CS:IP
    pub e_ss_sp: u32,     // SS:SP
    pub e_cbseg: u16,     // Count of segments
    pub e_cbmod: u16,     // Count of module references
    pub e_cbnres: u16,    // Size of Nonresident names table
    pub e_segtab: u16,
    pub e_cbres: u16, 
    pub e_resntab: u16,   // Resident names table
    pub e_modtab: u16,    // Module references table
    pub e_imptab: u16,    // Importing module names
    pub e_nrestab: u32,   // Non-Resident names table (raw offset)
    pub e_cbentmov: u16,  // Count of moveable entries 
    pub e_align: u16,     // Sector shift. (0 means 512)
    pub e_restab: u16,    // Resources table
    pub e_os: u8,         // Target OS
    // **OS/2 part** of header. (checks by IBM OS/2 Win-OS/2 module)
    pub e_flagothers: u8, // OS/2 flags for loader (e.g. HPFS/FAT naming) 
    pub e_pretthunk: u16, // Return Thunk offset
    pub e_thunk: u16,     // Segment reference thunk offset
    pub e_swap: u16,      // minimum code swap
    pub e_expver: [u8; 2],// Expected Windows version!
                          // (little endian reinterpretation!)
}

NE Header has fields-masks which tells more about exploring binary image.

NE Header | LINK.EXE

Depending on the version of Microsoft Link, the processed file may have minor changes in NE segmentation format. That’s why images linked by LINK.EXE 4.x are have wrong reinterpretation of EntryTable LINK.EXE 5.10 instead

NE Header | e_flags

The e_flags field has 2 categories. Program and Application flags.

Program flags are a common module description which stores CPU, module type, flags.

//
// In 16-bit DOS/Windows terminology, DGROUP is a segment class that referring
// to segments that are used for data.
//
// Win16 used segmentation to permit a DLL or program to have multiple
// instances along with an instance handle and manage multiple data
// segments. This allowed one NOTEPAD.EXE code segment to execute
// multiple instances of the notepad application.
//
enum FlagWord {
    // how is data handled?
    NOAUTODATA = 0x0000,
    SINGLEDATA = 0x0001, // shared among instances of the same program
    MULTIPLEDATA = 0x0002, // separate for each instance of the same program

    // additional flags:
    LINKERROR = 0x2000, // Linker error, module can't be loaded
    LIBMODULE = 0x8000, // if this flag is set, this is a DLL;
                        // see the "Dynamic Libraries" section below
};

#define GLOBINIT  1 << 2    // global initialization
#define PMODEONLY 1 << 3    // Protected mode only
#define I8086     1 << 4    // 8086 instructions
#define I286      1 << 5    // 80286 instructions
#define I386      1 << 6    // 80386 instructions
#define I8087     1 << 7    // 80x87 (FPU) instructions

Application flags tells a program’s window behavoiur. Windows 3.x and Win-OS/2 uses this flags for running module

// Application flags
// 
// I suggest, Win-OS/2 or Windows 3.x uses this 
// information, so application flags tells how to work Windows
// OR OS/2 Presentation Manager. (shorten P.M.) 
// 
enum apptype {
    none,
    fullscreeen,    // fullscreen (not aware of Windows/P.M. API)
    winpmcompat,    // compatible with Windows/P.M. API
    winpmuses       // uses Windows/P.M. API
};

More information has Oracle VirtualBox driver for various operating systems. Oracle holds a C/++ sources of NE Header declaration

NE Header | e_os

Value that e_os holds is optional, because not all binaries was compiled for the IBM OS/2 environment. In old Windows 1.x executables e_os flag is zeroed what means 2 things:

  1. Target OS is unknown;
  2. Any OS supported (don’t think about unix).

Fonts compiled as NE executables have zeroed target os flag too.

enum targetos {
    Unknown = 0x00, // Any OS or unknown
    OS2     = 0x01, // IBM OS/2
    Win16   = 0x02, // Windows/286
    Dos4    = 0x03, // European DOS 4.x
    Win32s  = 0x04, // Windows/386
    Boss    = 0x05  // Borland OS service
}

Other structures?

Other structures will be in next pages, for each structure will be placed per one page. In future this region may contain links to other pages


Author | Alexey Tolstopyatov (21 y.0.)

Desktop developer and System developer enthusiast. Currently a student in Tomsk State University in the area of software for microprocessor systems.