kernel:Add Dynamic Signature Configuration

This commit is contained in:
ShirkNeko
2025-07-05 16:21:29 +08:00
parent 6a60b72e21
commit dd6d695020
13 changed files with 690 additions and 12 deletions

View File

@@ -351,4 +351,47 @@ NativeBridgeNP(getFullVersion, jstring) {
char buff[255] = { 0 };
get_full_version((char *) &buff);
return GetEnvironment()->NewStringUTF(env, buff);
}
NativeBridge(setDynamicSign, jboolean, jint size, jstring hash) {
if (!hash) {
LogDebug("setDynamicSign: hash is null");
return false;
}
const char* chash = GetEnvironment()->GetStringUTFChars(env, hash, nullptr);
bool result = set_dynamic_sign((unsigned int)size, chash);
GetEnvironment()->ReleaseStringUTFChars(env, hash, chash);
LogDebug("setDynamicSign: size=0x%x, result=%d", size, result);
return result;
}
NativeBridgeNP(getDynamicSign, jobject) {
struct dynamic_sign_user_config config;
bool result = get_dynamic_sign(&config);
if (!result) {
LogDebug("getDynamicSign: failed to get dynamic sign config");
return NULL;
}
jclass cls = GetEnvironment()->FindClass(env, "com/sukisu/ultra/Natives$DynamicSignConfig");
jmethodID constructor = GetEnvironment()->GetMethodID(env, cls, "<init>", "()V");
jobject obj = GetEnvironment()->NewObject(env, cls, constructor);
jfieldID sizeField = GetEnvironment()->GetFieldID(env, cls, "size", "I");
jfieldID hashField = GetEnvironment()->GetFieldID(env, cls, "hash", "Ljava/lang/String;");
GetEnvironment()->SetIntField(env, obj, sizeField, (jint)config.size);
GetEnvironment()->SetObjectField(env, obj, hashField, GetEnvironment()->NewStringUTF(env, config.hash));
LogDebug("getDynamicSign: size=0x%x, hash=%.16s...", config.size, config.hash);
return obj;
}
NativeBridgeNP(clearDynamicSign, jboolean) {
bool result = clear_dynamic_sign();
LogDebug("clearDynamicSign: result=%d", result);
return result;
}

View File

@@ -36,6 +36,11 @@
#define CMD_ENABLE_KPM 100
#define CMD_HOOK_TYPE 101
#define CMD_GET_SUSFS_FEATURE_STATUS 102
#define CMD_DYNAMIC_SIGN 103
#define DYNAMIC_SIGN_OP_SET 0
#define DYNAMIC_SIGN_OP_GET 1
#define DYNAMIC_SIGN_OP_CLEAR 2
static bool ksuctl(int cmd, void* arg1, void* arg2) {
int32_t result = 0;
@@ -140,3 +145,32 @@ bool get_susfs_feature_status(struct susfs_feature_status* status) {
return ksuctl(CMD_GET_SUSFS_FEATURE_STATUS, status, NULL);
}
bool set_dynamic_sign(unsigned int size, const char* hash) {
if (hash == NULL) {
return false;
}
struct dynamic_sign_user_config config;
config.operation = DYNAMIC_SIGN_OP_SET;
config.size = size;
strncpy(config.hash, hash, sizeof(config.hash) - 1);
config.hash[sizeof(config.hash) - 1] = '\0';
return ksuctl(CMD_DYNAMIC_SIGN, &config, NULL);
}
bool get_dynamic_sign(struct dynamic_sign_user_config* config) {
if (config == NULL) {
return false;
}
config->operation = DYNAMIC_SIGN_OP_GET;
return ksuctl(CMD_DYNAMIC_SIGN, config, NULL);
}
bool clear_dynamic_sign() {
struct dynamic_sign_user_config config;
config.operation = DYNAMIC_SIGN_OP_CLEAR;
return ksuctl(CMD_DYNAMIC_SIGN, &config, NULL);
}

View File

@@ -28,6 +28,16 @@ bool is_lkm_mode();
#define KSU_MAX_GROUPS 32
#define KSU_SELINUX_DOMAIN 64
#define DYNAMIC_SIGN_OP_SET 0
#define DYNAMIC_SIGN_OP_GET 1
#define DYNAMIC_SIGN_OP_CLEAR 2
struct dynamic_sign_user_config {
unsigned int operation;
unsigned int size;
char hash[65];
};
// SUSFS Functional State Structures
struct susfs_feature_status {
bool status_sus_path;
@@ -109,4 +119,10 @@ bool get_hook_type(char* hook_type, size_t size);
bool get_susfs_feature_status(struct susfs_feature_status* status);
bool set_dynamic_sign(unsigned int size, const char* hash);
bool get_dynamic_sign(struct dynamic_sign_user_config* config);
bool clear_dynamic_sign();
#endif //KERNELSU_KSU_H

View File

@@ -95,6 +95,27 @@ object Natives {
*/
external fun getSusfsFeatureStatus(): SusfsFeatureStatus?
/**
* Set dynamic signature configuration
* @param size APK signature size
* @param hash APK signature hash (64 character hex string)
* @return true if successful, false otherwise
*/
external fun setDynamicSign(size: Int, hash: String): Boolean
/**
* Get current dynamic signature configuration
* @return DynamicSignConfig object containing current configuration, or null if not set
*/
external fun getDynamicSign(): DynamicSignConfig?
/**
* Clear dynamic signature configuration
* @return true if successful, false otherwise
*/
external fun clearDynamicSign(): Boolean
private const val NON_ROOT_DEFAULT_PROFILE_KEY = "$"
private const val NOBODY_UID = 9999
@@ -147,6 +168,21 @@ object Natives {
val statusSusSu: Boolean = false
) : Parcelable
@Immutable
@Parcelize
@Keep
data class DynamicSignConfig(
val size: Int = 0,
val hash: String = ""
) : Parcelable {
constructor() : this(0, "")
fun isValid(): Boolean {
return size > 0 && hash.length == 64 && hash.all {
it in '0'..'9' || it in 'a'..'f' || it in 'A'..'F'
}
}
}
@Immutable
@Parcelize

View File

@@ -145,6 +145,13 @@ fun MoreSettingsScreen(
var showDpiConfirmDialog by remember { mutableStateOf(false) }
var showImageEditor by remember { mutableStateOf(false) }
// 动态签名配置状态
var dynamicSignConfig by remember { mutableStateOf<Natives.DynamicSignConfig?>(null) }
var isDynamicSignEnabled by remember { mutableStateOf(false) }
var dynamicSignSize by remember { mutableStateOf("") }
var dynamicSignHash by remember { mutableStateOf("") }
var showDynamicSignDialog by remember { mutableStateOf(false) }
// 主题模式选项
val themeOptions = listOf(
stringResource(R.string.theme_follow_system),
@@ -652,6 +659,147 @@ fun MoreSettingsScreen(
)
}
LaunchedEffect(Unit) {
// 初始化动态签名配置
dynamicSignConfig = Natives.getDynamicSign()
dynamicSignConfig?.let { config ->
if (config.isValid()) {
isDynamicSignEnabled = true
dynamicSignSize = config.size.toString()
dynamicSignHash = config.hash
}
}
}
// 动态签名配置对话框
if (showDynamicSignDialog) {
AlertDialog(
onDismissRequest = { showDynamicSignDialog = false },
title = { Text(stringResource(R.string.dynamic_sign_title)) },
text = {
Column(
modifier = Modifier.verticalScroll(rememberScrollState())
) {
// 启用开关
Row(
modifier = Modifier
.fillMaxWidth()
.clickable { isDynamicSignEnabled = !isDynamicSignEnabled }
.padding(vertical = 8.dp),
verticalAlignment = Alignment.CenterVertically
) {
Switch(
checked = isDynamicSignEnabled,
onCheckedChange = { isDynamicSignEnabled = it }
)
Spacer(modifier = Modifier.width(12.dp))
Text(stringResource(R.string.enable_dynamic_sign))
}
Spacer(modifier = Modifier.height(16.dp))
// 签名大小输入
androidx.compose.material3.OutlinedTextField(
value = dynamicSignSize,
onValueChange = { dynamicSignSize = it },
label = { Text(stringResource(R.string.signature_size)) },
enabled = isDynamicSignEnabled,
modifier = Modifier.fillMaxWidth(),
singleLine = true,
keyboardOptions = androidx.compose.foundation.text.KeyboardOptions(
keyboardType = androidx.compose.ui.text.input.KeyboardType.Number
)
)
Spacer(modifier = Modifier.height(12.dp))
// 签名哈希输入
androidx.compose.material3.OutlinedTextField(
value = dynamicSignHash,
onValueChange = { hash ->
// 只允许十六进制字符
if (hash.all { it in '0'..'9' || it in 'a'..'f' || it in 'A'..'F' }) {
dynamicSignHash = hash
}
},
label = { Text(stringResource(R.string.signature_hash)) },
enabled = isDynamicSignEnabled,
modifier = Modifier.fillMaxWidth(),
singleLine = true,
supportingText = {
Text(stringResource(R.string.hash_must_be_64_chars))
},
isError = isDynamicSignEnabled && dynamicSignHash.isNotEmpty() && dynamicSignHash.length != 64
)
}
},
confirmButton = {
Button(
onClick = {
if (isDynamicSignEnabled) {
val size = dynamicSignSize.toIntOrNull()
if (size != null && size > 0 && dynamicSignHash.length == 64) {
val success = Natives.setDynamicSign(size, dynamicSignHash)
if (success) {
dynamicSignConfig = Natives.DynamicSignConfig(size, dynamicSignHash)
Toast.makeText(
context,
context.getString(R.string.dynamic_sign_set_success),
Toast.LENGTH_SHORT
).show()
} else {
Toast.makeText(
context,
context.getString(R.string.dynamic_sign_set_failed),
Toast.LENGTH_SHORT
).show()
}
} else {
Toast.makeText(
context,
context.getString(R.string.invalid_sign_config),
Toast.LENGTH_SHORT
).show()
return@Button
}
} else {
val success = Natives.clearDynamicSign()
if (success) {
dynamicSignConfig = null
dynamicSignSize = ""
dynamicSignHash = ""
Toast.makeText(
context,
context.getString(R.string.dynamic_sign_disabled_success),
Toast.LENGTH_SHORT
).show()
} else {
Toast.makeText(
context,
context.getString(R.string.dynamic_sign_clear_failed),
Toast.LENGTH_SHORT
).show()
return@Button
}
}
showDynamicSignDialog = false
},
enabled = if (isDynamicSignEnabled) {
dynamicSignSize.toIntOrNull()?.let { it > 0 } == true &&
dynamicSignHash.length == 64
} else true
) {
Text(stringResource(R.string.confirm))
}
},
dismissButton = {
TextButton(onClick = { showDynamicSignDialog = false }) {
Text(stringResource(R.string.cancel))
}
}
)
}
Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = {
@@ -1226,6 +1374,17 @@ fun MoreSettingsScreen(
}
)
}
// 动态签名设置
SettingItem(
icon = Icons.Filled.Security,
title = stringResource(R.string.dynamic_sign_title),
subtitle = if (isDynamicSignEnabled) {
stringResource(R.string.dynamic_sign_enabled_summary, dynamicSignSize)
} else {
stringResource(R.string.dynamic_sign_disabled)
},
onClick = { showDynamicSignDialog = true }
)
}
}
}

View File

@@ -566,4 +566,16 @@
<string name="selected_apps_count">%1$d 个已选应用</string>
<string name="already_added_apps_count">%1$d 个已添加应用</string>
<string name="all_apps_already_added">所有应用均已添加</string>
<string name="dynamic_sign_title">动态签名配置</string>
<string name="dynamic_sign_enabled_summary">已启用 (大小: %s)</string>
<string name="dynamic_sign_disabled">未启用</string>
<string name="enable_dynamic_sign">启用动态签名</string>
<string name="signature_size">签名大小</string>
<string name="signature_hash">签名哈希值</string>
<string name="hash_must_be_64_chars">哈希值必须是64位十六进制字符</string>
<string name="dynamic_sign_set_success">动态签名配置设置成功</string>
<string name="dynamic_sign_set_failed">动态签名配置设置失败</string>
<string name="invalid_sign_config">无效的签名配置</string>
<string name="dynamic_sign_disabled_success">动态签名已禁用</string>
<string name="dynamic_sign_clear_failed">清除动态签名错误</string>
</resources>

View File

@@ -568,4 +568,16 @@
<string name="selected_apps_count">%1$d apps selected</string>
<string name="already_added_apps_count">%1$d apps already added</string>
<string name="all_apps_already_added">All apps have been added</string>
<string name="dynamic_sign_title">Dynamic Signature Configuration</string>
<string name="dynamic_sign_enabled_summary">Enabled (Size: %s)</string>
<string name="dynamic_sign_disabled">Disabled</string>
<string name="enable_dynamic_sign">Enable Dynamic Signature</string>
<string name="signature_size">Signature Size</string>
<string name="signature_hash">Signature Hash</string>
<string name="hash_must_be_64_chars">Hash must be 64 hexadecimal characters</string>
<string name="dynamic_sign_set_success">Dynamic signature configuration set successfully</string>
<string name="dynamic_sign_set_failed">Failed to set dynamic signature configuration</string>
<string name="invalid_sign_config">Invalid signature configuration</string>
<string name="dynamic_sign_disabled_success">Dynamic signature disabled</string>
<string name="dynamic_sign_clear_failed">Failed to clear dynamic signature</string>
</resources>