Intel® Developer Zone offers tools and how-to information for cross-platform app development, platform and technology information, code samples, and peer expertise to help developers innovate and succeed. Join our communities for Android, Internet of Things, Intel® RealSense™ Technology, and Windows to download tools, access dev kits, share ideas with like-minded developers, and participate in hackathon’s, contests, roadshows, and local events.
Contents
Study of the PIC Code in libtest_PIC.so
If the object is compiled in PIC mode, relocation is implemented differently. By observing the sections information of the libtest_PIC.so which is shown in Figure 17, the printf()
relocation information is located in two relocation sections: .rel.dyn and .rel.plt. Two new relocation types R_386_GLOB_DAT
and R_386_JMP_SLOT
are used, and the absolute 32-bit address of the substituted function should be filled in with these offset addresses.
Figure 1: Relocation section of libtest_PIC.so
The Figure 18 shows the assembly code of function libtest2()
which is compiled in non-PIC mode. The entry addresses of printf()
marked with red color are specified in the relocation sections .rel.dyn and .rel.plt in Figure 17.
Figure 2: Disassemble code of libtest2(), compiled with -PIC parameter
Figure 3: Working flow of 'printf("libtest2: 1st call to the original printf()\n");'
Figure 4: Working flow of 'global_printf2("libtest2: global_printf2()\n");'
Figure 5: Working flow of 'local_printf("libtest2: local_printf()\n");'
From Figures 19-21, it can be seen that when working with the dynamic library generated with the -PIC parameter, the code in libtest2()
will jump to the address placed in offset addresses 0x1fe0, 0x2010, and 0x2000, which are the entrances to printf()
.
Hook Solution
If the hook module wants to intercept the calls to printf()
and redirect to another function, it should write the redirected function address to the offset addresses of the symbol ‘printf’ defined in the relocation sections, after the linker loaded the dynamic library into memory.
To replace the call of the printf()
function with the call of the redirected hooked_printf()
function, as shown in the software flow diagram in Figure 22, a hook function should be implemented between the dlopen()
and libtest()
calls. The hook function will first get the offset address of symbol printf, which is 0x1fe0
from the relocation section named .rel.dyn. The hook function then writes the absolute address of hooked_printf()
function to the offset address. After that, when the code in libtest2()
calls into the printf()
, it will enter the hooked_printf()
instead.
Figure 6: Example of how the hook function intercepts the call to printf() and reroutes the call to hooked_printf(). The original function calling process is described in Figure 21.
To consider all the possible cases previously listed, the entire flow chart of the hook function is shown in Figure 23. And the part of the change in main()
function is depicted in Figure 24.
Figure 7: The flow chart of ELF hook module
Figure 8: Code in main() after hooking
The output of the program is shown in Figure 25, you can see that when the first call to libtest1()/libtest2() executes, the printf()
is called inside the functions. When calling the two functions again, after the hook functions are executed, the calls to the printf()
are redirected to the hooked_printf()
function. The hooked_printf()
function will attach the string “is HOOKED” at the end of the normal printed string. Figure 26 shows the program running flow after hooking, compare with the original flow shown in Figure 8, the hooked_printf()
has been injected into libtest1()
and libtest2()
.
Figure 9: Output of the test program, printf() has been hooked
Figure 10: The running flow of the test project after hooking
Case Study – a Hook-Based Protection Scheme in Android
Based on the studies of the hooking technique in the previous sections, we developed a plug-in to help Android application developers improve the security of their applications. Developers need to add only one Android native library to their projects and add one line of Java code to load this native library at start-up time. Then this library injects some protection code to other third-party libraries in the application. The protection code will aid encrypting the local file's input/output stream, as well as bypass the function __android_log_print()
to avoid some user privacy leakage by printing debugging information through Logcat.
To verify the effectiveness of the protection plug-in, we wrote an Android application to simulate a scene of an application that contains a third-party library. In the test application, the third party library does two things:
- When an external Java instruction calls the functions in the library, it will print some information by calling _
_android_log_print()
. - In the library, the code creates a file (/sdcard/data.dat) to save data in local storage without encryption, then reads it back and prints it on the screen. This action is to simulate the application trying to save some sensitive information in the local file system.
Figures 27-30 compare the screenshots of the test program, output of Logcat, and the content of the saving file in the device’s local file system before and after hooking.
Figure 11: The Android* platform is Teclast X89HD, Android 4.2.2
Figure 12: App output - no change after hooking
Figure 13: Logcat output - empty after hooking
Figure 14: Local file ‘data.dat’ at /sdcard has been encrypted after hooking
As the figures show, the running flow of the program after hooking is the same as the one without hooking. However, the Logcat cannot catch any output from the native library after hooking. Further, the content of the local file is no longer stored in a plain text format.
The plug-in helps the test application improve security against malicious attacks on collecting information via Logcat, as well as offline attacks to the local file system.
Conclusion
The hooking technique can be used in many development scenarios, providing seamless security protection to Android applications. Hook-based protection schemes can not only be used on Android, but also can be expanded to other operating systems such as Windows*, Embedded Linux, or other operating systems designed for Internet of Things (IoT) devices. It can significantly reduce the development cycle as well as maintenance costs. Developers can develop their own hook-based security scheme or use the professional third-party security solutions available on the market.
References
Redirecting functions in shared ELF libraries
Apriorit Inc, Anthony Shoumikhin, 25 Jul 2013
http://www.codeproject.com/Articles/70302/Redirecting-functions-in-shared-ELF-libraries
x86 API Hooking Demystified
Jurriaan Bremer
http://jbremer.org/x86-api-hooking-demystified/
Android developer guide
http://developer.android.com/index.html
Android Open Source Project
https://source.android.com/