001 ###########################################
002 package WriteTracer;
003 use strict;
004 use POSIX;
005 use Inline "C";
006 use Fcntl;
007
008 use Sys::Ptrace qw(ptrace
009             PTRACE_SYSCALL PTRACE_TRACEME);
010
011 ###########################################
012 sub run {
013 ###########################################
014   my($prg, @params) = @_;
015
016   my @files = ();
017   my %files = ();
018
019   if((my $pid = fork()) < 0) {
020       die "fork failed";
021
022   } elsif($pid == 0) {
023       # child
024     ptrace(PTRACE_TRACEME, $$, 0, 0);
025     exec($prg, @params);
026
027   } else {
028       # parent
029     {
030       my $rc = waitpid($pid, 0);
031       last if $rc < 0;
032
033       if( WIFSTOPPED($?) ) {
034         my($eax, $orig_eax, $ebx, $ecx,
035            $edx) = ptrace_getregs($pid);
036
037         if($eax == -ENOSYS()) {
038           if($orig_eax == 5 and
039              $ecx & O_WRONLY) {
040             my $str = ptrace_string_read(
041                                $pid, $ebx);
042             push @files, $str
043                  unless $files{$str}++;
044           }
045         }
046
047         ptrace(PTRACE_SYSCALL, $pid,
048                undef, undef);
049         redo;
050       }
051     }
052   }
053   return @files;
054 }
055
056 1;
057
058 __DATA__
059 __C__
060 #include <sys/ptrace.h>
061 #include <asm/user.h>
062
063 #define IVPUSH(x) Inline_Stack_Push( \
064                    sv_2mortal(newSViv(x)));
065
066 /* ------------------------------------- */
067 void ptrace_getregs(int pid) {
068   int rc;
069   struct user_regs_struct registers;
070   Inline_Stack_Vars;
071
072   rc = ptrace(PTRACE_GETREGS, pid,
073                           0, &registers);
074   if(rc == -1) {
075       return;
076   }
077
078   if( registers.eax == -ENOSYS ) {
079       Inline_Stack_Reset;
080       IVPUSH(registers.eax);
081       IVPUSH(registers.orig_eax);
082       IVPUSH(registers.ebx);
083       IVPUSH(registers.ecx);
084       IVPUSH(registers.edx);
085       Inline_Stack_Done;
086   }
087 }
088
089 /* ------------------------------------- */
090 int ptrace_aligned_word_read_c(int pid,
091          void *addr, char *buf, int *len) {
092   char *aligned_addr;
093   long  word;
094   void *ptr;
095
096   aligned_addr = (char *) (
097        (long)addr & ~ (sizeof(long) - 1) );
098
099   word = ptrace(PTRACE_PEEKDATA, pid,
100                 aligned_addr, NULL);
101
102   if(word == -1) {
103       return -1;
104   }
105
106   *len = sizeof(long) - ( (long) addr -
107                      (long) aligned_addr );
108   ptr = &word;
109   ptr += (sizeof(long) - *len);
110   memcpy(buf, ptr, *len);
111
112   return 0;
113 }
114
115 /* ------------------------------------- */
116 void ptrace_string_read(int pid,
117                         void *addr) {
118   char  word_buf[ sizeof(long) ];
119   int   word_len;
120   SV   *pv;
121   int   rc;
122   int   i;
123   Inline_Stack_Vars;
124
125   pv = newSVpv((const char *)"", 0);
126
127   while(1) {
128     rc = ptrace_aligned_word_read_c(pid,
129                 addr, word_buf, &word_len);
130     if(rc < 0) {
131         return;
132     }
133
134     for(i=0; i<word_len; i++) {
135       if(word_buf[i] == '\0') {
136         goto FINISH;
137       }
138       sv_catpvn(pv, (const char *)
139                     &word_buf[i], 1);
140     }
141     addr += word_len;
142   }
143
144   FINISH:
145   Inline_Stack_Reset;
146   Inline_Stack_Push(sv_2mortal(pv));
147   Inline_Stack_Done;
148 }