Esempio n. 1
0
def generate_cstring_dict(target, command, options):

    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
        modules = [module]
    else:
        modules = target.modules

    return_string = ''
    error = lldb.SBError()
    prog = re.compile(command)
    for m in modules:
        section = ds.getSection(m, '__TEXT.__cstring')
        if section is None:
            continue

        data = section.data
        dataArray = section.data.sint8s
        sectionAddress = section.addr.GetLoadAddress(target)

        moduleString = ''
        indices = [
            i for i, x in enumerate(dataArray)
            if x > 1 and dataArray[i - 1] == 0 and x != 0
        ]
        returnDict = {}
        for i in indices:
            cString = data.GetString(error, i)
            if prog.search(cString):
                returnDict[hex(sectionAddress + i)] = cString

        if len(returnDict) == 0:
            continue

        if options.module_summary:
            return_string += '{} hits in: {}\n'.format(str(len(returnDict)),
                                                       m.file.basename)
        else:
            moduleString = '\n' + ds.attrStr(
                '****************************************************',
                'cyan') + '\n{} hits in: {}'.format(
                    str(len(returnDict)),
                    ds.attrStr(m.file.basename, 'red')) + '\n' + ds.attrStr(
                        '****************************************************',
                        'cyan') + '\n'

            for k, v in returnDict.iteritems():
                if options.load_address:
                    moduleString += ds.attrStr('[' + k + ']', 'yellow') + ' '
                moduleString += ds.attrStr(v, 'cyan') + '\n'

        return_string += moduleString

    return return_string
Esempio n. 2
0
def processStackTraceStringFromAddresses(frameAddresses, target, options = None):

    frame_string = ''
    for index, frameAddr in enumerate(frameAddresses):
        addr = target.ResolveLoadAddress(frameAddr)
        prevAddr = target.ResolveLoadAddress(frameAddr - 1)
        symbol = addr.symbol
        name = symbol.name
        offset_str = ''
        offset = addr.GetLoadAddress(target) - addr.symbol.addr.GetLoadAddress(target)


        if options and options.source:
            resolvedAddr = prevAddr if prevAddr.GetLineEntry().GetLine() != 0 else addr
            if resolvedAddr.GetLineEntry().IsValid():
                lineEntry = resolvedAddr.GetLineEntry()
                line = lineEntry.GetLine() if lineEntry.GetLine() != 0 else "?"
                column = lineEntry.GetColumn() if lineEntry.GetColumn() != 0 else "?"
                fileName = resolvedAddr.GetCompileUnit().file.GetFilename()
                method_str = ds.attrStr('{}:{}:{}'.format(fileName, line, column), 'yellow')
            else:
                method_str = ds.attrStr('?', 'red')
        else:
            method_str = ds.attrStr(str(name), 'yellow') if not symbol.IsSynthetic() else ds.attrStr(str(name), 'red')
            if offset > 0:
                offset_str = '+ {}'.format(offset)


        i = ds.attrStr('frame #{:<2}: 0x{:012x} '.format(index, addr.GetLoadAddress(target)), 'grey')
        frame_string += '{} {}`{} {}\n'.format(i, ds.attrStr(str(addr.module.file.basename), 'cyan'), method_str, offset_str)

    return frame_string
Esempio n. 3
0
def handle_command(debugger, command, result, internal_dict):
    '''
    Disassemble with colors! Terminal only
    '''

    command_args = shlex.split(command, posix=False)
    target = ds.getTarget()
    parser = generate_option_parser()
    try:
        (options, args) = parser.parse_args(command_args)
    except:
        result.SetError(parser.usage)
        return

    if len(args) == 0:
        sym = ds.getFrame().GetSymbol()
    else:
        sym = ds.getTarget().ResolveLoadAddress(long(args[0], 16)).GetSymbol()

    instructions = sym.GetInstructions(target)
    output = ds.attrStr(sym.addr.module.file.basename + ', ' + sym.name,
                        'cyan') + '\n'
    counter = 0

    if len(instructions) == 0:
        return
    startAddress = instructions.GetInstructionAtIndex(
        0).GetAddress().GetLoadAddress(target)

    frame = ds.getFrame()
    for inst in instructions:
        line = ds.attrStr(str(counter).ljust(4), 'grey')
        counter += 1
        offset = str(inst.addr.GetLoadAddress(target) - startAddress)
        branch = (ds.attrStr('*', 'yellow') if inst.is_branch else ' ')
        pc = ds.attrStr('-> ', 'grey') if frame.addr == inst.addr else '   '

        loadaddr = ds.attrStr(
            hex(inst.addr.GetLoadAddress(target)) +
            (' <+' + offset + '>:').ljust(8), 'grey')
        mnemonic = ds.attrStr(inst.mnemonic.ljust(5), 'red')
        operands = ds.attrStr(inst.operands, 'bold')
        comments = ds.attrStr(inst.comment, 'green')
        if options.memory:
            tmp = ' '.join([
                hex(i).replace('0x', '').zfill(2)
                for i in inst.GetData(lldb.target).uint8s
            ])
            mem = ds.attrStr(tmp, 'cyan')
        else:
            mem = ''

        output += '{}{}{} {} {} {} {} {}\n'.format(pc, branch, line, loadaddr,
                                                   mem, mnemonic, operands,
                                                   comments)

    result.AppendMessage(output)
Esempio n. 4
0
File: info.py Progetto: lanza/LLDBds
def tryMachOAddress(addr, target, options):

    returnDescription = ""
    section = addr.GetSection()
    if not section.IsValid():
        return False, ""

    sectionName = section.GetName()
    tmpS = section
    while tmpS.GetParent().IsValid():
        tmpS = tmpS.GetParent()
        sectionName = "{}.{}".format(tmpS.GetName(), sectionName)

    module = addr.GetModule()
    if module.IsValid():
        sectionName = " `{}`{}".format(
            ds.attrStr(addr.GetModule().GetFileSpec().GetFilename(), 'cyan'),
            ds.attrStr(sectionName, 'yellow'))

    addrOffset = addr.GetLoadAddress(target) - section.GetLoadAddress(target)
    sectionName += " + {}".format(hex(addrOffset))

    symbol = addr.GetSymbol()
    #  Is it a known function?
    if symbol.IsValid():
        returnDescription += "  {}    ".format(
            ds.attrStr(symbol.GetName(), 'yellow'))
        startAddr = symbol.GetStartAddress()

        # Symbol address offset, if any
        addrOffset = addr.GetLoadAddress(target) - startAddr.GetLoadAddress(
            target)
        returnDescription += " <+{}>".format(addrOffset)

        # Mangled function
        if options.verbose:
            if symbol.GetMangledName():
                returnDescription += ", ({})".format(symbol.GetMangledName())

            returnDescription += ", External: {}".format(
                "YES" if symbol.IsSynthetic() else "NO")

    # tpe = target.GetBasicType(lldb.eBasicTypeNullPtr).GetPointerType()
    # val = target.EvaluateExpression("(void *){}".format(addr.GetLoadAddress(target)), ds.genExpressionOptions())
    # if val.IsValid():
    #     data = val.GetData()
    #     k = ds.formatFromData(data, section, 1)
    # returnDescription += '{}'.format(k[1])

    returnDescription += sectionName
    return True, returnDescription
Esempio n. 5
0
def generateAddressInfo(addresses, options, target):
    outputStr = ''
    for a in addresses:
        symbol = a.symbol
        if symbol:
            symbolOffset = a.GetLoadAddress(
                target) - symbol.addr.GetLoadAddress(target)
            symbolAddress = hex(symbol.addr.GetLoadAddress(target))
            outputStr += '[{}] {} + {}\n\n'.format(
                ds.attrStr(symbolAddress, 'yellow'),
                ds.attrStr(symbol.name, 'cyan'), symbolOffset)
        else:
            outputStr + 'error: '
    return outputStr
Esempio n. 6
0
def generate_return_string(target, frame, module_dict, options):
    return_string = ''
    for key in module_dict:
        count = len(module_dict[key])
        if len(module_dict[key]) == 0:
            continue
        tmp = module_dict[key][0]

        if options.module_summary:
            return_string += str(count) + ' hits in: ' + key + '\n'
            continue

        return_string += ds.attrStr('****************************************************', 'cyan') + '\n'
        return_string += str(count) + ' hits in: ' + ds.attrStr(key, 'red') + '\n'
        return_string += ds.attrStr('****************************************************', 'cyan') + '\n'

        for symbol_context in module_dict[key]:
            if options.global_var or options.global_var_noeval:
                name = symbol_context.symbol.name
                if options.global_var:
                    addr = hex(symbol_context.symbol.addr.GetLoadAddress(target))
                    val = frame.EvaluateExpression('*(void**)' + addr)
                    name += '\n' + (val.description if val.description else '0x%010x' % val.unsigned)

            elif symbol_context.function.name is not None:
                name = symbol_context.function.name
                if options.mangled_name:
                    mangledName = symbol_context.symbol.GetMangledName()
                    name += ', ' + mangledName if mangledName else '[NONE]'
            elif symbol_context.symbol.name is not None:
                name = symbol_context.symbol.name
                if options.mangled_name:
                    mangledName = symbol_context.symbol.GetMangledName()
                    name += ', ' + mangledName if mangledName else '[NONE]'
            else:
                return_string += 'Can\'t find info for ' + str(symbol_context) + '\n\n'
                continue


            if options.load_address:
                str_addr = str(hex(symbol_context.GetSymbol().GetStartAddress().GetLoadAddress(target)))
                end_addr = str(hex(symbol_context.GetSymbol().GetEndAddress().GetLoadAddress(target)))
                return_string += ds.attrStr('[' + str_addr + '-' + end_addr + '] ', 'yellow') + name
            else:  
                return_string += name

            return_string += '\n\n'


    return return_string
Esempio n. 7
0
def processStackTraceStringFromAddresses(frameAddresses, target):

    frame_string = ''
    for index, frameAddr in enumerate(frameAddresses):
        addr = target.ResolveLoadAddress(frameAddr)
        symbol = addr.symbol
        name = symbol.name
        offset_str = ''
        offset = addr.GetLoadAddress(target) - addr.symbol.addr.GetLoadAddress(target)
        if offset > 0:
            offset_str = '+ {}'.format(offset)

        i = ds.attrStr('frame #{:<2}: {} '.format(index, hex(addr.GetLoadAddress(target))), 'grey')
        frame_string += '{} {}`{} {}\n'.format(i, ds.attrStr(str(addr.module.file.basename), 'cyan'), ds.attrStr(str(name), 'yellow') if not symbol.IsSynthetic() else ds.attrStr(str(name), 'red') , offset_str)

    return frame_string
Esempio n. 8
0
def generateAddressInfo(addresses, options, target):
    outputStr = ''
    for a in addresses:
        symbol = a.symbol
        if symbol:
            symbolOffset = a.GetLoadAddress(
                target) - symbol.addr.GetLoadAddress(target)
            symbolAddress = hex(symbol.addr.GetLoadAddress(target))
            if a.GetLineEntry().IsValid():
                entry = a.GetLineEntry()
                sourceFile = entry.GetFileSpec().basename
            else:
                sourceFile = "No Source File"
            outputStr += '[{}] {} + {} ({})\n\n'.format(
                ds.attrStr(symbolAddress, 'yellow'),
                ds.attrStr(symbol.name, 'cyan'), symbolOffset, sourceFile)
        else:
            outputStr + 'error: '
    return outputStr
Esempio n. 9
0
def handle_command(debugger, command, exe_ctx, result, internal_dict):
    '''
    Disassemble with colors! Terminal only
    '''

    command_args = shlex.split(command, posix=False)
    target = exe_ctx.target
    parser = generate_option_parser()
    try:
        (options, args) = parser.parse_args(command_args)
    except:
        result.SetError(parser.usage)
        return

    output = ''

    if options.search_functions:
        query = options.search_functions
        symbol_context_list = target.FindGlobalFunctions(
            query, 0, lldb.eMatchTypeRegex)
        for symContext in symbol_context_list:
            output += generateAssemblyFromSymbol(symContext.symbol, options,
                                                 exe_ctx)
    elif len(args) == 0:
        sym = exe_ctx.frame.symbol
        output += generateAssemblyFromSymbol(sym, options, exe_ctx)
    elif args[0].startswith('0x'):
        sym = target.ResolveLoadAddress(int(args[0], 16)).GetSymbol()
        output += generateAssemblyFromSymbol(sym, options, exe_ctx)
    elif args[0].isdigit():
        sym = target.ResolveLoadAddress(int(args[0])).GetSymbol()
        output += generateAssemblyFromSymbol(sym, options, exe_ctx)
    else:
        cleanCommand = ' '.join(args)
        symList = target.FindGlobalFunctions(cleanCommand, 0,
                                             lldb.eMatchTypeNormal)
        if symList.GetSize() == 0:
            result.SetError(
                ds.attrStr(
                    "Couldn't find any matches for \"{}\"".format(
                        cleanCommand), 'red'))
            return
        sym = symList
        output += generateAssemblyFromSymbol(
            symList.GetContextAtIndex(0).symbol, options, exe_ctx)

    result.AppendMessage(output)
Esempio n. 10
0
def parseSection(sections, options, target):
    output = ''
    for section in sections:
        # if section

        name = ds.getSectionName(section)
        loadAddr = section.addr.GetLoadAddress(target)
        addr = section.addr
        size = section.size
        data = section.data
        endAddr = loadAddr + size
        addr = section.addr
        if options.summary:
            moduleName = addr.module.file.basename
            # bug TODO figure why pagezero is wonky
            if name == '__PAGEZERO':
                loadAddr = 0
                endAddr = size
            output += ds.attrStr(
                '[' + '{0:#016x}'.format(loadAddr) + '-' +
                '{0:#016x}'.format(endAddr) + '] ', 'cyan')
            output += ds.attrStr("{0:#012x}".format(size), 'grey') + ' '
            output += ds.attrStr(moduleName, 'yellow') + '`'
            output += ds.attrStr(name, 'cyan') + '\n'
            continue

        returnType = ds.getSectionData(section, options.count)

        # Ok, I really need to rewrite this, but whatever
        if isinstance(returnType, tuple):
            (indeces, sectionData) = returnType
            for index, x in enumerate(sectionData):
                if options.count != 0 and index >= options.count:
                    break

                if options.load_address:
                    output += ds.attrStr(hex(loadAddr + indeces[index]),
                                         'yellow') + ' '

                output += ds.attrStr(str(x), 'cyan') + '\n'
        elif isinstance(returnType, str):
            output += returnType

    return output
Esempio n. 11
0
def parseSection(sections, options):
    output = ''
    for section in sections:
        # if section 

        name = ds.getSectionName(section)
        loadAddr = section.addr.GetLoadAddress(ds.getTarget())
        addr = section.addr
        size = section.size
        data = section.data
        endAddr = loadAddr + size
        addr = section.addr
        if options.summary:
            moduleName  = addr.module.file.basename
            # bug TODO figure why pagezero is wonky 
            if name == '__PAGEZERO':
                loadAddr = 0
                endAddr = size
            output += ds.attrStr('[' + '{0:#016x}'.format(loadAddr) + '-' + '{0:#016x}'.format(endAddr) + '] ', 'cyan')
            output += ds.attrStr("{0:#012x}".format(size), 'grey') + ' '
            output += ds.attrStr(moduleName, 'yellow') + '`'
            output += ds.attrStr(name, 'cyan') + '\n'
            continue

        (indeces, sectionData) = ds.getSectionData(section, options.count)
        for index, x in enumerate(sectionData):
            if options.count != 0 and index  >= options.count:
                break

            if options.load_address:
                output += ds.attrStr(hex(loadAddr + indeces[index]), 'yellow') + ' '

            output += ds.attrStr(str(x), 'cyan') + '\n'


    return output
Esempio n. 12
0
def generateAssemblyFromSymbol(sym, options, exe_ctx):
    target = exe_ctx.target
    frame = exe_ctx.GetFrame()
    instructions = sym.GetInstructions(target)
    output = ds.attrStr(str(sym.addr.module.file.basename) + ', ',
                        'cyan') + ds.attrStr(str(sym.name), 'yellow') + '\n'
    counter = 0

    if len(instructions) == 0:
        return
    startAddress = instructions.GetInstructionAtIndex(
        0).GetAddress().GetLoadAddress(target)

    branches = []
    offsetSizeDict = {}
    grepSearch = False
    for inst in instructions:
        line = ds.attrStr(str(counter).ljust(4), 'grey')
        offset = str(inst.addr.GetLoadAddress(target) - startAddress)
        branch = (ds.attrStr('*', 'yellow') if inst.is_branch else ' ')
        pc = ds.attrStr('-> ', 'red') if frame.addr == inst.addr else '   '

        loadaddr = ds.attrStr(
            hex(inst.addr.GetLoadAddress(target)) +
            (' <+' + offset + '>:').ljust(8), 'grey')
        mnemonic = ds.attrStr(inst.GetMnemonic(target).ljust(5), 'red')
        mnemonicStr = inst.GetMnemonic(target).ljust(5)
        if len(inst.GetOperands(target).split(',')) > 1:
            ops = inst.GetOperands(target).split(',')
            operands = ds.attrStr(ops[0], 'bold') + ', ' + ds.attrStr(
                ops[1], 'yellow')
        else:
            operands = ds.attrStr(inst.GetOperands(target), 'bold')
        comments = ds.attrStr(inst.GetComment(target), 'cyan')

        if options.grep_functions:
            if re.search(options.grep_functions, comments):
                grepSearch = True

        # TODO x64 only, need arm64
        if 'rip' in inst.GetOperands(target):
            nextInst = instructions[counter + 1]
            m = re.search(r"(?<=\[).*(?=\])", inst.GetOperands(target))
            pcComment = ''

            if m and nextInst:
                nextPCAddr = hex(nextInst.addr.GetLoadAddress(target))
                commentLoadAddr = eval(m.group(0).replace('rip', nextPCAddr))

                addr = target.ResolveLoadAddress(commentLoadAddr)
                showComments, modName = generateDescriptionByAddress(
                    addr, target)
                if not showComments:
                    comments = ''

                if modName in comments:
                    comments = ''
                pcComment += ds.attrStr('; ' + modName, 'green')
                # interpreter.HandleCommand('image lookup -a ' + nextPCAddr, res)

                # # m = re.search('(?<=\().*(?=\s)', res.GetOutput())
                # # if m:
                # #     pcComment += ds.attrStr(' ' + m.group(0), 'green')

                # m = re.search('(?<=Summary\:\s).*$', res.GetOutput())
                # if m:
                #     pcComment += ds.attrStr(' sum:' + res.GetOutput(), 'blue')

                # res.Clear()

        else:
            pcComment = ''
        if 'call' in mnemonicStr and inst.GetOperands(target).startswith(
                '0x') and len(inst.GetOperands(target).split(',')) == 1:
            num = int(inst.GetOperands(target), 16)
            a = target.ResolveLoadAddress(num)
            pcComment = '; '
            if '__stubs' in a.section.name:
                pcComment += '(__TEXT.__stubs) '

            pcComment += a.symbol.name
            pcComment = ds.attrStr(pcComment, 'green')
            comments = ''

        match = re.search('(?<=\<\+)[0-9]+(?=\>)', inst.GetComment(target))
        offsetSizeDict[offset] = counter
        if options.show_branch and inst.is_branch and match:
            branches.append((counter, int(match.group(0))))

        if options.memory:
            tmp = ' '.join([
                hex(i).replace('0x', '').zfill(2)
                for i in inst.GetData(lldb.target).uint8s
            ])
            mem = ds.attrStr(tmp, 'cyan')
        else:
            mem = ''

        formatter = '{}' if options.show_branch else ''
        output += '{}{}{} {}{} {} {} {} {} {}\n'.format(
            pc, branch, line, formatter, loadaddr, mem, mnemonic, operands,
            comments, pcComment)
        counter += 1

    if options.show_branch:
        branchLines = generateBranchLines(branches, counter, offsetSizeDict)
        for i, line in enumerate(output.split('\n')):
            output += line.format(branchLines[i]) + '\n'

    if options.grep_functions:
        if grepSearch:
            return output
        else:
            return ''

    return output + '\n'
Esempio n. 13
0
def dclass(debugger, command, exe_ctx, result, internal_dict):
    '''
    Dumps all the NSObject inherited classes in the process. If you give it a module, 
    it will dump only the classes within that module. You can also filter out classes 
    to only a certain type and can also generate a header file for a specific class.
  
  Example: 
  
      # Dump ALL the NSObject classes within the process
      (lldb) dclass 

      # Dump all the classes that are a UIViewController within the process
      (lldb) dclass -f UIViewController
      
      # Dump all the classes with the regex case insensitive search "viewcontroller" in the class name
      (lldb) dclass -r (?i)viewCoNtrolLer
      
      # Dump all the classes within the UIKit module
      (lldb) dclass -m UIKit

      # Dump all classes in CKConfettiEffect NSBundle that are UIView subclasses
      (lldb) dclass /System/Library/Messages/iMessageEffects/CKConfettiEffect.bundle/CKConfettiEffect -f UIView
      
      # Generate a header file for the class specified:
      (lldb) dclass -g UIView
      
      # Generate a protocol that you can cast an object to. Ideal when working with private classes at dev time
      (lldb) dclass -P UIView

      # Dump all classes and methods for a particular module, ideal for viewing changes in frameworks over time
      (lldb) dclass -o UIKit

      # Only dump classes whose superclass is of type class and in UIKit module. Ideal for going after specific classes
      (lldb) dclass -s NSObject -m UIKit
    '''

    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

    if not args:
        # result.SetError('Usage: find NSObjectSubclass\n\nUse \'help find\' for more details')
        clean_command = None
        # return
    if not args and options.generate_header:
        result.SetError('Need to supply class for option')
        return
    else:
        clean_command = ('').join(args)

    res = lldb.SBCommandReturnObject()
    interpreter = debugger.GetCommandInterpreter()
    target = exe_ctx.target
    if options.dump_code_output:
        directory = '/tmp/{}_{}/'.format(target.executable.basename,
                                         datetime.datetime.now().time())
        os.makedirs(directory)

        modules = target.modules
        if len(args) > 0 and args[0] == '__all':
            os.makedirs(directory + 'PrivateFrameworks')
            os.makedirs(directory + 'Frameworks')
            modules = [
                i for i in target.modules if '/usr/lib/' not in i.file.fullpath
                and '__lldb_' not in i.file.fullpath
            ]
            outputMsg = "Dumping all private Objective-C frameworks"
        elif len(args) > 0 and args[0]:
            module = target.module[args[0]]
            if module is None:
                result.SetError(
                    "Unable to open module name '{}', to see list of images use 'image list -b'"
                    .format(args[0]))
                return
            modules = [module]
            outputMsg = "Dumping all private Objective-C frameworks"
        else:
            modules = [target.module[target.executable.fullpath]]

        for module in modules:
            command_script = generate_module_header_script(
                options, module.file.fullpath.replace('//', '/'))

            interpreter.HandleCommand(
                'expression -lobjc -O -u0 -- ' + command_script, res)
            # debugger.HandleCommand('expression -lobjc -O -- ' + command_script)
            if '/System/Library/PrivateFrameworks/' in module.file.fullpath:
                subdir = 'PrivateFrameworks/'
            elif '/System/Library/Frameworks/' in module.file.fullpath:
                subdir = 'Frameworks/'
            else:
                subdir = ''

            ds.create_or_touch_filepath(
                directory + subdir + module.file.basename + '.txt',
                res.GetOutput())
        print('Written output to: ' + directory + '... opening file')
        os.system('open -R ' + directory)
        return

    if options.module is not None:
        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(str(options.module)))
            return

    if options.conforms_to_protocol is not None:
        interpreter.HandleCommand(
            'expression -lobjc -O -- (id)NSProtocolFromString(@\"{}\")'.format(
                options.conforms_to_protocol), res)
        if 'nil' in res.GetOutput() or not res.GetOutput():
            result.SetError("No such Protocol name '{}'".format(
                options.conforms_to_protocol))
            return
        res.Clear()

    if options.generate_header or options.generate_protocol:
        command_script = generate_header_script(options, clean_command)
    else:
        command_script = generate_class_dump(target, options, clean_command)

    if options.generate_header or options.generate_protocol:
        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
        res.Clear()

        if options.generate_protocol:
            filepath = "/tmp/DS_" + clean_command + "Protocol.h"
        else:
            filepath = "/tmp/" + clean_command + ".h"
        interpreter.HandleCommand('expression -lobjc -O -- ' + command_script,
                                  res)
        # debugger.HandleCommand('expression -lobjc -O -g -- ' + command_script)
        if res.GetError():
            result.SetError(res.GetError())
            return
        contents = res.GetOutput()

        ds.create_or_touch_filepath(filepath, contents)
        print('Written output to: ' + filepath + '... opening file')
        os.system('open -R ' + filepath)
    else:
        msg = "Dumping protocols" if options.search_protocols else "Dumping classes"
        result.AppendMessage(ds.attrStr(msg, 'cyan'))

        interpreter.HandleCommand('expression -lobjc -O -- ' + command_script,
                                  res)
        # debugger.HandleCommand('expression -lobjc -O -g -- ' + command_script)
        if res.GetError():
            result.SetError(ds.attrStr(res.GetError(), 'red'))
            return
        result.AppendMessage(
            ds.attrStr(
                '************************************************************',
                'cyan'))
        if res.Succeeded():
            result.AppendMessage(res.GetOutput())
Esempio n. 14
0
def generate_return_string(target, frame, module_dict, options):
    return_string = ''
    shouldGetSummary = True if (len(module_dict) < 32) else False
    for key in module_dict:
        count = len(module_dict[key])
        if len(module_dict[key]) == 0:
            continue
        tmp = module_dict[key][0]

        if options.module_summary:
            return_string += str(count) + ' hits in: ' + key + '\n'
            continue

        return_string += ds.attrStr(
            '****************************************************',
            'cyan') + '\n'
        return_string += str(count) + ' hits in: ' + ds.attrStr(key,
                                                                'red') + '\n'
        return_string += ds.attrStr(
            '****************************************************',
            'cyan') + '\n'
        module = target.module[key]
        for symbol_context in module_dict[key]:
            if options.global_var or options.global_var_noeval:
                name = symbol_context.symbol.name
                if options.global_var:
                    addr = hex(
                        symbol_context.symbol.addr.GetLoadAddress(target))
                    if shouldGetSummary:
                        val = module.FindFirstGlobalVariable(target, name)
                        if not val:
                            # TODO get variable size
                            val = frame.EvaluateExpression('*(void**)' + addr)

                        descp = val.description

                        if val.summary:
                            name += '\n' + val.summary
                        elif descp and descp != '<object returned empty description>' and descp != '<nil>':
                            name += '\n' + descp
                        else:
                            name += '\n' + ('0x%010x' % val.unsigned)
                    else:
                        # TODO get variable size
                        val = frame.EvaluateExpression('*(void**)' + addr)
                        name += '\n' + (val.description if val.description else
                                        '0x%010x' % val.unsigned)

            elif symbol_context.function.name is not None:
                name = symbol_context.function.name
                if options.mangled_name:
                    mangledName = symbol_context.symbol.GetMangledName()
                    name += ', ' + mangledName if mangledName else '[NONE]'

                if options.source_info:
                    lineEntry = symbol_context.GetSymbol().GetStartAddress(
                    ).GetLineEntry()
                    if lineEntry.IsValid():
                        name += '\n' + lineEntry.file.fullpath + ':' + str(
                            lineEntry.line)

            elif symbol_context.symbol.name is not None:
                name = symbol_context.symbol.name
                if options.mangled_name:
                    mangledName = symbol_context.symbol.GetMangledName()
                    name += ', ' + mangledName if mangledName else '[NONE]'

                if options.source_info:
                    lineEntry = symbol_context.GetSymbol().GetStartAddress(
                    ).GetLineEntry()
                    if lineEntry.IsValid():
                        name += '\n' + lineEntry.file.fullpath + ':' + str(
                            lineEntry.line)

            else:
                return_string += 'Can\'t find info for ' + str(
                    symbol_context) + '\n\n'
                continue

            if options.load_address:
                str_addr = str(
                    hex(symbol_context.GetSymbol().GetStartAddress().
                        GetLoadAddress(target)))
                end_addr = str(
                    hex(symbol_context.GetSymbol().GetEndAddress().
                        GetLoadAddress(target)))
                return_string += ds.attrStr(
                    '[' + str_addr + '-' + end_addr + '] ', 'yellow') + name
            else:
                return_string += name

            return_string += '\n\n'

    return return_string
Esempio n. 15
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')
Esempio n. 16
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)
Esempio n. 17
0
def processStackTraceStringFromAddresses(frameAddresses, target, options=None):
    frame_string = ''
    startAddresses = [
        target.ResolveLoadAddress(f).symbol.addr.GetLoadAddress(target)
        for f in frameAddresses
    ]
    script = generateExecutableMethodsScript(startAddresses)

    # New content start 1
    methods = target.EvaluateExpression(script, ds.genExpressionOptions())
    charPointerType = target.FindFirstType(
        "char").GetPointerType().GetArrayType(len(frameAddresses))
    methods = methods.Cast(charPointerType)
    methodsVal = lldb.value(methods)
    # New content end 1

    # Enumerate each of the SBFrames in address list
    pointerType = target.FindFirstType("char").GetPointerType()
    for index, frameAddr in enumerate(frameAddresses):
        addr = target.ResolveLoadAddress(frameAddr)
        symbol = addr.symbol

        # New content start 2
        if symbol.synthetic:  # 1
            children = methodsVal.sbvalue.GetNumChildren()  # 4
            name = ds.attrStr(symbol.name + r' ... unresolved womp womp',
                              'redd')  # 2

            loadAddr = symbol.addr.GetLoadAddress(target)  # 3
            k = str(methodsVal[index]).split('"')  # 5
            if len(k) >= 2:
                name = ds.attrStr(k[1], 'bold')  # 6
        else:
            name = ds.attrStr(str(symbol.name), 'yellow')  # 7
        # New content end 2

        offset_str = ''
        offset = addr.GetLoadAddress(target) - addr.symbol.addr.GetLoadAddress(
            target)
        if offset > 0:
            offset_str = '+ {}'.format(offset)

        i = ds.attrStr('frame #{:<2}:'.format(index), 'grey')
        if options and options.address:
            frame_string += '{} {}`{} {}\n'.format(
                ds.attrStr(hex(addr.GetLoadAddress(target)), 'grey'),
                ds.attrStr(str(addr.module.file.basename), 'cyan'),
                ds.attrStr(str(name), 'yellow'),
                ds.attrStr(offset_str, 'grey'))
        else:
            frame_string += '{} {} {}`{} {}\n'.format(
                i, ds.attrStr(str(hex(addr.GetLoadAddress(target))), 'grey'),
                ds.attrStr(str(addr.module.file.basename), 'cyan'), name,
                ds.attrStr(str(offset_str), 'grey'))

    return frame_string
Esempio n. 18
0
def handle_command(debugger, command, result, internal_dict):
    '''
    Wrapper (w/ color!) for LLDB's disassembly
    '''

    interp = debugger.GetCommandInterpreter()
    res = lldb.SBCommandReturnObject()
    ()

    interp.HandleCommand('disassemble ' + str(command), res)
    if res.GetError() is None:
        result.SetError(str(res.GetError()))
        return

    output = res.GetOutput()
    finalOutput = ''
    for i, line in enumerate(output.split('\n')):
        if i == 0:
            w = line.split('`')
            if len(w) >= 2:
                finalOutput += ds.attrStr(w[0], 'cyan') + '`' + ds.attrStr(
                    w[1], 'yellow') + '\n'
                continue

        w = [i for i in line.split(':') if i]
        if not len(w):
            continue

        if len(w) >= 2:
            address = ds.attrStr(w[0].ljust(22) + ':', 'grey')
        else:
            address = ''

        code = w[1].split(
            None, 1
        )  # 'mov    r10, rcx ; lkjlkjlkj'.split(' ', 1)[1].split(',', 1)[1].split(';')

        mnemonic = ds.attrStr(code[0].ljust(6), 'red')  # mov

        if len(code) > 1 and len(code[1].split(';')) >= 2:
            k = code[1].split(';')
            comment = ds.attrStr('; ' + k[1].strip(), 'cyan')
        else:
            k = code[0].split(';')
            comment = ds.attrString('; ' +
                                    k[1].strip(), 'cyan') if len(k) > 1 else ''

        if len(code) == 1:
            opcodes = code[0].split(';')[0]
        else:
            opcodes = code[1].split(';')[0]

        ops = opcodes.split(',', 1)

        # # print('code: ' + str(code))
        # # print('opcodes '+ str(opcodes))
        # print(opcodes)
        if len(ops) == 1:  # something like 'ret'
            op1 = ops[0]
            op2 = ''
        elif len(ops) == 2:
            op1 = ops[0]
            op2 = ops[1]
        else:
            op1 = ''
            op2 = ''

        # op1 = ds.attrStr(op1
        # op1 = op1.ljust(6)
        op1 = op1 if op2 == '' else str(op1 + ',').ljust(6)
        op2 = ds.attrStr(op2, 'yellow')

        finalOutput += '{} {} {}{}{}\n'.format(address, mnemonic, op1, op2,
                                               comment)

    # Uncomment if you are expecting at least one argument
    # clean_command = shlex.split(args[0])[0]
    result.AppendMessage(finalOutput)
Esempio n. 19
0
def parseSection(sections, options, target):
    output = ''
    # sections is a list here
    if len(sections) > 0:
        for section in sections:
            name = ds.getSectionName(section)
            loadAddr = section.addr.GetLoadAddress(target)
            addr = section.addr
            size = section.size
            data = section.data
            endAddr = loadAddr + size
            addr = section.addr

            if options.summary:
                moduleName  = addr.module.file.basename
                if name == '__PAGEZERO':
                    loadAddr = 0
                    endAddr = size
                output += ds.attrStr('[' + '{0:#016x}'.format(loadAddr) + '-' + '{0:#016x}'.format(endAddr) + '] ', 'cyan')
                output += ds.attrStr("{0:#012x}".format(size), 'grey') + ' '
                output += ds.attrStr(moduleName, 'yellow') + '`'
                output += ds.attrStr(name, 'cyan') + '\n'
                continue

            returnType = ds.getSectionData(section, options.count)


            if options.filter is not None:
                prog = re.compile(options.filter.strip('"'))
            else: 
                prog = None 
            # Ok, I really need to rewrite this, but whatever
            if isinstance(returnType, tuple):
                if len(returnType) == 3:
                    (indeces, sectionData, descriptions) = returnType
                else:
                    (indeces, sectionData) = returnType
                    descriptions = None

                # Filter option
                for index, x in enumerate(sectionData):
                    if options.filter:
                        if prog.search(x) is None:
                            continue

                    if options.count != 0 and index  >= options.count:
                        break

                    if options.load_address:
                        if isinstance(indeces[index], tuple):
                            output += ds.attrStr("[" + hex(loadAddr + indeces[index][0]) + '-' + hex(loadAddr + indeces[index][0] + indeces[index][1]) + "]", 'yellow') + ' '
                        else:
                            output += ds.attrStr(hex(loadAddr + indeces[index]), 'yellow') + ' '

                    if descriptions != None and descriptions[index] != None:
                        output += "{} ".format(str(descriptions[index]))


                    output += ds.attrStr(str(x), 'cyan') + '\n'
            elif isinstance(returnType, str):
                output += returnType

    return output