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");
}
}