react-native-device-defense 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +236 -0
  3. package/android/build.gradle +90 -0
  4. package/android/proguard-rules.pro +28 -0
  5. package/android/src/main/AndroidManifest.xml +4 -0
  6. package/android/src/main/cpp/CMakeLists.txt +45 -0
  7. package/android/src/main/cpp/device-security.cpp +314 -0
  8. package/android/src/main/java/vn/osp/security/DebugDetection.kt +131 -0
  9. package/android/src/main/java/vn/osp/security/DeviceSecurityModule.kt +277 -0
  10. package/android/src/main/java/vn/osp/security/DeviceSecurityPackage.kt +58 -0
  11. package/android/src/main/java/vn/osp/security/EmulatorDetection.kt +204 -0
  12. package/android/src/main/java/vn/osp/security/HookDetection.kt +270 -0
  13. package/android/src/main/java/vn/osp/security/NativeSecurityCheck.kt +66 -0
  14. package/android/src/main/java/vn/osp/security/RootDetection.kt +349 -0
  15. package/lib/commonjs/NativeDeviceSecurity.js +9 -0
  16. package/lib/commonjs/NativeDeviceSecurity.js.map +1 -0
  17. package/lib/commonjs/api.js +213 -0
  18. package/lib/commonjs/api.js.map +1 -0
  19. package/lib/commonjs/components/SecurityBlockedScreen.js +177 -0
  20. package/lib/commonjs/components/SecurityBlockedScreen.js.map +1 -0
  21. package/lib/commonjs/components/index.js +13 -0
  22. package/lib/commonjs/components/index.js.map +1 -0
  23. package/lib/commonjs/hooks/index.js +13 -0
  24. package/lib/commonjs/hooks/index.js.map +1 -0
  25. package/lib/commonjs/hooks/useDeviceSecurity.js +81 -0
  26. package/lib/commonjs/hooks/useDeviceSecurity.js.map +1 -0
  27. package/lib/commonjs/index.js +48 -0
  28. package/lib/commonjs/index.js.map +1 -0
  29. package/lib/commonjs/types.js +2 -0
  30. package/lib/commonjs/types.js.map +1 -0
  31. package/lib/module/NativeDeviceSecurity.js +3 -0
  32. package/lib/module/NativeDeviceSecurity.js.map +1 -0
  33. package/lib/module/api.js +206 -0
  34. package/lib/module/api.js.map +1 -0
  35. package/lib/module/components/SecurityBlockedScreen.js +169 -0
  36. package/lib/module/components/SecurityBlockedScreen.js.map +1 -0
  37. package/lib/module/components/index.js +2 -0
  38. package/lib/module/components/index.js.map +1 -0
  39. package/lib/module/hooks/index.js +2 -0
  40. package/lib/module/hooks/index.js.map +1 -0
  41. package/lib/module/hooks/useDeviceSecurity.js +73 -0
  42. package/lib/module/hooks/useDeviceSecurity.js.map +1 -0
  43. package/lib/module/index.js +21 -0
  44. package/lib/module/index.js.map +1 -0
  45. package/lib/module/types.js +2 -0
  46. package/lib/module/types.js.map +1 -0
  47. package/lib/typescript/NativeDeviceSecurity.d.ts +16 -0
  48. package/lib/typescript/NativeDeviceSecurity.d.ts.map +1 -0
  49. package/lib/typescript/api.d.ts +55 -0
  50. package/lib/typescript/api.d.ts.map +1 -0
  51. package/lib/typescript/components/SecurityBlockedScreen.d.ts +23 -0
  52. package/lib/typescript/components/SecurityBlockedScreen.d.ts.map +1 -0
  53. package/lib/typescript/components/index.d.ts +2 -0
  54. package/lib/typescript/components/index.d.ts.map +1 -0
  55. package/lib/typescript/hooks/index.d.ts +3 -0
  56. package/lib/typescript/hooks/index.d.ts.map +1 -0
  57. package/lib/typescript/hooks/useDeviceSecurity.d.ts +7 -0
  58. package/lib/typescript/hooks/useDeviceSecurity.d.ts.map +1 -0
  59. package/lib/typescript/index.d.ts +12 -0
  60. package/lib/typescript/index.d.ts.map +1 -0
  61. package/lib/typescript/types.d.ts +81 -0
  62. package/lib/typescript/types.d.ts.map +1 -0
  63. package/package.json +72 -0
  64. package/react-native-device-security.podspec +18 -0
  65. package/src/NativeDeviceSecurity.ts +33 -0
  66. package/src/api.ts +225 -0
  67. package/src/components/SecurityBlockedScreen.tsx +204 -0
  68. package/src/components/index.ts +1 -0
  69. package/src/hooks/index.ts +5 -0
  70. package/src/hooks/useDeviceSecurity.ts +91 -0
  71. package/src/index.ts +27 -0
  72. package/src/types.ts +95 -0
@@ -0,0 +1,314 @@
1
+ #include <jni.h>
2
+ #include <string>
3
+ #include <vector>
4
+ #include <fstream>
5
+ #include <dirent.h>
6
+ #include <sys/stat.h>
7
+ #include <unistd.h>
8
+ #include <android/log.h>
9
+ #include <stdexcept>
10
+
11
+ #define LOG_TAG "DeviceSecurityNative"
12
+ #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
13
+ #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
14
+
15
+ /**
16
+ * Check if a file exists
17
+ */
18
+ static bool fileExists(const std::string& path) {
19
+ struct stat buffer;
20
+ return (stat(path.c_str(), &buffer) == 0);
21
+ }
22
+
23
+ /**
24
+ * Check if a file is executable
25
+ */
26
+ static bool isExecutable(const std::string& path) {
27
+ struct stat buffer;
28
+ if (stat(path.c_str(), &buffer) != 0) {
29
+ return false;
30
+ }
31
+ return (buffer.st_mode & S_IXUSR) != 0;
32
+ }
33
+
34
+ /**
35
+ * Check if a directory exists
36
+ */
37
+ static bool directoryExists(const std::string& path) {
38
+ struct stat buffer;
39
+ return (stat(path.c_str(), &buffer) == 0) && S_ISDIR(buffer.st_mode);
40
+ }
41
+
42
+ /**
43
+ * Check for su binary in various locations
44
+ */
45
+ static bool checkSuBinary() {
46
+ const std::vector<std::string> suPaths = {
47
+ "/system/bin/su",
48
+ "/system/xbin/su",
49
+ "/sbin/su",
50
+ "/data/local/xbin/su",
51
+ "/data/local/bin/su",
52
+ "/system/sd/xbin/su",
53
+ "/system/bin/failsafe/su",
54
+ "/data/local/su",
55
+ "/su/bin/su",
56
+ "/magisk/.core/bin/su",
57
+ "/system/usr/we-need-root/su"
58
+ };
59
+
60
+ for (const auto& path : suPaths) {
61
+ if (fileExists(path) && isExecutable(path)) {
62
+ LOGD("Found su binary at: %s", path.c_str());
63
+ return true;
64
+ }
65
+ }
66
+
67
+ return false;
68
+ }
69
+
70
+ /**
71
+ * Check for dangerous binaries
72
+ */
73
+ static bool checkDangerousBinaries() {
74
+ const std::vector<std::string> binaries = {
75
+ "/system/xbin/busybox",
76
+ "/system/bin/busybox",
77
+ "/sbin/busybox",
78
+ "/data/local/xbin/busybox",
79
+ "/data/local/bin/busybox",
80
+ "/system/app/Superuser.apk",
81
+ "/sbin/.magisk",
82
+ "/system/xbin/magisk",
83
+ "/system/bin/magisk"
84
+ };
85
+
86
+ for (const auto& binary : binaries) {
87
+ if (fileExists(binary)) {
88
+ LOGD("Found dangerous binary: %s", binary.c_str());
89
+ return true;
90
+ }
91
+ }
92
+
93
+ return false;
94
+ }
95
+
96
+ /**
97
+ * Check for root-related directories
98
+ */
99
+ static bool checkRootDirectories() {
100
+ const std::vector<std::string> directories = {
101
+ "/data/local/xbin",
102
+ "/data/local/bin",
103
+ "/su",
104
+ "/system/app/SuperSU",
105
+ "/system/app/Superuser",
106
+ "/data/data/com.noshufou.android.su",
107
+ "/data/data/com.thirdparty.superuser",
108
+ "/data/data/eu.chainfire.supersu",
109
+ "/data/data/com.topjohnwu.magisk",
110
+ "/cache/magisk.log",
111
+ "/dev/com.topjohnwu.magisk",
112
+ "/system/app/MagiskManager",
113
+ "/data/adb/magisk",
114
+ "/data/adb/modules"
115
+ };
116
+
117
+ for (const auto& dir : directories) {
118
+ if (directoryExists(dir)) {
119
+ LOGD("Found root directory: %s", dir.c_str());
120
+ return true;
121
+ }
122
+ }
123
+
124
+ return false;
125
+ }
126
+
127
+ /**
128
+ * Check system properties for root indicators
129
+ */
130
+ static bool checkSystemProperties() {
131
+ const std::vector<std::string> propFiles = {
132
+ "/default.prop",
133
+ "/system/build.prop",
134
+ "/vendor/build.prop",
135
+ "/product/build.prop"
136
+ };
137
+
138
+ for (const auto& propFile : propFiles) {
139
+ if (!fileExists(propFile)) continue;
140
+
141
+ std::ifstream file(propFile);
142
+ std::string line;
143
+
144
+ while (std::getline(file, line)) {
145
+ if (line.find("ro.debuggable=1") != std::string::npos) {
146
+ LOGD("Found ro.debuggable=1 in %s", propFile.c_str());
147
+ return true;
148
+ }
149
+ if (line.find("ro.secure=0") != std::string::npos) {
150
+ LOGD("Found ro.secure=0 in %s", propFile.c_str());
151
+ return true;
152
+ }
153
+ if (line.find("service.adb.root=1") != std::string::npos) {
154
+ LOGD("Found service.adb.root=1 in %s", propFile.c_str());
155
+ return true;
156
+ }
157
+ }
158
+ }
159
+
160
+ return false;
161
+ }
162
+
163
+ /**
164
+ * Check mount points for RW system
165
+ */
166
+ static bool checkMountPoints() {
167
+ std::ifstream mounts("/proc/mounts");
168
+ std::string line;
169
+
170
+ const std::vector<std::string> systemMounts = {
171
+ "/system",
172
+ "/vendor",
173
+ "/product",
174
+ "/system_ext"
175
+ };
176
+
177
+ while (std::getline(mounts, line)) {
178
+ // Check if any system mount is mounted RW
179
+ for (const auto& mount : systemMounts) {
180
+ if (line.find(mount) != std::string::npos) {
181
+ if (line.find("rw,") != std::string::npos ||
182
+ line.find(" rw ") != std::string::npos) {
183
+ LOGD("Found RW mount: %s", line.c_str());
184
+ return true;
185
+ }
186
+ }
187
+ }
188
+ }
189
+
190
+ return false;
191
+ }
192
+
193
+ /**
194
+ * Check for tracer PID (debugger detection)
195
+ */
196
+ static bool checkTracerPid() {
197
+ std::ifstream statusFile("/proc/self/status");
198
+ std::string line;
199
+
200
+ while (std::getline(statusFile, line)) {
201
+ if (line.find("TracerPid:") == 0) {
202
+ try {
203
+ size_t pos = line.find_last_not_of(" \t\n\r");
204
+ if (pos != std::string::npos && pos > 10) {
205
+ std::string value = line.substr(10, pos - 9);
206
+ int tracerPid = std::stoi(value);
207
+ if (tracerPid > 0) {
208
+ LOGD("Tracer PID detected: %d", tracerPid);
209
+ return true;
210
+ }
211
+ }
212
+ } catch (const std::exception& e) {
213
+ // Parse error, ignore
214
+ }
215
+ }
216
+ }
217
+
218
+ return false;
219
+ }
220
+
221
+ /**
222
+ * Check for Frida in /proc/self/maps
223
+ */
224
+ static bool checkFridaInMaps() {
225
+ std::ifstream mapsFile("/proc/self/maps");
226
+ std::string line;
227
+
228
+ while (std::getline(mapsFile, line)) {
229
+ if (line.find("frida") != std::string::npos ||
230
+ line.find("frida-agent") != std::string::npos ||
231
+ line.find("libfrida") != std::string::npos) {
232
+ LOGD("Found Frida in maps: %s", line.c_str());
233
+ return true;
234
+ }
235
+ }
236
+
237
+ return false;
238
+ }
239
+
240
+ /**
241
+ * Main root detection function
242
+ */
243
+ static bool performRootDetection() {
244
+ // Check for su binary
245
+ if (checkSuBinary()) {
246
+ return true;
247
+ }
248
+
249
+ // Check for dangerous binaries
250
+ if (checkDangerousBinaries()) {
251
+ return true;
252
+ }
253
+
254
+ // Check for root directories
255
+ if (checkRootDirectories()) {
256
+ return true;
257
+ }
258
+
259
+ // Check system properties
260
+ if (checkSystemProperties()) {
261
+ return true;
262
+ }
263
+
264
+ // Check mount points
265
+ if (checkMountPoints()) {
266
+ return true;
267
+ }
268
+
269
+ return false;
270
+ }
271
+
272
+ extern "C" JNIEXPORT jboolean JNICALL
273
+ Java_vn_osp_security_NativeSecurityCheck_isRooted(JNIEnv* env, jobject /* this */) {
274
+ return performRootDetection() ? JNI_TRUE : JNI_FALSE;
275
+ }
276
+
277
+ extern "C" JNIEXPORT jboolean JNICALL
278
+ Java_vn_osp_security_NativeSecurityCheck_hasDangerousBinaries(JNIEnv* env, jobject /* this */) {
279
+ return checkDangerousBinaries() ? JNI_TRUE : JNI_FALSE;
280
+ }
281
+
282
+ extern "C" JNIEXPORT jboolean JNICALL
283
+ Java_vn_osp_security_NativeSecurityCheck_hasSuspiciousSystemProperties(JNIEnv* env, jobject /* this */) {
284
+ return checkSystemProperties() ? JNI_TRUE : JNI_FALSE;
285
+ }
286
+
287
+ extern "C" JNIEXPORT jboolean JNICALL
288
+ Java_vn_osp_security_NativeSecurityCheck_hasHookFramework(JNIEnv* env, jobject /* this */) {
289
+ return checkFridaInMaps() ? JNI_TRUE : JNI_FALSE;
290
+ }
291
+
292
+ extern "C" JNIEXPORT jboolean JNICALL
293
+ Java_vn_osp_security_NativeSecurityCheck_isDebuggerAttached(JNIEnv* env, jobject /* this */) {
294
+ return checkTracerPid() ? JNI_TRUE : JNI_FALSE;
295
+ }
296
+
297
+ extern "C" JNIEXPORT jstring JNICALL
298
+ Java_vn_osp_security_NativeSecurityCheck_getSecurityStatus(JNIEnv* env, jobject /* this */) {
299
+ bool isRooted = performRootDetection();
300
+ bool hasDangerousBins = checkDangerousBinaries();
301
+ bool hasSuspiciousProps = checkSystemProperties();
302
+ bool hasHook = checkFridaInMaps();
303
+ bool hasDebugger = checkTracerPid();
304
+
305
+ std::string json = "{";
306
+ json += "\"isRooted\":" + std::string(isRooted ? "true" : "false") + ",";
307
+ json += "\"hasDangerousBins\":" + std::string(hasDangerousBins ? "true" : "false") + ",";
308
+ json += "\"hasSuspiciousProps\":" + std::string(hasSuspiciousProps ? "true" : "false") + ",";
309
+ json += "\"hasHookFramework\":" + std::string(hasHook ? "true" : "false") + ",";
310
+ json += "\"isDebuggerAttached\":" + std::string(hasDebugger ? "true" : "false");
311
+ json += "}";
312
+
313
+ return env->NewStringUTF(json.c_str());
314
+ }
@@ -0,0 +1,131 @@
1
+ package vn.osp.security
2
+
3
+ import android.content.Context
4
+ import android.os.Debug
5
+ import java.io.BufferedReader
6
+ import java.io.File
7
+ import java.io.InputStreamReader
8
+
9
+ /**
10
+ * Detection for debuggers and debugging tools
11
+ */
12
+ class DebugDetection(private val context: Context) {
13
+
14
+ /**
15
+ * Check if app is debuggable
16
+ */
17
+ fun isDebuggable(): Boolean {
18
+ // Check application flags
19
+ val appInfo = context.applicationInfo
20
+ if ((appInfo.flags and android.content.pm.ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
21
+ return true
22
+ }
23
+
24
+ // Check if debugger is connected
25
+ if (Debug.isDebuggerConnected()) {
26
+ return true
27
+ }
28
+
29
+ // Check if debugger is waiting
30
+ if (Debug.waitingForDebugger()) {
31
+ return true
32
+ }
33
+
34
+ // Check for tracer PID
35
+ if (checkTracerPid()) {
36
+ return true
37
+ }
38
+
39
+ return false
40
+ }
41
+
42
+ /**
43
+ * Check for tracer PID in /proc/self/status
44
+ * Tracer PID > 0 indicates a debugger is attached
45
+ */
46
+ private fun checkTracerPid(): Boolean {
47
+ try {
48
+ val statusFile = File("/proc/self/status")
49
+ if (!statusFile.exists()) {
50
+ return false
51
+ }
52
+
53
+ val bufferedReader = BufferedReader(InputStreamReader(statusFile.inputStream()))
54
+ bufferedReader.use { reader ->
55
+ var line: String?
56
+ while (reader.readLine().also { line = it } != null) {
57
+ if (line?.startsWith("TracerPid:") == true) {
58
+ val tracerPid = line.substringAfter(":").trim()
59
+ val pid = tracerPid.toIntOrNull()
60
+ // TracerPid > 0 means a debugger is attached
61
+ return pid != null && pid > 0
62
+ }
63
+ }
64
+ }
65
+ } catch (e: Exception) {
66
+ // Ignore errors
67
+ }
68
+
69
+ return false
70
+ }
71
+
72
+ /**
73
+ * Check for debugging tools installed
74
+ */
75
+ fun hasDebuggingTools(): Boolean {
76
+ val debugPackages = listOf(
77
+ "com.android.spare_parts", // Android spare parts
78
+ "com.android.development", // Development settings
79
+ "com.android.customlocale2", // Custom locale
80
+ "com.android.emulator.gps", // Emulator GPS
81
+ "com.saurik.substrate", // Substrate (cydia alternative)
82
+ "com.n0n3m4.gpsroot", // GPS root
83
+ "com.zachspong.temprootremovejb", // Temp root remove
84
+ "com.ramdroid.appquarantine", // App quarantine
85
+ "com.devadvance.rootcloak", // Root cloak
86
+ "com.devadvance.rootcloakplus", // Root cloak plus
87
+ "de.robv.android.xposed.installer", // Xposed
88
+ "com.saurik.substrate", // Substrate
89
+ "com.pyler.panel", // Xposed module
90
+ "com.elpuerco.touches", // Touches indicator
91
+ "com.manic.networkhandup", // Network handup
92
+ "com.automate1234 automate", // Automate
93
+ "com.faendir.leo.louise", // Louise
94
+ "com.faendir.leo.louise.free", // Louise free
95
+ "com.faendir.leo.louise.paid", // Louise paid
96
+ "com.faendir.leo.louise.unlock", // Louise unlock
97
+ "com.faendir.leo.louise.unlock.all" // Louise unlock all
98
+ )
99
+
100
+ return debugPackages.any { isPackageInstalled(it) }
101
+ }
102
+
103
+ /**
104
+ * Check if ADB debugging is enabled
105
+ */
106
+ fun isAdbEnabled(): Boolean {
107
+ // Check global settings for ADB
108
+ return try {
109
+ val settings = android.provider.Settings.Global.getInt(
110
+ context.contentResolver,
111
+ android.provider.Settings.Global.ADB_ENABLED,
112
+ 0
113
+ )
114
+ settings == 1
115
+ } catch (e: Exception) {
116
+ false
117
+ }
118
+ }
119
+
120
+ /**
121
+ * Check if package is installed
122
+ */
123
+ private fun isPackageInstalled(packageName: String): Boolean {
124
+ return try {
125
+ context.packageManager.getPackageInfo(packageName, 0)
126
+ true
127
+ } catch (e: Exception) {
128
+ false
129
+ }
130
+ }
131
+ }