예제 #1
0
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')
예제 #2
0
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)