anais-apk-forensic 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.
- package/LICENSE +21 -0
- package/README.md +249 -0
- package/anais.sh +669 -0
- package/analysis_tools/__pycache__/apk_basic_info.cpython-313.pyc +0 -0
- package/analysis_tools/__pycache__/apk_basic_info.cpython-314.pyc +0 -0
- package/analysis_tools/__pycache__/check_zip_encryption.cpython-313.pyc +0 -0
- package/analysis_tools/__pycache__/check_zip_encryption.cpython-314.pyc +0 -0
- package/analysis_tools/__pycache__/detect_obfuscation.cpython-313.pyc +0 -0
- package/analysis_tools/__pycache__/detect_obfuscation.cpython-314.pyc +0 -0
- package/analysis_tools/__pycache__/dex_payload_hunter.cpython-314.pyc +0 -0
- package/analysis_tools/__pycache__/entropy_analyzer.cpython-314.pyc +0 -0
- package/analysis_tools/__pycache__/error_logger.cpython-313.pyc +0 -0
- package/analysis_tools/__pycache__/error_logger.cpython-314.pyc +0 -0
- package/analysis_tools/__pycache__/find_encrypted_payload.cpython-314.pyc +0 -0
- package/analysis_tools/__pycache__/fix_apk_headers.cpython-313.pyc +0 -0
- package/analysis_tools/__pycache__/fix_apk_headers.cpython-314.pyc +0 -0
- package/analysis_tools/__pycache__/manifest_analyzer.cpython-313.pyc +0 -0
- package/analysis_tools/__pycache__/manifest_analyzer.cpython-314.pyc +0 -0
- package/analysis_tools/__pycache__/network_analyzer.cpython-313.pyc +0 -0
- package/analysis_tools/__pycache__/network_analyzer.cpython-314.pyc +0 -0
- package/analysis_tools/__pycache__/report_generator.cpython-313.pyc +0 -0
- package/analysis_tools/__pycache__/report_generator.cpython-314.pyc +0 -0
- package/analysis_tools/__pycache__/report_generator_modular.cpython-314.pyc +0 -0
- package/analysis_tools/__pycache__/sast_scanner.cpython-313.pyc +0 -0
- package/analysis_tools/__pycache__/sast_scanner.cpython-314.pyc +0 -0
- package/analysis_tools/__pycache__/so_string_analyzer.cpython-314.pyc +0 -0
- package/analysis_tools/__pycache__/yara_enhanced_analyzer.cpython-314.pyc +0 -0
- package/analysis_tools/__pycache__/yara_results_processor.cpython-314.pyc +0 -0
- package/analysis_tools/apk_basic_info.py +85 -0
- package/analysis_tools/check_zip_encryption.py +142 -0
- package/analysis_tools/detect_obfuscation.py +650 -0
- package/analysis_tools/dex_payload_hunter.py +734 -0
- package/analysis_tools/entropy_analyzer.py +335 -0
- package/analysis_tools/error_logger.py +75 -0
- package/analysis_tools/find_encrypted_payload.py +485 -0
- package/analysis_tools/fix_apk_headers.py +154 -0
- package/analysis_tools/manifest_analyzer.py +214 -0
- package/analysis_tools/network_analyzer.py +287 -0
- package/analysis_tools/report_generator.py +506 -0
- package/analysis_tools/report_generator_modular.py +885 -0
- package/analysis_tools/sast_scanner.py +412 -0
- package/analysis_tools/so_string_analyzer.py +406 -0
- package/analysis_tools/yara_enhanced_analyzer.py +330 -0
- package/analysis_tools/yara_results_processor.py +368 -0
- package/analyzer_config.json +113 -0
- package/apkid/__init__.py +32 -0
- package/apkid/__pycache__/__init__.cpython-313.pyc +0 -0
- package/apkid/__pycache__/__init__.cpython-314.pyc +0 -0
- package/apkid/__pycache__/apkid.cpython-313.pyc +0 -0
- package/apkid/__pycache__/apkid.cpython-314.pyc +0 -0
- package/apkid/__pycache__/main.cpython-313.pyc +0 -0
- package/apkid/__pycache__/main.cpython-314.pyc +0 -0
- package/apkid/__pycache__/output.cpython-313.pyc +0 -0
- package/apkid/__pycache__/rules.cpython-313.pyc +0 -0
- package/apkid/apkid.py +266 -0
- package/apkid/main.py +98 -0
- package/apkid/output.py +177 -0
- package/apkid/rules/apk/common.yara +68 -0
- package/apkid/rules/apk/obfuscators.yara +118 -0
- package/apkid/rules/apk/packers.yara +1197 -0
- package/apkid/rules/apk/protectors.yara +301 -0
- package/apkid/rules/dex/abnormal.yara +104 -0
- package/apkid/rules/dex/anti-vm.yara +568 -0
- package/apkid/rules/dex/common.yara +60 -0
- package/apkid/rules/dex/compilers.yara +434 -0
- package/apkid/rules/dex/obfuscators.yara +602 -0
- package/apkid/rules/dex/packers.yara +761 -0
- package/apkid/rules/dex/protectors.yara +520 -0
- package/apkid/rules/dll/common.yara +38 -0
- package/apkid/rules/dll/obfuscators.yara +43 -0
- package/apkid/rules/elf/anti-vm.yara +43 -0
- package/apkid/rules/elf/common.yara +54 -0
- package/apkid/rules/elf/obfuscators.yara +991 -0
- package/apkid/rules/elf/packers.yara +1128 -0
- package/apkid/rules/elf/protectors.yara +794 -0
- package/apkid/rules/res/common.yara +43 -0
- package/apkid/rules/res/obfuscators.yara +46 -0
- package/apkid/rules/res/protectors.yara +46 -0
- package/apkid/rules.py +77 -0
- package/bin/anais +3 -0
- package/dist/cli.js +82 -0
- package/dist/index.js +123 -0
- package/dist/types/index.js +2 -0
- package/dist/utils/index.js +21 -0
- package/dist/utils/output.js +44 -0
- package/dist/utils/paths.js +107 -0
- package/docs/ARCHITECTURE.txt +353 -0
- package/docs/Workflow and Reference.md +445 -0
- package/package.json +70 -0
- package/rules/yara_general_rules.yar +323 -0
- package/scripts/dynamic_analysis_helper.sh +334 -0
- package/scripts/frida/dpt_dex_dumper.js +145 -0
- package/scripts/frida/frida_dex_dump.js +145 -0
- package/scripts/frida/frida_hooks.js +437 -0
- package/scripts/frida/frida_websocket_extractor.js +154 -0
- package/scripts/setup.sh +206 -0
- package/scripts/validate_framework.sh +224 -0
- package/src/cli.ts +91 -0
- package/src/index.ts +123 -0
- package/src/types/index.ts +44 -0
- package/src/utils/index.ts +6 -0
- package/src/utils/output.ts +50 -0
- package/src/utils/paths.ts +72 -0
- package/tsconfig.json +14 -0
|
@@ -0,0 +1,602 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2023 RedNaga. https://rednaga.io
|
|
3
|
+
* All rights reserved. Contact: rednaga@protonmail.com
|
|
4
|
+
*
|
|
5
|
+
*
|
|
6
|
+
* This file is part of APKiD
|
|
7
|
+
*
|
|
8
|
+
*
|
|
9
|
+
* Commercial License Usage
|
|
10
|
+
* ------------------------
|
|
11
|
+
* Licensees holding valid commercial APKiD licenses may use this file
|
|
12
|
+
* in accordance with the commercial license agreement provided with the
|
|
13
|
+
* Software or, alternatively, in accordance with the terms contained in
|
|
14
|
+
* a written agreement between you and RedNaga.
|
|
15
|
+
*
|
|
16
|
+
*
|
|
17
|
+
* GNU General Public License Usage
|
|
18
|
+
* --------------------------------
|
|
19
|
+
* Alternatively, this file may be used under the terms of the GNU General
|
|
20
|
+
* Public License version 3.0 as published by the Free Software Foundation
|
|
21
|
+
* and appearing in the file LICENSE.GPL included in the packaging of this
|
|
22
|
+
* file. Please visit http://www.gnu.org/copyleft/gpl.html and review the
|
|
23
|
+
* information to ensure the GNU General Public License version 3.0
|
|
24
|
+
* requirements will be met.
|
|
25
|
+
*
|
|
26
|
+
**/
|
|
27
|
+
|
|
28
|
+
import "dex"
|
|
29
|
+
include "common.yara"
|
|
30
|
+
|
|
31
|
+
private rule short_unicode_field_names : internal
|
|
32
|
+
{
|
|
33
|
+
meta:
|
|
34
|
+
description = "one or two character unicode field names"
|
|
35
|
+
|
|
36
|
+
condition:
|
|
37
|
+
is_dex and
|
|
38
|
+
for 3 i in (0..dex.header.field_ids_size) : (dex.field[i].name matches /[^\x00-\x7F]{1,4}/)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
private rule short_unicode_method_names : internal
|
|
42
|
+
{
|
|
43
|
+
meta:
|
|
44
|
+
description = "one or two character unicode method names"
|
|
45
|
+
|
|
46
|
+
condition:
|
|
47
|
+
is_dex and
|
|
48
|
+
for 3 i in (0..dex.header.method_ids_size) : (dex.method[i].name matches /[^\x00-\x7F]{1,4}/)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
rule dexguard_a : obfuscator
|
|
52
|
+
{
|
|
53
|
+
meta:
|
|
54
|
+
description = "DexGuard"
|
|
55
|
+
url = "https://www.guardsquare.com/en/products/dexguard"
|
|
56
|
+
sample = "74eb7cf3b81ff14add71ca884ef0cc9c7477b4193a74ca71b92f81212ff56101"
|
|
57
|
+
|
|
58
|
+
strings:
|
|
59
|
+
$opcodes = {
|
|
60
|
+
00 06 00 01 00 03 00 00 00 00 00 00 00
|
|
61
|
+
[20-65]
|
|
62
|
+
0c 01
|
|
63
|
+
12 12
|
|
64
|
+
23 22 ?? ??
|
|
65
|
+
1c 03 ?? ??
|
|
66
|
+
12 04
|
|
67
|
+
4d 03 02 04
|
|
68
|
+
6e 3? ?? ?? 10 02
|
|
69
|
+
0c 00
|
|
70
|
+
62 01 ?? ??
|
|
71
|
+
12 12
|
|
72
|
+
23 22 ?? ??
|
|
73
|
+
12 03
|
|
74
|
+
4d 05 02 03
|
|
75
|
+
6e 3? ?? ?? 10 02
|
|
76
|
+
0c 00
|
|
77
|
+
1f 00 ?? ??
|
|
78
|
+
11 00
|
|
79
|
+
}
|
|
80
|
+
$a = "getClass"
|
|
81
|
+
$b = "getDeclaredMethod"
|
|
82
|
+
$c = "invoke"
|
|
83
|
+
|
|
84
|
+
condition:
|
|
85
|
+
is_dex and
|
|
86
|
+
$opcodes and
|
|
87
|
+
all of ($a, $b, $c) and
|
|
88
|
+
uint32(dex.header.data_offset + dex.header.data_size - 4) == 0
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
rule dexguard_b : obfuscator
|
|
92
|
+
{
|
|
93
|
+
meta:
|
|
94
|
+
description = "DexGuard"
|
|
95
|
+
url = "https://www.guardsquare.com/en/products/dexguard"
|
|
96
|
+
sample = "41a9b44af8931d63812b4a23395b29279d2e055f357222dabed7153d4aee6299"
|
|
97
|
+
|
|
98
|
+
strings:
|
|
99
|
+
// Other obfuscators use aux and con (protected Windows file names), but not from Lo/
|
|
100
|
+
$a_aux_class = { 00 07 4C 6F 2F (41|61) (55|75) (58|78) 3B 00 } // Lo/[Aa][Uu][Xx];
|
|
101
|
+
$a_con_class = { 00 07 4C 6F 2F (43|63) (4F|6F) (4E|6E) 3B 00 } // Lo/[Cc][Oo][Nn];
|
|
102
|
+
$a_if_class = { 00 ?? 4C 6F 2F [1-4] 24 (49|69) (46|66) 3B 00 } // Lo/???$[iI][fF];
|
|
103
|
+
// A single unicode code point may take 1 or more bytes depending on encoding.
|
|
104
|
+
// Normally only see one code point worth, but not sure how many bytes it might be in some variants.
|
|
105
|
+
// Also note the trailing null byte in the regex so this is less of a naked string.
|
|
106
|
+
$a_inner_unicode = /Lo\/([\u0000-\u007F]{1,4}|[^\u0000-\u007F]{1,4})\$[^\u0000-\u007F]{1,4};\x00/
|
|
107
|
+
$b_o_three_class = { 00 07 4C 6F 2F ?? ?? ?? 3B 00 } // Lo/???;
|
|
108
|
+
|
|
109
|
+
condition:
|
|
110
|
+
2 of ($a_*)
|
|
111
|
+
or (#a_if_class >= 3 and (short_unicode_field_names or short_unicode_method_names))
|
|
112
|
+
or (#b_o_three_class >= 3 and (short_unicode_field_names or short_unicode_method_names))
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
rule dexguard_c : obfuscator
|
|
116
|
+
{
|
|
117
|
+
meta:
|
|
118
|
+
description = "DexGuard"
|
|
119
|
+
url = "https://www.guardsquare.com/en/products/dexguard"
|
|
120
|
+
sample = "de67161a8bd7ebcaa26c9661efd811375b59260924eb0dfd9436d3a47a1c31fe"
|
|
121
|
+
sample2 = "db11762886cc24bd4f938002f15f78680b512cf550d15c77b217fc5548b0c939"
|
|
122
|
+
|
|
123
|
+
strings:
|
|
124
|
+
$dexguard_pkg1 = "guardsquare/dexguard/runtime/"
|
|
125
|
+
$dexguard_pkg2 = {
|
|
126
|
+
001e4c64657867756172642f7574696c2f54616d7065724465746563746f723b00
|
|
127
|
+
} // Ldexguard/util/TamperDetector;
|
|
128
|
+
$dexguard_pkg3 = {
|
|
129
|
+
00224c64657867756172642f7574696c2f4365727469666963617465436865636b65723b00
|
|
130
|
+
} // Ldexguard/util/CertificateChecker;
|
|
131
|
+
$dexguard_pkg4 = "com/guardsquare/dexguard/"
|
|
132
|
+
|
|
133
|
+
// Most of some kind of runtime decryption method, signature = a(IIZI[I[[I[I)V
|
|
134
|
+
$decrypt_method = {
|
|
135
|
+
12 01 // const/4 v1, 0x0
|
|
136
|
+
39 ?? ?? ?? // if-nez ??, :????
|
|
137
|
+
71 ?? ?? ?? ?? ?? // invoke-static {??}, ??
|
|
138
|
+
01 10 // move v0, v1
|
|
139
|
+
35 ?? ?? ?? // if-ge ?, ?, :????
|
|
140
|
+
44 ?? ?? ?? // aget ??, ??, ??
|
|
141
|
+
B7 ?? // xor-int/2addr (xor is fairly rare in legit code)
|
|
142
|
+
71 ?? ?? ?? ?? ?? // invoke-static
|
|
143
|
+
0A ?? // move-result ??
|
|
144
|
+
97 ?? ?? ?? // xor-int ??, ??, ??
|
|
145
|
+
D8 00 00 01 // add-int/lit8 v0, v0, 0x1
|
|
146
|
+
01 ?? // move ?, ?
|
|
147
|
+
28 F2 // goto
|
|
148
|
+
21 80 // array-length
|
|
149
|
+
D8 00 00 FE // add-int/lit8 v0, v0, -0x2
|
|
150
|
+
44 ?? ?? ?? // aget ??
|
|
151
|
+
B7 ?? // xor-int/2addr
|
|
152
|
+
21 ?? // invoke-static
|
|
153
|
+
D8 ?? ?? ?? // add-int
|
|
154
|
+
44 ?? ?? ?? // aget
|
|
155
|
+
B7 ?? // xor-int/2addr
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
condition:
|
|
159
|
+
is_dex
|
|
160
|
+
and any of them
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
rule dexguard_d : obfuscator
|
|
164
|
+
{
|
|
165
|
+
meta:
|
|
166
|
+
description = "DexGuard"
|
|
167
|
+
url = "https://www.guardsquare.com/en/products/dexguard"
|
|
168
|
+
sample = "423b09d2aec74b1624d5b5c63d24486efc873c9cce75ea9e2f2d699f40ca8f7c"
|
|
169
|
+
|
|
170
|
+
strings:
|
|
171
|
+
// Ldexguard/util/TamperDetection;
|
|
172
|
+
$dexguard_class = {00 1F 4C 64 65 78 67 75 61 72 64 2F 75 74 69 6C 2F 54 61 6D 70 65 72 44 65 74 65 63 74 69 6F 6E 3B 00}
|
|
173
|
+
$a_aux_class = { 00 05 4C (41|61) (55|75) (58|78) 3B 00 } // L[Aa][Uu][Xx];
|
|
174
|
+
$a_con_class = { 00 05 4C (43|63) (4F|6F) (4E|6E) 3B 00 } // L[Cc][Oo][Nn];
|
|
175
|
+
$a_if_class = { 00 ?? 4C [1-4] 24 (49|69) (46|66) 3B 00 } // L???$[iI][fF];
|
|
176
|
+
$a_inner_unicode = /L([\u0000-\u007F]{1,4}|[^\u0000-\u007F]{1,4})\$[^\u0000-\u007F]{1,4};\x00/
|
|
177
|
+
|
|
178
|
+
condition:
|
|
179
|
+
3 of them
|
|
180
|
+
or $dexguard_class
|
|
181
|
+
or (#a_if_class >= 3 and (short_unicode_field_names or short_unicode_method_names))
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
rule dexprotector : obfuscator
|
|
185
|
+
{
|
|
186
|
+
meta:
|
|
187
|
+
description = "DexProtector"
|
|
188
|
+
|
|
189
|
+
strings:
|
|
190
|
+
$method = {
|
|
191
|
+
07 00 02 00 00 00 02 00 00 00 00 00 3E 00 00 00
|
|
192
|
+
12 01 13 00 0E 00 48 00 05 00 E0 00 00 10 01 12
|
|
193
|
+
39 02 2A 00 12 32 D5 63 FF 00 48 03 05 03 D5 33
|
|
194
|
+
FF 00 E1 04 06 08 D5 44 FF 00 48 04 05 04 D5 44
|
|
195
|
+
FF 00 E0 04 04 08 B6 43 E1 04 06 10 D5 44 FF 00
|
|
196
|
+
48 04 05 04 D5 44 FF 00 E0 04 04 10 B6 43 E1 04
|
|
197
|
+
06 18 D5 44 FF 00 48 00 05 04 E0 00 00 18 B6 30
|
|
198
|
+
0F 00 0D 02 39 01 FE FF 12 21 DD 02 06 7F 48 00
|
|
199
|
+
05 02 E1 00 00 08 28 F5 0D 03 28 CB 0D 00 00 00
|
|
200
|
+
20 00 ?? 00 37 00 00 00 02 00 ?? 00 02 01
|
|
201
|
+
}
|
|
202
|
+
$a = "getClass"
|
|
203
|
+
$b = "getDeclaredMethod"
|
|
204
|
+
$c = "invoke"
|
|
205
|
+
|
|
206
|
+
condition:
|
|
207
|
+
is_dex and
|
|
208
|
+
$method and
|
|
209
|
+
all of ($a, $b, $c)
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
rule bitwise_antiskid : obfuscator
|
|
213
|
+
{
|
|
214
|
+
meta:
|
|
215
|
+
description = "Bitwise AntiSkid"
|
|
216
|
+
|
|
217
|
+
strings:
|
|
218
|
+
$credits = "AntiSkid courtesy of Bitwise\x00"
|
|
219
|
+
$array = "AntiSkid_Encrypted_Strings_Courtesy_of_Bitwise"
|
|
220
|
+
$truth1 = "Don't be a script kiddy, go actually learn something. Stealing credit is pathetic, you didn't make this or even contribute to it and you know it."
|
|
221
|
+
$truth2 = "Only skids can't get plaintext. Credits to Bitwise.\x00"
|
|
222
|
+
|
|
223
|
+
condition:
|
|
224
|
+
is_dex and
|
|
225
|
+
any of them
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
rule arxan : obfuscator
|
|
229
|
+
{
|
|
230
|
+
meta:
|
|
231
|
+
description = "Arxan"
|
|
232
|
+
url = "https://www.arxan.com/products/application-protection-mobile/"
|
|
233
|
+
sample = "7bd1139b5f860d48e0c35a3f117f980564f45c177a6ef480588b5b5c8165f47e"
|
|
234
|
+
author = "Eduardo Novella"
|
|
235
|
+
|
|
236
|
+
strings:
|
|
237
|
+
// Obfuscated Lpackage/class/: "L([a-z]\1{5}\/[a-z]{6}\/".
|
|
238
|
+
// AFAIK, Yara does not support backreferences at the moment, thus this is the combo:
|
|
239
|
+
$pkg = /L(a{6}|b{6}|c{6}|d{6}|e{6}|f{6}|g{6}|h{6}|i{6}|j{6}|k{6}|l{6}|m{6}|n{6}|o{6}|p{6}|q{6}|r{6}|s{6}|t{6}|u{6}|v{6}|w{6}|x{6}|y{6}|z{6})\/[a-z]{6}/
|
|
240
|
+
|
|
241
|
+
// Obfuscated methods are found to follow a pattern like:
|
|
242
|
+
// 1 byte size + 1 byte ASCII + [7-26] non-ASCII bytes + 00 (null terminator)
|
|
243
|
+
$m1 = { 10 62 (6? | 75) [14] 00 }
|
|
244
|
+
$m2 = { (0b | 0d) 62 d0 [15] 00 }
|
|
245
|
+
$m3 = { (0e | 10) 62 30 34 3? [15] 00 }
|
|
246
|
+
$m4 = { (0b | 0d) 62 30 34 3? [13] 00 }
|
|
247
|
+
$m5 = { (08 | 0b | 0d | 0e ) 62 [7-13] 00 }
|
|
248
|
+
$m6 = { 0a 62 (30 34 3? | d? ?? ??) [11] 00 }
|
|
249
|
+
$m7 = { (0d | 0b | 11) (62 d1 8? | 6? ?? ??) [14] 00 }
|
|
250
|
+
|
|
251
|
+
condition:
|
|
252
|
+
is_dex and
|
|
253
|
+
$pkg and
|
|
254
|
+
6 of ($m*)
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
rule arxan_multidex : obfuscator
|
|
258
|
+
{
|
|
259
|
+
meta:
|
|
260
|
+
description = "Arxan (multidex)"
|
|
261
|
+
url = "https://www.arxan.com/products/application-protection-mobile/"
|
|
262
|
+
sample = "9b2a978a937293d6cb93439e0f819b4e044a3fad80dde92dec9b67e419278b5d"
|
|
263
|
+
author = "Eduardo Novella"
|
|
264
|
+
|
|
265
|
+
strings:
|
|
266
|
+
// Obfuscated Lpackage/class/: "L([a-z]\1{5}\/[a-z]{6}\/".
|
|
267
|
+
// AFAIK, Yara does not support backreferences at the moment, thus this is the combo:
|
|
268
|
+
$pkg = /L(a{6}|b{6}|c{6}|d{6}|e{6}|f{6}|g{6}|h{6}|i{6}|j{6}|k{6}|l{6}|m{6}|n{6}|o{6}|p{6}|q{6}|r{6}|s{6}|t{6}|u{6}|v{6}|w{6}|x{6}|y{6}|z{6})\/[a-z]{6}/
|
|
269
|
+
|
|
270
|
+
// Obfuscated methods are found to follow a pattern like:
|
|
271
|
+
// 1 byte size + 1 byte ASCII + [7-26] non-ASCII bytes + 00 (null terminator)
|
|
272
|
+
$m1 = { 10 62 (6? | 75) [14] 00 }
|
|
273
|
+
$m2 = { (0b | 0d) 62 d0 [15] 00 }
|
|
274
|
+
$m3 = { (0e | 10) 62 30 34 3? [15] 00 }
|
|
275
|
+
$m4 = { (0b | 0d) 62 30 34 3? [13] 00 }
|
|
276
|
+
$m5 = { (08 | 0b | 0d | 0e ) 62 [7-13] 00 }
|
|
277
|
+
$m6 = { 0a 62 (30 34 3? | d? ?? ??) [11] 00 }
|
|
278
|
+
$m7 = { (0d | 0b | 11) (62 d1 8? | 6? ?? ??) [14] 00 }
|
|
279
|
+
|
|
280
|
+
condition:
|
|
281
|
+
is_dex and
|
|
282
|
+
$pkg and
|
|
283
|
+
2 of ($m*) and
|
|
284
|
+
not arxan
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
rule arxan_b : obfuscator
|
|
288
|
+
{
|
|
289
|
+
meta:
|
|
290
|
+
description = "Arxan"
|
|
291
|
+
url = "https://github.com/rednaga/APKiD/issues/160"
|
|
292
|
+
sample = "86ade15e885cf7927e5840dd2bf2782905fcd6843be77f898b51b64c2277f3de"
|
|
293
|
+
author = "Tim 'diff' Strazzere"
|
|
294
|
+
|
|
295
|
+
strings:
|
|
296
|
+
// Targeting this seemingly static byte sequence used inside the injected obfuscation:
|
|
297
|
+
// move-result v0 (moving result from own deobfuscation, v2 and v3 are always consts)
|
|
298
|
+
$deobf = {
|
|
299
|
+
0A 0?
|
|
300
|
+
DF 01 03 FF
|
|
301
|
+
// and-int/2addr v1, v0
|
|
302
|
+
B5 01
|
|
303
|
+
// xor-int/lit8 v0, v0, -0x1
|
|
304
|
+
DF 00 00 FF
|
|
305
|
+
// and-int/2addr v0, v3
|
|
306
|
+
B5 30
|
|
307
|
+
// or-int/2addr v1, v0
|
|
308
|
+
B6 01
|
|
309
|
+
// int-to-short v7, v1
|
|
310
|
+
8F 1?
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
condition:
|
|
314
|
+
is_dex and
|
|
315
|
+
$deobf
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
rule arxan_c : obfuscator
|
|
319
|
+
{
|
|
320
|
+
meta:
|
|
321
|
+
description = "Arxan"
|
|
322
|
+
url = "https://digital.ai/products/application-security/"
|
|
323
|
+
sample = "7bd1139b5f860d48e0c35a3f117f980564f45c177a6ef480588b5b5c8165f47e"
|
|
324
|
+
author = "Abhi"
|
|
325
|
+
|
|
326
|
+
strings:
|
|
327
|
+
// Example: .9Lcom/arxan/guardit4j/util/PackageNameEnumeratorException;.
|
|
328
|
+
$pkg = { 00 ?? 4C 63 6F 6D 2F 61 72 78 61 6E 2F 67 75 61 72 64 69 74 } // .??Lcom/arxan/guardit
|
|
329
|
+
|
|
330
|
+
condition:
|
|
331
|
+
is_dex and
|
|
332
|
+
$pkg and
|
|
333
|
+
not (arxan or arxan_multidex or arxan_b)
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
rule allatori_demo : obfuscator
|
|
337
|
+
{
|
|
338
|
+
meta:
|
|
339
|
+
description = "Allatori demo"
|
|
340
|
+
url = "http://www.allatori.com/features.html"
|
|
341
|
+
author = "Eduardo Novella"
|
|
342
|
+
sample = "7f2f5aac9833f7bdccc0b9865f5cc2a9c94ee795a285ef2fa6ff83a34c91827f"
|
|
343
|
+
sample2 = "8c9e6c7b8c516499dd2065cb435ef68089feb3d4053faf2cfcb2b759b051383c"
|
|
344
|
+
|
|
345
|
+
strings:
|
|
346
|
+
// null-prev-str + len + str + null
|
|
347
|
+
$s = { 00 0D 41 4C 4C 41 54 4F 52 49 78 44 45 4D 4F 00 } // ALLATORIxDEMO
|
|
348
|
+
|
|
349
|
+
condition:
|
|
350
|
+
is_dex and $s
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
rule aamo_str_enc : obfuscator
|
|
354
|
+
{
|
|
355
|
+
meta:
|
|
356
|
+
description = "AAMO"
|
|
357
|
+
author = "P0r0"
|
|
358
|
+
url = "https://github.com/necst/aamo"
|
|
359
|
+
sample = "c1ef860af0e168f924663630ed3b61920b474d0c8b10e2bde6bfd3769dbd31a8"
|
|
360
|
+
sample2 = "eb0d4e1ba2e880749594eb8739e65aa21b6f7b43798f04b6681065b396c15a78"
|
|
361
|
+
|
|
362
|
+
strings:
|
|
363
|
+
$opcodes_nops = {
|
|
364
|
+
22 ?? ?? ?? //new-instance v? Ljava/lang/String;
|
|
365
|
+
( 00 00 | 00 00 00 00 | 00 00 00 00 00 00 )
|
|
366
|
+
12 ?2 //const/4 v2, 0x2 (the register and constant never change)
|
|
367
|
+
( 00 00 | 00 00 00 00 | 00 00 00 00 00 00 )
|
|
368
|
+
1a ?? ?? ?? //const-string v?, _ref_to_string_
|
|
369
|
+
( 00 00 | 00 00 00 00 | 00 00 00 00 00 00 )
|
|
370
|
+
71 ?? ?? ?? ?? ?? //invoke-static {v?, v?}, Landroid/content/res/_RANDOM_CLASS_NAME.getStorageEncryption(ILjava/lang/String;)Ljavax/crypto/Cipher;
|
|
371
|
+
0c 02 //move-result-object v2 (the register never changes)
|
|
372
|
+
( 00 00 | 00 00 00 00 | 00 00 00 00 00 00 )
|
|
373
|
+
71 ?? ?? ?? ?? ?? //invoke-static {v?, v?}, Landroid/content/res/_RANDOM_CLASS_NAME.decode(Ljava/lang/String;)[B
|
|
374
|
+
0c 03 //move-result-object v3
|
|
375
|
+
( 00 00 | 00 00 00 00 | 00 00 00 00 00 00 )
|
|
376
|
+
6e ?? ?? ?? ?? ?? //invoke-virtual {v?, v?}, Ljavax/crypto/Cipher.doFinal([B)[B
|
|
377
|
+
0c 02 //move-result-object v2
|
|
378
|
+
( 00 00 | 00 00 00 00 | 00 00 00 00 00 00 )
|
|
379
|
+
1a ?? ?? ?? //const-string v?, _CONST_STR_
|
|
380
|
+
( 00 00 | 00 00 00 00 | 00 00 00 00 00 00 )
|
|
381
|
+
70 ?? ?? ?? ?? ?? //invoke-direct {v?, v?, v?}, Ljava/lang/String.<init>([BLjava/lang/String;)
|
|
382
|
+
71 ?? ?? ?? ?? ?? //invoke-static {v?, v?}, Landroid/content/res/_RANDOM_CLASS_NAME._RANDOM_METHOD_NAME_(Ljava/lang/String;)Ljava/lang/String;
|
|
383
|
+
0c ?? //move-result-object v4
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
$opcodes = {
|
|
387
|
+
22 ?? ?? ?? //new-instance v? Ljava/lang/String;
|
|
388
|
+
12 ?2 //const/4 v2, 0x2 (the register and constant never change)
|
|
389
|
+
1a ?? ?? ?? //const-string v?, _ref_to_string_
|
|
390
|
+
71 ?? ?? ?? ?? ?? //invoke-static {v?, v?}, Landroid/content/res/_RANDOM_CLASS_NAME.getStorageEncryption(ILjava/lang/String;)Ljavax/crypto/Cipher;
|
|
391
|
+
0c 02 //move-result-object v2 (the register never changes)
|
|
392
|
+
71 ?? ?? ?? ?? ?? //invoke-static {v?, v?}, Landroid/content/res/_RANDOM_CLASS_NAME.decode(Ljava/lang/String;)[B
|
|
393
|
+
0c 03 //move-result-object v3
|
|
394
|
+
6e ?? ?? ?? ?? ?? //invoke-virtual {v?, v?}, Ljavax/crypto/Cipher.doFinal([B)[B
|
|
395
|
+
0c 02 //move-result-object v2
|
|
396
|
+
1a ?? ?? ?? //const-string v?, _CONST_STR_
|
|
397
|
+
70 ?? ?? ?? ?? ?? //invoke-direct {v?, v?, v?}, Ljava/lang/String.<init>([BLjava/lang/String;)
|
|
398
|
+
71 ?? ?? ?? ?? ?? //invoke-static {v?, v?}, Landroid/content/res/_RANDOM_CLASS_NAME._RANDOM_METHOD_NAME_(Ljava/lang/String;)Ljava/lang/String;
|
|
399
|
+
0c ?? //move-result-object v4
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
$a = { 00 0f 63 6f 6e 76 65 72 74 54 6f 53 74 72 69 6e 67 00 } // convertToString
|
|
403
|
+
$b = { 00 14 67 65 74 53 74 6f 72 61 67 65 45 6e 63 72 79 70 74 69 6f 6e 00 } //getStorageEncryption
|
|
404
|
+
|
|
405
|
+
condition:
|
|
406
|
+
is_dex and 1 of ($opcodes*) and all of ($a, $b)
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
rule appsuit_a : obfuscator
|
|
410
|
+
{
|
|
411
|
+
meta:
|
|
412
|
+
description = "AppSuit"
|
|
413
|
+
url = "http://www.stealien.com/appsuit.html"
|
|
414
|
+
sample = "b99bafbbd5288ac93647d22f1c5b1863c96f581ae7a19fdc0e84bff4c2141328"
|
|
415
|
+
author = "Eduardo Novella"
|
|
416
|
+
|
|
417
|
+
strings:
|
|
418
|
+
$a1 = { 00 0741707053756974 00 } // 00AppSuit00
|
|
419
|
+
$a2 = { 00 0741505053554954 00 } // 00APPSUIT00
|
|
420
|
+
$c1 = { 00 144c636f6d2f737465616c69656e2f636f6e73743b00 } // 00Lcom/stealien/const;00
|
|
421
|
+
$c3 = { 00 084c615f6c6f636b3b00 } // 00La_lock;00
|
|
422
|
+
$l1 = { 00 6c6962417070537569742e736f 00 } // 00libAppSuit.so00
|
|
423
|
+
$o = { 000c 6368 6563 6b41 7070 5375 6974 00 } // 00checkAppSuit00
|
|
424
|
+
$p1 = { 00 08737465616c69656e 00 } // 00stealien00
|
|
425
|
+
|
|
426
|
+
condition:
|
|
427
|
+
is_dex and 2 of them
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
rule appsuit_b : obfuscator
|
|
431
|
+
{
|
|
432
|
+
meta:
|
|
433
|
+
description = "AppSuit"
|
|
434
|
+
url = "http://www.stealien.com/appsuit.html"
|
|
435
|
+
sample = "6055deceb83233cceefc89b2bce4e978fd417820c5f534b0df66415122f394ea"
|
|
436
|
+
author = "Eduardo Novella"
|
|
437
|
+
|
|
438
|
+
strings:
|
|
439
|
+
$c = { 00?? 4c636f6d2f737465616c69656e2f61707073756974 2f } // 00??Lcom/stealien/appsuit/
|
|
440
|
+
|
|
441
|
+
condition:
|
|
442
|
+
is_dex and all of them
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
rule gemalto_sdk : obfuscator
|
|
446
|
+
{
|
|
447
|
+
meta:
|
|
448
|
+
description = "Gemalto"
|
|
449
|
+
url = "https://www.gemalto.com/brochures-site/download-site/Documents/eba_ezio_on_mobile.pdf"
|
|
450
|
+
author = "Eduardo Novella"
|
|
451
|
+
sample = "294f95298189080a25b20ef28295d60ecde27ee12361f93ad2f024fdcb5bdb0b"
|
|
452
|
+
|
|
453
|
+
strings:
|
|
454
|
+
$p1 = "Lcom/gemalto/idp/mobile/"
|
|
455
|
+
$p2 = "Lcom/gemalto/medl/"
|
|
456
|
+
$p3 = "Lcom/gemalto/ezio/mobile/sdk/"
|
|
457
|
+
|
|
458
|
+
condition:
|
|
459
|
+
is_dex and any of them
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
rule kiwi_amazon : obfuscator
|
|
463
|
+
{
|
|
464
|
+
meta:
|
|
465
|
+
description = "Kiwi encrypter"
|
|
466
|
+
sample = "3e309548f90160e3a4dc6f67621c75d2b66cc3b580da7306ff3dc6d6c25bb8a1"
|
|
467
|
+
author = "Eduardo Novella"
|
|
468
|
+
|
|
469
|
+
strings:
|
|
470
|
+
$key = { 00 19 4B6977695F5F56657273696F6E5F5F4F626675736361746F72 00 } // 00+len+"Kiwi__Version__Obfuscator"+00
|
|
471
|
+
$class = { 00 19 4B69776956657273696F6E456E637279707465722E6A617661 00 } // 00+len+"KiwiVersionEncrypter.java"+00
|
|
472
|
+
|
|
473
|
+
condition:
|
|
474
|
+
is_dex and all of them
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
rule unreadable_field_names : obfuscator
|
|
478
|
+
{
|
|
479
|
+
meta:
|
|
480
|
+
description = "unreadable field names"
|
|
481
|
+
sample = "afd6da00440ec83d54aefea742f26ba045505ac520f074512207a7bb50aaf9c4"
|
|
482
|
+
|
|
483
|
+
condition:
|
|
484
|
+
short_unicode_field_names
|
|
485
|
+
and (not dexguard_a and not dexguard_b and not dexguard_c and not dexguard_d)
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
rule unreadable_method_names : obfuscator
|
|
489
|
+
{
|
|
490
|
+
meta:
|
|
491
|
+
description = "unreadable method names"
|
|
492
|
+
sample = "afd6da00440ec83d54aefea742f26ba045505ac520f074512207a7bb50aaf9c4"
|
|
493
|
+
|
|
494
|
+
condition:
|
|
495
|
+
short_unicode_method_names
|
|
496
|
+
and (not dexguard_a and not dexguard_b and not dexguard_c and not dexguard_d)
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
rule apkencryptor : obfuscator
|
|
500
|
+
{
|
|
501
|
+
meta:
|
|
502
|
+
description = "ApkEncryptor"
|
|
503
|
+
url = "https://github.com/FlyingYu-Z/ApkEncryptor"
|
|
504
|
+
sample = "26c25dacacd0b4fdd411d7459747021d66cb45e9d57f92743004d190af74acea"
|
|
505
|
+
author = "Eduardo Novella"
|
|
506
|
+
|
|
507
|
+
strings:
|
|
508
|
+
$p1 = "Lcn/beingyi/sub/utils/Native"
|
|
509
|
+
$p2 = "Lcom/beingyi/encrypt/StringPool"
|
|
510
|
+
$p3 = "Lcn/beingyi/sub/ui/JniAlert"
|
|
511
|
+
|
|
512
|
+
condition:
|
|
513
|
+
any of them and is_dex and unreadable_field_names and unreadable_method_names
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
rule blackobfuscator : obfuscator
|
|
517
|
+
{
|
|
518
|
+
meta:
|
|
519
|
+
description = "BlackObfuscator"
|
|
520
|
+
url = "https://github.com/CodingGay/BlackObfuscator"
|
|
521
|
+
sample = "92ae23580c83642ad0e50f19979b9d2122f28d8b3a9d4b17539ce125ae8d93eb" // com.plus.currencyconverter
|
|
522
|
+
sample2 = "1730a1244ed5b01bf14426ff464042976c79796d8b6361648f6ed98c30d77997" // com.abhi.myapplication with depth 1
|
|
523
|
+
sample3 = "a01550f444063d7a96f48d7f276c88b9f0ac277fd8409586f370f189d347ad30" // com.abhi.myapplication with depth 2
|
|
524
|
+
sample4 = "6f1e14a590b73848871d6f5331c395086b1334e7d04e0f78d4211476c5b966e0" // com.abhi.myapplication with depth 5
|
|
525
|
+
author = "Abhi"
|
|
526
|
+
|
|
527
|
+
strings:
|
|
528
|
+
/**
|
|
529
|
+
protected void onCreate(Bundle bundle) {
|
|
530
|
+
String str = "ۖۨ";
|
|
531
|
+
while (true) {
|
|
532
|
+
switch ((str.hashCode() ^ 9) ^ (-1279807116)) {
|
|
533
|
+
....
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
*/
|
|
538
|
+
$opcodes = {
|
|
539
|
+
1A 00 ?? ?? // const-string v0, "random_weird_string"
|
|
540
|
+
6E 10 ?? (AC | 00) 00 00 // invoke-virtual {v0}, Ljava/lang/String.hashCode()I
|
|
541
|
+
0A ?? // move-result v(\d)
|
|
542
|
+
13 02 ?? ?? // const/16 v(\d), 0x(\d+)
|
|
543
|
+
(14 0? ?? ?? ?? ?? | B7 ??) // const v(\d), 0x(\d+) or xor-int/2addr v(\d), v(\d)
|
|
544
|
+
(B7 ?? | D7 ?? ?? ??) // xor-int/2addr v(\d), v(\d) or xor-int/lit16 v(\d), v(\d), 0x(\d+)
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
547
|
+
switch (...) {
|
|
548
|
+
case -2084167413:
|
|
549
|
+
....
|
|
550
|
+
case -2084167413:
|
|
551
|
+
....
|
|
552
|
+
case -2084167413:
|
|
553
|
+
....
|
|
554
|
+
...
|
|
555
|
+
}
|
|
556
|
+
*/
|
|
557
|
+
$switch = {
|
|
558
|
+
2C ?? ?? ?? ?? ?? // sparse-switch v(\d), 0x(\d+)
|
|
559
|
+
28 ?? // goto 0x(\d+)
|
|
560
|
+
1A 00 ?? ?? // const-string v0, "random_weird_string"
|
|
561
|
+
28 ?? // goto 0x(\d+)
|
|
562
|
+
1A 00 ?? ?? // const-string v0, "random_weird_string"
|
|
563
|
+
28 ?? // goto 0x(\d+)
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
condition:
|
|
567
|
+
is_dex and (#opcodes >= 2 and #switch >= 2)
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
rule mtprotector_dex : obfuscator
|
|
571
|
+
{
|
|
572
|
+
meta:
|
|
573
|
+
description = "MT Protector"
|
|
574
|
+
url = "https://mt2.cn/download/"
|
|
575
|
+
sample = "7fd0657a9d7a3b8f44e9a8938669439db8ef90585259d24aad31b9cc1599a419"
|
|
576
|
+
author = "Eduardo Novella"
|
|
577
|
+
|
|
578
|
+
strings:
|
|
579
|
+
$classname = { 00 204c 6269 6e2f 6d74 2f61 6e6e 6f74 6174 696f 6e73 2f4d 5450 726f 7465 6374 6f72 3b00 } // Lbin/mt/annotations/MTProtector;
|
|
580
|
+
|
|
581
|
+
condition:
|
|
582
|
+
is_dex and any of them
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
rule stringfog : obfuscator
|
|
586
|
+
{
|
|
587
|
+
meta:
|
|
588
|
+
description = "StringFog"
|
|
589
|
+
url = "https://github.com/MegatronKing/StringFog"
|
|
590
|
+
sample = "1b89174083b22d97979537dc00dc91473243155d2d23654f40958577c4641185"
|
|
591
|
+
author = "Abhi"
|
|
592
|
+
|
|
593
|
+
strings:
|
|
594
|
+
$classname = { 00 2E 4C 63 6F 6D 2F 67 69 74 68 75 62 2F 6D 65 67
|
|
595
|
+
61 74 72 6F 6E 6B 69 6E 67 2F 73 74 72 69 6E 67 66
|
|
596
|
+
6F 67 2F 49 53 74 72 69 6E 67 46 6F 67 3B 00 } // Lcom/github/megatronking/stringfog/IStringFog;
|
|
597
|
+
|
|
598
|
+
condition:
|
|
599
|
+
is_dex and any of them
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
|