Exemple #1
0
    def __init__(self, handle: HANDLE, base: DWORD):
        """

        Given a handle and base address of the loaded DLL,
        determine the DLL name and size to fully initialize
        the system DLL object.

        @type  handle: HANDLE
        @param handle: Handle to the loaded DLL
        @type  base:   DWORD
        @param base:   Loaded address of DLL

        @raise PDError: An exception is raised on failure.
        """

        self.handle = handle
        self.base = base
        self.name = None
        self.path = None
        self.pe = None
        self.size = 0

        # calculate the file size of the
        file_size_hi = c_ulong(0)
        file_size_lo = kernel32.GetFileSize(handle, byref(file_size_hi))
        self.size = (file_size_hi.value << 8) + file_size_lo

        # create a file mapping from the dll handle.
        file_map = kernel32.CreateFileMappingA(handle, 0, PAGE_READONLY, 0, 1,
                                               0)

        if not file_map:
            raise PDError('CreateFileMappingA()', True)

        # Map a single byte of the dll into memory
        # so we can query for the file name.
        kernel32.MapViewOfFile.restype = POINTER(c_char)
        file_ptr = kernel32.MapViewOfFile(file_map, FILE_MAP_READ, 0, 0, 1)

        if file_ptr:
            # Query for the filename of the mapped file.
            filename = create_string_buffer(2048)
            psapi.GetMappedFileNameA(kernel32.GetCurrentProcess(), file_ptr,
                                     byref(filename), 2048)

            # Store the full path. this is kind of ghetto,
            # but i didn't want to mess with QueryDosDevice() etc ...
            self.path = os.sep + filename.value.split(os.sep, 3)[3]

            # Store the file name.
            # XXX - this really shouldn't be failing. but i've seen it happen.
            try:
                self.name = filename.value[filename.value.rindex(os.sep) + 1:]
            except Exception:
                self.name = self.path

            kernel32.UnmapViewOfFile(file_ptr)

        kernel32.CloseHandle(file_map)
Exemple #2
0
    def pickle_recv(self):
        """
        This routine is used for marshaling arbitrary data from
        the PyDbg server. We can send pretty much anything here.
        For example a tuple containing integers, strings, arbitrary objects
        and structures. Our "protocol" is a simple length-value protocol
        where each datagram is prefixed by a 4-byte length of
        the data to be received.

        @raise pdx: An exception is raised if the connection was severed.
        @rtype:     Mixed
        @return:    Whatever is received over the socket.
        """

        try:
            length = int(self.sock.recv(4), 16)
            received = self.sock.recv(length)
        except:
            raise PDError("connection severed")

        return pickle.loads(received)
Exemple #3
0
    def __init__(self, host, port):
        """
        Set the default client attributes. The target host and port are required.

        @type  host: String
        @param host: Host address of PyDBG server (dotted quad IP address or hostname)
        @type  port: Integer
        @param port: Port that the PyDBG server is listening on.

        @raise PDError: An exception is raised if a connection to the PyDbg server can not be established.
        """

        self.host = host
        self.port = port
        self.pydbg = PyDBG()
        self.callbacks = {}

        try:
            self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.sock.connect((host, port))
        except:
            raise PDError("connection severed")
Exemple #4
0
    def pickle_send(self, data):
        """
        This routine is used for marshaling arbitrary data to the PyDbg server.
        We can send pretty much anything here.
        For example a tuple containing integers, strings, arbitrary objects
        and structures. Our "protocol" is a simple length-value protocol
        where each datagram is prefixed by a 4-byte length of
        the data to be received.

        @type  data: Mixed
        @param data: Data to marshal and transmit. Data can *pretty much* contain anything you throw at it.

        @raise pdx: An exception is raised if the connection was severed.
        """

        data = pickle.dumps(data)

        try:
            self.sock.send("%04x" % len(data))
            self.sock.send(data)
        except:
            raise PDError("connection severed")
Exemple #5
0
    def debug_event_loop(self):
        """
        Overriden debug event handling loop.
        A transparent mirror here with method_missing() would not do.
        Our debug event loop is reduced here to a data marshaling loop with
        the server. If the received type from the server is a tuple then
        we assume a debug or exception event has occured and
        pass it to any registered callbacks.
        The callback is free to call arbitrary PyDbg routines.
        Upon return of the callback, a special token, **DONE**, is used to
        flag to the PyDbg server that we are done processing
        the exception and it is free to move on.
        """

        self.pickle_send(("debug_event_loop", ()))

        while 1:
            received = self.pickle_recv()

            if not received:
                continue

            # if we received a "special" type, which can currently be one of:
            #   - debugger callback event
            #   - user callback event
            #   - raised exception

            if isinstance(received, tuple):
                # callback type
                if received[0] == "callback":
                    (msg_type, dbg, context) = received

                    # debugger callback event
                    if dbg and context:
                        # propogate the convenience variables.
                        self.dbg = dbg
                        self.context = context
                        self.exception_address = dbg.u.Exception.ExceptionRecord.ExceptionAddress
                        self.write_violation = dbg.u.Exception.ExceptionRecord.ExceptionInformation[
                            0]
                        self.violation_address = dbg.u.Exception.ExceptionRecord.ExceptionInformation[
                            1]

                        exception_code = dbg.u.Exception.ExceptionRecord.ExceptionCode
                        ret = DBG_CONTINUE

                        if exception_code in self.callbacks:
                            print('processing handler for 0x{:08x}'.format(
                                exception_code))
                            ret = self.callbacks[exception_code](self)

                    # user callback event.
                    elif USER_CALLBACK_DEBUG_EVENT in self.callbacks:
                        ret = self.callbacks[USER_CALLBACK_DEBUG_EVENT](self)

                # raised exception type.
                elif received[0] == "exception":
                    (msg_type, exception_string) = received
                    print(exception_string)
                    raise PDError(exception_string)

                self.pickle_send(('**DONE**', ret))