ai_root_shield 0.1.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.
@@ -0,0 +1,375 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AiRootShield
4
+ module Analyzers
5
+ # Detects hooking frameworks and runtime instrumentation
6
+ class HookingDetector
7
+ # Frida indicators
8
+ FRIDA_INDICATORS = %w[
9
+ frida-server
10
+ frida-agent
11
+ frida-gadget
12
+ re.frida.server
13
+ /data/local/tmp/frida-server
14
+ /system/bin/frida-server
15
+ /system/xbin/frida-server
16
+ libfrida-gadget.so
17
+ frida-agent.so
18
+ FridaGadget
19
+ ].freeze
20
+
21
+ # Xposed Framework indicators
22
+ XPOSED_INDICATORS = %w[
23
+ de.robv.android.xposed.installer
24
+ XposedBridge
25
+ XposedHelpers
26
+ libxposed_art.so
27
+ libxposed_dalvik.so
28
+ /system/framework/XposedBridge.jar
29
+ /system/bin/app_process_xposed
30
+ /system/xbin/xposed
31
+ XposedMods
32
+ ].freeze
33
+
34
+ # Substrate/Cydia Substrate indicators
35
+ SUBSTRATE_INDICATORS = %w[
36
+ MobileSubstrate
37
+ libsubstrate.dylib
38
+ /Library/MobileSubstrate/
39
+ /usr/lib/libsubstrate.dylib
40
+ CydiaSubstrate
41
+ MSHookFunction
42
+ MSHookMessageEx
43
+ substrate.h
44
+ ].freeze
45
+
46
+ # Magisk indicators
47
+ MAGISK_INDICATORS = %w[
48
+ magisk
49
+ magiskhide
50
+ magiskpolicy
51
+ /sbin/magisk
52
+ /system/xbin/magisk
53
+ com.topjohnwu.magisk
54
+ magisk.img
55
+ magisk_merge.img
56
+ .magisk
57
+ magiskinit
58
+ ].freeze
59
+
60
+ # Debugging indicators
61
+ DEBUG_INDICATORS = %w[
62
+ android:debuggable
63
+ ro.debuggable
64
+ gdb
65
+ gdbserver
66
+ lldb
67
+ lldb-server
68
+ strace
69
+ ltrace
70
+ /system/bin/gdbserver
71
+ /data/local/tmp/gdbserver
72
+ ].freeze
73
+
74
+ def analyze(device_data)
75
+ factors = []
76
+ risk_score = 0
77
+
78
+ # Check for Frida
79
+ frida_result = check_frida_presence(device_data)
80
+ factors.concat(frida_result[:factors])
81
+ risk_score += frida_result[:risk_score]
82
+
83
+ # Check for Xposed Framework
84
+ xposed_result = check_xposed_framework(device_data)
85
+ factors.concat(xposed_result[:factors])
86
+ risk_score += xposed_result[:risk_score]
87
+
88
+ # Check for Substrate (iOS)
89
+ substrate_result = check_substrate_presence(device_data)
90
+ factors.concat(substrate_result[:factors])
91
+ risk_score += substrate_result[:risk_score]
92
+
93
+ # Check for Magisk
94
+ magisk_result = check_magisk_presence(device_data)
95
+ factors.concat(magisk_result[:factors])
96
+ risk_score += magisk_result[:risk_score]
97
+
98
+ # Check for debugging tools
99
+ debug_result = check_debugging_tools(device_data)
100
+ factors.concat(debug_result[:factors])
101
+ risk_score += debug_result[:risk_score]
102
+
103
+ # Check runtime behavior indicators
104
+ runtime_result = check_runtime_indicators(device_data)
105
+ factors.concat(runtime_result[:factors])
106
+ risk_score += runtime_result[:risk_score]
107
+
108
+ {
109
+ factors: factors,
110
+ risk_score: [risk_score, 100].min
111
+ }
112
+ end
113
+
114
+ private
115
+
116
+ def check_frida_presence(device_data)
117
+ factors = []
118
+ risk_score = 0
119
+
120
+ # Check processes
121
+ processes = device_data[:processes] || []
122
+ process_names = processes.map { |proc| proc.is_a?(Hash) ? proc["name"] : proc.to_s }
123
+
124
+ FRIDA_INDICATORS.each do |indicator|
125
+ if process_names.any? { |proc| proc.downcase.include?(indicator.downcase) }
126
+ factors << "FRIDA_GADGET"
127
+ risk_score += 25
128
+ break
129
+ end
130
+ end
131
+
132
+ # Check file system
133
+ file_system = device_data[:file_system] || {}
134
+ all_files = (file_system[:suspicious_files] || []) + (file_system[:system_binaries] || [])
135
+
136
+ FRIDA_INDICATORS.each do |indicator|
137
+ if all_files.any? { |file| file.to_s.downcase.include?(indicator.downcase) }
138
+ factors << "FRIDA_FILES_DETECTED"
139
+ risk_score += 20
140
+ break
141
+ end
142
+ end
143
+
144
+ # Check installed packages
145
+ packages = device_data[:installed_packages] || []
146
+ package_names = packages.map { |pkg| pkg.is_a?(Hash) ? pkg["name"] : pkg.to_s }
147
+
148
+ if package_names.any? { |pkg| pkg.downcase.include?("frida") }
149
+ factors << "FRIDA_PACKAGE_INSTALLED"
150
+ risk_score += 22
151
+ end
152
+
153
+ {
154
+ factors: factors,
155
+ risk_score: risk_score
156
+ }
157
+ end
158
+
159
+ def check_xposed_framework(device_data)
160
+ factors = []
161
+ risk_score = 0
162
+
163
+ # Check installed packages
164
+ packages = device_data[:installed_packages] || []
165
+ package_names = packages.map { |pkg| pkg.is_a?(Hash) ? pkg["name"] : pkg.to_s }
166
+
167
+ XPOSED_INDICATORS.each do |indicator|
168
+ if package_names.any? { |pkg| pkg.downcase.include?(indicator.downcase) }
169
+ factors << "XPOSED_FRAMEWORK"
170
+ risk_score += 22
171
+ break
172
+ end
173
+ end
174
+
175
+ # Check file system for Xposed files
176
+ file_system = device_data[:file_system] || {}
177
+ all_files = (file_system[:suspicious_files] || []) + (file_system[:system_binaries] || [])
178
+
179
+ XPOSED_INDICATORS.each do |indicator|
180
+ if all_files.any? { |file| file.to_s.include?(indicator) }
181
+ factors << "XPOSED_FILES_DETECTED"
182
+ risk_score += 18
183
+ break
184
+ end
185
+ end
186
+
187
+ # Check system logs for Xposed activity
188
+ logs = device_data[:logs] || []
189
+ if logs.any? { |log| log.to_s.downcase.include?("xposed") }
190
+ factors << "XPOSED_LOG_ACTIVITY"
191
+ risk_score += 15
192
+ end
193
+
194
+ {
195
+ factors: factors,
196
+ risk_score: risk_score
197
+ }
198
+ end
199
+
200
+ def check_substrate_presence(device_data)
201
+ factors = []
202
+ risk_score = 0
203
+
204
+ return { factors: factors, risk_score: risk_score } unless device_data[:platform] == "ios"
205
+
206
+ # Check file system for Substrate files
207
+ file_system = device_data[:file_system] || {}
208
+ all_files = (file_system[:suspicious_files] || []) + (file_system[:system_binaries] || [])
209
+
210
+ SUBSTRATE_INDICATORS.each do |indicator|
211
+ if all_files.any? { |file| file.to_s.include?(indicator) }
212
+ factors << "SUBSTRATE_INJECTION"
213
+ risk_score += 18
214
+ break
215
+ end
216
+ end
217
+
218
+ # Check installed packages for Substrate-related apps
219
+ packages = device_data[:installed_packages] || []
220
+ package_names = packages.map { |pkg| pkg.is_a?(Hash) ? pkg["name"] : pkg.to_s }
221
+
222
+ if package_names.any? { |pkg| pkg.downcase.include?("substrate") || pkg.downcase.include?("cydia") }
223
+ factors << "SUBSTRATE_PACKAGE_DETECTED"
224
+ risk_score += 20
225
+ end
226
+
227
+ {
228
+ factors: factors,
229
+ risk_score: risk_score
230
+ }
231
+ end
232
+
233
+ def check_magisk_presence(device_data)
234
+ factors = []
235
+ risk_score = 0
236
+
237
+ return { factors: factors, risk_score: risk_score } unless device_data[:platform] == "android"
238
+
239
+ # Check processes for Magisk
240
+ processes = device_data[:processes] || []
241
+ process_names = processes.map { |proc| proc.is_a?(Hash) ? proc["name"] : proc.to_s }
242
+
243
+ MAGISK_INDICATORS.each do |indicator|
244
+ if process_names.any? { |proc| proc.downcase.include?(indicator.downcase) }
245
+ factors << "MAGISK_MODULES"
246
+ risk_score += 20
247
+ break
248
+ end
249
+ end
250
+
251
+ # Check file system for Magisk files
252
+ file_system = device_data[:file_system] || {}
253
+ all_files = (file_system[:suspicious_files] || []) + (file_system[:system_binaries] || [])
254
+
255
+ MAGISK_INDICATORS.each do |indicator|
256
+ if all_files.any? { |file| file.to_s.downcase.include?(indicator.downcase) }
257
+ factors << "MAGISK_FILES_DETECTED"
258
+ risk_score += 18
259
+ break
260
+ end
261
+ end
262
+
263
+ # Check installed packages
264
+ packages = device_data[:installed_packages] || []
265
+ package_names = packages.map { |pkg| pkg.is_a?(Hash) ? pkg["name"] : pkg.to_s }
266
+
267
+ if package_names.any? { |pkg| pkg.downcase.include?("magisk") }
268
+ factors << "MAGISK_APP_INSTALLED"
269
+ risk_score += 22
270
+ end
271
+
272
+ {
273
+ factors: factors,
274
+ risk_score: risk_score
275
+ }
276
+ end
277
+
278
+ def check_debugging_tools(device_data)
279
+ factors = []
280
+ risk_score = 0
281
+
282
+ # Check processes for debugging tools
283
+ processes = device_data[:processes] || []
284
+ process_names = processes.map { |proc| proc.is_a?(Hash) ? proc["name"] : proc.to_s }
285
+
286
+ DEBUG_INDICATORS.each do |indicator|
287
+ if process_names.any? { |proc| proc.downcase.include?(indicator.downcase) }
288
+ factors << "DEBUGGER_ATTACHED"
289
+ risk_score += 15
290
+ break
291
+ end
292
+ end
293
+
294
+ # Check file system for debugging binaries
295
+ file_system = device_data[:file_system] || {}
296
+ all_files = (file_system[:suspicious_files] || []) + (file_system[:system_binaries] || [])
297
+
298
+ DEBUG_INDICATORS.each do |indicator|
299
+ if all_files.any? { |file| file.to_s.include?(indicator) }
300
+ factors << "DEBUG_TOOLS_PRESENT"
301
+ risk_score += 12
302
+ break
303
+ end
304
+ end
305
+
306
+ # Check system settings for debugging flags
307
+ system_info = device_data[:system_info] || {}
308
+ security_settings = device_data[:security_settings] || {}
309
+
310
+ if security_settings[:usb_debugging] == true
311
+ factors << "USB_DEBUGGING_ENABLED"
312
+ risk_score += 10
313
+ end
314
+
315
+ {
316
+ factors: factors,
317
+ risk_score: risk_score
318
+ }
319
+ end
320
+
321
+ def check_runtime_indicators(device_data)
322
+ factors = []
323
+ risk_score = 0
324
+
325
+ # Check for suspicious library injections
326
+ processes = device_data[:processes] || []
327
+
328
+ processes.each do |process|
329
+ next unless process.is_a?(Hash)
330
+
331
+ libraries = process["loaded_libraries"] || []
332
+
333
+ # Check for known hooking libraries
334
+ hooking_libs = %w[libfrida libxposed libsubstrate libmagisk]
335
+
336
+ hooking_libs.each do |lib|
337
+ if libraries.any? { |library| library.to_s.downcase.include?(lib) }
338
+ factors << "RUNTIME_LIBRARY_INJECTION"
339
+ risk_score += 18
340
+ break
341
+ end
342
+ end
343
+ end
344
+
345
+ # Check system logs for hooking activity
346
+ logs = device_data[:logs] || []
347
+
348
+ hooking_keywords = %w[hook inject frida xposed substrate magisk]
349
+
350
+ hooking_keywords.each do |keyword|
351
+ if logs.any? { |log| log.to_s.downcase.include?(keyword) }
352
+ factors << "HOOKING_LOG_ACTIVITY"
353
+ risk_score += 12
354
+ break
355
+ end
356
+ end
357
+
358
+ # Check for method swizzling indicators (iOS)
359
+ if device_data[:platform] == "ios"
360
+ swizzling_indicators = %w[method_exchangeImplementations class_replaceMethod]
361
+
362
+ if logs.any? { |log| swizzling_indicators.any? { |indicator| log.to_s.include?(indicator) } }
363
+ factors << "METHOD_SWIZZLING_DETECTED"
364
+ risk_score += 15
365
+ end
366
+ end
367
+
368
+ {
369
+ factors: factors,
370
+ risk_score: risk_score
371
+ }
372
+ end
373
+ end
374
+ end
375
+ end