Rico's blog.

逆向防护

字数统计: 533阅读时长: 2 min
2020/05/29 Share

逆向防护

0x01

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// 加载命令检测
static BOOL CheckLoadDylib() {
struct mach_header_64 *header = (struct mach_header_64 *)&_mh_execute_header;
// 64bit only
if (header->magic == MH_MAGIC_64) {
struct segment_command_64 *cur_seg_cmd;
uintptr_t cur = (uintptr_t)header + sizeof(struct mach_header_64);
for (uint i = 0; i < header->ncmds; i++,cur += cur_seg_cmd->cmdsize) {
cur_seg_cmd = (struct segment_command_64*)cur;
if(cur_seg_cmd->cmd == LC_LOAD_DYLIB || cur_seg_cmd->cmd == LC_LOAD_WEAK_DYLIB) {
struct dylib_command *dylib = (struct dylib_command*)cur_seg_cmd;
char* name = (char*)((uintptr_t)dylib + dylib->dylib.name.offset);
// printf("🌈🌈🌈🌈🌈🌈🌈🌈dylib_name=%s\n", name);
// TODO 这里可以加入白名单判断,如果发现了@rpath之类的路径就要怀疑是否注入了三方库
// return YES;
}
}
}
return NO;
}

// 代码检测
static NSString *GetTextSectionHash() {
unsigned long size;

uint8_t *ptr = getsectiondata(&_mh_execute_header, "__TEXT", "__text", &size);
if (!ptr) {
return @"";
}

unsigned char digest[CC_MD5_DIGEST_LENGTH];
CC_MD5(ptr, (CC_LONG)size, digest);
NSMutableString *result = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
for(int i = 0; i < CC_MD5_DIGEST_LENGTH; i++)
[result appendFormat:@"%02x", digest[i]];

return result;
}

//c方法检测hook
int isFunctionHooked(void *funcptr){
unsigned int * funcaddr = (unsigned int *)funcptr;
if (funcptr) {
// NSLog(@"💖💖💖💖💖💖%x____%x_____%x",funcaddr[0],funcaddr[1],funcaddr[2]);
if ((funcaddr[0]==0x58000050 || funcaddr[0]==0x58000051) && (funcaddr[1] == 0xd61f0200 || funcaddr[1] == 0xd61f0220)) {
return 0;
}
}
return 1;;
}

//oc方法检测hook(暂时不能检查静态库里面的oc方法)
BOOL checkMethodSwizzing(const char *className, const char *selName){
Dl_info info;
IMP imp = class_getMethodImplementation(objc_getClass(className), sel_registerName(selName));
if (!dladdr(imp, &info)) {
NSLog(@"❤️❤️❤️❤️❤️找不到");
return NO;
}
// NSLog(@"❤️❤️❤️❤️❤️%p_______%p",info.dli_fbase,info.dli_saddr);
if (strcmp(info.dli_fname, _dyld_get_image_name(0)) != 0) {
// NSLog(@"❤️❤️❤️❤️❤️%p____%p",info.dli_fname,_dyld_get_image_name(0));
return NO;
}
return YES;
}

//环境变量检查
BOOL CheckEnv() {
char *class = getenv("CLASSIC_OVERRIDE");

char *env = getenv("DYLD_INSERT_LIBRARIES");
printf("🪐🪐🪐🪐🪐🪐env=%s___%s \n", env,class);
if (env != NULL) {

return YES;
}

return NO;
}

extern char **environ;
BOOL CheckEnv2() {
char **p = environ;
while(*p) {
printf("✨✨✨✨✨✨%s (%p)\n", *p, *p);
if(strstr(*p, "MobileSubstrate") || strstr(*p, "DYLD_INSERT_LIBRARIES") || strstr(*p, "_MSSafeMode")) {
printf("%s (%p)\n", *p, *p);
return YES;
}
p++;
}
return NO;
}

// 检测签名信息
static void CheckTeamID(const char *szTeamID) {
struct load_command *lc;
struct mach_header_64 *header = (struct mach_header_64 *)&_mh_execute_header;
// 64bit only
if (header->magic == MH_MAGIC_64) {

uintptr_t cur = (uintptr_t)header + sizeof(struct mach_header_64);

for (uint i = 0; i < header->ncmds; i++, cur += lc->cmdsize) {
lc = (struct load_command *)cur;
if (lc->cmd == LC_CODE_SIGNATURE) {
NSLog(@"CMD==LC_CODE_SIGNATURE");

char *codeSignature = (char *)header + ((struct linkedit_data_command *)lc)->dataoff;
int codeSignatureSize = ((struct linkedit_data_command *)lc)->datasize;

void *p = memmem(codeSignature, codeSignatureSize, szTeamID, strlen(szTeamID));
if(!p) {
printf("校验失败\n");
// TODO 处理校验失败逻辑...
exit(0);
}

break;
}
}
}
}

0x20

关于OC Hook及C Hook检测还需要多研究静态库中的情况

CATALOG
  1. 1. 逆向防护
    1. 1.1. 0x01
    2. 1.2. 0x20