I am currently trying to implement a simple Parent PID Spoofing in Rust but I'm facing with Segfault errors / Invalid Handle when creating process whom I'm trying to spoof its parent.
I made this code and modified it a lot in order to accomplish the wanted result:
let mut sinfo = STARTUPINFOEXA::default();
let mut cb_attribute_list_size = 0;
const PROC_THREAD_ATTRIBUTE_PARENT_PROCESS: DWORD = 0x00020000;
let mut h_parent_process: HANDLE = NULL as HANDLE;
let dw_pid: DWORD = 2176;
const CMDLINE: &str = "notepad";
unsafe {
InitializeProcThreadAttributeList(
null_mut(),
1,
0,
&mut cb_attribute_list_size
);
sinfo.lpAttributeList = HeapAlloc(
GetProcessHeap(),
0,
cb_attribute_list_size
).cast();
if InitializeProcThreadAttributeList(
sinfo.lpAttributeList,
1,
0,
&mut cb_attribute_list_size
) == 0 {
eprintln!("[x] Error Initializing proccess attribute");
return Ok(());
}
h_parent_process = OpenProcess(
PROCESS_ALL_ACCESS,
0,
dw_pid // explorer.exe
);
if h_parent_process.is_null() {
eprintln!("[x] Error opening parent process");
return Ok(());
}
if UpdateProcThreadAttribute(
sinfo.lpAttributeList,
0,
0x00020000,
transmute::<PHANDLE, LPVOID>(&mut h_parent_process),
size_of::<HANDLE>(),
null_mut(),
null_mut()
) == 0 {
eprintln!("[x] Error updating PROC_THREAD_ATTRIBUTE_PARENT_PROCESS");
return Ok(());
}
let mut process_info= PROCESS_INFORMATION::default();
sinfo.StartupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
sinfo.StartupInfo.wShowWindow = 0;
sinfo.StartupInfo.cb = size_of::<STARTUPINFOEXA>() as u32;
if CreateProcessA(
null_mut(),
CMDLINE.to_string().as_ptr() as LPSTR,
null_mut(),
null_mut(),
0,
EXTENDED_STARTUPINFO_PRESENT,
null_mut(),
null_mut(),
&mut sinfo.StartupInfo,
&mut process_info
) == 0 {
eprintln!("[x] Error creating process");
return Ok(());
}
println!("[+] Process created: {}", process_info.dwProcessId);
DeleteProcThreadAttributeList(sinfo.lpAttributeList);
CloseHandle(process_info.hProcess);
CloseHandle(process_info.hThread);
CloseHandle(h_parent_process);
}
I tried allocating the pAttributeList from Rust with Vec::with_capacity() or from C with HeapAlloc().
The same code works in C but I don't know what am I doing wrong in Rust. I didn't success to find an actual implementation of Parent PID Spoofing in Rust but I found some usage of UpdateProcThreadAttributeList() function.
The C source code I am trying to convert to Rust can be found here: https://www.ired.team/offensive-security/defense-evasion/parent-process-id-ppid-spoofing#ppid-spoofing
Thanks for help
---EDIT---
I reviewed the code to use Ansi version of the API, the code works fine but does not produce the result I wanted. It spawn a notepad but with no parent (System is its).
I wonder if my call to UpdateProcThreadAttributeList() is correct, I think I would have to pass the reference to the Handle of the Parent Process but HANDLE structure is a *mut c_void and LPVOID/PVOID is also a *mut c_void. I'm not quite sure if the problem reside in this thing.
As one of comment suggested, there is my C code that I try to convert:
STARTUPINFOEX sie = { sizeof(sie) };
PROCESS_INFORMATION pi;
SIZE_T cbAttributeListSize = 0;
PPROC_THREAD_ATTRIBUTE_LIST pAttributeList = nullptr;
HANDLE hParentProcess = nullptr;
DWORD dwPid = 2176;
const char* lpCommandLine = "notepad";
InitializeProcThreadAttributeList(NULL, 1, 0, &cbAttributeListSize);
pAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, cbAttributeListSize);
if (NULL == pAttributeList)
{
std::cout << "[x] Error allocating heap: " << GetLastError() << std::endl;
return 0;
}
if (!InitializeProcThreadAttributeList(pAttributeList, 1, 0, &cbAttributeListSize))
{
std::cout << "[x] Error Initializing proccess attribute: " << GetLastError() << std::endl;
return 0;
}
hParentProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
if (NULL == hParentProcess)
{
std::cout << "[x] Error opening parent process: " << GetLastError() << std::endl;
return 0;
}
if (!UpdateProcThreadAttribute(pAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &hParentProcess, sizeof(HANDLE), NULL, NULL))
{
std::cout << "[x] Error updating PROC_THREAD_ATTRIBUTE_PARENT_PROCESS: " << GetLastError() << std::endl;
return 0;
}
sie.lpAttributeList = pAttributeList;
if (!CreateProcessA(NULL, const_cast<LPSTR>(lpCommandLine), NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, &sie.StartupInfo, &pi))
{
std::cout << "[x] Error creating process: " << GetLastError();
return 0;
}
std::cout << "[+] Process created: " << pi.dwProcessId << std::endl;
DeleteProcThreadAttributeList(pAttributeList);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
CloseHandle(hParentProcess);
Thanks again
--LAST EDIT--
I finally figured out what I was making wrong ! During CreateProcessA() call it was trying to read the location pointed by the value of the Parent Process Handle but I was passing its value directly instead of its reference.
I edited the Rust code above. Thanks all I can close this issue.