Android Decompiler / 初探反編譯

0x00 TOC

原理

無混淆無加密無加殼

僅混淆

僅加密

僅加殼

自動化實現

一些軟件

參考鏈接

0x01 原理

首先在逆向領域,有一個是需要區別的。就是反彙編和反編譯。

反彙編把程序的原始機器碼,翻譯成較便於閱讀理解的彙編代碼。比如IDA、OD等。

反編譯,通常是將機器碼(彙編語言)轉換爲高級編程語言。

由於Java、.net這樣的基於虛擬機技術的語言都是採用了ByteCode的二進制結構,因此很容易將ByteCode轉化爲“抽象語法樹”(簡稱AST,《編譯原理》這門課中的概念),然後採用反編譯器就可以將AST轉換爲代碼了。

詳細可以參考烏雲上的文章反編譯系列教程(上)

0x02 無混淆無加密無加殼

一個Android程序,如果沒有進行混淆,加密,加殼等行爲時,如果進行反編譯的話,是可以逆向到Java源碼的。

1.Dex2JarJD-GUI(或者Jad)

先通過Dex2Jar軟件將classes.dex轉換爲jar文件,然後再通過Java反編譯工具JD-GUI將jar文件轉換成JAVA源文件。

總之這是通過dex轉jar,然後再轉java源代碼的思路。其中dex轉jar也可以選擇一些其他軟件,例如谷歌官方的enjarify

下載Dex2Jar和Jd-gui的地址:

Dex2Jar:https://github.com/pxb1988/dex2jar/releases

JD-GUI:http://jd.benow.ca/

使用Dex2Jar和Jd-gui的命令:

dex2jar <file0>
//即
./d2j-dex2jar.sh xxx.apk
java -jar jd-gui-x.y.z.jar
//或者是
java -classpath jd-gui-x.y.z.jar org.jd.gui.App
//也可以直接運行客戶端

以下即爲反匯編出來的結果。

2.APK改之理、APKDB、Android逆向助手、Android Killer之類軟件

實際本質上還是通過Dex2jar或者apktool工具的封裝。

還有一個Jadx的軟件也比較好用。

3.在線反編譯網站

地址:http://www.decompileandroid.com/

地址:http://www.ludaima.cn/android.html

只需要上傳需要反編譯的apk,稍等片刻,即可下載源碼。

4.smali和Baksmali以及Smali Viewer

smali是將smali文件轉換成dex。

Baksmali和smali相反,將dex轉換成smali。

Quora的一篇問答中,介紹了smali和baksmali的作用。

Smali/Baksmali is an assembler/disassembler for the dex format used by dalvik,
 Android's Java VM implementation. The names "Smali" and "Baksmali" are the
  Icelandic equivalents of "assembler" and "disassembler" respectively.

0x03 僅混淆

通常Android混淆方法,有ProGuard、DexGuard和APKfuscator等。

怎樣使用ProGuard對Android項目源碼進行混淆保護,在Android Studio中build.gradle,修改以下代碼片段

release {
    minifyEnabled true
    proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
     'proguard-rules.pro'
}

minifyEnabled改爲true。去除無效資源的話需要添加shrinkResources true

然後在proguard-rules.pro文件中,編寫一些特定框架的混淆規則。

# ProGuard configurations for Bugtags
-keepattributes LineNumberTable,SourceFile

-keep class com.bugtags.library.** {*;}
-dontwarn org.apache.http.**
-dontwarn android.net.http.AndroidHttpClient
-dontwarn com.bugtags.library.**
# End Bugtags

# retrofit
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }
-keepattributes Signature
-keepattributes Exceptions

# android-async-http
-dontwarn android-async-http-1.4.9.jar.**
-keep class android-async-http-1.4.9.jar.**{*;}
-keep class org.apache.http.** {*; }

並且混淆時需要對使用的框架進行混淆,或者是避免混淆一些類。這時就對框架的文檔進行閱讀,分析需要增加的混淆規則。

混淆的效果如下圖所示。

以及加速gradle編譯的配置:

org.gradle.daemon=true
org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:
+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
org.gradle.parallel=true
org.gradle.configureondemand=true

如何對抗這種混淆呢?這種混淆僅僅是增大了閱讀難度,在反彙編之後,類名變成了a,b,c之類的。

dex2jar作者在Android混淆技巧與反混淆中談到,ProGuard有Shrinking、Optimization、Name Obfuscation、Removal of logging code等功能。在面對名字替換時,有閱讀源代碼、JEB、ProGuard分析等方法,Flanker大牛也分享過利用JEB API編寫插件分析

默認的混淆規則在proguard-android.txt

可以使用Proguard再混淆一次,利用自己寫的規則Mapping文件。

這裏以一個文件爲例。進行Proguard的混淆以及反混淆。

在Proguard配置文件中,添加如下語句,可打印出默認混淆規則的Mapping文件。

-printmapping mapping.txt

在修改好對應的值以後,利用以下語句,應用Mapping文件,再建一個項目,分析對應的代碼。

-applymapping mapping.txt

最後結果如下:

這樣反混淆了以後,降低了代碼閱讀的難度,增加了應用被破解的風險。

0x04 僅加密

加密方式有很多種,本文不能面面俱到,只能找出一些典型的。比如有流程混排加密、代碼內部字符串加密,對so源碼、so函數名稱以及接口調用進行加密隱藏,對classes.dex中的所有函數功能代碼進行提取,然後加密單獨存放等。

當然如果面面俱到,文章篇幅就比較長了,並且實踐、研究花費的時間也比較多。這裏就舉比較簡單的例子。

Android簽名校驗:

在android程序中,可以使用以下代碼進行簽名的獲取。

public int getSignature(String packageName) {
    PackageManager pm = this.getPackageManager();
    PackageInfo pi = null;
    int sig = 0;
    try {
        pi = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
        Signature[] s = pi.signatures;
        sig = s[0].hashCode();
    } catch (Exception e1) {
        sig = 0;
        e1.printStackTrace();
    }
    return sig;
}

可以在APP每次訪問服務器的時候,攜帶上當前APP的簽名,服務端做個簽名驗證,如果不對,直接不通過,返回客戶端信息,然後客戶端進行一定的處理。當然這樣的話破解者也可以通過抓包的方式,抓取到簽名驗證的包,然後每次通信時修改對應的包即可。

0x05 僅加殼

so加殼,upx是最爲so加殼的首選,以前在PC端也做過upx的脫殼

這裏做個示例,加殼so。

在前一篇文章裏,涉及到了如何在so裏打log文件。在寫好jni代碼了以後,將so文件複製出來。

然後添加到文件夾裏,如下圖所示。

準備UPX殼編譯環境:

zlib-1.2.8.tar.gz
ucl-1.03.tar.gz
lzma443.tar.bz2
upx-hg-68db2e569c63.tar.gz

編譯安裝:

cd ucl-1.03
./configure --prefix=$PWD/../../upx-hg-6cd5982ece4f/build
make
cd zlib-1.2.8
./configure --prefix=$PWD/../../upx-hg-6cd5982ece4f/build
make
vi .bash_profile

設置環境變量。

export UPX_UCLDIR=/Users/qingfeng/software/upx/libs/ucl-1.03
export UPX_ZLIBDIR=/Users/qingfeng/software/upx/libs/zlib-1.2.8
export UPX_LZMADIR=/Users/qingfeng/software/upx/libs/lzma443
export UPX_LZMA_VERSION=0x443
export UPX_DIR=/Users/qingfeng/software/upx/upx-hg-68db2e569c63

查看環境變量的命令env,應用環境變量的命令source .bash_profile

然後在編譯make all的過程中,遇到了以下的錯誤。

./bele_policy.h:156:9: error: unused typedef 'acc_cta_t__39' [-Werror,-Wunused-local-typedef]
        COMPILE_TIME_ASSERT(sizeof(U16) == 2)
        ^
./conf.h:359:34: note: expanded from macro 'COMPILE_TIME_ASSERT'
#define COMPILE_TIME_ASSERT(e)   ACC_COMPILE_TIME_ASSERT(e)
./miniacc.h:1563:54: note: expanded from macro 'ACC_COMPILE_TIME_ASSERT'
#    define ACC_COMPILE_TIME_ASSERT(e)  {typedef int __ACC_CTA_NAME(acc_cta_t__)[1-2*!(e)];}
./miniacc.h:1531:37: note: expanded from macro '__ACC_CTA_NAME'
#  define __ACC_CTA_NAME(a)         ACC_PP_ECONCAT2(a,__COUNTER__)
./miniacc.h:331:41: note: expanded from macro 'ACC_PP_ECONCAT2'
#define ACC_PP_ECONCAT2(a,b)            ACC_PP_CONCAT2(a,b)
./miniacc.h:325:41: note: expanded from macro 'ACC_PP_CONCAT2'
#define ACC_PP_CONCAT2(a,b)             a ## b
<scratch space>:183:1: note: expanded from here
acc_cta_t__39

無論是upx是3.9.1,還是最新版,無論lzma是443版本還是最新版1610,編譯的時候都會出現這個問題

然後試着升級了一下g++的版本,mac自帶的是4.2版本,用brew升級到了4.8,然後用zsh的alias功能(vi .zshrc)將自帶的替換掉,然後再編譯還是不行,最後還是使用ubuntu進行編譯吧。

然後就下了一個16.04的鏡像,然後跑起了虛擬機,下載並編譯那些依賴,然後在upx目錄下make all的過程中,出現了以下的問題:

compress.cpp:32:18: fatal error: zlib.h: No such file or directory
     #include <zlib.h>

沒找到zlib.h,可是自己在zlib那也make了啊,在查找資料的過程中,試着在zlib目錄make install了一下,然後就編譯完成了,在src目錄下也有./upx.out了,版本是3.9.2。

這個時候就應該考慮so的init段的問題了。據這篇文章說,加殼的文件中需要有INIT段,添加init段的代碼如下:

void _init(void){} \\c++
extern "C" {void _init(void){}}    \\c

然後加殼的命令如下:

./upx.out -f -o libdemo_upx.so libdemo.so

然後脫殼自然-d參數即可,需要判斷標誌是否爲UPX!,以及處理變形等問題,脫完殼就可以使用IDA進行android的so分析了。

0x06 自動化實現

如何實現一些自動化腳本,進行反彙編的還原工作。

當然網上已經有人實現過相關內容,比如Mac下的AndroidDecompiler,或者是easy-android-decompiler

0x07 一些軟件

Baksmali 和 Dedexer

apktool

JEB

jadx

jdgui

DEX轉jar:

enjarify

dex2jar

app調試器:

gikdbg

代碼混淆軟件:

Proguard

DashO

Dexguard

DexProtector

ApkProtect

Shield4j

Stringer

Allitori

對抗混淆:

dex-oracle

simplify

bytecode-viewer

逆向工程集

0x08 參考鏈接

當然實際情況是混淆,加密,加殼綜合起來的,實際情況要具體分析。

參考鏈接:

一次app抓包引發的Android分析記錄

Android 安全工具包(持續更新)

Android安全攻防戰,反編譯與混淆技術完全解析

Android應用安全開發之源碼安全

Android逆向之旅—反編譯利器Apktool和Jadx源碼分析以及錯誤糾正

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章