def decode(self, address, code): # Decode each instruction in the buffer. result = [] offset = 0 while offset < len(code): # Decode the current instruction. opcode = libdisassemble.Opcode(code[offset:offset + 32]) length = opcode.getSize() disasm = opcode.printOpcode('INTEL') hexdump = HexDump.hexadecimal(code[offset:offset + length]) # Add the decoded instruction to the list. result.append(( address + offset, length, disasm, hexdump, )) # Move to the next instruction. offset += length # Return the list of decoded instructions. return result
def decode(self, address, code): # Decode each instruction in the buffer. result = [] offset = 0 while offset < len(code): # Decode the current instruction. opcode = libdisassemble.Opcode( code[offset:offset+32] ) length = opcode.getSize() disasm = opcode.printOpcode('INTEL') hexdump = HexDump.hexadecimal( code[offset:offset+length] ) # Add the decoded instruction to the list. result.append(( address + offset, length, disasm, hexdump, )) # Move to the next instruction. offset += length # Return the list of decoded instructions. return result
def decode(self, address, code): # Decode each instruction in the buffer. result = [] offset = 0 while offset < len(code): # Try to decode the current instruction. instruction = pydasm.get_instruction(code[offset:offset+32], pydasm.MODE_32) # Get the memory address of the current instruction. current = address + offset # Illegal opcode or opcode longer than remaining buffer. if not instruction or instruction.length + offset > len(code): hexdump = '%.2X' % ord(code[offset]) disasm = 'db 0x%s' % hexdump ilen = 1 # Correctly decoded instruction. else: disasm = pydasm.get_instruction_string(instruction, pydasm.FORMAT_INTEL, current) ilen = instruction.length hexdump = HexDump.hexadecimal(code[offset:offset+ilen]) # Add the decoded instruction to the list. result.append(( current, ilen, disasm, hexdump, )) # Move to the next instruction. offset += ilen # Return the list of decoded instructions. return result
def decode(self, address, code): # Decode each instruction in the buffer. result = [] offset = 0 while offset < len(code): # Try to decode the current instruction. instruction = pydasm.get_instruction(code[offset:offset + 32], pydasm.MODE_32) # Get the memory address of the current instruction. current = address + offset # Illegal opcode or opcode longer than remaining buffer. if not instruction or instruction.length + offset > len(code): hexdump = '%.2X' % ord(code[offset]) disasm = 'db 0x%s' % hexdump ilen = 1 # Correctly decoded instruction. else: disasm = pydasm.get_instruction_string(instruction, pydasm.FORMAT_INTEL, current) ilen = instruction.length hexdump = HexDump.hexadecimal(code[offset:offset + ilen]) # Add the decoded instruction to the list. result.append(( current, ilen, disasm, hexdump, )) # Move to the next instruction. offset += ilen # Return the list of decoded instructions. return result
def decode(self, address, code): # Get the constants for the requested architecture. arch, mode = self.__constants[self.arch] # Get the decoder function outside the loop. md = capstone.Cs(arch, mode) decoder = md.disasm_lite # If the buggy version of the bindings are being used, we need to catch # all exceptions broadly. If not, we only need to catch CsError. if self.__bug: CsError = Exception else: CsError = capstone.CsError # Create the variables for the instruction length, mnemonic and # operands. That way they won't be created within the loop, # minimizing the chances data might be overwritten. # This only makes sense for the buggy vesion of the bindings, normally # memory accesses are safe). length = mnemonic = op_str = None # For each instruction... result = [] offset = 0 while offset < len(code): # Disassemble a single instruction, because disassembling multiple # instructions may cause excessive memory usage (Capstone allocates # approximately 1K of metadata per each decoded instruction). instr = None try: instr = list(decoder( code[offset:offset+16], address+offset, 1 ))[0] except IndexError: pass # No instructions decoded. except CsError: pass # Any other error. # On success add the decoded instruction. if instr is not None: # Get the instruction length, mnemonic and operands. # Copy the values quickly before someone overwrites them, # if using the buggy version of the bindings (otherwise it's # irrelevant in which order we access the properties). length = instr[1] mnemonic = instr[2] op_str = instr[3] # Concatenate the mnemonic and the operands. if op_str: disasm = "%s %s" % (mnemonic, op_str) else: disasm = mnemonic # Get the instruction bytes as a hexadecimal dump. hexdump = HexDump.hexadecimal( code[offset:offset+length] ) # On error add a "define constant" instruction. # The exact instruction depends on the architecture. else: # The number of bytes to skip depends on the architecture. # On Intel processors we'll skip one byte, since we can't # really know the instruction length. On the rest of the # architectures we always know the instruction length. if self.arch in (win32.ARCH_I386, win32.ARCH_AMD64): length = 1 else: length = 4 # Get the skipped bytes as a hexadecimal dump. skipped = code[offset:offset+length] hexdump = HexDump.hexadecimal(skipped) # Build the "define constant" instruction. # On Intel processors it's "db". # On ARM processors it's "dcb". if self.arch in (win32.ARCH_I386, win32.ARCH_AMD64): mnemonic = "db " else: mnemonic = "dcb " bytes = [] for b in skipped: if b.isalpha(): bytes.append("'%s'" % b) else: bytes.append("0x%x" % ord(b)) op_str = ", ".join(bytes) disasm = mnemonic + op_str # Add the decoded instruction to the list. result.append(( address + offset, length, disasm, hexdump, )) # Update the offset. offset += length # Return the list of decoded instructions. return result
def decode(self, address, code): # Get the constants for the requested architecture. arch, mode = self.__constants[self.arch] # Get the decoder function outside the loop. decoder = capstone.cs_disasm_quick # If the buggy version of the bindings are being used, we need to catch # all exceptions broadly. If not, we only need to catch CsError. if self.__bug: CsError = Exception else: CsError = capstone.CsError # Create the variables for the instruction length, mnemonic and # operands. That way they won't be created within the loop, # minimizing the chances data might be overwritten. # This only makes sense for the buggy vesion of the bindings, normally # memory accesses are safe). length = mnemonic = op_str = None # For each instruction... result = [] offset = 0 while offset < len(code): # Disassemble a single instruction, because disassembling multiple # instructions may cause excessive memory usage (Capstone allocates # approximately 1K of metadata per each decoded instruction). instr = None try: instr = list( decoder(arch, mode, code[offset:offset + 16], address + offset, 1))[0] except IndexError: pass # No instructions decoded. except CsError: pass # Any other error. # On success add the decoded instruction. if instr is not None: # Get the instruction length, mnemonic and operands. # Copy the values quickly before someone overwrites them, # if using the buggy version of the bindings (otherwise it's # irrelevant in which order we access the properties). length = instr.size mnemonic = instr.mnemonic op_str = instr.op_str # Concatenate the mnemonic and the operands. if op_str: disasm = "%s %s" % (mnemonic, op_str) else: disasm = mnemonic # Get the instruction bytes as a hexadecimal dump. hexdump = HexDump.hexadecimal(code[offset:offset + length]) # On error add a "define constant" instruction. # The exact instruction depends on the architecture. else: # The number of bytes to skip depends on the architecture. # On Intel processors we'll skip one byte, since we can't # really know the instruction length. On the rest of the # architectures we always know the instruction length. if self.arch in (win32.ARCH_I386, win32.ARCH_AMD64): length = 1 else: length = 4 # Get the skipped bytes as a hexadecimal dump. skipped = code[offset:offset + length] hexdump = HexDump.hexadecimal(skipped) # Build the "define constant" instruction. # On Intel processors it's "db". # On ARM processors it's "dcb". if self.arch in (win32.ARCH_I386, win32.ARCH_AMD64): mnemonic = "db " else: mnemonic = "dcb " bytes = [] for b in skipped: if b.isalpha(): bytes.append("'%s'" % b) else: bytes.append("0x%x" % ord(b)) op_str = ", ".join(bytes) disasm = mnemonic + op_str # Add the decoded instruction to the list. result.append(( address + offset, length, disasm, hexdump, )) # Update the offset. offset += length # Return the list of decoded instructions. return result
def search_process(cls, process, patterns, minAddr=None, maxAddr=None, bufferPages=None, overlapping=True): """ Search for the given string or pattern within the process memory. @type process: L{Process} @param process: Process to search. @type patterns: L{list of Pattern} @param patterns: List of strings or wildcard patterns to search for. It must be an instance of a subclass of L{Pattern}. The following L{Pattern} subclasses are provided by WinAppDbg: - L{StringPattern} (case sensitive string search) - L{IStringPattern} (case insensitive string search) - L{HexPattern} (hexadecimal pattern with wildcards) You can also write your own subclass of L{Pattern} for customized searches. @type minAddr: int @param minAddr: (Optional) Start the search at this memory address. @type maxAddr: int @param maxAddr: (Optional) Stop the search at this memory address. @type bufferPages: int @param bufferPages: (Optional) Number of memory pages to buffer when performing the search. Valid values are: - C{0} or C{None}: Automatically determine the required buffer size. This is the default. - C{> 0}: Set the buffer size in memory pages. - C{< 0}: Disable buffering entirely. This may give you a little speed gain at the cost of an increased memory usage. If the target process has very large contiguous memory regions it may actually be slower or even fail. @type overlapping: bool @param overlapping: C{True} to allow overlapping results, C{False} otherwise. Overlapping results yield the maximum possible number of results. For example, if searching for "AAAA" within "AAAAAAAA" at address C{0x10000}, when overlapping is turned off the following matches are yielded:: (0x10000, 4, "AAAA") (0x10004, 4, "AAAA") If overlapping is turned on, the following matches are yielded:: (0x10000, 4, "AAAA") (0x10001, 4, "AAAA") (0x10002, 4, "AAAA") (0x10003, 4, "AAAA") (0x10004, 4, "AAAA") As you can see, the middle results are overlapping the last two. @rtype: iterator of tuple( int, int, str ) @return: An iterator of tuples. Each tuple contains the following: - The memory address where the pattern was found. - The size of the data that matches the pattern. - The data that matches the pattern. @raise WindowsError: An error occurred when querying or reading the process memory. """ # Quit early if we have no list of patterns. if not patterns: return # Reset all patterns. for searcher in patterns: searcher.reset() # Get a list of allocated memory regions. memory = list() for mbi in process.get_memory_map(minAddr, maxAddr): if mbi.State == win32.MEM_COMMIT and \ not mbi.Protect & win32.PAGE_GUARD: memory.append((mbi.BaseAddress, mbi.RegionSize)) # If default buffer allocation is requested, calculate it. # We want one more page than the minimum required to allocate the # target string to find. Typically this will be 2 pages, since # most searches will not be looking for strings over 4k. # (We can't do it with 1 page - the target may be between pages!) if bufferPages is None or bufferPages == 0: bufferPages = MemoryAddresses.get_buffer_size_in_pages( 0, sorted(map(len, patterns))[-1] + 1) # If no allocation limit is set, # read entire regions and search on them. if bufferPages <= 0: for (address, size) in memory: try: data = process.read(address, size) except WindowsError, e: begin = HexDump.address(address) end = HexDump.address(address + size) msg = "Error reading %s-%s: %s" msg = msg % (begin, end, str(e)) warnings.warn(msg, MemoryAccessWarning) continue for result in cls._search_block(process, patterns, data, address, 0, overlapping): yield result
end = address + total_size shift = 0 buffer = process.read(address, min(size, total_size)) while 1: for result in cls._search_block( process, patterns, buffer, address, shift, overlapping): yield result shift = step address = address + step if address >= end: break buffer = buffer[step:] buffer = buffer + process.read(address, step) except WindowsError, e: begin = HexDump.address(address) end = HexDump.address(address + total_size) msg = "Error reading %s-%s: %s" msg = msg % (begin, end, str(e)) warnings.warn(msg, MemoryAccessWarning) @staticmethod def _search_block(process, patterns, data, address, shift, overlapping): for searcher in patterns: if shift == 0: searcher.reset() else: searcher.shift(shift) while 1: searcher.search(address, data, overlapping) if searcher.result is None:
def search_process(cls, process, patterns, minAddr = None, maxAddr = None, bufferPages = None, overlapping = True): """ Search for the given string or pattern within the process memory. @type process: L{Process} @param process: Process to search. @type patterns: L{list of Pattern} @param patterns: List of strings or wildcard patterns to search for. It must be an instance of a subclass of L{Pattern}. The following L{Pattern} subclasses are provided by WinAppDbg: - L{StringPattern} (case sensitive string search) - L{IStringPattern} (case insensitive string search) - L{HexPattern} (hexadecimal pattern with wildcards) You can also write your own subclass of L{Pattern} for customized searches. @type minAddr: int @param minAddr: (Optional) Start the search at this memory address. @type maxAddr: int @param maxAddr: (Optional) Stop the search at this memory address. @type bufferPages: int @param bufferPages: (Optional) Number of memory pages to buffer when performing the search. Valid values are: - C{0} or C{None}: Automatically determine the required buffer size. This is the default. - C{> 0}: Set the buffer size in memory pages. - C{< 0}: Disable buffering entirely. This may give you a little speed gain at the cost of an increased memory usage. If the target process has very large contiguous memory regions it may actually be slower or even fail. @type overlapping: bool @param overlapping: C{True} to allow overlapping results, C{False} otherwise. Overlapping results yield the maximum possible number of results. For example, if searching for "AAAA" within "AAAAAAAA" at address C{0x10000}, when overlapping is turned off the following matches are yielded:: (0x10000, 4, "AAAA") (0x10004, 4, "AAAA") If overlapping is turned on, the following matches are yielded:: (0x10000, 4, "AAAA") (0x10001, 4, "AAAA") (0x10002, 4, "AAAA") (0x10003, 4, "AAAA") (0x10004, 4, "AAAA") As you can see, the middle results are overlapping the last two. @rtype: iterator of tuple( int, int, str ) @return: An iterator of tuples. Each tuple contains the following: - The memory address where the pattern was found. - The size of the data that matches the pattern. - The data that matches the pattern. @raise WindowsError: An error occurred when querying or reading the process memory. """ # Quit early if we have no list of patterns. if not patterns: return # Reset all patterns. for searcher in patterns: searcher.reset() # Get a list of allocated memory regions. memory = list() for mbi in process.get_memory_map(minAddr, maxAddr): if mbi.State == win32.MEM_COMMIT and \ not mbi.Protect & win32.PAGE_GUARD: memory.append( (mbi.BaseAddress, mbi.RegionSize) ) # If default buffer allocation is requested, calculate it. # We want one more page than the minimum required to allocate the # target string to find. Typically this will be 2 pages, since # most searches will not be looking for strings over 4k. # (We can't do it with 1 page - the target may be between pages!) if bufferPages is None or bufferPages == 0: bufferPages = MemoryAddresses.get_buffer_size_in_pages( 0, sorted(map(len, patterns))[-1] + 1) # If no allocation limit is set, # read entire regions and search on them. if bufferPages <= 0: for (address, size) in memory: try: data = process.read(address, size) except WindowsError, e: begin = HexDump.address(address) end = HexDump.address(address + size) msg = "Error reading %s-%s: %s" msg = msg % (begin, end, str(e)) warnings.warn(msg, MemoryAccessWarning) continue for result in cls._search_block( process, patterns, data, address, 0, overlapping): yield result