xcode反汇编调试iOS模拟器程序(五)调试objc_msgSend函数_hursing的博客-程序员资料

技术标签: xcode反汇编调试iOS模拟器程序  调试  反汇编  iOS模拟器程序  xcode  objc_msgSend  

反汇编调试objective-c,遇到最多的就是objc_msgSend这函数了,本节主要讲讲它的实现以及调试过程的一些技巧。

以UIWebView为例子,看看它在loadRequest时做了什么。

首先必须明白,原始代码中调用

[uiWebViewInstance loadRequest:request]
的实质是调用了
objc_msgSend(uiWebViewInstance, "loadRequest:"的selector, request)

编写一个用到UIWebView的demo,主要功能是打开一个网页。

在main函数加断点,触发后,在命令行输入:

b -[UIWebView loadRequest:]
然后continue,直到触发断点,如下图:


用step over跑到第17行,或直接在那加个断点continue到那。旁边的注释已经显示,call的是存储了objc_msgSend这个函数的偏移地址的代码位置。

17行的前三行,可以看出其动作是往栈上传参数,这三个参数原本是放在edx,ecx,eax的,所以如果参数不多,也可以不用esp为基址来查参数。

在当前的命令行输入

register read
来查看各寄存器的值。lldb会把当前值的意义也输出来。但gdb不会,gdb对应的命令是
info registers

结果如下图:


从ecx的内容可以看出,要call的selector的名字同样是loadRequest:,后面会验证。

接着,step into,可以看到:

那里只有一个跳转命令,继续step into,跳到objc_msgSend真正的地址,看到下图所示的代码:


简单点说,这些代码做了这些事:

1. 先判断传来的对象是否nil,是的话,把返回值(esp+4)置0就返回了,不是就进行下一步。即使是void型的函数,也是被当做有返回值的,只是没用。

2. 查找这个method有没有被cache,有就jmpl到cache了的IMP地址;没有就以selector代表的字符串从这个类的method list里找出method来(第13到20行的循环),cache后再jmpl。如果找不到method就抛出异常然后程序崩溃了。

一个小技巧是,如果想省去点好多次step over来跳过查找的步骤,可以在两个jmpl *%eax的地方加断点,然后run到那里(图中的第31行和38行)。如果传来的对象不是nil,最后都会到这来。此时eax里保存的是函数的地址,即objective-c运行时库定义的IMP(指向函数的指针),jump过去就能到目标函数里了。

另外,在调试反汇编时,step over和step into不要用快捷键,要用调试工具栏上的按钮。不知道为什么按快捷键都等于run了……

接着,在jmpl处step into,就到真实的函数了:


证实了刚才ecx是传了selector名字。


在lldb中搜索

image lookup -r -s objc_msgSend
可以看到:
13 symbols match the regular expression 'objc_msgSend' in /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator6.1.sdk/usr/lib/libobjc.A.dylib:
        Address: libobjc.A.dylib[0x0001708c] (libobjc.A.dylib.__TEXT.__text + 90252)
        Summary: libobjc.A.dylib`objc_msgSend        Address: libobjc.A.dylib[0x00017104] (libobjc.A.dylib.__TEXT.__text + 90372)
        Summary: libobjc.A.dylib`objc_msgSendSuper        Address: libobjc.A.dylib[0x0001716c] (libobjc.A.dylib.__TEXT.__text + 90476)
        Summary: libobjc.A.dylib`objc_msgSendSuper2        Address: libobjc.A.dylib[0x00017468] (libobjc.A.dylib.__TEXT.__text + 91240)
        Summary: libobjc.A.dylib`objc_msgSendSuper2_debug        Address: libobjc.A.dylib[0x00017338] (libobjc.A.dylib.__TEXT.__text + 90936)
        Summary: libobjc.A.dylib`objc_msgSendSuper2_stret        Address: libobjc.A.dylib[0x00017478] (libobjc.A.dylib.__TEXT.__text + 91256)
        Summary: libobjc.A.dylib`objc_msgSendSuper2_stret_debug        Address: libobjc.A.dylib[0x000172c8] (libobjc.A.dylib.__TEXT.__text + 90824)
        Summary: libobjc.A.dylib`objc_msgSendSuper_stret        Address: libobjc.A.dylib[0x00017460] (libobjc.A.dylib.__TEXT.__text + 91232)
        Summary: libobjc.A.dylib`objc_msgSend_debug        Address: libobjc.A.dylib[0x000171dc] (libobjc.A.dylib.__TEXT.__text + 90588)
        Summary: libobjc.A.dylib`objc_msgSend_fpret        Address: libobjc.A.dylib[0x00017480] (libobjc.A.dylib.__TEXT.__text + 91264)
        Summary: libobjc.A.dylib`objc_msgSend_fpret_debug        Address: libobjc.A.dylib[0x00017488] (libobjc.A.dylib.__TEXT.__text + 91272)
        Summary: libobjc.A.dylib`objc_msgSend_noarg        Address: libobjc.A.dylib[0x00017254] (libobjc.A.dylib.__TEXT.__text + 90708)
        Summary: libobjc.A.dylib`objc_msgSend_stret        Address: libobjc.A.dylib[0x00017470] (libobjc.A.dylib.__TEXT.__text + 91248)
        Summary: libobjc.A.dylib`objc_msgSend_stret_debug
objc_msgSend会有好多个版本:

objc_msgSend是普通调用,返回值为void、id、指针、int等32bit能表示的数据的objective-c函数会用到它。

objc_msgSend_stret在返回值为结构体时用到,stret表示structure return。值得一提的是,C++类也算是结构体哦。

objc_msgSend_fpret在返回值为浮点数时用到,fpret表示floating point return

带Super的表示调用父类的函数。


如上节所说,在obj_msgSend的第一行加自动断点 p (char*)*(SEL*)($esp+8) 就会打印多到你不想看的selector名字。注意这个地方不能去po对象,因为po的实质是调用对象的description,这个会再调用obj_msgSend,无限递归就挂了。


转载请注明出处:http://blog.csdn.net/hursing

xcode反汇编调试iOS模拟器程序
(一)查看反汇编
(二)看懂反汇编
(三)查看Objective-C函数与参数
(四)自动断点应用之NSNotificationCenter
(五)调试objc_msgSend函数
(六)函数出入口处的处理与局部变量
(七)Debug与Release的区别

(八)反汇编自己的代码来掌握规则

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/hursing/article/details/8755491

智能推荐

第3章 AI技术在RPA中的应用_Sunshine_ysc的博客-程序员资料

企业在梳理如何实现业务流程自动化的过程中,面临着很多挑战,其中之一便是RPA仅能够处理规则明确的、高重复性的流程,这让流程自动化很受限。随着人工智能技术的快速发展,如何将其合理有效地与RPA相结合,从而完成更多、更复杂、更智能的业务流程,是现阶段商业应用探索的主要方向,也是本章中我们将要共同探讨的核心问题。...

很多人都不知道外包公司居然有两种,真的要去该怎么选择?_外包公司分为哪几种_程序员徐小白的博客-程序员资料

前言经常会听说,程序员进外包毁一生,程序员进入外包就会被鄙视。。。这些彷佛说的外包公司十分的差劲,一旦有程序员去了外包公司就不得翻身了所以我结合我的亲身经历和对外包的认识,给出我的一些见解,希望对大家有帮助。什么是外包公司想要知道该不该去外包,不得先知道什么是外包吗?外包公司分为两种,一种承包人力的,另一种是承包项目的。承包人力的公司就是那种A公司跟你签合同,A公司给你发工资,但是你是去B公司上班的,你不属于B公司的员工,可能工牌都不一样,如果B公司没活干了。你就会被派到其他公司去干活。

使用天乐软件加密狗(JDProtect)保护您的软件,防止程序被跟踪/逆向/反编译/破解_maikforever的博客-程序员资料

作者:庄晓立(liigo)日期:2011-4-8原创链接:http://blog.csdn.net/liigo/archive/2011/04/08/6310677.aspx转换请注明出处:http://blog.csdn.net/liigo   天乐软件加密狗(JDProtect),貌似几年前的软件,也很久没人更新了,这个暂且不管。本文并非推荐软件,而是介绍软件用法。本人(l

ruby安装报错ERROR: While executing gem ... (Gem::Exception) Unable to require openssl......................_weixin_30655219的博客-程序员资料

今天在centOS7上安装ruby3.2.0时,gem install redis 出现ERROR: While executing gem ... (Gem::Exception) Unable to require openssl....................试了网上很多的方法还是出现了这个问题。最后索性删除了本来的ruby,重新安装后就可以了。正确的安装步骤是先安装开发...

分布式系统概念_alenlyx_Alenlyx的博客-程序员资料

一 分布式系统分布式系统的由来:国内来讲,移动互联网的爆发伴随着分布式系统的突现,移动互联网最大的特点是2(to)c的o2o产品越来越多,这跟传统2B的系统最大区别就是用户量的不同,2C系统的用户量远远要高于2b系统,这就对系统提出了各种各样的高标准,响应时间,性能,灾备,吞吐量等等,各种分布式技术也是为了这些标准而服务。分布式架构的应用:分布式文件系统分布式缓存系统分布式数据库分布...

javap查看java字节码_csdn_dengyu的博客-程序员资料

javap是JDK自带的反汇编器,可以查看java编译器为我们生成的字节码。通过它,我们可以对照源代码和字节码,从而了解很多编译器内部的工作。 语法:   javap [ 命令选项 ] class…   javap 命令用于解析类文件。其输出取决于所用的选项。若没有使用选项,javap 将输出传递给它的类的 public 域及方法。javap 将其输出到标准输出设备上。 命令选项   -...

随便推点

[PCL]点云渐进形态学滤波_weixin_34307464的博客-程序员资料

PCL支持点云的形态学滤波,四种操作:侵蚀、膨胀、开(先侵蚀后膨胀)、闭(先膨胀后侵蚀)关于渐进的策略,在初始cell_size_ 的基础上逐渐变大。满足如下公式:$$window\_size =cell\_size *(2*base^{k}+1)$$$$window\_size =cell\_size *(2*base*(k+1)+1)$$ 1 // Compute the ...

Python 字符编码及其文件操作_weixin_33842328的博客-程序员资料

本章节内容导航:1.字符编码:人识别的语言与机器机器识别的语言转化的媒介。2.字符与字节:字符占多少个字节,字符串转化3.文件操作:操作硬盘中的一块区域:读写操作注:浅拷贝与深拷贝用法:1 dic={'name':'zhaokang','age':18,'aa':[12,13,14]}2 l.copy()浅拷贝:会重新开辟内存地址去存储值的内存地址,但值得内...

百度新站提交助手_dlm92376的博客-程序员资料

如果是你批量上站的话,可以用这个提交助手批量提交,等待百度收录,但不建议多次重复提交。转载于:https://www.cnblogs.com/renzhe/archive/2013/06/02/3113592.html...

宝塔面板搭建密码管理bitwarden_宝塔反代 bitwarden不显示_vv1025的博客-程序员资料

宝塔面板搭建密码管理bitwardenBitwarden 是一款开源密码管理器,它会将所有密码加密存储在服务器上,它的工作方式与 LastPass、1Password 或 Dashlane 相同。官方的版本搭建对服务器要求很高,搭建不容易,github上有人用 Rust 实现了 Bitwarden 服务器,项目叫 bitwarden_rs,并且提供了 Docker 镜像,这个实现更进一步降低了对机器配置的要求,并且 Docker 镜像体积很小,部署非常方便。此外,官方服务器中需要付费订阅的一些功能,

Timer & TimerTask 源码分析_Young.Chen的博客-程序员资料

承接上一篇,看一看 Timer 和 TimerTask 内部的实现。之前说了我自己极少使用这个,目前在 Java 开发中使用 Timer 应该也非常少见了,既然是这样一个夕阳组件,为什么还要写个源码分析呢?主要是由于这部分的实现非常有借鉴意义,如果你工作中需要开发一个自动化流程,让它每一步都能定时执行,那么其实现方式和 Timer、TimerTask 的内部实现其实大同小异,都是维护一个 Task...

javascript时间戳和日期字符串相互转换_风神修罗使的博客-程序员资料

<html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <script type="text/javascript"> // 获取当前时间戳(以s为单位) var timesta

推荐文章

热门文章

相关标签