AndroidNativeEmu模拟执行大厂so实操教程(七) 构造参数来调用Native函数
2020-12-03 18:19:33 Author: 91fans.com.cn(查看原文) 阅读量:121 收藏

一、目标

一、目标

这次的报错是

Could not find class 'com/jingdong/jdsdk/widget/ToastUtils' for JNIEnv.

二、步骤

这个简单,再增加一个 ToastUtils

class ToastUtils(metaclass=JavaClassDef, jvm_name='com/jingdong/jdsdk/widget/ToastUtils'):
    def __init__(self):
        pass

    @java_method_def(name='longToast',args_list=["jstring"], signature='(Ljava/lang/String;)V')
    def longToast(self, mu, *args, **kwargs):
        logger.info("longToast %r" % args)
        pass

emulator.java_classloader.add_class(ToastUtils)

跑一下,耶!!! JNI_OnLoad 跑通了,

下面开始来构造参数调用我们的目标 getSignFromJni

getSignFromJni函数我们之前分析过,它一共有6个参数,第一个参数是Context,后面5个都是String

Context正好原作者有实现,(实际在本例中Context只是传进去了,并没有使用)

调用方法如下:

activity_Th = ActivityThread()
result = emulator.call_symbol(lib_module, 'Java_com_jingdong_common_utils_BitmapkitUtils_getSignFromJni',emulator.java_vm.jni_env.address_ptr,0x00, activity_Th.getSystemContext(emulator),"asynInteface", '{"intefaceType":"asynIntefaceType","skuId":"100008667315"}', "99001184062989-f460e22c02fa", "android", "9.2.2")

logger.info("Response from JNI call: %s" % result.toString(emulator))

为什么前面多两个参数呢? 我们看看 IDA出来的伪码,比java调用的多两个参数,第一个是 JNIEnv *env, 第二个是 jobject obj

int __fastcall Java_com_jingdong_common_utils_BitmapkitUtils_getSignFromJni(JNIEnv *a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8)
{
  return sub_127E4(a1, a3, a4, a5, a6, a7, a8);
}

JNIEnv类型实际上代表了Java环境,通过这个JNIEnv* 指针,就可以对Java端的代码进行操作。例如,创建Java类中的对象,调用Java对象的方法,获取Java对象中的属性等等。JNIEnv的指针会被JNI传入到本地方法的实现函数中来对Java端的代码进行操作。

参数:jobject obj的解释:

如果native方法不是static的话,这个obj就代表这个native方法的类实例

如果native方法是static的话,这个obj就代表这个native方法的类的class对象实例(static方法不需要类实例的,所以就代表这个类的class对象)

这两个参数是所有的JNI函数都有的。

好了,继续跑

这次要增加java/lang/StringBuffer

这时候就体现 unidbg 的优势了,增加 StringBuffer 这种java类,用java来写,太TMD的简单了。用python就不那么好过了。

class StringBuffer(metaclass=JavaClassDef, jvm_name='java/lang/StringBuffer'):
    def __init__(self):
        self._str = ''
        pass

    @java_method_def(name='<init>', signature='()V', native=False)
    def init(self, emu):
        pass

    @java_method_def(name='append', args_list=["jstring"], signature='(Ljava/lang/String;)Ljava/lang/StringBuffer;', native=False)
    def append(self, emu,*args, **kwargs):
        logger.info("append %r" % args)
        pyobj = JNIEnv.jobject_to_pyobject(args[0])
        self._str += pyobj
        return self

    @java_method_def(name='toString', signature='()Ljava/lang/String;', native=False)
    def toString(self, emu):
        logger.info("toString %r" % self._str)
        return String(self._str)

这里我们实现了 appendtoString 这两个函数。

再依葫芦画瓢增加好 java/lang/Integer 和 java/lang/String

再跑一下, 成功了

三、总结

本次教程,一共介绍了

  • 增加类
  • 增加成员函数
  • 填jmethodID相同的坑
  • 实现函数的功能
  • 增加字段(成员变量)
  • 补齐jni函数 最后 构造参数来调用Native函数。

其中最难的部分就是 补齐jni函数实现java类 。 这里需要对Android开发和java开发的熟悉,在实现java类方面 unidbg 有天然的优势。而 填jmethodID相同的坑 就要靠经验和细心了,再就是绝不放弃的精神。

做逆向,七分靠运气,三分靠努力,诸君共勉

文章作者 奋飞

上次更新 2020-12-03

许可协议 奋飞安全原创,转载请注明出处。


文章来源: http://91fans.com.cn/post/androidemusev/
如有侵权请联系:admin#unsafe.sh