Android.Hook框架Cydia篇(脫殼機制作)

wyzsk發表於2020-08-19
作者: 瘦蛟舞 · 2015/08/17 14:53

注:框架有風險,使用要謹慎.

Cydia Substrate是一個程式碼修改平臺.它可以修改任何主程式的程式碼,不管是用Java還是C/C++(native程式碼)編寫的.而Xposed只支援HOOK app_process中的java函式,因此Cydia Substrate是一款強大而實用的HOOK工具.

官網地址:http://www.cydiasubstrate.com/

官方教程:http://www.cydiasubstrate.com/id/38be592b-bda7-4dd2-b049-cec44ef7a73b

SDK下載地址:http://asdk.cydiasubstrate.com/zips/cydia_substrate-r2.zip

0x00Hook Java 層


之前講解過 xposed 的用法為啥還要整這個了,下面簡單對比兩款框架.想了解之前 xposed 篇的可以看這裡:/tips/?id=7488

劣勢:

  • 沒啥錯誤提醒,排錯比較麻煩.
  • 需要對 NDK 開發有一定了解,相對 xposed 模組的開發學習成本高一些.
  • 因為不開源網上(github)上可以參考的模組程式碼很少.

優勢:

  • 可以對 native 函式進行 hook .
  • 與 xposed hook 原理不一樣,因為不是開源具體原理我也不清楚. 結果就是一些Anti hook 可能對 xposed 有效而對 Cydia 無效.

使用方法


1.安裝框架app:http://www.cydiasubstrate.com/download/com.saurik.substrate.apk

2.建立一個空的Android工程.由於建立的工程將以外掛的形式被載入,所以不需要activity.將SDK中的substrate-api.jar複製到project/libs資料夾中.

3.配置Manifest檔案

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application>
        <meta-data android:name="com.saurik.substrate.main"
            android:value=".Main"/>
    </application>
    <uses-permission android:name="cydia.permission.SUBSTRATE"/>
</manifest>

4.建立一個類,類名為Main.類中包含一個static方法initialize,當外掛被載入的時候,該方法中的程式碼就會執行,完成一些必要的初始化工作.

#!java
import com.saurik.substrate.MS;
public class Main {
    static void initialize() { 
        // ... code to run when extension is loaded
    }
}

5.hook imei example

#!java
import com.saurik.substrate.MS;
public class Main {
    static void initialize() {
        MS.hookClassLoad("android.telephony.TelephonyManager",
                new MS.ClassLoadHook() {
                    @SuppressWarnings("unchecked")
                    public void classLoaded(Class<?> arg0) {
                        Method hookimei;
                        try {
                            hookimei = arg0.getMethod("getDeviceId", null);
                        } catch (NoSuchMethodException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                            hookimei = null;
                        }
                        if (hookimei != null) {
                            final MS.MethodPointer old1 = new MS.MethodPointer();
                            MS.hookMethod(arg0, hookimei, new MS.MethodHook() {
                                @Override
                                public Object invoked(Object arg0,
                                        Object... arg1) throws Throwable {
                                    // TODO Auto-generated method stub
                                    System.out.println("hook imei----------->");
                                    String imei = (String) old1.invoke(arg0,
                                            arg1);
                                    System.out.println("imei-------->" + imei);
                                    imei = "999996015409998";
                                    return imei;
                                }
                            }, old1);
                        }
                    }
                });
    }
}

6.在 cydia app 介面中點選 Link Substrate Files 之後重啟手機

7.使用getimei的小程式驗證imei是否被改變

#!java
public class MainActivity extends ActionBarActivity {
    private static final String tag = "MainActivity";
    TextView mText ;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mText = (TextView) findViewById(R.id.text);
        TelephonyManager mtelehonyMgr = (TelephonyManager) getSystemService(this.TELEPHONY_SERVICE);
        Build bd = new Build(); 
        String imei = mtelehonyMgr.getDeviceId(); 
        String imsi = mtelehonyMgr.getSubscriberId();
        //getSimSerialNumber()   獲取 SIM 序列號  getLine1Number 獲取手機號
        String androidId = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID); 
        String id = UUID.randomUUID().toString();
        String model = bd.MODEL;
        StringBuilder sb = new StringBuilder();
        sb.append("imei = "+ imei);
        sb.append("\nimsi = " + imsi);
        sb.append("\nandroid_id = " + androidId);
        sb.append("\nuuid = " + id);
        sb.append("\nmodel = " + model);
        if(imei!=null)
            mText.setText(sb.toString());
        else
            mText.setText("fail");
    }

8.關鍵api介紹

MS.hookClassLoad:該方法實現在指定的類被載入的時候發出通知(改變其實現方式?).因為一個類可以在任何時候被載入,所以Substrate提供了一個方法用來檢測使用者感興趣的類何時被載入.

這個api需要實現一個簡單的介面MS.ClassLoadHook,該介面只有一個方法classLoaded,當類被載入的時候該方法會被執行.載入的類以引數形式傳入此方法.

void hookClassLoad(String name, MS.ClassLoadHook hook);
引數 描述
name 包名+類名,使用java的.符號(被hook的完整類名)
hook MS.ClassLoadHook的一個例項,當這個類被載入的時候,它的classLoaded方法會被執行.
#!java
MS.hookClassLoad("java.net.HttpURLConnection",
    new MS.ClassLoadHook() {
        public void classLoaded(Class<?> _class) {
            /* do something with _class argument */
        }
    }
);

MS.hookMethod:該API允許開發者提供一個回撥函式替換原來的方法,這個回撥函式是一個實現了MS.MethodHook介面的物件,是一個典型的匿名內部類.它包含一個invoked函式.

#!java
void hookMethod(Class _class, Member member, MS.MethodHook hook, MS.MethodPointer old);
引數 描述
_class 載入的目標類,為classLoaded傳下來的類引數
member 透過反射得到的需要hook的方法(或建構函式). 注意:不能HOOK欄位 (在編譯的時候會進行檢測).
hook MS.MethodHook的一個例項,其包含的invoked方法會被呼叫,用以代替member中的程式碼

0x01Hook Native 層


這塊的功能 xposed 就不能實現啦.

整個流程大致如下:

  • 建立工程,新增 NDK 支援
  • 將 cydia 的庫和標頭檔案加入工程
  • 修改 AndroidManifest配置檔案
  • 修改Android.md
  • 開發模組
    • 指定要hook 的 lib 庫
    • 保留原來的地址
    • 替換的函式
    • Substrate entry point
      • MSGetImageByName or dlopen
      • MSFindSymbol or dlsym or nlist 指定方法,得到開始地址
      • MSHookFunction 替換函式

使用方法


**第零步:新增 ndk 支援,將 cydia 的庫和標頭檔案加入工程

有關 ndk 開發的基礎可以參考此文: NDK入門篇

注意要是 xxx.cy.cpp,不要忘記.cy

其實應該是動態連結庫名稱中的 cy 必須有,所有在 Android.md 中module 處的 .cy 必須帶上咯

LOCAL_MODULE    := DumpDex2.cy

第一步:修改配置檔案

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:installLocation="internalOnly"
>
    <application android:hasCode="false">
    </application>

    <uses-permission android:name="cydia.permission.SUBSTRATE"/>
</manifest>

設定 android:hasCode 屬性 false,設定android:installLocation屬性internalOnly"

第二步:指定要 hook 的 lib 庫

#include <substrate.h>

MSConfig(MSFilterExecutable, "/system/bin/app_process")  //MSConfig(MSFilterLibrary, "liblog.so")

// this is a macro that uses __attribute__((__constructor__))
MSInitialize {
    // ... code to run when extension is loaded
}

設定要 hook 的可執行檔案或者動態庫

第三步: 等待 class

static void OnResources(JNIEnv *jni, jclass resources, void *data) {
    // ... code to modify the class when loaded
}

MSInitialize {
    MSJavaHookClassLoad(NULL, "android/content/res/Resources", &OnResources);
}

第四步:修改實現

static jint (*_Resources$getColor)(JNIEnv *jni, jobject _this, ...);

static jint $Resources$getColor(JNIEnv *jni, jobject _this, jint rid) {
    jint color = _Resources$getColor(jni, _this, rid);
    return color & ~0x0000ff00 | 0x00ff0000;
}

static void OnResources(JNIEnv *jni, jclass resources, void *data) {
    jmethodID method = jni->GetMethodID(resources, "getColor", "(I)I");
    if (method != NULL)
        MSJavaHookMethod(jni, resources, method,
            &$Resources$getColor, &_Resources$getColor);
}

下面是步驟是在官網教程基礎上對小白同學的一些補充吧.

» file libprocess.so                                                                  
libprocess.so: ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked (uses shared libs), not stripped

第五步

複製libsubstrate-dvm.so(注意 arm 和 x86平臺的選擇)和substrate.h到 jni 目錄下.建立SuperMathHook.cy.cpp檔案

第六步

配置Android.mk檔案

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE:= substrate-dvm
LOCAL_SRC_FILES := libsubstrate-dvm.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE    := SuperMathHook.cy
LOCAL_SRC_FILES := SuperMathHook.cy.cpp
LOCAL_LDLIBS := -llog
LOCAL_LDLIBS += -L$(LOCAL_PATH) -lsubstrate-dvm //-L指定庫檔案的目錄,-l指定庫檔名,-I指定標頭檔案的目錄.
include $(BUILD_SHARED_LIBRARY)

加入 c 的 lib

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE:= substrate-dvm
LOCAL_SRC_FILES := libsubstrate-dvm.so
include $(PREBUILT_SHARED_LIBRARY)


include $(CLEAR_VARS)
LOCAL_MODULE:= substrate
LOCAL_SRC_FILES := libsubstrate.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)

LOCAL_MODULE    := CydiaN.cy
LOCAL_SRC_FILES := CydiaN.cy.cpp
LOCAL_LDLIBS := -llog
LOCAL_LDLIBS += -L$(LOCAL_PATH) -lsubstrate-dvm -lsubstrate

include $(BUILD_SHARED_LIBRARY)

strings 檢視下里面的函式.

/data/data/com.jerome.jni/lib # strings libprocess.so                                                               <
/system/bin/linker
__cxa_finalize
__cxa_atexit
Jstring2CStr
malloc
memcpy
__aeabi_unwind_cpp_pr0
Java_com_jerome_jni_JNIProcess_getInfoMD5
....

脫殼機模組發開


網上流傳的 IDA dump 脫殼流程大致如下:

  • 對/system/lib/libdvm.so 方法JNI_OnLoad/dvmLoadNativeCode/dvmDexFileOpenPartial下斷點分析
  • IDA 附加 app (IDA6.5以及之後版本)
  • Ctrl+s 檢視基地址+偏移
  • IDA 分析尋找 dump 點
  • F8/F9執行到dex完全被解密到記憶體中時候進行 dump

現在目標就是透過 Cydia 的模組來自動化完成這個功能.這裡我們選擇對dvmDexFileOpenPartial函式進行 hook.至於為什麼要選擇這裡了?這就需要分析下 android dex最佳化過程


Android會對每一個安裝的應用的dex檔案進行最佳化,生成一個odex檔案.相比於dex檔案,odex檔案多了一個optheader,依賴庫資訊(dex檔案所需要的本地函式庫)和輔助資訊(類索引資訊等).

dex的最佳化過程是一個獨立的功能模組來實現的,位於http://androidxref.com/4.4.3_r1.1/xref/dalvik/dexopt/OptMain.cpp#57 其中extractAndProcessZip()函式完成最佳化操作.

http://androidxref.com/4.1.1/xref/dalvik/dexopt/OptMain.cpp

OptMain中的main函式就是載入dex的最原始入口

#!c
int main(int argc, char* const argv[])
{
    set_process_name("dexopt");

    setvbuf(stdout, NULL, _IONBF, 0);

    if (argc > 1) {
        if (strcmp(argv[1], "--zip") == 0)
            return fromZip(argc, argv);
        else if (strcmp(argv[1], "--dex") == 0)
            return fromDex(argc, argv);
        else if (strcmp(argv[1], "--preopt") == 0)
            return preopt(argc, argv);
    }
    ...
    return 1;
}

可以看到,這裡會分別對3中型別的檔案做不同處理,我們關心的是dex檔案,所以接下來看看fromDex函式:

#!c
static int fromDex(int argc, char* const argv[])
{
...
if (dvmPrepForDexOpt(bootClassPath, dexOptMode, verifyMode, flags) != 0) {
    ALOGE("VM init failed");
    goto bail;
}

vmStarted = true;

/* do the optimization */
if (!dvmContinueOptimization(fd, offset, length, debugFileName,
        modWhen, crc, (flags & DEXOPT_IS_BOOTSTRAP) != 0))
{
    ALOGE("Optimization failed");
    goto bail;
}
...
}

這個函式先初始化了一個虛擬機器,然後呼叫dvmContinueOptimization函式 /dalvik/vm/analysis/DexPrepare.cpp,進入這個函式:

#!c
bool dvmContinueOptimization(int fd, off_t dexOffset, long dexLength,
    const char* fileName, u4 modWhen, u4 crc, bool isBootstrap)
{
    ...
    /*
         * Rewrite the file.  Byte reordering, structure realigning,
         * class verification, and bytecode optimization are all performed
         * here.
         *
         * In theory the file could change size and bits could shift around.
         * In practice this would be annoying to deal with, so the file
         * layout is designed so that it can always be rewritten in place.
         *
         * This creates the class lookup table as part of doing the processing.
         */
        success = rewriteDex(((u1*) mapAddr) + dexOffset, dexLength,
                    doVerify, doOpt, &pClassLookup, NULL);

        if (success) {
            DvmDex* pDvmDex = NULL;
            u1* dexAddr = ((u1*) mapAddr) + dexOffset;

            if (dvmDexFileOpenPartial(dexAddr, dexLength, &pDvmDex) != 0) {
                ALOGE("Unable to create DexFile");
                success = false;
            } else {
    ...
}

這個函式中對Dex檔案做了一些最佳化(如位元組重排序,結構對齊等),然後重新寫入Dex檔案.如果最佳化成功的話接下來呼叫dvmDexFileOpenPartial,而這個函式中呼叫了真正的Dex檔案.在具體看看這個函式/dalvik/vm/DvmDex.cpp

#!c
/*
 * Create a DexFile structure for a "partial" DEX.  This is one that is in
 * the process of being optimized.  The optimization header isn't finished
 * and we won't have any of the auxillary data tables, so we have to do
 * the initialization slightly differently.
 *
 * Returns nonzero on error.
 */
int dvmDexFileOpenPartial(const void* addr, int len, DvmDex** ppDvmDex)
{
    DvmDex* pDvmDex;
    DexFile* pDexFile;
    int parseFlags = kDexParseDefault;
    int result = -1;

    /* -- file is incomplete, new checksum has not yet been calculated
    if (gDvm.verifyDexChecksum)
        parseFlags |= kDexParseVerifyChecksum;
    */

    pDexFile = dexFileParse((u1*)addr, len, parseFlags);
    if (pDexFile == NULL) {
        ALOGE("DEX parse failed");
        goto bail;
    }
    pDvmDex = allocateAuxStructures(pDexFile);
    if (pDvmDex == NULL) {
        dexFileFree(pDexFile);
        goto bail;
    }

    pDvmDex->isMappedReadOnly = false;
    *ppDvmDex = pDvmDex;
    result = 0;

bail:
    return result;
}

這個函式的前兩個引數非常關鍵,第一個引數是dex檔案的起始地址,第二個引數是dex檔案的長度,有了這兩個引數,就可以從記憶體中將這個dex檔案dump下來了,這也是在此函式下斷點的原因.該函式會呼叫dexFileParse()對dex檔案進行解析

所以在dexFileParse函式處來進行 dump 也是可行的.但是因為這個函式的原型是

DexFile* dexFileParse(const u1* data, size_t length, int flags) 

其返回值為一個結構體指標struct DexFile { ... },要 hook 這個函式得把結構體從 android 原始碼中扣出來或者直接改映象.

找到dvmDexFileOpenPartial函式在 libdvm.so 對應的名稱

#!bash
» strings libdvm_arm.so|grep dvmDexFileOpenPartial
_Z21dvmDexFileOpenPartialPKviPP6DvmDex

» strings libdvm_arm.so|grep dexFileParse
_Z12dexFileParsePKhji

有了上述理論基礎,現在可以正式開發模組了.大致流程如下

  • 指定要hook 的 lib 庫
  • Original method template 原函式模板
  • Modified method 替換的函式
  • Substrate entry point
    • MSGetImageByName or dlopen 載入lib得到 image
    • MSFindSymbol or dlsym or nlist 指定方法,得到開始地址
    • MSHookFunction 替換函式

完整程式碼

#!c
#include "substrate.h"
#include <android/log.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>

#define BUFLEN 1024
#define TAG "DEXDUMP"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)

//get packagename from pid
int getProcessName(char * buffer){
    char path_t[256]={0};
    pid_t pid=getpid();
    char str[15];
    sprintf(str, "%d", pid);
    memset(path_t, 0 , sizeof(path_t));
    strcat(path_t, "/proc/");
    strcat(path_t, str);
    strcat(path_t, "/cmdline");
    //LOG_ERROR("zhw", "path:%s", path_t);
    int fd_t = open(path_t, O_RDONLY);
    if(fd_t>0){
        int read_count = read(fd_t, buffer, BUFLEN);

        if(read_count>0){
              int  processIndex=0;
              for(processIndex=0;processIndex<strlen(buffer);processIndex++){
                  if(buffer[processIndex]==':'){
                      buffer[processIndex]='_';
                  }

              }
            return 1;
        }
    }
    return 0;
}

//指定要hook 的 lib 庫
MSConfig(MSFilterLibrary,"/system/lib/libdvm.so")

//保留原來的地址  DexFile* dexFileParse(const u1* data, size_t length, int flags)
int (* oldDexFileParse)(const void * addr,int len,int flags);

//替換的函式
int myDexFileParse(const void * addr,int len,void ** dvmdex)
{
    LOGD("call my dvm dex!!:%d",getpid());

    {
        //write to file
        //char buf[200];
        // 匯出dex檔案
        char dexbuffer[64]={0};
        char dexbufferNamed[128]={0};
        char * bufferProcess=(char*)calloc(256,sizeof(char));
        int  processStatus= getProcessName(bufferProcess);
        sprintf(dexbuffer, "_dump_%d", len);
        strcat(dexbufferNamed,"/sdcard/");
        if (processStatus==1) {
          strcat(dexbufferNamed,bufferProcess);
            strcat(dexbufferNamed,dexbuffer);

        }else{
            LOGD("FAULT pid not  found\n");
        }

        if(bufferProcess!=NULL)
        {

          free(bufferProcess);
        }

        strcat(dexbufferNamed,".dex");

        //sprintf(buf,"/sdcard/dex.%d",len);
        FILE * f=fopen(dexbufferNamed,"wb");
        if(!f)
        {
            LOGD(dexbuffer + " : error open sdcard file to write");
        }
        else{
            fwrite(addr,1,len,f);
            fclose(f);
        }



    }
    //進行原來的呼叫,不影響程式執行
    return oldDexFileParse(addr,len,dvmdex);
}

//Substrate entry point
MSInitialize
{
    LOGD("Substrate initialized.");
    MSImageRef image;
    //載入lib
    image = MSGetImageByName("/system/lib/libdvm.so");
    if (image != NULL)
    {

        void * dexload=MSFindSymbol(image,"_Z21dvmDexFileOpenPartialPKviPP6DvmDex");
        if(dexload==NULL)
        {
            LOGD("error find _Z21dvmDexFileOpenPartialPKviPP6DvmDex ");

        }
        else{
            //替換函式
            //3.MSHookFunction
            MSHookFunction(dexload,(void*)&myDexFileParse,(void **)&oldDexFileParse);
        }
    }
    else{
        LOGD("ERROR FIND LIBDVM");
    }
}

效果如下:

[email protected]:/sdcard $ l |grep dex
app_process_classes_3220.dex
com.ali.tg.testapp_classes_606716.dex
com.chaozh.iReaderFree_classes_4673256.dex
com.secken.app_xg_service_v2_classes_6327832.dex

脫殼機模組改進一

更改 hook 點為 dexFileParse,上文已經講解了為啥也可以選擇這裡.也分析了 dex 最佳化的過程,這裡在分析下 dex 載入的過程.

DexClassLoader廣泛被開發者用於外掛的動態載入.而PathClassLoader幾乎沒怎麼見過.

因為PathClassLoader 沒有提供最佳化 dex 的目錄而是固定將 odex 存放到 /data/dalvik-cache 中 ,故它只能載入已經安裝到 Android 系統中的 apk 檔案,也就是 /data/app 目錄下的 apk 檔案.

PathClassLoader 和 DexClassLoader 父類為 BaseDexClassLoader

http://androidxref.com/4.4.2_r1/xref/libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java

#!c
45    public BaseDexClassLoader(String dexPath, File optimizedDirectory,
       String libraryPath, ClassLoader parent) {

http://androidxref.com/4.4.2_r1/xref/libcore/dalvik/src/main/java/dalvik/system/DexPathList.java

#!c
DexPathList(this, dexPath, libraryPath, optimizedDirectory);

260    private static DexFile loadDexFile(File file, File optimizedDirectory)

http://androidxref.com/4.4.2_r1/xref/libcore/dalvik/src/main/java/dalvik/system/DexFile.java

#!c
141 static public DexFile loadDex(String sourcePathName, String outputPathName, int flags)

呼叫 native 函式 native private static int openDexFileNative(String sourceName, String outputName, int flags)

#!c
294    private static int openDexFile(String sourceName, String outputName,
295        int flags) throws IOException {
296        return openDexFileNative(new File(sourceName).getCanonicalPath(),
297                                 (outputName == null) ? null : new File(outputName).getCanonicalPath(),
298                                 flags);
299    }

http://androidxref.com/4.4.2_r1/xref/dalvik/vm/native/dalvik_system_DexFile.cpp

#!c
151 static void Dalvik_dalvik_system_DexFile_openDexFileNative(const u4* args, JValue* pResult)
//249 static void Dalvik_dalvik_system_DexFile_openDexFile_bytearray(const u4* args, JValue* pResult)

http://androidxref.com/4.4.2_r1/xref/dalvik/vm/RawDexFile.cpp

#!c
109 int dvmRawDexFileOpen(const char* fileName, const char* odexOutputName, RawDexFile** ppRawDexFile, bool isBootstrap)  //工具類方法開啟DEX檔案/Jar檔案

http://androidxref.com/4.4.4_r1/xref/dalvik/vm/DvmDex.cpp

#!c
93 int dvmDexFileOpenFromFd(int fd, DvmDex** ppDvmDex)  //從一個開啟的DEX檔案,對映到只讀共享記憶體並且解析內容
//146 int dvmDexFileOpenPartial(const void* addr, int len, DvmDex** ppDvmDex)  //透過地址和長度開啟部分DEX檔案

http://androidxref.com/4.4.4_r1/xref/dalvik/libdex/DexFile.cpp

#!c
289 dexFileParse(const u1* data, size_t length, int flags)  //解析dex檔案

方法openDexFile裡透過dvmDexFileOpenFromFd函式呼叫dexFileParse函式,分析Dex檔案裡每個類名稱和類的程式碼所在索引,然後dexFileParse呼叫函式dexParseOptData來把類名稱寫物件pDexFile->pClassLookup裡面,當然也更新了索引

#!c
//Substrate entry point
MSInitialize
{
    LOGD("Cydia Init");
    MSImageRef image;
    //載入lib
    image = MSGetImageByName("/system/lib/libdvm.so");
    if (image != NULL)
    {
        void * dexload=MSFindSymbol(image,"_Z12dexFileParsePKhji");
        if(dexload==NULL)
        {
            LOGD("error find _Z12dexFileParsePKhji");

        }
        else{
            //替換函式
            //3.MSHookFunction
            MSHookFunction(dexload,(void*)&myDexFileParse,(void **)&oldDexFileParse);
        }
    }
    else{
        LOGD("ERROR FIND LIBDVM");
    }
}

脫殼機模組改進二

  • 加入encode
  • 最佳化輸出
  • ...

github 地址如下,裡面已經有一個編譯好但是沒有簽名的 apk 了...

https://github.com/WooyunDota/DumpDex

如果提取的是 encode 版的,需要 decode 一下:

base64 -D -i com.ali.tg.testapp_606716.dex.encode.dex -o my.dex

一些錯誤排除


NDK Symbol 'NULL' could not be resolved

NDK環境沒有配好,沒有找到stddef.h

jni.h標頭檔案找不到

也是NDK環境未配置好,或者編譯器 BUG.先強行編譯一次若問題未解決就檢查下 NDK 環境.

如果遇到一些成員 ref 到兩種標頭檔案中,需要配置下 include.我在使用 mkdir 的時候 mode_t 就 ref 到 ndk 和 osx 的標頭檔案中導致編譯失敗.解決辦法下加入了include:

android-ndk-r10d/platforms/android-17/arch-arm/usr/include/sys

Android Studio 1.3已經開始支援 NDK,完全拋棄 eclipse 的時日即將到來.

0x03參考


http://www.cnblogs.com/goodhacker/p/4014617.html

http://www.cnblogs.com/goodhacker/p/4014617.html

http://www.cnblogs.com/baizx/p/4254359.html

http://www.gitzx.com/android-cydiasubstrate/

從原始碼中跟蹤Dex的載入流程

https://github.com/bunnyblue/DexExtractor

Android逆向之動態除錯總結

dex檔案的最佳化解析及裝載

Android系統ODEX檔案格式解析

DexClassLoader4.4.2動態載入分析(磁碟載入分析)

Android4.0記憶體Dex資料動態載入技術

本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章