Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

小米手机提取微信聊天记录数据库 #1

Open
Heyxk opened this issue Jan 12, 2019 · 14 comments
Open

小米手机提取微信聊天记录数据库 #1

Heyxk opened this issue Jan 12, 2019 · 14 comments

Comments

@Heyxk
Copy link
Owner

Heyxk commented Jan 12, 2019

小米6提取微信聊天记录笔记

通过MI6本地备份提取聊天记录

要导出微信安卓客户端的聊天记录,首先得找到聊天记录的数据库。
安卓客户端的聊天记录储存在私有目录 /data/data/com.tencent.mm/MicroMsg 下,这个目录需要root权限才能进去,但是,那样太太太麻烦了,好在我们MI6有本地备份的功能,利用这个功能。我们轻而易举就可以获得数据库。

需要的工具

此处下载

环境

需要安装Java环境,未安装可以搜索Java安装

提取数据库

  1. 首先到手机:设置->更多设置->备份和重置->本地备份 里面点击新建备份,选择软件程序中的微信进行备份

  2. 然后到文件管理 /内部储存设备/MIUI/backup/ALLBackup/ 下将备份的文件夹复制到电脑

  3. 接下来是从备份的文件中提取微信聊天记录,通过WinHex软件查看备份包信息,发现miui备份包是在原生安卓的备份基础上多加了一个文件头。选中多余的文件头,按delete键删除,点击保存。修改后的文件就是标准的原生安卓备份文件。

  4. 接下来,将修改后的com.tencent.mm.bak 处理成原文件,首先将abe.jar复制到和com.tencent.mm.bak同一个文件夹下
    终端执行:

java -jar abe.jar unpack com.tencent.mm.bak mm.tar

会生成一个mm.tar文件,用解压软件将这个包解压,会得到一个apps文件夹,apps文件夹下面有com.tencent.mm文件夹,聊天记录数据库就存在apps/com.tencent.mm/r/MicroMsg/ 下,打开文件夹会发现里面有32位字符(MD5值)的文件夹(登录过多个用户的有多个),打开此文件夹其中EnMicroMsg.db就是要找的数据库文件。

生成数据库密码

找到聊天数据库了,但是目前还不能得到聊天记录,因为这个数据库是sqlcipher加密数据库,需要密码才能打开。

数据库密码有很多种生成方式:

  1. 手机IMEI+uin(微信用户id userinformation) 将拼接的字符串MD5加密取前7位

    IMEI123456uinabc,则拼接后的字符串为123456abc 将此字符串用MD5加密(32位)后

    df10ef8509dc176d733d59549e7dbfaf 那么前7位df10ef8 就是数据库的密码,由于有的手机是双卡,有多个IMEI,或者当手机获取不到IMEI时会用默认字符串1234567890ABCDEF来代替,由于种种原因,并不是所有人都能得出正确的密码,此时我们可以换一种方法。

  2. 反序列化CompatibleInfo.cfgsystemInfo.cfg

    不管是否有多个IMEI ,或者是微信客户端没有获取到IMEI,而使用默认字符串代替,微信客户端都会将使用的信息保存在MicroMsg文件夹下面的CompatibleInfo.cfgsystemInfo.cfg文件中,可以通过这两个文件来得到正确的密码,但是这两个文件需要处理才能看到信息。

  3. 使用hook方式得到数据库的密码,这个方法最有效参考

  4. 暴力破解

...

使用反序列化的方式获得密码

由于我的手机有多个IMEI码,试了半天出来的密码都不对,故使用此方法来得到密码。
首先将CompatibleInfo.cfgsystemInfo.cfg以及EnMicroMsg.db复制出来,将下面这段代码保存到IMEI.java文件

import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.security.MessageDigest;
import java.util.HashMap;
public class IMEI {
 public static void main(String[] args) {
  try {
   ObjectInputStream in = new ObjectInputStream(new FileInputStream(
     args[0]));
   Object DL = in.readObject();
   HashMap hashWithOutFormat = (HashMap) DL;
   ObjectInputStream in1 = new ObjectInputStream(new FileInputStream(
     args[1]));
   Object DJ = in1.readObject();
   HashMap hashWithOutFormat1 = (HashMap) DJ;
   String s = String.valueOf(hashWithOutFormat1.get(Integer
     .valueOf(258))); // 取手机的IMEI
   System.out.println("The IMEI is : " + s);
   String uin = String.valueOf(hashWithOutFormat.get(Integer.valueOf(1)));
   System.out.println("The uin is : " + uin);
   s = s + uin; //合并到一个字符串
   s = encode(s); // hash
   System.out.println("The Key is : " + s.substring(0, 7));
   in.close();
   in1.close();
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
 public static String encode(String content)
  {
   try {
    MessageDigest digest = MessageDigest.getInstance("MD5");
    digest.update(content.getBytes());
    return getEncode32(digest);
    }
   catch (Exception e)
   {
    e.printStackTrace();
   }
   return null;
  }
  private static String getEncode32(MessageDigest digest)
  {
   StringBuilder builder = new StringBuilder();
   for (byte b : digest.digest())
   {
    builder.append(Integer.toHexString((b >> 4) & 0xf));
    builder.append(Integer.toHexString(b & 0xf));
   }
    return builder.toString();

  }
}

将这段代码保存到IMEI.java文件,将三个文件放在相同目录下
终端运行

javac IMEI.java
java IMEI systemInfo.cfg CompatibleInfo.cfg

运行完成后就会得到密码
参考链接

解密数据库

Windows用户可以使用sqlcipher.exe软件来查看数据库
打开数据库,输入密码,就可以查看数据库中的表
文字聊天记录储存在message表中,可以选中表,点击软件的右上角file-export导出表到csv文件,可以通过Excell查看表中的信息
执行这段命令可以查看制定对象的聊天记录

select datetime(subStr(cast(m.createTime as text),1,10),'unixepoch', 'localtime') as theTime,case m.isSend when 0 then r.nickname when 1 then ''end as person,m.content from message m inner join rcontact r on m.talker = r.username where m.type=1 and r.nickname = '对方微信昵称'

Linux用户可以使用sqlcipher来解密

sudo apt-get update

sudo apt-get install sqlcipher

sqlcipher EnMicroMsg.db 'PRAGMA key = "yourkey"; PRAGMA cipher_use_hmac = off; PRAGMA kdf_iter = 4000; ATTACH DATABASE "decrypted_database.db" AS decrypted_database KEY "";SELECT sqlcipher_export("decrypted_database");DETACH DATABASE decrypted_database;' 

执行上面的命令之后会得到一个解密后的数据库decrypted_database.db,可以使用数据库软件查看

得到数据库之后可以分析一下你的聊天记录,顺便制作一个词云来给你的心上人看一下你们都聊了啥:eyes:

看了一下我和女票日消息数走势,最多一天竟然发了809条:joy:

@gitgitss
Copy link

命令行获取的IMEI为null是什么原因呀

@chshcq
Copy link

chshcq commented Nov 16, 2019

我也是有这个null的问题,看了下手机有两个imei,尝试用了第一个imei 加上uid 做一个md5的hash,前七位就是密码

@yhm2046
Copy link

yhm2046 commented Dec 11, 2019

C:\wechat>java IMEI systemInfo.cfg CompatibleInfo.cfg
错误: 找不到或无法加载主类 IMEI

这个是什么问题??急求

@chshcq
Copy link

chshcq commented Dec 11, 2019

先不要急,不过我不太了解这个中文错误码对应的英文是什么,应该不是null

@chshcq
Copy link

chshcq commented Dec 11, 2019

你能确认一下你 IMEI.java 健全?

@yhm2046
Copy link

yhm2046 commented Dec 19, 2019

你能确认一下你 IMEI.java 健全?

我试过几次不行就换其他方法了,使用iemi少一位加uin取MD5 加密32位小写前面七位解出了密码:)

@Heyxk Heyxk closed this as completed Mar 19, 2020
@Heyxk Heyxk reopened this Mar 19, 2020
@gitgitss
Copy link

如果他获取的IMEI是null 那他下面算md5就会用null这4个字母

@linxingwu
Copy link

我和你的完全不一样,我miui 10 开发版,备份出来的bak文件完全就是一个压缩包,可以直接winrar查看,并没有app这个目录,直接就是com.tencent.mm/r,r下面也没有MicroMsg.

@fly-dragon211
Copy link

您好,运行脚本时我也出现了这个问题:
错误: 找不到或无法加载主类 IMEI 原因: java.lang.ClassNotFoundException: IMEI

@yuqyu
Copy link

yuqyu commented Sep 24, 2020

日消息数走势是怎么分析的呀

@fly-dragon211
Copy link

日消息数走势是怎么分析的呀

这个就是一个统计图,按时间分类就好

@flylzj
Copy link

flylzj commented Nov 3, 2020

我的CompatibleInfo.cfg是空的

@fly-dragon211
Copy link

我的CompatibleInfo.cfg是空的

https://github.com/fly-dragon211/Wechat-message-analysis

@forconz
Copy link

forconz commented Oct 12, 2021

因为CompatibleInfo.cfg 有可能0字节,所以IMEI.java需要修改下

import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.security.MessageDigest;
import java.util.HashMap;
import java.io.File;

public class IMEI {
    public static void main(String[] args) {
        try {
            ObjectInputStream in = new ObjectInputStream(new FileInputStream(args[0]));
            Object DL = in.readObject();
            HashMap hashWithOutFormat = (HashMap) DL;

           // CompatibleInfo.cfg 有可能0字节
           String imei = "1234567890ABCDEF"; // 默认字符串
           File fCompatibleInfo = new File(args[1]);
           // 取手机的IMEI
           if(fCompatibleInfo.length() > 0) {
            FileInputStream fisCompatibleInfo = new FileInputStream(fCompatibleInfo);
            ObjectInputStream in1 = new ObjectInputStream(fisCompatibleInfo);
            Object DJ = in1.readObject();            
            HashMap hashWithOutFormat1 = (HashMap) DJ;
            imei = String.valueOf(hashWithOutFormat1.get(Integer.valueOf(258)));
            in1.close();
           }
           System.out.println("The IMEI is : " + imei);

           String uin = String.valueOf(hashWithOutFormat.get(Integer.valueOf(1)));
           System.out.println("The uin is : " + uin);
           imei = imei + uin; //合并到一个字符串
           imei = encode(imei); // hash
           System.out.println("The Key is : " + imei.substring(0, 7));
           in.close();           
        } catch (Exception e) {
            e.printStackTrace();
        }
 }

 public static String encode(String content)
  {
   try {
    MessageDigest digest = MessageDigest.getInstance("MD5");
    digest.update(content.getBytes());
    return getEncode32(digest);
    }
   catch (Exception e)
   {
    e.printStackTrace();
   }
   return null;
  }
  private static String getEncode32(MessageDigest digest)
  {
   StringBuilder builder = new StringBuilder();
   for (byte b : digest.digest())
   {
    builder.append(Integer.toHexString((b >> 4) & 0xf));
    builder.append(Integer.toHexString(b & 0xf));
   }
    return builder.toString(); 
  }
}


保存java文件以后

> javac IMEI.java
> java IMEI systemInfo.cfg CompatibleInfo.cfg

这个java代码中,uin的获取是没问题的。
The uin is :得到的uin和 com.tencent.mm/sp/auth_info_key_prefs.xml 文件里的
<int name="_auth_uin" value="" />
的value值是一样的。

根据uin计算的key,解密数据库实测没有问题。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants