平方X

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 3045|回复: 0

备份安卓微信聊天记录及加密方式研究

[复制链接]

414

主题

709

帖子

3602

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3602
QQ
发表于 2017-9-17 20:58:08 | 显示全部楼层 |阅读模式
[md]
>本文由平方X发表于平方X网,转载请注明出处。[http://blog.pingfangx.com/2369.html](http://blog.pingfangx.com/2369.html)

# 0x00 需求
我有一个小米手机MI2s,还有一个米5。好像在某一次迁移还是刷机过程中,数据丢失了,想要恢复到一起。

# 0x01 官方的备分与恢复
官方用电脑与手机wifi连接,进行备份,备份速度约2M/S。

# 0x02 静态方式破解
很久以前在csdn看到的一篇文章,一直留着看,今天在收藏夹里一搜,居然没找到,吓我一跳,还好又在网止搜了回来。  
[尼古拉斯_赵四.《 Android逆向之旅---静态方式破解微信获取聊天记录和通讯录信息》](http://blog.csdn.net/jiangwei0910410003/article/details/52238891)  

## 2.1 导出数据库
adb pull /data/data/com.tencent.mm/MicroMsg/847c648f740954a4a7c6023b2305e874/EnMicroMsg.db D:/adb  
后面那一串是MD5("mm"+uin)  
来源于[y788iiiiii](http://blog.csdn.net/y788iiiiii) 回复于 [博文6楼](http://blog.csdn.net/yuanbohx/article/details/41674949)  

## 2.2 读取源码
在博客中已经有了步骤,只是有些类变化了,自已跟着学习了一遍。
```
com.tencent.wcdb.database.SQLiteDatabase

    public static SQLiteDatabase openDatabase(String str, byte[] bArr, SQLiteCipherSpec sQLiteCipherSpec, CursorFactory cursorFactory, int i, DatabaseErrorHandler databaseErrorHandler, int i2) {
        SQLiteDatabase sQLiteDatabase = new SQLiteDatabase(str, i, cursorFactory, databaseErrorHandler);
        sQLiteDatabase.open(bArr, sQLiteCipherSpec, i2);
        return sQLiteDatabase;
    }
    private void openInner(byte[] bArr, SQLiteCipherSpec sQLiteCipherSpec, int i)

    public static SQLiteConnectionPool open(SQLiteDatabase sQLiteDatabase, SQLiteDatabaseConfiguration sQLiteDatabaseConfiguration, byte[] bArr, SQLiteCipherSpec sQLiteCipherSpec, int i) {
        if (sQLiteDatabaseConfiguration == null) {
            throw new IllegalArgumentException("configuration must not be null.");
        }
        SQLiteConnectionPool sQLiteConnectionPool = new SQLiteConnectionPool(sQLiteDatabase, sQLiteDatabaseConfiguration, i);
        sQLiteConnectionPool.mPassword = bArr;
        sQLiteConnectionPool.mCipher = sQLiteCipherSpec == null ? null : new SQLiteCipherSpec(sQLiteCipherSpec);
        sQLiteConnectionPool.open();
        return sQLiteConnectionPool;
    }

带密码打开数据库的方法搜索
Lcom/tencent/wcdb/database/SQLiteDatabase;->openDatabase(Ljava/lang/String;[BL

定位到com\tencent\mm\bj\e.smali
public static e r(String str, String str2, boolean z)

str2是密码
搜索该方法得
                    this.uJJ = e.r(str, this.arH, z);

arH是密码,看赋值
    private boolean a(String str, long j, String str2, boolean z, String str3) {
        ...
        this.arH = g.n((str2 + j).getBytes()).substring(0, 7);
        ...
    }
g.n()方法是md5,看a方法

public final boolean a(String str, String str2, String str3, long j, String str4, HashMap<Integer, g.c> hashMap, boolean z) {
    ...
        this.uJL = a(str2, j, str4, e.bNC(), str3);
    ...
}
需要的是str4和j

    public final boolean a(String str, String str2, String str3, long j, String str4, HashMap<Integer, c> hashMap, boolean z) {
        ...
        if (!this.uKi.a(str, str2, str3, j, str4, hashMap, z) || this.uKi.uJJ == null) {
        ...
    }
需要的是str4和j

            if (vI.gXW.a(str, str2, str3, (long) uH, p.rA(), vI.uh(), true)) {
需要的是p.rA()和uH

先看p.rA()
    public static String rA() {
        GMTrace.i(13801340534784L, 102828);
        String str = (String) k.rj().get(258);
        if (str != null) {
            GMTrace.o(13801340534784L, 102828);
        } else {
            str = getDeviceID(aa.getContext());
            if (str == null) {
                str = "1234567890ABCDEF";
            }
            k.rj().set(258, str);
            GMTrace.o(13801340534784L, 102828);
        }
        return str;
    }

再看uH
        int uH = gWW.uH();

        public final int uH() {
            int i;
            synchronized (this) {
                GMTrace.i(13525388886016L, 100772);
                if (!this.gXo) {
                    va();
                    this.gXo = true;
                }
                i = this.uin;
                GMTrace.o(13525388886016L, 100772);
            }
            return i;
        }

uin的赋值
这个是默认值,可以看到获取的是default_uin
private void va() {
    ...

                if (sVar == null) {
                    com.tencent.mm.sdk.platformtools.v.w("MMKernel.CoreAccount", "summer read detault uin exception sysCfg is null!");
                } else {
                    Integer num = (Integer) sVar.get(1);
                    if (num == null) {
                        if (sVar.uxm) {
                            com.tencent.mm.plugin.report.c.oRz.a(148, 40, 1, false);
                        }
                        Integer valueOf = Integer.valueOf(aa.getContext().getSharedPreferences("system_config_prefs", 4).getInt("default_uin", 0));
                        if (valueOf != null) {
                            com.tencent.mm.sdk.platformtools.v.i("MMKernel.CoreAccount", "summer read detault uin[%d], bakUin[%d] sysCfg.isOpenException[%b]", num, valueOf, Boolean.valueOf(sVar.uxm));
                            if (gXq) {
                                com.tencent.mm.sdk.platformtools.v.w("MMKernel.CoreAccount", "summer read detault uin exception backup uin[%d], stack[%s]", valueOf, bf.bJP());
                                com.tencent.mm.plugin.report.c.oRz.i(11911, Integer.valueOf(bf.f(valueOf)));
                                gXq = false;
                            }
                            a(sVar, valueOf.intValue());
                            num = valueOf;
                        }
                    }
                    com.tencent.mm.sdk.platformtools.v.i("MMKernel.CoreAccount", "summer getDefaultUin uin[%d]", Integer.valueOf(bf.f(num)));
                    i = bf.f(num);
                }
                this.uin = i;

    ...
}
但是追_auth_uin的时候,怎么也追不到,好复杂的样子。最后就放弃了。


```
结论:
并没有发生变化,和原博文的一致。
>概要:微信的核心数据库是EnMicroMsg.db,但是是加密操作的,而加密的密码是设备的IMEI+用户的UIN值(在SP中保存了),计算MD5(字符是小写),取出前7位字符即可。

## 2.3 工具选择
jdgui、jeb、jadx


# 0x03 查看
获取到了密码,在读取数据库的时候,却还是失败的。  
难道是我密码计算错了,写安卓代码算了一下,没错呀。  
看到有人回复  
http://blog.csdn.net/yuanbohx/article/details/41674949,32楼  
八只爪
>(IMEI+UIN)计算出的MD5值的前7位,和我在手机里安装的“微信加密聊天记录导出"软件不一致。。。手机安装的软件计算出来的数据库密码才是正确的,原因不太清楚……至于sqlite怎么导出查找到的数据,在研究中……

于是我就网上找他所说的“微信加密聊天记录导出”,结果下了一个电脑版,要收费,只能看7条,又下了一个查看器,要2个csdn积分……  
这个技术……是自己的吗……居然要收费,唉。  
好在兑换了2积分,下载后,那个sqlcipher.exe是可以使用的,原来是我的软件不正确。
[/md]
我是平方X~
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|手机版|Archiver|平方X ( 冀ICP备14018164号 )

GMT+8, 2024-4-23 19:08 , Processed in 0.093737 second(s), 21 queries .

技术支持:Powered by Discuz!X3.4  © 2001-2013 Comsenz Inc.

版权所有:Copyright © 2014-2018 平方X www.pingfangx.com All rights reserved.

快速回复 返回顶部 返回列表