0
点赞
收藏
分享

微信扫一扫

Frida和IDA分析OLLVM混淆APK


查看APK Java代码

用到了hello-jni.so里的Native函数sign1。

package com.example.hellojni;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.example.hellojni_sign2.R;
import org.apache.commons.lang3.RandomStringUtils;

public class HelloJni extends AppCompatActivity {
TextView tv;

public native String sign1(String str);

public native String stringFromJNI();

/* access modifiers changed from: protected */
@Override // android.support.v7.app.AppCompatActivity, android.support.v4.app.SupportActivity, android.support.v4.app.FragmentActivity
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity_hello_jni);
this.tv = (TextView) findViewById(R.id.hello_textview);
this.tv.setText(stringFromJNI());
((Button) findViewById(R.id.button_sign1)).setOnClickListener(new View.OnClickListener() {
/* class com.example.hellojni.HelloJni.AnonymousClass1 */

public void onClick(View view) {
HelloJni.this.tv.setText(HelloJni.this.sign1(RandomStringUtils.randomAscii(16)));
}
});
}

static {
System.loadLibrary("hello-jni");
}
}

IDA Exports 查找​​JNI_Onload​​:

Frida和IDA分析OLLVM混淆APK_OLLVM


双击:

Frida和IDA分析OLLVM混淆APK_OLLVM_02

加载

Shift+F11打开Type libraries窗口,并加载​​Android Arm​​:

Frida和IDA分析OLLVM混淆APK_交叉引用_03

Frida和IDA分析OLLVM混淆APK_OLLVM_04


根据​​源码​​可知:

JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
base::android::InitVM(vm);

if (!base::android::OnJNIOnLoadInit())
return -1;

mojo::core::Init();
return JNI_VERSION_1_4;
}

JNI_OnLoad第一个参数类型是​​JavaVM*​​,因此在IDA里修改参数类型,IDA会自动把GetEnv等函数自动更改为对应的函数名称:

Frida和IDA分析OLLVM混淆APK_android_05

在GetEnv上,右键,​​Force call type​​:

Frida和IDA分析OLLVM混淆APK_OLLVM_06

result = (*a1)->GetEnv(a1, (void **)&v5, 65540);

查看​​定义​​:

Frida和IDA分析OLLVM混淆APK_交叉引用_07


可知,参数v5是​​JNIEnv*​​ 类型,然后修改v5类型:

Frida和IDA分析OLLVM混淆APK_java_08


可以看到​​FindClass​​​,​​RegisterNatives​​等函数名,如果没出来以上函数名,可以多试几下。

​Force call type​​:

Frida和IDA分析OLLVM混淆APK_android_09


RegisterNatives函数​​定义​​:

Frida和IDA分析OLLVM混淆APK_android_10


v6应该是methods数组,双击​​v6 = off_33D60​​​中的​​off_33D60​​,

Frida和IDA分析OLLVM混淆APK_OLLVM_11


按键D三次,变化为:DCB->DCW->DCD->DCQ,从Byte->Word->DoubleWord(32位)->Quadword(64位):

Frida和IDA分析OLLVM混淆APK_android_12


查看aYcmd的交叉引用(x):

Frida和IDA分析OLLVM混淆APK_java_13


一般.datadiv_decode开始的,紧接着随机数的,OLLVM混淆的字符串的解密函数。查看一下调用位置(随便找一个.datadiv_decode,查一下交叉引用,找到上面的EXPORT,再查看一下交叉引用):

Frida和IDA分析OLLVM混淆APK_java_14


在​​.init_array​​​节里面,比​​JNI_Onload​​加载的还早。

Hook查看数据

查看一下加密字符串​​ycmd;​​​(虚拟地址是​​0x3070​​)的解密字符串:

Frida和IDA分析OLLVM混淆APK_java_15

function print_hex(addr) {
var base_hello_jni = Module.findBaseAddress("libhello-jni.so");
console.log(hexdump(base_hello_jni.add(addr)));
}
// print_hex(0x37070)

看到解密的字符串:

7f3a0be070  73 69 67 6e 31 00 00 00 00 00 00 00 00 00 00 00  sign1...........
7f3a0be080 28 4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 74 72 69 (Ljava/lang/Stri
7f3a0be090 6e 67 3b 29 4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 ng;)Ljava/lang/S
7f3a0be0a0 74 72 69 6e 67 3b 00 00 62 61 73 69 63 5f 73 74 tring;..basic_st
7f3a0be0b0 72 69 6e 67 00 00 00 00 00 00 00 00 00 00 00 00 ring............

Hook Env函数

先获取到sign1函数虚拟地址(根据函数物理地址找到模块基地址,然后算出函数虚拟地址),本例是​​0xe76c​​,跳转到函数(G):

Frida和IDA分析OLLVM混淆APK_交叉引用_16


修改第一个参数类型为​​JNIEnv*​​​,修改第一个参数名为:​​env​​:

Frida和IDA分析OLLVM混淆APK_java_17

Hook Env的这几个函数:​​GetStringUTFChars​​​、​​NewStringUTF​​​、​​RegisterNatives​​。

function hook_libart() {

var module_libart = Process.findModuleByName("libart.so");
console.log(module_libart);
var addr_RegisterNatives = null;
var addr_GetStringUTFChars = null;
var addr_NewStringUTF = null;
//枚举模块的符号
var symbols = module_libart.enumerateSymbols();
for (var i = 0; i < symbols.length; i++) {
var name = symbols[i].name;
if (name.indexOf("CheckJNI") == -1 && name.indexOf("JNI") > 0) {
if (name.indexOf("RegisterNatives") > 0) {
console.log(name);
addr_RegisterNatives = symbols[i].address;
} else if (name.indexOf("GetStringUTFChars") > 0) {
console.log(name);
addr_GetStringUTFChars = symbols[i].address;
} else if (name.indexOf("NewStringUTF") > 0) {
console.log(name);
addr_NewStringUTF = symbols[i].address;
}

}
}

if (addr_RegisterNatives) {
Interceptor.attach(addr_RegisterNatives, {
onEnter: function (args) {
var java_class = Java.vm.tryGetEnv().getClassName(args[1]);
var methods = args[2];
var method_count = parseInt(args[3]);
console.log("addr_RegisterNatives java_class:", java_class, "method_count:", method_count);
for (var i = 0; i < method_count; i++) {
console.log(methods.add(i * Process.pointerSize * 3).readPointer().readCString());
console.log(methods.add(i * Process.pointerSize * 3 + Process.pointerSize).readPointer().readCString());
var fnPtr = methods.add(i * Process.pointerSize * 3 + Process.pointerSize * 2).readPointer();
var module_so = Process.findModuleByAddress(fnPtr);
// 找到函数虚拟地址
console.log(module_so.name + "!" + fnPtr.sub(module_so.base));

}
}, onLeave: function (retval) {

}
})
}
if (addr_GetStringUTFChars) {
Interceptor.attach(addr_GetStringUTFChars, {
onLeave : function(retval) {
console.log("[GetStringUTFChars] : ", ptr(retval).readCString());
}
})
}
if (addr_NewStringUTF) {
Interceptor.attach(addr_NewStringUTF, {
onEnter : function(args) {
console.log("[NewStringUTF] : ", ptr(args[1]).readCString());
}
})
}
}

通过不断的交叉引用分析,找到了类似md5的函数:

Frida和IDA分析OLLVM混淆APK_java_18


改名(N):​​(*v4)->NewStringUTF(v4, (const char *)&result_buffer);​

Frida和IDA分析OLLVM混淆APK_android_19


​print_hex(0x37040)​​是​​02x​​:

Frida和IDA分析OLLVM混淆APK_OLLVM_20


继续往上回溯,​​sub_103F0​​:

Frida和IDA分析OLLVM混淆APK_android_21


Frida和IDA分析OLLVM混淆APK_android_22


其中参数a3是返回结果,改名(N):

Frida和IDA分析OLLVM混淆APK_交叉引用_23


继续查看result_buffer的交叉引用(x):

Frida和IDA分析OLLVM混淆APK_交叉引用_24


Frida和IDA分析OLLVM混淆APK_交叉引用_25


Frida和IDA分析OLLVM混淆APK_java_26


Frida和IDA分析OLLVM混淆APK_android_27


查看​​sub_FD90​​,并改名:

Frida和IDA分析OLLVM混淆APK_OLLVM_28


查看_result_buffer交叉引用:

Frida和IDA分析OLLVM混淆APK_java_29


改名v3为​​__result_buffer​​:

Frida和IDA分析OLLVM混淆APK_OLLVM_30


查看交叉引用,在sub_FD90发现:

Frida和IDA分析OLLVM混淆APK_交叉引用_31

Frida和IDA分析OLLVM混淆APK_android_32


查看v6的处理函数​​sub_F008​​​,发现md的常量:​​0xD76AA478​​:

Frida和IDA分析OLLVM混淆APK_android_33


查看sub_FD90的交叉引用,发现​​lrand48​​:

Frida和IDA分析OLLVM混淆APK_交叉引用_34

function hook_java() {
Java.perform(function() {
var HelloJni = Java.use("com.example.hellojni.HelloJni");
HelloJni.sign1.implementation = function(args) {
// 传入固定的参数
return this.sign1("0123456789abcdef");
}
});
}

function hook_native() {
var base_hello_jni = Module.findBaseAddress("libhello-jni.so");
Interceptor.attach(base_hello_jni.add(0xFD90), {
// 查看虚拟地址为0xFD90的函数
onEnter : function(args) {
this.arg0 = args[0]; //把参数保存到局部变量里面
this.arg1 = args[1];
}, onLeave : function(retval) {
console.log("0xFD90:\r\n", hexdump(this.arg0), "\r\n", hexdump(this.arg1));
}
});

Interceptor.attach(base_hello_jni.add(0xF008), {
// Hook md5函数(虚拟地址0xF008),查看参数
onEnter : function(args) {
this.arg0 = args[0]; //把参数保存到局部变量里面
this.arg1 = args[1];
}, onLeave : function(retval) {
console.log("0xF008:\r\n", hexdump(this.arg0), "\r\n", hexdump(this.arg1));
// +++++++++salt2+0123456789abcdef
console.log("0xF008:", ptr(this.arg1).readCString());
}
});
}

function hook_libc() {
Interceptor.attach(Module.findExportByName("libc.so", "lrand48"), {
// Hook lrand48
onLeave : function(retval) {
// 替换生成的随机数,固定随机数
retval.replace(0xAAAAAAAA);
console.log("lrand48:", retval);
}
})
}


举报

相关推荐

0 条评论