[UI] 从 Mac mmkv 数据库导入密钥 #25

Closed
opened 2023-06-11 22:30:40 +00:00 by jixunmoe · 0 comments
Owner

参考 #20 的安卓客户端数据库密钥导入。

参考 mmkv 解析实现(简易情况):

from struct import unpack

# QM_Mac MMKV EKey Parser by Jixun


class MMKVParser:

    def __init__(self, data: bytes):
        self.data = data
        (actual_payload_size, ) = unpack('<L', data[0:4])
        self.pos_eof = 4 + actual_payload_size
        self.pos = 8

    def __str__(self) -> str:
        return f'<MMKVParser offset={self.pos:08x}>'

    def is_eof(self) -> bool:
        return self.pos >= self.pos_eof

    def peek_byte(self):
        return self.data[self.pos]

    def next_byte(self):
        next_byte = self.data[self.pos]
        self.pos += 1
        return next_byte

    def next_int(self):
        shift = 0
        result = 0
        while True:
            b = self.next_byte()

            # Little Endian - 低位在字节组的前面
            result |= (b & 0x7f) << shift
            shift += 7
            if (b & 0x80) == 0:
                break
        return result

    def next_bytes(self, len: int):
        data = self.data[self.pos:self.pos + len]
        self.pos += len
        return data

    def next_str(self):
        # String [
        #   len: int,
        #   data: byte[int], # utf-8
        # ]
        str_size = self.next_int()
        data = self.next_bytes(str_size)
        result = bytes(data).decode('utf-8')
        return result

    def next_variant_str(self):
        # Container [
        #   len: int,
        #   data: variant
        # ]
        container_len = self.next_int()
        new_pos = self.pos + container_len
        result = self.next_str()
        assert self.pos == new_pos  # 简单的检查
        return result


def dump_mmkv_to_map(data: bytes):
    result = {}
    parser = MMKVParser(data)
    while not parser.is_eof():
        key = parser.next_str()
        value = parser.next_variant_str()
        result[key] = value
    return result


def main():
    with open('MMKVStreamEncryptId', 'rb') as f:
        mmkv_map = dump_mmkv_to_map(f.read())

    for (k, v) in mmkv_map.items():
        print(f'{k} => {v}')


if __name__ == '__main__':
    main()

参考 #20 的安卓客户端数据库密钥导入。 参考 mmkv 解析实现(简易情况): ```py from struct import unpack # QM_Mac MMKV EKey Parser by Jixun class MMKVParser: def __init__(self, data: bytes): self.data = data (actual_payload_size, ) = unpack('<L', data[0:4]) self.pos_eof = 4 + actual_payload_size self.pos = 8 def __str__(self) -> str: return f'<MMKVParser offset={self.pos:08x}>' def is_eof(self) -> bool: return self.pos >= self.pos_eof def peek_byte(self): return self.data[self.pos] def next_byte(self): next_byte = self.data[self.pos] self.pos += 1 return next_byte def next_int(self): shift = 0 result = 0 while True: b = self.next_byte() # Little Endian - 低位在字节组的前面 result |= (b & 0x7f) << shift shift += 7 if (b & 0x80) == 0: break return result def next_bytes(self, len: int): data = self.data[self.pos:self.pos + len] self.pos += len return data def next_str(self): # String [ # len: int, # data: byte[int], # utf-8 # ] str_size = self.next_int() data = self.next_bytes(str_size) result = bytes(data).decode('utf-8') return result def next_variant_str(self): # Container [ # len: int, # data: variant # ] container_len = self.next_int() new_pos = self.pos + container_len result = self.next_str() assert self.pos == new_pos # 简单的检查 return result def dump_mmkv_to_map(data: bytes): result = {} parser = MMKVParser(data) while not parser.is_eof(): key = parser.next_str() value = parser.next_variant_str() result[key] = value return result def main(): with open('MMKVStreamEncryptId', 'rb') as f: mmkv_map = dump_mmkv_to_map(f.read()) for (k, v) in mmkv_map.items(): print(f'{k} => {v}') if __name__ == '__main__': main() ```
Sign in to join this conversation.
No description provided.