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\n\t"
"int3\n\t");
printf("Hello from main!\n");
return 0;
}

二. 文件描述符

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

#include
#include
#include
int main(void)
{
if(close(3) == -1) {
printf("OK\n");
} else {
printf("traced!\n");
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\n", ppid); if (get_name_by_pid(ppid, name))
return -1;
if (strcmp(name, "bash") == 0 ||
strcmp(name, "init") == 0)
printf("OK!\n");
else if (strcmp(name, "gdb") == 0 ||
strcmp(name, "strace") == 0 ||
strcmp(name, "ltrace") == 0)
printf("Traced!\n");
else
printf("Unknown! Maybe traced!\n"); return 0;
}

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

#include
#include
#include int main(void)
{
printf("getsid: %d\n", getsid(getpid()));
printf("getppid: %d\n", getppid()); if (getsid(getpid()) != getppid()) {
printf("traced!\n");
exit(EXIT_FAILURE);
}
printf("OK\n"); 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\n", getenv("_"));
printf("argv[0]: %s\n", argv[0]); if(strcmp(argv[0], (char *)getenv("_"))) {
printf("traced!\n");
exit(-1);
} printf("OK\n");
return 0;
}

五. 利用ptrace

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

#include
#include
#include int main(void)
{
if ( ptrace(PTRACE_TRACEME, 0, 1, 0) < 0 ) {
printf("traced!\n");
return 1;
}
printf("OK\n");
return 0;
}

Linux下的反调试技术的更多相关文章

  1. 基于TLS的反调试技术

    TLS(Thread Local Storage 线程局部存储) 一个进程中的每个线程在访问同一个线程局部存储时,访问到的都是独立的绑定于该线程的数据块.在PEB(进程环境块)中TLS存储槽共64个( ...

  2. 反调试技术常用API,用来对付检测od和自动退出程序

    在调试一些病毒程序的时候,可能会碰到一些反调试技术,也就是说,被调试的程序可以检测到自己是否被调试器附加了,如果探知自己正在被调试,肯定是有人试图反汇编啦之类的方法破解自己.为了了解如何破解反调试技术 ...

  3. Windows 反调试技术——OpenProcess 权限过滤 - ObRegisterCallback

    转载: https://blog.xpnsec.com/anti-debug-openprocess/ 看雪翻译:https://bbs.pediy.com/thread-223857.htm 本周我 ...

  4. linux下多进程的调试

    linux下多进程的调试:  (1)follow-fork-mode           set follow-fork-mode [parent | child] ---- fork之后选择调试父进 ...

  5. Linux下用Xdebug调试php

    Linux下用Xdebug调试php 博客分类: php PHPLinuxZendEclipseC# 为了调试PHP程序,安装一下xdebug. 官方网址: http://www.xdebug.org ...

  6. Ubuntu\Linux 下编写及调试C\C++

    一.在Ubuntu\Linux 下编写及调试C\C++需要配置基本的环境,即配置gcc编译器.安装vim编译器,具体配置安装步骤我在这里就不多说了. 二.基本环境配置完了我们就可以进入自己的程序编写了 ...

  7. Windows反调试技术(上)

    写在前面 在逆向工程中为了防止破解者调试软件,通常都会在软件中采用一些反调试技术来防破解.下面就是一些在逆向工程中常见的反调试技巧与示例. BeingDebuged 利用调试器加载程序时调试器会通过C ...

  8. Windows反调试技术(下)

    OD的DBGHELP模块 检测DBGHELP模块,此模块是用来加载调试符号的,所以一般加载此模块的进程的进程就是调试器.绕过方法也很简单,将DBGHELP.DLL改名. #include <Wi ...

  9. Linux驱动设计—— 驱动调试技术

    参考博客与书籍: <Linux设备驱动开发详解> <Linux设备驱动程序> http://blog.chinaunix.net/uid-24219701-id-2884942 ...

随机推荐

  1. openssl & openssh

    什么是OpenSSL众多的密码算法.公钥基础设施标准以及SSL协议,或许这些有趣的功能会让你产生实现所有这些算法和标准的想法.果真如此,在对你表示敬佩的同时,还是忍不住提醒你:这是一个令人望而生畏的过 ...

  2. Python 扩展知识

    Python 练习题 Python 编程习惯 Python 转义字符 Python 格式化输出 Python 列表表达式 Python 生成器表达式 Python 序列化 Python2 与 Pyth ...

  3. [Windows] Windows 8.1 取消在任务栏显示应用商店的应用

  4. linux 开机自启

    cd /home/dpf 1.vi startup.sh #!/bin/shecho "hello world" >> /home/dpf/test.txt vi mq ...

  5. PowerShell的初步学习

    今天要重新学习一钟语法,由于工作中项目的需要,不得不说学习新的语言是必不可少的.          Windows PowerShell 是一种命令行外科程序和脚本环境,使命令行用户和脚本编写者可以利 ...

  6. thinkphp 控制器unset删除对象变量失败。。

    今儿开发过程中发现 tp是unset 变量失败..具体代码 foreach( $this->menu as $k => $v){ if(0 == $v['flag']) unset($th ...

  7. POJ2356 Find a multiple 抽屉原理(鸽巢原理)

    题意:给你N个数,从中取出任意个数的数 使得他们的和 是 N的倍数: 在鸽巢原理的介绍里面,有例题介绍:设a1,a2,a3,……am是正整数的序列,试证明至少存在正数k和l,1<=k<=l ...

  8. 【大数据系列】在hadoop2.8.0下配置SecondaryNameNode

    修改namenode上的hdfs-site.xml configuration> <property> <name>dfs.replication</name> ...

  9. How to Verify Email Address

    http://www.ruanyifeng.com/blog/2017/06/smtp-protocol.html  如何验证 Email 地址:SMTP 协议入门教程 https://en.wiki ...

  10. LeetCode 14 Longest Common Prefix(最长公共前缀)

    题目链接:https://leetcode.com/problems/longest-common-prefix/?tab=Description   Problem: 找出给定的string数组中最 ...