jmpews/NoteZ

Darwin [dyld] Tips

jmpews opened this issue · 0 comments

Prologue

Somniloquy

1. Dyld 中有一些 Macho 文件格式描述的文件, 适合用来做 parser | Tag: [parser]

dyld-519.2.1/launch-cache/MachOFileAbstraction.hpp

dyld-519.2.1/launch-cache/MachOLayout.hpp

dyld-519.2.1/launch-cache/FileAbstraction.hpp

dyld-519.2.1/launch-cache/Architectures.hpp

2. ARM64 下的 macho-segment 必须做 dyld_page_round 对齐, 也就是 0x4000 | Tag: [brute-force]

具体参考:

// dyld-519.2.1/src/ImageLoaderMachO.cpp
intptr_t ImageLoaderMachO::assignSegmentAddresses(const LinkContext& context)
{
    // preflight and calculate slide if needed
    const bool inPIE = (fgNextPIEDylibAddress != 0);
    intptr_t slide = 0;
    if ( this->segmentsCanSlide() && this->segmentsMustSlideTogether() ) {
        bool needsToSlide = false;
        bool imageHasPreferredLoadAddress = segHasPreferredLoadAddress(0);
        uintptr_t lowAddr = (unsigned long)(-1);
        uintptr_t highAddr = 0;
        for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
            const uintptr_t segLow = segPreferredLoadAddress(i);
            // <<Tips>> set segment map end address with round(segSeize(i))
            const uintptr_t segHigh = dyld_page_round(segLow + segSize(i));
            if ( segLow < highAddr ) {
                if ( dyld_page_size > 4096 )
                    dyld::throwf("can't map segments into 16KB pages");
                else
                    dyld::throwf("overlapping segments");
            }
            if ( segLow < lowAddr )
                lowAddr = segLow;
            if ( segHigh > highAddr )
                highAddr = segHigh;

            if ( needsToSlide || !imageHasPreferredLoadAddress || inPIE || !reserveAddressRange(segPreferredLoadAddress(i), segSize(i)) )
                needsToSlide = true;
        }
        if ( needsToSlide ) {
            // find a chunk of address space to hold all segments
            uintptr_t addr = reserveAnAddressRange(highAddr-lowAddr, context);
            slide = addr - lowAddr;
        }
    }

3. 可以通过 removeImageFromAllImages 将一个 dylib 的信息从 dyld_all_image_infos 的 vector list 中逻辑删除 | Tag: [inject-detect-bypass, jailbreak-detect-bypass]

这是一个未保留的函数, 可以从两个角度进行调用.

  1. parse dyld, search symbol table
  2. dyld_load_address + function_offset (hardcode)

4. Convert macho executable to dyld | Tag: [reverse]

  1. remove __PAGEZERO

ref: blog.imjun.net/posts/convert-iOS-app-to-dynamic-library/

  1. hook dyld load check Function

ref: http://iosre.com/t/pagezero/10249/7

5. dyld 的 lazy bind 函数 dyld_stub_binder | Tag: [context-save]

refer: /Users/jmpews/Downloads/dyld-433.5/src/dyld_stub_binder.s

#if __arm64__
 /*    
  * sp+0	lazy binding info offset
  * sp+8	address of ImageLoader cache
  */
	.text
	.align 2
	.globl	dyld_stub_binder
dyld_stub_binder:
	stp		fp, lr, [sp, #-16]!
	mov		fp, sp
	sub		sp, sp, #240
	stp		x0,x1, [fp, #-16]	; x0-x7 are int parameter registers
	stp		x2,x3, [fp, #-32]
	stp		x4,x5, [fp, #-48]
	stp		x6,x7, [fp, #-64]
	stp		x8,x9, [fp, #-80]	; x8 is used for struct returns
	stp		q0,q1, [fp, #-128]	; q0-q7 are vector/fp parameter registers
	stp		q2,q3, [fp, #-160]
	stp		q4,q5, [fp, #-192]
	stp		q6,q7, [fp, #-224]

	ldr		x0, [fp, #24]	; move address ImageLoader cache to 1st parameter
	ldr		x1, [fp, #16]	; move lazy info offset 2nd parameter
	; call dyld::fastBindLazySymbol(loadercache, lazyinfo)
	bl		__Z21_dyld_fast_stub_entryPvl
	mov		x16,x0			; save target function address in lr
	
	; restore parameter registers
	ldp		x0,x1, [fp, #-16]
	ldp		x2,x3, [fp, #-32]
	ldp		x4,x5, [fp, #-48]
	ldp		x6,x7, [fp, #-64]
	ldp		x8,x9, [fp, #-80]
	ldp		q0,q1, [fp, #-128]
	ldp		q2,q3, [fp, #-160]
	ldp		q4,q5, [fp, #-192]
	ldp		q6,q7, [fp, #-224]
	
	mov		sp, fp
	ldp		fp, lr, [sp], #16
	add		sp, sp, #16	; remove meta-parameters
	br		x16

#endif