越狱的设备上,在应用运行的时候插入动态库
划重点----DYLD_INSERT_LIBRARIES
DYLD源码分析
dyld.cpp-插入任意的libraries
_main(const macho_header* mainExecutableMH, uintptr_t mainExecutableSlide,
int argc, const char* argv[], const char* envp[], const char* apple[],
uintptr_t* startGlue){
...
#if __MAC_OS_X_VERSION_MIN_REQUIRED
//当allowEnvVarsPrint、allowEnvVarsPath、allowEnvVarsSharedCache全为false时
if ( !gLinkContext.allowEnvVarsPrint && !gLinkContext.allowEnvVarsPath && !gLinkContext.allowEnvVarsSharedCache ) {
//移除插入的环境变量,执行这个方法后面的插入就会失败
pruneEnvironmentVariables(envp, &apple);
// set again because envp and apple may have changed or moved
setContext(mainExecutableMH, argc, argv, envp, apple);
}
else
#endif
...
// load any inserted libraries
if ( sEnv.DYLD_INSERT_LIBRARIES != NULL ) {
for (const char* const* lib = sEnv.DYLD_INSERT_LIBRARIES; *lib != NULL; ++lib)
loadInsertedDylib(*lib);
}
...
return result;
}
如何才能让allowEnvVarsPrint、allowEnvVarsPath、allowEnvVarsSharedCache全为false呢
dyld.cpp
static void configureProcessRestrictions(const macho_header* mainExecutableMH)
{
...
bool isRestricted = false;
bool libraryValidation = false;
// any processes with setuid or setgid bit set or with __RESTRICT segment is restricted
//issetugid无法改变,所以只有看hasRestrictedSegment什么时候为true
if ( issetugid() || hasRestrictedSegment(mainExecutableMH) ) {
isRestricted = true;
}
bool usingSIP = (csr_check(CSR_ALLOW_TASK_FOR_PID) != 0);
uint32_t flags;
if ( csops(0, CS_OPS_STATUS, &flags, sizeof(flags)) != -1 ) {
// On OS X CS_RESTRICT means the program was signed with entitlements
if ( ((flags & CS_RESTRICT) == CS_RESTRICT) && usingSIP ) {
isRestricted = true;
}
// Library Validation loosens searching but requires everything to be code signed
if ( flags & CS_REQUIRE_LV ) {
isRestricted = false;
libraryValidation = true;
}
}
//当isRestricted为true时
gLinkContext.allowAtPaths = !isRestricted;
gLinkContext.allowEnvVarsPrint = !isRestricted;
gLinkContext.allowEnvVarsPath = !isRestricted;
...
}
//
// Look for a special segment in the mach header.
// Its presences means that the binary wants to have DYLD ignore
// DYLD_ environment variables.
//
#if __MAC_OS_X_VERSION_MIN_REQUIRED
//mh为MachO文件的头
static bool hasRestrictedSegment(const macho_header* mh)
{
const uint32_t cmd_count = mh->ncmds;
//cmds为commands
const struct load_command* const cmds = (struct load_command*)(((char*)mh)+sizeof(macho_header));
const struct load_command* cmd = cmds;
for (uint32_t i = 0; i < cmd_count; ++i) {
switch (cmd->cmd) {
case LC_SEGMENT_COMMAND:
{
//取出SEGMENT
const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
//dyld::log("seg name: %s\n", seg->segname);
//是否存在segment的那么为__RESTRICT
if (strcmp(seg->segname, "__RESTRICT") == 0) {
const struct macho_section* const sectionsStart = (struct macho_section*)((char*)seg + sizeof(struct macho_segment_command));
const struct macho_section* const sectionsEnd = §ionsStart[seg->nsects];
for (const struct macho_section* sect=sectionsStart; sect < sectionsEnd; ++sect) {
//是否存在segment的value为__restrict
if (strcmp(sect->sectname, "__restrict") == 0)
return true;
}
}
}
break;
}
cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
}
return false;
}
#endif
总结
通过在Mach-O文件中,增加segname为__RESTRICT,value为__restrict的值,可以使isRestricted返回YES,然后后gLinkContext.allowAtPaths、gLinkContext.allowEnvVarsPrint、gLinkContext.allowEnvVarsPath值就为false,进而执行pruneEnvironmentVariables方法,移除插入的环境变量,最终是的插入失败
越狱防护
Build Setting -> Other Linker Flags 中新增内容
-Wl,-sectcreate,__RESTRICT,__restrict,/dev/null
这个设置可以在Mach-O文件中增加segname为__RESTRICT,value为__restrict的段,以达到防护的效果!!!
生活如此美好,今天就点到为止。。。