Le dossier sécurisé est une fonctionnalité présente sur les téléphones Android permettant de dissimuler des fichiers dans un emplacement dont l’accès est protégé par un code PIN ou un schéma.

Où les fichiers du dossier sécurisé sont-ils stockés ?
La première étape est de déterminer la localisation physique du dossier sécurisé. Énumérons les fichiers de plus de 500Mo présents sur le téléphone :
lynx:/ # find / -type f -size +500M 2>/dev/null
/data/user/0/com.android.virtualization.terminal/files/linux/root_part
/data/data/com.android.virtualization.terminal/files/linux/root_part
/data/gsi/ota/product_b-cow-img.img.0000
/data_mirror/data_ce/null/0/com.android.virtualization.terminal/files/linux/root_part
Maintenant, créons dans /data/media/0/Download un fichier constitué d’environ 500 millions de ‘a’ :
lynx:/data/media/0/Download # dd if=/dev/zero bs=16M count=32 2>/dev/null | tr '\0' 'a' > a.txt
lynx:/data/media/0/Download # chmod 777 a.txt
lynx:/data/media/0/Download # ls -l a.txt
-rwxrwxrwx 1 root media_rw 536870912 2026-10-13 17:36 a.txt
lynx:/data/media/0/Download # ls -lh a.txt
-rwxrwxrwx 1 root media_rw 512M 2026-10-13 17:36 a.txt
lynx:/data/media/0/Download # md5sum a.txt
31e4d9c6d74cd592b78f77f72965d6ab a.txt
Relançons la recherche :
lynx:/data/media/0/Download # find / -type f -size +500M 2>/dev/null
/storage/emulated/0/Download/a.txt
/mnt/pass_through/0/emulated/0/Download/a.txt
/mnt/androidwritable/0/emulated/0/Download/a.txt
/mnt/installer/0/emulated/0/Download/a.txt
/mnt/user/0/emulated/0/Download/a.txt
/data/media/0/Download/a.txt
/data/user/0/com.android.virtualization.terminal/files/linux/root_part
/data/data/com.android.virtualization.terminal/files/linux/root_part
/data/gsi/ota/product_b-cow-img.img.0000
/data_mirror/data_ce/null/0/com.android.virtualization.terminal/files/linux/root_part
Cette recherche identifie sans ambiguïté notre fichier a.txt.
Déplaçons-le maintenant dans le dossier sécurisé. Le fichier résultant sera probablement chiffré et aura une taille normalement supérieure au fichier clair.
En relançant find une nouvelle fois, nous n’allons plus voir a.txt, mais allons voir apparaître un nouveau fichier qui sera a.txt dans le dossier sécurisé :
lynx:/ # find / -type f -size +500M 2>/dev/null
/data/user/0/com.android.virtualization.terminal/files/linux/root_part
/data/user/0/com.google.android.apps.nbu.files/files/.FilesByGoogle/a.txt
/data/data/com.android.virtualization.terminal/files/linux/root_part
/data/data/com.google.android.apps.nbu.files/files/.FilesByGoogle/a.txt
/data_mirror/data_ce/null/0/com.android.virtualization.terminal/files/linux/root_part
/data_mirror/data_ce/null/0/com.google.android.apps.nbu.files/files/.FilesByGoogle/a.txt
Recalculons le haché du fichier a.txt présent dans le dossier sécurisé :
lynx:/ # ls -l /data/data/com.google.android.apps.nbu.files/files/.FilesByGoogle/a.txt
-rw------- 1 u0_a152 u0_a152 536870912 2026-10-14 00:02 /data/data/com.google.android.apps.nbu.files/files/.FilesByGoogle/a.txt
lynx:/ # md5sum /data/data/com.google.android.apps.nbu.files/files/.FilesByGoogle/a.txt
31e4d9c6d74cd592b78f77f72965d6ab /data/data/com.google.android.apps.nbu.files/files/.FilesByGoogle/a.txt
C’est le haché du fichier en clair ! C’est une surprise car l’on pouvait imaginer que les fichiers déplacés dans le dossier sécurisé y soient chiffrés.
Redémarrons le téléphone et recherchons maintenant les fichiers de plus de 500 Mo, mais AVANT de déverrouiller le téléphone :
1|lynx:/ # find / -type f -size +500M -exec ls -l {} \; 2>/dev/null
-rw------- 1 u0_a287 u0_a287 112117940224 2026-10-03 00:27 /data/user/0/du138wAAAAADPUh3FVAZLIOdWc_ENZiuCVge453wRVY8vvFIF_qquihAEXhb2dh1m9cXeupIX4Y/3p65BgAAAABciauWOY0P98nR-TWuoyno/5_mUvQAAAACygXiwUHlOY1RR-h6qhuPC/v5HKLAAAAAD4KcFDgbz6-8WtQc6aU0mU
-rw------- 1 u0_a152 u0_a152 536870912 2026-10-14 00:02 /data/user/0/2IWWHQAAAACV0A7Iqks0v7u4pCNyeYjgSVReZOFcWtZfp27PTKmE_xzdEktNzJ-JtIL91VUTQ8U/5ozATwAAAAAjRgE9_ZBOnzcXokYTVtSL/xmqMnQAAAABYP5Z_Wnd4GPsSVtWgN7ur/qQ5TuAAAAADC21R90w_CmiR59zBPZ-Ch
-rw------- 1 u0_a287 u0_a287 112117940224 2026-10-03 00:27 /data/data/du138wAAAAADPUh3FVAZLIOdWc_ENZiuCVge453wRVY8vvFIF_qquihAEXhb2dh1m9cXeupIX4Y/3p65BgAAAABciauWOY0P98nR-TWuoyno/5_mUvQAAAACygXiwUHlOY1RR-h6qhuPC/v5HKLAAAAAD4KcFDgbz6-8WtQc6aU0mU
-rw------- 1 u0_a152 u0_a152 536870912 2026-10-14 00:02 /data/data/2IWWHQAAAACV0A7Iqks0v7u4pCNyeYjgSVReZOFcWtZfp27PTKmE_xzdEktNzJ-JtIL91VUTQ8U/5ozATwAAAAAjRgE9_ZBOnzcXokYTVtSL/xmqMnQAAAABYP5Z_Wnd4GPsSVtWgN7ur/qQ5TuAAAAADC21R90w_CmiR59zBPZ-Ch
-rw------- 1 u0_a287 u0_a287 112117940224 2026-10-03 00:27 /data_mirror/data_ce/null/0/du138wAAAAADPUh3FVAZLIOdWc_ENZiuCVge453wRVY8vvFIF_qquihAEXhb2dh1m9cXeupIX4Y/3p65BgAAAABciauWOY0P98nR-TWuoyno/5_mUvQAAAACygXiwUHlOY1RR-h6qhuPC/v5HKLAAAAAD4KcFDgbz6-8WtQc6aU0mU
-rw------- 1 u0_a152 u0_a152 536870912 2026-10-14 00:02 /data_mirror/data_ce/null/0/2IWWHQAAAACV0A7Iqks0v7u4pCNyeYjgSVReZOFcWtZfp27PTKmE_xzdEktNzJ-JtIL91VUTQ8U/5ozATwAAAAAjRgE9_ZBOnzcXokYTVtSL/xmqMnQAAAABYP5Z_Wnd4GPsSVtWgN7ur/qQ5TuAAAAADC21R90w_CmiR59zBPZ-Ch
Le fichier est bien présent (c’est le fichier de 536870912 octets), sous une forme chiffrée. Ce mécanisme de chiffrement n’a toutefois rien à voir avec la fonctionnalité de dossier sécurisé : il s’agit du chiffrement FBE mis en oeuvre par Android lui-même.
Nous savons que l’application implémentant le dossier sécurisé est Files by Google, dont le nom de package est com.google.android.apps.nbu.files.
Quel est l’emplacement de l’apk correspondant ?
lynx:/ # pm list packages -f | grep 'nbu.files'
package:/data/app/~~13rQB2-z-UJSzQgCOBkBEw==/com.google.android.apps.nbu.files-lBnlganWVRDi9OsMDpPctw==/base.apk=com.google.android.apps.nbu.files
Récupérons-le, et étudions-le statiquement et dynamiquement.
Pour cela, recherchons des appels à des fonctions et api cryptographiques usuelles. Il est plausible que le code PIN saisi soit utilisé dans une opération de dérivation de clef, qui risque de faire intervenir un HMAC. Une piste naturelle est donc de tracer les méthodes dont le nom contient le mot « HMAC » :
Bingo, un appel au constructeur de BasePBKDF2WithHmacSHA1 est appelé :
frida-trace -U -f com.google.android.apps.nbu.files -j '*Hmac*!*'
(...)
12378 ms PBEPBKDF2$PBKDF2WithHmacSHA1UTF8.$init()
12380 ms | PBEPBKDF2$BasePBKDF2WithHmacSHA1.$init("PBKDF2WithHmacSHA1", 5)
Si à la place du mot-clé « Hmac » on utilise le mot-clé « symmetric », on trouve pas mal de choses intéressantes. En restreignant un peu, on tombe sur l’appel à une fonction convertPassword
qui reçoit le code PIN utilisé (2718, caractères qui ont pour valeur ascii (0x32, 0x37, 0x31, 0x38), soit (50, 55, 49, 56) en décimal), et sur un tableau de 32 octets qui pourrait tout à fait être une clé symétrique :
frida-trace -U -f com.google.android.apps.nbu.files -j 'com.android.org.bouncycastle.jcajce.provider.symmetric*!*'
(...)
/* TID 0x1d1 */
8674 ms PBEPBKDF2$PBKDF2WithHmacSHA1UTF8.$init()
8678 ms | PBEPBKDF2$BasePBKDF2WithHmacSHA1.$init("PBKDF2WithHmacSHA1", 5)
8679 ms | | PBEPBKDF2$BasePBKDF2.$init("PBKDF2WithHmacSHA1", 5, 1, null)
8680 ms | | | PBEPBKDF2$BasePBKDF2.$init("PBKDF2WithHmacSHA1", 5, 1)
8681 ms | | | | PBEPBKDF2$BasePBKDF2.$init("PBKDF2WithHmacSHA1", 5, 1, 0, 0)
8686 ms | | | | | BaseSecretKeyFactory.$init("PBKDF2WithHmacSHA1", "<instance: com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier>")
8698 ms PBEPBKDF2$BasePBKDF2.engineGenerateSecret("<instance: java.security.spec.KeySpec, $className: javax.crypto.spec.PBEKeySpec>")
8702 ms | PBE$Util.makePBEMacParameters("<instance: javax.crypto.spec.PBEKeySpec>", 5, 1, 256)
8702 ms | | PBE$Util.makePBEGenerator(5, 1)
8706 ms | | <= "<instance: com.android.org.bouncycastle.crypto.PBEParametersGenerator, $className: com.android.org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator>"
8707 ms | | PBE$Util.convertPassword(5, "<instance: javax.crypto.spec.PBEKeySpec>")
8708 ms | | <= [50,55,49,56]
9400 ms | <= "<instance: com.android.org.bouncycastle.crypto.CipherParameters, $className: com.android.org.bouncycastle.crypto.params.KeyParameter>"
9401 ms | BCPBEKey.$init("PBKDF2WithHmacSHA1", "<instance: com.android.org.bouncycastle.asn1.ASN1ObjectIdentifier>", 5, 1, 256, -1, "<instance: javax.crypto.spec.PBEKeySpec>", "<instance: com.android.org.bouncycastle.crypto.CipherParameters, $className: com.android.org.bouncycastle.crypto.params.KeyParameter>")
9401 ms <= "<instance: javax.crypto.SecretKey, $className: com.android.org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey>"
9401 ms BCPBEKey.getEncoded()
9401 ms | BCPBEKey.checkDestroyed("<instance: javax.security.auth.Destroyable, $className: com.android.org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey>")
9401 ms | | BCPBEKey.isDestroyed()
9401 ms | | <= false
9402 ms <= [-123,-52,-68,-30,-92,-106,-21,124,30,-58,53,59,24,-59,99,-114,34,-17,-8,79,103,3,-13,28,13,-9,99,30,109,-74,35,-13]
Si l’on trace ensuite les appels aux méthodes des packages javax.crypto, on observe un appel à un constructeur de PBEKeySpec, auquel est passé en argument :
- le code PIN,
- un sel de 256 octets,
- un nombre d’itérations (égal à 10000),
- la taille de la clé à produire (256 bits)
frida-trace -U -f com.google.android.apps.nbu.files -j 'javax.crypto*!*'
/* TID 0x426 */
7445 ms SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1")
7445 ms | SecretKeyFactory.$init("PBKDF2WithHmacSHA1")
7446 ms | | SecretKeyFactory.nextSpi(null)
7447 ms | | | SecretKeyFactorySpi.$init()
7447 ms | | <= "<instance: javax.crypto.SecretKeyFactorySpi, $className: com.android.org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF2$PBKDF2WithHmacSHA1UTF8>"
7449 ms <= "<instance: javax.crypto.SecretKeyFactory>"
7449 ms PBEKeySpec.$init(["2","7","1","8"], [-68,-49,-9,88,51,-48,-44,73,98,-117,-76,-14,-40,16,-8,-43,-80,-100,-115,41,78,69,-104,0,-30,-13,106,-113,-124,-9,21,1,-67,3,-84,-106,1,15,-49,-44,63,103,-8,-82,-81,-53,80,53,89,-27,-19,28,91,-46,-30,-109,-89,11,-92,-99,5,-52,-44,-102,37,-123,25,6,-73,-126,-32,-12,24,-44,4,-119,99,35,56,15,124,-70,-46,-90,68,-102,-32,105,24,-127,-59,20,104,7,-92,-69,93,104,-30,90,-42,-14,-7,121,114,75,-110,-102,25,-80,-92,71,119,-46,97,-20,-55,102,-87,86,-65,-1,-37,-74,-86,29,96,45,-32,44,86,71,-52,-26,-80,-128,77,7,-70,17,-76,-21,76,24,-84,33,-93,-116,-108,-38,-89,84,114,-68,-101,-79,-74,-94,98,-98,-30,-45,-73,-54,-25,37,-37,-103,-24,86,120,-88,-99,106,95,23,-124,77,-58,-122,-40,36,-32,-100,101,34,-72,96,73,-22,4,104,89,-54,14,-64,81,-60,-125,-98,0,110,18,-107,86,41,-56,119,56,-110,58,122,-43,-46,5,-122,-54,56,48,11,117,-55,48,14,-121,70,8,-60,56,-54,-68,6,89,-100,-14,-77,59,-54,-8,51,-10,119,-9,-52,-86,37,-12,91,76,7,97,39,-79,25,99,1], 10000, 256)
7451 ms SecretKeyFactory.generateSecret("<instance: java.security.spec.KeySpec, $className: javax.crypto.spec.PBEKeySpec>")
7451 ms | PBEKeySpec.getSalt()
7451 ms | <= [-68,-49,-9,88,51,-48,-44,73,98,-117,-76,-14,-40,16,-8,-43,-80,-100,-115,41,78,69,-104,0,-30,-13,106,-113,-124,-9,21,1,-67,3,-84,-106,1,15,-49,-44,63,103,-8,-82,-81,-53,80,53,89,-27,-19,28,91,-46,-30,-109,-89,11,-92,-99,5,-52,-44,-102,37,-123,25,6,-73,-126,-32,-12,24,-44,4,-119,99,35,56,15,124,-70,-46,-90,68,-102,-32,105,24,-127,-59,20,104,7,-92,-69,93,104,-30,90,-42,-14,-7,121,114,75,-110,-102,25,-80,-92,71,119,-46,97,-20,-55,102,-87,86,-65,-1,-37,-74,-86,29,96,45,-32,44,86,71,-52,-26,-80,-128,77,7,-70,17,-76,-21,76,24,-84,33,-93,-116,-108,-38,-89,84,114,-68,-101,-79,-74,-94,98,-98,-30,-45,-73,-54,-25,37,-37,-103,-24,86,120,-88,-99,106,95,23,-124,77,-58,-122,-40,36,-32,-100,101,34,-72,96,73,-22,4,104,89,-54,14,-64,81,-60,-125,-98,0,110,18,-107,86,41,-56,119,56,-110,58,122,-43,-46,5,-122,-54,56,48,11,117,-55,48,14,-121,70,8,-60,56,-54,-68,6,89,-100,-14,-77,59,-54,-8,51,-10,119,-9,-52,-86,37,-12,91,76,7,97,39,-79,25,99,1]
7452 ms | PBEKeySpec.getSalt()
7452 ms | <= [-68,-49,-9,88,51,-48,-44,73,98,-117,-76,-14,-40,16,-8,-43,-80,-100,-115,41,78,69,-104,0,-30,-13,106,-113,-124,-9,21,1,-67,3,-84,-106,1,15,-49,-44,63,103,-8,-82,-81,-53,80,53,89,-27,-19,28,91,-46,-30,-109,-89,11,-92,-99,5,-52,-44,-102,37,-123,25,6,-73,-126,-32,-12,24,-44,4,-119,99,35,56,15,124,-70,-46,-90,68,-102,-32,105,24,-127,-59,20,104,7,-92,-69,93,104,-30,90,-42,-14,-7,121,114,75,-110,-102,25,-80,-92,71,119,-46,97,-20,-55,102,-87,86,-65,-1,-37,-74,-86,29,96,45,-32,44,86,71,-52,-26,-80,-128,77,7,-70,17,-76,-21,76,24,-84,33,-93,-116,-108,-38,-89,84,114,-68,-101,-79,-74,-94,98,-98,-30,-45,-73,-54,-25,37,-37,-103,-24,86,120,-88,-99,106,95,23,-124,77,-58,-122,-40,36,-32,-100,101,34,-72,96,73,-22,4,104,89,-54,14,-64,81,-60,-125,-98,0,110,18,-107,86,41,-56,119,56,-110,58,122,-43,-46,5,-122,-54,56,48,11,117,-55,48,14,-121,70,8,-60,56,-54,-68,6,89,-100,-14,-77,59,-54,-8,51,-10,119,-9,-52,-86,37,-12,91,76,7,97,39,-79,25,99,1]
7452 ms | PBEKeySpec.getIterationCount()
7453 ms | <= 10000
7453 ms | PBEKeySpec.getKeyLength()
7453 ms | <= 256
7453 ms | PBEKeySpec.getPassword()
7453 ms | <= ["2","7","1","8"]
7453 ms | PBEKeySpec.getKeyLength()
7453 ms | <= 256
7453 ms | PBEKeySpec.getPassword()
7454 ms | <= ["2","7","1","8"]
7454 ms | PBEKeySpec.getSalt()
7454 ms | <= [-68,-49,-9,88,51,-48,-44,73,98,-117,-76,-14,-40,16,-8,-43,-80,-100,-115,41,78,69,-104,0,-30,-13,106,-113,-124,-9,21,1,-67,3,-84,-106,1,15,-49,-44,63,103,-8,-82,-81,-53,80,53,89,-27,-19,28,91,-46,-30,-109,-89,11,-92,-99,5,-52,-44,-102,37,-123,25,6,-73,-126,-32,-12,24,-44,4,-119,99,35,56,15,124,-70,-46,-90,68,-102,-32,105,24,-127,-59,20,104,7,-92,-69,93,104,-30,90,-42,-14,-7,121,114,75,-110,-102,25,-80,-92,71,119,-46,97,-20,-55,102,-87,86,-65,-1,-37,-74,-86,29,96,45,-32,44,86,71,-52,-26,-80,-128,77,7,-70,17,-76,-21,76,24,-84,33,-93,-116,-108,-38,-89,84,114,-68,-101,-79,-74,-94,98,-98,-30,-45,-73,-54,-25,37,-37,-103,-24,86,120,-88,-99,106,95,23,-124,77,-58,-122,-40,36,-32,-100,101,34,-72,96,73,-22,4,104,89,-54,14,-64,81,-60,-125,-98,0,110,18,-107,86,41,-56,119,56,-110,58,122,-43,-46,5,-122,-54,56,48,11,117,-55,48,14,-121,70,8,-60,56,-54,-68,6,89,-100,-14,-77,59,-54,-8,51,-10,119,-9,-52,-86,37,-12,91,76,7,97,39,-79,25,99,1]
7454 ms | PBEKeySpec.getIterationCount()
7455 ms | <= 10000
8056 ms | PBEKeySpec.getPassword()
8056 ms | <= ["2","7","1","8"]
8056 ms | PBEKeySpec.getIterationCount()
8056 ms | <= 10000
8056 ms | PBEKeySpec.getSalt()
8056 ms | <= [-68,-49,-9,88,51,-48,-44,73,98,-117,-76,-14,-40,16,-8,-43,-80,-100,-115,41,78,69,-104,0,-30,-13,106,-113,-124,-9,21,1,-67,3,-84,-106,1,15,-49,-44,63,103,-8,-82,-81,-53,80,53,89,-27,-19,28,91,-46,-30,-109,-89,11,-92,-99,5,-52,-44,-102,37,-123,25,6,-73,-126,-32,-12,24,-44,4,-119,99,35,56,15,124,-70,-46,-90,68,-102,-32,105,24,-127,-59,20,104,7,-92,-69,93,104,-30,90,-42,-14,-7,121,114,75,-110,-102,25,-80,-92,71,119,-46,97,-20,-55,102,-87,86,-65,-1,-37,-74,-86,29,96,45,-32,44,86,71,-52,-26,-80,-128,77,7,-70,17,-76,-21,76,24,-84,33,-93,-116,-108,-38,-89,84,114,-68,-101,-79,-74,-94,98,-98,-30,-45,-73,-54,-25,37,-37,-103,-24,86,120,-88,-99,106,95,23,-124,77,-58,-122,-40,36,-32,-100,101,34,-72,96,73,-22,4,104,89,-54,14,-64,81,-60,-125,-98,0,110,18,-107,86,41,-56,119,56,-110,58,122,-43,-46,5,-122,-54,56,48,11,117,-55,48,14,-121,70,8,-60,56,-54,-68,6,89,-100,-14,-77,59,-54,-8,51,-10,119,-9,-52,-86,37,-12,91,76,7,97,39,-79,25,99,1]
8057 ms <= "<instance: javax.crypto.SecretKey, $className: com.android.org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey>
En examinant les appelants de ce constructeur, on s’intéresse à la classe koe de l’application, en particulier à sa méthode d :
@Override // defpackage.kno
public final byte[] d(String str, byte[] bArr) {
qva.cg();
return SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1").generateSecret(new PBEKeySpec(str.toCharArray(), bArr, 10000, 256)).getEncoded();
}
La méthode koe.d est appelée par hzk.a et jwn.a. En pratique, dans notre cas elle est toujours appelée par jwn.a.
Hookons les fonctions koe.d avec frida :
[Pixel 7a::com.google.android.apps.nbu.files ]-> koe.d, args:
pin: 2718
array:
bc cf f7 58 33 d0 d4 49 62 8b b4 f2 d8 10 f8 d5 b0 9c 8d 29 4e 45 98 00 e2 f3 6a 8f 84 f7 15 01
bd 03 ac 96 01 0f cf d4 3f 67 f8 ae af cb 50 35 59 e5 ed 1c 5b d2 e2 93 a7 0b a4 9d 05 cc d4 9a
25 85 19 06 b7 82 e0 f4 18 d4 04 89 63 23 38 0f 7c ba d2 a6 44 9a e0 69 18 81 c5 14 68 07 a4 bb
5d 68 e2 5a d6 f2 f9 79 72 4b 92 9a 19 b0 a4 47 77 d2 61 ec c9 66 a9 56 bf ff db b6 aa 1d 60 2d
e0 2c 56 47 cc e6 b0 80 4d 07 ba 11 b4 eb 4c 18 ac 21 a3 8c 94 da a7 54 72 bc 9b b1 b6 a2 62 9e
e2 d3 b7 ca e7 25 db 99 e8 56 78 a8 9d 6a 5f 17 84 4d c6 86 d8 24 e0 9c 65 22 b8 60 49 ea 04 68
59 ca 0e c0 51 c4 83 9e 00 6e 12 95 56 29 c8 77 38 92 3a 7a d5 d2 05 86 ca 38 30 0b 75 c9 30 0e
87 46 08 c4 38 ca bc 06 59 9c f2 b3 3b ca f8 33 f6 77 f7 cc aa 25 f4 5b 4c 07 61 27 b1 19 63 01
koe.d, result:
85 cc bc e2 a4 96 eb 7c 1e c6 35 3b 18 c5 63 8e 22 ef f8 4f 67 03 f3 1c 0d f7 63 1e 6d b6 23 f3
Le premier argument de koe.d est le code PIN, le deuxième argument est un sel de 256 octets.
En retrouve ce sel dans le fichier SafeFolderAuthStore.pb stocké dans
/data/data/com.google.android.apps.nbu.files/files/ :
lynx:/data/data/com.google.android.apps.nbu.files/files # xxd SafeFolderAuthStore.pb
00000000: 0aa5 0212 8002 bccf f758 33d0 d449 628b .........X3..Ib.
00000010: b4f2 d810 f8d5 b09c 8d29 4e45 9800 e2f3 .........)NE....
00000020: 6a8f 84f7 1501 bd03 ac96 010f cfd4 3f67 j.............?g
00000030: f8ae afcb 5035 59e5 ed1c 5bd2 e293 a70b ....P5Y...[.....
00000040: a49d 05cc d49a 2585 1906 b782 e0f4 18d4 ......%.........
00000050: 0489 6323 380f 7cba d2a6 449a e069 1881 ..c#8.|...D..i..
00000060: c514 6807 a4bb 5d68 e25a d6f2 f979 724b ..h...]h.Z...yrK
00000070: 929a 19b0 a447 77d2 61ec c966 a956 bfff .....Gw.a..f.V..
00000080: dbb6 aa1d 602d e02c 5647 cce6 b080 4d07 ....`-.,VG....M.
00000090: ba11 b4eb 4c18 ac21 a38c 94da a754 72bc ....L..!.....Tr.
000000a0: 9bb1 b6a2 629e e2d3 b7ca e725 db99 e856 ....b......%...V
000000b0: 78a8 9d6a 5f17 844d c686 d824 e09c 6522 x..j_..M...$..e"
000000c0: b860 49ea 0468 59ca 0ec0 51c4 839e 006e .`I..hY...Q....n
000000d0: 1295 5629 c877 3892 3a7a d5d2 0586 ca38 ..V).w8.:z.....8
000000e0: 300b 75c9 300e 8746 08c4 38ca bc06 599c 0.u.0..F..8...Y.
000000f0: f2b3 3bca f833 f677 f7cc aa25 f45b 4c07 ..;..3.w...%.[L.
00000100: 6127 b119 6301 1a20 85cc bce2 a496 eb7c a'..c.. .......|
00000110: 1ec6 353b 18c5 638e 22ef f84f 6703 f31c ..5;..c."..Og...
00000120: 0df7 631e 6db6 23f3 220b 0880 9094 d706 ..c.m.#.".......
00000130: 1080 9c9c 3928 01 ....9(.
Quant à la valeur de retour de koe.d, c’est un tableau de 32 octets :
koe.d, result:
85 cc bc e2 a4 96 eb 7c 1e c6 35 3b 18 c5 63 8e 22 ef f8 4f 67 03 f3 1c 0d f7 63 1e 6d b6 23 f3
Cette valeur apparaît aussi à la fin de SafeFolderAuthStore.pb !
Dans la méthode jwn.a, ce tableau (d dans le code décompilé par jadx) est comparé avec un autre (stocké dans la variable a) :
Dans jwn.a, la valeur retournée par koe.d (lcgVar.b.d((String) this.b, vipVar2.y()) ici) est comparée avec une valeur de référence :
byte[] d = lcgVar.b.d((String) this.b, vipVar2.y());
if (a.length == d.length) {
int i13 = 0;
char c4 = 0;
while (i13 < a.length) {
?? r10 = c4 | ((a[i13] ^ d[i13]) == true ? 1 : 0);
i13++;
c4 = r10;
}
if (c4 == 0) {
z2 = true;
plzVar.c(a6, new pfb("FilesSafeFolder_verifySecret"));
En conclusion, le déverrouillage du dossier sécurisé demande à l’utilisateur d’entrer un code PIN. Ce code PIN est utilisé avec un sel de 256 octets stocké dans le fichier SafeFolderAuthStore.pb.
pour dériver une clé de 32 octets.
Cette valeur est comparée à la valeur de référence, présente elle aussi dans
le fichier SafeFolderAuthStore.pb.
Aucune opération de déchiffrement des fichiers stockés dans le dossier sécurisé n’est effectuée.
Notons enfin que le nom des classes et méthodes varient d’une version à l’autre de Files by Google : Dans une version antérieure (la dernière version testée étant la 2061783), la classe koe était nommée kmv.
Un mécanisme d’obfuscation semble donc être mis en oeuvre lors de la compilation de l’apk.