{"record":{"id":"daf4405fd7d1bc2d","repo":"pranshuparmar/witr","slug":"failed-to-read-processparameters-struct","errorCode":null,"errorMessage":"failed to read ProcessParameters struct","messagePattern":"failed to read ProcessParameters struct","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/proc/peb_windows.go","lineNumber":175,"sourceCode":"\n\tif pbi.PebBaseAddress == 0 {\n\t\treturn fmt.Errorf(\"PEB Base Address is 0\")\n\t}\n\n\t// Read PEB\n\tvar pebPtr uintptr\n\tparamsOffset := uintptr(0x20)\n\tif unsafe.Sizeof(uintptr(0)) == 4 {\n\t\tparamsOffset = 0x10\n\t}\n\n\tif !readProcessMemory(handle, pbi.PebBaseAddress+paramsOffset, unsafe.Pointer(&pebPtr), unsafe.Sizeof(pebPtr)) {\n\t\treturn fmt.Errorf(\"failed to read PEB ProcessParameters address\")\n\t}\n\n\tvar params rtlUserProcessParameters\n\tif !readProcessMemory(handle, pebPtr, unsafe.Pointer(&params), unsafe.Sizeof(params)) {\n\t\treturn fmt.Errorf(\"failed to read ProcessParameters struct\")\n\t}\n\n\tinfo.Cwd = readUnicodeString(handle, params.CurrentDirectoryPath)\n\tinfo.CommandLine = readUnicodeString(handle, params.CommandLine)\n\tinfo.Exe = readUnicodeString(handle, params.ImagePathName)\n\tinfo.Env = readEnvironmentBlock(handle, params.Environment)\n\n\treturn nil\n}\n\nfunc readProcessMemory(handle syscall.Handle, addr uintptr, dest unsafe.Pointer, size uintptr) bool {\n\t// lpNumberOfBytesRead is a SIZE_T* (pointer-sized: 8 bytes on x64). It MUST\n\t// be uintptr, not uint32 — a uint32 here lets the kernel write 8 bytes into\n\t// a 4-byte slot, corrupting adjacent memory and causing nondeterministic\n\t// crashes far from this call site.\n\tvar read uintptr\n\tret, _, _ := procReadProcessMem.Call(\n\t\tuintptr(handle),","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/pranshuparmar/witr/blob/dc4fa1da82d3e266fcbd928641b4f30b3077c64f/internal/proc/peb_windows.go#L157-L193","documentation":"witr reads a target process's PEB via readProcessMemory to extract cwd, command line, exe path and environment on Windows. This error means the PEB address was readable but the rtlUserProcessParameters struct at that address could not be read, so no process detail could be collected. It is typically caused by the target process exiting mid-inspection, insufficient privileges, or cross-bitness/cross-architecture reading.","triggerScenarios":"Calling GetProcessDetailedInfo on a Windows process where the second readProcessMemory call for the rtlUserProcessParameters struct fails — usually because the process terminated between the PEB read and this read, the handle lacks PROCESS_VM_READ rights, or the target is a protected/elevated process.","commonSituations":"Inspecting short-lived processes that exit during the scan; running witr without elevation while probing a service running as SYSTEM/protected light processes; 32-bit target inspected from a 64-bit build (or vice versa) making the params offset/size mismatch.","solutions":["Re-run the lookup; if the target process was exiting, retry on a live process.","Run witr elevated (Administrator) so the handle has PROCESS_VM_READ on the target.","Verify the target and witr bitness/architecture match (x64 vs x86, ARM64).","Check whether the process is protected (e.g. protected process light); fall back to the snapshot-based lookup (getInfoFromSnapshot) or skip detail collection.","Confirm the paramsOffset derivation matches the target OS build."],"exampleFix":"// before\nif !readProcessMemory(handle, pebPtr, unsafe.Pointer(&params), unsafe.Sizeof(params)) {\n    return fmt.Errorf(\"failed to read ProcessParameters struct\")\n}\n// after\nif !readProcessMemory(handle, pebPtr, unsafe.Pointer(&params), unsafe.Sizeof(params)) {\n    // degrade gracefully instead of failing the whole lookup\n    return partialInfo, nil // caller still gets PID/PPID/exe from snapshot\n}","handlingStrategy":"try-catch","validationCode":"// Windows: check the process is still alive and accessible before detailed lookup\nh, err := windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION|windows.PROCESS_VM_READ, false, uint32(pid))\nif err != nil { /* process gone or access denied */ }\nwindows.CloseHandle(h)","typeGuard":null,"tryCatchPattern":"p, err := GetProcessDetailedInfo(pid)\nif err != nil {\n    if strings.Contains(err.Error(), \"failed to read ProcessParameters struct\") {\n        // degrade: fall back to snapshot-based info (PID/PPID/exe only)\n        p, err = getSnapshotInfo(pid)\n    }\n}","preventionTips":["Run elevated when probing system or protected processes","Re-check process liveness immediately before detailed reads","Match process bitness/architecture between witr and the target","Fall back to snapshot-based enumeration when VM reads fail"],"tags":["windows","process-memory","privileges"],"backgroundTag":"process-memory-read-failed","analyzedSha":"dc4fa1da82d3e266fcbd928641b4f30b3077c64f","analyzedAt":"2026-09-01T12:17:08.767Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}