This article is based on Android WeChat 8.0.3.
Finding the Database File#
First, find the uin
, located in the file /data/data/com.tencent.mm/shared_prefs/auth_info_key_prefs.xml
:
The WeChat chat database is named EnMicroMsg.db and is located in a specific folder under data/data/com.tencent.mm/MicroMsg/
, with the file name md5_32_low(imel + uin)
:
The WeChat database password is generated by concatenating the IMEI number and WeChat uin, and encrypting it with md5 to obtain a 32-bit lowercase password. The first 7 digits are used as the password.
Note: In special cases when the password is incorrect and WeChat cannot obtain the IMEI number, a fixed value of 1234567890ABCDEF will be used as the default.
Initially, various SQLCipher viewing tools on the Mac platform were unable to open it. I thought the algorithm had changed, but after analyzing it, I found that it was correct and could be opened using SQLCipher.exe on the Windows platform.
Analysis Process#
WeChat uses the wcdb database. By referring to the WCDB documentation for Android integration, you can learn about the method for opening the wcdb database:
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(
"path/to/database", // DB path
passphrase.getBytes(), // WCDB password, parameter type is byte[]
cipher, // Encryption description object created above
null, // CursorFactory
null // DatabaseErrorHandler
// The SQLiteDatabaseHook parameter has been removed, and the same purpose can be achieved by specifying the parameters in the cipher
);
Through analysis with jadx, there are several overloaded methods for openOrCreateDatabase
, and they all internally use the SQLiteDatabase.openDatabase
method.
By hooking this function using frida and tracing the call stack, we can find the password generation rules.
Call Stack#
Tracing the call stack to find the location of password generation.
com.tencent.mm.storagebase.a.b:
this.key = C7959g.getMessageDigest((C8811q.m22244dJ(true) + j).getBytes()).substring(0, 7);
this.kiF = C67989f.m106126E(str, this.key, z);
By hooking the getMessageDigest
method, we obtain:
Parameter: 1234567890ABCDEF-156*****65 (1234567890ABCDEF + uin) Here, j represents uin, and there is no dispute. Let's continue analyzing C8811q.m22244dJ(true),
which returns 552**********************ac9fbb6.
public static String m22244dJ(boolean z) {
AppMethodBeat.m18334i(155720);
String str = gXe.get();
if (!Util.isNullOrNil(str)) {
AppMethodBeat.m18335o(155720);
return str;
} else if (z) {
AppMethodBeat.m18335o(155720);
return "1234567890ABCDEF";
} else {
AppMethodBeat.m18335o(155720);
return "";
}
}
gXe is a class that obtains device information, and it seems quite complex to analyze. Let's stop here.
Related files: https://pan.baidu.com/s/1WIZ_wdAFn_9tMZNxzC5i5Q Extraction code: xpnk