好贷网好贷款

[置顶] 如何导出微信聊天记录

发布时间:2016-12-3 2:07:40 编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"[置顶] 如何导出微信聊天记录",主要涉及到[置顶] 如何导出微信聊天记录方面的内容,对于[置顶] 如何导出微信聊天记录感兴趣的同学可以参考一下。

首先,很容易发现数据库在/data/data/com.tencent.mm/MicroMsg/<some id> 下,file之,显示为data…… 好吧看来被腾讯加密了。。 我找女朋友的聊天记录就是找他们帮忙的希望可以帮助你Q2690683499 希望可以帮助你 在/data/data/com.tencent.mm/里随便看,发现lib里有个libmmcrypto.so,大概就是用来加密的了。nm -D之,发现一堆sqlite3_*;稍微google下,觉得应该是用了sqlcipher。于是只用拿到密钥就好啦。 gdb  希望break到sqlite3_exec之类的函数来看到密钥。发现android自带的gdbserver有问题,attach上去后根本看不到调用栈,不明原因。于是手动编译了静态的arm构架的gdb,push上去,能attach和traceback了;但一旦下断点,目标进程就会蹦,不明原理。此想法失败。替换掉libmmcrypto.so 希望用自己修改的sqlcipher来替换原来的库,把密钥直接打印出来。花了很多时间,交叉编译了不少东西,但最后微信在使用被换掉的库的情况下总还是要崩……逆向+肉眼密钥算法 使用apktool逆向微信的app(需要注意的是使用apktol前应该安装framework,否则会各种错误;我在这里耗了好久)。grep 'PRAGMA key',真的有,前后看了下,发现貌似是把this中的一个东西作为了key。。。没找到生成密钥的算法……injection 想到修改代码把key直接打出来。google了一会儿,发现了以下方法: [plain] view plaincopy const-string v1, "!!!!!SQL:  "    invoke-static {v1, p1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I   然后再用logcat就能看到日志了。兴冲冲改好代码,打包,用signapk.jar签名,但进行安装时总是说Data exceeds UNCOMPRESS_DATA_MAX,会有一些资源找不到导致程序蹦掉。。google了很多解决方法都没成功。。 后来灵机一动,只把原来微信.apk里的classes.dex替换成修改过的版本,重新签名,it works,在log里看到密钥了! 一阵激动,于是把数据库拿到pc上,用本地编译的sqlcipher想直接读出来。。。但总还是失败。。难道腾讯还修改过加密算法…… 没有办法,想直接调用libmmcrypto.so。。结果发现我的工具链里的glibc和android系统里的版本不兼容,最终也没能实现交叉调用(这大概也是最初自己编译的sqlcipher不能被微信使用的原因)…… 后来想起android貌似还有个ndk,于是糙快猛入门,编译了个executable出来,总算work了。。 运行过程中发现mmcrypto打出了些debug信息,估计真是被腾讯改过了;而且版本好老,木有sqlcipher_export ,还得自己手动写程序dump…… 微信做了数据库加密,而且密钥跟机器相关(甚至可能还跟系统相关),一旦机器蹦了或丢了数据就没了,但不提供导出记录,呵呵…… 附:dump数据库用的小程序(从sqlite3 里抠了不少代码……) [cpp] view plaincopy #include <string.h>   #include <stdlib.h>   #include <dlfcn.h>   #include <stdio.h>   #include <sqlite3.h>   #include <assert.h>      #define DECLARE(name) \       static typeof(name) *f_##name;      DECLARE(sqlite3_close)   DECLARE(sqlite3_column_text)   DECLARE(sqlite3_column_count)   DECLARE(sqlite3_errmsg)   DECLARE(sqlite3_exec)   DECLARE(sqlite3_finalize)   DECLARE(sqlite3_free)   DECLARE(sqlite3_initialize)   DECLARE(sqlite3_mprintf)   DECLARE(sqlite3_open_v2)   DECLARE(sqlite3_prepare)   DECLARE(sqlite3_shutdown)   DECLARE(sqlite3_snprintf)   DECLARE(sqlite3_step)   DECLARE(sqlite3_trace)      #define UNUSED_PARAMETER(name) (void)(name)      static int callback(void *NotUsed, int argc, char **argv, char **azColName){       UNUSED_PARAMETER(NotUsed);       int i;       for(i=0; i<argc; i++){           printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");       }       printf("\n");       return 0;   }   /*  ** An pointer to an instance of this structure is passed from  ** the main program to the callback.  This is used to communicate  ** state and mode information.  */   struct callback_data {     sqlite3 *db;           /* The database */     int echoOn;            /* True to echo input commands */     int statsOn;           /* True to display memory stats before each finalize */     int cnt;               /* Number of records displayed so far */     FILE *out;             /* Write results here */     FILE *traceOut;        /* Output for f_sqlite3_trace() */     int nErr;              /* Number of errors seen */     int mode;              /* An output mode setting */     int writableSchema;    /* True if PRAGMA writable_schema=ON */     int showHeader;        /* True to show column names in List or Column mode */     char *zDestTable;      /* Name of destination table when MODE_Insert */     char separator[20];    /* Separator character for MODE_List */     int colWidth[100];     /* Requested width of each column when in column mode*/     int actualWidth[100];  /* Actual width of each column */     char nullvalue[20];    /* The text to print when a NULL comes back from                           ** the database */     const char *zDbFilename;    /* name of the database file */     const char *zVfs;           /* Name of VFS to use */     sqlite3_stmt *pStmt;   /* Current statement if any. */     FILE *pLog;            /* Write log output here */   };      /*  ** Execute a query statement that will generate SQL output.  Print  ** the result columns, comma-separated, on a line and then add a  ** semicolon terminator to the end of that line.  **  ** If the number of columns is 1 and that column contains text "--"  ** then write the semicolon on a separate line.  That way, if a   ** "--" comment occurs at the end of the statement, the comment  ** won't consume the semicolon terminator.  */   static int run_table_dump_query(     struct callback_data *p, /* Query context */     const char *zSelect,     /* SELECT statement to extract content */     const char *zFirstRow    /* Print before first row, if not NULL */   ){     sqlite3_stmt *pSelect;     int rc;     int nResult;     int i;     const char *z;     rc = f_sqlite3_prepare(p->db, zSelect, -1, &pSelect, 0);     if( rc!=SQLITE_OK || !pSelect ){       fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, f_sqlite3_errmsg(p->db));       p->nErr++;       return rc;     }     rc = f_sqlite3_step(pSelect);     nResult = f_sqlite3_column_count(pSelect);     while( rc==SQLITE_ROW ){       if( zFirstRow ){         fprintf(p->out, "%s", zFirstRow);         zFirstRow = 0;       }       z = (const char*)f_sqlite3_column_text(pSelect, 0);       fprintf(p->out, "%s", z);       for(i=1; i<nResult; i++){          fprintf(p->out, ",%s", f_sqlite3_column_text(pSelect, i));       }       if( z==0 ) z = "";       while( z[0] && (z[0]!='-' || z[1]!='-') ) z++;       if( z[0] ){         fprintf(p->out, "\n;\n");       }else{         fprintf(p->out, ";\n");       }           rc = f_sqlite3_step(pSelect);     }     rc = f_sqlite3_finalize(pSelect);     if( rc!=SQLITE_OK ){       fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, f_sqlite3_errmsg(p->db));       p->nErr++;     }     return rc;   }      /*  ** Compute a string length that is limited to what can be stored in  ** lower 30 bits of a 32-bit signed integer.  */   static int strlen30(const char *z){     const char *z2 = z;     while( *z2 ){ z2++; }     return 0x3fffffff & (int)(z2 - z);   }         /* zIn is either a pointer to a NULL-terminated string in memory obtained  ** from malloc(), or a NULL pointer. The string pointed to by zAppend is  ** added to zIn, and the result returned in memory obtained from malloc().  ** zIn, if it was not NULL, is freed.  **  ** If the third argument, quote, is not '\0', then it is used as a   ** quote character for zAppend.  */   static char *appendText(char *zIn, char const *zAppend, char quote){     int len;     int i;     int nAppend = strlen30(zAppend);     int nIn = (zIn?strlen30(zIn):0);        len = nAppend+nIn+1;     if( quote ){       len += 2;       for(i=0; i<nAppend; i++){         if( zAppend[i]==quote ) len++;       }     }        zIn = (char *)realloc(zIn, len);     if( !zIn ){       return 0;     }        if( quote ){       char *zCsr = &zIn[nIn];       *zCsr++ = quote;       for(i=0; i<nAppend; i++){         *zCsr++ = zAppend[i];         if( zAppend[i]==quote ) *zCsr++ = quote;       }       *zCsr++ = quote;       *zCsr++ = '\0';       assert( (zCsr-zIn)==len );     }else{       memcpy(&zIn[nIn], zAppend, nAppend);       zIn[len-1] = '\0';     }        return zIn;   }      /*  ** This is a different callback routine used for dumping the database.  ** Each row received by this callback consists of a table name,  ** the table type ("index" or "table") and SQL to create the table.  ** This routine should print text sufficient to recreate the table.  */   static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){     int rc;     const char *zTable;     const char *zType;     const char *zSql;     const char *zPrepStmt = 0;     struct callback_data *p = (struct callback_data *)pArg;        UNUSED_PARAMETER(azCol);     if( nArg!=3 ) return 1;     zTable = azArg[0];     zType = azArg[1];     zSql = azArg[2];          if( strcmp(zTable, "sqlite_sequence")==0 ){       zPrepStmt = "DELETE FROM sqlite_sequence;\n";     }else if( strcmp(zTable, "sqlite_stat1")==0 ){       fprintf(p->out, "ANALYZE sqlite_master;\n");     }else if( strncmp(zTable, "sqlite_", 7)==0 ){       return 0;     }else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){       char *zIns;       if( !p->writableSchema ){         fprintf(p->out, "PRAGMA writable_schema=ON;\n");         p->writableSchema = 1;       }       zIns = f_sqlite3_mprintf(          "INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"          "VALUES('table','%q','%q',0,'%q');",          zTable, zTable, zSql);       fprintf(p->out, "%s\n", zIns);       f_sqlite3_free(zIns);       return 0;     }else{       fprintf(p->out, "%s;\n", zSql);     }        if( strcmp(zType, "table")==0 ){       sqlite3_stmt *pTableInfo = 0;       char *zSelect = 0;       char *zTableInfo = 0;       char *zTmp = 0;       int nRow = 0;             zTableInfo = appendText(zTableInfo, "PRAGMA table_info(", 0);       zTableInfo = appendText(zTableInfo, zTable, '"');       zTableInfo = appendText(zTableInfo, ");", 0);          rc = f_sqlite3_prepare(p->db, zTableInfo, -1, &pTableInfo, 0);       free(zTableInfo);       if( rc!=SQLITE_OK || !pTableInfo ){         return 1;       }          zSelect = appendText(zSelect, "SELECT 'INSERT INTO ' || ", 0);       /* Always quote the table name, even if it appears to be pure ascii,      ** in case it is a keyword. Ex:  INSERT INTO "table" ... */       zTmp = appendText(zTmp, zTable, '"');       if( zTmp ){         zSelect = appendText(zSelect, zTmp, '\'');         free(zTmp);       }       zSelect = appendText(zSelect, " || ' VALUES(' || ", 0);       rc = f_sqlite3_step(pTableInfo);       while( rc==SQLITE_ROW ){         const char *zText = (const char *)f_sqlite3_column_text(pTableInfo, 1);         zSelect = appendText(zSelect, "quote(", 0);         zSelect = appendText(zSelect, zText, '"');         rc = f_sqlite3_step(pTableInfo);         if( rc==SQLITE_ROW ){           zSelect = appendText(zSelect, "), ", 0);         }else{           zSelect = appendText(zSelect, ") ", 0);         }         nRow++;       }       rc = f_sqlite3_finalize(pTableInfo);       if( rc!=SQLITE_OK || nRow==0 ){         free(zSelect);         return 1;       }       zSelect = appendText(zSelect, "|| ')' FROM  ", 0);       zSelect = appendText(zSelect, zTable, '"');          rc = run_table_dump_query(p, zSelect, zPrepStmt);       if( rc==SQLITE_CORRUPT ){         zSelect = appendText(zSelect, " ORDER BY rowid DESC", 0);         run_table_dump_query(p, zSelect, 0);       }       free(zSelect);     }     return 0;   }      /*  ** Run zQuery.  Use dump_callback() as the callback routine so that  ** the contents of the query are output as SQL statements.  ** 我找女朋友的聊天记录就是找他们帮忙的希望可以帮助你Q2690683499 希望可以帮助你 ** If we get a SQLITE_CORRUPT error, rerun the query after appending  ** "ORDER BY rowid DESC" to the end.  */   static int run_schema_dump_query(     struct callback_data *p,      const char *zQuery   ){     int rc;     char *zErr = 0;     rc = f_sqlite3_exec(p->db, zQuery, dump_callback, p, &zErr);     if( rc==SQLITE_CORRUPT ){       char *zQ2;       int len = strlen30(zQuery);       fprintf(p->out, "/****** CORRUPTION ERROR *******/\n");       if( zErr ){         fprintf(p->out, "/****** %s ******/\n", zErr);         f_sqlite3_free(zErr);         zErr = 0;       }       zQ2 = malloc( len+100 );       if( zQ2==0 ) return rc;       f_sqlite3_snprintf(len+100, zQ2, "%s ORDER BY rowid DESC", zQuery);       rc = f_sqlite3_exec(p->db, zQ2, dump_callback, p, &zErr);       if( rc ){         fprintf(p->out, "/****** ERROR: %s ******/\n", zErr);       }else{         rc = SQLITE_CORRUPT;       }       f_sqlite3_free(zErr);       free(zQ2);     }     return rc;   }      static void dump(struct callback_data *p)   {       /* When playing back a "dump", the content might appear in an order       ** which causes immediate foreign key constraints to be violated.       ** So disable foreign-key constraint enforcement to prevent problems. */       fprintf(p->out, "PRAGMA foreign_keys=OFF;\n");       fprintf(p->out, "BEGIN TRANSACTION;\n");       p->writableSchema = 0;       f_sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0);       p->nErr = 0;       run_schema_dump_query(p,                "SELECT name, type, sql FROM sqlite_master "               "WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'"               );       run_schema_dump_query(p,                "SELECT name, type, sql FROM sqlite_master "               "WHERE name=='sqlite_sequence'"               );       run_table_dump_query(p,               "SELECT sql FROM sqlite_master "               "WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0               );       if( p->writableSchema ){           fprintf(p->out, "PRAGMA writable_schema=OFF;\n");           p->writableSchema = 0;       }       f_sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);       f_sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0);       fprintf(p->out, p->nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n");   }      int main(int argc, char **argv){       sqlite3 *db;       char *zErrMsg = 0;       int rc, i;          if( argc < 4 ){           fprintf(stderr, "Usage: %s library DATABASE SQL-STATEMENTs\n", argv[0]);           return 1;       }              void *hdl = dlopen(argv[1], RTLD_LAZY);       if (!hdl) {           fprintf(stderr, "failed to load lib: %s\n", dlerror());           return -1;       }      #define SOLVE(name) \       f_##name = dlsym(hdl, # name); \       if (!f_##name) { \           fprintf(stderr, "failed to resolve %s: %s\n", #name, dlerror()); \           return -1; \       }          SOLVE(sqlite3_close);       SOLVE(sqlite3_column_text);       SOLVE(sqlite3_column_count);       SOLVE(sqlite3_errmsg);       SOLVE(sqlite3_exec);       SOLVE(sqlite3_finalize);       SOLVE(sqlite3_free);       SOLVE(sqlite3_initialize);       SOLVE(sqlite3_mprintf);       SOLVE(sqlite3_open_v2);       SOLVE(sqlite3_prepare);       SOLVE(sqlite3_shutdown);       SOLVE(sqlite3_snprintf);       SOLVE(sqlite3_step);       SOLVE(sqlite3_trace);          f_sqlite3_initialize();          rc = f_sqlite3_open_v2(argv[2], &db,               SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);       if( rc ){           fprintf(stderr, "Can't open database: %s\n", f_sqlite3_errmsg(db));           f_sqlite3_close(db);           return 1;       }       for (i = 3; i < argc; i ++)       {           fprintf(stderr, "exec: %s\n", argv[i]);           if (!strncmp(argv[i], ".dump", 5)) {               struct callback_data p;               memset(&p, 0, sizeof(p));               p.out = fopen(argv[i] + 5, "w");               if (!p.out) {                   fprintf(stderr, "failed to open file %s: %m\n", argv[i] + 5);                   break;               }               p.db = db;               dump(&p);               fclose(p.out);               continue;           }           rc = f_sqlite3_exec(db, argv[i], callback, 0, &zErrMsg);           if( rc!=SQLITE_OK ) {               fprintf(stderr, "SQL error: %s\n", zErrMsg);               f_sqlite3_free(zErrMsg);               break;           }       }       f_sqlite3_close(db);       f_sqlite3_shutdown();       return 0;   }  

上一篇:再谈*在参数中的使用
下一篇:phpmyadmin的初始账号密码是多少

相关文章

相关评论