主要内容
1:使用unidbg 调用函数sub_13558
2:使用unidbg 里的IHookZz进行hook函数sub_13558,读取入参和出参
3:使用unidbg 里的IHookZz进行替换函数sub_13558里的参数
4:使用unidbg 里的IHookZz进行替换函数sub_13558的返回值
代码如下:
package com.unidbg2;
import com.github.unidbg.*;
import com.github.unidbg.android.MyTraceSystemMemoryWriteListener;
import com.github.unidbg.arm.HookStatus;
import com.github.unidbg.arm.context.RegisterContext;
import com.github.unidbg.hook.HookContext;
import com.github.unidbg.hook.ReplaceCallback;
import com.github.unidbg.hook.hookzz.*;
import com.github.unidbg.hook.whale.IWhale;
import com.github.unidbg.hook.whale.Whale;
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.memory.MemoryBlock;
import com.github.unidbg.pointer.UnidbgPointer;
import com.sun.jna.Pointer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import unicorn.Arm64Const;
import unicorn.ArmConst;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
/**
* AbstractJni解决的问题:
* 如果自己在apk写java代码调用so层函数,遇到so通过反射调用java层函数时,需要自己补上java层对应的类、方法和变量,因为这些需要执行的代码是绕不过去的!
*/
public class HookInUnidbgByConsoleDebuggerV2 extends AbstractJni implements ModuleListener {
private static final Log logger = LogFactory.getLog(HookInUnidbgByConsoleDebuggerV2.class);
private final AndroidEmulator emulator;
private final VM vm;
private final Module module;
private Memory memory;
private static AndroidEmulator createARMEmulator() {
return AndroidEmulatorBuilder.for64Bit()
.setProcessName("hellojni_2.0.3")
// .addBackendFactory(new DynarmicFactory(true))
.build();
}
HookInUnidbgByConsoleDebuggerV2() {
// 创建模拟器实例,可以自定义模拟器,参考QDReaderJni
//emulator = AndroidEmulatorBuilder.for64Bit().setProcessName("hellojni_2.0.3").build();
emulator = createARMEmulator();
// 模拟器的内存操作接口
memory = emulator.getMemory();
// 设置系统类库解析
AndroidResolver resolver = new AndroidResolver(23);
memory.setLibraryResolver(resolver);// 设置系统类库解析
// 重点: 实现ModuleListener接口后通过下面的代码,设置模块加载监听
memory.addModuleListener(this);
// 创建Android虚拟机
vm = emulator.createDalvikVM(new File("unidbg-android/src/test/resources/unidbg/hellojni_2.0.3.apk"));
vm.setDvmClassFactory(new ProxyClassFactory());
// 设置是否打印Jni调用细节
vm.setVerbose(true);
vm.setJni(this);
// 加载so到虚拟内存
DalvikModule dm = vm.loadLibrary("hello-jni", false);
// 加载好的 libhookinunidbg.so对应为一个模块
module = dm.getModule();
// 执行JNIOnLoad(如果有的话)
dm.callJNI_OnLoad(emulator);
}
// 调用native方法
public void callSign2(){
DvmClass HelloJni = vm.resolveClass("com/example/hellojni/HelloJni");
// 参考文档:https://blog.csdn.net/xubaoyong/article/details/121752455
// public native String sign2(String str, String str2);
String sign2 = "sign2(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;";
DvmObject<?> dvmObject = HelloJni.newObject(null);
String arg0 = "1234567890";
String arg1 = "abcdefghigklmnopqrstuvwxyz";
DvmObject result = dvmObject.callJniMethodObject(emulator, sign2,arg0,arg1);
logger.info("call 入参:arg0="+arg0+",arg1="+arg1+",返回值是:"+result.getValue());
}
//
public void hookLibc(){
IWhale whale = Whale.getInstance(emulator);
Symbol strlen = emulator.getMemory().findModule("libc.so").findSymbolByName("strlen");
whale.inlineHookFunction(strlen, new ReplaceCallback() {
@Override
public HookStatus onCall(Emulator<?> emulator, long originFunction) {
logger.info("hookLibc strlen=" + emulator.getContext().getPointerArg(0).getString(0));
return HookStatus.RET(emulator, originFunction);
}
});
}
public void hookLibArtSo(){
}
public void hookLibArtSo1(){
Module module = emulator.getMemory().findModule("libart.so");
// 参考文档:
// https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html
Symbol findClass = module.findSymbolByName("FindClass");
IWhale whale = Whale.getInstance(emulator);
whale.inlineHookFunction(findClass, new ReplaceCallback() {
@Override
public HookStatus onCall(Emulator<?> emulator, long originFunction) {
RegisterContext context = emulator.getContext();
logger.info("hookLibArtSo strlen=" + context.getPointerArg(0).getString(0));
return HookStatus.RET(emulator, originFunction);
}
});
}
public void hook_sub_13558(Module module){
long start = module.base+0x13558;
IHookZz hookZz = HookZz.getInstance(emulator); // 加载HookZz,支持inline hook,文档看https://github.com/jmpews/HookZz
hookZz.enable_arm_arm64_b_branch(); // 测试enable_arm_arm64_b_branch,可有可无
hookZz.wrap(start, new WrapCallback<HookZzArm64RegisterContext>() {
UnidbgPointer outPointer = null;
String traceId = null;
@Override
public void preCall(Emulator<?> emulator, HookZzArm64RegisterContext context, HookEntryInfo info) {
traceId = UUID.randomUUID().toString().replaceAll("-","");
outPointer = context.getPointerArg(0);
UnidbgPointer in = context.getPointerArg(1);
int length = context.getIntArg(2);
logger.info(traceId+",emulator.attach().addBreakPoint sub_13558 入参arg1:"+in.getString(0));
logger.info(traceId+",emulator.attach().addBreakPoint sub_13558 入参arg2:"+length);
logger.info(traceId+",emulator.attach().addBreakPoint sub_13558 入参arg3:"+outPointer.getString(0));
} // inline wrap导出函数
@Override
public void postCall(Emulator<?> emulator, HookZzArm64RegisterContext context, HookEntryInfo info) {
int rep = context.getIntArg(0);
logger.info(traceId+",emulator.attach().addBreakPoint sub_13558 返回结果:"+rep);
logger.info(traceId+",emulator.attach().addBreakPoint sub_13558 返回字符串结果:"+outPointer.getString(0));
}
});
hookZz.disable_arm_arm64_b_branch();
// xHook 不能应用与这个场景
}
public void call_sub_13558(Module module){
long sub_13558_address = module.base+0x13558;
MyTraceSystemMemoryWriteListener listener = new MyTraceSystemMemoryWriteListener();
String traceFile = "unidbg-android/src/test/resources/unidbg/hellojni_2.0.3.txt";
PrintStream traceStream = null;
try {
traceStream = new PrintStream(new FileOutputStream(traceFile), true);
emulator.traceCode(sub_13558_address, sub_13558_address+0x358,listener).setRedirect(traceStream);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
String inputStream = "+++++++++";
int length = inputStream.length();
//int128,malloc 16
// 方法一 128个比特,分配16个字节就好
Pointer outPutStream = memory.allocateStack(16);
// 这个打印的是什么,https://blog.csdn.net/li_ph/article/details/9712225
// logger.info(new Stat64(outPutStream));
Number[] numbers = module.callFunction(emulator,0x13558,outPutStream,inputStream,length);
logger.info("numbers="+numbers[0].intValue());
logger.info("outPutStream="+outPutStream.getString(0));
}
/**
* 替换函数 sub_13558的参数
* @param module
*/
public void replace_sub_13558_arg(Module module){
long sub_13558_address = module.base+0x13558;
HookZz hook = HookZz.getInstance(emulator);
hook.replace(sub_13558_address, new ReplaceCallback() {
UnidbgPointer outPointer = null;
String traceId = null;
@Override
public HookStatus onCall(Emulator<?> emulator, HookContext context, long originFunction) {
traceId = UUID.randomUUID().toString().replaceAll("-","");
outPointer = context.getPointerArg(0);
UnidbgPointer in = context.getPointerArg(1);
int length = context.getIntArg(2);
//
logger.info(traceId+",初始 replace_sub_13558_arg 入参arg1:"+in.getString(0));
logger.info(traceId+",初始 replace_sub_13558_arg 入参arg2:"+length);
logger.info(traceId+",初始 replace_sub_13558_arg 入参arg3:"+outPointer.getString(0));
String helloInput = "hello world";
length = helloInput.length();
MemoryBlock helloInputBlock = emulator.getMemory().malloc(length, true);
helloInputBlock.getPointer().write(helloInput.getBytes(StandardCharsets.UTF_8));
// 修改r0为指向新字符串的新指针,此处注意64位的使用Arm64Const.UC_ARM64_REG_W1,32位的使用ArmConst.UC_ARM_REG_R1
emulator.getBackend().reg_write(Arm64Const.UC_ARM64_REG_W1, helloInputBlock.getPointer().peer);
// 修改r1值为新长度
emulator.getBackend().reg_write(Arm64Const.UC_ARM64_REG_W2, length);
in = context.getPointerArg(1);
length = context.getIntArg(2);
logger.info(traceId+",修改后 replace_sub_13558_arg 入参arg1:"+in.getString(0));
logger.info(traceId+",修改后 replace_sub_13558_arg 入参arg2:"+length);
return HookStatus.RET(emulator,originFunction);
}
@Override
public void postCall(Emulator<?> emulator, HookContext context) {
int rep = context.getIntArg(0);
logger.info(traceId+",:"+rep);
logger.info(traceId+",replace_sub_13558_arg 返回字符串结果:"+outPointer.getString(0));
// super.postCall(emulator, context);
}
},true);
}
public void replace_sub_13558_result(Module module){
long sub_13558_address = module.base+0x13558;
HookZz hook = HookZz.getInstance(emulator);
hook.replace(sub_13558_address, new ReplaceCallback() {
UnidbgPointer outPointer = null;
String traceId = null;
@Override
public HookStatus onCall(Emulator<?> emulator, HookContext context, long originFunction) {
traceId = UUID.randomUUID().toString().replaceAll("-","");
outPointer = context.getPointerArg(0);
return HookStatus.RET(emulator,originFunction);
}
// _BYTE *__fastcall sub_13558(_BYTE *result, const void *a2, unsigned __int64 length)
@Override
public void postCall(Emulator<?> emulator, HookContext context) {
String helloInput = "VeryGood";
int length = helloInput.length();
MemoryBlock helloInputBlock = emulator.getMemory().malloc(length, true);
helloInputBlock.getPointer().write(helloInput.getBytes(StandardCharsets.UTF_8));
// 修改r0为指向新字符串的新指针,此处注意64位的使用Arm64Const.UC_ARM64_REG_W1,32位的使用ArmConst.UC_ARM_REG_R0
emulator.getBackend().reg_write(Arm64Const.UC_ARM64_REG_W0, 2);
outPointer.setString(0,helloInput);
}
},true);
}
public static void main(String[] args) throws IOException {
HookInUnidbgByConsoleDebuggerV2 mydemo = new HookInUnidbgByConsoleDebuggerV2();
// mydemo. hook_sub_13558(mydemo.module);
// 替换函数sub_13558的参数
// mydemo.replace_sub_13558_arg(mydemo.module);
mydemo.replace_sub_13558_result(mydemo.module);
// mydemo.callSign2();
mydemo.call_sub_13558(mydemo.module);
mydemo.destroy();
}
Module libc = null;
@Override
public void onLoaded(Emulator<?> emulator, Module module) {
if("libc.so".equals(module.name)){
hookLibc();
}else if("libart.so".equals(module.getPath())){
hookLibArtSo();
}else if("libhello-jni.so".equals(module.getPath())){
//call_sub_13558(module);
}
logger.info(module.getPath()+"文件加载完毕,"+module.getBaseHeader());
}
void destroy() throws IOException {
emulator.close();
System.out.println("destroy");
}
}
补充知识
1:使用unidbg 里的IHookZz进行替换函数sub_13558里的参数
emulator.getBackend().reg_write(Arm64Const.UC_ARM64_REG_W1, helloInputBlock.getPointer().peer);
此处注意,64位的使用Arm64Const.UC_ARM64_REG_W0,32位使用ArmConst.UC_ARM_REG_R0等
2:使用unidbg 里的IHookZz进行替换函数sub_13558的返回值
emulator.getBackend().reg_write(Arm64Const.UC_ARM64_REG_W0, 2);
此处注意,64位的使用Arm64Const.UC_ARM64_REG_W0,32位使用ArmConst.UC_ARM_REG_R0
|