android
demo
MASTG-TEST-0341
MASTG-DEMO-0108: Bypassing Frida Detection in /proc/self/maps to Extract Sensitive Data
Download MASTG-DEMO-0108 APK
Open MASTG-DEMO-0108 Folder
Build MASTG-DEMO-0108 APK
Sample
This sample uses the same code as Detecting Frida hooks and terminating the application on response , which encrypts and decrypts a sensitive API key using AES/GCM via the Android KeyStore. The code includes a runtime hook detection mechanism that scans /proc/self/maps for Frida-related libraries and terminates the process via Process.killProcess() if any are found. This demo demonstrates bypassing the detection by hooking BufferedReader.readLine() to hide Frida entries from /proc/self/maps, causing detectHooking() to return false so the termination path is never reached.
See Detection of Reverse Engineering Tools and Runtime Integrity Verification for more context on bypassing runtime detection mechanisms.
Note
This is a series of correlated tests.
../MASTG-DEMO-0107/MastgTest.kt 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99 package org . owasp . mastestapp
import android.content.Context
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import android.util.Base64
import java.io.BufferedReader
import java.io.FileReader
import java.security.KeyStore
import javax.crypto.Cipher
import javax.crypto.KeyGenerator
import javax.crypto.SecretKey
import javax.crypto.spec.GCMParameterSpec
class MastgTest ( private val context : Context ) {
private val sensitiveApiKey = "sk-OWASP-MAS-SuperSecretKey-1234567890"
private val keyAlias = "mastgCipherKey"
init {
if ( detectHooking ()) {
android . os . Process . killProcess ( android . os . Process . myPid ())
}
}
private fun detectHooking (): Boolean {
try {
BufferedReader ( FileReader ( "/proc/self/maps" )) . use { reader ->
var line : String ?
while ( reader . readLine () . also { line = it } != null ) {
val l = line !! . lowercase ()
if ( l . contains ( "frida" ) || l . contains ( "gadget" )) {
return true
}
}
}
} catch ( _ : Exception ) {
// Unable to read maps
}
return false
}
private fun getOrCreateSecretKey (): SecretKey {
val keyStore = KeyStore . getInstance ( "AndroidKeyStore" ) . apply { load ( null ) }
return if ( keyStore . containsAlias ( keyAlias )) {
( keyStore . getEntry ( keyAlias , null ) as KeyStore . SecretKeyEntry ) . secretKey
} else {
KeyGenerator . getInstance (
KeyProperties . KEY_ALGORITHM_AES ,
"AndroidKeyStore"
) . apply {
init (
KeyGenParameterSpec . Builder (
keyAlias ,
KeyProperties . PURPOSE_ENCRYPT or KeyProperties . PURPOSE_DECRYPT
)
. setBlockModes ( KeyProperties . BLOCK_MODE_GCM )
. setEncryptionPaddings ( KeyProperties . ENCRYPTION_PADDING_NONE )
. build ()
)
} . generateKey ()
}
}
fun mastgTest (): String {
// Check for hooking before performing cryptographic operations
if ( detectHooking ()) {
android . os . Process . killProcess ( android . os . Process . myPid ())
return ""
}
return try {
val key = getOrCreateSecretKey ()
// Encrypt the sensitive API key
val encryptCipher = Cipher . getInstance ( "AES/GCM/NoPadding" )
encryptCipher . init ( Cipher . ENCRYPT_MODE , key )
val iv = encryptCipher . iv
val encryptedBytes = encryptCipher . doFinal ( sensitiveApiKey . toByteArray ( Charsets . UTF_8 ))
val encryptedData = Base64 . encodeToString ( iv + encryptedBytes , Base64 . DEFAULT )
// Decrypt to verify
val decodedData = Base64 . decode ( encryptedData , Base64 . DEFAULT )
val ivFromData = decodedData . copyOfRange ( 0 , 12 )
val ciphertext = decodedData . copyOfRange ( 12 , decodedData . size )
val decryptCipher = Cipher . getInstance ( "AES/GCM/NoPadding" )
decryptCipher . init ( Cipher . DECRYPT_MODE , key , GCMParameterSpec ( 128 , ivFromData ))
val decryptedBytes = decryptCipher . doFinal ( ciphertext )
val decryptedString = String ( decryptedBytes , Charsets . UTF_8 )
"Encryption and decryption successful. \n " +
"Encrypted: $encryptedData \n " +
"Decrypted: $decryptedString"
} catch ( e : Exception ) {
"Error: $ {e.message} "
}
}
}
Steps
Install the app on a device ( Installing Apps )
Run run.sh to spawn the app with the bypass script
Click the Start button
Stop the script by pressing Ctrl+C and/or q to quit the Frida CLI
Observation
The output contains eight frida-agent-64.so memory segments filtered from /proc/self/maps across two scans. Two Cipher.doFinal() calls are captured: one in ENCRYPT_MODE with the plaintext input sk-OWASP-MAS-SuperSecretKey-1234567890, and another in DECRYPT_MODE with the same plaintext as output.
output.txt 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 [ + ] BufferedReader . readLine () hooked : filtering Frida - related entries from / proc / self / maps
[ + ] Cipher . doFinal () hooked : extracting sensitive data
[ * ] Hiding line from / proc / self / maps : 6 d69a0b000 - 6 d6a351000 r -- p 00000000 00 : 01 188 / memfd : frida - agent - 64. so ( deleted )
[ * ] Hiding line from / proc / self / maps : 6 d6a352000 - 6 d6b092000 r - xp 00946000 00 : 01 188 / memfd : frida - agent - 64. so ( deleted )
[ * ] Hiding line from / proc / self / maps : 6 d6b092000 - 6 d6b163000 r -- p 01685000 00 : 01 188 / memfd : frida - agent - 64. so ( deleted )
[ * ] Hiding line from / proc / self / maps : 6 d6b164000 - 6 d6b17f000 rw - p 01756000 00 : 01 188 / memfd : frida - agent - 64. so ( deleted )
[ * ] Hiding line from / proc / self / maps : 6 d69a0b000 - 6 d6a351000 r -- p 00000000 00 : 01 188 / memfd : frida - agent - 64. so ( deleted )
[ * ] Hiding line from / proc / self / maps : 6 d6a352000 - 6 d6b092000 r - xp 00946000 00 : 01 188 / memfd : frida - agent - 64. so ( deleted )
[ * ] Hiding line from / proc / self / maps : 6 d6b092000 - 6 d6b163000 r -- p 01685000 00 : 01 188 / memfd : frida - agent - 64. so ( deleted )
[ * ] Hiding line from / proc / self / maps : 6 d6b164000 - 6 d6b17f000 rw - p 01756000 00 : 01 188 / memfd : frida - agent - 64. so ( deleted )
[ * ] Cipher . doFinal ( byte []) called
Algorithm : AES / GCM / NoPadding
Mode : ENCRYPT_MODE
Input ( plaintext ): sk - OWASP - MAS - SuperSecretKey - 1234567890
Output ( ciphertext hex ): e9ff1fd068d108fad6e3e64aca3ce460c169d956123a119ab596887d7f62d14245a24eeb93da5cb8395bbab4f8bc637d0852221fc96e
Backtrace :
javax . crypto . Cipher . doFinal ( Native Method )
org . owasp . mastestapp . MastgTest . mastgTest ( MastgTest . kt : 79 )
org . owasp . mastestapp . MainActivityKt . MainScreen $ lambda $ 12 $ lambda $ 11 ( MainActivity . kt : 101 )
org . owasp . mastestapp . MainActivityKt . $ r8 $ lambda $ Pm6AsbKBmypP53K - UABM21E_Xxk ( Unknown Source : 0 )
org . owasp . mastestapp . MainActivityKt $$ ExternalSyntheticLambda3 . run ( D8 $$ SyntheticClass : 0 )
java . lang . Thread . run ( Thread . java : 1119 )
[ * ] Cipher . doFinal ( byte []) called
Algorithm : AES / GCM / NoPadding
Mode : DECRYPT_MODE
Input ( ciphertext hex ): e9ff1fd068d108fad6e3e64aca3ce460c169d956123a119ab596887d7f62d14245a24eeb93da5cb8395bbab4f8bc637d0852221fc96e
Output ( plaintext ): sk - OWASP - MAS - SuperSecretKey - 1234567890
Backtrace :
javax . crypto . Cipher . doFinal ( Native Method )
org . owasp . mastestapp . MastgTest . mastgTest ( MastgTest . kt : 89 )
org . owasp . mastestapp . MainActivityKt . MainScreen $ lambda $ 12 $ lambda $ 11 ( MainActivity . kt : 101 )
org . owasp . mastestapp . MainActivityKt . $ r8 $ lambda $ Pm6AsbKBmypP53K - UABM21E_Xxk ( Unknown Source : 0 )
org . owasp . mastestapp . MainActivityKt $$ ExternalSyntheticLambda3 . run ( D8 $$ SyntheticClass : 0 )
java . lang . Thread . run ( Thread . java : 1119 )
Evaluation
The test fails because the BufferedReader.readLine() hook successfully concealed all Frida memory segments from /proc/self/maps, causing detectHooking() to return false. With detection bypassed, the app proceeded with its cryptographic operations, which were intercepted by the Cipher.doFinal() hooks to extract the sensitive API key sk-OWASP-MAS-SuperSecretKey-1234567890 in plaintext.