-
Notifications
You must be signed in to change notification settings - Fork 56
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
Feature request: 读取新版QQNT数据库 #38
Comments
Electron那个?有计划,有时间可能去试一试 |
是的 大佬加油! |
然后Windows版貌似是在 |
那应该是比较简单的,用Frida hook一下就可以了 |
我这边貌似也不太行……只要注入 Frida 就会段错误/拒绝注入,想必是有反调一类的 |
似乎 Windows 上 key 长度为 16(? |
我在这边没有什么进展,要是有什么进度可以给我发发 |
顺带一提,windows 上 key 长就是 16 |
但是我不知道 BLOB 中的内容如何解码 |
是的,开源的那个就可以 Blob我明天再看看 PR 的话 好像这个函数在不同版本的 wrapper.node 里二进制不太一样,比较难写成脚本。。。。 |
有什么特征汇编指令序列一类的吗?再不济用户手动输入函数地址都没问题,毕竟这个repo本身就不是为了提供全套解决方案的 |
那我试着写个教程 |
更新 已经寄了 |
8.9.78+包括8.9.78.12275吗?我这儿显示是最新版本了,但是能hook到呢,只是地址变了。 setTimeout(function () {
let base_addr = Module.findBaseAddress("libkernel.so");
console.log("libkernel.so base address: " + base_addr);
// nt_sqlite3_key_v2, sub_1CCE4DC
let nt_sqlite3_key_v2_addr = base_addr.add(0x1cce4dc);
console.log("nt_sqlite3_key_v2_addr: " + nt_sqlite3_key_v2_addr);
Interceptor.attach(nt_sqlite3_key_v2_addr, {
onEnter: function (args) {
console.log("pKey: " + Memory.readCString(args[2]));
console.log("nKey: " + args[3].toInt32());
},
});
}, 1200); |
解密的话你看下那个仓库里的 |
我测试是不行的,我怀疑那是Windows的解密方式 |
那我最近也试一试,不行的话去加个“可能不可靠”的标志 |
呼,搞了一晚上终于搞好了。 // frida -U -f com.tencent.mobileqq -l final.js
const DATABASE_URI = "/data/user/0/com.tencent.mobileqq/databases/nt_db/nt_qq_{CHNAGE_THIS_TO_YOURS}/nt_msg.db";
// FOR LOG
let SQLITE3_EXEC_CALLBACK_LOG = true;
let index1 = 0;
let xCallback = new NativeCallback(
(para, nColumn, colValue, colName) => {
if (!SQLITE3_EXEC_CALLBACK_LOG) {
return 0;
}
console.log();
console.log(
"------------------------" + index1++ + "------------------------"
);
for (let index = 0; index < nColumn; index++) {
let c_name = colName
.add(index * 8)
.readPointer()
.readUtf8String();
let c_value = "";
try {
c_value =
colValue
.add(index * 8)
.readPointer()
.readUtf8String() ?? "";
} catch {}
console.log(c_name, "\t", c_value);
}
return 0;
},
"int",
["pointer", "int", "pointer", "pointer"]
);
// CODE BELOW
let get_filename_from_sqlite3_handle = function (sqlite3_db) {
// full of magic number
let zFilename = "";
try {
let db_pointer = sqlite3_db.add(0x8 * 5).readPointer();
let pBt = db_pointer.add(0x8).readPointer();
let pBt2 = pBt.add(0x8).readPointer();
let pPager = pBt2.add(0x0).readPointer();
zFilename = pPager.add(208).readPointer().readCString();
} catch (e) {}
return zFilename;
};
setTimeout(function () {
let base_addr = Module.findBaseAddress("libkernel.so");
console.log("libkernel.so base address: " + base_addr);
// sqlite3_exec -> sub_1CFB9C0
let sqlite3_exec_addr = base_addr.add(0x1cfb9c0);
console.log("sqlite3_exec_addr: " + sqlite3_exec_addr);
let sqlite3_exec = new NativeFunction(sqlite3_exec_addr, "int", [
"pointer",
"pointer",
"pointer",
"int",
"int",
]);
let target_db_handle = null;
let js_sqlite3_exec = function (sql) {
if (target_db_handle == null) {
return -1;
}
let sql_pointer = Memory.allocUtf8String(sql);
return sqlite3_exec(target_db_handle, sql_pointer, xCallback, 0, 0);
};
// ATTACH BELOW
Interceptor.attach(sqlite3_exec_addr, {
onEnter: function (args) {
// sqlite3*,const char*,sqlite3_callback,void*,char**
let sqlite3_db = ptr(args[0]);
let sql = Memory.readCString(args[1]);
let callback_addr = ptr(args[2]);
let callback_arg = ptr(args[3]);
let errmsg = ptr(args[4]);
let databasae_name = get_filename_from_sqlite3_handle(sqlite3_db);
if (databasae_name == DATABASE_URI) {
console.log("sqlite3_db: " + sqlite3_db);
console.log("sql: " + sql);
target_db_handle = sqlite3_db;
}
},
});
setTimeout(function () {
let ret = js_sqlite3_exec(
`ATTACH DATABASE '/storage/emulated/0/Download/plaintext.db' AS plaintext KEY '';SELECT sqlcipher_export('plaintext');DETACH DATABASE plaintext;`
);
console.log("js_sqlite3_exec ret: " + ret);
}, 4000);
}, 1200); |
主要就是几个点:
|
下一步的话可以看看insert是怎么实现的/能不能hook到 大概 |
After the decryption, it's still |
Sorry I didn't dive into these reverse engineering things at all and can't answer you anything about this project or their way to get the key. I just brute forced it by memory dumping, and if you're interested, here's the link (in Chinese) FYI: https://gist.github.com/bczhc/c0f29920d4e9d0cc6d2c49f7f2fb3a78. |
Thank you. I will try the brute force method as well. |
Even this didn't work. So, I doubt the key is not correct even though I followed the same steps. |
js_sqlite3_exec
大佬js_sqlite3_execs前段时间还能正常返回0,现在为啥是14 了 |
可能新版的结构体变了,不过我现在手机没root,没法测试。 |
也不算是新版我用的v8.9.85.12850,前几天正常来着,然后前两天刷机重新安装这个版本就突然不行了,奇怪了。 |
@cxapython 请注意裁剪你的回复内容,不要把代码块整个引用了 |
This comment was marked as resolved.
This comment was marked as resolved.
问一下各位大佬,目前用qqwindbkey的方法导出了安卓qqnt数据库了,之后要怎样才能导出指定某个人的聊天记录? |
好像没有直接跑的仓库?你改改这个代码应该能跑东西出来 |
大佬们,想问一下已经过期只有本地缓存的图片,在解密后的数据库内要如何获取到 |
猜的(
那个不是数据库的列,而是消息列二进制解码的id |
看了一下解密出来的数据库有一个简单的思路或许可行 可以先按 这个仓库 的指引用
因此在代码里加一个条件进行筛选私聊目标应该就可以提取出特定人的聊天记录 在提取出来的数据库的这个 打开后 |
This comment was marked as off-topic.
This comment was marked as off-topic.
请问现在有可以直接运行的仓库吗?我已经能解密数据库了,包括发送人接受人这些信息都能读取到,但是得到的聊天信息确实一串乱码,好像是probotuf格式的。请问聊天信息要怎么解密呢? |
这个大佬有给出一些protobuf的定义 |
这个应该怎么用呢) |
@NicoOrz #38 (comment) |
This comment was marked as off-topic.
This comment was marked as off-topic.
https://t.me/rvalue_daily/4862 |
好像是从 Harmony Next 版 QQ 解包的 |
现在就看看能不能给pcqq也有点好处了() |
不用好像,就是的 |
看起来和数据库中的protobuf定义对不上,可能是通信的协议,不过对字段的确定可能有一些参考价值 |
现在腾讯在推NT架构的QQ,要搞全平台统一,然后手机版的NT架构的QQ也开始内测了。
最新的手机版内测QQNT上的数据库架构已经大改了,变得和Windows/Mac/Linux版QQNT一样了。
版本:8.9.58.11050
如图 老版本的数据库仍然存在,但是很明显聊天记录已经不存放在老库里面了
现在新QQNT聊天记录数据库的位置是/databases/nt_db
从文件名来看这个数据库架构和电脑版QQNT是一样的
(Windows版QQNT数据库)
目前还没研究出新数据库密钥存放的位置以及新数据库的格式
(从文件头来看是SQLite3?)
不知道有没有希望搞定新版的数据库解密
另:手机版QQNT内测包下载链接:https://downv6.qq.com/qqweb/QQ_1/android_apk/qq_8.9.58.11050_64.apk
(就算没有内测资格也能用,在弹出内测活动已结束的窗口的时候按两下返回就可以把那个窗口关掉)
(不建议用大号测试,这个内测QQNT一旦登录之后就会把所有的老库里的聊天记录全都迁移进新库,无法撤销)
另2:MacQQNT的数据库位置:/Users/{用户名}/Library/Containers/com.tencent.qq/Data/Library/Application Support/QQ/nt_qq_{一串ID}/nt_db
目测数据库格式和其他平台是一样的
The text was updated successfully, but these errors were encountered: