This is a theoretical situation:
I am writing an app to detect the presence of another on the phone
The classpath, name, Activity names etc. of the target app have been randomized, I can't just check if it's there (it is semantically the same but syntactically unique)
I have root access to the phone
The app is open source, and (apart from the package name and application name) I know everything about it.
The app generates no Log output.
I've been thinking of ways to detect whether this other app is present on the phone (assuming it is actually run from time to time), are the following methods feasible at all?
Look periodically for the presence of certain classes in memory
Search for known chunks of the compiled code in each installed apk
Detect the app running by inspecting the memory of the device at certain intervals and look for usage patterns matching the app
Are there any other ways of detecting another app under these circumstances?
Use PackageManager. It has a method returning info about all the apps, installed on the system: getInstalledPackages().
Related
I am trying to diagnose an issue in an app I have written. The issue is a sporadic one, and occurs only under real-world conditions: in the field, away from my PC, and when I’m in the middle of something else, with no resources to spare for immediate debugging. Therefore, my best bet is collecting and analyzing log data.
Unfortunately, by the time I realize the issue has struck again and get around to debugging it, any log data has already rotated out of the Android log as I frequently have other chatty apps running at the same time. Increasing the size of the log buffer has not helped (either Android does not honor it or other apps are still too chatty) so I have abandoned this route.
For this reason, I am now considering having my app log to a separate text file in addition to the regular log.
Now I could easily double every call like
Log.i(TAG, "something happened");
adding another call that writes the same thing to the log file—but that does not seem very elegant to me.
Another option would be to replace all calls to Log with a wrapper that writes the event both to the Android log and the log file.
Question: Does the Android API provide a built-in mechanism for this, i.e. telling Log to write its data to the default log and a text file at the same time? Or do I need to code this by myself?
Edit:
Assumptions:
I know where in my code I need to generate log output (which can happen anywhere, which may or may not involve an exception) and what I want to be written to the log.
Getting log data from the device to my PC is also not a concern (one-man show, I just plug my phone into my PC and transfer the log file).
If you know the current Android API has no built-in mechanism to achieve what I want, then ”no, Android does not support this” is a perfectly acceptable answer. In that case the solution is clear—I would fall back to the wrapper function. I am specifically not looking for a different approach to the problem.
After doing some more research, it seems the Android API does not provide a standard way to do this. There are two possible workarounds:
Mirror output at the source
System.out and System.err output, which is written to the console in desktop systems, writes to the log on Android. These two can be redirected into any PrintStream of your choice, which would give you all Java console output. You can subclass PrintStream to duplicate its input, feeding it into the default stream as well as into a file of your choice.
Create a class which exposes the same methods as android.util.Log. In each method, call through to the respective android.util.Log method and additionally log the data to a file. If you call your class Log (but with a different package name, e.g. org.example.Log), then all you need to do is replace imports of android.util.Log with an import of your class, and any Log method calls will go to your class.
Caveats: This will only give you data explicitly logged by your code (i.e. for which you have the source files), as well as anything that goes to System.out or System.err. It will not include log output from JAR libraries (if you cannot modify their source code), nor any output generated by the system (such as stack traces from default exception handlers) or by other processes (some of which may be system processes and report conditions related to your process).
Read the logs from the command line
This article explains how to read the logs from within Android. In a nutshell:
Android includes a command line utility called logcat on the device, which will give you a continuous feed of log messages until stopped. (Try it by adb shelling into your device and running it. It has a bunch of command-line options to control its behavior. Not sure if it is present on all distributions, though.)
Launch this command via Runtime.getRuntime().exec("logcat"), then obtain the input stream of the process returned. This will give you an input stream of log messages.
According to the article, your app needs the android.permission.READ_LOGS permission to read logs.
I have read statements that certain versions of Android (4.2 was mentioned) do not allow this permission to be granted to non-system apps, though. According to my own tests, behavior without this permissions differ: Anbox will return the full logcat, while LineageOS (tested on 15.1) will only show log entries from the app which called it (including previous instances, presumably everything associated with the same Linux user). This can be a limitation or a welcome filter feature. YMMV.
logcat conveniently has a command line option, -f, to specify an output file. I tried
Runtime.getRuntime().exec("logcat -f " + absolutePathToLogFile);
and logcat keeps logging as long as the app’s process runs. Killing the app (by clicking the X in the title bar on Anbox) apparently also terminated the child process.
Now you can either run this code when your app starts up, or you can turn this functionality into a separate app which starts on boot and continuously collects logs for all apps.
Caveats: This may fill up your storage space quickly if you have some chatty apps running (which is why entries rotate out of the logcat so quickly in the first place). It is recommended to make log mirroring configurable (e.g. via Preferences) and/or ensure old files are deleted regularly. Also, if you keep the logcat process running until your app terminates, you will not be able to access the file over MTP as there is no easy way to run the media scanner (if you scan the file while it is still written to, it will appear truncated over MTP until another media scan runs).
You have not specified if some exception are thrown but you don't handle.
In case, take a look at this answer:
Android Handling Unhandled Exception
If you must look at a bunch of variables and objects, I'd suggest two choices:
Write a copy of your logs on a file. When your problem occurs, just ask the user to send the file to you. This is ideal during tests with self-aware users.
Obtain statistics about usage, like commercial software do. Just log user operations and send the data to your server (you would need one for this). This is the most transparent way to do remote logging.
In the case of writing log to a file, you can read and write what you want in internal memory (inside the app's sandbox) or external memory (in this case, write permission is required and explicit permission must have been granted at runtime if you are targeting Android 6 and above).
I thought there would be some straight forward solution to this.
Requirements:
Uniquely identify device across app install/uninstall sessions.
Options:
Use some kind of Android's device-identifier-API each time when needed (read it every time from Android's API). According to Identififying-app-installations blog post this is not recommended and not reliable solution.
Generate UUID once (on first app start) and persist it somewhere somehow that it would be preserved across multiple app installs/uninstalls. This "somewhere somehow" part is the mystery. Solutions like storing onto the SD card or Cloud are not an option. iOS has keychain that can be used for this kind of stuff but I didn't find Android's equivalent of it.
What are my other options here? I prefer going the (2) route because of my server implementation (server is generating UUID for the first time if not present). But if it is not an option, I can fallback to (1) and modify the server.
Thanks.
To uniquely identify an application between application installs/reinstalls, you need to get it's hardware ID and use that as your credentials/key.
To fetch the hardwareID, you can use the following method:
public static String getHardwareId(Context context) {
return Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
}
it's partially equivallent to a UUID with the following exception: The value may change if a factory reset is performed on the device.
The reason why i call it "partially equivallent" is this:
The HardwareID is a 64-bit number (as a hex string) that is randomly generated when the user first sets up the device and should remain constant for the lifetime of the user's device. The value may change if a factory reset is performed on the device.
Note: When a device has multiple users (available on certain devices running Android 4.2 or higher), each user appears as a completely separate device, so the ANDROID_ID value is unique to each user.
But this hits the #2 problem: where and how to store it; storing it in SharedPreferences is useless as that is wiped if the app is uninstalled. Same for /data/data/your.package.name/my_stored_keys folder as that one gets deleted from the phone during uninstallation as well.
You will need to save it server-side if you wish to persist between uninstalling and reinstalling the app.
Does anyone know what is the behavior in production of a device-owner App, distributed thru Google Play, when updates occur?
As we know, installing a device-owner App involves some motivation and is not easy: reset to factory default then NFC-provision the device with a second device etc… So even if we consider this step done, would any further update involve so much pain, each time?
This question occurs because on my development device, I cannot re-launch the device-owner App with changes if it was previously installed… unless I reset the device to factory settings!
Thanks for reading…
Once your Device Owner app is set, a new file is created under /data/system/device_owner.xml that references the Device/Profile owner apps.
The Android system is then reading this file to check which application is considered as Device Owner or Profile Owner App.
This file contains refers to the applications by using their package name. Updating these apps won't infer on this file since the package name stays the same.
When you're updating your app, just make sure you're always using the same certificate as the one you previously used when first setting you device owner for the first time (which is a standard rule of security for every application update in Android anyway).
Permissions can also be updated the same way, without the need to reprovision it through NFC, nor dpm tool.
I am trying to know if I can get root privileges with a system app to execute commands.
In this code:
getApplicationInfo().uid
In the documentation I can read that the uid is the kernel user-ID that has been assigned to this application; currently this is not a unique ID (multiple applications can have the same uid).
But how is this assigned?,
And the uid assigned to system apps,
does it has more privileges than normal apps to execute commands?
For all practical purposes, your Application's process will never be executing as uid=0 or root, as it has irreversibly changed to an ordinary user ID before a single line of code written by you executes.
When people make "root" apps, they are not changing the application process itself back to root - that is simply not possible. Instead, what they are doing is executing a new helper process which runs as root. Underneath the java level, this is ultimately done by calling an exec() family function on a file which has the setuid bit set. This file might either be the helper program itself, or more commonly it is a "root shim" such as a hacked "su" which in turn runs the specified helper program as root. Such a helper program is almost always native code, and is probably not registered with the Android framework to be able to utilize Android-level functionality.
System Applications do not run as root either. What they have that third party apps do not is special Android-level Permissions which cause platform services that do run as root or other privileged user id's to privileged things on their behalf. A few android permissions can also confer membership in user groups which have special access - some of these are available to third party apps (Internet permission for example) and some are not.
Basically, (I am not delving into the entire Linux explanation about uids. It can be easily found if you are interested). The uid in android is comprised of 2 parameters:
Application id
User id
The formula is this:
uid = app_id+100,000 * user_id
app_id is basically a random number (not REALLY random, but is different from device to device) that is assigned ti each application and the user_id, which is used on tablets running JellyBean, is assigned per user on the device (users are assigned a number starting user 0 , user 1, ...user n - for every new user defined on the device).
Applications can share an id as explained here: http://developer.android.com/guide/topics/manifest/manifest-element.html
Of course an app can't have the same uid for two different users, but the same app can have the same uid as another app the same user possesses.
System apps run are the only apps that may actually have access to services that other users may not have access to. They are located on the device under /system.
In order to write a system application you need to download the AOSP from Google, and compile it yourself with your app included.
This question has been asked before at How does Android enforce permissions?. While the discussions there are good, the question is still not fully answered.
In the development environment, exceptions are thrown when the app tries to do something that requires permissions not declared in AndroidManifest.xml. So how does the run-time system implement the run-time checking?
I guess it's most likely done in the core framework, which may or may not need support from native code. But I don't know what source code files in AOSP are relevant to this.
Android uses a lot of the standard Linux(-kernel?) mechanisms especially when it comes to hardware restrictions.
Every app gets assigned a new unique (Linux-)user id and whenever the app process is created the system creates it with that user id. The id will never change unless you remove the app. That means for accessing the lower system levels your app will appear as a certain user and every (Linux-)permission system that works with users will also apply to your app.
If you request WRITE_EXTERNAL_STORAGE in the manifest your app will also become member of the (Linux-)group (called sdcard_rw) that has permissions to write to that storage. Permissions on the filesystem are enforced to only allow writing to the system user (=owner) and the sdcard_rw group, anyone else (=other) may only read. See also Is Google blocking apps writing to SD cards
By doing that Android has to do pretty much nothing except for setting the correct UID/GIDs of the processes it spawns once the app starts and the rest is handled at lower levels. Apps that are not member of a certain group simply don't get access to certain hardware.
List of permission <> group mappings: platform.xml
There are also some (Android software) restrictions that are based on either the signature of your app and / or simply by looking up the permissions your app requested: e.g. ContextImpl#checkPermission() - but those permissions have to be checked at every entrypoint to code that allows restricted actions.
From time to time people discover ways to e.g. turn on GPS programmatically because a check like that is missing somewhere.
With regard to your second paragraph, "exceptions" are runtime faults. Permissions are not enforced at build time, only at run time.
Accessing hardware, low level operating system resources, and system files generally requires the app userid to be a member of an appropriate group which it may be assigned by the package manager as a result of having a corresponding android permission. (Familiar examples of that would be network sockets, and the sdcard write which zapl mentioned, but also system-only things like talking directly to the GSM modem or reading the raw touchscreen coordinates).
For the majority of android operations that are done by way of calling library functions which are stubs for interprocess communication to services running in a different process, the platform code running in the more privileged process on the receiving end of the ipc request checks with the package manager to find out if the calling application has the necessary android permission.
Many special permissions are only available to apps signed with the system signature - even if another app claims those in its manifest, they will not be applied by the package manager.