Example #1
0
    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
Example #2
0
    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
Example #3
0
                    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:
Example #4
0
                    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: