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.
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