首页
社区
课程
招聘
[原创]某聊天工具数据库解密
发表于: 2022-9-2 15:16 13305

[原创]某聊天工具数据库解密

2022-9-2 15:16
13305

众所周知的,微信PC版存放聊天记录等数据采用的是sqlite3去存放的,实现功能的核心dll是wechatwin.dll。所以帮wechat数据库解密需要两步,第一步是找到key,第二步是代码还原。

在目前版本wechat 3.7.0版本再去通过搜寻“encryptDB %s DBKey can’t be nul”上下文来寻找pkey的方法已经失效,,既然如此,把思路打开,sqlite3在使用加密数据库的时候必定先解密,解密必然会调用sqlite3_key函数去解密。
函数原型为:

直接wechatwin.dll 扒出来,扔到ida去看看。 找到关键字 cipher_version 和 4.2.0 ,看来用wechat用的是sqlcipher 4.2.0 ,直接上github.com/sqlcipher/sqlcipher 找到4.2.0版本,编译出来。
有了符号,我们可以通过对照找到sqlit3_key()函数,在wechatwein.dll 3.7.0版本中,并没有sqlite3_key()函数,应该是编译器优化掉了,通过阅读源码可知,sqlite3_key_v2()调用了sqlcipher_find_db_index 和 sqlite3CodecAttach函数。 sqlite3_key_v2函数原型为:

到这里已经大概清楚,pkey是解密数据库的密钥,一种做法是直接hook函数sqlite3CodecAttach,通过hook的方式获取key(什么?不知道wechatwin.dll的sqlite3CodeAttach函数在哪里?方法很多种,我用的是目测对比法。),另一种方法是直接还原他的算法,很不幸的是3.7.0版本的核心算法是vm掉的,本菜鸡找到一个2.9.0版本的wechatwin.dll 关键函数也是vm掉的。所以还原算法就先需要还原VM掉的代码。难度太大了,(我这种小菜鸡做不来。有大佬会的教教我)。

通过资料得知sqlite3_rekey()可以解密函数,但是万万没想到的是这里面有个大坑,sqlcipher的sqlite3_rekey()因为文档在低版本标注出错了,导致我想了好长时间,扒开源码才发现sqlite3_rekey()在参数pkey和nkey == NULL的时候直接返回错误。
附3.4.2文档错误注释:

4.2.0版本注释

很明显 社区版的明确告知 没有实现通过sqlite3_rekey()来解密数据库。应该使用sqlcipher_export() 来解密。
既然这样,不如使用一下tx的传统艺能,复制粘贴。扒下微信的操作,直接上od看看微信是怎么操作数据库的。
先通过符号 对照找到wechatwin.dll中 sqlite3_exec()这个函数,函数原型为:

把参数记录下来,找到 一下几条关键数据库语句操作
PRAGMA cipher_compatibility = 3
PRAGMA cipher_page_size = 4096
PRAGMA synchronous=NORMAL
SELECT name, rootpage, sql FROM \"main\".sqlite_master ORDER BY rowid
PRAGMA auto_vacuum=0
PRAGMA journal_mode = WAL
然后外加好多回调函数,不过大多数也是vm掉的回调,脑子疼。
附:(想问这些语句是什么意思的可以具参考一下 https://www.zetetic.net/sqlcipher/sqlcipher-api/文档介绍。)
额,很显然,没有找到任何线索。
不过参考sqlcipher文档,可以清晰的知道如何解密数据库的,我还是直接复制粘贴了

关键是使用SELECT sqlcipher_export('plaintext');来重新生成一个未加密的数据库
直接上代码

然后在 当前路径下会生成一个解密后的数据库。 直接使用数据库连接工具打开即可。
注:垃圾佬的日常垃圾分析。没有任何技术含量的分析。有不对的地方请告知。

SQLITE_API int sqlite3_key(
 sqlite3 *db,
 const void *pKey,
  int nKey) {
  return sqlite3_key_v2(db, "main", pKey, nKey);
}
SQLITE_API int sqlite3_key(
 sqlite3 *db,
 const void *pKey,
  int nKey) {
  return sqlite3_key_v2(db, "main", pKey, nKey);
}
SQLITE_API int sqlite3_key_v2(
 sqlite3 *db,
 const char *zDb,
 const void *pKey,
 int nKey) {
      /*
      attach key if db and pKey are not null and nKey is > 0
   */
    if(db && pKey && nKey) {
     int db_index = sqlcipher_find_db_index(db, zDb);
     return sqlite3CodecAttach(db, db_index, pKey, nKey);
  }
  return SQLITE_ERROR;
}
SQLITE_API int sqlite3_key_v2(
 sqlite3 *db,
 const char *zDb,
 const void *pKey,
 int nKey) {
      /*
      attach key if db and pKey are not null and nKey is > 0
   */
    if(db && pKey && nKey) {
     int db_index = sqlcipher_find_db_index(db, zDb);
     return sqlite3CodecAttach(db, db_index, pKey, nKey);
  }
  return SQLITE_ERROR;
}
/*
** Change the key on an open database.  If the current database is not encrypted, this routine will encrypt it.  If pNew==0 or nNew==0, the  database is decrypted.
**
** The code to implement this API is not available in the public release  of SQLite.
*/
/*
** Change the key on an open database.  If the current database is not encrypted, this routine will encrypt it.  If pNew==0 or nNew==0, the  database is decrypted.
**
** The code to implement this API is not available in the public release  of SQLite.
*/
/* BEGIN SQLCIPHER
   SQLCipher usage note:
   If the current database is plaintext SQLCipher will NOT encrypt it.
   If the current database is encrypted and pNew==0 or nNew==0, SQLCipher will NOT decrypt it.
   This routine will ONLY work on an already encrypted database in order to change the key.
   Conversion from plaintext-to-encrypted or encrypted-to-plaintext should
   use an ATTACHed database and the sqlcipher_export() convenience function as per the SQLCipher Documentation.
   END SQLCIPHER
*/
/* BEGIN SQLCIPHER
   SQLCipher usage note:
   If the current database is plaintext SQLCipher will NOT encrypt it.
   If the current database is encrypted and pNew==0 or nNew==0, SQLCipher will NOT decrypt it.
   This routine will ONLY work on an already encrypted database in order to change the key.
   Conversion from plaintext-to-encrypted or encrypted-to-plaintext should
   use an ATTACHed database and the sqlcipher_export() convenience function as per the SQLCipher Documentation.
   END SQLCIPHER
*/
SQLITE_API int sqlite3_exec(
  sqlite3 *db,                /* The database on which the SQL executes */
  const char *zSql,           /* The SQL to be executed */
  sqlite3_callback xCallback, /* Invoke this callback routine */
  void *pArg,                 /* First argument to xCallback() */
  char **pzErrMsg             /* Write error messages here */
)
SQLITE_API int sqlite3_exec(
  sqlite3 *db,                /* The database on which the SQL executes */
  const char *zSql,           /* The SQL to be executed */
  sqlite3_callback xCallback, /* Invoke this callback routine */
  void *pArg,                 /* First argument to xCallback() */
  char **pzErrMsg             /* Write error messages here */
)
$ ./sqlcipher encrypted.db
sqlite> PRAGMA key = 'testkey';
sqlite> ATTACH DATABASE 'plaintext.db' AS plaintext KEY '';  -- empty key will disable encryption
sqlite> SELECT sqlcipher_export('plaintext');
sqlite> DETACH DATABASE plaintext;
$ ./sqlcipher encrypted.db

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2022-9-2 17:12 被青丝梦编辑 ,原因: 修改
收藏
免费 2
支持
分享
最新回复 (10)
雪    币: 475
活跃值: (157)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
可以查找字符串 cipher_integrity_check  找到引用该字符串的函数,该函数下面的第一个函数可以看到SQLITE format 3,继续往下滑给下面连续三个函数都下断点,断下后,有一个参数指向密钥,下一个参数是0x20
2022-9-4 18:19
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
厉害了
2022-9-15 17:00
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
想请教您一下 不知是否方便  有偿也是可以的~  
2022-9-15 17:02
0
雪    币: 865
活跃值: (1613)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
5
这是我分析vx的思路,https://blog.ltools.vip/archives/173/。
2022-10-18 18:23
0
雪    币: 1420
活跃值: (2281)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
6
凌哥 这是我分析vx的思路,https://blog.ltools.vip/archives/173/。
是这样的,不过我通过查看tencent在github的仓库,发现了他使用的sqlcipher。劫持数据库句柄是实现功能的一种手段。
2022-10-18 19:28
0
雪    币: 10964
活跃值: (4597)
能力值: ( LV12,RANK:404 )
在线值:
发帖
回帖
粉丝
7



wx_id也在这附近,忘了这个类叫啥了。。。

2022-10-18 20:38
1
雪    币: 865
活跃值: (1613)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
8
青丝梦 是这样的,不过我通过查看tencent在github的仓库,发现了他使用的sqlcipher。劫持数据库句柄是实现功能的一种手段。
条条大路通罗马,互相学习
2022-10-24 15:52
0
雪    币: 15
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
9
感谢分享
2022-12-11 21:20
0
游客
登录 | 注册 方可回帖
返回
//