build(devcontainer): Theos サイドカーコンテナと開発環境を整備

- Theos ビルド用サイドカーコンテナを追加 (.devcontainer/theos/)
- VSCode tasks.json に Theos ビルド・mitmproxy タスクを追加
- .envrc にデバイス IP / UIポート設定を追加
- .envrc.local.example を新規追加

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
tkgstrator
2026-04-07 02:04:41 +00:00
co-authored by Claude Opus 4.6
parent 3443ac2d50
commit 60f6a03024
10 changed files with 319 additions and 9 deletions
+42 -1
View File
@@ -1 +1,42 @@
FROM mcr.microsoft.com/devcontainers/python:dev-3.12
FROM mcr.microsoft.com/devcontainers/base:ubuntu-24.04
# ── Reverse Engineering Tools (apt) ──
# radare2 : ARM64 逆アセンブル・バイナリ解析 (Mach-O / ELF)
# apktool : Android APK リソース展開・smali 逆アセンブル
RUN \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
--mount=type=cache,target=/var/cache/apt,sharing=locked \
apt-get update && apt-get install -y \
wget \
unzip \
jq \
radare2 \
apktool
# ── jadx (GitHub Release) ──
# Android APK → Java 逆コンパイル (プラットフォーム非依存 JAR、JRE は devcontainer feature の Java で提供)
RUN JADX_URL=$(wget -qO- https://api.github.com/repos/skylot/jadx/releases/latest | jq -r '.assets[] | select(.name | test("^jadx-[0-9].*\\.zip$")) | .browser_download_url') && \
wget -q "$JADX_URL" -O /tmp/jadx.zip && \
unzip -q /tmp/jadx.zip -d /opt/jadx && \
ln -s /opt/jadx/bin/jadx /usr/local/bin/jadx && \
ln -s /opt/jadx/bin/jadx-gui /usr/local/bin/jadx-gui && \
rm /tmp/jadx.zip
# ── Ghidra (Headless) ──
# NSA 製リバースエンジニアリングツール。ヘッドレスモードで C++ 擬似コード生成に使用
# 使い方: analyzeHeadless /tmp/project name -import <binary>
RUN GHIDRA_URL=$(wget -qO- https://api.github.com/repos/NationalSecurityAgency/ghidra/releases/latest | jq -r '.assets[] | select(.name | test("PUBLIC.*\\.zip$")) | .browser_download_url') && \
wget -q "$GHIDRA_URL" -O /tmp/ghidra.zip && \
unzip -q /tmp/ghidra.zip -d /opt && \
GHIDRA_DIR=$(find /opt -maxdepth 1 -name 'ghidra_*' -type d) && \
ln -s "$GHIDRA_DIR" /opt/ghidra && \
rm /tmp/ghidra.zip
ENV PATH="/opt/ghidra/support:$PATH"
# ── ipsw ──
# Go 製 Mach-O 解析ツール。iOS バイナリの ObjC/Swift クラスダンプ、シンボル解析に使用
# 使い方: ipsw macho info <binary> --class-dump
RUN IPSW_URL=$(wget -qO- https://api.github.com/repos/blacktop/ipsw/releases/latest | jq -r '.assets[] | select(.name | test("^ipsw_.*linux_arm64\\.tar\\.gz$")) | .browser_download_url') && \
wget -q "$IPSW_URL" -O /tmp/ipsw.tar.gz && \
tar xzf /tmp/ipsw.tar.gz -C /usr/local/bin ipsw && \
rm /tmp/ipsw.tar.gz
+11
View File
@@ -6,6 +6,17 @@ services:
volumes:
- ../:/home/vscode/app:cached
- venv:/home/vscode/app/.venv
ports:
- 9080:9080
tty: true
stdin_open: true
theos:
build:
context: ./theos
dockerfile: Dockerfile
volumes:
- ../:/home/vscode/app:cached
tty: true
stdin_open: true
+32 -4
View File
@@ -1,5 +1,5 @@
{
"name": "Frida Container",
"name": "Mobile RE Toolkit",
"dockerComposeFile": [
"compose.yaml"
],
@@ -7,11 +7,18 @@
"workspaceFolder": "/home/vscode/app",
"shutdownAction": "stopCompose",
"remoteUser": "vscode",
"containerEnv": {
"CLAUDE_CONFIG_DIR": "/home/vscode/.claude"
},
"mounts": [
"source=${env:HOME}/home/vscode/.ssh,target=/.ssh,type=bind,consistency=cached,readonly"
"source=${env:HOME}/.aws,target=/home/vscode/.aws,type=bind,consistency=cached,readonly",
"source=${env:HOME}/.claude,target=/home/vscode/.claude,type=bind,consistency=cached",
"source=${env:HOME}/.ssh,target=/home/vscode/.ssh,type=bind,consistency=cached,readonly",
"source=${env:HOME}/.mitmproxy,target=/home/vscode/.mitmproxy,type=bind,consistency=cached"
],
"remoteEnv": {
"WAKATIME_API_KEY": "${localEnv:WAKATIME_API_KEY}",
"GH_TOKEN": "${localEnv:GH_TOKEN}",
"UV_LINK_MODE": "copy"
},
"features": {
@@ -21,10 +28,30 @@
"ghcr.io/devcontainers/features/common-utils:2": {
"configureZshAsDefaultShell": true
},
"ghcr.io/devcontainers/features/python:1": {
"version": "3.12"
},
"ghcr.io/devcontainers/features/github-cli:1": {},
"ghcr.io/jsburckhardt/devcontainer-features/uv:1": {},
"ghcr.io/christophermacgown/devcontainer-features/direnv:1": {}
"ghcr.io/stu-bell/devcontainer-features/claude-code:0": {},
"ghcr.io/christophermacgown/devcontainer-features/direnv:1": {},
"ghcr.io/devcontainers/features/node:1": {
"version": "25.9.0"
},
"ghcr.io/shyim/devcontainers-features/bun:0": {},
"ghcr.io/devcontainers/features/java:1": {
"version": "21",
"installMaven": false,
"installGradle": false
},
"ghcr.io/devcontainers/features/docker-in-docker:2": {
"moby": false
},
"ghcr.io/devcontainers/features/docker-outside-of-docker:1": {
"moby": false
}
},
"forwardPorts": [],
"postAttachCommand": "/bin/sh .devcontainer/postAttachCommand.sh",
"postCreateCommand": "/bin/sh .devcontainer/postCreateCommand.sh",
"customizations": {
@@ -45,10 +72,11 @@
"ms-python.python",
"pHofer94.vscode-taskviewexplorer",
"redhat.vscode-yaml",
"swiftlang.swift-vscode",
"tamasfe.even-better-toml",
"vsls-contrib.gitdoc"
],
"settings": {}
}
}
}
}
+50
View File
@@ -0,0 +1,50 @@
FROM mcr.microsoft.com/devcontainers/base:ubuntu-24.04
# ── Theos + Swift 依存パッケージ ──
RUN \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
--mount=type=cache,target=/var/cache/apt,sharing=locked \
apt-get update && apt-get install -y --no-install-recommends \
make \
perl \
fakeroot \
zip \
unzip \
xz-utils \
lzma \
libtinfo6 \
libxml2 \
libncurses6 \
libz3-dev
# ── Theos 本体 ──
USER vscode
ENV THEOS=/home/vscode/theos
RUN git clone --recursive https://github.com/theos/theos.git ${THEOS}
# ── Toolchain (L1ghtmann, aarch64 対応) ──
RUN ARCH=$(uname -m) && \
curl -fsSL "https://github.com/L1ghtmann/llvm-project/releases/latest/download/iOSToolchain-${ARCH}.tar.xz" \
| tar xJ -C ${THEOS}/toolchain
# ── Swift Toolchain (kabiroberai, iOS クロスコンパイル用) ──
RUN ARCH=$(uname -m) && \
curl -fsSL "https://github.com/kabiroberai/swift-toolchain-linux/releases/download/v2.3.0/swift-5.8-ubuntu22.04-${ARCH}.tar.xz" \
| tar xJ -C ${THEOS}/toolchain
# ── ホスト Swift (SPM ビルド用) ──
USER root
RUN ARCH=$(uname -m) && \
curl -fsSL "https://download.swift.org/swift-5.8.1-release/ubuntu2204-${ARCH}/swift-5.8.1-RELEASE/swift-5.8.1-RELEASE-ubuntu22.04-${ARCH}.tar.gz" \
| tar xz --strip-components=2 -C /usr
USER vscode
# ── iOS SDKs (15.6 + 16.5) ──
RUN curl -fsSL "https://github.com/theos/sdks/archive/master.tar.gz" \
| tar xz -C /tmp && \
mv /tmp/sdks-master/iPhoneOS15.6.sdk ${THEOS}/sdks/ && \
mv /tmp/sdks-master/iPhoneOS16.5.sdk ${THEOS}/sdks/ && \
rm -rf /tmp/sdks-master
# ── ビルド用作業ディレクトリ ──
WORKDIR /home/vscode/app
+6
View File
@@ -1,5 +1,11 @@
source .venv/bin/activate
source_env_if_exists .envrc.local
dotenv
export GIT_AUTHOR_NAME="${GIT_AUTHOR_NAME:-$(git config user.name)}"
export GIT_AUTHOR_EMAIL="${GIT_AUTHOR_EMAIL:-$(git config user.email)}"
export GIT_COMMITTER_NAME="${GIT_COMMITTER_NAME:-$(git config user.name)}"
export GIT_COMMITTER_EMAIL="${GIT_COMMITTER_EMAIL:-$(git config user.email)}"
alias frida-trace="frida-trace -H $HOST --ui-port $UI_PORT"
alias frida-ps="frida-ps -H $HOST"
+9
View File
@@ -0,0 +1,9 @@
# リポジトリ別にGitHub CLIのアカウントを切り替えたい場合のみ設定
# 未設定ならホスト側の GH_TOKEN が使われます
# export GH_TOKEN=ghp_your_token_here
# 必要な場合のみ設定(未設定なら ~/.gitconfig の値が使われます)
# export GIT_AUTHOR_NAME="Your Name"
# export GIT_AUTHOR_EMAIL="you@example.com"
# export GIT_COMMITTER_NAME="Your Name"
# export GIT_COMMITTER_EMAIL="you@example.com"
+22
View File
@@ -265,18 +265,40 @@ $RECYCLE.BIN/
*.apk
*.ipa
*.dylib
*.mp4
# Extracted / dumped
extracted_ipa/
extracted_apk/
# Assets (large binaries)
assets/
# Logs & captures
logs/
raws/
cache/
output/
cookie.txt
cookies.txt
headers.md
capture.ndjson
console.log
# Locks
uv.lock
# Secrets / env
.env
.envrc.local
secrets/
# Node.js (frida-compile toolchain)
node_modules/
# Frida compiled output
packages/frida/*.js
!packages/frida/src/**/*.js
# Chrome extension build output
packages/chrome-extension/dist/
+7 -1
View File
@@ -11,5 +11,11 @@
],
"gitdoc.pushMode": "push",
"gitdoc.timeZone": "Asia/Tokyo",
"gitlens.ai.generateCommitMessage.customInstructions": "Generate a commit message in Japanese following the Conventional Commits specification and `commitlint` rules. Use the format `<type>(<scope>): <short description>` and choose `<type>` from `build`, `ci`, `docs`, `feat`, `fix`, `perf`, `chore`, `refactor`, `revert`, `format`, `test`. Limit `<short description>` to 72 characters. If `<short description>` starts with an English word, it must be in lowercase."
"gitlens.ai.generateCommitMessage.customInstructions": "Generate a commit message in Japanese following the Conventional Commits specification and `commitlint` rules. Use the format `<type>(<scope>): <short description>` and choose `<type>` from `build`, `ci`, `docs`, `feat`, `fix`, `perf`, `chore`, `refactor`, `revert`, `format`, `test`. Limit `<short description>` to 72 characters. If `<short description>` starts with an English word, it must be in lowercase.",
"files.exclude": {
"**/__pycache__": true,
"**/.venv": true,
"**/.ruff_cache": true,
"**/cache": true
}
}
+132
View File
@@ -0,0 +1,132 @@
{
"version": "2.0.0",
"tasks": [
// ── Build ──
{
"label": "frida: build (iOS)",
"type": "shell",
"command": "npm run build:ios",
"options": { "cwd": "${workspaceFolder}/packages/frida" },
"group": "build",
"problemMatcher": []
},
{
"label": "frida: build (Android)",
"type": "shell",
"command": "npm run build:android",
"options": { "cwd": "${workspaceFolder}/packages/frida" },
"group": "build",
"problemMatcher": []
},
{
"label": "frida: build (Chrome CDM)",
"type": "shell",
"command": "npm run build:chrome",
"options": { "cwd": "${workspaceFolder}/packages/frida" },
"group": "build",
"problemMatcher": []
},
{
"label": "chrome-extension: build",
"type": "shell",
"command": "bun run build",
"options": { "cwd": "${workspaceFolder}/packages/chrome-extension" },
"group": "build",
"problemMatcher": []
},
// ── Watch ──
{
"label": "frida: watch (iOS)",
"type": "shell",
"command": "npm run watch:ios",
"options": { "cwd": "${workspaceFolder}/packages/frida" },
"isBackground": true,
"problemMatcher": []
},
{
"label": "frida: watch (Android)",
"type": "shell",
"command": "npm run watch:android",
"options": { "cwd": "${workspaceFolder}/packages/frida" },
"isBackground": true,
"problemMatcher": []
},
// ── Run (Hook) ──
{
"label": "frida: hook iOS (Netflix)",
"type": "shell",
"command": "uv run python tools/run.py packages/frida/hook_netflix.js",
"dependsOn": "frida: build (iOS)",
"group": {
"kind": "test",
"isDefault": true
},
"presentation": {
"reveal": "always",
"panel": "dedicated",
"clear": true
},
"problemMatcher": []
},
{
"label": "frida: hook Android (Netflix)",
"type": "shell",
"command": "uv run python tools/run.py --android packages/frida/hook_netflix_android.js",
"dependsOn": "frida: build (Android)",
"group": "test",
"presentation": {
"reveal": "always",
"panel": "dedicated",
"clear": true
},
"problemMatcher": []
},
// ── Tweak (Theos) ──
{
"label": "tweak: build",
"type": "shell",
"command": "docker compose -f .devcontainer/compose.yaml exec theos make -C /home/vscode/app/${relativeFileDirname}",
"group": "build",
"problemMatcher": []
},
{
"label": "tweak: clean",
"type": "shell",
"command": "docker compose -f .devcontainer/compose.yaml exec theos make -C /home/vscode/app/${relativeFileDirname} clean",
"problemMatcher": []
},
{
"label": "tweak: package",
"type": "shell",
"command": "docker compose -f .devcontainer/compose.yaml exec theos make -C /home/vscode/app/${relativeFileDirname} package",
"group": "build",
"problemMatcher": []
},
// ── Proxy ──
{
"label": "mitmproxy: Netflix iOS capture",
"type": "shell",
"command": "uv run mitmdump --listen-port 9080 --set block_global=false --ssl-insecure -s packages/mitmproxy/netflix_ios_capture.py",
"isBackground": true,
"presentation": {
"reveal": "always",
"panel": "dedicated",
"clear": true
},
"problemMatcher": []
},
{
"label": "frida: hook Chrome CDM",
"type": "shell",
"command": "uv run python tools/run_chrome_cdm.py",
"dependsOn": "frida: build (Chrome CDM)",
"group": "test",
"presentation": {
"reveal": "always",
"panel": "dedicated",
"clear": true
},
"problemMatcher": []
}
]
}
+8 -3
View File
@@ -11,8 +11,8 @@ dependencies = [
"colorama>=0.4.6",
"cryptography>=46.0.5",
"enum34>=1.1.10",
"frida>=17.8.0",
"frida-tools>=14.6.1",
"frida>=17.9.1",
"frida-tools>=14.8.1",
"idna>=3.11",
"ipaddress>=1.0.23",
"objection>=1.12.3",
@@ -27,7 +27,12 @@ dependencies = [
"six>=1.17.0",
"tqdm>=4.67.3",
"wcwidth>=0.6.0",
"protobuf>=3.19.0,<3.21.0",
"protobuf>=4.25.1,<5.0.0",
"pycryptodome>=3.20.0",
"cbor2>=5.8.0",
"pywidevine>=1.8.0",
"lief>=0.17.6",
"unicorn>=2.1.4",
"capstone>=5.0.7",
"mitmproxy>=12.2.1",
]