示例#1
0
    def extract(self):
        try:
            content = open(self.filename,'rb').read()

            # search all '.proto' strings
            protos = []
            stream = content
            while len(stream)>0:
                try:
                    r = stream.index('.proto')
                    for j in range(64):
                        try:
                            if decode_varint128(stream[r-j:])[0]==(j+5) and is_valid_filename(stream[r-j+1:r+6]):
                                # Walk the fields and get a probable size
                                walker = ProtobufFieldsWalker(stream[r-j-1:])
                                walker.walk()
                                probable_size = walker.get_size()
                                
                                """
                                Probable size approach is not perfect,
                                we add a delta of 1024 bytes to be sure
                                not to miss something =)
                                """
                                for k in range(probable_size+1024, 0, -1):
                                    try:
                                        fds  = FileDescriptorProto()
                                        fds.ParseFromString(stream[r-j-1:r-j-1+k])
                                        protos.append(stream[r-j-1:r-j-1+k])
                                        print('[i] Found protofile %s (%d bytes)' % (stream[r-j+1:r+6], k))
                                        break
                                    except DecodeError:
                                        pass
                                    except UnicodeDecodeError:
                                        pass
                                break
                        except IndexError:
                            pass
                    stream = stream[r+6:]
                except ValueError:
                    break

            # Load successively each binary proto file and rebuild it from scratch
            seen = []
            for content in protos:
                try:
                    # Load the prototype
                    fds  = FileDescriptorProto()
                    fds.ParseFromString(content)
                    res = FileDescriptorDisassembler(fds)
                    if len(res.desc.name)>0:
                        if res.desc.name not in seen:
                            open(res.desc.name+'.protoc','wb').write(content)
                            res.render()
                            seen.append(res.desc.name)
                except DecodeError:
                    pass
            
        except IOError:
            print('[!] Unable to read %s' % sys.argv[1])
 def _add_file_from_response(
         self, file_descriptor: FileDescriptorResponse) -> None:
     protos: List[bytes] = file_descriptor.file_descriptor_proto
     for proto in protos:
         desc = FileDescriptorProto()
         desc.ParseFromString(proto)
         if desc.name not in self._known_files:
             self._logger.info("Loading descriptors from file: %s",
                               desc.name)
             self._known_files.add(desc.name)
             self.Add(desc)
示例#3
0
async def test_file_by_filename_response(channel):
    r1, r2 = await ServerReflectionStub(channel).ServerReflectionInfo([
        ServerReflectionRequest(file_by_filename=DESCRIPTOR.name, ),
        ServerReflectionRequest(file_by_filename='my/missing.proto', ),
    ])

    proto_bytes, = r1.file_descriptor_response.file_descriptor_proto
    dummy_proto = FileDescriptorProto()
    dummy_proto.ParseFromString(proto_bytes)
    assert dummy_proto.name == DESCRIPTOR.name
    assert dummy_proto.package == DESCRIPTOR.package

    assert r2 == ServerReflectionResponse(error_response=ErrorResponse(
        error_code=5,
        error_message='not found',
    ), )
示例#4
0
async def test_file_containing_symbol_response(channel):
    r1, r2 = await ServerReflectionStub(channel).ServerReflectionInfo([
        ServerReflectionRequest(file_containing_symbol=(
            DESCRIPTOR.message_types_by_name['DummyRequest'].full_name), ),
        ServerReflectionRequest(file_containing_symbol='unknown.Symbol', ),
    ])

    proto_bytes, = r1.file_descriptor_response.file_descriptor_proto
    dummy_proto = FileDescriptorProto()
    dummy_proto.ParseFromString(proto_bytes)
    assert dummy_proto.name == DESCRIPTOR.name
    assert dummy_proto.package == DESCRIPTOR.package

    assert r2 == ServerReflectionResponse(error_response=ErrorResponse(
        error_code=5,
        error_message='not found',
    ), )
示例#5
0
def walk_binary(binr):
    if type(binr) == str:
        with open(binr, 'rb') as fd:
            binr = fd.read()

    # Search for:
    # ".proto" or ".protodevel", as part of the "name" (1) field
    cursor = 0
    while cursor < len(binr):
        cursor = binr.find(b'.proto', cursor)

        if cursor == -1:
            break
        cursor += len('.proto')
        cursor += (binr[cursor:cursor + 5] == b'devel') * 5

        # Search back for the (1, length-delimited) marker
        start = binr.rfind(b'\x0a', max(cursor - 1024, 0), cursor)

        if start > 0 and binr[start - 1] == 0x0a == (cursor - start - 1):
            start -= 1

        # Check whether length byte is coherent
        if start == -1:
            continue
        varint, end = _DecodeVarint(binr, start + 1)
        if cursor - end != varint:
            continue

        # Look just after for subsequent markers
        tags = b'\x12\x1a\x22\x2a\x32\x3a\x42\x4a\x50\x58\x62'
        if binr[cursor] not in tags:
            continue

        while cursor < len(binr) and binr[cursor] in tags:
            tags = tags[tags.index(binr[cursor]):]

            varint, end = _DecodeVarint(binr, cursor + 1)
            cursor = end + varint * (binr[cursor] & 0b111 == 2)

        # Parse descriptor
        proto = FileDescriptorProto()
        proto.ParseFromString(binr[start:cursor])

        # Convert to ascii
        yield descpb_to_proto(proto)
示例#6
0
    def reconstitute_file_from_bytes(self, file_descriptor_proto_bytes):
        """
        Reconstitutes one or more Python protobuf classes from a byte
        stream. The intended purpose of this function is to create a
        set of Protobuf Python classes from a byte stream file sent
        from another service. This way, services can define arbitrary
        data types and send schemas for those types to other services.
        Args:
            file_descriptor_proto_bytes: Serialized protocol buffer file
                                         containing one or more messages.

        Returns:
            An array containing each class contained in
            file_descriptor_proto_bytes.
        """
        file_descriptor_proto = FileDescriptorProto()
        file_descriptor_proto.ParseFromString(file_descriptor_proto_bytes)
        return self.reconstitute_file(file_descriptor_proto)
示例#7
0
    def disassemble(self):
        """Disassemble serialized protocol buffers file.
        """
        ser_pb = open(self.input_file, 'rb').read()  # Read serialized pb file

        fd = FileDescriptorProto()
        fd.ParseFromString(ser_pb)
        self.name = fd.name

        self._print('// Reversed by pbd (https://github.com/rsc-dev/pbd)')

        if len(fd.package) > 0:
            self._print('package {};'.format(fd.package))
            self.package = fd.package
        else:
            self._print('// Package not defined')

        self._walk(fd)
示例#8
0
def update_message_classes():
    global message_classes, descriptor_path, method_info
    factory = MessageFactory()
    # Add well-known types first
    for file_descriptor in file_descriptors.values():
        file_proto = FileDescriptorProto()
        file_proto.ParseFromString(file_descriptor.serialized_pb)
        factory.pool.Add(file_proto)
    # Then add our types
    with open(descriptor_path, 'rb') as f:
        fileset = google.protobuf.descriptor_pb2.FileDescriptorSet.FromString(f.read())
    for file_proto in fileset.file:
        factory.pool.Add(file_proto)
    message_classes = factory.GetMessages([file_proto.name for file_proto in fileset.file])

    # HACK to add nested types. Is there an API for this?
    for desc in factory.pool._descriptors.values():
        if desc.full_name not in message_classes:
            message_classes[desc.full_name] = factory.GetPrototype(desc)

    method_info = {}

    for file_proto in fileset.file:
        for service in file_proto.service:
            for method in service.method:
                k = "{}.{}".format(service.name, method.name)
                input_type = method.input_type
                output_type = method.output_type
                if input_type.startswith('.'):
                    input_type = input_type[1:]
                if output_type.startswith('.'):
                    output_type = output_type[1:]
                if input_type not in message_classes or output_type not in message_classes:
                    print("WARNING: types for method {} not found".format(k))
                input_type = message_classes[input_type]
                output_type = message_classes[output_type]

                method_info[k] = (method, input_type, output_type)