Usually stacktraces (backtraces) are generated from point where special stacktrace generation function is called (like _Unwind_Backtrace here: Android NDK: getting the backtrace). Is it possible to generate stacktrace which also includes libc functions? For example, I would like to inspect stacktrace for "open" libc call when it's called from my program (without modifying libc library). I know that in Java it's possible to invoke some method which throws exception and get stacktrace in exception handler from point where exception was thrown. I would like to do something similar in C but I don't think it's possible as there even are no exceptions in C.
For example, I would like to inspect stacktrace for "open" libc call when it's called from my program (without modifying libc library).
There are several use cases to consider:
Direct calls from your program to open
Indirect calls (e.g. you call getgroups, which opens /etc/nsswitch.conf)
Calls to open that are not triggered by your program at all (e.g. dynamic loader opening libc.so
Your question suggests that you are only interested in case 1, which is trivial to solve: compile the code from which you want to intercept open with -Dopen=open_with_stacktrace, and link with a separate file:
// Compile without -Dopen=...
#include <stdlib.>
ssize_t open_with_stacktrace(const char *fname, int flags, int mode)
{
// Do whatever to record the stack trace.
return open(fname, flags, mode);
}
For case 2, you may use a function interposer via LD_PRELOAD.
For case 3, you'll have to use external tracer, such as GDB.
What I actually want is to implement security feature ...
You should have started with that. In general, you can't implement any meaningful security in the program itself, you have to use an external monitor.
You are trying to detect whether someone interposed open. But that someone could just as easily interpose your "checker" function, and make it always return "everything is fine" result.
You should consider using one of the sandboxing techniques instead.
Related
I am trying to get firebase working with my Android app but it is mainly C++ code.
A lot of chances are that if there is any crash it will be some kind of bad access in the C++ part.
Firebase works well with uncaught java exceptions however I cannot get it to work with JNI signals/exceptions.
As far as I know it is not yet compatible with JNI but I thought a workaround would be something similar to this:
Somewehre in the C++ add a signal handler for signals we would like to handle that will send it back to the Java side and try to send a report ( with part of the stacktrace if possible ).
#include <cisgnal>
namespace
{
void SignalHandler( int sig )
{
// Code to call a static method in my Activity
}
}
CrashReporter::CrashReporter()
{
::signal( SIGABRT, & ::SignalHandler )
}
// In java
public static void SendReportOnCrash()
{
FirebaseCrash.report( new Exception( "OOPS" ) );
}
Unfortunately, fake reports are never sent, however I do get callback in Java.
I tried to launch a process separated activity in which I would call FirebaseCrash.report() but there is no non-static way to it therefore it always crash since FirebaseApp/Crash are not instantiated in secondary activity.
I come here to ask if someone would have a hint on how to do that.
My last try but least wanted test would be to write the stack trace to a file, and upon a new start, test if this file exists, if so use FirebaseCrash.log then send a fake report...
You are not guaranteed to be able to do any Java processing after the JVM calls abort() for a fatal error. Per the Java documentation:
SIGABRT
The HotSpot VM does not handle this signal. Instead it calls the abort
function after fatal error handling. If an application uses this
signal then it should terminate the process to preserve the expected
semantics.
Yes, that is for the Oracle implementation. It quite likely applies to all other implementations also.
Because at the point it calls abort(), the JVM expects to be killed.
In my current implementation, I can only intercept the Method_Entry event of the some Class initialization methods, including:
*.<init> or *.<cinit>
* stands for any Class
All the methods written in Java applications are missing.
Currently, I have inserted "fprintf()" in the following places:
stack.cpp: dvmCallMethod()
stack.cpp: dvmCallMethodV()
stack.cpp: dvmCallMethodA()
stack.cpp: dvmInvokeMethod()
Interp.cpp: dvmInterpret()
Mterp.cpp: dvmMterpStd()
When these places of DVM are executed, I will print a message in my log file. However, only the Class initialization functions has triggered my println() code. In other words, it looks like that the execution of application methods does not go through the above places of DVM. I don't know which part of DVM is responsible for method execution of applications. Can anyone give me a clue?
The easiest way to figure out how things work is to look at how the method profiling works. Profiling adds an entry to a log file every time a method is called. The key file is dalvik/vm/Profile.h, which defines macros like TRACE_METHOD_ENTER. (In gingerbread, this was all you needed to look for. The situation changed quite a bit in ICS, when the interaction between debugging, profiling, and JIT compilation got reworked. And KitKat added the "sampling" profiler into the mix. So it's a bit more twisty now, and there are some other functions to be aware of, like dvmFastMethodTraceEnter().)
The entry points you've identified in your question are for reflection and calls in and out of native code. Calls between interpreted code are handled by updating the stack and program counter, and just continuing to loop through the interpreter. You can see this at line 3928 in the portable interpreter.
The non-obvious part is the FINISH() macro, defined on line 415. This calls into dvmCheckBefore(), line 1692 in Interp.cpp. This function checks the subMode field to see if there is anything interesting to do; you can find the various meanings in the definition, line 50 in InterpState.h. In short, flags are used for various profiling, debugging, and JIT compilation features.
You can see a subMode check on line 3916 in the portable interpreter, in the method invocation handling. It calls into dvmReportInvoke(), over in Interp.cpp, which invokes the TRACE_METHOD_ENTER macro.
If you're just trying to have something happen every time any method is invoked, you should probably just wire it into the profiling system, as that's already doing what you want. If you don't need the method profiling features, just replace them with your code.
I'm working on a collage project about security in Android. One part of the project attempts to capture and log all API function called by the selected APK. This can't be done with a external programs so in the project we are working with the Android source code to modify the ROM.
At the present time we only have two possible solutions:
DVM JNI Bridge
The API is Java code so, obviously, the Dalvik Virtual Machine needs a bridge to execute JNI code. The function which handle all cases is dvmCallJNIMethod(const u4* args, JValue* pResult, const Method* method, Thread* self). In this function we can get the name and the class of the called function.
This function can log all the JNI code executed, which includes API calls. But there is no easy way to distinct between private calls and API calls. And, if we wanted to execute some code depending on the risk of the API call executed, we would have to create a huge and inefficient switch.
API Framework
another solution To log all API calls is creating a new interface for the framework. With a new logging class and a simple inheritance should be easy to log all calls and add a risk parameter. But it would mean changing a lot of code. Also, Java code has worst performance than C, so it might not be the most efficient way.
More over, we would like to ask you a few questions about Android DVM and the API.
1.Which is exactly the call flow between DVM and the API?
2.Could be the DVM monitor a good idea to log the calls?
3.Which role have the shared libraries in all of this?
4.Are all API calls really Java code?
Thanks for your time.
I'm trying to build an Android application that uses an existing C library for some background operation (i.e. does some radio scans, tunes to stations etc). As a stand-alone C executable, the main-loop can deal with message handling from lower levels (hardware components). My understanding is that using JNI, no main function is required because
1) a shared library is created and
2) the shared library is "alive" for as long as the java thread that loaded it is alive.
So assuming that the C library uses multiple threads: where should then the message handling that normally is done in the initial main-loop be done? Is it as simple as by calling C functions that are declared together with the JNI functions?
Re 2) library is "alive" in the meaning of persisting in the memory. But it does not do anything on its own. If you need the library to "do something" even if no functions are being called through JNI, then you need a separate native thread of course. You can create the thread and start a message loop within a regular JNI function call (init method or use JNI_OnLoad for that purpose). It will keep on running when the JNI function call returns. You then also need a teardown method which stops the thread and tears it down (JNI_OnUnload can be used for that)
I have a pretty basic question regarding JNI calls to Java in Android NDK. I have no problems with making the actual calls, but I am not sure whether the Java call is blocked or not when it is called from C.
My question is specifically whether the c call blocks while the Java method is executed, or if it returns immediately. The reason I am asking is that I pass a byteArray to Java and I wonder if Java has access to it after the call is initiated.
JNI calls are like nornal function call. Your native code continues running when JNI call (and Java function) returns.
You should be careful about your selection of JNI calls, some can become blocking. For example getting a Critical pointer to a byte array and not releasing it can block the jvm from continuing to operate.