1#!/usr/bin/python 2 3#---------------------------------------------------------------------- 4# Be sure to add the python path that points to the LLDB shared library. 5# 6# # To use this in the embedded python interpreter using "lldb" just 7# import it with the full path using the "command script import" 8# command 9# (lldb) command script import /path/to/cmdtemplate.py 10#---------------------------------------------------------------------- 11 12import commands 13import platform 14import os 15import re 16import sys 17 18try: 19 # Just try for LLDB in case PYTHONPATH is already correctly setup 20 import lldb 21except ImportError: 22 lldb_python_dirs = list() 23 # lldb is not in the PYTHONPATH, try some defaults for the current platform 24 platform_system = platform.system() 25 if platform_system == 'Darwin': 26 # On Darwin, try the currently selected Xcode directory 27 xcode_dir = commands.getoutput("xcode-select --print-path") 28 if xcode_dir: 29 lldb_python_dirs.append( 30 os.path.realpath( 31 xcode_dir + 32 '/../SharedFrameworks/LLDB.framework/Resources/Python')) 33 lldb_python_dirs.append( 34 xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python') 35 lldb_python_dirs.append( 36 '/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python') 37 success = False 38 for lldb_python_dir in lldb_python_dirs: 39 if os.path.exists(lldb_python_dir): 40 if not (sys.path.__contains__(lldb_python_dir)): 41 sys.path.append(lldb_python_dir) 42 try: 43 import lldb 44 except ImportError: 45 pass 46 else: 47 print 'imported lldb from: "%s"' % (lldb_python_dir) 48 success = True 49 break 50 if not success: 51 print "error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly" 52 sys.exit(1) 53 54import commands 55import optparse 56import shlex 57import string 58import struct 59import time 60 61 62def append_data_callback(option, opt_str, value, parser): 63 if opt_str == "--uint8": 64 int8 = int(value, 0) 65 parser.values.data += struct.pack('1B', int8) 66 if opt_str == "--uint16": 67 int16 = int(value, 0) 68 parser.values.data += struct.pack('1H', int16) 69 if opt_str == "--uint32": 70 int32 = int(value, 0) 71 parser.values.data += struct.pack('1I', int32) 72 if opt_str == "--uint64": 73 int64 = int(value, 0) 74 parser.values.data += struct.pack('1Q', int64) 75 if opt_str == "--int8": 76 int8 = int(value, 0) 77 parser.values.data += struct.pack('1b', int8) 78 if opt_str == "--int16": 79 int16 = int(value, 0) 80 parser.values.data += struct.pack('1h', int16) 81 if opt_str == "--int32": 82 int32 = int(value, 0) 83 parser.values.data += struct.pack('1i', int32) 84 if opt_str == "--int64": 85 int64 = int(value, 0) 86 parser.values.data += struct.pack('1q', int64) 87 88 89def create_memfind_options(): 90 usage = "usage: %prog [options] STARTADDR [ENDADDR]" 91 description = '''This command can find data in a specified address range. 92Options are used to specify the data that is to be looked for and the options 93can be specified multiple times to look for longer streams of data. 94''' 95 parser = optparse.OptionParser( 96 description=description, 97 prog='memfind', 98 usage=usage) 99 parser.add_option( 100 '-s', 101 '--size', 102 type='int', 103 metavar='BYTESIZE', 104 dest='size', 105 help='Specify the byte size to search.', 106 default=0) 107 parser.add_option( 108 '--int8', 109 action="callback", 110 callback=append_data_callback, 111 type='string', 112 metavar='INT', 113 dest='data', 114 help='Specify a 8 bit signed integer value to search for in memory.', 115 default='') 116 parser.add_option( 117 '--int16', 118 action="callback", 119 callback=append_data_callback, 120 type='string', 121 metavar='INT', 122 dest='data', 123 help='Specify a 16 bit signed integer value to search for in memory.', 124 default='') 125 parser.add_option( 126 '--int32', 127 action="callback", 128 callback=append_data_callback, 129 type='string', 130 metavar='INT', 131 dest='data', 132 help='Specify a 32 bit signed integer value to search for in memory.', 133 default='') 134 parser.add_option( 135 '--int64', 136 action="callback", 137 callback=append_data_callback, 138 type='string', 139 metavar='INT', 140 dest='data', 141 help='Specify a 64 bit signed integer value to search for in memory.', 142 default='') 143 parser.add_option( 144 '--uint8', 145 action="callback", 146 callback=append_data_callback, 147 type='string', 148 metavar='INT', 149 dest='data', 150 help='Specify a 8 bit unsigned integer value to search for in memory.', 151 default='') 152 parser.add_option( 153 '--uint16', 154 action="callback", 155 callback=append_data_callback, 156 type='string', 157 metavar='INT', 158 dest='data', 159 help='Specify a 16 bit unsigned integer value to search for in memory.', 160 default='') 161 parser.add_option( 162 '--uint32', 163 action="callback", 164 callback=append_data_callback, 165 type='string', 166 metavar='INT', 167 dest='data', 168 help='Specify a 32 bit unsigned integer value to search for in memory.', 169 default='') 170 parser.add_option( 171 '--uint64', 172 action="callback", 173 callback=append_data_callback, 174 type='string', 175 metavar='INT', 176 dest='data', 177 help='Specify a 64 bit unsigned integer value to search for in memory.', 178 default='') 179 return parser 180 181 182def memfind_command(debugger, command, result, dict): 183 # Use the Shell Lexer to properly parse up command options just like a 184 # shell would 185 command_args = shlex.split(command) 186 parser = create_memfind_options() 187 (options, args) = parser.parse_args(command_args) 188 # try: 189 # (options, args) = parser.parse_args(command_args) 190 # except: 191 # # if you don't handle exceptions, passing an incorrect argument to the OptionParser will cause LLDB to exit 192 # # (courtesy of OptParse dealing with argument errors by throwing SystemExit) 193 # result.SetStatus (lldb.eReturnStatusFailed) 194 # print >>result, "error: option parsing failed" # returning a string is the same as returning an error whose description is the string 195 # return 196 memfind(debugger.GetSelectedTarget(), options, args, result) 197 198 199def print_error(str, show_usage, result): 200 print >>result, str 201 if show_usage: 202 print >>result, create_memfind_options().format_help() 203 204 205def memfind(target, options, args, result): 206 num_args = len(args) 207 start_addr = 0 208 if num_args == 1: 209 if options.size > 0: 210 print_error( 211 "error: --size must be specified if there is no ENDADDR argument", 212 True, 213 result) 214 return 215 start_addr = int(args[0], 0) 216 elif num_args == 2: 217 if options.size != 0: 218 print_error( 219 "error: --size can't be specified with an ENDADDR argument", 220 True, 221 result) 222 return 223 start_addr = int(args[0], 0) 224 end_addr = int(args[1], 0) 225 if start_addr >= end_addr: 226 print_error( 227 "error: inavlid memory range [%#x - %#x)" % 228 (start_addr, end_addr), True, result) 229 return 230 options.size = end_addr - start_addr 231 else: 232 print_error("error: memfind takes 1 or 2 arguments", True, result) 233 return 234 235 if not options.data: 236 print >>result, 'error: no data specified to search for' 237 return 238 239 if not target: 240 print >>result, 'error: invalid target' 241 return 242 process = target.process 243 if not process: 244 print >>result, 'error: invalid process' 245 return 246 247 error = lldb.SBError() 248 bytes = process.ReadMemory(start_addr, options.size, error) 249 if error.Success(): 250 num_matches = 0 251 print >>result, "Searching memory range [%#x - %#x) for" % ( 252 start_addr, end_addr), 253 for byte in options.data: 254 print >>result, '%2.2x' % ord(byte), 255 print >>result 256 257 match_index = string.find(bytes, options.data) 258 while match_index != -1: 259 num_matches = num_matches + 1 260 print >>result, '%#x: %#x + %u' % (start_addr + 261 match_index, start_addr, match_index) 262 match_index = string.find(bytes, options.data, match_index + 1) 263 264 if num_matches == 0: 265 print >>result, "error: no matches found" 266 else: 267 print >>result, 'error: %s' % (error.GetCString()) 268 269 270if __name__ == '__main__': 271 print 'error: this script is designed to be used within the embedded script interpreter in LLDB' 272elif getattr(lldb, 'debugger', None): 273 memfind_command.__doc__ = create_memfind_options().format_help() 274 lldb.debugger.HandleCommand( 275 'command script add -f memory.memfind_command memfind') 276 print '"memfind" command installed, use the "--help" option for detailed help' 277