From 70de143278dd5578bc9a72a48564d7e64346bc27 Mon Sep 17 00:00:00 2001 From: Zach Riggle Date: Mon, 10 Jul 2017 15:54:07 -0500 Subject: [PATCH] Enhance unlock_bootloader with better status messages - Detect bootloaders that are already unklocked - Detect bootloader unlock success - Detect bootloaders that cannot be unlocked - Detect devices which have not enabled bootloader unlocking --- pwnlib/adb/adb.py | 60 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/pwnlib/adb/adb.py b/pwnlib/adb/adb.py index c71960654..516534926 100644 --- a/pwnlib/adb/adb.py +++ b/pwnlib/adb/adb.py @@ -276,7 +276,7 @@ def __do_deferred_initialization(self): return with context.local(device=self.serial): - abi = str(properties.ro.product.cpu.abi) + abi = getprop('ro.product.cpu.abi') context.clear() context.arch = str(abi) self._arch = context.arch @@ -959,17 +959,17 @@ def fastboot(args, *a, **kw): @with_device def fingerprint(): """Returns the device build fingerprint.""" - return str(properties.ro.build.fingerprint) + return getprop('ro.build.fingerprint') @with_device def product(): """Returns the device product identifier.""" - return str(properties.ro.build.product) + return getprop('ro.build.product') @with_device def build(): """Returns the Build ID of the device.""" - return str(properties.ro.build.id) + return getprop('ro.build.id') @with_device @no_emulator @@ -979,9 +979,33 @@ def unlock_bootloader(): Note: This requires physical interaction with the device. """ - AdbClient().reboot_bootloader() - fastboot(['oem', 'unlock']) - fastboot(['continue']) + w = log.waitfor("Unlocking bootloader") + with w: + if getprop('ro.oem_unlock_supported') == '0': + log.error("Bootloader cannot be unlocked: ro.oem_unlock_supported=0") + + if getprop('ro.boot.oem_unlock_support') == '0': + log.error("Bootloader cannot be unlocked: ro.boot.oem_unlock_support=0") + + if getprop('sys.oem_unlock_allowed') == '0': + log.error("Bootloader cannot be unlocked: Enable OEM Unlock in developer settings first", context.device) + + AdbClient().reboot_bootloader() + + # Check to see if it's unlocked before attempting unlock + unlocked = fastboot(['getvar', 'unlocked']) + if 'unlocked: yes' in unlocked: + w.success("Already unlocked") + fastboot(['continue']) + return + + fastboot(['oem', 'unlock']) + unlocked = fastboot(['getvar', 'unlocked']) + + fastboot(['continue']) + + if 'unlocked: yes' not in unlocked: + log.error("Unlock failed") class Kernel(object): _kallsyms = None @@ -1038,7 +1062,7 @@ def lastmsg(self): def enable_uart(self): """Reboots the device with kernel logging to the UART enabled.""" - model = str(properties.ro.product.model) + model = getprop('ro.product.model') known_commands = { 'Nexus 4': None, @@ -1086,6 +1110,7 @@ def enable_uart(self): class Property(object): def __init__(self, name=None): + # Need to avoid overloaded setattr() so we go through __dict__ self.__dict__['_name'] = name def __str__(self): @@ -1107,6 +1132,15 @@ def __setattr__(self, attr, value): attr = '%s.%s' % (self._name, attr) setprop(attr, value) + def __eq__(self, other): + # Allow simple comparison, e.g.: + # adb.properties.ro.oem_unlock_supported == "1" + return type(other)(self) == other + + def __hash__(self, other): + # Allow hash indices matching on the property + return hash(self._name) + properties = Property() def _build_date(): @@ -1209,8 +1243,8 @@ def compile(source): # If we have an attached device, use its settings. if context.device: - abi = str(properties.ro.product.cpu.abi) - sdk = str(properties.ro.build.version.sdk) + abi = getprop('ro.product.cpu.abi') + sdk = getprop('ro.build.version.sdk') if abi is None: log.error("Unknown CPU ABI") @@ -1381,3 +1415,9 @@ def packages(): """Returns a list of packages installed on the system""" packages = process(['pm', 'list', 'packages']).recvall() return [line.split('package:', 1)[-1] for line in packages.splitlines()] + +@context.quietfunc +def version(): + """Returns rthe platform version as a tuple.""" + prop = getprop('ro.build.version.release') + return [int(v) for v in prop.split('.')]