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