首页 > 恢复资讯 > 恢复教程 > 正文

手机里的微信聊天记录如何导出

2016-08-30 12:59:16   来源:华军科技数据恢复

手机恢复微信聊天记录数据,首先要考虑找到微信聊天数据库,恢复数据库后导出数据,详细描述了导出微信聊天记录的方法,镜像手机emmc存储芯片或者通过数据线读取到数据本文没有描述。
微信

首先,很容易发现数据库在/data/data/com.tencent.mm/MicroMsg/ 下,file之,显示为data…… 好吧看来被腾讯加密了。
在/data/data/com.tencent.mm/里随便看,发现lib里有个libmmcrypto.so,大概就是用来加密的了。nm -D之,发现一堆sqlite3_*;稍微google下,觉得应该是用了sqlcipher。于是只用拿到密钥就好啦。
希望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了一会儿,发现了以下方法:

  1. const-string v1, "!!!!!SQL:  " 
  2. 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 里抠了不少代码……)


  1. #include 
  2. #include 
  3. #include 
  4. #include 
  5. #include 
  6. #include 
  7.  
  8. #define DECLARE(name) \
  9.         static typeof(name) *f_##name;
  10.  
  11. DECLARE(sqlite3_close)
  12. DECLARE(sqlite3_column_text)
  13. DECLARE(sqlite3_column_count)
  14. DECLARE(sqlite3_errmsg)
  15. DECLARE(sqlite3_exec)
  16. DECLARE(sqlite3_finalize)
  17. DECLARE(sqlite3_free)
  18. DECLARE(sqlite3_initialize)
  19. DECLARE(sqlite3_mprintf)
  20. DECLARE(sqlite3_open_v2)
  21. DECLARE(sqlite3_prepare)
  22. DECLARE(sqlite3_shutdown)
  23. DECLARE(sqlite3_snprintf)
  24. DECLARE(sqlite3_step)
  25. DECLARE(sqlite3_trace)
  26.  
  27. #define UNUSED_PARAMETER(name) (void)(name)
  28.  
  29. static int callback(void *NotUsed, int argc, char **argv, char **azColName){
  30.         UNUSED_PARAMETER(NotUsed);
  31.         int i;
  32.         for(i=0; i
  33.                 printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
  34.         }
  35.         printf("\n");
  36.         return 0;
  37. }
  38. /*
  39. ** An pointer to an instance of this structure is passed from
  40. ** the main program to the callback.  This is used to communicate
  41. ** state and mode information.
  42. */
  43. struct callback_data {
  44.   sqlite3 *db;           /* The database */
  45.   int echoOn;            /* True to echo input commands */
  46.   int statsOn;           /* True to display memory stats before each finalize */
  47.   int cnt;               /* Number of records displayed so far */
  48.   FILE *out;             /* Write results here */
  49.   FILE *traceOut;        /* Output for f_sqlite3_trace() */
  50.   int nErr;              /* Number of errors seen */
  51.   int mode;              /* An output mode setting */
  52.   int writableSchema;    /* True if PRAGMA writable_schema=ON */
  53.   int showHeader;        /* True to show column names in List or Column mode */
  54.   char *zDestTable;      /* Name of destination table when MODE_Insert */
  55.   char separator[20];    /* Separator character for MODE_List */
  56.   int colWidth[100];     /* Requested width of each column when in column mode*/
  57.   int actualWidth[100];  /* Actual width of each column */
  58.   char nullvalue[20];    /* The text to print when a NULL comes back from
  59.                          ** the database */
  60.   const char *zDbFilename;    /* name of the database file */
  61.   const char *zVfs;           /* Name of VFS to use */
  62.   sqlite3_stmt *pStmt;   /* Current statement if any. */
  63.   FILE *pLog;            /* Write log output here */
  64. };
  65.  
  66. /*
  67. ** Execute a query statement that will generate SQL output.  Print
  68. ** the result columns, comma-separated, on a line and then add a
  69. ** semicolon terminator to the end of that line.
  70. **
  71. ** If the number of columns is 1 and that column contains text "--"
  72. ** then write the semicolon on a separate line.  That way, if a 
  73. ** "--" comment occurs at the end of the statement, the comment
  74. ** won't consume the semicolon terminator.
  75. */
  76. static int run_table_dump_query(
  77.   struct callback_data *p, /* Query context */
  78.   const char *zSelect,     /* SELECT statement to extract content */
  79.   const char *zFirstRow    /* Print before first row, if not NULL */
  80. ){
  81.   sqlite3_stmt *pSelect;
  82.   int rc;
  83.   int nResult;
  84.   int i;
  85.   const char *z;
  86.   rc = f_sqlite3_prepare(p->db, zSelect, -1, &pSelect, 0);
  87.   if( rc!=SQLITE_OK || !pSelect ){
  88.     fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, f_sqlite3_errmsg(p->db));
  89.     p->nErr++;
  90.     return rc;
  91.   }
  92.   rc = f_sqlite3_step(pSelect);
  93.   nResult = f_sqlite3_column_count(pSelect);
  94.   while( rc==SQLITE_ROW ){
  95.     if( zFirstRow ){
  96.       fprintf(p->out, "%s", zFirstRow);
  97.       zFirstRow = 0;
  98.     }
  99.     z = (const char*)f_sqlite3_column_text(pSelect, 0);
  100.     fprintf(p->out, "%s", z);
  101.     for(i=1; i
  102.       fprintf(p->out, ",%s", f_sqlite3_column_text(pSelect, i));
  103.     }
  104.     if( z==0 ) z = "";
  105.     while( z[0] && (z[0]!='-' || z[1]!='-') ) z++;
  106.     if( z[0] ){
  107.       fprintf(p->out, "\n;\n");
  108.     }else{
  109.       fprintf(p->out, ";\n");
  110.     }    
  111.     rc = f_sqlite3_step(pSelect);
  112.   }
  113.   rc = f_sqlite3_finalize(pSelect);
  114.   if( rc!=SQLITE_OK ){
  115.     fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, f_sqlite3_errmsg(p->db));
  116.     p->nErr++;
  117.   }
  118.   return rc;
  119. }
  120.  
  121. /*
  122. ** Compute a string length that is limited to what can be stored in
  123. ** lower 30 bits of a 32-bit signed integer.
  124. */
  125. static int strlen30(const char *z){
  126.   const char *z2 = z;
  127.   while( *z2 ){ z2++; }
  128.   return 0x3fffffff & (int)(z2 - z);
  129. }
  130.  
  131.  
  132. /* zIn is either a pointer to a NULL-terminated string in memory obtained
  133. ** from malloc(), or a NULL pointer. The string pointed to by zAppend is
  134. ** added to zIn, and the result returned in memory obtained from malloc().
  135. ** zIn, if it was not NULL, is freed.
  136. **
  137. ** If the third argument, quote, is not '\0', then it is used as a 
  138. ** quote character for zAppend.
  139. */
  140. static char *appendText(char *zIn, char const *zAppend, char quote){
  141.   int len;
  142.   int i;
  143.   int nAppend = strlen30(zAppend);
  144.   int nIn = (zIn?strlen30(zIn):0);
  145.  
  146.   len = nAppend+nIn+1;
  147.   if( quote ){
  148.     len += 2;
  149.     for(i=0; i
  150.       if( zAppend[i]==quote ) len++;
  151.     }
  152.   }
  153.  
  154.   zIn = (char *)realloc(zIn, len);
  155.   if( !zIn ){
  156.     return 0;
  157.   }
  158.  
  159.   if( quote ){
  160.     char *zCsr = &zIn[nIn];
  161.     *zCsr++ = quote;
  162.     for(i=0; i
  163.       *zCsr++ = zAppend[i];
  164.       if( zAppend[i]==quote ) *zCsr++ = quote;
  165.     }
  166.     *zCsr++ = quote;
  167.     *zCsr++ = '\0';
  168.     assert( (zCsr-zIn)==len );
  169.   }else{
  170.     memcpy(&zIn[nIn], zAppend, nAppend);
  171.     zIn[len-1] = '\0';
  172.   }
  173.  
  174.   return zIn;
  175. }
  176.  
  177. /*
  178. ** This is a different callback routine used for dumping the database.
  179. ** Each row received by this callback consists of a table name,
  180. ** the table type ("index" or "table") and SQL to create the table.
  181. ** This routine should print text sufficient to recreate the table.
  182. */
  183. static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
  184.   int rc;
  185.   const char *zTable;
  186.   const char *zType;
  187.   const char *zSql;
  188.   const char *zPrepStmt = 0;
  189.   struct callback_data *p = (struct callback_data *)pArg;
  190.  
  191.   UNUSED_PARAMETER(azCol);
  192.   if( nArg!=3 ) return 1;
  193.   zTable = azArg[0];
  194.   zType = azArg[1];
  195.   zSql = azArg[2];
  196.   
  197.   if( strcmp(zTable, "sqlite_sequence")==0 ){
  198.     zPrepStmt = "DELETE FROM sqlite_sequence;\n";
  199.   }else if( strcmp(zTable, "sqlite_stat1")==0 ){
  200.     fprintf(p->out, "ANALYZE sqlite_master;\n");
  201.   }else if( strncmp(zTable, "sqlite_", 7)==0 ){
  202.     return 0;
  203.   }else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
  204.     char *zIns;
  205.     if( !p->writableSchema ){
  206.       fprintf(p->out, "PRAGMA writable_schema=ON;\n");
  207.       p->writableSchema = 1;
  208.     }
  209.     zIns = f_sqlite3_mprintf(
  210.        "INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"
  211.        "VALUES('table','%q','%q',0,'%q');",
  212.        zTable, zTable, zSql);
  213.     fprintf(p->out, "%s\n", zIns);
  214.     f_sqlite3_free(zIns);
  215.     return 0;
  216.   }else{
  217.     fprintf(p->out, "%s;\n", zSql);
  218.   }
  219.  
  220.   if( strcmp(zType, "table")==0 ){
  221.     sqlite3_stmt *pTableInfo = 0;
  222.     char *zSelect = 0;
  223.     char *zTableInfo = 0;
  224.     char *zTmp = 0;
  225.     int nRow = 0;
  226.    
  227.     zTableInfo = appendText(zTableInfo, "PRAGMA table_info(", 0);
  228.     zTableInfo = appendText(zTableInfo, zTable, '"');
  229.     zTableInfo = appendText(zTableInfo, ");", 0);
  230.  
  231.     rc = f_sqlite3_prepare(p->db, zTableInfo, -1, &pTableInfo, 0);
  232.     free(zTableInfo);
  233.     if( rc!=SQLITE_OK || !pTableInfo ){
  234.       return 1;
  235.     }
  236.  
  237.     zSelect = appendText(zSelect, "SELECT 'INSERT INTO ' || ", 0);
  238.     /* Always quote the table name, even if it appears to be pure ascii,
  239.     ** in case it is a keyword. Ex:  INSERT INTO "table" ... */
  240.     zTmp = appendText(zTmp, zTable, '"');
  241.     if( zTmp ){
  242.       zSelect = appendText(zSelect, zTmp, '\'');
  243.       free(zTmp);
  244.     }
  245.     zSelect = appendText(zSelect, " || ' VALUES(' || ", 0);
  246.     rc = f_sqlite3_step(pTableInfo);
  247.     while( rc==SQLITE_ROW ){
  248.       const char *zText = (const char *)f_sqlite3_column_text(pTableInfo, 1);
  249.       zSelect = appendText(zSelect, "quote(", 0);
  250.       zSelect = appendText(zSelect, zText, '"');
  251.       rc = f_sqlite3_step(pTableInfo);
  252.       if( rc==SQLITE_ROW ){
  253.         zSelect = appendText(zSelect, "), ", 0);
  254.       }else{
  255.         zSelect = appendText(zSelect, ") ", 0);
  256.       }
  257.       nRow++;
  258.     }
  259.     rc = f_sqlite3_finalize(pTableInfo);
  260.     if( rc!=SQLITE_OK || nRow==0 ){
  261.       free(zSelect);
  262.       return 1;
  263.     }
  264.     zSelect = appendText(zSelect, "|| ')' FROM  ", 0);
  265.     zSelect = appendText(zSelect, zTable, '"');
  266.  
  267.     rc = run_table_dump_query(p, zSelect, zPrepStmt);
  268.     if( rc==SQLITE_CORRUPT ){
  269.       zSelect = appendText(zSelect, " ORDER BY rowid DESC", 0);
  270.       run_table_dump_query(p, zSelect, 0);
  271.     }
  272.     free(zSelect);
  273.   }
  274.   return 0;
  275. }
  276.  
  277. /*
  278. ** Run zQuery.  Use dump_callback() as the callback routine so that
  279. ** the contents of the query are output as SQL statements.
  280. **
  281. ** If we get a SQLITE_CORRUPT error, rerun the query after appending
  282. ** "ORDER BY rowid DESC" to the end.
  283. */
  284. static int run_schema_dump_query(
  285.   struct callback_data *p, 
  286.   const char *zQuery
  287. ){
  288.   int rc;
  289.   char *zErr = 0;
  290.   rc = f_sqlite3_exec(p->db, zQuery, dump_callback, p, &zErr);
  291.   if( rc==SQLITE_CORRUPT ){
  292.     char *zQ2;
  293.     int len = strlen30(zQuery);
  294.     fprintf(p->out, "/****** CORRUPTION ERROR *******/\n");
  295.     if( zErr ){
  296.       fprintf(p->out, "/****** %s ******/\n", zErr);
  297.       f_sqlite3_free(zErr);
  298.       zErr = 0;
  299.     }
  300.     zQ2 = malloc( len+100 );
  301.     if( zQ2==0 ) return rc;
  302.     f_sqlite3_snprintf(len+100, zQ2, "%s ORDER BY rowid DESC", zQuery);
  303.     rc = f_sqlite3_exec(p->db, zQ2, dump_callback, p, &zErr);
  304.     if( rc ){
  305.       fprintf(p->out, "/****** ERROR: %s ******/\n", zErr);
  306.     }else{
  307.       rc = SQLITE_CORRUPT;
  308.     }
  309.     f_sqlite3_free(zErr);
  310.     free(zQ2);
  311.   }
  312.   return rc;
  313. }
  314.  
  315. static void dump(struct callback_data *p)
  316. {
  317.         /* When playing back a "dump", the content might appear in an order
  318.          ** which causes immediate foreign key constraints to be violated.
  319.          ** So disable foreign-key constraint enforcement to prevent problems. */
  320.         fprintf(p->out, "PRAGMA foreign_keys=OFF;\n");
  321.         fprintf(p->out, "BEGIN TRANSACTION;\n");
  322.         p->writableSchema = 0;
  323.         f_sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0);
  324.         p->nErr = 0;
  325.         run_schema_dump_query(p, 
  326.                         "SELECT name, type, sql FROM sqlite_master "
  327.                         "WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'"
  328.                         );
  329.         run_schema_dump_query(p, 
  330.                         "SELECT name, type, sql FROM sqlite_master "
  331.                         "WHERE name=='sqlite_sequence'"
  332.                         );
  333.         run_table_dump_query(p,
  334.                         "SELECT sql FROM sqlite_master "
  335.                         "WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0
  336.                         );
  337.         if( p->writableSchema ){
  338.                 fprintf(p->out, "PRAGMA writable_schema=OFF;\n");
  339.                 p->writableSchema = 0;
  340.         }
  341.         f_sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
  342.         f_sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0);
  343.         fprintf(p->out, p->nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n");
  344. }
  345.  
  346. int main(int argc, char **argv){
  347.         sqlite3 *db;
  348.         char *zErrMsg = 0;
  349.         int rc,

    版权说明:如非注明,本站文章均为华军科技数据恢复原创,转载请注明出处和附带本文链接。

CopyRight2014-2016 杭州华军科技有限公司//www.sosit.com.cn 版权所有 浙ICP备15017254号-5 成功案例|华军资讯|硬盘服务|数据恢复