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