dncil
is a Common Intermediate Language (CIL
) disassembly library written in Python that supports parsing the header, instructions, and exception handlers of .NET
managed methods. Parsed data is exposed through an object-oriented API to help you quickly develop CIL
analysis tools using dncil
.
Why Python
? Existing libraries that support CIL
disassembly, like dnLib
, are written in C#
. To leverage these tools, you must build C#
applications which requires C#
development experience. Using dncil
, a pure Python
alternative, you:
- Do not need
C#
experience to analyzeCIL
programmatically. - Can quickly develop and test your
CIL
analysis tools. - Can easily integrate your
CIL
analysis tools with existingPython
projects.
The example script print_cil_from_dn_file.py
uses dncil
together with .NET
analysis library dnfile
to disassemble the managed methods found in a .NET
executable. Let's see what it can do.
First, we compile the following C#
source code:
using System;
public class HelloWorld
{
public static void Main(string[] args)
{
Console.WriteLine ("Hello World!");
}
}
Compilation results in a PE
executable containing .NET
metadata which informs the Common Language Runtime
(CLR
) how to execute our code. We use dnfile
to parse this metadata which gives us the offset of our managed method Main
. We then use dncil
to disassemble and display the CIL
instructions stored at this location.
Let's see the above in action:
$ python scripts/print_cil_from_dn_file.py hello-world.exe
Method: Main
0000 00 nop
0001 72 01 00 00 70 ldstr "Hello World!"
0006 28 04 00 00 0a call System.Console::WriteLine
000B 00 nop
000C 2a ret
Our method Main
is represented by the CilMethodBody
class. This class holds data that includes the header, CIL
instructions, and exception handlers of a given managed method. It also exposes various helper functions:
> main_method_body.flags
SmallFormat : false
TinyFormat : false
FatFormat : false
TinyFormat1 : true
MoreSects : false
InitLocals : false
CompressedIL : false
> main_method_body.size
14
> hexdump.hexdump(main_method_body.get_bytes())
00000000: 36 00 72 01 00 00 70 28 04 00 00 0A 00 2A 6.r...p(.....*
> hexdump.hexdump(main_method_body.get_header_bytes())
00000000: 36 6
> hexdump.hexdump(main_method_body.get_instruction_bytes())
00000000: 00 72 01 00 00 70 28 04 00 00 0A 00 2A .r...p(.....*
Each CIL
instruction found in our managed method Main
is represented by the Instruction
class. This class holds data that includes the offset, mnemonic, opcode, and operand of a given CIL
instruction. It also exposes various helper functions:
> len(main_method_body.instructions)
5
> insn = main_method_body.instructions[1]
> insn.offset
1
> insn.mnemonic
'ldstr'
> insn.operand
token(0x70000001)
> insn.is_ldstr()
True
> insn.size
5
> hexdump.hexdump(insn.get_bytes())
00000000: 72 01 00 00 70 r...p
> hexdump.hexdump(insn.get_opcode_bytes())
00000000: 72 r
> hexdump.hexdump(insn.get_operand_bytes())
00000000: 01 00 00 70 ...p
Download the dncil
source and run the following command from the root directory:
$ pip install .
To execute the example scripts be sure to install dnfile
. Alternatively, install dncil
with the development dependencies as described in the Testing
section below.
See print_cil_from_bytes.py for a quick example of using dncil
to print the CIL
instructions found in a byte stream containing a .NET
managed method.
Ensure you have installed dncil
with the development dependencies:
$ pip install .[dev]
Then invoke pytest:
$ python -m pytest tests/
Ensure you have installed dncil
with the development dependencies as described above.
Then:
$ pycodestyle --show-source dncil tests
$ python -m black -l 120 -c .
$ python -m isort --profile black --length-sort --line-width 120 -c .
dncil
is based on the CIL
parsing code found in dnLib
.