From 47daed9e8deb298713fbd641e1637dc10e81fb7d Mon Sep 17 00:00:00 2001 From: yotti Date: Thu, 30 Apr 2026 22:45:04 +0900 Subject: [PATCH 1/7] docs: fix installation section with correct repo URL and venv instructions --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 550d883..0d648f5 100644 --- a/README.md +++ b/README.md @@ -47,26 +47,26 @@ Optional (for `analyze`): | [Il2CppDumper](https://github.com/Perfare/Il2CppDumper) | IL2CPP symbol extraction | | `strings` | Native `.so` string extraction | -Optional Python extras: - -```bash -uv pip install "enma[unity]" # UnityPy for asset extraction -``` - --- ## Installation ```bash -git clone https://github.com/yourname/enma +git clone https://github.com/ykus4/enma cd enma uv sync ``` -Install git hooks for development: +Activate the virtual environment (optional — prefix commands with `uv run` instead): ```bash -uv run pre-commit install +source .venv/bin/activate +``` + +For Unity asset extraction, install the optional extra: + +```bash +uv pip install "enma[unity]" ``` --- From c3004351a64c4852c89141c3d3288c0ba6c7a717 Mon Sep 17 00:00:00 2001 From: yotti Date: Thu, 30 Apr 2026 22:46:00 +0900 Subject: [PATCH 2/7] docs: fix unity duplicate install note, repack requirements, and missing ue4 in layout --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 0d648f5..b11855e 100644 --- a/README.md +++ b/README.md @@ -212,6 +212,8 @@ uv run enma repack app.apk -o app-gadget.apk --arch arm64 | `--arch` | `arm64` (default) / `arm` / `x86_64` / `x86` | | `--keep-workdir` | Keep the intermediate smali directory | +Requires on `PATH`: `apktool`, `zipalign`, and `apksigner` (Android build-tools) or `jarsigner` (JDK). + Pipeline: 1. Download `frida-gadget-{ver}-android-{arch}.so.xz` → cached in `~/.cache/enma/` 2. `apktool d` — decode APK @@ -230,11 +232,7 @@ uv run enma unity uv run enma unity ./dump -o ./extracted ``` -Requires `UnityPy`: - -```bash -uv pip install "enma[unity]" -``` +Requires the `enma[unity]` extra (see [Installation](#installation)). Extracts from every `.unity3d` bundle in the dump directory: @@ -569,6 +567,7 @@ enma/ ├── bypass/ # ssl, crypto, anti_detect, anti_tamper, safetynet ├── network/ # http, websocket, protobuf, binder ├── storage/ # sqlite, fileio, dlopen + ├── ue4/ # ue4_sdk, ue4_pak, ue4_blueprint └── mem/ # memscan, mempatch ``` From 8512784161f705e06b7c3947b1dfdfabb4d7894f Mon Sep 17 00:00:00 2001 From: yotti Date: Thu, 30 Apr 2026 22:48:10 +0900 Subject: [PATCH 3/7] docs: add ue4 agents to architecture (agent count, categories, hook layers, dispatch map) --- docs/architecture.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/docs/architecture.md b/docs/architecture.md index b8689e3..849fdc9 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -54,7 +54,7 @@ enma is a two-process system: a **Python host** running on the analyst's machine ## Agent Categories -The 20 agents are grouped into 5 functional categories, each in its own subdirectory. +The 23 agents are grouped into 6 functional categories, each in its own subdirectory. ``` agents/ @@ -89,6 +89,11 @@ agents/ │ ├── fileio_agent.js File open/write/delete monitoring │ └── dlopen_agent.js Dynamic library load monitoring │ +├── ue4/ ← Unreal Engine 4 runtime analysis +│ ├── ue4_sdk_agent.js GNames/GUObjectArray dump → SDK JSON (UE4.23–4.27) +│ ├── ue4_pak_agent.js PAK file discovery and dump +│ └── ue4_blueprint_agent.js Blueprint ProcessEvent call tracer +│ └── mem/ ← Interactive memory manipulation ├── memscan_agent.js CheatEngine-style value scanner └── mempatch_agent.js Write / NOP / freeze memory @@ -209,6 +214,7 @@ enma mempatch com.example.game 0x7ff1a2b4 -t int32 -v 99999 │ "unity" ──► run_unity() ◄── unity.py │ │ "setup" ──► run_setup() ◄── device.py │ │ "repack" ──► run_repack() ◄── repack.py │ +│ "ue4" ──► run_ue4() ◄── ue4.py │ │ "list" ──► list_apps() │ └──────────────────────────────────────────────────────────────────┘ @@ -327,7 +333,10 @@ Each agent operates at one or more of the following hook layers: │ Layer 2: Native libraries │ │ Interceptor.attach(Module.findExportByName("libssl.so", …)) │ │ Interceptor.attach(Module.findExportByName("libcrypto.so", …)) │ -│ → ssl (BoringSSL), crypto (EVP_*), dlopen (libdl) │ +│ Interceptor.attach(Module.findExportByName("libUE4.so", …)) │ +│ → ssl (BoringSSL), crypto (EVP_*), dlopen (libdl), │ +│ ue4_sdk (GNames/GUObjectArray), ue4_pak (FPakFile), │ +│ ue4_blueprint (ProcessEvent) │ ├─────────────────────────────────────────────────────────────────┤ │ Layer 1: libc / syscall │ │ Interceptor.attach(Module.findExportByName("libc.so", "open")) │ From f40235afad81dd8f00dffa324f280b343c42ddde Mon Sep 17 00:00:00 2001 From: yotti Date: Thu, 30 Apr 2026 22:48:40 +0900 Subject: [PATCH 4/7] docs: fix misaligned ASCII art in system overview diagram --- docs/architecture.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/docs/architecture.md b/docs/architecture.md index 849fdc9..4238d7c 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -13,7 +13,7 @@ enma is a two-process system: a **Python host** running on the analyst's machine │ Analyst Machine │ │ │ │ ┌─────────────────────────────────────────────────────────────┐ │ -│ │ enma CLI (Python) │ │ +│ │ enma CLI (Python) │ │ │ │ │ │ │ │ cli.py ──► device.py (frida-server deploy) │ │ │ │ ──► repack.py (APK gadget injection) │ │ @@ -21,6 +21,7 @@ enma is a two-process system: a **Python host** running on the analyst's machine │ │ ──► analyze.py (post-dump analysis) │ │ │ │ ──► report.py (HTML report generation) │ │ │ │ ──► unity.py (AssetBundle extraction) │ │ +│ │ ──► ue4.py (UE4 runtime analysis) │ │ │ └────────────────────────┬────────────────────────────────────┘ │ │ │ Frida RPC / message bus │ │ │ (USB / TCP) │ @@ -37,15 +38,15 @@ enma is a two-process system: a **Python host** running on the analyst's machine │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ Target App Process │ │ │ │ │ │ -│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ -│ │ │ Java VM │ │ ART / JIT│ │ Native │ │ libc / │ │ │ -│ │ │ (Dalvik) │ │ (libart) │ │ Libs │ │ BoringSSL│ │ │ -│ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ │ -│ │ │ │ │ │ │ │ -│ │ └─────────────┴─────────────┴──────────────┘ │ │ -│ │ ▲ │ │ -│ │ Frida Interceptors │ │ -│ │ (JS agents injected) │ │ +│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ +│ │ │ Java VM │ │ ART / JIT│ │ Native │ │ libc / │ │ │ +│ │ │ (Dalvik) │ │ (libart) │ │ Libs │ │ BoringSSL│ │ │ +│ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ │ +│ │ │ │ │ │ │ │ +│ │ └─────────────┴─────────────┴──────────────┘ │ │ +│ │ ▲ │ │ +│ │ Frida Interceptors │ │ +│ │ (JS agents injected) │ │ │ └─────────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────┘ ``` From bced69667a8c169988ec444a94554a559fa52bf0 Mon Sep 17 00:00:00 2001 From: yotti Date: Thu, 30 Apr 2026 22:50:44 +0900 Subject: [PATCH 5/7] chore: add CircleCI config with ruff lint job --- .circleci/config.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .circleci/config.yml diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..648cf44 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,25 @@ +version: 2.1 + +jobs: + lint: + docker: + - image: cimg/python:3.12 + steps: + - checkout + - run: + name: Install uv + command: pip install uv --quiet + - run: + name: Install dependencies + command: uv sync + - run: + name: ruff check + command: uv run ruff check src/ + - run: + name: ruff format check + command: uv run ruff format --check src/ + +workflows: + ci: + jobs: + - lint From 81cfe7b2d1f04f8855f0f8885f5b495276d87fe5 Mon Sep 17 00:00:00 2001 From: yotti Date: Thu, 30 Apr 2026 22:53:06 +0900 Subject: [PATCH 6/7] chore: replace CircleCI with GitHub Actions lint workflow --- .circleci/config.yml | 25 ------------------------- .github/workflows/ci.yml | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 25 deletions(-) delete mode 100644 .circleci/config.yml create mode 100644 .github/workflows/ci.yml diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 648cf44..0000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,25 +0,0 @@ -version: 2.1 - -jobs: - lint: - docker: - - image: cimg/python:3.12 - steps: - - checkout - - run: - name: Install uv - command: pip install uv --quiet - - run: - name: Install dependencies - command: uv sync - - run: - name: ruff check - command: uv run ruff check src/ - - run: - name: ruff format check - command: uv run ruff format --check src/ - -workflows: - ci: - jobs: - - lint diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..b22edfd --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,18 @@ +name: CI + +on: + push: + branches: ["**"] + pull_request: + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: astral-sh/setup-uv@v5 + with: + python-version: "3.12" + - run: uv sync + - run: uv run ruff check src/ + - run: uv run ruff format --check src/ From 052ba3d97c49540e673c81a58426945d6a6e8430 Mon Sep 17 00:00:00 2001 From: yotti Date: Thu, 30 Apr 2026 22:54:38 +0900 Subject: [PATCH 7/7] style: fix ruff format violations in repack.py --- src/enma/repack.py | 48 ++++++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/src/enma/repack.py b/src/enma/repack.py index c30dc7d..9dc357b 100644 --- a/src/enma/repack.py +++ b/src/enma/repack.py @@ -84,14 +84,22 @@ def _ensure_debug_keystore(keystore: Path) -> None: logger.info("Generating debug keystore ...") keytool_args = [ "-genkeypair", - "-keystore", str(keystore), - "-alias", "androiddebugkey", - "-keyalg", "RSA", - "-keysize", "2048", - "-validity", "10000", - "-storepass", "android", - "-keypass", "android", - "-dname", "CN=Android Debug,O=Android,C=US", + "-keystore", + str(keystore), + "-alias", + "androiddebugkey", + "-keyalg", + "RSA", + "-keysize", + "2048", + "-validity", + "10000", + "-storepass", + "android", + "-keypass", + "android", + "-dname", + "CN=Android Debug,O=Android,C=US", ] _run("keytool", *keytool_args) @@ -137,20 +145,28 @@ def _sign_apk(signer: str, signer_path: str, src: Path, dest: Path, keystore: Pa _run( signer_path, "sign", - "--ks", str(keystore), - "--ks-pass", "pass:android", - "--key-pass", "pass:android", - "--ks-key-alias", "androiddebugkey", - "--out", str(dest), + "--ks", + str(keystore), + "--ks-pass", + "pass:android", + "--key-pass", + "pass:android", + "--ks-key-alias", + "androiddebugkey", + "--out", + str(dest), str(src), ) else: shutil.copy(src, dest) _run( signer_path, - "-keystore", str(keystore), - "-storepass", "android", - "-keypass", "android", + "-keystore", + str(keystore), + "-storepass", + "android", + "-keypass", + "android", str(dest), "androiddebugkey", )