首页
社区
课程
招聘
利用AndroidNativeEmu完成多层jni调用的模拟(题目出自看雪高研班2021年12月份作业第二题)
发表于: 2022-7-17 18:05 13892

利用AndroidNativeEmu完成多层jni调用的模拟(题目出自看雪高研班2021年12月份作业第二题)

2022-7-17 18:05
13892

这道题主要考察的是对多层jni调用的模拟,所谓多层jni调用指native java函数的实现c/c++函数中又反过来调用java函数,而这个被调用的java函数仍然是一个native函数。而对于AndroidNativeEmuUniDbg目前(做题的时候)都不支持这种多层调用,UniDbg更新应该算是比较频繁的,有可能后边会支持。
不能直接支持,只能用取巧的方式来实现。我这里用了两个程序来实现,一个程序通过subprocess来调用另外一个程序,获取这个程序的结果进一步利用。这种实现方式是有缺陷的,如果模拟的程序函数对全局的变量产生了副作用,或者有共同的依赖,那么模拟可能会失败,在这种情况下需要做特殊的处理,单独处理同步共享的全局变量。
通过这个题目的练习可以学得AndroidNativeEmuUniDbg不支持的地方,或者说有待改进的点。工具不支持,必要时必须自己写代码扩展功能。

单独为crypt2函数写一个源文件,crypt2_impl.py文件内容为:

main.py文件内容:

当输入值为'XUe'时打印出来的结果为:

当输入值不为'XUe'时打印出来的结果为:

模拟成功。

import logging
import sys
from androidemu.emulator import Emulator
from androidemu.java.helpers.native_method import native_method
from androidemu.utils import memory_helpers
 
@native_method
def sprintf(uc, str, format, args):
    str_utf8 = memory_helpers.read_utf8(uc, str)
    format_utf8 = memory_helpers.read_utf8(uc, format)
    args_utf8 = memory_helpers.read_utf8(uc, args)
    logger.info("str_utf8:{}, format_utf8:{}, args_utf8:{}".format(str_utf8, format_utf8, args_utf8))
 
    result_string = format_utf8 % args_utf8
    memory_helpers.write_utf8(uc, str, result_string)
    return len(result_string)
 
 
@native_method
def malloc(uc, size):
    return emulator.memory_manager.allocate(size)
 
 
@native_method
def strcmp(uc, s1, s2):
    s1_utf8 = memory_helpers.read_utf8(uc, s1)
    s2_utf8 = memory_helpers.read_utf8(uc, s2)
 
    if s1_utf8 == s2_utf8:
        ret = 0
    elif s1_utf8 < s2_utf8:
        ret = -1
    else:
        ret = 1
    logger.info("s1:{},s2:{},ret:{}".format(s1_utf8, s2_utf8, ret))
    return ret
 
 
# Configure logging
logging.basicConfig(
    stream=sys.stderr,
    level=logging.DEBUG,
    format="%(asctime)s %(levelname)7s %(name)34s | %(message)s"
)
 
logger = logging.getLogger(__name__)
 
so_file = "my_binaries/libnative-lib.so"
libc_file = "example_binaries/32/libc.so"
 
# Initialize emulator
emulator = Emulator(vfp_inst_set=True)
 
emulator.modules.add_symbol_hook('sprintf', emulator.hooker.write_function(sprintf) + 1)
emulator.modules.add_symbol_hook('malloc', emulator.hooker.write_function(malloc) + 1)
emulator.modules.add_symbol_hook('strcmp', emulator.hooker.write_function(strcmp) + 1)
 
libc_module = emulator.load_library(libc_file, do_init=False)
lib_module = emulator.load_library(so_file, do_init=False)
 
# call .init.proc
emulator.call_native(lib_module.base + 0x320B8 + 1)
 
for funcptr in lib_module.init_array:
    logger.info("init_array -->" + str(hex(funcptr)))
    emulator.call_native(funcptr)
 
result = emulator.call_symbol(lib_module, "Java_com_kanxue_crackme_MainActivity_crypt2",
                              emulator.java_vm.jni_env.address_ptr, 0, sys.argv[1], is_return_jobject=False)
print(result)
import logging
import sys
from androidemu.emulator import Emulator
from androidemu.java.helpers.native_method import native_method
from androidemu.utils import memory_helpers
 
@native_method
def sprintf(uc, str, format, args):
    str_utf8 = memory_helpers.read_utf8(uc, str)
    format_utf8 = memory_helpers.read_utf8(uc, format)
    args_utf8 = memory_helpers.read_utf8(uc, args)
    logger.info("str_utf8:{}, format_utf8:{}, args_utf8:{}".format(str_utf8, format_utf8, args_utf8))
 
    result_string = format_utf8 % args_utf8
    memory_helpers.write_utf8(uc, str, result_string)
    return len(result_string)
 
 
@native_method
def malloc(uc, size):
    return emulator.memory_manager.allocate(size)
 
 
@native_method
def strcmp(uc, s1, s2):
    s1_utf8 = memory_helpers.read_utf8(uc, s1)
    s2_utf8 = memory_helpers.read_utf8(uc, s2)
 
    if s1_utf8 == s2_utf8:
        ret = 0
    elif s1_utf8 < s2_utf8:
        ret = -1
    else:
        ret = 1
    logger.info("s1:{},s2:{},ret:{}".format(s1_utf8, s2_utf8, ret))
    return ret
 
 
# Configure logging
logging.basicConfig(
    stream=sys.stderr,
    level=logging.DEBUG,
    format="%(asctime)s %(levelname)7s %(name)34s | %(message)s"
)
 
logger = logging.getLogger(__name__)
 
so_file = "my_binaries/libnative-lib.so"
libc_file = "example_binaries/32/libc.so"
 
# Initialize emulator
emulator = Emulator(vfp_inst_set=True)
 
emulator.modules.add_symbol_hook('sprintf', emulator.hooker.write_function(sprintf) + 1)
emulator.modules.add_symbol_hook('malloc', emulator.hooker.write_function(malloc) + 1)
emulator.modules.add_symbol_hook('strcmp', emulator.hooker.write_function(strcmp) + 1)
 
libc_module = emulator.load_library(libc_file, do_init=False)
lib_module = emulator.load_library(so_file, do_init=False)
 
# call .init.proc
emulator.call_native(lib_module.base + 0x320B8 + 1)
 
for funcptr in lib_module.init_array:
    logger.info("init_array -->" + str(hex(funcptr)))
    emulator.call_native(funcptr)
 
result = emulator.call_symbol(lib_module, "Java_com_kanxue_crackme_MainActivity_crypt2",
                              emulator.java_vm.jni_env.address_ptr, 0, sys.argv[1], is_return_jobject=False)
print(result)
import logging
import sys
import unicorn
import capstone
from androidemu.emulator import Emulator
from androidemu.utils import memory_helpers
from androidemu.java.java_class_def import JavaClassDef
from androidemu.java.java_method_def import java_method_def
from androidemu.java.helpers.native_method import native_method
from subprocess import check_output
 
cs = capstone.Cs(capstone.CS_ARCH_ARM, capstone.CS_MODE_THUMB)
cs.detail = True
 
 
class MainActivity(metaclass=JavaClassDef, jvm_name='com/kanxue/crackme/MainActivity'):
 
    def __init__(self):
        pass
 
    @java_method_def(name='crypt2', args_list=['jstring'], signature='(Ljava/lang/String;)Z', native=False)
    def crypt2(self, *args, **kwargs):
        arg = args[0].value
        print("crypt2 args : {}".format(arg))
        ret = check_output(["python","crypt2_impl.py",arg])
        ret = int(ret.decode('utf-8').strip())
        print("crypt2 result : {}".format(ret))
        return ret
 
 
@native_method
def sprintf(uc, str, format, args):
    str_utf8 = memory_helpers.read_utf8(uc, str)
    format_utf8 = memory_helpers.read_utf8(uc, format)
    args_utf8 = memory_helpers.read_utf8(uc, args)
    print("str_utf8:{}, format_utf8:{}, args_utf8:{}".format(str_utf8, format_utf8, args_utf8))
 
    result_string = format_utf8 % args_utf8
    memory_helpers.write_utf8(uc, str, result_string)
    return len(result_string)
 
 
@native_method
def malloc(uc, size):
    return emulator.memory_manager.allocate(size)
 
 
@native_method
def strcmp(uc, s1, s2):
    s1_utf8 = memory_helpers.read_utf8(uc, s1)
    s2_utf8 = memory_helpers.read_utf8(uc, s2)
 
    if s1_utf8 == s2_utf8:
        return 0
 
    print("s1:{},s2:{}".format(s1_utf8, s2_utf8))
    return len(s1_utf8) - len(s2_utf8)
 
 
# Configure logging
logging.basicConfig(
    stream=sys.stdout,
    level=logging.DEBUG,
    format="%(asctime)s %(levelname)7s %(name)34s | %(message)s"
)
 
logger = logging.getLogger(__name__)
 
 
def mem_read_unmapped(uc, type, address, size, value, user_data):
    print("mem_read_unmapped type:{},address:{},size:{},value:{},pc:{}".format(type, address, size, value,
                                                                               hex(uc.reg_read(
                                                                                   unicorn.arm_const.UC_ARM_REG_PC) - libc_module.base)))
 
 
def hook_code(uc, address, size, user_data):
    if lib_module.base < address < (lib_module.base + lib_module.size):
        lib_name = "libnative-lib.so"
        pc = uc.reg_read(unicorn.arm_const.UC_ARM_REG_PC) - lib_module.base
    elif libc_module.base < address < (libc_module.base + libc_module.size):
        lib_name = "libc.so"
        pc = uc.reg_read(unicorn.arm_const.UC_ARM_REG_PC) - libc_module.base
    else:
        lib_name = "lib_Unknown"
        pc = uc.reg_read(unicorn.arm_const.UC_ARM_REG_PC)
 
    CODE = uc.mem_read(uc.reg_read(unicorn.arm_const.UC_ARM_REG_PC), size)
    dis_code = None
    for i in cs.disasm(CODE, 0, len(CODE)):
        dis_code = i.mnemonic + " " + i.op_str
    print(lib_name + " >>> Tracing instruction at {}, instruction size = {} , pc:{}, bytes:{}".format(pc, size,
                                                                                                      hex(pc),
                                                                                                      dis_code))
 
 
def UC_HOOK_MEM_WRITE(uc, type, address, size, value, userdata):
    print("address:" + str(hex(address)) + ",value:" + str(value))
 
 
so_file = "my_binaries/libnative-lib.so"
libc_file = "example_binaries/32/libc.so"
 
# Initialize emulator
emulator = Emulator(vfp_inst_set=True)
 
emulator.modules.add_symbol_hook('sprintf', emulator.hooker.write_function(sprintf) + 1)
emulator.modules.add_symbol_hook('malloc', emulator.hooker.write_function(malloc) + 1)
emulator.modules.add_symbol_hook('strcmp', emulator.hooker.write_function(strcmp) + 1)
 
libc_module = emulator.load_library(libc_file, do_init=False)
lib_module = emulator.load_library(so_file, do_init=False)
 
# emulator.mu.hook_add(unicorn.UC_HOOK_CODE, hook_code)
 
# call .init.proc
emulator.call_native(lib_module.base + 0x320B8 + 1)
 
for funcptr in lib_module.init_array:
    logger.info("init_array -->" + str(hex(funcptr)))
    emulator.call_native(funcptr)
 
emulator.java_classloader.add_class(MainActivity)
 
result = emulator.call_symbol(lib_module, "Java_com_kanxue_crackme_MainActivity_jnicheck",
                              emulator.java_vm.jni_env.address_ptr, 0, "XUe", is_return_jobject=False)
print("jnicheck result : {}".format(result))
import logging
import sys
import unicorn
import capstone
from androidemu.emulator import Emulator
from androidemu.utils import memory_helpers
from androidemu.java.java_class_def import JavaClassDef
from androidemu.java.java_method_def import java_method_def
from androidemu.java.helpers.native_method import native_method
from subprocess import check_output
 
cs = capstone.Cs(capstone.CS_ARCH_ARM, capstone.CS_MODE_THUMB)
cs.detail = True
 
 
class MainActivity(metaclass=JavaClassDef, jvm_name='com/kanxue/crackme/MainActivity'):
 
    def __init__(self):
        pass
 
    @java_method_def(name='crypt2', args_list=['jstring'], signature='(Ljava/lang/String;)Z', native=False)
    def crypt2(self, *args, **kwargs):
        arg = args[0].value
        print("crypt2 args : {}".format(arg))
        ret = check_output(["python","crypt2_impl.py",arg])
        ret = int(ret.decode('utf-8').strip())
        print("crypt2 result : {}".format(ret))
        return ret
 
 
@native_method
def sprintf(uc, str, format, args):
    str_utf8 = memory_helpers.read_utf8(uc, str)
    format_utf8 = memory_helpers.read_utf8(uc, format)
    args_utf8 = memory_helpers.read_utf8(uc, args)
    print("str_utf8:{}, format_utf8:{}, args_utf8:{}".format(str_utf8, format_utf8, args_utf8))
 
    result_string = format_utf8 % args_utf8
    memory_helpers.write_utf8(uc, str, result_string)
    return len(result_string)
 
 
@native_method
def malloc(uc, size):
    return emulator.memory_manager.allocate(size)
 
 
@native_method
def strcmp(uc, s1, s2):
    s1_utf8 = memory_helpers.read_utf8(uc, s1)
    s2_utf8 = memory_helpers.read_utf8(uc, s2)
 
    if s1_utf8 == s2_utf8:
        return 0
 
    print("s1:{},s2:{}".format(s1_utf8, s2_utf8))
    return len(s1_utf8) - len(s2_utf8)
 
 
# Configure logging
logging.basicConfig(
    stream=sys.stdout,
    level=logging.DEBUG,

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2022-7-17 18:06 被飞翔的猫咪编辑 ,原因:
上传的附件:
收藏
免费 3
支持
分享
打赏 + 80.00雪花
打赏次数 1 雪花 + 80.00
 
赞赏  Editor   +80.00 2022/09/15 恭喜您获得“雪花”奖励,安全圈有你而精彩!
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//