def search(debugger, command, exe_ctx, result, internal_dict): ''' Finds all subclasses of a class. This class must by dynamic (aka inherit from a NSObject class). Currently doesn't work with NSString or NSNumber (tagged pointer objects). NOTE: This script will leak memory Examples: # Find all UIViews and subclasses of UIViews find UIView # Find all UIStatusBar instances find UIStatusBar # Find all UIViews, ignore subclasses find UIView -e # Find all instances of UIViews (and subclasses) where tag == 5 find UIView -c "[obj tag] == 5" ''' if not ds.isProcStopped(): result.SetError( ds.attrStr( 'You must have the process suspended in order to execute this command', 'red')) return command_args = shlex.split(command) parser = generate_option_parser() try: (options, args) = parser.parse_args(command_args) except: result.SetError(parser.usage) return if not args: result.SetError( 'Usage: find NSObjectSubclass\n\nUse \'help find\' for more details' ) return clean_command = ('').join(args) res = lldb.SBCommandReturnObject() interpreter = debugger.GetCommandInterpreter() if options.module: target = exe_ctx.target module = target.FindModule(lldb.SBFileSpec(options.module)) if not module.IsValid(): result.SetError( "Unable to open module name '{}', to see list of images use 'image list -b'" .format(options.module)) return options.module = generate_module_search_sections_string(module, target) if options.pointer_reference: objectiveC_class = '(uintptr_t *){}'.format(clean_command) if options.pointer_reference and (options.exact_match or options.module or options.module or options.condition or options.perform_action): result.SetError( "Can only use the --pointer_reference with --barebones") else: interpreter.HandleCommand( 'expression -lobjc -O -- (Class)NSClassFromString(@\"{}\")'.format( clean_command), res) if 'nil' in res.GetOutput(): result.SetError( 'Can\'t find class named "{}". Womp womp...'.format( clean_command)) return objectiveC_class = 'NSClassFromString(@"{}")'.format(clean_command) command_script = get_command_script(objectiveC_class, options) # print command_script # return expr_options = lldb.SBExpressionOptions() expr_options.SetIgnoreBreakpoints(True) expr_options.SetFetchDynamicValue(lldb.eNoDynamicValues) expr_options.SetTimeoutInMicroSeconds(30 * 1000 * 1000) # 30 second timeout expr_options.SetTryAllThreads(False) expr_options.SetTrapExceptions(False) expr_options.SetUnwindOnError(True) expr_options.SetGenerateDebugInfo(True) expr_options.SetLanguage(lldb.eLanguageTypeObjC_plus_plus) expr_options.SetCoerceResultToId(True) # expr_options.SetAutoApplyFixIts(True) frame = exe_ctx.frame if frame is None: result.SetError( 'You must have the process suspended in order to execute this command' ) return # debugger.HandleCommand('po ' + command_script) # debugger.HandleCommand('expression -lobjc++ -g -O -- ' + command_script) # return # print(command_script) expr_sbvalue = frame.EvaluateExpression(command_script, expr_options) if not expr_sbvalue.error.success: result.SetError("\n**************************************\nerror: " + str(expr_sbvalue.error)) return val = lldb.value(expr_sbvalue) count = val.count.sbvalue.unsigned global s s = val if count > 100: result.AppendWarning( 'Exceeded 100 hits, try narrowing your search with the --condition option' ) count = 100 if options.pointer_reference: for i in range(count): v = val.values[i].sbvalue offset = val.offsets[i].sbvalue.unsigned val_description = ds.attrStr(str( v.GetTypeName()), 'cyan') + ' [' + ds.attrStr( str(v.GetValue()), 'yellow') + ']' + ' + ' + ds.attrStr( str(offset), 'yellow') result.AppendMessage(val_description) else: if options.barebones: for i in range(count): v = val.values[i].sbvalue val_description = ds.attrStr(str( v.GetTypeName()), 'cyan') + ' [' + ds.attrStr( str(v.GetValue()), 'yellow') + ']' result.AppendMessage(val_description) else: for i in range(count): v = val.values[i].sbvalue if not v.description: continue desc = v.description result.AppendMessage(desc + '\n')
def lookup(debugger, command, exe_ctx, result, internal_dict): ''' Perform a regular expression search for stuff in an executable # Find all methods that contain the phrase viewDidLoad (lldb) lookup viewDidLoad # Find a summary of all the modules that have a (known) function containing the phrase viewDidLoad (lldb) lookup viewDidLoad -s # Search for Objective-C code in a stripped module (i.e. in SpringBoard) (lldb) loo -x StocksFramework . # Search for Objective-C code containing the case insensitive phrase init inside a stripped main bundle (lldb) lookup -X (?i)init # Search for all hardcoded, embeded `char *` inside an executable containing the phrase *http* inside UIKit (lldb) lookup -S http -m UIKit # Dump all the md5'd keys in libMobileGestalt along w/ the address in memory (lldb) loo -S ^[a-zA-Z0-9\+]{22,22}$ -m libMobileGestalt.dylib -l # Dump all the global bss code referenced by DWARF. Ideal for accessing `static` variables when not in scope (lldb) lookup . -g HonoluluArt -l ''' if not ds.isProcStopped(): result.SetError( ds.attrStr( 'You must have the process suspended in order to execute this command', 'red')) return command_args = shlex.split(command, posix=False) parser = generate_option_parser() try: (options, args) = parser.parse_args(command_args) except: result.SetError(parser.usage) return clean_command = ('').join(args) target = exe_ctx.target frame = exe_ctx.frame if options.stripped_executable is not None or options.stripped_executable_main: expr_options = lldb.SBExpressionOptions() expr_options.SetIgnoreBreakpoints(False) expr_options.SetFetchDynamicValue(lldb.eDynamicCanRunTarget) expr_options.SetTimeoutInMicroSeconds(30 * 1000 * 1000) # 30 second timeout expr_options.SetTryAllThreads(True) expr_options.SetUnwindOnError(False) expr_options.SetGenerateDebugInfo(True) expr_options.SetLanguage(lldb.eLanguageTypeObjC_plus_plus) expr_options.SetCoerceResultToId(True) if frame is None: result.SetError( 'You must have the process suspended in order to execute this command' ) return if options.stripped_executable: module_name = options.stripped_executable module = target.module[module_name] if module is None: result.SetError('Couldn\'t find the module, "', module_name + '"') return command_script = generate_main_executable_class_address_script( module.file.dirname, options) else: command_script = generate_main_executable_class_address_script( None, options) # debugger.HandleCommand('expression -g -lobjc -O -- ' + command_script) # return expr_value = frame.EvaluateExpression(command_script, expr_options) output_description = str(expr_value.GetObjectDescription()) # result.AppendMessage(output_description) # print(output_description.split()) output = '\n\n'.join([ line for line in output_description.split('\n') if re.search(clean_command, line) ]) if options.create_breakpoint: m = re.findall('0x[a-fA-F0-9]+', output) result.AppendMessage( ds.attrStr("Creating breakpoints on all returned functions", 'red')) for k in m: hexAddr = int(k, 16) target.BreakpointCreateByAddress(hexAddr) if not ds.isXcode(): output = re.sub('0x[a-fA-F0-9]+', '\x1b\x5b33m\g<0>\x1b\x5b39m', output) output = re.sub('[\-|\+].*', '\033[36m\g<0>\033[0m', output) result.AppendMessage(output) return if options.strings: output = generate_cstring_dict(target, args[0], options) result.AppendMessage(output) return if options.module: module_name = options.module module = target.FindModule(lldb.SBFileSpec(module_name)) if not module.IsValid(): result.SetError( "Unable to open module name '{}', to see list of images use 'image list -b'" .format(module_name)) return module_dict = {} if options.global_var or options.global_var_noeval: module_name = options.global_var if options.global_var else options.global_var_noeval module = target.FindModule(lldb.SBFileSpec(module_name)) if not module.IsValid(): result.SetError( "Unable to open module name '{}', to see list of images use 'image list -b'" .format(module_name)) return symbol_context_list = [ i for i in module.get_symbols_array() if i.GetType() == lldb.eSymbolTypeData and i.addr.IsValid() and i.IsValid() ] else: symbol_context_list = target.FindGlobalFunctions( clean_command, 0, lldb.eMatchTypeRegex) for symbol_context in symbol_context_list: if options.global_var is not None or options.global_var_noeval is not None: key = symbol_context.addr.module.file.basename else: key = symbol_context.module.file.basename if options.module and key != options.module: continue if not key in module_dict: module_dict[key] = [] if options.global_var or options.global_var_noeval: if re.search(clean_command, symbol_context.name): module_dict[key].append( symbol_context.addr.GetSymbolContext( lldb.eSymbolContextEverything)) else: module_dict[key].append(symbol_context) return_string = generate_return_string(target, frame, module_dict, options) result.AppendMessage(return_string)