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