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