一、目标
在做代码还原的时候,有时候会分析一组结果,希望在中途下个条件断点,比如在代码行0x1234,R0=0x5678的时候触发断点。
今天我们就来试着搞一下。
TIP: Unidbg代码同步到官方最新版,最新版已经支持浮点寄存器的显示了。
二、步骤
先写个floatdemotwo
把祖传算法升个级
extern "C" JNIEXPORT jstring JNICALL Java_com_fenfei_app_floatdemo_MainActivity_stringFromJNI( JNIEnv* env, jobject Obj, jdouble value) { std::string hello = "Hello from C++"; double p=3.14159; double s,v,rc; for(int i=0 ; i< 10; i++){ hello +="\n"; v = 2*p* (value + i); s = p * (value + i) * (value + i); rc = v+s; hello += std::to_string(rc); } return env->NewStringUTF(hello.c_str()); }
算出10个圆的周长和面积之和。
打印出来结果是这样的
Hello from C++ 150.796320 197.920170 251.327200 311.017410 376.990800 449.247370 527.787120 612.610050 703.716160 801.105450
我们的目标是要在结果等于 #449.247370# 的时候触发断点,假装分析下后面 527.787120 的计算过程。
IDA一把
我们在0x127C0下断点,然后n单步几下,到了0x127D4,执行完 FADD D0, D1, D0 这个加法指令之后,可以看到 D0的值是 150.796320 。
目标就是它了。我们把条件断点下在0x127D4,当D0=449.247370 的时候触发。
hook_add_new
先创建一个ffcodehook类,继承自com.github.unidbg.arm.backend.CodeHook 然后把它加入到emulator
// com/fenfei/test/runfloatdemo.java analyseHookA = new FFCodehook(emulator); emulator.getBackend().hook_add_new(analyseHookA, module.base + 0x127D8, module.base + 0x127D8, emulator); // com/fenfei/test/ffcodehook.java public class FFCodehook implements CodeHook { private final Emulator<?> emulator; public FFCodehook(Emulator<?> emulator) { super(); this.emulator = emulator; } private Unicorn.UnHook unHook; @Override public void onAttach(Unicorn.UnHook unHook) { if (this.unHook != null) { throw new IllegalStateException(); } this.unHook = unHook; } @Override public void detach() { if (unHook != null) { unHook.unhook(); unHook = null; } } private static BigInteger newBigInteger(byte[] data) { if (data.length != 16) { throw new IllegalStateException("data.length=" + data.length); } byte[] copy = Arrays.copyOf(data, data.length); for (int i = 0; i < 8; i++) { byte b = copy[i]; copy[i] = copy[15 - i]; copy[15 - i] = b; } byte[] bytes = new byte[copy.length + 1]; System.arraycopy(copy, 0, bytes, 1, copy.length); // makePositive return new BigInteger(bytes); } @Override public void hook(Backend backend, long address, int size, Object user) { try { if (address == 0x400127d8) { byte[] data = backend.reg_read_vector(Arm64Const.UC_ARM64_REG_Q0); if (data != null) { String strShow = String.format(Locale.US, " Q0=0x%s%s", newBigInteger(data).toString(16), Utils.decodeVectorRegister(data)); System.out.println("##### value " + strShow); } } } catch (BackendException e) { throw new IllegalStateException(e); } } }
这样就可以把运行到 0x127D8 指令时的 D0的值都打印出来。
##### value Q0=0x4062d97b7414a4d2(150.79631999999998) ##### value Q0=0x4068bd72085b1854(197.92016999999998) ##### value Q0=0x406f6a786c22680a(251.3272) ##### value Q0=0x407370474fb549fa(311.01741000000004) ##### value Q0=0x40778fda5119ce07(376.9908) ##### value Q0=0x407c13f53a3ec02f(449.24737) ##### value Q0=0x40807e4c05921038(527.78712) ##### value Q0=0x408324e161e4f765(612.6100499999999) ##### value Q0=0x4085fdbab21815a0(703.71616) ##### value Q0=0x408908d7f62b6ae8(801.10545)
来个条件
现在可以做判断了,在 D0=449.247370 的时候断在它的下一一行,进入调试模式。
double bOutD = bytes2Double(data); if(bOutD == 449.247370){ Debugger MyDbg = emulator.attach(DebuggerType.CONSOLE); MyDbg.addBreakPoint(0x400127dc); }
好了,成功进入到了调试模式,可以慢慢分析后面 527.787120 的计算过程了。
注意: 浮点数不能直接用 == 判断,因为精度不一样,比较安全的做法是这样的:
final double THRESHOLD = .0001; double bOutD = bytes2Double(data); if (Math.abs(bOutD - 449.247370 ) < THRESHOLD) { ... }
三、总结
条件断点在分析一组数据的时候很有用。
hook_add_new其实还可以当Inline Hook用。你也许会问,Inline Hook使用 xhook和其他一些Hook工具不香吗?
悟空,等你遇到那些神通广大会检测重要代码是否被修改的妖怪的时候,就会想起“硬件断点”的好处了。
老一辈的人常告诉我们,年轻的时候多吃点苦,这样老了才能习惯啊!
TIP: 本文的目的只有一个就是学习更多的逆向技巧和思路,如果有人利用本文技术去进行非法商业获取利益带来的法律责任都是操作者自己承担,和本文以及作者没关系,本文涉及到的代码项目可以去 奋飞的朋友们 知识星球自取,欢迎加入知识星球一起学习探讨技术。有问题可以加我wx: fenfei331 讨论下。
关注微信公众号: 奋飞安全,最新技术干货实时推送