In the application development process, we need to not only complete the normal business logic, application performance, code robustness related issues, we sometimes need to consider the application security issues.
So the issue of application security has a lot to do with it. For example, to prevent static analysis, code confusion, logic confusion; To prevent re-signing, apply ID checking, even code HASH checking, and so on. So in this article I want to talk about injection detection of code, because we find that with the update of iOS, our protection methods have changed a little bit.
Code injection
There are roughly two ways to inject code
-
Jailbreak injection: Inserts dynamic libraries and executes by modifying the value of the DYLD_INSERT_LIBRARIES environment variable
-
Non-jailbreak injection:
-
Package your custom Framwork or Dylib libraries directly into the APP and re-sign them
-
Use Yololib to modify the MachO file and add the library path. Dyld loads and executes when the application starts.
-
Early protection mode
Find Other Linker Flages in the project’s Build Settings and add the field
-Wl,-sectcreate,__RESTRICT,__raestrict,/dev/null
This operation adds a Section to the executable file. We use MachOView as follows:
When this field is present in the MachO file, the way we insert the dynamic library through the jailbreak environment is disabled. Play a protective role. Its principle can be analyzed in DYLD source code.
Dyld source code analysis
The source version of DYLD analyzed here is 519.2.2. We can locate the _main function to load the insert dynamic library by retrieving DYLD_INSERT_LIBRARIES as follows.
if ( sEnv.DYLD_INSERT_LIBRARIES ! = NULL ) { for (const char* const* lib = sEnv.DYLD_INSERT_LIBRARIES; *lib ! = NULL; ++lib) loadInsertedDylib(*lib); }Copy the code
But long before this environmental variable was judged, Dyld had made a judgment call
pruneEnvironmentVariables(envp, &apple);
// set again because envp and apple may have changed or moved
setContext(mainExecutableMH, argc, argv, envp, apple);
}
Copy the code
If the process is restricted! The current process is restricted from inserting into the dynamic library! Will call pruneEnvironmentVariables function to remove related environment variables.
When will our processIsRestricted value be true?
Further analysis of the source reveals that two key functions influence its value. The hasRestrictedSegment function specializes in detecting RESTRICT segments
if ( issetugid() || hasRestrictedSegment(mainExecutableMH) ) {
gLinkContext.processIsRestricted = true;
}
Copy the code
You can also see this through comments. Dynamic library inserts for any process whose __RESTRICT section is set to RESTRICTED will be restricted. We enter the processIsRestricted function, which is implemented as follows.
static bool hasRestrictedSegment(const macho_header* mh)
{
const uint32_t cmd_count = mh->ncmds;
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:
{
const struct macho_segment_command* seg = (struct macho_segment_command*)cmd;
//dyld::log("seg name: %s\n", seg->segname);
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) {
if (strcmp(sect->sectname, "__restrict") == 0)
return true;
}
}
}
break;
}
cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
}
return false;
}
Copy the code
Therefore, setting restricted to RESTRICTED in MachO by adding Other Linker Flags can be used to prevent code injection from jailbreaking. But the new dyLD source code drops the __RESTRICT detection. Starting with iOS10, this protection is no longer available
DYLD_INSERT_LIBRARIES detection
Now that the DYLD loading process no longer checks the __RESTRICT section, we manually check the DYLD_INSERT_LIBRARIES environment variable. Function to view the value of the current process environment variable.
char *env = getenv("DYLD_INSERT_LIBRARIES");
NSLog(@"%s",env);
Copy the code
Env is null when the dynamic library is not inserted. Then we can see the console output once the plug-in is written to our application
The 2019-01-03 19:20:37. 285 antiInject [7482-630392] / Library/MobileSubstrate/MobileSubstrate dylibCopy the code
Whitelist detection
So the above detection can only detect code injection in jailbroken environments. In non-jailbroken environments, reverse engineers can use the Yololib tool to inject dynamic libraries. So we can check to see if the dynamic library loaded by our application is owned by our source
bool HKCheckWhitelist(){
int count = _dyld_image_count();
for(int i = 0; i < count; I++) {// get the library name! const char * imageName = _dyld_get_image_name(i); // To determine whether the application is in the whitelist, the path of the application itself is uncertain, so it should be excluded.if(! strstr(libraries, imageName)&&! strstr(imageName,"/var/mobile/Containers/Bundle/Application")) {
printf("This library is not whitelisted!! \n%s",imageName);
returnNO; }}return YES;
}
Copy the code
Where the libraries variable is whitelist.
Xiaobian recommend a QQ group: 551346706 this group is quite good, I am in the group to see the learning materials to write this article, this article has source code and video materials need to understand, the group and the interview questions and algorithms of major factories. There are also a lot of ordinary work problems can be solved.