热门标签 | HotTags
当前位置:  开发笔记 > 后端 > 正文

iosBlock参数和返回值类型获取

原博客:http:www.swiftyper.com20161216debuging-objective-c-blocks-in-lldb注:本篇文章都是在64位系统下进行分析,如

原博客:http://www.swiftyper.com/2016/12/16/debuging-objective-c-blocks-in-lldb/

注:本篇文章都是在 64 位系统下进行分析,如果是 32 位系统,整型与指针类型的大小都是与 64 位不一致的,请自行进行修改。

Block 的内存结构

在 LLVM 文档中,可以看到 Block 的实现规范,其中最关键的地方是对于 Block 内存结构的定义:

struct Block_literal_1 {
void *isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock
int flags;
int reserved;
void (*invoke)(void *, ...);
struct Block_descriptor_1 {
unsigned
long int reserved; // NULL
unsigned long int size; // sizeof(struct Block_literal_1)
// optional helper functions
void (*copy_helper)(void *dst, void *src); // IFF (1<<25)
void (*dispose_helper)(void *src); // IFF (1<<25)
// required ABI.2010.3.16
const char *signature; // IFF (1<<30)
} *descriptor;
// imported variables
};

可以看到第一个成员是 isa,说明了 Block 在 Objective-C 当中也是一个对象。我们重点要关注的就是 void (*invode)(void *, ...); 和 descriptor 中的 const char *signature,前者指向了 Block 具体实现的地址,后者是表示 Block 函数签名的字符串。

 

 通过分析界面以及 class-dump 出来头文件就能分析出某个函数的参数为block类型,主要对block中返回值和入参进行分析,方便后期的hook,例:

- (void)requestCorpse:(CDUnknownBlockType)arg1;

   

 通过hook 该函数debug可以看到block函数的具体地址

 

在 64 位系统上,指针类型的大小是 8 个字节,而 int 是 4 个字节,long int 8个字节

因此,invoke 函数指针的地址就是在第 16 个字节之后。我们可以通过 lldb 的 memory 命令来打印出指定地址的内存,我们上面已经得到了 block 的地址,现在就打印出它的内存内容:

(lldb) memory read --size 8 --format x 0x16db93bb8
0x16db93bb8: 0x00000001f81c4870 0x00000000c0000000
0x16db93bc8: 0x000000010497cc34 0x0000000109f49750
0x16db93bd8: 0x4277c7d786884399 0x0000000000000000
0x16db93be8: 0x40ea4cd7c8a9a6a0 0x0000000281eecc60

如前所述,函数指针的地址是在第 16 个字节之后,并占用 8 个字节,所以可以得到函数的地址是0x000000010497cc34

void *isa; 指针8个字节:0x00000001f81c4870
int flags; int reserved; int4个字节,2个int8个:0x00000000c0000000
(
*invoke)(void *, ...); 指针8个所以该地址:0x000000010497cc34
struct Block_descriptor_1{...}*descriptor 0x0000000109f49750

 


找出 Block 的函数签名

         要找出 Block 的函数签名,需要通过 descriptor 结构体中的 signature 成员,然后通过它得到一个 NSMethodSignature 对象。

首先,需要找到 descriptor 结构体。这个结构体在 Block 中是通过指针持有的,它的位置正好在 invoke 成员后面,占用 8 个字节。可以从上面的内存打印中看到 descriptor 指针的地址是 0x0000000109f49750

找到地址,并打印出它的字符串内容:       ios中第9位大部分时候为1,第8位为0,其他的容易超出内存

(lldb) memory read --size 8 --format x 0x0000000109f49750
0x109f49750: 0x0000000000000000 0x0000000000000028
0x109f49760: 0x000000010ce7a034 0x000000010d9cad29
0x109f49770: 0x00000001f81c49b0 0x0000000050000000
0x109f49780: 0x00000001022d1498 0x0000000109eee450
(lldb) p (
char *)0x000000010ce7a034 //一般来说为第二行第一个,或第三行第一个,具体可看下文扩展知识
(
char *) $2 = 0x000000010ce7a034 "v16@?0@\"NSDictionary\"8"

拿到函数签名后,只是我们需要通过 NSMethodSignature 找出它的参数和返回类型:

(lldb) po [NSMethodSignature signatureWithObjCTypes:"v16@?0@\"NSDictionary\"8"]
0x8ce27f0dea645e47>
number of arguments
= 2
frame size
= 224
is special struct return? NO
return value: -------- -------- -------- --------
type encoding (v)
'v'
flags {}
modifiers {}
frame {offset
= 0, offset adjust = 0, size = 0, size adjust = 0}
memory {offset
= 0, size = 0}
argument
0: -------- -------- -------- --------
type encoding (@)
'@?'
flags {isObject, isBlock}
modifiers {}
frame {offset
= 0, offset adjust = 0, size = 8, size adjust = 0}
memory {offset
= 0, size = 8}
argument
1: -------- -------- -------- --------
type encoding (@)
'@"NSDictionary"'
flags {isObject}
modifiers {}
frame {offset
= 8, offset adjust = 0, size = 8, size adjust = 0}
memory {offset
= 0, size = 8}
class 'NSDictionary'

注意,字符串中的双引号需要对其进行转义。


 对我们最有用的 type encoding 字段,这些符号对应的解释可以参考 Type Encoding 官方文档。

 

所以,总结来讲就是:这个方法没有返回值 void类型,它接受2个参数,第一个是 block (即我们自己的 block 的引用)"@?" 代表本身所以hook中不需要写,第二个是一个 NSDictionary 对象。

callBack:(void (^)(NSDictionary *)arg1;

 

本文章仅供学习参考,如有版权侵犯,请联系作者修改,转载请注明出处!



推荐阅读
  • 本文探讨了在iOS平台上开发BLE(蓝牙低功耗)应用程序时遇到的挑战,特别是如何实现应用在后台模式下仍能持续扫描并连接蓝牙设备。文章提供了具体的配置方法和常见的问题解决方案。 ... [详细]
  • 在使用 iOS 应用时,遇到网络请求错误是常见的问题。本文将探讨两种常见的错误代码 -1003 和 -1001,并提供详细的解释和解决方案。 ... [详细]
  • iOS 开发技巧:TabBarController 自定义与本地通知设置
    本文介绍了如何在 iOS 中自定义 TabBarController 的背景颜色和选中项的颜色,以及如何使用本地通知设置应用程序图标上的提醒个数。通过这些技巧,可以提升应用的用户体验。 ... [详细]
  • 本文介绍了如何在Swift 3.0中实现对设备识别码(DeviceNo)和用户账号ID(AccountId)的获取及存储。通过使用系统提供的UserDefaults服务,我们能够有效地管理这些关键数据,确保应用在不同场景下的稳定性和用户体验。 ... [详细]
  • 在Swift项目中集成Objective-C类或第三方框架的方法
    本文通过实例讲解如何在Swift项目中引入并使用Objective-C编写的ProgressHUD库。首先需要在项目中添加库文件,并设置Objective-C桥接头文件以实现语言间的互操作性。 ... [详细]
  • 作为一名在大型手机游戏公司工作的程序员,尽管主要负责游戏逻辑和内容的开发,但对iOS底层开发接触较少。现在有了iPhone和可以虚拟MAC环境的电脑,希望能找到有效的iOS开发学习路径。 ... [详细]
  • iOS 10 系统下 AVPlayer 视频播放故障排除
    在使用 iOS 10 系统时,如果遇到 AVPlayer 无法正常播放视频的问题,这可能是由于 Xcode 中异常处理设置不当导致的。本文将详细探讨如何调整 Xcode 设置以解决这一问题。 ... [详细]
  • 本文介绍了iOS应用开发的主要框架,包括Foundation、UIKit、CoreData及CoreGraphics等,并探讨了开发iOS应用所需的硬件和软件环境,以及推荐的编程语言。 ... [详细]
  • 本文基于前文的内容,进一步探讨如何在 iOS 应用中高效地实现高斯模糊背景效果。我们将通过具体代码示例,展示如何利用 Swift 和 UIKit 创建具有毛玻璃效果的界面背景。 ... [详细]
  • 本文旨在探讨Swift中的Closure与Objective-C中的Block之间的区别与联系,通过定义、使用方式以及外部变量捕获等方面的比较,帮助开发者更好地理解这两种机制的特点及应用场景。 ... [详细]
  • 本文详细介绍了Git分布式版本控制系统中远程仓库的概念和操作方法。通过具体案例,帮助读者更好地理解和掌握如何高效管理代码库。 ... [详细]
  • 本文将带领读者深入了解Android系统源码在手机中的实际表现,通过详细的步骤和专业的解释,帮助你更好地理解Android系统的底层运作机制。 ... [详细]
  • 本文探讨了在iOS应用中实现类似Android Snack Bar功能的方法,并特别关注如何确保Snack Bar正确显示在键盘下方。 ... [详细]
  • 实现‘点击恢复’功能 - Tap-to-Resume Feature in SpriteKit
    了解如何在应用程序从非活动状态返回时,在SpriteKit游戏中添加一个‘点击恢复’的文字提示。 ... [详细]
  • 在现代移动应用开发中,尤其是iOS应用,处理来自服务器的JSON数据是一项基本技能。无论是使用Swift还是PHP,有效地解析和利用JSON数据对于提升用户体验至关重要。本文将探讨如何在Swift中优雅地处理JSON,以及PHP中处理JSON的一些技巧。 ... [详细]
author-avatar
菜蕻的薇笑2602929033
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有