Python下借用AndroidNativeEmu实现在PC端模拟调用Android Native so库函数

目录

 

涉及工具

开发IDE之PyCharm

Python

AndroidNativeEmu

最简单示例演示

问题

keystone-engine库在Window10下不能正常调用问题

对于没有Jni_OnLoad函数的so库如何调用以Java_开头的函数问题?

NotImplementedError问题

Invalid memory fetch (UC_ERR_FETCH_UNMAPPED)问题

如何手动确定出现Bug的位置

Invalid get_reference(%d)问题

多次执行同一函数会报错问题

申请的内存如何释放问题(重要)

后记

体会

总结


涉及工具

开发IDE之PyCharm

版本:2019.2.5免费版

下载地址:

Python

版本:python3.7.0

下载地址:https://download.csdn.net/download/aiming66/10667438

AndroidNativeEmu

下载地址:https://github.com/P4nda0s/AndroidNativeEmu

最简单示例演示

参考:https://github.com/P4nda0s/AndroidNativeEmu/blob/8d3b75b00cc3178955dc8f9ad909f3911a67dd5b/samples/example_jni.py

 

class MainActivity(metaclass=JavaClassDef, jvm_name='local/myapp/testnativeapp/MainActivity'):

    def __init__(self):
        pass

    @java_method_def(name='stringFromJNI', signature='()Ljava/lang/String;', native=True)
    def string_from_jni(self, mu):
        pass

    def test(self):
        pass
    emulator.mu.hook_add(UC_HOOK_CODE, debug_utils.hook_code)
    main_activity = MainActivity()
    logger.info("Response from JNI call: %s" % main_activity.string_from_jni(emulator))

输出

2019-12-04 23:37:06,637    INFO                           __main__ | Response from JNI call: Hello from C++ ONLOAD!!
2019-12-04 23:37:06,637    INFO                           __main__ | Exited EMU.
2019-12-04 23:37:06,637    INFO                           __main__ | Native methods registered to MainActivity:
2019-12-04 23:37:06,637    INFO                           __main__ | - [0xcbc9cfb9] stringFromJNI - ()Ljava/lang/String;

问题

keystone-engine库在Window10下不能正常调用问题

直接去官网(http://www.keystone-engine.org/download/)下载Python module for Windows - Binaries,然后在电脑上安装即可

对于没有Jni_OnLoad函数的so库如何调用以Java_开头的函数问题?

解决方案如下

emulator.java_vm.address_ptr替换成 emulator.java_vm.jni_env.address_ptr即可,实例如下

   emulator.call_symbol(lib_module, 'Java_org_xxxx_encryptMessage',emulator.java_vm.address_ptr, 0x00, msgData,len(msgData), key)

------更新解决方案------

提示Jni_OnLoad报错可以不用管,不影响后面执行 ,参考:https://www.52pojie.cn/thread-1031123-1-1.html#28013966_emu%E4%BB%A3%E7%A0%81

因为JNIEnv 和jobject未使用,所以下面可以直接传0

NotImplementedError问题

解决方法在后面

Invalid memory fetch (UC_ERR_FETCH_UNMAPPED)问题

参考:https://github.com/zhkl0228/unidbg/issues/12

参考:https://www.anquanke.com/post/id/95199

如何手动确定出现Bug的位置

这个工具现在国内文章寥寥无几,遇到问题实在很难找到解决方法,因此既然没有人帮我们抓鱼,就要我们自己去学习怎么抓鱼了,接下来就来研究下怎么抓鱼(抓bug)吧

我是参考的这篇文章的做法https://www.anquanke.com/post/id/95199

就是打印每条执行的指令,当出错时自然知道在哪条指令哪个地址出错了,然后我们在IDA里找到对应的地址,看看其究竟执行了什么。

就比如上面那个NotImplementedError错误,经过利用上面的方法跟踪发现是在调用env->GetByteArrayElements()出现了问题

既然找到了问题,接下来就来说下怎么解决这些问题, 在上面参考的那篇文章中,他是采用跳过的方法,不过我这个地方,应该不能跳过,毕竟后面还需要这条指令的返回值呢

经过深入调试发现NotImplementedError是由于在so中调用了某个jni方法,而这个方法作者直接抛出了异常,并没有实现其功能,如下图所示:

这是我实现后的

Invalid get_reference(%d)问题

根据错误堆栈,确定出错地方是在下图这个地方

经过单步调试发现问题,显然传入的参数不对,正常情况下应该是0,1,2,....之类的数字,并且经过我手动调整后,的确可以正常运行了,不知道是作者的错误还是我的so库有问题

经过调试,猜测应该是参数过多问题

多次执行同一函数会报错问题

应该由于多次申请内存,并且预先申请的总内存过小,导致出现错误。

临时解决办法:调整预先申请的总内存大小

理想解决办法:申请内存后及时释放

申请的内存如何释放问题(重要)

其实程序会自己释放,而我这个之所以没释放,是由于原先用于释放的代码我没有实现导致的,具体举个例子来说明

一般程序执行了env->get_byte_array_elements函数,就必须执行env->release_byte_array_elements

但我原先以为release_byte_array_elements执行了没什么用,所以就直接填个pass(python里的关键字)代替了,所以就导致了上面的内存问题,具体解决方法就是在release_byte_array_elements实现释放内存的操作就行了,如下图:

后记

当看到成功解出的明文后,那种满满的成就感真实非常美妙啊,霎时感觉这几天的努力终于有了回报,喜悦的都快要哭出来了,哈哈😄 。

体会

感觉就像上帝一样,控制着每一条指令的执行,那种感觉真是太爽了,真是激发了我对于汇编的兴趣!

总结

1.寄存器原来是固定分配的,每个寄存器都有对应的机器码(十六进制值),而不是在运行时随机分配的

相关推荐
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页