方法一:白名单
网上搜反注入,关于这个方法的搜索结果是最多的,简述下:
首先,自己创建一个类,在类里检索所有当前工程用到的动态库,然后把检索结果和自己预先设定的白名单进行对比,如果有多余的动态库,则判定,当前工程受到了注入,此时可以直接退出程序,亦或是上报服务器。
整体代码逻辑如下:
1.打开自己的主工程,加入如下代码:
//获取动态库个数
int count = _dyld_image_count();
for (int i = 1; i < count; i++) {
//打印所有动态库名称,用,隔开
printf("%s,",_dyld_get_image_name(i));
}
2.获取到所有的主工程动态库后,把字符串尽量保存在服务器。
3.判断应用加载进入的时候,是否有不包含的库(这里如果存在,就视为注入的库)
for (int i = 1; i < count; i++) {
// printf("%s,",_dyld_get_image_name(i));
if (!strstr(libStr, _dyld_get_image_name(i))) {
//如果不包含,视为注入库!
NSLog(@"注入库。采取防护措施~!");
}
}
缺点:库太多,不好维护,不同机型、系统依赖的库可能不一致,容易误伤。
方法二:Ptrace
逆向APP的时候,有时候不仅仅是静态分析,还可能会动态调试
而动态调试,无论是终端调试,还是Xcode附加。都是通过debugserver监测进程做到的!
Ptrace就是通过限制进程来阻止附加调试的。
一般来说,新创建的iOS项目里没有ptrace文件,我们此时可以自己创建下:
/*
* Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. The rights granted to you under the License
* may not be used to create, or enable the creation or redistribution of,
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
/*-
* Copyright (c) 1984, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)ptrace.h 8.2 (Berkeley) 1/4/94
*/
#ifndef _SYS_PTRACE_H_
#define _SYS_PTRACE_H_
#include
#include
enum {
ePtAttachDeprecated __deprecated_enum_msg("PT_ATTACH is deprecated. See PT_ATTACHEXC") = 10
};
#define PT_TRACE_ME 0 /* child declares it's being traced */
#define PT_READ_I 1 /* read word in child's I space */
#define PT_READ_D 2 /* read word in child's D space */
#define PT_READ_U 3 /* read word in child's user structure */
#define PT_WRITE_I 4 /* write word in child's I space */
#define PT_WRITE_D 5 /* write word in child's D space */
#define PT_WRITE_U 6 /* write word in child's user structure */
#define PT_CONTINUE 7 /* continue the child */
#define PT_KILL 8 /* kill the child process */
#define PT_STEP 9 /* single step the child */
#define PT_ATTACH ePtAttachDeprecated /* trace some running process */
#define PT_DETACH 11 /* stop tracing a process */
#define PT_SIGEXC 12 /* signals as exceptions for current_proc */
#define PT_THUPDATE 13 /* signal for thread# */
#define PT_ATTACHEXC 14 /* attach to running process with signal exception */
#define PT_FORCEQUOTA 30 /* Enforce quota for root */
#define PT_DENY_ATTACH 31
#define PT_FIRSTMACH 32 /* for machine-specific requests */
__BEGIN_DECLS
int ptrace(int _request, pid_t _pid, caddr_t _addr, int _data);
__END_DECLS
#endif /* !_SYS_PTRACE_H_ */
引入头文件后,直接调用:
//告诉系统当前进程拒绝被debugserver附加
ptrace(PT_DENY_ATTACH, 0, 0, 0);//
注意,ptrace在main函数之后调用App会直接闪退,main以及之前调用会停止进程附加,以第一次调用为准。正常打开App没有问题,只影响LLDB调试。
当然,hook了这个函数后,就能破解这种反注入方案,既然ptrace
能够被Hook
,那么自己先Hook
住ptrace
。调用的时候直接调用自己存储的地址就可以了。我们可以在自己的项目中增加一个Framework
。这个库在Link Binary With Libraries
中尽可能的靠前。这与dyld
加载动态库的顺序有关。
这样就可以不被ptrace
Hook
了。
创建个动态库,在文件中加入如下代码:
#import
int (*ptrace_p)(int _request, pid_t pid, caddr_t _addr, int _data);
void ptrace() {
void * handle = dlopen("usr/lib/system/libsystem_kernel.dylib", RTLD_LAZY);
ptrace_p = dlsym(handle, "ptrace");
if (!ptrace_p) {
exit(0);
return;
}
//通过函数指针调用
ptrace_p(31, 0, 0, 0);
}
方法三:sysctl
#import
bool isDebugServer(){
//控制码
int name[4];//放字节码-查询信息
name[0] = CTL_KERN;//内核查看
name[1] = KERN_PROC;//查询进程
name[2] = KERN_PROC_PID; //通过进程id查进程
name[3] = getpid();//拿到自己进程的id
//查询结果
struct kinfo_proc info;//进程查询信息结果
size_t info_size = sizeof(info);//结构体大小
int error = sysctl(name, sizeof(name)/sizeof(*name), &info, &info_size, 0, 0);
assert(error == 0);//0就是没有错误,设置个断言
//结果解析 p_flag的第12位为1就是有调试
//p_flag 与 P_TRACED =0 就是有调试
return ((info.kp_proc.p_flag & P_TRACED) !=0);
}
- (void)viewDidLoad {
[super viewDidLoad];
if (isDebugServer()) {
NSLog(@"在debugserver调试状态!");
//自行处理
}else{
NSLog(@"在正常运行状态!");
}
}
当前,此方法也会被hook,所以最好也在动态库里做相应的处理。