前面介绍过引入xlog,将日志打印成一个xlog文件,这里就来介绍一下怎么将xlog文件解码成正常的可读日志文件。
对于不加密的xlog进行解码
如果在Android代码里初始化xlog的时候,使用的是不加密的方式,比如这样:
Xlog.open(false, Xlog.LEVEL_DEBUG, Xlog.AppednerModeAsync,"", logPath,"dbxLog","");最后一个入参表示pubkey,传空就代表不对日志内容进行加密。
那就可以直接用mars工程里的decode_mars_nocrypt_log_file.py文件直接转换,但是mars提供的这个python工具是python2的版本。现在多数都是用python3的,如果你愿意在本地配多个python版本,那就配置一个python2,添加一些需要的库,直接执行那个就可以。
如果你不想配置python2,就想用python3执行,也可以手动改一下这个python文件,这是我改完后的:
!/usr/bin/pythonimportsysimportosimportglobimportzlibimportstructimportbinasciiimporttracebackMAGIC_NO_COMPRESS_START=0x03MAGIC_NO_COMPRESS_START1=0x06MAGIC_NO_COMPRESS_NO_CRYPT_START=0x08MAGIC_COMPRESS_START=0x04MAGIC_COMPRESS_START1=0x05MAGIC_COMPRESS_START2=0x07MAGIC_COMPRESS_NO_CRYPT_START=0x09MAGIC_END=0x00lastseq=0defIsGoodLogBuffer(_buffer, _offset, count):if_offset == len(_buffer): return (True, )magic_start=_buffer[_offset]ifMAGIC_NO_COMPRESS_START == magic_start or MAGIC_COMPRESS_START == magic_start or MAGIC_COMPRESS_START1 == magic_start:crypt_key_len=4elifMAGIC_COMPRESS_START2 == magic_start or MAGIC_NO_COMPRESS_START1 == magic_start or MAGIC_NO_COMPRESS_NO_CRYPT_START == magic_start or MAGIC_COMPRESS_NO_CRYPT_START == magic_start:crypt_key_len=64else:return(False, _buffer[%d]:%d != MAGIC_NUM_START % (_offset, _buffer[_offset]))headerLen=1 + 2 + 1 + 1 + 4 + crypt_key_lenif_offset + headerLen + 1 + 1 > len(_buffer): return (False,offset:%d > len(buffer):%d % (_offset, len(_buffer)))start=_offset + headerLen - 4 - crypt_key_lenlength=struct.unpack_from("I", memoryview(_buffer)[start:start + 4].tobytes())[0]if_offset + headerLen + length + 1 > len(_buffer):return(False,loglength:%d, end pos %d > len(buffer):%d % (length, _offset + headerLen + length + 1, len(_buffer)))ifMAGIC_END != _buffer[_offset + headerLen + length]: return (False,loglength:%d, buffer[%d]:%d != MAGIC_END % (length,_offset + headerLen + length,_buffer[_offset+ headerLen + length]))if(1 >= count):return(True, )else:returnIsGoodLogBuffer(_buffer, _offset + headerLen + length + 1, count - 1)defGetLogStartPos(_buffer, _count):offset=0whileTrue:ifoffset >= len(_buffer): breakifMAGIC_NO_COMPRESS_START == _buffer[offset] or MAGIC_NO_COMPRESS_START1 == _buffer[offset]or MAGIC_COMPRESS_START == _buffer[offset] or MAGIC_COMPRESS_START1 == _buffer[offset]or MAGIC_COMPRESS_START2 == _buffer[offset] or MAGIC_COMPRESS_NO_CRYPT_START == _buffer[offset]or MAGIC_NO_COMPRESS_NO_CRYPT_START == _buffer[offset]:ifIsGoodLogBuffer(_buffer, offset, _count)[0]: return offsetoffset+= 1return-1defDecodeBuffer(_buffer, _offset, _outbuffer):if_offset >= len(_buffer): return -1if _offset + 1 + 4 + 1 + 1 > len(_buffer): return -1ret=IsGoodLogBuffer(_buffer, _offset, 1)ifnot ret[0]:fixpos=GetLogStartPos(_buffer[_offset:], 1)if-1 == fixpos:return-1else:_outbuffer.extend("[F]decode_log_file.pydecode error len=%d, result:%s n" % (fixpos, ret[1]))_offset+= fixposmagic_start=_buffer[_offset]ifMAGIC_NO_COMPRESS_START == magic_start or MAGIC_COMPRESS_START == magic_start or MAGIC_COMPRESS_START1 == magic_start:crypt_key_len=4elifMAGIC_COMPRESS_START2 == magic_start or MAGIC_NO_COMPRESS_START1 == magic_start or MAGIC_NO_COMPRESS_NO_CRYPT_START == magic_start or MAGIC_COMPRESS_NO_CRYPT_START == magic_start:crypt_key_len=64else:_outbuffer.extend(inDecodeBuffer _buffer[%d]:%d != MAGIC_NUM_START % (_offset, magic_start))return-1headerLen=1 + 2 + 1 + 1 + 4 + crypt_key_lenstart=_offset + headerLen - 4 - crypt_key_lenlength=struct.unpack_from("I", memoryview(_buffer)[start:start + 4])[0]tmpbuffer=bytearray(length)seq=struct.unpack_from("H", memoryview(_buffer)[start - 2 - 2: start - 2])[0]begin_hour=struct.unpack_from("c", memoryview(_buffer)[start - 1 - 1:start - 1])[0]end_hour=struct.unpack_from("c", memoryview(_buffer)[start - 1:start])[0]globallastseqifseq != 0 and seq != 1 and lastseq != 0 and seq != (lastseq + 1):_outbuffer.extend("[F]decode_log_file.pylog seq:%d-%d is missingn" % (lastseq + 1, seq - 1))ifseq != 0:lastseq=seqtmpbuffer[:] = _buffer[_offset + headerLen:_offset + headerLen + length]try:decompressor=zlib.decompressobj(-zlib.MAX_WBITS)ifMAGIC_NO_COMPRESS_START1 == _buffer[_offset] or MAGIC_COMPRESS_START2 == _buffer[_offset]:print("usewrong decode script")elifMAGIC_COMPRESS_START == _buffer[_offset] or MAGIC_COMPRESS_NO_CRYPT_START == _buffer[_offset]:tmpbuffer=decompressor.decompress(bytes(tmpbuffer))elifMAGIC_COMPRESS_START1 == _buffer[_offset]:decompress_data=bytearray()whilelen(tmpbuffer) > 0:single_log_len=struct.unpack_from("H", memoryview(tmpbuffer)[0:2])[0]decompress_data.extend(tmpbuffer[2:single_log_len + 2])tmpbuffer[:] = tmpbuffer[single_log_len + 2:len(tmpbuffer)]tmpbuffer=decompressor.decompress(str(decompress_data))else:pass_outbuffer.extend(seq:%d, hour:%d-%d len:%d decompress:%dn %(seq, ord(begin_hour), ord(end_hour), length, len(tmpbuffer)))exceptException as e:traceback.print_exc()_outbuffer.extend("[F]decode_log_file.pydecompress err, " + str(e) + "n")return_offset + headerLen + length + 1_outbuffer.extend(tmpbuffer)return_offset + headerLen + length + 1defParseFile(_file, _outfile):fp=open(_file, "rb")_buffer=bytearray(os.path.getsize(_file))fp.readinto(_buffer)fp.close()startpos=GetLogStartPos(_buffer, 2)if-1 == startpos:returnoutbuffer=bytearray()whileTrue:startpos=DecodeBuffer(_buffer, startpos, outbuffer)if-1 == startpos: break;if0 == len(outbuffer): returnfpout=open(_outfile, "wb")fpout.write(outbuffer)fpout.close()defmain(args):globallastseqif1 == len(args):ifos.path.isdir(args[0]):filelist=glob.glob(args[0] + "/*.xlog")forfilepath in filelist:lastseq=0ParseFile(filepath,filepath + ".log")else:ParseFile(args[0],args[0] + ".log")elif2 == len(args):ParseFile(args[0],args[1])else:filelist=glob.glob("*.xlog")forfilepath in filelist:lastseq=0ParseFile(filepath,filepath + ".log")if__name__ == "__main__":main(sys.argv[1:])改的思路其实也很简单,用python3执行,哪里报错改哪里,主要是buffer()方法在python3中没有了,换了一个方法。
这个是我修改后文件(decode_mars_nocrypt_log_file.py)的地址:https://www.aliyundrive.com/s/CTiyzYJWjVK
解码的具体操作就是直接执行,将xlog文件作为参数传入:
pythondecode_mars_nocrypt_log_file.pydbxLog_20220514.xlog对于加密的xlog进行解码
mars已经提供了加密的工具:gen_key.py,直接执行就可以获取一组随机的公钥、私钥:
通过gen_key.py获取的密钥
在Android代码中初始化xlog的时候,将公钥传递给指定参数,输出的日志就会进行加密:
Xlog.open(false, Xlog.LEVEL_DEBUG, Xlog.AppednerModeAsync,"", logPath,"dbxLog","68f0b7d5c8a792e1ea94cfc5aaad0db0840282e2b8f5a82f369a996f681c6cd1292f2d6d06712eaf735459584819c4fa71b94f2d9bd53837782ea35aef52ef35");解码解密的工具是这个:decode_mars_crypt_log_file.py,mars也有提供,不过不能直接使用,需要将里面的密钥需要进行修改:
更新密钥
需要注意mars提供的这个工具,也是需要python2执行。我有修改成python3的,如果有需要可以看一下:
!/usr/bin/pythonimportsysimportosimportglobimportzlibimportstructimportbinasciiimportpyellipticimporttracebackMAGIC_NO_COMPRESS_START=0x03MAGIC_NO_COMPRESS_START1=0x06MAGIC_NO_COMPRESS_NO_CRYPT_START=0x08MAGIC_COMPRESS_START=0x04MAGIC_COMPRESS_START1=0x05MAGIC_COMPRESS_START2=0x07MAGIC_COMPRESS_NO_CRYPT_START=0x09MAGIC_END=0x00lastseq=0PRIV_KEY=bbabff40958d0346b8c602dff415e082e94ed5872903ed0ea2a3b198cd3e5d454PUB_KEY=b68f0b7d5c8a792e1ea94cfc5aaad0db0840282e2b8f5a82f369a996f681c6cd1b292f2d6d06712eaf735459584819c4fa71b94f2d9bd53837782ea35aef52ef35deftea_decipher(v, k):op=0xffffffffv0,v1 = struct.unpack(=LL, v[0:8])k1,k2, k3, k4 = struct.unpack(=LLLL, k[0:16])delta=0x9E3779B9s=(delta << 4) & opfori in range(16):v1=(v1 - (((v0 << 4) + k3) ^ (v0 + s) ^ ((v0 >> 5) + k4))) & opv0=(v0 - (((v1 << 4) + k1) ^ (v1 + s) ^ ((v1 >> 5) + k2))) & ops=(s - delta) & opreturnstruct.pack(=LL, v0, v1)deftea_decrypt(v, k):num=int(len(v) / 8 * 8)ret=bfori in range(0, num, 8):vi=v[i:i + 8]iflen(vi) != 8:continuex=tea_decipher(vi, k)ret+= xret+= v[num:]returnretdefIsGoodLogBuffer(_buffer, _offset, count):if_offset == len(_buffer): return (True, )magic_start=_buffer[_offset]ifMAGIC_NO_COMPRESS_START == magic_start or MAGIC_COMPRESS_START == magic_start or MAGIC_COMPRESS_START1 == magic_start:crypt_key_len=4elifMAGIC_COMPRESS_START2 == magic_start or MAGIC_NO_COMPRESS_START1 == magic_start or MAGIC_NO_COMPRESS_NO_CRYPT_START == magic_start or MAGIC_COMPRESS_NO_CRYPT_START == magic_start:crypt_key_len=64else:returnFalse, _buffer[%d]:%d != MAGIC_NUM_START % (_offset, _buffer[_offset])headerLen=1 + 2 + 1 + 1 + 4 + crypt_key_lenif_offset + headerLen + 1 + 1 > len(_buffer):returnFalse, offset:%d > len(buffer):%d % (_offset, len(_buffer))start=_offset + headerLen - 4 - crypt_key_lenlength=struct.unpack_from("I", memoryview(_buffer)[start:start + 4])[0]if_offset + headerLen + length + 1 > len(_buffer):returnFalse, log length:%d, end pos %d > len(buffer):%d % (length,_offset + headerLen + length + 1, len(_buffer))ifMAGIC_END != _buffer[_offset + headerLen + length]:returnFalse, log length:%d, buffer[%d]:%d != MAGIC_END % (length,_offset + headerLen + length, _buffer[_offset + headerLen + length])if(1 >= count):return(True, )else:returnIsGoodLogBuffer(_buffer, _offset + headerLen + length + 1, count - 1)defGetLogStartPos(_buffer, _count):offset=0whileTrue:ifoffset >= len(_buffer): breakifMAGIC_NO_COMPRESS_START == _buffer[offset] or MAGIC_NO_COMPRESS_START1 == _buffer[offset]or MAGIC_COMPRESS_START == _buffer[offset] or MAGIC_COMPRESS_START1 == _buffer[offset]or MAGIC_COMPRESS_START2 == _buffer[offset] or MAGIC_COMPRESS_NO_CRYPT_START == _buffer[offset]or MAGIC_NO_COMPRESS_NO_CRYPT_START == _buffer[offset]:ifIsGoodLogBuffer(_buffer, offset, _count)[0]: return offsetoffset+= 1return-1defDecodeBuffer(_buffer, _offset, _outbuffer):if_offset >= len(_buffer):return-1if _offset + 1 + 4 + 1 + 1 > len(_buffer): return -1ret=IsGoodLogBuffer(_buffer, _offset, 1)ifnot ret[0]:fixpos=GetLogStartPos(_buffer[_offset:], 1)if-1 == fixpos:return-1else:_outbuffer.extend("[F]decode_log_file.pydecode error len=%d, result:%s n" % (fixpos, ret[1]))_offset+= fixposmagic_start=_buffer[_offset]ifMAGIC_NO_COMPRESS_START == magic_start or MAGIC_COMPRESS_START == magic_start or MAGIC_COMPRESS_START1 == magic_start:crypt_key_len=4elifMAGIC_COMPRESS_START2 == magic_start or MAGIC_NO_COMPRESS_START1 == magic_start or MAGIC_NO_COMPRESS_NO_CRYPT_START == magic_start or MAGIC_COMPRESS_NO_CRYPT_START == magic_start:crypt_key_len=64else:_outbuffer.extend(inDecodeBuffer _buffer[%d]:%d != MAGIC_NUM_START % (_offset, magic_start))return-1headerLen=1 + 2 + 1 + 1 + 4 + crypt_key_lenstart=_offset + headerLen - 4 - crypt_key_lenlength=struct.unpack_from("I", memoryview(_buffer)[start: start + 4])[0]tmpbuffer=bytearray(length)seq=struct.unpack_from("H", memoryview(_buffer)[start - 2 - 2:start - 2])[0]begin_hour=struct.unpack_from("c", memoryview(_buffer)[start - 1 - 1:start - 1])[0]end_hour=struct.unpack_from("c", memoryview(_buffer)[start - 1:start])[0]globallastseqifseq != 0 and seq != 1 and lastseq != 0 and seq != (lastseq + 1):_outbuffer.extend("[F]decode_log_file.pylog seq:%d-%d is missingn" % (lastseq + 1, seq - 1))ifseq != 0:lastseq=seqtmpbuffer[:] = _buffer[_offset + headerLen:_offset + headerLen + length]try:decompressor=zlib.decompressobj(-zlib.MAX_WBITS)ifMAGIC_NO_COMPRESS_START1 == _buffer[_offset]:passelifMAGIC_COMPRESS_START2 == _buffer[_offset]:svr=pyelliptic.ECC(curve=secp256k1)client=pyelliptic.ECC(curve=secp256k1)start=_offset + headerLen - crypt_key_lenclient.pubkey_x=memoryview(_buffer)[start:int(start + crypt_key_len / 2)].tobytes()client.pubkey_y=memoryview(_buffer)[int(start + crypt_key_len / 2):start + crypt_key_len].tobytes()svr.privkey=binascii.unhexlify(PRIV_KEY)tea_key=svr.get_ecdh_key(client.get_pubkey())tmpbuffer=tea_decrypt(tmpbuffer, tea_key)tmpbuffer=decompressor.decompress(bytes(tmpbuffer))elifMAGIC_COMPRESS_START == _buffer[_offset] or MAGIC_COMPRESS_NO_CRYPT_START == _buffer[_offset]:tmpbuffer=decompressor.decompress(bytes(tmpbuffer))elifMAGIC_COMPRESS_START1 == _buffer[_offset]:decompress_data=bytearray()whilelen(tmpbuffer) > 0:single_log_len=struct.unpack_from("H", memoryview(tmpbuffer)[0:2])[0]decompress_data.extend(tmpbuffer[2:single_log_len + 2])tmpbuffer[:] = tmpbuffer[single_log_len + 2:len(tmpbuffer)]tmpbuffer=decompressor.decompress(str(decompress_data))else:pass_outbuffer.extend(seq:%d, hour:%d-%d len:%d decompress:%dn %(seq, ord(begin_hour), ord(end_hour), length, len(tmpbuffer)))exceptException as e:traceback.print_exc()_outbuffer.extend("[F]decode_log_file.pydecompress err, " + str(e) + "n")return_offset + headerLen + length + 1_outbuffer.extend(tmpbuffer)return_offset + headerLen + length + 1defParseFile(_file, _outfile):fp=open(_file, "rb")_buffer=bytearray(os.path.getsize(_file))fp.readinto(_buffer)fp.close()startpos=GetLogStartPos(_buffer, 2)if-1 == startpos:returnoutbuffer=bytearray()whileTrue:startpos=DecodeBuffer(_buffer, startpos, outbuffer)if-1 == startpos:breakif0 == len(outbuffer):returnfpout=open(_outfile, "wb")fpout.write(outbuffer)fpout.close()defmain(args):globallastseqif1 == len(args):ifos.path.isdir(args[0]):filelist=glob.glob(args[0] + "/*.xlog")forfilepath in filelist:lastseq=0ParseFile(filepath,filepath + ".log")else:ParseFile(args[0],args[0] + ".log")elif2 == len(args):ParseFile(args[0],args[1])else:filelist=glob.glob("*.xlog")forfilepath in filelist:lastseq=0ParseFile(filepath,filepath + ".log")if__name__ == "__main__":main(sys.argv[1:])这个是我修改后文件(decode_mars_crypt_log_file.py)的地址:https://www.aliyundrive.com/s/oUGormRrEBa
使用方式也是一样的:
pythondecode_mars_crypt_log_file.pydbxLog_20220514.xlog免责声明:内容来自用户上传并发布,站点仅提供信息存储空间服务,不拥有所有权,本网站所提供的信息只供参考之用。