栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

Linux下的signal调试

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Linux下的signal调试

Linux下的signal调试

最近逆向时候碰到了好几个关于signal的逆向题,因此来做个总结。

打开gdb输入info handle可以看到gdb对于所有信号量的默认处理方式,我们关注常用的前几个:

注意到圈起来的部分是gdb在调试时自己处理而不会传递给源程序的几个信号量,因此这几个信号量就大量用于逆向题中搞一些骚操作。对这四个信号量进行改写时,如果不更改gdb中的“pass to program”选项,则程序还是会安装默认的处理方式处理该信号。想要进行调试,需要用handle 信号量名 pass进行更改。

下面我们逐个讲解这四个信号量。

SIGINT

这是linux中的中断信号,当运行程序时按下ctrl+c时就出发了这个中断,正常情况下会结束程序。但是我们可以自己改写对该信号的处理函数。下面就是非常经典的一种用法:

#include 
#include 
#include 

void     INThandler(int);

void  main(void)
{
    signal(SIGINT, INThandler);// install SIGINT的处理函数
    while (1)
        pause();
}

void  INThandler(int sig)
{
    char  c;

    signal(sig, SIG_IGN); // uninstall 当前signal的处理函数
    printf("nDo you really want to quit? [y/n] ");
    c =getchar();
    if (c == 'y' || c == 'Y')
        exit(0);
    else
        signal(SIGINT, INThandler);
    getchar();  // 读取n
}

注意到我们在INThandler里先uninstall了对SIGINT的处理,之后再reinstall它。这是考虑到如果在处理上一个信号量时又有一个信号量输入进来导致程序发生错误。

SIGTRAP

The SIGTRAP signal is sent to a process when an exception (or trap) occurs: a condition that a debugger has requested to be informed of — for example, when a particular function is executed, or when a particular variable changes value.

我们的软件断点使用int 3实现,int 3会产生一个SIGTRAP的信号量,当在调试时如果不将该信号pass to program,那么程序就会停在这里作为一个断点。但有时候,程序本身注册了对于SIGTRAP的处理函数,如果不把信号量pass则会产生同一程序在调试与否的情况下会产生不同的运行结果。因此,很多逆向题会用这个方法来隐藏程序真正的逻辑。下面是一个案例:

#include 
#include 
   
#define SPC_DEBUGGER_PRESENT (num_traps == 0)
static int num_traps = 0;
   
static void int3handler(int signo) {
  num_traps++;
}
 
int spc_trap_detect(void) {
  if (signal(SIGTRAP, int3handler) == SIG_ERR) return 0;
  raise(SIGTRAP);
  return 1;
}

如果上面的程序正常运行,那么会触发int3handler,因此SPC_DEBUGGER_PRESENT为false。而如果调试器在的话,因为SIGTRAP被调试器截获,因此不会触发num_traps++, SPC_DEBUGGER_PRESENT为True。

SIGSEGV

这个信号量相信大家都不陌生,写bug的程序员们最讨厌它了。SIGSEGV is the signal a program gets from referencing a place in memory far away from all the areas in use.

这个也可以用作反调试,当程序正常运行时,SIGSEGV会被用户写的函数处理,因此不会直接崩溃。但是如果调试时没有pass,则程序会直接崩溃。

void sigsegv_handler(int signo, siginfo_t *info, void *extra) {
    ucontext_t* p = (ucontext_t*)extra;
	char* pc = (void*)(p->uc_mcontext.gregs[REG_RIP]);//获取触发SIGSEGV时的RIP
    char n = pc[5], m = pc[4];
    char *d = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
    decode_and_run(d, &pc[8], n, m); //对encrypted_func解密并运行
	munmap(d, 0x1000);
}

void fun() {
    encrypted_func(); //被加密的代码块,里面会触发SIGSEGV
    while(1);
}

SIGALRM

SIGALRM occurs when the alarm clock timer goes off (which happens only if your program has requested an alarm).

在逆向题目中往往用alarm来注册并隐藏用于检查输入是否合法的check函数。因为处理SIGALRM并不会暂停程序(在gdb的info handle中第一个stop是no),所以用alarm可以做出并行处理。下面是一个SIGALRM的样例:

#include  
#include  

unsigned long  counter;            
int            MAX;                
int            ALARMcount;         
int            SECOND;             

void  ALARMhandler(int sig)
{
     signal(SIGALRM, SIG_IGN);      
     ALARMcount++;              
     printf("*** ALARMhandler --> alarm received no. %d.n", ALARMcount);
     printf("*** ALARMhandler --> counter = %ldn", counter);
     printf("*** ALARMhandler --> alarm reset to %d secondsn", SECOND);
     if (ALARMcount == MAX) {          
          printf("*** ALARMhandler --> Maximum alarm count reached.  exitn");
          exit(0);
     }          
     counter = 0;                       
     alarm(SECOND);                     
     signal(SIGALRM, ALARMhandler);     
}

void  main(int argc, char *argv[])
{
     if (argc != 3) {
          printf("Use: %s seconds max-alarm-countn", argv[0]);
          printf("No. of seconds is set to 1n");
          SECOND = 1;
          printf("Max number of alarms set to 5n");
          MAX    = 5;
     }
     else {
          SECOND = atoi(argv[1]);
          MAX    = atoi(argv[2]);
     }
     counter    = 0;              
     ALARMcount = 0;                  
     signal(SIGALRM,ALARMhandler);    
     printf("Alarm set to %d seconds and is ticking now.....n", SECOND);
     alarm(SECOND);                   
     while (1)                        
          counter++;
}
Reference

Linux - signal处理的一些补充

Install a Signal Handler

Signals

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/277609.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号