Skip to content

Instantly share code, notes, and snippets.

@gekigek99
Last active April 21, 2023 13:09
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gekigek99/94f3629e929d514ca6eed55e111ae442 to your computer and use it in GitHub Desktop.
Save gekigek99/94f3629e929d514ca6eed55e111ae442 to your computer and use it in GitHub Desktop.
Get the child processes pids of a process (retrieve the complete process tree)
// This is a script to retrieve the child processes pids of a process (retrieve the complete process tree)
// Tn this example the process identified by pid 7400 is used
// (please to run the test chose a process pid that has at least 1 child process)
// (tested on windows)
package main
import (
"fmt"
"syscall"
"unsafe"
)
func main() {
rootPid := uint32(7400)
tree, err := getTreePids(rootPid)
if err != nil {
fmt.Println(err)
}
fmt.Println("tree [", len(tree), "]:\t", tree)
}
// getTreePids will return a list of pids that represent the tree of process pids originating from the specified one.
// (they are ordered: [parent, 1 gen child, 2 gen child, ...])
func getTreePids(rootPid uint32) ([]uint32, error) {
// https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/ns-tlhelp32-processentry32
procEntry := syscall.ProcessEntry32{}
parentLayer := []uint32{rootPid}
treePids := parentLayer
foundRootPid := false
snapshot, err := syscall.CreateToolhelp32Snapshot(uint32(syscall.TH32CS_SNAPPROCESS), 0)
if err != nil {
return nil, err
}
defer syscall.CloseHandle(snapshot)
procEntry.Size = uint32(unsafe.Sizeof(procEntry))
for {
// set procEntry to the first process in the snapshot
err = syscall.Process32First(snapshot, &procEntry)
if err != nil {
return nil, err
}
// loop through the processes in the snapshot, if the parent pid of the analyzed process
// is in in the parent layer, append the analyzed process pid in the child layer
var childLayer []uint32
for {
if procEntry.ProcessID == rootPid {
foundRootPid = true
}
if contains(parentLayer, procEntry.ParentProcessID) {
// avoid adding a pid if it's already contained in treePids
// useful for pid 0 whose ppid is 0 and would lead to recursion (windows)
if !contains(treePids, procEntry.ProcessID) {
childLayer = append(childLayer, procEntry.ProcessID)
}
}
// advance to next process in snapshot
err = syscall.Process32Next(snapshot, &procEntry)
if err != nil {
// if there aren't anymore processes to be analyzed, break out of the loop
break
}
}
// if the specified rootPid is not found, return error
if !foundRootPid {
return nil, fmt.Errorf("specified rootPid not found")
}
// fmt.Println(childLayer)
// there are no more child processes, return the process tree
if len(childLayer) == 0 {
return treePids, nil
}
// append the child layer to the tree pids
treePids = append(treePids, childLayer...)
// to analyze the next layer, set the child layer to be the new parent layer
parentLayer = childLayer
}
}
func contains(list []uint32, e uint32) bool {
for _, l := range list {
if l == e {
return true
}
}
return false
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment