I have one app which can call java functions from scripts defined at runtime, but has not enough permissions to do most of the stuff, like toggling wifi.
So I tried to create a module hooking the Packagemanager to grant these permissions.
My code so far:
Code:
public class Hook implements IXposedHookLoadPackage, IXposedHookZygoteInit {
ArrayList<String> newPerms;
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
if(!loadPackageParam.packageName.equals("android"))return;
final Class<?> clsPMS = findClass("com.android.server.pm.PackageManagerService", loadPackageParam.classLoader);
XC_MethodHook hookGrantPermissions = new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
String pkgName = (String) getObjectField(param.args[0], "packageName");
if(!(pkgName.equals(Strings.LLX)||pkgName.equals(Strings.LL)))return;
//XposedBridge.log("Package: "+pkgName);
if(newPerms == null || newPerms.isEmpty() ) return;
ArrayList<String> origRequestedPermissions = (ArrayList<String>) getObjectField(param.args[0], "requestedPermissions");
param.setObjectExtra("orig_requested_permissions", origRequestedPermissions);
//XposedBridge.log("Old Permissions "+Arrays.toString(origRequestedPermissions.toArray()));
//XposedBridge.log("New Permissions "+Arrays.toString(newPerms.toArray()));
ArrayList<String> newRequestedPermissions = new ArrayList<>(origRequestedPermissions);
newRequestedPermissions.addAll(newPerms);
//XposedBridge.log("All Permissions"+Arrays.toString(newRequestedPermissions.toArray()));
//param.args[1] = true;
[U][B]setObjectField(param.args[0], "requestedPermissions", newRequestedPermissions);[/B][/U]
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
ArrayList<String> origRequestedPermissions = (ArrayList<String>) param.getObjectExtra("orig_requested_permissions");
if (origRequestedPermissions != null)
setObjectField(param.args[0], "requestedPermissions", origRequestedPermissions);
}
};
if (Build.VERSION.SDK_INT < 21) {
findAndHookMethod(clsPMS, "grantPermissionsLPw", "android.content.pm.PackageParser$Package", boolean.class, hookGrantPermissions);
} else {
findAndHookMethod(clsPMS, "grantPermissionsLPw", "android.content.pm.PackageParser$Package", boolean.class, String.class, hookGrantPermissions);
}
}
@Override
public void initZygote(StartupParam startupParam) throws Throwable {
XSharedPreferences pref = new XSharedPreferences(this.getClass().getPackage().getName(), Strings.PREF_NAME);
pref.makeWorldReadable();
newPerms = Strings.read(pref);
}
Sidenote: Code is partially forked from Appsettings module: https://github.com/rovo89/XposedAppSettings
The problem is: when I restart my phone after enabling the module, I just get a blackscreen after the bootanimation.
When I comment out the line marked fat underlined, it works, but does nothing (because this line is essential).
I have practically no idea why this isn't working.
I know that the input returned from Strings.read is valid.
My Question: What am I doing wrong?
LM13 said:
I have one app which can call java functions from scripts defined at runtime, but has not enough permissions to do most of the stuff, like toggling wifi.
So I tried to create a module hooking the Packagemanager to grant these permissions.
My code so far:
Code:
public class Hook implements IXposedHookLoadPackage, IXposedHookZygoteInit {
ArrayList<String> newPerms;
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
if(!loadPackageParam.packageName.equals("android"))return;
final Class<?> clsPMS = findClass("com.android.server.pm.PackageManagerService", loadPackageParam.classLoader);
XC_MethodHook hookGrantPermissions = new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
String pkgName = (String) getObjectField(param.args[0], "packageName");
if(!(pkgName.equals(Strings.LLX)||pkgName.equals(Strings.LL)))return;
//XposedBridge.log("Package: "+pkgName);
if(newPerms == null || newPerms.isEmpty() ) return;
ArrayList<String> origRequestedPermissions = (ArrayList<String>) getObjectField(param.args[0], "requestedPermissions");
param.setObjectExtra("orig_requested_permissions", origRequestedPermissions);
//XposedBridge.log("Old Permissions "+Arrays.toString(origRequestedPermissions.toArray()));
//XposedBridge.log("New Permissions "+Arrays.toString(newPerms.toArray()));
ArrayList<String> newRequestedPermissions = new ArrayList<>(origRequestedPermissions);
newRequestedPermissions.addAll(newPerms);
//XposedBridge.log("All Permissions"+Arrays.toString(newRequestedPermissions.toArray()));
//param.args[1] = true;
[U][B]setObjectField(param.args[0], "requestedPermissions", newRequestedPermissions);[/B][/U]
}
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
ArrayList<String> origRequestedPermissions = (ArrayList<String>) param.getObjectExtra("orig_requested_permissions");
if (origRequestedPermissions != null)
setObjectField(param.args[0], "requestedPermissions", origRequestedPermissions);
}
};
if (Build.VERSION.SDK_INT < 21) {
findAndHookMethod(clsPMS, "grantPermissionsLPw", "android.content.pm.PackageParser$Package", boolean.class, hookGrantPermissions);
} else {
findAndHookMethod(clsPMS, "grantPermissionsLPw", "android.content.pm.PackageParser$Package", boolean.class, String.class, hookGrantPermissions);
}
}
@Override
public void initZygote(StartupParam startupParam) throws Throwable {
XSharedPreferences pref = new XSharedPreferences(this.getClass().getPackage().getName(), Strings.PREF_NAME);
pref.makeWorldReadable();
newPerms = Strings.read(pref);
}
Sidenote: Code is partially forked from Appsettings module: https://github.com/rovo89/XposedAppSettings
The problem is: when I restart my phone after enabling the module, I just get a blackscreen after the bootanimation.
When I comment out the line marked fat underlined, it works, but does nothing (because this line is essential).
I have practically no idea why this isn't working.
I know that the input returned from Strings.read is valid.
My Question: What am I doing wrong?
Click to expand...
Click to collapse
I am doing something similar. Maybe you can get some ideas from my PermissionGranter at:
https://github.com/GravityBox/Gravi...co/lollipop/gravitybox/PermissionGranter.java
I thought it would be better to modify the query instead of lists itself, but I'll try that out. Thanks!
Now my Hook looks like this:
Code:
XC_MethodHook hookGrantPermissions = new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
String pkgName = (String) getObjectField(param.args[0], "packageName");
if (!(pkgName.equals(Strings.LLX) || pkgName.equals(Strings.LL))) return;
Object extras = getObjectField(param.args[0], "mExtras");
Set<String> grantedPerms = (Set<String>) getObjectField(extras, "grantedPermissions");
Object settings = getObjectField(param.thisObject, "mSettings");
Object permissions = getObjectField(settings, "mPermissions");
for (String perm : newPerms) {
Object permission = callMethod(permissions, "get", perm);
if (permission == null) continue;
grantedPerms.add(perm);
int[] gpGids = (int[]) getObjectField(extras, "gids");
int[] bpGids = (int[]) getObjectField(permission, "gids");
gpGids = (int[]) callStaticMethod(param.thisObject.getClass(),
"appendInts", gpGids, bpGids);
if (BuildConfig.DEBUG) XposedBridge.log("Permission added: " + permission);
}
}
};
But checkCallingOrSelfPermsisson still fails for the added permissions...
I get the log (in fact two times) but I still don't seem to have the permissions inside of the app.
Solved it myself. If there is a shared user, it has to be used instead of normal object.
Code:
XC_MethodHook hookGrantPermissions = new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
String pkgName = (String) getObjectField(param.args[0], "packageName");
if (!(pkgName.equals(Strings.LLX) || pkgName.equals(Strings.LL))) return;
Object extras = getObjectField(param.args[0], "mExtras");
Set<String> grantedPerms = (Set<String>) getObjectField(extras, "grantedPermissions");
Object sharedUser = getObjectField(extras, "sharedUser");
if(sharedUser != null) grantedPerms = (Set<String>) getObjectField(sharedUser, "grantedPermissions");
Object settings = getObjectField(param.thisObject, "mSettings");
Object permissions = getObjectField(settings, "mPermissions");
for (String perm : newPerms) {
Object permission = callMethod(permissions, "get", perm);
if (permission == null) continue;
grantedPerms.add(perm);
int[] gpGids = (int[]) getObjectField(sharedUser!=null?sharedUser:extras, "gids");
int[] bpGids = (int[]) getObjectField(permission, "gids");
callStaticMethod(param.thisObject.getClass(),
"appendInts", gpGids, bpGids);
if (BuildConfig.DEBUG) XposedBridge.log("Permission added: " + permission);
}
}
};
@C3C076 do you know any way how to get runtime (level dangerous) permissions on Android Marshmallow?
Getting normal permissions is actually a bit easier now, but I haven't found a way for runtime permissions.
Related
Hi, I have code:
Code:
Class<?> pm =
XposedHelpers.findClass(packageManagerService, null);
hookAllConstructors(pm, packageManagerServiceHook);
packageManagerServiceHook = new XC_MethodHook() {
@Override
protected void afterHookedMethod(final MethodHookParam param) throws Throwable {
Context context = (Context) XposedHelpers.getObjectField(
param.thisObject, "mContext");
if (context == null && param.args.length != 0) {
context = (Context) param.args[0];
}
XposedBridge.log(context==null? "null" : "not null");
if (context != null) {
mContext = context;
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ACTION_ENABLE_SIGNATURE_CHECK);
intentFilter.addAction(ACTION_DISABLE_SIGNATURE_CHECK);
mContext.registerReceiver(mBroadcastReceiver, intentFilter);
}
}
};
I get "not null" but then, I get NPE on line mContext.registerReceiver(mBroadcastReceiver, intentFilter); Any solution?
I'd check if mBroadcastReceiver is null, I don't see you assigning that. Otherwise post the full log.
public class MainActivity extends Activity {
EditText name, phonenumber, address;
Button insert;
RequestQueue requestQueue;
String insertUrl = "localhosti/insertCustomer.php";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/* CHECK INTERNET CONNECTION */
boolean mobileNwInfo = false;
ConnectivityManager conxMgr = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
try { mobileNwInfo = conxMgr.getActiveNetworkInfo().isConnected(); }
catch (NullPointerException e) { mobileNwInfo = false; }
if ( mobileNwInfo == false ) {
Toast.makeText(this, "No Network, please check your connection. ", Toast.LENGTH_LONG).show();
}
/* CHECK INTERNET CONNECTION PROCEDURE DONE */
name = (EditText) findViewById(R.id.editText);
phonenumber= (EditText) findViewById(R.id.editText2);
address = (EditText) findViewById(R.id.editText3);
insert = (Button) findViewById(R.id.insert);
requestQueue = Volley.newRequestQueue(getApplicationContext());
insert.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
final ProgressDialog pd = new ProgressDialog(MainActivity.this);
pd.setMessage("Booking Service ....");
pd.show();
StringRequest request = new StringRequest(Request.Method.POST, insertUrl, new Response.Listener<String>() {
@Override
public void onResponse(String response) {
pd.hide();
System.out.println(response.toString());
name.setText("");
phonenumber.setText("");
address.setText("");
Toast.makeText(getApplicationContext(), "Service successfully booked !!", Toast.LENGTH_LONG).show();
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
pd.hide();
Toast.makeText(getApplicationContext(), "Error: Please try again later.", Toast.LENGTH_LONG).show();
}
}) {
@Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> parameters = new HashMap<String, String>();
parameters.put("name", name.getText().toString());
parameters.put("phonenumber", phonenumber.getText().toString());
parameters.put("address", address.getText().toString());
return parameters;
}
};
requestQueue.add(request);
}
});
}
}
Click to expand...
Click to collapse
how can i fetch the data from a spinner and post it to my db along with the current data ?
Code:
public class SuperHook implements IXposedHookLoadPackage, IXposedHookZygoteInit {
Config mConfig;
Gson mGson;
@Override
public void initZygote(StartupParam startupParam) throws Throwable {
mConfig = new Config();
mGson = new Gson();
}
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
Log.d("SuperHook", "handleLoadPackage imei:" + mConfig.getmImei());
if (loadPackageParam.packageName.equals("cn.superscript.supertools")) {
Class<?> classSuperService = XposedHelpers.findClass(SuperService.class.getName(), loadPackageParam.classLoader);
XposedHelpers.findAndHookMethod(classSuperService, "onStartCommand", Intent.class, int.class, int.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
Intent intent = (Intent) param.args[0];
String json = intent.getStringExtra("json");
mConfig = mGson.fromJson(json, new TypeToken<Config>() {
}.getType());
Log.d("SuperHook", "onStartCommand: imei = " + mConfig.getmImei());
}
});
}
}
}
Log:
01-21 18:49:56.220 664-664/? D/SuperHook: handleLoadPackage imei:null
01-21 18:49:56.240 664-664/? D/SuperHook: onStartCommand: imei = 3333333
01-21 18:50:00.930 757-757/com.android.settings D/SuperHook: handleLoadPackage imei:null
why handleLoadPackage imei = null , onStartCommand: imei = 3333333 successful.
Please help me, thank you
Hey guys, I am having problem with deleting the childview from my expandablelistview. It deletes (I think), however, when I add a new childview, it is the exact same as the one I just deleted.
youtu.be/eJjR9FEpaaY
codes below
My activity
Code:
public class PlanSetterAct extends AppCompatActivity {
private Button nextBtn;
private EditText planName, weekNum;
private ExpandableListView weekdayList;
List<String> listDataHeader;
HashMap<String, List<String>> listDataChild;
private PlanSetterListAdapter adapter;
private int childCount = 0;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.plan_setter);
weekdayList = (ExpandableListView) findViewById(R.id.plan_setter_exercise_list);
nextBtn = (Button) findViewById(R.id.plan_next_btn);
planName = (EditText) findViewById(R.id.plan_name_edit);
weekNum = (EditText) findViewById(R.id.plan_num_edit);
prepareNextButton();
prepareExerciseList();
adapter = new PlanSetterListAdapter(this.getApplicationContext(),listDataHeader,listDataChild);
weekdayList.setAdapter(adapter);
exerciseListChildListener();
}
private void prepareNextButton(){
nextBtn.animate().setDuration(1000);
nextBtn.animate().translationXBy(-500);
nextBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(Checker.hasText(planName) && Checker.isNum(weekNum)){
Utilities.setButtonClickColor(nextBtn, Color.GREEN);
startActivity(new Intent(PlanSetterAct.this, UserMainAct.class));
finish();
Utilities.debugLog("Moving to UserMainAct");
}else{
Utilities.setButtonClickColor(nextBtn, Color.RED);
}
}
});
}
private void prepareExerciseList() {
listDataHeader = new ArrayList<String>();
listDataChild = new HashMap<String, List<String>>();
// Adding child data
listDataHeader.add("Monday");
listDataHeader.add("Tuesday");
listDataHeader.add("Wednesday");
listDataHeader.add("Thursday");
listDataHeader.add("Friday");
listDataHeader.add("Saturday");
listDataHeader.add("Sunday");
for(int i = 0; i < listDataHeader.size(); i++) {
listDataChild.put(listDataHeader.get(i), new ArrayList<String>());
}
}
private void exerciseListChildListener(){
weekdayList.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
ExpandableListView expandableListView = (ExpandableListView) parent;
long pos = expandableListView.getExpandableListPosition(position);
int itemType = ExpandableListView.getPackedPositionType(pos);
int groupPosition = ExpandableListView.getPackedPositionGroup(pos);
int childPosition = ExpandableListView.getPackedPositionChild(pos);
List<String> parentGroup = listDataChild.get(listDataHeader.get(groupPosition));
if(itemType == ExpandableListView.PACKED_POSITION_TYPE_GROUP){
parentGroup.add(childPosition+"");
adapter.notifyDataSetChanged();
return true;
}else if(itemType == ExpandableListView.PACKED_POSITION_TYPE_CHILD){
debugLog("Parent position: " + groupPosition +" | child position: " + childPosition);
parentGroup.remove(childPosition);
adapter.notifyDataSetChanged();
return true;
}
return false;
}
});
}
}
My Adapter
Code:
public class PlanSetterListAdapter extends BaseExpandableListAdapter {
private Context context;
private List<String> listDataHeader;
private HashMap<String, List<String>> listDataChild;
public PlanSetterListAdapter(Context context, List<String> listDataHeader,
HashMap<String, List<String>> listChildData) {
this.context = context;
this.listDataHeader = listDataHeader;
this.listDataChild = listChildData;
}
@Override
public Object getChild(int groupPosition, int childPosititon) {
return this.listDataChild.get(this.listDataHeader.get(groupPosition))
.get(childPosititon);
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
@Override
public View getChildView(int groupPosition, final int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
final LayoutInflater inflater;
if (convertView == null) {
inflater= (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.add_exercise_layout, null);
}
final LinearLayout txtListChild = (LinearLayout) convertView.findViewById(R.id.plan_setter_add_exercise);
final LinearLayout addExerciseLayout = (LinearLayout) txtListChild.getChildAt(0);
Button okBtn = (Button) addExerciseLayout.getChildAt(1);
//init and gone from xml
okBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
TextView errorView = (TextView) txtListChild.getChildAt(1);
TextView finalView = (TextView) txtListChild.getChildAt(2);
LinearLayout exerciseAddLayout = (LinearLayout) addExerciseLayout.getChildAt(0);
EditText exerciseNameEdit = ((EditText)exerciseAddLayout.getChildAt(0));
EditText exerciseLbsEdit = (EditText)exerciseAddLayout.getChildAt(2);
EditText exerciseRepsEdit = (EditText) exerciseAddLayout.getChildAt(4);
if(hasText(exerciseNameEdit) && isNum(exerciseLbsEdit) && isNum(exerciseRepsEdit)){
String exerciseNameStr = exerciseNameEdit.getText().toString();
String exerciseWeightStr = exerciseLbsEdit.getText().toString()+"lbs";
String exerciseRepsStr = exerciseLbsEdit.getText().toString()+"x";
finalView.setText(exerciseNameStr + " at " + exerciseWeightStr + " for " +exerciseRepsStr);
finalView.setTextSize(20);
//display
setVisibleAndAnimate(context,finalView);
addExerciseLayout.setVisibility(View.GONE);
errorView.setVisibility(View.GONE);
}else{
setVisibleAndAnimate(context,errorView);
}
}
});
return convertView;
}
@Override
public int getChildrenCount(int groupPosition) {
return this.listDataChild.get(this.listDataHeader.get(groupPosition))
.size();
}
@Override
public Object getGroup(int groupPosition) {
return this.listDataHeader.get(groupPosition);
}
@Override
public int getGroupCount() {
return this.listDataHeader.size();
}
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
@Override
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
String headerTitle = (String) getGroup(groupPosition);
if (convertView == null) {
LayoutInflater infalInflater = (LayoutInflater) this.context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = infalInflater.inflate(R.layout.expandable_list_parent, null);
}
TextView lblListHeader = (TextView) convertView
.findViewById(R.id.lblListHeader);
lblListHeader.setTypeface(null, Typeface.BOLD);
lblListHeader.setText(headerTitle);
return convertView;
}
@Override
public boolean hasStableIds() {
return false;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
}
Have you ever tried to extend your favorite app with new features using Xposed, but were shocked halfway that your hooked app doesn't declare a permission in AndroidManifest ? And then you spent infinite hours on the internet trying to solve this frustrating problem, you decided to use services and an external intent, but you found out that it was not convenient, and finally you gave up...
So you are like me, who wasted hours looking for a solution, until I figured out how to do it myself. Here's a snippet to save time for future Xposed enthusiasts. Put this code snippet in handleLoadPackage
Java:
// Hook will only patch System Framework
if (!lpparam.packageName.equals("android")) return;
String targetPkgName = "com.example.app"; // Replace this with the target app package name
String[] newPermissions = new String[] { // Put the new permissions here
"android.permission.INTERNET",
"android.permission.ACCESS_NETWORK_STATE"
};
String grantPermissionsMethod = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
grantPermissionsMethod = "restorePermissionState";
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.S_V2) {
XposedBridge.log("[WARNING] THIS HOOK IS NOT GUARANTEED TO WORK ON ANDROID VERSIONS NEWER THAN ANDROID 12");
}
} else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.P) {
grantPermissionsMethod = "grantPermissions";
}
else {
grantPermissionsMethod = "grantPermissionsLPw";
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
XposedBridge.log("[WARNING] THIS HOOK IS NOT GUARANTEED TO WORK ON ANDROID VERSIONS PRIOR TO JELLYBEAN");
}
}
XposedBridge.hookAllMethods(XposedHelpers.findClass("com.android.server.pm.permission.PermissionManagerService", lpparam.classLoader),
grantPermissionsMethod, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
// on Android R and above, param.args[0] is an instance of android.content.pm.parsing.ParsingPackageImpl
// on Android Q and older, param.args[0] is an instance of android.content.pm.PackageParser$Package
// However, they both declare the same fields we need, so no need to check for class type
String pkgName = (String) XposedHelpers.getObjectField(param.args[0], "packageName");
XposedBridge.log("Package " + pkgName + " is requesting permissions");
if (pkgName.equals(targetPkgName)) {
List<String> permissions = (List<String>) XposedHelpers.getObjectField(param.args[0], "requestedPermissions");
for (String newPermission: newPermissions) {
if (!permissions.contains(newPermission)) {
permissions.add(newPermission);
XposedBridge.log("Added " + newPermission + " permission to " + pkgName);
}
}
}
}
});
Notes:
You must check System Framework in LSposed Manager
A reboot is required after adding the target permissions
You still need to prompt the user to accept sensitive permissions (ie android.permission.READ_CONTACTS), even if you have added them using this method
Wow, thx. Great for the install permissions!
I wrote a class to grant install and runtime/sensitive permissions (without prompting users).
Android 12 and 13 implementation:
Java:
public class Grant_Package_Permissions {
private static final int sdk = android.os.Build.VERSION.SDK_INT;
public static void hook(LoadPackageParam lpparam) {
try {
Class<?> PermissionManagerService = XposedHelpers.findClass(
sdk >= 33 /* android 13+ */ ?
"com.android.server.pm.permission.PermissionManagerServiceImpl" :
"com.android.server.pm.permission.PermissionManagerService", lpparam.classLoader);
Class<?> AndroidPackage = XposedHelpers.findClass(
"com.android.server.pm.parsing.pkg.AndroidPackage", lpparam.classLoader);
Class<?> PermissionCallback = XposedHelpers.findClass(
sdk >= 33 /* android 13+ */ ?
"com.android.server.pm.permission.PermissionManagerServiceImpl$PermissionCallback" :
"com.android.server.pm.permission.PermissionManagerService$PermissionCallback", lpparam.classLoader);
// PermissionManagerService(Impl) - restorePermissionState
XposedHelpers.findAndHookMethod(PermissionManagerService, "restorePermissionState",
AndroidPackage, boolean.class, String.class, PermissionCallback, int.class, new XC_MethodHook() {
@SuppressWarnings("unchecked")
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
// params
Object pkg = param.args[0];
int filterUserId = (int) param.args[4];
// obtém os campos
Object mState = XposedHelpers.getObjectField(param.thisObject, "mState");
Object mRegistry = XposedHelpers.getObjectField(param.thisObject, "mRegistry");
Object mPackageManagerInt = XposedHelpers.getObjectField(param.thisObject, "mPackageManagerInt");
// Continua ?
String packageName = (String) XposedHelpers.callMethod(pkg, "getPackageName");
Object ps = XposedHelpers.callMethod(mPackageManagerInt,
sdk >= 33 /* android 13+ */ ?
"getPackageStateInternal" :
"getPackageSetting", packageName);
if (ps == null)
return;
int[] getAllUserIds = (int[]) XposedHelpers.callMethod(param.thisObject, "getAllUserIds");
int userHandle_USER_ALL = XposedHelpers.getStaticIntField(Class.forName("android.os.UserHandle"), "USER_ALL");
final int[] userIds = filterUserId == userHandle_USER_ALL ? getAllUserIds : new int[]{filterUserId};
for (int userId : userIds) {
List<String> requestedPermissions;
Object userState = XposedHelpers.callMethod(mState, "getOrCreateUserState", userId);
int appId = (int) XposedHelpers.callMethod(ps, "getAppId");
Object uidState = XposedHelpers.callMethod(userState, "getOrCreateUidState", appId);
// package 1
if (packageName.equals("PACKAGE_1")) {
requestedPermissions = (List<String>) XposedHelpers.callMethod(pkg, "getRequestedPermissions");
grantInstallOrRuntimePermission(requestedPermissions, uidState, mRegistry,
Manifest.permission.RECORD_AUDIO);
grantInstallOrRuntimePermission(requestedPermissions, uidState, mRegistry,
Manifest.permission.MODIFY_AUDIO_SETTINGS);
}
// package 2
if (packageName.equals("PACKAGE_2")) {
requestedPermissions = (List<String>) XposedHelpers.callMethod(pkg, "getRequestedPermissions");
grantInstallOrRuntimePermission(requestedPermissions, uidState, mRegistry,
Manifest.permission.READ_CONTACTS);
}
}
}
});
} catch (Exception e) {
XposedBridge.log(e);
}
}
private static void grantInstallOrRuntimePermission(List<String> requestedPermissions, Object uidState,
Object registry, String permission) {
if (!requestedPermissions.contains(permission))
XposedHelpers.callMethod(uidState, "grantPermission",
XposedHelpers.callMethod(registry, "getPermission", permission));
}
}
Edit: Android 12 and 13 implementation!
this looks promising. how to use this in xposed ? is there a module available?