对doModInitFunctions理解的一次失败尝试

在网上看到一篇帖子,能够对C++ static initializers进行hook, 使用 MachOView 打开一个MachO文件,多数情况下会看到这个section __mod_init_func,里面保存了当前模块所有的initializer函数地址,当dyld调用doModInitFunctions时便能一一调用这些initizlizer。

因为__mod_init_func在data 段,于是尝试能否在程序运行的过程中动态修改这些initializer的函数地址以达到hook的目的

其中关键的文件在for循环中的这句: ```
memory[idx] = (MemoryType)myInitFunc_Initializer;

意思是将每个initializer的函数地址都改为自己的函数地址,但会导致崩溃,有哪位懂的能说说是啥原因不???

关键代码如下:

声明dyld中的doModInitFunctions函数
typedef void (*OriginalInitializer)(int argc, const char* argv[], const char* envp[], const char* apple[], const MyProgramVars* vars);

定义自己的ModInit函数
static void myInitFunc_Initializer(int argc, const char* argv[], const char* envp[], const char* apple[], const struct MyProgramVars* vars){
         NSLog(@"hook_cpp my init func\n");
         //其他代码。。。
}

static void hookModInitFunc(char *model_name) {

    uint32_t counts = _dyld_image_count();

    const struct mach_header *mhp;

    intptr_t slider;

    for(uint32_t i=0; i<counts; i++){

        const char* name = _dyld_get_image_name(i);

        if (strstr(name, model_name)) {

            mhp = _dyld_get_image_header(i);

            slider = _dyld_get_image_vmaddr_slide(i);

            break;

        }

    }



#ifndef __LP64__

    unsigned long size = 0;

    MemoryType *memory = (uint32_t*)getsectiondata(mhp, "__DATA", "__mod_init_func", & size);

#else /* defined(__LP64__) */

    const struct mach_header_64 *mhp64 = (const struct mach_header_64 *)mhp;

    unsigned long size = 0;

    MemoryType *memory = (uint64_t*)getsectiondata(mhp64, "__DATA", "__mod_init_func", & size);

#endif /* defined(__LP64__) */

    for(int idx = 0; idx < size/sizeof(void*); ++idx){

        MemoryType original_ptr = memory[idx];

        NSLog(@"original_ptr = %lld",original_ptr);

        [g_initializer addObject:[NSNumber numberWithLongLong:original_ptr]]; //保存原来的地址

        memory[idx] = (MemoryType)myInitFunc_Initializer;//替换为我们自己的Initializer
    }
}

@interface FooObject : NSObject @end
@implementation FooObject
+ (void)load{
    NSLog(@"hook_cpp==foo object load \n");
    
    g_initializer = [NSMutableArray new];
    g_cur_index = -1;
    
    char *model_name = (char *)"/test";// 一个名为test的APP
    hookModInitFunc(model_name);
}
@end

略微尝试了一下,有点奇怪:(测试于ios14.4 frida15)

把数组里的两个指针交换 应用不崩溃
数组某个指针值+4 应用不崩溃
将指针指向frida申请的函数 应用崩溃

所以这个指针可能有范围限制?

1 个赞

我刚也尝试了,直接把上面的代码放在test应用工程里执行,应用不崩溃

但尝试放在一个动态库中进行注入执行 就会崩溃

难道这个指针值真有范围限制?只能在当前模块中吗?这就有点意思了

 // <rdar://problem/8543820&9228031> verify initializers are in image
if ( ! this->containsAddress(stripPointer((void*)func)) ) {
    dyld::throwf("initializer function %p not in mapped image for %s\n", func, this->getPath());
}
//----------------
bool ImageLoader::containsAddress(const void* addr) const
{
	for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
		const uint8_t* start = (const uint8_t*)segActualLoadAddress(i);
		const uint8_t* end = (const uint8_t*)segActualEndAddress(i);
		if ( (start <= addr) && (addr < end) && !segUnaccessible(i) )
			return true;
	}
	return false;
}

限制了必须在当前模块的segment里面

1 个赞