微信读书本地文件加密分析
前言
仅供交流学习
加密分析
拿一台已经root了的机子找到/data/user/0/com.tencent.weread/databases/<用户ID>/books/
下,这里存在已经下载到本地的书籍
下面存在几个目录,目录的名字一般都是数字,目录下有许多文件后缀为.res
或.st
或.ts.a
的文件
.res
后缀的文件以压缩文件打开提示需要密码
jadx中查找这个后缀名,可以找到getDownloadPath
方法, 寻找引用观察到一个getCanonicalPath
方法,继续查找引用可以发现一个来自readDataFormDisk
的调用
该方法中校验了文件的魔数,这个就是读取文件的方法
继续寻找引用,发现covertChapterToHtml
方法,
看到下面的unzip方法,可知这里是解压缩的地方
定位到该方法的unzipResponse
调用中
看到解压密码是传入的第二个参数,也就是dataFormDisk
中
可以看到这个
byteArray
从文件中读取,又进行了EncryptUtils
中的处理
EncryptUtils
中的方法如下:
这里提供了两个参数,用户ID和加密后的内容,而后调用了nativeDecryptHeaderKey
,是native方法,到IDA中查看对应的so文件
关键逻辑如下:
以上是将vid补全到32位,接下来,根据程序内置的表映射了vid的每一位
这里实际上传入的是byte,识别为指针是ida的识别错误,对应表如下:
下面的解密调用:
注意到这里没有传入IV,观察解密函数
下面调用了openssl
的AES解密函数,根据公开的函数定义,倒数第二个参数是iv
这里IDA将key的定义类型识别为了unsigned __int8 *
,所以iv被反编译为key+1
,实际上指向的是后16字节。而前16字节在AES_set_decrypt_key
中被作为key使用
手工解密
回顾readDataFormDisk
方法
第一次读取4字节魔数,然后再读取4字节作为循环次数,然后依据循环次数读取多个4字节,在这之后读取了4字节作为readByteArray
的参数,这也是加密后的密码。
根据so中的解密逻辑,写出映射脚本:
随后我们输出,便得到了key和iv,前16字节为key,后16字节为iv
CyberChef中AES解密一下即可得到解压密码
(完)