Skip to main content

Command Palette

Search for a command to run...

APT Earth Baxia - Charon Ransomware: An In-Depth Analysis

Updated
APT Earth Baxia - Charon Ransomware:  An In-Depth Analysis

Charon is a sophisticated ransomware strain associated with the Earth Baxia APT group. This report dissects its TTPs end‑to‑end: DLL sideloading, multi‑layer shellcode staging, process hollowing into svchost.exe, pre‑encryption anti‑recovery/defense‑impairment, hybrid Curve25519+ChaCha20 encryption, and post‑encryption artifacts.


I. Earth Baxia's DLL Sideloading and Payload Injection Techniques

File NameSHA-256 Hash
Edge.exe5d0675f20eeb8f824097791711135a273680f77bf5e9f0e168074e97464f21b5
msedge.dlle0a23c0d99c45d40f6ef99c901bacf04bb12e9a3a15823b663b392abadd2444e
DumpStack.log739e2cac9e2a15631c770236b34ba569aad1d1de87c6243f285bf1995af2cdc2
  • A new ransomware dubbed Charon has been observed in targeted attacks against public sector and Middle Eastern aviation. The intrusion leverages DLL sideloading and closely resembles previously documented Earth Baxia campaigns (Trend Micro Earth Baxia).

  • A legitimate binary renamed to Edge.exe (originally cookie_exporter.exe) loads a malicious msedge.dll (SWORDLDR). That DLL decrypts and launches the ransomware payload staged in DumpStack.log.

High-level execution chain:

1. File msedge.dll Analysis

  • The malicious DLL is sideloaded by Edge.exe. Standard DLL load sequence is followed: map image, resolve imports, run TLS callbacks, and invoke DllEntryPoint(...).

  • msedge.dll is heavily obfuscated. DllEntryPoint(...) dispatches via an array of function pointers including function_pointer_1[0], [1], and notably [2], which transfers execution into the primary workflow (hereafter named fn_main_flow() for traceability).

  • The functions behind function_pointer_1[0] and [1] perform undetermined behavior; they most likely exist primarily for obfuscation .

  • Following the obfuscation routines, the program’s primary execution flow proceeds with two steps:

    • It checks for the presence of DumpStack.log, reads and decodes the file into payload_shellcode_layer_1. During this operation the code also performs anti-debug checks.

    • It resolves the Windows API functions whose names are embedded at the start of the decoded blob, and then executes the stage-1 shellcode (payload_shellcode_layer_1).

  • The routine reconstructs the full path to DumpStack.log, opens it, and reads contents into a heap buffer via CreateFileA, GetFileSize, and ReadFile. The decoded structure yields Windows API name strings, the target process path C:\Windows\System32\svchost.exe, and payload_shellcode_layer_1.

'Kernel32.dll',0,
'CreateProcessA',0,
'VirtualAllocEx',0,
'WriteProcessMemory',0,
'GetThreadContext',0,
'SetThreadContext',0,
'ResumeThread',0,
'VirtualProtectEx',0,
'C:\\Windows\\System32\\svchost.exe;W1'
  • Decoding logic used for DumpStack.log - Script Python:
// Per-byte transform
b = (~b) & 0xFF;   // 1) NOT
b ^= 0x2E;         // 2) XOR 0x2E
b = (0x100 - b) & 0xFF; // 3) 8-bit NEG
return b;

#!/usr/bin/env python3

import argparse
from pathlib import Path


def transform_byte(b: int) -> int:
    # 1) NOT
    b = (~b) & 0xFF
    # 2) XOR với 0x2E
    b ^= 0x2E
    # 3) NEG 8-bit: (0x100 - AL) & 0xFF
    b = (0x100 - b) & 0xFF
    return b


def decode_file(in_path: Path, out_path: Path, chunk_size: int = 1 << 20) -> None:
    """Đọc DumpStack.log, giải mã theo 3 bước, ghi ra data.bin."""
    with in_path.open("rb") as fin, out_path.open("wb") as fout:
        while True:
            chunk = fin.read(chunk_size)
            if not chunk:
                break
            buf = bytearray(chunk)
            for i in range(len(buf)):
                buf[i] = transform_byte(buf[i])
            fout.write(buf)


def main():
    ap = argparse.ArgumentParser(
        description="Decryption DumpStack.log => data.bin (NOT => XOR 0x2E => NEG)"
    )
    ap.add_argument("input", help="Path DumpStack.log (input)")
    ap.add_argument("-o", "--output", default="data.bin", help="Path data.bin (output)")
    ap.add_argument(
        "--chunk", type=int, default=1 << 20, help="Chunk size (default 1MB)"
    )
    args = ap.parse_args()

    in_path = Path(args.input)
    out_path = Path(args.output)

    if not in_path.is_file():
        raise SystemExit(f"File not found: {in_path}")

    decode_file(in_path, out_path, args.chunk)
    print(f"[OK] Decrypted: {in_path} -> {out_path}")


if __name__ == "__main__":
    main()

###########################################################
# python decode_dumpstack.py "DumpStack.log" -o data.bin
###########################################################
  • Anti‑Debug routine (invoked within the DumpStack.log decoder) inspects whether the process is under a debugger.

  • After decoding DumpStack.log, fn_main_flow() splits the blob by delimiter ; (0x3B) to extract target API names and then resolves them (e.g., CreateProcessA, VirtualAllocEx, ...).

  • The DLL performs process injection using CreateProcessA (suspended) + WriteProcessMemory + VirtualProtectEx + SetThreadContext + ResumeThread into C:\Windows\System32\svchost.exe to run payload_shellcode_layer_1.

  • This constitutes process hollowing: the thread context’s RIP in _CONTEXT is set to the address of the injected shellcode in svchost.exe. For x64, RIP is located at offset 0xF8 within _CONTEXT (see Microsoft docs - https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-context) .

StartupInfo.cb = 0x68;
memset(&StartupInfo.lpReserved, 0, 0x60);
CreateProcessA(0i64, strTargetProcess, 0i64, 0i64, 0, CREATE_SUSPENDED, 0i64, 0i64, &StartupInfo, &ProcessInformation);
pTargetProcessAddr = VirtualAllocEx(ProcessInformation.hProcess, 0i64, dwScSize, MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(ProcessInformation.hProcess, pTargetProcessAddr, shellCodePtr, dwScSize, 0i64);
VirtualProtectEx(ProcessInformation.hProcess, pTargetProcessAddr, dwScSize, PAGE_EXECUTE_READWRITE, flOldProtect);
threadCtx.ContextFlags = CONTEXT_FULL;
GetThreadContext(ProcessInformation.hThread, &threadCtx);
threadCtx.Rip = pTargetProcessAddr;
SetThreadContext(ProcessInformation.hThread, &threadCtx);
LODWORD(g_val_0x1_1) = ResumeThread(ProcessInformation.hThread);

2. Payload_Shellcode Analysis

  • To analyze payload_shellcode_layer_1, attach IDA to the target svchost.exe process. While debugging msedge.dll, dump the shellcode blob from memory and use shellcode2exe to compile/package that blob into a .exe file — analyzing the resulting .exe in IDA will be much easier.
import idaapi
import binascii

start_address = 0x000001932CC382C0
end_address = start_address + 0x000000000000F1B2
data = idaapi.get_bytes(start_address, 0x000000000000F1B2)

with open("dumped_data.bin", "wb") as f:
    f.write(data)
    print("Success dump file data!")
.\shellcode2exe.bat 64 dumped_data.bin payload_shellcode_layer_1.exe
  • At start, the shellcode resolves ntdll!LdrLoadDll, NtAllocateVirtualMemory, NtProtectVirtualMemory, and NtFreeVirtualMemory to manage staging buffers: allocate → copy/decode payload → switch to RX → cleanup.
// Structs and main() excerpt (abbrev.)
struct MW_API_INFO {               // sizeof=0x28
  INT64 LdrLoadDll;
  INT64 NtAllocateVirtualMemory;
  INT64 NtProtectVirtualMemory;
  INT64 NtFreeVirtualMemory;
  INT64 ntdllBaseAddr;
};

// ...locate ntdll via PEB->Ldr->InLoadOrderModuleList (hash 0x3729C0C)
// ...resolve exports via name-hash (BKDR*131 + tolower-style transform)
  • Locating ntdll: iterate PEB->Ldr->InLoadOrderModuleList, hash BaseDllName, compare to constant 0x3729C0C. API resolution walks the Export Table, hashing names with BKDR(131) and a custom tolower (if c <= 0x60 then c += 0x20).
// Exact decompiled pseudocode for the name-hash
uint32_t hash(const char* s, int len /*0 = null-terminated*/) {
    uint32_t h = 0; size_t i = 0;
    do {
        unsigned char c = s[i];
        if (!len && c == 0) break;      // until '\0' if len==0
        if (c) {
            if (c <= 0x60) c += 0x20;   // quirky tolower
            h = h*131 + c;              // BKDR(131)
        }
        ++i;
    } while (!len || i != (size_t)len);
    return h;
}
  • The shellcode constructs a MW_DATA_INFO object aggregating multiple blobs (shellcode, metadata, module/API hash info, XOR key, etc.), allocates a working buffer, and decodes/decompresses the next stage.

// Example before/after decoding of a metadata area
// Before:
// 0000000000252A23 0B 83 75 7C 68 F3 78 A8 2C 15 9E 9C 1B AE 6C FB ..u|hóx¨,....®lû
// 0000000000252A33 88 06 4F 30 77 65 88 00 00 00 BC 3F 34 AF 45 17 ..O0we....¼?4¯E.

// After:
// 0000000000252A23 6E 74 64 6C 6C 00 6B 65 72 6E 65 6C 33 32 00 6D ntdll.kernel32.m
// 0000000000252A33 73 76 63 72 74 00 88 00 00 00 BC 3F 34 AF 45 17 svcrt.....¼?4¯E.
  • It then resolves 0x22 APIs from ntdll/kernel32/msvcrt using the discovered hash table, including a notable function:
API hash: 0xD3471745 --> API found: RtlDecompressBuffer  // decompression
API hash: 0x88487882 --> API found: RtlInitAnsiString
API hash: 0x99478AD4 --> API found: RtlInitUnicodeString
// ... full hash list kept below in the original content
  • Interpretation: payload_shellcode_layer_1 serves as a stager that decrypts/decompresses payload_shellcode_layer_2 and supplies it with an embedded final payload blob (Charon PE).

  • Stage‑2 (payload_shellcode_layer_2) begins by XOR‑decoding and calling RtlDecompressBuffer to produce the Charon PE in memory. The PE is not dropped to disk; execution remains in‑memory.

  • Stage‑2 then process‑hollows again, updating thread RIP via NtSetContextThread to point at the PE’s entry/main.

  • Selected API hashes resolved by stage‑2 for injection/execution:

API hash: 0x35F50C56 --> API found: NtFreeVirtualMemory
API hash: 0x95F0B5C5 --> API found: NtGetContextThread
API hash: 0x8CEBABFE --> API found: NtOpenThread
API hash: 0x03D52223 --> API found: NtProtectVirtualMemory
API hash: 0xAF343FBC --> API found: NtReleaseMutant
API hash: 0x24D2D549 --> API found: NtResumeThread
API hash: 0xAFBD9CC9 --> API found: NtSetContextThread
API hash: 0x2BFE68AE --> API found: NtSignalAndWaitForSingleObject
API hash: 0x1D290EF0 --> API found: NtSuspendThread
API hash: 0x18537BC1 --> API found: NtTerminateThread
  • Tip: dump the in‑memory Charon_Ransomware PE while attached to svchost.exe (dumping from stage‑1 sometimes miscalculates file size due to e_lfanew patching issues).

  • If SizeOfImage is unknown, compute file size from headers . Below is the calculation logic and a Python dump script:

address_MZ = 0xABCDEFGH

addr_e_lfanew = address_MZ + 0x3C

value_e_lfanew = 4 byte little edian at addr_e_lfanew

addr_PE_header = address_MZ + value_e_lfanew

addr_number_of_section = addr_PE_header + 4 + 2

value_number_of_section = 2 bytes little edian at addr_number_of_section

offset_from_first_section_to_last_section = 0x28 \* (value_number_of_section - 1)

addr_first_section = addr_PE_header + 0x108

addr_last_section = addr_first_section + offset_from_first_section_to_last_section

addr_size_of_raw_data = addr_last_section + 0x10

addr_pointer_to_raw_data = addr_last_section + 0x14

size_of_raw_data = 4 byte little edian at addr_size_of_raw_data

pointer_to_raw_data = 4 byte little edian at addr_pointer_to_raw_data

file_size = size_of_raw_data + pointer_to_raw_data

===>>> dump byte to file start addr address_MZ to (address_MZ + file_size)
import struct
import ida_bytes

try:
    import idc  # để đọc RAM khi đang debug
except Exception:
    idc = None


def read_mem(ea, size):
    # RAM (debugger)
    if idc is not None:
        try:
            b = idc.read_dbg_memory(ea, size)
            if b:
                return b
        except Exception:
            pass
    # IDB
    return ida_bytes.get_bytes(ea, size)


def u16_at(ea):
    b = read_mem(ea, 2)
    if not b or len(b) < 2:
        raise RuntimeError(f"Không đọc được 2 bytes tại 0x{ea:X}")
    return struct.unpack_from("<H", b, 0)[0]


def u32_at(ea):
    b = read_mem(ea, 4)
    if not b or len(b) < 4:
        raise RuntimeError(f"Không đọc được 4 bytes tại 0x{ea:X}")
    return struct.unpack_from("<I", b, 0)[0]


def dump_pe_by_last_section(address_MZ, out_path):
    # Kiểm tra 'MZ'
    mz = read_mem(address_MZ, 2)
    if mz != b"MZ":
        raise RuntimeError(f"Không thấy 'MZ' tại 0x{address_MZ:X}")

    # addr_e_lfanew = address_MZ + 0x3C
    addr_e_lfanew = address_MZ + 0x3C
    value_e_lfanew = u32_at(addr_e_lfanew)

    # addr_PE_header = address_MZ + value_e_lfanew
    addr_PE_header = address_MZ + value_e_lfanew
    sig = read_mem(addr_PE_header, 4)
    if sig != b"PE\x00\x00":
        raise RuntimeError(f"Không thấy 'PE\\0\\0' tại 0x{addr_PE_header:X}")

    # addr_number_of_section = addr_PE_header + 4 + 2
    addr_number_of_section = addr_PE_header + 4 + 2
    value_number_of_section = u16_at(addr_number_of_section)
    if value_number_of_section == 0:
        raise RuntimeError("NumberOfSections = 0 (bất thường)")

    # offset_from_first_section_to_last_section = 0x28 * (value_number_of_section - 1)
    offset_from_first_section_to_last_section = 0x28 * (value_number_of_section - 1)

    # addr_first_section = addr_PE_header + 0x108   (theo logic bạn đưa)
    # LƯU Ý: 0x108 = 0x18 (COFF) + 0xF0 (SizeOfOptionalHeader cho PE32+)
    addr_first_section = addr_PE_header + 0x108

    # addr_last_section = addr_first_section + offset_from_first_section_to_last_section
    addr_last_section = addr_first_section + offset_from_first_section_to_last_section

    # addr_size_of_raw_data / addr_pointer_to_raw_data
    addr_size_of_raw_data = addr_last_section + 0x10
    addr_pointer_to_raw_data = addr_last_section + 0x14

    size_of_raw_data = u32_at(addr_size_of_raw_data)
    pointer_to_raw_data = u32_at(addr_pointer_to_raw_data)

    # file_size = size_of_raw_data + pointer_to_raw_data
    file_size = size_of_raw_data + pointer_to_raw_data
    if file_size <= 0:
        raise RuntimeError(f"Kích thước tính ra không hợp lệ: 0x{file_size:X}")

    # Dump bytes từ address_MZ đến address_MZ + file_size
    data = read_mem(address_MZ, file_size)
    if not data or len(data) < file_size:
        # Nếu đọc thiếu (do vùng RAM/segment chưa map), pad 0 phần còn lại
        have = len(data) if data else 0
        data = (data or b"") + b"\x00" * (file_size - have)

    with open(out_path, "wb") as f:
        f.write(data)

    print("[OK] Dumped by last section logic")
    print(f"    MZ @ 0x{address_MZ:X}")
    print(f"    PE @ 0x{addr_PE_header:X}")
    print(f"    NumberOfSections = {value_number_of_section}")
    print(f"    LastSectionHeader @ 0x{addr_last_section:X}")
    print(f"    SizeOfRawData = 0x{size_of_raw_data:X}")
    print(f"    PointerToRawData = 0x{pointer_to_raw_data:X}")
    print(f"    -> file_size = 0x{file_size:X} bytes")
    print(f"    Written: {out_path}")


# ================== CÁCH GỌI ==================
# Đặt địa chỉ MZ thực tế và đường dẫn output ở đây:
address_MZ = 0x000002889BD13098
out_path = r"C:\Users\trant\Desktop\APTxx\malware\CharonRansomware.exe"
dump_pe_by_last_section(address_MZ, out_path)

II. Technical analysis of the Charon Ransomware

Final payload (encryptor):

File NameSHA-256 Hash
Charon_Ransomware.exe80711e37f226ef1dc86dc80a8cbc0b2ec895b361e9ade85da793d94b1d876be8

1. Anti-Detection & Anti-Recovery (Pre-Encryption Behaviors)

  • On launch, Charon_Ransomware.exe accepts arguments for debug logging, network share enumeration, and path scoping. --sf (Shares First) inverts the default order (shares before local disks).
ArgumentDescription
--debug=<path\to\logfile>Enable error logging to the specified file. Logs errors across the encryption routine.
--shares=<host_or_ip_list>Enumerate target servers/IPs and encrypt accessible shares on those hosts (excluding ADMIN$).
--paths=<specific_paths>Restrict encryption to specific local paths (C:\folder) or drive letters (D:).
--sfShares First: prioritize network shares first, then local disks. Without this flag, default is local disks first, then shares.
  • A mutex OopsCharonHere ensures single‑instance execution. Before encryption, Charon executes a comprehensive preparation/impairment sequence:

    • Stop or release services that may hold/lock files (SQL/Oracle DBs, VSS, Veeam, Commvault, Backup Exec, Acronis, QuickBooks, etc.).

    • Terminate processes that keep files open (Office apps, browsers, mail clients, DB/backup tools) to free handles.

    • Impair defenses by stopping security services (Symantec, Sophos, Qihoo 360, etc.) and admin agents.

    • Remove recovery artifacts: delete Volume Shadow Copies, backup catalogs/metadata; empty Recycle Bin.

    • Initialize multi‑threading (based on CPU core count) to accelerate encryption.

  • Services commonly targeted for stopping (non‑exhaustive):

Service-NameDescription
vssVolume Shadow Copy Service
sqlMicrosoft SQL Server
svc$Hidden service/share name (abused by malware)
memtasMEMTAS (legacy AV/endpoint; frequent in kill‑lists)
mepocsMcAfee ePO Cloud/Agent
sophosSophos Endpoint Protection
veeamVeeam Backup & Replication
backupGeneric backup service
GxVss, GxBlr, GxFWD, GxCVD, GxCIMgrCommvault components
DefWatch, ccEvtMgr, ccSetMgr, SavRoam, RTVscanSymantec components
QBFCService, QBIDPService, Intuit.QuickBooks.FCS, QBCFMonitorServiceQuickBooks components
YooBackup, YooITYoo backup/IT services
zhudongfangyuQihoo 360 Proactive Defense
stc_raw_agentStorageCraft Raw Agent
VSNAPVSSvSnap VSS Provider
VeeamTransportSvc, VeeamDeploymentService, VeeamNFSSvcVeeam components
PDVFSServiceParagon virtual FS service
BackupExec*Veritas/Symantec Backup Exec components
AcrSch2Svc, AcronisAgentAcronis components
CASAD2DWebSvc, CAARCUpdateSvcCA ARCserve services
  • Processes commonly terminated prior to encryption (non‑exhaustive):

Process-NameDescription
sql.exeMicrosoft SQL tooling
oracle.exe, ocssd.exe, dbsnmp.exe, agntsvc.exe, isqlplussvc.exe, ocomm.exeOracle/DB/agent components
synctime.exeTime sync/enterprise utility
xfssvccon.exeXerox file system service controller
mydesktopservice.exe, mydesktopqos.exeEnterprise desktop agents
ocautoupds.exeOracle/OC auto‑update
encsvc.exeEncryption/Indexing (often Symantec/Nuance)
firefox.exe, thunderbird.exe, tbirdconfig.exe, steam.exeUser apps likely to hold files
excel.exe, infopath.exe, msaccess.exe, mspub.exe, onenote.exe, outlook.exe, powerpnt.exe, visio.exe, winword.exeMicrosoft Office apps
wordpad.exe, notepad.exeEditors
  • Recovery inhibition via COM/VSS requires Administrator privileges. During analysis, map relevant COM interfaces (vss.h, vsbackup.h).

  • Threading: the malware queries CPU core count and launches multiple worker threads for parallel encryption.

2. Encryption Logic Analysis

  • The core routine filters candidate files and encrypts them.

  • Skips specific extensions/names to avoid self‑bricking and noise:

- ".exe"

- ".dll"

- ".Charon"

- "How To Restore Your Files.txt"

  • Files are encrypted, renamed with the .Charon extension, and a marker string hCharon is enter to the urworld! is appended.

  • Hybrid scheme: Curve25519 (X25519) + ChaCha20.

    • Generate a random 32‑byte private key via Windows crypto.

  • Derive a public key, combine with a hard‑coded attacker public key to compute a shared secret (ECDH). Hash/derive a 256‑bit key and initialize a (modified) ChaCha20 stream cipher to encrypt file content.

  • Each encrypted file appends a 72‑byte footer with the victim’s public key and encryption metadata to enable later decryption.

  • Partial encryption policy to balance speed vs. impact:

    • ≤ 64 KB: encrypt entire file.

    • 64 KB–5 MB: encrypt 3 blocks (start ~0%, middle ~50%, tail ~75%).

    • 5 MB–20 MB: encrypt 5 evenly spaced blocks.

    • 20 MB: encrypt 7 blocks at ~0%, 12.5%, 25%, 50%, 75%, 87.5%, and near end.

  • Code excerpt showing partial‑encryption application and 72‑byte footer emission:

  • Finally, Charon drops a ransom note How To Restore Your Files.txt to all drives, network shares, and folders.

3. Other Behaviors Beyond Encryption

  • Lateral impact: actively enumerates network shares using NetShareEnum and WNetEnumResource, processes mapped drives and UNC paths, while skipping ADMIN$ to reduce attention during discovery.

  • EDR bypass package (dormant in this build): the payload bundle contains a driver compiled from dark-kill, intended to disable EDRs. The code to drop %SystemRoot%\System32\Drivers\WWC.sys and register a service WWC exists but was not invoked at runtime in the analyzed sample-likely an unfinished feature reserved for future variants.

  • Overview of features in development.


III. IOC and MITRE-ATT&CK Framework

  • The DumpStack.log decoder uniquely fingerprints Earth Baxia’s staging. Identifying this algorithm helps cluster related samples.

1. IoC Table

SHA256 HashDetectionDescription
80711e37f226ef1dc86dc80a8cbc0b2ec895b361e9ade85da793d94b1d876be8Ransom.Win64.CHARON.THGBCBEPayload (Charon Ransomware)
739e2cac9e2a15631c770236b34ba569aad1d1de87c6243f285bf1995af2cdc2Ransom.Win64.CHARON.A.encShellcode (DumpStack.log)
e0a23c0d99c45d40f6ef99c901bacf04bb12e9a3a15823b663b392abadd2444eTrojan.Win64.SWORDLDR.THGBCBESWORDLDR (msedge.dll)
8e6b1aa03a28590eac9b5ef0e58f37849169ca47c8990e7d34525000e5759402Ransom.Win64.CHARON.A.noteRansom note dropped after encryption (How To Restore Your Files.txt) - contains payment instructions, victim ID, and TOR/contacts

2. MITRE-ATT&CK Framework

Mapping Windows API/Interface ↔ ATT&CK ID ↔ Observed Behavior:

Windows API / Interface (examples)MITRE ATT&CK (ID - Name)Observed in Charon
Netapi32!NetShareEnumT1135 - Network Share DiscoveryEnumerate network shares (mapped drives/UNC), encrypt accessible shares; skip ADMIN$.
Mpr!WNetOpenEnum / WNetEnumResourceT1135 - Network Share DiscoveryScan network resources to propagate encryption scope.
Kernel32!CreateMutexW (mutex: OopsCharonHere)T1480.002 - Execution Guardrails: Mutual ExclusionSingle instance control.
COM/VSS: CoInitializeExCoCreateInstance(CLSID_VSSBackupComponents)IVssBackupComponents::DeleteSnapshotsT1490 - Inhibit System RecoveryDelete shadow copies via COM to hinder recovery.
Shell32!SHEmptyRecycleBinWT1070.004 - Indicator Removal: File DeletionEmpty Recycle Bin.
Advapi32!OpenSCManagerW / OpenServiceW / ControlServiceWT1489 - Service Stop & T1562.001 - Impair Defenses: Disable or Modify ToolsStop security/backup services.
Kernel32!OpenProcess / TerminateProcessT1562.001 - Impair Defenses: Disable or Modify ToolsTerminate AV/EDR‑related processes.
Advapi32!CreateServiceW / StartServiceW (driver registration)T1543.003 - Create or Modify System Process: Windows ServiceDrop %SystemRoot%\System32\Drivers\WWC.sys and register service WWC (present but not executed in the analyzed run).
LoadLibraryW / ntdll!LdrLoadDllT1574.002 - Hijack Execution Flow: DLL Side‑LoadingChain: Edge.exe sideloads malicious msedge.dll (SWORDLDR) → stage payload.
CreateProcess(... CREATE_SUSPENDED) + VirtualAllocEx / WriteProcessMemory / SetThreadContext / ResumeThreadT1055.012 - Process Injection: Process HollowingInject/hollow into svchost.exe and transfer control to staged shellcode/PE.
CNG/CryptoAPI (e.g., BCryptGenRandom; custom X25519+ChaCha20 implementation)T1486 - Data Encrypted for ImpactGenerate 32‑byte private key → ECDH with attacker pubkey → derive 256‑bit key → modified ChaCha20 → partial encryption + 72‑byte footer.

IV. Resource References