# Directory Structure ``` ├── APktool.py ├── gemini.md ├── README.md └── settings.json ``` # Files -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- ```markdown # Apktool MCP Server [](https://opensource.org/licenses/MIT) [](https://www.python.org/downloads/) [](https://modelcontextprotocol.io/) [](https://github.com/google-gemini/gemini-cli) A powerful **Model Context Protocol (MCP) server** that exposes [Apktool](https://ibotpeaches.github.io/Apktool/) functionality for Android APK analysis and reverse engineering. Integrates seamlessly with **Gemini CLI** to provide AI-powered APK security analysis, privacy auditing, and reverse engineering guidance through natural language commands. ## 🚀 Features ### 🔍 **Comprehensive APK Analysis** - **Decompile APKs** to extract resources, manifest, and smali code - **Analyze permissions** and app components for security assessment - **Extract string resources** and detect hardcoded secrets - **Search smali code** for specific patterns and security vulnerabilities - **Recompile modified APKs** after making changes ### 🤖 **AI-Powered Workflows** - **Natural language commands** for complex APK analysis tasks - **Automated security audits** with AI-generated insights - **Privacy compliance checking** and GDPR/CCPA analysis - **Step-by-step reverse engineering** guidance - **Intelligent vulnerability detection** and risk assessment ### 🛠 **8 Core Tools** | Tool | Description | |------|-------------| | `decode_apk` | Decompile APK files to extract all components | | `build_apk` | Recompile APK from modified source directory | | `install_framework` | Install system frameworks for system app analysis | | `analyze_manifest` | Parse AndroidManifest.xml for permissions and components | | `extract_strings` | Extract string resources with locale support | | `list_permissions` | Enumerate all requested permissions | | `find_smali_references` | Search for patterns in decompiled smali code | | `get_apk_info` | Get basic APK metadata and information | ### 📋 **Specialized Analysis Prompts** - **Security Analysis**: Comprehensive vulnerability assessment - **Privacy Audit**: Data collection and compliance analysis - **Reverse Engineering Guide**: Step-by-step analysis workflows ## 📦 Installation ### Prerequisites **1. Java JDK 8+** (Required by Apktool) ```bash # Ubuntu/Debian sudo apt update && sudo apt install default-jdk # macOS (Homebrew) brew install openjdk # Verify installation java -version ``` **2. Apktool** (Core dependency) ```bash # Option 1: Package manager (recommended) # Ubuntu/Debian sudo apt install apktool # macOS brew install apktool # Option 2: Manual installation # Download from https://ibotpeaches.github.io/Apktool/install/ # Verify installation apktool --version ``` **3. Python 3.10+** ```bash python3 --version # Should be 3.10 or higher ``` ### Setup Instructions **1. Clone the repository** ```bash git clone https://github.com/SecFathy/APktool-MCP.git cd APktool-MCP ``` **2. Create virtual environment** ```bash python3 -m venv venv source venv/bin/activate # Linux/macOS # or venv\Scripts\activate # Windows ``` **3. Install dependencies** ```bash pip install -r requirements.txt ``` **4. Test the installation** ```bash python3 apktool_server.py # Should start the MCP server successfully ``` ## ⚙️ Configuration ### Gemini CLI Integration **1. Install Gemini CLI** ```bash # Follow instructions at https://github.com/google-gemini/gemini-cli ``` **2. Configure MCP Server** Edit your Gemini CLI configuration file: - **Linux/macOS**: `~/.config/gemini-cli/config.json` - **Windows**: `%APPDATA%\gemini-cli\config.json` ```json { "mcpServers": { "apktool": { "command": "python3", "args": ["/absolute/path/to/apktool_server.py"], "env": { "APKTOOL_WORK_DIR": "/path/to/workspace" } } } } ``` ### Claude Desktop Integration (Alternative) Edit Claude Desktop configuration: - **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json` - **Windows**: `%APPDATA%\Claude\claude_desktop_config.json` - **Linux**: `~/.config/Claude/claude_desktop_config.json` ```json { "mcpServers": { "apktool": { "command": "python3", "args": ["/absolute/path/to/apktool_server.py"], "env": { "APKTOOL_WORK_DIR": "/path/to/workspace" } } } } ``` ## 🎯 Usage Examples ### Natural Language Commands ```bash # Start Gemini CLI gemini # Security Analysis > "Analyze the APK at ./suspicious_app.apk for security vulnerabilities" # Permission Analysis > "What permissions does ./myapp.apk request and are any of them dangerous?" # Code Analysis > "Find any hardcoded API keys or secrets in ./social_app.apk" # Privacy Audit > "Generate a privacy compliance report for ./messenger_app.apk" # Reverse Engineering > "Help me understand how the authentication works in ./banking_app.apk" ``` ### Direct Tool Usage ```bash # Decompile an APK > Use decode_apk to decompile ./sample.apk # Analyze permissions > Use list_permissions on the decompiled directory ./sample # Search for patterns > Use find_smali_references to search for "crypto" in ./sample # Extract strings > Use extract_strings from ./sample for locale "en" # Rebuild APK > Use build_apk to recompile ./sample into ./sample_modified.apk ``` ### Guided Workflows ```bash # Run automated security analysis > Run the security analysis prompt on ./target_app.apk # Perform privacy audit > Execute privacy audit workflow for ./social_media_app.apk # Get reverse engineering guidance > Use the reverse engineering guide for analyzing login functionality in ./app.apk ``` ## 📁 Project Structure ``` apktool-mcp-server/ ├── apktool_server.py # Main MCP server implementation ├── requirements.txt # Python dependencies ├── config.json # Example Gemini CLI configuration ├── README.md # This file ├── GEMINI.md # AI assistant context file ├── LICENSE # MIT license ├── examples/ # Usage examples and samples │ ├── sample_analysis.py # Example analysis scripts │ └── workflows/ # Common workflow examples ├── tests/ # Unit tests │ ├── test_server.py # Server functionality tests │ └── test_tools.py # Individual tool tests └── docs/ # Additional documentation ├── SECURITY.md # Security guidelines ├── CONTRIBUTING.md # Contribution guidelines └── TROUBLESHOOTING.md # Common issues and solutions ``` ## 🔒 Security Considerations ### ⚠️ **Important Security Notes** - **Legal Compliance**: Only analyze APKs you own or have explicit permission to analyze - **Malware Risk**: Unknown APKs may contain malicious code - use in isolated environments - **Data Privacy**: Decompiled APKs may contain sensitive user information - **Workspace Isolation**: Configure dedicated workspace with restricted permissions - **Process Limits**: Server includes timeouts to prevent resource exhaustion ### **Best Practices** ```bash # Use dedicated workspace export APKTOOL_WORK_DIR="/secure/isolated/workspace" # Set appropriate permissions chmod 750 /secure/isolated/workspace # Monitor resource usage htop # Watch memory and CPU during analysis # Clean up after analysis rm -rf /secure/isolated/workspace/* ``` ## 🧪 Testing ### Run Unit Tests ```bash # Install test dependencies pip install pytest pytest-asyncio # Run all tests pytest tests/ # Run with coverage pytest --cov=apktool_server tests/ ``` ### Manual Testing ```bash # Test server startup python3 apktool_server.py # Test with sample APK # Download a sample APK and test basic functionality ``` ### Integration Testing ```bash # Test Gemini CLI integration gemini > /tools # Should list apktool tools > Use decode_apk to analyze sample.apk ``` ## 🤝 Contributing We welcome contributions! Please see [CONTRIBUTING.md](docs/CONTRIBUTING.md) for details. ### Development Setup ```bash # Clone and setup development environment git clone https://github.com/SecFathy/APktool-MCP.git cd APktool-MCP python3 -m venv venv source venv/bin/activate pip install -r requirements.txt pip install -r requirements-dev.txt # Run tests pytest # Format code black apktool_server.py ``` ``` -------------------------------------------------------------------------------- /settings.json: -------------------------------------------------------------------------------- ```json { "theme": "Dracula", "selectedAuthType": "oauth-personal", "mcpServers": { "myPythonServer": { "command": "python", "args": ["mcp_server.py", "--port", "8080"], "cwd": "./mcp_tools/python", "timeout": 5000 }, "myNodeServer": { "command": "node", "args": ["mcp_server.js"], "cwd": "./mcp_tools/node" }, "myDockerServer": { "command": "docker", "args": ["run", "i", "--rm", "-e", "API_KEY", "ghcr.io/foo/bar"], "env": { "API_KEY": "$MY_API_TOKEN" } }, "apktool": { "command": "python3", "args": ["/Users/secfathy/Desktop/Workflow/APktool-MCP/APktool.py"], "cwd": "/Users/secfathy/Desktop/Workflow/APktool-MCP", "env": { "APKTOOL_WORK_DIR": "/Users/secfathy/Desktop/Workflow/APktool-MCP", "PYTHONPATH": "/Users/secfathy/Desktop/Workflow/APktool-MCP" }, "timeout": 30000, "trust": false } } } ``` -------------------------------------------------------------------------------- /gemini.md: -------------------------------------------------------------------------------- ```markdown # Apktool MCP Server: AI-Powered Android APK Analysis The **Apktool MCP Server** is a Model Context Protocol (MCP) server designed to expose `Apktool` functionality. It enables AI models, particularly those integrated with the Gemini CLI, to perform advanced Android APK analysis, reverse engineering, and modification workflows. ## 🚀 Key Features This server bridges the gap between powerful AI capabilities and `Apktool`'s robust set of tools, allowing for automated and intelligent interactions with Android application packages. * **Decompilation (`decode_apk`):** Decompile APKs into human-readable resources, AndroidManifest.xml, and Smali code for in-depth analysis. * **Recompilation (`build_apk`):** Recompile modified Smali code and resources back into an installable APK. * **Framework Management (`install_framework`):** Install necessary framework APKs for decompiling system applications or specific Android versions. * **Manifest Analysis (`analyze_manifest`, `list_permissions`):** Extract and analyze crucial information from `AndroidManifest.xml`, including declared permissions, activities, services, and receivers. * **Resource Extraction (`extract_strings`):** Pull string resources for various locales from decompiled APKs. * **Smali Code Analysis (`find_smali_references`):** Search for specific patterns, API calls, or sensitive information within the Smali assembly code. * **APK Information (`get_apk_info`):** Obtain basic metadata about an APK file. ## ✨ Integration with Gemini CLI This server is designed to be consumed by the Gemini CLI. When connected, the Gemini AI can leverage the exposed Apktool functionalities as "tools" and "resources" to facilitate complex APK analysis tasks. ### Exposed Tools (via `list_tools`) The following `apktool-mcp` tools are available for the AI to call: * `decode_apk`: Decompile an APK. * `build_apk`: Recompile an APK. * `install_framework`: Install a framework APK. * `analyze_manifest`: Analyze `AndroidManifest.xml`. * `extract_strings`: Extract string resources. * `list_permissions`: List all requested permissions. * `find_smali_references`: Search Smali code. * `get_apk_info`: Get basic APK information. ### Exposed Resources (via `list_resources` and `read_resource`) The AI can read specific files from decompiled APKs: * `apktool://apk/<apk_name>/manifest`: Access the `AndroidManifest.xml` of a decompiled APK. * `apktool://apk/<apk_name>/apktool_yml`: Access the `apktool.yml` configuration file. ### Available Prompts (via `list_prompts` and `get_prompt`) Pre-defined prompts guide the AI in common APK analysis scenarios: * `analyze_security`: Guides the AI to perform a comprehensive security assessment. * `privacy_audit`: Directs the AI to audit an APK for privacy-related concerns. * `reverse_engineer_guide`: Provides step-by-step instructions for reverse engineering a target feature within an APK. ## 🛠️ Setup and Running ### Prerequisites * **Python 3.x:** Ensure you have Python 3 installed. * **Apktool:** The `apktool` executable must be installed and available in your system's PATH. If not, the server will issue a warning. * Installation instructions for Apktool can be found here: [https://ibotpeaches.github.io/Apktool/install/](https://ibotpeaches.github.io/Apktool/install/) * **MCP Library:** Install the Model Context Protocol library: ```bash pip install google-mcp ``` ### Running the Server 1. **Save the server code:** Save your Python server code (the one you provided) as `apktool_server.py`. 2. **Run the server:** ```bash python apktool_server.py ``` The server will run and listen for connections, typically via standard I/O (stdio), which is the default for Gemini CLI integration. ## 🚀 Example Workflow with Gemini CLI (Conceptual) Once the server is running, you can interact with it using the Gemini CLI. 1. **Connect the server to Gemini CLI:** ```bash gemini context add --server-command "python apktool_server.py" apktool-server ``` 2. **List available tools/prompts:** ```bash gemini context list-tools apktool-server gemini context list-prompts apktool-server ``` 3. **Use a prompt (e.g., to analyze an APK):** First, ensure you have an APK file, for example, `my_app.apk`, in a location accessible by the server (e.g., in the same directory or specified with an absolute path). ```bash gemini prompt apktool-server analyze_security --apk_path my_app.apk ``` The Gemini AI will then use the `apktool-mcp` server to call `decode_apk`, `analyze_manifest`, `list_permissions`, and `find_smali_references` as guided by the prompt, returning its analysis. 4. **Directly call a tool:** ```bash gemini tool apktool-server decode_apk --apk_path my_app.apk --output_dir my_app_decompiled ``` --- ``` -------------------------------------------------------------------------------- /APktool.py: -------------------------------------------------------------------------------- ```python #!/usr/bin/env python3 """ Apktool MCP Server A Model Context Protocol server that exposes Apktool functionality for Android APK analysis and modification. Integrates with Gemini CLI for AI-powered APK reverse engineering workflows. """ import asyncio import json import os import subprocess import tempfile import shutil from pathlib import Path from typing import Any, Dict, List, Optional import logging from mcp.server import Server from mcp.types import ( Tool, TextContent, ImageContent, EmbeddedResource, Resource, Prompt, GetPromptResult, CallToolResult, ListResourcesResult, ListPromptsResult, ListToolsResult, ReadResourceResult, ) # Configure logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger("apktool-mcp") class ApktoolMCPServer: def __init__(self, apktool_path: str = "apktool", work_dir: str = None): """ Initialize the Apktool MCP Server Args: apktool_path: Path to apktool executable (default: "apktool") work_dir: Working directory for APK operations (default: temp dir) """ self.apktool_path = apktool_path self.work_dir = Path(work_dir) if work_dir else Path(tempfile.mkdtemp()) self.work_dir.mkdir(exist_ok=True) # Initialize MCP server self.server = Server("apktool-mcp") self._setup_tools() self._setup_resources() self._setup_prompts() def _setup_tools(self): """Register all available tools with the MCP server""" @self.server.list_tools() async def list_tools() -> ListToolsResult: return ListToolsResult( tools=[ Tool( name="decode_apk", description="Decompile an APK file to extract resources, manifest, and smali code", inputSchema={ "type": "object", "properties": { "apk_path": {"type": "string", "description": "Path to the APK file"}, "output_dir": {"type": "string", "description": "Output directory name (optional)"}, "force": {"type": "boolean", "description": "Force overwrite existing directory", "default": False}, "no_res": {"type": "boolean", "description": "Do not decode resources", "default": False}, "no_src": {"type": "boolean", "description": "Do not decode sources", "default": False} }, "required": ["apk_path"] } ), Tool( name="build_apk", description="Recompile/build an APK from decompiled source directory", inputSchema={ "type": "object", "properties": { "source_dir": {"type": "string", "description": "Path to decompiled APK directory"}, "output_apk": {"type": "string", "description": "Output APK filename (optional)"}, "force": {"type": "boolean", "description": "Force build all files", "default": False} }, "required": ["source_dir"] } ), Tool( name="install_framework", description="Install framework APK for system app decompilation", inputSchema={ "type": "object", "properties": { "framework_path": {"type": "string", "description": "Path to framework APK file"}, "tag": {"type": "string", "description": "Tag for framework identification (optional)"} }, "required": ["framework_path"] } ), Tool( name="analyze_manifest", description="Analyze AndroidManifest.xml from a decompiled APK", inputSchema={ "type": "object", "properties": { "apk_dir": {"type": "string", "description": "Path to decompiled APK directory"} }, "required": ["apk_dir"] } ), Tool( name="extract_strings", description="Extract all string resources from a decompiled APK", inputSchema={ "type": "object", "properties": { "apk_dir": {"type": "string", "description": "Path to decompiled APK directory"}, "locale": {"type": "string", "description": "Specific locale (e.g., 'en', 'es')", "default": ""} }, "required": ["apk_dir"] } ), Tool( name="list_permissions", description="List all permissions requested by an APK", inputSchema={ "type": "object", "properties": { "apk_dir": {"type": "string", "description": "Path to decompiled APK directory"} }, "required": ["apk_dir"] } ), Tool( name="find_smali_references", description="Search for specific patterns in smali code", inputSchema={ "type": "object", "properties": { "apk_dir": {"type": "string", "description": "Path to decompiled APK directory"}, "pattern": {"type": "string", "description": "Search pattern or string"}, "case_sensitive": {"type": "boolean", "description": "Case sensitive search", "default": True} }, "required": ["apk_dir", "pattern"] } ), Tool( name="get_apk_info", description="Get basic information about an APK file using aapt", inputSchema={ "type": "object", "properties": { "apk_path": {"type": "string", "description": "Path to the APK file"} }, "required": ["apk_path"] } ) ] ) @self.server.call_tool() async def call_tool(name: str, arguments: Dict[str, Any]) -> CallToolResult: try: if name == "decode_apk": result = await self._decode_apk(**arguments) elif name == "build_apk": result = await self._build_apk(**arguments) elif name == "install_framework": result = await self._install_framework(**arguments) elif name == "analyze_manifest": result = await self._analyze_manifest(**arguments) elif name == "extract_strings": result = await self._extract_strings(**arguments) elif name == "list_permissions": result = await self._list_permissions(**arguments) elif name == "find_smali_references": result = await self._find_smali_references(**arguments) elif name == "get_apk_info": result = await self._get_apk_info(**arguments) else: raise ValueError(f"Unknown tool: {name}") return CallToolResult(content=[TextContent(type="text", text=result)]) except Exception as e: error_msg = f"Error executing {name}: {str(e)}" logger.error(error_msg) return CallToolResult(content=[TextContent(type="text", text=error_msg)], isError=True) def _setup_resources(self): """Setup resources for accessing decompiled APK data""" @self.server.list_resources() async def list_resources() -> ListResourcesResult: resources = [] # List all decompiled APK directories for item in self.work_dir.iterdir(): if item.is_dir(): resources.append( Resource( uri=f"apktool://apk/{item.name}/manifest", name=f"{item.name} - AndroidManifest.xml", mimeType="application/xml" ) ) resources.append( Resource( uri=f"apktool://apk/{item.name}/apktool_yml", name=f"{item.name} - apktool.yml", mimeType="application/yaml" ) ) return ListResourcesResult(resources=resources) @self.server.read_resource() async def read_resource(uri: str) -> ReadResourceResult: try: if uri.startswith("apktool://apk/"): parts = uri.split("/") apk_name = parts[3] resource_type = parts[4] apk_dir = self.work_dir / apk_name if resource_type == "manifest": manifest_path = apk_dir / "AndroidManifest.xml" if manifest_path.exists(): content = manifest_path.read_text(encoding='utf-8') return ReadResourceResult(contents=[TextContent(type="text", text=content)]) elif resource_type == "apktool_yml": yml_path = apk_dir / "apktool.yml" if yml_path.exists(): content = yml_path.read_text(encoding='utf-8') return ReadResourceResult(contents=[TextContent(type="text", text=content)]) raise FileNotFoundError(f"Resource not found: {uri}") except Exception as e: error_msg = f"Error reading resource {uri}: {str(e)}" return ReadResourceResult(contents=[TextContent(type="text", text=error_msg)]) def _setup_prompts(self): """Setup prompts for common APK analysis tasks""" @self.server.list_prompts() async def list_prompts() -> ListPromptsResult: return ListPromptsResult( prompts=[ Prompt( name="analyze_security", description="Analyze APK for potential security issues", arguments=[ {"name": "apk_path", "description": "Path to APK file", "required": True} ] ), Prompt( name="privacy_audit", description="Audit APK for privacy-related permissions and data collection", arguments=[ {"name": "apk_path", "description": "Path to APK file", "required": True} ] ), Prompt( name="reverse_engineer_guide", description="Step-by-step guide for reverse engineering an APK", arguments=[ {"name": "apk_path", "description": "Path to APK file", "required": True}, {"name": "target_feature", "description": "Specific feature to analyze", "required": False} ] ) ] ) @self.server.get_prompt() async def get_prompt(name: str, arguments: Dict[str, str]) -> GetPromptResult: if name == "analyze_security": apk_path = arguments.get("apk_path", "") prompt_text = f""" Please perform a comprehensive security analysis of the APK file: {apk_path} Steps to follow: 1. Use decode_apk to decompile the APK 2. Use analyze_manifest to examine permissions and components 3. Use list_permissions to identify potentially dangerous permissions 4. Use find_smali_references to search for: - Crypto/encryption usage - Network communications - File I/O operations - Sensitive API calls 5. Look for hardcoded secrets, API keys, or credentials 6. Analyze app components for potential vulnerabilities Provide a detailed security assessment with: - Risk level (Low/Medium/High) - Identified vulnerabilities - Recommendations for mitigation """ elif name == "privacy_audit": apk_path = arguments.get("apk_path", "") prompt_text = f""" Conduct a privacy audit for the APK file: {apk_path} Analysis should include: 1. Decompile the APK using decode_apk 2. Extract and analyze all permissions with list_permissions 3. Identify data collection patterns in smali code 4. Check for third-party SDK integrations 5. Examine network communications and endpoints 6. Review privacy policy compliance indicators Generate a privacy report covering: - Personal data types collected - Data sharing with third parties - User consent mechanisms - Compliance with privacy regulations (GDPR, CCPA) """ elif name == "reverse_engineer_guide": apk_path = arguments.get("apk_path", "") target_feature = arguments.get("target_feature", "general functionality") prompt_text = f""" Create a reverse engineering guide for APK: {apk_path} Target analysis: {target_feature} Provide step-by-step instructions for: 1. Initial APK decompilation and structure analysis 2. Understanding the app architecture from AndroidManifest.xml 3. Identifying key components and entry points 4. Analyzing smali code for the target feature 5. Resource analysis (strings, layouts, assets) 6. Modification strategies if needed 7. Recompilation and testing approaches Include specific apktool commands and file locations to examine. """ else: prompt_text = f"Unknown prompt: {name}" return GetPromptResult( description=f"APK analysis prompt for {name}", messages=[ { "role": "user", "content": { "type": "text", "text": prompt_text } } ] ) async def _run_command(self, cmd: List[str], cwd: Optional[Path] = None) -> str: """Execute a command and return its output""" try: process = await asyncio.create_subprocess_exec( *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, cwd=cwd or self.work_dir ) stdout, stderr = await process.communicate() output = stdout.decode('utf-8', errors='ignore') error = stderr.decode('utf-8', errors='ignore') if process.returncode != 0: raise RuntimeError(f"Command failed: {' '.join(cmd)}\nError: {error}") return output if output else error except Exception as e: raise RuntimeError(f"Failed to execute command: {' '.join(cmd)}\nError: {str(e)}") async def _decode_apk(self, apk_path: str, output_dir: str = None, force: bool = False, no_res: bool = False, no_src: bool = False) -> str: """Decompile an APK file using apktool""" apk_file = Path(apk_path) if not apk_file.exists(): raise FileNotFoundError(f"APK file not found: {apk_path}") if not output_dir: output_dir = apk_file.stem output_path = self.work_dir / output_dir cmd = [self.apktool_path, "d", str(apk_file)] if force: cmd.append("-f") if no_res: cmd.append("-r") if no_src: cmd.append("-s") cmd.extend(["-o", str(output_path)]) result = await self._run_command(cmd) return f"Successfully decompiled APK to: {output_path}\n\nOutput:\n{result}" async def _build_apk(self, source_dir: str, output_apk: str = None, force: bool = False) -> str: """Build/recompile an APK from source directory""" source_path = Path(source_dir) if not source_path.exists(): raise FileNotFoundError(f"Source directory not found: {source_dir}") cmd = [self.apktool_path, "b", str(source_path)] if force: cmd.append("-f") if output_apk: cmd.extend(["-o", output_apk]) result = await self._run_command(cmd) return f"Successfully built APK from: {source_path}\n\nOutput:\n{result}" async def _install_framework(self, framework_path: str, tag: str = None) -> str: """Install framework APK for system app decompilation""" framework_file = Path(framework_path) if not framework_file.exists(): raise FileNotFoundError(f"Framework file not found: {framework_path}") cmd = [self.apktool_path, "if", str(framework_file)] if tag: cmd.extend(["-t", tag]) result = await self._run_command(cmd) return f"Successfully installed framework: {framework_path}\n\nOutput:\n{result}" async def _analyze_manifest(self, apk_dir: str) -> str: """Analyze AndroidManifest.xml from decompiled APK""" manifest_path = Path(apk_dir) / "AndroidManifest.xml" if not manifest_path.exists(): raise FileNotFoundError(f"AndroidManifest.xml not found in: {apk_dir}") content = manifest_path.read_text(encoding='utf-8') # Extract key information analysis = [] lines = content.split('\n') for line in lines: line = line.strip() if 'package=' in line: analysis.append(f"Package: {line}") elif 'android:name=' in line and 'activity' in line.lower(): analysis.append(f"Activity: {line}") elif 'android:name=' in line and 'service' in line.lower(): analysis.append(f"Service: {line}") elif 'android:name=' in line and 'receiver' in line.lower(): analysis.append(f"Receiver: {line}") elif 'uses-permission' in line: analysis.append(f"Permission: {line}") analysis_text = '\n'.join(analysis) if analysis else "No key elements found" return f"AndroidManifest.xml Analysis:\n\n{analysis_text}\n\nFull content:\n{content}" async def _extract_strings(self, apk_dir: str, locale: str = "") -> str: """Extract string resources from decompiled APK""" res_dir = Path(apk_dir) / "res" if not res_dir.exists(): raise FileNotFoundError(f"Resources directory not found: {res_dir}") strings_files = [] if locale: strings_files = list(res_dir.glob(f"values-{locale}/strings.xml")) else: strings_files = list(res_dir.glob("values*/strings.xml")) if not strings_files: return f"No string files found for locale: {locale or 'default'}" all_strings = [] for strings_file in strings_files: content = strings_file.read_text(encoding='utf-8') all_strings.append(f"\n--- {strings_file.name} ---\n{content}") return f"Extracted strings from {len(strings_files)} files:\n{''.join(all_strings)}" async def _list_permissions(self, apk_dir: str) -> str: """List all permissions from AndroidManifest.xml""" manifest_path = Path(apk_dir) / "AndroidManifest.xml" if not manifest_path.exists(): raise FileNotFoundError(f"AndroidManifest.xml not found in: {apk_dir}") content = manifest_path.read_text(encoding='utf-8') permissions = [] for line in content.split('\n'): if 'uses-permission' in line: permissions.append(line.strip()) if not permissions: return "No permissions found in AndroidManifest.xml" return f"Found {len(permissions)} permissions:\n\n" + '\n'.join(permissions) async def _find_smali_references(self, apk_dir: str, pattern: str, case_sensitive: bool = True) -> str: """Search for patterns in smali code""" smali_dirs = [] apk_path = Path(apk_dir) # Find all smali directories for item in apk_path.iterdir(): if item.is_dir() and item.name.startswith('smali'): smali_dirs.append(item) if not smali_dirs: return "No smali directories found" matches = [] search_pattern = pattern if case_sensitive else pattern.lower() for smali_dir in smali_dirs: for smali_file in smali_dir.rglob("*.smali"): try: content = smali_file.read_text(encoding='utf-8') search_content = content if case_sensitive else content.lower() if search_pattern in search_content: # Find line numbers lines = content.split('\n') for i, line in enumerate(lines, 1): line_search = line if case_sensitive else line.lower() if search_pattern in line_search: matches.append(f"{smali_file.relative_to(apk_path)}:{i}: {line.strip()}") except Exception as e: continue if not matches: return f"Pattern '{pattern}' not found in smali code" return f"Found {len(matches)} matches for '{pattern}':\n\n" + '\n'.join(matches[:50]) async def _get_apk_info(self, apk_path: str) -> str: """Get basic APK information using aapt or alternative""" apk_file = Path(apk_path) if not apk_file.exists(): raise FileNotFoundError(f"APK file not found: {apk_path}") try: # Try using aapt if available cmd = ["aapt", "dump", "badging", str(apk_file)] result = await self._run_command(cmd) return f"APK Information:\n\n{result}" except: # Fallback to basic file information stat = apk_file.stat() return f"APK File Information:\n" \ f"Path: {apk_file}\n" \ f"Size: {stat.st_size} bytes\n" \ f"Modified: {stat.st_mtime}\n" \ f"Note: aapt not available for detailed analysis" async def run(self, transport_type: str = "stdio"): """Run the MCP server""" if transport_type == "stdio": from mcp.server.stdio import stdio_server async with stdio_server() as (read_stream, write_stream): await self.server.run(read_stream, write_stream, self.server.create_initialization_options()) else: raise ValueError(f"Unsupported transport type: {transport_type}") # Server instance server_instance = None async def main(): """Main entry point for the MCP server""" import sys # Check if apktool is available try: process = await asyncio.create_subprocess_exec( "apktool", "--version", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE ) await process.communicate() if process.returncode != 0: raise FileNotFoundError() except: print("Warning: apktool not found in PATH. Please install apktool first.", file=sys.stderr) print("Visit: https://ibotpeaches.github.io/Apktool/install/", file=sys.stderr) # Create and run server global server_instance server_instance = ApktoolMCPServer() await server_instance.run() if __name__ == "__main__": asyncio.run(main()) ```