bool OSKext::registerIdentifier(void) { // ... /* If we don't have an existing kext with this identifier, * just record the new kext and we're done! */ existingKext = OSDynamicCast(OSKext, sKextsByID->getObject(bundleID)); if (!existingKext) { sKextsByID->setObject(bundleID, this); result = true; goto finish; } // ... returntrue; }
void StartIOKit( void * p1, void * p2, void * p3, void * p4 ) { // ... /* If the bootstrap segment set up a function to record startup * extensions, call it now. */ if (record_startup_extensions_function) { record_startup_extensions_function(); } // ... }
/********************************************************************* * Set the function pointers for the entry points into the bootstrap * segment upon C++ static constructor invocation. *********************************************************************/ KLDBootstrap::KLDBootstrap(void) { if (this != &sBootstrapObject) { panic("Attempt to access bootstrap segment."); } record_startup_extensions_function = &bootstrapRecordStartupExtensions; load_security_extensions_function = &bootstrapLoadSecurityExtensions; }
/* Function pointer set up for loading security extensions. * It is set to an actual function after OSlibkernInit() * has been called, and is set back to 0 by OSKextRemoveKextBootstrap() * after bsd_init(). */ void (*load_security_extensions_function)(void) = 0;
/* * Init after early Mach startup, but before BSD */ void mac_policy_initmach(void) { /* * For the purposes of modules that want to know if they were * loaded "early", set the mac_late flag once we've processed * modules either linked into the kernel, or loaded before the * kernel startup. */ if (load_security_extensions_function) { load_security_extensions_function(); } mac_late = 1; }
/* * Now running in a thread. Kick off other services, * invoke user bootstrap, enter pageout loop. */ staticvoid kernel_bootstrap_thread(void) { // ... #ifdef IOKIT kernel_bootstrap_log("PE_init_iokit"); PE_init_iokit(); #endif
其中 OSKext::load 中包含了注册到 IOKit,OSRuntimeInitializeCPP 完成了 libkern 的一些 C++ 环境初始化。
AppleMobileFileIntegrity.kext 注册到 IOKit
注册与启动服务
我们先来看 load 阶段,在 OSKext::load 的函数最后包含了这样一段逻辑:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/* If not excluding matching, send the personalities to the kernel. * This never affects the result of the load operation. * This is a bit of a hack, because we shouldn't be handling * personalities within the load function. */ OSReturn OSKext::load( OSKextExcludeLevel startOpt, OSKextExcludeLevel startMatchingOpt, OSArray * personalityNames) { // ... if (result == kOSReturnSuccess && startMatchingOpt == kOSKextExcludeNone) { result = sendPersonalitiesToCatalog(true, personalityNames); } // ... }
kern_return_t OSRuntimeInitializeCPP( OSKext * theKext) { // ... /* Tell the meta class system that we are starting the load */ metaHandle = OSMetaClass::preModLoad(kmodInfo->name); // ... /* Scan the header for all constructor sections, in any * segment, and invoke the constructors within those sections. */ for (segment = firstsegfromheader(header); segment != NULL && load_success; segment = nextsegfromheader(header, segment)) { /* Record the current segment in the event of a failure. */ failure_segment = segment; load_success = OSRuntimeCallStructorsInSection( theKext, kmodInfo, metaHandle, segment, sectionNames[kOSSectionNameInitializer], textStart, textEnd); } /* for (segment...) */ // ... /* Now, regardless of success so far, do the post-init registration * and cleanup. If we had to call the unloadCPP function, static * destructors have removed classes from the stalled list so no * metaclasses will actually be registered. */ result = OSMetaClass::postModLoad(metaHandle); // ... }
Pre 阶段
这里的加载主要包含 3 个阶段,其中 pre 阶段主要是为了准备 kext 的 Main Class 的加载上下文,这里的上下文通过一个全局变量保存,并通过一个锁保证串行队列:
/* * While loading a kext and running all its constructors to register * all OSMetaClass classes, the classes are queued up here. Only one * kext can be in flight at a time, guarded by sStalledClassesLock */ staticstructStalledData { constchar * kextIdentifier; OSReturn result; unsignedint capacity; unsignedint count; OSMetaClass ** classes; } * sStalled; IOLock * sStalledClassesLock = NULL;
/********************************************************************* * The core constructor for a MetaClass (defined with this name always * but within the scope of its represented class). * * MetaClass constructors are invoked in OSRuntimeInitializeCPP(), * in between calls to OSMetaClass::preModLoad(), which sets up for * registration, and OSMetaClass::postModLoad(), which actually * records all the class/kext relationships of the new MetaClasses. *********************************************************************/
OSReturn OSMetaClass::postModLoad(void * loadHandle) { // ... // static OSDictionary * sAllClassesDict; sAllClassesDict = OSDictionary::withCapacity(kClassCapacityIncrement); sAllClassesDict->setOptions(OSCollection::kSort, OSCollection::kSort); myKextName = const_cast<OSSymbol *>(OSSymbol::withCStringNoCopy( sStalled->kextIdentifier)); myKext = OSKext::lookupKextWithIdentifier(myKextName); /* First pass checking classes aren't already loaded. If any already * exist, we don't register any, and so we don't technically have * to do any C++ teardown. * * Hack alert: me->className has been a C string until now. * We only release the OSSymbol if we store the kext. */ IOLockLock(sAllClassesLock); for (unsignedint i = 0; i < sStalled->count; i++) { const OSMetaClass * me = sStalled->classes[i]; unsignedint depth = 1; while ((me = me->superClassLink)) { depth++; } // static unsigned int sDeepestClass; if (depth > sDeepestClass) { sDeepestClass = depth; } } IOLockUnlock(sAllClassesLock); IOLockLock(sAllClassesLock); for (unsignedint i = 0; i < sStalled->count; i++) { const OSMetaClass * me = sStalled->classes[i]; OSMetaClass * me = sStalled->classes[i]; me->className = OSSymbol::withCStringNoCopy((constchar *)me->className); sAllClassesDict->setObject(me->className, me); me->reserved->kext = myKext; myKext->addClass(me, sStalled->count); } IOLockLock(sAllClassesLock); sBootstrapState = kCompletedBootstrap; sStalled = NULL; return kOSReturnSuccess; }