代码还原的技术: Unidbg调试浮点数运算(一)

一、目标

在做代码还原的时候,经常能看到一些奇怪的寄存器和奇怪的指令:

vldr s15, [r1]
vadd.f32 s15, s14, s15

很像某些流量明星,看上去很眼熟,仔细看看又不认识。

它们就是传说中的浮点数运算,今天我们来点亮一个很有用的技能树: Unidbg调试浮点数运算

二、步骤

先写个floatdemo

有这么一个祖传的算法函数。

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;

    v = 2*p*value;
    s = p*value*value;

    rc = v+s;

    hello = std::to_string(rc);

    return env->NewStringUTF(hello.c_str());
}

算出圆的周长和面积,然后再把它们相加。

高级语言就是好,一目了然。

IDA一把

floatone.png

可以看出两个区别, 一个是寄存器不一样,普通运算使用的寄存器是R0-Rx,浮点数运算使用的是D0-Dx (其实还有 S0-Sx),另一个是指令不一样,普通运算是MOV、MUL,而浮点数运算使用的是VMOV,VMUL,感觉就是普通运算的VIP版。

第一个知识点就出来了,V开头的指令就是浮点数运算指令,Dx Sx Qx 就是浮点数寄存器

Unidbg亮相

按照 Unidbg模拟执行某段子so实操教程(一) 先把框架搭起来 这个框架把我们刚才编译的 floatdemo.apk 跑起来,然后增加一个 stringFromJNI 函数的调用。

private String callfun(String methodSign, Object ...args) {
        DvmObject mainactivity = MainActivity_dvmclass.newObject(null);
        Object value = mainactivity.callJniMethodObject(emulator,methodSign,args).getValue();
        return value.toString();
}

由于 stringFromJNI 不是静态(static)的类函数,所以我们需要先创建个一个 MainActivity 对象,才可以调用它的方法。

先跑一下看看结果

Find native function Java_com_fenfei_app_floatdemo_MainActivity_stringFromJNI(D)Ljava/lang/String; => RX@0x4000c6c9[libnative-lib.so]0xc6c9
JNIEnv->NewStringUTF("150.796320") was called from RX@0x4000c73d[libnative-lib.so]0xc73d
ret:150.796320
emulator destroy...

我们传了个参数6,半径是6的圆, 周长是 37.699, 面积是113.097 ,它们之和是 150.796。 结果没毛病,那我们开始调试了。

Unidbg调试

从刚才运行的结果里我们知道 stringFromJNI 函数的地址在 0xc6c9, 那么我们现在需要在这个地址下个断点,让调试器停在这个地址。

Unidbg的调试功能依然很强大,它支持三种调试模式 CONSOLE、GDB和IDA,目前我用的顺手的是 CONSOLE 模式,今天先介绍这个。

开启调试炒鸡简单,加上这两行代码就行

Debugger MyDbg = emulator.attach(DebuggerType.CONSOLE);
MyDbg.addBreakPoint(module.base + 0xc6c9);

运行一下,就顺利的进入到调试器命令行了,直接回车,会显示目前支持的调试命令。

debugone.png

我们是新手嘛,先掌握一个n和s两个命令就行了,n是单步步过,就是执行一条指令,步过函数调用;s是单步步入,就是执行一条指令,进入函数调用。

n命令跑几下来到我们要分析的浮点数运算的位置,发现尴尬了……

Unidbg调试器只显示了Rx寄存器,没有显示Dx系列的寄存器,这下怎么分析,不能盲摸呀?

打开Unidbg浮点数寄存器显示

Unidbg是支持浮点数运算模拟的,那么一定是有地方去读取浮点数寄存器的,只是没有显示出来而已。

我们先分析下Unidbg调试时寄存器显示部分的代码。

先搜索 r0= 在哪里处理的?

armjava.png

showRegs 就是显示寄存器, 当参数为null的时候,通过 ARM.getAllRegisters 来显示所有的寄存器。但是为啥没有显示浮点寄存器呢?奇怪。

我们再往下翻,发现在ARM64的模拟下显示了Q0-Q31寄存器,通过查阅资料,我们知道了原来它们都是一伙的。

d0.png

那ARM32先放一下,我们把模拟环境切换到ARM64

emulator = AndroidEmulatorBuilder.for64Bit().setProcessName("com.fenfei.runfloatdemo").build(); // 创建模拟器实例,要模拟32位或者64位,在这里区分

再跑一下,调试器没有激活?

这是为什么? 原来我们把模拟器从Arm32切换到了Arm64,那么载入的so就是64位的了,所以 stringFromJNI 函数的地址也变了,需要把断点下在新的地址 0x12738 上面。

qreg.png

这下不一样了,浮点寄存器都显示出来了。

优化一下浮点寄存器的显示

李老板: 奋飞呀,这个0x400921f9f01b866e是啥意思呀,你是不是搞错了,浮点数寄存器显示的咋不是 3.14159 ,而是这个乱七八糟的数据?

奋飞: 老板,程序员的母语就是16进制,没有一眼把 0x400921f9f01b866e 认出是 3.14159的,晚饭是不配加鸡腿的,也不配变秃的。

有理想的同学请自行搜索 IEEE754 二进制浮点数算术标准

其他的同学请和我一起优化下浮点寄存器的显示。

由于飞哥目前为止还没有变秃,确实也看不出来这玩意就是 3.14159, 只好另辟蹊径,给大家传授一个神奇的函数:

public static double bytes2Double(byte[] arr) {
    long value = 0;
    for (int i = 0; i < 8; i++) {
        value |= ((long) (arr[i] & 0xff)) << (8 * i);
    }
    return Double.longBitsToDouble(value);
}


// 在showRegs64函数里面加个显示
case Arm64Const.UC_ARM64_REG_Q0:
    byte[] data = backend.reg_read_vector(reg);

    double bOut = bytes2Double(data);

    if (data != null) {
        builder.append("\n>>>");
        builder.append(String.format(Locale.US, " q0=0x%s(%.3f)", newBigInteger(data).toString(16),bOut));
    }
    break;

科学研究表明:在没有变秃的前提下,我们依然有机会变强。

floatshow.png

其实C/C++ 有个神奇的玩意叫指针,这种显示一把梭就行

BYTE dPiByte[8] = {0x6e, 0x86, 0x1b, 0xf0, 0xf9, 0x21, 0x09, 0x40 };
double dPi = *(double*)dPiByte;

好了,后面的几步运算就是乘乘加加了,同学你自己n几下就ok了。

(此处应有掌声)

三、总结

为什么要去调试,直接F5大法不香吗?

现在Ollvm肆虐,掌握一些手撕汇编的良方可保你无忧。

为什么要用Unidbg去调试,IDA不香吗?

悟空,等你遇上内存防修改,无法下软件断点和一些BT的反调试的时候,你自会回来和为师唱这首歌的: Only You ......

预告一下,下一篇是开启Arm32下的浮点数寄存器显示和TraceCode

ffshow.jpeg

知道为何自古红颜多薄命吗?因为没人在意丑的人活多久。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,142评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,298评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,068评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,081评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,099评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,071评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,990评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,832评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,274评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,488评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,649评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,378评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,979评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,625评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,643评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,545评论 2 352

推荐阅读更多精彩内容