Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add 'objection signapk' command to facilitate split APK patching #375

Merged
merged 2 commits into from
Feb 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions objection/commands/mobile_packages.py
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from ..__init__ import __version__
from ..api.app import create_app as create_api_app
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.app import app_state
from ..state.connection import state_connection
Expand Down Expand Up @@ -370,6 +370,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
Original file line number Diff line number Diff line change
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,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will modify the original APK, yeah? I would like to completely avoid modifying the source application.

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)