dnfile


Namednfile JSON
Version 0.15.1 PyPI version JSON
download
home_pageNone
SummaryParse .NET executable files.
upload_time2024-10-19 02:26:26
maintainerNone
docs_urlNone
authorMalwareFrank
requires_python>=3.8
licenseMIT License
keywords dnfile
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            ======
dnfile
======


.. image:: https://github.com/malwarefrank/dnfile/actions/workflows/lint.yml/badge.svg
        :target: https://github.com/malwarefrank/dnfile/actions/workflows/lint.yml
.. image:: https://img.shields.io/pypi/v/dnfile.svg
        :target: https://pypi.python.org/pypi/dnfile
.. image:: https://img.shields.io/pypi/dm/dnfile
        :target: https://pypistats.org/packages/dnfile


Parse .NET executable files.


* Free software: MIT license


Features
--------

* Parse as much as we can, even if the file is partially malformed.
* Easy to use.  Developed with IDE autocompletion in mind.


Quick Start
-----------

.. code-block:: shell

   pip install dnfile

Then create a simple program that loads a .NET binary, parses it, and displays
information about the streams and Metadata Tables.

.. code-block:: python

   import sys
   import dnfile

   filepath = sys.argv[1]

   pe = dnfile.dnPE(filepath)
   pe.print_info()


Everything is an object, and raw structure values are stored in an object's "struct"
attribute.  The CLR directory entry object is accessible from the "net"
attribute of a dnPE object.

.. code-block:: python

    import dnfile
    import hashlib

    pe = dnfile.dnPE(FILEPATH)

    # access the directory entry raw structure values
    pe.net.struct

    # access the metadata raw structure values
    pe.net.metadata.struct

    # access the streams
    for s in pe.net.metadata.streams_list:
        if isinstance(s, dnfile.stream.MetaDataTables):
            # how many Metadata tables are defined in the binary?
            num_of_tables = len(s.tables_list)

    # the last Metadata tables stream can also be accessed by a shortcut
    num_of_tables = len(pe.net.mdtables.tables_list)

    # create a set to hold the hashes of all resources
    res_hash = set()
    # access the resources
    for r in pe.net.resources:
        # if resource data is a simple byte stream
        if isinstance(r.data, bytes):
            # hash it and add the hash to the set
            res_hash.add(hashlib.sha256(r.data).hexdigest())
        # if resource data is a ResourceSet, a dotnet-specific datatype
        elif isinstance(r.data, dnfile.resource.ResourceSet):
            # if there are no entries
            if not r.data.entries:
                # skip it
                continue
            # for each entry in the ResourceSet
            for entry in r.data.entries:
                # if it has data
                if entry.data:
                    # hash it and add the hash to the set
                    res_hash.add(hashlib.sha256(entry.data).hexdigest())


TODO
----

* more tests
* Documentation on readthedocs


Credits
-------

This package was created with Cookiecutter_ and the `audreyr/cookiecutter-pypackage`_ project template.

.. _Cookiecutter: https://github.com/audreyr/cookiecutter
.. _`audreyr/cookiecutter-pypackage`: https://github.com/audreyr/cookiecutter-pypackage

=======
History
=======

0.15.1 (2024)
-------------

* BUGFIX: read_compressed_int() now returns None on invalid data len instead of IndexError
* BUGFIX: when parsing resources, ignore DateTimeKind bits of a serialized System.DateTime
* EXAMPLE: Iterate guids

0.15.0 (2024)
-------------
* BREAKING CHANGE: each heap stream's .get() returns a HeapItem instead of bytes
* FEATURE: All HeapItem objects include the RVA of where they were retrieved
* FEATURE: HeapItemBinary objects allow easy access to interpreted item size (CompressedInt)
* FEATURE: HeapItemString and UserString allow easy access to raw bytes and interpreted value
* improvements to pypi publishing and tox testing

0.14.1 (2023)
-------------
* fix github workflow

0.14.0 (2023)
-------------
* BREAKING CHANGE: Minimum required Python version is now 3.8
* BUGFIX: ValueError fired before UnicodeDecodeError when parsing assembly resources
* BUGFIX: mdtable row run-lists of size one were being ignored
* BUGFIX: some struct file offsets were RVA values
* FEATURE: Add ``clr_lazy_load`` option for lazy loading Metadata tables and assembly resources
* move from legacy setup.py to pyproject.toml and tox
* bump dev dependencies: mypy and isort
* update tests and examples
* update README badge to use download statistics from pypistats

0.13.0 (2022)
-------------
* BREAKING CHANGE: rename GenericMethod mdtable to MethodSpec per ECMA 335
* parse more resources, even if there are exceptions

0.12.0 (2022)
-------------
* FEATURE: parse ``#Schema`` stream as MetaDataTables
* BUGFIX: MDTableRow off-by-one for end of run
* BUGFIX: MethodSemanticsRow typo list of tables for the Method Index
* more test data

0.11.0 (2022)
-------------
* FEATURE: access .NET resources (not same as PE resources!) by a shortcut
* BUGFIX: dnstrings example
* more attributes default to None
* update dev dependencies
* remove some warnings

0.10.0 (2022)
-------------

* BREAKING CHANGE: structure attributes no longer exist by default
* BREAKING CHANGE: objects' attributes always exist, but may be None
* BUGFIX: use last stream if multiple of same name
* CI: added mypy type checking
* when duplicate stream names, behave like runtime and use last one for shortcuts
* add user_strings shortcut
* able to access MetaDataTables like a 0-based list, with square brackets
* added use of logging module for warnings
* better type hints for IDEs
* more better source comments
* more tests

0.9.0 (2021)
------------

* bugfix: row indices parsed in structures are one-based, not zero-based
* bugfix: TypeDefRow was not parsing Extends coded index
* bugfix: incorrect BLOBS_MASK and add EXTRA_DATA skip if flag set
* added CI using github workflow
* added tests and submodule dnfile-testfiles
* added style consistency using pycodestyle and isort
* added more examples
* parse MetaData tables' list-type indexes into lists of MDTableRow objects

0.8.0 (2021)
------------

* bugfix: Metadata Table indexes (i.e. indexes into other tables) were off by one

0.7.1 (2021)
------------

* bugfix: coded index always None

0.7.0 (2021)
------------

* bugfix: improper data length check

0.6.0 (2021)
------------

* bugfix: referenced wrong object
* parse utf-16 strings in #US stream

0.5.0 (2021-01-29)
------------------

* First release.

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "dnfile",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": "dnfile",
    "author": "MalwareFrank",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/8f/89/6781fe5a1d623b9235f12a10cd76d7eba8458f950a83e861974d103a896d/dnfile-0.15.1.tar.gz",
    "platform": null,
    "description": "======\ndnfile\n======\n\n\n.. image:: https://github.com/malwarefrank/dnfile/actions/workflows/lint.yml/badge.svg\n        :target: https://github.com/malwarefrank/dnfile/actions/workflows/lint.yml\n.. image:: https://img.shields.io/pypi/v/dnfile.svg\n        :target: https://pypi.python.org/pypi/dnfile\n.. image:: https://img.shields.io/pypi/dm/dnfile\n        :target: https://pypistats.org/packages/dnfile\n\n\nParse .NET executable files.\n\n\n* Free software: MIT license\n\n\nFeatures\n--------\n\n* Parse as much as we can, even if the file is partially malformed.\n* Easy to use.  Developed with IDE autocompletion in mind.\n\n\nQuick Start\n-----------\n\n.. code-block:: shell\n\n   pip install dnfile\n\nThen create a simple program that loads a .NET binary, parses it, and displays\ninformation about the streams and Metadata Tables.\n\n.. code-block:: python\n\n   import sys\n   import dnfile\n\n   filepath = sys.argv[1]\n\n   pe = dnfile.dnPE(filepath)\n   pe.print_info()\n\n\nEverything is an object, and raw structure values are stored in an object's \"struct\"\nattribute.  The CLR directory entry object is accessible from the \"net\"\nattribute of a dnPE object.\n\n.. code-block:: python\n\n    import dnfile\n    import hashlib\n\n    pe = dnfile.dnPE(FILEPATH)\n\n    # access the directory entry raw structure values\n    pe.net.struct\n\n    # access the metadata raw structure values\n    pe.net.metadata.struct\n\n    # access the streams\n    for s in pe.net.metadata.streams_list:\n        if isinstance(s, dnfile.stream.MetaDataTables):\n            # how many Metadata tables are defined in the binary?\n            num_of_tables = len(s.tables_list)\n\n    # the last Metadata tables stream can also be accessed by a shortcut\n    num_of_tables = len(pe.net.mdtables.tables_list)\n\n    # create a set to hold the hashes of all resources\n    res_hash = set()\n    # access the resources\n    for r in pe.net.resources:\n        # if resource data is a simple byte stream\n        if isinstance(r.data, bytes):\n            # hash it and add the hash to the set\n            res_hash.add(hashlib.sha256(r.data).hexdigest())\n        # if resource data is a ResourceSet, a dotnet-specific datatype\n        elif isinstance(r.data, dnfile.resource.ResourceSet):\n            # if there are no entries\n            if not r.data.entries:\n                # skip it\n                continue\n            # for each entry in the ResourceSet\n            for entry in r.data.entries:\n                # if it has data\n                if entry.data:\n                    # hash it and add the hash to the set\n                    res_hash.add(hashlib.sha256(entry.data).hexdigest())\n\n\nTODO\n----\n\n* more tests\n* Documentation on readthedocs\n\n\nCredits\n-------\n\nThis package was created with Cookiecutter_ and the `audreyr/cookiecutter-pypackage`_ project template.\n\n.. _Cookiecutter: https://github.com/audreyr/cookiecutter\n.. _`audreyr/cookiecutter-pypackage`: https://github.com/audreyr/cookiecutter-pypackage\n\n=======\nHistory\n=======\n\n0.15.1 (2024)\n-------------\n\n* BUGFIX: read_compressed_int() now returns None on invalid data len instead of IndexError\n* BUGFIX: when parsing resources, ignore DateTimeKind bits of a serialized System.DateTime\n* EXAMPLE: Iterate guids\n\n0.15.0 (2024)\n-------------\n* BREAKING CHANGE: each heap stream's .get() returns a HeapItem instead of bytes\n* FEATURE: All HeapItem objects include the RVA of where they were retrieved\n* FEATURE: HeapItemBinary objects allow easy access to interpreted item size (CompressedInt)\n* FEATURE: HeapItemString and UserString allow easy access to raw bytes and interpreted value\n* improvements to pypi publishing and tox testing\n\n0.14.1 (2023)\n-------------\n* fix github workflow\n\n0.14.0 (2023)\n-------------\n* BREAKING CHANGE: Minimum required Python version is now 3.8\n* BUGFIX: ValueError fired before UnicodeDecodeError when parsing assembly resources\n* BUGFIX: mdtable row run-lists of size one were being ignored\n* BUGFIX: some struct file offsets were RVA values\n* FEATURE: Add ``clr_lazy_load`` option for lazy loading Metadata tables and assembly resources\n* move from legacy setup.py to pyproject.toml and tox\n* bump dev dependencies: mypy and isort\n* update tests and examples\n* update README badge to use download statistics from pypistats\n\n0.13.0 (2022)\n-------------\n* BREAKING CHANGE: rename GenericMethod mdtable to MethodSpec per ECMA 335\n* parse more resources, even if there are exceptions\n\n0.12.0 (2022)\n-------------\n* FEATURE: parse ``#Schema`` stream as MetaDataTables\n* BUGFIX: MDTableRow off-by-one for end of run\n* BUGFIX: MethodSemanticsRow typo list of tables for the Method Index\n* more test data\n\n0.11.0 (2022)\n-------------\n* FEATURE: access .NET resources (not same as PE resources!) by a shortcut\n* BUGFIX: dnstrings example\n* more attributes default to None\n* update dev dependencies\n* remove some warnings\n\n0.10.0 (2022)\n-------------\n\n* BREAKING CHANGE: structure attributes no longer exist by default\n* BREAKING CHANGE: objects' attributes always exist, but may be None\n* BUGFIX: use last stream if multiple of same name\n* CI: added mypy type checking\n* when duplicate stream names, behave like runtime and use last one for shortcuts\n* add user_strings shortcut\n* able to access MetaDataTables like a 0-based list, with square brackets\n* added use of logging module for warnings\n* better type hints for IDEs\n* more better source comments\n* more tests\n\n0.9.0 (2021)\n------------\n\n* bugfix: row indices parsed in structures are one-based, not zero-based\n* bugfix: TypeDefRow was not parsing Extends coded index\n* bugfix: incorrect BLOBS_MASK and add EXTRA_DATA skip if flag set\n* added CI using github workflow\n* added tests and submodule dnfile-testfiles\n* added style consistency using pycodestyle and isort\n* added more examples\n* parse MetaData tables' list-type indexes into lists of MDTableRow objects\n\n0.8.0 (2021)\n------------\n\n* bugfix: Metadata Table indexes (i.e. indexes into other tables) were off by one\n\n0.7.1 (2021)\n------------\n\n* bugfix: coded index always None\n\n0.7.0 (2021)\n------------\n\n* bugfix: improper data length check\n\n0.6.0 (2021)\n------------\n\n* bugfix: referenced wrong object\n* parse utf-16 strings in #US stream\n\n0.5.0 (2021-01-29)\n------------------\n\n* First release.\n",
    "bugtrack_url": null,
    "license": "MIT License",
    "summary": "Parse .NET executable files.",
    "version": "0.15.1",
    "project_urls": {
        "repository": "https://github.com/malwarefrank/dnfile"
    },
    "split_keywords": [
        "dnfile"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "698280b8c2111eb37b59871d4df2ef826a7aaa8046f1dc021c56ebeaf7d98906",
                "md5": "14c75b999577e51bd41edbde29132e5f",
                "sha256": "585c8e3e4a29824402430a0a8b7e7ae82c040fc17eeb3a06758fdceebe2d923e"
            },
            "downloads": -1,
            "filename": "dnfile-0.15.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "14c75b999577e51bd41edbde29132e5f",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 46602,
            "upload_time": "2024-10-19T02:26:25",
            "upload_time_iso_8601": "2024-10-19T02:26:25.055998Z",
            "url": "https://files.pythonhosted.org/packages/69/82/80b8c2111eb37b59871d4df2ef826a7aaa8046f1dc021c56ebeaf7d98906/dnfile-0.15.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "8f896781fe5a1d623b9235f12a10cd76d7eba8458f950a83e861974d103a896d",
                "md5": "a515f67c92c1d2ab537be7db94bb7ebc",
                "sha256": "1529cf0f976b1382f60a3c56b2e0def90f3486e41193ffd34677e74563c8426c"
            },
            "downloads": -1,
            "filename": "dnfile-0.15.1.tar.gz",
            "has_sig": false,
            "md5_digest": "a515f67c92c1d2ab537be7db94bb7ebc",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 49703,
            "upload_time": "2024-10-19T02:26:26",
            "upload_time_iso_8601": "2024-10-19T02:26:26.821789Z",
            "url": "https://files.pythonhosted.org/packages/8f/89/6781fe5a1d623b9235f12a10cd76d7eba8458f950a83e861974d103a896d/dnfile-0.15.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-10-19 02:26:26",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "malwarefrank",
    "github_project": "dnfile",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "tox": true,
    "lcname": "dnfile"
}
        
Elapsed time: 0.65545s