rustntdllwindows-rs

How to convert a u32 pid to windows-rs HANDLE


I'm trying to make the NtOpenProcess syscall in rust using the windows-rs crate. I've got the following code but cannot figure out how to convert a u32 pid to a HANDLE type, which is needed for the struct.

use windows::Wdk::Foundation::{
    OBJECT_ATTRIBUTES,
};
use windows::Win32::Foundation::{
    HANDLE,
};
use windows::Win32::System::WindowsProgramming::{
    CLIENT_ID,
};
use windows::Win32::System::Threading::{
    PROCESS_ALL_ACCESS,
};

fn some_func() {
    // ...

    let pid: u32 = 1402; // Obtained somewhere else (not relevant to the question how)
    let mut handle: HANDLE = HANDLE::default();
    let oa = OBJECT_ATTRIBUTES::default();
    let cid: CLIENT_ID = CLIENT_ID {
            UniqueProcess: pid,
            UniqueThread: 0
        };
    unsafe {
        // This part is out of scope for the question; assume this macro will work
        syscall!(
            "NtOpenProcess",
            &mut handle,
            PROCESS_ALL_ACCESS,
            &oa,
            &cid
        );
    }

    // ...
}

When compiling I get the following errors:

error[E0308]: mismatched types
  --> src/main.rs:67:28
   |
67 |             UniqueProcess: pid,
   |                            ^^^ expected `HANDLE`, found `u32`

error[E0308]: mismatched types
  --> src/main.rs:68:27
   |
68 |             UniqueThread: 0
   |                           ^ expected `HANDLE`, found integer

So the question is; how to I convert this to valid code?

Edit: Using the ntapi crate it does seem to be possible to obtain a valid CLIENT_ID using a u32 PID. However, I would really like to use a single package for all windows interaction (the windows-rs one, as this one is maintained by Microsoft).

use ntapi::ntapi_base::CLIENT_ID;

let cid: CLIENT_ID = CLIENT_ID {
        UniqueProcess: pid as _,
        UniqueThread: 0 as _
};

Solution

  • You are getting type mismatches because windows::Win32::System::WindowsProgramming::CLIENT_ID is auto-generated from winternl.h, an oddball include file in Windows SDK that should not be used to work with ntdll-level APIs like NtOpenProcess() that are not part of Windows API. If you use NtOpenProcess(), you need to use corresponding struct definitions. If you don't want to pull in the whole ntapi crate, just define your own struct CLIENT_ID. Since you're invoking NtOpenProcess() with a "soft" syscall macro anyway, it should not make any difference in terms of compatibility, portability etc.

    PS: a bit of wording clarification: a PID and a HANDLE are completely different things and cannot be 'converted' to each other. HANDLE is a userspace handle to the kernel process object and a PID is a property of said object. You get the PID by handle with GetProcessId(), and you get a handle by creating a new process or opening an existing process, whether with OpenProcess() or NtOpenProcess().