Skip to content

Commit

Permalink
Add 'objection signapk' command to facilitate split APK patching (#375)
Browse files Browse the repository at this point in the history
Co-authored-by: Martin Tschirsich <martin@martin-ThinkPad-X1-Carbon-3rd>
  • Loading branch information
mtschirs and Martin Tschirsich committed Feb 17, 2021
1 parent 925d2bc commit 724019a
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 19 deletions.
27 changes: 27 additions & 0 deletions objection/commands/mobile_packages.py
Expand Up @@ -216,8 +216,35 @@ def patch_android_apk(source: str, architecture: str, pause: bool, skip_cleanup:
input('Press ENTER to continue...')

patcher.build_new_apk(use_aapt2=use_aapt2)
patcher.zipalign_apk()
patcher.sign_apk()

# woohoo, get the APK!
destination = source.replace('.apk', '.objection.apk')

click.secho(
'Copying final apk from {0} to {1} in current directory...'.format(patcher.get_patched_apk_path(), destination))
shutil.copyfile(patcher.get_patched_apk_path(), os.path.join(os.path.abspath('.'), destination))

def sign_android_apk(source: str, skip_cleanup: bool = True) -> None:
"""
Zipaligns and signs an Android APK with the objection key.
:param source:
:param skip_cleanup:
:return:
"""

patcher = AndroidPatcher(skip_cleanup=skip_cleanup)

# ensure that we have all of the commandline requirements
if not patcher.are_requirements_met():
return

patcher.set_apk_source(source=source)
patcher.zipalign_apk()
patcher.sign_apk()

# woohoo, get the APK!
destination = source.replace('.apk', '.objection.apk')
Expand Down
12 changes: 11 additions & 1 deletion objection/console/cli.py
Expand Up @@ -8,7 +8,7 @@
from .repl import Repl
from ..__init__ import __version__
from ..commands.device import get_device_info
from ..commands.mobile_packages import patch_ios_ipa, patch_android_apk
from ..commands.mobile_packages import patch_ios_ipa, patch_android_apk, sign_android_apk
from ..commands.plugin_manager import load_plugin
from ..state.api import api_state
from ..state.app import app_state
Expand Down Expand Up @@ -369,6 +369,16 @@ def patchapk(source: str, architecture: str, gadget_version: str, pause: bool, s

patch_android_apk(**locals())

@cli.command()
@click.argument('sources', nargs=-1, type=click.Path(exists=True), required=True)
@click.option('--skip-cleanup', '-k', is_flag=True,
help='Do not clean temporary files once finished.', show_default=True)
def signapk(sources, skip_cleanup: bool) -> None:
"""
Zipalign and sign an APK with the objection key.
"""
for source in sources:
sign_android_apk(source, skip_cleanup)

if __name__ == '__main__':
cli()
37 changes: 19 additions & 18 deletions objection/utils/patchers/android.py
Expand Up @@ -4,6 +4,7 @@
import tempfile
import xml.etree.ElementTree as ElementTree
from pkg_resources import parse_version
import contextlib
import re

import click
Expand Down Expand Up @@ -187,8 +188,8 @@ class AndroidPatcher(BasePlatformPatcher):
'adb': {
'installation': 'apt install adb (Kali Linux); brew install adb (macOS)'
},
'jarsigner': {
'installation': 'apt install default-jdk (Linux); brew cask install java (macOS)'
'apksigner': {
'apksigner': 'apt install apksigner (Kali Linux)'
},
'apktool': {
'installation': 'apt install apktool (Kali Linux)'
Expand Down Expand Up @@ -868,7 +869,7 @@ def zipalign_apk(self):
self.required_commands['zipalign']['location'],
'-p',
'4',
self.apk_temp_frida_patched,
self.apk_temp_frida_patched if os.path.exists(self.apk_temp_frida_patched) else self.apk_source,
self.apk_temp_frida_patched_aligned
]))

Expand All @@ -893,22 +894,18 @@ def sign_apk(self):
click.secho('Signing new APK.', dim=True)

o = delegator.run(self.list2cmdline([
self.required_commands['jarsigner']['location'],
'-sigalg',
'SHA1withRSA',
'-digestalg',
'SHA1',
'-tsa',
'http://timestamp.digicert.com',
'-storepass',
'basil-joule-bug',
'-keystore',
self.required_commands['apksigner']['location'],
'sign',
'--ks',
self.keystore,
self.apk_temp_frida_patched,
'objection'
'--ks-pass',
'pass:basil-joule-bug',
'--ks-key-alias',
'objection',
self.apk_temp_frida_patched_aligned
]))

if len(o.err) > 0 or 'jar signed' not in o.out:
if len(o.err) > 0:
click.secho('Signing the new APK may have failed.', fg='red')
click.secho(o.out, fg='yellow')
click.secho(o.err, fg='red')
Expand All @@ -931,8 +928,12 @@ def __del__(self):
try:

shutil.rmtree(self.apk_temp_directory, ignore_errors=True)
os.remove(self.apk_temp_frida_patched)
os.remove(self.apk_temp_frida_patched_aligned)

with contextlib.suppress(FileNotFoundError):
os.remove(self.apk_temp_frida_patched)

with contextlib.suppress(FileNotFoundError):
os.remove(self.apk_temp_frida_patched_aligned)

except Exception as err:
click.secho('Failed to cleanup with error: {0}'.format(err), fg='red', dim=True)

0 comments on commit 724019a

Please sign in to comment.