亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

PC微信逆向分析の繞過加密訪問SQLite數據庫

發布時間:2020-04-08 16:20:56 來源:網絡 閱讀:1190 作者:趙慶明老師 欄目:編程語言

PC微信逆向分析の繞過加密訪問SQLite數據庫


作者:zmrbak(趙慶明老師)


前言:


微信,無疑是國內目前最為流行的應用軟件,其在社交領域的霸主地位依然無人可以撼動!它不但撐起了龐大的騰訊軟件帝國的一角,而且足以讓騰訊傲立于BAT中國互聯網三巨頭之首。微信,改變了這個世界,而騰訊也成了無數優秀程序員夢想的歸宿。圍繞著微信這個軟件的延伸,騰訊也無私地為代碼世界貢獻了近百個優秀的開源項目。


從古到今,任何一個巨人,都是站在前一輩巨人的肩膀上而成長為新的巨人。百度如此,阿里如此,騰訊亦是如此。SQLite數據庫,一個不為人熟知,但已超過10000億個設備在使用的開源數據庫,已經滲入人們生活的各個環節。目前超過11億個活躍的微信號,每時每刻都在與這個深藏功與名的SQLite數據庫共舞著。


由于微信的巨大成功,從而成為眾多癡迷技術的探秘者的實驗品。同樣,嵌入微信內部那個深藏功名的SQLite數據庫,也成為這些人的又一個解剖對象。接下來,準備好我們的工具,讓我們一起來窺探其中的奧妙!


微信中的數據庫


無論是在微信安裝還是運行的時候,普通用戶是不會覺察到微信中居然還有一個默默無聞的SQLite數據庫。就算在微信的安裝目錄中,你也不會發現有任何對于SQLite數據庫的描述、說明和感謝(基于SQLite的許可協議,不允許以SQLite的名義來推銷產品),但是卻在用戶的文件夾下(C:\Users\xxxxxx\Documents\WeChat Files\xxxx\Msg\)留下一堆以db為擴展名的文件。對于細心的探索者來說,微信留下來的任何蛛絲馬跡,都會變成重要的探秘線索。


這些db文件,都是經過加密處理的。即使你懷疑它是一個SQLite數據庫文件,但是你根本無法用任何一個SQLite管理器打開。雖然網上有不少的文章告訴你,去到微信中尋找那個密碼,然后使用某某工具進行解密還原。先不說這些工具各種各樣的莫名其妙的問題,就算你確實可以順利搞到密碼,再到完成了解密,再進行訪問,其實已經晚了半拍。當然,你要相信,騰訊的那些頂級程序員,會在保證軟件功能和性能的情況下,會為這些探秘者設置各種各樣的障礙。至少我們知道,那些db文件的確是一個個SQLite數據庫,只是經過了加密處理而已。


窺探SQLite數據庫


SQLite數據庫是一個開源的軟件,也就是說,任何人都可以免費地獲取它的源代碼,對它進行研究、分析,當然還有修改。如果你要把你修改的內容“貢獻”給SQLite官方,那么你必須申明你放棄你修改的這些代碼的“版權”,不過你提供的代碼基本不會原樣照搬,而是被SQLite官方按照自己的標準重寫一次(開源,但不開放)。當然,如果你要修改后自己用的話,那就隨便你啦,SQLite官方并不會找你要錢。即便如此,g---o--o--g--l--e依然每年給予SQLite巨額的贊助,當然國內騰訊、阿里等這些巨頭也毫不吝嗇。雖然這個軟件包括源代碼在內都是免費開放的,但由于有不少的巨頭為其撐腰,就算SQLite不收你的錢,它也會活得很好。如果你非要交錢買個許可的話,那就花6000美元買一個吧,官方稱這些錢會用于資助SQLite的持續改進和支持。


既然SQLite數據庫是開放源代碼的,而且還有來自微信開發團隊的嚴苛加密,那么將其與微信一起研究,則更為令人振奮。登上SQLite的官方主頁,http://www.sqlite.org,你可以隨時把SQLite誕生以來近20年的各個版本抓來研究一番。網站上還有各種示例,教你如何使用SQLite數據庫,詳盡的各種解說,如果你愿意,你可以通過這個網站了解到它的各種之末細節和詳盡的實現方式。雖然,網站沒提供中文版,不過,語言并不是障礙,瀏覽器的翻譯功能,可以讓你了解個八九不離十。


一個簡單的SQLite示例


如果你還不知道這個SQLite數據庫怎么用,網站上提供了TCL的示例代碼和C語言的示例代碼。現摘抄C示例代碼如下(代碼來源:https://www.sqlite.com/quickstart.html)。


01? #include <stdio.h>

02? #include <sqlite3.h>

03??

04? static int callback(void *NotUsed, int argc, char **argv, char **azColName){

05? ? int i;

06? ? for(i=0; i<argc; i++){

07? ? ? printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");

08? ? }

09? ? printf("\n");

10? ? return 0;

11? }

12??

13? int main(int argc, char **argv){

14? ? sqlite3 *db;

15? ? char *zErrMsg = 0;

16? ? int rc;

17??

18? ? if( argc!=3 ){

19? ? ? fprintf(stderr, "Usage: %s DATABASE SQL-STATEMENT\n", argv[0]);

20? ? ? return(1);

21? ? }

22? ? rc = sqlite3_open(argv[1], &db);

23? ? if( rc ){

24? ? ? fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));

25? ? ? sqlite3_close(db);

26? ? ? return(1);

27? ? }

28? ? rc = sqlite3_exec(db, argv[2], callback, 0, &zErrMsg);

29? ? if( rc!=SQLITE_OK ){

30? ? ? fprintf(stderr, "SQL error: %s\n", zErrMsg);

31? ? ? sqlite3_free(zErrMsg);

32? ? }

33? ? sqlite3_close(db);

34? ? return 0;

35? }


示例很簡單,也很完善。由于我們的目的是為了探索和研究,因此,我們在確保程序示例可用的情況下,再繼續精簡。我們刪除了很多代碼,只剩下核心的幾條:


01? #include <stdio.h>

02? #include <sqlite3.h>

03??

04? static int callback(void *NotUsed, int argc, char **argv, char **azColName){

06? ? for(int i=0; i<argc; i++){

07? ? ? printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");

08? ? }

10? ? return 0;

11? }

12??

13? int main(int argc, char **argv){

14? ? sqlite3 *db;

22? ? sqlite3_open(argv[1], &db);

28? ? sqlite3_exec(db, argv[2], callback, 0, &zErrMsg);

33? ? sqlite3_close(db);

34? ? return 0;

35? }


先從main函數開始,首先定義一個sqlite3的db作為數據庫的句柄,然后讓執行sqlite3_open打開數據庫,接下來執行sqlite3_exec查詢數據庫,最后執行sqlite3_close關閉數據庫。在sqlite3_exec執行期間,使用回調函數callback來處理查詢的結果。這,就是一個完整的流程。


執行sqlite3_open打開數據庫這個操作,要執行不少的操作,相對比價耗費系統資源。如果一個軟件在運行過程中要不斷地查詢數據庫,修改數據庫,那么最優的方式就是打開后不要關閉,等到軟件關閉的時候再關閉數據庫。這樣可以節約系統資源,也可以提高數據庫的響應速度。


繞過加密訪問SQLite數據庫


無論是給數據庫加上密碼,還是使用其它更強有力的方式為數據庫加密,無非是為了防止數據庫被非法操作。但是,由于基于性能的考慮,應用軟件打開SQLite數據庫后,只有等到應用程序被關閉的時候,才去關閉數據庫。那么在整個應用軟件運行期間,SQLite數據庫一旦被打開,則將一直保持打開狀態。也就是說,上面示例的db,在程序還未調用sqlite3_close函數前,一直是有效的,隨時可以接受sqlite3_exec函數的查詢操作。這個查詢并不是指select,而是指所有可能的sql語句。我們暫且不討論具有破壞性的操作,如增加(INSERT)、修改(UPDATE)、刪除(DELETE)等,在這里我們只來討論“無破壞性”的“查”(SELECT)的操作。


數據庫的加密驗證,往往只在于打開數據庫的時候,一旦數據庫被打開,剩下的操作,則不再對加密進行驗證。因此,我們等數據庫打開之后,獲取db這個數值,然后就可以“非法”地調用sqlite3_exec函數,來執行我們期望的操作。如果這樣操作,那么無論軟件設計人員設計的任何加密方式,都形同虛設。也就是說,我們可以輕松地實現“繞過加密來訪問SQLite數據庫”。


為了實現“繞過加密來訪問SQLite數據庫”,接下來需要解決三個問題。

  • 如何取得已打開的數據庫的句柄db的具體數值?

  • 可被非法地調用的sqlite3_exec函數在哪里?

  • 如何非法地調用sqlite3_exec函數?


接下來,讓我們依次來解決這三個問題。


如何取得打開數據庫的句柄?


如果從正向編程的思維來思考的話,似乎沒有答案。但是如果用逆向的思維,你會發現,其實很簡單,在調用sqlite3_open函數的時候,其中一個參數就是db,這個db的數值,就是我們正在尋找的打開數據庫的句柄。因此,這個問題又轉換成,在什么地方調用了sqlite3_open函數。那么,只要我們在調用完sqlite3_open函數之后,馬上獲取db的值,這個問題就解決了。


如果你使用過OD或者IDA,你就知道,這些軟件可以幫你分析出,在程序的什么地方調用了這個函數,而且每一個調用的地方都可以幫你分析出來。如果再配合inline hook,取數據就如同探囊取物一般容易。


我們知道,在調用sqlite3_open函數的時候,必然會打開一個文件。在Windows系統中,必然會調用Windows中的CreateFileW函數,而這個函數可以被OD、IDA等逆向工具所識別。因此,通過倒推的方式,就能順藤摸瓜找到sqlite3_open函數。如果使用OD來動態調試的話,sqlite3_open就非常容易找到,而且還可以找到調用這個函數的代碼段,同時還可以直觀地觀察到某內存地址中的具體數值。因此,db的值就可以很容易地獲取。如果你再編寫了inline hook后,只要程序調用了sqlite3_open函數,就可以馬上獲取db的值。


sqlite3_exec函數在哪里?


在軟件中往往會執行一些sql語句,而sqlite3_exec函數對多條函數進行了包裝,讓程序員執行sql語句更為簡單。因此,在應用軟件中會有大量的sqlite3_exec函數調用。這恰好是一個切入點。


sqlite3_exec函數的第一個參數是數據庫句柄,其實也就是一個DWORD,第二個參數是一條被執行的sql語句,其實就是一個字符串的地址。這些字符串,往往在程序員編程的時候手工寫入的,并且嵌入到軟件之中,而這些字符串在OD、IDA等這些軟件中,可以很容易地識別出來。從而成為找到這個函數的切入點。


比如在軟件中尋找“select * from”之類的sql語句,就可以簡單地定位到sqlite3_exec函數,從而確定它在應用軟件中的具體地址。


如何調用sqlite3_exec


既然我們已經獲得到數據庫的句柄db的值,而且已經找到和sqlite3_exec的地址,接下來我們就可以來“非法”地調用這個sqlite3_exec函數了。首先,我們來了解一下這個函數的所需的參數:


sqlite3_exec(db, argv[2], callback, 0, &zErrMsg);


第二個參數,是一個查詢的sql語句。我們可以定義一個sql的字符串即可,比如“select * from sqlite_master”。由于這條語句是用來查詢這個數據庫的結構的,因此,在任何一個sqlite數據庫中都可以執行成功。當然,你也可以寫一個你自己喜歡的sql語句。為了確保一定能查詢到信息,我們就用這個字符串。


第三個參數,是一個回調函數,參照SQLite官方的示例代碼編寫。


第四個參數,是為這個回調函數提供的參數,如果沒有,或者不需要提供,那么可以直接填寫0或NULL。


第五個參數,返回執行的錯誤信息,如果不需要的話,可以填寫為0或者NULL。


我們只是找到了sqlite3_exec在軟件中的地址而已,但地址并不是一個函數,我們也無法直接用字符sqlite3_exec來調用這個函數。但是,我們可以通過C語言內嵌匯編來調用這個函數,也可以用“函數”指針的方式來調用。使用匯編語言,不是很直觀,因此使用函數指針,是一個比較好的方法。


我們從SQLite源代碼中找到sqlite3_exec函數,把它復制過來,然后做一些修改。把sqlite3_exec第一個字符變成大寫Sqlite3_exec,加上typedef、__cdecl*,刪除形參,再將db所在的形參改為DWORD:


typedef int(__cdecl* Sqlite3_exec)(

? DWORD,? ? ? ? ? ? ? ? /* The database on which the SQL executes */

? const char *,? ? ? ? ? ? ?/* The SQL to be executed */

? sqlite3_callback,? ? ? ? ? /* Invoke this callback routine */

? void *,? ? ? ? ? ? ? ? ? /* First argument to xCallback() */

? char **? ? ? ? ? ? ? ? ? /* Write error messages here */

);


假如sqlite3_exec的地址是:0x12345678,那么我們可以這樣定義和調用:


Sqlite3_ exec p_Sqlite3_ exec = (Sqlite3_ exec) 0x12345678;

p_Sqlite3_ exec(db, zSql, callback, 0, 0);


運行結果示例


?PC微信逆向分析の繞過加密訪問SQLite數據庫

PC微信逆向分析の繞過加密訪問SQLite數據庫

PC微信逆向分析の繞過加密訪問SQLite數據庫

PC微信逆向分析の繞過加密訪問SQLite數據庫

?

?總結:


很多初次接觸到逆向的人,會被黑壓壓的匯編代碼、一串串的C代碼、還有風格詭異的e語言所嚇倒。常常有人問我“逆向分析很難嗎?”。我也套用一句經典來回答:“天下事有難易乎?為之,則難者亦易矣;不為,則易者亦難矣!”


逆向分析,如同玩猜謎活動,當你看到一個個謎底慢慢浮現的時候,只有身在其中的人,才能享受其中的刺激和樂趣。作為看客,永遠無緣體驗這份樂趣。你并不是孤身一人,你還有我們。加入我們的QQ交流群456197310,一起在玩這個其樂無窮的猜謎活動。


源碼分享

https://github.com/zmrbak/SQLiteReverse



交流QQ群:

456197310 點擊鏈接加入群聊【軟件逆向分析入門】


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

汉沽区| 理塘县| 肃南| 浏阳市| 花莲市| 马关县| 岑巩县| 岳阳市| 积石山| 江华| 封开县| 龙井市| 山东| 长泰县| 定边县| 屯留县| 怀集县| 衡山县| 汶川县| 新民市| 瑞昌市| 济阳县| 太和县| 泰来县| 原平市| 黄骅市| 马鞍山市| 南川市| 苍山县| 山东省| 天气| 湄潭县| 沈丘县| 改则县| 遂溪县| 新巴尔虎右旗| 霸州市| 镇安县| 都江堰市| 肥城市| 栾城县|