Created
June 27, 2014 20:44
-
-
Save polachok/6069b41d2cfec66e6b7a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import "syscall" | |
import "log" | |
import "runtime" | |
import "flag" | |
import "fmt" | |
import "strconv" | |
import "os" | |
import "os/signal" | |
import "bytes" | |
var pid int = -1 | |
type SyscallTable map[int]func(syscall.PtraceRegs) func(syscall.PtraceRegs) | |
func init() { | |
runtime.LockOSThread() | |
flag.IntVar(&pid, "p", -1, "pid") | |
flag.Parse() | |
} | |
const ( | |
SysRead = 0 | |
SysWrite = 1 | |
SysOpen = 2 | |
SysClose = 3 | |
SysSocket = 41 | |
SysConnect = 42 | |
SysClone = 56 | |
SysFork = 57 | |
SysVfork = 58 | |
SysExit = 231 | |
) | |
func initSyscalls() SyscallTable { | |
m := make(SyscallTable) | |
read_or_write := func(name string, regs syscall.PtraceRegs) func(syscall.PtraceRegs) { | |
var addr = regs.Rsi | |
var count = int32(regs.Rdx) | |
fd := regs.Rdi | |
fmt.Printf(`%s(%d, `, name, fd) | |
return func(regs syscall.PtraceRegs) { | |
result := int32(regs.Rax) | |
var buf []byte = []byte{} | |
if (result > 0) { | |
buf = make([]byte, result+4) | |
for i := 0; i <= int(result); i += 4 { | |
syscall.PtracePeekData(pid, uintptr(addr), buf[i:i+4]) | |
addr += 4 | |
} | |
fmt.Printf("%s, %d) = %d\n", strconv.Quote(string(buf[0:result])), count, result) | |
} else { | |
fmt.Printf("\"\", %d) = %d\n", count, result) | |
} | |
} | |
} | |
m[SysRead] = func(regs syscall.PtraceRegs) func(syscall.PtraceRegs) { | |
return read_or_write("read", regs) | |
} | |
m[SysWrite] = func(regs syscall.PtraceRegs) func(syscall.PtraceRegs) { | |
return read_or_write("write", regs) | |
} | |
m[SysClose] = func(regs syscall.PtraceRegs) func(syscall.PtraceRegs) { | |
fd := regs.Rdi | |
fmt.Printf("close(%d)", fd) | |
return func(regs syscall.PtraceRegs) { | |
var ret = int32(regs.Rax) | |
fmt.Printf(" = %d\n", ret) | |
} | |
} | |
m[SysOpen] = func(regs syscall.PtraceRegs) func(syscall.PtraceRegs) { | |
var fnameptr = regs.Rdi | |
var flags = regs.Rsi | |
var mode = regs.Rdx | |
var buf = bytes.NewBuffer([]byte{}) | |
var mbuf = make([]byte, 4) | |
var nullFound = false | |
for { | |
syscall.PtracePeekData(pid, uintptr(fnameptr), mbuf[0:4]) | |
j := 0 | |
for _, v := range mbuf { | |
if v == '\x00' { | |
nullFound = true | |
break | |
} | |
j++ | |
} | |
buf.Write(mbuf[0:j]) | |
if nullFound { | |
break | |
} | |
fnameptr += 4 | |
} | |
fmt.Printf("open(%s, %x, %x)", strconv.Quote(string(buf.Bytes())), flags, mode) | |
return func(regs syscall.PtraceRegs) { | |
ret := int32(regs.Rax) | |
fmt.Printf(" = %d\n", ret) | |
} | |
} | |
m[SysSocket] = func(regs syscall.PtraceRegs) func(regs syscall.PtraceRegs) { | |
family := regs.Rdi | |
typ := regs.Rsi | |
proto := regs.Rdx | |
families := []string{ | |
"PF_UNSPEC", | |
"PF_UNIX", | |
"PF_INET", | |
"PF_AX25", | |
"PF_IPX", | |
"PF_APPLETALK", | |
"PF_NETROM", | |
"PF_BRIDGE", | |
"PF_ATMPVC", | |
"PF_X25", | |
"PF_INET6", | |
/* more */ | |
} | |
types := []string { | |
"", | |
"SOCK_STREAM", | |
"SOCK_DGRAM", | |
"SOCK_RAW", | |
"SOCK_RDM", | |
"SOCK_SEQPACKET", | |
"SOCK_DCCP", | |
"SOCK_PACKET", | |
} | |
fmt.Printf("socket(%s, %s, %d)", families[family], types[typ & 0xf], proto) | |
return func(regs syscall.PtraceRegs) { | |
ret := int32(regs.Rax) | |
fmt.Printf(" = %d\n", ret) | |
} | |
} | |
m[SysConnect] = func(regs syscall.PtraceRegs) func(regs syscall.PtraceRegs) { | |
fd := regs.Rdi | |
sockaddr := regs.Rsi | |
addrlen := regs.Rdx | |
fmt.Printf("connect(%d, %x, %x)", fd, sockaddr, addrlen) | |
return func(regs syscall.PtraceRegs) { | |
ret := int32(regs.Rax) | |
fmt.Printf(" = %d\n", ret) | |
} | |
} | |
m[SysExit] = func(regs syscall.PtraceRegs) func(regs syscall.PtraceRegs) { | |
var code = regs.Rdi | |
fmt.Printf("exit_group(%d)\n", code) | |
return func(regs syscall.PtraceRegs) { } | |
} | |
fork_or_vfork := func(name string, regs syscall.PtraceRegs) func(regs syscall.PtraceRegs) { | |
fmt.Printf("%s()", name) | |
return func(regs syscall.PtraceRegs) { | |
var code = int32(regs.Rax) | |
fmt.Printf(" = %d", code) | |
} | |
} | |
m[SysFork] = func(regs syscall.PtraceRegs) func(regs syscall.PtraceRegs) { | |
return fork_or_vfork("fork", regs) | |
} | |
m[SysVfork] = func(regs syscall.PtraceRegs) func(regs syscall.PtraceRegs) { | |
return fork_or_vfork("vfork", regs) | |
} | |
m[SysClone] = func(regs syscall.PtraceRegs) func(regs syscall.PtraceRegs) { | |
var flags = regs.Rdi | |
var sp = regs.Rsi | |
var envp = regs.Rdx | |
fmt.Printf("clone(%x, %x, %x)", flags, sp, envp) | |
return func(regs syscall.PtraceRegs) { | |
var code = int32(regs.Rax) | |
fmt.Printf(" = %d", code) | |
} | |
} | |
return m | |
} | |
func (sc SyscallTable) Call(regs syscall.PtraceRegs) func(syscall.PtraceRegs) { | |
f, ok := sc[int(regs.Orig_rax)] | |
if ok { | |
return f(regs) | |
} else { | |
log.Printf("unknown syscall %d", int(regs.Orig_rax)) | |
return nil | |
} | |
} | |
func check(c chan os.Signal, die *bool) { | |
for { | |
<-c | |
log.Printf("dying") | |
*die = true | |
} | |
} | |
func main() { | |
var wstat syscall.WaitStatus | |
var complete func(syscall.PtraceRegs) = nil | |
var die = false | |
regs := syscall.PtraceRegs{} | |
isSyscall := func(wstat syscall.WaitStatus) bool { | |
return (((uint32(wstat) & 0xff00) >> 8) & 0x80) != 0 | |
} | |
sc := initSyscalls() | |
c := make(chan os.Signal, 1) | |
signal.Notify(c, os.Kill, os.Interrupt) | |
go check(c, &die) | |
if pid == -1 { | |
log.Fatal("No pid set") | |
} | |
err := syscall.PtraceAttach(pid) | |
if err != nil { | |
log.Print("attach") | |
log.Print(err) | |
goto fail | |
} | |
_, err = syscall.Wait4(pid, &wstat, 0, nil) | |
if err != nil { | |
log.Printf("wait %d err %s\n", pid, err) | |
goto fail | |
} | |
err = syscall.PtraceSetOptions(pid, syscall.PTRACE_O_TRACESYSGOOD) | |
if err != nil { | |
log.Print("ptrace set options") | |
log.Print(err) | |
goto fail | |
} | |
for !die { | |
err = syscall.PtraceSyscall(pid, 0) | |
if err != nil { | |
log.Print("syscall") | |
log.Print(err) | |
goto fail | |
} | |
_, err = syscall.Wait4(pid, &wstat, 0, nil) | |
if err != nil { | |
log.Printf("wait %d err %s\n", pid, err) | |
goto fail | |
} | |
// ENTER | |
if wstat.Stopped() { | |
if isSyscall(wstat) { | |
err = syscall.PtraceGetRegs(pid, ®s) | |
if err != nil { | |
log.Print("regs") | |
log.Print(err) | |
goto fail | |
} | |
complete = sc.Call(regs) | |
} | |
} | |
err = syscall.PtraceSyscall(pid, 0) | |
if err != nil { | |
log.Print("syscall 2") | |
log.Print(err) | |
goto fail | |
} | |
_, err = syscall.Wait4(pid, &wstat, 0, nil) | |
if err != nil { | |
log.Printf("wait %d err %s\n", pid, err) | |
goto fail | |
} | |
os.Stdout.Sync() | |
if wstat.Stopped() { | |
if isSyscall(wstat) { | |
err = syscall.PtraceGetRegs(pid, ®s) | |
if err != nil { | |
log.Print("regs") | |
log.Print(err) | |
goto fail | |
} | |
//log.Printf("NUM: %d ::%#v", syscallNum, regs) | |
if (complete != nil) { | |
complete(regs) | |
complete = nil | |
} | |
} | |
} | |
} | |
fail: | |
syscall.Kill(pid, 18) | |
err = syscall.PtraceDetach(pid) | |
if err != nil { | |
log.Print("detach") | |
log.Print(err) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment