Code example analysis of inline hook in Android

The following content analyzes the usage of inline hook in android in detail from four aspects: 1. Implementing the target injection program, 2. Implementing the main program, 3. Implementing the injection function, 4. Implementing the thumb instruction set. The following is all the content: @ h_ 301_ 1@

Recently, I finally settled down to knock the code of hook and injection into the book, and planned to write several blogs to record them.

For the first time, I will introduce the most difficult inline hook. The implementation code refers to the game security introduction of Tencent GAD.

The general process of inline hook is as follows:

First, replace the target instruction with the jump instruction, and the jump address is a piece of assembly code written by ourselves. This assembly code first executes the code specified by the user, such as modifying the value of the register, then executes the replaced original instruction 2, and finally jumps back to the original instruction 3 to restore the normal operation of the program.

In order to avoid the injection process, we demonstrate it through the dynamic connection library loaded by hook's own process.

1. Implement target injection program

We compile this program into a dynamic link library, and then load it in the main program as the target of hook.

Note local in android.mk_ ARM_ Mode: = arm means that the 4-byte arm instruction set is used at compile time instead of the 2-byte thumb instruction set.

2. Implement the main program

In the main program, we first load the dynamic link library written before, and then hook the function target_ Foo.

Here, the implementation function of our hook function is hook_ inline_ Make, the four parameters are dynamic library path, target address, user function and instruction set at target address.

When the program executes to the target address, it will call back the user function we passed in, which can be accessed through the parameter hook_ Reg to change the value of the register (excluding register PC). Because the android.mk file of the dynamic link library specifies to compile using the arm instruction set, the last parameter specified here is true.

3. Implement injection function

Now to the most critical place, in order to realize this function, we still need to understand a few knowledge.

(1) . get the base address of the dynamic link library in memory

The memory loading information of each process in the Linux system can be found in the / proc / PID / maps file. Through it, we can get the loading base address of the dynamic link library in memory.

(2) , change binary code in memory

In today's computer system, memory is generally managed in segments. Different segments have different properties of reading, writing and execution. Generally speaking, code segments only have read and execute attributes, and write operations on code segments are not allowed. In Linux system, the properties of memory are changed through the function mprotect. One thing to note is that it needs to be aligned with the size of memory pages.

Next, we can start to implement the function. The inline hook is closely related to the instruction set. Here, we first demonstrate the arm instruction set, and then discuss the thumb instruction set. The function realized here is that users can modify the value of hook point register in their registered callback function.

In order to realize the long jump of 32-bit address space, we need the length of two instructions (8 bytes). Generally, the arm processor on a mobile phone is a three-level pipeline, so the value of the PC register always points to the second instruction after the current instruction is executed. Therefore, LDR, PC, [PC, #-4] is used to load the jump address after the instruction. When the program jumps to shellcode, the register group is first backed up, then the callback function registered by the user is invoked. The user can modify the values of all registers in the backup (except PC registers) in the callback function, then recover the register set from the backup and then jump to stubcode. The function of stubcode is to execute the two instructions replaced by the jump instruction of the hook point. Finally, jump back to the original program.

Shellcode is implemented by assembly. When it is used, it needs to repair the two addresses inside. The user callback function address (_hook_func_addr_s) and the stub code address (_stub_func_addr_s).

Next, we can look at the hook function_ inline_ The concrete implementation of make

Note the change here_ addr_ The writable function will add an execution attribute to the address corresponding to false or true. Since the processor adopts pipeline and multi-level cache, we need to manually refresh the cache after changing the code, that is, the function cacheflush (the third parameter is meaningless).

4. Thumb instruction set implementation

Because the function of thumb instruction set is limited, although the idea is the same as that of arm instruction set, more instructions are needed in the implementation. The following is an implementation method I think of. Welcome to communicate.

It should be noted that since each thumb instruction is 16bit, the 32-bit jump address needs to occupy the space of two instructions, and the R0 register will be polluted during jump, so it should be protected. When I implement the program, I compile shellcode into arm instruction set, so when the original program, shellcode and stubbcode jump to each other, I need to use BX instruction to switch the processor state (when the address code to jump is thumb instruction set, I need to set the first bit of the address).

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>