1、DYLD_INSERT_LIBRARIES
注意:该方法只支持iOS10以下系统并且只防护动态库插入的形式,在高版本上系统不会去检查该函数
我们在低版本的DYLD源码中可以发现在环境变量DYLD_INSERT_LIBRARIES
判断之前有这样一个代码。
当gLinkContext.processIsRestricted == YES
即当前进程受限制的时候,pruneEnvironmentVariables
函数会移除相关的环境变量,也就是insert_libraries
里的数据会清空,即我们插入的动态库无法被加载
pruneEnvironmentVariables源码解析
-
DYLD_INSERT_LIBRARIES 判断
DYLD_INSERT_LIBRARIES 判断
-
gLinkContext.processIsRestricted 进程受限
进程受限
-
全局搜索
processIsRestricted = true
,我们可以看到下图红框的有两个判断,其中issetugid
是不能自己调用的,所以只剩hasRestrictedSegment
这个方法,它是判断当前mach-o是否受限
,因为他在dyld之前,所以这个函数没法进行hook
processIsRestricted = true
-
hasRestrictedSegment函数就是通过读取
mach-o
文件中的load commands
,判断当前segname == "__RESTRICT"
,并且sectname == __restrict
,就返回true
hasRestrictedSegment函数
-
没有进行防护的mach-o文件
没有进行防护的mach-o文件
防护
选择Targets --> Build Settings --> Other Linker Flags
,点击添加-Wl,-sectcreate,__RESTRICT,__resyrict,/dev/null
![](https://img.haomeiwen.com/i16490557/2800399325305d22.png)
编译运行后,查看对应的mach-o
![](https://img.haomeiwen.com/i16490557/d02a5df18847ace2.png)
破解processIsRestricted防护
当我们通过二进制修改工具来修改对应的__RESTRICT 和 __restrict
后,该防护就会失效,
![](https://img.haomeiwen.com/i16490557/77b2b8f11c058ff3.png)
优化
我们可以将DYLD中hasRestrictedSegment
方法复制到自己工程中,来检测mach-o
中的__RESTRICT
段是否被修改,当我们检测到工程被人注入的时候,我们可以向服务器发送请求标记当前账号、手机被注入,或者我们前端主动进行断网的操作,或者在网络请求的时候返回脏数据,封杀IP地址等等,切记不可做一些强标记,例如直接退出程序,防止被人找到当前防注入的方法进行hook
#import <mach-o/loader.h>
#import <mach-o/dyld.h>
#if __LP64__
#define macho_header mach_header_64
#define LC_SEGMENT_COMMAND LC_SEGMENT_64
#define LC_SEGMENT_COMMAND_WRONG LC_SEGMENT
#define LC_ENCRYPT_COMMAND LC_ENCRYPTION_INFO
#define macho_segment_command segment_command_64
#define macho_section section_64
#else
#define macho_header mach_header
#define LC_SEGMENT_COMMAND LC_SEGMENT
#define LC_SEGMENT_COMMAND_WRONG LC_SEGMENT_64
#define LC_ENCRYPT_COMMAND LC_ENCRYPTION_INFO_64
#define macho_segment_command segment_command
#define macho_section section
#endif
@interface ViewController ()
@end
@implementation ViewController
+(void)load
{
const struct macho_header * header = _dyld_get_image_header(0);
if (yp_hasRestrictedSegment(header)) {
NSLog(@"防止Tweak注入!");
}else{
NSLog(@"被修改了!");
// exit(0);//相当于这是一个记号! -- 给服务器发请求!
}
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
//-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
// //这里不能碰!
// exit(0);
//}
static bool yp_hasRestrictedSegment(const struct macho_header* mh)
{
const uint32_t cmd_count = mh->ncmds;
const struct load_command* const cmds = (struct load_command*)(((char*)mh)+sizeof(struct macho_header));
const struct load_command* cmd = cmds;
for (uint32_t i = 0; i < cmd_count; ++i) {
switch (cmd->cmd) {
case LC_SEGMENT_COMMAND:
{
const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
// printf("seg name: %s\n", seg->segname);
//dyld::log("seg name: %s\n", seg->segname);
if (strcmp(seg->segname, "__RESTRICT") == 0) {
const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
const struct macho_section* const sectionsEnd = §ionsStart[seg->nsects];
for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
if (strcmp(sect->sectname, "__restrict") == 0)
return true;
}
}
}
break;
}
cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
}
return false;
}
@end
网友评论