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. Django 官方推荐的姿势:类视图

    作者:HelloGitHub-追梦人物 文中所涉及的示例代码,已同步更新到 HelloGitHub-Team 仓库 在开发网站的过程中,有一些视图函数虽然处理的对象不同,但是其大致的代码逻辑是一样的. ...

  2. SSH框架项目配置和启动的加载顺序及请求的执行顺序

    1:======配置和启动====== (1)配置web.xml 配置<context-param>,其中内容为Spring的配置文件applicationContext.xml.注意&l ...

  3. javascript学习总结之对象的深拷贝和浅拷贝

    前言 最近在写ES6的文章的时候发现重复遇到关于javascript深拷贝和浅拷贝的问题,然后查找了一些资料,根据资料和自己的理解做了以下笔记,毕竟javascript关于深拷贝和浅拷贝的问题在一些面 ...

  4. MySQL 分页查询优化——延迟关联优化

    目录 1.   InnoDB表的索引的几个概念 2.   覆盖索引和回表 3.   分页查询 4.   延迟关联优化 写在前面 下面的介绍均是在选用MySQL数据库和Innodb引擎的基础开展.我们先 ...

  5. 基于 HTML5 + WebGL 的 3D 可视化挖掘机

    前言 在工业互联网以及物联网的影响下,人们对于机械的管理,机械的可视化,机械的操作可视化提出了更高的要求.如何在一个系统中完整的显示机械的运行情况,机械的运行轨迹,或者机械的机械动作显得尤为的重要,因 ...

  6. 解决html连续字符或数字换行的问题

    word-break: break-all; word-wrap:break-word; 强制换行

  7. 【Bug】解决 SpringBoot Artifact contains illegal characters 错误

    解决 SpringBoot  Artifact contains illegal characters错误 错误原因:Artifact包含非法字符(大写字母) 解决方法:将Artifact名称改成小写 ...

  8. EFCore--->> CodeFirst (Vs2019 Core3.0)的简单使用

    直接上干货 EFCore--->> CodeFirst (Vs2019 Core3.0) 1: 安装下面3个对应的package(在Nuget控制台或者直接NuGet包查询点击下载,我喜欢 ...

  9. SQlserver高效分页,还在使用row_number(),top之类的?

    row_number() ,还是top 这些分页的方法比较老了,效率不是很高效的, Sqlserve2012就有了,效率对比比较明显,尤其是数据比较大的情况下(我们可以观看查询执行计划) Offset ...

  10. day3-02 python入门之基本的数据类型

    目录 一.整型(int) 二.浮点型(float) 三.字符串类型(str) 字符串在python2和python3中的细微区别 四.复数 五.列表(list) 六.数据字典(dict) 定义方式 七 ...