zoukankan      html  css  js  c++  java
  • Linux下的反调试技术

    Linux下的反调试技术

    2014年01月30日 ⁄ 综合 ⁄ 共 2669字 ⁄ 字号    ⁄ 评论关闭

    转自  http://wangcong.org/blog/archives/310

    如何防止自己的程序被调试器跟踪,这是一个很有趣的话题,也是反逆向工程中的一个重要话题。这里简单介绍一下Linux平台上的反调试技术。

    (本文主要参考:http://blog.txipinet.com/2006/10/05/37-tecnicas-anti-debugging-sencillas-para-gnu-linux/
    做人要厚道,转载请指明出处!

    一. int3指令

    Intel Software Developer’s Manual Volume 2A中提到:

    The INT 3 instruction generates a special one byte opcode (CC) that is intended for
    calling the debug exception handler. (This one byte form is valuable because it can be
    used to replace the first byte of any instruction with a breakpoint, including other one
    byte instructions, without over-writing other code).

    int3是一个特殊的中断指令(从名字上也看得出来),专门用来给调试器使用。这时,我们应该很容易想到,要反调试,只要插入int3来迷惑调试器即可。不过,这会不会影响正常的程序?会!因为int3会在用户空间产生SIGTRAP。没关系,我们只要忽略这个信号就可以了。

    #include 
    #include 
    void handler(int signo)
    {}
     
    int main(void)
    {
        signal(SIGTRAP, handler);
        __asm__("nop
    	"
            "int3
    	");
        printf("Hello from main!
    ");
        return 0;
    }
    

    二. 文件描述符

    这是一个很巧妙的办法,不过它只对gdb之类的调试器有效。方法如下:

    #include 
    #include 
    #include  
    int main(void)
    {
        if(close(3) == -1) {
            printf("OK
    ");
        } else {
            printf("traced!
    ");
            exit(-1);
        }
        return 0;
    }
    

    gdb要调试这个程序时会打开一个额外的文件描述符来读这个可执行文件,而这个程序正是利用了这个“弱点”。当然,你应该能猜到,这个技巧对strace是无效的。

    三. 利用getppid

    和上面一个手法类似,不过这个更高明,它利用getppid来进行探测。我们知道,在Linux上要跟踪一个程序,必须是它的父进程才能做到,因此,如果一个程序的父进程不是意料之中的bash等(而是gdb,strace之类的),那就说明它被跟踪了。程序代码如下:

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include  
    
    int get_name_by_pid(pid_t pid, char* name)
    {
        int fd;
        char buf[1024] = {0};
        snprintf(buf, 1024, "/proc/%d/cmdline", pid);
        if ((fd = open(buf, O_RDONLY)) == -1)
            return -1;
        read(fd, buf, 1024);
        strncpy(name, buf, 1023);
        return 0;
    }
     
    int main(void)
    {
        char name[1024];
        pid_t ppid = getppid();
        printf("getppid: %d
    ", ppid);
     
            if (get_name_by_pid(ppid, name))
            return -1;
        if (strcmp(name, "bash") == 0 ||
            strcmp(name, "init") == 0)
                printf("OK!
    ");
        else if (strcmp(name, "gdb") == 0 ||
            strcmp(name, "strace") == 0 ||
            strcmp(name, "ltrace") == 0)
            printf("Traced!
    ");
        else
            printf("Unknown! Maybe traced!
    ");
     
        return 0;
    }
    

    同样的手法,一个更简单的方式是利用session id。我们知道,不论被跟踪与否,session id是不变的,而ppid会变!下面的程序就利用了这一点。

    #include 
    #include 
    #include  
    
    int main(void)
    {
        printf("getsid: %d
    ", getsid(getpid()));
        printf("getppid: %d
    ", getppid());
     
            if (getsid(getpid()) != getppid()) {
            printf("traced!
    ");
            exit(EXIT_FAILURE);
        }
            printf("OK
    ");
     
        return 0;
    }
    

    四. 利用环境变量

    bash有一个环境变量叫$_,它保存的是上一个执行的命令的最后一个参数。如果在被跟踪的状态下,这个变量的值是会发生变化的(为什么?)。下面列出了几种情况:

                    argv[0]                    getenv("_")
    shell           ./test                     ./test
    strace          ./test                     /usr/bin/strace
    ltrace          ./test                     /usr/bin/ltrace
    gdb              /home/user/test           (NULL)
    

    所以我们也可以据此来判断。

    #include 
    #include 
    #include  
    
    int main( int argc, char *argv[])
    {
        printf("getenv(_): %s
    ", getenv("_"));
        printf("argv[0]: %s
    ", argv[0]);
     
        if(strcmp(argv[0], (char *)getenv("_"))) {
            printf("traced!
    ");
            exit(-1);
        }
     
        printf("OK
    ");
            return 0;
    }
    

    五. 利用ptrace

    很简单,如果被跟踪了还再调用ptrace(PTRACE_TRACEME…)自然会不成功。

    #include 
    #include 
    #include  
    
    int main(void)
    {
         if ( ptrace(PTRACE_TRACEME, 0, 1, 0) < 0 ) {
            printf("traced!
    ");
            return 1;
        }
        printf("OK
    ");
        return 0;
    }
    
  • 相关阅读:
    图-拓扑排序
    图-最短路径-Dijkstra及其变种
    【链表问题】打卡7:将单向链表按某值划分成左边小,中间相等,右边大的形式
    【链表问题】打卡5:环形单链表约瑟夫问题
    【链表问题】打卡6:三种方法带你优雅判断回文链表
    【链表问题】打卡4:如何优雅着反转单链表
    【链表问题】打卡3:删除单链表的中间节点
    【链表问题】打卡2:删除单链表的第 K个节点
    史上最全面试题汇总,没有之一,不接受反驳
    一些可以让你装逼的算法技巧总结
  • 原文地址:https://www.cnblogs.com/SZLLQ2000/p/5093054.html
Copyright © 2011-2022 走看看