Getting ready for v0.1.0

This commit is contained in:
Alexander Kiselev
2026-01-26 16:04:00 -08:00
parent 3cb63d1953
commit 76fde9c3f7
73 changed files with 2709 additions and 1038 deletions
+32
View File
@@ -0,0 +1,32 @@
name: Lint
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
env:
CARGO_TERM_COLOR: always
jobs:
fmt:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt
- name: Check formatting
run: cargo fmt --all -- --check
clippy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy
- uses: Swatinem/rust-cache@v2
- name: Clippy
run: cargo clippy -- -D warnings
+95
View File
@@ -0,0 +1,95 @@
name: Release
on:
push:
tags:
- 'v*'
env:
CARGO_TERM_COLOR: always
jobs:
build:
name: Build ${{ matrix.target }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-unknown-linux-gnu
os: ubuntu-latest
archive: tar.gz
- target: x86_64-apple-darwin
os: macos-latest
archive: tar.gz
- target: aarch64-apple-darwin
os: macos-latest
archive: tar.gz
- target: x86_64-pc-windows-msvc
os: windows-latest
archive: zip
steps:
- uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Build release binary
run: cargo build --release --target ${{ matrix.target }}
- name: Create archive (Unix)
if: matrix.os != 'windows-latest'
run: |
cd target/${{ matrix.target }}/release
tar -czvf ../../../ghidra-cli-${{ github.ref_name }}-${{ matrix.target }}.tar.gz ghidra
cd ../../..
- name: Create archive (Windows)
if: matrix.os == 'windows-latest'
run: |
cd target/${{ matrix.target }}/release
7z a ../../../ghidra-cli-${{ github.ref_name }}-${{ matrix.target }}.zip ghidra.exe
cd ../../..
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ghidra-cli-${{ matrix.target }}
path: ghidra-cli-${{ github.ref_name }}-${{ matrix.target }}.*
release:
name: Create GitHub Release
needs: build
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Create release
uses: softprops/action-gh-release@v1
with:
generate_release_notes: true
files: artifacts/**/*
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
publish:
name: Publish to crates.io
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- name: Publish to crates.io
run: cargo publish --token ${{ secrets.CARGO_REGISTRY_TOKEN }}
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
+22
View File
@@ -0,0 +1,22 @@
name: Test
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
env:
CARGO_TERM_COLOR: always
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Build
run: cargo build --verbose
- name: Run unit tests
run: cargo test --lib --verbose
+46
View File
@@ -0,0 +1,46 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [0.1.0] - 2025-01-26
### Added
- Daemon-only architecture with persistent Ghidra connection
- Auto-start daemon on import/analyze/quick commands
- Comprehensive reverse engineering commands:
- Function analysis (list, decompile, disassemble, calls, xrefs)
- Symbol management (list, get, create, delete, rename)
- String analysis and search
- Type definitions and application
- Comment management
- Memory operations
- Cross-reference analysis
- Search capabilities:
- String patterns
- Byte sequences
- Function names
- Crypto constants
- Interesting patterns
- Call graph generation and export
- Binary patching (bytes, NOP, export)
- Script execution (Python and Java)
- Batch operations
- Flexible output formats:
- Human-readable (default for TTY)
- Compact JSON (default for pipes)
- Pretty JSON (--pretty flag)
- Expression-based filtering
- AI agent integration support
### Security
- Local IPC communication only (Unix sockets / named pipes)
[unreleased]: https://github.com/akiselev/ghidra-cli/compare/v0.1.0...HEAD
[0.1.0]: https://github.com/akiselev/ghidra-cli/releases/tag/v0.1.0
+2
View File
@@ -25,5 +25,7 @@ See @AGENTS.md for agent-specific instructions.
| What | When |
|------|------|
| `CONTRIBUTING.md` | Setting up development environment, understanding PR process, test requirements |
| `CHANGELOG.md` | Reviewing version history and release notes |
| `src/daemon/README.md` | Understanding daemon architecture and IPC protocol |
| `tests/README.md` | Understanding test structure and conventions |
+1 -1
View File
@@ -262,4 +262,4 @@ Contributions are welcome! Please feel free to submit issues and pull requests.
## License
MIT License - See [LICENSE](LICENSE) for details.
GPL-3.0 License - See [LICENSE](LICENSE) for details.
+259
View File
@@ -0,0 +1,259 @@
---
name: ghidra-cli-skill
description: >
Use ghidra-cli for reverse engineering tasks: binary analysis, decompilation, function inspection, cross-reference analysis, pattern discovery, and binary patching.
Activate when the user requests:
- Binary analysis or reverse engineering
- Decompilation or disassembly
- Function listing, inspection, or renaming
- Cross-reference or call graph analysis
- String or byte pattern searches
- Binary patching or modification
- Ghidra project management
---
# ghidra-cli
Use ghidra-cli for reverse engineering tasks: binary analysis, decompilation, function inspection, cross-reference analysis, pattern discovery, and binary patching.
## When to Use
Activate when the user requests:
- Binary analysis or reverse engineering
- Decompilation or disassembly
- Function listing, inspection, or renaming
- Cross-reference or call graph analysis
- String or byte pattern searches
- Binary patching or modification
- Ghidra project management
## Workflow
### Pre-flight Check
Before running queries, verify the environment:
```bash
# Check if daemon is running for fast queries
ghidra daemon status --project <project>
# If not running, start it
ghidra daemon start --project <project> --program <program>
```
### Quick Start (New Binary)
For one-off analysis, use quick mode:
```bash
ghidra quick ./binary
ghidra daemon start --project quick-analysis --program binary
```
### Full Project Setup
For sustained analysis:
```bash
ghidra project create myproject
ghidra import ./binary --project myproject
ghidra analyze --project myproject --program binary
ghidra daemon start --project myproject --program binary
```
## Command Reference
### Querying Functions
```bash
# List all functions
ghidra function list --project <p> --program <prog>
# Filter functions by size or name
ghidra function list --filter "size > 500"
ghidra function list --filter "name contains 'crypt'"
# Get function details
ghidra function get main
# Decompile to pseudocode
ghidra function decompile main
# Disassemble
ghidra function disasm main
# Cross-references
ghidra function xrefs main
ghidra function calls main
```
### Search Operations
```bash
# Find functions by pattern
ghidra find function "*crypt*"
# Find strings
ghidra find string "password"
# Find byte patterns (hex)
ghidra find bytes "4883ec08"
# Find crypto constants
ghidra find crypto
# Find suspicious patterns (anti-analysis, obfuscation)
ghidra find interesting
```
### Cross-References
```bash
# References TO an address
ghidra x-ref to 0x401000
# References FROM an address
ghidra x-ref from 0x401000
```
### Call Graphs
```bash
# Full call graph
ghidra graph calls
# Who calls this function (callers)
ghidra graph callers main --depth 3
# What does this function call (callees)
ghidra graph callees main --depth 3
# Export as DOT format
ghidra graph export dot
```
### Symbols and Strings
```bash
# List symbols
ghidra symbol list
# List strings
ghidra strings list --limit 100
# References to a string
ghidra strings refs "error"
```
### Memory and Types
```bash
# Memory map
ghidra memory map
# Read memory at address
ghidra memory read 0x401000 64
# List data types
ghidra type list
# Apply type to address
ghidra type apply 0x402000 "char[32]"
```
### Modifications
```bash
# Rename function
ghidra function rename sub_401000 decrypt_password
# Add comment
ghidra comment set 0x401000 "Key derivation starts here"
# Patch bytes
ghidra patch bytes 0x401000 "90909090"
# NOP instructions
ghidra patch nop 0x401010 --count 5
# Export patched binary
ghidra patch export --output patched.bin
```
### Scripting
```bash
# Run Python script
ghidra script run analysis.py
# Inline Python
ghidra script python "print(currentProgram.getName())"
# Batch commands from file
ghidra batch commands.txt
```
## Output Handling
ghidra-cli outputs JSON by default. Parse the structured data:
```bash
# JSON output (default)
ghidra function list
# Table format for display
ghidra function list --format table
# Count only
ghidra function list --format count
```
When processing results, extract relevant fields from JSON rather than displaying raw output.
## Common Patterns
### Investigate a Function
```bash
ghidra function get <name> # Overview
ghidra function decompile <name> # Pseudocode
ghidra function calls <name> # What it calls
ghidra function xrefs <name> # Who calls it
ghidra graph callers <name> --depth 2
```
### Find Interesting Code
```bash
ghidra find crypto # Crypto constants
ghidra find interesting # Suspicious patterns
ghidra find function "*alloc*" # Memory functions
ghidra strings list --filter "length > 50"
```
### Trace Data Flow
```bash
ghidra x-ref to <address> # Who writes here
ghidra x-ref from <address> # What this references
ghidra graph callees <func> --depth 3
```
## Error Recovery
| Situation | Resolution |
| ------------------ | ------------------------------------------------------------- |
| Daemon not running | `ghidra daemon start --project <p> --program <prog>` |
| No project exists | `ghidra project create <name>` or use `ghidra quick <binary>` |
| Function not found | Use `ghidra find function "*pattern*"` to search |
| Address format | Use hex with 0x prefix: `0x401000` |
| Slow queries | Start daemon for sub-second response times |
## Global Options
All commands accept:
- `--project <name>` - Target project
- `--program <name>` - Target program within project
- `--format json|table|count` - Output format
- `--filter <expr>` - Filter expression
- `--limit <N>` - Max results
Binary file not shown.
+199
View File
@@ -0,0 +1,199 @@
I started by searching for interesting strings:
```
[Forge] > Enter Name:
[Forge] > Enter Key:
[*] Consult the Norns...
[VM] Stack Overflow!
The ribbon tightens! %s has forged Gleipnir!
```
The `[VM] Stack Overflow!` string led me to the VM dispatcher at `0x140001850`.
### Program Flow
Tracing from `main` (`0x140001010`):
1. Display banner/story
2. Read username into buffer
3. Read serial key into buffer
4. Call validation function `0x140001e10`
5. Display success or failure message
---
## The Yggdrasil Virtual Machine
### VM Structure (0x140001850)
The VM uses a simple architecture:
- **9 registers**: R0-R8 (64-bit each)
- **Stack**: 1024 entries
- **Instruction pointer** and **stack pointer**
### Opcode Table
| Opcode | Mnemonic | Format | Description |
|--------|----------|--------|-------------|
| 0x00 | HALT | `00` | Stop execution |
| 0x01 | LOAD | `01 reg imm64` | Load 64-bit immediate into register |
| 0x02 | MOV | `02 dst src` | Copy register to register |
| 0x03 | ADD | `03 dst src` | dst += src |
| 0x04 | SUB | `04 dst src` | dst -= src |
| 0x05 | XOR | `05 dst src` | dst ^= src |
| 0x06 | MUL | `06 dst src` | dst *= src |
| 0x07 | PUSH | `07 reg` | Push register to stack |
| 0x08 | POP | `08 reg` | Pop stack to register |
| 0x09 | JMP | `09 addr64` | Unconditional jump |
| 0x0A | JZ | `0A addr64` | Jump if R0 == 0 |
| 0x0B | NOP | `0B` | No operation |
---
## Serial Validation (0x140001e10)
The validation function:
1. **Parses serial** as 4 hex values separated by non-alphanumeric characters
- Example: `AAAA-BBBB-CCCC-DDDD`
- Each part can be up to 16 hex digits (64-bit)
2. **Initializes VM context** via `0x140001b90`
- R0-R8 set to 0
- Serial parts loaded into R5-R8
3. **Generates bytecode** via `0x140001bf0` based on username
4. **Executes VM** via `0x140001850`
5. **Checks result**: Success if `R0 == 0x13371337CAFEBABE`
---
## Bytecode Generator (0x140001bf0)
### PRNG Seeding
The username is hashed using **FNV-1a**:
```c
uint32_t fnv1a_hash(char *username) {
uint32_t hash = 0x811c9dc5; // FNV offset basis
while (*username) {
hash = (*username ^ hash) * 0x1000193; // FNV prime
username++;
}
return hash;
}
```
### LCG PRNG
The hash seeds a Linear Congruential Generator:
```c
uint32_t lcg_next(uint32_t state) {
return state * 0x41c64e6d + 0x3039;
}
```
### Coefficient Extraction
Four coefficients (C1-C4) are generated, each from two LCG steps:
```c
state1 = lcg_next(state);
state2 = lcg_next(state1);
coefficient = ((state1 >> 16) & 0x7fff) | (state2 & 0x7fff0000);
```
This creates a 30-bit value with bit 15 always 0.
Four additional PRNG values (p1-p4) are extracted:
```c
state = lcg_next(state);
p_value = (state >> 16) & 0x7fff;
```
### Generated Bytecode Structure
The bytecode performs these operations:
```asm
LOAD R1, C1 ; Load coefficient 1
LOAD R2, C2 ; Load coefficient 2
LOAD R3, C3 ; Load coefficient 3
LOAD R4, C4 ; Load coefficient 4
XOR R1, R5 ; R1 = C1 ^ S1 (serial part 1)
LOAD R0, p1 ; Load PRNG offset
ADD R1, R0 ; R1 = (C1 ^ S1) + p1
ADD R2, R6 ; R2 = C2 + S2
LOAD R0, p2
XOR R2, R0 ; R2 = (C2 + S2) ^ p2
SUB R3, R7 ; R3 = C3 - S3
LOAD R0, p3
ADD R3, R0 ; R3 = (C3 - S3) + p3
XOR R4, R8 ; R4 = C4 ^ S4
LOAD R0, p4
XOR R4, R0 ; R4 = (C4 ^ S4) ^ p4
MOV R0, R1 ; Start accumulation
ADD R0, R2 ; R0 = R1 + R2
ADD R0, R3 ; R0 = R0 + R3
ADD R0, R4 ; R0 = R0 + R4
HALT
```
---
## The Equation
From the bytecode analysis, the final equation is:
```
R0 = (C1 ^ S1 + p1) + ((C2 + S2) ^ p2) + (C3 - S3 + p3) + ((C4 ^ S4) ^ p4)
```
Where:
- **C1-C4**: PRNG-derived coefficients (from username)
- **S1-S4**: Serial parts (user input)
- **p1-p4**: PRNG-derived offsets
- **Target**: `R0 == 0x13371337CAFEBABE`
### Solving for S4
Since we have 4 unknowns and 1 equation, we can fix S1, S2, S3 and solve for S4:
```
TARGET = partial + ((C4 ^ S4) ^ p4)
where partial = (C1 ^ S1 + p1) + ((C2 + S2) ^ p2) + (C3 - S3 + p3)
Solving:
(C4 ^ S4) ^ p4 = TARGET - partial
C4 ^ S4 = (TARGET - partial) ^ p4
S4 = C4 ^ ((TARGET - partial) ^ p4)
```
---
## Heimdall Anti-Debug (0x140001fc0)
The anti-debug system uses three checks:
1. **IsDebuggerPresent()** - Windows API
2. **Timing check** - rdtsc before/after a loop, fails if > 100000 cycles
3. **PEB.BeingDebugged** - Direct PEB flag check
If any check triggers, Heimdall injects additional bytecode:
```asm
LOAD R5, 0xBADF00D
ADD R0, R5
```
This corrupts the calculation, making the serial fail even if mathematically correct.
Binary file not shown.
+190
View File
@@ -0,0 +1,190 @@
#!/usr/bin/env python3
"""Keygen for Ragnarok.exe crackme based on bytecode analysis."""
import argparse
FNV_INIT = 0x811c9dc5
FNV_PRIME = 0x1000193
LCG_MULT = 0x41c64e6d
LCG_ADD = 0x3039
TARGET = 0x13371337cafebabe
MASK_64 = 0xFFFFFFFFFFFFFFFF
MASK_32 = 0xFFFFFFFF
def fnv1a_hash(username: str) -> int:
"""Compute FNV-1a hash of username.
Binary does: hash = (byte ^ hash) * prime
Note the XOR happens BEFORE multiply.
"""
hash_value = FNV_INIT
for char in username:
hash_value = ((ord(char) ^ hash_value) * FNV_PRIME) & MASK_32
return hash_value
def lcg_next(state: int) -> int:
"""Perform one LCG step."""
return (state * LCG_MULT + LCG_ADD) & MASK_32
def extract_coefficients(username: str) -> tuple:
"""Generate C1-C4 and PRNG offsets from username hash.
From FUN_140001bf0 decompilation:
- Two LCG steps per coefficient
- Coefficient = (state1 >> 16 & 0x7fff) | (state2 & 0x7fff0000)
- This creates a 30-bit value with bit 15 always 0
"""
state = fnv1a_hash(username)
# C1: two LCG steps, combine bits
state1 = lcg_next(state)
state2 = lcg_next(state1)
c1 = ((state1 >> 16) & 0x7fff) | (state2 & 0x7fff0000)
state = state2
# C2
state1 = lcg_next(state)
state2 = lcg_next(state1)
c2 = ((state1 >> 16) & 0x7fff) | (state2 & 0x7fff0000)
state = state2
# C3
state1 = lcg_next(state)
state2 = lcg_next(state1)
c3 = ((state1 >> 16) & 0x7fff) | (state2 & 0x7fff0000)
state = state2
# C4
state1 = lcg_next(state)
state2 = lcg_next(state1)
c4 = ((state1 >> 16) & 0x7fff) | (state2 & 0x7fff0000)
state = state2
# Additional PRNG values used as offsets in bytecode (p1-p4)
state = lcg_next(state)
p1 = (state >> 16) & 0x7fff
state = lcg_next(state)
p2 = (state >> 16) & 0x7fff
state = lcg_next(state)
p3 = (state >> 16) & 0x7fff
state = lcg_next(state)
p4 = (state >> 16) & 0x7fff
return (c1, c2, c3, c4, p1, p2, p3, p4)
def solve_serial(coeffs: tuple, s1: int, s2: int, s3: int) -> int:
"""Solve for S4 given coefficients and S1, S2, S3.
From VM trace, the actual equation is:
R0 = (C1 ^ S1 + p1) + ((C2 + S2) ^ p2) + (C3 - S3 + p3) + ((C4 ^ S4) ^ p4)
Each serial part is processed differently:
- S1: XOR with C1, then ADD p1
- S2: ADD to C2, then XOR with p2
- S3: SUB from C3, then ADD p3
- S4: XOR with C4, then XOR with p4
Solving for S4:
TARGET = partial + ((C4 ^ S4) ^ p4)
(C4 ^ S4) ^ p4 = TARGET - partial
C4 ^ S4 = (TARGET - partial) ^ p4
S4 = C4 ^ ((TARGET - partial) ^ p4)
"""
c1, c2, c3, c4, p1, p2, p3, p4 = coeffs
# Compute known contributions from S1, S2, S3
r1 = (c1 ^ s1) + p1
r2 = (c2 + s2) ^ p2
r3 = (c3 - s3 + p3)
partial = (r1 + r2 + r3) & MASK_64
# Solve for S4
needed = (TARGET - partial) & MASK_64
s4 = c4 ^ (needed ^ p4)
return s4
def verify_serial(username: str, s1: int, s2: int, s3: int, s4: int) -> tuple:
"""Verify serial produces target value. Returns (result, matches)."""
coeffs = extract_coefficients(username)
c1, c2, c3, c4, p1, p2, p3, p4 = coeffs
# Emulate actual VM computation
r1 = (c1 ^ s1) + p1
r2 = (c2 + s2) ^ p2
r3 = (c3 - s3 + p3)
r4 = (c4 ^ s4) ^ p4
r0 = (r1 + r2 + r3 + r4) & MASK_64
return r0, r0 == TARGET
def generate_serial(username: str) -> str:
"""Generate complete serial for given username."""
coeffs = extract_coefficients(username)
s1 = s2 = s3 = 0x1337
s4 = solve_serial(coeffs, s1, s2, s3)
return f"{s1:X}-{s2:X}-{s3:X}-{s4:X}"
def main():
"""CLI entry point."""
parser = argparse.ArgumentParser(description='Ragnarok.exe Keygen')
parser.add_argument('username', nargs='?', help='Username to generate serial for')
parser.add_argument('-v', '--verbose', action='store_true', help='Show debug info')
args = parser.parse_args()
if args.username:
username = args.username
else:
username = input("Enter username: ").strip()
if not username:
print("Error: Username cannot be empty")
return 1
serial = generate_serial(username)
print(f"\n{'='*50}")
print(f" Username: {username}")
print(f" Serial: {serial}")
print(f"{'='*50}")
# Verify the generated serial
s1 = s2 = s3 = 0x1337
coeffs = extract_coefficients(username)
s4 = solve_serial(coeffs, s1, s2, s3)
result, matches = verify_serial(username, s1, s2, s3, s4)
if args.verbose:
c1, c2, c3, c4, p1, p2, p3, p4 = coeffs
print(f"\n[Debug] FNV-1a hash: 0x{fnv1a_hash(username):08X}")
print(f"[Debug] C1=0x{c1:08X} C2=0x{c2:08X} C3=0x{c3:08X} C4=0x{c4:08X}")
print(f"[Debug] p1=0x{p1:04X} p2=0x{p2:04X} p3=0x{p3:04X} p4=0x{p4:04X}")
print(f"[Debug] S4=0x{s4:016X}")
print(f"[Debug] Result: 0x{result:016X}")
print(f"[Debug] Target: 0x{TARGET:016X}")
if matches:
print("\n[OK] Serial verified!")
else:
print(f"\n[FAIL] Serial verification failed!")
print(f" Expected: 0x{TARGET:016X}")
print(f" Got: 0x{result:016X}")
return 1
return 0
if __name__ == '__main__':
import sys
sys.exit(main() or 0)
+259
View File
@@ -0,0 +1,259 @@
---
name: ghidra-cli-skill
description: >
Use ghidra-cli for reverse engineering tasks: binary analysis, decompilation, function inspection, cross-reference analysis, pattern discovery, and binary patching.
Activate when the user requests:
- Binary analysis or reverse engineering
- Decompilation or disassembly
- Function listing, inspection, or renaming
- Cross-reference or call graph analysis
- String or byte pattern searches
- Binary patching or modification
- Ghidra project management
---
# ghidra-cli
Use ghidra-cli for reverse engineering tasks: binary analysis, decompilation, function inspection, cross-reference analysis, pattern discovery, and binary patching.
## When to Use
Activate when the user requests:
- Binary analysis or reverse engineering
- Decompilation or disassembly
- Function listing, inspection, or renaming
- Cross-reference or call graph analysis
- String or byte pattern searches
- Binary patching or modification
- Ghidra project management
## Workflow
### Pre-flight Check
Before running queries, verify the environment:
```bash
# Check if daemon is running for fast queries
ghidra daemon status --project <project>
# If not running, start it
ghidra daemon start --project <project> --program <program>
```
### Quick Start (New Binary)
For one-off analysis, use quick mode:
```bash
ghidra quick ./binary
ghidra daemon start --project quick-analysis --program binary
```
### Full Project Setup
For sustained analysis:
```bash
ghidra project create myproject
ghidra import ./binary --project myproject
ghidra analyze --project myproject --program binary
ghidra daemon start --project myproject --program binary
```
## Command Reference
### Querying Functions
```bash
# List all functions
ghidra function list --project <p> --program <prog>
# Filter functions by size or name
ghidra function list --filter "size > 500"
ghidra function list --filter "name contains 'crypt'"
# Get function details
ghidra function get main
# Decompile to pseudocode
ghidra function decompile main
# Disassemble
ghidra function disasm main
# Cross-references
ghidra function xrefs main
ghidra function calls main
```
### Search Operations
```bash
# Find functions by pattern
ghidra find function "*crypt*"
# Find strings
ghidra find string "password"
# Find byte patterns (hex)
ghidra find bytes "4883ec08"
# Find crypto constants
ghidra find crypto
# Find suspicious patterns (anti-analysis, obfuscation)
ghidra find interesting
```
### Cross-References
```bash
# References TO an address
ghidra x-ref to 0x401000
# References FROM an address
ghidra x-ref from 0x401000
```
### Call Graphs
```bash
# Full call graph
ghidra graph calls
# Who calls this function (callers)
ghidra graph callers main --depth 3
# What does this function call (callees)
ghidra graph callees main --depth 3
# Export as DOT format
ghidra graph export dot
```
### Symbols and Strings
```bash
# List symbols
ghidra symbol list
# List strings
ghidra strings list --limit 100
# References to a string
ghidra strings refs "error"
```
### Memory and Types
```bash
# Memory map
ghidra memory map
# Read memory at address
ghidra memory read 0x401000 64
# List data types
ghidra type list
# Apply type to address
ghidra type apply 0x402000 "char[32]"
```
### Modifications
```bash
# Rename function
ghidra function rename sub_401000 decrypt_password
# Add comment
ghidra comment set 0x401000 "Key derivation starts here"
# Patch bytes
ghidra patch bytes 0x401000 "90909090"
# NOP instructions
ghidra patch nop 0x401010 --count 5
# Export patched binary
ghidra patch export --output patched.bin
```
### Scripting
```bash
# Run Python script
ghidra script run analysis.py
# Inline Python
ghidra script python "print(currentProgram.getName())"
# Batch commands from file
ghidra batch commands.txt
```
## Output Handling
ghidra-cli outputs JSON by default. Parse the structured data:
```bash
# JSON output (default)
ghidra function list
# Table format for display
ghidra function list --format table
# Count only
ghidra function list --format count
```
When processing results, extract relevant fields from JSON rather than displaying raw output.
## Common Patterns
### Investigate a Function
```bash
ghidra function get <name> # Overview
ghidra function decompile <name> # Pseudocode
ghidra function calls <name> # What it calls
ghidra function xrefs <name> # Who calls it
ghidra graph callers <name> --depth 2
```
### Find Interesting Code
```bash
ghidra find crypto # Crypto constants
ghidra find interesting # Suspicious patterns
ghidra find function "*alloc*" # Memory functions
ghidra strings list --filter "length > 50"
```
### Trace Data Flow
```bash
ghidra x-ref to <address> # Who writes here
ghidra x-ref from <address> # What this references
ghidra graph callees <func> --depth 3
```
## Error Recovery
| Situation | Resolution |
| ------------------ | ------------------------------------------------------------- |
| Daemon not running | `ghidra daemon start --project <p> --program <prog>` |
| No project exists | `ghidra project create <name>` or use `ghidra quick <binary>` |
| Function not found | Use `ghidra find function "*pattern*"` to search |
| Address format | Use hex with 0x prefix: `0x401000` |
| Slow queries | Start daemon for sub-second response times |
## Global Options
All commands accept:
- `--project <name>` - Target project
- `--program <name>` - Target program within project
- `--format json|table|count` - Output format
- `--filter <expr>` - Filter expression
- `--limit <N>` - Max results
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<FILE_INFO>
<BASIC_INFO>
<STATE NAME="CONTENT_TYPE" TYPE="string" VALUE="Program" />
<STATE NAME="PARENT" TYPE="string" VALUE="/" />
<STATE NAME="FILE_ID" TYPE="string" VALUE="7f01199e7609371500416946" />
<STATE NAME="FILE_TYPE" TYPE="int" VALUE="0" />
<STATE NAME="READ_ONLY" TYPE="boolean" VALUE="false" />
<STATE NAME="NAME" TYPE="string" VALUE="thevoid.exe" />
</BASIC_INFO>
</FILE_INFO>
@@ -0,0 +1,5 @@
VERSION=1
/
00000000:thevoid.exe:7f01199e7609371500416946
NEXT-ID:1
MD5:d41d8cd98f00b204e9800998ecf8427e
@@ -0,0 +1,5 @@
VERSION=1
/
00000000:thevoid.exe:7f01199e7609371500416946
NEXT-ID:1
MD5:d41d8cd98f00b204e9800998ecf8427e
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<FILE_INFO>
<BASIC_INFO>
<STATE NAME="OWNER" TYPE="string" VALUE="kiselev" />
</BASIC_INFO>
</FILE_INFO>
@@ -0,0 +1,4 @@
VERSION=1
/
NEXT-ID:0
MD5:d41d8cd98f00b204e9800998ecf8427e
@@ -0,0 +1,4 @@
VERSION=1
/
NEXT-ID:0
MD5:d41d8cd98f00b204e9800998ecf8427e

Some files were not shown because too many files have changed in this diff Show More