记录一下windows取证的一些步骤,主要是为了导出windows上的微信&qq的聊天记录,没什么新的东西,把最近实践的过程记录下。
微信聊天记录存储在sqlite数据库中,但是加密了,所以需要先获取到解密密钥。解密密钥的获取一般都是在内存中,所以需要微信在登录状态下才能获取到。
这里要利用到开源工具https://github.com/AdminTest0/SharpWxDump,需要自己编译
一般情况下,我用vs2022打开项目,会提示当前目标.net版本为4.0,是否需要升级该项目的.net版本,这时候最好别升级,尽可能适配更多的目标环境。安装4.0的运行环境可以参考这篇文章:https://blog.csdn.net/GoodCooking/article/details/125347856
编译选择release、x86即可。
直接运行可以获取到key:
微信数据默认情况下位于C:\Users\xxx\Documents\WeChat Files\
,而聊天记录数据库位于该目录下面的wxid_xxxx\Msg\Multi
。聊天记录文件命名一般是MSG.db,超出240MB会自动生成MSG1.db,以此类推
wxid_xxxxxxxx\Msg\Multi\MSG0.db > 聊天记录
wxid_xxxxxxxx\Msg\Multi\MSG1.db > 聊天记录
wxid_xxxxxxxx\Msg\Multi\MSG2.db > 聊天记录
wxid_xxxxxxxx\Msg\MicroMsg.db > Contact字段 > 好友列表
wxid_xxxxxxxx\Msg\MediaMsg.db > 语音 > 格式为silk
在上一步获取到解密密钥之后,我们可以直接使用下面的脚本解密聊天记录数据库:
# jiemi.py
from Crypto.Cipher import AES
import hashlib, hmac, ctypes, sys, getopt
SQLITE_FILE_HEADER = bytes('SQLite format 3', encoding='ASCII') + bytes(1)
IV_SIZE = 16
HMAC_SHA1_SIZE = 20
KEY_SIZE = 32
DEFAULT_PAGESIZE = 4096
DEFAULT_ITER = 64000
opts, args = getopt.getopt(sys.argv[1:], 'hk:d:')
input_pass = ''
input_dir = ''
for op, value in opts:
if op == '-k':
input_pass = value
else:
if op == '-d':
input_dir = value
password = bytes.fromhex(input_pass.replace(' ', ''))
with open(input_dir, 'rb') as (f):
blist = f.read()
print(len(blist))
salt = blist[:16]
key = hashlib.pbkdf2_hmac('sha1', password, salt, DEFAULT_ITER, KEY_SIZE)
first = blist[16:DEFAULT_PAGESIZE]
mac_salt = bytes([x ^ 58 for x in salt])
mac_key = hashlib.pbkdf2_hmac('sha1', key, mac_salt, 2, KEY_SIZE)
hash_mac = hmac.new(mac_key, digestmod='sha1')
hash_mac.update(first[:-32])
hash_mac.update(bytes(ctypes.c_int(1)))
if hash_mac.digest() == first[-32:-12]:
print('Decryption Success')
else:
print('Password Error')
blist = [blist[i:i + DEFAULT_PAGESIZE] for i in range(DEFAULT_PAGESIZE, len(blist), DEFAULT_PAGESIZE)]
with open(input_dir, 'wb') as (f):
f.write(SQLITE_FILE_HEADER)
t = AES.new(key, AES.MODE_CBC, first[-48:-32])
f.write(t.decrypt(first[:-48]))
f.write(first[-48:])
for i in blist:
t = AES.new(key, AES.MODE_CBC, i[-48:-32])
f.write(t.decrypt(i[:-48]))
f.write(i[-48:])
windows上如果报错没有Crypto,就使用下面的命令安装下:
pip install pycryptodome
运行命令如下:
python3 .\jiemi.py -k 数据库密钥 -d .\MSG0.db
直接使用navicate导入sqllite即可:
可以使用查询语句快速检索如查询带"密码"的聊天记录,同时包含个人消息、群消息等等
SELECT * FROM "MSG" WHERE StrContent like'%密码%'
qq的数据存储也是通过加密的sqlite,但是和微信不一样的是,qq数据库解密的密钥是会变化的,每次登录时会下发一个密钥,所以这也导致了密钥和数据库是一一对应的。
qq聊天记录文件一般保存在C:\Users\xxxx\Documents\Tencent Files\xxxxxxx\Msg3.0.db
解密密钥的破解可以找到下面几个文章:
我们可以直接使用项目https://github.com/Young-Lord/qq-win-db-key来获取解密密钥,在登录时使用frida hook KernelUtil.dll,拿到key之后通过hook解密函数可以直接获取解密之后的db文件。
该脚本运行时需要hook到登录过程,也就是执行要遵守:备份Msg3.0.db
-> 打开 QQ -> python hook.py
-> 登录 -> 得到 key
可以看到解密之后的db文件已经保存在当前目录下面了,可以直接使用navicate打开db文件:
主要的聊天信息记录在MsgContent列里面,但是由于被编码了,所以没法直接看到明文。
上一步虽然数据库已经解密了,但是数据都被编码了,没办法直接看到明文,所以还需要解码一下。
https://github.com/Akegarasu/qmsg-unpacker 这个项目可以用来解码MsgContent,具体用法可以参考example。
我在使用过程中,发现这个example不太友好,大家可以参考下面的example
package main
import (
"database/sql"
"fmt"
"github.com/Akegarasu/qmsg-unpacker/qqmsg"
_ "github.com/mattn/go-sqlite3"
)
func main() {
db, err := sql.Open("sqlite3", "./Msg3.0.db_0_xxxxx.db")
if err != nil {
panic(err)
}
//查询数据
rows, err := db.Query("SELECT * FROM group_xxxxxx")
if err != nil {
panic(err)
}
for rows.Next() {
var time int
var rand int
var senduin int
var msgcontent []byte
var msgDecode string
var info []byte
err := rows.Scan(&time, &rand, &senduin, &msgcontent, &info)
if err != nil {
panic(err)
}
fmt.Printf("time: %+v, rand: %+v,senduin: %+v,msgcontent: %+v,info: %+v\n", time, rand, senduin, msgcontent, info)
msg := qqmsg.Unpack(msgcontent)
fmt.Printf("msg %+v\n", msg)
fmt.Printf("SenderNickname: %s\n", msg.SenderNickname)
fmt.Printf("msg.Header.Time: %+v\n", msg.Header.Time)
msgPrintable := qqmsg.EncodeMsg(msg)
// fmt.Println(msgPrintable)
fmt.Printf("msgPrintable: %+v\n", msgPrintable)
break
}
rows.Close()
db.Close()
}
或者可以使用我编写的python脚本,项目地址为:https://github.com/saucer-man/qq_msg_decode,解码原理就是参考了上面的golang项目,在代码中修改下数据库地址,然后直接运行就行,这个脚本会自动将所有的msgContent
字段解密,并且增加一列DecodedMsg
用于存放明文,代码用gpt转的,有点丑陋,对于数据库比较大的情况下,转换过程会比较缓慢。
下面是https://github.com/saucer-man/qq_msg_decode解码后的数据库: