From 2a689081dce536407201c3b5eb5a5c7a89a2de3b Mon Sep 17 00:00:00 2001 From: JingMatrix Date: Wed, 10 Sep 2025 11:41:05 +0200 Subject: [PATCH] Detect mount inconsistency of /system/bin `proc/self/exe` is a symbolic link to `/system/bin/app_process64`. Hence, it can be used to test if this file is mounted under a file system that is different from the normal one (EXT4). --- app/src/main/cpp/CMakeLists.txt | 2 +- app/src/main/cpp/include/statfs.hpp | 5 +++ app/src/main/cpp/native-lib.cpp | 15 ++++++-- app/src/main/cpp/statfs.cpp | 56 +++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 app/src/main/cpp/include/statfs.hpp create mode 100644 app/src/main/cpp/statfs.cpp diff --git a/app/src/main/cpp/CMakeLists.txt b/app/src/main/cpp/CMakeLists.txt index 79a9e4a..eb45ec9 100644 --- a/app/src/main/cpp/CMakeLists.txt +++ b/app/src/main/cpp/CMakeLists.txt @@ -29,7 +29,7 @@ set(CMAKE_CXX_STANDARD 20) # used in the AndroidManifest.xml file. add_library(${CMAKE_PROJECT_NAME} SHARED # List C/C++ source files with relative paths to this CMakeLists.txt. - atexit.cpp elf_util.cpp native-lib.cpp smap.cpp solist.cpp vmap.cpp) + atexit.cpp elf_util.cpp native-lib.cpp smap.cpp solist.cpp statfs.cpp vmap.cpp) target_include_directories(${CMAKE_PROJECT_NAME} PUBLIC include) # Specifies libraries CMake should link to your target library. You diff --git a/app/src/main/cpp/include/statfs.hpp b/app/src/main/cpp/include/statfs.hpp new file mode 100644 index 0000000..2e8d7e1 --- /dev/null +++ b/app/src/main/cpp/include/statfs.hpp @@ -0,0 +1,5 @@ +#pragma once + +#include + +std::string get_filesystem_type(const std::string &path); diff --git a/app/src/main/cpp/native-lib.cpp b/app/src/main/cpp/native-lib.cpp index 51dc1cc..fb29c6f 100644 --- a/app/src/main/cpp/native-lib.cpp +++ b/app/src/main/cpp/native-lib.cpp @@ -2,6 +2,7 @@ #include "logging.h" #include "smap.h" #include "solist.hpp" +#include "statfs.hpp" #include "vmap.hpp" #include #include @@ -14,6 +15,8 @@ Java_org_matrix_demo_MainActivity_stringFromJNI(JNIEnv *env, std::string solist_detection = "No injection found using solist"; std::string vmap_detection = "No injection found using vitrual map"; std::string counter_detection = "No injection found using module counter"; + std::string system_mount_detection = + "No traces found for /system re-mounting"; SoList::SoInfo *abnormal_soinfo = SoList::DetectInjection(); VirtualMap::MapInfo *abnormal_vmap = VirtualMap::DetectInjection(); size_t module_injected = SoList::DetectModules(); @@ -22,6 +25,7 @@ Java_org_matrix_demo_MainActivity_stringFromJNI(JNIEnv *env, if (g_array != nullptr) { LOGD("g_array status: %s", g_array->format_state_string().c_str()); } + auto mount_type = get_filesystem_type("/proc/self/exe"); if (abnormal_soinfo != nullptr) { solist_detection = @@ -42,7 +46,12 @@ Java_org_matrix_demo_MainActivity_stringFromJNI(JNIEnv *env, "Module counter: {} shared libraries unloaded", module_injected); } - return env->NewStringUTF( - (solist_detection + "\n" + vmap_detection + "\n" + counter_detection) - .c_str()); + if (mount_type != "EXT4") { + system_mount_detection = + std::format("/system/bin was mounted with type {}", mount_type); + } + + return env->NewStringUTF((solist_detection + "\n" + vmap_detection + "\n" + + counter_detection + "\n" + system_mount_detection) + .c_str()); } diff --git a/app/src/main/cpp/statfs.cpp b/app/src/main/cpp/statfs.cpp new file mode 100644 index 0000000..d49d680 --- /dev/null +++ b/app/src/main/cpp/statfs.cpp @@ -0,0 +1,56 @@ +#include "statfs.hpp" + +#include // For errno +#include // For strerror +#include // For std::hex and std::setw +#include +#include // Provides standard magic number definitions +#include // For converting hex +#include // For statfs + +/** + * @brief Get the filesystem type for a given mount path. + * + * This function uses statfs() to retrieve the filesystem magic number + * and returns a human-readable string representation (e.g., "EXT4", + * "OverlayFS"). If the filesystem type is unknown, it returns the magic number + * in hex. + * + * @param path The mount path to check (e.g., "/system"). + * @return A std::string containing the name of the filesystem or an error + * message. + */ +std::string get_filesystem_type(const std::string &path) { + struct statfs statfs_buf; + + // Call statfs to get filesystem statistics + if (statfs(path.c_str(), &statfs_buf) != 0) { + // If statfs fails, return an error string with the reason + return "Error checking filesystem: " + std::string(strerror(errno)); + } + + // Check the f_type field against known magic numbers + switch (statfs_buf.f_type) { + case EXT4_SUPER_MAGIC: + return "EXT4"; + case OVERLAYFS_SUPER_MAGIC: + return "OverlayFS"; + case F2FS_SUPER_MAGIC: + return "F2FS"; + case TMPFS_MAGIC: + return "tmpfs"; + case PROC_SUPER_MAGIC: + return "procfs"; + // case SQUASHFS_MAGIC: + // return "SquashFS"; + // case EROFS_SUPER_MAGIC_V1: + // return "EROFS"; + default: { + // If the type is unknown, format it as a hex string for logging + std::stringstream ss; + ss << "Unknown (0x" << std::hex << std::setw(8) << std::setfill('0') + << statfs_buf.f_type << ")"; + return ss.str(); + } + } +}