玩转ptrace(一)

ptrace 分析[基于Android 8.0 msm-4.4] 从 man开始: $man 2 ptrace PTRACE(2)                                                                       Linux Programmer's Manual 阅读详情

转自:http://blog.youkuaiyun.com/silentvoid/article/details/1477439

by Pradeep Padala

Created 2002-11-01 02:00

翻译: Magic.D E-mail: adamgic@163.com

译者序:在开发Hust Online Judge的过程中,查阅了不少资料,关于调试器技术的资料在网上是很少,即便是UNIX编程巨著《UNIX环境高级编程》中,相关内容也不多,直到我在http://www.linuxjournal.com上找到这篇文章,如获至宝,特翻译之,作为鄙人翻译技术文档的第一次尝试,必定会有不少蹩脚之处,各位就将就一下吧,欢迎大力拍砖。


你想过怎么实现对系统调用的拦截吗?你尝试过通过改变系统调用的参数来愚弄你的系统kernel吗?你想过调试器是如何使运行中的进程暂停并且控制它吗?

你可能会开始考虑怎么使用复杂的kernel编程来达到目的,那么,你错了。实际上Linux提供了一种优雅的机制来完成这些:ptrace系统函数。 ptrace提供了一种使父进程得以监视和控制其它进程的方式,它还能够改变子进程中的寄存器和内核映像,因而可以实现断点调试和系统调用的跟踪。

使用ptrace,你可以在用户层拦截和修改系统调用(sys call)

在这篇文章中,我们将学习如何拦截一个系统调用,然后修改它的参数。在本文的第二部分我们将学习更先进的技术:设置断点,插入代码到一个正在运行的程序中;我们将潜入到机器内部,偷窥和纂改进程的寄存器和数据段。

 

基本知识

操作系统提供了一种标准的服务来让程序员实现对底层硬件和服务的控制(比如文件系统),叫做系统调用(system calls)。当一个程序需要作系统调用的时候,它将相关参数放进系统调用相关的寄存器,然后调用软中断0x80,这个中断就像一个让程序得以接触到内核模式的窗口,程序将参数和系统调用号交给内核,内核来完成系统调用的执行。

 

在i386体系中(本文中所有的代码都是面向i386体系),系统调用号将放入%eax,它的参数则依次放入%ebx, %ecx, %edx, %esi 和 %edi。 比如,在以下的调用

 

       Write(2, “Hello”, 5)

 

的汇编形式大概是这样的

      

    movl   $4, %eax

    movl   $2, %ebx

    movl   $hello, %ecx

    movl   $5, %edx

    int    $0x80

 

这里的$hello指向的是标准字符串”Hello”。

 

那么,ptrace会在什么时候出现呢?在执行系统调用之前,内核会先检查当前进程是否处于被“跟踪”(traced)的状态。如果是的话,内核暂停当前进程并将控制权交给跟踪进程,使跟踪进程得以察看或者修改被跟踪进程的寄存器。

 

让我们来看一个例子,演示这个跟踪程序的过程

 

#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <linux/user.h>   /**//* For constants 
                                   ORIG_EAX etc */
int main()
...{
   pid_t child;
    long orig_eax;
    child = fork();
    if(child == 0) ...{
        ptrace(PTRACE_TRACEME, 0, NULL, NULL);
        execl("/bin/ls", "ls", NULL);
    }
    else ...{
        wait(NULL);
        orig_eax = ptrace(PTRACE_PEEKUSER, 
                          child, 4 * ORIG_EAX, 
                          NULL);
        printf("The child made a "
               "system call %ld ", orig_eax);
        ptrace(PTRACE_CONT, child, NULL, NULL);
    }
    return 0;
}

运行这个程序,将会在输出ls命令的结果的同时,输出:

 

The child made a system call 11

 

说明:11是execve的系统调用号,这是该程序调用的第一个系统调用。

想知道系统调用号的详细内容,察看 /usr/include/asm/unistd.h。

 

在以上的示例中,父进程fork出了一个子进程,然后跟踪它。在调用exec函数之前,子进程用PTRACE_TRACEME作为第一个参数调用了ptrace函数,它告诉内核:让别人跟踪我吧!然后,在子进程调用了execve()之后,它将控制权交还给父进程。当时父进程正使用wait()函数来等待来自内核的通知,现在它得到了通知,于是它可以开始察看子进程都作了些什么,比如看看寄存器的值之类。

 

出现系统调用之后,内核会将eax中的值(此时存的是系统调用号)保存起来,我们可以使用PTRACE_PEEKUSER作为ptrace的第一个参数来读到这个值。

我们察看完系统调用的信息后,可以使用PTRACE_CONT作为ptrace的第一个参数,调用ptrace使子进程继续系统调用的过程。

 

ptrace函数的参数

 

Ptrace有四个参数

long ptrace(enum __ptrace_request request,
            pid_t pid,
            void *addr,
            void *data);

 

第一个参数决定了ptrace的行为与其它参数的使用方法,可取的值有:

PTRACE_ME

PTRACE_PEEKTEXT

PTRACE_PEEKDATA

PTRACE_PEEKUSER

PTRACE_POKETEXT

PTRACE_POKEDATA

PTRACE_POKEUSER

PTRACE_GETREGS

PTRACE_GETFPREGS,

PTRACE_SETREGS

PTRACE_SETFPREGS

PTRACE_CONT

PTRACE_SYSCALL,

PTRACE_SINGLESTEP

PTRACE_DETACH

在下文中将对这些常量的用法进行说明。

 

读取系统调用的参数

 

通过将PTRACE_PEEKUSER作为ptrace 的第一个参数进行调用,可以取得与子进程相关的寄存器值。

 

先看下面这个例子

#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <linux/user.h>
#include <sys/syscall.h>   /**//* For SYS_write etc */

int main()
...{   
    pid_t child;
    long orig_eax, eax;
    long params[3];
    int status;
    int insyscall = 0;
    child = fork();
    if(child == 0) ...{
        ptrace(PTRACE_TRACEME, 0, NULL, NULL);
        execl("/bin/ls", "ls", NULL);
    }
    else ...{
       while(1) ...{
          wait(&status);
          if(WIFEXITED(status))
              break;
          orig_eax = ptrace(PTRACE_PEEKUSER, 
                     child, 4 * ORIG_EAX, NULL);
          if(orig_eax == SYS_write) ...{
             if(insyscall == 0) ...{    
                /**//* Syscall entry */
                insyscall = 1;
                params[0] = ptrace(PTRACE_PEEKUSER,
                                   child, 4 * EBX, 
                                   NULL);
                params[1] = ptrace(PTRACE_PEEKUSER,
                                   child, 4 * ECX, 
                                   NULL);
                params[2] = ptrace(PTRACE_PEEKUSER,
                                   child, 4 * EDX, 
                                   NULL);
                printf("Write called with "
                       "%ld, %ld, %ld ",
                       params[0], params[1],
                       params[2]);
                }
          else ...{ /**//* Syscall exit */
                eax = ptrace(PTRACE_PEEKUSER, 
                             child, 4 * EAX, NULL);
                    printf("Write returned "
                           "with %ld ", eax);
                    insyscall = 0;
                }
            }
            ptrace(PTRACE_SYSCALL, 
                   child, NULL, NULL);
        }
    }
    return 0;
}

这个程序的输出是这样的

 

ppadala@linux:~/ptrace > ls
a.out        dummy.s      ptrace.txt   
libgpm.html  registers.c  syscallparams.c
dummy        ptrace.html  simple.c
ppadala@linux:~/ptrace > ./a.out
Write called with 1, 1075154944, 48
a.out        dummy.s      ptrace.txt
Write returned with 48
Write called with 1, 1075154944, 59
libgpm.html  registers.c  syscallparams.c
Write returned with 59
Write called with 1, 1075154944, 30
dummy        ptrace.html  simple.c
Write returned with 30

 

 

以上的例子中我们跟踪了write系统调用,而ls命令的执行将产生三个write系统调用。使用PTRACE_SYSCALL作为ptrace的第一个参数,使内核在子进程做出系统调用或者准备退出的时候暂停它。这种行为与使用PTRACE_CONT,然后在下一个系统调用/进程退出时暂停它是等价的。

 

在前一个例子中,我们用PTRACE_PEEKUSER来察看write系统调用的参数。系统调用的返回值会被放入%eax。

 

wait函数使用status变量来检查子进程是否已退出。它是用来判断子进程是被ptrace暂停掉还是已经运行结束并退出。有一组宏可以通过status的值来判断进程的状态,比如WIFEXITED等,详情可以察看wait(2) man。

 

读取寄存器的值

 

如果你想在系统调用或者进程终止的时候读取它的寄存器,使用前面那个例子的方法是可以的,但是这是笨拙的方法。使用PRACE_GETREGS作为ptrace的第一个参数来调用,可以只需一次函数调用就取得所有的相关寄存器值。

获得寄存器值得例子如下:

#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <linux/user.h>
#include <sys/syscall.h>

int main()
...{   
    pid_t child;
    long orig_eax, eax;
    long params[3];
    int status;
    int insyscall = 0;
    struct user_regs_struct regs;
    child = fork();
    if(child == 0) ...{
        ptrace(PTRACE_TRACEME, 0, NULL, NULL);
        execl("/bin/ls", "ls", NULL);
    }
    else ...{
       while(1) ...{
          wait(&status);
          if(WIFEXITED(status))
              break;
          orig_eax = ptrace(PTRACE_PEEKUSER, 
                            child, 4 * ORIG_EAX, 
                            NULL);
          if(orig_eax == SYS_write) ...{
              if(insyscall == 0) ...{
                 /**//* Syscall entry */
                 insyscall = 1;
                 ptrace(PTRACE_GETREGS, child, 
                        NULL, &regs);
                 printf("Write called with "
                        "%ld, %ld, %ld ",
                        regs.ebx, regs.ecx, 
                        regs.edx);
             }
             else ...{ /**//* Syscall exit */
                 eax = ptrace(PTRACE_PEEKUSER, 
                              child, 4 * EAX, 
                              NULL);
                 printf("Write returned "
                        "with %ld ", eax);
                 insyscall = 0;
             }
          }
          ptrace(PTRACE_SYSCALL, child,
                 NULL, NULL);
       }
   }
   return 0;
}

这段代码与前面的例子是比较相似的,不同的是它使用了PTRACE_GETREGS。 其中的user_regs_struct结构是在<linux/user.h>中定义的。

 

 

来点好玩的

 

现在该做点有意思的事情了,我们将要把传给write系统调用的字符串给反转。

#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <linux/user.h>
#include <sys/syscall.h>

const int long_size = sizeof(long);

void reverse(char *str)
...{   
    int i, j;
    char temp;
    for(i = 0, j = strlen(str) - 2; 
        i <= j; ++i, --j) ...{
        temp = str[i];
        str[i] = str[j];
        str[j] = temp;
    }
}

void getdata(pid_t child, long addr, 
             char *str, int len)
...{   
    char *laddr;
    int i, j;
    union u ...{
            long val;
            char chars[long_size];
    }data;

    i = 0;
    j = len / long_size;
    laddr = str;
    while(i < j) ...{
        data.val = ptrace(PTRACE_PEEKDATA, 
                          child, addr + i * 4, 
                          NULL);
        memcpy(laddr, data.chars, long_size);
        ++i;
        laddr += long_size;
    }
    j = len % long_size;
    if(j != 0) ...{
        data.val = ptrace(PTRACE_PEEKDATA, 
                          child, addr + i * 4, 
                          NULL);
        memcpy(laddr, data.chars, j);
    }
    str[len] = '';
}

void putdata(pid_t child, long addr, 
             char *str, int len)
...{   
    char *laddr;
    int i, j;
    union u ...{
            long val;
            char chars[long_size];
    }data;

    i = 0;
    j = len / long_size;
    laddr = str;
    while(i < j) ...{
        memcpy(data.chars, laddr, long_size);
        ptrace(PTRACE_POKEDATA, child, 
               addr + i * 4, data.val);
        ++i;
        laddr += long_size;
    }
    j = len % long_size;
    if(j != 0) ...{
        memcpy(data.chars, laddr, j);
        ptrace(PTRACE_POKEDATA, child, 
               addr + i * 4, data.val);
    }
}

int main()
...{   
   pid_t child;
   child = fork();
   if(child == 0) ...{
      ptrace(PTRACE_TRACEME, 0, NULL, NULL);
      execl("/bin/ls", "ls", NULL);
   }
   else ...{
      long orig_eax;
      long params[3];
      int status;
      char *str, *laddr;
      int toggle = 0;
      while(1) ...{
         wait(&status);
         if(WIFEXITED(status))
             break;
         orig_eax = ptrace(PTRACE_PEEKUSER, 
                           child, 4 * ORIG_EAX, 
                           NULL);
         if(orig_eax == SYS_write) ...{
            if(toggle == 0) ...{
               toggle = 1;
               params[0] = ptrace(PTRACE_PEEKUSER, 
                                  child, 4 * EBX, 
                                  NULL);
               params[1] = ptrace(PTRACE_PEEKUSER, 
                                  child, 4 * ECX, 
                                  NULL);
               params[2] = ptrace(PTRACE_PEEKUSER,
                                  child, 4 * EDX, 
                                  NULL);
               str = (char *)calloc((params[2]+1)
                                 * sizeof(char));
               getdata(child, params[1], str, 
                       params[2]);
               reverse(str);
               putdata(child, params[1], str, 
                       params[2]);
            }
            else ...{
               toggle = 0;
            }
         }
      ptrace(PTRACE_SYSCALL, child, NULL, NULL);
      }
   }
   return 0;
}

输出是这样的:

 

ppadala@linux:~/ptrace > ls
a.out        dummy.s      ptrace.txt
libgpm.html  registers.c  syscallparams.c
dummy        ptrace.html  simple.c
ppadala@linux:~/ptrace > ./a.out
txt.ecartp      s.ymmud      tuo.a
c.sretsiger     lmth.mpgbil  c.llacys_egnahc
c.elpmis        lmth.ecartp  ymmud

 

 

这个例子中涵盖了前面讨论过的所有知识点,当然还有些新的内容。这里我们用PTRACE_POKEDATA作为第一个参数,以此来改变子进程中的变量值。它以与PTRACE_PEEKDATA相似的方式工作,当然,它不只是偷窥变量的值了,它可以修改它们。

 

单步

 

ptrace提供了对子进程进行单步的功能。 ptrace(PTRACE_SINGLESTEP, …) 会使内核在子进程的每一条指令执行前先将其阻塞,然后将控制权交给父进程。下面的例子可以查出子进程当前将要执行的指令。为了便于理解,我用汇编写了这个受控程序,而不是让你为c的库函数到底会作那些系统调用而头痛。

 

以下是被控程序的代码 dummy1.s,使用gcc  –o dummy1 dummy1.s来编译

 

.data
hello:
    .string "hello world/n"
.globl  main
main:
    movl    $4, %eax
    movl    $2, %ebx
    movl    $hello, %ecx
    movl    $12, %edx
    int     $0x80
    movl    $1, %eax
    xorl    %ebx, %ebx
    int     $0x80
    ret

 

 

以下的程序则用来完成单步:

#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <linux/user.h> 
#include <sys/syscall.h>
int main()
...{
    pid_t child;
    const int long_size = sizeof(long);
    child = fork();
    if(child == 0) ...{
        ptrace(PTRACE_TRACEME, 0, NULL, NULL);
        execl("./dummy1", "dummy1", NULL);
    }
    else ...{
        int status;
        union u ...{
            long val;
            char chars[long_size];
        }data;
        struct user_regs_struct regs;
        int start = 0;
        long ins;
        while(1) ...{
            wait(&status);
            if(WIFEXITED(status))
                break;
            ptrace(PTRACE_GETREGS, 
                   child, NULL, &regs);
            if(start == 1) ...{
                ins = ptrace(PTRACE_PEEKTEXT, 
                             child, regs.eip, 
                             NULL);
                printf("EIP: %lx Instruction "
                       "executed: %lx ", 
                       regs.eip, ins);
            }
            if(regs.orig_eax == SYS_write) ...{
                start = 1;
                ptrace(PTRACE_SINGLESTEP, child, 
                       NULL, NULL);
            }
            else
                ptrace(PTRACE_SYSCALL, child, 
                       NULL, NULL);
        }
    }
    return 0;
}

程序的输出是这样的:

你可能需要察看Intel的用户手册来了解这些指令代码的意思。

更复杂的单步,比如设置断点,则需要很仔细的设计和更复杂的代码才可以实现。

 

 

在第二部分,我们将会看到如何在程序中加入断点,以及将代码插入到已经在运行的程序中。


在Android使用上ptrace的尝试(一) Ptrace功能强大,可以用于调试跟踪。跑了蒸米大神写的例子,学习一下。 实验1:获取system call的编号 要ptrace的目标程序target,用来一直循环输出 #include int count = 0; void sevenWeapons(int number){ char* str = "hello!"; printf("%s, %d\n",str,n 阅读详情

相关推荐

立创·庐山派-K230-CanMV(嘉楠勘智)开发板通过ATK-ESP8266实现图像识别数据无线传输至原子云

本文详细介绍了如何使用立创·庐山派-K230-CanMV开发板,通过ATK-ESP8266 WIFI模块实现图像识别数据的无线传输至原子云平台。内容包括硬件连接、软件环境搭建、AT指令控制、原子云连接及数据上传的全过程,并提供了实用的调试技巧和常见问题解决方案,为物联网应用开发提供了完整实践指南。

potato的博客 743

linux ptrace,Linux ptrace 简介

Linux ptrace 简介2017-06-15 Thursdayptrace() 是一个由 Linux 内核提供的系统调用,允许一个用户态进程检查、修改另一个进程的内存和寄存器,通常用在类似 gdb、strace 的调试器中,用来实现断点调试、系统调用的跟踪。你想过怎么实现对系统调用的拦截吗?你尝试过通过改变系统调用的参数来愚弄你的系统 kernel 吗?你想过调试器是如何使运行中的进程暂停并...

weixin_39574246的博客 1054

STM32H743IIT6上LVGL移植实战:从零到触摸屏驱动的完整配置流程

本文详细记录了在STM32H743IIT6高性能MCU上,从零开始移植LVGL图形库到7寸RGB触摸屏的完整实战流程。内容涵盖工程搭建、显示与触摸驱动配置、LVGL核心优化及常见问题排查,重点讲解了如何利用STM32H743的硬件特性(如DMA2D、LTDC)提升GUI性能,为嵌入式GUI开发提供了一份详实的配置指南。

spark7igniter的博客 561

玩转ptrace(一) [z](转帖真的很好)

 玩转ptrace(一) [z]  by Pradeep Padala Created 2002-11-01 02:00翻译: Magic.D E-mail: adamgic@163.com译者序:在开发Hust Online Judge的过程中,查阅了不少资料,关于调试器技术的资料在网上是

zgl07的专栏 901

相机光学(三十八)——VCM(Voice Coil Motor)音圈马达

VCM(Voice Coil Motor)音圈马达全称Voice Coil Montor,电子学里面的音圈电机,是马达的一种。因为原理和扬声器类似,所以叫音圈电机,具有高频响、高精度的特点。其主要原理是在一个永久磁场内,通过改变马达内线圈的直流电流大小,来控制弹簧片的拉伸位置,从而带动上下运动。手机摄像头广泛的使用VCM实现自动对焦功能,通过VCM可以调节镜头的位置,呈现清晰的图像。弹片式结构滚珠式结构摩擦式结构Open loop开马达Close loop闭环马达。

图像学习之旅 7224

GD32官方资料学习体系(主要包括MCU选型、原理图PCB设计、软件开发入门及用户手册等)

大部分还未更新,先占个坑,日后更新…… 目前国外芯片涨价涨的离谱(就是在说ST),国内最好的替代就是兆易创新出的系列芯片了。但是官方资料繁杂,小白上手不易,因此边入门边记录,也给后来者根据官方资料可以有一个较为完整的学习体系。

Eddie的博客 1万+

linux后门程序利用,利用Linux的共享库编写出injectso后门程序

下面让我们来写一个简单后门程序。第1步,我们可以调用上面给出的ptrace_attach()完成。第2步,可以通过find_symbol()找到_dl_open的地址。第3步我们可以调用ptrace_call()来调用_dl_open,但是要注意_dl_open定义为’internal_function’,这说明它的传递方式是通过寄存器而不是堆栈,这样看来在调用_dl_open之前还需做一些琐碎的...

weixin_42458217的博客 425

ubuntu恢复分区表——testdisk

testdisk恢复ubuntu分区表testdisk介绍安装testdisk使用testdisk恢复分区表 testdisk介绍 testdisk 具有广泛的功能,包括恢复丢失或损坏的分区和使不能启动磁盘可以重新启动,也经常被用来恢复被误删的文件。 安装testdisk 如果系统分区表被删除,需要使用ubuntu的启动盘,选择try ubnutu模式进入试用系统。 1、可以直接在终端安装testdisk: sudo apt-get install testdisk 通过命令直接打开testdisk: t

ZNestor的博客 6460

玩转ptrace(一) [转]

原文:http://blog.chinaunix.net/u/19651/showart_362901.html英文原文:http://www.linuxjournal.com/article/6100code:ftp.ssc.com/pub/lj/listings/issue103/6011.tgz-------------------------------------------------

scancsdn的专栏 568

飞控芯片的隐形战场:传感器冗余与实时OS的可靠性革命

本文深入探讨飞控芯片在工业级无人机中的可靠性设计,聚焦传感器冗余架构与实时操作系统(RTOS)的容错机制。通过多IMU备份、自适应加权融合算法及NuttX、ChibiOS等RTOS的故障隔离技术,确保系统在极端环境下毫秒级自愈。文章还涵盖开源生态如PX4的跨平台移植及RISC-V架构的应用,为高可靠性飞控系统提供关键技术参考。

z5a6b的博客 877

手把手教你学Simulink——基于经典PID控制的电机系统场景实例:BLDC电机PID电流控制策略仿真

*无刷直流电机(Brushless DC Motor, BLDC)**因其高效率、长寿命和低维护成本,在众多领域如家用电器、工业自动化、电动汽车等得到了广泛应用。为了实现对BLDC电机的有效控制,通常采用基于霍尔传感器或反电动势检测的换相技术,并结合电流闭环控制以提高系统的动态响应和稳定性。本教程将带你使用构建一个基于PID控制的BLDC电机电流控制策略仿真模型BLDC电机建模PID控制器设计与应用系统仿真与调试控制效果分析本文介绍了如何使用构建一个。

MHD0815的博客 197

玩转ptrace (一)

http://www.cnblogs.com/catch/p/3476280.html [本文翻译自这里: http://www.linuxjournal.com/article/6100?page=0,0,作者:Pradeep Padaia]   你是否曾经想过怎样才能拦截系统调用?你是否曾经想过通过修改一下系统调用的参数来耍一把内核?你是否想过调试器是怎样把一个进

zhangmiaoping23的专栏 866

PointNet++改进策略 :模块改进 | x-Conv | PointCNN, 结合局部结构与全局排列提升模型性能

这篇论文介绍了一种名为PointCNN的方法,旨在从点云(point cloud)数据中学习特征。传统卷积神经网络(CNN)在处理规则网格数据(如图像)时非常有效,但由于点云是无序且不规则的,直接在其上应用卷积操作会导致形状信息丢失,并对点的排列顺序敏感。为了解决这一问题,论文提出了一种X-Conv操作。该方法通过学习一种来重新排列点云中的点并加权输入特征。然后,将典型的卷积操作应用于转换后的特征。这种方法将传统的 CNN 扩展到点云特征学习,并命名为PointCNN。

u012901740的博客 2300

Playing with ptrace, Part I — 玩转ptrace(一)

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34186128的博客 144

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

[译] 玩转ptrace (一)

[本文翻译自这里:http://www.linuxjournal.com/article/6100?page=0,0,作者:Pradeep Padaia] 你是否曾经想过怎样才能拦截系统调用?你是否曾经想过通过修改一下系统调用的参数来耍一把内核?你是否想过调试器是怎样把一个进程停下来,然后把控制权转移给你的?如果你以为这些都是通过复杂的内核编程来实现的,那你就错了,事实上,Linux 提...

weixin_34360651的博客 335

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

【转】玩转ptrace(一)

【转】玩转ptrace(一)

code09的专栏 568

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

[译] 玩转ptrace (一) 拦截系统调用

[本文翻译自这里: http://www.linuxjournal.com/article/6100?page=0,0,作者:Pradeep Padaia]   你是否曾经想过怎样才能拦截系统调用?你是否曾经想过通过修改一下系统调用的参数来耍一把内核?你是否想过调试器是怎样把一个进程停下来,然后把控制权转移给你的?如果你以为这些都是通过复杂的内核编程来实现的,那你就错了,事实上,Linux 提

xiaoxinyu316的专栏 3444

[转] Playing with ptrace, Part I — 玩转ptrace(一)

Playing with ptrace, Part Iby Pradeep Padala p_padala@yahoo.com http://www.cise.ufl.edu/~ppadalaCreated 2002-11-01 02:00 翻译: Magic.D E-mail: adamgic@163.com 译者序: 在开发Hust Online Judge的过程中,查阅了不少资料,关于调试器...

weixin_30740295的博客 85

玩转ptrace(二)

by Pradeep PadalaCreated 2002-11-01 02:00翻译: Magic.D 在第一部分中我们已经看到ptrace怎么获取子进程的系统调用以及改变系统调用的参数。在这篇文章中,我们将要研究如何在子进程中设置断点和往运行中的程序里插入代码。实际上调试器就是用这种方法来设置断点和执行调试句柄。与前面一样,这里的所有代码都是针对i386平台的。 附着在

4914

玩转ptrace

原文地址:http://www.cnblogs.com/catch/p/3476280.html点击打开链接 二点击打开链接 [译] 玩转ptrace (一) [本文翻译自这里: http://www.linuxjournal.com/article/6100?page=0,0,作者:Pradeep Padaia]   你是否曾经想过怎样才能拦截系统调用?你是否曾经想过通过修改一

yang_chen_shi_wo的博客 373
上一篇: STL中容器的几个容易混淆的成员函数-size, capacity, resize, reserve
下一篇: 玩转ptrace(二)
小文兄弟
博客等级 码龄17年 28粉丝 18原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值