unicorn_starting
模拟Jni与Java交互
目标
hook这个函数,其中存在调用java类和java函数
尝试将上一次的代码进行修改后直接执行,观察结果
注册java类和方法
结果发现不能找到java这个类,下面已经给出申明,直接复制即可
class com_sec_udemo_MainActivity(metaclass=JavaClassDef, jvm_name="com/sec/udemo/MainActivity"):
def __init__(self):
pass
# 添加自定义java类
emulator.java_classloader.add_class(com_sec_udemo_MainActivity)
执行后发现又要声明相关方法:
声明方法:
@java_method_def(name='getSaltFromJava',signature='(Ljava/lang/String;)Ljava/lang/String;',
args_list=['jstring'],native=False) # 这里native=False申明此方法非native方法
def getSaltFromJava(self,mu,data):
pass
这个函数在java中的功能如下:
这里我们作出拼接返回即可
执行后再次报错
这里我们缺少jobject对象,这里我们手动创建一下,然后传入进去
obj = com_sec_udemo_MainActivity()
sign = emulator.call_symbol(libnat_mod,'Java_com_sec_udemo_MainActivity_sign_1lv3',
emulator.java_vm.jni_env.address_ptr,obj,'123')
print(sign)
然后这里又有相加时出现错误
这里我们调试一下,data的内容:
一看是java string类型,类型展开发现value中value就是python的str类型
修改后成功出结果:
完整代码:
from unicorn import *
import logging
import sys
from androidemu.java.helpers.native_method import native_method
from UnicornTraceDebugger import udbg
from androidemu.emulator import Emulator
from androidemu.utils import memory_helpers
from androidemu.java.java_classloader import JavaClassDef
from androidemu.java.java_method_def import java_method_def
# 配置logging
logging.basicConfig(
stream=sys.stdout,
level=logging.DEBUG,
format="%(asctime)s %(levelname)7s %(name)34s | %(message)s"
)
# 用于打印调试信息
logger = logging.getLogger(__name__)
class com_sec_udemo_MainActivity(metaclass=JavaClassDef, jvm_name="com/sec/udemo/MainActivity"):
def __init__(self):
pass
@java_method_def(name='getSaltFromJava',signature='(Ljava/lang/String;)Ljava/lang/String;',
args_list=['jstring'],native=False)
def getSaltFromJava(self,mu,data):
print('hello')
return data.value.value + 'salt..'
# 根据执行失败的库函数,进行hook,直接本地写函数实现相关库函数功能,首先导入修饰器
@native_method
def __aeabi_memclr(mu,addr,size):
mu.mem_write(addr,bytes(size))
print('__aeabi_memclr_ptr (addr:%x,size:%d)' % (addr,size))
@native_method
def __aeabi_memcpy(mu,dist,source,size):
data = mu.mem_read(source,size)
mu.mem_write(dist,bytes(data))
print('__aeabi_memcpy (dist:%x,source:%x)' % (dist,source))
@native_method
def sprintf(mu,buffer,format,arg1,arg2):
format1 = memory_helpers.read_utf8(mu,format)
data1 = memory_helpers.read_utf8(mu,arg1)
res = format1 % (data1,arg2)
mu.mem_write(buffer,bytes((res+'\x00').encode('utf-8')))
print('sprintf (%s)' % (format))
# 创建模拟器
emulator = Emulator()
# 添加hook 此处必须在导入so文件之前就hook,因为此hook的本质就是hook got表的内容
# 在导入so文件之前hook才生效,导入之后没法hook
emulator.modules.add_symbol_hook('__aeabi_memclr', emulator.hooker.write_function(__aeabi_memclr) + 1)
emulator.modules.add_symbol_hook('__aeabi_memcpy', emulator.hooker.write_function(__aeabi_memcpy) + 1)
emulator.modules.add_symbol_hook('sprintf', emulator.hooker.write_function(sprintf) + 1)
# 添加自定义java类
emulator.java_classloader.add_class(com_sec_udemo_MainActivity)
# 加载相关so文件
# do_init 参数为false,即不执行初始化函数,因为unicorn不能实现相关初始化操作,
# 这可能会涉及更多库的调用
emulator.load_library('./lib/libc.so',do_init=False)
libnat_mod = emulator.load_library('./lib/libnative-lib.so',do_init=False)
# 执行报错时打印调试信息,跟踪报错与定位发生报错的相关地址
dbg = udbg.UnicornDebugger(emulator.mu,udbg.UDBG_MODE_ALL)
# 开始执行想要执行的jni函数
try:
# 根据so模块调用指定的函数,后面都是函数的参数
# 参数1: JNIEnv
# 参数2: 是java类的对象,这里填0即可
# 参数3: 是函数输入字符串
obj = com_sec_udemo_MainActivity()
sign = emulator.call_symbol(libnat_mod,'Java_com_sec_udemo_MainActivity_sign_1lv3',
emulator.java_vm.jni_env.address_ptr,obj,'123')
print(sign)
except UcError as e:
# 打印调用栈
tracks = dbg.get_tracks()
# 这里打印调用地址即可,打印后100条
for addr in tracks[-100:-1]:
print(hex(addr - 0xcbc66000))
print(e)
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 jaytp@qq.com