From a13d338a383ea22273a412cf772f3715cbb742f6 Mon Sep 17 00:00:00 2001 From: Tim W Date: Mon, 18 Jul 2022 19:29:41 +0700 Subject: [PATCH] fix #714, Add process Architecture to the ps command --- client/command/processes/ps.go | 10 ++-- .../sliver/handlers/rpc-handlers_darwin.go | 1 + implant/sliver/handlers/rpc-handlers_linux.go | 1 + implant/sliver/ps/ps.go | 3 ++ implant/sliver/ps/ps_darwin.go | 7 +++ implant/sliver/ps/ps_linux.go | 34 ++++++++++++++ implant/sliver/ps/ps_windows.go | 41 ++++++++++++----- protobuf/commonpb/common.pb.go | 46 +++++++++++-------- protobuf/commonpb/common.proto | 5 +- 9 files changed, 114 insertions(+), 34 deletions(-) diff --git a/client/command/processes/ps.go b/client/command/processes/ps.go index 0640bf38d6..f73a0ba7d0 100644 --- a/client/command/processes/ps.go +++ b/client/command/processes/ps.go @@ -110,13 +110,13 @@ func PrintPS(os string, ps *sliverpb.Ps, interactive bool, ctx *grumble.Context, switch os { case "windows": - tw.AppendHeader(table.Row{"pid", "ppid", "owner", "executable", "session"}) + tw.AppendHeader(table.Row{"pid", "ppid", "owner", "arch", "executable", "session"}) case "darwin": fallthrough case "linux": - tw.AppendHeader(table.Row{"pid", "ppid", "owner", "executable"}) + fallthrough default: - tw.AppendHeader(table.Row{"pid", "ppid", "owner", "executable"}) + tw.AppendHeader(table.Row{"pid", "ppid", "owner", "arch", "executable"}) } cmdLine := ctx.Flags.Bool("print-cmdline") @@ -182,6 +182,7 @@ func procRow(tw table.Writer, proc *commonpb.Process, cmdLine bool, con *console fmt.Sprintf(color+"%d"+console.Normal, proc.Pid), fmt.Sprintf(color+"%d"+console.Normal, proc.Ppid), fmt.Sprintf(color+"%s"+console.Normal, proc.Owner), + fmt.Sprintf(color+"%s"+console.Normal, proc.Architecture), fmt.Sprintf(color+"%s"+console.Normal, args), fmt.Sprintf(color+"%d"+console.Normal, proc.SessionID), } @@ -190,6 +191,7 @@ func procRow(tw table.Writer, proc *commonpb.Process, cmdLine bool, con *console fmt.Sprintf(color+"%d"+console.Normal, proc.Pid), fmt.Sprintf(color+"%d"+console.Normal, proc.Ppid), fmt.Sprintf(color+"%s"+console.Normal, proc.Owner), + fmt.Sprintf(color+"%s"+console.Normal, proc.Architecture), fmt.Sprintf(color+"%s"+console.Normal, proc.Executable), fmt.Sprintf(color+"%d"+console.Normal, proc.SessionID), } @@ -210,6 +212,7 @@ func procRow(tw table.Writer, proc *commonpb.Process, cmdLine bool, con *console fmt.Sprintf(color+"%d"+console.Normal, proc.Pid), fmt.Sprintf(color+"%d"+console.Normal, proc.Ppid), fmt.Sprintf(color+"%s"+console.Normal, proc.Owner), + fmt.Sprintf(color+"%s"+console.Normal, proc.Architecture), fmt.Sprintf(color+"%s"+console.Normal, args), } } else { @@ -217,6 +220,7 @@ func procRow(tw table.Writer, proc *commonpb.Process, cmdLine bool, con *console fmt.Sprintf(color+"%d"+console.Normal, proc.Pid), fmt.Sprintf(color+"%d"+console.Normal, proc.Ppid), fmt.Sprintf(color+"%s"+console.Normal, proc.Owner), + fmt.Sprintf(color+"%s"+console.Normal, proc.Architecture), fmt.Sprintf(color+"%s"+console.Normal, proc.Executable), } } diff --git a/implant/sliver/handlers/rpc-handlers_darwin.go b/implant/sliver/handlers/rpc-handlers_darwin.go index 2670b9f7e6..e57c6a9066 100644 --- a/implant/sliver/handlers/rpc-handlers_darwin.go +++ b/implant/sliver/handlers/rpc-handlers_darwin.go @@ -55,6 +55,7 @@ func psHandler(data []byte, resp RPCResponse) { Ppid: int32(proc.PPid()), Executable: proc.Executable(), Owner: proc.Owner(), + Architecture: proc.Architecture(), } p.CmdLine = proc.(*ps.DarwinProcess).CmdLine() psList.Processes = append(psList.Processes, p) diff --git a/implant/sliver/handlers/rpc-handlers_linux.go b/implant/sliver/handlers/rpc-handlers_linux.go index 382ca9d733..ba7cd83c52 100644 --- a/implant/sliver/handlers/rpc-handlers_linux.go +++ b/implant/sliver/handlers/rpc-handlers_linux.go @@ -55,6 +55,7 @@ func psHandler(data []byte, resp RPCResponse) { Ppid: int32(proc.PPid()), Executable: proc.Executable(), Owner: proc.Owner(), + Architecture: proc.Architecture(), } p.CmdLine = proc.(*ps.UnixProcess).CmdLine() psList.Processes = append(psList.Processes, p) diff --git a/implant/sliver/ps/ps.go b/implant/sliver/ps/ps.go index 4dce40c5a5..8155129640 100644 --- a/implant/sliver/ps/ps.go +++ b/implant/sliver/ps/ps.go @@ -25,6 +25,9 @@ type Process interface { // Owner is the account name of the process owner. Owner() string + + // Architecture is the architecture of the process. + Architecture() string } // Processes returns all processes. diff --git a/implant/sliver/ps/ps_darwin.go b/implant/sliver/ps/ps_darwin.go index 043cb32dd9..6d210affc7 100644 --- a/implant/sliver/ps/ps_darwin.go +++ b/implant/sliver/ps/ps_darwin.go @@ -19,6 +19,7 @@ type DarwinProcess struct { ppid int binary string owner string + arch string cmdLine []string } @@ -42,6 +43,10 @@ func (p *DarwinProcess) CmdLine() []string { return p.cmdLine } +func (p *DarwinProcess) Architecture() []string { + return p.arch +} + func findProcess(pid int) (Process, error) { ps, err := processes() if err != nil { @@ -98,6 +103,7 @@ func processes() ([]Process, error) { if owner == "" { owner = uid } + arch := "amd64" darwinProcs[i] = &DarwinProcess{ pid: int(p.Proc.P_pid), @@ -105,6 +111,7 @@ func processes() ([]Process, error) { binary: binPath, owner: owner, cmdLine: cmdLine, + arch: arch, } } diff --git a/implant/sliver/ps/ps_linux.go b/implant/sliver/ps/ps_linux.go index 21befcbe73..dbfaf7f515 100644 --- a/implant/sliver/ps/ps_linux.go +++ b/implant/sliver/ps/ps_linux.go @@ -21,6 +21,7 @@ type UnixProcess struct { state rune pgrp int sid int + arch string cmdLine []string binary string @@ -51,6 +52,10 @@ func (p *UnixProcess) CmdLine() []string { return p.cmdLine } +func (p *UnixProcess) Architecture() string { + return p.arch +} + func getProcessOwnerUid(pid int) (uint32, error) { filename := fmt.Sprintf("/proc/%d/task", pid) f, err := os.Open(filename) @@ -89,6 +94,34 @@ func getProcessCmdLine(pid int) ([]string, error) { return argv, nil } +func getProcessArchitecture(pid int) (string, error) { + exePath := fmt.Sprintf("/proc/%d/exe", pid) + + f, err := os.Open(exePath) + if err != nil { + return "Unknown", err + } + _, err = f.Seek(0x12, 0) + if err != nil { + return "Unknown", err + } + mach := make([]byte, 2) + _, err = io.ReadAtLeast(f, mach, 2) + + f.Close() + + if mach[0] == 0xb3 { + return "aarch64", nil + } + if mach[0] == 0x03 { + return "x86", nil + } + if mach[0] == 0x3e { + return "amd64", nil + } + return "Unknown", err +} + // Refresh reloads all the data associated with this process. func (p *UnixProcess) Refresh() error { statPath := fmt.Sprintf("/proc/%d/stat", p.pid) @@ -176,6 +209,7 @@ func processes() ([]Process, error) { p.binary = argv[0] } } + p.arch, err = getProcessArchitecture(int(pid)) results = append(results, p) } } diff --git a/implant/sliver/ps/ps_windows.go b/implant/sliver/ps/ps_windows.go index ea13c3c888..958682d0c1 100644 --- a/implant/sliver/ps/ps_windows.go +++ b/implant/sliver/ps/ps_windows.go @@ -18,6 +18,7 @@ type WindowsProcess struct { ppid int exe string owner string + arch string cmdLine []string sessionID int } @@ -38,6 +39,10 @@ func (p *WindowsProcess) Owner() string { return p.owner } +func (p *WindowsProcess) Architecture() string { + return p.arch +} + func (p *WindowsProcess) CmdLine() []string { return p.cmdLine } @@ -57,7 +62,7 @@ func newWindowsProcess(e *syscall.ProcessEntry32) *WindowsProcess { } account, _ := getProcessOwner(e.ProcessID) sessionID, _ := getSessionID(e.ProcessID) - cmdLine, _ := getCmdLine(e.ProcessID) + cmdLine, arch, _ := getProcessInfo(e.ProcessID) return &WindowsProcess{ pid: int(e.ProcessID), @@ -65,6 +70,7 @@ func newWindowsProcess(e *syscall.ProcessEntry32) *WindowsProcess { exe: syscall.UTF16ToString(e.ExeFile[:end]), owner: account, cmdLine: cmdLine, + arch: arch, sessionID: sessionID, } } @@ -167,17 +173,17 @@ func main() { fmt.Println(uintptrToBytes(&u)) } -func getCmdLine(pid uint32) ([]string, error) { +func getProcessInfo(pid uint32) ([]string, string, error) { handle, err := syscall.CreateToolhelp32Snapshot(syscall.TH32CS_SNAPMODULE, pid) if err != nil { - return []string{}, err + return []string{}, "", err } defer syscall.CloseHandle(handle) var module syscalls.MODULEENTRY32W module.DwSize = uint32(unsafe.Sizeof(module)) if err = syscalls.Module32FirstW(windows.Handle(handle), &module); err != nil { - return []string{}, err + return []string{}, "", err } proc, err := syscall.OpenProcess( @@ -186,7 +192,7 @@ func getCmdLine(pid uint32) ([]string, error) { pid, ) if err != nil { - return strings.Fields(syscall.UTF16ToString(module.SzExePath[:])), err + return strings.Fields(syscall.UTF16ToString(module.SzExePath[:])), "", err } var info windows.PROCESS_BASIC_INFORMATION @@ -198,7 +204,7 @@ func getCmdLine(pid uint32) ([]string, error) { nil, ) if err != nil { - return strings.Fields(syscall.UTF16ToString(module.SzExePath[:])), err + return strings.Fields(syscall.UTF16ToString(module.SzExePath[:])), "", err } var peb windows.PEB @@ -210,7 +216,7 @@ func getCmdLine(pid uint32) ([]string, error) { nil, ) if err != nil { - return strings.Fields(syscall.UTF16ToString(module.SzExePath[:])), err + return strings.Fields(syscall.UTF16ToString(module.SzExePath[:])), "", err } var params windows.RTL_USER_PROCESS_PARAMETERS @@ -222,7 +228,7 @@ func getCmdLine(pid uint32) ([]string, error) { nil, ) if err != nil { - return strings.Fields(syscall.UTF16ToString(module.SzExePath[:])), err + return strings.Fields(syscall.UTF16ToString(module.SzExePath[:])), "", err } var cmdLine []uint16 = make([]uint16, params.CommandLine.Length) @@ -234,15 +240,28 @@ func getCmdLine(pid uint32) ([]string, error) { nil, ) if err != nil { - return strings.Fields(syscall.UTF16ToString(module.SzExePath[:])), err + return strings.Fields(syscall.UTF16ToString(module.SzExePath[:])), "", err + } + + + var arch string + var is64Bit bool + if err := windows.IsWow64Process(proc, &is64Bit); err != nil { + arch = "Unknown" + } else { + if !is64Bit { + arch = "x86" + } else { + arch = "amd64" + } } err = syscall.CloseHandle(proc) if err != nil { - return strings.Fields(syscall.UTF16ToString(module.SzExePath[:])), err + return strings.Fields(syscall.UTF16ToString(module.SzExePath[:])), "", err } - return strings.Fields(syscall.UTF16ToString(module.SzExePath[:]) + " : " + syscall.UTF16ToString(cmdLine[:])), nil + return strings.Fields(syscall.UTF16ToString(module.SzExePath[:]) + " : " + syscall.UTF16ToString(cmdLine[:])), arch, nil } func getSessionID(pid uint32) (int, error) { diff --git a/protobuf/commonpb/common.pb.go b/protobuf/commonpb/common.pb.go index 9898dce664..ab0e467125 100644 --- a/protobuf/commonpb/common.pb.go +++ b/protobuf/commonpb/common.pb.go @@ -266,12 +266,13 @@ type Process struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Pid int32 `protobuf:"varint,1,opt,name=Pid,proto3" json:"Pid,omitempty"` - Ppid int32 `protobuf:"varint,2,opt,name=Ppid,proto3" json:"Ppid,omitempty"` - Executable string `protobuf:"bytes,3,opt,name=Executable,proto3" json:"Executable,omitempty"` - Owner string `protobuf:"bytes,4,opt,name=Owner,proto3" json:"Owner,omitempty"` - SessionID int32 `protobuf:"varint,5,opt,name=SessionID,proto3" json:"SessionID,omitempty"` - CmdLine []string `protobuf:"bytes,6,rep,name=CmdLine,proto3" json:"CmdLine,omitempty"` + Pid int32 `protobuf:"varint,1,opt,name=Pid,proto3" json:"Pid,omitempty"` + Ppid int32 `protobuf:"varint,2,opt,name=Ppid,proto3" json:"Ppid,omitempty"` + Executable string `protobuf:"bytes,3,opt,name=Executable,proto3" json:"Executable,omitempty"` + Owner string `protobuf:"bytes,4,opt,name=Owner,proto3" json:"Owner,omitempty"` + Architecture string `protobuf:"bytes,5,opt,name=Architecture,proto3" json:"Architecture,omitempty"` + SessionID int32 `protobuf:"varint,6,opt,name=SessionID,proto3" json:"SessionID,omitempty"` + CmdLine []string `protobuf:"bytes,7,rep,name=CmdLine,proto3" json:"CmdLine,omitempty"` } func (x *Process) Reset() { @@ -334,6 +335,13 @@ func (x *Process) GetOwner() string { return "" } +func (x *Process) GetArchitecture() string { + if x != nil { + return x.Architecture + } + return "" +} + func (x *Process) GetSessionID() int32 { if x != nil { return x.SessionID @@ -426,24 +434,26 @@ var file_commonpb_common_proto_rawDesc = []byte{ 0x06, 0x54, 0x61, 0x73, 0x6b, 0x49, 0x44, 0x22, 0x2e, 0x0a, 0x04, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x04, 0x44, 0x61, 0x74, 0x61, 0x22, 0x9d, 0x01, 0x0a, 0x07, 0x50, 0x72, 0x6f, 0x63, + 0x0c, 0x52, 0x04, 0x44, 0x61, 0x74, 0x61, 0x22, 0xc1, 0x01, 0x0a, 0x07, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x50, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x50, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x50, 0x70, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x50, 0x70, 0x69, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x12, - 0x1c, 0x0a, 0x09, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x05, 0x52, 0x09, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x18, 0x0a, - 0x07, 0x43, 0x6d, 0x64, 0x4c, 0x69, 0x6e, 0x65, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, - 0x43, 0x6d, 0x64, 0x4c, 0x69, 0x6e, 0x65, 0x22, 0x30, 0x0a, 0x06, 0x45, 0x6e, 0x76, 0x56, 0x61, - 0x72, 0x12, 0x10, 0x0a, 0x03, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x4b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x73, 0x68, 0x6f, 0x70, 0x66, 0x6f, - 0x78, 0x2f, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x22, 0x0a, 0x0c, 0x41, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x41, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, + 0x75, 0x72, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x44, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, + 0x44, 0x12, 0x18, 0x0a, 0x07, 0x43, 0x6d, 0x64, 0x4c, 0x69, 0x6e, 0x65, 0x18, 0x07, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x07, 0x43, 0x6d, 0x64, 0x4c, 0x69, 0x6e, 0x65, 0x22, 0x30, 0x0a, 0x06, 0x45, + 0x6e, 0x76, 0x56, 0x61, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x4b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x2f, 0x5a, + 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x69, 0x73, 0x68, + 0x6f, 0x70, 0x66, 0x6f, 0x78, 0x2f, 0x73, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/protobuf/commonpb/common.proto b/protobuf/commonpb/common.proto index 6449cb2e6c..6745e5b872 100644 --- a/protobuf/commonpb/common.proto +++ b/protobuf/commonpb/common.proto @@ -39,8 +39,9 @@ message Process { int32 Ppid = 2; string Executable = 3; string Owner = 4; - int32 SessionID = 5; - repeated string CmdLine = 6; + string Architecture = 5; + int32 SessionID = 6; + repeated string CmdLine = 7; } // EnvVar - Environment variable K/V