Some time ago, I got the decoding of dat pictures in WeChat, and later some students asked how to decode the database.. Of course, after looking at it one after another, plus the messy things in hospital, it has not been handled. After handling it in the last few days, we found that the data format of the WeChat database is really troublesome...
How to view WeChat dat pictures click the link below
http://sdxlp.cn/article/%E5%BE%AE%E4%BF%A15.html
Recent operations under a simple comb:
- Get the key of PC-side WeChat database by od
- Decrypt PC-side WeChat database db file to normal DB through c++.
- Read sqlite database through nodejs to get friends and chat records
I won't talk about the first two. I also did it directly with the tutorial of the Great God. Nothing changed, and nothing could be said. This article mainly does a simple record compilation, really nothing special..
First few pictures
Decrypt the database based on the 64-bit key you get.
Decrypted database
Open with sqlite to see the following table
MSG database
With MSG. For example, db, this database mainly stores chat records, and MSG table stores chat records for all friends + groups, as shown below:
MSG Table Chat Record
data base
WeChat MSG has a lot of database files. If we need friends + chat records, we only need three database files: MSG.db MediaMsg.db MicroMsg.db, of course, after a certain volume of data is stored, there will be MSG0 MSG1, etc.
- MSG.db stored as chat log data
- MicroMsg.db stores contact information as a friend + group, etc.
- MediaMsg.db mainly stores voice data in silk format.
- Misc.db stores avatar data
extract
So, we only need to get the contact, then get the corresponding chat record according to the contact, and then show the chat record. Of course, the idea is simpler. The trouble is that there are more chat data formats in WeChat, about a dozen, including: message/picture/emoticon/voice/video/map/business card/recall/red packet/group message/take a photo, and so on.
We also need to parse into different content according to different data formats. Due to limited interest, we only made three simple messages/pictures/videos. Except for messages, pictures and videos are stored paths. File tables are displayed under filestorage/image and filestorage/video s, and we get the files to show through regular matching.
Blue stands for friends who have chat records
Style is low, write freely
Main business code
/**** * * WeChat uses all business queries */ const fs = require('fs'); const sqlite3 = require('sqlite3').verbose(); const lib = require('./lib'); module.exports = function (options) { let wxid = options.wxid; const MicroIns = new sqlite3.Database(options.MicroMsg); const MSGIns = options.MSG.split(',').map(str => { return new sqlite3.Database(str); }); const MEDIAIns = new sqlite3.Database(options.MEDIA); return { /*** * Get all WeChat contacts - friends */ getFriends: async function () { let list = await lib.all(MicroIns, 'select UserName,Remark,NickName,PYInitial,RemarkPYInitial from Contact where verifyFlag = 0 and (type=3 or type > 50)', []); //Do a simple sort, A list.forEach(item => { item.zimu = (item.RemarkPYInitial || item.PYInitial); item.f = item.zimu.length > 0 ? item.zimu.substr(0, 1) : '-'; }); list.sort((a, b) => { return a.f.charCodeAt(0) - b.f.charCodeAt(0); }) return list; }, /*** * Get all the group data from WeChat */ getGroups: async function () { let list = await lib.all(MicroIns, 'select UserName,Remark,NickName,PYInitial,RemarkPYInitial from Contact where type=2'); //Do a simple sort, A list.forEach(item => { item.zimu = (item.RemarkPYInitial || item.PYInitial); item.f = item.zimu.length > 0 ? item.zimu.substr(0, 1) : '-'; }); list.sort((a, b) => { return a.f.charCodeAt(0) - b.f.charCodeAt(0); }) return list; }, /*** * Get public number information in WeChat */ getOfficial: async function () { let list = await lib.all(MicroIns, 'select UserName,Remark,NickName,PYInitial,RemarkPYInitial,VerifyFlag from Contact where type=3 and (VerifyFlag=24 or VerifyFlag=8)'); //Do a simple sort, A list.forEach(item => { item.zimu = (item.RemarkPYInitial || item.PYInitial); item.f = item.zimu.length > 0 ? item.zimu.substr(0, 1) : '-'; }); list.sort((a, b) => { return a.f.charCodeAt(0) - b.f.charCodeAt(0); }) return list; }, /*** * Get information about strangers in WeChat */ getStrangers: async function () { let list = await lib.all(MicroIns, 'select UserName,Remark,NickName,PYInitial,RemarkPYInitial from Contact where type=4'); //Do a simple sort, A list.forEach(item => { item.zimu = (item.RemarkPYInitial || item.PYInitial); item.f = item.zimu.length > 0 ? item.zimu.substr(0, 1) : '-'; }); list.sort((a, b) => { return a.f.charCodeAt(0) - b.f.charCodeAt(0); }) return list; }, /*** * Get a row of Contact records from UserName */ getContactByUserName: async function (UserName) { let list = await lib.get(MicroIns, 'select UserName,Remark,NickName,PYInitial,RemarkPYInitial from Contact where UserName=?', UserName); return list; }, /*** * Get ContactHeadImgUrl avatar information from UserName */ getHeadImageByUserName: async function (UserName) { let list = await lib.get(MicroIns, 'select usrName,smallHeadImgUrl,bigHeadImgUrl,headImgMd5 from ContactHeadImgUrl where usrName=?', UserName); return list; }, //Get the number of chat entries getRecordCount: async function (UserName) { let count = 0; for (let i in MSGIns) { let temp = await lib.get(MSGIns[i], 'select count(1) as num from MSG where StrTalker=?', UserName); count += temp.num; } return { num: count }; }, /** * Query MSG chat record data in MSG0-N based on UserName * @param {String} UserName */ getRecordList: async function (UserName) { let list = []; for (let i in MSGIns) { let temp = await lib.all(MSGIns[i], 'select localId,TalkerId,Type,SubType,IsSender,CreateTime,Sequence,StrContent,StrTalker,BytesExtra from MSG where StrTalker=?', UserName); list = list.concat(temp); } list.forEach(item => { //type=3, picture message //type=43, video message //type=47, emoticon message //type=34, voice message //type=1, normal message //type=42, business card message //type=48, map location message //type=49,50, indeterminate //type=10000, recall message, message from BytesExtra //type=10002, group invitation message var info = item.BytesExtra.toString('utf8'); if (info != null) { info = info.trim(); var rr = info.match(/\b(.*)?\u001a/); if (rr) { item.from = rr[1];//From whom to speak } } var type = item.Type; if (type == 3) {//Picture messages, need thumbnails and large map data var info = item.BytesExtra.toString('utf8'); var reg = new RegExp(wxid + '.*?(\.dat)', 'g'); var ja = info.match(reg); if (ja) { item.bigImage = ja[0]; item.smallImage = ja[1]; item.BytesExtra = null; item.StrContent = null; } else { item.StrContent = info; } } else if (type == 43) {//video var info = item.BytesExtra.toString('utf8'); var reg = new RegExp(wxid + '.*?(\.jpg)', 'g'); var reg2 = new RegExp('' + wxid + '.*?(\.mp4)', 'g'); var ja = info.match(reg); if (ja != null) { item.videoPost = ja[0]; info = info.replace(ja[0], ''); } var ja2 = info.match(reg2); if (ja2 != null) { item.Video = ja2[0]; } item.StrContent = null; item.BytesExtra = null; } else if (type == '47') {//Emotional message item.StrContent = null; item.BytesExtra = null; } else if (type == 34) {//Voice message, need to convert voice data to mp3 or play directly // console.log(item) // console.log(item.BytesExtra.toString('utf8')); } else if (type == 1) {//Common message // console.log(item); // console.log(item.StrContent) //Who spoke } else if (type == 42) {//Business card message } else if (type == 48) {//Map positioning var label = item.StrContent.match(/label="(.*?)"/); if (label != null) { label = label[1]; } var poiname = item.StrContent.match(/poiname="(.*?)"/); if (poiname != null) { poiname = poiname[1] } item.StrContent = label + poiname; item.BytesExtra = null; } else if (type == 10000) {//Retract/Red Bag/Take a Photo } else if (type == 10002) {//Invite to Group item.StrContent = 'Invite Group Information'; item.BytesExtra = null; } else { // console.log(item); if (item.SubType == 6) {//Enclosure var regExp = new RegExp('((' + wxid + ').*)'); if (regExp) { item.filePath = regExp[0]; } } else if (item.SubType == 5 || item.SubType == 33) { var reg = new RegExp(wxid + '.*?(\.jpg)', 'g'); var ja = info.match(reg); if (ja) { item.bigImage = ja[0]; } } else if (item.SubType == 8) {//gif var reg = new RegExp(wxid + '.*?(\.gif)', 'g'); var ja = info.match(reg); if (ja) { item.bigImage = ja[0]; } } else { // console.log(info); item.StrContent = item.BytesExtra.toString('utf8'); item.BytesExtra = null; } // console.log(item.BytesExtra.toString('utf8')) } }) return list; }, getMedia: async function () { let list = await lib.all(MEDIAIns, 'select * from media'); return list; } }; }
Other
Of course, it doesn't really make sense to feel like this, after all... The key must be logged in by WeChat before it can be obtained. At the same time, due to the mechanism of WeChat, what can the database see, what can WeChat see.. So it doesn't make much sense unless you're ready to save the record. If you really have spare egg pain in the future, you might beautify the chat record by adding different formats, restoring as much as possible, and then adding a pdf?