阿里云服务器免费领卷啦。

捡代码论坛-最全的游戏源码下载技术网站!

 找回密码
 立 即 注 册

QQ登录

只需一步,快速开始

搜索
关于源码区的附件失效或欺骗帖, 处理办法
查看: 4035|回复: 0

[Android 原创] 几个简单的Android反调试手段

[复制链接]

4208

主题

210

回帖

12万

积分

管理员

管理员

Rank: 9Rank: 9Rank: 9

积分
126171
QQ
发表于 2017-2-12 09:21:13 | 显示全部楼层 |阅读模式
当时写cm里加进去的,期间又搜集资料,各种学习姿势补充了几点调试方式,

具体可参见源代码,220行以下请忽略,
  1. https://github.com/Qrilee/crackme
复制代码



https://github.com/Qrilee/crackm ... Debug/antidebug.cpp

  1. #include "antidebug.h"


  2. #define CHECK_TIME 10
  3. #define MAX 128
  4. #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, "qtfreet00", __VA_ARGS__)
  5. #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, "qtfreet00", __VA_ARGS__)
  6. #define WCHAN_ELSE 0;
  7. #define WCHAN_RUNNING 1;
  8. #define WCHAN_TRACING 2;
  9. int keep_running;

  10. void signal_handle(int num) {
  11.     keep_running = 0;
  12. }

  13. int getWchanStatus() {
  14.     char *wchaninfo = new char[128];
  15.     int result = WCHAN_ELSE;
  16.     char *cmd = new char[128];
  17.     pid_t pid = syscall(__NR_getpid);
  18.     sprintf(cmd, "cat /proc/%d/wchan", pid);
  19.     //LOGE("cmd= %s", cmd);
  20.     if (cmd == NULL) {
  21.         return WCHAN_ELSE;
  22.     }
  23.     FILE *ptr;
  24.     if ((ptr = popen(cmd, "r")) != NULL) {
  25.         if (fgets(wchaninfo, 128, ptr) != NULL) {
  26.             LOGE("wchaninfo= %s", wchaninfo);
  27.         }
  28.     }
  29.     if (strncasecmp(wchaninfo, "sys_epoll\0", strlen("sys_epoll\0")) == 0) {
  30.         result = WCHAN_RUNNING;
  31.     }
  32.     else if (strncasecmp(wchaninfo, "ptrace_stop\0", strlen("ptrace_stop\0")) == 0) {
  33.         result = WCHAN_TRACING;
  34.     }
  35.     return result;
  36. }


  37. void CalcTime(int res, int des) {
  38.     int pid = getpid();
  39.     if (des - res >= 2) {
  40.         kill(pid, SIGKILL);
  41.     } else {
  42.     }
  43. }

  44. void checkAndroidServer() {
  45.     char szLines[1024] = {0};
  46.     //监听23946端口
  47.     FILE *fp = fopen("/proc/net/tcp", "r");
  48.     if (fp != NULL) {
  49.         while (fgets(szLines, sizeof(szLines), fp)) {
  50.             //23946端口
  51.             if (strstr(szLines, "00000000:5D8A")) {
  52.                 kill(getpid(), SIGKILL);
  53.                 break;
  54.             }
  55.         }

  56.         fclose(fp);
  57.     }

  58.     LOGE("no find android server");
  59. }

  60. void readStatus() {
  61.     FILE *fd;
  62.     char filename[MAX];
  63.     char line[MAX];
  64.     pid_t pid = syscall(__NR_getpid);
  65.     int ret = getWchanStatus();
  66.     if (2 == ret) {
  67.         kill(pid, SIGKILL);
  68.     }
  69.     sprintf(filename, "/proc/%d/status", pid);// 读取proc/pid/status中的TracerPid
  70.     if (fork() == 0) {
  71.         int pt;
  72.         pt = ptrace(PTRACE_TRACEME, 0, 0, 0); //子进程反调试
  73.         if (pt == -1)
  74.             exit(0);
  75.         while (1) {
  76.             checkAndroidServer();
  77.             fd = fopen(filename, "r");
  78.             while (fgets(line, MAX, fd)) {
  79.                 if (strncmp(line, "TracerPid", 9) == 0) {
  80.                     int statue = atoi(&line[10]);
  81. //                    LOGE("########## statue = %d,%s", statue, line);
  82.                     fclose(fd);
  83.                     syscall(__NR_close, fd);
  84.                     if (statue != 0) {
  85.                         // LOGE("########## here");
  86.                         int ret = kill(pid, SIGKILL);
  87.                         // LOGE("########## kill = %d", ret);
  88.                         return;
  89.                     }

  90.                     break;
  91.                 }
  92.             }
  93.             sleep(CHECK_TIME);
  94.         }
  95.     } else {
  96. //        LOGE("fork error");
  97.     }
  98. }


  99. int event_check(int fd) {
  100.     fd_set rfds;
  101.     FD_ZERO(&rfds);
  102.     FD_SET(fd, &rfds);

  103.     return select(FD_SETSIZE, &rfds, NULL, NULL, NULL);
  104. }

  105. int read_event(int fd) {
  106.     char buffer[16384] = {0};
  107.     size_t index = 0;
  108.     struct inotify_event *ptr_event;

  109.     ssize_t r = read(fd, buffer, 16384);
  110.     if (r <= 0) {
  111.         LOGE("read_event");
  112.         return r;
  113.     }

  114.     while (index < r) {
  115.         ptr_event = (struct inotify_event *) &buffer[index];
  116. //        LOGD("wd = %d mask = %d cookie = %d len = %d dir = %s\n",
  117. //             ptr_event->wd, ptr_event->mask, ptr_event->cookie, ptr_event->len,
  118. //             (ptr_event->mask & IN_ISDIR) ? "yes" : "no");
  119. //        if (ptr_event->len)
  120. //            LOGD("name = %s", ptr_event->name);
  121.         //此处监控事件的读和打开,如果出现则直接结束进程
  122.         if ((ptr_event->mask & IN_ACCESS) || (ptr_event->mask & IN_OPEN)) {
  123.             //    LOGD("kill!!!!!\n");
  124.             //事件出现则杀死父进程
  125.             LOGE("hhhahahahahahahahahaahah");
  126.             int ret = kill(getpid(), SIGKILL);
  127.             //  LOGD("ret = %d", ret);
  128.             return 0;
  129.         }

  130.         index += sizeof(struct inotify_event) + ptr_event->len;
  131.     }
  132.     return 0;
  133. }

  134. void runInotify() {
  135.     keep_running = 1;
  136.     pid_t ppid = syscall(__NR_getpid);
  137. //    if (signal(SIGINT, signal_handle) == SIG_IGN) {
  138. //        signal(SIGINT, SIG_IGN);
  139. //    }

  140.     int fd;
  141.     char buf[1024];
  142.     fd = inotify_init();//初始化
  143.     if (fd == -1) { //错误处理
  144.         LOGE("inotify_init error");
  145.         switch (errno) {
  146.             case EMFILE:
  147.                 LOGD("errno: EMFILE");
  148.                 break;
  149.             case ENFILE:
  150.                 LOGD("errno: ENFILE");
  151.                 break;
  152.             case ENOMEM:
  153.                 LOGD("errno: ENOMEM");
  154.                 break;
  155.             default:
  156.                 LOGD("unkonw errno");
  157.         }
  158.         return;
  159.     }

  160.     int wd;
  161.     sprintf(buf, "/proc/%d/maps", ppid);
  162.     wd = inotify_add_watch(fd, buf, IN_ALL_EVENTS); //添加监视
  163.     if (wd == -1) { //错误处理
  164.         LOGE("inotify_add_watch");
  165.         switch (errno) {
  166.             case EACCES:
  167.                 LOGE("errno: EACCES");
  168.                 break;
  169.             case EBADF:
  170.                 LOGE("errno: EBADF");
  171.                 break;
  172.             case EFAULT:
  173.                 LOGE("errno: EFAULT");
  174.                 break;
  175.             case EINVAL:
  176.                 LOGE("errno: EINVAL");
  177.                 break;
  178.             case ENOMEM:
  179.                 LOGE("errno: ENOMEM");
  180.                 break;
  181.             case ENOSPC:
  182.                 LOGD("errno: ENOSPC");
  183.                 break;
  184.             default:
  185.                 LOGD("unkonw errno");
  186.         }
  187.         return;
  188.     }

  189.     while (keep_running) {
  190.         if (event_check(fd) > 0) {
  191.             read_event(fd);
  192.         }
  193.     }
  194.     return;
  195. }
  196. //以下方法暂不清楚如何利用


  197. void AntiDebug() {
  198.     // LOGE("Call inotify");
  199.     pid_t ppid = syscall(__NR_getpid);
  200.     char buf[1024];
  201.     char readbuf[MAX];
  202.     int wd, ret, len, i;
  203.     int fd;
  204.     fd_set readfds;
  205.     //防止调试子进程
  206.     ptrace(PTRACE_TRACEME, 0, 0, 0);
  207.     fd = inotify_init();
  208.     sprintf(buf, "/proc/%d/maps", ppid);

  209.     //wd = inotify_add_watch(fd, "/proc/self/mem", IN_ALL_EVENTS);
  210.     wd = inotify_add_watch(fd, buf, IN_ALL_EVENTS);
  211.     if (wd < 0) {
  212.         // LOGD("can't watch %s", buf);
  213.         return;
  214.     }
  215.     while (1) {
  216.         i = 0;
  217.         //注意要对fd_set进行初始化
  218.         FD_ZERO(&readfds);
  219.         FD_SET(fd, &readfds);
  220.         //第一个参数固定要+1,第二个参数是读的fdset,第三个是写的fdset,最后一个是等待的时间
  221.         //最后一个为NULL则为阻塞
  222.         ret = select(fd + 1, &readfds, 0, 0, 0);
  223.         if (ret == -1)
  224.             break;
  225.         if (ret) {
  226.             len = read(fd, readbuf, MAX);
  227.             LOGE("come in!");

  228.             while (i < len) {
  229.                 //   LOGE("comeeeeee i n ...");
  230.                 //返回的buf中可能存了多个inotify_event
  231.                 struct inotify_event *event = (struct inotify_event *) &readbuf[i];
  232.                 //  LOGE("event mask %d\n", (event->mask & IN_ACCESS) || (event->mask & IN_OPEN));
  233.                 //这里监控读和打开事件
  234.                 if ((event->mask & IN_ACCESS) || (event->mask & IN_OPEN)) {
  235.                     //    LOGD("kill!!!!!\n");
  236.                     //事件出现则杀死父进程
  237.                     int ret = kill(ppid, SIGKILL);
  238.                     //  LOGD("ret = %d", ret);
  239.                     return;
  240.                 }
  241.                 i += sizeof(struct inotify_event) + event->len;
  242.             }
  243.         }
  244.         sleep(CHECK_TIME);
  245.     }
  246.     inotify_rm_watch(fd, wd);
  247.     close(fd);
  248. }

  249. int gpipe[2];

  250. void *parent_read_thread(void *param) {
  251.     LOGD("wait for child process to write decode data");
  252.     int readPipe = gpipe[0];
  253.     read(readPipe, 0, 0x10);
  254.     close(readPipe);
  255.     return 0;
  256. }

  257. void *child_attach_thread(void *param) {
  258.     int pid = *(int *) param;
  259.     LOGD("check child status %d", pid);
  260.     safe_attach(pid);
  261.     handle_events();
  262.     LOGE("watch thread exit");

  263.     kill(getpid(), 9);
  264. }


  265. int checkDebugger() {
  266. // use Multi process to protect itself
  267.     int forktime = 0;

  268.     FORKLABEL:
  269.     forktime++;
  270.     if (forktime > 5) {
  271.         return 0;
  272.     }

  273.     if (pipe(gpipe)) {
  274.         return 0;
  275.     }
  276.     int pid = fork();
  277.     prctl(PR_SET_DUMPABLE, 1);

  278.     if (pid != 0) {
  279.         // parent
  280.         close(gpipe[1]);
  281.         LOGD("start new thread to read decode data");
  282.         pthread_t ntid;
  283.         pthread_create(&ntid, NULL, parent_read_thread, &pid);
  284.         bool flag = false;
  285.         do {
  286.             int childstatus;
  287.             int childpid = waitpid(pid, &childstatus, WNOHANG);
  288.             bool succ = childpid == 0;
  289.             if (childpid > 0) {
  290.                 succ = childstatus == 1;
  291.                 LOGD("Child process end!");
  292.             }
  293.             if (!succ) {
  294.                 kill(pid, 9);
  295.                 goto FORKLABEL;
  296.             }
  297.             flag = true;
  298.         } while (!flag);
  299.     } else {
  300.         // child
  301.         // Write key to pipe
  302.         int cpid = getppid();
  303.         safe_attach(cpid);
  304.         LOGD("child process Attach success, try to write data");

  305.         close(gpipe[0]);
  306.         int writepipe = gpipe[1];

  307.         char tflag[0x10 + 1] = {
  308.                 0x4A, 0x75, 0x73, 0x74, 0x48, 0x61, 0x76, 0x65,
  309.                 0x41, 0x54, 0x72, 0x79, 0x21, 0x21, 0x21, 0x21
  310.         };

  311.         write(writepipe, tflag, 0x10);
  312.         close(writepipe);
  313.         handle_events();
  314.         exit(EXIT_FAILURE);

  315.     }
  316.     return 0;
  317. }

  318. bool may_cause_group_stop(int signo) {
  319.     switch (signo) {
  320.         case SIGSTOP:
  321.         case SIGTSTP:
  322.         case SIGTTIN:
  323.         case SIGTTOU:
  324.             return true;
  325.             break;
  326.         default:
  327.             break;
  328.     }

  329.     return false;
  330. }

  331. void handle_events() {
  332.     int status = 0;
  333.     pid_t pid = 0;

  334.     do {
  335.         pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, __WALL));
  336.         if (pid < 0) {
  337.             perror("waitpid");
  338.             exit(EXIT_FAILURE);
  339.         }

  340.         if (WIFEXITED(status)) {
  341.             LOGE("%d exited, status=%d\n", pid, WEXITSTATUS(status));
  342.         }
  343.         else if (WIFSIGNALED(status)) {
  344.             LOGE("%d killed by signal %d\n", pid, WTERMSIG(status));
  345.         }
  346.         else if (WIFSTOPPED(status)) {
  347.             int signo = WSTOPSIG(status);
  348.             LOGE("%d stopped by signal %d\n", pid, signo);

  349.             if (may_cause_group_stop(signo)) {
  350.                 signo = 0;
  351.             }

  352.             long err = ptrace(PTRACE_CONT, pid, NULL, signo);
  353.             if (err < 0) {
  354.                 perror("PTRACE_CONT");
  355.                 exit(EXIT_FAILURE);
  356.             }
  357.         }

  358.     } while (!WIFEXITED(status) && !WIFSIGNALED(status));

  359. }

  360. void safe_attach(pid_t pid) {
  361.     long err = ptrace(PTRACE_ATTACH, pid, NULL, NULL);
  362.     if (err < 0) {
  363.         LOGE("PTRACE_ATTACH");
  364.         exit(EXIT_FAILURE);
  365.     }

  366.     int status = 0;
  367.     err = TEMP_FAILURE_RETRY(waitpid(pid, &status, __WALL));
  368.     if (err < 0) {
  369.         LOGE("waitpid");
  370.         exit(EXIT_FAILURE);
  371.     }

  372.     if (WIFEXITED(status)) {
  373.         LOGE("%d exited, status=%d\n", pid, WEXITSTATUS(status));
  374.         exit(EXIT_SUCCESS);
  375.     }
  376.     else if (WIFSIGNALED(status)) {
  377.         LOGE("%d killed by signal %d\n", pid, WTERMSIG(status));
  378.         exit(EXIT_SUCCESS);
  379.     }
  380.     else if (WIFSTOPPED(status)) {
  381.         int signo = WSTOPSIG(status);
  382.         LOGE("%d stopped by signal %d\n", pid, signo);

  383.         if (may_cause_group_stop(signo)) {
  384.             signo = 0;
  385.         }

  386.         err = ptrace(PTRACE_CONT, pid, NULL, signo);
  387.         if (err < 0) {
  388.             LOGE("PTRACE_CONT");
  389.             exit(EXIT_FAILURE);
  390.         }
  391.     }

  392.     LOGD("Debugger: attached to process %d\n", pid);
  393. }
复制代码


代码可以正常运行(cm自身是只支持4.4以下的,把qtfreet.cpp的init函数注释掉可以在5.0+上运行,此处为davilk动态自篡改),

但难免不会有我个人理解的问题,兼容或者没测试出的bug,欢迎大牛提出问题,提出新的检测方式和提交代码,最好顺手给个star,谢谢


捡代码论坛-最全的游戏源码下载技术网站! - 论坛版权郑重声明:
1、本主题所有言论和图片纯属会员个人意见,与本论坛立场无关
2、本站所有主题由该帖子作者发表,该帖子作者与捡代码论坛-最全的游戏源码下载技术网站!享有帖子相关版权
3、捡代码论坛版权,详细了解请点击。
4、本站所有内容均由互联网收集整理、网友上传,并且以计算机技术研究交流为目的,仅供大家参考、学习,不存在任何商业目的与商业用途。
5、若您需要商业运营或用于其他商业活动,请您购买正版授权并合法使用。 我们不承担任何技术及版权问题,且不对任何资源负法律责任。
6、如无法链接失效或侵犯版权,请给我们来信:jiandaima@foxmail.com

回复

使用道具 举报

*滑块验证:
您需要登录后才可以回帖 登录 | 立 即 注 册

本版积分规则

技术支持
在线咨询
QQ咨询
3351529868

QQ|手机版|小黑屋|捡代码论坛-专业源码分享下载 ( 陕ICP备15015195号-1|网站地图

GMT+8, 2024-4-25 14:53

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表