hopper反汇编工具的逆向伪代码功能并不理想
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反汇编工具的逆向伪代码功能并不理想的更多相关文章
- 反汇编工具 objdump的使用简介
arm-linux-objdump -D led.elf > led_elf.dis objdump是gcc工具链中的反汇编工具,作用是由编译链接好的elf格式的可执行程序反过来得到反汇编代码 ...
- 【转】iOS开发工具系列(按功能分)
http://www.cocoachina.com/newbie/basic/2014/0417/8187.html 这是我们多篇iOS开发工具系列篇中的一篇,此前的文章比如:那些不能错过的Xcode ...
- 安卓反汇编工具arm-eabi-objdump
安卓反汇编工具 在Arm平台系统自带的反编译工具在android/prebuild/linux-/toolchail/arm-abil-/bin目录下的arm_eabi-objdump进行反汇编 ar ...
- 痞子衡嵌入式:开启NXP-MCUBootUtility工具的HAB加密功能 - CST(中英双语)
1 Reason for enabling HAB encryption function 为什么要开启HAB加密功能 NXP-MCUBootUtility is a tool designed fo ...
- 痞子衡嵌入式:开启NXP-MCUBootUtility工具的HAB签名功能 - CST(中英双语)
1 Reason for enabling HAB signature function 为什么要开启HAB签名功能 NXP-MCUBootUtility is a tool designed for ...
- Python交互K线工具 K线核心功能+指标切换
Python交互K线工具 K线核心功能+指标切换 aiqtt团队量化研究,用vn.py回测和研究策略.基于vnpy开源代码,刚开始接触pyqt,开发界面还是很痛苦,找了很多案例参考,但并不能完全满足我 ...
- 微信小程序开发——开发者工具中素材管理功能使用的注意事项
为什么使用“素材管理”: 微信小程序环境中本地资源图片是无法通过 WXSS 获取的,可以使用网络图片,或者 base64,或者使用<image/>标签.. 当然,如果不想这么麻烦,你可能会 ...
- 学汇编的时候可以拿IDA之类的反汇编工具辅助学习,再用gdb或者IDA动态调试,跟踪每条指令的 执行结果。都不难
作者:潘安仁链接:https://www.zhihu.com/question/40720890/answer/87926792来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明 ...
- 自制反汇编工具使用实例 其二(使用xmm寄存器初始化对象,以及空的成员函数指针)
在反汇编代码中,当看到xmm寄存器,第一反应是将要进行浮点操作或访问,但是更加多的情况是在使用xmm寄存器初始化局部对象. 下面是自制反汇编工具翻译出来的代码: // -[CALayer setAll ...
随机推荐
- 【Java必修课】各种集合类的合并(数组、List、Set、Map)
1 介绍 集合类可谓是学习必知.编程必用.面试必会的,而且集合的操作十分重要:本文主要讲解如何合并集合类,如合并两个数组,合并两个List等.通过例子讲解几种不同的方法,有JDK原生的方法,还有使用第 ...
- 记录手动签名APK的过程
记录手动签名APK的过程 前两天更新了华为平台上的APK,被驳回,原因是新APK签名和老的APK不一致,老用户安装会失败,用命令行安装会报如下的错误: harlanc@harlancdeMacBook ...
- Azure EventHub快速入门和使用心得
Azure Event Hubs(事件中心)是一个大数据流式数据摄取服务平台,每秒接受数百万事件; EventHubs 是一个有数据保留期限的缓冲区,类似分布式日志:可缩放的关键在于[分区消费模型], ...
- 百万年薪python之路 -- 小数据池和代码块练习
1.请用代码验证 "alex" 是否在字典的值中? info = {'name':'王刚蛋','hobby':'铁锤','age':'18',...100个键值对} info = ...
- H5 + WebGL 实现的楼宇自控 3D 可视化监控
前言 智慧楼宇和人们的生活息息相关,楼宇智能化程度的提高,会极大程度的改善人们的生活品质,在当前工业互联网大背景下受到很大关注.目前智慧楼宇可视化监控的主要优点包括: 智慧化 -- 智慧楼宇是一个生态 ...
- Coremail接口存配置读取漏洞POC
Coremail产品诞生于1999年,经过二十多年发展,如今从亿万级别的运营系统,到几万人的大型企业,都有了Coremail的客户. 截止2019年,Coremail邮件系统产品在国内已拥有10亿终端 ...
- Python 图形验证码库、二维码库的使用
1. 图形验证码库 captcha # 引入图形库 from captcha.image import ImageCaptcha # 获取图像对象 image = ImageCaptcha(width ...
- Java 中文数字转换为阿拉伯数字
贴出代码,方便学习交流,稍后放出镜像问题的代码 package com.thunisoft.cail.utils; import com.sun.istack.internal.NotNull; im ...
- [系列] Go gRPC 调试工具
目录 概述 写一个 gRPC API grpcui 使用 go-gin-api 系列文章 概述 最近这段时间工作挺忙的,发现已经 3 周没更文了... 感谢你们还在,今天给大家分享一款 gRPC 的调 ...
- .NET进阶篇06-async异步、thread多线程1
知识需要不断积累.总结和沉淀,思考和写作是成长的催化剂 异步多线程挺大一块内容,既想拆开慢慢学,又想一股脑全倒出.纠结再三,还是拆开吃透,也不至于篇幅过长,劝退许多人 本篇先做一个概述,列明一些基本概 ...