发一个较好的调试工具

本文介绍了一种使用ptrace系统调用进行程序调试的方法,详细解释了如何绕过常见的反调试技术,如检测ptrace调用和系统调用的监控。通过实例展示了如何在遇到反调试代码时修改返回值,以及如何在特定系统调用(如read)完成时生成内存镜像。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

//a good crackme tool,usr ptrace to debug the need-crack file
 //from tiocsti's solution to yanisto's Tiny Crackme,URL: http://crackmes.de/users/yanisto/tiny_crackme/solutions/tiocsti/browse
 //added some comments
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/ptrace.h>
 #include <sys/signal.h>
 #include <sys/syscall.h>
 #include <asm/unistd.h>
 #include <linux/user.h>

int handle_ptrace_singlestep(pid_t pid, FILE *fp)
 {
     struct user_regs_struct regs;
     ptrace(PTRACE_GETREGS, pid, 0, &regs);
     //在每条指令停止后,记录下需要监控的寄存器的内容
    fprintf(fp, "%08x eax=%x ebx=%x ecx=%x edx=%x esi=%x edi=%x\n",
         regs.eip,
         regs.eax,
         regs.ebx,
         regs.ecx,
         regs.edx,
         regs.esi,
         regs.edi);
     ptrace(PTRACE_SINGLESTEP, pid, 0, 0);
     return 1;
 }

int handle_ptrace_syscall(pid_t pid, FILE *fp)
 {
     struct user_regs_struct regs;
     //拷贝child 进程的常用或浮点寄存器的数据到&regs中
        ptrace(PTRACE_GETREGS, pid, 0, &regs);
        //下面通过检测寄存器的值,来判断程序执行到什么步骤
    //orig_eax为系统调用号
    //eax为系统调用返回值
    //orig_eax为26,且返回值为-1,则说明子进程识别到被ptrace了
    if(regs.orig_eax == __NR_ptrace && regs.eax == -1)
         {
         fprintf(fp, "identified anti ptrace code...disabling\n");
         //修改返回值eax为0,并返回给子进程
            regs.eax = 0;
                 ptrace(PTRACE_SETREGS, pid, 0, &regs);
         }
     //检测到read系统调用完成了
    else if(regs.orig_eax == __NR_read && regs.ebx == 1 && regs.eax == 4)
     {
         FILE *outputfile;
         unsigned int i = 0x00200000;
         unsigned int dataword;

        fprintf(fp, "identified sys_read, trying to dump image and switch to single step mode\n");
         //将一个32 bits 的0拷贝到ecx寄存器指向的内存位置
        //ssize_t read(int fd, void *buf, size_t count);
         ptrace(PTRACE_POKEDATA, pid, regs.ecx, 0);

             //下面以二进制方式将内存镜像写入文件
        outputfile = fopen("bmcrack.bin", "wb");
         for(;i < 0x00200320;i+=4)
         {
         //从子进程地址空间的位置i 拷贝一个word,并返回给dataword
         //如果读多了怎么办,这里是不是也应该有容错代码????
             dataword = ptrace(PTRACE_PEEKDATA, pid, i, 0);
             fwrite(&dataword, 4, 1, outputfile);
         }
         //将镜像文件写入完毕
        //作者选择在这个位置开始dump出镜像文件,如果不行就得选其他地方:)
         fclose(outputfile);
         
         //PTRACE_SYSCALL,在执行一条指令后停止
        ptrace(PTRACE_SINGLESTEP, pid, 0, 0);
         return 1;
     }
        //继续执行一次PTRACE_SYSCALL        
         ptrace(PTRACE_SYSCALL, pid, 0, 0);
     return 0;
 }

int main(int argc, char **argv)
 {
     pid_t mypid;
     FILE *fp=NULL;
     int state=0;

    mypid = fork();
     switch(mypid)
     {
         case 0:
             // child process
             //执行待监控的对象
            ptrace(PTRACE_TRACEME, 0, 0, 0);
             execl(argv[1], argv[1], NULL);
             _exit(0);
         case -1:
             // error
             perror("fork");
             _exit(-1);
         default:
             fp = fopen("log.txt", "wt");
             if(!fp)
             {
                 perror("fopen");
                 kill(mypid, 9);
                 wait(NULL);
                 _exit(-1);
             }
             wait(NULL);
             //通过发送0检查进程是否存在
            if(kill(mypid, 0) == -1)
             {
                 fclose(fp);
                 exit(0);
             }
             //PTRACE_SYSCALL,在每个系统调用进入/退出时停止
            ptrace(PTRACE_SYSCALL, mypid, 0, 0);
             while(1)
             {
                 wait(NULL);
                 if(kill(mypid, 0) == -1)
                 {
                     fclose(fp);
                     exit(0);
                 }
                 if(state == 0)
                     //首先,执行去除anti-ptrace的代码
                    //然后,检测到read syscall后生成dump文件
                    state=handle_ptrace_syscall(mypid, fp);
                 else
                     //第三,才是开始跟踪read调用后的每一个指令
                    state=handle_ptrace_singlestep(mypid, fp);
             }
     }
 }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值