Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
M
Magisk
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
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
Magisk
Commits
357d913f
Commit
357d913f
authored
Aug 26, 2022
by
topjohnwu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Dynamically generate component names at runtime
parent
71b0c8b4
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
145 additions
and
63 deletions
+145
-63
BaseActivity.kt
.../main/java/com/topjohnwu/magisk/core/base/BaseActivity.kt
+6
-3
DownloadService.kt
...ava/com/topjohnwu/magisk/core/download/DownloadService.kt
+2
-8
HideAPK.kt
app/src/main/java/com/topjohnwu/magisk/core/tasks/HideAPK.kt
+74
-1
MainActivity.kt
app/src/main/java/com/topjohnwu/magisk/ui/MainActivity.kt
+23
-0
Codegen.kt
buildSrc/src/main/java/Codegen.kt
+40
-51
No files found.
app/src/main/java/com/topjohnwu/magisk/core/base/BaseActivity.kt
View file @
357d913f
...
...
@@ -34,9 +34,11 @@ abstract class BaseActivity : AppCompatActivity() {
permissionCallback
?.
invoke
(
it
)
permissionCallback
=
null
}
private
var
installCallback
:
((
Boolean
)
->
Unit
)?
=
null
private
val
requestInstall
=
registerForActivityResult
(
RequestInstall
())
{
permission
Callback
?.
invoke
(
it
)
permission
Callback
=
null
install
Callback
?.
invoke
(
it
)
install
Callback
=
null
}
private
var
contentCallback
:
ContentResultCallback
?
=
null
...
...
@@ -93,10 +95,11 @@ abstract class BaseActivity : AppCompatActivity() {
callback
(
true
)
return
}
permissionCallback
=
callback
if
(
permission
==
REQUEST_INSTALL_PACKAGES
)
{
installCallback
=
callback
requestInstall
.
launch
(
Unit
)
}
else
{
permissionCallback
=
callback
requestPermission
.
launch
(
permission
)
}
}
...
...
app/src/main/java/com/topjohnwu/magisk/core/download/DownloadService.kt
View file @
357d913f
...
...
@@ -101,15 +101,9 @@ class DownloadService : NotificationService() {
zf
.
getInputStream
(
zf
.
getEntry
(
"assets/stub.apk"
)).
writeTo
(
apk
)
// Patch and install
val
session
=
APKInstall
.
startSession
(
this
)
session
.
openStream
(
this
).
use
{
val
label
=
applicationInfo
.
nonLocalizedLabel
if
(!
HideAPK
.
patch
(
this
,
apk
,
it
,
packageName
,
label
))
{
throw
IOException
(
"HideAPK patch error"
)
}
}
subject
.
intent
=
HideAPK
.
upgrade
(
this
,
apk
)
?:
throw
IOException
(
"HideAPK patch error"
)
apk
.
delete
()
subject
.
intent
=
session
.
waitIntent
()
}
else
{
ActivityTracker
.
foreground
?.
let
{
// Relaunch the process if we are foreground
...
...
app/src/main/java/com/topjohnwu/magisk/core/tasks/HideAPK.kt
View file @
357d913f
...
...
@@ -4,6 +4,7 @@ import android.app.Activity
import
android.content.Context
import
android.content.Intent
import
android.widget.Toast
import
androidx.annotation.WorkerThread
import
com.topjohnwu.magisk.BuildConfig.APPLICATION_ID
import
com.topjohnwu.magisk.R
import
com.topjohnwu.magisk.StubApk
...
...
@@ -28,6 +29,7 @@ import java.io.FileOutputStream
import
java.io.IOException
import
java.io.OutputStream
import
java.security.SecureRandom
import
kotlin.random.asKotlinRandom
object
HideAPK
{
...
...
@@ -37,6 +39,7 @@ object HideAPK {
// Some arbitrary limit
const
val
MAX_LABEL_LENGTH
=
32
const
val
PLACEHOLDER
=
"COMPONENT_PLACEHOLDER"
private
fun
genPackageName
():
String
{
val
random
=
SecureRandom
()
...
...
@@ -61,7 +64,61 @@ object HideAPK {
return
builder
.
toString
()
}
fun
patch
(
private
fun
classNameGenerator
()
=
sequence
{
val
c1
=
mutableListOf
<
String
>()
val
c2
=
mutableListOf
<
String
>()
val
c3
=
mutableListOf
<
String
>()
val
random
=
SecureRandom
()
val
kRandom
=
random
.
asKotlinRandom
()
fun
<
T
>
chain
(
vararg
iters
:
Iterable
<
T
>)
=
sequence
{
iters
.
forEach
{
it
.
forEach
{
v
->
yield
(
v
)
}
}
}
for
(
a
in
chain
(
'a'
..
'z'
,
'A'
..
'Z'
))
{
if
(
a
!=
'a'
&&
a
!=
'A'
)
{
c1
.
add
(
"$a"
)
}
for
(
b
in
chain
(
'a'
..
'z'
,
'A'
..
'Z'
,
'0'
..
'9'
))
{
c2
.
add
(
"$a$b"
)
for
(
c
in
chain
(
'a'
..
'z'
,
'A'
..
'Z'
,
'0'
..
'9'
))
{
c3
.
add
(
"$a$b$c"
)
}
}
}
c1
.
shuffle
(
random
)
c2
.
shuffle
(
random
)
c3
.
shuffle
(
random
)
fun
notJavaKeyword
(
name
:
String
)
=
when
(
name
)
{
"do"
,
"if"
,
"for"
,
"int"
,
"new"
,
"try"
->
false
else
->
true
}
fun
List
<
String
>.
process
()
=
asSequence
().
filter
(
::
notJavaKeyword
)
val
names
=
mutableListOf
<
String
>()
names
.
addAll
(
c1
)
names
.
addAll
(
c2
.
process
().
take
(
30
))
names
.
addAll
(
c3
.
process
().
take
(
30
))
while
(
true
)
{
val
seg
=
2
+
random
.
nextInt
(
4
)
val
cls
=
StringBuilder
()
for
(
i
in
0
until
seg
)
{
cls
.
append
(
names
.
random
(
kRandom
))
if
(
i
!=
seg
-
1
)
cls
.
append
(
'.'
)
}
// Old Android does not support capitalized package names
// Check Android 7.0.0 PackageParser#buildClassName
cls
[
0
]
=
cls
[
0
].
lowercaseChar
()
yield
(
cls
.
toString
())
}
}.
distinct
().
iterator
()
private
fun
patch
(
context
:
Context
,
apk
:
File
,
out
:
OutputStream
,
pkg
:
String
,
label
:
CharSequence
...
...
@@ -72,12 +129,15 @@ object HideAPK {
JarMap
.
open
(
apk
,
true
).
use
{
jar
->
val
je
=
jar
.
getJarEntry
(
ANDROID_MANIFEST
)
val
xml
=
AXML
(
jar
.
getRawData
(
je
))
val
generator
=
classNameGenerator
()
if
(!
xml
.
patchStrings
{
for
(
i
in
it
.
indices
)
{
val
s
=
it
[
i
]
if
(
s
.
contains
(
APPLICATION_ID
))
{
it
[
i
]
=
s
.
replace
(
APPLICATION_ID
,
pkg
)
}
else
if
(
s
.
contains
(
PLACEHOLDER
))
{
it
[
i
]
=
generator
.
next
()
}
else
if
(
s
==
origLabel
)
{
it
[
i
]
=
label
.
toString
()
}
...
...
@@ -193,4 +253,17 @@ object HideAPK {
}
if
(!
success
)
onFailure
.
run
()
}
@WorkerThread
fun
upgrade
(
context
:
Context
,
apk
:
File
):
Intent
?
{
val
label
=
context
.
applicationInfo
.
nonLocalizedLabel
val
pkg
=
context
.
packageName
val
session
=
APKInstall
.
startSession
(
context
)
session
.
openStream
(
context
).
use
{
if
(!
patch
(
context
,
apk
,
it
,
pkg
,
label
))
{
return
null
}
}
return
session
.
waitIntent
()
}
}
app/src/main/java/com/topjohnwu/magisk/ui/MainActivity.kt
View file @
357d913f
...
...
@@ -12,6 +12,7 @@ import androidx.core.content.pm.ShortcutManagerCompat
import
androidx.core.view.forEach
import
androidx.core.view.isGone
import
androidx.core.view.isVisible
import
androidx.lifecycle.lifecycleScope
import
androidx.navigation.NavDirections
import
com.topjohnwu.magisk.MainDirections
import
com.topjohnwu.magisk.R
...
...
@@ -22,12 +23,15 @@ import com.topjohnwu.magisk.core.Const
import
com.topjohnwu.magisk.core.Info
import
com.topjohnwu.magisk.core.isRunningAsStub
import
com.topjohnwu.magisk.core.model.module.LocalModule
import
com.topjohnwu.magisk.core.tasks.HideAPK
import
com.topjohnwu.magisk.databinding.ActivityMainMd2Binding
import
com.topjohnwu.magisk.ktx.startAnimations
import
com.topjohnwu.magisk.ui.home.HomeFragmentDirections
import
com.topjohnwu.magisk.utils.Utils
import
com.topjohnwu.magisk.view.MagiskDialog
import
com.topjohnwu.magisk.view.Shortcuts
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.launch
import
java.io.File
class
MainViewModel
:
BaseViewModel
()
...
...
@@ -59,6 +63,7 @@ class MainActivity : SplashActivity<ActivityMainMd2Binding>() {
setContentView
()
showUnsupportedMessage
()
askForHomeShortcut
()
checkStubComponent
()
// Ask permission to post notifications for background update check
if
(
Config
.
checkUpdate
)
{
...
...
@@ -227,4 +232,22 @@ class MainActivity : SplashActivity<ActivityMainMd2Binding>() {
}.
show
()
}
}
@SuppressLint
(
"InlinedApi"
)
private
fun
checkStubComponent
()
{
if
(
intent
.
component
?.
className
?.
contains
(
HideAPK
.
PLACEHOLDER
)
==
true
)
{
// The stub APK was not properly patched, re-apply our changes
withPermission
(
Manifest
.
permission
.
REQUEST_INSTALL_PACKAGES
)
{
granted
->
if
(
granted
)
{
lifecycleScope
.
launch
(
Dispatchers
.
IO
)
{
val
apk
=
File
(
applicationInfo
.
sourceDir
)
HideAPK
.
upgrade
(
this
@MainActivity
,
apk
)
?.
let
{
startActivity
(
it
)
}
}
}
}
}
}
}
buildSrc/src/main/java/Codegen.kt
View file @
357d913f
...
...
@@ -82,7 +82,7 @@ fun genStubManifest(srcDir: File, outDir: File): String {
cmpList
.
add
(
"""
|<provider
| android:name="
%s
"
| android:name="
x.COMPONENT_PLACEHOLDER_0
"
| android:authorities="${'$'}{applicationId}.provider"
| android:directBootAware="true"
| android:exported="false"
...
...
@@ -92,7 +92,7 @@ fun genStubManifest(srcDir: File, outDir: File): String {
cmpList
.
add
(
"""
|<receiver
| android:name="
%s
"
| android:name="
x.COMPONENT_PLACEHOLDER_1
"
| android:exported="false">
| <intent-filter>
| <action android:name="android.intent.action.LOCALE_CHANGED" />
...
...
@@ -111,7 +111,7 @@ fun genStubManifest(srcDir: File, outDir: File): String {
cmpList
.
add
(
"""
|<activity
| android:name="
%s
"
| android:name="
x.COMPONENT_PLACEHOLDER_2
"
| android:exported="true">
| <intent-filter>
| <action android:name="android.intent.action.MAIN" />
...
...
@@ -123,7 +123,7 @@ fun genStubManifest(srcDir: File, outDir: File): String {
cmpList
.
add
(
"""
|<activity
| android:name="
%s
"
| android:name="
x.COMPONENT_PLACEHOLDER_3
"
| android:directBootAware="true"
| android:exported="false"
| android:taskAffinity=""
...
...
@@ -138,56 +138,49 @@ fun genStubManifest(srcDir: File, outDir: File): String {
cmpList
.
add
(
"""
|<service
| android:name="
%s
"
| android:name="
x.COMPONENT_PLACEHOLDER_4
"
| android:exported="false" />"""
.
ind
(
2
)
)
cmpList
.
add
(
"""
|<service
| android:name="
%s
"
| android:name="
x.COMPONENT_PLACEHOLDER_5
"
| android:exported="false"
| android:permission="android.permission.BIND_JOB_SERVICE" />"""
.
ind
(
2
)
)
val
names
=
mutableListOf
<
String
>()
names
.
addAll
(
c1
)
names
.
addAll
(
c2
.
subList
(
0
,
10
))
names
.
addAll
(
c3
.
subList
(
0
,
10
))
names
.
shuffle
(
RANDOM
)
val
pkgNames
=
names
// Distinct by lower case to support case insensitive file systems
.
distinctBy
{
it
.
toLowerCase
(
Locale
.
ROOT
)
}
// Old Android does not support capitalized package names
// Check Android 7.0.0 PackageParser#buildClassName
.
map
{
it
.
decapitalize
(
Locale
.
ROOT
)
}
fun
isJavaKeyword
(
name
:
String
)
=
when
(
name
)
{
"do"
,
"if"
,
"for"
,
"int"
,
"new"
,
"try"
->
true
else
->
false
}
val
classNameGenerator
=
sequence
{
fun
notJavaKeyword
(
name
:
String
)
=
when
(
name
)
{
"do"
,
"if"
,
"for"
,
"int"
,
"new"
,
"try"
->
false
else
->
true
}
val
cmps
=
mutableListOf
<
String
>()
val
usedNames
=
mutableListOf
<
String
>()
fun
genCmpName
():
String
{
var
pkgName
:
String
do
{
pkgName
=
pkgNames
.
random
(
kRANDOM
)
}
while
(
isJavaKeyword
(
pkgName
))
var
clzName
:
String
do
{
clzName
=
names
.
random
(
kRANDOM
)
}
while
(
isJavaKeyword
(
clzName
))
val
cmp
=
"${pkgName}.${clzName}"
usedNames
.
add
(
cmp
)
return
cmp
}
fun
List
<
String
>.
process
()
=
asSequence
()
.
filter
(
::
notJavaKeyword
)
// Distinct by lower case to support case insensitive file systems
.
distinctBy
{
it
.
toLowerCase
(
Locale
.
ROOT
)
}
val
names
=
mutableListOf
<
String
>()
names
.
addAll
(
c1
)
names
.
addAll
(
c2
.
process
().
take
(
30
))
names
.
addAll
(
c3
.
process
().
take
(
30
))
names
.
shuffle
(
RANDOM
)
while
(
true
)
{
val
cls
=
StringBuilder
()
cls
.
append
(
names
.
random
(
kRANDOM
))
cls
.
append
(
'.'
)
cls
.
append
(
names
.
random
(
kRANDOM
))
// Old Android does not support capitalized package names
// Check Android 7.0.0 PackageParser#buildClassName
cls
[
0
]
=
cls
[
0
].
toLowerCase
()
yield
(
cls
.
toString
())
}
}.
distinct
().
iterator
()
fun
genClass
(
type
:
String
)
{
val
clzName
=
genCmpName
()
fun
genClass
(
type
:
String
)
:
String
{
val
clzName
=
classNameGenerator
.
next
()
val
(
pkg
,
name
)
=
clzName
.
split
(
'.'
)
val
pkgDir
=
File
(
outDir
,
pkg
)
pkgDir
.
mkdirs
()
...
...
@@ -195,22 +188,18 @@ fun genStubManifest(srcDir: File, outDir: File): String {
it
.
println
(
"package $pkg;"
)
it
.
println
(
"public class $name extends com.topjohnwu.magisk.$type {}"
)
}
return
clzName
}
// Generate 2 non redirect-able classes
genClass
(
"DelegateComponentFactory"
)
genClass
(
"DelegateApplication"
)
for
(
gen
in
cmpList
)
{
val
name
=
genCmpName
()
cmps
.
add
(
gen
.
format
(
name
))
}
val
factory
=
genClass
(
"DelegateComponentFactory"
)
val
app
=
genClass
(
"DelegateApplication"
)
// Shuffle the order of the components
cmp
s
.
shuffle
(
RANDOM
)
cmp
List
.
shuffle
(
RANDOM
)
val
xml
=
File
(
srcDir
,
"AndroidManifest.xml"
).
readText
()
return
xml
.
format
(
usedNames
[
0
],
usedNames
[
1
],
cmps
.
joinToString
(
"\n\n"
))
return
xml
.
format
(
factory
,
app
,
cmpList
.
joinToString
(
"\n\n"
))
}
fun
genEncryptedResources
(
res
:
InputStream
,
outDir
:
File
)
{
...
...
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