換一個帥一點姿勢實現DexHunter

env->ReleaseStringUTFChars(methodName_, methodName);

return ret;

}

6. binggo,使用smali api,直接解碼

/**

* 將指定loader的smali全部dump到硬盤,請異步執行該函數

*

* @param loader loader

*/

public static void dissembleAllDex(Object loader) {

Class loaderClass = resolveLoaderClass(loader);

DexBackedDexFile memoryMethodDexFile = createMemoryDexFile(loaderClass);

File dumpDir = resolveDumpDir(memoryMethodDexFile);

DexFile reWritedDexFile = rewrite(memoryMethodDexFile, loaderClass.getClassLoader());

XposedBridge.log("脫殼目錄:" + dumpDir.getAbsolutePath());

int jobs = Runtime.getRuntime().availableProcessors();

if (jobs > 6) {

jobs = 6;

}

if (memoryMethodDexFile instanceof DexBackedOdexFile) {

baksmaliOptions.inlineResolver = InlineMethodResolver

.createInlineMethodResolver(((DexBackedOdexFile) memoryMethodDexFile).getOdexVersion());

}

Log.i("weijia", "開始進行脫殼");

if (Baksmali.disassembleDexFile(reWritedDexFile, dumpDir, jobs, baksmaliOptions)) {

Log.i("weijia", "脫殼完成,但是存在錯誤");

} else {

Log.i("weijia", "脫殼成功,請在" + dumpDir + "中查看smali文件");

}

Toast.makeText(SharedObject.context, "脫殼完成,請在" + dumpDir + "中查看smali文件", Toast.LENGTH_LONG).show();

}

7.binggo,使用smali API,輸出dex文件

/**

* 將對應class對應的dex文件的二進制dump出來

*

* @param loader 該dex文件定義的任何一個class,或者class定義的object

* @return 一個byteBuffer,包含了二進制數據

*/

public static ByteBuffer dumpDex(Object loader) {

Class loaderClass = resolveLoaderClass(loader);

DexBackedDexFile memoryDexFile = createMemoryDexFile(loaderClass);

byte[] buf = (byte[]) XposedHelpers.getObjectField(memoryDexFile, "buf");

DexFile dexFile = rewrite(memoryDexFile, loaderClass.getClassLoader());

final DexBuilder builder = new DexBuilder(Opcodes.forApi(apiLevel()));

MemoryDataStore memoryDataStore = new MemoryDataStore(buf.length);

for (ClassDef classDef : dexFile.getClasses()) {

try {

buildClassDef(classDef, builder);

} catch (Exception e) {

Log.i("weijia", "error when define class:" + classDef.getType() + " skipped for rebuild it");

}

}

try {

builder.writeTo(memoryDataStore);

} catch (IOException ioe) {

//the memory writer,no ioe happend

throw new RuntimeException(ioe);

}

return ByteBuffer.wrap(memoryDataStore.getData());

}

7. 如何調用

XposedHelpers.findAndHookConstructor(Activity.class, new XC_MethodHook() {

@Override

protected void afterHookedMethod(MethodHookParam param) throws Throwable {

Object activity = param.thisObject;

if (activity == null) {

return;

}

XposedBridge.log("hook class " + activity.getClass());

if (StringUtils.equalsIgnoreCase(activity.getClass().getName(), "com.xxx.xxx.MainActivity")) {

Dumper.dumpDex(activity);

}

}

});

8. 對了你需要移植dalvik的dexlib模塊代碼,還有/vm/oo包下面的代碼,到你的jni環境下。要不然沒有dex的相關數據結構,也沒有ClassObject的數據結構。

然後,不願意放整個工程,不要求代碼。論文放出來,還是自己實現一遍才能有收穫。

其他:

相比原始DexHunter的優點:

1. 定位dex更加精準,DexHunter用過filename來確定當前dex是不是需要處理,很容易被加殼平臺識別到這個特徵。而且每次都要在放Android系統push一些文件,比較麻煩。我這個,直接通過class對象尋找,想找按個找那個。

2. 併發,可能沒有寫過Linux c語言程序,看那個pthread哪裡看不懂。DexHunter為了防止多次重複處理同一個dex文件,寫了比較複雜的加鎖邏輯。這個放到java層,很簡單實現吧。

3. 多dex,如果一個apk多個dex都需要處理。DexHunter不好處理,因為他輸出就是whole.dex

4. dvmDefineClass失敗,就算正常情況,一個classLoader下面的class,也不是全部可以正常load成功。DexHunter的流程是刪除這些bad class,我還可以儘可能的使用原始dex數據進行解碼。

5. Dalvik_dalvik_system_DexFile_defineClassNative被替換,這可能導致defineClassNative函數不被調用,這樣DexHunter無法攔截到。我用classLoader.loadeClass,java標準接口,這個他永遠沒法替換。

6.其他數據結構加密調整,如果未來不光光是method的數據變化了。由於使用baksmali建立的模型,任何數據結構都很容易重構替換,畢竟是java,抽象封裝很好用。

7.脫殼時機,脫殼輸出控制更加方便。提供的是api,你調用就脫殼不調用就不脫殼。脫殼結果是java的二進制流,你想怎麼編碼、加密、轉儲都很方便。java層的api太多了。

8.可移植性,是一個普通的xposed項目,任何一個有xposed環境的Android機器都可以(當然現在還沒有實現art,不過理論上沒問題)。也不需要編譯系統鏡像。等幾天再把xposed包裝一下,免root脫殼。

當然,我對dex文件格式,並不是非常熟,反正沒有DexHunter玩兒的那麼溜,所以只有多用別人的api了。

關注看雪學院公眾號:ikanxue,更多幹貨等你來拿~


分享到:


相關文章: