Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Sign in / Register
Toggle navigation
E
Easy File Manager
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wanglei
Easy File Manager
Commits
003faa1b
Commit
003faa1b
authored
Jun 24, 2024
by
wanglei
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
移除混淆功能
parent
157d8d2c
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
3 additions
and
1956 deletions
+3
-1956
proguard.py
app/proguard.py
+0
-1815
MyApplication.kt
app/src/main/java/com/base/easyfilemanager/MyApplication.kt
+1
-14
AESHelper.kt
...src/main/java/com/base/easyfilemanager/helps/AESHelper.kt
+0
-60
AESTextView.kt
...c/main/java/com/base/easyfilemanager/helps/AESTextView.kt
+0
-16
BarUtils.kt
app/src/main/java/com/base/easyfilemanager/helps/BarUtils.kt
+2
-2
ConfigHelper.kt
.../main/java/com/base/easyfilemanager/helps/ConfigHelper.kt
+0
-7
KotlinExt.kt
...src/main/java/com/base/easyfilemanager/helps/KotlinExt.kt
+0
-42
No files found.
app/proguard.py
deleted
100644 → 0
View file @
157d8d2c
import
json
import
os
import
random
import
re
import
shutil
from
base64
import
b64encode
,
b64decode
import
cv2
import
numpy
as
np
import
regex
as
re2
from
Cryptodome.Cipher
import
AES
from
Cryptodome.Random
import
get_random_bytes
import
string
import
random
def
encrypt
(
content
):
try
:
iv
=
get_random_bytes
(
12
)
cipher
=
AES
.
new
(
aesKey
.
encode
(
'utf-8'
),
AES
.
MODE_GCM
,
nonce
=
iv
)
encrypt_data
,
tag
=
cipher
.
encrypt_and_digest
(
content
.
encode
(
'utf-8'
))
result
=
iv
+
encrypt_data
+
tag
return
b64encode
(
result
)
.
decode
(
'utf-8'
)
except
Exception
as
e
:
print
(
'error: '
+
str
(
e
))
return
content
def
decrypt
(
content
):
try
:
combined
=
b64decode
(
content
.
encode
(
'utf-8'
))
iv
=
combined
[:
12
]
tag
=
combined
[
-
16
:]
encrypt_data
=
combined
[
12
:
-
16
]
cipher
=
AES
.
new
(
aesKey
.
encode
(
'utf-8'
),
AES
.
MODE_GCM
,
nonce
=
iv
)
decrypt_data
=
cipher
.
decrypt_and_verify
(
encrypt_data
,
tag
)
return
decrypt_data
.
decode
(
'utf-8'
)
except
(
ValueError
,
KeyError
)
as
e
:
print
(
e
)
return
content
def
get_classes_impl
(
result
,
class_type
,
path
=
'.'
):
listdir
=
os
.
listdir
(
path
)
for
i
in
listdir
:
path_join
=
os
.
path
.
join
(
path
,
i
)
if
os
.
path
.
isdir
(
path_join
):
if
path
.
endswith
(
'.'
)
and
i
in
[
"build"
,
"debug"
,
"release"
]:
continue
if
path
.
endswith
(
'src'
)
and
i
in
[
"androidTest"
,
"test"
]:
continue
get_classes_impl
(
result
,
class_type
,
path_join
)
elif
os
.
path
.
isfile
(
path_join
):
if
os
.
path
.
splitext
(
i
)[
-
1
][
1
:]
in
class_type
:
result
.
append
(
path_join
)
def
get_classes
(
class_type
=
None
):
if
class_type
is
None
:
class_type
=
[
"kt"
,
"java"
]
result
=
[]
get_classes_impl
(
result
,
class_type
)
return
result
def
find_text_impl
(
reg
,
result
,
skip_name
,
path
,
is_one
):
listdir
=
os
.
listdir
(
path
)
for
i
in
listdir
:
if
is_one
and
len
(
result
)
>
0
:
return
path_join
=
os
.
path
.
join
(
path
,
i
)
if
os
.
path
.
isdir
(
path_join
):
if
path
.
endswith
(
'.'
)
and
i
in
[
"build"
,
"debug"
,
"release"
]:
continue
if
path
.
endswith
(
'src'
)
and
i
in
[
"androidTest"
,
"test"
]:
continue
find_text_impl
(
reg
,
result
,
skip_name
,
path_join
,
is_one
)
elif
os
.
path
.
isfile
(
path_join
):
if
path
.
endswith
(
'.'
)
and
i
.
split
(
'.'
)[
-
1
]
in
[
'py'
]:
continue
is_skip
=
False
for
j
in
skip_name
:
if
j
in
i
:
is_skip
=
True
break
if
is_skip
:
continue
with
open
(
path_join
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
if
not
f
.
readable
():
continue
try
:
text
=
f
.
read
()
except
ValueError
:
continue
findall
=
re
.
findall
(
reg
,
text
)
if
len
(
findall
)
>
0
:
result
.
extend
(
findall
)
def
find_text
(
reg
,
path
=
'.'
,
is_one
=
False
,
skip_name
=
None
):
if
skip_name
is
None
:
skip_name
=
[]
result
=
[]
if
os
.
path
.
isdir
(
path
):
find_text_impl
(
reg
,
result
,
skip_name
,
path
,
is_one
)
else
:
with
open
(
path
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
if
f
.
readable
():
try
:
text
=
f
.
read
()
findall
=
re
.
findall
(
reg
,
text
)
if
len
(
findall
)
>
0
:
result
.
extend
(
findall
)
except
ValueError
:
pass
if
is_one
:
if
len
(
result
)
>
0
:
return
result
[
0
]
else
:
return
None
return
result
def
find_file_impl
(
reg
,
result
,
skip_name
,
path
=
'.'
):
listdir
=
os
.
listdir
(
path
)
for
i
in
listdir
:
if
len
(
result
)
>
0
:
return
path_join
=
os
.
path
.
join
(
path
,
i
)
if
os
.
path
.
isdir
(
path_join
):
if
path
.
endswith
(
'.'
)
and
i
in
[
"build"
,
"debug"
,
"release"
]:
continue
if
path
.
endswith
(
'src'
)
and
i
in
[
"androidTest"
,
"test"
]:
continue
find_file_impl
(
reg
,
result
,
skip_name
,
path_join
)
elif
os
.
path
.
isfile
(
path_join
):
if
path
.
endswith
(
'.'
)
and
i
not
in
[
"pro"
]:
continue
is_skip
=
False
for
j
in
skip_name
:
if
j
in
i
:
is_skip
=
True
break
if
is_skip
:
continue
with
open
(
path_join
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
if
not
f
.
readable
():
continue
try
:
text
=
f
.
read
()
except
ValueError
:
continue
findall
=
re
.
findall
(
reg
,
text
)
if
len
(
findall
)
>
0
:
result
.
append
(
path_join
)
def
find_file
(
reg
,
path
=
'.'
,
skip_name
=
None
):
if
skip_name
is
None
:
skip_name
=
[]
result
=
[]
if
os
.
path
.
isdir
(
path
):
find_file_impl
(
reg
,
result
,
skip_name
,
path
)
else
:
with
open
(
path
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
if
f
.
readable
():
try
:
text
=
f
.
read
()
findall
=
re
.
findall
(
reg
,
text
)
if
len
(
findall
)
>
0
:
result
.
append
(
path
)
except
ValueError
:
pass
return
result
[
0
]
if
len
(
result
)
>
0
else
""
def
get_class_path
(
path
):
with
open
(
path
,
'r'
)
as
f
:
text
=
f
.
read
()
package
=
re
.
search
(
'package (.*?)
\\
s'
,
text
)
.
group
(
1
)
name
=
os
.
path
.
basename
(
path
)
name
=
name
[:
name
.
rfind
(
'.'
)]
return
package
+
'.'
+
name
def
replace_map_text
(
mapping
,
path
=
'.'
):
listdir
=
os
.
listdir
(
path
)
for
i
in
listdir
:
path_join
=
os
.
path
.
join
(
path
,
i
)
if
os
.
path
.
isdir
(
path_join
):
if
path
.
endswith
(
'.'
)
and
i
in
[
"build"
,
"debug"
,
"release"
]:
continue
if
path
.
endswith
(
'src'
)
and
i
in
[
"androidTest"
,
"test"
]:
continue
replace_map_text
(
mapping
,
path_join
)
elif
os
.
path
.
isfile
(
path_join
):
if
path
.
endswith
(
'.'
)
and
os
.
path
.
splitext
(
i
)[
-
1
][
1
:]
not
in
[
"pro"
]:
continue
with
open
(
path_join
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
if
not
f
.
readable
():
continue
try
:
text
=
f
.
read
()
except
ValueError
:
continue
with
open
(
path_join
,
'w'
,
encoding
=
'utf-8'
)
as
f
:
reverse
=
sorted
(
list
(
mapping
.
keys
()),
key
=
len
,
reverse
=
True
)
for
name
in
reverse
:
text
=
text
.
replace
(
str
(
name
),
mapping
[
name
])
f
.
write
(
text
)
def
sub_map_text
(
mapping
,
is_reverse
=
True
,
path
=
'.'
,
skip_type
=
None
,
skip_name
=
None
):
if
len
(
mapping
)
==
0
:
return
[]
if
skip_type
is
None
:
skip_type
=
[]
if
skip_name
is
None
:
skip_name
=
[]
result
=
[]
sub_map_text_impl
(
mapping
,
result
,
skip_type
,
skip_name
,
is_reverse
,
path
)
return
result
def
sub_map_text_impl
(
mapping
,
result
,
skip_type
,
skip_name
,
is_reverse
=
True
,
path
=
'.'
):
listdir
=
os
.
listdir
(
path
)
for
i
in
listdir
:
path_join
=
os
.
path
.
join
(
path
,
i
)
if
os
.
path
.
isdir
(
path_join
):
if
path
.
endswith
(
'.'
)
and
i
in
[
"build"
,
"debug"
,
"release"
]:
continue
if
path
.
endswith
(
'src'
)
and
i
in
[
"androidTest"
,
"test"
]:
continue
sub_map_text_impl
(
mapping
,
result
,
skip_type
,
skip_name
,
is_reverse
,
path_join
)
elif
os
.
path
.
isfile
(
path_join
):
if
path
.
endswith
(
'.'
)
and
os
.
path
.
splitext
(
i
)[
-
1
][
1
:]
not
in
[
"pro"
]:
continue
if
os
.
path
.
splitext
(
i
)[
-
1
][
1
:]
in
skip_type
:
continue
is_skip
=
False
for
j
in
skip_name
:
if
j
in
i
:
is_skip
=
True
break
if
is_skip
:
continue
with
open
(
path_join
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
if
not
f
.
readable
():
continue
try
:
text
=
f
.
read
()
except
ValueError
:
continue
with
open
(
path_join
,
'w'
,
encoding
=
'utf-8'
)
as
f
:
reverse
=
sorted
(
list
(
mapping
.
keys
()),
key
=
len
,
reverse
=
is_reverse
)
text_result
=
text
for
name
in
reverse
:
text_result
=
re2
.
sub
(
str
(
name
),
mapping
[
name
],
text_result
)
if
text_result
!=
text
:
result
.
append
(
path_join
)
f
.
write
(
text_result
)
def
replace_text
(
old
,
new
,
path
=
'.'
):
listdir
=
os
.
listdir
(
path
)
for
i
in
listdir
:
path_join
=
os
.
path
.
join
(
path
,
i
)
if
os
.
path
.
isdir
(
path_join
):
if
path
.
endswith
(
'.'
)
and
i
in
[
"build"
,
"debug"
,
"release"
]:
continue
if
path
.
endswith
(
'src'
)
and
i
in
[
"androidTest"
,
"test"
]:
continue
replace_text
(
old
,
new
,
path_join
)
elif
os
.
path
.
isfile
(
path_join
):
if
path
.
endswith
(
'.'
)
and
os
.
path
.
splitext
(
i
)[
-
1
][
1
:]
not
in
[
"pro"
]:
continue
with
open
(
path_join
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
if
not
f
.
readable
():
continue
try
:
text
=
f
.
read
()
except
ValueError
:
continue
with
open
(
path_join
,
'w'
,
encoding
=
'utf-8'
)
as
f
:
f
.
write
(
text
.
replace
(
old
,
new
))
def
get_random_package
():
packages
=
[
get_random_string
(
4
)
for
_
in
range
(
get_random_int
(
1
,
3
))]
return
'.'
.
join
(
packages
)
def
check_mapping
():
try
:
loads
=
json
.
load
(
open
(
'mapping.json'
,
'r'
,
encoding
=
'utf-8'
))
except
(
ValueError
,
IOError
):
loads
=
{}
old_mapping
=
loads
.
get
(
'dir'
,
{})
packages
=
find_text
(
'package (.*?)[;]?
\\
s'
,
'src'
)
packages
.
append
(
applicationId
)
packages
=
sorted
(
set
(
packages
),
key
=
packages
.
index
)
packages
.
sort
(
key
=
len
)
mapping
=
{}
for
i
in
packages
:
if
applicationId
not
in
i
:
continue
value
=
old_mapping
.
get
(
i
)
if
value
is
not
None
:
mapping
[
i
]
=
value
continue
mapping
[
i
]
=
get_random_package
()
value
=
mapping
.
get
(
i
[:
i
.
rfind
(
'.'
)])
if
value
is
not
None
:
mapping
[
i
]
=
value
+
'.'
+
mapping
[
i
]
loads
[
"dir"
]
=
mapping
json
.
dump
(
loads
,
open
(
'mapping.json'
,
'w'
,
encoding
=
'utf-8'
),
indent
=
4
)
return
mapping
def
check_class_mapping
():
try
:
loads
=
json
.
load
(
open
(
'mapping.json'
,
'r'
,
encoding
=
'utf-8'
))
except
(
ValueError
,
IOError
):
loads
=
{}
old_mapping
=
loads
.
get
(
'class'
,
{})
mapping
=
{}
classes
=
get_classes
()
for
i
in
classes
:
if
'_D'
in
i
:
continue
name
=
os
.
path
.
basename
(
i
)
name
=
name
[:
name
.
rfind
(
'.'
)]
value
=
old_mapping
.
get
(
name
)
if
value
is
not
None
:
mapping
[
name
]
=
value
continue
mapping
[
name
]
=
get_title
(
get_random_string
(
4
),
True
)
loads
[
"class"
]
=
mapping
json
.
dump
(
loads
,
open
(
'mapping.json'
,
'w'
,
encoding
=
'utf-8'
),
indent
=
4
)
return
mapping
def
check_type_ids_mapping
(
ids_type
):
try
:
loads
=
json
.
load
(
open
(
'mapping.json'
,
'r'
,
encoding
=
'utf-8'
))
except
(
ValueError
,
IOError
):
loads
=
{}
old_mapping
=
loads
.
get
(
ids_type
+
"_ids"
,
{})
mapping
=
{}
type_ids
=
find_text
(
'<'
+
ids_type
+
' name="(.*?)".*?>'
,
get_path
(
'.
\\
src
\\
main
\\
res'
))
for
i
in
type_ids
:
if
i
.
endswith
(
'_D'
):
continue
value
=
old_mapping
.
get
(
i
)
if
value
is
not
None
:
mapping
[
i
]
=
value
continue
mapping
[
i
]
=
get_random_string
(
5
,
False
)
type_ids
=
find_text
(
'<item name="(.*?)".*? type="'
+
ids_type
+
'">'
,
get_path
(
'.
\\
src
\\
main
\\
res'
))
for
i
in
type_ids
:
value
=
old_mapping
.
get
(
i
)
if
value
is
not
None
:
mapping
[
i
]
=
value
continue
mapping
[
i
]
=
get_random_string
(
5
,
False
)
if
len
(
mapping
)
!=
0
:
loads
[
ids_type
+
"_ids"
]
=
mapping
json
.
dump
(
loads
,
open
(
'mapping.json'
,
'w'
,
encoding
=
'utf-8'
),
indent
=
4
)
return
mapping
def
check_styleable_mapping
():
try
:
loads
=
json
.
load
(
open
(
'mapping.json'
,
'r'
,
encoding
=
'utf-8'
))
except
(
ValueError
,
IOError
):
loads
=
{}
old_mapping
=
loads
.
get
(
"styleable"
,
{})
mapping
=
{}
styleables
=
find_text
(
'<declare-styleable name=".*?">[
\\
s
\\
S]*?</declare-styleable>'
)
for
i
in
styleables
:
styleable_id
=
re
.
findall
(
'<declare-styleable name="(.*?)">'
,
i
)[
0
]
mapping
[
styleable_id
]
=
old_mapping
.
get
(
styleable_id
,
get_random_string
(
5
,
False
))
styleables_attr
=
re
.
findall
(
'<attr name="(.*?)".*?/>'
,
i
)
for
attr
in
styleables_attr
:
mapping
[
attr
+
'_A'
]
=
old_mapping
.
get
(
attr
+
'_A'
,
get_random_string
(
5
))
if
len
(
mapping
)
!=
0
:
loads
[
"styleable"
]
=
mapping
json
.
dump
(
loads
,
open
(
'mapping.json'
,
'w'
,
encoding
=
'utf-8'
),
indent
=
4
)
return
mapping
def
deal_ids_type
(
ids_type
):
type_ids_mapping
=
check_type_ids_mapping
(
ids_type
)
if
len
(
type_ids_mapping
)
==
0
:
return
print
(
type_ids_mapping
)
sub_map
=
{}
for
i
in
type_ids_mapping
:
sub_map
[
'<'
+
ids_type
+
' name="'
+
i
+
'"'
]
=
'<'
+
ids_type
+
' name="'
+
type_ids_mapping
[
i
]
+
'"'
sub_map
[
'<item name="'
+
i
+
'"(.*? type="'
+
ids_type
+
'")>'
]
=
\
'<item name="'
+
type_ids_mapping
[
i
]
+
'"
\\
g<1>>'
sub_map
[
'(?<=[^
\\
.])R
\\
.'
+
ids_type
+
'
\\
.'
+
i
+
'(?=
\\
W)'
]
=
'R.'
+
ids_type
+
'.'
+
type_ids_mapping
[
i
]
sub_map
[
'(?<=>|")@'
+
ids_type
+
'/'
+
i
+
'(?=<|")'
]
=
'@'
+
ids_type
+
'/'
+
type_ids_mapping
[
i
]
sub_map
[
'<'
+
ids_type
+
'(.*?) parent="'
+
i
+
'"(.*?)>'
]
=
\
'<'
+
ids_type
+
'
\\
g<1> parent="'
+
type_ids_mapping
[
i
]
+
'"
\\
g<2>>'
sub_map_text
(
sub_map
)
def
check_strings_mapping
():
try
:
loads
=
json
.
load
(
open
(
'mapping.json'
,
'r'
,
encoding
=
'utf-8'
))
except
(
ValueError
,
IOError
):
loads
=
{}
mapping
=
loads
.
get
(
'strings'
,
{})
string_values
=
find_text
(
'<string name="(.*?)".*?>(.*?)</string>'
,
get_path
(
'.
\\
src
\\
main
\\
res
\\
values'
))
strings
=
[]
for
i
in
string_values
:
if
i
[
0
]
.
endswith
(
'___'
)
or
i
[
0
]
in
[
'app_name'
,
'facebook_app_id'
]:
continue
if
mapping
.
get
(
i
[
1
])
is
not
None
:
continue
strings
.
append
(
i
[
1
])
for
i
in
strings
:
mapping
[
i
]
=
encrypt
(
i
)
loads
[
"strings"
]
=
mapping
json
.
dump
(
loads
,
open
(
'mapping.json'
,
'w'
,
encoding
=
'utf-8'
),
indent
=
4
)
return
mapping
def
check_view_ids_mapping
():
try
:
loads
=
json
.
load
(
open
(
'mapping.json'
,
'r'
,
encoding
=
'utf-8'
))
except
(
ValueError
,
IOError
):
loads
=
{}
mapping
=
loads
.
get
(
'view_ids'
,
{})
view_ids
=
find_text
(
'"
\\
@
\\
+id/(.*?)"'
,
get_path
(
'.
\\
src
\\
main
\\
res'
))
for
i
in
view_ids
:
if
i
==
'root'
:
continue
key
=
get_title
(
i
)
if
mapping
.
get
(
key
)
is
not
None
:
continue
mapping
[
key
]
=
get_random_string
(
7
)
loads
[
"view_ids"
]
=
mapping
json
.
dump
(
loads
,
open
(
'mapping.json'
,
'w'
,
encoding
=
'utf-8'
),
indent
=
4
)
return
mapping
def
check_layout_mapping
():
try
:
loads
=
json
.
load
(
open
(
'mapping.json'
,
'r'
,
encoding
=
'utf-8'
))
except
(
ValueError
,
IOError
):
loads
=
{}
mapping
=
loads
.
get
(
'layout'
,
{})
layout_path
=
get_path
(
'.
\\
src
\\
main
\\
res
\\
layout'
)
listdir
=
os
.
listdir
(
layout_path
)
for
i
in
listdir
:
name
=
i
[:
i
.
rfind
(
'.'
)]
if
mapping
.
get
(
name
)
is
not
None
:
continue
mapping
[
name
]
=
get_random_string
(
6
)
loads
[
"layout"
]
=
mapping
json
.
dump
(
loads
,
open
(
'mapping.json'
,
'w'
,
encoding
=
'utf-8'
),
indent
=
4
)
return
mapping
def
check_res_mapping
(
res_type
):
try
:
loads
=
json
.
load
(
open
(
'mapping.json'
,
'r'
,
encoding
=
'utf-8'
))
except
(
ValueError
,
IOError
):
loads
=
{}
mapping
=
loads
.
get
(
res_type
,
{})
res_path
=
get_path
(
'.
\\
src
\\
main
\\
res'
)
listdir
=
os
.
listdir
(
res_path
)
for
i
in
listdir
:
if
not
i
.
startswith
(
res_type
):
continue
for
j
in
os
.
listdir
(
os
.
path
.
join
(
res_path
,
i
)):
if
j
.
startswith
(
'book_'
):
continue
if
j
.
endswith
(
'.9.png'
):
name
=
j
[:
-
len
(
'.9.png'
)]
else
:
name
=
j
.
rsplit
(
'.'
,
1
)[
0
]
if
mapping
.
get
(
name
)
is
not
None
:
continue
mapping
[
name
]
=
get_random_string
(
8
)
if
len
(
mapping
)
!=
0
:
loads
[
res_type
]
=
mapping
json
.
dump
(
loads
,
open
(
'mapping.json'
,
'w'
,
encoding
=
'utf-8'
),
indent
=
4
)
return
mapping
def
get_random_string
(
length
=
8
,
is_ascii
=
True
):
s
=
''
for
i
in
range
(
length
):
if
is_ascii
:
s
+=
chr
(
random
.
randint
(
0
,
25
)
+
ord
(
'a'
))
else
:
s
+=
chr
(
random
.
randrange
(
0x0780
,
0x07A5
+
1
))
return
s
def
get_random_int
(
a
=
0
,
b
=
10000
):
return
random
.
randint
(
a
,
b
)
def
get_dictionary_string
(
length
=
10
):
random_str
=
random
.
choice
(
string
.
ascii_letters
)
random_str
+=
''
.
join
(
random
.
choice
(
string
.
ascii_letters
+
string
.
digits
)
for
_
in
range
(
length
-
1
))
return
random_str
def
check_obfuscation_dictionary
():
if
not
os
.
path
.
exists
(
'dictionary.txt'
):
dictionary
=
set
()
while
len
(
dictionary
)
!=
5000
:
dictionary
.
add
(
get_dictionary_string
())
with
open
(
'dictionary.txt'
,
'w'
,
encoding
=
'utf-8'
)
as
f
:
f
.
write
(
'
\n
'
.
join
(
dictionary
))
with
open
(
'proguard-rules.pro'
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
text
=
f
.
read
()
if
'-obfuscationdictionary'
in
text
:
return
text
+=
'
\n
-obfuscationdictionary dictionary.txt'
text
+=
'
\n
-classobfuscationdictionary dictionary.txt'
text
+=
'
\n
-packageobfuscationdictionary dictionary.txt'
with
open
(
'proguard-rules.pro'
,
'w'
,
encoding
=
'utf-8'
)
as
f
:
f
.
write
(
text
)
def
mkdir
(
dir_path
):
try
:
os
.
makedirs
(
dir_path
)
except
OSError
:
pass
def
replace_click_method
():
try
:
path
=
get_path
(
'.
\\
src
\\
main
\\
java'
)
file
=
find_file
(
'fun View.setTrackedOnClickListener'
,
path
)
if
file
:
class_path
=
get_class_path
(
file
)
+
'.setTrackedOnClickListener'
# java类不能直接使用扩展函数
sub_map_text
({
'([.@])setOnClickListener'
:
'
\\
g<1>setTrackedOnClickListener'
,
},
path
=
path
,
skip_type
=
[
'java'
])
add_import
(
class_path
,
get_classes
([
'kt'
]))
except
IndexError
:
return
def
deal_code
():
# 替换点击事件
replace_click_method
()
# 生成包映射文件
mapping
=
check_mapping
()
packages
=
list
(
mapping
.
keys
())
print
(
mapping
)
# 移动文件
root_path
=
get_path
(
'.
\\
src
\\
main
\\
java'
)
for
key
in
packages
:
key
=
str
(
key
)
old_path
=
get_path
(
root_path
+
'
\\
'
+
key
.
replace
(
'.'
,
'
\\
'
))
new_path
=
get_path
(
root_path
+
'
\\
'
+
mapping
[
key
]
.
replace
(
'.'
,
'
\\
'
))
if
not
os
.
path
.
exists
(
old_path
):
mkdir
(
old_path
)
if
not
os
.
path
.
exists
(
new_path
):
mkdir
(
new_path
)
listdir
=
os
.
listdir
(
old_path
)
for
i
in
listdir
:
path_join
=
os
.
path
.
join
(
old_path
,
i
)
if
os
.
path
.
isdir
(
path_join
):
continue
shutil
.
move
(
path_join
,
os
.
path
.
join
(
new_path
,
i
))
shutil
.
rmtree
(
get_path
(
root_path
+
'
\\
'
+
applicationId
[:
applicationId
.
find
(
'.'
)]))
# 修改manifest
with
open
(
get_path
(
'.
\\
src
\\
main
\\
AndroidManifest.xml'
),
'r'
,
encoding
=
'utf-8'
)
as
f
:
text
=
f
.
read
()
findall
=
re
.
findall
(
'android:name=(".*?")'
,
text
)
for
i
in
findall
:
if
i
.
startswith
(
'".'
):
text
=
text
.
replace
(
i
,
'"'
+
applicationId
+
i
[
1
:
-
1
]
+
'"'
)
with
open
(
get_path
(
'.
\\
src
\\
main
\\
AndroidManifest.xml'
),
'w'
,
encoding
=
'utf-8'
)
as
f
:
f
.
write
(
text
)
# 修改依赖
sub_map
=
{}
for
i
in
mapping
:
sub_map
[
'(?<=
\\
W)'
+
i
+
'(?=
\\
W)'
]
=
mapping
[
i
]
# 过滤修改
sub_map
[
'(?<=
\\
W)'
+
mapping
[
applicationId
]
+
'.R(?=
\\
W)'
]
=
applicationId
+
'.R'
sub_map
[
'(?<=
\\
W)'
+
mapping
[
applicationId
]
+
'.databinding(?=
\\
W)'
]
=
applicationId
+
'.databinding'
sub_map
[
'(?<=
\\
W)'
+
mapping
[
applicationId
]
+
'.BuildConfig(?=
\\
W)'
]
=
applicationId
+
'.BuildConfig'
sub_map_text
(
sub_map
)
# 根包名下 R 单独处理
new_path
=
get_path
(
root_path
+
'
\\
'
+
mapping
[
packages
[
0
]]
.
replace
(
'.'
,
'
\\
'
))
listdir
=
os
.
listdir
(
new_path
)
result_path
=
[]
for
i
in
listdir
:
if
os
.
path
.
isdir
(
os
.
path
.
join
(
new_path
,
i
)):
continue
result_path
.
append
(
os
.
path
.
join
(
new_path
,
i
))
add_import
(
applicationId
+
'.R'
,
result_path
)
add_import
(
applicationId
+
'.BuildConfig'
,
result_path
)
# 类名
class_mapping
=
check_class_mapping
()
classes
=
get_classes
()
print
(
class_mapping
)
for
i
in
classes
:
if
'_D'
in
i
:
continue
name
=
os
.
path
.
basename
(
i
)
name
=
name
[:
name
.
rfind
(
'.'
)]
shutil
.
move
(
i
,
i
.
replace
(
name
,
class_mapping
[
name
]))
sub_map
=
{}
for
i
in
class_mapping
:
sub_map
[
'(?<=
\\
W)'
+
i
+
'(?=
\\
W)'
]
=
class_mapping
[
i
]
sub_map_text
(
sub_map
)
# 混淆字典
check_obfuscation_dictionary
()
def
deal_res_type
(
res_type
):
type_mapping
=
check_res_mapping
(
res_type
)
if
len
(
type_mapping
)
==
0
:
return
print
(
type_mapping
)
res_path
=
get_path
(
'.
\\
src
\\
main
\\
res'
)
listdir
=
os
.
listdir
(
res_path
)
for
i
in
listdir
:
if
not
i
.
startswith
(
res_type
):
continue
path_join
=
os
.
path
.
join
(
res_path
,
i
)
for
j
in
os
.
listdir
(
path_join
):
if
j
.
startswith
(
'book_'
):
continue
if
j
.
endswith
(
'.9.png'
):
name
=
j
[:
-
len
(
'.9.png'
)]
else
:
name
=
j
.
rsplit
(
'.'
,
1
)[
0
]
path
=
os
.
path
.
join
(
path_join
,
j
)
if
'.DS_Store'
not
in
path
:
shutil
.
move
(
path
,
path
.
replace
(
name
,
type_mapping
[
name
]))
sub_map
=
{}
for
i
in
type_mapping
:
sub_map
[
'R
\\
.'
+
res_type
+
'
\\
.'
+
i
+
'(
\\
W)'
]
=
'R.'
+
res_type
+
'.'
+
type_mapping
[
i
]
+
'
\\
g<1>'
sub_map
[
'(>|")@'
+
res_type
+
'/'
+
i
+
'(<|")'
]
=
'
\\
g<1>@'
+
res_type
+
'/'
+
type_mapping
[
i
]
+
'
\\
g<2>'
sub_map_text
(
sub_map
)
def
add_image_noise
(
path
):
try
:
image
=
cv2
.
imread
(
path
,
cv2
.
IMREAD_UNCHANGED
)
if
path
.
endswith
(
'.9.png'
):
return
# 添加随机噪声
noise
=
np
.
random
.
randint
(
0
,
2
,
image
.
shape
,
np
.
uint8
)
image
=
cv2
.
add
(
image
,
noise
)
new_path
=
path
.
rsplit
(
'.'
,
1
)[
0
]
+
'.webp'
cv2
.
imwrite
(
new_path
,
image
,
[
cv2
.
IMWRITE_WEBP_QUALITY
,
75
])
if
new_path
!=
path
:
os
.
remove
(
path
)
except
AttributeError
:
return
def
deal_image
():
res_path
=
get_path
(
'.
\\
src
\\
main
\\
res'
)
listdir
=
os
.
listdir
(
res_path
)
for
i
in
listdir
:
path_join
=
os
.
path
.
join
(
res_path
,
i
)
if
os
.
path
.
isdir
(
path_join
):
for
j
in
os
.
listdir
(
path_join
):
add_image_noise
(
os
.
path
.
join
(
path_join
,
j
))
def
get_title
(
string
,
is_all_upper
=
False
):
splits
=
string
.
split
(
'_'
)
s
=
''
for
i
in
range
(
len
(
splits
)):
if
i
==
0
and
not
is_all_upper
:
s
=
splits
[
i
]
elif
len
(
splits
[
i
])
>
0
:
s
+=
splits
[
i
][
0
]
.
upper
()
+
splits
[
i
][
1
:]
return
s
def
add_import
(
path
,
listfile
):
for
i
in
listfile
:
with
open
(
i
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
text
=
f
.
read
()
if
len
(
re
.
findall
(
'import '
+
path
,
text
))
!=
0
:
continue
if
i
.
endswith
(
'kt'
):
text
=
re
.
sub
(
'(package
\\
S+?
\\
s+?)(?=
\\
S)'
,
'
\\
g<1>import '
+
path
+
'
\n
'
,
text
,
flags
=
re
.
S
)
elif
i
.
endswith
(
'java'
):
text
=
re
.
sub
(
'(package
\\
S+?
\\
s+?)(?=
\\
S)'
,
'
\\
g<1>import '
+
path
+
';
\n
'
,
text
,
flags
=
re
.
S
)
with
open
(
i
,
'w'
,
encoding
=
'utf-8'
)
as
f
:
f
.
write
(
text
)
def
check_class_string_mapping
():
try
:
loads
=
json
.
load
(
open
(
'mapping.json'
,
'r'
,
encoding
=
'utf-8'
))
except
(
ValueError
,
IOError
):
loads
=
{}
mapping
=
loads
.
get
(
'class_string'
,
{})
classes
=
get_classes
([
'kt'
])
for
path
in
classes
:
if
os
.
path
.
basename
(
path
)
.
startswith
(
'AESHelper'
):
continue
with
open
(
path
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
text
=
f
.
read
()
text
=
re
.
sub
(
'@SuppressLint.*?
\n
'
,
'
\n
'
,
text
)
text
=
re
.
sub
(
'//[^"]*?(("[^"]*?){2})*?
\n
'
,
'
\n
'
,
text
)
text
=
re
.
sub
(
' +
\n
'
,
'
\n
'
,
text
)
text
=
re
.
sub
(
'=
\\
s+'
,
'= '
,
text
)
text
=
re
.
sub
(
':
\\
s+'
,
': '
,
text
)
text
=
re
.
sub
(
',
\\
s+'
,
', '
,
text
)
text
=
re
.
sub
(
'
\n
{2,}'
,
'
\n\n
'
,
text
)
result_text
=
text
strings
=
re
.
findall
(
'".*?[^
\\\\
]"'
,
re
.
sub
(
r'@[^)]*'
,
lambda
x
:
x
.
group
()
.
replace
(
'"'
,
"'"
),
result_text
))
last_string
=
''
for
string
in
strings
:
if
len
(
string
)
<=
4
or
string
.
isspace
()
or
\
string
[
1
:
-
1
]
in
[
'
\\\\
n'
,
'
\\\\
r'
,
'
\\\\\'
'
,
'
\\\\\\
"'
,
'
\\\\
?'
,
'&'
,
'UTF-8'
]:
continue
if
string
in
last_string
:
continue
start
=
text
.
find
(
string
)
if
start
==
-
1
:
continue
index
=
start
+
1
sign_stack
=
[
'"'
]
while
len
(
sign_stack
)
!=
0
:
if
text
[
index
]
==
'
\\
'
:
index
+=
1
elif
text
[
index
]
==
'"'
and
sign_stack
[
-
1
]
==
'"'
:
sign_stack
.
pop
()
elif
text
[
index
]
==
'"'
:
sign_stack
.
append
(
'"'
)
elif
text
[
index
]
==
'}'
and
sign_stack
[
-
1
]
==
'${'
:
sign_stack
.
pop
()
elif
text
[
index
-
1
:
index
+
1
]
==
'${'
:
sign_stack
.
append
(
'${'
)
index
+=
1
string
=
text
[
start
:
index
]
last_string
=
string
params
=
[]
result
=
string
if
'$'
in
string
:
count
=
0
last
=
-
1
res
=
[]
for
i
in
range
(
len
(
string
)):
if
last
==
-
1
and
string
[
i
]
==
'$'
:
if
count
==
0
:
last
=
i
elif
last
!=
-
1
:
if
string
[
i
]
==
'{'
:
count
+=
1
elif
string
[
i
]
==
'}'
:
count
-=
1
if
count
==
0
:
res
.
append
((
last
,
i
+
1
))
last
=
-
1
elif
count
==
0
:
last
=
-
1
for
i
in
re
.
findall
(
'
\\
$
\\
w*'
,
string
):
if
i
==
'$'
:
continue
find
=
string
.
find
(
i
)
res
.
append
((
find
,
find
+
len
(
i
)))
res
=
sorted
(
res
,
key
=
lambda
l
:
l
[
0
])
last_res
=
None
for
i
in
res
:
if
last_res
is
not
None
and
i
[
0
]
<
last_res
[
1
]:
continue
params
.
append
(
string
[
i
[
0
]:
i
[
1
]])
last_res
=
i
for
i
in
params
:
result
=
result
.
replace
(
i
,
"[str]"
)
result
=
result
[
1
:
-
1
]
.
replace
(
'
%
'
,
'
%%
'
)
.
replace
(
'
\\\\
'
,
'
\\
'
)
.
replace
(
'[str]'
,
'
%
s'
)
if
result
==
aesKey
:
continue
if
mapping
.
get
(
result
)
is
not
None
:
continue
mapping
[
result
]
=
get_random_string
(
5
,
False
)
+
'_D'
loads
[
'class_string'
]
=
mapping
json
.
dump
(
loads
,
open
(
'mapping.json'
,
'w'
,
encoding
=
'utf-8'
),
indent
=
4
)
return
mapping
def
deal_class_string
():
# 获取映射
string_mapping
=
check_class_string_mapping
()
print
(
string_mapping
)
with
open
(
get_path
(
'.
\\
src
\\
main
\\
res
\\
values
\\
strings.xml'
),
'r'
,
encoding
=
'utf-8'
)
as
f
:
text
=
f
.
read
()
rfind
=
text
.
rfind
(
'
\n
'
)
text_result
=
text
[:
rfind
]
for
i
in
string_mapping
:
string
=
i
string
=
string
.
replace
(
'&'
,
'&'
)
string
=
string
.
replace
(
'?'
,
'
\\
?'
)
string
=
string
.
replace
(
'
\'
'
,
'
\\\'
'
)
text_result
+=
'
\n
<string name="'
+
string_mapping
[
i
]
+
'" translatable="false">'
+
string
+
'</string>'
text_result
+=
text
[
rfind
:]
with
open
(
get_path
(
'.
\\
src
\\
main
\\
res
\\
values
\\
strings.xml'
),
'w'
,
encoding
=
'utf-8'
)
as
f
:
f
.
write
(
text_result
)
# 搜索 Int.string() 路径
file_path
=
find_file
(
'fun Int.string'
,
get_path
(
'.
\\
src
\\
main
\\
java'
))
class_path
=
get_class_path
(
file_path
)
+
'.string'
if
file_path
else
""
classes
=
get_classes
([
'kt'
])
for
path
in
classes
:
# 跳过 AESHelper 类中的字符串,避免嵌套
if
os
.
path
.
basename
(
path
)
.
startswith
(
'AESHelper'
):
continue
with
open
(
path
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
text
=
f
.
read
()
text
=
re
.
sub
(
'@SuppressLint.*?
\n
'
,
'
\n
'
,
text
)
text
=
re
.
sub
(
'//[^"]*?(("[^"]*?){2})*?
\n
'
,
'
\n
'
,
text
)
text
=
re
.
sub
(
' +
\n
'
,
'
\n
'
,
text
)
text
=
re
.
sub
(
'=
\\
s+'
,
'= '
,
text
)
text
=
re
.
sub
(
':
\\
s+'
,
': '
,
text
)
text
=
re
.
sub
(
',
\\
s+'
,
', '
,
text
)
text
=
re
.
sub
(
'
\n
{2,}'
,
'
\n\n
'
,
text
)
result_text
=
text
strings
=
re
.
findall
(
'".*?[^
\\\\
]"'
,
re
.
sub
(
r'@[^)]*'
,
lambda
x
:
x
.
group
()
.
replace
(
'"'
,
"'"
),
result_text
))
last_string
=
''
for
string
in
strings
:
if
len
(
string
)
<=
4
or
string
.
isspace
()
or
\
string
[
1
:
-
1
]
in
[
'
\\\\
n'
,
'
\\\\
r'
,
'
\\\\\'
'
,
'
\\\\\\
"'
,
'
\\\\
?'
,
'&'
,
'UTF-8'
]:
continue
if
string
in
last_string
:
continue
start
=
text
.
find
(
string
)
if
start
==
-
1
:
continue
index
=
start
+
1
sign_stack
=
[
'"'
]
while
len
(
sign_stack
)
!=
0
:
if
text
[
index
]
==
'
\\
'
:
index
+=
1
elif
text
[
index
]
==
'"'
and
sign_stack
[
-
1
]
==
'"'
:
sign_stack
.
pop
()
elif
text
[
index
]
==
'"'
:
sign_stack
.
append
(
'"'
)
elif
text
[
index
]
==
'}'
and
sign_stack
[
-
1
]
==
'${'
:
sign_stack
.
pop
()
elif
text
[
index
-
1
:
index
+
1
]
==
'${'
:
sign_stack
.
append
(
'${'
)
index
+=
1
# 得到完整字符串
string
=
text
[
start
:
index
]
last_string
=
string
# 参数
params
=
[]
result
=
string
# 处理字符串拼接
if
'$'
in
string
:
count
=
0
last
=
-
1
res
=
[]
for
i
in
range
(
len
(
string
)):
if
last
==
-
1
and
string
[
i
]
==
'$'
:
if
count
==
0
:
last
=
i
elif
last
!=
-
1
:
if
string
[
i
]
==
'{'
:
count
+=
1
elif
string
[
i
]
==
'}'
:
count
-=
1
if
count
==
0
:
res
.
append
((
last
,
i
+
1
))
last
=
-
1
elif
count
==
0
:
last
=
-
1
for
i
in
re
.
findall
(
'
\\
$
\\
w*'
,
string
):
if
i
==
'$'
:
continue
find
=
string
.
find
(
i
)
res
.
append
((
find
,
find
+
len
(
i
)))
res
=
sorted
(
res
,
key
=
lambda
l
:
l
[
0
])
last_res
=
None
for
i
in
res
:
if
last_res
is
not
None
and
i
[
0
]
<
last_res
[
1
]:
continue
params
.
append
(
string
[
i
[
0
]:
i
[
1
]])
last_res
=
i
for
i
in
params
:
result
=
result
.
replace
(
i
,
"[str]"
)
for
i
in
range
(
len
(
params
)):
if
params
[
i
][
1
]
==
'{'
:
params
[
i
]
=
params
[
i
][
2
:
-
1
]
else
:
params
[
i
]
=
params
[
i
][
1
:]
# 每个参数加上 toString
params
[
i
]
=
'('
+
params
[
i
]
+
').toString()'
# 拼接部分替换为 %s
result
=
result
[
1
:
-
1
]
.
replace
(
'
%
'
,
'
%%
'
)
.
replace
(
'
\\\\
'
,
'
\\
'
)
.
replace
(
'[str]'
,
'
%
s'
)
# aesKey 密钥不加密
if
result
==
aesKey
:
continue
result_text
=
result_text
.
replace
(
text
[
start
:
index
],
'R.string.'
+
string_mapping
[
result
]
+
'.string('
+
', '
.
join
(
params
)
+
')'
)
# 添加 Int.string() 方法引用
if
class_path
:
if
len
(
re
.
findall
(
'import '
+
class_path
,
text
))
==
0
:
result_text
=
re
.
sub
(
'(package
\\
S+?
\\
s+?)(?=
\\
S)'
,
'
\\
g<1>import '
+
class_path
+
'
\n
'
,
result_text
,
flags
=
re
.
S
)
# 添加资源 R 引用
if
len
(
re
.
findall
(
'import '
+
applicationId
+
'.R'
,
text
))
==
0
:
result_text
=
re
.
sub
(
'(package
\\
S+?
\\
s+?)(?=
\\
S)'
,
'
\\
g<1>import '
+
applicationId
+
'.R'
+
'
\n
'
,
result_text
,
flags
=
re
.
S
)
# 去除 const
result_text
=
re
.
sub
(
'const (val.*?R
\\
.string
\\
.
\\
S+?
\\
.string
\\
(
\\
))'
,
'
\\
g<1>'
,
result_text
)
with
open
(
path
,
'w'
,
encoding
=
'utf-8'
)
as
f
:
f
.
write
(
result_text
)
def
check_xml_string_mapping
():
try
:
loads
=
json
.
load
(
open
(
'mapping.json'
,
'r'
,
encoding
=
'utf-8'
))
except
(
ValueError
,
IOError
):
loads
=
{}
old_mapping
=
loads
.
get
(
'xml_string'
,
{})
strings
=
find_text
(
'android:text="(?<!@string/)([^@"]+?)"'
,
get_path
(
'.
\\
src
\\
main
\\
res
\\
layout'
),
skip_name
=
[
'notify'
,
'notity'
])
mapping
=
{}
for
i
in
strings
:
value
=
old_mapping
.
get
(
i
)
if
value
is
not
None
:
mapping
[
i
]
=
value
continue
# 添加 '_D' 结尾,资源混淆时过滤不用再次改名
mapping
[
i
]
=
get_random_string
(
5
,
False
)
+
'_D'
loads
[
'xml_string'
]
=
mapping
json
.
dump
(
loads
,
open
(
'mapping.json'
,
'w'
,
encoding
=
'utf-8'
),
indent
=
4
)
return
mapping
def
deal_xml_string
():
# 获取映射
string_mapping
=
check_xml_string_mapping
()
print
(
string_mapping
)
with
open
(
get_path
(
'.
\\
src
\\
main
\\
res
\\
values
\\
strings.xml'
),
'r'
,
encoding
=
'utf-8'
)
as
f
:
text
=
f
.
read
()
rfind
=
text
.
rfind
(
'
\n
'
)
text_result
=
text
[:
rfind
]
for
i
in
string_mapping
:
string
=
i
string
=
string
.
replace
(
'&'
,
'&'
)
string
=
string
.
replace
(
'?'
,
'
\\
?'
)
string
=
string
.
replace
(
'
\'
'
,
'
\\\'
'
)
text_result
+=
'
\n
<string name="'
+
string_mapping
[
i
]
+
'" translatable="false">'
+
string
+
'</string>'
text_result
+=
text
[
rfind
:]
with
open
(
get_path
(
'.
\\
src
\\
main
\\
res
\\
values
\\
strings.xml'
),
'w'
,
encoding
=
'utf-8'
)
as
f
:
f
.
write
(
text_result
)
sub_map
=
{}
for
i
in
string_mapping
:
sub_map
[
'(?<=android:text=")'
+
re
.
escape
(
i
)
+
'(?=")'
]
=
'@string/'
+
re
.
escape
(
string_mapping
[
i
])
# 替换时跳过通知布局
sub_map_text
(
sub_map
,
path
=
get_path
(
'.
\\
src
\\
main
\\
res
\\
layout'
),
skip_name
=
[
'notify'
,
'notity'
])
def
deal_code_string
():
# 处理布局文件中的明文字符串
deal_xml_string
()
# 处理代码文件中的明文字符串
deal_class_string
()
def
deal_res
():
# 添加字符串为 string 资源
deal_code_string
()
# 替换 TextView 为 AESTextView
aes_text_view
=
get_class_path
(
find_file
(
'class AESTextView'
,
get_path
(
'.
\\
src
\\
main
\\
java'
)))
sub_map
=
{
'(?<=<)TextView'
:
aes_text_view
,
'(?<=<)com.noober.background.view.BLTextView'
:
aes_text_view
}
sub_map_text
(
sub_map
,
path
=
get_path
(
'.
\\
src
\\
main
\\
res
\\
layout'
),
skip_name
=
[
'notify'
,
'notity'
])
# 加密 string
strings_mapping
=
check_strings_mapping
()
print
(
strings_mapping
)
sub_map
=
{}
for
i
in
strings_mapping
:
sub_map
[
'<string(.*?)>'
+
re
.
escape
(
i
)
+
'</string>'
]
=
\
'<string
\\
g<1>>'
+
re
.
escape
(
strings_mapping
[
i
])
+
'</string>'
sub_map_text
(
sub_map
,
path
=
get_path
(
'.
\\
src
\\
main
\\
res
\\
values'
))
# 改 string id
deal_ids_type
(
'string'
)
# 改 color id
deal_ids_type
(
'color'
)
# 改 dimen id
deal_ids_type
(
'dimen'
)
# 改 style id
deal_ids_type
(
'style'
)
# 改 declare-styleable
styleable_mapping
=
check_styleable_mapping
()
print
(
styleable_mapping
)
sub_map
=
{}
styleables
=
find_text
(
'<declare-styleable name=".*?">[
\\
s
\\
S]*?</declare-styleable>'
)
for
i
in
styleables
:
result
=
i
styleable_id
=
re
.
findall
(
'<declare-styleable name="(.*?)">'
,
i
)[
0
]
result
=
result
.
replace
(
'<declare-styleable name="'
+
styleable_id
+
'">'
,
'<declare-styleable name="'
+
styleable_mapping
[
styleable_id
]
+
'">'
)
sub_map
[
'R
\\
.styleable
\\
.'
+
styleable_id
+
'(
\\
W)'
]
=
\
'R.styleable.'
+
styleable_mapping
[
styleable_id
]
+
'
\\
g<1>'
styleables_attr
=
re
.
findall
(
'<attr name="(.*?)".*?/>'
,
i
)
for
attr
in
styleables_attr
:
result
=
result
.
replace
(
'<attr name="'
+
attr
+
'"'
,
'<attr name="'
+
styleable_mapping
[
attr
+
'_A'
]
+
'"'
)
sub_map
[
'R
\\
.styleable
\\
.'
+
styleable_id
+
'_'
+
attr
+
'(
\\
W)'
]
=
\
'R.styleable.'
+
styleable_mapping
[
styleable_id
]
+
'_'
+
styleable_mapping
[
attr
+
'_A'
]
+
'
\\
g<1>'
sub_map
[
'app:'
+
attr
+
'='
]
=
'app:'
+
styleable_mapping
[
attr
+
'_A'
]
+
'='
sub_map
[
re
.
escape
(
i
)]
=
result
sub_map_text
(
sub_map
)
# 改 view id
view_ids
=
find_text
(
'"
\\
@
\\
+id/(.*?)"'
,
get_path
(
'.
\\
src
\\
main
\\
res'
))
view_ids_mapping
=
check_view_ids_mapping
()
print
(
view_ids_mapping
)
sub_map
=
{}
for
i
in
view_ids
:
if
i
==
'root'
:
continue
key
=
get_title
(
i
)
sub_map
[
'(>|")@(
\\
+)?id/'
+
i
+
'(<|")'
]
=
'
\\
g<1>@
\\
g<2>id/'
+
view_ids_mapping
[
key
]
+
'
\\
g<3>'
sub_map
[
'R
\\
.id
\\
.'
+
i
+
'(
\\
W)'
]
=
'R.id.'
+
view_ids_mapping
[
key
]
+
'
\\
g<1>'
sub_map
[
'([bB]inding
\\
??(?:
\\
.
\\
w+)?
\\
??)
\\
.'
+
key
+
'(
\\
W)'
]
=
'
\\
g<1>.'
+
view_ids_mapping
[
key
]
+
'
\\
g<2>'
sub_map
[
'(?<=app:constraint_referenced_ids=".*?)'
+
i
+
'(?=.*?")'
]
=
view_ids_mapping
[
key
]
sub_map_text
(
sub_map
)
# 改 layout 文件名
layout_mapping
=
check_layout_mapping
()
print
(
layout_mapping
)
layout_path
=
get_path
(
'.
\\
src
\\
main
\\
res
\\
layout'
)
listdir
=
os
.
listdir
(
layout_path
)
for
i
in
listdir
:
name
=
i
[:
i
.
rfind
(
'.'
)]
if
layout_mapping
.
get
(
name
)
is
None
:
continue
path_join
=
os
.
path
.
join
(
layout_path
,
i
)
shutil
.
move
(
path_join
,
path_join
.
replace
(
name
,
layout_mapping
[
name
]))
sub_map
=
{}
for
i
in
layout_mapping
:
sub_map
[
'R
\\
.layout
\\
.'
+
i
+
'(
\\
W)'
]
=
'R.layout.'
+
layout_mapping
[
i
]
+
'
\\
g<1>'
# ViewBinding 同步修改
sub_map
[
get_title
(
i
,
True
)
+
'Binding'
]
=
get_title
(
layout_mapping
[
i
],
True
)
+
'Binding'
sub_map
[
'(>|")@layout/'
+
i
+
'(<|")'
]
=
'
\\
g<1>@layout/'
+
layout_mapping
[
i
]
+
'
\\
g<2>'
sub_map_text
(
sub_map
)
# 改 drawable 文件名
deal_res_type
(
'drawable'
)
# 改 mipmap 文件名
deal_res_type
(
'mipmap'
)
# 改 raw 文件名
deal_res_type
(
'raw'
)
# 改 raw 文件名
deal_res_type
(
'xml'
)
# 改图片内容
deal_image
()
def
check_activity_mapping
():
try
:
loads
=
json
.
load
(
open
(
'mapping.json'
,
'r'
,
encoding
=
'utf-8'
))
except
(
ValueError
,
IOError
):
loads
=
{}
old_list
=
loads
.
get
(
'activity'
,
[])
old_paths
=
[]
for
i
in
old_list
:
old_paths
.
append
(
i
[:
i
.
rfind
(
'.'
)])
old_paths
=
sorted
(
set
(
old_paths
),
key
=
old_paths
.
index
)
old_paths
.
sort
(
key
=
len
)
classes
=
get_classes
()
paths
=
[]
root_path
=
get_path
(
'.
\\
src
\\
main
\\
java'
)
for
i
in
classes
:
paths
.
append
(
i
[
len
(
root_path
)
+
1
:
i
.
rfind
(
os
.
sep
)]
.
replace
(
os
.
sep
,
'.'
))
paths
=
sorted
(
set
(
paths
),
key
=
paths
.
index
)
paths
.
sort
(
key
=
len
)
new_list
=
[]
for
i
in
old_list
:
if
i
[:
i
.
rfind
(
'.'
)]
in
paths
:
new_list
.
append
(
i
)
for
i
in
paths
:
if
i
in
old_paths
:
continue
# 每个路径下产生随机个垃圾类
for
_
in
range
(
random
.
randint
(
0
,
3
)):
name
=
get_title
(
get_random_string
(
4
),
True
)
+
'_D'
new_list
.
append
(
i
+
'.'
+
name
)
loads
[
"activity"
]
=
new_list
json
.
dump
(
loads
,
open
(
'mapping.json'
,
'w'
,
encoding
=
'utf-8'
),
indent
=
4
)
return
new_list
def
add_junk_activity
():
root_path
=
get_path
(
'.
\\
src
\\
main
\\
java'
)
new_list
=
check_activity_mapping
()
count
=
len
(
new_list
)
random
.
shuffle
(
new_list
)
for
i
in
range
(
count
):
class_path
=
get_path
(
root_path
+
'
\\
'
+
new_list
[
i
]
.
replace
(
'.'
,
'
\\
'
)
+
'.kt'
)
# 获取垃圾类代码
code
=
get_random_activity_code
(
new_list
[
i
],
new_list
[(
i
+
1
)
%
count
])
with
open
(
class_path
,
'w'
,
encoding
=
'utf-8'
)
as
f
:
f
.
write
(
code
)
print
(
class_path
)
with
open
(
get_path
(
'.
\\
src
\\
main
\\
AndroidManifest.xml'
),
'r'
,
encoding
=
'utf-8'
)
as
f
:
text
=
f
.
read
()
replace_string
=
'
\n
'
for
i
in
new_list
:
replace_string
+=
' <activity android:name="'
+
i
+
'" />
\n
'
text
=
text
.
replace
(
' </application>'
,
replace_string
+
''' </application>'''
)
with
open
(
get_path
(
'.
\\
src
\\
main
\\
AndroidManifest.xml'
),
'w'
,
encoding
=
'utf-8'
)
as
f
:
f
.
write
(
text
)
def
get_random_view
():
return
random
.
choice
(
[
'TextView'
,
'Button'
,
'EditText'
,
'ImageView'
,
'FrameLayout'
,
'LinearLayout'
,
'CalendarView'
,
'CheckBox'
,
'CheckedTextView'
,
'DatePicker'
,
'ExpandableListView'
,
'GridLayout'
,
'GridView'
,
'HorizontalScrollView'
,
'ImageButton'
,
'ListView'
,
'RelativeLayout'
,
'ScrollView'
,
'SearchView'
,
'SeekBar'
,
'TableLayout'
])
def
get_random_activity_code
(
class1
,
class2
):
# 代码中,class1 跳转 class2,确保垃圾类被引用到
package1
=
class1
[:
class1
.
rfind
(
'.'
)]
name1
=
class1
[
len
(
package1
)
+
1
:]
package2
=
class2
[:
class2
.
rfind
(
'.'
)]
name2
=
class2
[
len
(
package2
)
+
1
:]
view
=
get_random_view
()
if
package1
==
package2
:
import_code
=
''
else
:
import_code
=
'
\n
import '
+
class2
code
=
'''package '''
+
package1
+
'''
import android.content.Intent
import android.os.Bundle
import android.widget.'''
+
view
+
'''
import androidx.appcompat.app.AppCompatActivity'''
+
import_code
+
'''
class '''
+
name1
+
''' : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView('''
+
view
+
'''(this))
startActivity(Intent(this, '''
+
name2
+
'''::class.java))
}
}'''
return
code
def
add_junk_method
():
classes
=
get_classes
([
'kt'
])
for
path
in
classes
:
with
open
(
path
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
text
=
f
.
read
()
if
text
.
find
(
'data class'
)
!=
-
1
:
continue
text
=
re
.
sub
(
'@SuppressLint.*?
\n
'
,
'
\n
'
,
text
)
text
=
re
.
sub
(
'//[^"]*?(("[^"]*?){2})*?
\n
'
,
'
\n
'
,
text
)
text
=
re
.
sub
(
' +
\n
'
,
'
\n
'
,
text
)
text
=
re
.
sub
(
'=
\\
s+'
,
'= '
,
text
)
text
=
re
.
sub
(
':
\\
s+'
,
': '
,
text
)
text
=
re
.
sub
(
',
\\
s+'
,
', '
,
text
)
text
=
re
.
sub
(
'/
\\
*[
\\
s
\\
S]*?
\\
*/'
,
''
,
text
)
text
=
re
.
sub
(
'
\n
{2,}'
,
'
\n\n
'
,
text
)
result_text
=
text
interfaces
=
re
.
findall
(
'interface .*?{.*?}'
,
text
,
flags
=
re
.
S
)
for
interface
in
interfaces
:
start
=
text
.
find
(
interface
)
start
=
text
[:
start
]
.
rfind
(
'
\n
'
)
+
1
if
start
==
-
1
:
continue
index
=
start
count
=
0
isStart
=
False
while
(
not
isStart
or
count
>
0
)
and
index
<
len
(
text
):
if
text
[
index
]
==
'{'
:
count
+=
1
if
count
==
1
:
isStart
=
True
elif
text
[
index
]
==
'}'
:
count
-=
1
index
+=
1
# 过滤接口及其内容
text
=
text
.
replace
(
text
[
start
:
index
],
''
)
functions
=
re
.
findall
(
'fun (?!interface ).*?
\\
(.*?
\\
)'
,
text
,
flags
=
re
.
S
)
for
function
in
functions
:
start
=
text
.
find
(
function
)
start
=
text
[:
start
]
.
rfind
(
'
\n
'
)
+
1
if
start
==
-
1
:
continue
index
=
start
count
=
0
isStart
=
False
while
(
not
isStart
or
count
>
0
)
and
index
<
len
(
text
):
if
text
[
index
]
==
'('
:
count
+=
1
if
count
==
1
:
isStart
=
True
elif
text
[
index
]
==
')'
:
count
-=
1
index
+=
1
if
'abstract'
in
text
[
start
:
index
]:
continue
count
=
0
isStart
=
False
param_end
=
index
while
(
not
isStart
or
count
>
0
)
and
index
<
len
(
text
):
if
not
isStart
and
text
[
index
]
==
'='
:
break
if
text
[
index
]
==
'{'
:
count
+=
1
if
count
==
1
:
isStart
=
True
param_end
=
index
elif
text
[
index
]
==
'}'
:
count
-=
1
index
+=
1
if
not
isStart
:
continue
fun_text
=
text
[
start
:
index
]
header
=
text
[
start
:
param_end
]
param_start
=
start
+
header
.
find
(
'('
)
context
=
re
.
search
(
'fun (.*?
\\
.)?
\\
w*?'
,
text
[
start
:
param_start
])[
1
]
if
context
is
None
:
context
=
''
param_string
=
text
[
param_start
:
param_end
]
if
'override fun '
in
header
and
'
\n
'
+
\
re
.
sub
(
'(final )?override fun '
,
'super.'
,
header
[:
header
.
index
(
param_string
)])
in
fun_text
:
methods
=
[]
for
i
in
range
(
random
.
randint
(
0
,
5
)):
result
=
add_one_method
(
fun_text
,
param_string
,
header
,
context
)
if
result
is
None
or
len
(
result
)
!=
3
:
continue
fun_text
,
method_text1
,
method_text2
=
result
methods
.
insert
(
0
,
method_text2
)
methods
.
insert
(
0
,
method_text1
)
methods
.
insert
(
0
,
fun_text
)
fun_text
=
'
\n\n
'
.
join
(
methods
)
else
:
methods
=
[]
for
i
in
range
(
random
.
randint
(
0
,
5
)):
result
=
add_one_method
(
fun_text
,
param_string
,
header
,
context
)
if
result
is
None
or
len
(
result
)
!=
2
:
continue
fun_text
,
method_text
=
result
methods
.
insert
(
0
,
method_text
)
methods
.
insert
(
0
,
fun_text
)
fun_text
=
'
\n\n
'
.
join
(
methods
)
result_text
=
result_text
.
replace
(
text
[
start
:
index
],
fun_text
)
with
open
(
path
,
'w'
,
encoding
=
'utf-8'
)
as
f
:
f
.
write
(
result_text
)
def
add_one_method
(
fun_text
,
param_string
,
header
,
context
):
if
'suspend '
in
header
:
suspend
=
'suspend '
else
:
suspend
=
''
body
=
fun_text
[
len
(
header
):]
intent
=
len
(
fun_text
)
-
len
(
fun_text
.
lstrip
())
param
=
param_string
[
1
:
param_string
.
rfind
(
')'
)]
param
=
re
.
sub
(
'<.*?>'
,
''
,
param
)
param
=
re
.
sub
(
'
\\
([^(]*?
\\
)'
,
'()'
,
param
)
param
=
[
i
.
strip
()
.
split
(
':'
)[
0
]
for
i
in
param
.
split
(
','
)]
for
i
in
range
(
len
(
param
)):
if
param
[
i
]
.
startswith
(
'vararg'
):
param
[
i
]
=
'*'
+
param
[
i
]
.
split
(
' '
)[
-
1
]
elif
param
[
i
]
.
startswith
(
'@'
):
param
[
i
]
=
param
[
i
]
.
split
(
' '
)[
-
1
]
if
'override fun '
in
header
and
'
\n
'
+
\
re
.
sub
(
'(final )?override fun '
,
'super.'
,
header
[:
header
.
index
(
param_string
)])
in
fun_text
:
if
':'
in
param_string
[
param_string
.
rfind
(
')'
):]:
return
method_split
=
[
i
.
rstrip
()
for
i
in
fun_text
.
split
(
'
\n
'
)]
if
method_split
[
0
]
.
rstrip
()[
-
1
]
!=
'{'
or
method_split
[
-
1
]
.
lstrip
()[
0
]
!=
'}'
:
return
method_body
=
method_split
[
1
:
-
1
]
super_index
=
-
1
for
i
in
range
(
len
(
method_body
)):
if
'super.'
in
method_body
[
i
]:
if
super_index
>=
0
:
super_index
=
-
1
break
super_index
=
i
if
super_index
<
0
:
return
method_text1
=
method_split
.
copy
()
method_name1
=
get_random_string
(
is_ascii
=
False
)
method_text1
[
0
]
=
method_text1
[
0
]
.
replace
(
header
,
' '
*
intent
+
'private '
+
suspend
+
'fun '
+
context
+
method_name1
+
param_string
)
method_text1
[
1
:
-
1
]
=
method_body
[:
super_index
]
method_text2
=
method_split
.
copy
()
method_name2
=
get_random_string
(
is_ascii
=
False
)
method_text2
[
0
]
=
method_text2
[
0
]
.
replace
(
header
,
' '
*
intent
+
'private '
+
suspend
+
'fun '
+
context
+
method_name2
+
param_string
)
method_text2
[
1
:
-
1
]
=
method_body
[
super_index
+
1
:]
method_body
[
super_index
+
1
:]
=
[
' '
*
(
intent
+
4
)
+
method_name2
+
'('
+
', '
.
join
(
param
)
+
')'
]
method_body
[:
super_index
]
=
[
' '
*
(
intent
+
4
)
+
method_name1
+
'('
+
', '
.
join
(
param
)
+
')'
]
method_split
[
1
:
-
1
]
=
method_body
method_text1
=
'
\n
'
.
join
(
method_text1
)
method_text2
=
'
\n
'
.
join
(
method_text2
)
fun_text
=
'
\n
'
.
join
(
method_split
)
return
fun_text
,
method_text1
,
method_text2
else
:
method_name
=
get_random_string
(
is_ascii
=
False
)
method_text
=
fun_text
if
':'
in
param_string
[
param_string
.
rfind
(
')'
):]:
method_text
=
method_text
.
replace
(
header
,
' '
*
intent
+
'private '
+
suspend
+
'fun '
+
context
+
method_name
+
param_string
)
fun_text
=
fun_text
.
replace
(
body
,
'{
\n
'
+
' '
*
(
intent
+
4
)
+
'return '
+
method_name
+
'('
+
', '
.
join
(
param
)
+
')
\n
'
+
' '
*
intent
+
'}'
)
else
:
method_text
=
method_text
.
replace
(
header
,
' '
*
intent
+
'private '
+
suspend
+
'fun '
+
context
+
method_name
+
param_string
)
fun_text
=
fun_text
.
replace
(
body
,
'{
\n
'
+
' '
*
(
intent
+
4
)
+
method_name
+
'('
+
', '
.
join
(
param
)
+
')
\n
'
+
' '
*
intent
+
'}'
)
return
fun_text
,
method_text
def
add_junk_code
():
classes
=
get_classes
([
'kt'
])
for
path
in
classes
:
with
open
(
path
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
text
=
f
.
read
()
if
text
.
find
(
'data class'
)
!=
-
1
:
continue
text
=
re
.
sub
(
'@SuppressLint.*?
\n
'
,
'
\n
'
,
text
)
text
=
re
.
sub
(
'//[^"]*?(("[^"]*?){2})*?
\n
'
,
'
\n
'
,
text
)
text
=
re
.
sub
(
' +
\n
'
,
'
\n
'
,
text
)
text
=
re
.
sub
(
'=
\\
s+'
,
'= '
,
text
)
text
=
re
.
sub
(
':
\\
s+'
,
': '
,
text
)
text
=
re
.
sub
(
',
\\
s+'
,
', '
,
text
)
text
=
re
.
sub
(
'/
\\
*[
\\
s
\\
S]*?
\\
*/'
,
''
,
text
)
text
=
re
.
sub
(
'
\n
{2,}'
,
'
\n\n
'
,
text
)
functions
=
re
.
findall
(
'((?=fun .*?
\\
([^}]*?
\\
)|init |val.*?by lazy)[^}]*?
\\
{)'
,
text
)
result_text
=
text
for
function
in
functions
:
start
=
text
.
find
(
function
)
start
=
text
[:
start
]
.
rfind
(
'
\n
'
)
+
1
if
start
==
-
1
:
continue
index
=
start
count
=
0
isStart
=
False
while
(
not
isStart
or
count
>
0
)
and
index
<
len
(
text
):
if
text
[
index
]
==
'('
:
count
+=
1
if
count
==
1
:
isStart
=
True
elif
text
[
index
]
==
')'
:
count
-=
1
if
not
isStart
and
text
[
index
]
==
'{'
:
break
index
+=
1
count
=
0
isStart
=
False
while
(
not
isStart
or
count
>
0
)
and
index
<
len
(
text
):
if
text
[
index
]
==
'{'
:
count
+=
1
if
count
==
1
:
isStart
=
True
elif
text
[
index
]
==
'}'
:
count
-=
1
index
+=
1
fun_text
=
text
[
start
:
index
]
fun_text
=
fun_text
.
split
(
'
\n
'
)
intent_stack
=
[]
last_intent
=
0
log_indexes
=
[]
skip_text
=
[
False
for
_
in
fun_text
]
i
=
0
while
i
<
len
(
fun_text
):
if
'object : '
in
fun_text
[
i
]
and
fun_text
[
i
]
.
rstrip
()
.
endswith
(
'{'
):
intent
=
len
(
fun_text
[
i
])
-
len
(
fun_text
[
i
]
.
lstrip
())
while
i
<
len
(
fun_text
)
-
1
:
i
+=
1
skip_text
[
i
]
=
True
if
fun_text
[
i
]
.
lstrip
()
.
startswith
(
'}'
)
and
\
len
(
fun_text
[
i
])
-
len
(
fun_text
[
i
]
.
lstrip
())
==
intent
:
break
i
+=
1
for
i
in
range
(
len
(
fun_text
)):
if
skip_text
[
i
]:
continue
intent
=
len
(
fun_text
[
i
])
-
len
(
fun_text
[
i
]
.
lstrip
())
if
intent
==
0
or
intent
%
4
!=
0
:
continue
if
intent
>
last_intent
and
i
>
0
:
j
=
i
-
1
while
len
(
fun_text
[
j
])
-
len
(
fun_text
[
j
]
.
lstrip
())
==
0
and
j
>=
0
:
j
-=
1
if
j
>=
0
:
for
k
in
range
(
int
((
intent
-
last_intent
)
/
4
)):
intent_stack
.
append
(
j
)
elif
intent
<
last_intent
:
for
k
in
range
(
int
((
last_intent
-
intent
)
/
4
)):
intent_stack
.
pop
()
if
len
(
intent_stack
)
>
0
and
intent
>=
last_intent
\
and
len
(
fun_text
[
i
]
.
strip
())
!=
0
and
fun_text
[
i
]
.
lstrip
()[
0
]
!=
')'
:
last_text
=
fun_text
[
intent_stack
[
-
1
]]
if
last_text
[
-
1
]
!=
'{'
:
continue
if
last_text
.
lstrip
()[
0
]
==
')'
:
last_text_intent
=
len
(
last_text
)
-
len
(
last_text
.
lstrip
())
j
=
intent_stack
[
-
1
]
-
1
while
j
>=
0
:
temp_text
=
fun_text
[
j
]
if
len
(
temp_text
)
-
len
(
temp_text
.
lstrip
())
==
last_text_intent
:
break
j
-=
1
if
j
>=
0
:
last_text
=
fun_text
[
j
]
+
last_text
.
strip
()
if
'when'
not
in
last_text
and
'$'
not
in
last_text
and
\
'object'
not
in
last_text
and
'class '
not
in
last_text
and
'interface '
not
in
last_text
:
log_indexes
.
append
((
i
,
intent
))
last_intent
=
intent
log_indexes
.
reverse
()
for
i
in
log_indexes
:
if
random
.
random
()
>
0.35
:
continue
junk_code
=
get_random_junk_code
()
junk_code
=
junk_code
.
replace
(
'
\n
'
,
'
\n
'
+
' '
*
i
[
1
])[
1
:]
fun_text
.
insert
(
i
[
0
],
junk_code
)
result_text
=
result_text
.
replace
(
text
[
start
:
index
],
'
\n
'
.
join
(
fun_text
))
with
open
(
path
,
'w'
,
encoding
=
'utf-8'
)
as
f
:
f
.
write
(
result_text
)
add_import
(
'android.util.Log'
,
classes
)
def
get_random_junk_code
():
junk_code
=
random
.
choice
(
junk_codes
)
count
=
1
while
True
:
random_str
=
get_random_string
(
is_ascii
=
False
)
replace
=
junk_code
.
replace
(
'[str'
+
str
(
count
)
+
']'
,
random_str
)
if
junk_code
==
replace
:
break
junk_code
=
replace
count
+=
1
count
=
1
while
True
:
random_int
=
get_random_int
()
replace
=
junk_code
.
replace
(
'[int'
+
str
(
count
)
+
']'
,
str
(
random_int
))
if
junk_code
==
replace
:
break
junk_code
=
replace
count
+=
1
return
junk_code
junk_codes
=
[
'''
if (System.currentTimeMillis() < [int1]) {
println(System.currentTimeMillis())
}'''
,
'''
Log.d("[str1]", "[str1]")'''
,
'''
val [str1] = [int1]..[int1] + 10
println([str1].random())'''
,
'''
val [str1]: (Int, Int) -> Int = { [str2], [str3] -> [str2] + [str3] }
println([str1].invoke([int1], [int2]))'''
,
'''
class [str1](val [str2]: String, val [str3]: Int)
println([str1]("[str4]", [int1]))'''
,
'''
open class [str1] {
open fun [str2]() {}
}
class [str3] : [str1]() {
override fun [str2]() {
println("[str5]")
}
}
val [str4] = [str3]()
println([str4])'''
,
'''
fun String.[str1](): Boolean {
return this == this.reversed()
}
val [str2] = "[str4]"
val [str3] = [str2].[str1]()
println([str3])'''
,
'''
fun [str1]([str2]: Int, [str3]: Int): Int {
return [str2] + [str3]
}
println([str1]([int1], [int2]))'''
,
'''
val [str1] = { [str2]: String -> println([str2]) }
[str1]("[str3]!")'''
,
'''
fun [str1]([str2]: String) {
println("tag, $[str2]!")
}
[str1]("[str3]")'''
,
'''
fun [str1]() {
fun [str2]([str3]: Int) {
println([str3])
}
[str2]([int1])
[str2]([int2])
[str2]([int3])
}
[str1]()'''
,
'''
class [str1] {
inner class [str2] {
fun [str3]() {
println("[str5]")
}
}
}
val [str4] = [str1]().[str2]()
[str4].[str3]()'''
,
'''
class [str1] {
fun [str2]() {
println("[str3]")
}
}
[str1]().[str2]()'''
,
'''
abstract class [str1] {
abstract fun [str2]()
}
class [str3] : [str1]() {
override fun [str2]() {
println("[str5]")
}
}
val [str4] = [str3]()
[str4].[str2]()'''
,
'''
class [str1]<T>(val [str2]: T)
val [str3] = [str1]([int1])
val [str4] = [str1]("[str5]")
println([str3])
println([str4])'''
,
'''
fun <T> [str1]([str2]: T) {
println([str2])
}
[str1]([int1])
[str1]("[str3]")'''
,
'''
class [str1]<T, K>(val [str3]: T, val [str4]: K) {
init {
println("[str5]")
}
}
val [str2] = [str1]("[str6]", [int1])
println([str2])'''
,
'''
class [str1]<T>(val [str2]: T, val [str3]: Int) {
constructor([str4]: T) : this([str4], [int1]) {
println("[str5]")
}
}
println([str1]("[str6]"))'''
,
'''
val [str1] = [int1]
val [str2] = [int2]
val [str3] = [str1] * [str2] * [str2]
println([str3])'''
,
'''
fun [str1]([str3]: Int, [str4]: Int): Int {
return [str3] + [str4]
}
val [str2] = [str1]([int1], [int2])
println([str2])'''
,
'''
fun [str1]([str4]: Int, [str5]: Int): Int {
fun [str2]([str6]: Int, [str7]: Int): Int {
return [str6] + [str7]
}
return [str2]([str4], [str5])
}
val [str3] = [str1]([int1], [int2])
println([str3])'''
,
'''
class [str1] {
val [str2] by lazy {
println("[str4]")
"[str5]!"
}
}
val [str3] = [str1]()
println([str3].[str2])'''
,
'''
class [str1]<T>([str3]: T) {
init {
println("[str4]: $[str3]")
}
}
println([str1]("[str2]"))'''
,
'''
class [str1]<T>(val [str3]: T, val [str4]: Int) {
constructor([str3]: T) : this([str3], [int1]) {
println("[str4]")
}
}
println([str1]("[str2]"))'''
,
'''
class [str1]<T>(val [str4]: T)
val [str2] = [str1]([int1])
val [str3] = [str1]("[str5]")
println([str2].[str4])
println([str3].[str4])'''
]
def
class_disorder
():
classes
=
get_classes
([
'kt'
])
for
path
in
classes
:
with
open
(
path
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
text
=
f
.
read
()
if
text
.
find
(
'data class'
)
!=
-
1
:
continue
text
=
re
.
sub
(
'@SuppressLint.*?
\n
'
,
'
\n
'
,
text
)
text
=
re
.
sub
(
'//[^"]*?(("[^"]*?){2})*?
\n
'
,
'
\n
'
,
text
)
text
=
re
.
sub
(
' +
\n
'
,
'
\n
'
,
text
)
text
=
re
.
sub
(
'=
\\
s+'
,
'= '
,
text
)
text
=
re
.
sub
(
':
\\
s+'
,
': '
,
text
)
text
=
re
.
sub
(
',
\\
s+'
,
', '
,
text
)
text
=
re
.
sub
(
'/
\\
*[
\\
s
\\
S]*?
\\
*/'
,
''
,
text
)
text
=
re
.
sub
(
'
\n
{2,}'
,
'
\n\n
'
,
text
)
lines
=
text
.
split
(
'
\n
'
)
count
=
0
begin
=
0
result
=
[]
start
=
-
1
end
=
0
for
index
in
range
(
len
(
lines
)):
if
len
(
lines
[
index
]
.
strip
())
==
0
:
continue
if
start
==
-
1
:
if
lines
[
index
][
-
1
]
==
'{'
:
start
=
index
count
+=
1
continue
for
char
in
lines
[
index
]:
if
char
in
[
'{'
,
'('
]:
count
+=
1
elif
char
in
[
'}'
,
')'
]:
if
count
==
1
:
end
=
index
count
-=
1
if
count
==
1
:
if
lines
[
index
][
-
1
]
in
[
'}'
,
')'
]
and
begin
!=
0
:
if
'get()'
in
lines
[
begin
]
or
'set(value)'
in
lines
[
begin
]:
for
i
in
range
(
len
(
result
)):
if
result
[
i
][
1
]
==
begin
:
result
[
i
]
=
(
result
[
i
][
0
],
index
+
1
)
break
else
:
result
.
append
((
begin
,
index
+
1
))
begin
=
0
elif
lines
[
index
][
-
1
]
not
in
[
'{'
,
'('
]:
strip
=
lines
[
index
]
.
lstrip
()
if
strip
[
0
]
==
'.'
or
strip
.
startswith
(
'get() ='
)
or
strip
.
startswith
(
'set(value) = '
):
for
i
in
range
(
len
(
result
)):
if
result
[
i
][
1
]
==
index
:
result
[
i
]
=
(
result
[
i
][
0
],
index
+
1
)
break
else
:
result
.
append
((
index
,
index
+
1
))
elif
count
==
2
and
(
lines
[
index
][
-
1
]
in
[
'{'
,
'('
]
or
lines
[
index
]
.
endswith
(
'->'
))
\
and
lines
[
begin
][
-
1
]
not
in
[
'{'
,
'('
]:
begin
=
index
result_temp
=
[]
i
=
0
while
i
<
len
(
result
):
begin
=
result
[
i
][
0
]
while
lines
[
result
[
i
][
0
]]
.
lstrip
()
.
startswith
(
'@'
):
i
+=
1
result_temp
.
append
([
begin
,
result
[
i
][
1
]])
i
+=
1
result
=
result_temp
random
.
shuffle
(
result
)
result_sort
=
result
.
copy
()
var_weight
=
{}
for
i
in
re
.
findall
(
'va[lr] (
\\
w+)'
,
text
):
var_weight
[
i
]
=
len
(
re
.
findall
(
'
\\
W'
+
re
.
escape
(
i
)
+
'
\\
W'
,
text
))
for
var
in
sorted
(
var_weight
,
key
=
lambda
k
:
var_weight
[
k
]):
for
i
in
range
(
len
(
result
)):
findall
=
re
.
findall
(
'va[lr] ('
+
re
.
escape
(
var
)
+
')'
,
lines
[
result
[
i
][
0
]])
if
len
(
findall
)
==
0
:
continue
result_sort
.
remove
(
result
[
i
])
result_sort
.
insert
(
0
,
result
[
i
])
break
result
=
result_sort
text
=
'
\n
'
.
join
(
lines
[:
start
+
1
])
+
'
\n
'
for
i
in
result
:
text
+=
'
\n
'
+
'
\n
'
.
join
(
lines
[
i
[
0
]:
i
[
1
]])
+
'
\n
'
text
+=
'
\n
'
.
join
(
lines
[
end
:])
with
open
(
path
,
'w'
,
encoding
=
'utf-8'
)
as
f
:
f
.
write
(
text
)
def
deal_junk
():
# 添加垃圾类
# add_junk_activity()
# # 添加方法嵌套
# add_junk_method()
# # 添加垃圾代码
# add_junk_code()
# 类成员乱序
class_disorder
()
def
get_path
(
path
):
paths
=
path
.
split
(
'
\\
'
)
return
str
(
os
.
path
.
join
(
*
paths
))
def
main
():
if
not
os
.
path
.
exists
(
get_path
(
'.
\\
src
\\
main
\\
java
\\
'
+
applicationId
[:
applicationId
.
find
(
'.'
)])):
return
# 资源混淆
deal_res
()
# 垃圾代码
deal_junk
()
# 代码处理
deal_code
()
if
__name__
==
'__main__'
:
if
os
.
path
.
exists
(
'build.gradle'
):
gradle_path
=
'build.gradle'
elif
os
.
path
.
exists
(
'build.gradle.kts'
):
gradle_path
=
'build.gradle.kts'
else
:
exit
(
'找不到 build.gradle 文件'
)
applicationId
=
re
.
search
(
'applicationId .*?["
\'
](.*?)["
\'
]'
,
open
(
gradle_path
,
'r'
,
encoding
=
'utf-8'
)
.
read
())[
1
]
aesKey
=
find_text
(
' aesKey ?= ?"(.*?)"'
,
get_path
(
'.
\\
src
\\
main
\\
java'
))[
0
]
print
(
'包名: '
+
applicationId
,
'aesKey: '
+
aesKey
)
if
find_text
(
'release ?{
\\
s*?(?:isM|m)inifyEnabled(?: ?= ?| )true'
,
is_one
=
True
)
is
None
:
exit
(
'官方混淆未开启'
)
if
find_text
(
'
\\
s*?ndk ?{'
,
is_one
=
True
)
is
None
:
exit
(
'ndk未配置'
)
main
()
app/src/main/java/com/base/easyfilemanager/MyApplication.kt
View file @
003faa1b
...
@@ -24,20 +24,7 @@ class MyApplication : BaseApplication() {
...
@@ -24,20 +24,7 @@ class MyApplication : BaseApplication() {
fun
initApp
()
{
fun
initApp
()
{
if
(
ConfigHelper
.
ifAgreePrivacy
)
{
if
(
ConfigHelper
.
ifAgreePrivacy
)
{
MobileAds
.
initialize
(
this
)
{
initializationStatus
->
}
MobileAds
.
initialize
(
this
)
{
initializationStatus
->
val
statusMap
=
initializationStatus
.
adapterStatusMap
for
(
adapterClass
in
statusMap
.
keys
)
{
val
status
=
statusMap
[
adapterClass
]
Log
.
d
(
"MyApp"
,
String
.
format
(
"Adapter name: %s, Description: %s, Latency: %d"
,
adapterClass
,
status
!!
.
description
,
status
.
latency
)
)
}
}
}
}
initLifeListener
()
initLifeListener
()
}
}
...
...
app/src/main/java/com/base/easyfilemanager/helps/AESHelper.kt
deleted
100644 → 0
View file @
157d8d2c
package
com.base.easyfilemanager.helps
import
android.util.Base64
import
java.security.SecureRandom
import
javax.crypto.Cipher
import
javax.crypto.spec.GCMParameterSpec
import
javax.crypto.spec.SecretKeySpec
object
AESHelper
{
private
const
val
aesKey
=
"bt8n2r8wdqk30wcu"
private
val
cipher
by
lazy
{
Cipher
.
getInstance
(
"AES/GCM/NoPadding"
)
}
fun
encrypt
(
content
:
String
):
String
{
try
{
val
iv
=
ByteArray
(
12
).
apply
{
SecureRandom
().
nextBytes
(
this
)
}
val
contentBytes
=
content
.
toByteArray
(
Charsets
.
UTF_8
)
val
params
=
GCMParameterSpec
(
128
,
iv
)
cipher
.
init
(
Cipher
.
ENCRYPT_MODE
,
secretKey
,
params
)
val
encryptData
=
cipher
.
doFinal
(
contentBytes
)
assert
(
encryptData
.
size
==
contentBytes
.
size
+
16
)
val
message
=
ByteArray
(
12
+
contentBytes
.
size
+
16
)
System
.
arraycopy
(
iv
,
0
,
message
,
0
,
12
)
System
.
arraycopy
(
encryptData
,
0
,
message
,
12
,
encryptData
.
size
)
return
String
(
Base64
.
encode
(
message
,
Base64
.
NO_WRAP
),
Charsets
.
UTF_8
)
}
catch
(
_
:
Exception
)
{
}
return
content
}
@Synchronized
fun
decrypt
(
content
:
String
):
String
{
try
{
val
con
=
content
.
replace
(
" "
.
toRegex
(),
"+"
)
val
contentByte
=
Base64
.
decode
(
con
,
Base64
.
NO_WRAP
)
require
(
contentByte
.
size
>=
12
+
16
)
val
params
=
GCMParameterSpec
(
128
,
contentByte
,
0
,
12
)
cipher
.
init
(
Cipher
.
DECRYPT_MODE
,
secretKey
,
params
)
val
decryptData
=
cipher
.
doFinal
(
contentByte
,
12
,
contentByte
.
size
-
12
)
return
String
(
decryptData
,
Charsets
.
UTF_8
)
}
catch
(
_
:
Exception
)
{
}
return
content
}
private
val
secretKey
by
lazy
{
SecretKeySpec
(
aesKey
.
toByteArray
(),
"AES"
)
}
}
\ No newline at end of file
app/src/main/java/com/base/easyfilemanager/helps/AESTextView.kt
deleted
100644 → 0
View file @
157d8d2c
package
com.base.easyfilemanager.helps
import
android.content.Context
import
android.util.AttributeSet
import
com.base.easyfilemanager.helps.KotlinExt.decode
import
com.noober.background.view.BLTextView
class
AESTextView
@JvmOverloads
constructor
(
context
:
Context
,
attrs
:
AttributeSet
?
=
null
)
:
BLTextView
(
context
,
attrs
)
{
override
fun
setText
(
text
:
CharSequence
?,
type
:
BufferType
?)
{
super
.
setText
(
text
?.
toString
()
?.
run
{
decode
().
takeIf
{
it
!=
this
}
}
?:
text
,
type
)
}
}
\ No newline at end of file
app/src/main/java/com/base/easyfilemanager/helps/BarUtils.kt
View file @
003faa1b
package
com.base.easyfilemanager.helps
package
com.base.easyfilemanager.helps
//noinspection SuspiciousImport
//noinspection SuspiciousImport
import
android.R
import
android.annotation.SuppressLint
import
android.annotation.SuppressLint
import
android.app.Activity
import
android.app.Activity
import
android.content.Context
import
android.content.Context
...
@@ -73,7 +72,7 @@ object BarUtils {
...
@@ -73,7 +72,7 @@ object BarUtils {
private
fun
applyStatusBarColor
(
window
:
Window
,
color
:
Int
,
isDecor
:
Boolean
):
View
{
private
fun
applyStatusBarColor
(
window
:
Window
,
color
:
Int
,
isDecor
:
Boolean
):
View
{
val
parent
=
val
parent
=
if
(
isDecor
)
window
.
decorView
as
ViewGroup
else
(
window
.
findViewById
<
View
>(
R
.
id
.
content
)
as
ViewGroup
)
if
(
isDecor
)
window
.
decorView
as
ViewGroup
else
(
window
.
findViewById
<
View
>(
android
.
R
.
id
.
content
)
as
ViewGroup
)
var
fakeStatusBarView
=
var
fakeStatusBarView
=
parent
.
findViewWithTag
<
View
>(
TAG_STATUS_BAR
)
parent
.
findViewWithTag
<
View
>(
TAG_STATUS_BAR
)
if
(
fakeStatusBarView
!=
null
)
{
if
(
fakeStatusBarView
!=
null
)
{
...
@@ -102,6 +101,7 @@ object BarUtils {
...
@@ -102,6 +101,7 @@ object BarUtils {
// status bar
// status bar
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
private
const
val
TAG_STATUS_BAR
=
"TAG_STATUS_BAR"
private
const
val
TAG_STATUS_BAR
=
"TAG_STATUS_BAR"
@SuppressLint
(
"DiscouragedApi"
,
"InternalInsetResource"
)
@SuppressLint
(
"DiscouragedApi"
,
"InternalInsetResource"
)
fun
getStatusBarHeight
():
Int
{
fun
getStatusBarHeight
():
Int
{
val
resources
=
Resources
.
getSystem
()
val
resources
=
Resources
.
getSystem
()
...
...
app/src/main/java/com/base/easyfilemanager/helps/ConfigHelper.kt
View file @
003faa1b
...
@@ -6,13 +6,6 @@ import com.base.easyfilemanager.utils.SPUtils
...
@@ -6,13 +6,6 @@ import com.base.easyfilemanager.utils.SPUtils
object
ConfigHelper
{
object
ConfigHelper
{
var
gid
=
""
var
isOpenNotification
=
false
// 域名
const
val
eventUrl
=
"http://test"
const
val
apiUrl
=
"http://test"
// admob广告id
// admob广告id
const
val
openAdmobId
=
"/6499/example/app-open"
const
val
openAdmobId
=
"/6499/example/app-open"
...
...
app/src/main/java/com/base/easyfilemanager/helps/KotlinExt.kt
View file @
003faa1b
package
com.base.easyfilemanager.helps
package
com.base.easyfilemanager.helps
import
android.view.View
import
java.text.SimpleDateFormat
import
java.text.SimpleDateFormat
import
java.util.Locale
import
java.util.Locale
object
KotlinExt
{
object
KotlinExt
{
private
val
aesMap
=
mutableMapOf
<
Int
,
String
>()
fun
Int
.
string
(
vararg
arg
:
Any
)
=
try
{
(
aesMap
[
this
]
?:
BaseApplication
.
context
.
getString
(
this
).
decode
()).
run
{
aesMap
[
this
@string
]
=
this
String
.
format
(
this
,
*
arg
)
}
}
catch
(
_
:
Exception
)
{
""
}
fun
String
.
decode
()
=
AESHelper
.
decrypt
(
this
)
.
replace
(
"\\r"
,
"\r"
)
.
replace
(
"\\n"
,
"\n"
)
.
replace
(
"\\'"
,
"'"
)
.
replace
(
"\\\""
,
"\""
)
.
replace
(
"\\?"
,
"?"
)
.
replace
(
"&"
,
"&"
)
fun
Collection
<
View
>.
setOnClickListener
(
listener
:
(
View
)
->
Unit
)
{
this
.
forEach
{
it
.
setOnClickListener
(
listener
)
}
}
fun
View
.
setTrackedOnClickListener
(
action
:
(
view
:
View
)
->
Unit
)
{
setOnClickListener
{
action
(
this
)
var
view
:
View
?
=
this
while
(
view
!=
null
)
{
try
{
break
}
catch
(
_
:
Exception
)
{
view
=
view
.
parent
as
?
View
}
}
}
}
fun
Number
.
toFormatSize
(
count
:
Int
=
1
):
String
{
fun
Number
.
toFormatSize
(
count
:
Int
=
1
):
String
{
var
suffix
=
"B"
var
suffix
=
"B"
var
fSize
=
this
.
toDouble
()
var
fSize
=
this
.
toDouble
()
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment