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. 在Windows系统上搭建aria2下载器

    Aria2是一个命令行下运行.多协议.多来源下载工具(HTTP/HTTPS.FTP.BitTorrent.Metalink),并且支持迅雷离线以及百度云等常用网盘的多线程下载(甚至可以超过专用客户端的 ...

  2. AliRedis单机180w QPS, 8台服务器构建1000w QPS Cache集群

    转自:http://www.open-open.com/lib/view/open1389880948758.html 引言:        如今redis凭借其高性能的优势, 以及丰富的数据结构作为 ...

  3. 类型化dataset分页

    SELECT TOP (@每页行数) 所选列FROM 表名WHERE (主键 NOT IN( SELECT TOP ((@页数-1)*@每页行数) 主键FROM 表名where ( 条件)))AND ...

  4. RabbitMQ Queue中Arguments属性参数过期队列,过期消息,超时队列的声明

    开发十年,就只剩下这套Java开发体系了 >>>   创建队列时指定参数 队列属性:x-message-ttl 可以控制被publish到queue中的message 被丢弃前能够存 ...

  5. No.4 PyQt学习(页面跳转)

    先定义了两个MainWindow进行跳转,但发现这样的话,从第二个Window无法跳转会第一个.代码如下: # -*- coding: utf-8 -*- import sys from PyQt4. ...

  6. c++ 纯虚析构函数

    ; 这就是一个纯虚析构函数,这种定义是允许的. 一般纯虚函数都不允许有实体,但是因为析构一个类的过程中会把所有的父类全析构了,所以每个类必有一个析构函数. 所以.纯虚析构函数需要提供函数的实现,而一般 ...

  7. 【Java基础】StringTokenizer用法

    写在前面 因为最近在接触hadoop的东西,看示例WordCount的时候里面有一个StringTokenizer的东西特地看了一下 The string tokenizer class allows ...

  8. 【VI】如何删除匹配指定字符串的行(已解决)

    命令: g/pattern/d 如,删除包含字母 hell 的行 g/hell/d 删除 不 匹配指定字符的行(未验证,有需要的朋友可以试一下) v/pattern/d g!/pattern/d

  9. 使用 mysql workbench 建议

    在日常使用mysql workbench时,未免操作失误,不建议启用远程管理.

  10. Bat脚本实现监控进程功能

    脚本不间断监控notepad.exe进程是否执行,若停止,则自动重启该进程,程序如下: @echo off set _task = notepad.exe set _svr = c:\windows\ ...