D
DioProcess

Kernel Memory Dump

Ring 0

Dump process memory using kernel-level APIs to bypass usermode protections.

KsDumper-style

This feature uses MmCopyVirtualMemory for direct kernel-to-kernel memory transfer, similar to the KsDumper tool.

Overview

Protected processes (PPL, AV, EDR) often prevent memory reading via standard APIs like ReadProcessMemory. The kernel memory dump feature bypasses these restrictions by using MmCopyVirtualMemory directly from Ring 0.

Implementation

Kernel Copy Memory
NTSTATUS KernelCopyMemory(
    ULONG TargetProcessId,
    ULONG64 SourceAddress,
    ULONG64 DestinationAddress,  // In caller's process
    ULONG Size,
    PULONG BytesCopied
) {
    PEPROCESS SourceProcess;
    PEPROCESS CurrentProcess = PsGetCurrentProcess();
    SIZE_T NumberOfBytes = 0;
    
    // 1. Get target process EPROCESS
    NTSTATUS Status = PsLookupProcessByProcessId(
        (HANDLE)TargetProcessId,
        &SourceProcess
    );
    if (!NT_SUCCESS(Status)) return Status;
    
    // 2. Use MmCopyVirtualMemory for direct transfer
    // This function is undocumented but widely used
    Status = MmCopyVirtualMemory(
        SourceProcess,                      // Source process
        (PVOID)SourceAddress,               // Source address
        CurrentProcess,                     // Destination process (caller)
        (PVOID)DestinationAddress,          // Destination address
        (SIZE_T)Size,                       // Size to copy
        KernelMode,                         // Previous mode
        &NumberOfBytes                      // Bytes copied
    );
    
    *BytesCopied = (ULONG)NumberOfBytes;
    ObDereferenceObject(SourceProcess);
    
    return Status;
}

API

Usage
use callback::kernel_copy_memory;
use process::get_process_modules;

// Get main module info
let modules = get_process_modules(pid)?;
let main_module = &modules[0];  // First module is usually the main exe

// Allocate buffer for dump
let mut buffer = vec![0u8; main_module.size as usize];

// Read memory via kernel
let bytes_copied = kernel_copy_memory(
    pid,
    main_module.base_address,
    buffer.as_mut_ptr() as u64,
    buffer.len() as u32
)?;

// Save dump to file
std::fs::write("dump.bin", &buffer[..bytes_copied as usize])?;

Request Structures

Structures
struct KernelCopyMemoryRequest {
    ULONG TargetProcessId;      // Target process PID
    ULONG64 SourceAddress;      // Address in target to read
    ULONG64 DestinationAddress; // Address in caller's buffer
    ULONG Size;                 // Bytes to copy (max 64MB)
};

struct KernelCopyMemoryResponse {
    ULONG BytesCopied;
    BOOLEAN Success;
};

IOCTL

IOCTLCodeDescription
COPY_MEMORY0x00222180Copy memory from target process

What Can Be Dumped

  • ✓ Protected processes (AV, EDR)
  • ✓ PPL (Protected Process Light)
  • ✓ LSASS (credential dumping)
  • ✓ Processes with ObRegisterCallbacks protection
  • ✓ Any committed memory regions

UI Access

Right-click process → Miscellaneous → Kernel (Ring 0) → 📦 Dump Process

The dump operation:

  1. Gets the main module base address and size
  2. Allocates a buffer and calls kernel_copy_memory()
  3. Opens a save dialog for destination file
  4. Saves the raw memory dump to disk

PE Reconstruction

The dumped file is a raw memory dump, not a valid PE file. For static analysis:

  • IAT may need reconstruction — Imports are resolved to runtime addresses
  • Use PE-bear or Scylla — Tools to rebuild IAT from memory dump
  • Section alignment — Memory dump has section alignment, not file alignment

Limitations

  • • Maximum 64MB per request (larger dumps need multiple calls)
  • • Cannot dump non-committed memory
  • • PAGE_GUARD pages may cause issues
  • • Some kernel-protected memory still inaccessible

Use Cases

  • • Dump protected PE files from memory
  • • Credential extraction from LSASS
  • • Malware analysis of packed/protected samples
  • • Forensic collection of running process memory