Don’t be a fake learner

In the last article we looked at how Fishhook works, but there are many things that we can’t really absorb and translate into our own productivity if we just know the principles. You have to figure out how others use this principle to solve problems, but also learn from other people’s design ideas, and then combine our own thinking and practice and summary, in order to truly make knowledge become their own productivity.

Without further ado, let’s move on to the first topic of the day.

Fishhook usage scenario

The basic usage was demonstrated in the last article, and it is very simple to use, so I won’t expand it here. It is used in the fishhook scenario, as its name suggests, primarily for security purposes. Of course, god level of reverse and security protection experts let’s not talk about, that level of master I believe will not see this article, there is no absolute security, black and white will always be in the game, so I hope we do not boggle, at least we can not write a novice reverse can easily fix the application, right? Of course, we will also learn the knowledge of static analysis and assembly, master more advanced reverse and protection skills, that is to lay a good foundation after the words. Today we focus on source code analysis, incidentally review the C data structure.

Here’s a look at the basic idea of using FishHook to prevent HOOK attacks:

  1. In the basic dynamic debugging reverse, the most common method is to locate the target method, through several methods in the Runtime exchange, to achieve the purpose of code injection. Ready for you related article: iOS code injection +HOOK wechat login
  2. Since FishHook can intercept C functions outside the system, it can HOOK all methods in the Runtime library.
  3. We will then use FishHook to block any Runtime API that might be used to tamper with our OC method implementation so that it cannot be successfully hooked by code injection.

Clear your head, roll up your sleeves and get to work.

  • And just for the sake of demonstration, I’m going to go straight to a category here, which is ViewController instance methodsviewDidAppear:method_exchangeImplementations(Method _Nonnull m1, Method _Nonnull m2)The way tomy_viewDidAppear:Switch the implementation, on the code:

    When the program runs, we can see the following output:

  • To prevent it from completing the method exchange, we hookmethod_exchangeImplementationsMethod, drag in the Fishhook source file, add a category, and write the hookmethod_exchangeImplementationsThe code :(if successful hookmethod_exchangeImplementationsWhen someone else calls the methodmyExchangeAnd then by the wayNSLogDon’t be fooled by this 😜)

    Run again, huh? You will findmethod_exchangeImplementationsDidn’t HOOK it,viewDidAppear:Still tampered with the implementation, what’s the problem?

Yes, you must have found the problem: it was the order in which the code was executed

After practice, I found that the order of files involved in compilation in the project is the same as the loading order after compilation (the official compilation order has not been found yet, please refer to the research leaders for guidance). The load method of ViewController+HOOKTest will be called before the load method of ViewController+FishHook. So the implementation of method_exchangeImplementations gets us HOOK happening after viewDidAppear: is exchanged by someone else, thus causing the protection to fail:

So as you can see, we successfully hooked method_exchangeImplementations after we changed the order in which we compiled the file, but we can’t do something that clumsy in real development, and we can’t determine the loading order of the file that way, So we have to make sure that the Fishhook code is executed first.

So how do you do that? From the previous dyLD backstory & source code analysis, classes in the native Framework are always initialized before classes in the injected libraries (except for dynamic libraries, where non-jailbroken devices do not have access to dynamic libraries) and executable files. So we can move fishHook’s HOOK operation code into our own Framework:

method_getImplementation
method_setImplementation
exit(0)

Let’s move on to the second topic, source code analysis.

Fishhook source code analysis

When writing fishhook code, the first thing to do is declare a structure variable of type rebinding. The source code is as follows:

void **replaced
*replaced
method_exchangeImplementations
**replaced
method_exchangeImplementations

After writing the declaration and implementation according to the type of the struct members, assign values to the corresponding struct members one by one, and then put these struct members into an array. Then call the rebinding symbol function rebind_symbols(return 0 if the binding is successful, return -1 otherwise), and pass the struct array and the array length as parameters:

  1. The first thing I do is I call this functionprepend_rebindings, its specific implementation is as follows:

    Yi? The first argument passed in&_rebindings_headWhat is it?

    See the source code:_rebindings_headIs declared as a pointerrebindings_entryStatic pointer variable to a type structure, that&_rebindings_headTake the address of the pointer and look at the parameter declaration of the functionstruct rebindings_entry **Yeah, it’s another pointer to a pointer.

    The structure of the bodyrebindings_entryThe three members of are: point torebindingPointer to the first element of the structure array passed inrebindings_nel: Records the number of rebindings to be made this time (to create space of corresponding size), pointing to the next onerebindings_entryType of structure (to record the data that needs to be rebound next time), this is the typical data structure —The listAn implementation of._rebindings_headIt’s a pointer to that list.

To better understand the bindings function, I’ve drawn a diagram of how the Prepend_rebindings function works:

conclusion
prepend_rebindings
The new REbindings array is continuously added to the _rebindingS_head head of the list as a new header node

  1. The second thing is to hook the loaded image file (that is, the library) to find the target symbol one by one. We already know that fishHook’s code is executed very early, so the library to hook on the first execution may not have finished loading, so the first call will register the listener and callback methods through a function that loads the library:

extern void _dyld_register_func_for_add_image(void (*func)(const struct mach_header* mh, intptr_t vmaddr_slide))    __OSX_AVAILABLE_STARTING(__MAC_10_1, __IPHONE_2_0);
Copy the code

The source code is annotated as follows:

_rebind_symbols_for_image
header
image
slide

  1. The third thing is to find the function implementation address to which the pointer to the target symbol points, based on how Fishhook finds its steps in the shared library function implementation based on the pointer to the string in the symbol table:

    This process is rather boring, nothing more than a regular calculation of the address of various tables and Pointers in the table offset.

  2. Finally, based on the calculated symbol table address and offset, find the pointer used in the symbol table to point to the shared library target function, assign the value of the pointer (the address of the target function) to our * replacement, and finally change the value of the pointer to our replacement (the new function address). Perform_rebinding_with_section

Fishhook source code tour, come to an end

The fishhook source code implementation is 180+ lines without comments, and if you can read every line of fishhook’s source code, I’m sure you’ll have a better understanding of both Pointers and the data structure and implementation of linked lists. Of course, you get a better understanding of MachO’s file structure and loading mechanism, as well as basic security tips. Anyway, I hope your trip was worth it.

LLDB