Ejemplo n.º 1
0
func (t *tracerImpl) decodeArg(typ interface{}, value regParam, argValue *ArgValue) {

	if reflect.TypeOf(typ).Kind() == reflect.Ptr && value == 0 {
		argValue.Str = "NULL"
		argValue.Value = nil
		return
	}

	switch typ.(type) {
	case StringC:
		argValue.Str = t.decodeArgStringC(value)
		argValue.Value = argValue.Str

	case int, int8, int16,
		int32, int64, uint,
		uint8, uint16, uint32,
		uint64, float32, float64:
		argValue.Value = value
		argValue.Str = fmt.Sprintf("%d", argValue.Value)
	case *uint64:
		var out []byte = make([]byte, 8)
		count, err := syscall.PtracePeekData(t.cmd.Process.Pid, uintptr(value), out)
		if err != nil {
			log.Printf("Error while reading syscall arg: %s", err)
		}
		if count != 8 {
			log.Printf("Error while reading syscall arg: count = %d (should be 8)", count)
		}
		argValue.Value = binary.LittleEndian.Uint64(out)
		argValue.Str = fmt.Sprintf("%d", argValue.Value)
	default:
		argValue.Value = value
		argValue.Str = fmt.Sprintf("%v", value) + "(NOTIMPL=" + reflect.TypeOf(typ).String() + ")"
	}
}
Ejemplo n.º 2
0
func (t *thread) getSocketAddress(ptr uintptr) (addr net.IP, port uint16, err error) {
	var (
		buf  = make([]byte, syscall.SizeofSockaddrAny)
		read int
	)

	if ptr == 0 {
		err = fmt.Errorf("Null ptr")
		return
	}

	read, err = syscall.PtracePeekData(t.tid, ptr, buf)
	if read != syscall.SizeofSockaddrAny || err != nil {
		return
	}

	var sockaddr4 = (*syscall.RawSockaddrInet4)(unsafe.Pointer(&buf[0]))
	if sockaddr4.Family != syscall.AF_INET {
		return
	}

	addr = net.IP(sockaddr4.Addr[0:])
	port = ntohl(sockaddr4.Port)
	return
}
Ejemplo n.º 3
0
// getString returns the C string stored at the process' memory address addr.
func getString(pid int, addr uintptr) string {
	var buffer [4096]byte
	if _, err := syscall.PtracePeekData(pid, addr, buffer[:]); err == nil {
		if i := bytes.IndexByte(buffer[:], 0); i >= 0 && i < len(buffer) {
			return string(buffer[:i])
		}
	}
	return ""
}
Ejemplo n.º 4
0
func (t *tracerImpl) decodeArgBuffer(value regParam, size uint64) (buffer []byte, str string) {
	if size < 0 {
		return nil, ""
	}
	if size == 0 {
		return []byte{}, ""
	}

	bufferSize := size
	extra := false
	if bufferSize > t.maxBufferSize {
		extra = true
		bufferSize = t.maxBufferSize
	}
	buffer = make([]byte, bufferSize)
	count, err := syscall.PtracePeekData(t.cmd.Process.Pid, uintptr(value), buffer)
	if err != nil {
		str = fmt.Sprintf("Error while reading syscall arg: %s", err)
		return
	}
	if uint64(count) != bufferSize {
		str = fmt.Sprintf("Error while reading syscall arg: count = %d (should be %d)", count, bufferSize)
		return
	}
	strBuffer := make([]byte, 0, bufferSize+2)
	strBuffer = append(strBuffer, '"')
	for _, b := range buffer {
		switch {
		case b == '\n':
			strBuffer = append(strBuffer, '\\', 'n')
		case b == '\r':
			strBuffer = append(strBuffer, '\\', 'r')
		case b == '\t':
			strBuffer = append(strBuffer, '\\', 't')
		case b >= ' ' && b <= '~':
			strBuffer = append(strBuffer, b)
		default:
			strBuffer = append(strBuffer, []byte(fmt.Sprintf("\\%d", b))...)
		}
	}

	strBuffer = append(strBuffer, '"')
	if extra {
		strBuffer = append(strBuffer, "..."...)
	}
	str = string(strBuffer)

	return
}
Ejemplo n.º 5
0
func (t *tracerImpl) decodeArgStringC(value regParam) string {
	out := []byte{0}
	str := make([]byte, 0, 10)
	i := uint64(0)
	extra := false
	for {
		count, err := syscall.PtracePeekData(t.cmd.Process.Pid, uintptr(value+regParam(i)), out)
		if out[0] == 0 {
			break
		}
		if i > t.maxStringSize {
			extra = true
			break
		}
		if err != nil {
			log.Printf("Error while reading syscall arg: %s", err)
		}
		if count != 1 {
			log.Printf("Error while reading syscall arg: count = %d (should be 1)", count)
		}
		switch {
		case out[0] == '\n':
			str = append(str, '\\', 'n')
		case out[0] == '\r':
			str = append(str, '\\', 'r')
		case out[0] == '\t':
			str = append(str, '\\', 't')
		case out[0] >= ' ' && out[0] <= '~':
			str = append(str, out[0])
		default:
			str = append(str, []byte(fmt.Sprintf("\\%d", out[0]))...)
		}

		i++
	}

	result := "\"" + string(str) + "\""
	if extra {
		result += "..."
	}

	return result
}
Ejemplo n.º 6
0
func main() {
	runtime.LockOSThread()

	flag.Parse()
	args := flag.Args()

	if *verbose {
		log.Printf("Starting program %v", args)
	}

	cmd, wait_syscall := read_ptrace_events(args)

	var buf [1024]byte

	var filemap = map[uintptr]*File{}

	for {
		regs := wait_syscall()
		if regs == nil {
			break
		}
		call, args := syscall_params(regs)
		callname := strings.ToLower(syscall_name(call)[4:])
		//log.Printf("call %d", call)
		_ = callname

		// Return of syscall
		regs = wait_syscall()
		if regs == nil {
			break
		}
		retval := syscall_retval(regs)

		interesting := true

	sw:
		switch call {
		case syscall.SYS_OPEN:
			count, err := syscall.PtracePeekData(cmd.Process.Pid, uintptr(args[0]), buf[:])
			if err != nil {
				panic(err)
			}
			i := bytes.IndexByte(buf[:count], 0)
			path := string(buf[:i])

			errno := syscall.Errno(-retval)
			if retval < 0 {
				errno = 0
				args[1] = 99999
			}

			// For the moment hide failed opens
			if retval >= 0 {
				_ = errno
				if *verbose {
					log.Printf("open(path=%v, flags=0x%x, mode=0x%x) -> fd=%v e=%v",
						path, args[1], args[2], retval, errno)
				}
			} else {
				interesting = false
			}

			if retval >= 0 {
				fd := uintptr(retval)
				fileinfo, err := os.Stat(path)
				if err != nil {
					panic(err)
				}
				filemap[fd] = &File{path, fd, 0, fileinfo, make(map[int64]int64), []int64{}, 0}
			}

		case syscall.SYS_READ:
			if *verbose {
				log.Printf("read(fd=%v, buf=0x%x, bufsize=%v) -> ret=%v",
					args[0], args[1], args[2], retval)
			}

			if retval < 0 {
				interesting = false
				break sw
			}

			fd := uintptr(args[0])
			if _, ok := filemap[fd]; !ok {
				// stdin?
				break sw
				//log.Panic("fd not in file map: ", fd)
			}
			f := filemap[fd]

			rfp := &f.read_file_pieces
			pos := f.pos
			if size, present := (*rfp)[pos]; present {
				if retval > size {
					// this read is at the same place but larger, so it over-rides
					// the existing read
					(*rfp)[pos] = retval
				}
			} else {
				(*rfp)[pos] = retval
			}

			// Only keep the last N reads
			f.decay = append(f.decay, pos)
			if len(f.decay) > 1 {
				if _, ok := (*rfp)[f.decay[0]]; ok {
					delete(*rfp, f.decay[0])
				}
				f.decay = f.decay[1:]
			}

			f.pos += retval

			f.Show()

		case syscall.SYS_READV:
			if *verbose {
				log.Printf("readv(fd=%v, buf=0x%x, bufsize=%v) -> ret=%v",
					args[0], args[1], args[2], retval)
			}

			fd := uintptr(args[0])
			filemap[fd].pos += retval

		case syscall.SYS_PREAD64:
			log.Printf("pread64(fd=%v, buf=0x%x, bufsize=%v, offset=%v) -> ret=%v",
				args[0], args[1], args[2], args[3], retval)

			fd := uintptr(args[0])
			filemap[fd].pos += retval

		case syscall.SYS_LSEEK:
			if *verbose {
				log.Printf("lseek(fd=%v, offset=%v, whence=%v) -> ret=%v",
					args[0], args[1], args[2], retval)
			}

			fd := uintptr(args[0])
			offset := int64(args[1])
			whence := int(args[2])
			switch whence {
			case os.SEEK_SET:
				filemap[fd].pos = offset
			case os.SEEK_CUR:
				filemap[fd].pos += offset
			case os.SEEK_END:
				//
				panic("Not implemented")
			}

		case syscall.SYS_CLOSE:
			if *verbose {
				log.Printf("close(fd=%x) = %v", args[0], retval)
			}
			fd := uintptr(args[0])
			if retval >= 0 && fd > 2 {
				delete(filemap, fd)
			}

		default:
			interesting = false
		}

		if interesting {
			time.Sleep(*delay)
		}

	}

}
Ejemplo n.º 7
0
func (t *Tracer) PeekData(addr uintptr, out []byte) (int, error) {
	return syscall.PtracePeekData(t.Process.Pid, addr, out)
}
Ejemplo n.º 8
0
func initSyscalls() 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)
			}
		}
	}

	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)
		}
	}

	parseSockAddr := func(bs []byte) (error, *syscall.RawSockaddr) {
		if len(bs) < 2 {
			return errors.New("ETOOSHORT"), nil
		}
		var family uint16 = uint16(bs[1])<<8 | uint16(bs[0])

		log.Printf("FAMILY IS %d\n", family)
		switch family {
		case syscall.AF_LOCAL:
			var rsau *syscall.RawSockaddrUnix
			rsau = (*syscall.RawSockaddrUnix)(unsafe.Pointer(&bs))
			log.Printf("%#v", rsau)
		}
		return errors.New("LUL"), nil
	}

	readBytes := func(addr uintptr, length int) []byte {
		var buf = make([]byte, length+4)

		log.Printf("READBYTES addr: %v length: %d\n", addr, length)

		for i := 0; i < length; i += 4 {
			syscall.PtracePeekData(pid, addr, buf[i:i+4])
			addr += 4
		}
		return buf
	}

	readString := func(addr uintptr, length int) string {
		buf := readBytes(addr, length)

		return strconv.Quote(string(buf))
	}

	m := SyscallTable{

		SysRead: func(regs syscall.PtraceRegs) func(syscall.PtraceRegs) {
			return read_or_write("read", regs)
		},

		SysWrite: func(regs syscall.PtraceRegs) func(syscall.PtraceRegs) {
			return read_or_write("write", regs)
		},

		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)
			}
		},

		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)
			}
		},

		SysSocket: func(regs syscall.PtraceRegs) func(regs syscall.PtraceRegs) {
			family := regs.Rdi
			typ := regs.Rsi
			proto := regs.Rdx

			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)
			}
		},

		SysConnect: func(regs syscall.PtraceRegs) func(regs syscall.PtraceRegs) {
			fd := regs.Rdi
			sockaddr := regs.Rsi
			addrlen := regs.Rdx

			if sockaddr != 0 && addrlen != 0 {
				buf := readBytes(uintptr(sockaddr), int(addrlen))
				parseSockAddr(buf)
			}
			fmt.Printf("connect(%d, %x, %x)", fd, sockaddr, addrlen)

			return func(regs syscall.PtraceRegs) {
				ret := int32(regs.Rax)

				fmt.Printf(" = %d\n", ret)
			}
		},

		SysSendto: func(regs syscall.PtraceRegs) func(regs syscall.PtraceRegs) {
			fd := regs.Rdi
			bufptr := regs.Rsi
			length := regs.Rdx
			flags := regs.Rcx
			sockaddr := regs.R8
			addrlen := regs.R9

			buf := readString(uintptr(bufptr), int(length))

			fmt.Printf("sendto(%d, %s, %d, %d, %v, %d)", fd, buf, length, flags, sockaddr, addrlen)

			return func(regs syscall.PtraceRegs) {
				ret := int32(regs.Rax)

				fmt.Printf("= %d\n", ret)
			}
		},

		SysSendmsg: func(regs syscall.PtraceRegs) func(regs syscall.PtraceRegs) {
			fd := regs.Rdi
			msg := regs.Rsi
			flags := regs.Rdx

			fmt.Printf("sendmsg(%d, %v, %v)", fd, msg, flags)
			return func(regs syscall.PtraceRegs) {
				ret := int32(regs.Rax)

				fmt.Printf("= %d\n", ret)
			}
		},

		SysRecvmsg: func(regs syscall.PtraceRegs) func(regs syscall.PtraceRegs) {
			fd := regs.Rdi
			msg := regs.Rsi
			flags := regs.Rdx

			fmt.Printf("recvmsg(%d, ", fd)
			return func(regs syscall.PtraceRegs) {
				ret := int32(regs.Rax)

				if ret >= 0 {
					fmt.Printf("\"%v\", %s) = %d\n", msg, flags, ret)
				} else {
					fmt.Printf("\"\", %s) = %d\n", flags, ret)
				}
			}
		},

		SysSyslog: func(regs syscall.PtraceRegs) func(regs syscall.PtraceRegs) {
			typ := regs.Rdi
			msgptr := regs.Rsi
			length := regs.Rdx

			msg := readString(uintptr(msgptr), int(length))

			fmt.Printf("syslog(%d, %s, %d)", typ, msg, length)

			return func(regs syscall.PtraceRegs) {
				ret := int32(regs.Rax)

				fmt.Printf(" = %d\n", ret)
			}
		},

		SysGetuid: func(regs syscall.PtraceRegs) func(regs syscall.PtraceRegs) {
			fmt.Printf("getuid()")

			return func(regs syscall.PtraceRegs) {
				ret := int32(regs.Rax)

				fmt.Printf(" = %d\n", ret)
			}
		},

		SysGetgid: func(regs syscall.PtraceRegs) func(regs syscall.PtraceRegs) {
			fmt.Printf("getgid()")

			return func(regs syscall.PtraceRegs) {
				ret := int32(regs.Rax)

				fmt.Printf(" = %d\n", ret)
			}
		},

		SysSetuid: func(regs syscall.PtraceRegs) func(regs syscall.PtraceRegs) {
			uid := int32(regs.Rdi)
			fmt.Printf("setuid(%d)", uid)

			return func(regs syscall.PtraceRegs) {
				ret := int32(regs.Rax)

				fmt.Printf(" = %d\n", ret)
			}
		},

		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) {}
		},

		SysFork: func(regs syscall.PtraceRegs) func(regs syscall.PtraceRegs) {
			return fork_or_vfork("fork", regs)
		},

		SysVfork: func(regs syscall.PtraceRegs) func(regs syscall.PtraceRegs) {
			return fork_or_vfork("vfork", regs)
		},

		SysRestart: func(regs syscall.PtraceRegs) func(regs syscall.PtraceRegs) {
			fmt.Printf("<restarting syscall>")
			return func(regs syscall.PtraceRegs) {
			}
		},

		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
}