About deobf-string
deobf-string is a reverse-engineering skill for recovering encrypted strings from code or binaries. It uses IDA Pro MCP to inspect decryption routines, then guides a choice between a Python implementation and Unicorn emulation.
Key features
- 01Identify encrypted-string patterns
- 02Inspect decryption routines with IDA Pro MCP
- 03Infer algorithms and parameters
- 04Decrypt simple algorithms with Python
- 05Emulate complex routines with Unicorn
- 06Present strings with addresses
Use cases
- 01Recover strings from obfuscated binaries
- 02Analyze XOR or substitution-based string encryption
- 03Emulate runtime-dependent decryption
- 04Review decrypted strings before patching
MCP support
The skill requires an IDA Pro MCP connection to inspect and decompile the decryption function. It checks for that connection before starting analysis.
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ p4nda0s/ bin-deobf-skills --skill deobf-stringAfter installing, type/deobf-stringin Claude Code to confirm it loaded.
Details
From the project READMEDeobfuscate Strings
Prerequisites
Before starting analysis, check if IDA Pro MCP is connected. Use the MCP tool to verify the connection. If IDA Pro MCP is not available, inform the user:
IDA Pro MCP is not connected. Please open IDA Pro with the MCP plugin loaded and ensure the MCP server is running, then try again.
Workflow
Step 1: Identify Encrypted Strings
Analyze the user-provided code snippet or function to identify string encryption patterns:
- Look for byte arrays or data references that appear to be encrypted strings
- Identify the decryption routine (often called at string usage sites)
- Determine the encryption algorithm by reverse-engineering the decryption function
Common patterns:
- XOR with a single byte or key array
- Custom substitution ciphers
- RC4 or other stream ciphers
- Base64 + XOR combinations
- Stack-constructed strings with arithmetic transformations
Step 2: Analyze the Decryption Routine
Use IDA Pro MCP to:
- Decompile the decryption function
- Identify parameters: encrypted data pointer, length, key
- Determine the algorithm type and complexity
Step 3: Choose Decryption Strategy
Simple algorithms (pure computation, no external dependencies):
- Single-byte or multi-byte XOR
- ADD/SUB/ROT transformations
- Simple lookup tables
→ Write a standalone Python script to decrypt.
Complex algorithms (state-dependent, uses library functions, or too complex to reimplement):
- Custom crypto with many rounds
- Decryption depends on runtime state or global variables
- Algorithm is heavily obfuscated itself
→ Use Unicorn Engine to emulate the decryption function directly from the binary.
Step 4: Implement Decryption
Simple decryption (Python script):
def decrypt_string(enc_bytes, key):
# Example: XOR decryption
return bytes([b ^ key[i % len(key)] for i, b in enumerate(enc_bytes)])
Complex decryption (Unicorn emulation):
from unicorn import *
from unicorn.arm64_const import *
def emulate_decrypt(binary_path, func_addr, enc_data, enc_len, key_ptr):
with open(binary_path, 'rb') as f:
code = f.read()
mu = Uc(UC_ARCH_ARM64, UC_MODE_LITTLE_ENDIAN)
# Map code segment
mu.mem_map(base_addr, align(len(code)))
mu.mem_write(base_addr, code)
# Map stack
mu.mem_map(stack_base, stack_size)
mu.reg_write(UC_ARM64_REG_SP, stack_top)
# Set up arguments (AArch64 calling convention)
mu.reg_write(UC_ARM64_REG_X0, enc_data_addr)
mu.reg_write(UC_ARM64_REG_X1, enc_len)
mu.reg_write(UC_ARM64_REG_X2, key_addr)
# Emulate
mu.emu_start(func_addr, func_end)
# Read decrypted result
result = mu.mem_read(output_addr, enc_len)
return bytes(result)
Step 5: Output Results
After decryption, present results to the user:
- Display decrypted strings with their addresses in a table format:
Address | Decrypted String
-------------|------------------
0x00412000 | "Hello, World!"
0x00412020 | "/dev/null"
- Ask the user if they want to generate a patch file:
Decryption complete. Would you like me to write the results to a .patched file that replaces encrypted strings in the binary?
If yes, write a patched binary with encrypted bytes replaced by plaintext (null-terminated), saved as <original_name>.patched.