方法一:白名單
網上搜反注入,關于這個方法的搜索結果是最多的,簡述下:
首先,自己創(chuàng)建一個類,在類里檢索所有當前工程用到的動態(tài)庫,然后把檢索結果和自己預先設定的白名單進行對比,如果有多余的動態(tài)庫,則判定,當前工程受到了注入,此時可以直接退出程序,亦或是上報服務器。
整體代碼邏輯如下:
1.打開自己的主工程,加入如下代碼:
//獲取動態(tài)庫個數
int count = _dyld_image_count();
for (int i = 1; i < count; i++) {
//打印所有動態(tài)庫名稱,用,隔開
printf("%s,",_dyld_get_image_name(i));
}
2.獲取到所有的主工程動態(tài)庫后,把字符串盡量保存在服務器。
3.判斷應用加載進入的時候,是否有不包含的庫(這里如果存在,就視為注入的庫)
for (int i = 1; i < count; i++) {
// printf("%s,",_dyld_get_image_name(i));
if (!strstr(libStr, _dyld_get_image_name(i))) {
//如果不包含,視為注入庫!
NSLog(@"注入庫。采取防護措施~!");
}
}
缺點:庫太多,不好維護,不同機型、系統(tǒng)依賴的庫可能不一致,容易誤傷。
方法二:Ptrace
逆向APP的時候,有時候不僅僅是靜態(tài)分析,還可能會動態(tài)調試
而動態(tài)調試,無論是終端調試,還是Xcode附加。都是通過debugserver監(jiān)測進程做到的!
Ptrace就是通過限制進程來阻止附加調試的。
一般來說,新創(chuàng)建的iOS項目里沒有ptrace文件,我們此時可以自己創(chuàng)建下:
/*
* 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 <sys/appleapiopts.h>
#include <sys/cdefs.h>
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_ */
引入頭文件后,直接調用:
//告訴系統(tǒng)當前進程拒絕被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加載動態(tài)庫的順序有關。
這樣就可以不被ptrace Hook了。
創(chuàng)建個動態(tài)庫,在文件中加入如下代碼:
#import <dlfcn.h>
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 <sys/sysctl.h>
bool isDebugServer(){
//控制碼
int name[4];//放字節(jié)碼-查詢信息
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調試狀態(tài)!");
//自行處理
}else{
NSLog(@"在正常運行狀態(tài)!");
}
}
當前,此方法也會被hook,所以最好也在動態(tài)庫里做相應的處理。