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 }
