reverse-skills-max: initial public release (restored, redacted, hardened)
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
Apache License 2.0 — see the repository root LICENSE file for the full text.
|
||||
|
||||
Copyright the AnalystAIPack contributors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
@@ -0,0 +1,90 @@
|
||||
---
|
||||
name: analyzing-java-jar-malware
|
||||
description: 'Analyzes Java/JAR malware (such as Adwind/jRAT-class cross-platform RATs) by
|
||||
inventorying the archive, reading the manifest entry point, detecting obfuscators and string
|
||||
encryption, and flagging suspicious runtime, reflection, and networking class usage. Activates
|
||||
for requests to analyze a malicious JAR, inspect Java malware, or identify a Java RAT.'
|
||||
domain: cybersecurity
|
||||
subdomain: reverse-engineering
|
||||
tags:
|
||||
- reverse-engineering
|
||||
- java
|
||||
- jar
|
||||
- rat
|
||||
- decompilation
|
||||
version: 1.0.0
|
||||
author: analyst-ai-pack
|
||||
license: Apache-2.0
|
||||
mitre_attack:
|
||||
- T1059
|
||||
- T1027
|
||||
- T1620
|
||||
d3fend:
|
||||
- D3-SDA
|
||||
- D3-DA
|
||||
references:
|
||||
- 'JAR/ZIP and Java class file format — https://docs.oracle.com/javase/specs/jvms/se17/html/'
|
||||
- 'MITRE ATT&CK T1027 Obfuscated Files or Information — https://attack.mitre.org/techniques/T1027/'
|
||||
---
|
||||
|
||||
# Analyzing Java/JAR Malware
|
||||
|
||||
## When to Use
|
||||
|
||||
- You have a malicious or suspicious `.jar` (often a cross-platform RAT) and need to map its
|
||||
structure, entry point, obfuscation, and capability surface before decompiling.
|
||||
- You want to triage a Java payload without running the JVM.
|
||||
|
||||
**Do not use** `java -jar` to run it — that executes the malware. Treat the JAR as a ZIP and read
|
||||
its contents statically.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- The JAR file, read inertly. Optional: a Java decompiler (CFR, Procyon) for the next stage.
|
||||
|
||||
## Safety & Handling
|
||||
|
||||
- Read the archive statically; never launch the JVM on the sample. Defang any URLs found.
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Inventory the archive and entry point
|
||||
|
||||
```bash
|
||||
python scripts/analyst.py inspect sample.jar
|
||||
```
|
||||
|
||||
Lists `.class` files, embedded resources/payloads (nested JARs, scripts, encrypted blobs), and
|
||||
reads `META-INF/MANIFEST.MF` for `Main-Class`/`Premain-Class`.
|
||||
|
||||
### Step 2: Detect obfuscation and packers
|
||||
|
||||
Flags obfuscator fingerprints (Allatori, ProGuard, Zelix), single-character class/package names,
|
||||
and string-decryption indicators.
|
||||
|
||||
### Step 3: Flag capability classes
|
||||
|
||||
Surface dangerous API usage in strings/constant pools: `Runtime.exec`/`ProcessBuilder`,
|
||||
`java.lang.reflect`, `URLClassLoader`, `javax.crypto`, `java.net.Socket`, registry/persistence
|
||||
helpers.
|
||||
|
||||
### Step 4: Route to decompilation
|
||||
|
||||
Hand the key classes to a decompiler (CFR/Procyon) for source recovery; record IOCs.
|
||||
|
||||
## Validation
|
||||
|
||||
- The manifest entry point is read and reported.
|
||||
- Embedded payloads/nested archives are enumerated.
|
||||
- Capability flags are backed by concrete class/string evidence.
|
||||
|
||||
## Pitfalls
|
||||
|
||||
- String-encrypted samples where capability strings appear only after decryption.
|
||||
- Multi-stage droppers that unpack a second JAR at runtime.
|
||||
- Benign obfuscated commercial JARs — corroborate with capability and delivery context.
|
||||
|
||||
## References
|
||||
|
||||
- See [`references/api-reference.md`](references/api-reference.md) for the inspector.
|
||||
- JVM/JAR format and ATT&CK T1027 references (linked in frontmatter).
|
||||
@@ -0,0 +1,38 @@
|
||||
# API Reference: Analyzing Java/JAR Malware
|
||||
|
||||
## Overview
|
||||
|
||||
`scripts/analyst.py` treats a JAR as a ZIP and inventories `.class` files and embedded payloads,
|
||||
reads the manifest entry point, detects obfuscator fingerprints and name obfuscation, and scans
|
||||
class constant pools for dangerous API usage. It reads the archive statically, never launches the
|
||||
JVM, and defangs URLs.
|
||||
|
||||
## Dependencies
|
||||
|
||||
| Package | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| (stdlib) | — | zipfile, regex, JSON, file IO |
|
||||
| CFR / Procyon | optional | decompile recovered classes downstream (not required here) |
|
||||
|
||||
## Core functions
|
||||
|
||||
### `inspect(path)`
|
||||
Returns class count, `Main-Class`, embedded payloads, resources, obfuscators, a name-obfuscation
|
||||
flag, capability APIs, and defanged URLs.
|
||||
|
||||
## Capability APIs flagged
|
||||
|
||||
`Runtime`/`ProcessBuilder` (exec), `java.lang.reflect` + `URLClassLoader` (reflective loading),
|
||||
`javax.crypto` (encryption), `java.net.Socket`/`URL` (networking), `java.awt.Robot` (surveillance).
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
python scripts/analyst.py inspect sample.jar
|
||||
```
|
||||
|
||||
## Sources
|
||||
|
||||
- JVM specification (class file format, constant pool) — https://docs.oracle.com/javase/specs/jvms/se17/html/
|
||||
- JAR/ZIP structure and `MANIFEST.MF` `Main-Class` from the Java platform documentation
|
||||
- Obfuscator fingerprints (Allatori/ProGuard/Zelix) from public Java-malware analyses
|
||||
@@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Inspect a Java/JAR sample statically: structure, manifest, obfuscation, capabilities.
|
||||
|
||||
Treats the JAR as a ZIP, inventories .class files and embedded payloads, reads the manifest entry
|
||||
point, and scans class bytes for obfuscator fingerprints and dangerous API usage. Reads the archive
|
||||
statically; never launches the JVM. Defangs URLs.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
|
||||
EMBED_SIGS = [(b"PK\x03\x04", "nested ZIP/JAR"), (b"MZ", "PE executable"),
|
||||
(b"#!", "script"), (b"\x7fELF", "ELF")]
|
||||
OBFUSCATORS = [b"allatori", b"proguard", b"zelix", b"klassmaster", b"stringer", b"dasho"]
|
||||
CAPABILITY_APIS = [b"java/lang/Runtime", b"java/lang/ProcessBuilder", b"java/lang/reflect",
|
||||
b"java/net/URLClassLoader", b"javax/crypto", b"java/net/Socket",
|
||||
b"java/net/URL", b"java/awt/Robot", b"java/util/Base64"]
|
||||
RE_URL = re.compile(rb"https?://[\x21-\x7e]{4,}")
|
||||
|
||||
|
||||
def _defang(s: str) -> str:
|
||||
return s.replace("http", "hxxp").replace(".", "[.]")
|
||||
|
||||
|
||||
def inspect(path: str) -> dict:
|
||||
data = Path(path).read_bytes()
|
||||
result: dict = {"is_jar": False}
|
||||
if not zipfile.is_zipfile(path):
|
||||
return {"error": "not a ZIP/JAR archive"}
|
||||
result["is_jar"] = True
|
||||
classes = []
|
||||
resources = []
|
||||
manifest = ""
|
||||
obf = set()
|
||||
caps = set()
|
||||
urls = set()
|
||||
nested = []
|
||||
with zipfile.ZipFile(path) as zf:
|
||||
for name in zf.namelist():
|
||||
if name.endswith(".class"):
|
||||
classes.append(name)
|
||||
try:
|
||||
body = zf.read(name)
|
||||
except Exception:
|
||||
continue
|
||||
for o in OBFUSCATORS:
|
||||
if o in body.lower():
|
||||
obf.add(o.decode())
|
||||
for api in CAPABILITY_APIS:
|
||||
if api in body:
|
||||
caps.add(api.decode().replace("/", "."))
|
||||
for u in RE_URL.findall(body):
|
||||
urls.add(_defang(u.decode("latin-1", "ignore")))
|
||||
elif name == "META-INF/MANIFEST.MF":
|
||||
manifest = zf.read(name).decode("latin-1", "ignore")
|
||||
else:
|
||||
resources.append(name)
|
||||
try:
|
||||
head = zf.read(name)[:8]
|
||||
except Exception:
|
||||
head = b""
|
||||
for sig, label in EMBED_SIGS:
|
||||
if head.startswith(sig):
|
||||
nested.append({"name": name, "type": label})
|
||||
main_class = ""
|
||||
for line in manifest.splitlines():
|
||||
if line.lower().startswith(("main-class:", "premain-class:")):
|
||||
main_class = line.split(":", 1)[1].strip()
|
||||
break
|
||||
# single-character class names suggest name obfuscation
|
||||
short_names = sum(1 for c in classes if len(Path(c).stem) <= 2)
|
||||
return {
|
||||
"is_jar": True,
|
||||
"class_count": len(classes),
|
||||
"main_class": main_class,
|
||||
"embedded_payloads": nested[:50],
|
||||
"resources": resources[:50],
|
||||
"obfuscators": sorted(obf),
|
||||
"name_obfuscation_suspected": short_names > max(3, len(classes) // 5),
|
||||
"capability_apis": sorted(caps),
|
||||
"urls": sorted(urls)[:50],
|
||||
}
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
parser = argparse.ArgumentParser(description="Inspect a Java/JAR sample")
|
||||
sub = parser.add_subparsers(dest="cmd", required=True)
|
||||
p = sub.add_parser("inspect")
|
||||
p.add_argument("file")
|
||||
args = parser.parse_args(argv)
|
||||
print(json.dumps(inspect(args.file), indent=2))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user