Skip to content
This repository was archived by the owner on Feb 12, 2026. It is now read-only.

Commit 1c45be2

Browse files
committed
update: injection/dex2oat hardening method
This commit changes how injection hardening is made. Instead of following denylist, it now follows targets, but instead of communicating through the binder, which produces a lot of detections, use Zygisk companion instead, allowing the same effect with much more convenience, of, for example, injecting in denylisted apps.
1 parent 1867ea3 commit 1c45be2

File tree

10 files changed

+328
-221
lines changed

10 files changed

+328
-221
lines changed

app/src/main/java/org/lsposed/manager/ConfigManager.java

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -409,23 +409,4 @@ public static boolean setAutoInclude(String packageName, boolean enable) {
409409
return false;
410410
}
411411
}
412-
413-
public static boolean isInjectionHardeningEnabled() {
414-
try {
415-
return LSPManagerServiceHolder.getService().isInjectionHardeningEnabled();
416-
} catch (RemoteException e) {
417-
Log.e(App.TAG, Log.getStackTraceString(e));
418-
return false;
419-
}
420-
}
421-
422-
public static boolean setInjectionHardening(boolean enabled) {
423-
try {
424-
LSPManagerServiceHolder.getService().setInjectionHardening(enabled);
425-
return true;
426-
} catch (RemoteException e) {
427-
Log.e(App.TAG, Log.getStackTraceString(e));
428-
return false;
429-
}
430-
}
431412
}

app/src/main/java/org/lsposed/manager/ui/fragment/SettingsFragment.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -169,12 +169,6 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
169169
prefLogWatchDog.setOnPreferenceChangeListener((preference, newValue) -> ConfigManager.setLogWatchdog((boolean) newValue));
170170
}
171171

172-
MaterialSwitchPreference prefInjectionHardening = findPreference("disable_injection_hardening");
173-
if (prefInjectionHardening != null) {
174-
prefInjectionHardening.setChecked(!installed || ConfigManager.isInjectionHardeningEnabled());
175-
prefInjectionHardening.setOnPreferenceChangeListener((preference, newValue) -> ConfigManager.setInjectionHardening((boolean) newValue));
176-
}
177-
178172
MaterialSwitchPreference prefDexObfuscate = findPreference("enable_dex_obfuscate");
179173
if (prefDexObfuscate != null) {
180174
prefDexObfuscate.setEnabled(installed);

daemon/src/main/java/org/lsposed/lspd/service/ConfigManager.java

Lines changed: 9 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -275,9 +275,6 @@ private synchronized void updateConfig() {
275275

276276
bool = config.get("enable_log_watchdog");
277277
logWatchdog = bool == null || (boolean) bool;
278-
279-
bool = config.get("disable_injection_hardening");
280-
injectionHardening = bool == null || (boolean) bool;
281278

282279
bool = config.get("enable_dex_obfuscate");
283280
dexObfuscate = bool == null || (boolean) bool;
@@ -1040,45 +1037,6 @@ public boolean isLogWatchdogEnabled() {
10401037
return logWatchdog;
10411038
}
10421039

1043-
public void setInjectionHardening(boolean on) {
1044-
File configFile = new File("/data/adb/disable_injection_hardening");
1045-
if (on) {
1046-
try {
1047-
if(!configFile.exists()) {
1048-
configFile.createNewFile();
1049-
}
1050-
Os.chmod(configFile.getAbsolutePath(), 0644);
1051-
Log.d(TAG, "injection hardening enabled");
1052-
updateModulePrefs("lspd", 0, "config", "disable_injection_hardening", on);
1053-
injectionHardening = on;
1054-
}
1055-
catch (Throwable e) {
1056-
Log.e(TAG, "failed to create config file for injection hardening", e);
1057-
return;
1058-
}
1059-
} else {
1060-
try {
1061-
if(configFile.exists()) {
1062-
configFile.delete();
1063-
}
1064-
Log.d(TAG, "injection hardening disabled");
1065-
updateModulePrefs("lspd", 0, "config", "disable_injection_hardening", on);
1066-
injectionHardening = on;
1067-
}
1068-
catch (Throwable e) {
1069-
Log.e(TAG, "failed to delete config file for injection hardening", e);
1070-
return;
1071-
}
1072-
}
1073-
}
1074-
1075-
public boolean isInjectionHardeningEnabled() {
1076-
File configFile = new File("/data/adb/disable_injection_hardening");
1077-
injectionHardening = configFile.exists();
1078-
updateModulePrefs("lspd", 0, "config", "disable_injection_hardening", injectionHardening);
1079-
return injectionHardening;
1080-
}
1081-
10821040
public void setDexObfuscate(boolean on) {
10831041
updateModulePrefs("lspd", 0, "config", "enable_dex_obfuscate", on);
10841042
}
@@ -1216,21 +1174,16 @@ private void removeModulePrefs(int uid, String packageName) throws IOException {
12161174

12171175
public List<String> getDenyListPackages() {
12181176
List<String> result = new ArrayList<>();
1219-
if(!isInjectionHardeningEnabled())
1220-
{
1221-
try
1222-
{
1223-
List<PackageInfo> infos = PackageService.getInstalledPackagesFromAllUsers(PackageService.MATCH_ALL_FLAGS, false).getList();
1224-
return infos.parallelStream()
1225-
.filter(info -> DenylistManager.isInDenylist(info.packageName))
1226-
.map(info -> info.packageName)
1227-
.collect(Collectors.toList());
1228-
} catch (Throwable e) {
1229-
Log.e(TAG, "get denylist", e);
1230-
} finally {
1231-
DenylistManager.clearFd();
1232-
}
1177+
try {
1178+
List<PackageInfo> infos = PackageService.getInstalledPackagesFromAllUsers(PackageService.MATCH_ALL_FLAGS, false).getList();
1179+
return infos.parallelStream()
1180+
.filter(info -> DenylistManager.isInDenylist(info.packageName))
1181+
.map(info -> info.packageName)
1182+
.collect(Collectors.toList());
1183+
} catch (Throwable e) {
1184+
Log.e(TAG, "get denylist", e);
12331185
}
1186+
12341187
return result;
12351188
}
12361189

daemon/src/main/java/org/lsposed/lspd/service/DenylistManager.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424
package org.lsposed.lspd.service;
2525

2626
public class DenylistManager {
27-
native static boolean isInDenylist(String processName);
28-
native static boolean isInDenylistFromClasspathDir(String classpathDir);
29-
native static void clearFd();
27+
28+
static native boolean isInDenylist(String processName);
29+
30+
static native String getPkgFromClasspathArg(String classpathDir);
3031
}

daemon/src/main/java/org/lsposed/lspd/service/Dex2OatService.java

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@
2525
import static org.lsposed.lspd.ILSPManagerService.DEX2OAT_SELINUX_PERMISSIVE;
2626
import static org.lsposed.lspd.ILSPManagerService.DEX2OAT_SEPOLICY_INCORRECT;
2727

28-
import static org.lsposed.lspd.service.DenylistManager.isInDenylistFromClasspathDir;
29-
3028
import android.net.LocalServerSocket;
3129
import android.os.Build;
3230
import android.os.FileObserver;
@@ -36,6 +34,10 @@
3634
import android.system.Os;
3735
import android.system.OsConstants;
3836
import android.util.Log;
37+
import android.database.Cursor;
38+
import android.database.sqlite.SQLiteDatabase;
39+
import android.database.sqlite.SQLiteException;
40+
import android.system.StructStat;
3941

4042
import androidx.annotation.Nullable;
4143
import androidx.annotation.RequiresApi;
@@ -159,6 +161,59 @@ private boolean notMounted() {
159161
private void doMount(boolean enabled) {
160162
doMountNative(enabled, dex2oatArray[0], dex2oatArray[1], dex2oatArray[2], dex2oatArray[3]);
161163
}
164+
165+
private boolean isInDenylistFromClasspathDirJava(String classpathDirArg) {
166+
// parse package using the native wrapper we added earlier
167+
String pkg = DenylistManager.getPkgFromClasspathArg(classpathDirArg);
168+
if (pkg == null) {
169+
Log.w(TAG, "Unknown classpath dir: " + classpathDirArg);
170+
return false; // match prior native behavior (JNI_FALSE)
171+
}
172+
173+
// ignore sandbox packages (match original C behavior)
174+
if ("com.android.sdksandbox".equals(pkg) || "com.google.android.sdksandbox".equals(pkg)) {
175+
return false;
176+
}
177+
178+
// Stat app data dir: /data/data/<pkg> or /data/user_de/0/<pkg>
179+
StructStat st;
180+
try {
181+
try {
182+
st = Os.stat("/data/data/" + pkg);
183+
} catch (ErrnoException e1) {
184+
st = Os.stat("/data/user_de/0/" + pkg);
185+
}
186+
} catch (ErrnoException e) {
187+
Log.w(TAG, "Failed to stat /data/data and /data/user_de/0 for: " + pkg, e);
188+
return false; // match C get_stat failure behavior
189+
}
190+
191+
int scopeUserId = (int) (st.st_uid / 100000);
192+
193+
// Query DB via Java SQLite
194+
try {
195+
SQLiteDatabase db = SQLiteDatabase.openDatabase(
196+
"/data/adb/lspd/config/modules_config.db",
197+
null,
198+
SQLiteDatabase.OPEN_READONLY
199+
);
200+
Cursor c = db.rawQuery(
201+
"SELECT 1 FROM scope INNER JOIN modules ON scope.mid = modules.mid WHERE scope.app_pkg_name = ? AND scope.user_id = ? AND modules.enabled = 1 LIMIT 1;",
202+
new String[] { pkg, String.valueOf(scopeUserId) }
203+
);
204+
boolean found = c.moveToFirst();
205+
c.close();
206+
db.close();
207+
208+
// If found -> targeted by module -> NOT in denylist -> return false
209+
// If not found -> NOT targeted -> in denylist -> return true
210+
return !found;
211+
} catch (SQLiteException e) {
212+
Log.e(TAG, "Failed to open/query modules_config.db", e);
213+
// Conservative: on DB error treat as in denylist (do not inject)
214+
return true;
215+
}
216+
}
162217

163218
public void start() {
164219
if (notMounted()) { // Already mounted when restart daemon
@@ -313,7 +368,7 @@ public void run() {
313368

314369
Log.d(TAG, "Received classpath dir: " + classpathDirArg);
315370

316-
boolean isDenied = isInDenylistFromClasspathDir(classpathDirArg);
371+
boolean isDenied = isInDenylistFromClasspathDirJava(classpathDirArg);
317372

318373
writeInt(os, isDenied ? 1 : 0);
319374
Log.d(TAG, "Process is "
@@ -334,8 +389,6 @@ public void run() {
334389
doMount(false);
335390
compatibility = DEX2OAT_CRASHED;
336391
}
337-
} finally {
338-
DenylistManager.clearFd();
339392
}
340393
}
341394

daemon/src/main/java/org/lsposed/lspd/service/LSPManagerService.java

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -556,16 +556,6 @@ public void setLogWatchdog(boolean enabled) {
556556
public boolean isLogWatchdogEnabled() {
557557
return ConfigManager.getInstance().isLogWatchdogEnabled();
558558
}
559-
560-
@Override
561-
public void setInjectionHardening(boolean enabled) {
562-
ConfigManager.getInstance().setInjectionHardening(enabled);
563-
}
564-
565-
@Override
566-
public boolean isInjectionHardeningEnabled() {
567-
return ConfigManager.getInstance().isInjectionHardeningEnabled();
568-
}
569559

570560
@Override
571561
public boolean setAutoInclude(String packageName, boolean enabled) {

daemon/src/main/jni/denylist.cpp

Lines changed: 4 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,20 @@
2121
See https://github.com/PerformanC/ReZygisk repository for more details. */
2222
// ------------------------------------------------------------------------------------------------------------------------------------------------
2323

24+
#include <stdlib.h>
25+
#include <string.h>
2426
#include <fcntl.h>
25-
#include <jni.h>
2627
#include <sys/prctl.h>
2728
#include <sys/wait.h>
2829
#include <sys/stat.h>
2930
#include <sys/syscall.h>
30-
#include <stdlib.h>
31+
3132
#include <unistd.h>
3233

33-
#include <string>
34+
#include <jni.h>
3435

3536
#include "ksu.h"
3637
#include "logging.h"
37-
#include "packagename.h"
3838

3939
bool exec_command(char *buf, size_t len, const char *file, const char *argv[]) {
4040
int link[2];
@@ -482,74 +482,6 @@ Java_org_lsposed_lspd_service_DenylistManager_isInDenylist(JNIEnv *env, jclass,
482482
return JNI_FALSE;
483483
}
484484

485-
extern "C" JNIEXPORT jboolean JNICALL
486-
Java_org_lsposed_lspd_service_DenylistManager_isInDenylistFromClasspathDir(JNIEnv *env, jclass, jstring classpathDirArg) {
487-
const char *classpath_dir_arg = env->GetStringUTFChars(classpathDirArg, nullptr);
488-
489-
if (classpath_dir_arg == nullptr) {
490-
LOGE("Failed to get classpathdir string");
491-
return JNI_FALSE;
492-
}
493-
494-
int app_name_len = 0;
495-
char app_name[256] = { 0 };
496-
app_name_len = get_pkg_from_classpath_arg(classpath_dir_arg, app_name, sizeof(app_name));
497-
498-
if(app_name_len == -1)
499-
{
500-
LOGE("Unknown classpath dir: %s", classpath_dir_arg);
501-
return JNI_FALSE;
502-
}
503-
env->ReleaseStringUTFChars(classpathDirArg, classpath_dir_arg);
504-
505-
if (root_impl == -1 && !ksu_get_existence() && !magisk_get_existence() && !apatch_get_existence()) {
506-
LOGE("No supported root implementation found, skipping denylist check");
507-
508-
goto app_not_in_denylist;
509-
}
510-
511-
if (root_impl == 1) {
512-
struct stat st;
513-
if (get_stat(app_name, &st) == -1) goto app_not_in_denylist;
514-
515-
if (ksu_is_in_denylist(st.st_uid)) {
516-
LOGI("App %s is in KernelSU denylist", app_name);
517-
518-
goto app_in_denylist;
519-
}
520-
521-
goto app_not_in_denylist;
522-
}
523-
524-
if (root_impl == 2) {
525-
if (magisk_is_in_denylist(app_name)) {
526-
LOGI("App %s is in Magisk denylist", app_name);
527-
528-
goto app_in_denylist;
529-
}
530-
531-
goto app_not_in_denylist;
532-
}
533-
534-
if (root_impl == 3) {
535-
if (apatch_uid_should_umount(app_name)) {
536-
LOGI("App %s is in APatch denylist", app_name);
537-
538-
goto app_in_denylist;
539-
}
540-
541-
goto app_not_in_denylist;
542-
}
543-
544-
LOGE("No supported root implementation found, skipping denylist check");
545-
546-
app_not_in_denylist:
547-
return JNI_FALSE;
548-
549-
app_in_denylist:
550-
return JNI_TRUE;
551-
}
552-
553485
extern "C" JNIEXPORT void JNICALL
554486
Java_org_lsposed_lspd_service_DenylistManager_clearFd(JNIEnv *env, jclass) {
555487
ksu_close_fd();

daemon/src/main/jni/packagename.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
#include <errno.h>
1313
#include <stdbool.h>
1414

15+
#include <jni.h>
16+
1517
#include <rapidxml.hpp>
1618

1719
static const std::string packages_path = "/data/system/packages.xml";
@@ -114,6 +116,30 @@ extern "C" bool get_pkg_from_classpath_arg(const char* classpath_dir, char* pack
114116
return false;
115117
}
116118

119+
extern "C" JNIEXPORT jstring JNICALL Java_org_lsposed_lspd_service_DenylistManager_getPkgFromClasspathArg( JNIEnv *env, jclass, jstring classpathDirArg) {
120+
if (classpathDirArg == NULL) {
121+
LOGE("getPkgFromClasspathArg: classpathDirArg is null");
122+
123+
return NULL;
124+
}
125+
126+
const char *classpath_dir = env->GetStringUTFChars(classpathDirArg, NULL);
127+
if (classpath_dir == NULL) {
128+
LOGE("getPkgFromClasspathArg: failed to get chars");
129+
130+
return NULL;
131+
}
132+
133+
char package_name[256] = {0};
134+
bool ok = get_pkg_from_classpath_arg(classpath_dir, package_name, sizeof(package_name));
135+
136+
env->ReleaseStringUTFChars(classpathDirArg, classpath_dir);
137+
138+
if (!ok) return NULL;
139+
140+
return env->NewStringUTF(package_name);
141+
}
142+
117143
static std::vector<char> LoadFileToStdVector(std::string filename) {
118144
std::vector<char> out;
119145
size_t len;

0 commit comments

Comments
 (0)