I've been using a few Android apps that hook onto another process, scan its allocated memory and edit it. Obviously, I was using it to mess around with some games.
Then, it got me thinking, "How are they doing it?"
I know how to get the list of currently running apps but hooking onto another process and scanning and editing the process' memory are.. Beyond my knowledge.
It seems that I'd need some kind of "root" privileges to execute code like that but I don't mind. I just want to know how these app developers did it to sate my curiosity.
So..
Assuming root privileges are enabled..
1) How can I hook onto a currently running different app?
2) How can I scan its memory regions?
3) How can I edit its memory regions?
inb4 "Have you tried googling?"
I thought about it and did a tonne of Googling (1+ hours) but no results because the words "RAM" and "memory" just gives me stuff like how to track the current app's memory allocations and whatnot. In other words, not what I am looking for.
So, I finally turned to opening a thread here.
Putting this here for posterity
After a fair bit of research (read, 5 days straight), as far as Linux is concerned, one may attach to a process, read its memory and detach by simply doing this:
Heavily commented for the newbies like me, uncomment and whatever if you're better
#include <sys/ptrace.h> //For ptrace()
#include <sys/wait.h> //For waitpid()
int main () {
int pid = 1337; //The process id you wish to attach to
int address = 0x13371337; //The address you wish to read in the process
//First, attach to the process
//All ptrace() operations that fail return -1, the exceptions are
//PTRACE_PEEK* operations
if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) == -1) {
//Read the value of errno for details.
//To get a human readable, call strerror()
//strerror(errno) <-- Returns a human readable version of the
//error that occurred
return 0;
}
//Now, attaching doesn't mean we can read the value straight away
//We have to wait for the process to stop
int status;
//waitpid() returns -1 on failure
//W.I.F, not W.T.F
//WIFSTOPPED() returns true if the process was stopped when we attached to it
if (waitpid(pid, &status, 0) == -1 || !WIFSTOPPED(status)) {
//Failed, read the value of errno or strerror(errno)
return 0;
}
errno = 0; //Set errno to zero
//We are about to perform a PTRACE_PEEK* operation, it is possible that the value
//we read at the address is -1, if so, ptrace() will return -1 EVEN THOUGH it succeeded!
//This is why we need to 'clear' the value of errno.
int value = ptrace(PTRACE_PEEKDATA, pid, (void*)addr, NULL);
if (value == -1 && errno != 0) {
//Failed, read the value of errno or strerror(errno)
return 0;
} else {
//Success! Read the value
}
//Now, we have to detach from the process
ptrace(PTRACE_DETACH, pid, NULL, NULL);
return 0;
}
References:
http://linux.die.net/man/2/ptrace
http://linux.die.net/man/2/waitpid
How does this relate to editing Android app memory values?
Well, the headers for ptrace and wait exist in the Android NDK. So, to read/write an app's RAM, you will need native code in your app.
Also, ptrace() requires root privileges.
Why did it take you this long?
I've never written this kind of code before.
As far as Linux is concerned, it's forbidden by kernel to modify other memory that belongs to other processes (by the way, this is why there are no viruses on Linux).
What you are actually doing is editing Shared Preferences. They are written in plain text, and that means they can be edited if you have access to them(root).
You can check out CheatDroid application at Play Store. Also, if you want to develop similar app yourself, you can also check this link to create your first root app. http://www.xda-developers.com/android/how-to-build-an-android-app-part-2-writing-a-root-app-xda-tv/
Related
I try to access the accelerometer from the NDK. So far it works. But the way events are written to the eventqueue seems a little bit strange.
See the following code:
ASensorManager* AcquireASensorManagerInstance(void) {
typedef ASensorManager *(*PF_GETINSTANCEFORPACKAGE)(const char *name);
void* androidHandle = dlopen("libandroid.so", RTLD_NOW);
PF_GETINSTANCEFORPACKAGE getInstanceForPackageFunc = (PF_GETINSTANCEFORPACKAGE) dlsym(androidHandle, "ASensorManager_getInstanceForPackage");
if (getInstanceForPackageFunc) {
return getInstanceForPackageFunc(kPackageName);
}
typedef ASensorManager *(*PF_GETINSTANCE)();
PF_GETINSTANCE getInstanceFunc = (PF_GETINSTANCE) dlsym(androidHandle, "ASensorManager_getInstance");
return getInstanceFunc();
}
void init() {
sensorManager = AcquireASensorManagerInstance();
accelerometer = ASensorManager_getDefaultSensor(sensorManager, ASENSOR_TYPE_ACCELEROMETER);
looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
accelerometerEventQueue = ASensorManager_createEventQueue(sensorManager, looper, LOOPER_ID_USER, NULL, NULL);
auto status = ASensorEventQueue_enableSensor(accelerometerEventQueue,
accelerometer);
status = ASensorEventQueue_setEventRate(accelerometerEventQueue,
accelerometer,
SENSOR_REFRESH_PERIOD_US);
}
That's how I initialize everything. My SENSOR_REFRESH_PERIOD_US is 100.000 - so 10 refreshs per second. Now I have the following method to receive the events of the event queue.
vector<sensorEvent> update() {
ALooper_pollAll(0, NULL, NULL, NULL);
vector<sensorEvent> listEvents;
ASensorEvent event;
while (ASensorEventQueue_getEvents(accelerometerEventQueue, &event, 1) > 0) {
listEvents.push_back(sensorEvent{event.acceleration.x, event.acceleration.y, event.acceleration.z, (long long) event.timestamp});
}
return listEvents;
}
sensorEvent at this point is a custom struct which I use. This update method gets called via JNI from Android every 10 seconds from an IntentService (to make sure it runs even when the app itself is killed). Now I would expect to receive 100 values (10 per second * 10 seconds). In different tests I received around 130 which is also completly fine for me even it's a bit off. Then I read in the documentation of ASensorEventQueue_setEventRate that it's not forced to follow the given refresh period. So if I would get more than I wanted it would be totally fine.
But now the problem: Sometimes I receive like 13 values in 10 seconds and when I continue to call update 10 secods later I get the 130 values + the missing 117 of the run before. This happens completly random and sometimes it's not the next run but the fourth following or something like that.
I am completly fine with being off from the refresh period by having more values. But can anyone explain why it happens that there are so many values missing and they appear 10 seconds later in the next run? Or is there maybe a way to make sure I receive them in their desired run?
Your code is correct and as i see only one reason can be cause such behaviour. It is android system, for avoid drain battery, decreases frequency of accelerometer stream of events in some time after app go to background or device fall asleep.
You need to revise all axelerometer related logic and optimize according
Doze and App Standby
Also you can try to work with axelerometer in foreground service.
How can I check if the device has low storage on Android 8 Oreo. I saw in the Android Documentation that the Intent.ACTION_DEVICE_STORAGE_LOW is deprecated in API 26.
This constant was deprecated in API level 26.
if your app targets O or above, this broadcast will no longer be delivered to any BroadcastReceiver defined in your manifest. Instead, apps are strongly encouraged to use the improved getCacheDir() behavior so the system can automatically free up storage when needed.
- Android Documentation
They are encouraging me use getCacheDir() instead.
But I don't understand much of it, as getCacheDir() seems to return the system cache directory path as a FILE object, which can only be used to clear cache or some such.
But I need to check whether the device is running low on device storage. I hope someone will help me in this
See Android's (AndroidX work) StorageNotLowTracker implementation for an example of how to receive system broadcasts when storage becomes low or OK.
Note that this is the implementation used by AndroidX work when using a 'storage not low constraint'. It uses deprecated intent filter broadcast actions, but it still works today.
I have created a similar implementation (not shared in this answer) that can be registered, unregistered and has two callbacks: on storage low and on storage OK.
See StorageNotLowTrackerTest for an example of how to test this.
Old answer kept for reference below
As correctly stated in the question, the API 26 Intent.ACTION_DEVICE_STORAGE_LOW is deprecated and Context#getCacheDir() is advised to be used instead to free up space from you application's cache.
There are multiple problems with this (enumerated below), but first: note that it is good practice to keep cache 'reasonably small' (e.g. 1 MB), I quote:
getCacheDir()
Returns a File representing an internal directory for your app's temporary cache files. Be sure to delete each file once it is no longer needed and implement a reasonable size limit for the amount of memory you use at any given time, such as 1MB.
Caution: If the system runs low on storage, it may delete your cache files without warning.
(source)
So, there are three problems here:
We should clear the cache, but it is probably already reasonably small (e.g. 1 MB), so clearing it will probably not free enough space for the free storage to become OK again (similar to the also deprecated Intent.ACTION_DEVICE_STORAGE_OK that previously could be used for this)
As quoted, the cache quite possibly has already been cleared by the system, because the storage is low and the system may clear your application's cache if it so decides. Therefore, clearing it yourself possibly does not free up any storage.
The documentation does not specify at all how to actually detect if the device is low on storage.
So, clearing the cache doesn't seem to help, so I won't go into the details of how to do that.
However, as per this answer, we could assume that at 10% free storage the system enters the low storage state that we want to detect. This number is Android's default, but there's little preventing a device manufacturer (or ROM developer) from changing it, according to the linked answer.
At this point, to me, this 10% is a magic number and I'd like to know if I can determine this threshold programmatically. If you know how, please edit my answer, post an answer yourself or comment on my answer.
To do this using getCacheDir(), you could use the following:
Java, from a Context (e.g. Activity):
File cacheDir = getCacheDir();
if (cacheDir.getUsableSpace() * 100 / cacheDir.getTotalSpace() <= 10) { // Alternatively, use cacheDir.getFreeSpace()
// Handle storage low state
} else {
// Handle storage ok state
}
Kotlin, from a Context (e.g. Activity):
if (cacheDir.usableSpace * 100 / cacheDir.totalSpace <= 10) { // Alternatively, use cacheDir.freeSpace
// Handle storage low state
} else {
// Handle storage ok state
}
Now, whether to use the usable space or free space, that's not entirely clear to me. The difference is described here.
Diving into the Android source I found a system service, that I cannot access in my code, that checks for low storage: DeviceStorageMonitorService. It gets its lowBytes variable from StorageManager#getStorageLowBytes, which I cannot access either. If that would be possible in some non-hacky way, that would be a way to get the low storage bytes threshold. There you see the source uses getUsableSpace(), so that's why I chose that instead of getFreeSpace() too for my code snippets.
After digging into the code of android excatlty the class that release the Low storage notification called DeviceStorageMonitorService
Here's what i found, Some phones use the sys_storage_threshold_percentage and some use sys_storage_threshold_max_bytes so to test the storage you should get the real value from the Settings.Secure using both keys and then compare between sys_storage_threshold_percentage * Total memory size of data system folder and sys_storage_threshold_max_bytes and then take the small value and compare it to the available storage space of data system folder, here's the code of how to do it
private void checkForLowStorage() {
long mFreeMem = getDeviceCurrentStorage();
float deviceLowStorageThreshold = getDeviceLowStorageThreshold();
if (mFreeMem <= deviceLowStorageThreshold) {
Toast.makeText(this, R.string.low_storage_error_message, Toast.LENGTH_LONG).show();
// Handle storage low state
} else {
// Handle storage ok state
}
}
private long getDeviceCurrentStorage() {
long mFreeMem = 0;
try {
StatFs mDataFileStats = new StatFs("/data");
mDataFileStats.restat("/data");
mFreeMem = (long) mDataFileStats.getAvailableBlocksLong() *
mDataFileStats.getBlockSizeLong();
} catch (IllegalArgumentException e) {
// use the old value of mFreeMem
}
return mFreeMem;
}
private long getDeviceLowStorageThreshold() {
long value = Settings.Secure.getInt(
getContentResolver(),
"sys_storage_threshold_percentage",
10);
StatFs mDataFileStats = new StatFs("/data");
long mTotalMemory = ((long) mDataFileStats.getBlockCountLong() *
mDataFileStats.getBlockSizeLong()) / 100L;
value *= mTotalMemory;
long maxValue = Settings.Secure.getInt(
getContentResolver(),
"sys_storage_threshold_max_bytes",
500*1024*1024);
return Math.min(value, maxValue);
}
I'm still testing it, Dunno if it's not going to work on some devices
I'm trying to write a service that communicates with a USB device using USB Interrupt transfer. Basically I'm blocking on UsbConnection.requestWait() in a thread to wait for interrupts transfers in, then pass those to the activity using an intent.
I seem to be having problems when the USB devices sends me a largish number of interrupt packets in a row (about 50). It sometimes works but usually the app crash with a message of that flavor:
02-23 01:55:53.387: A/libc(8460): ### ABORTING: heap corruption detected by tmalloc_small
02-23 01:55:53.387: A/libc(8460): Fatal signal 11 (SIGSEGV) at 0xdeadbaad (code=1), thread 8460 (pf.mustangtamer)
it's not always a malloc call that fails, I have seen several flavors of malloc (dlmalloc, malloc_small) as well as dlfree. In every instance I get a Fatal Signal 11 and a reference to 0xdeadbaad so somehow I am corrupting the heap.
It's not obvious from the heap dump what is causing the corruption.
Here is what I believe is the offending code (the problem only occurs when receiving many packets back to back to back):
private class ReceiverThread extends Thread {
public ReceiverThread(String string) {
super(string);
}
public void run() {
ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
buffer.clear();
UsbRequest inRequest = new UsbRequest();
inRequest.initialize(mUsbConnection, mUsbEndpointIn);
while(mUsbDevice != null ) {
if (inRequest.queue(buffer, BUFFER_SIZE) == true) {
// (mUsbConnection.requestWait() is blocking
if (mUsbConnection.requestWait() == inRequest){
buffer.flip();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
//TODO: use explicit intent, not broadcast
Intent intent = new Intent(RECEIVED_INTENT);
intent.putExtra(DATA_EXTRA, bytes);
sendBroadcast(intent);
} else{
Log.d(TAG, "mConnection.requestWait() returned for a different request (likely a send operation)");
}
} else {
Log.e(TAG, "failed to queue USB request");
}
buffer.clear();
}
Log.d(TAG, "RX thread terminating.");
}
}
Right now the activity is not consuming the intents, I'm trying to get the USB communication to stop crashing before I implement that side.
I'm not seeing how the code above can corrupt the heap, possibly through some non-thread safe behavior. Only one request is queued at a time so I think "buffer" is safe.
My target is a tablet running JB 4.3.1 if that makes a difference.
I'm not seeing anything wrong with this either. You may want to try removing code from your loop and see if it still corrupts the heap to help you zoom on the offending area.
Remember that heap operations are usually delayed, the garbage collector doesn't run immediately, so you could be corrupting it somewhere else, and it's only showing up in this loop because it is very heap intensive.
try to use a larger heap size by setting android:largeHeap="true" in your application manifest.
I would have asked these questions in a comment, but alas, not enough rep.
I see nothing directly wrong with the code above, but I would check the following:
What is BUFFER_SIZE? crazily, I've had very strange problems with UsbRequest.queue() for sizes greater than 15KB. I'm pretty sure that this wouldn't cause your heap corruption, but it could lead to weirdness later. I had to break my requests into multiple calls to queue() to do large reads.
Are you using a bulk USB endpoint? I don't know what your application is, so I cant say for sure if you should be using a bulk endpoint or not, but its the type of endpoint intended for large transfers.
Lastly, when I encountered this 0xdeadbaad problem (detected by tmalloc_large), it had nothing to do with the code I thought was at fault (the code near the malloc) - it was of course a threading issue in which I had JNI native code reading/writing the same buffers on multiple separate threads! Its only that it gets detected when malloc is called, as user3343927 mentioned.
I am writing network communication program with Android ndk, using epoll.
I found the method ‘epoll_wait’ woken not very accurate
while(1){
struct epoll_event events[3];
log_string("epoll_wait start");//here will print start time
events_len = epoll_wait(_epoll_fd, events, 3, 20 * 1000);// wait 20 second,for test,I use pipe instead of socket,monitor a pipe EPOLLIN event
if (events_len <= 0) {
log_string("epoll_wait end events_len=%d,errno=%d", events_len, errno);//Normally,the events_len always is 0,and errno is 0
}
}
The above code runs on the PC(like Ubuntun PC) is very normal,as expected.
If it runs on Android Phone(use Android Service , separate thread to run) is as expected at first.
After some time,epoll_wait becomes not very accurate,sometimes got -1 and errno=4,sometimes waited very long.
So I only know that phenomenon, but do not know why.
Can you tell why and tell me the best practices for use android epoll?
thx
4 is EINTR, which means your app got a signal. This isn't really an error, just restart epoll.
Regarding "waited very long", does your app hold at least a partial wakelock?
I am trying to set the Performance Monitor User Mode Enable register on all cpus on a Nexus 4 running a mako kernel.
Right now I am setting the registers in a loadable module:
void enable_registers(void* info)
{
unsigned int set = 1;
/* enable user-mode access to the performance counter*/
asm volatile ("mcr p15, 0, %0, c9, c14, 0\n\t" : : "r" (set));
}
int init_module(void)
{
online = num_online_cpus();
possible = num_possible_cpus();
present = num_present_cpus();
printk (KERN_INFO "Online Cpus=%d\nPossible Cpus=%d\nPresent Cpus=%d\n", online, possible, present);
on_each_cpu(enable_registers , NULL, 1);
return 0;
}
The problem is that on_each_cpu only runs the function on Online cpus and as shown by the printk statment:
Online Cpus=1
Possible Cpus=4
Present Cpus=4
Only one of the four is online when I call on_each_cpu. So my question is, how do I force a cpu to be online, or how can force a certain cpu to execute code?
Thanks
You don't need to run the code on every cpu right now. What you need to do is arrange so that when the offline cpus come back online, your code is able to execute and enable the access to the PMU.
One way to achieve that would be with a cpu hotplug notifier.