[Android 原创] 几个简单的Android反调试手段
当时写cm里加进去的,期间又搜集资料,各种学习姿势补充了几点调试方式,具体可参见源代码,220行以下请忽略,
https://github.com/Qrilee/crackme
https://github.com/Qrilee/crackm ... Debug/antidebug.cpp
#include "antidebug.h"
#define CHECK_TIME 10
#define MAX 128
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, "qtfreet00", __VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "qtfreet00", __VA_ARGS__)
#define WCHAN_ELSE 0;
#define WCHAN_RUNNING 1;
#define WCHAN_TRACING 2;
int keep_running;
void signal_handle(int num) {
keep_running = 0;
}
int getWchanStatus() {
char *wchaninfo = new char;
int result = WCHAN_ELSE;
char *cmd = new char;
pid_t pid = syscall(__NR_getpid);
sprintf(cmd, "cat /proc/%d/wchan", pid);
//LOGE("cmd= %s", cmd);
if (cmd == NULL) {
return WCHAN_ELSE;
}
FILE *ptr;
if ((ptr = popen(cmd, "r")) != NULL) {
if (fgets(wchaninfo, 128, ptr) != NULL) {
LOGE("wchaninfo= %s", wchaninfo);
}
}
if (strncasecmp(wchaninfo, "sys_epoll\0", strlen("sys_epoll\0")) == 0) {
result = WCHAN_RUNNING;
}
else if (strncasecmp(wchaninfo, "ptrace_stop\0", strlen("ptrace_stop\0")) == 0) {
result = WCHAN_TRACING;
}
return result;
}
void CalcTime(int res, int des) {
int pid = getpid();
if (des - res >= 2) {
kill(pid, SIGKILL);
} else {
}
}
void checkAndroidServer() {
char szLines = {0};
//监听23946端口
FILE *fp = fopen("/proc/net/tcp", "r");
if (fp != NULL) {
while (fgets(szLines, sizeof(szLines), fp)) {
//23946端口
if (strstr(szLines, "00000000:5D8A")) {
kill(getpid(), SIGKILL);
break;
}
}
fclose(fp);
}
LOGE("no find android server");
}
void readStatus() {
FILE *fd;
char filename;
char line;
pid_t pid = syscall(__NR_getpid);
int ret = getWchanStatus();
if (2 == ret) {
kill(pid, SIGKILL);
}
sprintf(filename, "/proc/%d/status", pid);// 读取proc/pid/status中的TracerPid
if (fork() == 0) {
int pt;
pt = ptrace(PTRACE_TRACEME, 0, 0, 0); //子进程反调试
if (pt == -1)
exit(0);
while (1) {
checkAndroidServer();
fd = fopen(filename, "r");
while (fgets(line, MAX, fd)) {
if (strncmp(line, "TracerPid", 9) == 0) {
int statue = atoi(&line);
// LOGE("########## statue = %d,%s", statue, line);
fclose(fd);
syscall(__NR_close, fd);
if (statue != 0) {
// LOGE("########## here");
int ret = kill(pid, SIGKILL);
// LOGE("########## kill = %d", ret);
return;
}
break;
}
}
sleep(CHECK_TIME);
}
} else {
// LOGE("fork error");
}
}
int event_check(int fd) {
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
return select(FD_SETSIZE, &rfds, NULL, NULL, NULL);
}
int read_event(int fd) {
char buffer = {0};
size_t index = 0;
struct inotify_event *ptr_event;
ssize_t r = read(fd, buffer, 16384);
if (r <= 0) {
LOGE("read_event");
return r;
}
while (index < r) {
ptr_event = (struct inotify_event *) &buffer;
// LOGD("wd = %d mask = %d cookie = %d len = %d dir = %s\n",
// ptr_event->wd, ptr_event->mask, ptr_event->cookie, ptr_event->len,
// (ptr_event->mask & IN_ISDIR) ? "yes" : "no");
// if (ptr_event->len)
// LOGD("name = %s", ptr_event->name);
//此处监控事件的读和打开,如果出现则直接结束进程
if ((ptr_event->mask & IN_ACCESS) || (ptr_event->mask & IN_OPEN)) {
// LOGD("kill!!!!!\n");
//事件出现则杀死父进程
LOGE("hhhahahahahahahahahaahah");
int ret = kill(getpid(), SIGKILL);
//LOGD("ret = %d", ret);
return 0;
}
index += sizeof(struct inotify_event) + ptr_event->len;
}
return 0;
}
void runInotify() {
keep_running = 1;
pid_t ppid = syscall(__NR_getpid);
// if (signal(SIGINT, signal_handle) == SIG_IGN) {
// signal(SIGINT, SIG_IGN);
// }
int fd;
char buf;
fd = inotify_init();//初始化
if (fd == -1) { //错误处理
LOGE("inotify_init error");
switch (errno) {
case EMFILE:
LOGD("errno: EMFILE");
break;
case ENFILE:
LOGD("errno: ENFILE");
break;
case ENOMEM:
LOGD("errno: ENOMEM");
break;
default:
LOGD("unkonw errno");
}
return;
}
int wd;
sprintf(buf, "/proc/%d/maps", ppid);
wd = inotify_add_watch(fd, buf, IN_ALL_EVENTS); //添加监视
if (wd == -1) { //错误处理
LOGE("inotify_add_watch");
switch (errno) {
case EACCES:
LOGE("errno: EACCES");
break;
case EBADF:
LOGE("errno: EBADF");
break;
case EFAULT:
LOGE("errno: EFAULT");
break;
case EINVAL:
LOGE("errno: EINVAL");
break;
case ENOMEM:
LOGE("errno: ENOMEM");
break;
case ENOSPC:
LOGD("errno: ENOSPC");
break;
default:
LOGD("unkonw errno");
}
return;
}
while (keep_running) {
if (event_check(fd) > 0) {
read_event(fd);
}
}
return;
}
//以下方法暂不清楚如何利用
void AntiDebug() {
// LOGE("Call inotify");
pid_t ppid = syscall(__NR_getpid);
char buf;
char readbuf;
int wd, ret, len, i;
int fd;
fd_set readfds;
//防止调试子进程
ptrace(PTRACE_TRACEME, 0, 0, 0);
fd = inotify_init();
sprintf(buf, "/proc/%d/maps", ppid);
//wd = inotify_add_watch(fd, "/proc/self/mem", IN_ALL_EVENTS);
wd = inotify_add_watch(fd, buf, IN_ALL_EVENTS);
if (wd < 0) {
// LOGD("can't watch %s", buf);
return;
}
while (1) {
i = 0;
//注意要对fd_set进行初始化
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
//第一个参数固定要+1,第二个参数是读的fdset,第三个是写的fdset,最后一个是等待的时间
//最后一个为NULL则为阻塞
ret = select(fd + 1, &readfds, 0, 0, 0);
if (ret == -1)
break;
if (ret) {
len = read(fd, readbuf, MAX);
LOGE("come in!");
while (i < len) {
// LOGE("comeeeeee i n ...");
//返回的buf中可能存了多个inotify_event
struct inotify_event *event = (struct inotify_event *) &readbuf;
//LOGE("event mask %d\n", (event->mask & IN_ACCESS) || (event->mask & IN_OPEN));
//这里监控读和打开事件
if ((event->mask & IN_ACCESS) || (event->mask & IN_OPEN)) {
// LOGD("kill!!!!!\n");
//事件出现则杀死父进程
int ret = kill(ppid, SIGKILL);
//LOGD("ret = %d", ret);
return;
}
i += sizeof(struct inotify_event) + event->len;
}
}
sleep(CHECK_TIME);
}
inotify_rm_watch(fd, wd);
close(fd);
}
int gpipe;
void *parent_read_thread(void *param) {
LOGD("wait for child process to write decode data");
int readPipe = gpipe;
read(readPipe, 0, 0x10);
close(readPipe);
return 0;
}
void *child_attach_thread(void *param) {
int pid = *(int *) param;
LOGD("check child status %d", pid);
safe_attach(pid);
handle_events();
LOGE("watch thread exit");
kill(getpid(), 9);
}
int checkDebugger() {
// use Multi process to protect itself
int forktime = 0;
FORKLABEL:
forktime++;
if (forktime > 5) {
return 0;
}
if (pipe(gpipe)) {
return 0;
}
int pid = fork();
prctl(PR_SET_DUMPABLE, 1);
if (pid != 0) {
// parent
close(gpipe);
LOGD("start new thread to read decode data");
pthread_t ntid;
pthread_create(&ntid, NULL, parent_read_thread, &pid);
bool flag = false;
do {
int childstatus;
int childpid = waitpid(pid, &childstatus, WNOHANG);
bool succ = childpid == 0;
if (childpid > 0) {
succ = childstatus == 1;
LOGD("Child process end!");
}
if (!succ) {
kill(pid, 9);
goto FORKLABEL;
}
flag = true;
} while (!flag);
} else {
// child
// Write key to pipe
int cpid = getppid();
safe_attach(cpid);
LOGD("child process Attach success, try to write data");
close(gpipe);
int writepipe = gpipe;
char tflag = {
0x4A, 0x75, 0x73, 0x74, 0x48, 0x61, 0x76, 0x65,
0x41, 0x54, 0x72, 0x79, 0x21, 0x21, 0x21, 0x21
};
write(writepipe, tflag, 0x10);
close(writepipe);
handle_events();
exit(EXIT_FAILURE);
}
return 0;
}
bool may_cause_group_stop(int signo) {
switch (signo) {
case SIGSTOP:
case SIGTSTP:
case SIGTTIN:
case SIGTTOU:
return true;
break;
default:
break;
}
return false;
}
void handle_events() {
int status = 0;
pid_t pid = 0;
do {
pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, __WALL));
if (pid < 0) {
perror("waitpid");
exit(EXIT_FAILURE);
}
if (WIFEXITED(status)) {
LOGE("%d exited, status=%d\n", pid, WEXITSTATUS(status));
}
else if (WIFSIGNALED(status)) {
LOGE("%d killed by signal %d\n", pid, WTERMSIG(status));
}
else if (WIFSTOPPED(status)) {
int signo = WSTOPSIG(status);
LOGE("%d stopped by signal %d\n", pid, signo);
if (may_cause_group_stop(signo)) {
signo = 0;
}
long err = ptrace(PTRACE_CONT, pid, NULL, signo);
if (err < 0) {
perror("PTRACE_CONT");
exit(EXIT_FAILURE);
}
}
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
}
void safe_attach(pid_t pid) {
long err = ptrace(PTRACE_ATTACH, pid, NULL, NULL);
if (err < 0) {
LOGE("PTRACE_ATTACH");
exit(EXIT_FAILURE);
}
int status = 0;
err = TEMP_FAILURE_RETRY(waitpid(pid, &status, __WALL));
if (err < 0) {
LOGE("waitpid");
exit(EXIT_FAILURE);
}
if (WIFEXITED(status)) {
LOGE("%d exited, status=%d\n", pid, WEXITSTATUS(status));
exit(EXIT_SUCCESS);
}
else if (WIFSIGNALED(status)) {
LOGE("%d killed by signal %d\n", pid, WTERMSIG(status));
exit(EXIT_SUCCESS);
}
else if (WIFSTOPPED(status)) {
int signo = WSTOPSIG(status);
LOGE("%d stopped by signal %d\n", pid, signo);
if (may_cause_group_stop(signo)) {
signo = 0;
}
err = ptrace(PTRACE_CONT, pid, NULL, signo);
if (err < 0) {
LOGE("PTRACE_CONT");
exit(EXIT_FAILURE);
}
}
LOGD("Debugger: attached to process %d\n", pid);
}
代码可以正常运行(cm自身是只支持4.4以下的,把qtfreet.cpp的init函数注释掉可以在5.0+上运行,此处为davilk动态自篡改),
但难免不会有我个人理解的问题,兼容或者没测试出的bug,欢迎大牛提出问题,提出新的检测方式和提交代码,最好顺手给个star,谢谢
页:
[1]