admin 发表于 2017-2-12 09:21:13

[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]
查看完整版本: [Android 原创] 几个简单的Android反调试手段