在破解一款App
的時候胀瞪,在實(shí)際破解之前肯定是在做調(diào)試溉愁。LLDB
之所以能附加進(jìn)程時因?yàn)?code>debugserver菇篡,而debugserver
附加是通過ptrace
函數(shù)來trace process
的丘跌。
ptrace
是系統(tǒng)函數(shù),此函數(shù)提供一個進(jìn)程去監(jiān)聽和控制另一個進(jìn)程挡育,并且可以檢測被控制進(jìn)程的內(nèi)存和寄存器里面的數(shù)據(jù)。ptrace
可以用來實(shí)現(xiàn)斷點(diǎn)調(diào)試和系統(tǒng)調(diào)用跟蹤朴爬。
一即寒、反調(diào)試ptrace
在iOS
中#import <sys/ptrace.h>
頭文件不能直接導(dǎo)入,所以需要我們自己導(dǎo)出頭文件引入調(diào)用。當(dāng)然也可以聲明ptrace
函數(shù)直接調(diào)用母赵。
1.1 ptrace 頭文件
- 直接創(chuàng)建一個
macOS
程序?qū)?code>#import <sys/ptrace.h>頭文件逸爵,點(diǎn)進(jìn)去拷貝生成一個.h
文件就可以了:
/*
* 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_ */
- 直接聲明函數(shù):
int ptrace(int _request, pid_t _pid, caddr_t _addr, int _data);
-
_request
:要處理的事情 -
_pid
:要操作的進(jìn)程 -
_addr
和_data
:取決于_pid
參數(shù),要傳遞的數(shù)據(jù)地址和數(shù)據(jù)本身凹嘲。
1.2 ptrace調(diào)用
//告訴系統(tǒng)當(dāng)前進(jìn)程拒絕被debugserver附加
ptrace(PT_DENY_ATTACH, 0, 0, 0);
//ptrace(31, 0, 0, 0);
PT_DENY_ATTACH
表示拒絕附加师倔,值為31
。如果僅僅是聲明函數(shù)就傳31
就好了周蹭。_pid
為0
表示當(dāng)前進(jìn)程趋艘。這里不傳遞任何數(shù)據(jù)。
分別在以下方法中調(diào)用
-
load
方法中調(diào)用:
+ (void)load {
ptrace(PT_DENY_ATTACH, 0, 0, 0);
}
-
constructor
中調(diào)用:
__attribute__((constructor)) static void entry() {
ptrace(PT_DENY_ATTACH, 0, 0, 0);
}
-
main
函數(shù)中調(diào)用:
int main(int argc, char * argv[]) {
NSString * appDelegateClassName;
@autoreleasepool {
// Setup code that might create autoreleased objects goes here.
appDelegateClassName = NSStringFromClass([AppDelegate class]);
ptrace(PT_DENY_ATTACH, 0, 0, 0);
}
return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}
-
didFinishLaunchingWithOptions
中調(diào)用:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
ptrace(PT_DENY_ATTACH, 0, 0, 0);
return YES;
}
1
凶朗、2
致稀、3
情況下Xcode
啟動調(diào)試后調(diào)試直接斷開,App
能正常操作不能調(diào)試俱尼。4
在調(diào)試情況下App
直接閃退抖单,正常打開沒問題。同時調(diào)用的情況下以第一次為準(zhǔn)遇八。
也就是說 :ptrace
在main
函數(shù)之后調(diào)用App
會直接閃退矛绘,main
以及之前調(diào)用會停止進(jìn)程附加,以第一次調(diào)用為準(zhǔn)刃永。正常打開App
沒有問題货矮,只影響LLDB
調(diào)試。
通過上面的驗(yàn)證說明在程序沒有加載的時候調(diào)用ptrace
會設(shè)置一個標(biāo)志斯够,后續(xù)程序就不會被附加了囚玫,如果在已經(jīng)被附加了的情況下調(diào)用ptrace
會直接退出(因?yàn)檫@里ptrace
附加傳遞的pid
是0
主程序本身)。
PT_DENY_ATTACH
This request is the other operation used by the traced process; it allows a process that is not currently being traced to deny future traces by its parent. All other arguments are ignored. If the process is currently being traced, it will exit with the exit status of ENOTSUP; otherwise, it sets a flag that denies future traces. An attempt by the parent to trace a process which has set this flag will result in a segmentation violation in the parent.
原文地址
ENOTSUP含義如下:
define ENOTSUP 45 //Operation not supported
之前在手機(jī)端通過debugserver
附加程序直接報(bào)錯11
读规,定義如下:
PT_DETACH 11 // stop tracing a process
二抓督、 破解ptrace
ptrace
的特征:附加不了、Xcode運(yùn)行閃退/停止附加束亏、使用正常铃在。
既然ptrace
可以組織調(diào)試,那么我們只要Hook
了這個函數(shù)繞過PT_DENY_ATTACH
的調(diào)用就可以了碍遍。首先想到的就是fishhook
定铜。
#import "fishhook.h"
int (*ptrace_p)(int _request, pid_t _pid, caddr_t _addr, int _data);
int hp_ptrace(int _request, pid_t _pid, caddr_t _addr, int _data){
if (_request != 31) {//不是拒絕附加
return ptrace_p(_request, _pid, _addr, _data);
}
return 0;
}
void hp_hook_ptrace() {
struct rebinding ptrace_rb;
ptrace_rb.name ="ptrace";
ptrace_rb.replacement = hp_ptrace;
ptrace_rb.replaced = (void *)&ptrace_p;
struct rebinding bds[] = {ptrace_rb};
rebind_symbols(bds, 1);
}
+ (void)load {
hp_hook_ptrace();
}
這樣就能夠進(jìn)行附加調(diào)試了。
三怕敬、防止ptrace被破解
3.1 提前Hook防止ptrace被Hook
既然ptrace
能夠被Hook
揣炕,那么自己先Hook
住ptrace
。調(diào)用的時候直接調(diào)用自己存儲的地址就可以了东跪。我們可以在自己的項(xiàng)目中增加一個Framework
畸陡。這個庫在Link Binary With Libraries
中盡可能的靠前矮烹。這與dyld
加載動態(tài)庫的順序有關(guān)。
具體可以參考這個案例
這樣就可以不被ptrace
Hook
了罩锐。代碼邏輯和1.2
中相同奉狈,只不過調(diào)用要換成ptrace_p
。
記的頭文件中導(dǎo)出ptrace_p
:
CF_EXPORT int (*ptrace_p)(int _request, pid_t _pid, caddr_t _addr, int _data);
創(chuàng)建一個Monkey
工程涩惑,將3.1
生成的.app
包拖入工程重簽名仁期,這個時候主程序通過調(diào)用ptrace
已經(jīng)不能阻止我們調(diào)試了,但是調(diào)用ptrace_p
的地方Monkey
Hook
不到了竭恬。
3.2 修改二進(jìn)制破解提前Hook ptrace
在Monkey
的工程中打ptrace
符號斷點(diǎn):
這個時候可以看到是didFinishLaunchingWithOptions
中調(diào)用了ptrace_p
函數(shù):
用Hopper
打開MachO
文件找到didFinishLaunchingWithOptions
方法:
然后一直點(diǎn)下去找到ptrace_p
是屬于Inject.framework
的:
在.app
的Frameworks
中找到Inject.framework
用Hopper
打開跛蛋,可以看到_rebind_symbols
,上面的參數(shù)是ptrace
:
這里我們可以直接修改ptrace
讓先Hook
的變成另外一個函數(shù)痊硕,但是有風(fēng)險點(diǎn)是App
內(nèi)部調(diào)用ptrace_p
的時候如果沒有判斷空就crash
了赊级。如果判斷了可以這么處理。
還有另外一個方式是修改didFinishLaunchingWithOptions
代碼中的匯編岔绸,修改blr x8
為NOP
這樣就繞過了ptrace_p
的調(diào)用理逊。
修改blr x8
為NOP
:
替換00 01 3F D6
為1F 20 03 D5
:
修改后就變?yōu)?code>NOP了:
再次運(yùn)行就繞過了ptrace_p
的調(diào)用。這里不Hook
didFinishLaunchingWithOptions
的原因是它內(nèi)部可能還調(diào)用其它方法盒揉。
3.3 匯編調(diào)用ptrace
既然二進(jìn)制能被修改那么怎么能不暴露ptrace
的Hook
呢晋被?
答案是采用匯編:
__attribute__((constructor)) void entry() {
#ifdef DEBUG
//
#else
#ifdef __arm__
__asm__(
"mov r0,#0x1F\n"
"mov r1,#0x0\n"
"mov r2,#0x0\n"
"mov r12,#0x1A\n"
"svc #0x80");
#endif
#ifdef __arm64__
__asm__("mov X0, #0x1A\n"
"mov X1, #0x1F\n"
"mov X2, #0x0\n"
"mov X3, #0x0\n"
"mov X16,#0x0\n"
"svc #0x80");
#endif
}
#endif
這里的1A
就是26
,也就是ptrace
刚盈,在#import <sys/syscall.h>
中有它的編號:
3.4 匯編ptrace破解
分析找到svc #0x80
修改為nop
就可以了羡洛,抖音的防護(hù)就是通過匯編調(diào)用的。
參考:
http://www.45fan.com/article.php?aid=18070914507358856843184900