DexClassLoader解析微信朋友圈数据库

DexClassLoader解析微信朋友圈数据库

前提

当我们拿到微信的朋友圈数据库的时候,我们能够直接打开,这个数据库并没有像EnMicroMsg数据库一样采用了加密方式。但是当我们想要获取其内容的时候,发现content和attrBuf加密了,这是个Blob型的字段,虽然我们可以直接用String(contentBlob) 的方式拿到字符串,但是显示的内容夹杂了许多乱码。如下图所示:
发送一个纯文本朋友圈,且内容为:hello
如图
可以看到图上白圈内就是hello的字段,且还有我的微信号
为了找到解密方法,我查了一些资料,这里分享一个很好的文章,然后此文章也是因此而派生出来的~

https://www.jianshu.com/p/0704e0d58531

工具

root手机一部

DexClassLoader

打开上面的那个链接,翻到最后面,作者有列出两种方式来解析数据,而本文的主题就是使用DexClassLoader来解析数据,所以接下来以此来进行探究吧~

我们先来看看DexClassLoader的构造方法,把需要实例化该类的参数了解一下。

    public DexClassLoader(String dexPath, String optioptimizedmizedDirectory, String librarySearchPath, ClassLoader parent)

dexPath: 需要载入的apk文件的位置,在本文中需要指向微信apk的位置。
optioptimizedmizedDirectory: 这个目录是apk的解压路径。
librarySearchPath: 目标类可能使用的c或者c++的库文件的存放路径。
parent: 就是一个ClassLoader对象了。

接下来我们就一步一步操作吧。

  1. 先找到微信apk的路径
    微信的apk是存放在 /data/app/ 目录下 com.tencent.mm+随机字符的文件夹中,那么我们就先写一个方法(由于方法简单就不展示),来遍历 /data/app/ 目录下包含com.tencent.mm字符的目录,再指到该目录下base.apk。
  2. 实例化DexClassLoader
    通过第1步,我们已经拿到微信apk的路径,那么我们就直接使用吧:
 val dexClassLoader = DexClassLoader(
                        wxApkFile.absolutePath,
                        context.getDir("dex1", 0).absolutePath, 
                        null,
                        context.classLoader
                    )
  1. 加载TimeLineObject类
    根据上面的文章,我们可以知道,微信是通过TimeLineObject这个类,来解析content的,那么我们就直接加载该类,并且调用其parseFrom(byte[])方法
 val timeLineObjects = dexClassLoader.loadClass("com.tencent.mm.protocal.protobuf.TimeLineObject")
 val parseMeths = timeLineObjects.getMethod("parseFrom", ByteArray::class.java)
 //contentBlob是从数据库中直接获取!
 val parsedObj = parseMeths.invoke(timeLineObjects.newInstance(), contentBlob)
  1. 无脑的翻代码
    使用jadx工具解析微信的apk,我们查看timeLineObjects这个类,他里面的字段有String、int和其他类类型的属性,其实我们现在就可以直接通过反射的方式来获取其字段的值,不过先等等,因为我发现一个特点:那就是timeLineObjects的其他字段类型(不包括String和int)和timeLineObjects一样,都是继承自一个
	import com.tencent.mm.bt.a

当我们打开这个类,一下子就恍然大悟了!
该类中包含一个parseFrom(bye[])方法,我推测:所有继承该类的派生类都相当于是一个能够加密的储存数据的bean类
那么我们就直接创建一个递归方法来遍历该类,找到能够展示数据的字段吧


    fun findAllDisplayData(obj: Any, map: HashMap<String, String>) {
        val fields = obj.javaClass.fields
        if (fields.isEmpty()) {
            return
        }
        fields.forEach {
        	//使用下方Log,可以获取所有字段的类型
            //Log.e("===>SnsType", "===>${it.type.name}")
            when (it.type.name) {
            	//获取String类型的字段
                "java.lang.String" -> {
                    val valueObj = it.get(obj)
                    if (valueObj != null) {
                        map["${obj.hashCode()}" + it.name] = valueObj as String
                    }
                }
                "long",
                "float",
                "boolean",
                "java.lang.Boolean",
                "int" -> {
                    val valueObj = it.get(obj)
                    if (valueObj != null) {
                        map["${obj.hashCode()}" + it.name] = valueObj.toString()
                    }
                }
                "java.util.LinkedList" -> {
                    Log.e("===>SnsDeFind", "卧槽!这是个LinkedList")
                    val valueObj = it.get(obj)
                    if (valueObj != null) {
                        val list = valueObj as LinkedList<*>
                        list.forEach { item ->
                            findAllStringAndInt(item, map)
                        }
                    }
                }
                else -> {
                    val valueObj = it.get(obj)
                    if (valueObj != null) {
                        findAllStringAndInt(valueObj, map)
                    }
                }
            }
        }
    }

当我们打印map中的数据的时候,还真就获取到了一些有用的数据~
在这里插入图片描述

扩展

以上就是SnsMicroMsg数据库中SnsInfo表中content字段的解析。
但是当我们想再次以同样的方式解析attrBuf的时候,却出错了。 于是我很快的翻阅微信源码,查找关键字段:attrBuf
在这里插入图片描述
如上图红框的内容,看到了很熟悉的方法,但是却是不同的类来调用,根据上面的推测,这个类极有可能是继承自com.tencent.mm.bt.a,所以赶紧找到该类:
在这里插入图片描述
果然是继承 com.tencent.mm.bt.a!!,那么要解析attrBuf字段的话,就使用dexClassloader来加载这个cbf的类,使用该类调用parseFrom(byte[])方法就能够拿到attrBuf中的数据了!

### PyCharm 打开文件显示不全的解决方案 当遇到PyCharm打开文件显示不全的情况时,可以尝试以下几种方法来解决问题。 #### 方法一:清理缓存并重启IDE 有时IDE内部缓存可能导致文件加载异常。通过清除缓存再启动程序能够有效改善此状况。具体操作路径为`File -> Invalidate Caches / Restart...`,之后按照提示完成相应动作即可[^1]。 #### 方法二:调整编辑器字体设置 如果是因为字体原因造成的内容显示问题,则可以通过修改编辑区内的文字样式来进行修复。进入`Settings/Preferences | Editor | Font`选项卡内更改合适的字号大小以及启用抗锯齿功能等参数配置[^2]。 #### 方法三:检查项目结构配置 对于某些特定场景下的源码视图缺失现象,可能是由于当前工作空间未能正确识别全部模块所引起。此时应该核查Project Structure里的Content Roots设定项是否涵盖了整个工程根目录;必要时可手动添加遗漏部分,并保存变更生效[^3]。 ```python # 示例代码用于展示如何获取当前项目的根路径,在实际应用中可根据需求调用该函数辅助排查问题 import os def get_project_root(): current_file = os.path.abspath(__file__) project_dir = os.path.dirname(current_file) while not os.path.exists(os.path.join(project_dir, '.idea')): parent_dir = os.path.dirname(project_dir) if parent_dir == project_dir: break project_dir = parent_dir return project_dir print(f"Current Project Root Directory is {get_project_root()}") ```
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值