• Stars
    star
    1,536
  • Rank 30,468 (Top 0.7 %)
  • Language
    C
  • License
    BSD 2-Clause "Sim...
  • Created almost 7 years ago
  • Updated 7 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Fileless ring 3 rootkit with installer and persistence that hides processes, files, network connections, etc.

r77 Rootkit

Ring 3 rootkit

r77 is a ring 3 rootkit that hides everything:

  • Files, directories
  • Processes & CPU usage
  • Registry keys & values
  • Services
  • TCP & UDP connections
  • Junctions, named pipes, scheduled tasks

Hiding by prefix

Everything that starts with "$77" is hidden.

Configuration System

The dynamic configuration system allows to hide processes by PID and by name, file system items by full path, TCP & UDP connections of specific ports, etc.

The configuration is located in HKEY_LOCAL_MACHINE\SOFTWARE\$77config and is writable by any process without elevated privileges. The DACL of this key is set to grant full access to any user.

In addition, the $77config key is hidden by the rootkit.

Installer

The deployment of r77 requires only one file: Install.exe. Execution persists r77 on the system and injects all running processes.

Uninstall.exe removes r77 from the system completely, and gracefully.

Install.shellcode is the shellcode equivalent of the installer. This way, the installation can be integrated without dropping Install.exe. The shellcode can simply be loaded into memory, casted to a function pointer, and executed:

int main()
{
	// 1. Load Install.shellcode from resources or from a BYTE[]
	// Ideally, encrypt the file and decrypt it here to avoid scantime detection.
	LPBYTE shellCode = ...

	// 2. Make the shellcode RWX.
	DWORD oldProtect;
	VirtualProtect(shellCode, shellCodeSize, PAGE_EXECUTE_READWRITE, &oldProtect);

	// 3. Cast the buffer to a function pointer and execute it.
	((void(*)())shellCode)();

	// This is the fileless equivalent to executing Install.exe.

	return 0;
}

Fileless persistence

The rootkit resides in the system memory and does not write any files to the disk. This is achieved in multiple stages.

Stage 1: The installer creates two scheduled tasks for the 32-bit and the 64-bit r77 service. The scheduled tasks start powershell.exe with following command line:

[Reflection.Assembly]::Load([Microsoft.Win32.Registry]::LocalMachine.OpenSubkey('SOFTWARE').GetValue('$77stager')).EntryPoint.Invoke($Null,$Null)

The command is inline and does not require a .ps1 script. Here, the .NET Framework capabilities of PowerShell are utilized in order to load a C# executable from the registry and execute it in memory. For this, Assembly.Load().EntryPoint.Invoke() is used.

Stage 2: The executed C# binary is the stager. It will create the r77 service processes using process hollowing. The r77 service is a native executable compiled in both 32-bit and 64-bit separately. The parent process is spoofed and set to winlogon.exe for additional obscurity. In addition, the two processes are hidden by ID and are not visible in the task manager.

No executables or DLL's are ever stored on the disk. The stager is stored in the registry and loads the r77 service executable from its resources.

The PowerShell and .NET dependencies are present in a fresh installation of Windows 7 and Windows 10. Please review the documentation for a complete description of the fileless initialization.

Child process hooking

When a process creates a child process, the new process is injected before it can run any of its own instructions. The function NtResumeThread is always called when a new process is created. Therefore, it's a suitable target to hook. Because a 32-bit process can spawn a 64-bit child process and vice versa, the r77 service provides a named pipe to handle child process injection requests.

In addition, there is a periodic check every 100ms for new processes that might have been missed by child process hooking. This is necessary because some processes are protected and cannot be injected, such as services.exe.

In-memory injection

The rootkit DLL (r77-x86.dll and r77-x64.dll) can be injected into a process from memory and doesn't need to be stored on the disk. Reflective DLL injection is used to achieve this. The DLL provides an exported function that when called, loads all sections of the DLL, handles dependency loading and relocations, and finally calls DllMain.

Hooking

Detours is used to hook several functions from ntdll.dll. These low-level syscall wrappers are called by any WinAPI or framework implementation.

  • NtQuerySystemInformation
  • NtResumeThread
  • NtQueryDirectoryFile
  • NtQueryDirectoryFileEx
  • NtEnumerateKey
  • NtEnumerateValueKey
  • EnumServiceGroupW
  • EnumServicesStatusExW
  • NtDeviceIoControlFile

AV/EDR evasion

Several AV and EDR evasion techniques are in use:

  • AMSI bypass: The PowerShell inline script disables AMSI by patching amsi.dll!AmsiScanBuffer to always return AMSI_RESULT_CLEAN. Polymorphism is used to evade signature detection of the AMSI bypass.
  • DLL unhooking: Since EDR solutions monitor API calls by hooking ntdll.dll, these hooks need to be removed by loading a fresh copy of ntdll.dll from disk and restoring the original section. Otherwise, process hollowing would be detected.

Test environment

The Test Console is a useful tool to inject r77 into individual processes and to test drive the configuration system.

Technical Documentation

Please read the technical documentation to get a comprehensive and full overview of r77 and its internals, and how to deploy and integrate it.

Downloads

r77 Rootkit 1.4.3.zip (ZIP Password: bytecode77)
Technical Documentation

Project Page

bytecode77.com/r77-rootkit