This repository has been archived by the owner on Jun 7, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 11
/
apk.py
237 lines (205 loc) · 9.59 KB
/
apk.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# -*- coding: utf-8 -*-
# This file is part of Viper - https://github.com/viper-framework/viper
# See the file 'LICENSE' for copying permission.
from viper.common.abstracts import Module
from viper.core.session import __sessions__
try:
from androguard.core.bytecodes.dvm import DalvikVMFormat
from androguard.core.bytecodes.apk import APK, androconf
from androguard.core.analysis import analysis
from androguard.decompiler.decompiler import DecompilerDAD, DecompilerDed, DecompilerDex2Jad
from androguard.decompiler.dad.decompile import DvMethod
HAVE_ANDROGUARD = True
except Exception:
HAVE_ANDROGUARD = False
class AndroidPackage(Module):
cmd = 'apk'
description = 'Parse Android Applications'
authors = ['Kevin Breen']
categories = ["android"]
def __init__(self):
super(AndroidPackage, self).__init__()
self.parser.add_argument('-i', '--info', action='store_true', help='Show general info')
self.parser.add_argument('-p', '--perm', action='store_true', help='Show APK permissions')
self.parser.add_argument('-f', '--file', action='store_true', help='Show APK file list')
self.parser.add_argument('-u', '--url', action='store_true', help='Show URLs in APK')
self.parser.add_argument('-c', '--cert', action='store_true', help='Show certificate fingerprint')
self.parser.add_argument('-a', '--all', action='store_true', help='Run all options excluding dump')
self.parser.add_argument('-d', '--dump', metavar='dump_path', help='Extract all items from archive')
def run(self):
def analyze_apk(filename, raw=False, decompiler=None):
"""
Analyze an android application and setup all stuff for a more quickly analysis !
:param filename: the filename of the android application or a buffer which represents the application
:type filename: string
:param raw: True is you would like to use a buffer (optional)
:type raw: boolean
:param decompiler: ded, dex2jad, dad (optional)
:type decompiler: string
:rtype: return the :class:`APK`, :class:`DalvikVMFormat`, and :class:`VMAnalysis` objects
"""
a = APK(filename, raw)
d, dx = analyze_dex(a.get_dex(), raw=True, decompiler=decompiler)
return a, d, dx
def analyze_dex(filename, raw=False, decompiler=None):
"""
Analyze an android dex file and setup all stuff for a more quickly analysis !
:param filename: the filename of the android dex file or a buffer which represents the dex file
:type filename: string
:param raw: True is you would like to use a buffer (optional)
:type raw: boolean
:param decompiler: the type of decompiler to use ("dad", "dex2jad", "ded")
:type decompiler: string
:rtype: return the :class:`DalvikVMFormat`, and :class:`VMAnalysis` objects
"""
d = None
if raw:
d = DalvikVMFormat(filename)
else:
d = DalvikVMFormat(open(filename, "rb").read())
dx = analysis.Analysis(d)
d.set_vmanalysis(dx)
run_decompiler(d, dx, decompiler)
dx.create_xref()
return d, dx
def run_decompiler(d, dx, decompiler):
"""
Run the decompiler on a specific analysis
:param d: the DalvikVMFormat object
:type d: :class:`DalvikVMFormat` object
:param dx: the analysis of the format
:type dx: :class:`VMAnalysis` object
:param decompiler: the type of decompiler to use ("dad", "dex2jad", "ded")
:type decompiler: string
"""
if decompiler is not None:
decompiler = decompiler.lower()
if decompiler == "dex2jad":
d.set_decompiler(DecompilerDex2Jad(d, androconf.CONF["PATH_DEX2JAR"], androconf.CONF["BIN_DEX2JAR"],
androconf.CONF["PATH_JAD"], androconf.CONF["BIN_JAD"],
androconf.CONF["TMP_DIRECTORY"]))
elif decompiler == "ded":
d.set_decompiler(DecompilerDed(d, androconf.CONF["PATH_DED"], androconf.CONF["BIN_DED"],
androconf.CONF["TMP_DIRECTORY"]))
elif decompiler == "dad":
d.set_decompiler(DecompilerDAD(d, dx))
else:
self.log('info', "Unknown decompiler, use DAD decompiler by default")
d.set_decompiler(DecompilerDAD(d, dx))
# List all files and types
def andro_file(a):
self.log('info', "APK Contents")
rows = []
for file_name, file_type in a.files.items():
rows.append([file_name, file_type])
self.log('table', dict(header=['File Name', 'File Type'], rows=rows))
# List general info
def andro_info(a):
self.log('info', "APK General Information")
self.log('item', "Package Name: {0}".format(a.package))
self.log('item', "Version Code: {0}".format(a.androidversion['Code']))
self.log('item', "Valid APK: {0}".format(a.is_valid_APK()))
self.log('item', "Main Activity: {0}".format(a.get_main_activity()))
self.log('info', "Other Activities")
for item in a.get_activities():
self.log('item', item)
self.log('info', "Services")
for item in a.get_services():
self.log('item', item)
self.log('info', "Receivers")
for item in a.get_receivers():
self.log('item', item)
# List all the permisisons
def andro_perm(a):
self.log('info', "APK Permissions")
for perms in a.permissions:
self.log('item', perms)
# List all URL in the dex file
def andro_url(vm):
url_set = vm.get_regex_strings("http(s){0,1}://")
self.log('info', "APK URLs")
for url in url_set:
self.log('item', url.encode('utf-8'))
# Show certificate fingerprint
def andro_cert(a):
rsa_signature_filename = a.get_signature_name()
cert = a.get_certificate(rsa_signature_filename)
self.log('info', "Certificate Fingerprints")
self.log('item', "SHA1: " + cert.sha1_fingerprint)
self.log('item', "SHA256: " + cert.sha256_fingerprint)
# Decompile and Dump all the methods
def andro_dump(vm, vmx, dump_path):
# Export each decompiled method
for method in vm.get_methods():
mx = vmx.get_method(method)
if method.get_code() is None:
continue
ms = DvMethod(mx)
ms.process()
with open(dump_path, 'a+') as outfile:
outfile.write(str(method.get_class_name()))
outfile.write(str(method.get_name()) + '\n')
outfile.write(ms.get_source())
outfile.write('\n')
def process_apk():
# Process the APK File
try:
self.log('info', "Processing the APK, this may take a moment...")
APK_FILE = __sessions__.current.file.path
a, vm, vmx = analyze_apk(APK_FILE, decompiler='dad')
return a, vm, vmx
except AttributeError as e:
self.log('error', "Error: {0}".format(e))
return False, False, False
def _load_params():
a = None
vm = None
vmx = None
if hasattr(__sessions__.current, 'param_a'):
a = __sessions__.current.param_a
if hasattr(__sessions__.current, 'param_vm'):
vm = __sessions__.current.param_vm
if hasattr(__sessions__.current, 'param_vmx'):
vmx = __sessions__.current.param_vmx
if not a or not vm or not vmx:
a, vm, vmx = process_apk()
__sessions__.current.param_a = a
__sessions__.current.param_vm = vm
__sessions__.current.param_vmx = vmx
return a, vm, vmx
super(AndroidPackage, self).run()
if self.args is None:
return
# Check for session
if not __sessions__.is_set():
self.log('error', "No open session. This command expects a file to be open.")
return
# Check for androguard
if not HAVE_ANDROGUARD:
self.log('error', "Unable to import AndroGuard")
self.log('error', "Install https://github.com/androguard/androguard/archive/v2.0.tar.gz")
return
a, vm, vmx = _load_params()
if not a:
return
if self.args.dump is not None:
self.log('info', "Decompiling Code")
andro_dump(vm, vmx, self.args.dump)
self.log('info', "Decompiled code saved to {0}".format(self.args.dump))
elif self.args.info:
andro_info(a)
elif self.args.perm:
andro_perm(a)
elif self.args.file:
andro_file(a)
elif self.args.url:
andro_url(vm)
elif self.args.cert:
andro_cert(a)
elif self.args.all:
andro_info(a)
andro_perm(a)
andro_file(a)
else:
self.log('error', 'At least one of the parameter is required')
self.usage()