Unauthorized Caller Error - android

I am stuck writing some code that uses reflection that calls IConnectivityManager.startLegacyVpn
The error I get is java.lang.SecurityException: Unauthorized Caller
Looking through the android source I see this is the code hanging me up:
if (Binder.getCallingUid() != Process.SYSTEM_UID) { raise the above exception }
My question is if I root my AVD and install my app in system/app will this be sufficient to get around this error?
If so, any tips on how to do this (every time I try to move my apk to the system/app folder it says the app is not installed when I click on the app icon.
Thanks!

I have the same problem, following android 4.01 open source, i see somethings like this:
public synchronized LegacyVpnInfo getLegacyVpnInfo() {
// Only system user can call this method.
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
throw new SecurityException("Unauthorized Caller");
}
return (mLegacyVpnRunner == null) ? null : mLegacyVpnRunner.getInfo();
}
Or,
// Only system user can revoke a package.
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
throw new SecurityException("Unauthorized Caller");
}
Or,
public void protect(ParcelFileDescriptor socket, String interfaze) throws Exception {
PackageManager pm = mContext.getPackageManager();
ApplicationInfo app = pm.getApplicationInfo(mPackage, 0);
if (Binder.getCallingUid() != app.uid) {
throw new SecurityException("Unauthorized Caller");
}
jniProtect(socket.getFd(), interfaze);
}
However, these block of code above is belongs to com.android.server.connectivity.Vpn
(class Vpn), which is not defined in interface IConnectivityManager.
I also find in startLegacyVpnInfo() function but i can't see anything involve exception
"Unauthorized Caller", so i wonder why startLegacyVpnInfo() function throws this exception?
Any solutions for this?

I am trying to make the same calls. So far I can confirm that rooting the device and copying the apk to /system/app does not work, it does not start under the system uid.
Also, this does not work:
Field uidField = Process.class.getDeclaredField("SYSTEM_UID");
uidField.setAccessible(true);
uidField.set(null, Process.myUid());
Those calls succeed, but they don't seem to affect the SYSTEM_UID field, the field is probably optimized out at compile time.

If you include android: sharedUserId="android.uid.system" into your manifest tag (not just the manifest), this should then run the application as system. This should now let you run the code.
As for pushing to /system/app, you need to run adb root followed by adb remount. This will now let you push to /system/app.

Related

Android AccountManager's getAuthToken SecurityException

i (lets say app 'C' )am trying to get the auth token of an installed app ( say 'S' ) through Android's AccountManager's getAuthToken function.
this function is not working as expected, it doesn't return any results (the run function is never called )
AccountManagerFuture<Bundle> future1 = AccountManager.get(Main2.this).getAuthToken(account,account.type,null,false, new AccountManagerCallback<Bundle>() {
#Override
public void run(AccountManagerFuture<Bundle> future) {
Bundle result = null;
try {
result = future.getResult();
String check = "";
}
catch (OperationCanceledException e){ }
catch (IOException e1){}
catch (AuthenticatorException e2){}
}
} , new Handler(Looper.getMainLooper()));
when i see the device ADB Logs, i see the following
java.lang.SecurityException: Activity to be started with KEY_INTENT must share Authenticator's signatures
at com.android.server.accounts.AccountManagerService$Session.onResult(AccountManagerService.java:2580)
at com.android.server.accounts.AccountManagerService$6.onResult(AccountManagerService.java:1677)
at com.android.server.accounts.AccountManagerService$6.onResult(AccountManagerService.java:1652)
at android.accounts.IAccountAuthenticatorResponse$Stub.onTransact(IAccountAuthenticatorResponse.java:59)
Apps 'C' and 'S' described above are unrelated, so they are signed with different certificates.
I am guessing the function should have worked in above scenario ( which is one of the main purpose of AccountManager - Sharing of account access tokens across apps ) as well ( with a security dialog thrown to the user on whether he should allow 'C' to access 'S' ) , whats the reason it is not working ? Am i missing anything here ?
Thanks
First go to your implementation of AbstractAuthenticator in app S. Find getAuthToken() implementation. Check, which activity you return as KEY_INTENT. It must be in same app as authenticator (yes, there are ways to launch an activity from another app).
Make sure, you run on a real device, because you must see a "grant permissions" android system screen in that case.
If you come here, than I don't know another reason except some bug. Try totally removing both apps and restarting emulator, then check if problem persists.

How to install apps in phone which contains sqlite database in android

I want to install my app which contains regestration form whose username and password is stored im sqlite database. after copyiny .apk file my apps does not contains any database table for that work.
So my question is how to import this database in my app which is installed on android device it is working fine on emulator.
Have you initialized database class object
EditDatabase db=new EditDatabase(this);
onCreate or onResume activity?
if not then initialize it.
Update from logcat output
Based on the logcat output, it shows that this is an unhandled exception. i.e. it happens outside the try{} ... catch{} block of the onClick(View) method.
This means that it is a problem in one of these 2 lines:
unname = username1.getText().toString();
storePassword1 = db.getdata(unname);
My feeling is that username1 is null because it is not referenced in your layout XML file.
Here's how you should check - replace those 2 lines with these null checks:
if (unname != null)
{
unname = username1.getText().toString();
}
else
{
Log.d("MyTag", "unname is null");
}
if (storePassword1 != null)
{
storePassword1 = db.getdata(unname);
}
else
{
Log.d("MyTag", "storePassword1 is null");
}
if (unname == null || storePassword1 == null)
{
return;
}
Run the code again, check the logcat output again, and see if it tells you about the problem.
Also try not to use System.out(String) - rather use the Log.d(String, String) methods. These are more useful on Android.
Original
Firstly, please provide a stack trace - it will show where the null pointer error happened.
For Android, the most useful way of doing that will be to use the adb logcat terminal command. This outputs the internal log of your Android device/emulator to the screen, so you can view what went wrong.
In your catch{} block, I would put the following line:
Log.d("MyTag", "Stack Trace of exception...", e);
This will output the text, and information about the error e to this log - I think it will include the stack trace.
Copy the lines starting with "MyTag" and paste them into your question.
Secondly, without the stack trace, confirm that these 3 variables are not null typically:
username1
db
password (if the app actually crashed with the NullPointerException then this one is not the problem, because the exception would be handled by the catch{} block)
i.e. confirm that you have initialised all of them before the click event.

Lucky patcher, how can I protect from it? [duplicate]

This question already has answers here:
Way to protect from Lucky Patcher / play licensing [closed]
(8 answers)
Closed 5 years ago.
I know this topic has been opened multiple times and I learnt a lot but I stumbled across a problem I really need advice on.
I'm using LVL with Obfuscation. I changed the default LVL ALOT so that anti-LVL does not break it. However, Lucky Patcher with one click breaks it! I tried to see the new broken APK. Yes it simply called my "allow method".
My question is if someone can recommend a way to prevent Lucky Patcher from breaking it? I know I can't make it bullet-proof, but I want it at least to be not so easy for one-click software.
Code to check your certificate:
public void checkSignature(final Context context) {
try {
Signature[] signatures = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES).signatures;
if (signatures[0].toCharsString() != <YOUR CERTIFICATE STRING GOES HERE>) {
// Kill the process without warning. If someone changed the certificate
// is better not to give a hint about why the app stopped working
android.os.Process.killProcess(android.os.Process.myPid());
}
}
catch (NameNotFoundException ex) {
// Must never fail, so if it does, means someone played with the apk, so kill the process
android.os.Process.killProcess(android.os.Process.myPid());
}
}
Next how to find which one is your certificate. You must produce an APK, in release mode, as the debug certificate is different from the release one. Output your certificate into your Logcat:
signatures[0].toCharsString();
Remember that when you are back to debug mode, the certificate is different again. To avoid debug issues use next line to skip the verification:
if ((context.getApplicationContext().getApplicationInfo().flags &= ApplicationInfo.FLAG_DEBUGGABLE) != 0)
return;
Next the lucky patcher checker.
I decompiled all versions of Lucky Patcher, and I've found that its creator used 2 package names between all realeases. So you only need to keep track of new versions and keep adding future package names.
private boolean checkLuckyPatcher() {
if (packageExists("com.dimonvideo.luckypatcher"))
return true;
if (packageExists("com.chelpus.lackypatch"))
return true;
if (packageExists("com.android.vending.billing.InAppBillingService.LACK"))
return true;
return false;
}
private boolean packageExists(final String packageName) {
try {
ApplicationInfo info = this.getPackageManager().getApplicationInfo(packageName, 0);
if (info == null) {
// No need really to test for null, if the package does not
// exist it will really rise an exception. but in case Google
// changes the API in the future lets be safe and test it
return false;
}
return true;
}
catch (Exception ex) {
// If we get here only means the Package does not exist
}
return false;
}
As of current version (6.4.6), Lucky Patcher generates very short token. For example, real purchase token:
felihnbdiljiajicjhdpcgbb.AO-J1OyQgD6gEBTUHhduDpATg3hLkTYSWyVZUvFwe4KzT3r-O7o5kdt_PbG7sSUuoC1l6dtqsYZW0ZuoEkVUOq5TMi8LO1MvDwdx5Kr7vIHCVBDcjCl3CKP4UigtKmXotCUd6znJ0KfW
And that is Lucky Token:
kvfmqjhewuojbsfiwqngqqmc
Pretty straight forward solution is to check string length of token
#Override public void onIabPurchaseFinished(IabResult result, Purchase info) {
if (info.getToken().length < 25) {
Log.wtf("PIRATE", "PIRATE DETECTED");
return;
}
}
Implement a function that gets called under certain actions, and which checks whether the LuckyPatcher package is installed in the device.
If found, then exit your app. Don’t allow to use it regardless if is paid or not, better bad reviews than thousands of illegal copies. Alternatively you could show a message stating that LuckyPatcher has been found and the app can't run.
If your app gets patched by LuckyPatcher, meaning that it has hacked your LVL implementation, then at least your app will not execute due to the LuckyPatcher package detection.
A way, is to check if lucky patcher is installed and if so, then show a message to the user, and kill your process afterwards. If a user has it, means he is trying to crack your software or other developer's one. So better not to allow to use your app in a phone that has it installed. Fight piracy.
Whenever Lucky Patcher creates a modded APK file, it always ends up with a different package name, as you can't run two apps under the same package name.
Here's a simple solution that checks if your code is running under the wrong package name:
PackageManager pm = getPackageManager();
try {
PackageInfo packageInfo = pm.getPackageInfo("YOUR_PACKAGE_NAME",PackageManager.GET_ACTIVITIES);
} catch (PackageManager.NameNotFoundException e){
finish();
//If you get here, your code is running under a different package name... Kill the process!
}
I just call finish(); on my app and I can't break it, but it might be best to use android.os.Process.killProcess(android.os.Process.myPid()); as #PerracoLabs suggested.

Runtime.exec() bug: hangs

First thing my app does is checking for "su" since it's necessary for the app to work. Even though it sometimes work, often after typing "killall packageName" in the terminal. I've done a simple test application and I can't get it to work every time.
Code where it happens:
String[] args = new String[] { "su" };
Log.v(TAG, "run(" + Arrays.toString(args) + ")");
FutureTask<Process> task = new FutureTask<Process>(new Callable<Process>() {
#Override
public Process call() throws Exception {
return Runtime.getRuntime().exec(args);
}
});
try {
Executors.newSingleThreadExecutor().execute(task);
return task.get(10, TimeUnit.SECONDS);
} catch (Throwable t) {
task.cancel(true);
throw new IOException("failed to start process within 10 seconds", t);
}
Complete project: https://github.com/chrulri/android_testexec
Since this app does nothing more than running exec() in the first place, I cannot close any previously opened file descriptors as mentioned in another stackoverflow question: https://stackoverflow.com/a/11317150/1145705
PS: I run Android 4.0.3 / 4.0.4 on different devices.
3c71 was right about open file descriptors. In my case, it was the AdMob SDK which caused the problems since it was sometimes (re-)loading the Ads from the web at the sime time I tried to call exec(..) leaving me hanging in a deadlock.
My solution is to fork a "su" process ONCE and reuse it for all commands and load the Ads AFTER forking that process.
To use Runtime.exec safely you should wait for the process to finish and consume the output and error streams, preferably concurrently (to prevent blocking):
http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html

How to prevent name caching and detect bluetooth name changes on discovery

I'm writing an Android app which receives information from a Bluetooth device. Our client has suggested that the Bluetooth device (which they produce) will change its name depending on certain conditions - for the simplest example its name will sometimes be "xxx-ON" and sometimes "xxx-OFF". My app is just supposed to seek this BT transmitter (I use BluetoothAdapter.startDiscovery() ) and do different things depending on the name it finds. I am NOT pairing with the Bluetooth device (though I suppose it might be possible, the app is supposed to eventually work with multiple Android devices and multiple BT transmitters so I'm not sure it would be a good idea).
My code works fine to detect BT devices and find their names. Also, if the device goes off, I can detect the next time I seek, that it is not there. But it seems that if it is there and it changes name, I pick up the old name - presumably it is cached somewhere. Even if the bluetooth device goes off, and we notice that, the next time I detect it, I still see the old name.
I found this issue in Google Code: here but it was unclear to me even how to use the workaround given ("try to connect"). Has anyone done this and had any luck? Can you share code?
Is there a simple way to just delete the cached names and search again so I always find the newest names? Even a non-simple way would be good (I am writing for a rooted device).
Thanks
I would suggest 'fetchUuidsWithSdp()'. It's significance is that, unlike the similar getUuids() method, fetchUuidsWithSdp causes the device to update cached information about the remote device. And I believe this includes the remote name as well as the SPD.
Note that both the methods I mentioned are hidden prior to 4.0.3, so your code would look l ike this:
public static void startServiceDiscovery( BluetoothDevice device ) {
// Need to use reflection prior to API 15
Class cl = null;
try {
cl = Class.forName("android.bluetooth.BluetoothDevice");
} catch( ClassNotFoundException exc ) {
Log.e(CTAG, "android.bluetooth.BluetoothDevice not found." );
}
if (null != cl) {
Class[] param = {};
Method method = null;
try {
method = cl.getMethod("fetchUuidsWithSdp", param);
} catch( NoSuchMethodException exc ) {
Log.e(CTAG, "fetchUuidsWithSdp not found." );
}
if (null != method) {
Object[] args = {};
try {
method.invoke(device, args);
} catch (Exception exc) {
Log.e(CTAG, "Failed to invoke fetchUuidsWithSdp method." );
}
}
}
}
You'll then need to listen for the BluetoothDevice.ACTION_NAME_CHANGED intent, and extract BluetoothDevice.EXTRA_NAME from it.
Let me know if that helps.

Categories

Resources