一、前言
在前一篇文章中詳細介紹了Android現階段可以采用的幾種反調試方案策略,我們在破解逆向應用的時候,一般現在第一步都回去解決反調試,不然后續步驟無法進行,當然如果你是靜態分析的話獲取就沒必要了。但是有時候必須要借助動態調試方可破解,就需要進行操作了。現階段反調試策略主要包括以下幾種方式:
第一、自己附加進程,先占坑,ptrace(PTRACE_TRACEME, 0, 0, 0)!第二、簽名校驗不可或缺的一個選擇,本地校驗和服務端校驗雙管齊下!第三、借助系統api判斷應用調試狀態和調試屬性,最基礎的防護!第四、輪訓檢查android_server調試端口信息和進程信息,防護IDA的一種有效方式!第五、輪訓檢查自身status中的TracerPid字段值,防止被其他進程附加調試的一種有效方式!
所以本文就來一一講解如何解決這幾種方式的反調試方案。
二、方法總結
第一種:找到關鍵方法,注釋代碼
這種方式需要采用靜態方式分析代碼,找到關鍵方法進行反調試代碼功能注釋,這種方式可以應對與上面所有的反調試方案,但是對于輪訓檢查這種方式就不太適合了,為什么?因為大家如果看過這篇文章:脫掉360加固應用保護殼;操作過的同學會發現,在去除反調試功能的時候那種痛苦了。所以這種注釋代碼,個人覺得只適用于以下幾種反調試:
第一、自己附加進程
這個可以IDA打開關鍵so代碼,找到這段代碼處:ptrace(PTRACE_TRACEME, 0, 0, 0),直接nop掉即可。這個沒什么難度,因為就一行代碼,說白了就幾條arm指令罷了。IDA靜態分析so也是無壓力的。
第二、簽名校驗
這個在之前的文章中介紹過了,不了解的同學可以查看這篇文章:Android中破解某應用的簽名校驗邏輯;最后總結了一個比較簡單的過濾簽名校驗的方法:先在Jadx中打開應用之后,全局搜字符串內容:”signatures”,這個就可以定位到獲取應用簽名信息的地方了,然后可以依次跟蹤校驗的地方了。找到具體地方代碼直接注釋即可。
但是如果服務端交互信息中攜帶了簽名校驗,而簽名校驗又在so中,那么就需要另外操作了,這部分知識點將在后面單獨一篇文章詳細介紹如何破解。
第三、調用系統api判斷當前應用是否處于調試狀態
這種方式看到我們實現的邏輯還是比較簡單的,直接調用系統的android.os.Debug.isDebuggerConnected()方法和判斷當前應用屬性:ApplicationInfo.FLAG_DEBUGGABLE,那么可以依然采用全局搜索反編譯之后的應用內容,找到這部分內容,然后直接注釋代碼即可。
第二種:修改IDA通信端口
上面分析完了,直接使用靜態方式+注釋代碼功能解決了之前提到的三種反調試方案。但是還有兩種沒有解決,下面就會詳細介紹一種非常靠譜方便永久的方法。而這部分內容才是本文的重點。首先來看看如何解決之前提到的利用檢查IDA調試端口23946這個反調試方案。這個其實思路很簡單,因為你檢查的端口號是默認的23946,所以我們如果能把這個端口號改成其他值,那么其實就解決了。
修改這個端口號,也比較簡單:網上有一種方案就是android_server本身支持自定義端口號的,命令很簡單:
./android_server -p12345;****直接加上-p參數即可,注意端口號和參數之間沒空格:
有的人說,這方法這么簡單,那下面就不介紹了,當然不是,我寫文章的目的不是為了簡單,而是為了讓大家了解更多的知識,寧愿多走彎路,走多條路出來。而且上面的這種方式每次都加-p比較麻煩,我想用另外一種方式去一次性解決問題,同時我更想在這個過程中熟悉一下IDA的使用,使用IDA打開android_server文件,其實他是elf格式的,打開無壓力,打開之后使用shift+12查看字符串內容界面:
找到這三處關鍵字符串內容,我們可以通過以往運行過android_server之后的提示信息察覺:
找到這三處字符串內容,下面就簡單了,一處一處進行修改,雙擊字符串條目內容:
選中按X鍵,進行切換:
選擇第一個跳轉到arm指令處:
這是graph視圖,可以使用空格鍵進行切換:
看到arm指令了,LDR R5,=0x5D8A;其中0x5D8A就是十進制的23946,也就是默認端口號,所以這里我們只需要將這個arm指令,改成MOVS R5,#0xDD;可對R5進行重新賦值,這里賦值為DD,也就是221;這里有個小問題就是如何進行修改,IDA中可以切換到Hex View視圖進行修改編輯二進制,但是這樣修改不會生效到源文件中,所以我們這里還得借助一個二進制編輯工具010Editor,我們使用這個軟件打開android_server之后,使用Ctrl+G可以直接跳轉到指定地址,使用Ctrl+F可以跳轉到搜索內容處,記住以下這兩個快捷鍵。
這里看到了99 4D就是:LDR R5, =0x5D8A 對應的指令十六進制值,關于指令和十六進制值之間轉化可以去網上搜一個小工具即可。我們想將其變成 MOVS R5,#0xDD 指令,對應的十六進制是:DD 25,其中DD就是立即數值,25表示MOVS R5指令。所以下面就可以直接進行修改即可:
修改完成之后,進行保存即可,這樣我們就修改好了一處,還有兩處操作一模一樣:
繼續修改init_sockets處,命令都是一樣的,記住地址:B98A,去010Editor中進行修改即可:
然后繼續修改IDA Android 32-bit...處
記住地址:B64C,去010Editor進行修改即可:
這樣我們就全部改好了,保存android_server文件,再次使用IDA打開,找到一個地方查看修改是否成功:
的確修改成功了,下面我們把android_server拷貝到設備中運行,看看端口是否為221(0xDD):
看到了,這里成功的修改了,android_server監聽端口了,主要當打開IDA進行連接的時候需要注意端口是221,而不是23946了,或者你可以用adb forward tcp:221...命令進行轉發也可以!
第三種:修改boot.img文件,跳過反調試
這種方式是為了解決現在常用的反調試策略,就是輪訓檢查進程的TracerPid值,所以我們需要修改設備的boot.img文件,將這個值直接寫死為0即可。關于如何修改操作,看雪上已經有大神講解了非常詳細的過程,我就是按照這個流程進行操作的:http://bbs.pediy.com/thread-207538.htm,因為每個設備的boot.img都不一樣,所以在操作的過程中可能遇到很多問題,所以下面就把我操作的過程中遇到的問題講解一下,順便精煉的說一下步驟:
第一步,你得有一個可以折騰的root手機
因為現在是在玩boot.img了,后面得刷機,所以你得搞一個你覺得沒多大意義的設備,即使成磚頭了也無妨。當然一般不會成為磚頭。
第二步:root環境下提取zImage內核文件
這里我用的是三星note2設備,自己刷了一個CM4.4系統,按照大神的貼中先去找到系統boot的文件位置,這個路徑一定要注意:/dev/block/platform/[每個設備目錄不一樣]/by-name;其中platform目錄中的子目錄因為每個設備都不一樣,所以需要注意,查看自己設備目錄名稱,然后進入到by-name之后,使用 ls -l 命令查看詳情,找到一項BOOT,記住link的路徑地址,這里是/dev/block/mmcblk0p8,然后使用命令,將boot導出為boot.imgdd if=/dev/block/mmcblk0p8 of=/data/local/boot.imgadb pull /data/local/boot.img boot.img
這里可能有人會遇到一個問題就是,看到多個BOOT,比如BOOT1,BOOT2,這里可以選擇BOOT即可,也有的人會發現沒這個選項,那么只能在刷個其他系統進行操作了。
第三步:借助bootimg.exe工具解壓boot.img文件
這個工具我會在后面一起給出壓縮包,命令用法很簡單,
**解包是:bootimg.exe --unpack-boot boot.img **
壓包是:bootimg.exe --repack-boot
這里有一個坑,我找到兩個版本,第一個版本工具操作之后刷機總是黑屏啟動失敗,最后找到了第二個版本工具才成功的。其實這些工具原理很簡單,就是解析boot.img文件格式罷了,因為boot和recovery映像并不是一個完整的文件系統,它們是一種android自定義的文件格式,該格式包括了2K的文件頭,后面緊跟著是用gzip壓縮過的內核,再后面是一個ramdisk內存盤,然后緊跟著第二階段的載入器程序(這個載入器程序是可選的,在某些映像中或許沒有這部分):
我們想要的是kernel內核信息。所以用這個工具進行操作之后,會發現有這么幾個目錄和文件:
解壓之后有一個kernel文件,這個就是內核文件,而ramdisk.gz就是釋放到設備目錄內容,也就是initrd目錄,進入查看內容:
看到了吧,這就是最終設備的目錄結構,可以看到這里有init.rc啟動文件,default.prop配置文件等。
接下來我們就要對kernel內核文件進行特別處理了:將kernel文件復制為文件名為zImage.gz的文件,并使用010Editor工具,Ctrl+F快捷鍵查找十六進制內容1F 8B 08 00,找到后把前面的數據全刪掉,使zImage.gz文件變成標準的gzip壓縮文件,這樣子就可以使用gunzip解壓了。命令:gunzip zImage.gz;這時候獲取到了解壓之后的zImage才是我們要處理的最終文件。
第四步:IDA打開zImage內核文件進行修改
有了上面一步得到的內核文件zImage,直接使用IDA打開,但是打開的時候需要注意設置選項:
然后設置開始地址為0xC0008000:
這里為什么要設置成這個起始地址,因為Linux啟動內核的地址為0xC0008000;打開之后,我們可以直接shift+F12,查看字符串內容,因為我們想改TracerPid值,所以直接搜字符串"TracerPid"值:
雙擊進入,這時候我們可以記下這個地址,然后減去剛剛我們那個偏移地址0xC0008000:
也就是0xC0A3853C-0xC0008000=0xA3053C,這里沒有像看雪大神操作那么復雜,先去定位函數位置,修改指令,因為每個設備不一樣,指令代碼就不一樣,不具備通用性,所以這里有一個更好的方案,就是直接改TracerPid的格式字符串值,原始格式化字符串內容為:
\t%s\nTgid:\t%d\nPid:\t%d\nPPid:\t%d\nTracerPid:\t0\t\nUid:\t%d\t%d\t%d\t%d\nGid:\t%d\t%d\t%d\t%d\n
這里應該用到了C語言中的占位符%d,來進行值的填充,那么我們可以把TracerPid那一項的占位符%d,改成'0',但是'%d'是兩個字符,所以我們可以改成'00',或者'0\t',或者'0\n';只要保證修改后的字符串內容對其就好。這樣TracerPid這一項的值占位符就失效,值永遠都是0了。而上面計算的地址就是我們要去010Editor中操作的地址,用010Editor打開zImage文件,Ctrl+G跳轉到0xA3053C處:
這里我們將其改成'0\t'值,對應的十六進制就是:30 09;這樣我們就修改成功了。
第五步:生成修改后的boot.img文件
這里操作其實就是一個相反的過程,首先使用gzip命令壓縮上面修改好的內核文件zImage:gzip -n -f -9 zImage;然后使用010Editor將壓縮好的zImage.gz的二進制數據覆蓋到原kernel文件的1F 8B 08 00處的位置(回寫回去時不能改變原kernel文件的大小及修改原kernel文件后面的內容,否則會很麻煩),這時得到了新的kernel文件內容。這里需要特別強調一下,也就是我踩過的坑:比如kernel原來是10M大小,1F8B0800之前刪除的是1M,我們修改之后的zImage.gz大小是8M,那么我們回寫覆蓋的時候一定是1M~9M的位置,而kernel的前面1M內容和后面1M內容不能有任何改動,搞錯的話,刷機會出現啟動失敗的情況。下面用我操作的案例講解一下:
這是我修改之后的壓縮好的zImage.gz文件,最后一個數據是0x65E18D,然后全選內容復制好,記住之后,再去原來的kernel內容:
在kernel中的1F8B0800位置是0x47A0,那么我們就需要把剛剛賦值的內容從這里開始替換,到哪里結束呢?將這兩個地址相加即可:0x65E18D+0x47A0=0x66292D;也就是到0x66292D結束:
這樣原來的kernel內容大小肯定不會發生變化了,始終都是0x662967,所以在替換內容的時候內容一定不能發生變化。替換完成之后,將新的kernel文件替換原來的kernel文件,在使用之前提到的bootimg.exe工具生成新的boot.img文件即可。
第六步:刷機boot.img文件
這里有一個坑,在刷機的時候用到的是fastboot命令,但是遇到最多的問題就是這個錯誤:
這個是因為設備還沒有啟動fastboot,關于每個設備啟動fastboot不一樣操作,比如小米是電源鍵+音量減,三星是音量減+HOME鍵+電源鍵;具體設備可以自行網上搜索即可。到了fastboot界面再次運行fastboot就可以了:
fastboot flash boot boot-new.img
然后在運行fastboot reboot重啟設備即可。有的同學在操作的時候,始終進入fastboot失敗,導致fastboot命令運行錯誤,這個真解決不了那就換個手機試一下吧。
這時候我們啟動設備,然后調試一個app,發現他的TracerPid值永遠都是0了,因為我之前將TracerPid改成'00'字符串了,也是可以的:
因為感覺不正規,所以就有重新改成了'0\t'值了。都是可以的。
注意:一定要保存原始提取的內核文件boot.img,當你把設備弄成磚頭啟動失敗的時候,可以在把這個原始的boot.img刷回去就可!
三、內容延展
不知道大家以前在看:脫360加固應用的保護殼 文章的時候當時說到了一個工具mprop,他的作用就是能夠改寫系統的內存中的ro.debuggable這個屬性值,這樣我們就沒必要每次反編譯app,然后在AndroidManifest.xml中添加android:debuggable="true",讓應用可調試了。
Android逆向之旅---應用的"反調試"方案解析(附加修改IDA調試端口和修改內核信息)
當時說到這個工具有一個弊端就是他只能修改內存中的值,當設備重啟就會失效,那么現在我們可以讓他永久有效,其實這個屬性值,是在系統根目錄下的default.prop文件中的,設備啟動就會解析存入內存中。所以如果我們能夠把這個文件中的值改成1,那么就永久有效了。在上面解包boot.img的時候,說到了有一個initrd目錄,其實default.prop就是在這個目錄下:
這里我們直接將其改成1,因為我們現在已經進行了修改boot.img操作,那就順便把這個功能也給改了。多方便呀!
四、提取內核操作總結
第一步:設備root之后,查看設備的內核文件路徑: cd /dev/block/platform/[具體設備具體查看]/by-name,然后使用命令ls -l 查看boot屬性的,記住路徑
第二步:dd if=/dev/block/[你的內核路徑] of=/data/local/boot.img
adb pull /data/local/boot.img boot.img
第三步:使用bootimg.exe工具進行boot.img解包;得到kernel文件,將kernel文件復制為文件名為zImage.gz的文件,并使用010Editor工具,Ctrl+F快捷鍵查找十六進制內容1F 8B 08 00,找到后把前面的數據全刪掉,使zImage.gz文件變成標準的gzip壓縮文件,這樣子就可以使用gunzip解壓了。命令:gunzip zImage.gz
第四步:使用IDA打開zImage內核文件,記得設置選項和起始地址:0xC0008000;打開之后,使用shift+F12查找到字符串“TracerPid”值,記住文件起始地址,然后減去0xC0008000;在使用010Editor打開內核文件,Ctrl+G跳轉到這個地址,進行內容修改,將TracerPid那個占位符‘%d’改成‘0\t’保存即可
第五步:首先使用gzip命令壓縮上面修改好的內核文件zImage:gzip -n -f -9 zImage;然后使用010Editor將壓縮好的zImage.gz的二進制數據覆蓋到原kernel文件的1F 8B 08 00處的位置(回寫回去時不能改變原kernel文件的大小及修改原kernel文件后面的內容,否則會很麻煩)
第六步:啟動設備為fastboot模式,然后使用fastboot命令進行刷機:fastboot flash boot boot-new.img,然后在重啟即可
總結一張圖:
踩過的坑
坑一:一定保留最原始提取的內核文件boot.img,為了防止你刷失敗了,可以還原操作。坑二:修改TracerPid值時,只需要將‘%d’占位符改成‘0\t’即可,無需改動arm命令操作。坑三:在還原kernel文件的使用一定要記得不能改變原始kernel文件的大小。坑四:fastboot命令運行失敗,設備必須處于fastboot模式,如果還不行那就換個手機吧。
五、技術總結
第一:關于反調試的第一種解決方案比較簡單,就是靜態分析代碼,找到反調試的位置,然后注釋代碼即可。
第二:對于監聽IDA端口反調試,通過修改android_server的啟動端口,這里也學會了如何修改端口號操作。
第三:修改內核文件,讓TracerPid始終為0,ro.debuggable屬性值始終為1,這個操作過程還是有點繁瑣的,遇到的問題肯定很多,而且每個人遇到的問題可能不一樣,但是這是一個鍛煉的過程,如果成功了意味著你學會了提取內核操作,了解內核文件結構,學會分析內核文件,修改內核文件。意義重大。比如你還可以修改設備的啟動圖,慢慢的你可以定制自己的rom了。
第四:在以上操作中,也熟悉了IDA工具使用,了解到了字符串內容永遠都是尋找問題的最好突破口,IDA中查找字符串Shirt+F12即可,010Editor中Ctrl+G和Ctrl+F查找快捷鍵。
解包boot.img文件的工具下載地址:http://download.csdn.net/detail/jiangwei0910410003/9793611
六、總結
本文介紹的內容主要是如何解決反調試問題,主要是三種方案,最后一種修改手機內核文件的操作比較繁瑣,遇到的問題也會比較多。但是如果要是成功了,以后進行破解逆向就方便多了。所以就努力看文章,自己手動操作一次。看完文章之后,記得多多點贊和分享擴散,要是有打賞就最好啦啦!
更多內容:點擊這里
關注微信公眾號,最新技術干貨實時推送
編碼美麗技術圈
微信掃一掃進入我的"技術圈"世界
掃一掃加小編微信添加時請注明:“編碼美麗”非常感謝!