unicorn

unicorn capstone keystone

安装

pip install capstone
pip install unicorn
pip install keystone-engine

ida 插件 :keypatch :将汇编代码转换为二进制

frida api :Instrction 得到反汇编
frida 动态反调试,将代码中的kill,exit函数调动nop调用

// 将二进制 反汇编
// 接口比较多,看frida的文档
function dis(address, number) {
    for (var i = 0; i < number; i++) {
        var ins = Instruction.parse(address); // 将地址解析成汇编
        console.log("address:" + address + "--dis:" + ins.toString());
        address = ins.next; //获取下一条指令
    }
}

//libc->strstr()
function hook() {
//call_function("DT_INIT", init_func_, get_realpath()); 函数调用前会执行call_function
    var linkermodule = Process.getModuleByName("linker");
    var call_function_addr = null;
    var symbols = linkermodule.enumerateSymbols();
    for (var i = 0; i < symbols.length; i++) {
        var symbol = symbols[i];
        //LogPrint(linkername + "->" + symbol.name + "---" + symbol.address);
        if (symbol.name.indexOf("__dl__ZL13call_functionPKcPFviPPcS2_ES0_") != -1) {
            call_function_addr = symbol.address;
            //LogPrint("linker->" + symbol.name + "---" + symbol.address)

        }
    }
    Interceptor.attach(call_function_addr, {
        onEnter: function (args) {
            var type = ptr(args[0]).readUtf8String();
            var address = args[1];
            var sopath = ptr(args[2]).readUtf8String();
            console.log("loadso:" + sopath + "--addr:" + address + "--type:" + type);
            if (sopath.indexOf("libnative-lib.so") != -1) {
                var libnativemodule = Process.getModuleByName("libnative-lib.so");
                var base = libnativemodule.base;
                dis(base.add(0x8D8E).add(1), 10);
                var patchaddr = base.add(0x8d96);
                // patch的第一种写法
                // 参数 : 地址,patch的大小,
                Memory.patchCode(patchaddr, 4, patchaddr => {
                    var cw = new ThumbWriter(patchaddr); // 以 thumb的方式获取一个patch对象
                    cw.putNop();  // 进行patch
                    cw = new ThumbWriter(patchaddr.add(0x2));
                    cw.putNop();
                    cw.flush(); // 内存刷新
                });
                /*                Memory.protect(base.add(0x8d96),4,'rwx');
                                base.add(0x8d96).writeByteArray([0x00,0xbf,0x00,0xbf]);*/
                console.log("+++++++++++++++++++++++")
                dis(base.add(0x8D8E).add(1), 10);
                console.log("----------------------")

                dis(base.add(0x8E6E).add(1), 10);
                // patch的第二种写法
                Memory.protect(base.add(0x8E78), 4, 'rwx'); // 修改内存属性
                base.add(0x8E78).writeByteArray([0x00, 0xbf, 0x00, 0xbf]); // 直接往内存中写nop指令
                console.log("+++++++++++++++++++++++")
                dis(base.add(0x8E6E).add(1), 10);


            }
        }
    })
}

function main() {
    hook();
}

setImmediate(main);

frida的启动参数 : 需要添加一个 --runtime=v8

capstone、keystone的例子

import capstone
import keystone
'''ROM:CE8EC3EE 00 00                       MOVS            R0, R0  ; Rd = Op2
ROM:CE8EC3F0 83 B0                       SUB             SP, SP, #0xC ; Rd = Op1 - Op2
ROM:CE8EC3F2 10 B5                       PUSH            {R4,LR} ; Push registers
ROM:CE8EC3F4 83 B0                       SUB             SP, SP, #0xC ; Rd = Op1 - Op2
ROM:CE8EC3F6 84 46                       MOV             R12, R0 ; Rd = Op2
ROM:CE8EC3F8 0C 48                       LDR             R0, =0x91624 ; Load from Memory'''
def testarm32_thumb():
    CODE=b'\x00\x00\x83\xb0\x10\xb5\x83\xb0\x84\x46\x0c\x48'
    CP=capstone.Cs(capstone.CS_ARCH_ARM,capstone.CS_MODE_THUMB)
    KP=keystone.Ks(keystone.KS_ARCH_ARM,keystone.KS_MODE_THUMB)
    for i in CP.disasm(CODE,0,len(CODE)):
        print(i.mnemonic+" "+i.op_str)
        ins=KP.asm(i.mnemonic+" "+i.op_str)
        print('----------')
        print(ins)
        print('----------')
    return

if __name__ == '__main__':
    testarm32_thumb()

unicorn 初步上手

内存相关:
uc_mem_map
uc_mem_read
uc_mem_write

寄存器相关
uc_reg_read
uc_reg_write

指令执行类
UC_HOOK_INTR
UC_HOOK_INSN
UC_HOOK_CODE
UC_HOOK_BLOCK

内存访问类:
UC_HOOK_MEM_READ
UC_HOOK_MEM_WRITE
UC_HOOK_MEM_FETCH

异常处理类
UC_HOOK_MEM_READ_UNMAPPED
UC_HOOK_MEM_WRITE_UNMAPPED
UC_HOOK_MEM_FETCH_UNMAPPED

添加一个指令类hook回调:
UC_HOOK_CODE & UC_HOOK_BLOCK的callback定义
typedef void (*uc_cb_hookcode_t)(un_engine uc,uint64_t address,uint32_t size,void user_data);
address :当前执行的指令地址
size :当前执行指令的长度,如果长度未知,则为0
user_data : hook_add 设置的user_data参数

import unicorn
import capstone
import binascii

def printArm32Regs(mu): # 打印寄存器的值
    for i in range(66,78): # 为什么66-78,uncorin定义的ARM寄存器常量的是这个
        print("R%d,value:%x"%(i-66,mu.reg_read(i)))
        
#typedef void (*uc_cb_hookcode_t)(uc_engine *uc, uint64_t address, uint32_t size, void *user_data);
def hook_code(mu,address,size,user_data):
    code=mu.mem_read(address,size)
    CP=capstone.Cs(capstone.CS_ARCH_ARM,capstone.CS_MODE_THUMB)
    for i in CP.disasm(code,0,len(code)):
        print("[addr:%x]:%s %s\n"%(address,i.mnemonic,i.op_str))
    print("-----------------------------")
    printArm32Regs(mu)
    print("-----------------------------")
    return
    
#typedef void (*uc_cb_hookintr_t)(uc_engine *uc, uint32_t intno, void *user_data);
def hook_syscall(mu,intno,user_data):
    print("syscall num:0x%d is called!!"%intno)
    if intno==2:
        print("exit syscall is called!!")
    print("-----------------------------")
    printArm32Regs(mu)
    print("-----------------------------")
    return
    
#void (*uc_cb_hookmem_t)(uc_engine *uc, uc_mem_type type,uint64_t address, int size, int64_t value, void *user_data);
def hook_mem_write_unmapped(mu,type,address,size,value,user_data): # 内存的写事件
    if type==unicorn.UC_MEM_WRITE_UNMAPPED:
       print("UC_HOOK_MEM_WRITE_UNMAPPED addr:0x%x,size:%d,value:0x%x"%(address,size,value))
       mu.mem_map(0x0,0x1000)
    print("hook_mem type:%d addr:0x%x,size:%d,value:0x%x" % (type, address, size, value))
    return True
    
def hook_mem(mu,type,address,size,value,user_data):
    if type==unicorn.UC_MEM_WRITE:
       print("write addr:0x%x,size:%d,value:0x%x"%(address,size,value))
    if type==unicorn.UC_MEM_READ:
       print("read addr:0x%x,size:%d,value:0x%x"%(address,size,value))
    print("hook_mem type:%d addr:0x%x,size:%d,value:0x%x"%(type,address,size,value))
    return
    
def testthumb():
#  text:00008ACA 0A 46                       MOV             R2, R1  ; Rd = Op2
# .text:00008ACC 03 46                       MOV             R3, R0  ; Rd = Op2
#.text:00008B04 04 92                        STR             R2, [SP,#0x40+var_30] ; Store to Memory
    CODE=b'\x0a\x46\x03\x46\x04\x92\x4F\xF0\x0B\x07\x00\xdf'
    CP=capstone.Cs(capstone.CS_ARCH_ARM,capstone.CS_MODE_THUMB)
    for i in CP.disasm(CODE,0,len(CODE)):
        print("[addr:%x]:%s %s\n"%(i.address,i.mnemonic,i.op_str))
    # 1、获取unicorn对象,需要初始化:设置架构,设置指令集
    mu=unicorn.Uc(unicorn.UC_ARCH_ARM,unicorn.UC_MODE_THUMB)
    ADDRESS=0x1000
    SIZE=1024
    # 2、分配内存
    mu.mem_map(ADDRESS,SIZE)
    # 3、往内存中写入指令
    mu.mem_write(ADDRESS,CODE)
    bytes=mu.mem_read(ADDRESS,10) # 可以读取内存中的指令
    print("ADDRESS:%x,content:%s"%(ADDRESS,binascii.b2a_hex(bytes)))
    # 4、设置寄存器
    mu.reg_write(unicorn.arm_const.UC_ARM_REG_R0,0x100)
    mu.reg_write(unicorn.arm_const.UC_ARM_REG_R1,0x200)
    mu.reg_write(unicorn.arm_const.UC_ARM_REG_R2,0x300)
    mu.reg_write(unicorn.arm_const.UC_ARM_REG_R3,0x400)


	# 5、设置指令回调函数 unicorn.UC_HOOK_CODE :当执行指令时,调用hook_code函数
    hook_code1=mu.hook_add(unicorn.UC_HOOK_CODE, hook_code)
    #mu.hook_del(hook_code1)
    '''/*
  Callback function for hooking memory (READ, WRITE & FETCH)

  @type: this memory is being READ, or WRITE
  @address: address where the code is being executed
  @size: size of data being read or written
  @value: value of data being written to memory, or irrelevant if type = READ.
  @user_data: user data passed to tracing APIs
*/
typedef void (*uc_cb_hookmem_t)(uc_engine *uc, uc_mem_type type,
        uint64_t address, int size, int64_t value, void *user_data);'''
    #mu.hook_add(unicorn.UC_HOOK_MEM_WRITE,hook_mem)
    # 设置回调 
    # 当指令执行,写内存时,进入回调函数
    mu.hook_add(unicorn.UC_HOOK_MEM_WRITE,hook_mem)
    # 当指令执行,调用系统调用时 - 可以获取系统调用号
    mu.hook_add(unicorn.UC_HOOK_INTR,hook_syscall)
    # 当指令执行,写未分配内存空间时 - 可以通过这个回调自动分配空间
    mu.hook_add(unicorn.UC_HOOK_MEM_WRITE_UNMAPPED,hook_mem_write_unmapped)
    try:
    	# 启动unicorn : 参数执行的开始的地址(thumb需要加1),执行指令的长度
        mu.emu_start(ADDRESS+1,ADDRESS+len(CODE))
        print("emulat over")
        printArm32Regs(mu)
        bytes=mu.mem_read(0x10,4)
        print("mem:0x%x,value:%s"%(0x10,binascii.b2a_hex(bytes)))
    except unicorn.UcError as e: # 需要try-catch住,看看unicorn为什么崩溃
        print(e)
    #def hook_add(self, htype, callback, user_data=None, begin=1, end=0, arg1=0)

    return
    
if __name__ == '__main__':
    testthumb()

Unicorn调用so中函数

在arm下,主要是考虑参数的个数
小于等于4,通过寄存器直接传递参数
参数大于等于4的时候,寄存器R0-R3传递前4个参数,其他的参数使用栈进行传参
除了参数使用到栈,函数执行的局部变量也需要用到栈,不要忘了分配栈

import unicorn
import capstone
import binascii
import struct
def printArm32Regs(mu):
    for i in range(66,78):
        print("R%d,value:%x"%(i-66,mu.reg_read(i)))
    print("SP->value:%x" % (mu.reg_read(unicorn.arm_const.UC_ARM_REG_SP)))
    print("PC->value:%x" % (mu.reg_read(unicorn.arm_const.UC_ARM_REG_PC)))

def readstring(mu,address):
    result=''
    tmp=mu.mem_read(address,1)
    while(tmp[0]!=0):
        result=result+chr(tmp[0])
        address=address+1
        tmp = mu.mem_read(address, 1)
    return result

#typedef void (*uc_cb_hookcode_t)(uc_engine *uc, uint64_t address, uint32_t size, void *user_data);
def hook_code(mu,address,size,user_data):
    code=mu.mem_read(address,size)
    if address==0x1000+0x859A:
        r0value=readstring(mu,mu.reg_read(unicorn.arm_const.UC_ARM_REG_R0))
        r1value = readstring(mu, mu.reg_read(unicorn.arm_const.UC_ARM_REG_R1))
        print(r0value+"---"+r1value)
        index=r0value.find(r1value)
        if index==-1:
            mu.reg_write(unicorn.arm_const.UC_ARM_REG_R0,0)
        else:
            mu.reg_write(unicorn.arm_const.UC_ARM_REG_R0, index)
        print("call strstr------------------")

    CP=capstone.Cs(capstone.CS_ARCH_ARM,capstone.CS_MODE_THUMB)
    for i in CP.disasm(code,0,len(code)):
        print("[addr:%x]:%s %s\n"%(address,i.mnemonic,i.op_str))
    # print("-----------------------------")
    # printArm32Regs(mu)
    # print("-----------------------------")
    return

def hook_block(mu,address,size,user_data):
    print("hook_block-----------------------------")
    code=mu.mem_read(address,size)
    CP=capstone.Cs(capstone.CS_ARCH_ARM,capstone.CS_MODE_THUMB)
    for i in CP.disasm(code,0,len(code)):
        print("[hook_block addr:%x]:%s %s\n"%(address,i.mnemonic,i.op_str))

    printArm32Regs(mu)
    print("hook_block-----------------------------")
    return

#typedef void (*uc_cb_hookintr_t)(uc_engine *uc, uint32_t intno, void *user_data);
def hook_syscall(mu,intno,user_data):
    print("hook_syscall-----------------------------")
    printArm32Regs(mu)
    print("hook_syscall-----------------------------")
    return

#void (*uc_cb_hookmem_t)(uc_engine *uc, uc_mem_type type,uint64_t address, int size, int64_t value, void *user_data);
def hook_mem_write_unmapped(mu,type,address,size,value,user_data):
    if type==unicorn.UC_MEM_WRITE_UNMAPPED:
       print("UC_HOOK_MEM_WRITE_UNMAPPED addr:0x%x,size:%d,value:0x%x"%(address,size,value))
       mu.mem_map(0x0,0x1000)
    print("hook_mem type:%d addr:0x%x,size:%d,value:0x%x" % (type, address, size, value))
    return True

def hook_mem(mu,type,address,size,value,user_data):
    if type==unicorn.UC_MEM_WRITE:
       print("write addr:0x%x,size:%d,value:0x%x"%(address,size,value))
    if type==unicorn.UC_MEM_READ:
       print("read addr:0x%x,size:%d,value:0x%x"%(address,size,value))
    print("hook_mem type:%d addr:0x%x,size:%d,value:0x%x"%(type,address,size,value))
    return

def testthumb_arg2():
#  text:00008ACA 0A 46                       MOV             R2, R1  ; Rd = Op2
# .text:00008ACC 03 46                       MOV             R3, R0  ; Rd = Op2
#.text:00008B04 04 92                        STR             R2, [SP,#0x40+var_30] ; Store to Memory
    CODE=None
    with open("so/03.so",'rb') as sofile:
        CODE=sofile.read()
    CP=capstone.Cs(capstone.CS_ARCH_ARM,capstone.CS_MODE_THUMB)
    for i in CP.disasm(CODE[0x8500:],0,20):
        print("[addr:%x]:%s %s\n"%(0x8500+i.address,i.mnemonic,i.op_str))
    for i in CP.disasm(CODE[0x851C:],0,20):
        print("[addr:%x]:%s %s\n"%(0x851C+i.address,i.mnemonic,i.op_str))
    mu=unicorn.Uc(unicorn.UC_ARCH_ARM,unicorn.UC_MODE_THUMB)
    ADDRESS=0x1000
    SIZE=10*1024*1024
    mu.mem_map(ADDRESS,SIZE)
    mu.mem_write(ADDRESS,CODE)
    mu.reg_write(unicorn.arm_const.UC_ARM_REG_R0,0x1)
    mu.reg_write(unicorn.arm_const.UC_ARM_REG_R1,0x2)
    SP=ADDRESS+SIZE-1
    mu.reg_write(unicorn.arm_const.UC_ARM_REG_SP,SP)
    mu.hook_add(unicorn.UC_HOOK_CODE, hook_code)
    #mu.hook_del(hook_code1)
    '''/*
  Callback function for hooking memory (READ, WRITE & FETCH)
  @type: this memory is being READ, or WRITE
  @address: address where the code is being executed
  @size: size of data being read or written
  @value: value of data being written to memory, or irrelevant if type = READ.
  @user_data: user data passed to tracing APIs
*/
typedef void (*uc_cb_hookmem_t)(uc_engine *uc, uc_mem_type type,
        uint64_t address, int size, int64_t value, void *user_data);'''
    #mu.hook_add(unicorn.UC_HOOK_MEM_WRITE,hook_mem)
    mu.hook_add(unicorn.UC_HOOK_MEM_WRITE,hook_mem)
    mu.hook_add(unicorn.UC_HOOK_INTR,hook_syscall)
    mu.hook_add(unicorn.UC_HOOK_BLOCK,hook_block)
    mu.hook_add(unicorn.UC_HOOK_MEM_WRITE_UNMAPPED,hook_mem_write_unmapped)
    addstart=ADDRESS+0x8500+1
    addend=ADDRESS+0x851A
    try:
        mu.emu_start(addstart,addend)
        print("emulat over")
        printArm32Regs(mu)
    except unicorn.UcError as e:
        print(e)
    #def hook_add(self, htype, callback, user_data=None, begin=1, end=0, arg1=0):
    return
    
def testthumb_arg6():
#  text:00008ACA 0A 46                       MOV             R2, R1  ; Rd = Op2
# .text:00008ACC 03 46                       MOV             R3, R0  ; Rd = Op2
#.text:00008B04 04 92                        STR             R2, [SP,#0x40+var_30] ; Store to Memory
    CODE=None
    with open("so/03.so",'rb') as sofile:
        CODE=sofile.read()
    CP=capstone.Cs(capstone.CS_ARCH_ARM,capstone.CS_MODE_THUMB)
    for i in CP.disasm(CODE[0x8500:],0,20):
        print("[addr:%x]:%s %s\n"%(0x8500+i.address,i.mnemonic,i.op_str))
    for i in CP.disasm(CODE[0x851C:],0,20):
        print("[addr:%x]:%s %s\n"%(0x851C+i.address,i.mnemonic,i.op_str))
    mu=unicorn.Uc(unicorn.UC_ARCH_ARM,unicorn.UC_MODE_THUMB)
    ADDRESS=0x1000
    SIZE=10*1024*1024
    mu.mem_map(ADDRESS,SIZE)
    mu.mem_write(ADDRESS,CODE)
    mu.reg_write(unicorn.arm_const.UC_ARM_REG_R0,0x1)
    mu.reg_write(unicorn.arm_const.UC_ARM_REG_R1,0x2)
    mu.reg_write(unicorn.arm_const.UC_ARM_REG_R2,0x3)
    mu.reg_write(unicorn.arm_const.UC_ARM_REG_R3,0x4)

    mu.reg_write(unicorn.arm_const.UC_ARM_REG_LR,ADDRESS+0x456)

	# 参数大于4的时候,使用栈传递参数
    SP=ADDRESS+SIZE-16
    mu.reg_write(unicorn.arm_const.UC_ARM_REG_SP,SP)
    # byte类型,传递参数的
    mu.mem_write(SP,struct.pack('I',5))
    mu.mem_write(SP+4,struct.pack('I',6))

    mu.hook_add(unicorn.UC_HOOK_CODE, hook_code)
    mu.hook_add(unicorn.UC_HOOK_MEM_WRITE,hook_mem)
    mu.hook_add(unicorn.UC_HOOK_INTR,hook_syscall)
    mu.hook_add(unicorn.UC_HOOK_BLOCK,hook_block)
    mu.hook_add(unicorn.UC_HOOK_MEM_WRITE_UNMAPPED,hook_mem_write_unmapped)
    addstart=ADDRESS+0x851C+1
    addend=ADDRESS+0x858E
    try:
        mu.emu_start(addstart,addend+8)
        print("emulat over")
        printArm32Regs(mu)
    except unicorn.UcError as e:
        print(e)
    #def hook_add(self, htype, callback, user_data=None, begin=1, end=0, arg1=0):


# 函数调用了libc中的strstr
def testthumb_callstrstrarg6():
#  text:00008ACA 0A 46                       MOV             R2, R1  ; Rd = Op2
# .text:00008ACC 03 46                       MOV             R3, R0  ; Rd = Op2
#.text:00008B04 04 92                        STR             R2, [SP,#0x40+var_30] ; Store to Memory
    CODE=None
    with open("so/callstrstr.so",'rb') as sofile:
        CODE=sofile.read()
    CP=capstone.Cs(capstone.CS_ARCH_ARM,capstone.CS_MODE_THUMB)
    for i in CP.disasm(CODE[0x8500:],0,20):
        print("[addr:%x]:%s %s\n"%(0x8500+i.address,i.mnemonic,i.op_str))
    for i in CP.disasm(CODE[0x851C:],0,20):
        print("[addr:%x]:%s %s\n"%(0x851C+i.address,i.mnemonic,i.op_str))
    mu=unicorn.Uc(unicorn.UC_ARCH_ARM,unicorn.UC_MODE_THUMB)
    ADDRESS=0x1000
    SIZE=10*1024*1024

    mu.mem_map(ADDRESS,SIZE)
    mu.mem_write(ADDRESS,CODE)
    
    # 把strstr的函数调用先nop掉,然后通过hook_code,用python实现该地址处的strstr
    mu.mem_write(ADDRESS+0x859A,b'\x00\xbf\x00\xbf')
    mu.mem_map(ADDRESS+SIZE+0x1000,1024)
    # 传递参数是指针的时候
    mu.mem_write(ADDRESS+SIZE+0x1000,b'flag4')
    bytes=mu.mem_read(ADDRESS+SIZE+0x1000,5)
    print(binascii.b2a_hex(bytes))
    mu.reg_write(unicorn.arm_const.UC_ARM_REG_R0,ADDRESS+SIZE+0x1000)

    mu.reg_write(unicorn.arm_const.UC_ARM_REG_R1,0x2)
    mu.reg_write(unicorn.arm_const.UC_ARM_REG_R2,0x3)
    mu.reg_write(unicorn.arm_const.UC_ARM_REG_R3,0x4)

    mu.reg_write(unicorn.arm_const.UC_ARM_REG_LR,ADDRESS+0x456)
    SP=ADDRESS+SIZE-16
    mu.reg_write(unicorn.arm_const.UC_ARM_REG_SP,SP)
    mu.mem_write(SP,struct.pack('I',5))
    mu.mem_write(SP+4,struct.pack('I',6))

    mu.hook_add(unicorn.UC_HOOK_CODE, hook_code)
    mu.hook_add(unicorn.UC_HOOK_MEM_WRITE,hook_mem)
    mu.hook_add(unicorn.UC_HOOK_INTR,hook_syscall)
    mu.hook_add(unicorn.UC_HOOK_BLOCK,hook_block)
    mu.hook_add(unicorn.UC_HOOK_MEM_WRITE_UNMAPPED,hook_mem_write_unmapped)
    addstart=ADDRESS+0x854C+1
    addend=ADDRESS+0x85D8
    try:
        mu.emu_start(addstart,addend+8)
        print("emulat over")
        printArm32Regs(mu)
    except unicorn.UcError as e:
        print(e)
    #def hook_add(self, htype, callback, user_data=None, begin=1, end=0, arg1=0):
if __name__ == '__main__':
    #testthumb_arg2()
    testthumb_callstrstrarg6()

unicorn模拟调用jni接口函数

对于一般的jni函数来说,必然会使用到jni提供的一系类api,如GetStringChars,NewStringUTF,FindClass,CallObjectMethod等等
那么如何设计和模拟实现jni函数对这些jni中接口函数的调用呢?

1、jni接口都是通过JNIEnv来调用的
2、jni接口的调用 : jnienv + 地址
3、创建jniinterface结构体

import unicorn
import capstone
import binascii
import struct
def printArm32Regs(mu):
    for i in range(66,78):
        print("R%d,value:%x"%(i-66,mu.reg_read(i)))
    print("SP->value:%x" % (mu.reg_read(unicorn.arm_const.UC_ARM_REG_SP)))
    print("PC->value:%x" % (mu.reg_read(unicorn.arm_const.UC_ARM_REG_PC)))

def readstring(mu,address):
    result=''
    tmp=mu.mem_read(address,1)
    while(tmp[0]!=0):
        result=result+chr(tmp[0])
        address=address+1
        tmp = mu.mem_read(address, 1)
    return result

#typedef void (*uc_cb_hookcode_t)(uc_engine *uc, uint64_t address, uint32_t size, void *user_data);
def hook_code(mu,address,size,user_data):
    code=mu.mem_read(address,size)
    if address==0x1000+0x088C:
        print("log is called!!!")
        r0value = mu.reg_read(unicorn.arm_const.UC_ARM_REG_R0)
        r1value = mu.reg_read(unicorn.arm_const.UC_ARM_REG_R1)
        r2value = mu.reg_read(unicorn.arm_const.UC_ARM_REG_R2)
        r3value = mu.reg_read(unicorn.arm_const.UC_ARM_REG_R3)
        content1 = readstring(mu, r1value)
        content2 = readstring(mu, r2value)
        content3 = readstring(mu, r3value)
        print(str(r0value)+"---"+content1+"---"+content2+"---"+content3)
        print("log is called!!!")
    if address>=0 and address<=300*4:
        index=address/4
        if index==169:
            print("call GetStringUTFChars------------------")
            r0value=mu.reg_read(unicorn.arm_const.UC_ARM_REG_R0)
            r1value=mu.reg_read(unicorn.arm_const.UC_ARM_REG_R1)
            r2value=mu.reg_read(unicorn.arm_const.UC_ARM_REG_R2)
            content=readstring(mu,r1value)
            mu.reg_write(unicorn.arm_const.UC_ARM_REG_R0,r1value)
            print(str(r0value)+"---"+content+"---"+str(r2value))
            print("call GetStringUTFChars over------------------")
        if index==167:
            print("call NewStringUTF------------------")
            r0value = mu.reg_read(unicorn.arm_const.UC_ARM_REG_R0)
            r1value = mu.reg_read(unicorn.arm_const.UC_ARM_REG_R1)
            content = readstring(mu, r1value)
            mu.reg_write(unicorn.arm_const.UC_ARM_REG_R0, r1value)
            print(str(r0value) + "---" + content)
            print("call NewStringUTF over------------------")

        print("call jni interface------------------")
    CP=capstone.Cs(capstone.CS_ARCH_ARM,capstone.CS_MODE_THUMB)
    for i in CP.disasm(code,0,len(code)):
        print("[addr:%x]:%s %s\n"%(address,i.mnemonic,i.op_str))
    # print("-----------------------------")
    # printArm32Regs(mu)
    # print("-----------------------------")
    return

def hook_block(mu,address,size,user_data):
    print("hook_block-----------------------------")
    code=mu.mem_read(address,size)
    CP=capstone.Cs(capstone.CS_ARCH_ARM,capstone.CS_MODE_THUMB)
    for i in CP.disasm(code,0,len(code)):
        print("[hook_block addr:%x]:%s %s\n"%(address,i.mnemonic,i.op_str))

    printArm32Regs(mu)
    print("hook_block-----------------------------")
    return

#typedef void (*uc_cb_hookintr_t)(uc_engine *uc, uint32_t intno, void *user_data);
def hook_syscall(mu,intno,user_data):
    print("hook_syscall-----------------------------")
    printArm32Regs(mu)
    print("hook_syscall-----------------------------")
    return

#void (*uc_cb_hookmem_t)(uc_engine *uc, uc_mem_type type,uint64_t address, int size, int64_t value, void *user_data);
def hook_mem(mu,type,address,size,value,user_data):
    if type==unicorn.UC_MEM_WRITE:
       print("write addr:0x%x,size:%d,value:0x%x"%(address,size,value))
    if type==unicorn.UC_MEM_READ:
       print("read addr:0x%x,size:%d,value:0x%x"%(address,size,value))
    print("hook_mem type:%d addr:0x%x,size:%d,value:0x%x"%(type,address,size,value))
    return
    
def testthumb_calljni():
#  text:00008ACA 0A 46                       MOV             R2, R1  ; Rd = Op2
# .text:00008ACC 03 46                       MOV             R3, R0  ; Rd = Op2
#.text:00008B04 04 92                        STR             R2, [SP,#0x40+var_30] ; Store to Memory
    CODE=None
    with open("so/testcalljni.so",'rb') as sofile:
        CODE=sofile.read()
    CP=capstone.Cs(capstone.CS_ARCH_ARM,capstone.CS_MODE_THUMB)
    for i in CP.disasm(CODE[0x0B58:],0,20):
        print("[addr:%x]:%s %s\n"%(0x0B58+i.address,i.mnemonic,i.op_str))
    mu=unicorn.Uc(unicorn.UC_ARCH_ARM,unicorn.UC_MODE_THUMB)

		
	 # 最简单的函数调用,用于初始化填充jni接口
     #0-0x1000
     #push {lr} 00 b5
     #pop {pc}  00 bd
    JNIFUNCTIONLISTBASE=0x0
    JNIFUNCTIONLISTSIZE=0x1000
    JNINATIVEINTERFACE=301
    mu.mem_map(0,0x1000)
    #初始化jni接口中的每一个函数
    for i in range(0,300,1):
        mu.mem_write(i*4+JNIFUNCTIONLISTBASE,b'\x00\xb5\x00\xbd')  #最简单的函数调用
    #初始化JNINativeInterface结构体
    for i in range(300,600,1):
        mu.mem_write(i*4,struct.pack("I",(i-300)*4+1))
    #初始化jnienv× env
    jnienv_pointer=601*4
    mu.mem_write(jnienv_pointer,struct.pack("I",300*4))
    
    ADDRESS=0x1000
    SIZE=10*1024*1024
	# jni接口的具体实现,通过地址转jni 编号,在hook_code中实现
    mu.mem_map(ADDRESS,SIZE)
    mu.mem_write(ADDRESS,CODE)
    #mu.mem_write(ADDRESS+0x0B8C,b'\x00\xbf\x00\xbf')
    
    # 把android_log相关的nop掉
    # 在多处调用不相关的函数的时候,直接进入到plt表中打patch, bx lr ,直接返回    
    mu.mem_write(ADDRESS+0x088C,b'\x1E\xFF\x2F\xE1') 

	# 第一个参数是env
	# 第二个参数是jobject
	# 第三个参数是jstring
    mu.reg_write(unicorn.arm_const.UC_ARM_REG_R0,jnienv_pointer) #jnienv* env
    mu.reg_write(unicorn.arm_const.UC_ARM_REG_R1,0x0)#jobject
    mu.mem_map(ADDRESS+SIZE+0x1000,1024)
    mu.mem_write(ADDRESS+SIZE+0x1000,b'imtestfromjni')
    mu.reg_write(unicorn.arm_const.UC_ARM_REG_R2,ADDRESS+SIZE+0x1000)#jstring

    SP=ADDRESS+SIZE-16
    mu.reg_write(unicorn.arm_const.UC_ARM_REG_SP,SP)

    mu.hook_add(unicorn.UC_HOOK_CODE, hook_code)
    mu.hook_add(unicorn.UC_HOOK_MEM_WRITE,hook_mem)
    mu.hook_add(unicorn.UC_HOOK_INTR,hook_syscall)
    mu.hook_add(unicorn.UC_HOOK_BLOCK,hook_block)
    addstart=ADDRESS+0x0B58+1
    addend=ADDRESS+0x0BA6
    try:
        mu.emu_start(addstart,addend)
        print("emulat over")
        printArm32Regs(mu)
        r0value=mu.reg_read(unicorn.arm_const.UC_ARM_REG_R0)
        result=readstring(mu,r0value)
        print("return->"+result)
    except unicorn.UcError as e:
        print(e)
    #def hook_add(self, htype, callback, user_data=None, begin=1, end=0, arg1=0):

if __name__ == '__main__':
    testthumb_calljni()

unicorn模拟调用JNI_OnLoad

JNI_OnLoad中重要的函数
jint ( GetEnv) (JavaVM * , void*, jint); 把设置好的env设置给它就行了
jclass (FindClass)(JNIEnv, const char*);
jint (RegisterNatives)(JNIEnv, jclass, const JNINativeMethod*,jint);

import unicorn
import capstone
import binascii
import struct

def printArm32Regs(mu):
    for i in range(66,78):
        print("R%d,value:%x"%(i-66,mu.reg_read(i)))
    print("SP->value:%x" % (mu.reg_read(unicorn.arm_const.UC_ARM_REG_SP)))
    print("PC->value:%x" % (mu.reg_read(unicorn.arm_const.UC_ARM_REG_PC)))

def readstring(mu,address):
    result=''
    tmp=mu.mem_read(address,1)
    while(tmp[0]!=0):
        result=result+chr(tmp[0])
        address=address+1
        tmp = mu.mem_read(address, 1)
    return result

#typedef void (*uc_cb_hookcode_t)(uc_engine *uc, uint64_t address, uint32_t size, void *user_data);
def hook_code(mu,address,size,user_data):
    code=mu.mem_read(address,size)
    if address>=700*4 and address<=710*4:
        index=(address-700*4)/4
        print("call javavm function---------------"+str(index))
        if index==6:
            print("call javavm->GetEnv---------------" + str(index))
            #    jint        (*GetEnv)(JavaVM*, void**, jint);
            r1value=mu.reg_read(unicorn.arm_const.UC_ARM_REG_R1)
            mu.mem_write(r1value,struct.pack("I",601*4))
    if address>=0 and address<=300*4:
        index=address/4
        print("call jnienv function-----------------"+str(index))
        if index == 6:
            print("jnienv FindClass:")
            #    jclass      (*FindClass)(JNIEnv*, const char*);
            r1value = mu.reg_read(unicorn.arm_const.UC_ARM_REG_R1)
            classname=readstring(mu,r1value)
            #666 com/example/unicorncourse05/MainActivity
            print("jnienv FindClass:"+classname)
            mu.reg_write(unicorn.arm_const.UC_ARM_REG_R0,666)
        if index == 215:
            #    jint        (*RegisterNatives)(JNIEnv*, jclass, const JNINativeMethod*,jint);
            print("jnienv RegisterNatives:")
            r0value = mu.reg_read(unicorn.arm_const.UC_ARM_REG_R0)
            r1value = mu.reg_read(unicorn.arm_const.UC_ARM_REG_R1)
            r2value = mu.reg_read(unicorn.arm_const.UC_ARM_REG_R2)

            # funcname_bytearray=mu.mem_read(r2value,4)
            # funcname_addr=struct.unpack("I",funcname_bytearray);
            # funcname=readstring(mu,funcname_addr)


            r3value = mu.reg_read(unicorn.arm_const.UC_ARM_REG_R3)
            print("env:"+str(r0value)+"---jclass:"+str(r1value)+"---"+str(r2value)+"----"+str(r3value))
        if index==169:
            print("call GetStringUTFChars------------------")
            r0value=mu.reg_read(unicorn.arm_const.UC_ARM_REG_R0)
            r1value=mu.reg_read(unicorn.arm_const.UC_ARM_REG_R1)
            r2value=mu.reg_read(unicorn.arm_const.UC_ARM_REG_R2)
            content=readstring(mu,r1value)
            mu.reg_write(unicorn.arm_const.UC_ARM_REG_R0,r1value)
            print(str(r0value)+"---"+content+"---"+str(r2value))
            print("call GetStringUTFChars over------------------")
        if index==167:
            print("call NewStringUTF------------------")
            r0value = mu.reg_read(unicorn.arm_const.UC_ARM_REG_R0)
            r1value = mu.reg_read(unicorn.arm_const.UC_ARM_REG_R1)
            content = readstring(mu, r1value)
            mu.reg_write(unicorn.arm_const.UC_ARM_REG_R0, r1value)
            print(str(r0value) + "---" + content)
            print("call NewStringUTF over------------------")

        print("call jni interface------------------")
    CP=capstone.Cs(capstone.CS_ARCH_ARM,capstone.CS_MODE_THUMB)
    for i in CP.disasm(code,0,len(code)):
        print("[addr:%x]:%s %s\n"%(address,i.mnemonic,i.op_str))
    print("-----------------------------")
    printArm32Regs(mu)
    print("-----------------------------")
    return

def hook_block(mu,address,size,user_data):
    print("hook_block-----------------------------")
    code=mu.mem_read(address,size)
    CP=capstone.Cs(capstone.CS_ARCH_ARM,capstone.CS_MODE_THUMB)
    for i in CP.disasm(code,0,len(code)):
        print("[hook_block addr:%x]:%s %s\n"%(address,i.mnemonic,i.op_str))

    printArm32Regs(mu)
    print("hook_block-----------------------------")
    return

#typedef void (*uc_cb_hookintr_t)(uc_engine *uc, uint32_t intno, void *user_data);
def hook_syscall(mu,intno,user_data):
    print("hook_syscall-----------------------------")
    printArm32Regs(mu)
    print("hook_syscall-----------------------------")
    return

#void (*uc_cb_hookmem_t)(uc_engine *uc, uc_mem_type type,uint64_t address, int size, int64_t value, void *user_data);
def hook_mem(mu,type,address,size,value,user_data):
    if type==unicorn.UC_MEM_WRITE:
       print("write addr:0x%x,size:%d,value:0x%x"%(address,size,value))
    if type==unicorn.UC_MEM_READ:
       print("read addr:0x%x,size:%d,value:0x%x"%(address,size,value))
    print("hook_mem type:%d addr:0x%x,size:%d,value:0x%x"%(type,address,size,value))
    return

    
def testthumb_calljni():
#  text:00008ACA 0A 46                       MOV             R2, R1  ; Rd = Op2
# .text:00008ACC 03 46                       MOV             R3, R0  ; Rd = Op2
#.text:00008B04 04 92                        STR             R2, [SP,#0x40+var_30] ; Store to Memory
    CODE=None
    with open("so/unicorn05.so",'rb') as sofile:
        CODE=sofile.read()
    CP=capstone.Cs(capstone.CS_ARCH_ARM,capstone.CS_MODE_THUMB)
    for i in CP.disasm(CODE[0x0B58:],0,20):
        print("[addr:%x]:%s %s\n"%(0x0B58+i.address,i.mnemonic,i.op_str))
    mu=unicorn.Uc(unicorn.UC_ARCH_ARM,unicorn.UC_MODE_THUMB)


     #0-0x1000
     #push {lr} 00 b5
     #pop {pc}  00 bd
    JNIFUNCTIONLISTBASE=0x0
    JNIFUNCTIONLISTSIZE=0x1000
    JNINATIVEINTERFACE=301
    mu.mem_map(0,0x1000)
    #初始化jni接口中的每一个函数
    for i in range(0,300,1):
        mu.mem_write(i*4+JNIFUNCTIONLISTBASE,b'\x00\xb5\x00\xbd')
    #初始化JNINativeInterface结构体
    for i in range(300,600,1):
        mu.mem_write(i*4,struct.pack("I",(i-300)*4+1))
    #初始化jnienv× env
    jnienv_pointer=601*4
    mu.mem_write(jnienv_pointer,struct.pack("I",300*4))
    ADDRESS=0x1000
    SIZE=10*1024*1024

    JAVAVMFUNCTIONLISTBASE=700*4
    #初始化jni接口中的每一个函数
    for i in range(0,10,1):
        mu.mem_write(i*4+JAVAVMFUNCTIONLISTBASE,b'\x00\xb5\x00\xbd')
    #初始化JNIInvokeInterface结构体
    for i in range(0,10,1):
        mu.mem_write(i*4+JAVAVMFUNCTIONLISTBASE+40,struct.pack("I",i*4+JAVAVMFUNCTIONLISTBASE+1))
        
    #初始化javavm× vm
    javavm_pointer=700*4+80
    mu.mem_write(javavm_pointer,struct.pack("I",JAVAVMFUNCTIONLISTBASE+40))



    mu.mem_map(ADDRESS,SIZE)
    mu.mem_write(ADDRESS,CODE)



    mu.reg_write(unicorn.arm_const.UC_ARM_REG_R0,javavm_pointer) #javavm*
    mu.reg_write(unicorn.arm_const.UC_ARM_REG_R1,0x0)#jobject

    SP=ADDRESS+SIZE-16
    mu.reg_write(unicorn.arm_const.UC_ARM_REG_SP,SP)
    import datetime
    starttime=datetime.datetime.now()
    mu.hook_add(unicorn.UC_HOOK_CODE, hook_code)
    mu.hook_add(unicorn.UC_HOOK_MEM_WRITE,hook_mem)
    mu.hook_add(unicorn.UC_HOOK_INTR,hook_syscall)
    # mu.hook_add(unicorn.UC_HOOK_BLOCK,hook_block)
    addstart=ADDRESS+0xc00+1
    addend=ADDRESS+0xC66
    try:
        mu.emu_start(addstart,addend)
        print("emulat over")
        endtime=datetime.datetime.now()
        print(endtime-starttime)
        #35431 ms
        #7560 ms
    except unicorn.UcError as e:
        print(e)
    #def hook_add(self, htype, callback, user_data=None, begin=1, end=0, arg1=0):

if __name__ == '__main__':
    testthumb_calljni()

AndroidNativeEmu调用jni函数

AndroidNativeEmu :
elf文件解析及so加载
栈支持
内存管理
文件系统
JNI支持
常见syscall模拟支持

import logging
import sys

from unicorn import UC_HOOK_CODE
from unicorn.arm_const import *

from androidemu.emulator import Emulator
from samples import debug_utils
from androidemu.utils import memory_helpers
from androidemu.java.helpers.native_method import native_method, native_read_args
@native_method
def strlen(uc,buffer):
    content=memory_helpers.read_utf8(uc,buffer)
    length=len(content)
    return length

@native_method
def _Z4testv(uc):
    return 666


# Configure logging
logging.basicConfig(
    stream=sys.stdout,
    level=logging.DEBUG,
    format="%(asctime)s %(levelname)7s %(name)34s | %(message)s"
)

logger = logging.getLogger(__name__)

# Initialize emulator
emulator = Emulator(vfp_inst_set=True)
#emulator.load_library("example_binaries/libc.so", do_init=False)
emulator.modules.add_symbol_hook('strlen',emulator.hooker.write_function(strlen) + 1)
emulator.modules.add_symbol_hook('_Z4testv',emulator.hooker.write_function(_Z4testv) + 1)
#modules.add_symbol_hook('__android_log_print', hooker.write_function(self.android_log_print) + 1)
lib_module = emulator.load_library("unicorncourse/unicorncourse06.so", do_init=False)

# Show loaded modules.
logger.info("Loaded modules:")

for module in emulator.modules:
    logger.info("[0x%x] %s" % (module.base, module.filename))


# Add debugging.
# def hook_code(mu, address, size, user_data):
#     instruction = mu.mem_read(address, size)
#     instruction_str = ''.join('{:02x} '.format(x) for x in instruction)
#
#     print('# Tracing instruction at 0x%x, instruction size = 0x%x, instruction = %s' % (address, size, instruction_str))
#

emulator.mu.hook_add(UC_HOOK_CODE, debug_utils.hook_code)

# Runs a method of "libnative-lib.so" that calls an imported function "strlen" from "libc.so".
funcname='Java_com_example_unicorncourse04_MainActivity_stringFromJNI'
result=emulator.call_symbol(lib_module, 'Java_com_example_unicorncourse04_MainActivity_stringFromJNI',emulator.java_vm.jni_env.address_ptr,0,"testjnifunction")
print(result)
print("second--------------------------------")
result=emulator.call_native(lib_module.base+0x0b58+1,emulator.java_vm.jni_env.address_ptr,0,"testjnifunction")
print(result)

AndroidNativeEmu模拟与java函数交互

对系统调用号模拟实现
在这里插入图片描述

对.init_array没有支持

Unidbg加载so并调用so中函数

unidbg的底层引擎 :dynarmic,unicorn
支持对so的加载
支持对jni接口函数的模拟调用
支持常见syscalls的模拟调用
支持ARM32和ARM64
支持android和ios
其他功能:
基于HookZz实现的inline hook,xhook实现的hook,substrace,gdb,ida远程调试功能

test 目录下面有一些demo

unidbg模拟加载so并调用so中函数
1、加载so,并调用init以及init_array中的函数
2、调用so中普通方法
3、调用JNI_OnLoad函数
4、调用jni函数

package com.example.unicorncourse08;

import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.LibraryResolver;
import com.github.unidbg.Module;
import com.github.unidbg.PointerNumber;
import com.github.unidbg.arm.ARM;
// import com.github.unidbg.arm.backend.dynarmic.DynarmicLoader;
import com.github.unidbg.arm.backend.DynarmicFactory;
import com.github.unidbg.linux.android.AndroidARMEmulator;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.DvmClass;
import com.github.unidbg.linux.android.dvm.DvmObject;
import com.github.unidbg.linux.android.dvm.StringObject;
import com.github.unidbg.linux.android.dvm.VM;
import com.github.unidbg.memory.Memory;
import com.github.unidbg.memory.MemoryBlock;
import com.github.unidbg.pointer.UnidbgPointer;
import sun.applet.Main;
import unicorn.ArmConst;

import java.io.File;

public class MainActivity {
//    static {
//        DynarmicLoader.useDynarmic();
//    }
    public static void main(String[] args) {
        // android 模拟器
        AndroidEmulator emulator;
        emulator = AndroidEmulatorBuilder
                .for32Bit()
                .addBackendFactory(new DynarmicFactory(true))
                .build();
        final Memory memory = emulator.getMemory(); // 申请内存


        VM vm = emulator.createDalvikVM(null);
        vm.setVerbose(true);

        // 基本的依赖库,并选择版本,将依赖库放入内存
        LibraryResolver resolver = new AndroidResolver(23);
        memory.setLibraryResolver(resolver);

        // 加载so文件,自动执行init,.init_array
        // 加载类,调用普通方法,获取参数
        Module unicorn08module=emulator.loadLibrary(new File("unidbg-android/src/test/resources/example_binaries/unicorncourse/libnative-lib.so"));
        Number result=unicorn08module.callFunction(emulator,"_Z3addii",1,2)[0]; // 可以通过导出符号,或者偏移进行调用,返回值是一个数组,这里只要数组中的第一个返回值
        System.out.println(result.intValue());

        //_Z7add_sixiiiiii
        result=unicorn08module.callFunction(emulator,"_Z7add_sixiiiiii",1,2,3,4,5,6)[0];
        System.out.println(result.intValue());

        //_Z15getstringlengthPKc
        // 申请内存,获取内存的指针,并往其中写入内容
        MemoryBlock block1=memory.malloc(10,true);
        UnidbgPointer str1_ptr=block1.getPointer();
        str1_ptr.write("hello".getBytes());

        String content=ARM.readCString(emulator.getBackend(),str1_ptr.peer);
        System.out.println(str1_ptr.toString()+"---"+content);

        // 调用参数为指针的函数并获取返回值
        result=unicorn08module.callFunction(emulator,"_Z15getstringlengthPKc",new PointerNumber(str1_ptr))[0];
        Number r0value=emulator.getBackend().reg_read(ArmConst.UC_ARM_REG_R0);
        System.out.println(result.intValue()+"----"+r0value);


        MemoryBlock block2=memory.malloc(10,true);
        UnidbgPointer str2_ptr=block2.getPointer();
        str2_ptr.write("666".getBytes());
        String content2=ARM.readCString(emulator.getBackend(),str2_ptr.peer);
        System.out.println(str2_ptr.toString()+"---"+content2);
        result=unicorn08module.callFunction(emulator,"_Z16getstringlength2PKcS0_",new PointerNumber(str1_ptr),new PointerNumber(str2_ptr))[0];
        r0value=emulator.getBackend().reg_read(ArmConst.UC_ARM_REG_R0);
        System.out.println(result.intValue()+"----"+r0value);


        //调用jni_OnLoad函数
        vm.callJNI_OnLoad(emulator,unicorn08module);

        //调用jni函数,对于动态注册的jni函数必须在完成地址的绑定才能调用
        System.out.println("stringFromJNI1-------------------------");
        DvmClass MainActivity_dvmclass=vm.resolveClass("com/example/unicorncourse08/MainActivity");
        DvmObject resultobj=MainActivity_dvmclass.callStaticJniMethodObject(emulator,"stringFromJNI1(Ljava/lang/String;)Ljava/lang/String;","helloworld");
        System.out.println("resultobj:"+resultobj);
        resultobj=MainActivity_dvmclass.callStaticJniMethodObject(emulator,"stringFromJNI1(Ljava/lang/String;)Ljava/lang/String;",new StringObject(vm, "hellokanxue"));
        System.out.println("resultobj:"+resultobj);
        System.out.println("stringFromJNI1-------------------------");

        //动态注册的jni函数stringFromJNI2
        resultobj=MainActivity_dvmclass.callStaticJniMethodObject(emulator,"stringFromJNI2(Ljava/lang/String;)Ljava/lang/String;",new StringObject(vm, "hellostringFromJNI2"));
        System.out.println("resultobj:"+resultobj);
        System.out.println("stringFromJNI2-------------------------");


        DvmObject mainactivity=MainActivity_dvmclass.newObject(null);
        mainactivity.callJniMethodObject(emulator,"stringFromJNI2(Ljava/lang/String;)Ljava/lang/String;",new StringObject(vm, "hellostringFromJNI2"));
        System.out.println("resultobj:"+resultobj);
        System.out.println("stringFromJNI2-------------------------");

    }
}

Unidbg模拟与java交互

两种使用方法

比较复杂的方法,与AndroidNativeEmu

package com.example.test;

import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.Module;
import com.github.unidbg.arm.backend.DynarmicFactory;
import com.github.unidbg.linux.android.AndroidARMEmulator;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.*;
import com.github.unidbg.linux.android.dvm.jni.ProxyClassFactory;
import com.github.unidbg.memory.Memory;
import com.github.unidbg.virtualmodule.android.AndroidModule;
import com.github.unidbg.virtualmodule.android.JniGraphics;
import org.apache.commons.codec.binary.Base64;
import sun.applet.Main;

import java.io.File;
import java.lang.reflect.Field;

public class MainActivitymethod1 extends AbstractJni {

    private static DvmClass MainActivityClass;

    @Override
    public DvmObject<?> getStaticObjectField(BaseVM vm, DvmClass dvmClass, String signature) {
        System.out.println("getStaticObjectField->"+signature);
        if(signature.equals("com/example/testjni/MainActivity->staticcontent:Ljava/lang/String;")){
            return new StringObject(vm,"staticcontent");
        }

        //
   /*     try {
            Class MainActivityclass=MainActivitymethod1.class.getClassLoader().loadClass("com.example.testjni.MainActivity");
            Field staticcontentfield=MainActivityclass.getField("staticcontent");
            String content= (String) staticcontentfield.get(null);
            return new StringObject(vm,content);
        } catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }*/
        //com/example/testjni/MainActivity->staticcontent:Ljava/lang/String;
        return super.getStaticObjectField(vm, dvmClass, signature);
    }

    @Override
    public DvmObject<?> getObjectField(BaseVM vm, DvmObject<?> dvmObject, String signature) {
        System.out.println("getObjectField->"+signature);
        if(signature.equals("com/example/testjni/MainActivity->objcontent:Ljava/lang/String;")){
            return new StringObject(vm,"objcontent");
        }
        return super.getObjectField(vm, dvmObject, signature);
    }

    public String base64(String arg3) {
        String result=Base64.encodeBase64String(arg3.getBytes());
        return result;
    }

    @Override
    public DvmObject<?> callObjectMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {
        System.out.println("callObjectMethodV->"+signature);
        if(signature.equals("com/example/testjni/MainActivity->base64(Ljava/lang/String;)Ljava/lang/String;")){
            DvmObject dvmobj=vaList.getObject(0);
            String arg= (String) dvmobj.getValue();
            String result=base64(arg);
            return new StringObject(vm,result);
        }
        return super.callObjectMethodV(vm, dvmObject, signature, vaList);
    }

    public static void main(String[] args) {
        MainActivitymethod1 mainActivitymethod1=new MainActivitymethod1();
//        AndroidARMEmulator emulator = new AndroidARMEmulator("org.telegram.messenger");
        AndroidEmulator emulator;
        emulator = AndroidEmulatorBuilder
                .for32Bit()
                .addBackendFactory(new DynarmicFactory(true))
                .build();
        final Memory memory = emulator.getMemory();
        memory.setLibraryResolver(new AndroidResolver(23));
        VM vm = emulator.createDalvikVM(null);
        vm.setVerbose(true);
        vm.setJni(mainActivitymethod1);
        DalvikModule dm = vm.loadLibrary(new File("unidbg-android/src/test/resources/example_binaries/unicorncourse/calljava.so"), true);
        dm.callJNI_OnLoad(emulator);
        MainActivityClass=vm.resolveClass("com/example/testjni/MainActivity");
        DvmObject obj=MainActivityClass.newObject(null);
        obj.callJniMethodObject(emulator,"base64byjni(Ljava/lang/String;)Ljava/lang/String;","callbase64byjni");


    }
}

比较简洁的方法

package com.example.testjni;

import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.arm.backend.DynarmicFactory;
import com.github.unidbg.linux.android.AndroidARMEmulator;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.DalvikModule;
import com.github.unidbg.linux.android.dvm.DvmClass;
import com.github.unidbg.linux.android.dvm.DvmObject;
import com.github.unidbg.linux.android.dvm.VM;
import com.github.unidbg.linux.android.dvm.jni.ProxyClassFactory;
import com.github.unidbg.linux.android.dvm.jni.ProxyDvmObject;
import com.github.unidbg.memory.Memory;
import org.apache.commons.codec.binary.Base64;

import java.io.File;

public class MainActivity {
    private static DvmClass MainActivityClass;
    public String objcontent="objcontent";
    public static String staticcontent="staticcontent";

    public String base64(String arg3) {
        String result= Base64.encodeBase64String(arg3.getBytes());
        return result;
    }

    public static void main(String[] args) {
//        AndroidARMEmulator emulator = new AndroidARMEmulator("org.telegram.messenger");
        AndroidEmulator emulator;
        emulator = AndroidEmulatorBuilder
                .for32Bit()
                .addBackendFactory(new DynarmicFactory(true))
                .build();
        final Memory memory = emulator.getMemory();
        memory.setLibraryResolver(new AndroidResolver(23));
        VM vm = emulator.createDalvikVM(null);
        vm.setVerbose(true);

        vm.setDvmClassFactory(new ProxyClassFactory());

        DalvikModule dm = vm.loadLibrary(new File("unidbg-android/src/test/resources/example_binaries/unicorncourse/calljava.so"), true);
        dm.callJNI_OnLoad(emulator);

        MainActivityClass=vm.resolveClass("com/example/testjni/MainActivity");
        MainActivity mainActivity=new MainActivity();
        DvmObject obj= ProxyDvmObject.createObject(vm,mainActivity);
        obj.callJniMethodObject(emulator,"base64byjni(Ljava/lang/String;)Ljava/lang/String;","callbase64byjni");


    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值