I've been doing the SEED Android Device Rooting Lab to understand a little bit more about Android rooting, and it has gone well so far.
But I've encountered a problem when trying to execute code as root via switching the app_process program for one coded by me that simply writes a dummy file to the /system directory and executes the real app_process64.
The problem that I'm encountering is that with this code, the dummy file is not being created. I have compiled this code with NDK:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
extern char** environ;
int main(int argc, char** argv) {
//Write the dummy file
FILE* f = fopen("/system/dummy2", "w");
if (f == NULL) {
printf("Permission Denied.\n");
exit(EXIT_FAILURE);
}
fclose(f);
//Launch the original binary
char* cmd = "/system/bin/app_process_original";
execve(cmd, argv, environ);
//execve() returns only if it fails
return EXIT_FAILURE;
}
I can't quite understand why it wouldn't work. I have the file structure as follows: Symlink with name app_process that points to this program, a symlink called app_process_original that points to the app_process64 which is the one that has to run.
The system boots as per usual, but the file does not show up. I think that app_process is not running as root. The lab uses Android 7.1. If I execute the program under root once Android has started, the file appears, so it seems to be a permissions issue, but the lab is about acquiring root permissions through this program, so I'm really confused.
Does anyone see what the problem is here? Is app_process not running as root?
Thank you in advance.
/system is usually mounted as read-only. Even if it were writeable, SELinux would probably not allow your process to write that file.
You should try to find out what actually prevents your process from creating that file:
Check if /system is writable with adb shell mount.
Check the error message by evaluating errno with strerror(errno).
Check SELinux messages with adb logcat | grep avc.
I made a simple android executable with CMake that links with the native zlib on the ndk. Everything compiles correctly, but when calling deflateInit I get a segmentation fault.
Here is the code:
main.cpp
#include <iostream>
#include <zlib.h>
int main()
{
z_stream strm;
deflateInit(&strm, Z_DEFAULT_COMPRESSION);
std::cout << "it works!" << std::endl;
}
And the corresponding CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project(zlib-on-android)
add_executable(main main.cpp)
find_package(ZLIB REQUIRED)
set_target_properties(main
PROPERTIES POSITION_INDEPENDENT_CODE ON)
target_link_libraries(main PUBLIC ZLIB::ZLIB)
I then compile with the following command:
cmake -H. -Bbuild -DCMAKE_SYSTEM_NAME=Android -DCMAKE_ANDROID_NDK=~/android-ndk-r17b -DCMAKE_ANDROID_STL_TYPE=c++_static -DCMAKE_SYSTEM_VERSION=16 -DCMAKE_ANDROID_NDK_TOOLCHAIN_VERSION=clang
Everything works fine. Then I do the following:
cd build
adb push main /data/local/tmp/.
adb shell
shell#device:/ $ cd /data/local/tmp
shell#device:/ $ ./main
[1] + Stopped (signal) ./main
Does anyone know the reason? I am having a lot of trouble trying to hook up gdb with this executable. Since the same code works on my Macosx, I cannot understand why it does not work on android.
EDIT
For some reason the same code crashes on Macosx (the one that worked was a similar code). This is the error: bus error ./main
Well, turns out that setting z_stream to zero fixes the problem.
#include <iostream>
#include <zlib.h>
#include <cstdlib>
int main()
{
z_stream strm;
std::memset(&strm, 0, sizeof(z_stream));
deflateInit(&strm, Z_DEFAULT_COMPRESSION);
std::cout << "it works!" << std::endl;
}
I am trying to use JNI code to print Android sensor timestamps to a file.
The timestamps are defined as int64_t.
The line to print the timestamp is:
fout<<timestamp<<std::endl;
Where fout is an open file stream in output mode.
When I try to compile, the following error results:
ambiguous overload for 'operator<<' (operand types are 'std::ofstream {aka std::basic_ofstream >}' and 'int64_t {aka long long int}') XXX.cpp /YYY/jni line ZZZ C/C++ Problem
I thought I would make an MWE for this using standard C++:
#include <iostream>
#include <cstdint>
int main(){
int64_t a;
std::cin>>a;
std::cout<<a<<std::endl;
}
But this compiles without an issue, which makes me think the problem is somehow in the way Eclipse compiles the code.
I am inside Eclipse 3.8.1. My default compiler is GCC 4.9.2.
I solved this problem by going into jni/Application.mk and using this line:
LOCAL_CPPFLAGS += -std=gnu++11
instead of this line:
LOCAL_CPPFLAGS+=-std=c++11.
Some have conjectured that the problem is due to different mappings of long long int in stlport.
I can't get my Nexus S (running Android 4.0) to redirect native stdout message to logcat. I've read that I need to do this:
$ adb shell stop
$ adb shell setprop log.redirect-stdio true
$ adb shell start
However, this doesn't seem to work. (It does break JUnit though, as mentioned here, so it's not without effect.)
For reference, here's my code:
package com.mayastudios;
import android.util.Log;
public class JniTester {
public static void test() {
Log.e("---------", "Start of test");
System.err.println("This message comes from Java.");
void printCMessage();
Log.e("---------", "End of test");
}
private static native int printCMessage();
static {
System.loadLibrary("jni_test");
}
}
And the JNI .c file:
JNIEXPORT void JNICALL
Java_com_mayastudios_JniTester_printCMessage(JNIEnv *env, jclass cls) {
setvbuf(stdout, NULL, _IONBF, 0);
printf("This message comes from C (JNI).\n");
fflush(stdout);
//setvbuf(stderr, NULL, _IONBF, 0);
//fprintf(stderr, "This message comes from C (JNI).\n");
//fflush(stderr);
}
And the Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := jni_test
LOCAL_SRC_FILES := test_jni.c
include $(BUILD_SHARED_LIBRARY)
I'm compiling this just by calling ndk-build. The native method is called correctly but I don't get any log output from it (even on verbose). I do get the log output from Java though ("This message comes from Java.").
Any hints of what I might be doing wrong?
PS: I've set up a small Mercurial repository that demonstrates the problem: https://bitbucket.org/skrysmanski/android-ndk-log-output/
setprop log.redirect-stdio true redirects only output generated by java code, but not the native code. This fact is described on developer.android.com in following way:
By default, the Android system sends stdout and stderr (System.out and System.err) output to /dev/null. In processes that run the Dalvik VM, you can have the system write a copy of the output to the log file.
To get output from the native code, I really liked this solution
This was not obvious to me from the previous answers. Even on rooted devices you need to run:
adb root
adb shell stop
adb shell setprop log.redirect-stdio true
adb shell start
You should also be able to wrap your logging code to detect if it's Android and if so use Android's logging. This may or may not be practical for everyone.
Include the logging header file:
#include <android/log.h>
Use the built in logging functionality:
__android_log_print(ANDROID_LOG_INFO, "foo", "Error: %s", foobar);
Here the code I use to to output stdout and stderr to android log
#include <android/log.h>
#include <pthread.h>
#include <unistd.h>
static int pfd[2];
static pthread_t loggingThread;
static const char *LOG_TAG = "YOU APP LOG TAG";
static void *loggingFunction(void*) {
ssize_t readSize;
char buf[128];
while((readSize = read(pfd[0], buf, sizeof buf - 1)) > 0) {
if(buf[readSize - 1] == '\n') {
--readSize;
}
buf[readSize] = 0; // add null-terminator
__android_log_write(ANDROID_LOG_DEBUG, LOG_TAG, buf); // Set any log level you want
}
return 0;
}
static int runLoggingThread() { // run this function to redirect your output to android log
setvbuf(stdout, 0, _IOLBF, 0); // make stdout line-buffered
setvbuf(stderr, 0, _IONBF, 0); // make stderr unbuffered
/* create the pipe and redirect stdout and stderr */
pipe(pfd);
dup2(pfd[1], 1);
dup2(pfd[1], 2);
/* spawn the logging thread */
if(pthread_create(&loggingThread, 0, loggingFunction, 0) == -1) {
return -1;
}
pthread_detach(loggingThread);
return 0;
}
stdout/stderr are redirected to /dev/null in Android apps. The setprop workaround is a hack for rooted devices that copies stdout/stderr to the log. See Android Native Code Debugging.
Try putting fflush(stdout); after your printf. Or alternatively use fprintf(stderr, "This message comes from C (JNI).\n");
stdout by default is buffering. stderr - is not. And you are using System.err, not System.out from Java.
Also you can disable stdout buffering with this: setvbuf(stdout, NULL, _IONBF, 0); Just make sure you call it before first printf call.
I compiled a simple C program for Android via NDK, and ran that on Android.
C source:
#include <stdio.h>
int
main ()
{
printf ("Hello world!\n");
}
Script for compile C source:
#!/bin/bash
PREFIX="/opt/android-ndk-r7"
CC="$PREFIX/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-arm/bin/arm-linux-androideabi-gcc"
NDK="$PREFIX/platforms/android-14/arch-arm"
CFLAGS="-I$NDK/usr/include"
LDFLAGS="-nostdlib -Wl,-rpath-link=$NDK/usr/lib -L$NDK/usr/lib $NDK/usr/lib/crtbegin_dynamic.o -lc"
$CC -o hello hello.c $CFLAGS $LDFLAGS
What happened when I ran program on terminal on Android:
$ export PATH=/data/local/bin:$PATH
$ hello
Hello world!
[1] + Stopped (signal) hello
$ exit
You have stopped jobs.
[1] Illegal instruction hello
$ exit
When I ran program it worked but then occured "Stopped" and "Illegal instruction".
What should I do for solve this problem?
I'm with #Amigable Clark Kent on this. Think about what you've got there.
You tell the compiler that main() is going to return an int. On running, the loader is preparing to receive the returned value from the function, which is never actually returned. It doesn't matter if it's looking for it in a register or the stack, that place will hold the wrong stuff.