dncil - CIL Disassembler
dncil is an open-source Python library developed by the FLARE team to disassemble Common Intermediate Language (CIL) instructions. It supports parsing the header, instructions, and exception handlers of .NET managed methods, exposing the data through an object-oriented API. The library is currently at version 1.0.2 and receives minor bug fixes and improvements with each release.
Common errors
-
dncil.cil.error.MethodBodyFormatError: invalid method body format
cause The byte stream provided to `CilMethodBodyReader` does not conform to the expected structure of a CIL method body, indicating corrupted data, an incorrect starting offset, or non-CIL input.fixVerify that the input byte stream is indeed a valid CIL method body and that the offset used to initialize `CilMethodBodyReader` is correct. If extracting from a PE file, ensure `dnfile` (or similar) is used correctly. -
ModuleNotFoundError: No module named 'dncil.cil.body'
cause The `dncil` library is either not installed in the current Python environment, or the environment is not correctly configured to locate installed packages.fixEnsure `dncil` is installed by running `pip install dncil`. If using a virtual environment, confirm it is activated. Check `pip freeze` to see if `dncil` is listed. -
AttributeError: 'CilMethodBodyReader' object has no attribute 'read_some_data'
cause An attempt was made to call a method or access an attribute on a `CilMethodBodyReader` object that does not exist or is misspelled, often indicating a misunderstanding of the API.fixConsult the `dncil` documentation or source code for the correct API to read data, such as `read()`, `read_u8()`, `read_i32()`, `read_token()`, etc. Ensure method names and arguments match the library's interface.
Warnings
- gotcha Prior to `v1.0.1`, `dncil` might have incorrectly read CIL branch targets and 8-, 32-, and 64-bit constants as unsigned integers. `v1.0.1` corrected this behavior to read them as signed integers, aligning with the CIL specification.
- breaking Starting with `v1.0.2`, `dncil` now explicitly raises `dncil.cil.error.MethodBodyFormatError` when encountering invalid or malformed CIL method bodies. Previously, such conditions might have resulted in generic `Exception`s or undefined behavior.
- gotcha While `dncil` is capable of disassembling raw CIL bytes, it does not handle parsing the broader .NET Portable Executable (PE) file format. To extract CIL method bodies from .NET executables, you will typically need to use `dncil` in conjunction with a PE parsing library like `dnfile`.
Install
-
pip install dncil
Imports
- CilMethodBody
from dncil.cil.body import CilMethodBody
- CilMethodBodyReader
from dncil.cil.body.reader import CilMethodBodyReader
- Instruction
from dncil.cil.instruction import Instruction
- MethodBodyFormatError
from dncil.cil.error import MethodBodyFormatError
Quickstart
from dncil.cil.body import CilMethodBody
from dncil.cil.body.reader import CilMethodBodyReader
from dncil.cil.enums import InstructionPrefix, OpCode
# Example CIL bytes for a simple method that returns 5
# (e.g., ldarg.0, ret or ldc.i4.5, ret)
# This is a simplified example; real CIL bytes often come from a PE file.
# For a full .NET executable, you would typically use `dnfile` to extract method bytes.
simple_cil_bytes = bytes([
OpCode.LDC_I4_S.value, 0x05, # ldc.i4.s 5
OpCode.RET.value # ret
])
# Create a reader for the CIL bytes
reader = CilMethodBodyReader(simple_cil_bytes, 0)
# Parse the method body
try:
method_body = CilMethodBody(reader)
print(f"Method has {len(method_body.instructions)} instructions:")
for i, insn in enumerate(method_body.instructions):
print(f" {i:04X} {hex(insn.offset):<8} {insn.opcode.name:<15} {insn.operand}")
except Exception as e:
print(f"Error disassembling CIL: {e}")