Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
155 views
in Technique[技术] by (71.8m points)

ios - What would be the best approach patch-finding the pointer of a certain function on the XNU Kernel?

I am currently working on an iOS Jailbreak for iOS 13.7. As part of the jailbreak, I need to do a series of patches to the XNU Kernel live in the memory. Of course, the kernel is protected by kASLR, KPP / KTRR, and other memory watchdogs that would trigger a Kernel Panic if something is modified. As luck would have it, KTRR (Kernel Text Ready Only Region) can only protect, well, static data that is not supposed to change (i.e. the TEXT section and constants). The variables can still be altered.

I am building a PatchFinder which is supposed to locate a function or a variable in the XNU memory based on tell-tale symbols and I am wondering what would be the most effective approach for this.

I am currently adapting on top of the PatchFinder made publicly available back in the iOS 8 era by in7egal which looks like this:

uint32_t find_cs_enforcement_disable_amfi(uint32_t region, uint8_t* kdata, size_t ksize)
{
    // Find a function referencing cs_enforcement_disable_amfi
    const uint8_t search_function[] = {0x20, 0x68, 0x40, 0xF4, 0x40, 0x70, 0x20, 0x60, 0x00, 0x20, 0x90, 0xBD};
    uint8_t* ptr = memmem(kdata, ksize, search_function, sizeof(search_function));
    if(!ptr)
        return 0;

    // Only LDRB in there should try to dereference cs_enforcement_disable_amfi
    uint16_t* ldrb = find_last_insn_matching(region, kdata, ksize, (uint16_t*) ptr, insn_is_ldrb_imm);
    if(!ldrb)
        return 0;

    // Weird, not the right one.
    if(insn_ldrb_imm_imm(ldrb) != 0 || insn_ldrb_imm_rt(ldrb) > 12)
        return 0;

    // See what address that LDRB is dereferencing
    return find_pc_rel_value(region, kdata, ksize, ldrb, insn_ldrb_imm_rn(ldrb));
}

I wonder if there is any faster way or a more reliable way to locate the cs_enforcement_disable_amfi.

Once found by the PatchFinder in the XNU Kernel memory, it's used like this:

uint32_t cs_enforcement_disable_amfi = find_cs_enforcement_disable_amfi(kernel_base, kdata, ksize);
    printf("cs_enforcement_disable_amfi is at=0x%08x
",cs_enforcement_disable_amfi);
    if (cs_enforcement_disable_amfi){
        char patch[] ="x00xbfx00xbfx00xbfx00xbfx00xbf";
        kern_return_t kernret = vm_write(proccessTask, cs_enforcement_disable_amfi+kernel_base, patch, sizeof(patch)-1);
        if (kernret == KERN_SUCCESS){
            printf("Successfully patched cs_enforcement_disable_amfi
");
        }
    }

So the PatchFinder has to be able to reliably return the pointer to cs_enforcement_disable_amfi otherwise I am blindly writing to an invalid (or valid but different) address which almost certainly will trigger memory corruption.

The current code does return a valid pointer to cs_enforcement_disable_amfi most of the time, but randomly panics the kernel about 10-15% of the time which means the address it returns 10-15% of the time is invalid. Not sure how to make it more reliable.

question from:https://stackoverflow.com/questions/65516664/what-would-be-the-best-approach-patch-finding-the-pointer-of-a-certain-function

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The variable you're looking for doesn't exist anymore.

The bytes in your first snippet make up Thumb instructions, which find this function in AMFI in a 32bit kernelcache:

0x8074ad04      90b5           push {r4, r7, lr}
0x8074ad06      01af           add r7, sp, 4
0x8074ad08      0d48           ldr r0, [0x8074ad40]
0x8074ad0a      7844           add r0, pc
0x8074ad0c      0078           ldrb r0, [r0]
0x8074ad0e      0128           cmp r0, 1
0x8074ad10      03d1           bne 0x8074ad1a
0x8074ad12      0020           movs r0, 0
0x8074ad14      00f04efa       bl 0x8074b1b4
0x8074ad18      30b9           cbnz r0, 0x8074ad28
0x8074ad1a      7c69           ldr r4, [r7, 0x14]
0x8074ad1c      002c           cmp r4, 0
0x8074ad1e      05d0           beq 0x8074ad2c
0x8074ad20      2068           ldr r0, [r4]
0x8074ad22      40f44070       orr r0, r0, 0x300
0x8074ad26      2060           str r0, [r4]
0x8074ad28      0020           movs r0, 0
0x8074ad2a      90bd           pop {r4, r7, pc}

Given the magic constant 0x300 and the fact that AMFI's __TEXT_EXEC segment is quite small, we can easily find this in other kernels, including 64bit ones.
This is what it looks like on an iPhone 5s on 8.4:

0xffffff800268d2e4      f44fbea9       stp x20, x19, [sp, -0x20]!
0xffffff800268d2e8      fd7b01a9       stp x29, x30, [sp, 0x10]
0xffffff800268d2ec      fd430091       add x29, sp, 0x10
0xffffff800268d2f0      f30307aa       mov x19, x7
0xffffff800268d2f4      e8fc1110       adr x8, section.com.apple.driver.AppleMobileFileIntegrity.10.__DATA.__bss
0xffffff800268d2f8      1f2003d5       nop
0xffffff800268d2fc      08054039       ldrb w8, [x8, 1]
0xffffff800268d300      a8000037       tbnz w8, 0, 0xffffff800268d314
0xffffff800268d304      130100b4       cbz x19, 0xffffff800268d324
0xffffff800268d308      680240b9       ldr w8, [x19]
0xffffff800268d30c      08051832       orr w8, w8, 0x300
0xffffff800268d310      680200b9       str w8, [x19]
0xffffff800268d314      00008052       mov w0, 0
0xffffff800268d318      fd7b41a9       ldp x29, x30, [sp, 0x10]
0xffffff800268d31c      f44fc2a8       ldp x20, x19, [sp], 0x20
0xffffff800268d320      c0035fd6       ret

But by the time of iOS 11, the variable is gone:

0xfffffff006245d84      f44fbea9       stp x20, x19, [sp, -0x20]!
0xfffffff006245d88      fd7b01a9       stp x29, x30, [sp, 0x10]
0xfffffff006245d8c      fd430091       add x29, sp, 0x10
0xfffffff006245d90      f30307aa       mov x19, x7
0xfffffff006245d94      130100b4       cbz x19, 0xfffffff006245db4
0xfffffff006245d98      680240b9       ldr w8, [x19]
0xfffffff006245d9c      08051832       orr w8, w8, 0x300
0xfffffff006245da0      680200b9       str w8, [x19]
0xfffffff006245da4      00008052       mov w0, 0
0xfffffff006245da8      fd7b41a9       ldp x29, x30, [sp, 0x10]
0xfffffff006245dac      f44fc2a8       ldp x20, x19, [sp], 0x20
0xfffffff006245db0      c0035fd6       ret

Looking as iOS 12.0b1, we can learn the signature of that function:

_vnode_check_exec(ucred*, vnode*, vnode*, label*, label*, label*, componentname*, unsigned int*, void*, unsigned long)

So yeah, finding this function is really easy:

  1. Find AMFI's __TEXT_EXEC segment.
  2. Find an orr wN, wN, 0x300 in it.

But that won't help you unless you defeat kernel integrity.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...