For the complete documentation index, see llms.txt. This page is also available as Markdown.

NoNamed Mutation Engine

Previously on social media I discussed my work on a Polymorphic Mutation Engine, my implementation of it (known as encryption-based Polymorphism), and the general traits and features my code base possesses. This write-up will be a technical explanation of my code. It assumes you're familiar with some of the information present.


Dependencies and compilation

NoNamed contains no dependencies, omit NTDLL which is a requirement for binaries to work on Windows. NoNamed does load OLE32.DLL and VBSCRIPT.DLL for a brief moment to initialize COM components for the VBS payload demonstration. Everything else is manually reconstructed and built into the binary. This is not necessary for a proof-of-concept, but I enjoy the challenge. Sorry.

Library
Function
Custom Implementation

ucrtbase.dll

memset (ZeroMemory)

ZeroMemory2

ucrtbase.dll

wcslen

StringLengthW

ucrtbase.dll

strcmp

StringCompareA

kernel32.dll

CopyMemory

CopyMemoryEx

ucrtbase.dll

wcscat

StringConcatW

ucrtbase.dll

wcscopy

StringCopyW

kernel32.dll

MultiByteToWideChar

CharStringToWCharString

ucrtbase.dll

itoa

Uint32ToWcharString

ole32.dll

CoCreateInstance

RtlCreateVbsEngine

ucrtbase.dll

memcmp

MemoryCompare

ucrtbase.dll

rand

GetRandomIntegerKsecDDObject

kernel32.dll

GetProcAddress

ImportFunction

bcrypt.dll

BCryptOpenAlgorithmProvider

ChaChaInitializeContext

bcrypt.dll

BCryptBuffer

ChaChaBuffer

NoNamed mutates the .psdata section of the binary. Hence, it is specified to the compiler in the IDE for the creation of .psdata. The initial build of .psdata is the raw byes of a simple VBS script.

Additionally, to avoid the creation of a UI and a console Window, the subsystem to set to Windows, no default libraries are specified, and the entry point is modified to ensure the compiler doesn't insert security features which would introduce bloat to our application. Yes, this is generally dangerous. This is not best practices for general software develop. This is initially stripped to ensure the binary is as minimal as possible.

NoNamed flow overview

InitializeApiTable and InitializeMemoryManagementSystem:

Initialize API Table is fairly self-explanatory. NoNamed contains a structure of various NTDLL functionality required for this binary to operate. When the binary begins it programmatically walks the in-memory NTDLL Export Address Table and retrieves a pointer to any functionality required. A flaw in this implementation is it does not verify the first FLINK is NTDLL. In the instance it is replaced with an EDR and/or AV instance (hooking) it will fail. This does not perform indirect or direct SYSCALLs.

The API table contains a general usage variable (DWORD) at the base of the API table which is reserved for general usage (acting like RAX, omit it does not handle returns). To ensure all APIs were successfully loaded it verifies the pointers are valid by storing them in a temporary "VerificationTable" and iterates through them with an initial offset of size DWORD to skip past the GeneralUsage variable. GeneralUsage was intentionally placed at the base of the API table for this reason.

Note RtlAllocateHeap is not present. All memory is handled with a custom memory management system using NtAllocateVirtualMemory. I am in essence using an elementary heap manager. I am using the Arena algorithm. The primary difference is my implementation is stripped to the metaphorical bone because it does not require much heap usage. If you're curious read more here.

ChaChaInitializeContext:

ChaChaInitializeContext is a manual implementation of the ChaCha encryption algorithm. I am not a cryptographer. Nothing in this is extraordinarily novel. I manually introduced it into my code base to avoid external dependencies.

Last updated