Skip to content

Commit

Permalink
[added] jadx decompiler support to decompile apk
Browse files Browse the repository at this point in the history
  • Loading branch information
youhaveme9 committed Sep 9, 2024
0 parents commit 4ba849c
Show file tree
Hide file tree
Showing 15 changed files with 182 additions and 0 deletions.
Binary file added .DS_Store
Binary file not shown.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/temp_decompile
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Androud Info
Scan apk bundles or AndroidManifest.xml to extract formatted userful information (under development)
Binary file added __pycache__/androidinfo.cpython-312.pyc
Binary file not shown.
Binary file added __pycache__/logger.cpython-312.pyc
Binary file not shown.
5 changes: 5 additions & 0 deletions androidinfo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env python3
from androidinfo.main import main

if __name__ == '__main__':
main()
Empty file added androidinfo/__init__.py
Empty file.
Binary file added androidinfo/__pycache__/__init__.cpython-312.pyc
Binary file not shown.
Binary file added androidinfo/__pycache__/main.cpython-312.pyc
Binary file not shown.
Binary file added androidinfo/__pycache__/utils.cpython-312.pyc
Binary file not shown.
85 changes: 85 additions & 0 deletions androidinfo/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import os
import sys
import argparse

import xml.etree.ElementTree as ET
from androidinfo.utils import Utils
from rich.console import Console

console = Console()
utils = Utils()

def check_dependencies():
if os.system('which jadx') != 0:
utils.logError('Please install jadx')
sys.exit(0)

# Extract information from the AndroidManifest.xml file
def extract_info(xml):
android = str(xml.attrib)[2:int(str(xml.attrib).index('}')+1)]
utils.logInfo('Extracting information from the AndroidManifest.xml file')
check_dependencies()

# Package information
utils.printTitle('Package Information')
for i in xml.attrib:
if i == 'package':
utils.printText(f'Package Name: {xml.attrib[i]}')
if "versionName" in i:
utils.printText(f'Version Name: {xml.attrib[i]}')
if f"{android}compileSdkVersion" == i:
utils.printText(f'Compiler SDK Version: {xml.attrib[i]}')
print()

# Permissions
utils.printTitle('Permissions')
for child in xml:
if child.tag == 'uses-permission':
utils.printText(child.attrib[f'{android}name'])

def decompile_apk(apk_path):
with console.status("Decompiling APK ", spinner="dots2"):
os.system('mkdir temp_decompile')
os.system(f'jadx {apk_path} -d ./temp_decompile/apk_decompiled')
xml = utils.checkFile(f'./temp_decompile/apk_decompiled/Resources/AndroidManifest.xml')
utils.logInfo('APK decompiled successfully')
return xml

def parse_args():
parser = argparse.ArgumentParser(description='A simple tool to extract data from Android Mainfest files')
parser.add_argument('--apk', type=str, help='The path to the APK file', required=False)
parser.add_argument('--xml', type=str, help='The path to the AndroidManifest.xml file', required=False)
parser.add_argument('--output', type=str, help='The output file', required=False)
return parser.parse_args()

def parse_manifest(file_path):
if os.path.exists(file_path) is False:
utils.logError(f'The file {file_path} does not exist')
sys.exit(0)
else:
if file_path.endswith('.xml'):
amxml = utils.convert_to_xml(file_path)
extract_info(amxml)

elif file_path.endswith('.apk'):
xml_path = decompile_apk(file_path)
amxml = utils.convert_to_xml(xml_path)
extract_info(amxml)

else:
utils.logError('Unsupported file format')
sys.exit(0)


def main():
utils.heading()
choice = parse_args()
if choice.apk and choice.xml:
utils.logError('Please provide either apk or AndroidManifest.xml file')
exit(0)
elif choice.apk:
parse_manifest(choice.apk)
elif choice.xml:
parse_manifest(choice.xml)
else:
utils.logError('Usage: python3 androidinfo.py -apk <path_to_apk> -xml <path_to_AndroidManifest.xml> -output <output_file>')
46 changes: 46 additions & 0 deletions androidinfo/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
from rich import print
from pyfiglet import Figlet
import xml.etree.ElementTree as ET
import time
import os

class Utils:
def heading(self):
f = Figlet(font='slant')
print(f.renderText('Android Info'))
print(f"[bold green]v1.0.0[/bold green]")
print(f"[bold green]---[/bold green]")
print(f"[bold green]Extract useful information from AndroidManifest.xml[/bold green]")
print("\n\n")

def logInfo(self, message: str):
print(f"[bold blue][+] {message}[/bold blue]")

def logError(self, message: str):
print(f"[bold red][-] {message}[/bold red]")

def logWarning(self, message: str):
print(f"[bold yellow][!] {message}[/bold yellow]")

def printTitle(self, title: str):
print(f"[bold green][{title}] : [/bold green]")

def printText(self, text: str):
print(f"[yellow]{text}[/yellow]")

def checkFile(self, file: str):
try:
with open(file, 'r') as f:
return os.path.abspath(file)
except FileNotFoundError:
self.logError(f'The file {file} does not exist')
exit(0)

def convert_to_xml(self, xml):
try:
xml = ET.parse(xml)
print(f'xml: {xml}')
return xml.getroot()
except Exception as e:
self.logError(f'Error parsing the XML file: {e}')
exit(0)
34 changes: 34 additions & 0 deletions example/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.gympass">
<application
android:label="gympass"
android:name="${applicationName}"
android:icon="@mipmap/launcher_icon">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
</manifest>
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pyfiglet==1.0.2
requests==2.31.0
rich==13.7.1
6 changes: 6 additions & 0 deletions test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import xml.etree.ElementTree as ET

xml = ET.parse('AndroidManifest.xml')
root = xml.getroot()
if root.tag != 'manifest':
exit(1)

0 comments on commit 4ba849c

Please sign in to comment.