unicorn start
用unicorn调用so文件中的某个函数,观察函数的输入与输出
目标
hook so文件中的sign1函数的输出与输入
这个函数内部调用了两个函数,tea_encrypt和sprintf,这两个函数中tea_encrypt函数只需要修复got表项即可调用tea_encrypt,但是sprintf函数不行
这里我们开始实验
创建虚拟机
由于这里的指令都是两个字节为一条指令
所以这里为thumb指令集
def test_arm():
print("Emulate ARM code")
try:
# Initialize emulator in ARM mode
mu = Uc(UC_ARCH_ARM, UC_MODE_THUMB) # 创建代码
# 其它代码添加到此处
return mu
except UcError as e:
print("ERROR: %s" % e)
mu = test_arm() # mu就是arm虚拟机
建立内存映射+写入数据
由于这是要模拟执行一段函数,所以要建立镜像区,栈区,数据段区的内存
这里各个区的大小存粹靠估算
image = open('./libnative-lib.so','rb').read()
# 镜像内存
image_base = 0x0
mu.mem_map(image_base, 0x10000*8) # 这里大小自己估算
mu.mem_write(image_base,image)
# 栈内存
stack_base = 0xa0000
stack_size = 0x10000 * 3
mu.mem_map(stack_base, stack_size) # 这里大小自己估算
stack_top = stack_base + stack_size - 0x4
mu.reg_write(UC_ARM_REG_SP,stack_top)
# 数据段内存
a1 = b'123'
data_base = 0xf0000
data_size = 0x10000 * 3
mu.mem_map(data_base, data_size) # 这里大小自己估算
mu.mem_write(data_base,a1)
这里栈区的sp指针应小于栈大小的0x4,防止栈溢出,这里我们将‘123’字符串写入数据段,来作为函数的参数使用
添加hook函数
主要用于程序报错时可以及时追踪到哪里有问题
def hook_code(uc, address, size, user_data):
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size))
def hook_memory(uc, access, address, size,value, userdata):
pc = uc.reg_read(UC_ARM_REG_PC)
print ("memory error: pc:%x address:%x size:%x" % (pc, address, size))
mu.hook_add(UC_HOOK_CODE,hook_code,0)
mu.hook_add(UC_HOOK_MEM_UNMAPPED,hook_memory,0)
开始执行
#开始执行虚拟机
start_addr = 0x9B68
end_addr = 0x9C2C
try:
mu.emu_start(start_addr, end_addr)
R2 = mu.reg_read(UC_ARM_REG_R2)
res = mu.mem_read(R2,16)
print(binascii.b2a_hex(res))
except UcError as e:
print(e)
结果只运行到第一条指令:
这里将开始地址+1,然后执行:
然后这里就遇到了函数地址外的地址,很奇怪!!!,这里找到0x91ac,也就是最后一次正常的地方,发现来到了plt表,点击后又来到got表,这里的got表其实是ida已经自动补全了,unicorn需要自己手动补全
补全后:
执行代码:
#开始执行虚拟机
start_addr = 0x9B68
end_addr = 0x9C2C
try:
# 添加got表
mu.mem_write(0x1EDB0,b'\xD9\x98\x00\x00')
mu.emu_start(start_addr+1, end_addr)
R2 = mu.reg_read(UC_ARM_REG_R2)
res = mu.mem_read(R2,16)
print(binascii.b2a_hex(res))
except UcError as e:
print(e)
最后代码:
from unicorn import *
from unicorn.arm_const import *
import binascii
def hook_code(uc, address, size, user_data):
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size))
def hook_memory(uc, access, address, size,value, userdata):
pc = uc.reg_read(UC_ARM_REG_PC)
print ("memory error: pc:%x address:%x size:%x" % (pc, address, size))
def test_arm():
print("Emulate ARM code")
try:
# Initialize emulator in ARM mode
mu = Uc(UC_ARCH_ARM, UC_MODE_THUMB) # 创建代码
# 其它代码添加到此处
return mu
except UcError as e:
print("ERROR: %s" % e)
mu = test_arm() # mu就是arm虚拟机
image = open('./libnative-lib.so','rb').read()
# 镜像内存
image_base = 0x0
mu.mem_map(image_base, 0x10000*8) # 这里大小自己估算
mu.mem_write(image_base,image)
# 栈内存
stack_base = 0xa0000
stack_size = 0x10000 * 3
mu.mem_map(stack_base, stack_size) # 这里大小自己估算
stack_top = stack_base + stack_size - 0x4
mu.reg_write(UC_ARM_REG_SP,stack_top)
# 数据段内存
a1 = b'123'
data_base = 0xf0000
data_size = 0x10000 * 3
mu.mem_map(data_base, data_size) # 这里大小自己估算
mu.mem_write(data_base,a1)
#函数参数通过数据段传递 寄存器是R0
mu.reg_write(UC_ARM_REG_R0,data_base)
# 添加hook函数
# mu.hook_add(UC_HOOK_CODE,hook_code,0)
# mu.hook_add(UC_HOOK_MEM_UNMAPPED,hook_memory,0)
#开始执行虚拟机
start_addr = 0x9B68
end_addr = 0x9C2C
try:
# 添加got表
mu.mem_write(0x1EDB0,b'\xD9\x98\x00\x00')
mu.emu_start(start_addr+1, end_addr)
R2 = mu.reg_read(UC_ARM_REG_R2)
res = mu.mem_read(R2,16)
print(binascii.b2a_hex(res))
except UcError as e:
print(e)
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 jaytp@qq.com