├── .DS_Store ├── README.md └── app ├── build.gradle └── src ├── .DS_Store └── main ├── c ├── CMakeLists.txt ├── arch │ ├── arm64-v8a │ │ └── syscall_arch.h │ ├── armeabi-v7a │ │ └── syscall_arch.h │ ├── x86 │ │ └── syscall_arch.h │ └── x86_64 │ │ └── syscall_arch.h ├── mylibc.h ├── native-lib.c └── syscalls.h └── java └── com └── test └── MainActivity.java /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emanriquez/Android-AntiFrida/93dd1b45621ee8dd3dd87f49807b32caa32e7b33/.DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #U - DETECT FRIDA 2 | 3 | ## Comenzando 🚀 4 | 5 | Estas instrucciones te permitirán obtener una copia del proyecto en funcionamiento en tu máquina local para propósitos de desarrollo y pruebas. 6 | 7 | Mira **Deployment** para conocer como desplegar el proyecto. 8 | 9 | Que hace este proyecto? 10 | 11 | - Detectar a través de canalizaciones con nombre utilizadas por Frida 12 | - Detectar a través de un hilo con nombre específico de frida 13 | - Compare la sección de texto en la memoria con la sección de texto en el disco tanto para libc como para la biblioteca nativa 14 | 15 | Además, este proyecto tiene 3 mecanismos para endurecer el código nativo. 16 | 17 | 1. Reemplazar ciertas llamadas libc con syscalls 18 | 2. Reemplazar cadena, operación relacionada con la memoria con implementación personalizada 19 | 3. Aplicar la ofuscación nativa de O-LLVM 20 | 21 | ### Pre-requisitos 📋 22 | 23 | Android Studio 24 | 25 | ## Despliegue 📦 26 | 27 | 1. Clonar Repositorio 28 | 2. Copiar carpeta app/src/main/c en su proyecto Android. 29 | 3. Agregar en app/build.gradle llamados a Librerias Nativas Cmake 30 | 31 | ´ 32 | cmake { 33 | path "src/main/c/CMakeLists.txt" 34 | version "3.10.2" 35 | } 36 | ´ 4. En MainApplication agregar llamdo a Librerias Nativas 37 | 38 | // Used to load the 'native-lib' library on application startup. 39 | static { 40 | System.loadLibrary("native-lib"); 41 | } 42 | 43 | 5. Compile Aplicación en Android y Acepte nuevos componentes. 44 | 45 | ## Contribute 46 | 47 | Elias Manriquez 48 | 49 | ## Autores 50 | 51 | https://github.com/darvincisec/DetectFrida 52 | 53 | ## Licencia 📄 54 | 55 | Este proyecto está bajo la Licencia (CC) - mira el archivo [LICENSE.md](LICENSE.md) para detalles 56 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 30 5 | buildToolsVersion "30.0.3" 6 | defaultConfig { 7 | applicationId "com.test.nombreapp" 8 | minSdkVersion 19 9 | targetSdkVersion 30 10 | versionCode 2 11 | versionName "1.1" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | ndk { 14 | abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86_64' 15 | } 16 | } 17 | buildTypes { 18 | release { 19 | minifyEnabled false 20 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 21 | } 22 | } 23 | externalNativeBuild { 24 | cmake { 25 | path "src/main/c/CMakeLists.txt" 26 | version "3.10.2" 27 | } 28 | } 29 | } 30 | 31 | dependencies { 32 | implementation fileTree(dir: 'libs', include: ['*.jar']) 33 | implementation 'androidx.appcompat:appcompat:1.2.0' 34 | implementation 'androidx.constraintlayout:constraintlayout:2.0.4' 35 | testImplementation 'junit:junit:4.13.1' 36 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 37 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 38 | } 39 | -------------------------------------------------------------------------------- /app/src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emanriquez/Android-AntiFrida/93dd1b45621ee8dd3dd87f49807b32caa32e7b33/app/src/.DS_Store -------------------------------------------------------------------------------- /app/src/main/c/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # For more information about using CMake with Android Studio, read the 2 | # documentation: https://d.android.com/studio/projects/add-native-code.html 3 | 4 | # Sets the minimum version of CMake required to build the native library. 5 | 6 | cmake_minimum_required(VERSION 3.4.1) 7 | 8 | set(can_use_assembler TRUE) 9 | enable_language(ASM) 10 | 11 | #Start - Comment this block for generating non-obfuscated builds 12 | set(OLLVM_PATH ${CMAKE_HOME_DIRECTORY}/../../../../../o-llvm-binary/ollvm-tll/build/bin_Darwin) 13 | set(OLLVM_C_COMPILER ${OLLVM_PATH}/clang) 14 | set(OLLVM_CXX_COMPILER ${OLLVM_PATH}/clang++) 15 | 16 | set(OLLVM_C_FLAGS "-mllvm -sub -mllvm -bcf -mllvm -fla") 17 | 18 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OLLVM_C_FLAGS}") 19 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OLLVM_C_FLAGS}") 20 | set(CMAKE_C_COMPILER ${OLLVM_C_COMPILER}) 21 | set(CMAKE_CXX_COMPILER ${OLLVM_CXX_COMPILER}) 22 | #End - Comment this block for generating non-obfuscated builds 23 | 24 | #Set flags to detect arm32 bit or arm64 bit for switching between elf structures 25 | if(${ANDROID_ABI} STREQUAL "armeabi-v7a" OR ${ANDROID_ABI} STREQUAL "x86") 26 | add_definitions("-D_32_BIT") 27 | elseif(${ANDROID_ABI} STREQUAL "arm64-v8a" OR ${ANDROID_ABI} STREQUAL "x86_64") 28 | add_definitions("-D_64_BIT") 29 | endif() 30 | 31 | 32 | add_library( # Sets the name of the library. 33 | native-lib 34 | 35 | # Sets the library as a shared library. 36 | SHARED 37 | 38 | # Provides a relative path to your source file(s). 39 | native-lib.c) 40 | 41 | target_include_directories(native-lib PRIVATE arch/${ANDROID_ABI}) 42 | 43 | # Searches for a specified prebuilt library and stores the path as a 44 | # variable. Because CMake includes system libraries in the search path by 45 | # default, you only need to specify the name of the public NDK library 46 | # you want to add. CMake verifies that the library exists before 47 | # completing its build. 48 | 49 | find_library( # Sets the name of the path variable. 50 | log-lib 51 | 52 | # Specifies the name of the NDK library that 53 | # you want CMake to locate. 54 | log ) 55 | 56 | # Specifies libraries CMake should link to your target library. You 57 | # can link multiple libraries, such as libraries you define in this 58 | # build script, prebuilt third-party libraries, or system libraries. 59 | 60 | target_link_libraries( # Specifies the target library. 61 | native-lib 62 | 63 | # Links the target library to the log library 64 | # included in the NDK. 65 | ${log-lib} ) 66 | 67 | add_custom_command( TARGET native-lib 68 | POST_BUILD 69 | COMMAND "${ANDROID_TOOLCHAIN_PREFIX}strip" -R .comment -g -S -d --strip-unneeded ${CMAKE_HOME_DIRECTORY}/../../../build/intermediates/cmake/${CMAKE_BUILD_TYPE}/obj/${ANDROID_ABI}/libnative-lib.so 70 | COMMENT "Stripped native library") 71 | -------------------------------------------------------------------------------- /app/src/main/c/arch/arm64-v8a/syscall_arch.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------- 2 | Copyright © 2005-2020 Rich Felker, et al. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | ----------------------------------------------------------------------*/ 23 | #define __SYSCALL_LL_E(x) (x) 24 | #define __SYSCALL_LL_O(x) (x) 25 | 26 | #define __asm_syscall(...) do { \ 27 | __asm__ __volatile__ ( "svc 0" \ 28 | : "=r"(x0) : __VA_ARGS__ : "memory", "cc"); \ 29 | return x0; \ 30 | } while (0) 31 | 32 | __attribute__((always_inline)) 33 | static inline long __syscall0(long n) 34 | { 35 | register long x8 __asm__("x8") = n; 36 | register long x0 __asm__("x0"); 37 | __asm_syscall("r"(x8)); 38 | } 39 | 40 | __attribute__((always_inline)) 41 | static inline long __syscall1(long n, long a) 42 | { 43 | register long x8 __asm__("x8") = n; 44 | register long x0 __asm__("x0") = a; 45 | __asm_syscall("r"(x8), "0"(x0)); 46 | } 47 | __attribute__((always_inline)) 48 | static inline long __syscall2(long n, long a, long b) 49 | { 50 | register long x8 __asm__("x8") = n; 51 | register long x0 __asm__("x0") = a; 52 | register long x1 __asm__("x1") = b; 53 | __asm_syscall("r"(x8), "0"(x0), "r"(x1)); 54 | } 55 | __attribute__((always_inline)) 56 | static inline long __syscall3(long n, long a, long b, long c) 57 | { 58 | register long x8 __asm__("x8") = n; 59 | register long x0 __asm__("x0") = a; 60 | register long x1 __asm__("x1") = b; 61 | register long x2 __asm__("x2") = c; 62 | __asm_syscall("r"(x8), "0"(x0), "r"(x1), "r"(x2)); 63 | } 64 | __attribute__((always_inline)) 65 | static inline long __syscall4(long n, long a, long b, long c, long d) 66 | { 67 | register long x8 __asm__("x8") = n; 68 | register long x0 __asm__("x0") = a; 69 | register long x1 __asm__("x1") = b; 70 | register long x2 __asm__("x2") = c; 71 | register long x3 __asm__("x3") = d; 72 | __asm_syscall("r"(x8), "0"(x0), "r"(x1), "r"(x2), "r"(x3)); 73 | } 74 | 75 | __attribute__((always_inline)) 76 | static inline long __syscall5(long n, long a, long b, long c, long d, long e) 77 | { 78 | register long x8 __asm__("x8") = n; 79 | register long x0 __asm__("x0") = a; 80 | register long x1 __asm__("x1") = b; 81 | register long x2 __asm__("x2") = c; 82 | register long x3 __asm__("x3") = d; 83 | register long x4 __asm__("x4") = e; 84 | __asm_syscall("r"(x8), "0"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x4)); 85 | } 86 | 87 | __attribute__((always_inline)) 88 | static inline long __syscall6(long n, long a, long b, long c, long d, long e, long f) 89 | { 90 | register long x8 __asm__("x8") = n; 91 | register long x0 __asm__("x0") = a; 92 | register long x1 __asm__("x1") = b; 93 | register long x2 __asm__("x2") = c; 94 | register long x3 __asm__("x3") = d; 95 | register long x4 __asm__("x4") = e; 96 | register long x5 __asm__("x5") = f; 97 | __asm_syscall("r"(x8), "0"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x4), "r"(x5)); 98 | } 99 | 100 | #define VDSO_USEFUL 101 | #define VDSO_CGT_SYM "__kernel_clock_gettime" 102 | #define VDSO_CGT_VER "LINUX_2.6.39" 103 | 104 | #define IPC_64 0 105 | -------------------------------------------------------------------------------- /app/src/main/c/arch/armeabi-v7a/syscall_arch.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------- 2 | Copyright © 2005-2020 Rich Felker, et al. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | ----------------------------------------------------------------------*/ 23 | #define __SYSCALL_LL_E(x) \ 24 | ((union { long long ll; long l[2]; }){ .ll = x }).l[0], \ 25 | ((union { long long ll; long l[2]; }){ .ll = x }).l[1] 26 | #define __SYSCALL_LL_O(x) 0, __SYSCALL_LL_E((x)) 27 | 28 | #ifdef __thumb__ 29 | 30 | /* Avoid use of r7 in asm constraints when producing thumb code, 31 | * since it's reserved as frame pointer and might not be supported. */ 32 | #define __ASM____R7__ 33 | #define __asm_syscall(...) do { \ 34 | __asm__ __volatile__ ( "mov %1,r7 ; mov r7,%2 ; svc 0 ; mov r7,%1" \ 35 | : "=r"(r0), "=&r"((int){0}) : __VA_ARGS__ : "memory"); \ 36 | return r0; \ 37 | } while (0) 38 | 39 | #else 40 | 41 | #define __ASM____R7__ __asm__("r7") 42 | #define __asm_syscall(...) do { \ 43 | __asm__ __volatile__ ( "svc 0" \ 44 | : "=r"(r0) : __VA_ARGS__ : "memory"); \ 45 | return r0; \ 46 | } while (0) 47 | #endif 48 | 49 | /* For thumb2, we can allow 8-bit immediate syscall numbers, saving a 50 | * register in the above dance around r7. Does not work for thumb1 where 51 | * only movs, not mov, supports immediates, and we can't use movs because 52 | * it doesn't support high regs. */ 53 | #ifdef __thumb2__ 54 | #define R7_OPERAND "rI"(r7) 55 | #else 56 | #define R7_OPERAND "r"(r7) 57 | #endif 58 | 59 | __attribute__((always_inline)) 60 | static inline long __syscall0(long n) 61 | { 62 | register long r7 __ASM____R7__ = n; 63 | register long r0 __asm__("r0"); 64 | __asm_syscall(R7_OPERAND); 65 | } 66 | 67 | __attribute__((always_inline)) 68 | static inline long __syscall1(long n, long a) 69 | { 70 | register long r7 __ASM____R7__ = n; 71 | register long r0 __asm__("r0") = a; 72 | __asm_syscall(R7_OPERAND, "0"(r0)); 73 | } 74 | 75 | __attribute__((always_inline)) 76 | static inline long __syscall2(long n, long a, long b) 77 | { 78 | register long r7 __ASM____R7__ = n; 79 | register long r0 __asm__("r0") = a; 80 | register long r1 __asm__("r1") = b; 81 | __asm_syscall(R7_OPERAND, "0"(r0), "r"(r1)); 82 | } 83 | 84 | __attribute__((always_inline)) 85 | static inline long __syscall3(long n, long a, long b, long c) 86 | { 87 | register long r7 __ASM____R7__ = n; 88 | register long r0 __asm__("r0") = a; 89 | register long r1 __asm__("r1") = b; 90 | register long r2 __asm__("r2") = c; 91 | __asm_syscall(R7_OPERAND, "0"(r0), "r"(r1), "r"(r2)); 92 | } 93 | 94 | __attribute__((always_inline)) 95 | static inline long __syscall4(long n, long a, long b, long c, long d) 96 | { 97 | register long r7 __ASM____R7__ = n; 98 | register long r0 __asm__("r0") = a; 99 | register long r1 __asm__("r1") = b; 100 | register long r2 __asm__("r2") = c; 101 | register long r3 __asm__("r3") = d; 102 | __asm_syscall(R7_OPERAND, "0"(r0), "r"(r1), "r"(r2), "r"(r3)); 103 | } 104 | 105 | __attribute__((always_inline)) 106 | static inline long __syscall5(long n, long a, long b, long c, long d, long e) 107 | { 108 | register long r7 __ASM____R7__ = n; 109 | register long r0 __asm__("r0") = a; 110 | register long r1 __asm__("r1") = b; 111 | register long r2 __asm__("r2") = c; 112 | register long r3 __asm__("r3") = d; 113 | register long r4 __asm__("r4") = e; 114 | __asm_syscall(R7_OPERAND, "0"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4)); 115 | } 116 | 117 | __attribute__((always_inline)) 118 | static inline long __syscall6(long n, long a, long b, long c, long d, long e, long f) 119 | { 120 | register long r7 __ASM____R7__ = n; 121 | register long r0 __asm__("r0") = a; 122 | register long r1 __asm__("r1") = b; 123 | register long r2 __asm__("r2") = c; 124 | register long r3 __asm__("r3") = d; 125 | register long r4 __asm__("r4") = e; 126 | register long r5 __asm__("r5") = f; 127 | __asm_syscall(R7_OPERAND, "0"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r5)); 128 | } 129 | 130 | #define VDSO_USEFUL 131 | #define VDSO_CGT32_SYM "__vdso_clock_gettime" 132 | #define VDSO_CGT32_VER "LINUX_2.6" 133 | #define VDSO_CGT_SYM "__vdso_clock_gettime64" 134 | #define VDSO_CGT_VER "LINUX_2.6" 135 | 136 | #define SYSCALL_FADVISE_6_ARG 137 | 138 | #define SYSCALL_IPC_BROKEN_MODE 139 | -------------------------------------------------------------------------------- /app/src/main/c/arch/x86/syscall_arch.h: -------------------------------------------------------------------------------- 1 | //#define __SYSCALL_LL_E(x) (x) 2 | //#define __SYSCALL_LL_O(x) (x) 3 | // 4 | //#define __scc(X) sizeof(1?(X):0ULL) < 8 ? (unsigned long) (X) : (long long) (X) 5 | //typedef long long syscall_arg_t; 6 | // 7 | //static __inline long __syscall0(long long n) 8 | //{ 9 | // unsigned long ret; 10 | // __asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n) : "rcx", "r11", "memory"); 11 | // return ret; 12 | //} 13 | // 14 | //static __inline long __syscall1(long long n, long long a1) 15 | //{ 16 | // unsigned long ret; 17 | // __asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1) : "rcx", "r11", "memory"); 18 | // return ret; 19 | //} 20 | // 21 | //static __inline long __syscall2(long long n, long long a1, long long a2) 22 | //{ 23 | // unsigned long ret; 24 | // __asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2) 25 | // : "rcx", "r11", "memory"); 26 | // return ret; 27 | //} 28 | // 29 | //static __inline long __syscall3(long long n, long long a1, long long a2, long long a3) 30 | //{ 31 | // unsigned long ret; 32 | // __asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2), 33 | // "d"(a3) : "rcx", "r11", "memory"); 34 | // return ret; 35 | //} 36 | // 37 | //static __inline long __syscall4(long long n, long long a1, long long a2, long long a3, 38 | // long long a4_) 39 | //{ 40 | // unsigned long ret; 41 | // register long long a4 __asm__("r10") = a4_; 42 | // __asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2), 43 | // "d"(a3), "r"(a4): "rcx", "r11", "memory"); 44 | // return ret; 45 | //} 46 | // 47 | //static __inline long __syscall5(long long n, long long a1, long long a2, long long a3, 48 | // long long a4_, long long a5_) 49 | //{ 50 | // unsigned long ret; 51 | // register long long a4 __asm__("r10") = a4_; 52 | // register long long a5 __asm__("r8") = a5_; 53 | // __asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2), 54 | // "d"(a3), "r"(a4), "r"(a5) : "rcx", "r11", "memory"); 55 | // return ret; 56 | //} 57 | // 58 | //static __inline long __syscall6(long long n, long long a1, long long a2, long long a3, 59 | // long long a4_, long long a5_, long long a6_) 60 | //{ 61 | // unsigned long ret; 62 | // register long long a4 __asm__("r10") = a4_; 63 | // register long long a5 __asm__("r8") = a5_; 64 | // register long long a6 __asm__("r9") = a6_; 65 | // __asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2), 66 | // "d"(a3), "r"(a4), "r"(a5), "r"(a6) : "rcx", "r11", "memory"); 67 | // return ret; 68 | //} 69 | // 70 | //#undef SYS_futimesat 71 | // 72 | //#define SYS_clock_gettime64 SYS_clock_gettime 73 | //#define SYS_clock_settime64 SYS_clock_settime 74 | //#define SYS_clock_adjtime64 SYS_clock_adjtime 75 | //#define SYS_clock_nanosleep_time64 SYS_clock_nanosleep 76 | //#define SYS_timer_gettime64 SYS_timer_gettime 77 | //#define SYS_timer_settime64 SYS_timer_settime 78 | //#define SYS_timerfd_gettime64 SYS_timerfd_gettime 79 | //#define SYS_timerfd_settime64 SYS_timerfd_settime 80 | //#define SYS_utimensat_time64 SYS_utimensat 81 | //#define SYS_pselect6_time64 SYS_pselect6 82 | //#define SYS_ppoll_time64 SYS_ppoll 83 | //#define SYS_recvmmsg_time64 SYS_recvmmsg 84 | //#define SYS_mq_timedsend_time64 SYS_mq_timedsend 85 | //#define SYS_mq_timedreceive_time64 SYS_mq_timedreceive 86 | //#define SYS_semtimedop_time64 SYS_semtimedop 87 | //#define SYS_rt_sigtimedwait_time64 SYS_rt_sigtimedwait 88 | //#define SYS_futex_time64 SYS_futex 89 | //#define SYS_sched_rr_get_interval_time64 SYS_sched_rr_get_interval 90 | //#define SYS_getrusage_time64 SYS_getrusage 91 | //#define SYS_wait4_time64 SYS_wait4 92 | // 93 | //#define IPC_64 0 94 | 95 | 96 | #define __SYSCALL_LL_E(x) \ 97 | ((union { long long ll; long l[2]; }){ .ll = x }).l[0], \ 98 | ((union { long long ll; long l[2]; }){ .ll = x }).l[1] 99 | #define __SYSCALL_LL_O(x) __SYSCALL_LL_E((x)) 100 | 101 | #if SYSCALL_NO_TLS 102 | #define SYSCALL_INSNS "int $128" 103 | #else 104 | #define SYSCALL_INSNS "call *%%gs:16" 105 | #endif 106 | 107 | #define SYSCALL_INSNS_12 "xchg %%ebx,%%edx ; " SYSCALL_INSNS " ; xchg %%ebx,%%edx" 108 | #define SYSCALL_INSNS_34 "xchg %%ebx,%%edi ; " SYSCALL_INSNS " ; xchg %%ebx,%%edi" 109 | 110 | static inline long __syscall0(long n) 111 | { 112 | unsigned long __ret; 113 | __asm__ __volatile__ (SYSCALL_INSNS : "=a"(__ret) : "a"(n) : "memory"); 114 | return __ret; 115 | } 116 | 117 | static inline long __syscall1(long n, long a1) 118 | { 119 | unsigned long __ret; 120 | __asm__ __volatile__ (SYSCALL_INSNS_12 : "=a"(__ret) : "a"(n), "d"(a1) : "memory"); 121 | return __ret; 122 | } 123 | 124 | static inline long __syscall2(long n, long a1, long a2) 125 | { 126 | unsigned long __ret; 127 | __asm__ __volatile__ (SYSCALL_INSNS_12 : "=a"(__ret) : "a"(n), "d"(a1), "c"(a2) : "memory"); 128 | return __ret; 129 | } 130 | 131 | static inline long __syscall3(long n, long a1, long a2, long a3) 132 | { 133 | unsigned long __ret; 134 | #if !defined(__PIC__) || !defined(BROKEN_EBX_ASM) 135 | __asm__ __volatile__ (SYSCALL_INSNS : "=a"(__ret) : "a"(n), "b"(a1), "c"(a2), "d"(a3) : "memory"); 136 | #else 137 | __asm__ __volatile__ (SYSCALL_INSNS_34 : "=a"(__ret) : "a"(n), "D"(a1), "c"(a2), "d"(a3) : "memory"); 138 | #endif 139 | return __ret; 140 | } 141 | 142 | static inline long __syscall4(long n, long a1, long a2, long a3, long a4) 143 | { 144 | unsigned long __ret; 145 | #if !defined(__PIC__) || !defined(BROKEN_EBX_ASM) 146 | __asm__ __volatile__ (SYSCALL_INSNS : "=a"(__ret) : "a"(n), "b"(a1), "c"(a2), "d"(a3), "S"(a4) : "memory"); 147 | #else 148 | __asm__ __volatile__ (SYSCALL_INSNS_34 : "=a"(__ret) : "a"(n), "D"(a1), "c"(a2), "d"(a3), "S"(a4) : "memory"); 149 | #endif 150 | return __ret; 151 | } 152 | 153 | static inline long __syscall5(long n, long a1, long a2, long a3, long a4, long a5) 154 | { 155 | unsigned long __ret; 156 | #if !defined(__PIC__) || !defined(BROKEN_EBX_ASM) 157 | __asm__ __volatile__ (SYSCALL_INSNS 158 | : "=a"(__ret) : "a"(n), "b"(a1), "c"(a2), "d"(a3), "S"(a4), "D"(a5) : "memory"); 159 | #else 160 | __asm__ __volatile__ ("pushl %2 ; push %%ebx ; mov 4(%%esp),%%ebx ; " SYSCALL_INSNS " ; pop %%ebx ; add $4,%%esp" 161 | : "=a"(__ret) : "a"(n), "g"(a1), "c"(a2), "d"(a3), "S"(a4), "D"(a5) : "memory"); 162 | #endif 163 | return __ret; 164 | } 165 | 166 | static inline long __syscall6(long n, long a1, long a2, long a3, long a4, long a5, long a6) 167 | { 168 | unsigned long __ret; 169 | #if !defined(__PIC__) || !defined(BROKEN_EBX_ASM) 170 | __asm__ __volatile__ ("pushl %7 ; push %%ebp ; mov 4(%%esp),%%ebp ; " SYSCALL_INSNS " ; pop %%ebp ; add $4,%%esp" 171 | : "=a"(__ret) : "a"(n), "b"(a1), "c"(a2), "d"(a3), "S"(a4), "D"(a5), "g"(a6) : "memory"); 172 | #else 173 | unsigned long a1a6[2] = { a1, a6 }; 174 | __asm__ __volatile__ ("pushl %1 ; push %%ebx ; push %%ebp ; mov 8(%%esp),%%ebx ; mov 4(%%ebx),%%ebp ; mov (%%ebx),%%ebx ; " SYSCALL_INSNS " ; pop %%ebp ; pop %%ebx ; add $4,%%esp" 175 | : "=a"(__ret) : "g"(&a1a6), "a"(n), "c"(a2), "d"(a3), "S"(a4), "D"(a5) : "memory"); 176 | #endif 177 | return __ret; 178 | } 179 | 180 | #define VDSO_USEFUL 181 | #define VDSO_CGT32_SYM "__vdso_clock_gettime" 182 | #define VDSO_CGT32_VER "LINUX_2.6" 183 | #define VDSO_CGT_SYM "__vdso_clock_gettime64" 184 | #define VDSO_CGT_VER "LINUX_2.6" 185 | 186 | #define SYSCALL_USE_SOCKETCALL 187 | -------------------------------------------------------------------------------- /app/src/main/c/arch/x86_64/syscall_arch.h: -------------------------------------------------------------------------------- 1 | #define __SYSCALL_LL_E(x) (x) 2 | #define __SYSCALL_LL_O(x) (x) 3 | 4 | static __inline long __syscall0(long n) 5 | { 6 | unsigned long ret; 7 | __asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n) : "rcx", "r11", "memory"); 8 | return ret; 9 | } 10 | 11 | static __inline long __syscall1(long n, long a1) 12 | { 13 | unsigned long ret; 14 | __asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1) : "rcx", "r11", "memory"); 15 | return ret; 16 | } 17 | 18 | static __inline long __syscall2(long n, long a1, long a2) 19 | { 20 | unsigned long ret; 21 | __asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2) 22 | : "rcx", "r11", "memory"); 23 | return ret; 24 | } 25 | 26 | static __inline long __syscall3(long n, long a1, long a2, long a3) 27 | { 28 | unsigned long ret; 29 | __asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2), 30 | "d"(a3) : "rcx", "r11", "memory"); 31 | return ret; 32 | } 33 | 34 | static __inline long __syscall4(long n, long a1, long a2, long a3, long a4) 35 | { 36 | unsigned long ret; 37 | register long r10 __asm__("r10") = a4; 38 | __asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2), 39 | "d"(a3), "r"(r10): "rcx", "r11", "memory"); 40 | return ret; 41 | } 42 | 43 | static __inline long __syscall5(long n, long a1, long a2, long a3, long a4, long a5) 44 | { 45 | unsigned long ret; 46 | register long r10 __asm__("r10") = a4; 47 | register long r8 __asm__("r8") = a5; 48 | __asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2), 49 | "d"(a3), "r"(r10), "r"(r8) : "rcx", "r11", "memory"); 50 | return ret; 51 | } 52 | 53 | static __inline long __syscall6(long n, long a1, long a2, long a3, long a4, long a5, long a6) 54 | { 55 | unsigned long ret; 56 | register long r10 __asm__("r10") = a4; 57 | register long r8 __asm__("r8") = a5; 58 | register long r9 __asm__("r9") = a6; 59 | __asm__ __volatile__ ("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2), 60 | "d"(a3), "r"(r10), "r"(r8), "r"(r9) : "rcx", "r11", "memory"); 61 | return ret; 62 | } 63 | 64 | #define VDSO_USEFUL 65 | #define VDSO_CGT_SYM "__vdso_clock_gettime" 66 | #define VDSO_CGT_VER "LINUX_2.6" 67 | #define VDSO_GETCPU_SYM "__vdso_getcpu" 68 | #define VDSO_GETCPU_VER "LINUX_2.6" 69 | 70 | #define IPC_64 0 -------------------------------------------------------------------------------- /app/src/main/c/mylibc.h: -------------------------------------------------------------------------------- 1 | #ifndef DETECTFRIDA_MYLIBC_H 2 | #define DETECTFRIDA_MYLIBC_H 3 | /* 4 | * These functions are copied from glibc, android libc, apple libc open source code. 5 | * This is to avoid easy bypass through libc functions 6 | */ 7 | 8 | __attribute__((always_inline)) 9 | static inline size_t 10 | my_strlcpy(char *dst, const char *src, size_t siz) 11 | { 12 | char *d = dst; 13 | const char *s = src; 14 | size_t n = siz; 15 | /* Copy as many bytes as will fit */ 16 | if (n != 0) { 17 | while (--n != 0) { 18 | if ((*d++ = *s++) == '\0') 19 | break; 20 | } 21 | } 22 | /* Not enough room in dst, add NUL and traverse rest of src */ 23 | if (n == 0) { 24 | if (siz != 0) 25 | *d = '\0'; /* NUL-terminate dst */ 26 | while (*s++) 27 | ; 28 | } 29 | return(s - src - 1); /* count does not include NUL */ 30 | } 31 | 32 | __attribute__((always_inline)) 33 | static inline 34 | size_t my_strlen(const char *s) 35 | { 36 | size_t len = 0; 37 | while(*s++) len++; 38 | return len; 39 | } 40 | 41 | __attribute__((always_inline)) 42 | static inline int 43 | my_strncmp(const char *s1, const char *s2, size_t n) 44 | { 45 | if (n == 0) 46 | return (0); 47 | do { 48 | if (*s1 != *s2++) 49 | return (*(unsigned char *)s1 - *(unsigned char *)--s2); 50 | if (*s1++ == 0) 51 | break; 52 | } while (--n != 0); 53 | return (0); 54 | } 55 | 56 | __attribute__((always_inline)) 57 | static inline char * 58 | my_strstr(const char *s, const char *find) 59 | { 60 | char c, sc; 61 | size_t len; 62 | 63 | if ((c = *find++) != '\0') { 64 | len = my_strlen(find); 65 | do { 66 | do { 67 | if ((sc = *s++) == '\0') 68 | return (NULL); 69 | } while (sc != c); 70 | } while (my_strncmp(s, find, len) != 0); 71 | s--; 72 | } 73 | return ((char *)s); 74 | } 75 | 76 | __attribute__((always_inline)) 77 | static inline 78 | void* my_memset(void* dst, int c, size_t n) 79 | { 80 | char* q = (char*)dst; 81 | char* end = q + n; 82 | for (;;) { 83 | if (q >= end) break; *q++ = (char) c; 84 | if (q >= end) break; *q++ = (char) c; 85 | if (q >= end) break; *q++ = (char) c; 86 | if (q >= end) break; *q++ = (char) c; 87 | } 88 | return dst; 89 | } 90 | 91 | __attribute__((always_inline)) 92 | static inline int 93 | my_strcmp(const char *s1, const char *s2) 94 | { 95 | while (*s1 == *s2++) 96 | if (*s1++ == 0) 97 | return (0); 98 | return (*(unsigned char *)s1 - *(unsigned char *)--s2); 99 | } 100 | 101 | __attribute__((always_inline)) 102 | static inline int my_atoi(const char *s) 103 | { 104 | int n=0, neg=0; 105 | while (isspace(*s)) s++; 106 | switch (*s) { 107 | case '-': neg=1; 108 | case '+': s++; 109 | } 110 | /* Compute n as a negative number to avoid overflow on INT_MIN */ 111 | while (isdigit(*s)) 112 | n = 10*n - (*s++ - '0'); 113 | return neg ? n : -n; 114 | } 115 | 116 | 117 | #endif //DETECTFRIDA_MYLIBC_H 118 | -------------------------------------------------------------------------------- /app/src/main/c/native-lib.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "syscall_arch.h" 20 | #include "syscalls.h" 21 | #include "mylibc.h" 22 | 23 | #define MAX_LINE 512 24 | #define MAX_LENGTH 256 25 | static const char *APPNAME = "DetectFrida"; 26 | static const char *FRIDA_THREAD_GUM_JS_LOOP = "gum-js-loop"; 27 | static const char *FRIDA_THREAD_GMAIN = "gmain"; 28 | static const char *FRIDA_NAMEDPIPE_LINJECTOR = "linjector"; 29 | static const char *PROC_MAPS = "/proc/self/maps"; 30 | static const char *PROC_STATUS = "/proc/self/task/%s/status"; 31 | static const char *PROC_FD = "/proc/self/fd"; 32 | static const char *PROC_TASK = "/proc/self/task"; 33 | #define LIBC "libc.so" 34 | 35 | //Structure to hold the details of executable section of library 36 | typedef struct stExecSection { 37 | int execSectionCount; 38 | unsigned long offset[2]; 39 | unsigned long memsize[2]; 40 | unsigned long checksum[2]; 41 | unsigned long startAddrinMem; 42 | } execSection; 43 | 44 | 45 | #define NUM_LIBS 2 46 | 47 | //Include more libs as per your need, but beware of the performance bottleneck especially 48 | //when the size of the libraries are > few MBs 49 | static const char *libstocheck[NUM_LIBS] = {"libnative-lib.so", LIBC}; 50 | static execSection *elfSectionArr[NUM_LIBS] = {NULL}; 51 | 52 | 53 | #ifdef _32_BIT 54 | typedef Elf32_Ehdr Elf_Ehdr; 55 | typedef Elf32_Shdr Elf_Shdr; 56 | #elif _64_BIT 57 | typedef Elf64_Ehdr Elf_Ehdr; 58 | typedef Elf64_Shdr Elf_Shdr; 59 | #endif 60 | 61 | static inline void parse_proc_maps_to_fetch_path(char **filepaths); 62 | 63 | static inline bool fetch_checksum_of_library(const char *filePath, execSection **pTextSection); 64 | 65 | static inline void detect_frida_loop(void *pargs); 66 | 67 | static inline bool 68 | scan_executable_segments(char *map, execSection *pTextSection, const char *libraryName); 69 | 70 | static inline ssize_t read_one_line(int fd, char *buf, unsigned int max_len); 71 | 72 | static inline unsigned long checksum(void *buffer, size_t len); 73 | 74 | static inline void detect_frida_threads(); 75 | 76 | static inline void detect_frida_namedpipe(); 77 | 78 | static inline void detect_frida_memdiskcompare(); 79 | 80 | //Upon loading the library, this function annotated as constructor starts executing 81 | __attribute__((constructor)) 82 | void detectfrida() { 83 | 84 | char *filePaths[NUM_LIBS]; 85 | 86 | parse_proc_maps_to_fetch_path(filePaths); 87 | __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "Libc[%x][%x][%x][%x][%x][%x]", __NR_openat, 88 | __NR_lseek, __NR_read, __NR_close, __NR_readlinkat, __NR_nanosleep); 89 | for (int i = 0; i < NUM_LIBS; i++) { 90 | fetch_checksum_of_library(filePaths[i], &elfSectionArr[i]); 91 | if (filePaths[i] != NULL) 92 | free(filePaths[i]); 93 | } 94 | pthread_t t; 95 | pthread_create(&t, NULL, (void *) detect_frida_loop, NULL); 96 | 97 | } 98 | 99 | __attribute__((always_inline)) 100 | static inline void parse_proc_maps_to_fetch_path(char **filepaths) { 101 | int fd = 0; 102 | char map[MAX_LINE]; 103 | int counter = 0; 104 | if ((fd = my_openat(AT_FDCWD, PROC_MAPS, O_RDONLY | O_CLOEXEC, 0)) != 0) { 105 | 106 | while ((read_one_line(fd, map, MAX_LINE)) > 0) { 107 | for (int i = 0; i < NUM_LIBS; i++) { 108 | if (my_strstr(map, libstocheck[i]) != NULL) { 109 | char tmp[MAX_LENGTH] = ""; 110 | char path[MAX_LENGTH] = ""; 111 | char buf[5] = ""; 112 | sscanf(map, "%s %s %s %s %s %s", tmp, buf, tmp, tmp, tmp, path); 113 | if (buf[2] == 'x') { 114 | size_t size = my_strlen(path) + 1; 115 | filepaths[i] = malloc(size); 116 | my_strlcpy(filepaths[i], path, size); 117 | counter++; 118 | } 119 | } 120 | } 121 | if (counter == NUM_LIBS) 122 | break; 123 | } 124 | my_close(fd); 125 | } 126 | } 127 | 128 | __attribute__((always_inline)) 129 | static inline bool fetch_checksum_of_library(const char *filePath, execSection **pTextSection) { 130 | 131 | Elf_Ehdr ehdr; 132 | Elf_Shdr sectHdr; 133 | int fd; 134 | int execSectionCount = 0; 135 | fd = my_openat(AT_FDCWD, filePath, O_RDONLY | O_CLOEXEC, 0); 136 | if (fd < 0) { 137 | return NULL; 138 | } 139 | 140 | my_read(fd, &ehdr, sizeof(Elf_Ehdr)); 141 | my_lseek(fd, (off_t) ehdr.e_shoff, SEEK_SET); 142 | 143 | unsigned long memsize[2] = {0}; 144 | unsigned long offset[2] = {0}; 145 | 146 | 147 | for (int i = 0; i < ehdr.e_shnum; i++) { 148 | my_memset(§Hdr, 0, sizeof(Elf_Shdr)); 149 | my_read(fd, §Hdr, sizeof(Elf_Shdr)); 150 | 151 | // __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "SectionHeader[%d][%ld]", sectHdr.sh_name, sectHdr.sh_flags); 152 | 153 | //Typically PLT and Text Sections are executable sections which are protected 154 | if (sectHdr.sh_flags & SHF_EXECINSTR) { 155 | // __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "SectionHeader[%d][%ld]", sectHdr.sh_name, sectHdr.sh_flags); 156 | 157 | offset[execSectionCount] = sectHdr.sh_offset; 158 | memsize[execSectionCount] = sectHdr.sh_size; 159 | execSectionCount++; 160 | if (execSectionCount == 2) { 161 | break; 162 | } 163 | } 164 | } 165 | if (execSectionCount == 0) { 166 | __android_log_print(ANDROID_LOG_WARN, APPNAME, "No executable section found. Suspicious"); 167 | my_close(fd); 168 | return false; 169 | } 170 | //This memory is not released as the checksum is checked in a thread 171 | *pTextSection = malloc(sizeof(execSection)); 172 | 173 | (*pTextSection)->execSectionCount = execSectionCount; 174 | (*pTextSection)->startAddrinMem = 0; 175 | for (int i = 0; i < execSectionCount; i++) { 176 | my_lseek(fd, offset[i], SEEK_SET); 177 | uint8_t *buffer = malloc(memsize[i] * sizeof(uint8_t)); 178 | my_read(fd, buffer, memsize[i]); 179 | (*pTextSection)->offset[i] = offset[i]; 180 | (*pTextSection)->memsize[i] = memsize[i]; 181 | (*pTextSection)->checksum[i] = checksum(buffer, memsize[i]); 182 | free(buffer); 183 | // __android_log_print(ANDROID_LOG_WARN, APPNAME, "ExecSection:[%d][%ld][%ld][%ld]", i, 184 | // offset[i], 185 | // memsize[i], (*pTextSection)->checksum[i]); 186 | } 187 | 188 | my_close(fd); 189 | return true; 190 | } 191 | 192 | 193 | void detect_frida_loop(void *pargs) { 194 | 195 | struct timespec timereq; 196 | timereq.tv_sec = 5; //Changing to 5 seconds from 1 second 197 | timereq.tv_nsec = 0; 198 | 199 | while (1) { 200 | 201 | detect_frida_threads(); 202 | detect_frida_namedpipe(); 203 | detect_frida_memdiskcompare(); 204 | 205 | 206 | my_nanosleep(&timereq, NULL); 207 | 208 | } 209 | } 210 | 211 | __attribute__((always_inline)) 212 | static inline bool 213 | scan_executable_segments(char *map, execSection *pElfSectArr, const char *libraryName) { 214 | unsigned long start, end; 215 | char buf[MAX_LINE] = ""; 216 | char path[MAX_LENGTH] = ""; 217 | char tmp[100] = ""; 218 | 219 | sscanf(map, "%lx-%lx %s %s %s %s %s", &start, &end, buf, tmp, tmp, tmp, path); 220 | //__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "Map [%s]", map); 221 | 222 | if (buf[2] == 'x') { 223 | if (buf[0] == 'r') { 224 | uint8_t *buffer = NULL; 225 | 226 | buffer = (uint8_t *) start; 227 | for (int i = 0; i < pElfSectArr->execSectionCount; i++) { 228 | if (start + pElfSectArr->offset[i] + pElfSectArr->memsize[i] > end) { 229 | if (pElfSectArr->startAddrinMem != 0) { 230 | buffer = (uint8_t *) pElfSectArr->startAddrinMem; 231 | pElfSectArr->startAddrinMem = 0; 232 | break; 233 | } 234 | } 235 | } 236 | for (int i = 0; i < pElfSectArr->execSectionCount; i++) { 237 | unsigned long output = checksum(buffer + pElfSectArr->offset[i], 238 | pElfSectArr->memsize[i]); 239 | // __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "Checksum:[%ld][%ld]", output, 240 | // pElfSectArr->checksum[i]); 241 | 242 | if (output != pElfSectArr->checksum[i]) { 243 | __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, 244 | "Executable Section Manipulated, " 245 | "maybe due to Frida or other hooking framework." 246 | "Act Now!!!"); 247 | } 248 | } 249 | 250 | } else { 251 | 252 | char ch[10] = "", ch1[10] = ""; 253 | __system_property_get("ro.build.version.release", ch); 254 | __system_property_get("ro.system.build.version.release", ch1); 255 | int version = my_atoi(ch); 256 | int version1 = my_atoi(ch1); 257 | if (version < 10 || version1 < 10) { 258 | __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "Suspicious to get XOM in " 259 | "version < Android10"); 260 | } else { 261 | if (0 == my_strncmp(libraryName, LIBC, my_strlen(LIBC))) { 262 | //If it is not readable, then most likely it is not manipulated by Frida 263 | __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "LIBC Executable Section" 264 | " not readable! "); 265 | 266 | } else { 267 | __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "Suspicious to get XOM " 268 | "for non-system library on " 269 | "Android 10 and above"); 270 | } 271 | } 272 | } 273 | return true; 274 | } else { 275 | if (buf[0] == 'r') { 276 | pElfSectArr->startAddrinMem = start; 277 | } 278 | } 279 | return false; 280 | } 281 | 282 | __attribute__((always_inline)) 283 | static inline ssize_t read_one_line(int fd, char *buf, unsigned int max_len) { 284 | char b; 285 | ssize_t ret; 286 | ssize_t bytes_read = 0; 287 | 288 | my_memset(buf, 0, max_len); 289 | 290 | do { 291 | ret = my_read(fd, &b, 1); 292 | 293 | if (ret != 1) { 294 | if (bytes_read == 0) { 295 | // error or EOF 296 | return -1; 297 | } else { 298 | return bytes_read; 299 | } 300 | } 301 | 302 | if (b == '\n') { 303 | return bytes_read; 304 | } 305 | 306 | *(buf++) = b; 307 | bytes_read += 1; 308 | 309 | } while (bytes_read < max_len - 1); 310 | 311 | return bytes_read; 312 | } 313 | 314 | __attribute__((always_inline)) 315 | static inline unsigned long checksum(void *buffer, size_t len) { 316 | unsigned long seed = 0; 317 | uint8_t *buf = (uint8_t *) buffer; 318 | size_t i; 319 | for (i = 0; i < len; ++i) 320 | seed += (unsigned long) (*buf++); 321 | return seed; 322 | } 323 | 324 | __attribute__((always_inline)) 325 | static inline void detect_frida_threads() { 326 | 327 | DIR *dir = opendir(PROC_TASK); 328 | 329 | if (dir != NULL) { 330 | struct dirent *entry = NULL; 331 | while ((entry = readdir(dir)) != NULL) { 332 | char filePath[MAX_LENGTH] = ""; 333 | 334 | if (0 == my_strcmp(entry->d_name, ".") || 0 == my_strcmp(entry->d_name, "..")) { 335 | continue; 336 | } 337 | snprintf(filePath, sizeof(filePath), PROC_STATUS, entry->d_name); 338 | 339 | int fd = my_openat(AT_FDCWD, filePath, O_RDONLY | O_CLOEXEC, 0); 340 | if (fd != 0) { 341 | char buf[MAX_LENGTH] = ""; 342 | read_one_line(fd, buf, MAX_LENGTH); 343 | if (my_strstr(buf, FRIDA_THREAD_GUM_JS_LOOP) || 344 | my_strstr(buf, FRIDA_THREAD_GMAIN)) { 345 | //Kill the thread. This freezes the app. Check if it is an anticpated behaviour 346 | //int tid = my_atoi(entry->d_name); 347 | //int ret = my_tgkill(getpid(), tid, SIGSTOP); 348 | __android_log_print(ANDROID_LOG_WARN, APPNAME, 349 | "Frida specific thread found. Act now!!!"); 350 | } 351 | my_close(fd); 352 | } 353 | 354 | } 355 | closedir(dir); 356 | 357 | } 358 | 359 | } 360 | 361 | __attribute__((always_inline)) 362 | static inline void detect_frida_namedpipe() { 363 | 364 | DIR *dir = opendir(PROC_FD); 365 | if (dir != NULL) { 366 | struct dirent *entry = NULL; 367 | while ((entry = readdir(dir)) != NULL) { 368 | struct stat filestat; 369 | char buf[MAX_LENGTH] = ""; 370 | char filePath[MAX_LENGTH] = ""; 371 | snprintf(filePath, sizeof(filePath), "/proc/self/fd/%s", entry->d_name); 372 | 373 | lstat(filePath, &filestat); 374 | 375 | if ((filestat.st_mode & S_IFMT) == S_IFLNK) { 376 | //TODO: Another way is to check if filepath belongs to a path not related to system or the app 377 | my_readlinkat(AT_FDCWD, filePath, buf, MAX_LENGTH); 378 | if (NULL != my_strstr(buf, FRIDA_NAMEDPIPE_LINJECTOR)) { 379 | __android_log_print(ANDROID_LOG_WARN, APPNAME, 380 | "Frida specific named pipe found. Act now!!!"); 381 | } 382 | } 383 | 384 | } 385 | } 386 | closedir(dir); 387 | } 388 | 389 | __attribute__((always_inline)) 390 | static inline void detect_frida_memdiskcompare() { 391 | int fd = 0; 392 | char map[MAX_LINE]; 393 | 394 | if ((fd = my_openat(AT_FDCWD, PROC_MAPS, O_RDONLY | O_CLOEXEC, 0)) != 0) { 395 | 396 | while ((read_one_line(fd, map, MAX_LINE)) > 0) { 397 | for (int i = 0; i < NUM_LIBS; i++) { 398 | if (my_strstr(map, libstocheck[i]) != NULL) { 399 | if (true == scan_executable_segments(map, elfSectionArr[i], libstocheck[i])) { 400 | break; 401 | } 402 | } 403 | } 404 | } 405 | } else { 406 | __android_log_print(ANDROID_LOG_WARN, APPNAME, 407 | "Error opening /proc/self/maps. That's usually a bad sign."); 408 | 409 | } 410 | my_close(fd); 411 | 412 | } 413 | 414 | -------------------------------------------------------------------------------- /app/src/main/c/syscalls.h: -------------------------------------------------------------------------------- 1 | #ifndef DETECTFRIDA_SYSCALLS_H 2 | #define DETECTFRIDA_SYSCALLS_H 3 | /* 4 | * System calls such as file operations, sleep are converted to syscalls to avoid easy bypass 5 | * through readymade scripts hooking onto libc calls. 6 | */ 7 | __attribute__((always_inline)) 8 | static inline int my_openat(int __dir_fd, const void* __path, int __flags, int __mode ){ 9 | return (int)__syscall4(__NR_openat, __dir_fd, (long)__path, __flags, __mode); 10 | } 11 | 12 | __attribute__((always_inline)) 13 | static inline ssize_t my_read(int __fd, void* __buf, size_t __count){ 14 | return __syscall3(__NR_read, __fd, (long)__buf, (long)__count); 15 | } 16 | 17 | __attribute__((always_inline)) 18 | static inline off_t my_lseek(int __fd, off_t __offset, int __whence){ 19 | return __syscall3(__NR_lseek, __fd, __offset, __whence); 20 | } 21 | 22 | __attribute__((always_inline)) 23 | static inline int my_close(int __fd){ 24 | return (int)__syscall1(__NR_close, __fd); 25 | } 26 | 27 | __attribute__((always_inline)) 28 | static inline int my_nanosleep(const struct timespec* __request, struct timespec* __remainder){ 29 | return (int)__syscall2(__NR_nanosleep, (long)__request, (long)__remainder); 30 | } 31 | 32 | __attribute__((always_inline)) 33 | static inline ssize_t my_readlinkat(int __dir_fd, const char* __path, char* __buf, size_t __buf_size){ 34 | return __syscall4(__NR_readlinkat, __dir_fd, (long)__path, (long)__buf,(long)__buf_size); 35 | } 36 | 37 | //Not Used 38 | __attribute__((always_inline)) 39 | static inline int my_tgkill(int __tgid, int __tid, int __signal){ 40 | return (int)__syscall3(__NR_tgkill, __tgid, __tid, __signal); 41 | } 42 | 43 | //Not Used 44 | __attribute__((always_inline)) 45 | static inline void my_exit(int __status){ 46 | __syscall1(__NR_exit, __status); 47 | } 48 | 49 | #endif //DETECTFRIDA_SYSCALLS_H -------------------------------------------------------------------------------- /app/src/main/java/com/test/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.test; 2 | 3 | import androidx.appcompat.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | 6 | public class MainActivity extends AppCompatActivity { 7 | 8 | // Used to load the 'native-lib' library on application startup. 9 | static { 10 | System.loadLibrary("native-lib"); 11 | } 12 | 13 | @Override 14 | protected void onCreate(Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | setContentView(R.layout.activity_main); 17 | } 18 | 19 | } 20 | --------------------------------------------------------------------------------