hopper的逆向代码功能并不如想象中那么好,尤其是在逆向c++代码时。对于从ObjC进入iOS开发又不太清楚运行时的人员来说,hopper可以将反汇编码输出成[obj selector:what]这样的ObjC式的函数调用,一定会很惊叹。其实ObjC式函数调用的关键就是枢纽函数的msg_send(c style)以及枢纽机制(ObjC对象消息机制)中的分派机制(消息分派)的消息@selector。msg_send是c风格的函数,只要参照其传参设定(前面文章以经介绍过,《gcc在x64体系中如何传递参数,linux,mac,iOS适用》)。对象消息@selector是一个SEL类型,其定义是const char* const, 而且在映像的数据段必须有对应的字符串。这样一来,只要有这个SEL消息的字符串,就可以写一个类似格式转换输出的脚本。的确,用hopper来逆向ObjC的函数可以大大简化反汇编码的阅读(调用了哪些函数这一点上),例如一个ObjC式的函数调用,都那么重复那些步骤而且是许多步,一屏也看不了几个调用。

但c++的情况就不一样。下面我选了一个函数,因为hopper的简单分析失效了。

我选用的是cocoa的iOS模拟器x64版本里的QuartzCore.framework的一个函数,CA::Layer::set_bit。下面是hopper的逆向伪代码:

就这样一瞥,效果很不错,但是却是错误的。

首先是传参的解析,这个一错,就是开始错了,后面就大错。这比直接去分析反汇编码还冤枉。
其次是没有办法分辨静态成员函数还是成员函数。
第三就是不清楚成员函数指针的调用。

下面是我对hopper加的批注:

先是逆向伪代码:

再是反汇编代码:

<20161002 补充>

hopper将rdi至r8五个寄存器往函数原型的五个参数上硬套。

实际上CA::Layer::set_bit是一个成员函数,rdi是对象指针,rsi才是函数原型的第一个参数,一共使用了4个寄存数作为传参,最后一个参数是一个函数指针,没有使用r9,而是使用了堆栈两个cpu字长的长度作为最后一个参数。

</20161002>

现在开始逐一分析。
首先hopper无视了this指针这个参数。为什么ObjC的函数它又可以解析出this,严格来说self不是this指针,它是llvm编译器约定在c风格的函数msg_send定义的第一个参数,以及msg_send_stret定义的第二个参数,也就是说ObjC的函数调用实质是一个c风格的函数调用。而c++的成员函数调用又有另外的约定,所以hopper失效了。
hopper以c风格函数的传参约定套用在成员函数CA::Layer::set_bit定义的参数序列,这是错误的开端。可以参看反汇编码,寄存器%rsi是传送到了-0x40(%rbp)的内存单元中,而这个%rsi才是c++成员函数的第一个参数,而对应于hopper逆向代码的arg0。然而hopper错误套用约定,hopper看到的参数向左shift了一个身位,所以它将%rsi看成了成员函数的第二个参数,var_40=arg1。
所以hopper正确的逆向应该从这样开始:

int CA::Layer::set_bit(uint32_t arg1, uint32_t arg2, uint32_t arg3, bool arg4, void(*arg5)(*)) {
assert(this == arg0);
var_40 = arg1;

这样它逆向输出的代码才有可能不误导人。
你看出了不同了吗,我再补一下hopper的错误生成作对比

int CA::Layer::set_bit(uint32_t arg0, uint32_t arg1, uint32_t arg2, bool arg3, void(*arg4)(*)) {
var_40 = arg1;

这在实际开发和调试中,都足以冤枉大量工作时间。

通过调整,hopper失效的问题就是解决了吗?
没有,hopper逆向还是失效了。错误就在对成员函数指针的解析。逆向的样本CA::Layer::set_bit最后一个参数是一个成员函数指针,用于回调用的。但在hopper的逆向代码中,这个参数并没有被使用过,因为hopper失灵了。
或许在msvc平台下,hopper将成员函数指针看作是void*可能会擦边正确,但是在*nix和bsd体系的平台上就不一定。因为*nix和bsd是由GNU_C标准的编译器编译的,也就是GNU_C中成员函数指针的规则并非一个单纯的函数入口地址,前面的文章我也有介绍过。我们来回看反汇编码,这个样本函数并没有使用r9来传递arg5,然而却使用了两个堆栈单元来传参,这样一来参数个数就多出来了。如果这时你还不清楚GNU_C编译器下的成员函数指针是什么一回事,就比较难以解释这个函数了。详细请参看我前面的文章,《反汇编带看清成员函数指针的本尊(gcc@x64平台)》。这里的两个堆栈单元其实就是最后一个参数(成员函数指针),而且不是一个单纯的地址指针,而是一个sizeof(void*)*2大小的对象。没错成员函数指针是一个对象。在使用var_50和var_58的地方,其实就是在回调这个成员函数指针的引用。
但是hopper的逆向还是错了(rcx)(rdi),hopper将成员函数指针当作普通函数指针来解释了。清楚的人都明白,rdi就不是成员函数定义输入参数,修正后应该是rdi->(rcx)(var_38)。

还有就是hopper并没有正确分析出这个样本函数的返回类型,用了一个int来充当。其实从返回部分的反汇编码可以看到,并没有对rax作是任何操作,也就是说返回void。

第二个问题和上面的问题一样,但反应在逆向代码体中对其它成员函数的调用。CA::Transaction::lock()这个并非静态成员函数,必须要有一个调用的对象,然而是hopper没有明确生成关于调用对象的指向。
r12 = CA::Transaction::ensure_compat();
CA::Transaction::lock();
应该为:
rdi = r12 = CA::Transaction::ensure_compat();
((CA::Transaction*)r12)->lock();

第三个问题,不清楚成员函数指针的调用,这一点在第一个问题谈及成员函数指针参数时讲了。

最后我贴上我逆向出来的代码:

hopper反汇编工具的逆向伪代码功能并不理想的更多相关文章

  1. 反汇编工具 objdump的使用简介

    arm-linux-objdump -D led.elf > led_elf.dis objdump是gcc工具链中的反汇编工具,作用是由编译链接好的elf格式的可执行程序反过来得到反汇编代码 ...

  2. 【转】iOS开发工具系列(按功能分)

    http://www.cocoachina.com/newbie/basic/2014/0417/8187.html 这是我们多篇iOS开发工具系列篇中的一篇,此前的文章比如:那些不能错过的Xcode ...

  3. 安卓反汇编工具arm-eabi-objdump

    安卓反汇编工具 在Arm平台系统自带的反编译工具在android/prebuild/linux-/toolchail/arm-abil-/bin目录下的arm_eabi-objdump进行反汇编 ar ...

  4. 痞子衡嵌入式:开启NXP-MCUBootUtility工具的HAB加密功能 - CST(中英双语)

    1 Reason for enabling HAB encryption function 为什么要开启HAB加密功能 NXP-MCUBootUtility is a tool designed fo ...

  5. 痞子衡嵌入式:开启NXP-MCUBootUtility工具的HAB签名功能 - CST(中英双语)

    1 Reason for enabling HAB signature function 为什么要开启HAB签名功能 NXP-MCUBootUtility is a tool designed for ...

  6. Python交互K线工具 K线核心功能+指标切换

    Python交互K线工具 K线核心功能+指标切换 aiqtt团队量化研究,用vn.py回测和研究策略.基于vnpy开源代码,刚开始接触pyqt,开发界面还是很痛苦,找了很多案例参考,但并不能完全满足我 ...

  7. 微信小程序开发——开发者工具中素材管理功能使用的注意事项

    为什么使用“素材管理”: 微信小程序环境中本地资源图片是无法通过 WXSS 获取的,可以使用网络图片,或者 base64,或者使用<image/>标签.. 当然,如果不想这么麻烦,你可能会 ...

  8. 学汇编的时候可以拿IDA之类的反汇编工具辅助学习,再用gdb或者IDA动态调试,跟踪每条指令的 执行结果。都不难

    作者:潘安仁链接:https://www.zhihu.com/question/40720890/answer/87926792来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明 ...

  9. 自制反汇编工具使用实例 其二(使用xmm寄存器初始化对象,以及空的成员函数指针)

    在反汇编代码中,当看到xmm寄存器,第一反应是将要进行浮点操作或访问,但是更加多的情况是在使用xmm寄存器初始化局部对象. 下面是自制反汇编工具翻译出来的代码: // -[CALayer setAll ...

随机推荐

  1. Bootstrap Studio Mac网页设计神器

    Bootstrap Studio Mac网页设计神器 美丽的组件 Bootstrap Studio附带了大量漂亮的组件,用于构建响应式页面.我们有页眉,页脚,画廊,幻灯片甚至基本元素,如跨度和div. ...

  2. ESP8266开发之旅 网络篇② ESP8266 工作模式与ESP8266WiFi库

        在网络篇①中,博主主要讲解了Arduino上开发ESP8266的插件库 Arduino Core For ESP8266.但是,并没有讲到关于这个模块的工作模式,所以本篇讲着重讲解ESP826 ...

  3. 使PC端网页宽度自适应手机屏幕大小

    有时候我们会纠结PC页面在手机页面上无法正常显示,超出屏幕,有些内容看不到,现在又了下面的代码,可以做到自适应手机端的屏幕宽度: 在html的<head>中增加一个meta标签: < ...

  4. ThreadPoolExecutor源码中的适配器模式

    什么是适配器模式 网上已有很多的教程,不细讲了.可以参考:五分钟了解设计模式(3)---适配器模式 在适配器模式中,一定要识别清楚,Target Adaptee Adapter分别是哪些类或接口,这样 ...

  5. Mycat分布式数据库架构解决方案--配置defaultAccount属性报错解决方案

    echo编辑整理,欢迎转载,转载请声明文章来源.欢迎添加echo微信(微信号:t2421499075)交流学习. 百战不败,依不自称常胜,百败不颓,依能奋力前行.--这才是真正的堪称强大!!! 该文章 ...

  6. vue项目如何在node启动

    首先将vue项目通过命令npm run build 打包,然后创建start.js,代码如下: // const userApi = require('./api'); const fs = requ ...

  7. TICK技术栈(三)InfluxDB安装及使用

    1.什么是InfluxDB? InfluxDB是一个用Go语言开发的时序数据库,用于处理高写入和查询负载,专门为带时间戳的数据编写,对DevOps监控,IoT监控和实时分析等应用场景非常有用.通过自定 ...

  8. 用初中数学知识撸一个canvas环形进度条

    周末好,今天给大家带来一款接地气的环形进度条组件vue-awesome-progress.近日被设计小姐姐要求实现这么一个环形进度条效果,大体由四部分组成,分别是底色圆环,进度弧,环内文字,进度圆点. ...

  9. mysql设计规范一

    原文地址:http://www.jianshu.com/p/33b7b6e0a396 主键 表中每一行都应该有可以唯一标识自己的一列(或一组列). 一个顾客可以使用顾客编号列,而订单可以使用订单ID, ...

  10. CSPS模拟 57

    rank4大众rank T1 天空龙 让他自由翱翔吧 T2 巨神兵 对于n=10的测试点本可以打出非常优秀的分层状压 但是没有打出来,因为对拓扑图理解不够深刻,纠结于指回的边,实际上只关注伸出的边就可 ...