MCPcopy Index your code
hub / github.com/DavidBuchanan314/monomorph

github.com/DavidBuchanan314/monomorph @v1.0

Chat with this repo
repository ↗ · DeepWiki ↗ · release v1.0 ↗ · + Follow
121 symbols 246 edges 19 files 23 documented · 19%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README



    ════════════════════════════════════╦═══    
     ╔═╦═╗ ╔═╗ ╔═╗ ╔═╗ ╔═╦═╗ ╔═╗ ╔══╔═╗ ╠═╗     
    ═╩ ╩ ╩═╚═╝═╩ ╩═╚═╝═╩ ╩ ╩═╚═╝═╩  ╠═╝═╩ ╩═    
    ════════════════════════════════╩═══════    
                                  By Retr0id    

    ═══ MD5-Monomorphic Shellcode Packer ═══    


USAGE: python3 monomorph.py input_file output_file [payload_file]

What does it do?

It packs up to 4KB of compressed shellcode into an executable binary, near-instantly. The output file will always have the same MD5 hash: 3cebbe60d91ce760409bbe513593e401

Currently, only Linux x86-64 is supported. It would be trivial to port this technique to other platforms, although each version would end up with a different MD5. It would also be possible to use a multi-platform polyglot file like APE.

Example usage:

$ python3 monomorph.py bin/monomorph.linux.x86-64.benign bin/monomorph.linux.x86-64.meterpreter sample_payloads/bin/linux.x64.meterpreter.bind_tcp.bin

Why?

People have previously used single collisions to toggle a binary between "good" and "evil" modes. Monomorph takes this concept to the next level.

Some people still insist on using MD5 to reference file samples, for various reasons that don't make sense to me. If any of these people end up investigating code packed using Monomorph, they're going to get very confused.

How does it work?

For every bit we want to encode, a colliding MD5 block has been pre-calculated using FastColl. As summarised here, each collision gives us a pair of blocks that we can swap out without changing the overall MD5 hash.

To encode 4KB of data, we need to generate 4*1024*8 collisions (which takes a few hours), which take up 4MB of space in the final file.

To speed this up, I made some small tweaks to FastColl to make it even faster in practice, enabling it to be run in parallel. I'm sure there are smarter ways to parallelise it, but my naive approach is to start N instances simultaneously and wait for the first one to complete, then kill all the others.

Since I've already done the pre-computation, reconfiguring the payload can be done near-instantly. Swapping the state of the pre-computed blocks is done using a technique implemented by Ange Albertini.

Is it detectable?

Yes. It's not very stealthy at all, nor does it try to be. You can detect the collision blocks using detectcoll.

Core symbols most depended-on inside this repo

xrng64
called by 94
fastcoll/main.hpp
GG
called by 48
fastcoll/main.hpp
RL
called by 48
fastcoll/main.hpp
FF
called by 22
fastcoll/main.hpp
RR
called by 22
fastcoll/main.hpp
md5_compress
called by 14
fastcoll/md5.cpp
save_block
called by 8
fastcoll/main.cpp
HH
called by 6
fastcoll/main.hpp

Shape

Function 94
Class 27

Languages

C++88%
Python7%
C5%

Modules by API surface

sample_payloads/linux_syscall_support.h83 symbols
fastcoll/main.cpp8 symbols
fastcoll/main.hpp7 symbols
loader/monomorph.c4 symbols
monomorph.py3 symbols
collisions.py3 symbols
fastercoll.py2 symbols
sample_payloads/rickroll.c1 symbols
sample_payloads/hashquine.c1 symbols
sample_payloads/elf_to_shellcode.py1 symbols
fastcoll/md5.cpp1 symbols
fastcoll/block1wang.cpp1 symbols

For agents

$ claude mcp add monomorph \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact