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
Related
I have a minimal Android app created with the new project wizard with c++ support enabled. The purpose of the app is to allow c++ to call back into java after catching a signal (SIGSEGV). The sequence of the program is short and sweet, pseudo code would be like:
Enter Native Method handleSegv()
Native code calls back into java as a test
Native code sets up SIGSEGV handler
Enter Native Method sendSegv()
Native code raises/sends SIGSEGV
Enter Native Method signal_handler
Native code catches signal and logs it
Native code calls back into java
Native code logs again to show its stepped past the callback
The only step above that isn't working is step 3.2. It seems that after catching SIGSEGV nothing happens when the native code tries to call back into java. I've tried this both in the emulator and on the device with the same results. I'm not sure at this point if I'm doing something wrong or if there is something fundamental about handling the signal that won't allow me to call back into java after catching it.
I have code demonstrating this which can be cloned from the repo from on github but really there are only two source files:
CrashActivity.java:
package com.kevinkreiser.crashtest;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
public class CrashActivity extends AppCompatActivity {
static {
System.loadLibrary("native-lib");
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_crash);
//setup segv handler
handleSegv();
//cause a segv
sendSegv();
}
/**
* Sets up signal handler for SIGSEGV which will call the callback function below
* #return true if the handler was set
*/
public native boolean handleSegv();
/**
* Raises the SIGSEGV signal which will cause the handler to be called
*/
public native void sendSegv();
/**
* A function that the native code will call back when it receives SIGSEGV
* as an illustration it just logs
*
* #param message The message coming back from c++
*/
public void callback(String message) {
Log.e("CrashActivity.callback", message);
}
}
native-lib.cpp:
#include <android/log.h>
#include <jni.h>
#include <string.h>
#include <signal.h>
#include <string>
//globals persisting between calls from javaland
static JavaVM* vm = NULL;
static jobject activity = NULL;
static jmethodID callback = NULL;
//gets called first when a signal is sent to the running pid
static void signal_handler(int signal, siginfo_t*, void*) {
//get an env so we can call back to java
JNIEnv* env;
if(vm->AttachCurrentThread(&env, NULL) != JNI_OK)
return;
//call back to java with a message
__android_log_print(ANDROID_LOG_ERROR, "native-lib.signal_handler", "Calling with signal %d", signal);
std::string message = "Got signal " + std::to_string(signal);
jstring msg = env->NewStringUTF(message.c_str());
env->CallVoidMethod(activity, callback, msg);
__android_log_print(ANDROID_LOG_ERROR, "native-lib.signal_handler", "Called with signal %d", signal);
}
extern "C" JNIEXPORT void JNICALL
Java_com_kevinkreiser_crashtest_CrashActivity_sendSegv(JNIEnv*, jobject) {
raise(SIGSEGV);
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_kevinkreiser_crashtest_CrashActivity_handleSegv(JNIEnv* env, jobject obj) {
//get java hooks we need to make the callback
env->GetJavaVM(&vm);
activity = env->NewGlobalRef(obj);
if (!activity)
return false;
jclass activity_class = env->GetObjectClass(activity);
if (!activity_class)
return false;
callback = env->GetMethodID(activity_class, "callback", "(Ljava/lang/String;)V");
if (!callback)
return false;
//try calling back to java with a message
jstring message = env->NewStringUTF("No signal yet");
env->CallVoidMethod(activity, callback, message);
//register for SIGSEGV
struct sigaction action;
memset(&action, 0, sizeof(struct sigaction));
action.sa_sigaction = signal_handler;
action.sa_flags = SA_SIGINFO;
sigaction(SIGSEGV, &action, NULL);
return true;
}
When I run the program and I look at logcats output I see the following:
2019-01-15 11:59:50.795 11183-11183/com.kevinkreiser.crashtest E/CrashActivity.callback: No signal yet
2019-01-15 11:59:50.795 11183-11183/com.kevinkreiser.crashtest E/native-lib.signal_handler: Calling with signal 11
2019-01-15 11:59:50.795 11183-11183/com.kevinkreiser.crashtest E/native-lib.signal_handler: Called with signal 11
If I step through the program with the debugger and set a breakpoint in the native signal_handler I can step down to the line where it logs the first time Calling with signal.... After this if I step over any line that includes a call using the JNIEnv (env in this case) the debugger will detatch and the program will finish. You'll note that from the logcat output though, that I do get the last native log line Called with signal... after the calls making use of env and most importantly the call back into java.
I've seen other implementations here on stackoverflow that do essentially this but I've not been able to get any of them to work. I've also tried throwing a java exception from the native code but that ends up also not getting back to javaland with a message about pending exceptions. Can anyone see what is wrong here? Thanks in advance!
#Andrew Henle's comment was the correct answer:
Yes, you're doing something wrong: you're invoking undefined behavior by calling non-async-signal-safe functions from within a signal handler. Absent specific documentation supporting calling a function, such as the POSIX list of async-safe functions, you really can't make any calls from a signal handler. Footnote 188 of the C standard even states: "Thus, a signal handler cannot, in general, call standard library functions." POSIX provides a list of functions that are safe to call - under POSIX. Anything else is undefined behavior.
He previously gave a more detailed answer to this question here: https://stackoverflow.com/a/34553070/5251867
EDIT:
Looking over the available functions it seems there are two avenues that one can persue.
make use of open, write, close to drop a file with relevant info about the signal that was caught and deal with this file later (on app restart or from another service that monitors this file for changes)
make use of connect, bind, send to send the details over a socket to some other process
I guess both of these are technically IPC since both are means of letting another process get access to the information the signal handler puts out there. Getting this info to another process where you can do something with the information seems to be the only suitable way to go forward.
I am currently developing an app for Android and IOS using Qt Quick Controls 2 which will have login possibility. The account credentials will be stored into an external SQL database. I have figured out how I can interact with the database, but I am not able to figure out how I can use sessions in Qt for Android and IOS such that the user do not need to type the login credentials each time.
One possible way could be to store the credentials to a file locally on the phone, and then access the file each time the app is started. However, I am not sure if this is the best and safest way.
Thanks.
QSettings class is used for state management. QSettings information is often stored in the system registry on Windows, and in property list files on macOS and iOS. Here is raw example code that uses QSettings to store/retrieve session parameters .. you can extend to include needed session login management scenarios:
main.cpp
int main( int argc, char ** argv ) {
QApplication app( argc, argv );
app.setOrganizationName("myOrg");
app.setOrganizationDomain("myOrg.net");
app.setApplicationName("qsettings-test");
MyMainWindow mw;
mw.show();
return app.exec();
}
Then in your source .cpp
void MyMainWindow::readSettings() {
QSettings settings;
QString user = settings.value("UserName");
int lifTime = settings.value("sessionLifeTime").toInt();;
QByteArray state = settings.value("state", QByteArray())
.toByteArray();
restoreState(state);
}
// ...... lots of your code
void MyMainWindow::closeEvent(QCloseEvent* event) {
if (maybeSave()) {
writeSettings();
event->accept();
} else {
event->ignore();
}
}
void MyMainWindow::writeSettings() {
/* Save postion/size of main window */
QSettings settings;
settings.setValue("sessionLifeTime", 7);
settings.setValue("UserName", user);
settings.setValue("state", saveState());
}
You can also access INI and PLIST configuration files with QSettings class, For Android this can be considered where your INI file must be copied during build (store in res folder and include it in .pro ).
I try to display video on Android using Gstreamer like on other platforms:
gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(video_sink), this->ui->playback_widget->winId());
//playback_widget - QOpenGLWidget
But I think that winId() returns something else instead of ANativeWindow, because I get:
F libc : Fatal signal 11 (SIGSEGV), code 1, fault addr 0x5e in tid
3154 (gstglcontext)
So, how can I get instance of(or pointer to) ANativeWindow from some Qt widget on Android?
Support for embedding native widgets is incomplete and doesn't always work. Bear in mind that Qt may create native handles, but they do not necessarily represent actual native windows. Additionally, QWidget::winId() provides no effective guarantee of portability, only that the identifier is unique:
Portable in principle, but if you use it you are probably about to do something non-portable. Be careful.
The reason for this is that WId is actually a typedef for quintptr.
Solution: You will, at the very least, need to cast the return from winId to ANativeWindow, assuming this is the underlying window handle type that Qt uses to identify native windows.
This solution seems directed at X Windows but may provide some guidance.
Also see the documentation for QWidget::effectiveWinId() and QWidget::nativeParentWidget() for more helpful background information.
Update: Per the platform notes, there are quite a few caveats in using OpenGL + Qt + Android, including:
The platform plugin only supports full screen top-level OpenGL windows.
After the answer of #don-prog and some reading time I could make it work. Here is my code. Just a note: I have to delay this code execution until Qt finished loading views and layouts.
The following code retrieves the QtActivity Java object, then it dives into views and layout objects up to the QtSurface - which extends android.view.SurfaceView. Then it ask for the SurfaceHolder to finally get the Surface object that we need to call ANativeWindow_fromSurface.
QPlatformNativeInterface *nativeInterface = QApplication::platformNativeInterface();
jobject activity = (jobject)nativeInterface->nativeResourceForIntegration("QtActivity");
QAndroidJniEnvironment * qjniEnv;
JNIEnv * jniEnv;
JavaVM * jvm = qjniEnv->javaVM();
jvm->GetEnv(reinterpret_cast<void**>(&qjniEnv), JNI_VERSION_1_6);
jvm->AttachCurrentThread(&jniEnv,NULL);
jint r_id_content = QAndroidJniObject::getStaticField<jint>("android/R$id", "content");
QAndroidJniObject view = ((QAndroidJniObject) activity).callObjectMethod("findViewById", "(I)Landroid/view/View;", r_id_content);
if (view.isValid()) {
QAndroidJniObject child1 = view.callObjectMethod("getChildAt", "(I)Landroid/view/View;", 0);
QAndroidJniObject child2 = child1.callObjectMethod("getChildAt", "(I)Landroid/view/View;", 0);
if (child2.isValid()) {
QAndroidJniObject sHolder = child2.callObjectMethod("getHolder","()Landroid/view/SurfaceHolder;");
if (sHolder.isValid()) {
QAndroidJniObject theSurface = sHolder.callObjectMethod("getSurface","()Landroid/view/Surface;");
if (theSurface.isValid()) {
ANativeWindow* awindow = ANativeWindow_fromSurface(jniEnv, theSurface.object());
qDebug() << "This is a ANativeWindow " << awindow;
}
}
} else {
qDebug() << "Views are not loaded yet or you are not in the Qt UI Thread";
}
}
Hope it helps anybody else
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.
Continue my previous question, I succeeded to execute a process from an Android application. Now I can see two process like I wanted, they both up and running. Now I need to execute an Android application from the native C code.
Found similar questions (1, 2), but the following solutions did NOT work for me.
1. execl("/system/bin/sh", "sh", "-c", "am start -a android.intent.action.MAIN -n com.android.browser/.BrowserActivity", (char *)NULL);
2. execl("/system/bin/am", "start", "-a", "android.intent.action.MAIN",
"-n", "com.android.settings/.Settings", (char *)NULL);
None of the lines above didn't executed anything.
Even executing execl command with fork as follows did NOT help.
if (!fork()) {
execl...
}
Can you please give me some kind of a clue?
Thanks.
UPDATE: I've manage to print the stdout to the Android log, I'm getting errno
"Exec format error"
message from the execl method. Anybody have an idea how I can resolve this?
Maybe you can write this from the Android/ Java / VM scope and call it from native code using NDK & JNI (Java Native Interface) ?
Example :
From your app:
class MyActivity extends Activity {
public native int nativeMethodName();
public void launchSomeAppMethod() {
// launch some app
Intent LaunchIntent = getPackageManager().getLaunchIntentForPackage("com.package.someapp");
startActivity(LaunchIntent);
}
}
Native :
jint Java_com_yourpackage_appname_MyActivity_nativeMethodName(JNIEnv* env, jobject thiz) {
//....
// do your native work here
// ...
// call your obj instance that can launch another app
jclass cls = (*env)->GetObjectClass(env, thiz);
jmethodID method = (*env)->GetMethodID(env, cls, "launchSomeAppMethod", "()V");
(*env)->CallVoidMethod(env, thiz, method);
}
Hope it helps dude.
The error printed smells like permission problem.
Are you trying to run the application from an SD card? SD Cards by default are mounted without execute permission, you need to remount it.