背景

在前面的文章中,笔者有讲解如何设置以及获取一个section的数据,demo如下:

#import <Foundation/Foundation.h>
#import <dlfcn.h>
#include <mach-o/loader.h>
#include <mach-o/getsect.h>#ifndef __LP64__
#define mach_header mach_header
#else
#define mach_header mach_header_64
#endifconst struct mach_header *machHeader = NULL;
static NSString *configuration = @"";
//设置"__DATA,__customSection"的数据为kyson
char *kString __attribute__((section("__DATA,__customSection"))) = (char *)"kyson";int main(int argc, const char * argv[]) {@autoreleasepool {//设置machheader信息if (machHeader == NULL){Dl_info info;dladdr((__bridge const void *)(configuration), &info);machHeader = (struct mach_header_64*)info.dli_fbase;}unsigned long byteCount = 0;uintptr_t* data = (uintptr_t *) getsectiondata(machHeader, "__DATA", "__customSection", &byteCount);NSUInteger counter = byteCount/sizeof(void*);for(NSUInteger idx = 0; idx < counter; ++idx){char *string = (char*)data[idx];NSString *str = [NSString stringWithUTF8String:string];NSLog(@"%@",str);}}return 0;
}
复制代码

本文就带大家详细分析一下,这段代码的含义。本文您将了解到

  • __attribute__
  • dladdr
  • uintptr_t 等含义

__attribute__

关于__attribute__,其实前面的文章有说过其中的一种用法:

__attribute__((constructor)) void myentry(){NSLog(@"constructor");
}
复制代码

这段代码会优先于main方法执行。 很显然,其于一般方法不一样的地方在于有修饰符:

__attribute__((constructor))
复制代码

那么__attribute__修饰符有什么作用呢,这里引用一段:

This section describes the syntax with which __attribute__ may be used, and the constructs to which attribute specifiers bind, for the C language. Some details may vary for C++ and Objective-C. Because of infelicities in the grammar for attributes, some forms described here may not be successfully parsed in all cases. There are some problems with the semantics of attributes in C++. For example, there are no manglings for attributes, although they may affect code generation, so problems may arise when attributed types are used in conjunction with templates or overloading. Similarly, typeid does not distinguish between types with different attributes. Support for attributes in C++ may be restricted in future to attributes on declarations only, but not on nested declarators.

以上摘自gcc:gcc.gnu.org/onlinedocs/… 这里笔者也摘抄了其他博客的一些论述:

__attribute__可以设置函数属性(Function Attribute)、变量属性(Variable Attribute)和类型属性(Type Attribute)。它的书写特征是:__attribute__前后都有两个下划线,并切后面会紧跟一对原括弧,括弧里面是相应的__attribute__参数,语法格式如下: __attribute__((attribute-list)) 另外,它必须放于声明的尾部“;”之前。

这里再介绍一篇文章,用于讲解__attribute__的作用: 不使用 NSOBJECT 的 OBJECTIVE-C CLASS 这篇文章讲解了

__attribute__((objc_root_class))
复制代码

的用法,完整的代码如下:

#import <stdio.h>
#import <stdlib.h>
#import <objc/runtime.h>__attribute__((objc_root_class))
@interface Answer
{Class isa;
}+ (id)instantiate;
- (void)die;@property(assign, nonatomic) int value;@end@implementation Answer+ (id)instantiate
{Answer *result = malloc(class_getInstanceSize(self));result->isa = self;return result;
}- (void)die
{free(self);
}@endint main(int argc, char const *argv[])
{Answer *answer = [Answer instantiate];answer.value = 42;printf("The answer is: %d\n", answer.value);[answer die];return 0;
}
复制代码

回到本文开头的Demo,使用的是另外一个属性:

__attribute__((section("__DATA,__customSection")))
复制代码

明显看出,是声明的一个变量属性。 这个变量要“被放到” section为“__DATA,__customSection”里面。这么一来就不难理解了。

dladdr

使用dladdr方法可以获得一个函数所在模块,名称以及地址。

下面我们通过一个实例来说明:

#include <dlfcn.h>
#include <objc/objc.h>
#include <objc/runtime.h>
#include <stdio.h>
#include <string.h>int main()
{Dl_info info;IMP imp = class_getMethodImplementation(objc_getClass("NSArray"),sel_registerName("description"));printf("pointer %p\n", imp);if (dladdr(imp,&info)){printf("dli_fname: %s\n", info.dli_fname);printf("dli_sname: %s\n", info.dli_sname);printf("dli_fbase: %p\n", info.dli_fbase);printf("dli_saddr: %p\n", info.dli_saddr);} else{printf("error: can't find that symbol.\n");}
}
复制代码

运行结果如下:

所以我们可以通过这种方式来判断一个函数是不是被非法修改了。

为了更好说明函数dladdr作用,这里笔者再举个Demo:

static inline BOOL validate_methods(const char *cls,const char *fname) __attribute__ ((always_inline));BOOL validate_methods(const char *cls,const char *fname){Class aClass = objc_getClass(cls);Method *methods;unsigned int nMethods;Dl_info info;IMP imp;char buf[128];Method m;if(!aClass)return NO;methods = class_copyMethodList(aClass, &nMethods);while (nMethods--) {m = methods[nMethods];printf("validating [%s %s]\n",(const char *)class_getName(aClass),(const char *)method_getName(m));imp = method_getImplementation(m);//imp = class_getMethodImplementation(aClass, sel_registerName("allObjects"));if(!imp){printf("error:method_getImplementation(%s) failed\n",(const char *)method_getName(m));free(methods);return NO;}if(!dladdr(imp, &info)){printf("error:dladdr() failed for %s\n",(const char *)method_getName(m));free(methods);return NO;}/*Validate image path*/if(strcmp(info.dli_fname, fname))goto FAIL;if (info.dli_sname != NULL && strcmp(info.dli_sname, "<redacted>") != 0) {/*Validate class name in symbol*/snprintf(buf, sizeof(buf), "[%s ",(const char *) class_getName(aClass));if(strncmp(info.dli_sname + 1, buf, strlen(buf))){snprintf(buf, sizeof(buf),"[%s(",(const char *)class_getName(aClass));if(strncmp(info.dli_sname + 1, buf, strlen(buf)))goto FAIL;}/*Validate selector in symbol*/snprintf(buf, sizeof(buf), " %s]",(const char*)method_getName(m));if(strncmp(info.dli_sname + (strlen(info.dli_sname) - strlen(buf)), buf, strlen(buf))){goto FAIL;}}else{printf("<redacted>  \n");}}return YES;FAIL:printf("method %s failed integrity test:\n",(const char *)method_getName(m));printf("    dli_fname:%s\n",info.dli_fname);printf("    dli_sname:%s\n",info.dli_sname);printf("    dli_fbase:%p\n",info.dli_fbase);printf("    dli_saddr:%p\n",info.dli_saddr);free(methods);return NO;
}
复制代码

回到本文开头的Demo,不难看出,其实

if (machHeader == NULL)
{Dl_info info;dladdr((__bridge const void *)(configuration), &info);machHeader = (struct mach_header_64*)info.dli_fbase;
}
复制代码

这段代码的用途仅仅是为了获取header。至于header前面的 文章也提到过了,这里不多做讲解了,拿到的header作为函数getsectiondata的参数:

uintptr_t* data = (uintptr_t *) getsectiondata(machHeader, "__DATA", "__customSection", &byteCount);
复制代码

这里需要注意的是getsectiondata的定义如下:

extern uint8_t *getsectiondata(const struct mach_header_64 *mhp,const char *segname,const char *sectname,unsigned long *size);
复制代码

所以一开始笔者在返回类型的时候,使用了uint8_t结果发现不管怎么操作都不能打印出想要的数据。改成uintptr_t才能打印成功。原因大家可以猜想一下。 最后我们查看一下打印的结果:

本文参考

iOS安全–验证函数地址,检测是否被替换,反注入

iOS开发之runtime(16):设置/获取section数据详解相关推荐

  1. 【IoT】STM32 系统级开发之 ucosIII 或 freeRTOS 事件标志组详解

    1.轻型操作系统同步的方案详解 1)信号量 假设有两个任务 Task1 和 Task2,第一个任务进行按键的扫描,第二个任务进行LED灯的点亮 需求: 扫描到按键按下后点亮 LED 灯,也就是说第二个 ...

  2. echarts图表动态获取后台数据详解(二)

    前篇文章介绍了如何在现有的页面中,建立容器存放echarts图表,如何引入echarts.js文件,和配置图表库的路径.并将静态数据在页面上呈现出来.相当于是为动态获取后台数据做了铺垫.那么这篇文章, ...

  3. ios c语言编译环境搭建,iOS开发之runtime(一):runtime调试环境搭建

    本系列博客是本人的源码阅读笔记,如果有 iOS 开发者在看runtime的,欢迎大家多多交流.为了方便讨论,本人新建了一个微信群(iOS技术讨论群),想要加入的,请添加本人微信:zhujinhui20 ...

  4. iOS开发之Runtime关联属性

    2019独角兽企业重金招聘Python工程师标准>>> 首先,推荐给大家一个非常好用的一个网站: 非盈利无广告开发者专用网址导航:http://www.dev666.com/ API ...

  5. iOS开发之Runtime常用示例总结

    深度好文,转载自:https://github.com/lizelu/ObjCRuntimeDemo 经常有小伙伴私下在Q上问一些关于Runtime的东西,问我有没有Runtime的相关博客,之前还真 ...

  6. wxpython使用方法_python图形界面开发之wxPython树控件使用方法详解

    wxPython树控件介绍 树(tree)是一种通过层次结构展示信息的控件,如下图所示是树控件示例,左窗口中是树控件,在wxPython中树控件类是wx.TreeCtrl. wx.TreeCtrl常用 ...

  7. java开发之ServLet注解、自定义容器方式详解

    目录 一.为什么使用注解方式和自定义容器方式 二.注解方式步骤 1.创建javaEE8版本的web项目 2.创建一个类MyServlet继承HTTPServlet类并重写doGet()和doPost( ...

  8. iOS8开发之 PHAsset 保存图片到相册(相机胶卷) 详解三

    http://blog.csdn.net/jerrychenly/article/details/44858355 解决iOS8下ALAssetsLibrary创建相册的bug 说到ALAssetsL ...

  9. (013)java后台开发之Mac系统安装和配置tomcat步骤详解

    一:下载 打开Apache Tomcat官网,选择需要的版本下载: 二:存放到本地 文件夹重名民为ApacheTomcat,放到/Users/计算机名/Library/目录下 三:启动Tomcat 打 ...

最新文章

  1. Codeforces 859C - Pie Rules
  2. java定时器的使用
  3. mysql union 放弃索引_MySQL的or/in/union与索引优化
  4. JVM系列之:从汇编角度分析NullCheck
  5. 关于ES6的10个最佳特性
  6. 视觉slam十四讲 pdf_视觉SLAM十四讲|第12讲 回环检测
  7. JDK内置的进制转换
  8. 里面的自带的字典在哪里_影视剪辑高清素材哪里找?4种方法教你,适合新手入门...
  9. spring Quartz基于配置文件和注解的实现
  10. 编程基本功:工作环境、运行环境,跟代码一样重要,都要备份
  11. 是你渡过人生难关的助力_人工智能将助力安全返回工作场所。 这是如何做
  12. 步进电机选型及扭矩的计算(粗略计算)
  13. SAS和SATA它两的相同点与不同点
  14. QC DCP PD SCP FCP等充电协议
  15. 【地平线旭日X3派试用体验】基于MIPI Camera的目标检测 web 端展示,全流程(第三节)
  16. Newdex Swap闪兑系统已通过PeckShield安全审计服务
  17. linux硬件测试拷机软件,“拷机”中。
  18. -- 27、 查询出只有两门课程的全部学生的学号和姓名(不重点)(自己做出)
  19. 西安的草根互联网要靠外力挽救吗?
  20. .NET Core 之 七 EF Core(四)

热门文章

  1. 服务器Windows 2008 R2 安装SQL 2008 R2
  2. 一个Demo带你彻底掌握View的滑动冲突
  3. java-集合(三)
  4. MySQL性能调优与架构设计——第11章 常用存储引擎优化
  5. 百度:在O(1)空间复杂度范围内对一个数组中前后连段有序数组进行归并排序
  6. Visual Assist X Options 注释设置-类
  7. windows程序窗体创建流程模型A--利用基本数据类型
  8. 大数据之-Hadoop3.x_MapReduce_序列化案例FlowBean---大数据之hadoop3.x工作笔记0097
  9. C++提高部分_C++函数模板_案例_数组排序---C++语言工作笔记083
  10. 大数据之-Hadoop完全分布式_完全分布式模式下的集群配置---大数据之hadoop工作笔记0034