# Copyright 2005 Cody Brocious. Released under the terms of the GNU GPL v2 # Huge thanks to Kai Killebrew for the idea of using an infinite loop, leading to this idea. import process, struct, time class ProcessWatcher: def __init__(self, name=None, pid=None, allocate=True, code_address=None, data_address=None): self.p = process.Process(name=name, pid=pid) self.code_address = code_address self.data_address = data_address self.allocate = allocate if self.allocate: if not code_address or not data_address: allocated = self.p.allocatePages(4096) if not data_address: self.data_address = allocated allocated += 5 if not code_address: self.code_address = allocated self.watches = {} self.watchcallbacks = [None] def addEbpWatch(self, where, code_len, var, callback): self.watches[where] = (code_len, '\x8B\x8D' + struct.pack('] self.watchcallbacks.append(callback) def addEbpRefWatch(self, where, code_len, var, callback): self.watches[where] = (code_len, '\x8D\x8D' + struct.pack('] self.watchcallbacks.append(callback) def addDataWatch(self, where, code_len, address, callback): self.watches[where] = (code_len, '\x8B\x0D' + struct.pack('] self.watchcallbacks.append(callback) def doWatch(self): bp = False while not bp: while True: d = self.p.read(self.data_address, 1) if not d: return False d = ord(d) if d == 0 or not d & 0x80L: time.sleep(0.025) continue else: if not self.watchcallbacks[0xFF - d](struct.unpack(' mc += '\x90' * (old_len - 5) # nop self.p.write(where, mc) mc = '\x9C' # pushfd mc += '\x50' # push eax mc += '\x51' # push ecx mc += code # watch code mc += '\xB8' + struct.pack(' mc += '\xC6\x05' + struct.pack('], mc += '\xE9\xDE\xAD\xBE\xEF' # jmp
mc += '\x58' # REENTRY: pop eax mc += '\x9D' # popfd mc += self.recalculateOffsets(code=old, old_loc=where, new_loc=off+len(mc)) # old code with offsets recalculated if necessary off += len(mc) + 5 mc += '\xE9' + struct.pack(' jt.append(mc) main = self.code_address + len(''.join(jt)) off = self.code_address for mc in jt: mc = mc.replace('\xDE\xAD\xBE\xEF', struct.pack('], ecx mc += '\x59' # pop ecx mc += '\x50' # push eax mc += '\xF6\x15' + struct.pack('] mc += '\xA0' + struct.pack('] mc += '\x3C\x00' # cmp al, 00h mc += '\x74\x02' # je END mc += '\xEB\xF5' # jmp START mc += '\x58' # END: pop eax mc += '\xFF\xE0' # jmp eax self.p.write(main, mc) def recalculateOffsets(self, code, old_loc, new_loc): if len(code) == 5 and (code[0] == '\xE8' or code[0] == '\xE9'): code, offset = code[0], struct.unpack('