首页
社区
课程
招聘
[原创]绕过iOS 基于svc 0x80的ptrace反调试
2022-7-24 12:39 76396

[原创]绕过iOS 基于svc 0x80的ptrace反调试

2022-7-24 12:39
76396

ptrace反调试的原理与实现

由于厂商对于app安全方面的认识不断提升,当前iOS上的调试对抗愈演愈烈。而ptrace attach deny作为比较常用的反调试手段,其原理是将相关进程proc的p_lflag加上一个P_LNOATTACH标识位,当外部调试器想要再加载进程时,会返回一个Segmentation fault: 11 的错误标识:

1
2
3
4
5
iPhone8k:/usr/local root# debugserver 127.0.0.1:6666 -a Xxxx
debugserver-@(#)PROGRAM:LLDB  PROJECT:lldb-900.3.104
 for arm64.
Attaching to process Xxxx...
Segmentation fault: 11

ptrace源码,摘自xnu-6153.101.6/bsd/kern/mach_process.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int
ptrace(struct proc *p, struct ptrace_args *uap, int32_t *retval)
{
//....
 
    if (uap->req == PT_DENY_ATTACH) {
//....
        proc_lock(p);
        if (ISSET(p->p_lflag, P_LTRACED)) {
            proc_unlock(p);
            //...
            exit1(p, W_EXITCODE(ENOTSUP, 0), retval);
 
            thread_exception_return();
            /* NOTREACHED */
        }
        SET(p->p_lflag, P_LNOATTACH);//p_lflag |=0x00001000
        proc_unlock(p);
 
        return 0;
    }
....
}

厂商为了防止API hook使其失效,开始大量使用基于svc 0x80的服务调用方式,并伴随着代码混淆以及代码膨胀,使得想要快速定位svc 0x80调用并将其patch掉也变得难以实现。

 

使用svc方式调用ptrace attach deny

1
2
3
4
5
6
7
__asm__("mov X0, #31"
        "mov X1, #0"
        "mov X2, #0"
        "mov X3, #0"
        "mov X16, #26"
        "svc #0x80"
        );

以上是ptrace反调试的简单介绍,如有疑问可参考下面的文章
https://blog.it-securityguard.com/itunes-exploit-development/
https://cardaci.xyz/blog/2018/02/12/a-macos-anti-debug-technique-using-ptrace/

对抗方案

ptrace实现PT_DENY_ATTACH,就是对相关进程proc的p_lflag加上P_LNOATTACH标示位。那么要想使得进程和被调试器加载,只需要取消这个标志位。现在的问题是,proc链表结构,是位于iOS内核中,所以我们必须要拥有读写iOS内核的能力,要获取这个能力,第一个想到的办法是对iOS的漏洞利用,毕竟,iOS越狱也是基于这些漏洞,对特定内核位置进行读写。所幸的是,当前一些越狱工具,提供了tfp0(task for pid 0)接口,可供我们读写iOS内核。
那什么是tfp0呢?theiphonewiki上给出的说明如下:
In the XNU kernel, task_for_pid is a function that allows a (privileged) process to get the task port of another process on the same host, except the kernel task (process ID 0). A tfp0 patch (or task_for_pid(0) patch) removes this restriction, allowing any executable running as root to call task_for_pid for pid 0 (hence the name) and then use vm_read and vm_write to modify the kernel VM region. The entitlements get-task-allow and task_for_pid-allow are required to make AMFI happy.
https://www.theiphonewiki.com/wiki/Tfp0_patch

 

现在我们可以整理一下思路了:
1、找到kernproc在内核的地址,然后通tfp0调用读取kernproc
2、找到当前系统所有的进程信息,所有进程都放在了kernproc指向的链表中
3、找到相当进程的proc,对p_lflag,进行修改

方案实现

有了思路,那接下来我们要如何找到kernproc的内核地址呢?
通过阅读源码,我们知道kernproc的是一个全局变量,所以判断他的地址偏移一定是固定了,而且应该位于kernelcache,并且会在bsd_init过程中被初始化。
图片描述
根据上边的线索,我们可以通过逆向kernelcache镜像文件找到他的偏移
图片描述
找到偏移后,下一个问题来了,由于ASLR的存在,我们必须要获取到kernbase才能配合偏移量定位kernproc位置,进行进一步操作。
索性GeoSn0w大神已经在github上提供了这个功能的代码,其原理是通过扫描kernel heap 找到指向内核镜像的指针,再根据这个内核景象向上回溯machO的head。详细的可以通过阅读源码来了解。

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
bool
kernel_base_init_with_unsafe_heap_scan() {
    uint64_t kernel_region_base = 0xfffffff000000000;
    uint64_t kernel_region_end  = 0xfffffffbffffc000;
    // Try and find a pointer in the kernel heap to data in the kernel image. We'll take the
    // smallest such pointer.
    uint64_t kernel_ptr = (uint64_t)(-1);
    mach_vm_address_t address = 0;
    for (;;) {
        // Get the next memory region.
        mach_vm_size_t size = 0;
        uint32_t depth = 2;
        struct vm_region_submap_info_64 info;
        mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64;
        kern_return_t kr = mach_vm_region_recurse(kernel_task_port, &address, &size,
                &depth, (vm_region_recurse_info_t) &info, &count);
        if (kr != KERN_SUCCESS) {
            break;
        }
        // Skip any region that is not on the heap, not in a submap, not readable and
        // writable, or not fully mapped.
        int prot = VM_PROT_READ | VM_PROT_WRITE;
        if (info.user_tag != 12
            || depth != 1
            || (info.protection & prot) != prot
            || info.pages_resident * 0x4000 != size) {
            goto next;
        }
        // Read the first word of each page in this region.
        for (size_t offset = 0; offset < size; offset += 0x4000) {
            uint64_t value = 0;
            bool ok = kernel_read(address + offset, &value, sizeof(value));
            if (ok
                && kernel_region_base <= value
                && value < kernel_region_end
                && value < kernel_ptr) {
                kernel_ptr = value;
            }
        }
next:
        address += size;
    }
    // If we didn't find any such pointer, abort.
    if (kernel_ptr == (uint64_t)(-1)) {
        return false;
    }
    printf("found kernel pointer %p\n", (void *)kernel_ptr);
    // Now that we have a pointer, we want to scan pages until we reach the kernel's Mach-O
    // header.
    uint64_t page = kernel_ptr & ~0x3fff;
    for (;;) {
        bool found = is_kernel_base(page);
        if (found) {
            kernel_base = page;
            return true;
        }
        page -= 0x4000;
    }
    return false;
}

好了,万事俱备了,现在需要的是通过代码将其实现:

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
// ---- Main --------------------------------------------------------------------------------------
 
//iphone8  ios 13.4  kernel
#define TARGET_KERNELCACHE_VERSION_STRING "@(#)VERSION: Darwin Kernel Version 19.4.0: Mon Feb 24 22:04:29 PST 2020; root:xnu-6153.102.3~1/RELEASE_ARM64_T8015"
 
int main() {
    kernel_task_init();
    uint64_t kb = kernel_base_init();
    for (size_t i = 0; i < 8; i++) {
        printf("%016llx\n", kernel_read64(kb + 8 * i));
    }
    uint64_t versionstraddr = kb + 0x2FB64;
    char versionstr[256];
    if(kernel_read(versionstraddr, (void *)&versionstr, sizeof(versionstr)))
    {
        printf("%s\n", versionstr);
        if(strcmp(TARGET_KERNELCACHE_VERSION_STRING,versionstr) == 0)
        {
            printf("kernel cache hit\n");
            //226AF60  kernproc
            uint64_t kernel_proc0 = kernel_read64(kb + 0x226AF60);
 
            struct proc * proc0 =  (void *)malloc(sizeof(struct proc));
 
            if(!kernel_read(kernel_proc0, (void *)proc0, sizeof(struct proc)))
            {
                printf("proc0 read failed\n");
                return -1;
            }
             printf("uniqueid offset 0x%llx  comm offset 0x%llx \n",(int64_t)&(proc0->p_uniqueid) - (int64_t)proc0, (int64_t)&(proc0->p_comm)- (int64_t)proc0);
 
            struct proc * proc1 =  (struct proc *)malloc(sizeof(struct proc));
            uint64_t preptr = (uint64_t)(proc0->p_list.le_prev);
            while(preptr){
                if(!kernel_read(preptr, (void *)proc1, sizeof(struct proc)))
                {
                    printf("procnext read failed\n");
                    return -1;
                }else{
                    if(proc1->p_list.le_prev == 0)
                    {
                        printf("proc1->p_list.le_prev == 0\n");
                        break;
                    }
                    int64_t lflagoffset = (int64_t)&(proc1->p_lflag) - (int64_t)proc1;
                    int lflagvalue = proc1->p_lflag;
                    printf("(%llu)%s  proc = 0x%llx   lflag = 0x%x  lflag offset = 0x%llx"
                        ,proc1->p_uniqueid,
                        proc1->p_comm,//(char *)((int64_t)proc1 + 0x258),
                        preptr,lflagvalue,lflagoffset);
 
                        if(ISSET(lflagvalue, P_LNOATTACH))
                        {
                            printf(" !!!P_LNOATTACH set");
                            CLR(lflagvalue, P_LNOATTACH);
                            KERNEL_WRITE32(preptr + lflagoffset, lflagvalue);
                        }
                        printf("\n");
 
                    preptr = (uint64_t)(proc1->p_list.le_prev);
                }
            }
 
            printf("end\n");
            free(proc0);
            free(proc1);
        }else{
            printf("kernel cache version mismatch\n");
        }
    }else{
        printf("failed to read kernel version string\n");
    }
    return 0;
}

完整代码可到github上下载
https://github.com/xiaohang99/iOSFuckDenyAttach

 

最后,希望大家转发能注明出处


[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

最后于 2022-7-24 12:59 被xiaohang编辑 ,原因:
收藏
免费 10
打赏
分享
最新回复 (21)
雪    币: 3836
活跃值: (4142)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
caolinkai 2022-7-29 09:00
2
0
牛皮
雪    币: 3836
活跃值: (4142)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
caolinkai 2022-7-29 09:04
3
0
 only support under checkra1n and iphone8 iOS 13.4
雪    币: 1337
活跃值: (1479)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
mb_cwlqrkbj 2022-7-29 20:34
4
0
雪    币: 1009
活跃值: (125)
能力值: ( LV3,RANK:29 )
在线值:
发帖
回帖
粉丝
wx_突突兔 2022-8-7 17:20
5
0
为什么都已经有tfp0还要扫内存去获取aslr,直接这样不香么。
uint64_t get_kslide(void)
{
    task_t tfp0;
    kern_return_t ret = task_for_pid(mach_task_self(), 0, &tfp0);
    if(ret != KERN_SUCCESS) return 0;
    task_dyld_info_data_t info;
    uint32_t count = TASK_DYLD_INFO_COUNT;
    ret = task_info(tfp0, TASK_DYLD_INFO, (task_info_t)&info, &count);
    if(ret != KERN_SUCCESS) return 0;
    return info.all_image_info_size;
}
雪    币: 1009
活跃值: (125)
能力值: ( LV3,RANK:29 )
在线值:
发帖
回帖
粉丝
wx_突突兔 2022-8-7 17:51
6
0
https://github.com/tututu-patch/iOSFuckDenyAttach
iPhone 8 Plus iOS 13.6 , Darwin Kernel Version 19.6.0: Sat Jun 27 04:36:08 PDT 2020; root:xnu-6153.142.1~4/RELEASE_ARM64_T8015
雪    币: 2127
活跃值: (2921)
能力值: (RANK:260 )
在线值:
发帖
回帖
粉丝
xiaohang 3 2022-8-8 16:42
7
0
wx_突突兔 为什么都已经有tfp0还要扫内存去获取aslr,直接这样不香么。 uint64_t get_kslide(void) { task_t tfp0; kern_return_t ...
有空我也尝试一下
雪    币: 1009
活跃值: (125)
能力值: ( LV3,RANK:29 )
在线值:
发帖
回帖
粉丝
wx_突突兔 2022-8-8 17:29
8
0
我已经移植到了unc0ver,目前工作一切正常https://github.com/tututu-patch/iOSFuckDenyAttach/tree/unc0ver
雪    币: 229
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
迷你巨羊 2022-10-27 18:10
9
0

没弄懂,kernel_base_init_with_unsafe_heap_scan的运行原理。我在获得tfp0之后执行这个函数,手机重启.

问题解决。但是这个反ptrace貌似没起作用。我自己做个app,进入调试状态,使用ptrace并app退出了。

最后于 2022-11-1 11:41 被迷你巨羊编辑 ,原因:
雪    币: 469
活跃值: (376)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
chinasf 2022-11-10 14:42
10
0
wx_突突兔 我已经移植到了unc0ver,目前工作一切正常https://github.com/tututu-patch/iOSFuckDenyAttach/tree/unc0ver
我需要消化和验证下
雪    币: 49
活跃值: (1933)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
flashgg 2022-11-15 09:45
11
0
wx_突突兔 https://github.com/tututu-patch/iOSFuckDenyAttach iPhone 8 Plus iOS 13.6 , Darwin Kernel Version 19 ...
怎么下载的kernelcache能不能说一下?
雪    币: 49
活跃值: (1933)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
flashgg 2022-11-15 09:46
12
0
怎么下载的kernelcache能不能说一下?
雪    币: 2127
活跃值: (2921)
能力值: (RANK:260 )
在线值:
发帖
回帖
粉丝
xiaohang 3 2022-11-17 10:42
13
0
flashgg 怎么下载的kernelcache能不能说一下?
kernelcache可以通过解密ios固件包得到,具体方法请自行谷歌
雪    币: 416
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_bcbqumjf 2022-12-7 17:25
14
0
xiaohang kernelcache可以通过解密ios固件包得到,具体方法请自行谷歌
现在还需要解密才能得到吗? 另外 参照你的代码 我在iphone7 ios14.3上总是不成功
雪    币: 416
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_bcbqumjf 2022-12-7 17:27
15
0
mb_bcbqumjf 现在还需要解密才能得到吗? 另外 参照你的代码 我在iphone7 ios14.3上总是不成功
kernel_base_init_with_unsafe_heap_scan函数中的mach_vm_region_recurse调用失败
雪    币: 1009
活跃值: (125)
能力值: ( LV3,RANK:29 )
在线值:
发帖
回帖
粉丝
wx_突突兔 2022-12-18 16:03
16
0
flashgg 怎么下载的kernelcache能不能说一下?
https://ipsw.me/
雪    币: 42
活跃值: (1846)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
魅叉 2023-2-10 04:57
17
0

已解决

最后于 2023-2-11 05:15 被魅叉编辑 ,原因: 已解决
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_iyhdbgsm 2023-6-5 11:13
19
0

大佬的帖子厉害

最后于 2023-6-6 10:50 被mb_iyhdbgsm编辑 ,原因:
雪    币: 76
活跃值: (1477)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
yuzhouheike 2024-6-4 14:45
20
0

iphone7 iOS 14.1 , Darwin Kernel Version 20.0.0: Wed Sep 30 03:24:41 PDT 2020; root:xnu-7195.0.46~41/RELEASE_ARM64_T8010


https://github.com/yuzhouheike/iOSFuckDenyAttach-iPhone7-14.1/tree/main


默认失败怀疑proc结构体不同版本不一样所以按照自己的手机xnu相近版本修改了proc结构体

struct  proc {
LIST_ENTRY(proc) p_list;                /* List of all processes. */

void *          XNU_PTRAUTH_SIGNED_PTR("proc.task") task;       /* corresponding task (static)*/
struct  proc *  XNU_PTRAUTH_SIGNED_PTR("proc.p_pptr") p_pptr;   /* Pointer to parent process.(LL) */
pid_t           p_ppid;                 /* process's parent pid number */
pid_t           p_original_ppid;        /* process's original parent pid number, doesn't change if reparented */
pid_t           p_pgrpid;               /* process group id of the process (LL)*/
uid_t           p_uid;
gid_t           p_gid;
uid_t           p_ruid;
gid_t           p_rgid;
uid_t           p_svuid;
gid_t           p_svgid;
uint64_t        p_uniqueid;             /* process unique ID - incremented on fork/spawn/vfork, remains same across exec. */
uint64_t        p_puniqueid;            /* parent's unique ID - set on fork/spawn/vfork, doesn't change if reparented. */

lck_mtx_t       p_mlock;                /* mutex lock for proc */
pid_t           p_pid;                  /* Process identifier. (static)*/
char            p_stat;                 /* S* process status. (PL)*/
char            p_shutdownstate;
char            p_kdebug;               /* P_KDEBUG eq (CC)*/
char            p_btrace;               /* P_BTRACE eq (CC)*/

LIST_ENTRY(proc) p_pglist;              /* List of processes in pgrp.(PGL) */
LIST_ENTRY(proc) p_sibling;             /* List of sibling processes. (LL)*/
LIST_HEAD(, proc) p_children;           /* Pointer to list of children. (LL)*/
TAILQ_HEAD(, uthread) p_uthlist;        /* List of uthreads  (PL) */

LIST_ENTRY(proc) p_hash;                /* Hash chain. (LL)*/

#if CONFIG_PERSONAS
struct persona  *p_persona;
LIST_ENTRY(proc) p_persona_list;
#endif

lck_mtx_t       p_fdmlock;              /* proc lock to protect fdesc */
lck_mtx_t       p_ucred_mlock;          /* mutex lock to protect p_ucred */

    /* substructures: */
kauth_cred_t    XNU_PTRAUTH_SIGNED_PTR("proc.p_ucred") p_ucred; /* Process owner's identity. (PUCL) */
struct  filedesc *p_fd;                 /* Ptr to open files structure. (PFDL) */
struct  pstats *p_stats;                /* Accounting/statistics (PL). */
struct  plimit *p_limit;                /* Process limits.(PL) */

struct  sigacts *p_sigacts;             /* Signal actions, state (PL) */
lck_spin_t      p_slock;                /* spin lock for itimer/profil protection */

int             p_siglist;              /* signals captured back from threads */
unsigned int    p_flag;                 /* P_* flags. (atomic bit ops) */
unsigned int    p_lflag;                /* local flags  (PL) */
unsigned int    p_listflag;             /* list flags (LL) */
unsigned int    p_ladvflag;             /* local adv flags (atomic) */
int             p_refcount;             /* number of outstanding users(LL) */
int             p_childrencnt;          /* children holding ref on parent (LL) */
int             p_parentref;            /* children lookup ref on parent (LL) */
pid_t           p_oppid;                /* Save parent pid during ptrace. XXX */
u_int           p_xstat;                /* Exit status for wait; also stop signal. */

#ifdef _PROC_HAS_SCHEDINFO_
    /* may need cleanup, not used */
u_int           p_estcpu;               /* Time averaged value of p_cpticks.(used by aio and proc_comapre) */
fixpt_t         p_pctcpu;               /* %cpu for this process during p_swtime (used by aio)*/
u_int           p_slptime;              /* used by proc_compare */
#endif /* _PROC_HAS_SCHEDINFO_ */

struct  itimerval p_realtimer;          /* Alarm timer. (PSL) */
struct  timeval p_rtime;                /* Real time.(PSL)  */
struct  itimerval p_vtimer_user;        /* Virtual timers.(PSL)  */
struct  itimerval p_vtimer_prof;        /* (PSL) */

struct  timeval p_rlim_cpu;             /* Remaining rlim cpu value.(PSL) */
int             p_debugger;             /*  NU 1: can exec set-bit programs if suser */
boolean_t       sigwait;        /* indication to suspend (PL) */
void    *sigwait_thread;        /* 'thread' holding sigwait(PL)  */
void    *exit_thread;           /* Which thread is exiting(PL)  */
void *  p_vforkact;             /* activation running this vfork proc)(static)  */
int     p_vforkcnt;             /* number of outstanding vforks(PL)  */
int     p_fpdrainwait;          /* (PFDL) */
    /* Following fields are info from SIGCHLD (PL) */
pid_t   si_pid;                 /* (PL) */
u_int   si_status;              /* (PL) */
u_int   si_code;                /* (PL) */
uid_t   si_uid;                 /* (PL) */

void * vm_shm;                  /* (SYSV SHM Lock) for sysV shared memory */

#if CONFIG_DTRACE
user_addr_t                     p_dtrace_argv;                  /* (write once, read only after that) */
user_addr_t                     p_dtrace_envp;                  /* (write once, read only after that) */
lck_mtx_t                       p_dtrace_sprlock;               /* sun proc lock emulation */
uint8_t                         p_dtrace_stop;                  /* indicates a DTrace-desired stop */
int                             p_dtrace_probes;                /* (PL) are there probes for this proc? */
u_int                           p_dtrace_count;                 /* (sprlock) number of DTrace tracepoints */
struct dtrace_ptss_page*        p_dtrace_ptss_pages;            /* (sprlock) list of user ptss pages */
struct dtrace_ptss_page_entry*  p_dtrace_ptss_free_list;        /* (atomic) list of individual ptss entries */
struct dtrace_helpers*          p_dtrace_helpers;               /* (dtrace_lock) DTrace per-proc private */
struct dof_ioctl_data*          p_dtrace_lazy_dofs;             /* (sprlock) unloaded dof_helper_t's */
#endif /* CONFIG_DTRACE */

/* XXXXXXXXXXXXX BCOPY'ed on fork XXXXXXXXXXXXXXXX */
/* The following fields are all copied upon creation in fork. */
#define p_startcopy     p_argslen

u_int   p_argslen;       /* Length of process arguments. */
int     p_argc;                 /* saved argc for sysctl_procargs() */
user_addr_t user_stack;         /* where user stack was allocated */
struct  vnode * XNU_PTRAUTH_SIGNED_PTR("proc.p_textvp") p_textvp;       /* Vnode of executable. */
off_t   p_textoff;              /* offset in executable vnode */

sigset_t p_sigmask;             /* DEPRECATED */
sigset_t p_sigignore;   /* Signals being ignored. (PL) */
sigset_t p_sigcatch;    /* Signals being caught by user.(PL)  */

u_char  p_priority;     /* (NU) Process priority. */
u_char  p_resv0;        /* (NU) User-priority based on p_cpu and p_nice. */
char    p_nice;         /* Process "nice" value.(PL) */
u_char  p_resv1;        /* (NU) User-priority based on p_cpu and p_nice. */

// types currently in sys/param.h
command_t   p_comm;
proc_name_t p_name;     /* can be changed by the process */
uint8_t p_xhighbits;    /* Stores the top byte of exit status to avoid truncation*/
pid_t   p_contproc;     /* last PID to send us a SIGCONT (PL) */

struct  pgrp *  XNU_PTRAUTH_SIGNED_PTR("proc.p_pgrp") p_pgrp; /* Pointer to process group. (LL) */
uint32_t        p_csflags;      /* flags for codesign (PL) */
uint32_t        p_pcaction;     /* action  for process control on starvation */
uint8_t p_uuid[16];             /* from LC_UUID load command */

    /*
     * CPU type and subtype of binary slice executed in
     * this process.  Protected by proc lock.
     */
cpu_type_t      p_cputype;
cpu_subtype_t   p_cpusubtype;

uint8_t  *syscall_filter_mask;          /* syscall filter bitmask (length: nsysent bits) */
uint32_t        p_platform;
uint32_t        p_min_sdk;
uint32_t        p_sdk;

/* End area that is copied on creation. */
/* XXXXXXXXXXXXX End of BCOPY'ed on fork (AIOLOCK)XXXXXXXXXXXXXXXX */
#define p_endcopy       p_aio_total_count
int             p_aio_total_count;              /* all allocated AIO requests for this proc */
TAILQ_HEAD(, aio_workq_entry ) p_aio_activeq;   /* active async IO requests */
TAILQ_HEAD(, aio_workq_entry ) p_aio_doneq;     /* completed async IO requests */

struct klist p_klist;  /* knote list (PL ?)*/

struct  rusage_superset *p_ru;  /* Exit information. (PL) */
thread_t        p_signalholder;
thread_t        p_transholder;
int             p_sigwaitcnt;
    /* DEPRECATE following field  */
u_short p_acflag;       /* Accounting flags. */
volatile u_short p_vfs_iopolicy;        /* VFS iopolicy flags. (atomic bit ops) */

user_addr_t     p_threadstart;          /* pthread start fn */
user_addr_t     p_wqthread;             /* pthread workqueue fn */
int     p_pthsize;                      /* pthread size */
uint32_t        p_pth_tsd_offset;       /* offset from pthread_t to TSD for new threads */
user_addr_t     p_stack_addr_hint;      /* stack allocation hint for wq threads */
struct workqueue *_Atomic p_wqptr;                      /* workq ptr */

struct  timeval p_start;                /* starting time */
void *  p_rcall;
int             p_ractive;
int     p_idversion;            /* version of process identity */
void *  p_pthhash;                      /* pthread waitqueue hash */
volatile uint64_t was_throttled __attribute__((aligned(8))); /* Counter for number of throttled I/Os */
volatile uint64_t did_throttle __attribute__((aligned(8)));  /* Counter for number of I/Os this proc throttled */

#if DIAGNOSTIC
unsigned int p_fdlock_pc[4];
unsigned int p_fdunlock_pc[4];
#if SIGNAL_DEBUG
unsigned int lockpc[8];
unsigned int unlockpc[8];
#endif /* SIGNAL_DEBUG */
#endif /* DIAGNOSTIC */
uint64_t        p_dispatchqueue_offset;
uint64_t        p_dispatchqueue_serialno_offset;
uint64_t        p_dispatchqueue_label_offset;
uint64_t        p_return_to_kernel_offset;
uint64_t        p_mach_thread_self_offset;
#if VM_PRESSURE_EVENTS
struct timeval  vm_pressure_last_notify_tstamp;
#endif

#if CONFIG_MEMORYSTATUS
    /* Fields protected by proc list lock */
TAILQ_ENTRY(proc) p_memstat_list;               /* priority bucket link */
uint32_t          p_memstat_state;              /* state. Also used as a wakeup channel when the memstat's LOCKED bit changes */
int32_t           p_memstat_effectivepriority;  /* priority after transaction state accounted for */
int32_t           p_memstat_requestedpriority;  /* active priority */
int32_t           p_memstat_assertionpriority;  /* assertion driven priority */
uint32_t          p_memstat_dirty;              /* dirty state */
uint64_t          p_memstat_userdata;           /* user state */
uint64_t          p_memstat_idledeadline;       /* time at which process became clean */
uint64_t          p_memstat_idle_start;         /* abstime process transitions into the idle band */
uint64_t          p_memstat_idle_delta;         /* abstime delta spent in idle band */
int32_t           p_memstat_memlimit;           /* cached memory limit, toggles between active and inactive limits */
int32_t           p_memstat_memlimit_active;    /* memory limit enforced when process is in active jetsam state */
int32_t           p_memstat_memlimit_inactive;  /* memory limit enforced when process is in inactive jetsam state */
int32_t           p_memstat_relaunch_flags;     /* flags indicating relaunch behavior for the process */
#if CONFIG_FREEZE
uint32_t          p_memstat_freeze_sharedanon_pages; /* shared pages left behind after freeze */
uint32_t          p_memstat_frozen_count;
uint32_t          p_memstat_thaw_count;
#endif /* CONFIG_FREEZE */
#endif /* CONFIG_MEMORYSTATUS */

    /* cached proc-specific data required for corpse inspection */
pid_t             p_responsible_pid;    /* pid resonsible for this process */
_Atomic uint32_t  p_user_faults; /* count the number of user faults generated */

uint32_t          p_memlimit_increase; /* byte increase for memory limit for dyld SPI rdar://problem/49950264, structure packing 32-bit and 64-bit */

struct os_reason     *p_exit_reason;

#if CONFIG_PROC_UDATA_STORAGE
uint64_t        p_user_data;                    /* general-purpose storage for userland-provided data */
#endif /* CONFIG_PROC_UDATA_STORAGE */

char * p_subsystem_root_path;
lck_rw_t        p_dirs_lock;                    /* keeps fd_cdir and fd_rdir stable across a lookup */
pid_t           p_sessionid;
};

担心手机改出问题 .所以只对目标进程进行修改


     if( ISSET(lflagvalue, P_LNOATTACH))
                        {

						// change 630 to your target pid
							if(proc1->p_uniqueid == 630 ){
                  			printf(" !!!P_LNOATTACH set");
                            CLR(lflagvalue, P_LNOATTACH);
                            KERNEL_WRITE32(preptr + lflagoffset, lflagvalue);
							}
          
                        }



修改完后 debugserver附加目标app后手机重启了

zai 

在大佬的帮助下成功了


最后于 2024-6-4 20:05 被yuzhouheike编辑 ,原因: 评论不支持markdown语法
雪    币: 193
活跃值: (1407)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
alice 2024-6-6 11:59
21
0
借鉴和引用我的文章, 应该加个链接
雪    币: 599
活跃值: (1141)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
寻梦之璐 2024-6-11 17:42
22
0
wx_突突兔 https://ipsw.me/
你好,下载了之后打开全是binary,没有函数和字符串,请问如何定位
游客
登录 | 注册 方可回帖
返回