反編譯
反編譯代碼
- dex2jar 這個工具用於將dex文件轉換成jar文件
- jd-gui 這個工具用於將jar文件轉換成java代碼 ,使用jd-gui工具打開classes-dex2jar.jar這個文件就能查看Java代碼
反編譯資源
- apktool 這個工具用於最大幅度地還原APK文件中的9-patch圖片、佈局、字符串等等一系列的資源。
沒有反編譯資源以前,AndroidManifest.xml和activity_main.xml這樣的資源文件都是非明文的,沒法閱讀。php
從新打包
smali文件夾的目錄結構和咱們源碼中src的目錄結構是幾乎同樣的,主要的區別就是全部的java文件都變成了smali文件。smali文件其實也是真正的源代碼,只不過它的語法和java徹底不一樣,它有點相似於彙編的語法,是Android虛擬機所使用的寄存器語言。html
使用smali語法,修改代碼,就能從新編譯本身的apk。可是apk還不能安全,由於還沒簽名。java
由於沒法得到原來正版的簽名,可使用Android Studio生成本身的簽名,進行打包,生成本身的apk。android
參考:
blog.csdn.net/guolin_blog…web
混淆
混淆的好處:
- 令 APK 難以被逆向工程,增長反編譯的成本。
- 打包時移除無用資源,減小 APK 體積。
啓動混淆
android {
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
複製代碼
- minifyEnabled 設置爲
true
來開啓混淆
- 設置 shrinkResources 爲
true
來開啓資源的壓縮。
- 通常在打 release 包時才啓用混淆,由於混淆會增長額外的編譯時間,因此不建議在 debug 模式下啓用。
- 須要注意的是:只有在啓用混淆的前提下開啓資源壓縮纔會有效!
- 以上代碼中的 proguard-android.txt 表示 Android 系統爲咱們提供的默認混淆規則文件,而 proguard-rules.pro 則是咱們想要自定義的混淆規則,
不能被混淆的元素
枚舉
枚舉類內部存在 values
方法,混淆後該方法會被從新命名,並拋出 NoSuchMethodException
。Android 系統默認的混淆規則中已經添加了對於枚舉類的處理,咱們無需再去作額外工做。算法
被反射的元素
緣由在於:代碼混淆過程當中,被反射使用的元素會被重命名,然而反射依舊是按照先前的名稱去尋找元素,因此會常常發生 NoSuchMethodException
和 NoSuchFiledException
問題。數據庫
實體類
實體類即咱們常說的"數據類",固然常常伴隨着序列化與反序列化操做。不少人也應該都想到了,混淆是將本來有特定含義的"元素"轉變爲無心義的名稱,因此,通過混淆的"洗禮"以後,序列化以後的 value
對應的 key
已然變爲沒有意義的字段,這確定是咱們不但願的。api
反序列化的過程建立對象從根本上來講仍是藉助於反射,混淆以後 key
會被改變,因此也會違背咱們預期的效果。安全
四大組件
Android 中的四大組件一樣不該該被混淆。緣由在於:bash
- 四大組件使用前都須要在 AndroidManifest.xml 文件中進行註冊聲明,然而混淆處理以後,四大組件的類名就會被篡改,實際使用的類與
manifest
中註冊的類並不匹配,故而出錯。
- 其餘應用程序訪問組件時可能會用到類的包名加類名,若是通過混淆,可能會沒法找到對應組件或者產生異常。
JNI 調用的Java 方法
當 JNI 調用的 Java 方法被混淆後,方法名會變成無心義的名稱,這就與 C++ 中本來的 Java 方法名不匹配,於是會沒法找到所調用的方法。
其餘不該該被混淆的
- 自定義控件不須要被混淆
- JavaScript 調用 Java 的方法不該混淆
- Java 的 native 方法不該該被混淆
- 項目中引用的第三方庫也不建議混淆
參考
郭霖:blog.csdn.net/guolin_blog…
juejin.im/post/5d1717…
WebView
問題:WebView明文存儲密碼帶來的安全漏洞
- WebView組件默認開啓了密碼保存功能,會提示用戶是否保存密碼,當用戶選擇保存在WebView中輸入的用戶名和密碼,則會被明文保存到應用數據目錄的databases/webview.db中。攻擊者可能經過root的方式訪問該應用的WebView數據庫,從而竊取本地明文存儲的用戶名和密碼。
解決方案:
- 開發者調用 WebView.getSettings().setSavePassword(false),顯示調用API設置爲false,讓WebView不存儲密碼
四大組件
問題:動態註冊Receiver風險
- 使用BroadcastReceiver組件須要動態註冊或者靜態註冊,若是動態註冊廣播,即在代碼中使用registerReceiver()方法註冊BroadcastReceiver,只有當registerReceiver()的代碼執行到了才進行註冊,取消時則調用unregisterReceiver()方法。但registerReceiver()方法註冊的BroadcastReceiver是全局的而且默承認導出的,若是沒有限制訪問權限,能夠被任意外部APP訪問,向其傳遞Intent來執行特定的功能。所以,動態註冊的BroadcastReceive可能會致使拒絕服務攻擊、APP數據泄漏或是越權調用等安全風險
解決方案:
- 1:在 AndroidManifest.xml 文件中使用靜態註冊 BroadcastReceiver,同時設置 exported="false",不被外部應用調用。 2:必須動態註冊 BroadcastReceiver時,使用registerReceiver(BroadcastReceiver,IntentFilter,broadcastPermission,android.os.Handle)函數註冊。 3:Android8.0新特性想要支持靜態廣播、須要添加intent.setComponent(new ComponentName()),詳情能夠自行查閱
問題:公共組件配置風險
- Activity、Service、Provider、Receiver四大組件若配置爲android:exported =」true」,將能夠被外部應用調用,這樣存在安全隱患的風險。
解決方案:
- 在應用的AndroidManifest.xml文件中,設置組件的android:exported 屬性爲false或者經過設置自定義權限來限制對這些組件的訪問。值得一提的是,若部分功能使用前提是配置必須使用exported爲true,這種狀況開發者應該根據實際狀況來進行集成
問題:數據越權備份風險
- Android 2.1以上的系統能夠爲APP提供應用程序數據的備份和恢復功能,該功能由AndroidMainfest.xml文件中的allowBackup 屬性值控制,其默認值爲true。當該屬性沒有顯式設置爲false時,攻擊者可經過adb backup和adb restore對APP的應用數據進行備份和恢復,從而可能獲取明文存儲的用戶敏感信息,如用戶的密碼、證件號、手機號、交易密碼、身份令牌、服務器通訊記錄等。利用此類信息攻擊者可僞造用戶身份,盜取用戶帳戶資產,或者直接對服務器發起攻擊。
解決方案:
- 將AndroidMainfest.xml文件中的allowBackup屬性值設置爲false來關閉應用程序的備份和恢復功能;也可使用專業安全加固方案的本地數據保護功能,避免本地數據泄露。
數據存儲安全:加密和JNI寫入Native層
一、祕鑰及敏感信息
此類配置應當妥善存放,不要在類中硬編碼敏感信息,可使用JNI將敏感信息寫到Native層。
二、SharePreferences
首先不該當使用SharePreferences來存放敏感信息,sharedpreferces存儲的xml文件數據可能被反編譯拿到。存儲一些配置信息時也要配置好訪問權限,如私有的訪問權限 MODE_PRIVATE(Activity.MODE_PRIVATE,//默認操做模式,表明該文件是私有數據,只能被應用自己訪問,在該模式下,寫入的內容會覆蓋原文件的內容),避免配置信息被篡改。
三、SQLite數據庫文件的安全性 – 描述:敏感信息是否明文存儲 – 檢測:檢測數據庫裏面的重要信息,好比帳號密碼之類的是否明文存儲 – 建議:重要信息進行加密存儲
日誌數據泄露:Log控制,正式環境不打印
問題:日誌數據泄露風險
- 調試信息函數可能輸出重要的調試信息,常見的就是Log日誌類其中包含的信息可能會致使用戶信息泄露,泄露核心代碼邏輯等,爲發起攻擊提供便利,例如:Activity的組件名;通訊交互的日誌;跟蹤的變量值等
解決方案:
- 應用內使用統一的Log控制基類,能夠靈活的控制Log的輸出打印。(測試環境容許打印日誌、正式環境不打印);或者使用第三方的日誌框架
參考:
www.jianshu.com/p/79b30238b…
zhuanlan.zhihu.com/p/35100057
網絡安全:HTTPS、使用簽名和數據加密加密
1.1 無處不在的安全隱患
- 由於http協議是明文傳輸的,能夠採起MD5值傳輸和存儲,近幾年MD5破解能力提升,因此如今一般生成MD5值時都須要加鹽,例如MD5(name+pwd)做爲密碼存儲,一樣的密碼生成的值是不同的,在必定程度上提升了安全性。
- 攻擊不必定須要用戶名密碼,或許能夠直接打token和uid的主意。,一旦用戶登陸後,服務器就經過token來標識身份。若是這個token被黑客劫持了,他就能夠冒充你的身份進行攻擊,若是token機制設計不合理,攻擊者甚至能夠直接暴力去撞token。大部分網站的機制也相似,服務器經過一個sessionId標識用戶,攻擊者一旦拿到這個sessionId,就能夠去冒充一個合法用戶。
1.2 使用https是否就萬事大吉
- https分單向認證和雙向認證,大部分的應用場景是c/s模式,這時一般都是採用的單向認證的方式,也就是說能夠保證客戶端拿到的數據是後臺發送的,攻擊難度很大,除非你能忽悠別人安裝並信任你的證書
- 可是,不少人蹭wifi時或者在網上下載一些資源,系統提示要信任什麼東西,看都不看就點肯定。
- 使用抓包工具時,給目標設備安裝並信任裝包工具的自簽名證書,這時候就能夠分析https請求
- 杜絕 HTTPS 抓包的原理很簡單,其實就是攔截非法的證書,只經過咱們信任的 HTTPS 證書的請求。
- 還有一種比較簡單,直接設置okhttp禁用代理模式,也能夠避免一些抓包。可是用戶可能須要代理上網,這麼禁止會引來其餘問題
- 參考:www.jianshu.com/p/11577eb0c…
1.3 使用簽名和加密數據
上面能夠看到,https並不能阻擋攻擊者分析請求接口併發起惡意請求攻擊,爲了增長攻擊者分析請求的難度,一般能夠採用兩種方式:
-
使用簽名。
-
數據加密。
- post到服務器和從服務器返回的數據都作加密,這樣的話即便攻擊者拿到你的數據,他不知道你的加密算法就無能爲力了。
-
祕鑰使用JNI將敏感信息寫到Native層
參考:
www.jianshu.com/p/fe0206f8b…
JNI:儲存敏感信息,核心算法和祕鑰
- 一些常量是不會/不能被混淆的,這種敏感信息就須要額外保護
- 核心算法和祕鑰,通常選擇放到native層
native代碼的安全性保證
- 相對於java代碼容易被反編譯,使用NDK開發出來的原生C++代碼編譯後生成的so庫是一個二進制文件,這無疑增長了破解的難度。利用這個特性,能夠將客戶端敏感信息寫在C++代碼中,加強應用的安全性。
- 萬一別人將你的so庫直接copy出來拿去用了呢?所以,咱們還須要在native層對應用的包名、簽名進行鑑權校驗,若是不是本身的應用,不返回相關信息,或者直接退出應用!
安全風險
- 用ndk開發,將密鑰放在so文件,加密解密操做都在so文件裏,這從必定程度上提升了的安全性,擋住了一些逆向者,可是有經驗的逆向者仍是會使用IDA破解的。
- 在so文件中不存儲密鑰,so文件中對密鑰進行加解密操做,將密鑰加密後的密鑰命名爲其餘普通文件,存放在assets目錄下或者其餘目錄下,接着在so文件裏面添加無關代碼(花指令),雖然能夠增長靜態分析難度,可是可使用動態調式的方法,追蹤加密解密函數,也能夠查找到密鑰內容。
參考:
www.jianshu.com/p/fe0206f8b…
zhuanlan.zhihu.com/p/34902225
即時通信安全篇(四):實例分析Android中密鑰硬編碼的風險
加殼與脫殼
不管是編譯java代碼生成的dex文件,仍是編譯C/C++代碼生成的so文件,反編譯成本都不是特別的高。
加殼直觀理解就是給程序加一層殼,能夠用來對原程序進行資源壓縮、防調試、防注入、防反編譯,也就是說經過一個殼把原來的程序保護了起來。
咱們知道一個常規Android程序它的全部代碼都在dex文件中,程序啓動時要先把這個dex文件載入到內存中,因此若是要加殼的話,主要工做就是把原dex文件加密或者隱藏起來,放一個新的殼dex到apk中,程序啓動時運行這個殼dex,而後這個殼dex在運行時再加載原dex,用一張圖表示以下:
補充:hook和xposed
什麼是 Hook
Hook 又叫「鉤子」,它能夠在事件傳送的過程當中截獲並監控事件的傳輸,將自身的代碼與系統方法進行融入。這樣當這些方法被調用時,也就能夠執行咱們本身的代碼。
Xposed
- 能夠在不修改APK的狀況下影響程序運行(修改系統)的框架服務。
- 替換本身的代碼,使得程序加載Xposed的jar包,完成劫持
- 在
install
的時候須要root
權限,可是運行時不須要root
權限
經過替換 /system/bin/app_process 程序控制 Zygote 進程,使得 app_process 在啓動過程當中會加載 XposedBridge.jar 這個 Jar 包,從而完成對 Zygote 進程及其建立的 Dalvik 虛擬機的劫持。 Xposed 在開機的時候完成對全部的 Hook Function 的劫持,在原 Function 執行的先後加上自定義代碼
Xposed
框架介紹以及原理
Xposed
是Github
上rovo89
大佬設計的一個針對Android平臺
的動態劫持項目,經過替換/system/bin/app_process
程序控制Zygote
進程,使得app_process
在啓動過程當中會加載XposedBridge.jar
這個jar
包,從而完成對Zygote
進程及其建立的Dalvik虛擬機
的劫持。
由於Xposed
工做原理是在/system/bin
目錄下替換文件,在install
的時候須要root
權限,可是運行時不須要root
權限。
看到這裏不少人會很懵,什麼是Zygote
?簡單來講在Android
系統中,應用程序進程都是由Zygote
進程孵化出來的,而Zygote
進程是由Init
進程啓動的。Zygote
進程在啓動時會建立一個Dalvik
虛擬機實例,每當它孵化一個新的應用程序進程時,都會將這個Dalvik
虛擬機實例複製到新的應用程序進程裏面去,而一個應用程序進程被Zygote
進程孵化出來的時候,不只會得到Zygote
進程中的Dalvik
虛擬機實例拷貝,還會與Zygote
一塊兒共享Java運行時
庫。這也就是能夠將XposedBridge
這個jar
包加載到每個Android
應用程序中的緣由。XposedBridge
有一個私有的Native(JNI)
方法hookMethodNative
,這個方法也在app_process
中使用。這個函數提供一個方法對象利用Java
的Reflection
機制來對內置方法覆寫。。。。等等這些都會借鑑各路大神的思路和分析,總而言之,就是從底層替換方法,可讓咱們在不修改APK
源碼的狀況下,經過本身編寫的模塊來影響程序運行的框架服務,實現相似於自動搶紅包、微信消息自動回覆等功能。 其實,從本質上來說,Xposed
模塊也是一個Android
程序。但與普通程序不一樣的是,想要讓寫出的Android
程序成爲一個``Xposed 模塊,要額外多完成如下四個硬性任務:
一、讓手機上的xposed框架知道咱們安裝的這個程序是個xposed模塊。
二、模塊裏要包含有xposed的API的jar包,以實現下一步的hook操做。
三、這個模塊裏面要有對目標程序進行hook操做的方法。
四、要讓手機上的xposed框架知道,咱們編寫的xposed模塊中,哪個方法是實現hook操做的。
複製代碼
參考:
www.jianshu.com/p/fe0206f8b…
加密算法
加密主要有對稱加密、非對稱加密,不可逆加密。
對稱加密AES
AES主要是用在數據自己的加密,即便傳輸過程當中被截取了,也是加密事後的數據。但AES的弊端的是,客戶端加密的話,密鑰確定是儲存在app中,若是app被成功破解了,數據也就被暴露了。因此只有app自己程序的安全也解決了,app才能相對安全。
非對稱加密RSA
由於RSA加密有個長度限制,這就致使了RSA加密不能用於全部的數據交互。可是能夠用到一些短數據,好比用戶我的信息之類的,在交易中,一次訂單的數據也不是很大等。
不可逆加密
好比MD5加密、SHA加密等。所謂的不可逆加密就是,只能單向加密,不能反向解密。MD5把數據加密,最後獲得固定長度的16進制編碼。這個加密的做用通常是匹配驗證,驗證某個數據是否改變。好比密碼,在向服務器存儲密碼,通常不會存儲明文密碼。安卓本地存儲個標誌也通常不會明文存儲。
Android官方
推出了JetPack Security 。
確保數據安全 - 深刻解讀加密與安全開發 | AndroidDevSummit 中文字幕視頻