Coder Social home page Coder Social logo

nefile's Introduction

Like its namesake pefile does for the modern Portable Executable format, this nefile library parses the ancient 16-bit New Executable (NE) format.

I drafted this library because here are not many good cross-platform tools for analyzing and extracting data (more than just code) from NE files. For instance, Ghidra is great at decompilation but not really at resources. wrestool and icoutils are the only tools I have found to date that can extract resources from NE files, but I ran into multiple issues using wrestool, including resources being corrupted upon extraction.

This library fills the gap. Also, I just love Windows 3.1.

Currently there is read-only support for the NE header and resources, as that's all I need at the moment. Feel free to contribute if you need other functionality from Python.

If you like my projects, please consider supporting me!

Buy Me A Coffee

Spec References

The main spec reference used is the Microsoft Windows 3.1 Programmer's Reference, Volume 4 (Resources), referred to in the code as W3.1PRV4.

The Microsoft MS-DOS Programmer's Reference helped provide insight into the DOS MZ header.

Installation

Get it on PyPI: pip3 install nefile

Usage

import nefile
from nefile.resource_table import ResourceType

# OPEN THE WINDOWS 3.1 PROGRAM MANAGER.
progman = nefile.NE('/media/windows-3.1/WINDOWS/PROGMAN.EXE')
print(progman.header.target_operating_system) # <TargetOperatingSystem.WINDOWS_3X: 2>
print(progman.header.expected_windows_version) # 3.10
# See the resource types defined in Program Manager.
print(progman.resource_table.resource_type_tables.keys())
# Known resource types are replaced with an enum member. There can also be integer and string IDs
# for resource types that don't have a globally-defined type.
# dict_keys([<ResourceType.RT_GROUP_ICON: 14>, <ResourceType.RT_MENU: 4>, <ResourceType.RT_DIALOG: 5>, 
#            <ResourceType.RT_STRING: 6>, <ResourceType.RT_ACCELERATOR: 9>, <ResourceType.RT_VERSION: 16>,
#            <ResourceType.RT_ICON: 3>])
# 
# List all the bitmap resources defined in Program Manager.
print(progman.resource_table.resource_type_tables[ResourceType.RT_GROUP_ICON])
# Individual resource IDs are either integer or string IDs, as dictated in the file.
# {3: <nefile.resources.Resource object at 0x7f0d72c79fa0>, 6: <nefile.resources.Resource object at 0x7f0d72c7af40>, 
#  'DATAICON': <nefile.resources.Resource object at 0x7f0d72c7a0d0>, 'COMMICON': <nefile.resources.Resource object at 0x7f0d72c7afd0>, 
#  'MSDOSICON': <nefile.resources.Resource object at 0x7f0d72c7ab80>}

# OPEN THE WINDOWS 3.1 SHELL.
# This is where the famous easter egg is stored! I actually wrote this library
# because I wanted to get at those resources solely in Python and not bother
# with `wrestool`.
shell = nefile.NE('/media/windows-3.1/WINDOWS/SYSTEM/SHELL.DLL')
# dict_keys([<ResourceType.RT_BITMAP: 2>, <ResourceType.RT_DIALOG: 5>, <ResourceType.RT_STRING: 6>, 
#            <ResourceType.RT_RCDATA: 10>, <ResourceType.RT_VERSION: 16>, 100])
shell.export_resources("/root/shell")
# Produces files with names like "SHELL.DLL-RT_BITMAP-130.bmp".

Tests

Test data is not included in this repository, but these are the sources used:

To set up tests, create the tests/test_data directory and put NEs in there. Currently DLLs and EXEs are picked up. If any turn out to be PE files or plain DOS EXEs, they will be marked as skipped in the tests.

To run the tests, just run pytest from the root of the repository.

nefile's People

Contributors

bitplane avatar chkuendig avatar npjg avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

nefile's Issues

Extracting resources fails for lots of files

Hey, cool project, but I think you need more test data :)

source files

I was messing about with this collection from the Internet archive:

https://archive.org/details/630-windows-3x-games

extracting

Throw it in a dir and unzip it, then from my bash_history, I did this:

for f in *.ZIP; do mkdir $(echo $f | cut -d '.' -f 1); mv $f $(echo $f | cut -d '.' -f 1); done
for d in $(find -type d); do pushd $d ; unzip *.ZIP; popd; done
rm */*.ZIP
# do the same for .zip too I guess

And a hacky script to export the resources:

import nefile
import glob
import traceback


binaries = glob.glob('*/*.EXE')


for binary in binaries:
    try:
        f = nefile.nefile.NE(binary)
        f.export_resources(binary.split('/')[-2])
    except Exception as e:
        print('nope:', binary, type(e).__name__, str(e))
        traceback.print_exc()

results

it errors out 90% of the time:

$ find -name '*.EXE' | wc -l
744

$ python export.py > errors.txt
$ wc -l errors.txt
687

$ cat errors.txt | cut -d ' ' -f 3- | sort | uniq -c | sort -nr

    362 AttributeError 'ApplicationDefinedData' object has no attribute 'write_ico_file'
    145 TypeError Cursor.__init__() takes from 2 to 3 positional arguments but 4 were given
     86 AttributeError 'StringTable' object has no attribute 'export'
     43 AssertionError 
     30 UnicodeDecodeError 'ascii' codec can't decode byte 0x80 in position 2: ordinal not in range(128)
     14 ValueError seek out of range
      2 UnicodeDecodeError 'ascii' codec can't decode byte 0xa9 in position 0: ordinal not in range(128)
      1 UnicodeDecodeError 'ascii' codec can't decode byte 0xb0 in position 24: ordinal not in range(128)
      1 UnicodeDecodeError 'ascii' codec can't decode byte 0xae in position 5: ordinal not in range(128)
      1 UnicodeDecodeError 'ascii' codec can't decode byte 0xa9 in position 81: ordinal not in range(128)
      1 UnicodeDecodeError 'ascii' codec can't decode byte 0xa3 in position 1: ordinal not in range(128)
      1 UnicodeDecodeError 'ascii' codec can't decode byte 0x8b in position 0: ordinal not in range(128)

causes

In order of appearance

  1. Something weird going on here, caused by latest update? Can't eyeball this, need a debugger. - looks to be fixed in git
  2. Needs an extra dummy parameter adding to Cursor.__init__(), but PIL still fails afterwards if I do that on my machine. I installed Pillow rather than PIL because PIL is a dead project. Need to use Image.load not Image? edit: the bitmap stuff was confusing me, couldn't figure it out. I made the Cursor a subclass of Bitmap and dumped them to disk, but they look truncated in hexdump. Dunno if it's the bitmap writer, none of those exes have bitmap resources.
  3. Missing export method in resources/string.py - looks fixed in git
  4. Probably not a bug, but consider raising ValueError instead of assert here
  5. and the others are probably caused by EXEs that have different character encodings. Consider ignoring conversion errors, figure out the codepage, or cheat and use chardet to detect the encoding before converting to a string. - nope they're zero terminated, see #3
  6. Haven't looked into this. edit: had a little look, but couldn't figure it out yet

I'll raise a pull request or two :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.