re從零開始的反編譯教程

參考鏈接:https://www.52pojie.cn/thread-742703-1-1.html

寫在開頭,引用很喜歡的一句話:要么學!要么不學!學和不學之間沒有中間值 不學就放棄,學就要去認真的學! --致選擇

1、 反編譯簡介

為了回溯編譯過程(或對程序進行逆向工程),我們使用各種工具來撤銷匯編和編譯過程,這些工具就叫反匯編器和反編譯器。反匯編器撤銷匯編過程,因此我們可以得到匯編語言形式的輸出結果。反編譯器則以匯編語言甚至是機器語言為輸入,其輸出結果為高級語言。

2、 Smali語法教程

2.1 原始類型

  • B---byte
  • C---char
  • D---double
  • F---float
  • I---int
  • J---long
  • S---short
  • V---void
  • Z---boolean
  • [XXX---array
  • Lxxx/yyy---object

數組的表示方式是:在基本類型前加上前中括號“[”,例如int數組和float數組分別表示為:[I、[F;對象的表示則以L作為開頭,格式是LpackageName/objectName;

(注意必須有個分號跟在最后),例如String對象在smali中為:Ljava/lang/String;,其中java/lang 對應 java.lang包,String就是定義在該包中的一個對象。或許有人問,既然類是用LpackageName/objectName;來表示,那類里面的內部類又如何在smali中引用呢?
答案是:在LpackageName/objectName/subObjectNamesubObjectName前加 $ 符號。

2.2 方法

方法的定義一般為:Func-Name (Para-Type1Para-Type2Para-Type3...)Return-Type
注意參數與參數之間沒有任何分隔符,同樣舉幾個例子就容易明白

  1. hello ()V。沒錯,這就是void hello()
  2. hello (III)Z。這個則是boolean hello(int, int, int)
  3. hello (Z[I[ILjava/lang/String;J)Ljava/lang/String;
    看出來這是String hello (boolean, int[], int[], String, long) 了嗎?

2.3 Smali基本語法

無序列表的使用,在符號"-"后加空格使用。如下:

  • field private isFlag:z  定義變量
  • method  方法
  • parameter  方法參數
  • prologue  方法開始
  • line 123  此方法位于第123行
  • invoke-super  調用父函數
  • const/high16 v0, 0x7fo3  把0x7fo3賦值給v0
  • invoke-direct  調用函數
  • return-void  函數返回void
  • end method  函數結束
  • new-instance  創(chuàng)建實例
  • iput-object  對象賦值
  • iget-object  調用對象
  • invoke-static  調用靜態(tài)函數

2.4 條件跳轉分支

  • "if-eq vA, vB, :cond_*" 如果vA等于vB則跳轉到:cond_*
  • "if-ne vA, vB, :cond_*" 如果vA不等于vB則跳轉到:cond_*
  • "if-lt vA, vB, :cond_*" 如果vA小于vB則跳轉到:cond_*
  • "if-ge vA, vB, :cond_*" 如果vA大于等于vB則跳轉到:cond_*
  • "if-gt vA, vB, :cond_*" 如果vA大于vB則跳轉到:cond_*
  • "if-le vA, vB, :cond_*" 如果vA小于等于vB則跳轉到:cond_*
  • "if-eqz vA, :cond_*" 如果vA等于0則跳轉到:cond_*
  • "if-nez vA, :cond_*" 如果vA不等于0則跳轉到:cond_*
  • "if-ltz vA, :cond_*" 如果vA小于0則跳轉到:cond_*
  • "if-gez vA, :cond_*" 如果vA大于等于0則跳轉到:cond_*
  • "if-gtz vA, :cond_*" 如果vA大于0則跳轉到:cond_*
  • "if-lez vA, :cond_*" 如果vA小于等于0則跳轉到:cond_*

3、 Android Killer

3.1 反編譯失敗

http://www.itdecent.cn/p/1c54c1ccf5cc

https://www.cnblogs.com/onelikeone/p/7594177.html

3.2 .smali文件已丟失

解決:點擊進去jd-gui,刪除試一試。再不行換最新版本


3.3 Android Killer反編譯失敗:No resource identifier found for attribute 問題解決方法

解析結束后進行編譯報錯
解決方法:https://blog.csdn.net/fuchaosz/article/details/104800802

3.4 解決反編譯安裝失敗報Error: INSTALL_PARSE_FAILED_MANIFEST_MALFORMED的處理方式

Failed parse during installPackageLI: Targeting R+ (version 30 and above) requires the resources.arsc of installed APKs to be stored uncompress

解決方法:

  1. 使用安卓10及一下手機
  2. 手動降低該程序版本


降低gradle里版本,若出現
signatures do not match the previously installed version;,

使用adb install命令在手機上安裝app時,遇到這個報錯。原因是新裝的app和手機上現有的舊版app沖突了。
解決方法:刪除手機上原來的app,再重新安裝即可。

可是轉念一想如果反編譯的apk都是Version 30 R+以上,難道我解壓后挨個改一遍gradle?太徹淡了,一定有解決方法,所以有了下面探究出現這個問題的解決方法:既然報錯是資源文件高版本不支持,而且沒有4位對齊,那么不編譯資源文件就好了

  1. 不編譯資源文件,使用V2簽名(還是不能編譯資源文件,即使用了V2簽名s,在高版本)

4、 二次打包

APK簽名工具之jarsigner和apksigner:

https://blog.csdn.net/xzytl60937234/article/details/89088215?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_baidulandingword-1&spm=1001.2101.3001.4242

利用apktool反編譯apk,并且重新簽名打包:

https://blog.csdn.net/qq_21007661/article/details/109851522?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-4&spm=1001.2101.3001.4242

  1. 進入AndroidKiller_v1.3.1\bin\apktool目錄

驗證apktool能否使用


apktool -r d apk名字.apk,不反編譯資源文件,為什么這么做,先挖個坑


錯誤提示沒有4位對齊和不支持30版本以上的資源文件。所有嘗試不編譯資源文件

解決4位對齊的方法:


  1. 使用apktool進行反編譯(Android Killer有該工具)

    1. 解壓apk
    • apktool d src.apk //解壓apk到當前文件夾
    • apktool d src.apk -o temp //到temp文件夾
    • apktool -r d apk名字.apk //不反編譯資源文件,到當前文件夾
    • 直接用zip打開手動解壓
執(zhí)行反編譯命令,apktool d filename,這里我執(zhí)行的是apktool d app-debug.apk
其中d是decode的意思,表示要對這個apk進行解碼,除了這個基本用法,還有其他的附帶參數:

- -f 如果目標文件夾已存在,則強制刪除現有文件夾(默認如果目標文件夾已存在,則解碼失敗)。
- -o 指定解碼目標文件夾的名稱(默認使用APK文件的名字來命名目標文件夾)。
- -s 不反編譯dex文件,也就是說classes.dex文件會被保留(默認會將dex文件解碼成smali文件)。
- -r 不反編譯資源文件,也就是說resources.arsc文件會被保留(默認會將resources.arsc解碼成具體的資源文件)

2. 修改需要的內容,用AndroidKiller修改smali文件
3. 二次打包回apk,使用apktool進行編譯成apk安裝包
   - apktool b src //src為解壓的文件夾名稱
   查看src目錄,里面多了一個dist目錄,目錄里面有個 xxx.apk
  1. 簽名

使用keytool產生密鑰,生成abc.keystore

  • keytool -genkey -alias abc.keystore -keyalg RSA -validity 20000 -keystore abc.keystore

//keytool -genkeypair -keystore 密鑰庫名 -alias 密鑰別名 -validity 天數 -keyalg RSA

查看當前目錄,生成了新文件:abc.keystor

使用JarSigner對apk進行簽名,命令如下

jarsigner -verbose -keystore abc.keystore -signedjar testx.apk src.apk abc.keystore

直接反編譯的apk產生上述錯誤


但是只編譯資源文件的apk安裝時


發(fā)現沒有使用V2進行簽名,這時候進行V2簽名,(apksigner,默認同時使用V1和V2簽名

所以先對只編譯資源文件的apk進行V2嘗試看能否成功

重復1(進行apktool -r d apk名字.apk)-->2 -->3 -->4(不使用jarsigner而使用apksigner)

將生成的abc.keystore和打包回的apk(apktool\app-debug\dist里的app-debug.apk)放入C:\Users\taowei.lian\AppData\Local\Android\Sdk\build-tools\30.0.3下,因為Android studio的SDK下有apksigner.bat.

17.png

對jarsigner只是apk進行了V1簽名;在Android7.0引入了V2簽名,因此,當進入sdk\25.0.0及后續(xù)版本,會發(fā)現一個apksigner.bat執(zhí)行腳本。

我們可以通過apksigner進行V2簽名,當然,apksigner默認是同時支持V1與V2的,于是:

abc.keystore密鑰庫只有一個密鑰對

  • apksigner sign --ks debug.keystore app-debug.apk

在debug.keystore密鑰庫中有多個密鑰對,所以必須指定密鑰別名

  • apksigner sign --ks debug.keystore --ks-key-alias androiddebugkey app-debug.apk

5、 簽名驗證

5.1 簽名機制概述

學習了公鑰和密鑰的使用和區(qū)別,使用私鑰的加密算法稱為對稱加密算法,這種算法實現是接收方和發(fā)送方公用一道密鑰,優(yōu)點是效率高,缺點是安全性差,如果被第三人得知密鑰則信息泄露,由此衍生了公鑰加密算法,也就是非對稱加密算法,這個算法是接收方給發(fā)送方公鑰,發(fā)送方用公鑰加密后發(fā)給接收方,接受方再用私鑰解密。這樣即使所有人知道公鑰也不會造成信息泄露。缺點是效率非常低。

此外了解了RSA簽名的大致過程,發(fā)送方擁有公鑰和私鑰,對信息進行摘要然后把摘要通過密鑰進行簽名,然后把簽名和信息一起發(fā)出去,那么如何驗證該信息就是發(fā)送方發(fā)出的呢,這時候就使用到了公鑰驗證,通過公鑰對信息進行解簽,然后使用一樣的摘要算法得到摘要,如果得到的摘要和解簽后的內容一致則說明是發(fā)送方發(fā)出。
總結就是公鑰加密,私鑰解密。公鑰驗證,私鑰簽名

RSA 密碼體制是一種公鑰密碼體制,公鑰公開,私鑰保密,它的加密解密算法是公開的。由公鑰加密的內容可以并且只能由私鑰進行解密,而由私鑰加密的內容可以并且只能由公鑰進行解密。也就是說,RSA 的這一對公鑰、私鑰都可以用來加密和解密,并且一方加密的內容可以由并且只能由對方進行解密。

  • 加密:公鑰加密,私鑰解密的過程,稱為「加密」。

因為公鑰是公開的,任何公鑰持有者都可以將想要發(fā)送給私鑰持有者的信息進行加密后發(fā)送,而這個信息只有私鑰持有者才能解密。

  • 簽名:私鑰加密,公鑰解密的過程,稱為「簽名」。

它和加密有什么區(qū)別呢?因為公鑰是公開的,所以任何持有公鑰的人都能解密私鑰加密過的密文,所以這個過程并不能保證消息的安全性,但是它卻能保證消息來源的準確性和不可否認性,也就是說,如果使用公鑰能正常解密某一個密文,那么就能證明這段密文一定是由私鑰持有者發(fā)布的,而不是其他第三方發(fā)布的,并且私鑰持有者不能否認他曾經發(fā)布過該消息。故此將該過程稱為「簽名」。

Android 簽名機制 v1、v2、v3

5.2 方法一(keytool,只支持V1簽名校驗)

進入JDK/bin, 輸入命令

keytool -printcert -jarfile MyApp.apk (顯示簽名證書信息)

參數:

  • -printcert 打印證書內容
  • -jarfile 已簽名的jar文件 或apk文件

5.3 方法二(apksigner,支持V1和V2簽名校驗)

進入Android SDK/build-tools/SDK版本, 輸入命令

apksigner verify -v --print-certs xxx.apk

參數:

  • -v, --verbose 顯示詳情(顯示是否使用V1和V2簽名)
  • –print-certs 顯示簽名證書信息

例如:

apksigner verify -v MyApp.apk

最后安裝加 -t :

adb install -t app-debug-signed.apk

附上參考鏈接:

6、 用AS編寫第一個so

https://blog.csdn.net/A807296772/article/details/102298970

配置NDK的時候如果按鈕是灰色的,手動配置

sdk.dir=C\:\\Users\\taowei.lian\\AppData\\Local\\Android\\Sdk
ndk.dir=C\:\\Users\\taowei.lian\\AppData\\Local\\Android\\Sdk\\ndk\\21.3.6528147

問題一、javac編譯 解決警告:編碼 GBK 的不可映射字符

直接在javac后面指定編碼是UTF-8就是了。

javac -encoding UTF-8 xxxx.java

問題二、找不到 'com.example.jni.myJNI' 的類文件。

javah -classpath . -jni com.example.pixiaozhi.jni.TestJni

需要注意的是要加上* -classpath .其中classpath后面的一個黑點是不能省略的。

編譯好后如何導入so庫

  sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }

成功運行后發(fā)現lib目錄下已經apk編進去so了

7、 破解so

https://www.52pojie.cn/thread-732298-1-1.html
本節(jié)所有到的工具和Demo

IDA
鏈接:https://pan.baidu.com/s/15uCX8o6tTSSelgG_RN7kBQ 密碼:ftie

Demo
鏈接:https://pan.baidu.com/s/1vKC1SevvHfeI7f0d2c6IqQ 密碼:u1an

7.1 使用IDA工具,注意:拖進去的so必須是解壓apk的so,不然修改無法生效!

找到so并打開它 因為我的機型是支持arm的所以我這里打開的是armeabi文件夾下的so 如果機型是x86模式的那么這里要打開x86模式下的libJniTest.so

  • armeabiv-v7a: 第7代及以上的 ARM 處理器。2011年15月以后的生產的大部分Android設備都使用它.
  • arm64-v8a: 第8代、64位ARM處理器,很少設備,三星 Galaxy S6是其中之一。
  • armeabi: 第5代、第6代的ARM處理器,早期的手機用的比較多。
  • x86: 平板、模擬器用得比較多。
  • x86_64: 64位的平板。

編譯過程:


7.2 找到字符串hello 52pojie!并修改為hello world!

按住鍵盤組合鍵 shift + f12 打開字符串窗口 這個窗口將會列舉出so中所包含的所有字符串 因為上節(jié)課我們只編寫了一個字符串 所以這里只有一個hello 52pojie! 如果打開的是x86的so這里還會有一些.so 但是字符串只有這一個


7.3 雙擊進去將會找到hello 52pojie!的內存地址

7.4 修改內存地址

鼠標點在hello 52pojie!字符串上,打開 Hex dump窗口,修改hello 52pojie!對應內存地址的內容
關于字符對應的16進制可以在百度百科搜索ascii碼表 找到字符所對應的16進制

因為我要把hello 52pojie!修改成hello world! 是不是只要找到每個字符所對應的hex修改就好了
這里我看到 hello 52pojie!對應的hex是:68 65 6C 6C 6F 20 35 32 70 6F 6A 69 65 21
我在ascii碼表上找到world所對應的十六進制是:77 6F 72 6C 64
所以hello world! 對應的十六進制是:68 65 6C 6C 6F 20 77 6F 72 6C 64 21



7.5 找到所要修改的字符所對應的16進制 右鍵Edit

注意編輯的時候光標暫停的位置只有先輸入字母才能更改成功,修改好后 右鍵Apply changes應用

7.6 保存so。

退出后保存


此時已經so修改完畢


7.7 對原apk進行解壓,替換so,打包,簽名,安裝流程,運行看看

大功告成,hello 52pojie! --> hello world!


第一篇技術處女文,借鑒了許多大佬的學習資料,填上了學習過程中踩到的所有坑,文章段落結構方面還待改進,望共勵共勵! --后記

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • APK 反編譯 一、APK反編譯基本原理 1.APK分析 assets文件夾:原始資源文件夾,對應著Android...
    R7_Perfect閱讀 876評論 0 1
  • 1 工具篇 反編譯和回編用到的一些工具: apktool是解包APK 文件最常用的工具 keytool是一個Jav...
    Gavinme閱讀 14,765評論 0 8
  • !!! 嚴正聲明 本文相關反編譯技術僅限于技術研究使用,不能用于非法目的,否則后果自負. 1. apktool 逆...
    瀟風寒月閱讀 1,601評論 0 1
  • 1分鐘速覽,使用apktool反編譯涉及的命令如下: 需要注意的是,生成keystore文件時輸入的密碼一定要牢記...
    Ziv_紫藤花開閱讀 747評論 2 1
  • 我是黑夜里大雨紛飛的人啊 1 “又到一年六月,有人笑有人哭,有人歡樂有人憂愁,有人驚喜有人失落,有的覺得收獲滿滿有...
    陌忘宇閱讀 8,831評論 28 54

友情鏈接更多精彩內容