FreeBSD::i386::Ptrace - Ptrace for FreeBSD-i386
$Id: Ptrace.pm,v 0.3 2009/03/20 22:42:20 dankogai Exp dankogai $
# simple strace in perl use strict; use warnings; use FreeBSD::i386::Ptrace; use FreeBSD::i386::Ptrace::Syscall; die "$0 prog args ..." unless @ARGV; my $pid = fork(); die "fork failed:$!" if !defined($pid); if ( $pid == 0 ) { # son pt_trace_me; exec @ARGV; } else { # mom wait; # for exec; my $count = 0; while ( pt_to_sce($pid) == 0 ) { last if wait == -1; my $call = pt_getcall($pid); pt_to_scx($pid); wait; my $retval = pt_getcall($pid); my $name = $SYS{$call} || 'unknown'; print "$name() = $retval\n"; $count++; } warn "$count system calls issued\n"; }
ptrace, pt_trace_me, pt_attach, pt_detach, pt_syscall, pt_to_sce pt_to_scx pt_getcall,pt_setcall. pt_getregs, pt_setregs pt_read, pt_write, pt_peekstr, pt_pokestr pt_kill and PT_* constants.
ptrace
pt_trace_me
pt_attach
pt_detach
pt_syscall
pt_to_sce
pt_to_scx
pt_getcall
pt_setcall
pt_getregs
pt_setregs
pt_read
pt_write
pt_peekstr
pt_pokestr
pt_kill
for %SYS, use <FreeBSD::i386::Ptrace::Syscall>.
%SYS
A thin wrapper to "2" in ptrace.
#include <sys/types.h> #include <sys/ptrace.h> int ptrace(int request, pid_t pid, caddr_t addr, int data);
All arguments are integer from perl.
Shortand for ptrace(PT_TRACE_ME, 0, 0, 0).
ptrace(PT_TRACE_ME, 0, 0, 0)
Shortand for ptrace(PT_ATTACH, pid, 0, 0).
ptrace(PT_ATTACH, pid, 0, 0)
Shortand for ptrace(PT_DETACH, pid, 0, 0).
ptrace(PT_DETACH, pid, 0, 0)
Shortand for ptrace(PT_TO_SCE, pid, 0, 0).
ptrace(PT_TO_SCE, pid, 0, 0)
Looks like SCE stands for "System Call Entry".
Shortand for ptrace(PT_TO_SCX, pid, 0, 0).
ptrace(PT_TO_SCX, pid, 0, 0)
Looks like SCE stands for "System Call eXit".
Shortand for ptrace(PT_SYSCALL, pid, 1, 0). Unlike Linux the 3rd argument must be 1 or it loops infinitely.
ptrace(PT_SYSCALL, pid, 1, 0)
Note PT_SYSCALL is invoked both on entry to and return from the system call. See "SYNOPSIS" to see how to switch between them.
Returns the value of EAX register which holds the system call NUMBER on entry and the return value on return.
To get the name of system call you can import FreeBSD::i386::Ptrace::Syscall and use %SYS.
FreeBSD::i386::Ptrace::Syscall
my $call = pt_getcall(pid); my $name = %SYS{$call};
Sets the value of EAX register to $value. Returns status.
CAVEAT: does not seem to work immidiately after pt_to_sce. In other words, you cannot alter system call that way!
Shortand for ptrace(PT_KILL, $pid, 0, 0; ptrace, pt_trace_me, pt_attach, pt_detach, pt_syscall pt_getcall pt_kill and PT_* constants.
ptrace(PT_KILL, $pid, 0, 0
CAVEAT: You CANNOT prevent the system call from being invoked with this. pt_to_sce does stop BEFORE the invocation. But the signal is sent AFTER tha system call so the process stops AFTER the invocation. There seems no way to block the call.
while ( pt_to_sce($pid) == 0 ) { last if wait == -1; my $call = pt_getcall($pid); my $name = $SYS{$call} || 'unknown'; next if !$banned{ $name }; pt_kill($pid); # happens AFTER the system call. die "SYS_$SYS{$call}\n"; } alarm 0;
As for fork, pt_kill only kills the parent. Strangely replacing pt_kill with ptrace(PT_CONTINUE, $pid, 0, 9) kills the child as well in which case core is dumped.
fork
ptrace(PT_CONTINUE, $pid, 0, 9)
Gets the register values. Returns FreeBSD::i386::Struct::Regs object That object allows OO access to te register. Here is an example.
my $regs = pt_getregs($pid); warn $regs->eax;
Sets the register value to $reg where $reg is a FreeBSD::i386::Struct::Regs object. The code below alters the value of the EAX register.
my $regs = pt_getregs($pid); $regs->eax(0); $status = pt_setregs($pid, $regs); # -1 on error
Does ptrace(PT_READ_D, $pid, $addr, 0). The code below reads the value of the first argument of the stack.
my $regs = pt_getregs($pid); my $st0 = pt_read($pid, $regs->eap + 4); my $st1 = pt_read($pid, $regs->eap + 8); # ....
Writes one 32 bit value in $data to $addr
my $regs = pt_getregs($pid); # place null pointer to the first argument. my $status = pt_read($pid, $regs->eap + 4, 0);
Treats $addr as a string pointer and reads its content. Be careful when you use this.
my $regs = pt_getregs($pid); my $str = pt_peekstr($pid, $regs->eap + 4);
Writes $string to the string pointer $addr. If the $string is longer than the original string, the string is truncated before copied.
Dan Kogai, <dankogai at dan.co.jp>
<dankogai at dan.co.jp>
Please report any bugs or feature requests to bug-freebsd-i386-ptrace at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=FreeBSD-i386-Ptrace. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
bug-freebsd-i386-ptrace at rt.cpan.org
You can find documentation for this module with the perldoc command.
perldoc FreeBSD::i386::Ptrace
You can also look for information at:
RT: CPAN's request tracker
http://rt.cpan.org/NoAuth/Bugs.html?Dist=FreeBSD-i386-Ptrace
AnnoCPAN: Annotated CPAN documentation
http://annocpan.org/dist/FreeBSD-i386-Ptrace
CPAN Ratings
http://cpanratings.perl.org/d/FreeBSD-i386-Ptrace
Search CPAN
http://search.cpan.org/dist/FreeBSD-i386-Ptrace
Sys::Ptrace
Copyright 2009 Dan Kogai, all rights reserved.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
To install FreeBSD::i386::Ptrace, copy and paste the appropriate command in to your terminal.
cpanm
cpanm FreeBSD::i386::Ptrace
CPAN shell
perl -MCPAN -e shell install FreeBSD::i386::Ptrace
For more information on module installation, please visit the detailed CPAN module installation guide.