When I use LKM to hook syscall about Android Kernel,I get something wrong
but I'm not good at Linux kernel debug,and I want to know how to deal with this problem.The similar problem told me the reason is read is blocked but module has been rmmod,I want to know how to solve this problem.
The reason is I want to monitor the apk's behavior.so I choose hook Linux kernel 3.4.67(goldfish) and with Android 4.4.4 code complied
Here is My code,when I insmod the module,it really get the action about read sth. But when I rommd the module ,the emulator direct get oops,and I finally find the reason is in my sys_read() hook,because when I hook syscall open ,it's okay.
#include <linux/kernel.h>
#include <linux/module.h>
#include<linux/init.h>
#include <linux/unistd.h>
#include <linux/semaphore.h>
#include <linux/moduleparam.h>
#include <asm/cacheflush.h>
#include<linux/delay.h>
#include<linux/file.h>
#include<linux/fs.h>
#include<linux/dirent.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("SafeCode han");
void ** sys_call_table;
asmlinkage int (*original_call_read) (unsigned int, char*, int);
asmlinkage int hack_sys_read(unsigned int fd, char * buf, int count){
if(fd == 0 && count == 1)
{
printk("something is read aha %s\n", buf);
}
return original_call_read(fd,buf count);
}
int init_module()
{
//this is my sys_call_table address which found in System.map
sys_call_table =(void*)0xc000d984;
printk(KERN_ALERT "testhahaha\n");
original_call_read = sys_call_table[__NR_read];
sys_call_table[__NR_read] = hack_sys_read;
return 0;
}
/*when I need to rommd my module ,the devices oops..*/
void cleanup_module()
{
sys_call_table[__NR_read]=original_call_read;
//sys_call_table[__NR_open]=original_call_open;
}
so ,Plz help me~ thanks~,I want to know the depth reason and the solution
It is unsafe to revert previous value of the syscall's pointer and unload the module, contained replacement code: some process may use your syscall function at this moment, and it will be very upset when its code is gone off. As far as I know, there is no protection against that.
Syscalls are not intended to be changed by kernel modules. Either patch kernel code itself, or do not touch syscalls at all and use some sort of hooks, e.g. kprobes.
Related
I saw a post on bypassing the root detection for android app by using frida server. When i following these steps, root detection is not working. Any one have an idea to protect the root detection from bypassing using Frida server/any other
Check for root in a shared library and launch an activity saying, the device is rooted from the shared lib itself clearing the back stack.
The native binaries are difficult to reverse engineer (They need function name to manipulate on Frida).
Also you can prevent frida from attaching to your app.
From frida docs we can see that frida uses ptrace
Frida needs in a first step to inject an agent in the targeted >application so that it is in the memory space of the process.
On Android and Linux such injection is done with ptrace by attaching
or spawning a process and then injecting the agent. Once the agent is
injected, it communicates with its server through a pipe.
When the ptrace system call is used to attach to a process, the "TracerPid" field in the status file of the debugged process shows the PID of the attaching process. The default value of "TracerPid" is 0 (no process attached). Consequently, finding anything other than 0 in that field is a sign of debugging or other ptrace shenanigans.
The following implementation is from Tim Strazzere's Anti-Emulator project:
#include <jni.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <pthread.h>
static int child_pid;
void *monitor_pid() {
int status;
waitpid(child_pid, &status, 0);
/* Child status should never change. */
_exit(0); // Commit seppuku
}
void anti_debug() {
child_pid = fork();
if (child_pid == 0)
{
int ppid = getppid();
int status;
if (ptrace(PTRACE_ATTACH, ppid, NULL, NULL) == 0)
{
waitpid(ppid, &status, 0);
ptrace(PTRACE_CONT, ppid, NULL, NULL);
while (waitpid(ppid, &status, 0)) {
if (WIFSTOPPED(status)) {
ptrace(PTRACE_CONT, ppid, NULL, NULL);
} else {
// Process has exited
_exit(0);
}
}
}
} else {
pthread_t t;
/* Start the monitoring thread */
pthread_create(&t, NULL, monitor_pid, (void *)NULL);
}
}
JNIEXPORT void JNICALL
Java_sg_vantagepoint_antidebug_MainActivity_antidebug(JNIEnv *env, jobject instance) {
anti_debug();
}
Please refer to this guide for anti-debugging tricks by vantagepoint.
There is a specific section in this guide which addresses frida
Also https://github.com/b-mueller/frida-detection-demo
Otherwise, you can use the service of Appdome (IPaaS) to block frida from attaching to your app
I am interested in demoing printf vulnerabilities via an NDK app. To be clear, I am aware that to log in the console we can use __android_log_print(ANDROID_LOG_DEBUG, "LOG_TAG", "Print : %d %s",someVal, someStr);. I have tried it and I know it works. But I explicitly want to demo the vulnerabilities of printf(), specifically to use the %n specifier to write to a pointed location.
Is there a way to make printf() work to this effect or is it possible to achieve this via __android_log_print()? I attempted it with the android/log.h header but it didn't work.
I can get the app to crash by running something along the lines of printf(%s%s%s%s%s%s%s%s%s%s). But again, I can't manipulate pointers.
For general knowledge purposes, why is it that printf() doesn't work in the first place and how does __android_log_print() prevent these exploits?
You do realize that Android is open source.
Starting with looking for __android_log_print()
and finding it: https://android.googlesource.com/platform/system/core/+/refs/heads/master/liblog/logger_write.cpp
int __android_log_print(int prio, const char* tag, const char* fmt, ...) {
va_list ap;
char buf[LOG_BUF_SIZE];
va_start(ap, fmt);
vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
va_end(ap);
return __android_log_write(prio, tag, buf);
}
I eventually ended up looking at: https://android.googlesource.com/platform/bionic/+/refs/heads/master/libc/stdio/vfprintf.cpp
lines 453-454:
case 'n':
__fortify_fatal("%%n not allowed on Android");
Also referenced in the code is additional safety through FORTIFY which is described in the following blog post:
https://android-developers.googleblog.com/2017/04/fortify-in-android.html
Android specifically does not support %n format specifiers because they're vulnerable.
https://android.googlesource.com/platform/bionic/+/400b073ee38ecc2a38234261b221e3a7afc0498e/tests/stdio_test.cpp#328
Our Android software uses a virtual file system (VFS) for SQLite, which has been working correctly. Once we began using it with Android 6 (Marshmallow) all sorts of weird errors started to occur with large negative offsets being passed to ftruncate(), stack overflows, data corruptions, etc. Using readelf (among other tools), we eventually traced the problem to a change in the imports used by libsqlite.so: Lollipop and earlier import ftruncate and mmap, the newest libraries import ftruncate64 and mmap64. We "solved" the problem by changing which functions we use depending on the API version (Marshmallow is version 23):
/*
* Empirical testing of Tab S2 running Marshmallow revealed the SQLite
* unix_syscall table uses "ftruncate" and "mmap" as connection points,
* but the actual functions linked against are the *64 versions. This
* leads to stack corruption and all sorts of nasty errors as a result.
*/
if (getApiVersion() >= 23) // for Marshmallow
{ setUnixSystemCall(NULL, "ftruncate", our_ftruncate64);
setUnixSystemCall(NULL, "mmap", our_mmap64);
}
else // for Lollipop & older
{ setUnixSystemCall(NULL, "ftruncate", our_ftruncate);
setUnixSystemCall(NULL, "mmap", our_mmap);
}
Looking at the source code both from http://www.sqlite.org/2015/sqlite-amalgamation-3081002.zip and https://github.com/android/platform_external_sqlite/blob/master/dist/sqlite3.c all that the C source calls is ftruncate and mmap which makes our methodology "questionable" at best.
How does libsqlite.so import and use ftruncate64 and mmap64 where the source code only calls ftruncate and mmap? Are we not looking at the correct source code repository? Is there something going on at a link step? Did Marshmallow remove support for the non-64 bit versions of these functions?
It turns out the headers in the NDK don't exactly match the corresponding headers that the OS is ​built with!
Bionic: https://android.googlesource.com/platform/bionic.git/+/marshmallow-release/libc/include
Here's the way to BUILD the NDK: https://android.googlesource.com/platform/ndk/+/marshmallow-release
In particular,
https://android.googlesource.com/platform/bionic.git/+/marshmallow-release/libc/include/unistd.h
#if defined(__USE_FILE_OFFSET64)
extern int truncate(const char *, off_t) __RENAME(truncate64);
extern off_t lseek(int, off_t, int) __RENAME(lseek64);
extern ssize_t pread(int, void *, size_t, off_t) __RENAME(pread64);
extern ssize_t pwrite(int, const void *, size_t, off_t) __RENAME(pwrite64);
extern int ftruncate(int, off_t) __RENAME(ftruncate64);
https://android.googlesource.com/platform/bionic.git/+/marshmallow-release/libc/include/sys/mman.h has similar macros for mmap - the __RENAME() in the system headers means that any code built using the system headers (e.g., libc.so) will only export ftruncate64, not ftruncate, and when an app that calls ftruncate is linked against libc.so, it instead imports ftruncate64 rather than the call the source code was written with.
We didn't dive into the __RENAME() macro to investigate how this magic happens - the reality of trying to get a product out the door prohibits how deep we can go down the rabbit hole. If anybody wants to investigate this further, however, this is where you start.
I am using android 4.2.2(Jelly Been) with linux-kernel 3.0.31 source code. I am trying to hook open system call but i don't know that how to change a page from read-only to writable given an address because sys_call_table is read-only.
I have do it successfully on linux Ubuntu12.04 3.2.32 with lookup_address() function below.
int make_rw(unsigned long address)
{
unsigned int level;
pte_t *pte = lookup_address(address, &level);
if(pte->pte &~ _PAGE_RW)
pte->pte |= _PAGE_RW;
return 0;
}
but unfortunately this function is for x86 not for arm. I don't know how to do it on arm-arch
another way: based on write protect register
#define CR0_WP 0x10000 //Write Protect Bit (CR0:16)
unsigned long cr0;
cr0 = read_cr0();
write_cr0(cr0 & ~CR0_WP);/* remove write protection*/
hookfunc(){...};
write_cr0(cr0);/* set write protection*/
but i do not know the relative register on arm-arch
Does there anyone have solved this problem? waiting for answer online!
I have integrated two native libraries (.so ) in my application. The libraries compile fine and I can load them in my application too. The first time I invoke a native method of a library it works fine, but if I call the same method again in the Activity the application shuts down.
The problem I am facing is exactly the same as mentioned in here :
http://grokbase.com/t/gg/android-ndk/1226m68ydm/app-exit-on-second-native-call
The solution that works is to invoke the native method in another Activity and shut it down forcefully via System.exit(0). Following the article I tried setting the pointers to NULL of the called method after a successful operation, but this too didn't help me. Also its not possible to unload a library once its loaded by System.loadLibrary().
I want to call the native methods more than once without creating a new Activity. Any ideas how to solve this issue ?
(I FINALLY FOUND A SOLUTION ... HERE IT IS)
Okay, I have finally found a way to resolve this issue. The solution is actually pretty simple. Build another independent native library (utility library) to load and unload the other libraries. What we need to do is use dlopen() and dlclose() in the native method of the utility. We can load the utility library like before via System.loadLibrary().
So in the native method of the utility library what we need to do is:
Use#include <dlfcn.h> // this is required to call dlopen() and dlclose() functions.
Provide handler and function prototype:
void *handle;
typedef int (*func)(int); // define function prototype
func myFunctionName; // some name for the function
Open the library via dlopen() :
handle = dlopen("/data/data/my.package.com/lib/somelibrary.so", RTLD_LAZY);
Get and Call the function of the library:
myFunctionName = (func)dlsym(handle, "actualFunctionNameInLibrary");
myFunctionName(1); // passing parameters if needed in the call
Now that the call is done. Close it via dlclose():
dlclose(handle);
Hope this will help others facing the same issue.
So ... my solution was starting a service that runs the shared library code, this service has a different process name ( you can set it in the Android Manifest ), as it is a different process you can kill it ( Using Process.killProcess(Process.myPid()) when it finishes running, without affecting your application in any way.
Worked very well for me, hope it helps someone else.
As this is the top hit for this issue and as the issue itself still exists, it seems that the approach that ZakiMak shared with us is still the most popular solution.
For others who may want to implement it and would like a little more detail for the latest Android releases, here are some notes I made as I stumbled through this:
Firstly, there is a solution which implements this approach on GitHub now. I have not tried it personally, but I have used it as a reference. It is very useful to see how the Android.mk file is structured and how the library is opened and methods called. Link is here: https://github.com/jhotovy/android-ffmpeg
The path to the native library folder changes over Android releases and it also appears to change every time you run the app (although this may be just in debug mode). Either way, it is best to pass the path in from the calling Java method if possible. For example:
In the Java wrapping class:
import android.content.Context;
import android.util.Log;
public class FfmpegJNIWrapper {
//This class provides a Java wrapper around the exposed JNI ffmpeg functions.
static {
//Load the 'first' or 'outer' JNI library so this activity can use it
System.loadLibrary("ffmpeg_wraper_multi_invoke_jni");
}
public static int call_ffmpegWrapper(Context appContext, String[] ffmpegArgs) {
//Get the native libary path
String nativeLibPath = appContext.getApplicationInfo().nativeLibraryDir;
//Call the method in the first or 'outer' library, passing it the
//native library past as well as the original args
return ffmpegWrapper(nativeLibPath, ffmpegArgs);
}
// Native methods for ffmpeg functions
public static native int ffmpegWrapper(String nativeLibPath, String[] argv);
}
In the 'first' or 'outer' native library:
JNIEXPORT jint JNICALL Java_com_yourpackage_androidffmpegwrapper_FfmpegJNIWrapper_ffmpegWrapper(JNIEnv *pEnv, jobject pObj, jstring nativeLibPath, jobjectArray javaArgv) {
//Get the second or 'inner' native library path
char* nativePathPassedIn = (char *)(*pEnv)->GetStringUTFChars(pEnv, nativeLibPath, NULL);
char ourNativeLibraryPath[256];
snprintf(ourNativeLibraryPath, sizeof (ourNativeLibraryPath), "%s%s", nativePathPassedIn, "/libffmpeg_wraper_jni.so"); //the name of your ffmpeg library
//Open the so library
void *handle;
typedef int (*func)(JNIEnv*, jobject, jobjectArray);
handle = dlopen(ourNativeLibraryPath, RTLD_LAZY);
if (handle == NULL) {
__android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "could not open library: %s", dlerror());
printf("Could not dlopen(\"libbar.so\"): %s\n", dlerror());
return(-1);
}
//Call the ffmpeg wrapper functon in the second or 'inner' library
func reenterable_ffmpegWrapperFunction;
reenterable_ffmpegWrapperFunction = (func)dlsym(handle, "Java_com_yourpackage_androidffmpegwrapper_FfmpegJNIWrapper_ffmpegWrapper");
reenterable_ffmpegWrapperFunction(pEnv, pObj, javaArgv); //the original arguments
//Close the library
dlclose(handle);
// return
return(1);
}
The Android.mk file is a little 'flaky' to put it politely. Because you are building two separate libraries in one Android.mk file, this may be a little more complex that other NDK make files so if you get some strange errors do some searching before you start taking your project apart. For example: https://stackoverflow.com/a/6243727/334402