def getStackValue(self, func, call, param): inst = self.currentProgram.getListing().getInstructionAt(call) if inst is None: return None init = call curr = inst.getPrevious() while curr is not None: if self.monitor.isCancelled(): return doCancel() if curr.getFlowType().toString() != 'FALL_THROUGH': break init = curr.getAddress() curr = curr.getPrevious() emulatorHelper = EmulatorHelper(self.currentProgram) emulatorHelper.setBreakpoint(call) emulatorHelper.writeRegister(emulatorHelper.getPCRegister(), int(init.toString(), 16)) stackOffset = (call.getAddressSpace().getMaxAddress().getOffset() >> 1) - 0x7fff; emulatorHelper.writeRegister(emulatorHelper.getStackPointerRegister(), stackOffset) value = None last = self.currentProgram.getListing().getCodeUnitAt(init).getPrevious().getAddress() while not self.monitor.isCancelled(): emulatorHelper.step(self.monitor) if self.monitor.isCancelled(): return doCancel() address = emulatorHelper.getExecutionAddress() current = self.currentProgram.getListing().getCodeUnitAt(address) if address.equals(last): # skip bad instructions goto = current.getMaxAddress().next() emulatorHelper.writeRegister(emulatorHelper.getPCRegister(), int(goto.toString(), 16)) continue else: last = address if address.equals(call): start = param.getStackOffset() - param.getLength() value = emulatorHelper.readStackValue(start, param.getLength(), True) break emulatorHelper.clearBreakpoint(call) emulatorHelper.dispose() return value
def getStackValue(start, call, param): inst = getInstructionAt(start) if inst is None: return None emulatorHelper = EmulatorHelper(currentProgram) emulatorHelper.setBreakpoint(call) emulatorHelper.writeRegister(emulatorHelper.getPCRegister(), int(start.toString(), 16)) stackOffset = ( call.getAddressSpace().getMaxAddress().getOffset() >> 1) - 0x7fff emulatorHelper.writeRegister(emulatorHelper.getStackPointerRegister(), stackOffset) listing = currentProgram.getListing() value = None last = listing.getCodeUnitAt(start).getPrevious().getAddress() while not monitor.isCancelled(): emulatorHelper.step(monitor) if monitor.isCancelled(): return doCancel() address = emulatorHelper.getExecutionAddress() current = currentProgram.getListing().getCodeUnitAt(address) if address.equals(last): goto = current.getMaxAddress().next() emulatorHelper.writeRegister(emulatorHelper.getPCRegister(), int(goto.toString(), 16)) continue else: last = address if address.equals(call): width = currentProgram.getLanguage().getLanguageDescription( ).getSize() >> 3 start = param.getStackOffset() - width value = emulatorHelper.readStackValue(start, width, True) break emulatorHelper.clearBreakpoint(call) emulatorHelper.dispose() return value
res, ctx = libAFL.notify_code_coverage(ctx, executionAddress, debug=DEBUG) if not res: print("Error on notify_code_coverage") isRunning = False break if DEBUG: for reg in REG_FILTER: reg_value = emuHelper.readRegister(reg) print("\t{} ({}) =\t{:08X}".format(reg, D_REG[reg], reg_value)) # single step emulation success = emuHelper.step(monitor) if success == False: bCrash = True lastError = emuHelper.getLastError() print("Emulation Error: '{}'".format(lastError)) break # End of Emulation if bCrash: res, ctx = libAFL.notify_crash(ctx) else: res, ctx = libAFL.notify_end_exec(ctx) # End of prog ctx = libAFL.free_ctx(ctx)
class Emulator(object): def __init__(self, plugin, state=None, logger_fname="ghidra_emulator.txt"): self.plugin = plugin self.monitor = self.plugin.getMonitor() if state is None: state = self.plugin.getGhidraState() program = state.getCurrentProgram() address = state.getCurrentAddress() self.byte_substitution = {} self.initLogger(logger_fname) self.initEmulator(program, address) self.initCmdHandlers() self.emulator_state = EmulatorState.WAITING_FOR_PARAM self.flatapi = FlatProgramAPI(program) def initLogger(self, fname): self.logger_fname = fname self.logger = logging.getLogger(str(random.random()).replace(".","_")) self.logger.setLevel(logging.INFO) h_stdout = logging.StreamHandler(sys.stdout) h_stdout.setLevel(logging.INFO) self.logger.addHandler(h_stdout) if self.logger_fname: h_file = logging.FileHandler(self.logger_fname) h_file.setLevel(logging.INFO) self.logger.addHandler(h_file) def initEmulator(self, program, address, clear_param_map=True): ''' Setup the emulator helper, symbol maps and fn related stuff ''' self.program = program self.function = self.program.getFunctionManager().getFunctionContaining(address) if self.function is None: function_name = self.plugin.askString("You are not in a function, please enter an address or a function name", "address or symbol name") for f in self.plugin.state.currentProgram.getFunctionManager().getFunctions(True): if function == f.getName(): self.plugin.state.setCurrentAddress(function.getEntryPoint()) self.doStart() return for f in self.plugin.state.currentProgram.getFunctionManager().getFunctions(True): if int(function, 16) == f.getEntryPoint().getOffset(): self.plugin.state.setCurrentAddress(function.getEntryPoint()) self.doStart() return self.entrypoint = self.program.getListing().getInstructionAt(self.function.getEntryPoint()) self.logger.info("Program: %s" % self.program) self.logger.info("Function: %s" % self.function) self.decompinterface = DecompInterface() self.decompinterface.openProgram(program) result = self.decompinterface.decompileFunction(self.function, 0, self.monitor) self.highFunction = result.getHighFunction() # self.logger.info(result) # self.logger.info(self.highFunction) self.decompiled = str(result.getCCodeMarkup()) # self.logger.info("Decompiled: %s" % self.decompiled) self.symbolMap = self.highFunction.getLocalSymbolMap() # self.logger.info(self.symbolMap) if clear_param_map: self.parameterMap = {} # fuzz = 0 self.emulatorHelper = EmulatorHelper(self.program) self.stackPointer = (((1 << (self.emulatorHelper.getStackPointerRegister().getBitLength() - 1)) - 1) ^ ((1 << (self.emulatorHelper.getStackPointerRegister().getBitLength()//2))-1)) self.returnAddressSize = program.getLanguage().getProgramCounter().getBitLength() NULL_PTR_RET = 0 self.emulatorHelper.writeRegister(self.emulatorHelper.getStackPointerRegister(), self.stackPointer) self.emulatorHelper.setBreakpoint(self.getStackAddress(NULL_PTR_RET)) self.emulatorHelper.enableMemoryWriteTracking(True) self.emulator_state = EmulatorState.WAITING_FOR_PARAM if not clear_param_map: self.emulator_state = EmulatorState.READY self.history = [] self.lastAddresses = [] # self.emulatorHelper.getEmulator().executeInstruction = executeInstruction self.hookExternalFunctions() # def nopCallBack(BreakCallBack): # def __init__(self): # # BreakCallBack.__init__(self) # pass # def pcodeCallback(self, op): # return True # help(nopCallBack) # emulatorHelper.registerCallOtherCallback('HintPreloadData', nopCallBack(BreakCallBack())) def hookExternalFunctions(self): for externalFunction in list(self.program.getFunctionManager().getExternalFunctions()): self.logger.debug('Found external function `%s`' % (externalFunction.getName())) for library in lib.exports: self.logger.debug('Found library `%s`' % (library.name)) for function in library.exports: self.logger.debug('Found function `%s`' % (function.__name__)) if externalFunction.getName() == function.__name__: for address in externalFunction.getFunctionThunkAddresses(): self.logger.info('Hooked function `%s`@%s with implementation lib/%s/%s' % (externalFunction.getName(), str(address), library.name, function.__name__)) callback = DucktapeBreakCallback(function(self.program, self, self.program.getFunctionManager().getFunctionAt(address), self.monitor), lambda x: True) # callback.addressCallback = function(self.program, self, self.program.getFunctionManager().getFunctionAt(address), self.monitor) self.emulatorHelper.emulator.getBreakTable().registerAddressCallback(address, callback) # self.emulatorHelper.setBreakpoint(address) # break for thunkFunction in list(filter(lambda x: x.isThunk(), self.program.getFunctionManager().getFunctions(True))): for library in lib.exports: self.logger.debug('Found library `%s`' % (library.name)) for function in library.exports: self.logger.debug('Found function `%s`' % (function.__name__)) if thunkFunction.getName() == function.__name__: address = thunkFunction.getEntryPoint() self.logger.info('Hooked function `%s` at %s with implementation lib/%s/%s' % (thunkFunction.getName(), str(address), library.name, function.__name__)) callback = DucktapeBreakCallback(function(self.program, self, self.program.getFunctionManager().getFunctionAt(address), self.monitor), lambda x: True) # callback.addressCallback = function(self.program, self, self.program.getFunctionManager().getFunctionAt(address), self.monitor) self.emulatorHelper.emulator.getBreakTable().registerAddressCallback(address, callback) def initFunctionParameters(self, bytesValueBuffer=""): ''' Setup fn input parameters ''' self.input_wildcards = [] self.fnParametersAllBytesValue = "" for parameter in [self.symbolMap.getParam(i) for i in range(self.symbolMap.getNumParams())]: psize = self.parameterStorageSize(parameter) if len(bytesValueBuffer) < psize*2: bytesValueBuffer = self.plugin.askString('Setting Parameters for `{}` (size: {})'.format(parameter.name, psize), 'byte values') bytesValue = bytesValueBuffer[:psize*2] bytesValue = (bytesValue + "00"*psize)[:psize*2] assert(len(bytesValue) == psize*2) for i in range(0,len(bytesValue), 2): if bytesValue[i] in string.hexdigits and bytesValue[i+1] in string.hexdigits: continue self.input_wildcards.append(bytesValue[i:i+2]) self.parameterMap[parameter.name] = bytesValue self.fnParametersAllBytesValue += bytesValue bytesValueBuffer = bytesValueBuffer[psize*2:] # self.logger.info(self.parameterMap) if self.input_wildcards: self.logger.info("Found %d wildcards: %s" % (len(self.input_wildcards), self.input_wildcards)) self.logger.info("The next batch of cmds will be executed in fuzzing mode") for w in self.input_wildcards: self.byte_substitution[w] = "00" self.emulator_state = EmulatorState.READY # @staticmethod def parameterStorageSize(self, parameter): return sum(map(lambda x: x.getSize(), parameter.getStorage().getVarnodes())) def getAddress(self, offset): return self.program.getAddressFactory().getDefaultAddressSpace().getAddress(offset) def getStackAddress(self, offset): address = self.getAddress(self.emulatorHelper.readRegister(self.emulatorHelper.getStackPointerRegister()) + offset) orAddress = self.getAddress(self.stackPointer + offset) self.logger.debug('Stack address at {} or {}'.format(address, orAddress)) return orAddress def writeStackValue(offset, size, value): bytesValue = long_to_bytes(value, size) if not self.emulatorHelper.getLanguage().isBigEndian(): bytesValue = bytesValue[::-1] self.emulatorHelper.writeMemory(self.getStackAddress(offset), bytesValue) def applyByteSubstitution(self, bytesValue): for k,v in self.byte_substitution.items(): bytesValue = bytesValue.replace(k, v) return bytesValue.decode('hex') def start(self, byte_substitution=None): ''' Write the fn inputs in memory (eventually applying the byte substitution) and start the emulation, breaking at fn entry point''' assert(self.emulator_state == EmulatorState.READY) if byte_substitution is not None: self.byte_substitution = byte_substitution self.logger.info('Started with byte_sub: %r' % self.byte_substitution) for parameter in [self.symbolMap.getParam(i) for i in range(self.symbolMap.getNumParams())]: bytesValue = self.parameterMap[parameter.name] bytesValue = self.applyByteSubstitution(bytesValue) storage = parameter.getStorage() offset = 0 for varnode in storage.getVarnodes(): chunk = bytesValue[offset:offset+varnode.getSize()] if varnode.getAddress().isStackAddress(): self.emulatorHelper.writeMemory(self.getStackAddress(varnode.getAddress().getOffset()), chunk) else: self.emulatorHelper.writeMemory(varnode.getAddress(), chunk) offset += varnode.getSize() self.emulatorHelper.setBreakpoint(self.function.getEntryPoint()) self.emulatorHelper.run(self.function.getEntryPoint(), self.entrypoint, self.monitor) self.emulator_state = EmulatorState.EXECUTING def executeCmds(self, cmds): assert(self.emulator_state == EmulatorState.EXECUTING) cmds = cmds.strip().split(', ') for cmd_id, cmd in enumerate(cmds): cmd = cmd.strip().split() if cmd[0] not in self.cmd_handlers: self.logger.error("Unknown command %s (%r)" % (cmd[0], cmd)) self.cmdHelp(cmd) break res = self.cmd_handlers[cmd[0]](cmd) if res: self.last_result = res self.updateUI() # self.printState() self.logger.info('Stopping execution for {} at {:x} with error {}'.format(self.emulatorHelper.getEmulateExecutionState(), self.emulatorHelper.readRegister(self.emulatorHelper.getPCRegister()), self.emulatorHelper.getLastError())) def printState(self): for symbol in self.program.getSymbolTable().getAllSymbols(True): symbolObject = symbol.getObject() try: dataType = symbolObject.getDataType() name = symbol.getName() if name in self.decompiled and symbol.getAddress(): self.logger.debug('Found symbol name={} type={} location={}'.format(name, dataType, symbol.getAddress())) bytesValue = self.emulatorHelper.readMemory(symbol.getAddress(), dataType.getLength()) stringValue = bytesValue.tostring() printValue = repr(stringValue) if isPrintable(stringValue) else stringValue.encode('hex') self.logger.info('Variable {} has value `{}`'.format(name, printValue)) except AttributeError as e: self.logger.debug(str(e)) except Exception as e: self.logger.error(str(e)) writeSet = self.emulatorHelper.getTrackedMemoryWriteSet() for parameter in self.highFunction.getLocalSymbolMap().getSymbols(): if parameter.name not in self.decompiled: continue storage = parameter.getStorage() bytesValue = bytearray(0) for varnode in storage.getVarnodes(): if varnode.getAddress().isStackAddress(): bytesValue.extend(self.emulatorHelper.readMemory(self.getStackAddress(varnode.getAddress().getOffset()), varnode.getSize())) elif writeSet.contains(varnode.getAddress()): bytesValue.extend(self.emulatorHelper.readMemory(varnode.getAddress(), varnode.getSize())) stringValue = str(bytesValue) printValue = repr(stringValue) if isPrintable(stringValue) else stringValue.encode('hex') self.logger.info('Variable `{}` @ `{}` has value `{}`'.format(parameter.name, storage, printValue)) for register in self.emulatorHelper.getLanguage().getRegisters(): if register.isBaseRegister() and not register.isProcessorContext(): self.logger.debug(str(register)) self.logger.debug(str(self.emulatorHelper.readRegister(register))) self.logger.debug(str(self.emulatorHelper)) self.logger.debug(str(self.emulatorHelper.getLanguage())) self.logger.debug(str(self.emulatorHelper.getLanguage().getRegisters())) self.logger.info(str(['{} = {}'.format(register, self.emulatorHelper.readRegister(register)) for register in self.emulatorHelper.getLanguage().getRegisters() if register.isBaseRegister() and not register.isProcessorContext()])) self.logger.info('Stopping execution at {:x}'.format(self.emulatorHelper.readRegister(self.emulatorHelper.getPCRegister()))) self.logger.debug('Logged writes at {}'.format(self.emulatorHelper.getTrackedMemoryWriteSet())) def readMemory(self, from_, size): bytesValue = bytearray(0) bytesValue.extend(self.emulatorHelper.readMemory(self.getAddress(from_), size)) stringValue = str(bytesValue) self.logger.info('Reading from {} (size: {}): {}\n\thex={}'.format(from_, size, repr(stringValue), stringValue.encode("hex"))) return stringValue def readPointer(self, address): self.logger.debug('reading %d from address %s' % (self.program.getLanguage().getProgramCounter().getBitLength()//8, str(address))) packed = bytearray(0) packed.extend(self.emulatorHelper.readMemory(address, self.program.getLanguage().getProgramCounter().getBitLength()//8)) self.logger.debug('reading `%s` from address' % repr(str(packed))) if not self.program.getLanguage().isBigEndian(): packed = str(packed[::-1]) self.logger.debug('got pointer at `%s`' % repr(str(packed))) return int(packed.encode('hex'), 16) def writeMemory(self, from_, bytesValue): bytesValue = applyByteSubstitution(bytesValue) self.emulatorHelper.writeMemory(self.getAddress(from_), bytesValue) def updateUI(self): self.plugin.syncView(self.emulatorHelper.getExecutionAddress()) def initCmdHandlers(self): self.cmd_handlers = { 's': self.cmdStep, 'c': self.cmdContinue, 'n': self.cmdNext, 'b': self.cmdBreakpointAdd, 'd': self.cmdBreakpointRemove, 'x': self.cmdSleep, 'q': self.cmdQuit, 'r': self.cmdReadMem, 'w': self.cmdWriteMem, 'p': self.cmdPrintState, 'h': self.cmdHelp, 'l': self.cmdLogHistory, 'e': self.cmdEval, 'hook': self.cmdHook, 'list-hooks': self.cmdListHook, } @history def cmdHook(self, cmd): '''hook address module.function - replace a function with a python implementation e.g. hook 0x40000 libc6.puts ''' address = self.getAddress(int(cmd[1], 16)) library_name, function_name = cmd[2].split('.') thunkedFunction = self.program.getFunctionManager().getFunctionContaining(address) for library in lib.exports: if library_name == library_name: self.logger.debug('Found library `%s`' % (library.name)) for function in library.exports: self.logger.debug('Found function `%s`' % (function.__name__)) if function_name == function.__name__: self.logger.info('Hooked function `%s` at %s with implementation lib/%s/%s' % (thunkedFunction.getName(), str(address), library.name, function.__name__)) callback = DucktapeBreakCallback(function(self.program, self, thunkedFunction, self.monitor), lambda x: True) # callback.addressCallback = function(self.program, self, self.program.getFunctionManager().getFunctionAt(address), self.monitor) self.emulatorHelper.emulator.getBreakTable().registerAddressCallback(address, callback) break @history def cmdListHook(self, cmd): '''List available hooks ''' for library in lib.exports: self.logger.debug('Found library `%s`' % (library.name)) for function in library.exports: self.logger.debug('Found function `%s`' % (function.__name__)) self.logger.info('%s.%s - %s' % (library.name, function.__name__, function.__doc__)) @history def cmdStep(self, cmd): '''step''' self.emulatorHelper.step(self.monitor) def run(self, monitor): self.emulatorHelper.emulator.setHalt(False) while not self.emulatorHelper.emulator.getHalt(): self.emulatorHelper.step(monitor) currentAddress = self.emulatorHelper.getExecutionAddress() if len(self.lastAddresses) == 0 or self.lastAddresses[0] != currentAddress: self.lastAddresses = [currentAddress] + self.lastAddresses[:1] @history def cmdContinue(self, cmd): '''continue''' self.run(self.monitor) @history def cmdNext(self, cmd): '''step over/next''' address = self.flatapi.getInstructionAfter(self.emulatorHelper.getExecutionAddress()).getAddress() self.emulatorHelper.setBreakpoint(address) self.run(self.monitor) self.emulatorHelper.clearBreakpoint(address) @history def cmdBreakpointAdd(self, cmd): '''add breakpoint (`hex_address`)''' address = self.getAddress(int(cmd[1], 16)) self.emulatorHelper.setBreakpoint(address) @history def cmdBreakpointRemove(self, cmd): '''remove breakpoint (`hex_address`)''' address = self.getAddress(int(cmd[1], 16)) self.emulatorHelper.clearBreakpoint(address) @history def cmdSleep(self, cmd): '''sleep (`time(=5)`)''' for i in range(10000): self.monitor.isCancelled() # time.sleep(5 if len(cmd) == 1 else int(cmd[1])) @history def cmdQuit(self, cmd): '''quit''' self.printState() self.updateUI() self.emulator_state = EmulatorState.DONE @history def cmdReadMem(self, cmd): '''read memory addr (either `hex_from:hex_to` or `hex_from size`)''' if len(cmd) == 3: from_ = cmd[1] size = int(cmd[2], 16 if "0x" in cmd[2].lower() else 10) else: from_, to_ = map(lambda x: int(x,16), cmd[1].split(":")) size = to_-from_ from_ = hex(from_) return self.readMemory(from_.replace("0x",""), size) @history def cmdWriteMem(self, cmd): '''write memory addr (`hex_addr hex_bytes`)''' self.writeMemory(cmd[1], cmd[2]) @history def cmdPrintState(self, cmd): '''print state''' self.printState() @history def cmdEval(self, cmd): '''executes your command''' exec(' '.join(cmd[1:])) def cmdHelp(self, cmd): '''help''' self.logger.info("Commands:") for k,v in self.cmd_handlers.items(): self.logger.info("\t%s: %s" % (k, v.__doc__)) def cmdLogHistory(self, cmd): '''prints a serialized version of this debugging session''' self.logger.debug(self.history) self.logger.info("`%s`" % (', '.join(self.history)))
def main(): EIP = 0 # Определяем эмулируемую функцию main_addr = getSymbolAddress("main") # Инициализируем эмулятор emuHelper = EmulatorHelper(currentProgram) # Создаем переменную для идентефикации возврата из эмулируемой функции controlledReturnAddr = getAddress(EIP) # Устанавливаем начальный адрес EIP main_addr = int("0x{}".format(main_addr), 16) emuHelper.writeRegister(emuHelper.getPCRegister(), main_addr) # Для x86 `registers` содержит 812 регистров! # Поэтому придется отфильтровать их, для вывода только тех, которые нам нужны registers = getProgramRegisterList(currentProgram) # А тут, те регистры, которые мы хотив видеть в выводе эмулятора reg_filter = [ "EAX", "EBX", "ECX", "EDX", "ESI", "EDI", "ESP", "EBP", "EIP", "flags" ] # Устанавливаем значение регистров emuHelper.writeRegister("EAX", 0x1337) emuHelper.writeRegister("ESP", 0xDEADBEEF) emuHelper.writeRegister("EBP", 0xDEADBEEF) # Для записи используем emuHelper.writeMemoryValue или emuHelper.writeMemory emuHelper.writeMemory(getAddress(0xDEAD0000), b'\x68\x65\x6c\x6c\x6f\x20\x67\x69\x74\x68\x75\x62') # Для чтения используем emuHelper.readMemory str_0 = emuHelper.readMemory(getAddress(0xDEAD0000), 12) t = [] for i in str_0: t.append(chr(i)) print("Memory at 0xDEAD0000: {}".format(t)) # Начало эмуляции while monitor.isCancelled() is False: executionAddress = emuHelper.getExecutionAddress() if (executionAddress == controlledReturnAddr): print("Emulation complete.") return # Выводим состояние регистров print("Address: 0x{} ({})".format(executionAddress, getInstructionAt(executionAddress))) for reg in reg_filter: reg_value = emuHelper.readRegister(reg) print(" {} = {:#010x}".format(reg, reg_value)) # Эмулируем следующую инструкцию success = emuHelper.step(monitor) if (success == False): lastError = emuHelper.getLastError() printerr("Emulation Error: '{}'".format(lastError)) return # Очищаем ресурсы и освобождаем текущую программу emuHelper.dispose()