开门见山
1、手机获得root的最高权限
2、了解微信本地的目录结构
3、微信本地文件的读取权限
4、微信本地数据库的破解
5、找到相应的数据库表读取
一、手机获得root的最高权限
无论怎么操作,这个都是跳不过的前提,首先手机要root,才能访问别的app下面的数据库。root过程参考前面写的文章。
https://blog.csdn.net/hq222/article/details/89020608
二、了解微信本地的目录结构
/data/data/com.tencent.mm下就是微信本地的目录结构;本地数据库都在/data/data/com.tencent.mm/MicroMsg下面;
SharedPerferences文件都在 /data/data/com.tencent.mm/shared_prefs下面,这里存放的就是用户的一些个人私密信息,root之后可以利用RE管理器查看
三、修改微信文件的读取权限
int tx = RootCmd.execRootCmdSilent("chmod 777 -R " +WX_PATH);//每次读取前都要走这个方法,修改文件的权限
public static int execRootCmdSilent(String cmd) {
int result = -1;
DataOutputStream dos = null;
try {
Process p = Runtime.getRuntime().exec("su");
dos = new DataOutputStream(p.getOutputStream());
Log.i(TAG, cmd);
dos.writeBytes(cmd + "\n");
dos.flush();
dos.writeBytes("exit\n");
dos.flush();
p.waitFor();
result = p.exitValue();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (dos != null) {
try {
dos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}
每次准备读取数据库或者操作微信文件之前都需要执行一次该命令。Process localProcess = Runtime.getRuntime().exec("su")先通过这个命令, 使得当前app获取到root权限,然后再通过chmod命令来修改微信的data目录的读写权限,因为我们需要操作读取微信的数据库文件以及sp文件,所以必须要有微信文件的操作权限。
四、微信数据库密码的破解
微信的数据库密码是:MD5(手机的IMEI+微信UIN)的前7位(网上大神提供)
1、获取手机的IMEI
TelephonyManager tm = (TelephonyManager) getApplicationContext().getSystemService(TELEPHONY_SERVICE);
imei = tm.getDeviceId();
需要权限:
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
2、获取微信的UIN
微信的uin是存储在SharedPerferences里面,所以要在微信目录的shared_prefs文件夹里去查找,路径:shared_prefs/auth_info_key_prefs.xml
代码获取:
public String getWxUin() {
mCurrWxUin = null;
File file = new File(WX_SP_UIN_PATH);
try {
FileInputStream in = new FileInputStream(file);
SAXReader saxReader = new SAXReader();
Document document = saxReader.read(in);
Element root = document.getRootElement();
List<Element> elements = root.elements();
for (Element element : elements) {
if ("_auth_uin".equals(element.attributeValue("name"))) {
mCurrWxUin = element.attributeValue("value");
}
}
return mCurrWxUin;
} catch (Exception e) {
e.printStackTrace();
Log.i("huang", "获取微信uid失败,请检查auth_info_key_prefs文件权限");
}
return "";
}
3、根据IMEI和uin获取数据库的密码
String pwd = initDbPassword(imei, uin);
private String initDbPassword(String imei, String uin) {
if (TextUtils.isEmpty(imei) || TextUtils.isEmpty(uin)) {
return "";
}
String md5 = md5(imei + uin);
Log.i("huang","md5=="+md5);
String password = md5.substring(0, 7).toLowerCase();
return password;
}
4、数据库的父级文件夹名称的破解(重要!!!)
微信父级数据库的名称:MD5("mm"+auth_info_key_prefs.xml中解析出微信的uin码)
String dbParentsPath = md5("mm" + uin);
public static String md5(String string) {
if (TextUtils.isEmpty(string)) {
return "";
}
MessageDigest md5 = null;
try {
md5 = MessageDigest.getInstance("MD5");
byte[] bytes = md5.digest(string.getBytes());
String result = "";
for (byte b : bytes) {
String temp = Integer.toHexString(b & 0xff);
if (temp.length() == 1) {
temp = "0" + temp;
}
result += temp;
}
return result;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return "";
}
5、复制数据库
注意:为啥会有这一步,因为一个数据库文件不能被多次连接,只要我们一成功连接上那个db文件,微信的客户端就会自动退出登录,并且会出现异常。所有我现在的做法是把这个db文件拷贝到我们自己的app目录下,再进行连接。
public static boolean copyFile(String oldPath, String newPath) {
deleteFolderFile(newPath,true);
InputStream inStream = null;
FileOutputStream fs = null;
try {
int bytesum = 0;
int byteread = 0;
File oldfile = new File(oldPath);
Boolean flag = oldfile.exists();
if (oldfile.exists()) { //文件存在时
inStream = new FileInputStream(oldPath); //读入原文件
fs = new FileOutputStream(newPath);
byte[] buffer = new byte[2048];
while ((byteread = inStream.read(buffer)) != -1) {
bytesum += byteread; //字节数 文件大小
fs.write(buffer, 0, byteread);
}
return true;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (inStream != null) {
inStream.close();
}
if (fs != null) {
fs.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return false;
}
6、读取数据库的聊天记录
首先看一下微信的数据库的结构以及聊天记录的表结构
这只是一小部分,微信数据库中表特别多,不过联系人信息在rcontact表中,聊天记录在message表中
message表结构:
所以可以根据表中显示读取想要的聊天记录
private void openWxDb(File dbFile,String mDbPassword) {
Context context = DemoApplication.getInstance();
SQLiteDatabase.loadLibs(context);
SQLiteDatabaseHook hook = new SQLiteDatabaseHook() {
@Override
public void preKey(SQLiteDatabase database) {
}
@Override
public void postKey(SQLiteDatabase database) {
database.rawExecSQL("PRAGMA cipher_migrate;"); //兼容2.0的数据库
}
};
try {
//打开数据库连接
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(dbFile, mDbPassword, null, hook);
Cursor c1 = db.rawQuery("select * from message where type=1", null);
while (c1.moveToNext()) {
String talker = c1.getString(c1.getColumnIndex("talker"));
String content = c1.getString(c1.getColumnIndex("content"));
String type = c1.getString(c1.getColumnIndex("type"));
Log.i("huang","content=="+content);
Log.i("huang","talker=="+talker);
Log.i("huang","type=="+type);
record=record+"/"+content;
}
tvRecord.setText(record);
c1.close();
db.close();
} catch (Exception e) {
e.printStackTrace();
}
}
这里读取用到的是:
compile 'net.zetetic:android-database-sqlcipher:3.5.4@aar'
难点总结
1、手机必须root
2、让当前app获取su权限,以及修改微信目录的读写权限
3、破解微信的数据库密码
4、数据库的父级文件夹名称的获取
5、数据库必须复制出来再读取