【iOS 底层】dyld探索

原创
2021/07/04 10:20
阅读数 63

基础

  1. 作用:将应用的MachO加载到内存中。
  2. dyld在系统中以一个用户态的可执行文件形式存在,一般应用程序会在MachO文件部分指定一个LC_LOAD_DYLINK的加载命令,此加载命令指定了****

流程探索

  1. 首先我们创建一个工程,在任一类的+(void)load方法中打上断点,根据函数调用栈可以看到,先走到的是_dyld_start
  2. 打开dyld工程,全局搜索dyldbootstrap可以找到这个namespace的start函数
uintptr_t start(const dyld3::MachOLoaded* appsMachHeader, int argc, const char* argv[],
				const dyld3::MachOLoaded* dyldsMachHeader, uintptr_t* startGlue)
{
    // Emit kdebug tracepoint to indicate dyld bootstrap has started <rdar://46878536>
    dyld3::kdebug_trace_dyld_marker(DBG_DYLD_TIMING_BOOTSTRAP_START, 0, 0, 0, 0);
	// if kernel had to slide dyld, we need to fix up load sensitive locations
	// we have to do this before using any global variables
	// 重定向。在rebaseDyld方法中,会进行ASLR
    rebaseDyld(dyldsMachHeader);
	// kernel sets up env pointer to be just past end of agv array
	const char** envp = &argv[argc+1];
	// kernel sets up apple pointer to be just past end of envp array
	const char** apple = envp;
	while(*apple != NULL) { ++apple; }
	++apple;
	// set up random value for stack canary
	// 栈溢出保护
	__guard_setup(apple);
#if DYLD_INITIALIZER_SUPPORT
	// run all C++ initializers inside dyld
	runDyldInitializers(argc, argv, envp, apple);
#endif
	_subsystem_init(apple);
	// now that we are done bootstrapping dyld, call dyld's main
	uintptr_t appsSlide = appsMachHeader->getSlide();
	return dyld::_main((macho_header*)appsMachHeader, appsSlide, argc, argv, envp, apple, startGlue);
}

ASLR随机值:当MachO加载到内存中时,会随机加一个变量,保证在不定的内存中分布。为了防止缓存溢出。

  1. 初始化工作完成之后,就会走到dyld::_main方法中执行加载。

dyld::_main

uintptr_t
_main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide, 
		int argc, const char* argv[], const char* envp[], const char* apple[], 
		uintptr_t* startGlue)

1.主程序加载的准备工作, 配置相关环境等

	···
	// 获取到主程序的MachO Header和ASLR等值,设置上下文信息, 判断进程是否受限
	sMainExecutableMachHeader = mainExecutableMH;
	sMainExecutableSlide = mainExecutableSlide;
	···
	setContext(mainExecutableMH, argc, argv, envp, apple);
	···
	configureProcessRestrictions(mainExecutableMH, envp);
// 以后分析加载三方库时,会发现有的环境变量会直接影响三方库是否被加载
  1. 加载共享缓存
	// 检查缓存是否是禁用状态【iOS共享缓存库无法被禁用】
	checkSharedRegionDisable((dyld3::MachOLoaded*)mainExecutableMH, mainExecutableSlide);
	// 加载
	mapSharedCache(mainExecutableSlide);
  1. 实例化主程序
	sMainExecutable = instantiateFromLoadedImage(mainExecutableMH,mainExecutableSlide,sExecPath);

待更新

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部