어떻게 위챗 채팅 기록을 내보냅니까
/data/data/com.tencent.mm/리를 마음대로 보니lib에libmmcrypto가 있는 것을 발견하였다.so, 아마 암호화하는 데 쓰일 거예요.nm-D의, 한 무더기의 sqlite3 * 발견;약간 구글에서 sqlcipher를 사용한 것 같아요.그래서 키만 받았으면 좋겠어요.
const-string v1, "!!!!!SQL: "
invoke-static {v1, p1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
그리고logcat으로 로그를 볼 수 있다.흥겹게 코드를 고치고 포장하고signapk을 사용합니다.jar 서명, 하지만 설치할 때 항상 Data exceeds UNCOMPRESSDATA_MAX, 일부 자원을 찾지 못하면 프로그램이 튀어나올 수 있습니다.구글의 많은 해결 방법이 성공하지 못했다.나중에 영감이 떠올라 원래의 위챗만 썼다.apk의classes.dex를 수정된 버전으로 바꾸고 다시 서명합니다. itworks,log에서 키를 보았습니다!한바탕 흥분하여 데이터베이스를 pc에 가져와서 로컬에서 컴파일한 sqlcipher로 직접 읽으려고 합니다...그래도 실패했어..설마 텐센트가 암호화 알고리즘도 수정했단 말인가...어쩔 수 없이libmmcrypto를 직접 호출하려고 합니다.so..그 결과 내 도구 체인의glibc와android시스템의 버전이 호환되지 않았고 최종적으로 교차 호출을 실현하지 못했다. (이것은 아마도 처음에 자신이 컴파일한 sqlcipher가 위챗에 사용되지 못한 원인일 것이다)...나중에 안드로이드에 ndk가 있는 것 같다는 생각이 들어서 급하게 입문하여executable를 컴파일하여 마침내 work를 만들었다.운행 과정에서 mmcrypto가 debug 정보를 보낸 것을 발견했는데 정말 텐센트에 의해 바뀌었을 것이다.그리고 버전이 너무 낡았어. 나무는 sqlcipherexport, 프로그램 dump도 직접 써야 돼...첨부:dump 데이터베이스에 사용되는 작은 프로그램(sqlite3에서 많은 코드를 파냈는데......)
#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
", azColName[i], argv[i] ? argv[i] : "NULL");
}
printf("
");
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 *****/
", 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, "
;
");
}else{
fprintf(p->out, ";
");
}
rc = f_sqlite3_step(pSelect);
}
rc = f_sqlite3_finalize(pSelect);
if( rc!=SQLITE_OK ){
fprintf(p->out, "/**** ERROR: (%d) %s *****/
", 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;
";
}else if( strcmp(zTable, "sqlite_stat1")==0 ){
fprintf(p->out, "ANALYZE sqlite_master;
");
}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;
");
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
", zIns);
f_sqlite3_free(zIns);
return 0;
}else{
fprintf(p->out, "%s;
", 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.
**
** 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 *******/
");
if( zErr ){
fprintf(p->out, "/****** %s ******/
", 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 ******/
", 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;
");
fprintf(p->out, "BEGIN TRANSACTION;
");
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;
");
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
" : "COMMIT;
");
}
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
", argv[0]);
return 1;
}
void *hdl = dlopen(argv[1], RTLD_LAZY);
if (!hdl) {
fprintf(stderr, "failed to load lib: %s
", dlerror());
return -1;
}
#define SOLVE(name) \
f_##name = dlsym(hdl, # name); \
if (!f_##name) { \
fprintf(stderr, "failed to resolve %s: %s
", #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
", f_sqlite3_errmsg(db));
f_sqlite3_close(db);
return 1;
}
for (i = 3; i < argc; i ++)
{
fprintf(stderr, "exec: %s
", 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
", 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
", zErrMsg);
f_sqlite3_free(zErrMsg);
break;
}
}
f_sqlite3_close(db);
f_sqlite3_shutdown();
return 0;
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.