feat: add Windows RE plugin and multi-agent support for 9 coding agents - Add Windows reverse engineering plugin (Ghidra + ILSpy) - PowerShell scripts: check-deps, install-dep, decompile, find-api-calls - Ghidra headless Jython export script (ExportDecompiled.py) - Reference docs: setup guide, Ghidra/ILSpy CLI, API patterns, call flows - Add agent instruction files for Codex, Cursor, Copilot, Cline, Windsurf, Roo Code, Aider, OpenCode - Add universal installer (install.ps1 / install.sh) with interactive agent selection - Add AGENTS.md as universal agent instruction standard - Update README with multi-agent support and installer usage
This commit is contained in:
parent
ddeb9bc332
commit
c1dd4f7e8c
|
|
@ -0,0 +1,5 @@
|
|||
# Aider configuration for reverse engineering skills
|
||||
# AGENTS.md is auto-loaded as context for every session
|
||||
|
||||
read:
|
||||
- AGENTS.md
|
||||
|
|
@ -22,6 +22,19 @@
|
|||
"license": "Apache-2.0",
|
||||
"keywords": ["android", "reverse-engineering", "apk", "jadx", "decompile", "api-extraction"],
|
||||
"category": "security"
|
||||
},
|
||||
{
|
||||
"name": "windows-reverse-engineering",
|
||||
"source": "./plugins/windows-reverse-engineering",
|
||||
"description": "Decompile Windows EXE/DLL/.NET assemblies with Ghidra and ILSpy, trace call flows, and document extracted Win32/network APIs.",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "Simone Avogadro"
|
||||
},
|
||||
"repository": "https://github.com/SimoneAvogadro/android-reverse-engineering-skill",
|
||||
"license": "Apache-2.0",
|
||||
"keywords": ["windows", "reverse-engineering", "exe", "dll", "ghidra", "ilspy", "decompile", "pe-analysis", "api-extraction"],
|
||||
"category": "security"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
# Android Reverse Engineering
|
||||
|
||||
Decompile Android APK, XAPK, JAR, and AAR files using jadx and Fernflower/Vineflower. Extract Retrofit endpoints, OkHttp calls, hardcoded URLs, and authentication patterns.
|
||||
|
||||
## Dependencies
|
||||
|
||||
Run the dependency checker before decompiling:
|
||||
```bash
|
||||
bash plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/check-deps.sh
|
||||
```
|
||||
|
||||
Required: Java JDK 17+, jadx.
|
||||
Optional: Fernflower/Vineflower, dex2jar, apktool.
|
||||
|
||||
Install missing:
|
||||
```bash
|
||||
bash plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/install-dep.sh <dep>
|
||||
```
|
||||
|
||||
## Workflow
|
||||
|
||||
1. **Check deps**: `check-deps.sh` → outputs `INSTALL_REQUIRED:<dep>` for missing tools
|
||||
2. **Decompile**: `decompile.sh <file>` with `--engine jadx|fernflower|both`, `--deobf`
|
||||
3. **Analyze**: Review AndroidManifest.xml, package structure, architecture patterns
|
||||
4. **Trace flows**: Follow Activity → ViewModel → Repository → Retrofit/OkHttp → HTTP
|
||||
5. **Extract APIs**: `find-api-calls.sh <dir>` with `--retrofit`, `--okhttp`, `--urls`, `--auth`
|
||||
|
||||
## Script Locations
|
||||
|
||||
All scripts are at: `plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/`
|
||||
- `check-deps.sh` — verify dependencies
|
||||
- `install-dep.sh` — install a dependency
|
||||
- `decompile.sh` — main decompile wrapper
|
||||
- `find-api-calls.sh` — API call search
|
||||
|
||||
## Reference Documentation
|
||||
|
||||
- `plugins/android-reverse-engineering/skills/android-reverse-engineering/references/setup-guide.md`
|
||||
- `plugins/android-reverse-engineering/skills/android-reverse-engineering/references/jadx-usage.md`
|
||||
- `plugins/android-reverse-engineering/skills/android-reverse-engineering/references/fernflower-usage.md`
|
||||
- `plugins/android-reverse-engineering/skills/android-reverse-engineering/references/api-extraction-patterns.md`
|
||||
- `plugins/android-reverse-engineering/skills/android-reverse-engineering/references/call-flow-analysis.md`
|
||||
|
||||
## Output Format
|
||||
|
||||
Document each API endpoint as:
|
||||
```markdown
|
||||
### `METHOD /api/endpoint`
|
||||
- **Source**: ClassName.java:42
|
||||
- **Retrofit**: @POST("/api/endpoint")
|
||||
- **Headers**: Authorization: Bearer {token}
|
||||
- **Body**: { "key": "value" }
|
||||
- **Called from**: Activity → ViewModel → Repository → ApiService
|
||||
```
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
# Windows Reverse Engineering
|
||||
|
||||
Decompile Windows EXE, DLL, SYS, and .NET assemblies using Ghidra (native PE → C pseudocode) and ILSpy (.NET → C# source). Auto-detects binary type and selects the appropriate engine.
|
||||
|
||||
## Dependencies
|
||||
|
||||
Run the dependency checker before decompiling:
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/check-deps.ps1
|
||||
```
|
||||
|
||||
Required (at least one): Java JDK 17+ with Ghidra, OR ilspycmd (.NET SDK).
|
||||
Optional: strings/strings2, dumpbin (Visual Studio C++ Build Tools), de4dot.
|
||||
|
||||
Install missing:
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/install-dep.ps1 <dep>
|
||||
```
|
||||
|
||||
If PowerShell execution policy blocks scripts, use: `powershell -ExecutionPolicy Bypass -File <script>`.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. **Check deps**: `check-deps.ps1` → outputs `INSTALL_REQUIRED:<dep>` for missing tools
|
||||
2. **Decompile**: `decompile.ps1 <file>` — auto-detects .NET (→ ILSpy) vs native (→ Ghidra)
|
||||
- Options: `-Engine auto|ghidra|ilspy`, `-Output <dir>`, `-NoStrings`
|
||||
3. **Analyze**: Review PE imports/exports, namespace structure, entry points
|
||||
4. **Trace flows**: Follow WinMain/Main → handlers → business logic → API calls
|
||||
5. **Extract APIs**: `find-api-calls.ps1 <dir>` with `-Network`, `-Registry`, `-Crypto`, `-Urls`, `-Auth`, `-Process`, `-Persistence`
|
||||
|
||||
## Script Locations
|
||||
|
||||
All scripts are at: `plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/`
|
||||
- `check-deps.ps1` — verify dependencies
|
||||
- `install-dep.ps1` — install a dependency
|
||||
- `decompile.ps1` — main decompile wrapper
|
||||
- `find-api-calls.ps1` — API call search
|
||||
- `ghidra-scripts/ExportDecompiled.py` — Ghidra Jython export
|
||||
|
||||
## Reference Documentation
|
||||
|
||||
- `plugins/windows-reverse-engineering/skills/windows-reverse-engineering/references/setup-guide.md`
|
||||
- `plugins/windows-reverse-engineering/skills/windows-reverse-engineering/references/ghidra-headless-usage.md`
|
||||
- `plugins/windows-reverse-engineering/skills/windows-reverse-engineering/references/ilspy-usage.md`
|
||||
- `plugins/windows-reverse-engineering/skills/windows-reverse-engineering/references/api-extraction-patterns.md`
|
||||
- `plugins/windows-reverse-engineering/skills/windows-reverse-engineering/references/call-flow-analysis.md`
|
||||
|
||||
## Output Format
|
||||
|
||||
Document each API call as:
|
||||
```markdown
|
||||
### `FunctionName` (DLL: source.dll)
|
||||
- **Source**: filename.c:42
|
||||
- **Category**: Network / Registry / File I/O / Process / Crypto
|
||||
- **Parameters**: param1: value, param2: value
|
||||
- **Called from**: Main → InitNetwork → WinHttpSendRequest
|
||||
- **Purpose**: Description
|
||||
```
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
---
|
||||
description: "Decompile Android APK/XAPK/JAR/AAR files. Use jadx or Fernflower/Vineflower. Extract Retrofit/OkHttp API endpoints, trace call flows from Activities through ViewModels to network layer."
|
||||
globs: ["**/*.apk", "**/*.xapk", "**/*.jar", "**/*.aar"]
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Android Reverse Engineering
|
||||
|
||||
Decompile Android packages using jadx (broad coverage) or Fernflower/Vineflower (higher quality Java). Extract HTTP APIs — Retrofit endpoints, OkHttp calls, hardcoded URLs.
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# 1. Check dependencies
|
||||
bash plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/check-deps.sh
|
||||
|
||||
# 2. Install missing deps
|
||||
bash plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/install-dep.sh <dep>
|
||||
|
||||
# 3. Decompile
|
||||
bash plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/decompile.sh app.apk
|
||||
|
||||
# 4. Find API calls
|
||||
bash plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/find-api-calls.sh output/sources/
|
||||
```
|
||||
|
||||
## Workflow
|
||||
|
||||
1. **Verify deps** → run `check-deps.sh`, install any missing with `install-dep.sh`
|
||||
2. **Decompile** → run `decompile.sh` with `--engine jadx|fernflower|both`
|
||||
3. **Analyze structure** → AndroidManifest.xml, package layout, architecture patterns
|
||||
4. **Trace call flows** → Activity → ViewModel → Repository → Retrofit/OkHttp → HTTP
|
||||
5. **Extract APIs** → run `find-api-calls.sh` with `--retrofit`, `--okhttp`, `--urls`, `--auth`
|
||||
|
||||
## Engine Selection
|
||||
|
||||
| Situation | Engine |
|
||||
|---|---|
|
||||
| General APK analysis | jadx (default) |
|
||||
| Complex Java decompilation | Fernflower/Vineflower |
|
||||
| Side-by-side comparison | `--engine both` |
|
||||
| Obfuscated APK | jadx with `--deobf` |
|
||||
|
||||
## API Documentation Format
|
||||
|
||||
```markdown
|
||||
### `METHOD /api/endpoint`
|
||||
- **Source**: ClassName.java:42
|
||||
- **Retrofit**: @POST("/api/endpoint")
|
||||
- **Headers**: Authorization: Bearer {token}
|
||||
- **Body**: { "key": "value" }
|
||||
- **Called from**: Activity → ViewModel → Repository → ApiService
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- `plugins/android-reverse-engineering/skills/android-reverse-engineering/references/setup-guide.md`
|
||||
- `plugins/android-reverse-engineering/skills/android-reverse-engineering/references/jadx-usage.md`
|
||||
- `plugins/android-reverse-engineering/skills/android-reverse-engineering/references/fernflower-usage.md`
|
||||
- `plugins/android-reverse-engineering/skills/android-reverse-engineering/references/api-extraction-patterns.md`
|
||||
- `plugins/android-reverse-engineering/skills/android-reverse-engineering/references/call-flow-analysis.md`
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
---
|
||||
description: "Decompile Windows EXE/DLL/.NET assemblies. Use Ghidra for native PE binaries and ILSpy for .NET. Extract Win32 API calls, network endpoints, registry operations. Trace call flows from entry points to API calls."
|
||||
globs: ["**/*.exe", "**/*.dll", "**/*.sys"]
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Windows Reverse Engineering
|
||||
|
||||
Decompile Windows binaries using Ghidra (native PE → C pseudocode) or ILSpy (.NET → C# source). Auto-detects binary type.
|
||||
|
||||
## Quick Start
|
||||
|
||||
```powershell
|
||||
# 1. Check dependencies
|
||||
powershell -ExecutionPolicy Bypass -File plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/check-deps.ps1
|
||||
|
||||
# 2. Install missing deps
|
||||
powershell -ExecutionPolicy Bypass -File plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/install-dep.ps1 <dep>
|
||||
|
||||
# 3. Decompile (auto-detects engine)
|
||||
powershell -ExecutionPolicy Bypass -File plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/decompile.ps1 target.exe
|
||||
|
||||
# 4. Find API calls
|
||||
powershell -ExecutionPolicy Bypass -File plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/find-api-calls.ps1 output/sources/
|
||||
```
|
||||
|
||||
## Workflow
|
||||
|
||||
1. **Verify deps** → run `check-deps.ps1`, install any missing with `install-dep.ps1`
|
||||
2. **Decompile** → run `decompile.ps1` with `-Engine auto|ghidra|ilspy`
|
||||
3. **Analyze structure** → review imports, exports, PE headers, namespace layout
|
||||
4. **Trace call flows** → follow entry points (WinMain/Main) → handlers → API calls
|
||||
5. **Extract APIs** → run `find-api-calls.ps1` with `-Network`, `-Registry`, `-Crypto`, `-Urls`, `-Process`, `-Auth`, `-Persistence`
|
||||
|
||||
## Auto-Detection
|
||||
|
||||
| Binary Type | Engine |
|
||||
|---|---|
|
||||
| .NET assembly (CLI header present) | ILSpy → C# source |
|
||||
| Native C/C++ PE | Ghidra → C pseudocode |
|
||||
| Kernel driver (.sys) | Ghidra |
|
||||
|
||||
## API Documentation Format
|
||||
|
||||
```markdown
|
||||
### `FunctionName` (DLL: source.dll)
|
||||
- **Source**: filename.c:42
|
||||
- **Category**: Network / Registry / File I/O / Process / Crypto
|
||||
- **Called from**: Main → InitNetwork → WinHttpSendRequest
|
||||
- **Purpose**: Description
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- `plugins/windows-reverse-engineering/skills/windows-reverse-engineering/references/setup-guide.md`
|
||||
- `plugins/windows-reverse-engineering/skills/windows-reverse-engineering/references/ghidra-headless-usage.md`
|
||||
- `plugins/windows-reverse-engineering/skills/windows-reverse-engineering/references/ilspy-usage.md`
|
||||
- `plugins/windows-reverse-engineering/skills/windows-reverse-engineering/references/api-extraction-patterns.md`
|
||||
- `plugins/windows-reverse-engineering/skills/windows-reverse-engineering/references/call-flow-analysis.md`
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
# Reverse Engineering Skills
|
||||
|
||||
This repository provides AI-assisted reverse engineering for Windows and Android binaries.
|
||||
|
||||
## Windows RE
|
||||
- Decompiles EXE/DLL/.NET using Ghidra (native) and ILSpy (.NET)
|
||||
- Scripts: `plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/`
|
||||
- Check deps: `powershell -ExecutionPolicy Bypass -File plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/check-deps.ps1`
|
||||
- Decompile: `powershell -ExecutionPolicy Bypass -File plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/decompile.ps1 <file>`
|
||||
- Find APIs: `powershell -ExecutionPolicy Bypass -File plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/find-api-calls.ps1 <dir>`
|
||||
|
||||
## Android RE
|
||||
- Decompiles APK/XAPK/JAR/AAR using jadx and Fernflower
|
||||
- Scripts: `plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/`
|
||||
- Check deps: `bash plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/check-deps.sh`
|
||||
- Decompile: `bash plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/decompile.sh <file>`
|
||||
- Find APIs: `bash plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/find-api-calls.sh <dir>`
|
||||
|
||||
## Detailed References
|
||||
- See `plugins/*/skills/*/references/` for setup guides, tool CLI references, API patterns, and call flow analysis techniques.
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
---
|
||||
description: 'Android reverse engineering with jadx and Fernflower — decompile APK/JAR/AAR, extract Retrofit/OkHttp APIs, trace call flows'
|
||||
applyTo: '**/*.{apk,xapk,jar,aar}'
|
||||
---
|
||||
|
||||
# Android Reverse Engineering
|
||||
|
||||
Decompile Android packages using jadx (broad coverage) or Fernflower/Vineflower (higher quality Java).
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
# Check dependencies
|
||||
bash plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/check-deps.sh
|
||||
|
||||
# Install missing dependency
|
||||
bash plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/install-dep.sh <dep>
|
||||
|
||||
# Decompile
|
||||
bash plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/decompile.sh app.apk
|
||||
bash plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/decompile.sh --engine both --deobf app.apk
|
||||
|
||||
# Find API calls
|
||||
bash plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/find-api-calls.sh output/sources/
|
||||
bash plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/find-api-calls.sh output/sources/ --retrofit
|
||||
bash plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/find-api-calls.sh output/sources/ --urls
|
||||
```
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Verify dependencies → `check-deps.sh`
|
||||
2. Decompile → `decompile.sh` (jadx, fernflower, or both)
|
||||
3. Analyze AndroidManifest.xml and package structure
|
||||
4. Trace call flows from Activities → ViewModels → Repositories → API calls
|
||||
5. Extract and document APIs → `find-api-calls.sh`
|
||||
|
||||
## References
|
||||
|
||||
See `plugins/android-reverse-engineering/skills/android-reverse-engineering/references/` for detailed guides.
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
---
|
||||
description: 'Windows reverse engineering with Ghidra and ILSpy — decompile EXE/DLL/.NET, extract Win32 APIs, trace call flows'
|
||||
applyTo: '**/*.{exe,dll,sys}'
|
||||
---
|
||||
|
||||
# Windows Reverse Engineering
|
||||
|
||||
Decompile Windows binaries using Ghidra (native PE → C pseudocode) or ILSpy (.NET → C# source).
|
||||
|
||||
## Commands
|
||||
|
||||
```powershell
|
||||
# Check dependencies
|
||||
powershell -ExecutionPolicy Bypass -File plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/check-deps.ps1
|
||||
|
||||
# Install missing dependency
|
||||
powershell -ExecutionPolicy Bypass -File plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/install-dep.ps1 <dep>
|
||||
# Available: java, ghidra, ilspycmd, dotnet-sdk, strings, dumpbin, de4dot
|
||||
|
||||
# Decompile (auto-detects .NET vs native)
|
||||
powershell -ExecutionPolicy Bypass -File plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/decompile.ps1 target.exe
|
||||
powershell -ExecutionPolicy Bypass -File plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/decompile.ps1 -Engine ilspy MyDotNet.dll
|
||||
|
||||
# Find API calls in decompiled output
|
||||
powershell -ExecutionPolicy Bypass -File plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/find-api-calls.ps1 output/sources/
|
||||
powershell -ExecutionPolicy Bypass -File plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/find-api-calls.ps1 output/sources/ -Network
|
||||
powershell -ExecutionPolicy Bypass -File plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/find-api-calls.ps1 output/sources/ -Urls
|
||||
```
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Verify dependencies → `check-deps.ps1`
|
||||
2. Decompile → `decompile.ps1` (auto-detects engine)
|
||||
3. Analyze PE structure (imports, exports, headers)
|
||||
4. Trace call flows from entry points to API calls
|
||||
5. Extract and document APIs → `find-api-calls.ps1`
|
||||
|
||||
## References
|
||||
|
||||
See `plugins/windows-reverse-engineering/skills/windows-reverse-engineering/references/` for detailed guides.
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
# Android Reverse Engineering
|
||||
|
||||
Decompile Android APK, XAPK, JAR, and AAR files using jadx and Fernflower/Vineflower. Extract Retrofit endpoints, OkHttp calls, hardcoded URLs, and authentication patterns.
|
||||
|
||||
## Dependencies
|
||||
|
||||
Run the dependency checker before decompiling:
|
||||
```bash
|
||||
bash plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/check-deps.sh
|
||||
```
|
||||
|
||||
Required: Java JDK 17+, jadx.
|
||||
Optional: Fernflower/Vineflower, dex2jar, apktool.
|
||||
|
||||
Install missing:
|
||||
```bash
|
||||
bash plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/install-dep.sh <dep>
|
||||
```
|
||||
|
||||
## Workflow
|
||||
|
||||
1. **Check deps**: `check-deps.sh` → outputs `INSTALL_REQUIRED:<dep>` for missing tools
|
||||
2. **Decompile**: `decompile.sh <file>` with `--engine jadx|fernflower|both`, `--deobf`
|
||||
3. **Analyze**: Review AndroidManifest.xml, package structure, architecture patterns
|
||||
4. **Trace flows**: Follow Activity → ViewModel → Repository → Retrofit/OkHttp → HTTP
|
||||
5. **Extract APIs**: `find-api-calls.sh <dir>` with `--retrofit`, `--okhttp`, `--urls`, `--auth`
|
||||
|
||||
## Script Locations
|
||||
|
||||
All scripts are at: `plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/`
|
||||
- `check-deps.sh` — verify dependencies
|
||||
- `install-dep.sh` — install a dependency
|
||||
- `decompile.sh` — main decompile wrapper
|
||||
- `find-api-calls.sh` — API call search
|
||||
|
||||
## Reference Documentation
|
||||
|
||||
- `plugins/android-reverse-engineering/skills/android-reverse-engineering/references/setup-guide.md`
|
||||
- `plugins/android-reverse-engineering/skills/android-reverse-engineering/references/jadx-usage.md`
|
||||
- `plugins/android-reverse-engineering/skills/android-reverse-engineering/references/fernflower-usage.md`
|
||||
- `plugins/android-reverse-engineering/skills/android-reverse-engineering/references/api-extraction-patterns.md`
|
||||
- `plugins/android-reverse-engineering/skills/android-reverse-engineering/references/call-flow-analysis.md`
|
||||
|
||||
## Output Format
|
||||
|
||||
Document each API endpoint as:
|
||||
```markdown
|
||||
### `METHOD /api/endpoint`
|
||||
- **Source**: ClassName.java:42
|
||||
- **Retrofit**: @POST("/api/endpoint")
|
||||
- **Headers**: Authorization: Bearer {token}
|
||||
- **Body**: { "key": "value" }
|
||||
- **Called from**: Activity → ViewModel → Repository → ApiService
|
||||
```
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
# Windows Reverse Engineering
|
||||
|
||||
Decompile Windows EXE, DLL, SYS, and .NET assemblies using Ghidra (native PE → C pseudocode) and ILSpy (.NET → C# source). Auto-detects binary type and selects the appropriate engine.
|
||||
|
||||
## Dependencies
|
||||
|
||||
Run the dependency checker before decompiling:
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/check-deps.ps1
|
||||
```
|
||||
|
||||
Required (at least one): Java JDK 17+ with Ghidra, OR ilspycmd (.NET SDK).
|
||||
Optional: strings/strings2, dumpbin (Visual Studio C++ Build Tools), de4dot.
|
||||
|
||||
Install missing:
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/install-dep.ps1 <dep>
|
||||
```
|
||||
|
||||
If PowerShell execution policy blocks scripts, use: `powershell -ExecutionPolicy Bypass -File <script>`.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. **Check deps**: `check-deps.ps1` → outputs `INSTALL_REQUIRED:<dep>` for missing tools
|
||||
2. **Decompile**: `decompile.ps1 <file>` — auto-detects .NET (→ ILSpy) vs native (→ Ghidra)
|
||||
- Options: `-Engine auto|ghidra|ilspy`, `-Output <dir>`, `-NoStrings`
|
||||
3. **Analyze**: Review PE imports/exports, namespace structure, entry points
|
||||
4. **Trace flows**: Follow WinMain/Main → handlers → business logic → API calls
|
||||
5. **Extract APIs**: `find-api-calls.ps1 <dir>` with `-Network`, `-Registry`, `-Crypto`, `-Urls`, `-Auth`, `-Process`, `-Persistence`
|
||||
|
||||
## Script Locations
|
||||
|
||||
All scripts are at: `plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/`
|
||||
- `check-deps.ps1` — verify dependencies
|
||||
- `install-dep.ps1` — install a dependency
|
||||
- `decompile.ps1` — main decompile wrapper
|
||||
- `find-api-calls.ps1` — API call search
|
||||
- `ghidra-scripts/ExportDecompiled.py` — Ghidra Jython export
|
||||
|
||||
## Reference Documentation
|
||||
|
||||
- `plugins/windows-reverse-engineering/skills/windows-reverse-engineering/references/setup-guide.md`
|
||||
- `plugins/windows-reverse-engineering/skills/windows-reverse-engineering/references/ghidra-headless-usage.md`
|
||||
- `plugins/windows-reverse-engineering/skills/windows-reverse-engineering/references/ilspy-usage.md`
|
||||
- `plugins/windows-reverse-engineering/skills/windows-reverse-engineering/references/api-extraction-patterns.md`
|
||||
- `plugins/windows-reverse-engineering/skills/windows-reverse-engineering/references/call-flow-analysis.md`
|
||||
|
||||
## Output Format
|
||||
|
||||
Document each API call as:
|
||||
```markdown
|
||||
### `FunctionName` (DLL: source.dll)
|
||||
- **Source**: filename.c:42
|
||||
- **Category**: Network / Registry / File I/O / Process / Crypto
|
||||
- **Parameters**: param1: value, param2: value
|
||||
- **Called from**: Main → InitNetwork → WinHttpSendRequest
|
||||
- **Purpose**: Description
|
||||
```
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
# Android Reverse Engineering
|
||||
|
||||
Decompile Android APK, XAPK, JAR, and AAR files using jadx and Fernflower/Vineflower. Extract Retrofit endpoints, OkHttp calls, hardcoded URLs, and authentication patterns.
|
||||
|
||||
## Dependencies
|
||||
|
||||
Run the dependency checker before decompiling:
|
||||
```bash
|
||||
bash plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/check-deps.sh
|
||||
```
|
||||
|
||||
Required: Java JDK 17+, jadx.
|
||||
Optional: Fernflower/Vineflower, dex2jar, apktool.
|
||||
|
||||
Install missing:
|
||||
```bash
|
||||
bash plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/install-dep.sh <dep>
|
||||
```
|
||||
|
||||
## Workflow
|
||||
|
||||
1. **Check deps**: `check-deps.sh` → outputs `INSTALL_REQUIRED:<dep>` for missing tools
|
||||
2. **Decompile**: `decompile.sh <file>` with `--engine jadx|fernflower|both`, `--deobf`
|
||||
3. **Analyze**: Review AndroidManifest.xml, package structure, architecture patterns
|
||||
4. **Trace flows**: Follow Activity → ViewModel → Repository → Retrofit/OkHttp → HTTP
|
||||
5. **Extract APIs**: `find-api-calls.sh <dir>` with `--retrofit`, `--okhttp`, `--urls`, `--auth`
|
||||
|
||||
## Script Locations
|
||||
|
||||
All scripts are at: `plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/`
|
||||
- `check-deps.sh` — verify dependencies
|
||||
- `install-dep.sh` — install a dependency
|
||||
- `decompile.sh` — main decompile wrapper
|
||||
- `find-api-calls.sh` — API call search
|
||||
|
||||
## Reference Documentation
|
||||
|
||||
- `plugins/android-reverse-engineering/skills/android-reverse-engineering/references/setup-guide.md`
|
||||
- `plugins/android-reverse-engineering/skills/android-reverse-engineering/references/jadx-usage.md`
|
||||
- `plugins/android-reverse-engineering/skills/android-reverse-engineering/references/fernflower-usage.md`
|
||||
- `plugins/android-reverse-engineering/skills/android-reverse-engineering/references/api-extraction-patterns.md`
|
||||
- `plugins/android-reverse-engineering/skills/android-reverse-engineering/references/call-flow-analysis.md`
|
||||
|
||||
## Output Format
|
||||
|
||||
Document each API endpoint as:
|
||||
```markdown
|
||||
### `METHOD /api/endpoint`
|
||||
- **Source**: ClassName.java:42
|
||||
- **Retrofit**: @POST("/api/endpoint")
|
||||
- **Headers**: Authorization: Bearer {token}
|
||||
- **Body**: { "key": "value" }
|
||||
- **Called from**: Activity → ViewModel → Repository → ApiService
|
||||
```
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
# Windows Reverse Engineering
|
||||
|
||||
Decompile Windows EXE, DLL, SYS, and .NET assemblies using Ghidra (native PE → C pseudocode) and ILSpy (.NET → C# source). Auto-detects binary type and selects the appropriate engine.
|
||||
|
||||
## Dependencies
|
||||
|
||||
Run the dependency checker before decompiling:
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/check-deps.ps1
|
||||
```
|
||||
|
||||
Required (at least one): Java JDK 17+ with Ghidra, OR ilspycmd (.NET SDK).
|
||||
Optional: strings/strings2, dumpbin (Visual Studio C++ Build Tools), de4dot.
|
||||
|
||||
Install missing:
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/install-dep.ps1 <dep>
|
||||
```
|
||||
|
||||
If PowerShell execution policy blocks scripts, use: `powershell -ExecutionPolicy Bypass -File <script>`.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. **Check deps**: `check-deps.ps1` → outputs `INSTALL_REQUIRED:<dep>` for missing tools
|
||||
2. **Decompile**: `decompile.ps1 <file>` — auto-detects .NET (→ ILSpy) vs native (→ Ghidra)
|
||||
- Options: `-Engine auto|ghidra|ilspy`, `-Output <dir>`, `-NoStrings`
|
||||
3. **Analyze**: Review PE imports/exports, namespace structure, entry points
|
||||
4. **Trace flows**: Follow WinMain/Main → handlers → business logic → API calls
|
||||
5. **Extract APIs**: `find-api-calls.ps1 <dir>` with `-Network`, `-Registry`, `-Crypto`, `-Urls`, `-Auth`, `-Process`, `-Persistence`
|
||||
|
||||
## Script Locations
|
||||
|
||||
All scripts are at: `plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/`
|
||||
- `check-deps.ps1` — verify dependencies
|
||||
- `install-dep.ps1` — install a dependency
|
||||
- `decompile.ps1` — main decompile wrapper
|
||||
- `find-api-calls.ps1` — API call search
|
||||
- `ghidra-scripts/ExportDecompiled.py` — Ghidra Jython export
|
||||
|
||||
## Reference Documentation
|
||||
|
||||
- `plugins/windows-reverse-engineering/skills/windows-reverse-engineering/references/setup-guide.md`
|
||||
- `plugins/windows-reverse-engineering/skills/windows-reverse-engineering/references/ghidra-headless-usage.md`
|
||||
- `plugins/windows-reverse-engineering/skills/windows-reverse-engineering/references/ilspy-usage.md`
|
||||
- `plugins/windows-reverse-engineering/skills/windows-reverse-engineering/references/api-extraction-patterns.md`
|
||||
- `plugins/windows-reverse-engineering/skills/windows-reverse-engineering/references/call-flow-analysis.md`
|
||||
|
||||
## Output Format
|
||||
|
||||
Document each API call as:
|
||||
```markdown
|
||||
### `FunctionName` (DLL: source.dll)
|
||||
- **Source**: filename.c:42
|
||||
- **Category**: Network / Registry / File I/O / Process / Crypto
|
||||
- **Parameters**: param1: value, param2: value
|
||||
- **Called from**: Main → InitNetwork → WinHttpSendRequest
|
||||
- **Purpose**: Description
|
||||
```
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
# Reverse Engineering Skills
|
||||
|
||||
This repository provides AI-assisted reverse engineering tools for **Windows** (EXE/DLL/.NET) and **Android** (APK/XAPK/JAR/AAR) binaries. It includes decompilation scripts, API extraction, call flow tracing, and structured output documentation.
|
||||
|
||||
All scripts and references live under `plugins/`. The instructions below tell you how to use them.
|
||||
|
||||
---
|
||||
|
||||
## Windows Reverse Engineering
|
||||
|
||||
Decompile Windows EXE, DLL, SYS, and .NET assemblies using Ghidra (native PE → C pseudocode) and ILSpy (managed .NET → C# source). Auto-detects binary type.
|
||||
|
||||
### Dependencies
|
||||
|
||||
Run the dependency checker first:
|
||||
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/check-deps.ps1
|
||||
```
|
||||
|
||||
**Required (at least one decompiler):**
|
||||
- Java JDK 17+ and Ghidra (set `GHIDRA_INSTALL_DIR` env var) — for native PE
|
||||
- ilspycmd (`dotnet tool install -g ilspycmd`) — for .NET assemblies
|
||||
|
||||
**Optional:** strings/strings2, dumpbin (requires Visual Studio C++ Build Tools), de4dot (.NET deobfuscator)
|
||||
|
||||
Install missing dependencies:
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/install-dep.ps1 <dep>
|
||||
# Available: java, ghidra, ilspycmd, dotnet-sdk, strings, dumpbin, de4dot
|
||||
```
|
||||
|
||||
### PowerShell Execution Policy
|
||||
|
||||
If scripts are blocked, auto-fix with:
|
||||
```powershell
|
||||
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned -Force
|
||||
```
|
||||
If group policy prevents this, prefix all script calls with `powershell -ExecutionPolicy Bypass -File`.
|
||||
|
||||
### Workflow
|
||||
|
||||
#### Phase 1: Verify Dependencies
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/check-deps.ps1
|
||||
```
|
||||
Output includes `INSTALL_REQUIRED:<dep>` and `INSTALL_OPTIONAL:<dep>` lines. Install any required deps before proceeding.
|
||||
|
||||
#### Phase 2: Decompile
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/decompile.ps1 [OPTIONS] <file>
|
||||
```
|
||||
Options:
|
||||
- `-Output <dir>` — custom output directory (default: `<filename>-decompiled`)
|
||||
- `-Engine auto|ghidra|ilspy` — decompiler engine (default: `auto`)
|
||||
- `-NoStrings` — skip strings extraction
|
||||
|
||||
Auto-detection: .NET assemblies (CLI header present) → ILSpy. Native PE → Ghidra. The script reads the PE header to determine binary type.
|
||||
|
||||
**Output structure (Ghidra):**
|
||||
```
|
||||
<output>/decompiled/ — C pseudocode per function
|
||||
<output>/imports.txt — import table
|
||||
<output>/exports.txt — export table
|
||||
<output>/strings.txt — extracted strings
|
||||
<output>/summary.txt — analysis summary
|
||||
```
|
||||
|
||||
**Output structure (ILSpy):**
|
||||
```
|
||||
<output>/sources/ — C# source files with .csproj
|
||||
```
|
||||
|
||||
#### Phase 3: Analyze Structure
|
||||
- Review PE headers (architecture, subsystem, entry point, security features)
|
||||
- Survey import table — reveals which DLLs/APIs the binary uses
|
||||
- For .NET: examine namespace structure, referenced assemblies, DI container setup
|
||||
- For native: group functions by purpose, identify entry points, look for C++ vtables
|
||||
|
||||
#### Phase 4: Trace Call Flows
|
||||
- Start from entry points: `WinMain`, `main`, `DllMain`, `ServiceMain`, `DriverEntry` (native) or `static void Main()`, `Program.cs`, `Startup.cs` (.NET)
|
||||
- Follow initialization chain → user action handlers → business logic → API calls
|
||||
- Map dependency injection in .NET (`AddScoped`, `AddSingleton`, `AddTransient`)
|
||||
- Handle obfuscated code: use framework type names and string refs as anchors
|
||||
|
||||
#### Phase 5: Extract APIs
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/find-api-calls.ps1 <output>/sources/ [OPTIONS]
|
||||
```
|
||||
Options: `-Network`, `-Registry`, `-FileSystem`, `-Process`, `-Crypto`, `-Com`, `-Services`, `-Urls`, `-Auth`, `-Persistence`
|
||||
|
||||
Document each API call:
|
||||
```markdown
|
||||
### `FunctionName` (DLL: source.dll)
|
||||
- **Source**: filename.c:42
|
||||
- **Category**: Network / Registry / File I/O / Process / Crypto
|
||||
- **Parameters**: param1: value, param2: value
|
||||
- **Called from**: Main → InitNetwork → SendData → WinHttpSendRequest
|
||||
- **Purpose**: Description
|
||||
```
|
||||
|
||||
### Reference Documentation
|
||||
- `plugins/windows-reverse-engineering/skills/windows-reverse-engineering/references/setup-guide.md`
|
||||
- `plugins/windows-reverse-engineering/skills/windows-reverse-engineering/references/ghidra-headless-usage.md`
|
||||
- `plugins/windows-reverse-engineering/skills/windows-reverse-engineering/references/ilspy-usage.md`
|
||||
- `plugins/windows-reverse-engineering/skills/windows-reverse-engineering/references/api-extraction-patterns.md`
|
||||
- `plugins/windows-reverse-engineering/skills/windows-reverse-engineering/references/call-flow-analysis.md`
|
||||
|
||||
---
|
||||
|
||||
## Android Reverse Engineering
|
||||
|
||||
Decompile Android APK, XAPK, JAR, and AAR files using jadx and Fernflower/Vineflower. Extract Retrofit endpoints, OkHttp calls, hardcoded URLs, and authentication patterns.
|
||||
|
||||
### Dependencies
|
||||
|
||||
```bash
|
||||
bash plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/check-deps.sh
|
||||
```
|
||||
|
||||
**Required:** Java JDK 17+, jadx
|
||||
**Optional:** Fernflower/Vineflower, dex2jar, apktool
|
||||
|
||||
Install missing:
|
||||
```bash
|
||||
bash plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/install-dep.sh <dep>
|
||||
```
|
||||
|
||||
### Workflow
|
||||
|
||||
#### Phase 1: Verify Dependencies
|
||||
```bash
|
||||
bash plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/check-deps.sh
|
||||
```
|
||||
|
||||
#### Phase 2: Decompile
|
||||
```bash
|
||||
bash plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/decompile.sh [OPTIONS] <file>
|
||||
```
|
||||
Options:
|
||||
- `--output <dir>` — custom output directory
|
||||
- `--engine jadx|fernflower|both` — decompiler engine (default: `jadx`)
|
||||
- `--deobf` — enable deobfuscation
|
||||
|
||||
#### Phase 3: Analyze Structure
|
||||
- Review AndroidManifest.xml for activities, services, receivers, permissions
|
||||
- Survey package structure and identify architecture patterns (MVP, MVVM, Clean Architecture)
|
||||
- Find application entry points (Application class, main Activity, ContentProviders)
|
||||
|
||||
#### Phase 4: Trace Call Flows
|
||||
- Start from Activity/Fragment → ViewModel → Repository → API client
|
||||
- Follow Dagger/Hilt dependency injection
|
||||
- Map Retrofit interface → OkHttp interceptors → actual HTTP calls
|
||||
|
||||
#### Phase 5: Extract APIs
|
||||
```bash
|
||||
bash plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/find-api-calls.sh <output>/sources/ [OPTIONS]
|
||||
```
|
||||
Options: `--retrofit`, `--okhttp`, `--urls`, `--auth`, `--volley`
|
||||
|
||||
### Reference Documentation
|
||||
- `plugins/android-reverse-engineering/skills/android-reverse-engineering/references/setup-guide.md`
|
||||
- `plugins/android-reverse-engineering/skills/android-reverse-engineering/references/jadx-usage.md`
|
||||
- `plugins/android-reverse-engineering/skills/android-reverse-engineering/references/fernflower-usage.md`
|
||||
- `plugins/android-reverse-engineering/skills/android-reverse-engineering/references/api-extraction-patterns.md`
|
||||
- `plugins/android-reverse-engineering/skills/android-reverse-engineering/references/call-flow-analysis.md`
|
||||
161
README.md
161
README.md
|
|
@ -1,8 +1,79 @@
|
|||
# Android Reverse Engineering & API Extraction — Claude Code skill
|
||||
# Reverse Engineering & API Extraction — AI Coding Agent Skills
|
||||
|
||||
A Claude Code skill that decompiles Android APK/XAPK/JAR/AAR files and **extracts the HTTP APIs** used by the app — Retrofit endpoints, OkHttp calls, hardcoded URLs, authentication patterns — so you can document and reproduce them without the original source code.
|
||||
A collection of AI coding agent skills for reverse engineering mobile and desktop applications. Includes **Android** (APK/XAPK/JAR/AAR) and **Windows** (EXE/DLL/.NET) plugins that decompile binaries, extract APIs, trace call flows, and document findings.
|
||||
|
||||
Works with **Claude Code**, **OpenAI Codex**, **Cursor**, **GitHub Copilot**, **Cline**, **Windsurf**, **Roo Code**, **Aider**, and **OpenCode**.
|
||||
|
||||
---
|
||||
|
||||
## 🪟 Windows Reverse Engineering (NEW)
|
||||
|
||||
Decompiles Windows EXE/DLL/.NET assemblies and **extracts Win32 API calls**, network endpoints, registry operations, cryptographic usage, and more.
|
||||
|
||||
### What it does
|
||||
|
||||
- **Auto-detects** binary type (.NET vs native PE) and selects the best decompiler
|
||||
- **Decompiles** native PE binaries using **Ghidra** headless (C pseudocode output)
|
||||
- **Decompiles** .NET assemblies using **ILSpy** (ilspycmd) to C# source
|
||||
- **Extracts and documents APIs**: Win32 calls, WinHTTP/WinINet, Winsock, .NET HttpClient, registry, crypto, COM/WMI
|
||||
- **Traces call flows** from entry points (WinMain, DllMain, ServiceMain, Main) through to API calls
|
||||
- **Analyzes** PE structure: imports, exports, sections, strings, security features
|
||||
- **Detects** persistence mechanisms, process injection patterns, and hardcoded secrets
|
||||
|
||||
### Requirements
|
||||
|
||||
**Required (at least one decompiler):**
|
||||
- Java JDK 17+ and [Ghidra](https://github.com/NationalSecurityAgency/ghidra) — for native PE binaries
|
||||
- [ilspycmd](https://github.com/icsharpcode/ILSpy) (`dotnet tool install -g ilspycmd`) — for .NET assemblies
|
||||
|
||||
**Optional (recommended):**
|
||||
- [strings2](https://github.com/glmcdona/strings2) or SysInternals Strings — extract embedded strings
|
||||
- dumpbin (Visual Studio C++ Build Tools) — PE header analysis
|
||||
- [de4dot](https://github.com/de4dot/de4dot) — .NET deobfuscation
|
||||
|
||||
### Installation
|
||||
|
||||
Inside Claude Code, run:
|
||||
|
||||
```
|
||||
/plugin install windows-reverse-engineering@android-reverse-engineering-skill
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
```
|
||||
/decompile path/to/app.exe
|
||||
```
|
||||
|
||||
The skill auto-detects the binary type and runs the appropriate decompiler. You can also use natural language: "Reverse engineer this DLL", "Extract API calls from this .NET app", "Trace the login flow".
|
||||
|
||||
### Manual scripts (PowerShell)
|
||||
|
||||
```powershell
|
||||
# Check dependencies
|
||||
powershell -ExecutionPolicy Bypass -File plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/check-deps.ps1
|
||||
|
||||
# Install a missing dependency
|
||||
powershell -ExecutionPolicy Bypass -File plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/install-dep.ps1 ghidra
|
||||
powershell -ExecutionPolicy Bypass -File plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/install-dep.ps1 ilspycmd
|
||||
|
||||
# Decompile (auto-detect engine)
|
||||
powershell -ExecutionPolicy Bypass -File plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/decompile.ps1 app.exe
|
||||
|
||||
# Decompile with specific engine
|
||||
powershell -ExecutionPolicy Bypass -File plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/decompile.ps1 -Engine ilspy MyDotNetApp.dll
|
||||
|
||||
# Find API calls
|
||||
powershell -ExecutionPolicy Bypass -File plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/find-api-calls.ps1 output/sources/
|
||||
powershell -ExecutionPolicy Bypass -File plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/find-api-calls.ps1 output/sources/ -Network
|
||||
powershell -ExecutionPolicy Bypass -File plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/find-api-calls.ps1 output/sources/ -Urls
|
||||
powershell -ExecutionPolicy Bypass -File plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/find-api-calls.ps1 output/sources/ -Process
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🤖 Android Reverse Engineering
|
||||
|
||||
## What it does
|
||||
|
||||
- **Decompiles** APK, XAPK, JAR, and AAR files using jadx and Fernflower/Vineflower (single engine or side-by-side comparison)
|
||||
- **Extracts and documents APIs**: Retrofit endpoints, OkHttp calls, hardcoded URLs, auth headers and tokens
|
||||
|
|
@ -103,39 +174,101 @@ bash plugins/android-reverse-engineering/skills/android-reverse-engineering/scri
|
|||
```
|
||||
android-reverse-engineering-skill/
|
||||
├── .claude-plugin/
|
||||
│ └── marketplace.json # Marketplace catalog
|
||||
│ └── marketplace.json # Marketplace catalog (both plugins)
|
||||
├── plugins/
|
||||
│ └── android-reverse-engineering/
|
||||
│ ├── android-reverse-engineering/ # Android plugin
|
||||
│ │ ├── .claude-plugin/
|
||||
│ │ │ └── plugin.json
|
||||
│ │ ├── skills/
|
||||
│ │ │ └── android-reverse-engineering/
|
||||
│ │ │ ├── SKILL.md
|
||||
│ │ │ ├── references/
|
||||
│ │ │ │ ├── setup-guide.md
|
||||
│ │ │ │ ├── jadx-usage.md
|
||||
│ │ │ │ ├── fernflower-usage.md
|
||||
│ │ │ │ ├── api-extraction-patterns.md
|
||||
│ │ │ │ └── call-flow-analysis.md
|
||||
│ │ │ └── scripts/
|
||||
│ │ │ ├── check-deps.sh
|
||||
│ │ │ ├── install-dep.sh
|
||||
│ │ │ ├── decompile.sh
|
||||
│ │ │ └── find-api-calls.sh
|
||||
│ │ └── commands/
|
||||
│ │ └── decompile.md
|
||||
│ └── windows-reverse-engineering/ # Windows plugin (NEW)
|
||||
│ ├── .claude-plugin/
|
||||
│ │ └── plugin.json # Plugin manifest
|
||||
│ │ └── plugin.json
|
||||
│ ├── skills/
|
||||
│ │ └── android-reverse-engineering/
|
||||
│ │ └── windows-reverse-engineering/
|
||||
│ │ ├── SKILL.md # Core workflow (5 phases)
|
||||
│ │ ├── references/
|
||||
│ │ │ ├── setup-guide.md
|
||||
│ │ │ ├── jadx-usage.md
|
||||
│ │ │ ├── fernflower-usage.md
|
||||
│ │ │ ├── ghidra-headless-usage.md
|
||||
│ │ │ ├── ilspy-usage.md
|
||||
│ │ │ ├── api-extraction-patterns.md
|
||||
│ │ │ └── call-flow-analysis.md
|
||||
│ │ └── scripts/
|
||||
│ │ ├── check-deps.sh
|
||||
│ │ ├── install-dep.sh
|
||||
│ │ ├── decompile.sh
|
||||
│ │ └── find-api-calls.sh
|
||||
│ │ ├── check-deps.ps1
|
||||
│ │ ├── install-dep.ps1
|
||||
│ │ ├── decompile.ps1
|
||||
│ │ ├── find-api-calls.ps1
|
||||
│ │ └── ghidra-scripts/
|
||||
│ │ └── ExportDecompiled.py
|
||||
│ └── commands/
|
||||
│ └── decompile.md # /decompile slash command
|
||||
│ └── decompile.md
|
||||
├── LICENSE
|
||||
└── README.md
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
### Android
|
||||
- [jadx — Dex to Java decompiler](https://github.com/skylot/jadx)
|
||||
- [Fernflower — JetBrains analytical decompiler](https://github.com/JetBrains/fernflower)
|
||||
- [Vineflower — Fernflower community fork](https://github.com/Vineflower/vineflower)
|
||||
- [dex2jar — DEX to JAR converter](https://github.com/pxb1988/dex2jar)
|
||||
- [apktool — Android resource decoder](https://apktool.org/)
|
||||
|
||||
### Windows
|
||||
- [Ghidra — NSA reverse engineering framework](https://github.com/NationalSecurityAgency/ghidra)
|
||||
- [ILSpy — .NET decompiler](https://github.com/icsharpcode/ILSpy)
|
||||
- [de4dot — .NET deobfuscator](https://github.com/de4dot/de4dot)
|
||||
- [strings2 — Advanced string extraction](https://github.com/glmcdona/strings2)
|
||||
- [x64dbg — Open source Windows debugger](https://x64dbg.com/)
|
||||
|
||||
## Supported Agents
|
||||
|
||||
This skill works with all major AI coding agents. Use the universal installer to set up for your agent:
|
||||
|
||||
```powershell
|
||||
# Windows (PowerShell)
|
||||
.\install.ps1 # Interactive — choose your agent
|
||||
.\install.ps1 -Agent cursor # Install for Cursor
|
||||
.\install.ps1 -Agent all # Install for all agents
|
||||
.\install.ps1 -List # List supported agents
|
||||
.\install.ps1 -CheckDeps # Run dependency check
|
||||
```
|
||||
|
||||
```bash
|
||||
# Linux / macOS / WSL
|
||||
./install.sh # Interactive
|
||||
./install.sh --agent codex # Install for Codex
|
||||
./install.sh --agent all # Install for all agents
|
||||
./install.sh --list # List supported agents
|
||||
```
|
||||
|
||||
| Agent | Config Files | Auto-Detection |
|
||||
|---|---|---|
|
||||
| **Claude Code** | `.claude-plugin/` | Plugin manifest + SKILL.md |
|
||||
| **OpenAI Codex** | `AGENTS.md` | Reads from repo root |
|
||||
| **OpenCode** | `AGENTS.md` | Reads from repo root |
|
||||
| **Cursor** | `.cursor/rules/*.mdc` | Glob-matched + description-based |
|
||||
| **GitHub Copilot** | `.github/instructions/*.instructions.md` | File-pattern matched |
|
||||
| **Cline** | `.clinerules/*.md` | Auto-loaded into context |
|
||||
| **Windsurf** | `.windsurf/rules/*.md` | Auto-loaded by Cascade |
|
||||
| **Roo Code** | `.roo/rules/*.md` | Auto-loaded, alphabetical order |
|
||||
| **Aider** | `.aider.conf.yml` → `AGENTS.md` | Loaded via `read:` config |
|
||||
|
||||
## Disclaimer
|
||||
|
||||
This plugin is provided strictly for **lawful purposes**, including but not limited to:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,290 @@
|
|||
# install.ps1 - Universal installer for reverse engineering skills
|
||||
# Installs agent-specific instruction files for any supported AI coding agent.
|
||||
#
|
||||
# Usage:
|
||||
# .\install.ps1 # Interactive mode
|
||||
# .\install.ps1 -Agent cursor # Install for Cursor
|
||||
# .\install.ps1 -Agent all # Install for all agents
|
||||
# .\install.ps1 -Agent copilot -Target C:\MyProject # Install into another project
|
||||
# .\install.ps1 -List # List available agents
|
||||
# .\install.ps1 -CheckDeps # Run dependency check only
|
||||
|
||||
param(
|
||||
[ValidateSet('claude', 'codex', 'opencode', 'cursor', 'copilot', 'cline', 'windsurf', 'roo', 'aider', 'all')]
|
||||
[string]$Agent = '',
|
||||
|
||||
[string]$Target = '',
|
||||
|
||||
[switch]$List,
|
||||
|
||||
[switch]$CheckDeps,
|
||||
|
||||
[Alias('h')]
|
||||
[switch]$Help
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
|
||||
# --- Help ---
|
||||
if ($Help) {
|
||||
Write-Host 'Reverse Engineering Skills - Universal Installer'
|
||||
Write-Host ''
|
||||
Write-Host 'Usage:'
|
||||
Write-Host ' .\install.ps1 Interactive mode (choose agent)'
|
||||
Write-Host ' .\install.ps1 -Agent <agent> Install for a specific agent'
|
||||
Write-Host ' .\install.ps1 -Agent all Install for all agents'
|
||||
Write-Host ' .\install.ps1 -Agent <agent> -Target <dir> Install into another project'
|
||||
Write-Host ' .\install.ps1 -List List supported agents'
|
||||
Write-Host ' .\install.ps1 -CheckDeps Run dependency check only'
|
||||
Write-Host ''
|
||||
Write-Host 'Agents:'
|
||||
Write-Host ' claude - Claude Code (.claude-plugin/)'
|
||||
Write-Host ' codex - OpenAI Codex (AGENTS.md)'
|
||||
Write-Host ' opencode - OpenCode (AGENTS.md)'
|
||||
Write-Host ' cursor - Cursor IDE (.cursor/rules/*.mdc)'
|
||||
Write-Host ' copilot - GitHub Copilot (.github/instructions/)'
|
||||
Write-Host ' cline - Cline (.clinerules/)'
|
||||
Write-Host ' windsurf - Windsurf (.windsurf/rules/)'
|
||||
Write-Host ' roo - Roo Code (.roo/rules/)'
|
||||
Write-Host ' aider - Aider (.aider.conf.yml)'
|
||||
Write-Host ' all - Install for all agents at once'
|
||||
Write-Host ''
|
||||
Write-Host 'Options:'
|
||||
Write-Host ' -Target <dir> Target directory (default: current directory)'
|
||||
Write-Host ' -List List all supported agents'
|
||||
Write-Host ' -CheckDeps Run the dependency checker and exit'
|
||||
Write-Host ' -Help Show this help message'
|
||||
exit 0
|
||||
}
|
||||
|
||||
# --- Agent definitions ---
|
||||
$Agents = [ordered]@{
|
||||
claude = @{ Name = 'Claude Code'; Files = @('.claude-plugin/') }
|
||||
codex = @{ Name = 'OpenAI Codex'; Files = @('AGENTS.md') }
|
||||
opencode = @{ Name = 'OpenCode'; Files = @('AGENTS.md') }
|
||||
cursor = @{ Name = 'Cursor IDE'; Files = @('.cursor/rules/') }
|
||||
copilot = @{ Name = 'GitHub Copilot'; Files = @('.github/copilot-instructions.md', '.github/instructions/') }
|
||||
cline = @{ Name = 'Cline'; Files = @('.clinerules/') }
|
||||
windsurf = @{ Name = 'Windsurf'; Files = @('.windsurf/rules/') }
|
||||
roo = @{ Name = 'Roo Code'; Files = @('.roo/rules/') }
|
||||
aider = @{ Name = 'Aider'; Files = @('.aider.conf.yml', 'AGENTS.md') }
|
||||
}
|
||||
|
||||
# --- List ---
|
||||
if ($List) {
|
||||
Write-Host 'Supported AI Coding Agents:' -ForegroundColor Cyan
|
||||
Write-Host ''
|
||||
foreach ($key in $Agents.Keys) {
|
||||
$agentDef = $Agents[$key]
|
||||
$fileList = ($agentDef.Files -join ', ')
|
||||
Write-Host (' {0,-12} {1,-20} -> {2}' -f $key, $agentDef.Name, $fileList)
|
||||
}
|
||||
Write-Host ''
|
||||
Write-Host ' all All agents -> installs everything'
|
||||
Write-Host ''
|
||||
Write-Host 'Usage: .\install.ps1 -Agent <agent>' -ForegroundColor Green
|
||||
exit 0
|
||||
}
|
||||
|
||||
# --- Check deps ---
|
||||
if ($CheckDeps) {
|
||||
Write-Host '=== Running Dependency Checks ===' -ForegroundColor Cyan
|
||||
Write-Host ''
|
||||
Write-Host '--- Windows Dependencies ---' -ForegroundColor Yellow
|
||||
$winScript = Join-Path $ScriptDir 'plugins\windows-reverse-engineering\skills\windows-reverse-engineering\scripts\check-deps.ps1'
|
||||
if (Test-Path $winScript) {
|
||||
& powershell -ExecutionPolicy Bypass -File $winScript
|
||||
} else {
|
||||
Write-Host ('Windows check-deps.ps1 not found at: ' + $winScript) -ForegroundColor Red
|
||||
}
|
||||
Write-Host ''
|
||||
Write-Host '--- Android Dependencies ---' -ForegroundColor Yellow
|
||||
$androidScript = Join-Path $ScriptDir 'plugins\android-reverse-engineering\skills\android-reverse-engineering\scripts\check-deps.sh'
|
||||
if (Test-Path $androidScript) {
|
||||
$bashCmd = Get-Command bash -ErrorAction SilentlyContinue
|
||||
if ($bashCmd) {
|
||||
& bash $androidScript
|
||||
} else {
|
||||
Write-Host 'bash not found. Android dependency check requires WSL or Git Bash.' -ForegroundColor Yellow
|
||||
}
|
||||
} else {
|
||||
Write-Host ('Android check-deps.sh not found at: ' + $androidScript) -ForegroundColor Red
|
||||
}
|
||||
exit 0
|
||||
}
|
||||
|
||||
# --- Interactive mode ---
|
||||
if (-not $Agent) {
|
||||
Write-Host '+------------------------------------------------------+' -ForegroundColor Cyan
|
||||
Write-Host '| Reverse Engineering Skills - Universal Installer |' -ForegroundColor Cyan
|
||||
Write-Host '+------------------------------------------------------+' -ForegroundColor Cyan
|
||||
Write-Host ''
|
||||
Write-Host 'Which AI coding agent do you use?' -ForegroundColor Yellow
|
||||
Write-Host ''
|
||||
$i = 1
|
||||
$agentKeys = @($Agents.Keys)
|
||||
foreach ($key in $agentKeys) {
|
||||
Write-Host (' [{0}] {1,-12} ({2})' -f $i, $key, $Agents[$key].Name)
|
||||
$i++
|
||||
}
|
||||
Write-Host (' [{0}] all (Install for all agents)' -f $i)
|
||||
Write-Host ''
|
||||
|
||||
$choice = Read-Host 'Enter number or agent name'
|
||||
|
||||
if ($choice -match '^\d+$') {
|
||||
$idx = [int]$choice - 1
|
||||
if ($idx -ge 0 -and $idx -lt $agentKeys.Count) {
|
||||
$Agent = $agentKeys[$idx]
|
||||
} elseif ($idx -eq $agentKeys.Count) {
|
||||
$Agent = 'all'
|
||||
} else {
|
||||
Write-Host 'Invalid choice.' -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
} else {
|
||||
$Agent = $choice.ToLower().Trim()
|
||||
}
|
||||
}
|
||||
|
||||
# --- Target directory ---
|
||||
if (-not $Target) {
|
||||
$Target = Get-Location
|
||||
}
|
||||
|
||||
if (-not (Test-Path $Target)) {
|
||||
New-Item -ItemType Directory -Path $Target -Force | Out-Null
|
||||
}
|
||||
|
||||
$Target = (Resolve-Path $Target).Path
|
||||
|
||||
# --- Determine which agents to install ---
|
||||
if ($Agent -eq 'all') {
|
||||
$installAgents = @($Agents.Keys)
|
||||
} else {
|
||||
if (-not $Agents.ContainsKey($Agent)) {
|
||||
Write-Host ('Unknown agent: ' + $Agent) -ForegroundColor Red
|
||||
Write-Host 'Run: .\install.ps1 -List' -ForegroundColor Yellow
|
||||
exit 1
|
||||
}
|
||||
$installAgents = @($Agent)
|
||||
}
|
||||
|
||||
Write-Host ''
|
||||
Write-Host '=== Installing Reverse Engineering Skills ===' -ForegroundColor Cyan
|
||||
Write-Host ('Target: ' + $Target) -ForegroundColor DarkGray
|
||||
Write-Host ('Agents: ' + ($installAgents -join ', ')) -ForegroundColor DarkGray
|
||||
Write-Host ''
|
||||
|
||||
# --- Copy helper ---
|
||||
function Copy-SkillFile {
|
||||
param([string]$RelPath, [string]$SourceBase, [string]$DestBase)
|
||||
$src = Join-Path $SourceBase $RelPath
|
||||
$dst = Join-Path $DestBase $RelPath
|
||||
|
||||
if (-not (Test-Path $src)) {
|
||||
Write-Host (' [SKIP] ' + $RelPath + ' (source not found)') -ForegroundColor Yellow
|
||||
return $false
|
||||
}
|
||||
|
||||
$dstDir = Split-Path $dst -Parent
|
||||
if (-not (Test-Path $dstDir)) {
|
||||
New-Item -ItemType Directory -Path $dstDir -Force | Out-Null
|
||||
}
|
||||
|
||||
if (Test-Path $src -PathType Container) {
|
||||
Copy-Item -Path $src -Destination $dst -Recurse -Force
|
||||
Write-Host (' [DIR] ' + $RelPath) -ForegroundColor Green
|
||||
} else {
|
||||
Copy-Item -Path $src -Destination $dst -Force
|
||||
Write-Host (' [FILE] ' + $RelPath) -ForegroundColor Green
|
||||
}
|
||||
return $true
|
||||
}
|
||||
|
||||
# --- Always copy the plugins directory (core scripts + references) ---
|
||||
$isLocal = ($Target -eq (Resolve-Path $ScriptDir).Path)
|
||||
|
||||
if (-not $isLocal) {
|
||||
Write-Host 'Copying core plugins...' -ForegroundColor Yellow
|
||||
Copy-SkillFile 'plugins' $ScriptDir $Target | Out-Null
|
||||
}
|
||||
|
||||
# --- Install per-agent files ---
|
||||
$copiedAgents = @()
|
||||
$copiedFiles = @()
|
||||
|
||||
foreach ($agentKey in $installAgents) {
|
||||
$agentInfo = $Agents[$agentKey]
|
||||
Write-Host ''
|
||||
Write-Host ('Installing for ' + $agentInfo.Name + '...') -ForegroundColor Yellow
|
||||
|
||||
foreach ($filePath in $agentInfo.Files) {
|
||||
if ($filePath.EndsWith('/')) {
|
||||
$dirPath = $filePath.TrimEnd('/')
|
||||
$src = Join-Path $ScriptDir $dirPath
|
||||
if (Test-Path $src) {
|
||||
Copy-SkillFile $dirPath $ScriptDir $Target | Out-Null
|
||||
$copiedFiles += $dirPath
|
||||
} else {
|
||||
Write-Host (' [SKIP] ' + $dirPath + ' (not found in source)') -ForegroundColor Yellow
|
||||
}
|
||||
} else {
|
||||
$src = Join-Path $ScriptDir $filePath
|
||||
if (Test-Path $src) {
|
||||
if ($filePath -notin $copiedFiles) {
|
||||
Copy-SkillFile $filePath $ScriptDir $Target | Out-Null
|
||||
$copiedFiles += $filePath
|
||||
} else {
|
||||
Write-Host (' [SKIP] ' + $filePath + ' (already copied)') -ForegroundColor DarkGray
|
||||
}
|
||||
} else {
|
||||
Write-Host (' [SKIP] ' + $filePath + ' (not found in source)') -ForegroundColor Yellow
|
||||
}
|
||||
}
|
||||
}
|
||||
$copiedAgents += $agentInfo.Name
|
||||
}
|
||||
|
||||
# --- Summary ---
|
||||
Write-Host ''
|
||||
Write-Host '=== Installation Complete ===' -ForegroundColor Green
|
||||
Write-Host ''
|
||||
Write-Host ('Installed for: ' + ($copiedAgents -join ', ')) -ForegroundColor Cyan
|
||||
Write-Host ('Location: ' + $Target) -ForegroundColor Cyan
|
||||
Write-Host ''
|
||||
|
||||
# --- Next steps ---
|
||||
Write-Host 'Next steps:' -ForegroundColor Yellow
|
||||
Write-Host ''
|
||||
|
||||
if ('codex' -in $installAgents -or 'opencode' -in $installAgents -or 'all' -eq $Agent) {
|
||||
Write-Host ' Codex/OpenCode: AGENTS.md is automatically detected. Just start your agent.' -ForegroundColor DarkGray
|
||||
}
|
||||
if ('cursor' -in $installAgents -or 'all' -eq $Agent) {
|
||||
Write-Host ' Cursor: Rules in .cursor/rules/ are auto-loaded. Open the project in Cursor.' -ForegroundColor DarkGray
|
||||
}
|
||||
if ('copilot' -in $installAgents -or 'all' -eq $Agent) {
|
||||
Write-Host ' Copilot: Instructions in .github/ are auto-loaded in VS Code/GitHub.' -ForegroundColor DarkGray
|
||||
}
|
||||
if ('cline' -in $installAgents -or 'all' -eq $Agent) {
|
||||
Write-Host ' Cline: Rules in .clinerules/ are auto-loaded. Open project in VS Code with Cline.' -ForegroundColor DarkGray
|
||||
}
|
||||
if ('windsurf' -in $installAgents -or 'all' -eq $Agent) {
|
||||
Write-Host ' Windsurf: Rules in .windsurf/rules/ are auto-loaded. Open project in Windsurf.' -ForegroundColor DarkGray
|
||||
}
|
||||
if ('roo' -in $installAgents -or 'all' -eq $Agent) {
|
||||
Write-Host ' Roo Code: Rules in .roo/rules/ are auto-loaded. Open project in VS Code with Roo.' -ForegroundColor DarkGray
|
||||
}
|
||||
if ('aider' -in $installAgents -or 'all' -eq $Agent) {
|
||||
Write-Host ' Aider: .aider.conf.yml auto-loads AGENTS.md. Just run aider in the project.' -ForegroundColor DarkGray
|
||||
}
|
||||
if ('claude' -in $installAgents -or 'all' -eq $Agent) {
|
||||
Write-Host ' Claude Code: Plugin is auto-detected from .claude-plugin/. Just open the project.' -ForegroundColor DarkGray
|
||||
}
|
||||
|
||||
Write-Host ''
|
||||
Write-Host 'Run dependency check:' -ForegroundColor Yellow
|
||||
Write-Host ' .\install.ps1 -CheckDeps' -ForegroundColor White
|
||||
Write-Host ''
|
||||
|
|
@ -0,0 +1,282 @@
|
|||
#!/usr/bin/env bash
|
||||
# install.sh — Universal installer for reverse engineering skills
|
||||
# Installs agent-specific instruction files for any supported AI coding agent.
|
||||
#
|
||||
# Usage:
|
||||
# ./install.sh # Interactive mode
|
||||
# ./install.sh --agent cursor # Install for Cursor
|
||||
# ./install.sh --agent all # Install for all agents
|
||||
# ./install.sh --agent copilot --target ~/my-project
|
||||
# ./install.sh --list # List available agents
|
||||
# ./install.sh --check-deps # Run dependency check only
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
AGENT=""
|
||||
TARGET=""
|
||||
LIST=false
|
||||
CHECK_DEPS=false
|
||||
|
||||
# --- Parse arguments ---
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--agent|-a) AGENT="${2,,}"; shift 2 ;;
|
||||
--target|-t) TARGET="$2"; shift 2 ;;
|
||||
--list|-l) LIST=true; shift ;;
|
||||
--check-deps) CHECK_DEPS=true; shift ;;
|
||||
--help|-h)
|
||||
cat <<'EOF'
|
||||
Reverse Engineering Skills — Universal Installer
|
||||
|
||||
Usage:
|
||||
./install.sh Interactive mode (choose agent)
|
||||
./install.sh --agent <agent> Install for a specific agent
|
||||
./install.sh --agent all Install for all agents
|
||||
./install.sh --agent <agent> --target <dir> Install into another project
|
||||
./install.sh --list List supported agents
|
||||
./install.sh --check-deps Run dependency check only
|
||||
|
||||
Agents:
|
||||
claude — Claude Code (.claude-plugin/)
|
||||
codex — OpenAI Codex (AGENTS.md)
|
||||
opencode — OpenCode (AGENTS.md)
|
||||
cursor — Cursor IDE (.cursor/rules/*.mdc)
|
||||
copilot — GitHub Copilot (.github/instructions/)
|
||||
cline — Cline (.clinerules/)
|
||||
windsurf — Windsurf (.windsurf/rules/)
|
||||
roo — Roo Code (.roo/rules/)
|
||||
aider — Aider (.aider.conf.yml)
|
||||
all — Install for all agents at once
|
||||
EOF
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1"
|
||||
echo "Run: ./install.sh --help"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
VALID_AGENTS=(claude codex opencode cursor copilot cline windsurf roo aider)
|
||||
|
||||
# --- List ---
|
||||
if $LIST; then
|
||||
echo "Supported AI Coding Agents:"
|
||||
echo ""
|
||||
echo " claude Claude Code -> .claude-plugin/"
|
||||
echo " codex OpenAI Codex -> AGENTS.md"
|
||||
echo " opencode OpenCode -> AGENTS.md"
|
||||
echo " cursor Cursor IDE -> .cursor/rules/*.mdc"
|
||||
echo " copilot GitHub Copilot -> .github/instructions/"
|
||||
echo " cline Cline -> .clinerules/"
|
||||
echo " windsurf Windsurf -> .windsurf/rules/"
|
||||
echo " roo Roo Code -> .roo/rules/"
|
||||
echo " aider Aider -> .aider.conf.yml + AGENTS.md"
|
||||
echo ""
|
||||
echo " all All agents -> installs everything"
|
||||
echo ""
|
||||
echo "Usage: ./install.sh --agent <agent>"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# --- Check deps ---
|
||||
if $CHECK_DEPS; then
|
||||
echo "=== Running Dependency Checks ==="
|
||||
echo ""
|
||||
echo "--- Windows Dependencies ---"
|
||||
WIN_SCRIPT="$SCRIPT_DIR/plugins/windows-reverse-engineering/skills/windows-reverse-engineering/scripts/check-deps.ps1"
|
||||
if command -v powershell &>/dev/null && [ -f "$WIN_SCRIPT" ]; then
|
||||
powershell -ExecutionPolicy Bypass -File "$WIN_SCRIPT" || true
|
||||
elif command -v pwsh &>/dev/null && [ -f "$WIN_SCRIPT" ]; then
|
||||
pwsh -ExecutionPolicy Bypass -File "$WIN_SCRIPT" || true
|
||||
else
|
||||
echo "PowerShell not available. Skipping Windows dependency check."
|
||||
fi
|
||||
echo ""
|
||||
echo "--- Android Dependencies ---"
|
||||
ANDROID_SCRIPT="$SCRIPT_DIR/plugins/android-reverse-engineering/skills/android-reverse-engineering/scripts/check-deps.sh"
|
||||
if [ -f "$ANDROID_SCRIPT" ]; then
|
||||
bash "$ANDROID_SCRIPT" || true
|
||||
else
|
||||
echo "Android check-deps.sh not found."
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# --- Interactive mode ---
|
||||
if [ -z "$AGENT" ]; then
|
||||
echo "╔══════════════════════════════════════════════════════╗"
|
||||
echo "║ Reverse Engineering Skills — Universal Installer ║"
|
||||
echo "╚══════════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
echo "Which AI coding agent do you use?"
|
||||
echo ""
|
||||
for i in "${!VALID_AGENTS[@]}"; do
|
||||
printf " [%d] %s\n" $((i+1)) "${VALID_AGENTS[$i]}"
|
||||
done
|
||||
printf " [%d] all (install for all agents)\n" $(( ${#VALID_AGENTS[@]} + 1 ))
|
||||
echo ""
|
||||
read -rp "Enter number or agent name: " CHOICE
|
||||
|
||||
if [[ "$CHOICE" =~ ^[0-9]+$ ]]; then
|
||||
IDX=$((CHOICE - 1))
|
||||
if [ "$IDX" -ge 0 ] && [ "$IDX" -lt "${#VALID_AGENTS[@]}" ]; then
|
||||
AGENT="${VALID_AGENTS[$IDX]}"
|
||||
elif [ "$IDX" -eq "${#VALID_AGENTS[@]}" ]; then
|
||||
AGENT="all"
|
||||
else
|
||||
echo "Invalid choice."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
AGENT="${CHOICE,,}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- Validate agent ---
|
||||
if [ "$AGENT" != "all" ]; then
|
||||
FOUND=false
|
||||
for a in "${VALID_AGENTS[@]}"; do
|
||||
if [ "$a" = "$AGENT" ]; then
|
||||
FOUND=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
if ! $FOUND; then
|
||||
echo "Unknown agent: $AGENT"
|
||||
echo "Run: ./install.sh --list"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- Target directory ---
|
||||
if [ -z "$TARGET" ]; then
|
||||
TARGET="$(pwd)"
|
||||
fi
|
||||
|
||||
mkdir -p "$TARGET"
|
||||
TARGET="$(cd "$TARGET" && pwd)"
|
||||
|
||||
# --- Determine agents to install ---
|
||||
if [ "$AGENT" = "all" ]; then
|
||||
INSTALL_AGENTS=("${VALID_AGENTS[@]}")
|
||||
else
|
||||
INSTALL_AGENTS=("$AGENT")
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=== Installing Reverse Engineering Skills ==="
|
||||
echo "Target: $TARGET"
|
||||
echo "Agents: ${INSTALL_AGENTS[*]}"
|
||||
echo ""
|
||||
|
||||
# --- Copy helper ---
|
||||
copy_skill() {
|
||||
local rel_path="$1"
|
||||
local src="$SCRIPT_DIR/$rel_path"
|
||||
local dst="$TARGET/$rel_path"
|
||||
|
||||
if [ ! -e "$src" ]; then
|
||||
echo " [SKIP] $rel_path (source not found)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
mkdir -p "$(dirname "$dst")"
|
||||
|
||||
if [ -d "$src" ]; then
|
||||
cp -r "$src" "$(dirname "$dst")/"
|
||||
echo " [DIR] $rel_path"
|
||||
else
|
||||
cp "$src" "$dst"
|
||||
echo " [FILE] $rel_path"
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# --- Copy core plugins if installing to a different directory ---
|
||||
IS_LOCAL=false
|
||||
if [ "$TARGET" = "$SCRIPT_DIR" ]; then
|
||||
IS_LOCAL=true
|
||||
fi
|
||||
|
||||
if ! $IS_LOCAL; then
|
||||
echo "Copying core plugins..."
|
||||
copy_skill "plugins" || true
|
||||
fi
|
||||
|
||||
# --- Agent file map ---
|
||||
COPIED_FILES=()
|
||||
|
||||
install_agent() {
|
||||
local agent_key="$1"
|
||||
|
||||
case "$agent_key" in
|
||||
claude)
|
||||
echo ""
|
||||
echo "Installing for Claude Code..."
|
||||
copy_skill ".claude-plugin" || true
|
||||
;;
|
||||
codex|opencode)
|
||||
echo ""
|
||||
echo "Installing for $([ "$agent_key" = "codex" ] && echo "OpenAI Codex" || echo "OpenCode")..."
|
||||
if [[ ! " ${COPIED_FILES[*]:-} " =~ " AGENTS.md " ]]; then
|
||||
copy_skill "AGENTS.md" || true
|
||||
COPIED_FILES+=("AGENTS.md")
|
||||
else
|
||||
echo " [SKIP] AGENTS.md (already copied)"
|
||||
fi
|
||||
;;
|
||||
cursor)
|
||||
echo ""
|
||||
echo "Installing for Cursor IDE..."
|
||||
copy_skill ".cursor/rules" || true
|
||||
;;
|
||||
copilot)
|
||||
echo ""
|
||||
echo "Installing for GitHub Copilot..."
|
||||
copy_skill ".github/copilot-instructions.md" || true
|
||||
copy_skill ".github/instructions" || true
|
||||
;;
|
||||
cline)
|
||||
echo ""
|
||||
echo "Installing for Cline..."
|
||||
copy_skill ".clinerules" || true
|
||||
;;
|
||||
windsurf)
|
||||
echo ""
|
||||
echo "Installing for Windsurf..."
|
||||
copy_skill ".windsurf/rules" || true
|
||||
;;
|
||||
roo)
|
||||
echo ""
|
||||
echo "Installing for Roo Code..."
|
||||
copy_skill ".roo/rules" || true
|
||||
;;
|
||||
aider)
|
||||
echo ""
|
||||
echo "Installing for Aider..."
|
||||
copy_skill ".aider.conf.yml" || true
|
||||
if [[ ! " ${COPIED_FILES[*]:-} " =~ " AGENTS.md " ]]; then
|
||||
copy_skill "AGENTS.md" || true
|
||||
COPIED_FILES+=("AGENTS.md")
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
for agent_key in "${INSTALL_AGENTS[@]}"; do
|
||||
install_agent "$agent_key"
|
||||
done
|
||||
|
||||
# --- Summary ---
|
||||
echo ""
|
||||
echo "=== Installation Complete ==="
|
||||
echo ""
|
||||
echo "Installed for: ${INSTALL_AGENTS[*]}"
|
||||
echo "Location: $TARGET"
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo " Run dependency check: ./install.sh --check-deps"
|
||||
echo ""
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"name": "windows-reverse-engineering",
|
||||
"version": "1.0.0",
|
||||
"description": "Decompile Windows EXE/DLL/.NET assemblies with Ghidra and ILSpy, trace call flows, and document extracted Win32/network APIs.",
|
||||
"author": {
|
||||
"name": "Simone Avogadro"
|
||||
},
|
||||
"repository": "https://github.com/SimoneAvogadro/android-reverse-engineering-skill",
|
||||
"license": "Apache-2.0",
|
||||
"keywords": ["windows", "reverse-engineering", "exe", "dll", "ghidra", "ilspy", "decompile", "pe-analysis", "api-extraction"],
|
||||
"skills": "./skills/",
|
||||
"commands": "./commands/"
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
---
|
||||
allowed-tools: Bash, Read, Glob, Grep, Write, Edit
|
||||
description: Decompile a Windows EXE/DLL/.NET assembly and analyze its structure
|
||||
user-invocable: true
|
||||
argument-hint: <path to EXE, DLL, or .NET assembly>
|
||||
argument: path to EXE, DLL, or .NET assembly file (optional)
|
||||
---
|
||||
|
||||
# /decompile
|
||||
|
||||
Decompile a Windows application and perform initial structure analysis.
|
||||
|
||||
## Instructions
|
||||
|
||||
You are starting the Windows reverse engineering workflow. Follow these steps:
|
||||
|
||||
### Step 1: Get the target file
|
||||
|
||||
If the user provided a file path as an argument, use that. Otherwise, ask the user for the path to the EXE, DLL, or .NET assembly they want to decompile.
|
||||
|
||||
### Step 2: Check PowerShell execution policy
|
||||
|
||||
Before running any scripts, ensure PowerShell can execute `.ps1` files. Run:
|
||||
|
||||
```powershell
|
||||
$policy = Get-ExecutionPolicy -Scope CurrentUser
|
||||
if ($policy -eq 'Restricted' -or $policy -eq 'AllSigned') {
|
||||
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned -Force
|
||||
Write-Host "Execution policy updated to RemoteSigned for current user."
|
||||
}
|
||||
```
|
||||
|
||||
If setting the execution policy fails (e.g., group policy override), fall back to running scripts with:
|
||||
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File <script.ps1>
|
||||
```
|
||||
|
||||
### Step 3: Check and install dependencies
|
||||
|
||||
Run the dependency check:
|
||||
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File "${CLAUDE_PLUGIN_ROOT}/skills/windows-reverse-engineering/scripts/check-deps.ps1"
|
||||
```
|
||||
|
||||
Parse the output looking for `INSTALL_REQUIRED:` and `INSTALL_OPTIONAL:` lines.
|
||||
|
||||
**If required dependencies are missing**, install them one by one:
|
||||
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File "${CLAUDE_PLUGIN_ROOT}/skills/windows-reverse-engineering/scripts/install-dep.ps1" java
|
||||
powershell -ExecutionPolicy Bypass -File "${CLAUDE_PLUGIN_ROOT}/skills/windows-reverse-engineering/scripts/install-dep.ps1" ghidra
|
||||
powershell -ExecutionPolicy Bypass -File "${CLAUDE_PLUGIN_ROOT}/skills/windows-reverse-engineering/scripts/install-dep.ps1" ilspycmd
|
||||
```
|
||||
|
||||
The install script uses winget, Chocolatey, dotnet tool, or direct GitHub download. If an installer requires admin privileges the user doesn't have, it prints manual instructions (exit code 2). Show those to the user and stop.
|
||||
|
||||
**For optional dependencies** (`INSTALL_OPTIONAL:dumpbin`, `INSTALL_OPTIONAL:strings`, etc.), ask the user if they want to install them. Recommend strings for embedded URL/key extraction.
|
||||
|
||||
> **Note**: `dumpbin` requires Visual Studio C++ Build Tools. Make the user aware of this requirement if they want to use it.
|
||||
|
||||
After any installations, re-run `check-deps.ps1` to verify. Do not proceed until all required dependencies pass.
|
||||
|
||||
### Step 4: Decompile
|
||||
|
||||
Run the decompile script on the target file:
|
||||
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File "${CLAUDE_PLUGIN_ROOT}/skills/windows-reverse-engineering/scripts/decompile.ps1" <file>
|
||||
```
|
||||
|
||||
The script auto-detects the binary type:
|
||||
- **.NET assembly** (imports `mscoree.dll`, has CLI header) → decompiles with `ilspycmd` to C# source
|
||||
- **Native PE** (C/C++ compiled EXE/DLL/SYS) → decompiles with Ghidra headless to C pseudocode
|
||||
|
||||
The user can override detection with `-Engine ghidra` or `-Engine ilspy`.
|
||||
|
||||
For packed/obfuscated binaries (if the user mentions it or you detect high-entropy sections), note this and suggest manual unpacking before decompilation.
|
||||
|
||||
### Step 5: Analyze structure
|
||||
|
||||
After decompilation completes:
|
||||
|
||||
1. Review the PE header summary from the decompile output (architecture, subsystem, entry point)
|
||||
2. Review the import table — which DLLs and functions does the binary use?
|
||||
3. Review the export table (for DLLs) — what does the binary expose?
|
||||
4. List the top-level source structure (packages/namespaces for .NET, function groups for native)
|
||||
5. Identify the app's entry point and architecture pattern
|
||||
6. Report a summary to the user
|
||||
|
||||
### Step 6: Offer next steps
|
||||
|
||||
Tell the user what they can do next:
|
||||
- **Trace call flows**: "I can follow the execution flow from the entry point to network/API calls"
|
||||
- **Extract APIs**: "I can search for all Win32 API calls, network endpoints, registry operations, and hardcoded secrets"
|
||||
- **Analyze specific functions**: "Point me to a specific function or class to analyze in detail"
|
||||
- **Re-decompile with a different engine**: If auto-detection chose the wrong engine, offer to re-run
|
||||
|
||||
Refer to the full skill documentation in `${CLAUDE_PLUGIN_ROOT}/skills/windows-reverse-engineering/SKILL.md` for the complete workflow.
|
||||
|
|
@ -0,0 +1,300 @@
|
|||
---
|
||||
description: Decompile Windows EXE, DLL, and .NET assemblies using Ghidra or ILSpy. Reverse engineer Windows apps, extract Win32 API calls, network endpoints, registry operations, and trace call flows from entry points to network layer. Use when the user wants to decompile, analyze, or reverse engineer Windows binaries, find API endpoints, or follow call flows.
|
||||
trigger: decompile EXE|decompile DLL|reverse engineer Windows|extract API|analyze Windows|ghidra|ilspy|follow call flow|decompile .NET|Windows reverse engineering|find API endpoints|PE analysis|Win32 API
|
||||
---
|
||||
|
||||
# Windows Reverse Engineering
|
||||
|
||||
Decompile Windows EXE, DLL, SYS, and .NET assemblies using Ghidra (headless) and ILSpy (ilspycmd), trace call flows through application code, and produce structured documentation of extracted APIs — Win32 calls, network endpoints, registry operations, cryptographic usage, and more.
|
||||
|
||||
Two decompiler engines are supported:
|
||||
- **Ghidra** — for native C/C++ PE binaries (produces C pseudocode)
|
||||
- **ILSpy (ilspycmd)** — for .NET assemblies (produces C# source)
|
||||
|
||||
The skill auto-detects the binary type and selects the appropriate engine.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
This skill requires the following to be installed:
|
||||
|
||||
**Required (at least one decompiler):**
|
||||
- **Java JDK 17+** — needed by Ghidra
|
||||
- **Ghidra** — for native PE decompilation (set `GHIDRA_INSTALL_DIR` environment variable)
|
||||
- **ilspycmd** — for .NET assembly decompilation (install via `dotnet tool install -g ilspycmd`)
|
||||
|
||||
**Optional (recommended):**
|
||||
- **strings / strings2** — extract embedded strings from binaries
|
||||
- **dumpbin** — PE header and import/export analysis (requires Visual Studio C++ Build Tools)
|
||||
- **de4dot** — .NET deobfuscator for obfuscated assemblies
|
||||
- **x64dbg** — dynamic debugging (manual use)
|
||||
|
||||
Run the dependency checker to verify:
|
||||
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File "${CLAUDE_PLUGIN_ROOT}/skills/windows-reverse-engineering/scripts/check-deps.ps1"
|
||||
```
|
||||
|
||||
If anything is missing, follow the installation instructions in `${CLAUDE_PLUGIN_ROOT}/skills/windows-reverse-engineering/references/setup-guide.md`.
|
||||
|
||||
## PowerShell Execution Policy
|
||||
|
||||
All scripts in this skill are PowerShell `.ps1` files. If the system execution policy blocks script execution, automatically adjust it:
|
||||
|
||||
```powershell
|
||||
# Check current policy
|
||||
$policy = Get-ExecutionPolicy -Scope CurrentUser
|
||||
|
||||
# Auto-fix if restricted
|
||||
if ($policy -eq 'Restricted' -or $policy -eq 'AllSigned') {
|
||||
try {
|
||||
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned -Force
|
||||
} catch {
|
||||
# Group policy may prevent changes — use Bypass flag per invocation
|
||||
# Run all scripts as: powershell -ExecutionPolicy Bypass -File <script.ps1>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If `Set-ExecutionPolicy` fails due to group policy, run all scripts with:
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File <script.ps1> [args]
|
||||
```
|
||||
|
||||
## Workflow
|
||||
|
||||
### Phase 1: Verify and Install Dependencies
|
||||
|
||||
Before decompiling, confirm that the required tools are available — and install any that are missing.
|
||||
|
||||
**Action**: Run the dependency check script.
|
||||
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File "${CLAUDE_PLUGIN_ROOT}/skills/windows-reverse-engineering/scripts/check-deps.ps1"
|
||||
```
|
||||
|
||||
The output contains machine-readable lines:
|
||||
- `INSTALL_REQUIRED:<dep>` — must be installed before proceeding
|
||||
- `INSTALL_OPTIONAL:<dep>` — recommended but not blocking
|
||||
|
||||
**If required dependencies are missing** (exit code 1), install them automatically:
|
||||
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File "${CLAUDE_PLUGIN_ROOT}/skills/windows-reverse-engineering/scripts/install-dep.ps1" <dep>
|
||||
```
|
||||
|
||||
The install script detects available package managers (winget, Chocolatey, dotnet), then:
|
||||
- Installs without admin when possible (user-local installs, dotnet global tools)
|
||||
- Uses winget or Chocolatey when available
|
||||
- If admin is needed but unavailable, it prints the exact manual command and exits with code 2 — show these instructions to the user
|
||||
|
||||
**For optional dependencies**, ask the user if they want to install them.
|
||||
|
||||
> **Important**: `dumpbin` requires **Visual Studio C++ Build Tools** to be installed. If the user wants PE import/export analysis via dumpbin, they must install the Build Tools from https://visualstudio.microsoft.com/visual-cpp-build-tools/. Alternatively, Ghidra can extract the same information.
|
||||
|
||||
After installation, re-run `check-deps.ps1` to confirm everything is in place. Do not proceed to Phase 2 until at least one decompiler (Ghidra or ilspycmd) is available.
|
||||
|
||||
### Phase 2: Detect and Decompile
|
||||
|
||||
Use the decompile wrapper script to process the target file. The script auto-detects the binary type and selects the appropriate engine.
|
||||
|
||||
**Action**: Run the decompile script.
|
||||
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File "${CLAUDE_PLUGIN_ROOT}/skills/windows-reverse-engineering/scripts/decompile.ps1" [OPTIONS] <file>
|
||||
```
|
||||
|
||||
Options:
|
||||
- `-Output <dir>` — Custom output directory (default: `<filename>-decompiled`)
|
||||
- `-Engine auto|ghidra|ilspy` — Decompiler engine (default: `auto`)
|
||||
- `-NoStrings` — Skip strings extraction (faster)
|
||||
|
||||
**Auto-detection logic**:
|
||||
|
||||
| Binary Type | Detection | Engine |
|
||||
|---|---|---|
|
||||
| .NET assembly (C#/VB.NET/F#) | Imports `mscoree.dll`, has CLI header | `ilspy` |
|
||||
| Native C/C++ EXE/DLL | Standard PE without .NET metadata | `ghidra` |
|
||||
| Kernel driver (.sys) | PE with `native` subsystem | `ghidra` |
|
||||
| Packed/obfuscated | High-entropy `.text` section | Warn user, attempt `ghidra` |
|
||||
|
||||
**Engine selection strategy**:
|
||||
|
||||
| Situation | Engine |
|
||||
|---|---|
|
||||
| .NET assembly (any) | `ilspy` — produces clean C# source |
|
||||
| Native EXE/DLL | `ghidra` — produces C pseudocode |
|
||||
| .NET but obfuscated (Dotfuscator, ConfuserEx) | Run `de4dot` first, then `ilspy` |
|
||||
| Quick overview of imports only | Skip decompilation, use `dumpbin /imports` |
|
||||
| Mixed-mode .NET (native + managed) | `ghidra` for native, `ilspy` for managed |
|
||||
|
||||
**ILSpy output**:
|
||||
- `<output>/sources/` — Decompiled C# source files with project structure
|
||||
- `<output>/sources/*.csproj` — Reconstructed project file
|
||||
|
||||
**Ghidra output**:
|
||||
- `<output>/decompiled/` — C pseudocode files per function
|
||||
- `<output>/imports.txt` — Import table listing
|
||||
- `<output>/exports.txt` — Export table listing (DLLs)
|
||||
- `<output>/strings.txt` — Extracted string references
|
||||
|
||||
See `${CLAUDE_PLUGIN_ROOT}/skills/windows-reverse-engineering/references/ghidra-headless-usage.md` and `${CLAUDE_PLUGIN_ROOT}/skills/windows-reverse-engineering/references/ilspy-usage.md` for the full CLI references.
|
||||
|
||||
### Phase 3: Analyze Structure
|
||||
|
||||
Navigate the decompiled output to understand the application's architecture.
|
||||
|
||||
**Actions**:
|
||||
|
||||
1. **Review PE headers** from the decompile output or run separately:
|
||||
- Architecture: x86, x64, ARM64
|
||||
- Subsystem: console, GUI, driver, native
|
||||
- Entry point address
|
||||
- Compile timestamp
|
||||
- Check for ASLR, DEP, code signing
|
||||
|
||||
2. **Survey the import table** — this is the single most revealing artifact:
|
||||
- `kernel32.dll` — file I/O, process management, memory
|
||||
- `user32.dll` — GUI, window messages, clipboard
|
||||
- `advapi32.dll` — registry, services, security
|
||||
- `ws2_32.dll` / `winhttp.dll` / `wininet.dll` — networking
|
||||
- `crypt32.dll` / `bcrypt.dll` — cryptography
|
||||
- `ole32.dll` / `oleaut32.dll` — COM/OLE
|
||||
- `mscoree.dll` — .NET runtime
|
||||
- Unusual DLLs may indicate specific libraries or custom functionality
|
||||
|
||||
3. **Survey the export table** (for DLLs):
|
||||
- What functions does this DLL expose?
|
||||
- Are exports named or ordinal-only (indicates possible evasion)?
|
||||
|
||||
4. **For .NET assemblies**, examine:
|
||||
- Namespace structure under `<output>/sources/`
|
||||
- Referenced assemblies (NuGet packages used)
|
||||
- Look for namespaces containing `Api`, `Http`, `Client`, `Service`, `Data`, `Repository`
|
||||
- Identify the DI container setup (Startup.cs, Program.cs)
|
||||
|
||||
5. **For native binaries**, examine:
|
||||
- Top-level function list from Ghidra output
|
||||
- Group functions by calling convention and purpose
|
||||
- Identify the main entry point and initialization routines
|
||||
- Look for C++ class structures (vtables, RTTI)
|
||||
|
||||
6. **Identify the architecture pattern**:
|
||||
- **WinForms/WPF**: look for `Form`, `Window`, `UserControl` classes
|
||||
- **ASP.NET**: look for `Controller`, `Startup`, `Program` classes
|
||||
- **Windows Service**: look for `ServiceBase`, `OnStart`, `OnStop`
|
||||
- **Native GUI**: look for `CreateWindowEx`, `RegisterClassEx`, `WndProc`
|
||||
- **Console**: look for `Main` with argument parsing
|
||||
|
||||
### Phase 4: Trace Call Flows
|
||||
|
||||
Follow execution paths from entry points down to API calls.
|
||||
|
||||
**Actions**:
|
||||
|
||||
1. **Start from entry points**:
|
||||
- **Native**: `WinMain`, `wWinMain`, `main`, `DllMain`, `ServiceMain`, `DriverEntry`
|
||||
- **.NET**: `static void Main()`, `Program.cs`, `Startup.cs`
|
||||
|
||||
2. **Follow the initialization chain**:
|
||||
- Native: global constructors → `WinMain` → window creation → message loop
|
||||
- .NET: `Main()` → `HostBuilder` → dependency injection → `Startup.ConfigureServices()`
|
||||
|
||||
3. **Trace user actions**:
|
||||
- **Native GUI**: `WndProc` → `WM_COMMAND` handler → business logic → API calls
|
||||
- **WinForms**: button click event → method → service call → HTTP request
|
||||
- **.NET Web**: HTTP request → Controller → Service → Repository → external API
|
||||
|
||||
4. **Map dependency injection** (.NET):
|
||||
- Find `AddScoped`, `AddSingleton`, `AddTransient` registrations
|
||||
- Trace interface → implementation bindings
|
||||
- Follow `IHttpClientFactory` registrations for named HTTP clients
|
||||
|
||||
5. **Handle obfuscated code**:
|
||||
- **Native**: stripped symbols — use import calls and string refs as anchors
|
||||
- **.NET obfuscated**: run `de4dot` first, then string literals and framework types remain readable
|
||||
- **Packed**: detect UPX or custom packers — suggest dynamic analysis or manual unpacking
|
||||
|
||||
See `${CLAUDE_PLUGIN_ROOT}/skills/windows-reverse-engineering/references/call-flow-analysis.md` for detailed techniques.
|
||||
|
||||
### Phase 5: Extract and Document APIs
|
||||
|
||||
Find all API calls and produce structured documentation.
|
||||
|
||||
**Action**: Run the API search script for a broad sweep.
|
||||
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File "${CLAUDE_PLUGIN_ROOT}/skills/windows-reverse-engineering/scripts/find-api-calls.ps1" <output>/sources/
|
||||
```
|
||||
|
||||
Targeted searches:
|
||||
```powershell
|
||||
# Only network calls
|
||||
powershell -ExecutionPolicy Bypass -File "..." <output>/sources/ --network
|
||||
|
||||
# Only registry operations
|
||||
powershell -ExecutionPolicy Bypass -File "..." <output>/sources/ --registry
|
||||
|
||||
# Only hardcoded URLs and secrets
|
||||
powershell -ExecutionPolicy Bypass -File "..." <output>/sources/ --urls
|
||||
|
||||
# Only authentication patterns
|
||||
powershell -ExecutionPolicy Bypass -File "..." <output>/sources/ --auth
|
||||
|
||||
# Only process manipulation (injection indicators)
|
||||
powershell -ExecutionPolicy Bypass -File "..." <output>/sources/ --process
|
||||
```
|
||||
|
||||
Then, for each discovered API call, read the surrounding source code to extract:
|
||||
- API function name and DLL
|
||||
- Parameters and their values/sources
|
||||
- Return value handling
|
||||
- Where it's called from (the call chain from Phase 4)
|
||||
- Purpose in the application's workflow
|
||||
|
||||
**Document each API interaction** using this format:
|
||||
|
||||
```markdown
|
||||
### `FunctionName` (source DLL)
|
||||
|
||||
- **Source**: `filename.c:42` or `Namespace.ClassName` (ClassName.cs:42)
|
||||
- **Category**: Network / Registry / File I/O / Process / Crypto / COM
|
||||
- **Parameters**:
|
||||
- `param1`: value or source
|
||||
- `param2`: value or source
|
||||
- **Return handling**: checked / ignored / stored in `variable`
|
||||
- **Called from**: `Main → InitNetwork → HttpClient → WinHttpSendRequest`
|
||||
- **Purpose**: Sends user credentials to remote server
|
||||
```
|
||||
|
||||
For network endpoints specifically:
|
||||
|
||||
```markdown
|
||||
### `POST https://api.example.com/v1/auth/login`
|
||||
|
||||
- **Source**: `NetworkManager.cs:87`
|
||||
- **Method**: POST (via HttpClient)
|
||||
- **Headers**: `Authorization: Bearer <token>`, `Content-Type: application/json`
|
||||
- **Request body**: `{ "username": "string", "password": "string" }`
|
||||
- **Response type**: `LoginResponse { token: string, userId: int }`
|
||||
- **Called from**: `LoginForm.btnLogin_Click → AuthService.Login → HttpClient.PostAsync`
|
||||
```
|
||||
|
||||
See `${CLAUDE_PLUGIN_ROOT}/skills/windows-reverse-engineering/references/api-extraction-patterns.md` for Windows-specific search patterns and the full documentation template.
|
||||
|
||||
## Output
|
||||
|
||||
At the end of the workflow, deliver:
|
||||
|
||||
1. **Decompiled source** in the output directory (C pseudocode or C# source)
|
||||
2. **PE analysis summary** — architecture, imports, exports, sections, security features
|
||||
3. **Architecture summary** — app structure, main namespaces/modules, pattern used
|
||||
4. **API documentation** — all discovered Win32/network/registry/crypto calls in the format above
|
||||
5. **Call flow map** — key paths from entry point to interesting API calls (especially networking and persistence)
|
||||
|
||||
## References
|
||||
|
||||
- `${CLAUDE_PLUGIN_ROOT}/skills/windows-reverse-engineering/references/setup-guide.md` — Installing Java, Ghidra, ILSpy, strings, and optional tools on Windows
|
||||
- `${CLAUDE_PLUGIN_ROOT}/skills/windows-reverse-engineering/references/ghidra-headless-usage.md` — Ghidra headless CLI and scripting reference
|
||||
- `${CLAUDE_PLUGIN_ROOT}/skills/windows-reverse-engineering/references/ilspy-usage.md` — ilspycmd CLI options and .NET decompilation workflows
|
||||
- `${CLAUDE_PLUGIN_ROOT}/skills/windows-reverse-engineering/references/api-extraction-patterns.md` — Windows-specific search patterns and documentation template
|
||||
- `${CLAUDE_PLUGIN_ROOT}/skills/windows-reverse-engineering/references/call-flow-analysis.md` — Techniques for tracing call flows in Windows binaries
|
||||
|
|
@ -0,0 +1,228 @@
|
|||
# API Extraction Patterns
|
||||
|
||||
Patterns and Select-String commands for finding API calls, network endpoints, and secrets in decompiled Windows source code. Works on both Ghidra C pseudocode output and ILSpy C# output.
|
||||
|
||||
## Network — Win32 API (Native)
|
||||
|
||||
### WinHTTP
|
||||
|
||||
```powershell
|
||||
# WinHTTP functions
|
||||
Select-String -Path "sources\*" -Pattern 'WinHttpOpen|WinHttpConnect|WinHttpOpenRequest|WinHttpSendRequest|WinHttpReceiveResponse|WinHttpReadData|WinHttpSetOption' -Recurse
|
||||
|
||||
# WinHTTP URL construction
|
||||
Select-String -Path "sources\*" -Pattern 'WinHttpCrackUrl|WinHttpCreateUrl' -Recurse
|
||||
```
|
||||
|
||||
### WinINet
|
||||
|
||||
```powershell
|
||||
# WinINet functions
|
||||
Select-String -Path "sources\*" -Pattern 'InternetOpen|InternetConnect|HttpOpenRequest|HttpSendRequest|InternetReadFile|InternetCloseHandle|InternetSetOption' -Recurse
|
||||
|
||||
# FTP via WinINet
|
||||
Select-String -Path "sources\*" -Pattern 'FtpOpenFile|FtpGetFile|FtpPutFile|FtpFindFirstFile' -Recurse
|
||||
```
|
||||
|
||||
### Winsock
|
||||
|
||||
```powershell
|
||||
# Socket operations
|
||||
Select-String -Path "sources\*" -Pattern 'WSAStartup|socket\(|connect\(|send\(|recv\(|bind\(|listen\(|accept\(|closesocket|getaddrinfo|gethostbyname' -Recurse
|
||||
|
||||
# Higher-level winsock
|
||||
Select-String -Path "sources\*" -Pattern 'WSASocket|WSASend|WSARecv|WSAConnect|WSAAsyncSelect' -Recurse
|
||||
```
|
||||
|
||||
## Network — .NET
|
||||
|
||||
### HttpClient (modern)
|
||||
|
||||
```powershell
|
||||
# HttpClient usage
|
||||
Select-String -Path "sources\*" -Pattern 'HttpClient|GetAsync|PostAsync|PutAsync|DeleteAsync|SendAsync|GetStringAsync|GetStreamAsync' -Recurse
|
||||
|
||||
# HttpClientFactory
|
||||
Select-String -Path "sources\*" -Pattern 'IHttpClientFactory|AddHttpClient|CreateClient' -Recurse
|
||||
|
||||
# Request construction
|
||||
Select-String -Path "sources\*" -Pattern 'HttpRequestMessage|StringContent|JsonContent|FormUrlEncodedContent|MultipartFormDataContent' -Recurse
|
||||
```
|
||||
|
||||
### WebRequest (legacy)
|
||||
|
||||
```powershell
|
||||
Select-String -Path "sources\*" -Pattern 'WebRequest|HttpWebRequest|WebClient|DownloadString|DownloadFile|UploadString|UploadFile' -Recurse
|
||||
```
|
||||
|
||||
### RestSharp / Refit
|
||||
|
||||
```powershell
|
||||
Select-String -Path "sources\*" -Pattern 'RestClient|RestRequest|RestResponse|IRestClient' -Recurse
|
||||
Select-String -Path "sources\*" -Pattern '\[Get\(|Post\(|Put\(|Delete\(|Patch\(' -Recurse
|
||||
```
|
||||
|
||||
## Registry Operations
|
||||
|
||||
### Native
|
||||
|
||||
```powershell
|
||||
Select-String -Path "sources\*" -Pattern 'RegOpenKey|RegCreateKey|RegSetValue|RegQueryValue|RegDeleteKey|RegDeleteValue|RegEnumKey|RegEnumValue|RegCloseKey|RegNotifyChangeKeyValue' -Recurse
|
||||
```
|
||||
|
||||
### .NET
|
||||
|
||||
```powershell
|
||||
Select-String -Path "sources\*" -Pattern 'Microsoft\.Win32\.Registry|RegistryKey|OpenSubKey|SetValue|GetValue|CreateSubKey|DeleteSubKey' -Recurse
|
||||
```
|
||||
|
||||
## File System Operations
|
||||
|
||||
### Native
|
||||
|
||||
```powershell
|
||||
Select-String -Path "sources\*" -Pattern 'CreateFile[AW]?|ReadFile|WriteFile|DeleteFile[AW]?|CopyFile[AW]?|MoveFile[AW]?|FindFirstFile[AW]?|FindNextFile[AW]?|GetFileAttributes|SetFileAttributes|CreateDirectory[AW]?' -Recurse
|
||||
```
|
||||
|
||||
### .NET
|
||||
|
||||
```powershell
|
||||
Select-String -Path "sources\*" -Pattern 'File\.(Read|Write|Append|Copy|Move|Delete|Exists|Open|Create)|Directory\.(Create|Delete|Exists|GetFiles|GetDirectories)|FileStream|StreamReader|StreamWriter|BinaryReader|BinaryWriter' -Recurse
|
||||
```
|
||||
|
||||
## Process and Thread Manipulation
|
||||
|
||||
```powershell
|
||||
# Process creation
|
||||
Select-String -Path "sources\*" -Pattern 'CreateProcess[AW]?|ShellExecute[AW]?|WinExec|system\(' -Recurse
|
||||
|
||||
# Process injection indicators
|
||||
Select-String -Path "sources\*" -Pattern 'VirtualAlloc|VirtualAllocEx|VirtualProtect|WriteProcessMemory|ReadProcessMemory|CreateRemoteThread|NtCreateThreadEx|QueueUserAPC|SetThreadContext' -Recurse
|
||||
|
||||
# DLL injection
|
||||
Select-String -Path "sources\*" -Pattern 'LoadLibrary[AW]?|GetProcAddress|FreeLibrary|GetModuleHandle[AW]?' -Recurse
|
||||
|
||||
# .NET process
|
||||
Select-String -Path "sources\*" -Pattern 'Process\.Start|ProcessStartInfo|Process\.GetProcesses' -Recurse
|
||||
```
|
||||
|
||||
## Cryptography
|
||||
|
||||
### Native (CryptoAPI / BCrypt)
|
||||
|
||||
```powershell
|
||||
Select-String -Path "sources\*" -Pattern 'CryptAcquireContext|CryptEncrypt|CryptDecrypt|CryptHashData|CryptDeriveKey|CryptGenKey|CryptImportKey|CryptExportKey|CryptGenRandom' -Recurse
|
||||
Select-String -Path "sources\*" -Pattern 'BCryptOpenAlgorithmProvider|BCryptEncrypt|BCryptDecrypt|BCryptGenerateSymmetricKey|BCryptHash|BCryptCreateHash|BCryptFinishHash' -Recurse
|
||||
```
|
||||
|
||||
### .NET
|
||||
|
||||
```powershell
|
||||
Select-String -Path "sources\*" -Pattern 'System\.Security\.Cryptography|Aes\.|RSA\.|SHA256|SHA512|MD5|HMAC|RijndaelManaged|AesManaged|RSACryptoServiceProvider|X509Certificate' -Recurse
|
||||
```
|
||||
|
||||
## COM and WMI
|
||||
|
||||
```powershell
|
||||
# COM
|
||||
Select-String -Path "sources\*" -Pattern 'CoCreateInstance|CoInitialize|CoUninitialize|IDispatch|IUnknown|CLSIDFromProgID|ProgIDFromCLSID' -Recurse
|
||||
|
||||
# WMI (native)
|
||||
Select-String -Path "sources\*" -Pattern 'IWbemLocator|IWbemServices|ConnectServer|ExecQuery' -Recurse
|
||||
|
||||
# WMI (.NET)
|
||||
Select-String -Path "sources\*" -Pattern 'ManagementObjectSearcher|ManagementObject|ManagementScope|ObjectQuery|WqlObjectQuery|SelectQuery' -Recurse
|
||||
```
|
||||
|
||||
## Windows Services
|
||||
|
||||
```powershell
|
||||
# Native
|
||||
Select-String -Path "sources\*" -Pattern 'OpenSCManager|CreateService[AW]?|OpenService[AW]?|StartService|ControlService|DeleteService|ChangeServiceConfig|QueryServiceStatus|RegisterServiceCtrlHandler' -Recurse
|
||||
|
||||
# .NET
|
||||
Select-String -Path "sources\*" -Pattern 'ServiceBase|ServiceController|ServiceInstaller|ServiceProcessInstaller|OnStart|OnStop|ServiceName' -Recurse
|
||||
```
|
||||
|
||||
## Persistence Mechanisms
|
||||
|
||||
```powershell
|
||||
# Run keys
|
||||
Select-String -Path "sources\*" -Pattern 'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run|SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce' -Recurse
|
||||
|
||||
# Scheduled tasks
|
||||
Select-String -Path "sources\*" -Pattern 'schtasks|ITaskService|ITaskDefinition|TaskScheduler|ScheduledTask' -Recurse
|
||||
|
||||
# Startup folder
|
||||
Select-String -Path "sources\*" -Pattern 'Startup|shell:startup|Programs\\Startup' -Recurse
|
||||
|
||||
# Windows service registration
|
||||
Select-String -Path "sources\*" -Pattern 'CreateService|sc\.exe|New-Service|Install-Service' -Recurse
|
||||
```
|
||||
|
||||
## Hardcoded URLs, IPs, and Secrets
|
||||
|
||||
```powershell
|
||||
# HTTP/HTTPS URLs
|
||||
Select-String -Path "sources\*" -Pattern '"https?://[^"]+' -Recurse
|
||||
|
||||
# IP addresses
|
||||
Select-String -Path "sources\*" -Pattern '\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b' -Recurse
|
||||
|
||||
# API keys and tokens
|
||||
Select-String -Path "sources\*" -Pattern 'api[_\-]?key|api[_\-]?secret|auth[_\-]?token|bearer|access[_\-]?token|client[_\-]?secret|app[_\-]?secret' -CaseSensitive:$false -Recurse
|
||||
|
||||
# Base URL constants
|
||||
Select-String -Path "sources\*" -Pattern 'BASE_URL|API_URL|SERVER_URL|ENDPOINT|API_BASE|HOST_NAME|ServiceUrl|BaseAddress' -CaseSensitive:$false -Recurse
|
||||
|
||||
# Connection strings
|
||||
Select-String -Path "sources\*" -Pattern 'Data Source=|Server=|Initial Catalog=|connectionString|ConnectionStrings' -Recurse
|
||||
|
||||
# Passwords
|
||||
Select-String -Path "sources\*" -Pattern 'password|passwd|pwd|credential' -CaseSensitive:$false -Recurse
|
||||
```
|
||||
|
||||
## Documentation Template
|
||||
|
||||
For each discovered API call, document it using this template:
|
||||
|
||||
### Win32 API Template
|
||||
|
||||
```markdown
|
||||
### `FunctionName` (DLL: source.dll)
|
||||
|
||||
- **Source**: `filename.c:42` or `Namespace.ClassName` (file:line)
|
||||
- **Category**: Network / Registry / File I/O / Process / Crypto / COM / Service
|
||||
- **Parameters**:
|
||||
- `param1`: value or source description
|
||||
- `param2`: value or source description
|
||||
- **Return handling**: checked / ignored / stored in `variable`
|
||||
- **Called from**: `Main → InitNetwork → SendData → WinHttpSendRequest`
|
||||
- **Purpose**: Brief description of what this call accomplishes
|
||||
```
|
||||
|
||||
### Network Endpoint Template
|
||||
|
||||
```markdown
|
||||
### `METHOD https://api.example.com/v1/endpoint`
|
||||
|
||||
- **Source**: `NetworkManager.cs:87` or `sub_401234.c:15`
|
||||
- **Method**: GET / POST / PUT / DELETE
|
||||
- **Transport**: HttpClient / WinHTTP / WinINet / Winsock
|
||||
- **Headers**:
|
||||
- `Authorization: Bearer <token>`
|
||||
- `Content-Type: application/json`
|
||||
- **Request body**: `{ "username": "string", "password": "string" }`
|
||||
- **Response handling**: parsed as JSON / written to file / displayed in UI
|
||||
- **Called from**: `LoginForm.btnLogin_Click → AuthService.Login → HttpClient.PostAsync`
|
||||
```
|
||||
|
||||
## Search Strategy
|
||||
|
||||
1. Start with **import table analysis** — see what DLLs the binary imports (ws2_32.dll = networking, advapi32.dll = registry/services, etc.)
|
||||
2. Search for **hardcoded URLs and IPs** — find where the app communicates externally
|
||||
3. Search for **HTTP client construction** — HttpClient, WinHTTP, WinINet setup reveals base URLs and auth config
|
||||
4. Check for **authentication patterns** — tokens, credentials, API keys
|
||||
5. Look for **persistence mechanisms** — registry Run keys, scheduled tasks, services
|
||||
6. Search for **crypto operations** — may reveal how data is encrypted/decrypted before transmission
|
||||
7. Check for **process manipulation** — indicates potential injection or privilege escalation
|
||||
|
|
@ -0,0 +1,296 @@
|
|||
# Call Flow Analysis
|
||||
|
||||
Techniques for tracing execution flows in decompiled Windows applications, from entry points down to API calls.
|
||||
|
||||
## 1. Start from the PE Import Table
|
||||
|
||||
The import table is the single most revealing artifact in static analysis. It lists every DLL and function the binary uses at load time.
|
||||
|
||||
### What imports reveal
|
||||
|
||||
| Imported DLL | Indicates |
|
||||
|---|---|
|
||||
| `ws2_32.dll` | Network communication (sockets) |
|
||||
| `winhttp.dll` | HTTP/HTTPS requests |
|
||||
| `wininet.dll` | Internet/HTTP (legacy) |
|
||||
| `advapi32.dll` | Registry, services, security |
|
||||
| `crypt32.dll` / `bcrypt.dll` | Cryptography |
|
||||
| `user32.dll` | GUI, windows, message handling |
|
||||
| `ole32.dll` / `oleaut32.dll` | COM/OLE automation |
|
||||
| `mscoree.dll` | .NET runtime (managed binary) |
|
||||
| `ntdll.dll` (direct) | Low-level / possible evasion |
|
||||
| `kernel32.dll` | File I/O, process management, memory |
|
||||
|
||||
### Extracting imports
|
||||
|
||||
```powershell
|
||||
# Via dumpbin (if Visual Studio C++ Build Tools installed)
|
||||
dumpbin /imports target.exe
|
||||
|
||||
# Via Ghidra (see ExportDecompiled.py output)
|
||||
# Check <output>/imports.txt
|
||||
|
||||
# Via PowerShell (basic PE parsing)
|
||||
# The decompile.ps1 script includes PE header reading
|
||||
```
|
||||
|
||||
## 2. Entry Points
|
||||
|
||||
### Native executables
|
||||
|
||||
| Entry Point | Context |
|
||||
|---|---|
|
||||
| `WinMain` / `wWinMain` | GUI application |
|
||||
| `main` / `wmain` | Console application |
|
||||
| `DllMain` | DLL initialization/cleanup |
|
||||
| `ServiceMain` | Windows service |
|
||||
| `DriverEntry` | Kernel driver |
|
||||
| CRT `mainCRTStartup` | C runtime initialization → calls `main` |
|
||||
|
||||
Search in decompiled output:
|
||||
|
||||
```powershell
|
||||
# Find main entry points (Ghidra output)
|
||||
Select-String -Path "decompiled\*" -Pattern 'WinMain|wWinMain|main\(|DllMain|ServiceMain|DriverEntry' -Recurse
|
||||
|
||||
# Find the PE entry point function
|
||||
Select-String -Path "decompiled\*" -Pattern 'entry|_start|mainCRTStartup' -Recurse
|
||||
```
|
||||
|
||||
### .NET applications
|
||||
|
||||
| Entry Point | Context |
|
||||
|---|---|
|
||||
| `static void Main()` | Console / WinForms / WPF |
|
||||
| `Program.cs` | ASP.NET Core / Generic Host |
|
||||
| `Startup.cs` | ASP.NET Core (older pattern) |
|
||||
| `App.xaml.cs` | WPF application startup |
|
||||
| `Global.asax.cs` | ASP.NET Framework |
|
||||
|
||||
```powershell
|
||||
# Find .NET entry points
|
||||
Select-String -Path "sources\*" -Pattern 'static\s+(void|async\s+Task)\s+Main|class\s+Program|class\s+Startup|class\s+App\s*:' -Recurse
|
||||
```
|
||||
|
||||
## 3. Follow the Initialization Chain
|
||||
|
||||
### Native C/C++ application
|
||||
|
||||
```
|
||||
CRT mainCRTStartup()
|
||||
→ main() / WinMain()
|
||||
→ Initialize global singletons (COM, Winsock, etc.)
|
||||
→ Parse command line
|
||||
→ Create main window (RegisterClassEx → CreateWindowEx)
|
||||
→ Enter message loop (GetMessage → DispatchMessage)
|
||||
→ WndProc handles messages
|
||||
→ WM_COMMAND → menu/button handlers
|
||||
→ Business logic functions
|
||||
→ API calls (network, registry, file I/O)
|
||||
```
|
||||
|
||||
Key initialization to search:
|
||||
|
||||
```powershell
|
||||
# COM initialization
|
||||
Select-String -Path "decompiled\*" -Pattern 'CoInitialize|OleInitialize' -Recurse
|
||||
|
||||
# Winsock initialization
|
||||
Select-String -Path "decompiled\*" -Pattern 'WSAStartup' -Recurse
|
||||
|
||||
# Window creation
|
||||
Select-String -Path "decompiled\*" -Pattern 'CreateWindowEx|RegisterClassEx|RegisterClass\(' -Recurse
|
||||
|
||||
# Message loop
|
||||
Select-String -Path "decompiled\*" -Pattern 'GetMessage|PeekMessage|DispatchMessage|TranslateMessage' -Recurse
|
||||
```
|
||||
|
||||
### .NET application
|
||||
|
||||
```
|
||||
Program.Main()
|
||||
→ Host.CreateDefaultBuilder()
|
||||
→ ConfigureServices()
|
||||
→ Register DI services
|
||||
→ Configure HttpClient / API clients
|
||||
→ Configure authentication
|
||||
→ Configure()
|
||||
→ Set up middleware pipeline
|
||||
→ Map routes / endpoints
|
||||
```
|
||||
|
||||
```powershell
|
||||
# DI registration
|
||||
Select-String -Path "sources\*" -Pattern 'AddScoped|AddSingleton|AddTransient|AddHttpClient|AddDbContext' -Recurse
|
||||
|
||||
# Configuration
|
||||
Select-String -Path "sources\*" -Pattern 'Configuration\[|GetSection|GetValue|IOptions|appsettings' -Recurse
|
||||
|
||||
# Middleware
|
||||
Select-String -Path "sources\*" -Pattern 'UseAuthentication|UseAuthorization|UseRouting|MapControllers|MapGet|MapPost' -Recurse
|
||||
```
|
||||
|
||||
## 4. Identify User Action Handlers
|
||||
|
||||
### Native GUI (Win32)
|
||||
|
||||
```
|
||||
User clicks button
|
||||
→ WM_COMMAND message sent
|
||||
→ WndProc receives with LOWORD(wParam) = button ID
|
||||
→ Switch/if on button IDs
|
||||
→ Calls handler function
|
||||
→ Handler calls business logic → API calls
|
||||
```
|
||||
|
||||
```powershell
|
||||
# Window procedure
|
||||
Select-String -Path "decompiled\*" -Pattern 'WndProc|WNDPROC|WM_COMMAND|WM_NOTIFY|WM_CREATE' -Recurse
|
||||
|
||||
# Dialog procedures
|
||||
Select-String -Path "decompiled\*" -Pattern 'DialogBox|CreateDialog|DlgProc|DLGPROC|EndDialog' -Recurse
|
||||
|
||||
# Common control notifications
|
||||
Select-String -Path "decompiled\*" -Pattern 'BN_CLICKED|LVN_ITEMCHANGED|TVN_SELCHANGED' -Recurse
|
||||
```
|
||||
|
||||
### WinForms (.NET)
|
||||
|
||||
```powershell
|
||||
# Event handlers
|
||||
Select-String -Path "sources\*" -Pattern 'Click\s*\+=|_Click\(|button.*Click|EventHandler' -Recurse
|
||||
|
||||
# Form lifecycle
|
||||
Select-String -Path "sources\*" -Pattern 'InitializeComponent|Form_Load|Form_Shown|Form_Closing' -Recurse
|
||||
```
|
||||
|
||||
### WPF (.NET)
|
||||
|
||||
```powershell
|
||||
# Commands and bindings
|
||||
Select-String -Path "sources\*" -Pattern 'ICommand|RelayCommand|DelegateCommand|Command\s*{' -Recurse
|
||||
|
||||
# MVVM ViewModels
|
||||
Select-String -Path "sources\*" -Pattern 'ViewModel|INotifyPropertyChanged|ObservableCollection|BindingContext' -Recurse
|
||||
```
|
||||
|
||||
## 5. Dependency Injection (.NET)
|
||||
|
||||
Modern .NET apps use DI extensively. Trace bindings to find implementations:
|
||||
|
||||
```powershell
|
||||
# Service registration
|
||||
Select-String -Path "sources\*" -Pattern 'services\.Add(Scoped|Singleton|Transient)\s*<' -Recurse
|
||||
|
||||
# HTTP client configuration
|
||||
Select-String -Path "sources\*" -Pattern 'AddHttpClient|BaseAddress|DefaultRequestHeaders' -Recurse
|
||||
|
||||
# Interface → implementation
|
||||
Select-String -Path "sources\*" -Pattern 'services\.Add.*<I\w+,\s*\w+>' -Recurse
|
||||
|
||||
# Constructor injection
|
||||
Select-String -Path "sources\*" -Pattern 'public\s+\w+\(I\w+' -Recurse
|
||||
```
|
||||
|
||||
To trace a call flow through DI:
|
||||
1. Find where an interface is used (e.g., `IApiService` in a controller)
|
||||
2. Find the `AddScoped<IApiService, ApiService>` registration
|
||||
3. Follow `ApiService` to the actual HTTP/API call
|
||||
|
||||
## 6. Find Constants and Configuration
|
||||
|
||||
### Native
|
||||
|
||||
```powershell
|
||||
# String constants — often reveal URLs, paths, keys
|
||||
Select-String -Path "decompiled\*" -Pattern '"https?://|"\\\\|"C:\\' -Recurse
|
||||
|
||||
# Error messages — useful for understanding control flow
|
||||
Select-String -Path "strings.txt" -Pattern 'error|failed|invalid|unauthorized|denied' -CaseSensitive:$false
|
||||
```
|
||||
|
||||
### .NET
|
||||
|
||||
```powershell
|
||||
# Configuration access
|
||||
Select-String -Path "sources\*" -Pattern 'Configuration\[|ConfigurationManager|AppSettings|ConnectionStrings' -Recurse
|
||||
|
||||
# Constants
|
||||
Select-String -Path "sources\*" -Pattern 'const\s+string|static\s+readonly\s+string|BASE_URL|API_KEY|SECRET' -Recurse
|
||||
|
||||
# Resource strings
|
||||
Select-String -Path "sources\*" -Pattern 'Resources\.\w+|ResourceManager' -Recurse
|
||||
```
|
||||
|
||||
## 7. Navigating Stripped/Obfuscated Code
|
||||
|
||||
### Native (no debug symbols)
|
||||
|
||||
When symbols are stripped, Ghidra generates names like `FUN_00401000`, `DAT_00405000`:
|
||||
|
||||
**What you can still use:**
|
||||
- **Import table** — DLL function names are always readable
|
||||
- **String literals** — embedded strings survive stripping
|
||||
- **API call patterns** — sequences of Win32 calls reveal intent
|
||||
- **Constants** — magic numbers, sizes, flags are preserved
|
||||
|
||||
**Strategy:**
|
||||
1. Start from imports — find calls to network/registry/crypto APIs
|
||||
2. Cross-reference callers — Ghidra's output shows who calls what
|
||||
3. Use strings — grep `strings.txt` for URLs, error messages, paths
|
||||
4. Rename functions — once you understand a function's purpose, rename it in your analysis notes
|
||||
|
||||
### .NET obfuscated
|
||||
|
||||
**What gets obfuscated:**
|
||||
- Class names → `a`, `b`, `\u0001`
|
||||
- Method names → `a()`, `b()`, `\u0002()`
|
||||
- Field names → random characters
|
||||
|
||||
**What does NOT get obfuscated:**
|
||||
- **.NET framework types** — `HttpClient`, `FileStream`, `Process` keep their names
|
||||
- **Method signatures** — parameter types from framework classes are preserved
|
||||
- **String literals** (unless string encryption is used)
|
||||
- **NuGet package public APIs** — `Newtonsoft.Json`, `RestSharp` calls are readable
|
||||
- **Attributes** — `[Serializable]`, `[Route]`, `[HttpGet]` remain
|
||||
|
||||
## 8. Tracing a Complete Call Flow: Example
|
||||
|
||||
### Example: Finding how an app authenticates
|
||||
|
||||
**Native app:**
|
||||
```
|
||||
1. dumpbin /imports → finds winhttp.dll imported
|
||||
2. grep "WinHttpSendRequest" → found in sub_401A00
|
||||
3. Read sub_401A00 → builds POST request to "/api/auth/login"
|
||||
4. grep for callers of sub_401A00 → called from sub_401500
|
||||
5. Read sub_401500 → reads username/password from dialog fields
|
||||
6. grep for callers of sub_401500 → called from WndProc on WM_COMMAND
|
||||
7. WM_COMMAND handler checks button ID → "Login" button
|
||||
```
|
||||
|
||||
Result: `Login button → WndProc(WM_COMMAND) → sub_401500 → sub_401A00 → WinHttpSendRequest POST /api/auth/login`
|
||||
|
||||
**.NET app:**
|
||||
```
|
||||
1. grep for "HttpClient" → found in AuthService.cs
|
||||
2. Read AuthService.cs → PostAsync("auth/login", credentials)
|
||||
3. grep for IAuthService usage → injected into LoginViewModel
|
||||
4. Read LoginViewModel → LoginCommand calls AuthService.LoginAsync()
|
||||
5. LoginCommand bound to Login button in LoginView.xaml
|
||||
```
|
||||
|
||||
Result: `Login button → LoginViewModel.LoginCommand → AuthService.LoginAsync → HttpClient.PostAsync("auth/login")`
|
||||
|
||||
## 9. Tools and Commands Summary
|
||||
|
||||
| Goal | Command |
|
||||
|---|---|
|
||||
| Find entry points | `Select-String -Path "decompiled\*" -Pattern 'WinMain\|main\|DllMain' -Recurse` |
|
||||
| Find window procedures | `Select-String -Path "decompiled\*" -Pattern 'WndProc\|WM_COMMAND' -Recurse` |
|
||||
| Find .NET DI bindings | `Select-String -Path "sources\*" -Pattern 'AddScoped\|AddSingleton\|AddTransient' -Recurse` |
|
||||
| Find click handlers | `Select-String -Path "sources\*" -Pattern '_Click\|EventHandler\|ICommand' -Recurse` |
|
||||
| Find constants | `Select-String -Path "sources\*" -Pattern 'const\|BASE_URL\|API_KEY' -CaseSensitive:$false -Recurse` |
|
||||
| Find usages of a class | `Select-String -Path "sources\*" -Pattern 'ClassName' -Recurse` |
|
||||
| Find strings containing text | `Select-String -Path "strings.txt" -Pattern '"search text"'` |
|
||||
| Find network imports | `Select-String -Path "imports.txt" -Pattern 'ws2_32\|winhttp\|wininet'` |
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
# Ghidra Headless Analyzer CLI Reference
|
||||
|
||||
## Overview
|
||||
|
||||
Ghidra's Headless Analyzer (`analyzeHeadless.bat` on Windows) runs Ghidra analysis and scripting without the GUI. It imports binaries, performs auto-analysis, and can run custom scripts to export decompiled code.
|
||||
|
||||
## Basic Usage
|
||||
|
||||
```powershell
|
||||
& "$env:GHIDRA_INSTALL_DIR\support\analyzeHeadless.bat" <projectDir> <projectName> [OPTIONS]
|
||||
```
|
||||
|
||||
- `<projectDir>` — Directory where the Ghidra project will be created
|
||||
- `<projectName>` — Name of the Ghidra project
|
||||
|
||||
## Key Options
|
||||
|
||||
| Option | Description |
|
||||
|---|---|
|
||||
| `-import <file>` | Import a binary file into the project |
|
||||
| `-process <file>` | Process an already-imported file |
|
||||
| `-postScript <script>` | Run a script after analysis completes |
|
||||
| `-preScript <script>` | Run a script before analysis |
|
||||
| `-scriptPath <dir>` | Directory containing your scripts |
|
||||
| `-deleteProject` | Delete the project after processing |
|
||||
| `-noanalysis` | Skip auto-analysis (useful if re-running scripts only) |
|
||||
| `-processor <langID>` | Override architecture detection (e.g., `x86:LE:64:default`) |
|
||||
| `-analysisTimeoutPerFile <seconds>` | Timeout for analysis per file |
|
||||
| `-scriptlog <file>` | Write script output to a log file |
|
||||
| `-overwrite` | Overwrite existing files in the project |
|
||||
| `-recursive` | Import all files from a directory recursively |
|
||||
|
||||
## Common Workflows
|
||||
|
||||
### Decompile to C pseudocode (full workflow)
|
||||
|
||||
```powershell
|
||||
$projectDir = "C:\GhidraProjects"
|
||||
$projectName = "MyProject"
|
||||
$scriptPath = "${CLAUDE_PLUGIN_ROOT}\skills\windows-reverse-engineering\scripts\ghidra-scripts"
|
||||
|
||||
& "$env:GHIDRA_INSTALL_DIR\support\analyzeHeadless.bat" `
|
||||
$projectDir $projectName `
|
||||
-import "C:\targets\app.exe" `
|
||||
-scriptPath $scriptPath `
|
||||
-postScript "ExportDecompiled.py" `
|
||||
-deleteProject
|
||||
```
|
||||
|
||||
### Batch import multiple files
|
||||
|
||||
```powershell
|
||||
& "$env:GHIDRA_INSTALL_DIR\support\analyzeHeadless.bat" `
|
||||
$projectDir $projectName `
|
||||
-import "C:\targets\" `
|
||||
-recursive `
|
||||
-scriptPath $scriptPath `
|
||||
-postScript "ExportDecompiled.py"
|
||||
```
|
||||
|
||||
### Re-run script without re-analyzing
|
||||
|
||||
```powershell
|
||||
& "$env:GHIDRA_INSTALL_DIR\support\analyzeHeadless.bat" `
|
||||
$projectDir $projectName `
|
||||
-process "app.exe" `
|
||||
-noanalysis `
|
||||
-scriptPath $scriptPath `
|
||||
-postScript "ExportDecompiled.py"
|
||||
```
|
||||
|
||||
## Custom Export Scripts
|
||||
|
||||
This skill includes `ExportDecompiled.py`, a Jython script that:
|
||||
|
||||
1. Decompiles all functions to C pseudocode files
|
||||
2. Exports the import table
|
||||
3. Exports the export table (for DLLs)
|
||||
4. Exports all string references
|
||||
|
||||
The script is located at:
|
||||
```
|
||||
${CLAUDE_PLUGIN_ROOT}/skills/windows-reverse-engineering/scripts/ghidra-scripts/ExportDecompiled.py
|
||||
```
|
||||
|
||||
### Writing Custom Ghidra Scripts
|
||||
|
||||
Ghidra scripts use **Jython (Python 2.7)** with access to the Ghidra API:
|
||||
|
||||
```python
|
||||
# @category Export
|
||||
# @description Example: list all functions and their addresses
|
||||
|
||||
fm = currentProgram.getFunctionManager()
|
||||
functions = fm.getFunctions(True) # True = forward iteration
|
||||
|
||||
for func in functions:
|
||||
print("{} @ {}".format(func.getName(), func.getEntryPoint()))
|
||||
```
|
||||
|
||||
Key Ghidra API classes:
|
||||
- `currentProgram` — the loaded binary
|
||||
- `currentProgram.getFunctionManager()` — access functions
|
||||
- `currentProgram.getMemory()` — access memory/sections
|
||||
- `currentProgram.getSymbolTable()` — access symbols
|
||||
- `currentProgram.getListing()` — access instructions
|
||||
- `DecompInterface` — decompile functions to C
|
||||
|
||||
## Architecture Detection
|
||||
|
||||
Ghidra auto-detects the processor for most PE files. Override when needed:
|
||||
|
||||
| Architecture | Processor ID |
|
||||
|---|---|
|
||||
| x86 32-bit | `x86:LE:32:default` |
|
||||
| x86 64-bit | `x86:LE:64:default` |
|
||||
| ARM 32-bit | `ARM:LE:32:v8` |
|
||||
| ARM64 | `AARCH64:LE:64:v8A` |
|
||||
|
||||
## Memory Tuning
|
||||
|
||||
For large binaries (>50MB), increase the Java heap:
|
||||
|
||||
1. Edit `$env:GHIDRA_INSTALL_DIR\support\analyzeHeadless.bat`
|
||||
2. Find the `MAXMEM` variable
|
||||
3. Change from default to: `set MAXMEM=4G` (or more)
|
||||
|
||||
Or set via environment variable:
|
||||
```powershell
|
||||
$env:_JAVA_OPTIONS = "-Xmx4g"
|
||||
```
|
||||
|
||||
## Output Directory
|
||||
|
||||
The `ExportDecompiled.py` script outputs to a directory next to the input file (or as specified by script arguments):
|
||||
|
||||
```
|
||||
<output>/
|
||||
├── decompiled/ # C pseudocode per function
|
||||
│ ├── main.c
|
||||
│ ├── WinMain.c
|
||||
│ ├── sub_401000.c
|
||||
│ └── ...
|
||||
├── imports.txt # DLL imports listing
|
||||
├── exports.txt # DLL exports listing (if DLL)
|
||||
├── strings.txt # String references
|
||||
└── summary.txt # Analysis summary
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Problem | Solution |
|
||||
|---|---|
|
||||
| `GHIDRA_INSTALL_DIR not set` | Set environment variable to Ghidra directory |
|
||||
| `Java not found` | Install Java 17+ and ensure it's in PATH |
|
||||
| `OutOfMemoryError` | Increase `MAXMEM` in analyzeHeadless.bat |
|
||||
| Script errors | Use `-scriptlog <file>` to capture script output |
|
||||
| Wrong architecture detected | Use `-processor <langID>` to override |
|
||||
| Analysis hangs | Use `-analysisTimeoutPerFile 300` to set a 5-minute timeout |
|
||||
|
|
@ -0,0 +1,185 @@
|
|||
# ilspycmd CLI Reference
|
||||
|
||||
## Overview
|
||||
|
||||
`ilspycmd` is the command-line interface for ILSpy, the open-source .NET assembly decompiler. It decompiles .NET assemblies (EXE, DLL) to C# source code, including full project reconstruction with `.csproj` files.
|
||||
|
||||
## Installation
|
||||
|
||||
```powershell
|
||||
# Requires .NET SDK 6.0+
|
||||
dotnet tool install -g ilspycmd
|
||||
|
||||
# Update to latest
|
||||
dotnet tool update -g ilspycmd
|
||||
```
|
||||
|
||||
## When to Use ilspycmd vs Ghidra
|
||||
|
||||
| Scenario | Recommended |
|
||||
|---|---|
|
||||
| .NET Framework (4.x) assembly | ilspycmd |
|
||||
| .NET Core / .NET 5+ assembly | ilspycmd |
|
||||
| .NET assembly with WPF/WinForms | ilspycmd |
|
||||
| Native C/C++ EXE/DLL | Ghidra |
|
||||
| Mixed-mode assembly (native + managed) | Both — Ghidra for native, ilspycmd for managed |
|
||||
| Obfuscated .NET (Dotfuscator, ConfuserEx) | de4dot first, then ilspycmd |
|
||||
| .NET Native / AOT compiled | Ghidra (compiled to native code) |
|
||||
|
||||
## Basic Usage
|
||||
|
||||
```powershell
|
||||
ilspycmd [OPTIONS] <assembly>
|
||||
```
|
||||
|
||||
Input can be an `.exe` or `.dll` file containing .NET metadata.
|
||||
|
||||
## Key Options
|
||||
|
||||
| Option | Description |
|
||||
|---|---|
|
||||
| `-p` / `--project` | Decompile to a full C# project (with .csproj file) |
|
||||
| `-o <dir>` | Output directory for decompiled files |
|
||||
| `-t <type>` | Decompile a specific type (e.g., `MyApp.MainForm`) |
|
||||
| `-l` / `--list` | List all types and members in the assembly |
|
||||
| `--no-dead-code` | Remove unreachable code from output |
|
||||
| `-r <dir>` | Reference assembly search directory (improves type resolution) |
|
||||
| `--nested-directories` | Create nested directories matching namespace structure |
|
||||
| `-lv <version>` | Set the target language version (e.g., `CSharp10_0`) |
|
||||
|
||||
## Decompiling Different Targets
|
||||
|
||||
### Full project decompilation (recommended)
|
||||
|
||||
```powershell
|
||||
ilspycmd -p -o output_dir MyApp.exe
|
||||
```
|
||||
|
||||
Produces:
|
||||
- `output_dir/*.cs` — Decompiled C# source files
|
||||
- `output_dir/*.csproj` — Reconstructed project file
|
||||
- `output_dir/Properties/` — Assembly info and resources
|
||||
|
||||
### Decompile to individual files
|
||||
|
||||
```powershell
|
||||
ilspycmd -o output_dir MyApp.dll
|
||||
```
|
||||
|
||||
Produces C# files without a project structure.
|
||||
|
||||
### List all types
|
||||
|
||||
```powershell
|
||||
ilspycmd -l MyApp.exe
|
||||
```
|
||||
|
||||
Useful for identifying namespaces and classes before targeted decompilation.
|
||||
|
||||
### Decompile a specific type
|
||||
|
||||
```powershell
|
||||
ilspycmd -t "MyApp.Services.AuthService" MyApp.exe
|
||||
```
|
||||
|
||||
### Decompile with reference resolution
|
||||
|
||||
```powershell
|
||||
ilspycmd -p -o output_dir -r "C:\refs\" MyApp.exe
|
||||
```
|
||||
|
||||
When the assembly references other DLLs, put them in a directory and use `-r` for better type resolution.
|
||||
|
||||
## Handling Obfuscated .NET
|
||||
|
||||
.NET obfuscators (Dotfuscator, ConfuserEx, Eziriz .NET Reactor, etc.) rename types and members, encrypt strings, add control flow obfuscation, and may add anti-tamper checks.
|
||||
|
||||
### Preprocessing with de4dot
|
||||
|
||||
```powershell
|
||||
# Clean the obfuscated assembly first
|
||||
de4dot ObfuscatedApp.exe -o CleanApp.exe
|
||||
|
||||
# Then decompile the cleaned version
|
||||
ilspycmd -p -o output_dir CleanApp.exe
|
||||
```
|
||||
|
||||
### What de4dot handles
|
||||
- Renamed types/methods → restored to readable names
|
||||
- Encrypted strings → decrypted inline
|
||||
- Proxy delegates → resolved to direct calls
|
||||
- Dead code from obfuscation → removed
|
||||
|
||||
### What remains obfuscated
|
||||
- Control flow patterns (may still be convoluted)
|
||||
- Custom protection schemes de4dot doesn't recognize
|
||||
- Native stub protectors (e.g., .NET Reactor with native mode)
|
||||
|
||||
### Manual strategies for obfuscated .NET
|
||||
1. **String search**: string literals in resources and constants are often preserved
|
||||
2. **Framework types**: `HttpClient`, `WebRequest`, `SqlConnection` keep their names
|
||||
3. **Interface names**: public interface names are often preserved for serialization
|
||||
4. **Attribute values**: `[Route]`, `[HttpGet]`, `[Serializable]` annotations remain readable
|
||||
|
||||
## Common Patterns in Decompiled Output
|
||||
|
||||
### Dependency Injection (ASP.NET Core)
|
||||
|
||||
Look in `Startup.cs` or `Program.cs`:
|
||||
```csharp
|
||||
services.AddHttpClient<IApiService, ApiService>(client => {
|
||||
client.BaseAddress = new Uri("https://api.example.com/v1/");
|
||||
});
|
||||
services.AddScoped<IAuthService, AuthService>();
|
||||
```
|
||||
|
||||
### HTTP Clients
|
||||
|
||||
```csharp
|
||||
// HttpClient (modern)
|
||||
var response = await httpClient.PostAsync("/auth/login", content);
|
||||
|
||||
// WebRequest (legacy)
|
||||
var request = WebRequest.Create("https://api.example.com/data");
|
||||
|
||||
// RestSharp
|
||||
var request = new RestRequest("/users/{id}", Method.Get);
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
```csharp
|
||||
// appsettings.json values
|
||||
var apiUrl = Configuration["ApiSettings:BaseUrl"];
|
||||
var apiKey = Configuration.GetSection("ApiKeys")["Primary"];
|
||||
```
|
||||
|
||||
## Output Structure
|
||||
|
||||
When using `-p` (project mode), the output mirrors the original project:
|
||||
|
||||
```
|
||||
output_dir/
|
||||
├── MyApp.csproj # Reconstructed project file
|
||||
├── Program.cs # Entry point
|
||||
├── Properties/
|
||||
│ └── AssemblyInfo.cs # Assembly metadata
|
||||
├── Models/
|
||||
│ ├── User.cs
|
||||
│ └── LoginRequest.cs
|
||||
├── Services/
|
||||
│ ├── AuthService.cs
|
||||
│ └── ApiService.cs
|
||||
└── ...
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Problem | Solution |
|
||||
|---|---|
|
||||
| `ilspycmd: command not found` | Run `dotnet tool install -g ilspycmd` and restart terminal |
|
||||
| Assembly references not resolved | Use `-r <dir>` to point to referenced DLLs |
|
||||
| Output has `/* Error */` comments | Assembly may be obfuscated — try de4dot first |
|
||||
| `BadImageFormatException` | File is not a .NET assembly — use Ghidra instead |
|
||||
| `FileNotFoundException` for deps | Copy dependency DLLs next to the target assembly |
|
||||
| Decompiled code won't compile | Expected — decompiled code is for reading, not building |
|
||||
|
|
@ -0,0 +1,264 @@
|
|||
# Setup Guide: Dependencies for Windows Reverse Engineering
|
||||
|
||||
## Java JDK 17+
|
||||
|
||||
Ghidra requires Java 17 or later.
|
||||
|
||||
### winget (recommended)
|
||||
|
||||
```powershell
|
||||
winget install Microsoft.OpenJDK.17
|
||||
```
|
||||
|
||||
### Chocolatey
|
||||
|
||||
```powershell
|
||||
choco install openjdk17
|
||||
```
|
||||
|
||||
### Manual (Adoptium)
|
||||
|
||||
1. Go to <https://adoptium.net/temurin/releases/?version=17>
|
||||
2. Download the `.msi` installer for your architecture (x64 or ARM64)
|
||||
3. Run the installer — it adds Java to PATH automatically
|
||||
|
||||
### Verify
|
||||
|
||||
```powershell
|
||||
java -version
|
||||
# Should show version 17.x or higher
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Ghidra
|
||||
|
||||
Ghidra is the NSA's open-source reverse engineering framework. It decompiles native PE binaries to C pseudocode.
|
||||
|
||||
### GitHub Releases (recommended)
|
||||
|
||||
1. Go to <https://github.com/NationalSecurityAgency/ghidra/releases/latest>
|
||||
2. Download `ghidra_<version>_PUBLIC_<date>.zip`
|
||||
3. Extract to a permanent location (e.g., `C:\Tools\Ghidra`)
|
||||
4. Set the environment variable:
|
||||
|
||||
```powershell
|
||||
# Set for current user permanently
|
||||
[System.Environment]::SetEnvironmentVariable('GHIDRA_INSTALL_DIR', 'C:\Tools\Ghidra\ghidra_<version>_PUBLIC', 'User')
|
||||
|
||||
# Set for current session
|
||||
$env:GHIDRA_INSTALL_DIR = 'C:\Tools\Ghidra\ghidra_<version>_PUBLIC'
|
||||
```
|
||||
|
||||
### Chocolatey
|
||||
|
||||
```powershell
|
||||
choco install ghidra
|
||||
```
|
||||
|
||||
### Verify
|
||||
|
||||
```powershell
|
||||
# Check the environment variable
|
||||
$env:GHIDRA_INSTALL_DIR
|
||||
|
||||
# Check the headless analyzer
|
||||
& "$env:GHIDRA_INSTALL_DIR\support\analyzeHeadless.bat" -help
|
||||
```
|
||||
|
||||
> **Note**: On first run, Ghidra may prompt for agreement. The headless analyzer works without a GUI but requires a writable project directory.
|
||||
|
||||
---
|
||||
|
||||
## ilspycmd (.NET Decompiler)
|
||||
|
||||
ilspycmd is the command-line interface for ILSpy, the open-source .NET decompiler. It decompiles .NET assemblies to C# source.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Install the .NET SDK (6.0 or later):
|
||||
|
||||
```powershell
|
||||
# Via winget
|
||||
winget install Microsoft.DotNet.SDK.8
|
||||
|
||||
# Via Chocolatey
|
||||
choco install dotnet-sdk
|
||||
```
|
||||
|
||||
### Install ilspycmd
|
||||
|
||||
```powershell
|
||||
dotnet tool install -g ilspycmd
|
||||
```
|
||||
|
||||
This installs `ilspycmd` as a global .NET tool. The tool is automatically added to PATH.
|
||||
|
||||
### Verify
|
||||
|
||||
```powershell
|
||||
ilspycmd --version
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
```powershell
|
||||
# Decompile entire assembly to C# project
|
||||
ilspycmd -p -o output_dir MyApp.exe
|
||||
|
||||
# Decompile to individual C# files (no project)
|
||||
ilspycmd -o output_dir MyApp.dll
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## strings / strings2 (optional, recommended)
|
||||
|
||||
Extract readable ASCII and Unicode strings from binaries. Essential for finding hardcoded URLs, API keys, and error messages.
|
||||
|
||||
### SysInternals strings (Microsoft)
|
||||
|
||||
```powershell
|
||||
# Via winget
|
||||
winget install Microsoft.Sysinternals.Strings
|
||||
|
||||
# Or download directly
|
||||
# https://learn.microsoft.com/en-us/sysinternals/downloads/strings
|
||||
```
|
||||
|
||||
### strings2 (recommended — finds both ASCII and Unicode)
|
||||
|
||||
1. Download from <https://github.com/glmcdona/strings2/releases>
|
||||
2. Extract to a directory in your PATH (e.g., `C:\Tools\strings2\`)
|
||||
3. Add to PATH:
|
||||
|
||||
```powershell
|
||||
[System.Environment]::SetEnvironmentVariable('PATH', $env:PATH + ';C:\Tools\strings2', 'User')
|
||||
```
|
||||
|
||||
### Verify
|
||||
|
||||
```powershell
|
||||
strings --help
|
||||
# or
|
||||
strings2 --help
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## dumpbin (optional)
|
||||
|
||||
dumpbin is a CLI tool for inspecting PE headers, imports, exports, and sections. It ships with Visual Studio C++ Build Tools.
|
||||
|
||||
> **Important**: dumpbin requires **Visual Studio C++ Build Tools** to be installed. This is a large download (~2-4 GB). If you don't have Visual Studio, consider using Ghidra's PE analysis instead — it extracts the same information.
|
||||
|
||||
### Install Visual Studio C++ Build Tools
|
||||
|
||||
1. Download from <https://visualstudio.microsoft.com/visual-cpp-build-tools/>
|
||||
2. In the installer, select **"Desktop development with C++"**
|
||||
3. Install (requires admin)
|
||||
|
||||
### Find dumpbin
|
||||
|
||||
After installation, dumpbin is typically at:
|
||||
```
|
||||
C:\Program Files\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\<version>\bin\Hostx64\x64\dumpbin.exe
|
||||
```
|
||||
|
||||
To use it, open a **Developer Command Prompt** or **Developer PowerShell**, which adds dumpbin to PATH automatically.
|
||||
|
||||
### Verify
|
||||
|
||||
```powershell
|
||||
# From Developer Command Prompt / PowerShell
|
||||
dumpbin /?
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
```powershell
|
||||
# Show imports
|
||||
dumpbin /imports MyApp.exe
|
||||
|
||||
# Show exports
|
||||
dumpbin /exports MyLib.dll
|
||||
|
||||
# Show headers
|
||||
dumpbin /headers MyApp.exe
|
||||
|
||||
# Show all sections
|
||||
dumpbin /all MyApp.exe
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## de4dot (optional — .NET deobfuscation)
|
||||
|
||||
de4dot is an open-source .NET deobfuscator that can clean up obfuscated assemblies before decompilation.
|
||||
|
||||
### Download
|
||||
|
||||
1. Go to <https://github.com/de4dot/de4dot/releases>
|
||||
2. Download the latest release ZIP
|
||||
3. Extract to `C:\Tools\de4dot\`
|
||||
4. Add to PATH:
|
||||
|
||||
```powershell
|
||||
[System.Environment]::SetEnvironmentVariable('PATH', $env:PATH + ';C:\Tools\de4dot', 'User')
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
```powershell
|
||||
# Deobfuscate a .NET assembly
|
||||
de4dot ObfuscatedApp.exe -o CleanApp.exe
|
||||
|
||||
# Then decompile the clean version
|
||||
ilspycmd -p -o output_dir CleanApp.exe
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Optional Tools
|
||||
|
||||
### x64dbg
|
||||
|
||||
A free, open-source x86/x64 debugger for Windows. Useful for dynamic analysis.
|
||||
|
||||
```powershell
|
||||
# Via Chocolatey
|
||||
choco install x64dbg.portable
|
||||
|
||||
# Or download from https://x64dbg.com/
|
||||
```
|
||||
|
||||
### PE-bear
|
||||
|
||||
A portable PE viewer with a GUI for inspecting headers, sections, and overlays.
|
||||
|
||||
Download from <https://github.com/hasherezade/pe-bear/releases>
|
||||
|
||||
### Radare2
|
||||
|
||||
A powerful command-line reverse engineering framework.
|
||||
|
||||
```powershell
|
||||
choco install radare2
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Problem | Solution |
|
||||
|---|---|
|
||||
| `java: command not found` | Install Java 17+ and ensure it's in PATH |
|
||||
| `GHIDRA_INSTALL_DIR not set` | Set the environment variable to Ghidra's installation directory |
|
||||
| `analyzeHeadless` fails to start | Ensure Java 17+ is in PATH and `GHIDRA_INSTALL_DIR` is correct |
|
||||
| `ilspycmd: command not found` | Run `dotnet tool install -g ilspycmd` and restart your terminal |
|
||||
| `dotnet: command not found` | Install .NET SDK from https://dotnet.microsoft.com/ |
|
||||
| Ghidra runs out of memory | Set `JAVA_OPTS="-Xmx4g"` or edit `analyzeHeadless.bat` max heap |
|
||||
| `dumpbin: command not found` | Open Developer Command Prompt, or install VS C++ Build Tools |
|
||||
| PowerShell blocks script execution | Run `Set-ExecutionPolicy -Scope CurrentUser RemoteSigned -Force` |
|
||||
| ilspycmd fails on obfuscated .NET | Run `de4dot` first to clean the assembly, then retry |
|
||||
| Ghidra decompiler produces `undefined` | Binary may be packed — try unpacking with UPX or manual analysis |
|
||||
|
|
@ -0,0 +1,193 @@
|
|||
# check-deps.ps1 — Verify dependencies for Windows reverse engineering
|
||||
# Output includes machine-readable INSTALL_REQUIRED:<dep> and INSTALL_OPTIONAL:<dep> lines.
|
||||
# Exit code 0 = all required OK, 1 = missing required deps.
|
||||
|
||||
$ErrorActionPreference = 'SilentlyContinue'
|
||||
|
||||
$RequiredJavaMajor = 17
|
||||
$Errors = 0
|
||||
$MissingRequired = @()
|
||||
$MissingOptional = @()
|
||||
|
||||
Write-Host "=== Windows Reverse Engineering: Dependency Check ==="
|
||||
Write-Host ""
|
||||
|
||||
# --- Java ---
|
||||
$javaOk = $false
|
||||
$javaCmdExists = Get-Command java -ErrorAction SilentlyContinue
|
||||
if ($javaCmdExists) {
|
||||
$javaVersionOutput = & java -version 2>&1 | Select-Object -First 1
|
||||
$javaVersionStr = [string]$javaVersionOutput
|
||||
if ($javaVersionStr -match '"(\d+)') {
|
||||
$javaVersion = [int]$Matches[1]
|
||||
if ($javaVersion -ge $RequiredJavaMajor) {
|
||||
Write-Host "[OK] Java $javaVersion detected"
|
||||
$javaOk = $true
|
||||
} else {
|
||||
Write-Host "[WARN] Java detected but version $javaVersion is below $RequiredJavaMajor"
|
||||
$Errors++
|
||||
$MissingRequired += 'java'
|
||||
}
|
||||
} else {
|
||||
Write-Host "[WARN] Java detected but could not parse version from: $javaVersionStr"
|
||||
$Errors++
|
||||
$MissingRequired += 'java'
|
||||
}
|
||||
} else {
|
||||
Write-Host "[MISSING] Java is not installed or not in PATH"
|
||||
$Errors++
|
||||
$MissingRequired += 'java'
|
||||
}
|
||||
|
||||
# --- Ghidra ---
|
||||
$ghidraOk = $false
|
||||
$ghidraDir = $env:GHIDRA_INSTALL_DIR
|
||||
if ($ghidraDir -and (Test-Path "$ghidraDir\support\analyzeHeadless.bat")) {
|
||||
Write-Host "[OK] Ghidra detected at $ghidraDir"
|
||||
$ghidraOk = $true
|
||||
} elseif (Get-Command ghidra -ErrorAction SilentlyContinue) {
|
||||
Write-Host "[OK] Ghidra detected in PATH"
|
||||
$ghidraOk = $true
|
||||
} else {
|
||||
# Check common installation locations
|
||||
$ghidraLocations = @(
|
||||
"$env:ProgramFiles\Ghidra",
|
||||
"$env:ProgramFiles(x86)\Ghidra",
|
||||
"$env:USERPROFILE\ghidra",
|
||||
"C:\Tools\Ghidra",
|
||||
"C:\ghidra"
|
||||
)
|
||||
foreach ($loc in $ghidraLocations) {
|
||||
$candidates = Get-ChildItem -Path $loc -Directory -Filter "ghidra_*" -ErrorAction SilentlyContinue
|
||||
if ($candidates) {
|
||||
$ghidraDir = $candidates | Sort-Object Name -Descending | Select-Object -First 1 -ExpandProperty FullName
|
||||
if (Test-Path "$ghidraDir\support\analyzeHeadless.bat") {
|
||||
Write-Host "[OK] Ghidra detected at $ghidraDir"
|
||||
Write-Host " Hint: Set GHIDRA_INSTALL_DIR=$ghidraDir for faster detection"
|
||||
$ghidraOk = $true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if (-not $ghidraOk) {
|
||||
Write-Host "[MISSING] Ghidra is not installed or GHIDRA_INSTALL_DIR is not set"
|
||||
$MissingRequired += 'ghidra'
|
||||
$Errors++
|
||||
}
|
||||
}
|
||||
|
||||
# --- ilspycmd ---
|
||||
$ilspyOk = $false
|
||||
if (Get-Command ilspycmd -ErrorAction SilentlyContinue) {
|
||||
$ilspyVersion = & ilspycmd --version 2>&1 | Select-Object -First 1
|
||||
Write-Host "[OK] ilspycmd detected ($ilspyVersion)"
|
||||
$ilspyOk = $true
|
||||
} else {
|
||||
Write-Host "[MISSING] ilspycmd is not installed (for .NET assembly decompilation)"
|
||||
# ilspycmd is required if the user wants .NET support, but we only consider
|
||||
# at least one decompiler (ghidra OR ilspycmd) as strictly required
|
||||
if (-not $ghidraOk) {
|
||||
$MissingRequired += 'ilspycmd'
|
||||
$Errors++
|
||||
} else {
|
||||
$MissingOptional += 'ilspycmd'
|
||||
}
|
||||
}
|
||||
|
||||
# If neither decompiler is available, both are required
|
||||
if (-not $ghidraOk -and -not $ilspyOk) {
|
||||
Write-Host ""
|
||||
Write-Host "[ERROR] No decompiler available. At least one of Ghidra or ilspycmd is required."
|
||||
}
|
||||
|
||||
# --- strings / strings2 ---
|
||||
$stringsOk = $false
|
||||
if (Get-Command strings2 -ErrorAction SilentlyContinue) {
|
||||
Write-Host "[OK] strings2 detected"
|
||||
$stringsOk = $true
|
||||
} elseif (Get-Command strings -ErrorAction SilentlyContinue) {
|
||||
Write-Host "[OK] strings (SysInternals) detected"
|
||||
$stringsOk = $true
|
||||
} else {
|
||||
Write-Host "[MISSING] strings/strings2 not found (optional - extracts embedded strings from binaries)"
|
||||
$MissingOptional += 'strings'
|
||||
}
|
||||
|
||||
# --- dumpbin ---
|
||||
$dumpbinOk = $false
|
||||
if (Get-Command dumpbin -ErrorAction SilentlyContinue) {
|
||||
Write-Host "[OK] dumpbin detected"
|
||||
$dumpbinOk = $true
|
||||
} else {
|
||||
# Try to find via VS Developer environment
|
||||
$vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
|
||||
if (Test-Path $vswhere) {
|
||||
$vsInstallPath = & $vswhere -latest -property installationPath 2>$null
|
||||
if ($vsInstallPath) {
|
||||
$dumpbinCandidates = Get-ChildItem -Path "$vsInstallPath\VC\Tools\MSVC" -Recurse -Filter "dumpbin.exe" -ErrorAction SilentlyContinue
|
||||
if ($dumpbinCandidates) {
|
||||
Write-Host "[OK] dumpbin detected at $($dumpbinCandidates[0].FullName)"
|
||||
Write-Host " Note: Use Developer Command Prompt for automatic PATH setup"
|
||||
$dumpbinOk = $true
|
||||
}
|
||||
}
|
||||
}
|
||||
if (-not $dumpbinOk) {
|
||||
Write-Host "[MISSING] dumpbin not found (optional - requires Visual Studio C++ Build Tools)"
|
||||
Write-Host " Install from: https://visualstudio.microsoft.com/visual-cpp-build-tools/"
|
||||
$MissingOptional += 'dumpbin'
|
||||
}
|
||||
}
|
||||
|
||||
# --- .NET SDK (for ilspycmd) ---
|
||||
if (Get-Command dotnet -ErrorAction SilentlyContinue) {
|
||||
$dotnetVersion = & dotnet --version 2>$null
|
||||
Write-Host "[OK] .NET SDK $dotnetVersion detected"
|
||||
} else {
|
||||
Write-Host "[MISSING] .NET SDK not found (needed to install ilspycmd)"
|
||||
if (-not $ilspyOk) {
|
||||
$MissingOptional += 'dotnet-sdk'
|
||||
}
|
||||
}
|
||||
|
||||
# --- Optional: de4dot ---
|
||||
if (Get-Command de4dot -ErrorAction SilentlyContinue) {
|
||||
Write-Host "[OK] de4dot detected (optional - .NET deobfuscation)"
|
||||
} else {
|
||||
Write-Host "[MISSING] de4dot not found (optional - .NET deobfuscator for obfuscated assemblies)"
|
||||
$MissingOptional += 'de4dot'
|
||||
}
|
||||
|
||||
# --- Optional: x64dbg ---
|
||||
if (Get-Command x64dbg -ErrorAction SilentlyContinue) {
|
||||
Write-Host "[OK] x64dbg detected (optional)"
|
||||
} elseif (Test-Path "$env:ProgramFiles\x64dbg\release\x64\x64dbg.exe") {
|
||||
Write-Host "[OK] x64dbg detected (optional)"
|
||||
} else {
|
||||
Write-Host "[MISSING] x64dbg not found (optional - dynamic debugging)"
|
||||
$MissingOptional += 'x64dbg'
|
||||
}
|
||||
|
||||
# --- Machine-readable summary ---
|
||||
Write-Host ""
|
||||
foreach ($dep in $MissingRequired) {
|
||||
Write-Host "INSTALL_REQUIRED:$dep"
|
||||
}
|
||||
foreach ($dep in $MissingOptional) {
|
||||
Write-Host "INSTALL_OPTIONAL:$dep"
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
if ($Errors -gt 0) {
|
||||
Write-Host "*** $($MissingRequired.Count) required dependency/ies missing. ***"
|
||||
Write-Host "Run install-dep.ps1 <name> to install, or see references/setup-guide.md."
|
||||
exit 1
|
||||
} else {
|
||||
if ($MissingOptional.Count -gt 0) {
|
||||
Write-Host "Required dependencies OK. $($MissingOptional.Count) optional dependency/ies missing."
|
||||
Write-Host "Run install-dep.ps1 <name> to install optional tools."
|
||||
} else {
|
||||
Write-Host "All dependencies are installed. Ready to decompile."
|
||||
}
|
||||
exit 0
|
||||
}
|
||||
|
|
@ -0,0 +1,387 @@
|
|||
# decompile.ps1 — Decompile Windows EXE/DLL/.NET assemblies using Ghidra or ILSpy
|
||||
#
|
||||
# Usage: decompile.ps1 [OPTIONS] <file>
|
||||
#
|
||||
# Options:
|
||||
# -Output <dir> Output directory (default: <filename>-decompiled)
|
||||
# -Engine <engine> Decompiler engine: auto, ghidra, ilspy (default: auto)
|
||||
# -NoStrings Skip strings extraction (faster)
|
||||
# -Help Show help message
|
||||
|
||||
param(
|
||||
[Parameter(Position=0)]
|
||||
[string]$InputFile,
|
||||
|
||||
[Alias('o')]
|
||||
[string]$Output = "",
|
||||
|
||||
[ValidateSet('auto', 'ghidra', 'ilspy')]
|
||||
[string]$Engine = "auto",
|
||||
|
||||
[switch]$NoStrings,
|
||||
|
||||
[Alias('h')]
|
||||
[switch]$Help
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
|
||||
function Show-Usage {
|
||||
@"
|
||||
Usage: decompile.ps1 [OPTIONS] <file>
|
||||
|
||||
Decompile a Windows EXE, DLL, or .NET assembly.
|
||||
|
||||
Arguments:
|
||||
<file> Path to the .exe, .dll, or .sys file
|
||||
|
||||
Options:
|
||||
-Output <dir> Output directory (default: <filename>-decompiled)
|
||||
-Engine <engine> Decompiler engine: auto, ghidra, ilspy (default: auto)
|
||||
-NoStrings Skip strings extraction (faster)
|
||||
-Help Show this help message
|
||||
|
||||
Engines:
|
||||
auto Auto-detect binary type and choose the best engine (default)
|
||||
ghidra Use Ghidra headless analyzer (native C/C++ binaries)
|
||||
ilspy Use ilspycmd (for .NET assemblies)
|
||||
|
||||
Environment:
|
||||
GHIDRA_INSTALL_DIR Path to Ghidra installation directory
|
||||
|
||||
Examples:
|
||||
decompile.ps1 MyApp.exe
|
||||
decompile.ps1 -Engine ilspy MyDotNetApp.dll
|
||||
decompile.ps1 -Engine ghidra -Output .\analysis NativeApp.exe
|
||||
decompile.ps1 -NoStrings LargeApp.dll
|
||||
"@
|
||||
exit 0
|
||||
}
|
||||
|
||||
if ($Help) { Show-Usage }
|
||||
|
||||
# --- Validate input ---
|
||||
if (-not $InputFile) {
|
||||
Write-Host "Error: No input file specified." -ForegroundColor Red
|
||||
Show-Usage
|
||||
}
|
||||
|
||||
if (-not (Test-Path $InputFile)) {
|
||||
Write-Host "Error: File not found: $InputFile" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
$InputFileItem = Get-Item $InputFile
|
||||
$InputFileAbs = $InputFileItem.FullName
|
||||
$ext = $InputFileItem.Extension.ToLower()
|
||||
$basename = $InputFileItem.BaseName
|
||||
|
||||
if ($ext -notin @('.exe', '.dll', '.sys')) {
|
||||
Write-Host "Error: Unsupported file type '$ext'. Expected .exe, .dll, or .sys" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
if (-not $Output) {
|
||||
$Output = Join-Path (Split-Path $InputFileAbs -Parent) "${basename}-decompiled"
|
||||
}
|
||||
|
||||
# --- Detect binary type ---
|
||||
function Test-DotNetAssembly {
|
||||
param([string]$FilePath)
|
||||
|
||||
try {
|
||||
$bytes = [System.IO.File]::ReadAllBytes($FilePath)
|
||||
|
||||
# Check MZ header
|
||||
if ($bytes.Length -lt 64 -or $bytes[0] -ne 0x4D -or $bytes[1] -ne 0x5A) {
|
||||
return $false
|
||||
}
|
||||
|
||||
# Get PE header offset from 0x3C
|
||||
$peOffset = [BitConverter]::ToInt32($bytes, 0x3C)
|
||||
if ($peOffset -le 0 -or ($peOffset + 4) -ge $bytes.Length) {
|
||||
return $false
|
||||
}
|
||||
|
||||
# Check PE signature
|
||||
if ($bytes[$peOffset] -ne 0x50 -or $bytes[$peOffset+1] -ne 0x45 -or
|
||||
$bytes[$peOffset+2] -ne 0x00 -or $bytes[$peOffset+3] -ne 0x00) {
|
||||
return $false
|
||||
}
|
||||
|
||||
# COFF header starts at peOffset + 4
|
||||
$coffOffset = $peOffset + 4
|
||||
$sizeOfOptionalHeader = [BitConverter]::ToUInt16($bytes, $coffOffset + 16)
|
||||
|
||||
if ($sizeOfOptionalHeader -eq 0) {
|
||||
return $false
|
||||
}
|
||||
|
||||
# Optional header starts after COFF header (20 bytes)
|
||||
$optOffset = $coffOffset + 20
|
||||
$magic = [BitConverter]::ToUInt16($bytes, $optOffset)
|
||||
|
||||
# PE32 (0x10B) or PE32+ (0x20B)
|
||||
if ($magic -eq 0x10B) {
|
||||
# PE32: CLI header is data directory index 14, at offset 208 from optional header start
|
||||
$cliDirOffset = $optOffset + 208
|
||||
} elseif ($magic -eq 0x20B) {
|
||||
# PE32+: CLI header is data directory index 14, at offset 224 from optional header start
|
||||
$cliDirOffset = $optOffset + 224
|
||||
} else {
|
||||
return $false
|
||||
}
|
||||
|
||||
if (($cliDirOffset + 8) -gt $bytes.Length) {
|
||||
return $false
|
||||
}
|
||||
|
||||
# Check if CLR header data directory has a non-zero RVA and size
|
||||
$cliRva = [BitConverter]::ToUInt32($bytes, $cliDirOffset)
|
||||
$cliSize = [BitConverter]::ToUInt32($bytes, $cliDirOffset + 4)
|
||||
|
||||
return ($cliRva -gt 0 -and $cliSize -gt 0)
|
||||
} catch {
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
function Get-PeInfo {
|
||||
param([string]$FilePath)
|
||||
|
||||
$info = @{
|
||||
Architecture = "unknown"
|
||||
Subsystem = "unknown"
|
||||
IsDotNet = $false
|
||||
}
|
||||
|
||||
try {
|
||||
$bytes = [System.IO.File]::ReadAllBytes($FilePath)
|
||||
$peOffset = [BitConverter]::ToInt32($bytes, 0x3C)
|
||||
$coffOffset = $peOffset + 4
|
||||
|
||||
# Machine type
|
||||
$machine = [BitConverter]::ToUInt16($bytes, $coffOffset)
|
||||
switch ($machine) {
|
||||
0x14C { $info.Architecture = "x86" }
|
||||
0x8664 { $info.Architecture = "x64" }
|
||||
0xAA64 { $info.Architecture = "ARM64" }
|
||||
default { $info.Architecture = "unknown (0x{0:X4})" -f $machine }
|
||||
}
|
||||
|
||||
# Optional header
|
||||
$optOffset = $coffOffset + 20
|
||||
$magic = [BitConverter]::ToUInt16($bytes, $optOffset)
|
||||
|
||||
if ($magic -eq 0x10B) {
|
||||
# PE32
|
||||
$subsystem = [BitConverter]::ToUInt16($bytes, $optOffset + 68)
|
||||
} elseif ($magic -eq 0x20B) {
|
||||
# PE32+
|
||||
$subsystem = [BitConverter]::ToUInt16($bytes, $optOffset + 68)
|
||||
} else {
|
||||
$subsystem = 0
|
||||
}
|
||||
|
||||
switch ($subsystem) {
|
||||
1 { $info.Subsystem = "Native (driver)" }
|
||||
2 { $info.Subsystem = "GUI" }
|
||||
3 { $info.Subsystem = "Console" }
|
||||
default { $info.Subsystem = "unknown ($subsystem)" }
|
||||
}
|
||||
|
||||
$info.IsDotNet = Test-DotNetAssembly $FilePath
|
||||
} catch {
|
||||
# Silently fail — info will have defaults
|
||||
}
|
||||
|
||||
return $info
|
||||
}
|
||||
|
||||
# --- Determine engine ---
|
||||
$peInfo = Get-PeInfo $InputFileAbs
|
||||
$isDotNet = $peInfo.IsDotNet
|
||||
|
||||
Write-Host "=== Decompiling $InputFile ===" -ForegroundColor Cyan
|
||||
Write-Host "Architecture: $($peInfo.Architecture)"
|
||||
Write-Host "Subsystem: $($peInfo.Subsystem)"
|
||||
Write-Host ".NET Assembly: $isDotNet"
|
||||
Write-Host ""
|
||||
|
||||
if ($Engine -eq 'auto') {
|
||||
if ($isDotNet) {
|
||||
$Engine = 'ilspy'
|
||||
Write-Host "Auto-detected: .NET assembly -> using ILSpy" -ForegroundColor Green
|
||||
} else {
|
||||
$Engine = 'ghidra'
|
||||
Write-Host "Auto-detected: Native PE -> using Ghidra" -ForegroundColor Green
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "Engine: $Engine"
|
||||
Write-Host "Output directory: $Output"
|
||||
Write-Host ""
|
||||
|
||||
# --- ILSpy decompilation ---
|
||||
function Invoke-ILSpy {
|
||||
if (-not (Get-Command ilspycmd -ErrorAction SilentlyContinue)) {
|
||||
Write-Host "Error: ilspycmd is not installed. Run: dotnet tool install -g ilspycmd" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
$sourcesDir = Join-Path $Output "sources"
|
||||
New-Item -ItemType Directory -Path $sourcesDir -Force | Out-Null
|
||||
|
||||
Write-Host "Running: ilspycmd -p -o `"$sourcesDir`" `"$InputFileAbs`"" -ForegroundColor Yellow
|
||||
& ilspycmd -p -o $sourcesDir $InputFileAbs 2>&1
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "Warning: ilspycmd exited with code $LASTEXITCODE. Output may be incomplete." -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
# Count output files
|
||||
if (Test-Path $sourcesDir) {
|
||||
$csFiles = Get-ChildItem -Path $sourcesDir -Recurse -Filter "*.cs" | Measure-Object
|
||||
Write-Host ""
|
||||
Write-Host "C# files decompiled: $($csFiles.Count)" -ForegroundColor Green
|
||||
|
||||
# List top-level structure
|
||||
Write-Host ""
|
||||
Write-Host "Top-level structure:" -ForegroundColor Cyan
|
||||
Get-ChildItem -Path $sourcesDir -Depth 1 | ForEach-Object {
|
||||
$prefix = if ($_.PSIsContainer) { "[DIR] " } else { " " }
|
||||
Write-Host " $prefix$($_.Name)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# --- Ghidra decompilation ---
|
||||
function Invoke-Ghidra {
|
||||
# Find Ghidra
|
||||
$ghidraDir = $env:GHIDRA_INSTALL_DIR
|
||||
if (-not $ghidraDir) {
|
||||
# Try common locations
|
||||
$locations = @(
|
||||
"$env:ProgramFiles\Ghidra",
|
||||
"$env:USERPROFILE\.local\share\ghidra",
|
||||
"C:\Tools\Ghidra",
|
||||
"C:\ghidra"
|
||||
)
|
||||
foreach ($loc in $locations) {
|
||||
$candidates = Get-ChildItem -Path $loc -Directory -Filter "ghidra_*" -ErrorAction SilentlyContinue
|
||||
if ($candidates) {
|
||||
$ghidraDir = ($candidates | Sort-Object Name -Descending | Select-Object -First 1).FullName
|
||||
if (Test-Path "$ghidraDir\support\analyzeHeadless.bat") {
|
||||
break
|
||||
}
|
||||
$ghidraDir = $null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $ghidraDir -or -not (Test-Path "$ghidraDir\support\analyzeHeadless.bat")) {
|
||||
Write-Host "Error: Ghidra not found. Set GHIDRA_INSTALL_DIR environment variable." -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
$analyzeHeadless = "$ghidraDir\support\analyzeHeadless.bat"
|
||||
$ghidraScriptsDir = Join-Path $ScriptDir "ghidra-scripts"
|
||||
$projectDir = Join-Path $env:TEMP "GhidraProjects"
|
||||
$projectName = "DecompileProject"
|
||||
|
||||
# Create project directory
|
||||
New-Item -ItemType Directory -Path $projectDir -Force | Out-Null
|
||||
New-Item -ItemType Directory -Path $Output -Force | Out-Null
|
||||
|
||||
Write-Host "Running Ghidra headless analysis..." -ForegroundColor Yellow
|
||||
Write-Host "Project: $projectDir\$projectName" -ForegroundColor DarkGray
|
||||
Write-Host "Script: $ghidraScriptsDir\ExportDecompiled.py" -ForegroundColor DarkGray
|
||||
Write-Host ""
|
||||
|
||||
& cmd /c "`"$analyzeHeadless`" `"$projectDir`" `"$projectName`" -import `"$InputFileAbs`" -scriptPath `"$ghidraScriptsDir`" -postScript `"ExportDecompiled.py`" `"$Output`" -deleteProject -overwrite" 2>&1
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host ""
|
||||
Write-Host "Warning: Ghidra exited with code $LASTEXITCODE. Output may be incomplete." -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
# Report results
|
||||
$decompDir = Join-Path $Output "decompiled"
|
||||
if (Test-Path $decompDir) {
|
||||
$cFiles = Get-ChildItem -Path $decompDir -Recurse -Filter "*.c" | Measure-Object
|
||||
Write-Host ""
|
||||
Write-Host "C pseudocode files: $($cFiles.Count)" -ForegroundColor Green
|
||||
}
|
||||
|
||||
$importsFile = Join-Path $Output "imports.txt"
|
||||
if (Test-Path $importsFile) {
|
||||
$importLines = (Get-Content $importsFile | Where-Object { $_ -match '^\s+\w' }).Count
|
||||
Write-Host "Imported functions: $importLines"
|
||||
}
|
||||
|
||||
$exportsFile = Join-Path $Output "exports.txt"
|
||||
if (Test-Path $exportsFile) {
|
||||
$exportLines = (Get-Content $exportsFile | Where-Object { $_ -match '^\w' -and $_ -notmatch '^#' }).Count
|
||||
Write-Host "Exported functions: $exportLines"
|
||||
}
|
||||
|
||||
$summaryFile = Join-Path $Output "summary.txt"
|
||||
if (Test-Path $summaryFile) {
|
||||
Write-Host ""
|
||||
Write-Host "--- Analysis Summary ---" -ForegroundColor Cyan
|
||||
Get-Content $summaryFile | Write-Host
|
||||
}
|
||||
}
|
||||
|
||||
# --- Strings extraction ---
|
||||
function Invoke-StringsExtraction {
|
||||
if ($NoStrings) {
|
||||
Write-Host "Skipping strings extraction (-NoStrings flag set)"
|
||||
return
|
||||
}
|
||||
|
||||
$stringsOutput = Join-Path $Output "strings.txt"
|
||||
|
||||
# Check if strings were already extracted by Ghidra
|
||||
if (Test-Path $stringsOutput) {
|
||||
$existingLines = (Get-Content $stringsOutput | Measure-Object).Count
|
||||
if ($existingLines -gt 5) {
|
||||
Write-Host "Strings already extracted by decompiler ($existingLines references)"
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if (Get-Command strings2 -ErrorAction SilentlyContinue) {
|
||||
Write-Host "Extracting strings with strings2..."
|
||||
& strings2 $InputFileAbs > $stringsOutput 2>$null
|
||||
} elseif (Get-Command strings -ErrorAction SilentlyContinue) {
|
||||
Write-Host "Extracting strings with SysInternals strings..."
|
||||
& strings -q -accepteula $InputFileAbs > $stringsOutput 2>$null
|
||||
} else {
|
||||
Write-Host "No strings tool available. Skipping strings extraction."
|
||||
Write-Host "Install strings2 or SysInternals strings for embedded string analysis."
|
||||
return
|
||||
}
|
||||
|
||||
if (Test-Path $stringsOutput) {
|
||||
$stringCount = (Get-Content $stringsOutput | Measure-Object).Count
|
||||
Write-Host "Strings extracted: $stringCount"
|
||||
}
|
||||
}
|
||||
|
||||
# --- Run ---
|
||||
switch ($Engine) {
|
||||
'ilspy' {
|
||||
Invoke-ILSpy
|
||||
}
|
||||
'ghidra' {
|
||||
Invoke-Ghidra
|
||||
}
|
||||
}
|
||||
|
||||
Invoke-StringsExtraction
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "=== Decompilation complete ===" -ForegroundColor Green
|
||||
Write-Host "Output: $Output"
|
||||
|
|
@ -0,0 +1,266 @@
|
|||
# find-api-calls.ps1 — Search decompiled source for API calls, network endpoints, and secrets
|
||||
#
|
||||
# Usage: find-api-calls.ps1 <source-dir> [OPTIONS]
|
||||
#
|
||||
# Options:
|
||||
# --network Search only for network/HTTP patterns
|
||||
# --registry Search only for registry operations
|
||||
# --filesystem Search only for file system operations
|
||||
# --process Search only for process manipulation (injection indicators)
|
||||
# --crypto Search only for cryptography patterns
|
||||
# --com Search only for COM/WMI patterns
|
||||
# --services Search only for Windows service patterns
|
||||
# --urls Search only for hardcoded URLs and IPs
|
||||
# --auth Search only for authentication/API key patterns
|
||||
# --persistence Search only for persistence mechanisms
|
||||
# --all Search all patterns (default)
|
||||
# --help Show help message
|
||||
|
||||
param(
|
||||
[Parameter(Position=0)]
|
||||
[string]$SourceDir,
|
||||
|
||||
[switch]$Network,
|
||||
[switch]$Registry,
|
||||
[switch]$FileSystem,
|
||||
[switch]$Process,
|
||||
[switch]$Crypto,
|
||||
[switch]$Com,
|
||||
[switch]$Services,
|
||||
[switch]$Urls,
|
||||
[switch]$Auth,
|
||||
[switch]$Persistence,
|
||||
[switch]$All,
|
||||
|
||||
[Alias('h')]
|
||||
[switch]$Help
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'SilentlyContinue'
|
||||
|
||||
function Show-Usage {
|
||||
@"
|
||||
Usage: find-api-calls.ps1 <source-dir> [OPTIONS]
|
||||
|
||||
Search decompiled source (C pseudocode or C# files) for API calls and patterns.
|
||||
|
||||
Arguments:
|
||||
<source-dir> Path to the decompiled sources directory
|
||||
|
||||
Options:
|
||||
--Network Search only for network/HTTP patterns
|
||||
--Registry Search only for registry operations
|
||||
--FileSystem Search only for file system operations
|
||||
--Process Search only for process manipulation (injection indicators)
|
||||
--Crypto Search only for cryptography patterns
|
||||
--Com Search only for COM/WMI patterns
|
||||
--Services Search only for Windows service patterns
|
||||
--Urls Search only for hardcoded URLs, IPs, and secrets
|
||||
--Auth Search only for authentication/API key patterns
|
||||
--Persistence Search only for persistence mechanisms
|
||||
--All Search all patterns (default)
|
||||
--Help Show this help message
|
||||
|
||||
Output:
|
||||
Results are printed as file:line:match for easy navigation.
|
||||
"@
|
||||
exit 0
|
||||
}
|
||||
|
||||
if ($Help) { Show-Usage }
|
||||
|
||||
if (-not $SourceDir) {
|
||||
Write-Host "Error: No source directory specified." -ForegroundColor Red
|
||||
Show-Usage
|
||||
}
|
||||
|
||||
if (-not (Test-Path $SourceDir)) {
|
||||
Write-Host "Error: Directory not found: $SourceDir" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Determine if any specific flag is set
|
||||
$specificSearch = $Network -or $Registry -or $FileSystem -or $Process -or $Crypto -or $Com -or $Services -or $Urls -or $Auth -or $Persistence
|
||||
$searchAll = $All -or (-not $specificSearch)
|
||||
|
||||
# File extensions to search
|
||||
$includes = @("*.c", "*.cs", "*.h", "*.cpp", "*.txt")
|
||||
|
||||
function Write-Section {
|
||||
param([string]$Title)
|
||||
Write-Host ""
|
||||
Write-Host "==== $Title ====" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
function Search-Pattern {
|
||||
param(
|
||||
[string]$Pattern,
|
||||
[switch]$CaseInsensitive
|
||||
)
|
||||
|
||||
$params = @{
|
||||
Path = $SourceDir
|
||||
Pattern = $Pattern
|
||||
Include = $includes
|
||||
Recurse = $true
|
||||
}
|
||||
|
||||
if ($CaseInsensitive) {
|
||||
$params.CaseSensitive = $false
|
||||
}
|
||||
|
||||
$results = Select-String @params 2>$null
|
||||
|
||||
if ($results) {
|
||||
foreach ($r in $results) {
|
||||
$relPath = $r.Path
|
||||
try {
|
||||
$relPath = [System.IO.Path]::GetRelativePath($SourceDir, $r.Path)
|
||||
} catch { }
|
||||
Write-Host "${relPath}:$($r.LineNumber):$($r.Line.Trim())"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# =====================================================================
|
||||
# Search categories
|
||||
# =====================================================================
|
||||
|
||||
# --- Network (Native Win32) ---
|
||||
if ($searchAll -or $Network) {
|
||||
Write-Section "WinHTTP"
|
||||
Search-Pattern 'WinHttpOpen|WinHttpConnect|WinHttpOpenRequest|WinHttpSendRequest|WinHttpReceiveResponse|WinHttpReadData|WinHttpSetOption|WinHttpQueryHeaders'
|
||||
|
||||
Write-Section "WinINet"
|
||||
Search-Pattern 'InternetOpen[AW]?|InternetConnect[AW]?|HttpOpenRequest[AW]?|HttpSendRequest[AW]?|InternetReadFile|InternetCloseHandle|InternetSetOption[AW]?|HttpQueryInfo[AW]?'
|
||||
|
||||
Write-Section "Winsock"
|
||||
Search-Pattern 'WSAStartup|socket\s*\(|connect\s*\(|send\s*\(|recv\s*\(|bind\s*\(|listen\s*\(|accept\s*\(|closesocket|getaddrinfo|gethostbyname|WSASocket|WSASend|WSARecv'
|
||||
|
||||
Write-Section ".NET HttpClient"
|
||||
Search-Pattern 'HttpClient|GetAsync|PostAsync|PutAsync|DeleteAsync|SendAsync|GetStringAsync|GetStreamAsync|IHttpClientFactory|AddHttpClient|CreateClient'
|
||||
|
||||
Write-Section ".NET WebRequest (legacy)"
|
||||
Search-Pattern 'WebRequest|HttpWebRequest|WebClient|DownloadString|DownloadFile|UploadString|UploadFile'
|
||||
|
||||
Write-Section ".NET HTTP Request Construction"
|
||||
Search-Pattern 'HttpRequestMessage|StringContent|JsonContent|FormUrlEncodedContent|MultipartFormDataContent|BaseAddress'
|
||||
|
||||
Write-Section "RestSharp / Refit"
|
||||
Search-Pattern 'RestClient|RestRequest|RestResponse|IRestClient|\[Get\(|\[Post\(|\[Put\(|\[Delete\(|\[Patch\('
|
||||
}
|
||||
|
||||
# --- Registry ---
|
||||
if ($searchAll -or $Registry) {
|
||||
Write-Section "Registry (Native)"
|
||||
Search-Pattern 'RegOpenKey[AW]?(Ex)?|RegCreateKey[AW]?(Ex)?|RegSetValue[AW]?(Ex)?|RegQueryValue[AW]?(Ex)?|RegDeleteKey[AW]?(Ex)?|RegDeleteValue[AW]?|RegEnumKey[AW]?(Ex)?|RegEnumValue[AW]?|RegCloseKey'
|
||||
|
||||
Write-Section "Registry (.NET)"
|
||||
Search-Pattern 'Microsoft\.Win32\.Registry|RegistryKey|OpenSubKey|SetValue|GetValue|CreateSubKey|DeleteSubKey|RegistryHive'
|
||||
}
|
||||
|
||||
# --- File System ---
|
||||
if ($searchAll -or $FileSystem) {
|
||||
Write-Section "File System (Native)"
|
||||
Search-Pattern 'CreateFile[AW]?|ReadFile|WriteFile|DeleteFile[AW]?|CopyFile[AW]?|MoveFile[AW]?(Ex)?|FindFirstFile[AW]?|FindNextFile[AW]?|GetFileAttributes[AW]?|SetFileAttributes[AW]?|CreateDirectory[AW]?|RemoveDirectory[AW]?|GetTempPath|GetTempFileName'
|
||||
|
||||
Write-Section "File System (.NET)"
|
||||
Search-Pattern 'File\.(Read|Write|Append|Copy|Move|Delete|Exists|Open|Create)|Directory\.(Create|Delete|Exists|GetFiles|GetDirectories)|FileStream|StreamReader|StreamWriter|BinaryReader|BinaryWriter|Path\.Combine|Path\.GetTempPath'
|
||||
}
|
||||
|
||||
# --- Process and Thread Manipulation ---
|
||||
if ($searchAll -or $Process) {
|
||||
Write-Section "Process Creation"
|
||||
Search-Pattern 'CreateProcess[AW]?|ShellExecute[AW]?(Ex)?|WinExec|system\s*\('
|
||||
|
||||
Write-Section "Process Injection Indicators"
|
||||
Search-Pattern 'VirtualAlloc(Ex)?|VirtualProtect(Ex)?|WriteProcessMemory|ReadProcessMemory|CreateRemoteThread(Ex)?|NtCreateThreadEx|QueueUserAPC|SetThreadContext|GetThreadContext|SuspendThread|ResumeThread'
|
||||
|
||||
Write-Section "DLL Loading"
|
||||
Search-Pattern 'LoadLibrary[AW]?(Ex)?|GetProcAddress|FreeLibrary|GetModuleHandle[AW]?|GetModuleFileName[AW]?'
|
||||
|
||||
Write-Section "Process (.NET)"
|
||||
Search-Pattern 'Process\.Start|ProcessStartInfo|Process\.GetProcesses|Process\.GetCurrentProcess'
|
||||
|
||||
Write-Section "Memory Mapping"
|
||||
Search-Pattern 'CreateFileMapping[AW]?|MapViewOfFile(Ex)?|OpenFileMapping[AW]?|UnmapViewOfFile'
|
||||
}
|
||||
|
||||
# --- Cryptography ---
|
||||
if ($searchAll -or $Crypto) {
|
||||
Write-Section "CryptoAPI (Native)"
|
||||
Search-Pattern 'CryptAcquireContext|CryptEncrypt|CryptDecrypt|CryptHashData|CryptDeriveKey|CryptGenKey|CryptImportKey|CryptExportKey|CryptGenRandom|CryptCreateHash|CryptSetKeyParam'
|
||||
|
||||
Write-Section "BCrypt (Native)"
|
||||
Search-Pattern 'BCryptOpenAlgorithmProvider|BCryptEncrypt|BCryptDecrypt|BCryptGenerateSymmetricKey|BCryptHash|BCryptCreateHash|BCryptFinishHash|BCryptDeriveKey|BCryptGenerateKeyPair'
|
||||
|
||||
Write-Section "Cryptography (.NET)"
|
||||
Search-Pattern 'System\.Security\.Cryptography|Aes\.|AesManaged|AesCryptoServiceProvider|RSA\.|RSACryptoServiceProvider|SHA256|SHA512|MD5|HMAC|RijndaelManaged|X509Certificate|ProtectedData|DataProtection'
|
||||
}
|
||||
|
||||
# --- COM and WMI ---
|
||||
if ($searchAll -or $Com) {
|
||||
Write-Section "COM"
|
||||
Search-Pattern 'CoCreateInstance|CoInitialize(Ex)?|CoUninitialize|IDispatch|IUnknown|CLSIDFromProgID|ProgIDFromCLSID|CoGetClassObject'
|
||||
|
||||
Write-Section "WMI (Native)"
|
||||
Search-Pattern 'IWbemLocator|IWbemServices|ConnectServer|ExecQuery|ExecMethod'
|
||||
|
||||
Write-Section "WMI (.NET)"
|
||||
Search-Pattern 'ManagementObjectSearcher|ManagementObject|ManagementScope|ObjectQuery|WqlObjectQuery|SelectQuery|ManagementClass'
|
||||
}
|
||||
|
||||
# --- Windows Services ---
|
||||
if ($searchAll -or $Services) {
|
||||
Write-Section "Services (Native)"
|
||||
Search-Pattern 'OpenSCManager[AW]?|CreateService[AW]?|OpenService[AW]?|StartService|ControlService|DeleteService|ChangeServiceConfig[AW]?|QueryServiceStatus(Ex)?|RegisterServiceCtrlHandler(Ex)?|SetServiceStatus|StartServiceCtrlDispatcher'
|
||||
|
||||
Write-Section "Services (.NET)"
|
||||
Search-Pattern 'ServiceBase|ServiceController|ServiceInstaller|ServiceProcessInstaller|OnStart|OnStop|ServiceName|RunAsService'
|
||||
}
|
||||
|
||||
# --- Hardcoded URLs, IPs, and Secrets ---
|
||||
if ($searchAll -or $Urls) {
|
||||
Write-Section "Hardcoded URLs (http:// and https://)"
|
||||
Search-Pattern '"https?://[^"]+'
|
||||
|
||||
Write-Section "IP Addresses"
|
||||
Search-Pattern '\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b'
|
||||
|
||||
Write-Section "Connection Strings"
|
||||
Search-Pattern 'Data Source=|Server=|Initial Catalog=|connectionString|ConnectionStrings|Provider=' -CaseInsensitive
|
||||
|
||||
Write-Section "File Paths"
|
||||
Search-Pattern '"[A-Za-z]:\\[^"]+"|"\\\\[^"]+'
|
||||
}
|
||||
|
||||
# --- Authentication and API Keys ---
|
||||
if ($searchAll -or $Auth) {
|
||||
Write-Section "Authentication and API Keys"
|
||||
Search-Pattern 'api[_\-]?key|api[_\-]?secret|auth[_\-]?token|bearer|authorization|x-api-key|client[_\-]?secret|access[_\-]?token|refresh[_\-]?token' -CaseInsensitive
|
||||
|
||||
Write-Section "Base URLs and Constants"
|
||||
Search-Pattern 'BASE_URL|API_URL|SERVER_URL|ENDPOINT|API_BASE|HOST_NAME|ServiceUrl|BaseAddress|ApiEndpoint' -CaseInsensitive
|
||||
|
||||
Write-Section "Credentials"
|
||||
Search-Pattern 'password|passwd|pwd|credential|username|login|authenticate' -CaseInsensitive
|
||||
}
|
||||
|
||||
# --- Persistence Mechanisms ---
|
||||
if ($searchAll -or $Persistence) {
|
||||
Write-Section "Registry Run Keys"
|
||||
Search-Pattern 'CurrentVersion\\Run|CurrentVersion\\RunOnce|CurrentVersion\\RunServices|CurrentVersion\\Policies\\Explorer\\Run'
|
||||
|
||||
Write-Section "Scheduled Tasks"
|
||||
Search-Pattern 'schtasks|ITaskService|ITaskDefinition|TaskScheduler|Register-ScheduledTask|New-ScheduledTask'
|
||||
|
||||
Write-Section "Startup Folder"
|
||||
Search-Pattern 'Startup|shell:startup|Programs\\Startup|Environment\.GetFolderPath.*Startup'
|
||||
|
||||
Write-Section "Service Installation"
|
||||
Search-Pattern 'CreateService|sc\.exe\s+(create|config)|New-Service|Install-Service|RegisterServiceCtrlHandler'
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "=== Search complete ===" -ForegroundColor Green
|
||||
|
|
@ -0,0 +1,233 @@
|
|||
# @category Export
|
||||
# @description Export decompiled C pseudocode, imports, exports, and strings from a Windows PE binary
|
||||
# @author Windows Reverse Engineering Skill
|
||||
#
|
||||
# This Jython script is designed to be run by Ghidra's Headless Analyzer.
|
||||
# It decompiles all functions to C pseudocode and exports metadata.
|
||||
#
|
||||
# Usage via analyzeHeadless:
|
||||
# analyzeHeadless.bat <projectDir> <projectName> -import <binary> \
|
||||
# -scriptPath <this_dir> -postScript ExportDecompiled.py <outputDir>
|
||||
|
||||
import os
|
||||
import sys
|
||||
from ghidra.app.decompiler import DecompInterface
|
||||
from ghidra.util.task import ConsoleTaskMonitor
|
||||
from ghidra.program.model.symbol import SymbolType
|
||||
|
||||
# Get output directory from script arguments or use default
|
||||
args = getScriptArgs()
|
||||
if args and len(args) > 0:
|
||||
output_dir = args[0]
|
||||
else:
|
||||
# Default: create output next to the analyzed file
|
||||
prog_name = currentProgram.getName()
|
||||
base_name = prog_name.rsplit('.', 1)[0] if '.' in prog_name else prog_name
|
||||
output_dir = os.path.join(os.getcwd(), base_name + "-decompiled")
|
||||
|
||||
# Create output subdirectories
|
||||
decompiled_dir = os.path.join(output_dir, "decompiled")
|
||||
if not os.path.exists(decompiled_dir):
|
||||
os.makedirs(decompiled_dir)
|
||||
|
||||
print("=== Ghidra Export Script ===")
|
||||
print("Program: {}".format(currentProgram.getName()))
|
||||
print("Output directory: {}".format(output_dir))
|
||||
print("")
|
||||
|
||||
# =====================================================================
|
||||
# 1. Export decompiled C pseudocode for all functions
|
||||
# =====================================================================
|
||||
print("--- Decompiling functions ---")
|
||||
|
||||
monitor = ConsoleTaskMonitor()
|
||||
decomp = DecompInterface()
|
||||
decomp.openProgram(currentProgram)
|
||||
|
||||
# Set decompiler options for better output
|
||||
options = decomp.getOptions()
|
||||
# Increase timeout for complex functions (60 seconds)
|
||||
decomp.setSimplificationStyle("decompile")
|
||||
|
||||
fm = currentProgram.getFunctionManager()
|
||||
functions = fm.getFunctions(True) # Forward iteration
|
||||
|
||||
func_count = 0
|
||||
error_count = 0
|
||||
decompiled_count = 0
|
||||
|
||||
for func in functions:
|
||||
func_count += 1
|
||||
func_name = func.getName()
|
||||
entry = func.getEntryPoint()
|
||||
|
||||
# Skip thunks and external functions for cleaner output
|
||||
if func.isThunk():
|
||||
continue
|
||||
|
||||
try:
|
||||
results = decomp.decompileFunction(func, 60, monitor)
|
||||
if results and results.decompileCompleted():
|
||||
decomp_func = results.getDecompiledFunction()
|
||||
if decomp_func:
|
||||
c_code = decomp_func.getC()
|
||||
if c_code:
|
||||
# Sanitize function name for filename
|
||||
safe_name = func_name.replace('<', '_').replace('>', '_').replace(':', '_').replace('*', '_').replace('?', '_').replace('"', '_').replace('/', '_').replace('\\', '_').replace('|', '_')
|
||||
# Add address to avoid name collisions
|
||||
file_name = "{}_{}.c".format(safe_name, entry.toString())
|
||||
file_path = os.path.join(decompiled_dir, file_name)
|
||||
|
||||
with open(file_path, 'w') as f:
|
||||
f.write("// Function: {}\n".format(func_name))
|
||||
f.write("// Address: {}\n".format(entry.toString()))
|
||||
f.write("// Calling Convention: {}\n".format(func.getCallingConventionName()))
|
||||
f.write("//\n\n")
|
||||
f.write(c_code)
|
||||
|
||||
decompiled_count += 1
|
||||
else:
|
||||
error_count += 1
|
||||
except Exception as e:
|
||||
error_count += 1
|
||||
# Continue on error — don't stop for individual function failures
|
||||
|
||||
decomp.dispose()
|
||||
|
||||
print("Functions found: {}".format(func_count))
|
||||
print("Functions decompiled: {}".format(decompiled_count))
|
||||
print("Errors/timeouts: {}".format(error_count))
|
||||
print("")
|
||||
|
||||
# =====================================================================
|
||||
# 2. Export import table
|
||||
# =====================================================================
|
||||
print("--- Exporting imports ---")
|
||||
|
||||
imports_path = os.path.join(output_dir, "imports.txt")
|
||||
import_count = 0
|
||||
|
||||
with open(imports_path, 'w') as f:
|
||||
f.write("# Import Table for {}\n".format(currentProgram.getName()))
|
||||
f.write("# Format: DLL :: FunctionName @ Address\n\n")
|
||||
|
||||
sym_table = currentProgram.getSymbolTable()
|
||||
ext_symbols = sym_table.getExternalSymbols()
|
||||
|
||||
current_dll = None
|
||||
for sym in ext_symbols:
|
||||
if sym.getSymbolType() == SymbolType.FUNCTION:
|
||||
parent = sym.getParentNamespace()
|
||||
dll_name = parent.getName() if parent else "UNKNOWN"
|
||||
func_name = sym.getName()
|
||||
addr = sym.getAddress()
|
||||
|
||||
if dll_name != current_dll:
|
||||
f.write("\n[{}]\n".format(dll_name))
|
||||
current_dll = dll_name
|
||||
|
||||
f.write(" {} @ {}\n".format(func_name, addr.toString()))
|
||||
import_count += 1
|
||||
|
||||
print("Imports exported: {} functions".format(import_count))
|
||||
print("")
|
||||
|
||||
# =====================================================================
|
||||
# 3. Export export table (for DLLs)
|
||||
# =====================================================================
|
||||
print("--- Exporting exports ---")
|
||||
|
||||
exports_path = os.path.join(output_dir, "exports.txt")
|
||||
export_count = 0
|
||||
|
||||
with open(exports_path, 'w') as f:
|
||||
f.write("# Export Table for {}\n".format(currentProgram.getName()))
|
||||
f.write("# Format: FunctionName @ Address\n\n")
|
||||
|
||||
sym_table = currentProgram.getSymbolTable()
|
||||
for sym in sym_table.getAllSymbols(True):
|
||||
if sym.isExternalEntryPoint():
|
||||
f.write("{} @ {}\n".format(sym.getName(), sym.getAddress().toString()))
|
||||
export_count += 1
|
||||
|
||||
if export_count == 0:
|
||||
with open(exports_path, 'w') as f:
|
||||
f.write("# No exports found (this is expected for EXE files)\n")
|
||||
|
||||
print("Exports found: {}".format(export_count))
|
||||
print("")
|
||||
|
||||
# =====================================================================
|
||||
# 4. Export string references
|
||||
# =====================================================================
|
||||
print("--- Exporting strings ---")
|
||||
|
||||
strings_path = os.path.join(output_dir, "strings.txt")
|
||||
string_count = 0
|
||||
|
||||
with open(strings_path, 'w') as f:
|
||||
f.write("# String References for {}\n".format(currentProgram.getName()))
|
||||
f.write("# Format: Address | String\n\n")
|
||||
|
||||
listing = currentProgram.getListing()
|
||||
data_iter = listing.getDefinedData(True)
|
||||
|
||||
for data in data_iter:
|
||||
if monitor.isCancelled():
|
||||
break
|
||||
|
||||
data_type = data.getDataType()
|
||||
type_name = data_type.getName() if data_type else ""
|
||||
|
||||
if "string" in type_name.lower() or "unicode" in type_name.lower():
|
||||
value = data.getValue()
|
||||
if value:
|
||||
val_str = str(value)
|
||||
# Filter out very short or empty strings
|
||||
if len(val_str) >= 3:
|
||||
f.write("{} | {}\n".format(data.getAddress().toString(), val_str))
|
||||
string_count += 1
|
||||
|
||||
print("Strings exported: {}".format(string_count))
|
||||
print("")
|
||||
|
||||
# =====================================================================
|
||||
# 5. Export summary
|
||||
# =====================================================================
|
||||
print("--- Generating summary ---")
|
||||
|
||||
summary_path = os.path.join(output_dir, "summary.txt")
|
||||
|
||||
with open(summary_path, 'w') as f:
|
||||
f.write("=== Analysis Summary ===\n\n")
|
||||
f.write("Program: {}\n".format(currentProgram.getName()))
|
||||
f.write("Language: {}\n".format(currentProgram.getLanguage().getLanguageDescription().getDescription()))
|
||||
f.write("Compiler: {}\n".format(currentProgram.getCompilerSpec().getCompilerSpecDescription().getCompilerSpecName()))
|
||||
f.write("Image Base: {}\n".format(currentProgram.getImageBase().toString()))
|
||||
f.write("Min Address: {}\n".format(currentProgram.getMinAddress().toString()))
|
||||
f.write("Max Address: {}\n".format(currentProgram.getMaxAddress().toString()))
|
||||
|
||||
f.write("\nFunctions: {}\n".format(func_count))
|
||||
f.write("Decompiled: {}\n".format(decompiled_count))
|
||||
f.write("Decompile errors: {}\n".format(error_count))
|
||||
f.write("Imports: {}\n".format(import_count))
|
||||
f.write("Exports: {}\n".format(export_count))
|
||||
f.write("Strings: {}\n".format(string_count))
|
||||
|
||||
# List memory blocks / sections
|
||||
f.write("\n--- Sections ---\n")
|
||||
memory = currentProgram.getMemory()
|
||||
for block in memory.getBlocks():
|
||||
f.write(" {} | Start: {} | Size: {} | Permissions: {}{}{}\n".format(
|
||||
block.getName(),
|
||||
block.getStart().toString(),
|
||||
block.getSize(),
|
||||
"R" if block.isRead() else "-",
|
||||
"W" if block.isWrite() else "-",
|
||||
"X" if block.isExecute() else "-"
|
||||
))
|
||||
|
||||
print("Summary written to {}".format(summary_path))
|
||||
print("")
|
||||
print("=== Export complete ===")
|
||||
print("Output: {}".format(output_dir))
|
||||
Binary file not shown.
|
|
@ -0,0 +1,370 @@
|
|||
# install-dep.ps1 — Install a single dependency for Windows reverse engineering
|
||||
# Usage: install-dep.ps1 <dependency>
|
||||
# Dependencies: java, ghidra, ilspycmd, strings, dumpbin, de4dot, dotnet-sdk
|
||||
#
|
||||
# Exit codes:
|
||||
# 0 — installed successfully
|
||||
# 1 — installation failed
|
||||
# 2 — requires manual action (e.g. admin needed but not available)
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory=$true, Position=0)]
|
||||
[string]$Dependency
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# --- Detect environment ---
|
||||
$HasWinget = $null -ne (Get-Command winget -ErrorAction SilentlyContinue)
|
||||
$HasChoco = $null -ne (Get-Command choco -ErrorAction SilentlyContinue)
|
||||
$HasDotnet = $null -ne (Get-Command dotnet -ErrorAction SilentlyContinue)
|
||||
$IsAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||
|
||||
function Write-Info { param([string]$Message) Write-Host "[INFO] $Message" }
|
||||
function Write-Ok { param([string]$Message) Write-Host "[OK] $Message" }
|
||||
function Write-Fail { param([string]$Message) Write-Host "[FAIL] $Message" -ForegroundColor Red }
|
||||
function Write-Manual {
|
||||
param([string]$Message)
|
||||
Write-Host "[MANUAL] $Message" -ForegroundColor Yellow
|
||||
Write-Host " Cannot install automatically. Please install manually and retry." -ForegroundColor Yellow
|
||||
exit 2
|
||||
}
|
||||
|
||||
function Get-GithubLatestTag {
|
||||
param([string]$Repo)
|
||||
try {
|
||||
$release = Invoke-RestMethod -Uri "https://api.github.com/repos/$Repo/releases/latest" -UseBasicParsing
|
||||
return $release.tag_name
|
||||
} catch {
|
||||
return $null
|
||||
}
|
||||
}
|
||||
|
||||
function Download-File {
|
||||
param([string]$Url, [string]$Dest)
|
||||
Write-Info "Downloading from $Url..."
|
||||
try {
|
||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||
Invoke-WebRequest -Uri $Url -OutFile $Dest -UseBasicParsing
|
||||
} catch {
|
||||
Write-Fail "Download failed: $_"
|
||||
return $false
|
||||
}
|
||||
return $true
|
||||
}
|
||||
|
||||
function Add-ToUserPath {
|
||||
param([string]$Dir)
|
||||
$currentPath = [System.Environment]::GetEnvironmentVariable('PATH', 'User')
|
||||
if ($currentPath -notlike "*$Dir*") {
|
||||
[System.Environment]::SetEnvironmentVariable('PATH', "$currentPath;$Dir", 'User')
|
||||
$env:PATH = "$env:PATH;$Dir"
|
||||
Write-Info "Added $Dir to user PATH. Restart your terminal for full effect."
|
||||
}
|
||||
}
|
||||
|
||||
# =====================================================================
|
||||
# Dependency installers
|
||||
# =====================================================================
|
||||
|
||||
function Install-Java {
|
||||
$javaCmdExists = Get-Command java -ErrorAction SilentlyContinue
|
||||
if ($javaCmdExists) {
|
||||
$javaVersionOutput = & java -version 2>&1 | Select-Object -First 1
|
||||
if ([string]$javaVersionOutput -match '"(\d+)') {
|
||||
$ver = [int]$Matches[1]
|
||||
if ($ver -ge 17) {
|
||||
Write-Ok "Java $ver already installed"
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Write-Info "Installing Java JDK 17+..."
|
||||
|
||||
if ($HasWinget) {
|
||||
Write-Info "Installing via winget..."
|
||||
& winget install Microsoft.OpenJDK.17 --accept-source-agreements --accept-package-agreements
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-Ok "Java 17 installed via winget"
|
||||
return
|
||||
}
|
||||
Write-Info "winget failed, trying alternatives..."
|
||||
}
|
||||
|
||||
if ($HasChoco) {
|
||||
Write-Info "Installing via Chocolatey..."
|
||||
& choco install openjdk17 -y
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-Ok "Java 17 installed via Chocolatey"
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
Write-Manual "Install Java JDK 17+ from https://adoptium.net/temurin/releases/?version=17"
|
||||
}
|
||||
|
||||
function Install-Ghidra {
|
||||
# Check if already available
|
||||
$ghidraDir = $env:GHIDRA_INSTALL_DIR
|
||||
if ($ghidraDir -and (Test-Path "$ghidraDir\support\analyzeHeadless.bat")) {
|
||||
Write-Ok "Ghidra already installed at $ghidraDir"
|
||||
return
|
||||
}
|
||||
|
||||
if ($HasChoco) {
|
||||
Write-Info "Installing Ghidra via Chocolatey..."
|
||||
& choco install ghidra -y
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-Ok "Ghidra installed via Chocolatey"
|
||||
Write-Info "Set GHIDRA_INSTALL_DIR to the Ghidra installation directory."
|
||||
return
|
||||
}
|
||||
Write-Info "Chocolatey install failed, trying direct download..."
|
||||
}
|
||||
|
||||
# Direct download from GitHub
|
||||
Write-Info "Installing Ghidra from GitHub releases..."
|
||||
$tag = Get-GithubLatestTag "NationalSecurityAgency/ghidra"
|
||||
if (-not $tag) {
|
||||
Write-Manual "Could not determine latest Ghidra version. Download from https://github.com/NationalSecurityAgency/ghidra/releases/latest"
|
||||
}
|
||||
|
||||
$version = $tag -replace '^Ghidra_', '' -replace '_build$', ''
|
||||
|
||||
# Try to find the download URL from the release assets
|
||||
try {
|
||||
$release = Invoke-RestMethod -Uri "https://api.github.com/repos/NationalSecurityAgency/ghidra/releases/latest" -UseBasicParsing
|
||||
$asset = $release.assets | Where-Object { $_.name -like "ghidra_*_PUBLIC_*.zip" } | Select-Object -First 1
|
||||
if (-not $asset) {
|
||||
Write-Manual "Could not find Ghidra download. Download from https://github.com/NationalSecurityAgency/ghidra/releases/latest"
|
||||
}
|
||||
$downloadUrl = $asset.browser_download_url
|
||||
} catch {
|
||||
Write-Manual "Could not access GitHub API. Download Ghidra from https://github.com/NationalSecurityAgency/ghidra/releases/latest"
|
||||
}
|
||||
|
||||
$installDir = "$env:USERPROFILE\.local\share\ghidra"
|
||||
$tmpZip = "$env:TEMP\ghidra-download.zip"
|
||||
|
||||
if (-not (Download-File -Url $downloadUrl -Dest $tmpZip)) {
|
||||
Write-Manual "Download failed. Download manually from $downloadUrl"
|
||||
}
|
||||
|
||||
Write-Info "Extracting Ghidra..."
|
||||
if (Test-Path $installDir) { Remove-Item -Recurse -Force $installDir }
|
||||
New-Item -ItemType Directory -Path $installDir -Force | Out-Null
|
||||
Expand-Archive -Path $tmpZip -DestinationPath $installDir -Force
|
||||
Remove-Item $tmpZip -Force
|
||||
|
||||
# Find the actual Ghidra directory inside the extracted archive
|
||||
$ghidraSubDir = Get-ChildItem -Path $installDir -Directory -Filter "ghidra_*" | Select-Object -First 1
|
||||
if ($ghidraSubDir) {
|
||||
$ghidraPath = $ghidraSubDir.FullName
|
||||
} else {
|
||||
$ghidraPath = $installDir
|
||||
}
|
||||
|
||||
# Set environment variable
|
||||
[System.Environment]::SetEnvironmentVariable('GHIDRA_INSTALL_DIR', $ghidraPath, 'User')
|
||||
$env:GHIDRA_INSTALL_DIR = $ghidraPath
|
||||
|
||||
Write-Ok "Ghidra installed to $ghidraPath"
|
||||
Write-Info "GHIDRA_INSTALL_DIR set to $ghidraPath"
|
||||
Write-Info "Restart your terminal for the environment variable to take effect."
|
||||
}
|
||||
|
||||
function Install-IlspyCmd {
|
||||
if (Get-Command ilspycmd -ErrorAction SilentlyContinue) {
|
||||
Write-Ok "ilspycmd already installed"
|
||||
return
|
||||
}
|
||||
|
||||
if (-not $HasDotnet) {
|
||||
Write-Info ".NET SDK not found. Installing .NET SDK first..."
|
||||
Install-DotnetSdk
|
||||
# Re-check
|
||||
$HasDotnet = $null -ne (Get-Command dotnet -ErrorAction SilentlyContinue)
|
||||
if (-not $HasDotnet) {
|
||||
Write-Fail ".NET SDK installation failed. Cannot install ilspycmd."
|
||||
Write-Manual "Install .NET SDK from https://dotnet.microsoft.com/ then run: dotnet tool install -g ilspycmd"
|
||||
}
|
||||
}
|
||||
|
||||
Write-Info "Installing ilspycmd via dotnet tool..."
|
||||
& dotnet tool install -g ilspycmd
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-Ok "ilspycmd installed"
|
||||
} else {
|
||||
# May already be installed but older version
|
||||
& dotnet tool update -g ilspycmd
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-Ok "ilspycmd updated"
|
||||
} else {
|
||||
Write-Fail "ilspycmd installation failed."
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Install-DotnetSdk {
|
||||
if ($HasDotnet) {
|
||||
$ver = & dotnet --version 2>$null
|
||||
Write-Ok ".NET SDK $ver already installed"
|
||||
return
|
||||
}
|
||||
|
||||
Write-Info "Installing .NET SDK..."
|
||||
|
||||
if ($HasWinget) {
|
||||
Write-Info "Installing via winget..."
|
||||
& winget install Microsoft.DotNet.SDK.8 --accept-source-agreements --accept-package-agreements
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-Ok ".NET SDK installed via winget"
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if ($HasChoco) {
|
||||
Write-Info "Installing via Chocolatey..."
|
||||
& choco install dotnet-sdk -y
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-Ok ".NET SDK installed via Chocolatey"
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
Write-Manual "Install .NET SDK from https://dotnet.microsoft.com/download"
|
||||
}
|
||||
|
||||
function Install-Strings {
|
||||
if (Get-Command strings2 -ErrorAction SilentlyContinue) {
|
||||
Write-Ok "strings2 already installed"
|
||||
return
|
||||
}
|
||||
if (Get-Command strings -ErrorAction SilentlyContinue) {
|
||||
Write-Ok "strings (SysInternals) already installed"
|
||||
return
|
||||
}
|
||||
|
||||
# Try winget for SysInternals strings
|
||||
if ($HasWinget) {
|
||||
Write-Info "Installing SysInternals Strings via winget..."
|
||||
& winget install Microsoft.Sysinternals.Strings --accept-source-agreements --accept-package-agreements
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-Ok "SysInternals Strings installed via winget"
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
# Direct download strings2
|
||||
Write-Info "Installing strings2 from GitHub..."
|
||||
$tag = Get-GithubLatestTag "glmcdona/strings2"
|
||||
if (-not $tag) {
|
||||
$tag = "v2.0.0"
|
||||
}
|
||||
|
||||
$installDir = "$env:USERPROFILE\.local\share\strings2"
|
||||
New-Item -ItemType Directory -Path $installDir -Force | Out-Null
|
||||
|
||||
$downloadUrl = "https://github.com/glmcdona/strings2/releases/download/$tag/strings2.exe"
|
||||
if (Download-File -Url $downloadUrl -Dest "$installDir\strings2.exe") {
|
||||
$binDir = "$env:USERPROFILE\.local\bin"
|
||||
New-Item -ItemType Directory -Path $binDir -Force | Out-Null
|
||||
Copy-Item "$installDir\strings2.exe" "$binDir\strings2.exe" -Force
|
||||
Add-ToUserPath $binDir
|
||||
Write-Ok "strings2 installed to $binDir"
|
||||
} else {
|
||||
Write-Manual "Download strings2 from https://github.com/glmcdona/strings2/releases"
|
||||
}
|
||||
}
|
||||
|
||||
function Install-Dumpbin {
|
||||
if (Get-Command dumpbin -ErrorAction SilentlyContinue) {
|
||||
Write-Ok "dumpbin already installed"
|
||||
return
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "[INFO] dumpbin requires Visual Studio C++ Build Tools." -ForegroundColor Yellow
|
||||
Write-Host "[INFO] This is a large download (~2-4 GB) and requires admin privileges." -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
Write-Host "To install:" -ForegroundColor Cyan
|
||||
Write-Host " 1. Download from: https://visualstudio.microsoft.com/visual-cpp-build-tools/" -ForegroundColor Cyan
|
||||
Write-Host " 2. In the installer, select 'Desktop development with C++'" -ForegroundColor Cyan
|
||||
Write-Host " 3. After installation, use 'Developer Command Prompt' or 'Developer PowerShell' for dumpbin access" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host "Alternatively, Ghidra can extract the same PE information (imports, exports, headers)." -ForegroundColor Green
|
||||
Write-Host ""
|
||||
exit 2
|
||||
}
|
||||
|
||||
function Install-De4dot {
|
||||
if (Get-Command de4dot -ErrorAction SilentlyContinue) {
|
||||
Write-Ok "de4dot already installed"
|
||||
return
|
||||
}
|
||||
|
||||
Write-Info "Installing de4dot from GitHub..."
|
||||
$tag = Get-GithubLatestTag "de4dot/de4dot"
|
||||
|
||||
if (-not $tag) {
|
||||
Write-Manual "Could not determine latest de4dot version. Download from https://github.com/de4dot/de4dot/releases"
|
||||
}
|
||||
|
||||
$installDir = "$env:USERPROFILE\.local\share\de4dot"
|
||||
$tmpZip = "$env:TEMP\de4dot-download.zip"
|
||||
|
||||
# Find the appropriate asset
|
||||
try {
|
||||
$release = Invoke-RestMethod -Uri "https://api.github.com/repos/de4dot/de4dot/releases/latest" -UseBasicParsing
|
||||
$asset = $release.assets | Where-Object { $_.name -like "*.zip" } | Select-Object -First 1
|
||||
if (-not $asset) {
|
||||
Write-Manual "Could not find de4dot download. Download from https://github.com/de4dot/de4dot/releases"
|
||||
}
|
||||
$downloadUrl = $asset.browser_download_url
|
||||
} catch {
|
||||
Write-Manual "Could not access GitHub API. Download de4dot from https://github.com/de4dot/de4dot/releases"
|
||||
}
|
||||
|
||||
if (-not (Download-File -Url $downloadUrl -Dest $tmpZip)) {
|
||||
Write-Manual "Download failed. Download manually from $downloadUrl"
|
||||
}
|
||||
|
||||
if (Test-Path $installDir) { Remove-Item -Recurse -Force $installDir }
|
||||
New-Item -ItemType Directory -Path $installDir -Force | Out-Null
|
||||
Expand-Archive -Path $tmpZip -DestinationPath $installDir -Force
|
||||
Remove-Item $tmpZip -Force
|
||||
|
||||
# Find de4dot.exe
|
||||
$de4dotExe = Get-ChildItem -Path $installDir -Recurse -Filter "de4dot.exe" | Select-Object -First 1
|
||||
if ($de4dotExe) {
|
||||
$binDir = "$env:USERPROFILE\.local\bin"
|
||||
New-Item -ItemType Directory -Path $binDir -Force | Out-Null
|
||||
Copy-Item $de4dotExe.FullName "$binDir\de4dot.exe" -Force
|
||||
Add-ToUserPath $binDir
|
||||
Write-Ok "de4dot installed to $binDir"
|
||||
} else {
|
||||
Write-Fail "Could not find de4dot.exe in extracted archive."
|
||||
Write-Manual "Download and extract manually from https://github.com/de4dot/de4dot/releases"
|
||||
}
|
||||
}
|
||||
|
||||
# =====================================================================
|
||||
# Dispatch
|
||||
# =====================================================================
|
||||
|
||||
switch ($Dependency.ToLower()) {
|
||||
'java' { Install-Java }
|
||||
'ghidra' { Install-Ghidra }
|
||||
'ilspycmd' { Install-IlspyCmd }
|
||||
'dotnet-sdk' { Install-DotnetSdk }
|
||||
'strings' { Install-Strings }
|
||||
'dumpbin' { Install-Dumpbin }
|
||||
'de4dot' { Install-De4dot }
|
||||
default {
|
||||
Write-Host "Error: Unknown dependency '$Dependency'" -ForegroundColor Red
|
||||
Write-Host "Available: java, ghidra, ilspycmd, dotnet-sdk, strings, dumpbin, de4dot"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue