Skip to content

CCNODE22/memloader

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MemLoader is a proof-of-concept framework for running native PE executables or .NET assemblies entirely from memory. It ships with two independent loaders:

Loader Purpose
pe-loader Reflectively loads and runs a native PE (.exe)
dotnet-loader Hosts the CLR and executes a managed assembly

Both loaders can be built either as a console EXE or as a DLL.


Features

  • In-memory execution – no payload ever touches disk once the loader starts.
  • RC4 payload encryption – use Common/Encrypt.py to encrypt your binary and generate the header file included at build time.
  • Evasion techniques
    • Indirect system-call stubs for every Nt* API
    • Obfuscated, lazy reconstruction of the "LoadLibraryA" string on a worker thread
    • dotnet-loader only
      • AMSI & ETW are patched with hardware breakpoints (HWBP)
      • BaseThreadInitThunk in ntdll.dll is redirected so every newly-created thread starts with the same hooks
      • CPU context is taken with RtlCaptureContext and set via NtContinue, avoiding Nt{Get|Set}ContextThread detections
      • DOS headers of unbacked memory regions are wiped to defeat Get-ClrReflection.ps1 heuristics

Repository prerequisites

  • Visual Studio 2022 with the LLVM/Clang-cl toolset (except for dotnet-loader, which uses MSVC to leverage mscorlib.tlb for COM interop).
  • Windows 10 x64 or later (tested on 22H2).

Preparing an encrypted payload

# Encrypt a PE or .NET assembly with RC4
python Common/Encrypt.py -p /path/to/payload.exe -o Payload.h

Then copy the Payload in the correct header file in visual studio project.

DLL & Shellcode specification

The loaders implement a Cobalt Strike-compatible Reflective DLL entry point.

__declspec(dllexport) bool WINAPI DllMain
(
	_In_	HINSTANCE	hinstDLL,
	_In_	DWORD		fdwReason,
	_In_	LPVOID		lpvReserved
)
{
	switch (fdwReason)
	{
	case DLL_PROCESS_ATTACH:
		return true;
		break;

	case DLL_THREAD_ATTACH:
		break;

	case DLL_THREAD_DETACH:
		break;

	case 0x4:
		Run();
		break;

	case 0x0d:	//  DLL_BEACON_USER_DATA
		break;

	case DLL_PROCESS_DETACH:
		if (lpvReserved != nullptr)
		{
			break;
		}

		break;
	}
	return true;
}

As you can see, a cobaltstrike reflective dll uses it to execute the DLL :

// DLL post-ex
DllMainAddress(Base, DLL_PROCESS_ATTACH, nullptr);
DllMainAddress(Base, 0x4,              nullptr);

// DLL beacon
DllMainAddress(Base, 0xD,              nullptr); // DLL_BEACON_USER_DATA
DllMainAddress(Base, DLL_PROCESS_ATTACH, nullptr);
DllMainAddress(Base, 0x4,                nullptr);

Converting a DLL to shellcode

python Shellcode.py -u /path/to/udrl.bin -d /path/to/dll.dll -o /path/to/output.bin

Note

Not all UDRLs are stable with this project; some crash for reasons yet unknown. Confirmed working combinations: OdinLdr → dotnet-loader.dll KaynStrike → pe-loader (payload-dependent) and dotnet-loader

A reflective loader may be added in the future.

Passing arguments to the payload

  • dotnet-loader :Edit Main.cc, variable std::wstring AssemblyArgs (top of Run).
  • pe-loader : Edit Main.cc, variable std::string PeArgs (top of Run).

Compilation

  • Debug : Make an exe, printf is present during compilation. Debug with printf > all
  • Release : Make an exe, printf is excluse
  • DLL : Make an dll, printf is excluse

Credit

About

Run native PE or .NET executables entirely in-memory. Build the loader as an .exe or .dll—DllMain is Cobalt Strike UDRL-compatible

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • C++ 99.4%
  • Other 0.6%