Detect if Cycript / substrate or gdb is connected to the iOS app process?

I am creating an iOS application that transfers sensitive data to my server, and I sign my API requests as an extra measure. I want to reverse engineer as quickly as possible, and using Cycript to find the key signatures of some real-world applications, I know that it’s not difficult to find these keys by joining the process. I am absolutely sure that if someone really knows how and is zealous enough, they will eventually use it, but I try to make it as difficult as possible, but at the same time convenient for myself and for users.

I can check the status of jailbroken and take additional measures, or I can perform SSL binding, but both of them are still easy to circumvent by joining the process and changing the memory.

Is there a way to detect if something is connected (be it Cycript, gdb or some other tool that can be used to hack the process) and does not deviate from the App Store?

EDIT: This is not a duplicate Detection if the iOS application is running in the debugger . This question is more connected with the output and checks the output stream to determine if there is an output stream connected to the registrar, while my question is not related to this (and this check does not apply to my condition).

+5
source share
3 answers

The definition of gdb is doable through the related transition stack question - it uses kstat to determine if the process is being debugged. This will determine if the debugger is connected to the process.

There is also a piece of code - Using the SEC_IS_BEING_DEBUGGED_RETURN_NIL macro in an iOS application - this allows you to make a macro that runs a debugger attached to a check in a variety of places in your code (this is C / Objective-C).

As for detecting Cycript, when it runs against a process, it injects dylib into the process to process messages between the cycript command line and the process - the library has a part of the name that resembles cynject . This name is not like any libraries that are present in a typical iOS application. This needs to be detected with a small loop ( C ):

 BOOL hasCynject() { int max = _dyld_image_count(); for (int i = 0; i < max; i++) { const char *name = _dyld_get_image_name(i); if (name != NULL) { if (strstr(name, "cynject") == 0) return YES; } } } 

Again, give it a better name than would be appropriate, and also confuse the line you are testing.

These are just the approaches that can be taken - unfortunately, they will protect you in some way at runtime, if someone wants to specify an IDA or some other disassembler, then you will not be protected.

The reason that the check for the debugger is implemented as a macro is because you will place the code in different places in the code, and as a result, someone trying to fix it will have to fix the application in a variety of places.

+5
source

As far as I know, injection of the Cycript process is made possible thanks to debugging symbols. Thus, if you disable debugging symbols for the App Store release (the default setting for the Release configuration), this will help.

Another action that you could take that would not affect the usability of the application would be to use an obfuscator. However, this will cause any crash reports to be useless because you cannot understand the symbols, even if the crash report was symbolized.

+2
source

Based on @petesh's answer, I found that the code below achieved what I wanted on a Cycript jailbreak phone. The existence of printf strings is gold for the reverse engineer, so this code is only suitable for demo / crack-me applications.

 #include <stdio.h> #include <string.h> #include <mach-o/dyld.h> int main () { int max = _dyld_image_count(); for (int i = 0; i < max; i++) { const char *name = _dyld_get_image_name(i); const char needle[11] = "libcycript"; char *ret; if ((ret = strstr(name, needle)) != NULL){ printf("%s\nThe substring is: %s\n", name, ret); } } return 0; } 
+2
source

Source: https://habr.com/ru/post/1237566/


All Articles