EnumProcessModules returns 0 with error 299 - winapi

I'm currently trying to enumerate all the modules of a supsended 32-bits process I've previously created from my 32-bits program, my Windows is 64-bits.
(I've already read all the other topics on that problem).
Here is the code:
let a = CreateProcessA(
"C:\\Program Files (x86)\\GlassWire\\GlassWire.exe\0".as_ptr(),
null_mut(), null_mut(), null_mut(),
false,
0x00000004,
null_mut(), null_mut(), SI, PI);
println!("{}", GetLastError());
let mut buffer: [*mut c_void;10] = [0 as *mut c_void;10];
WaitForInputIdle((*PI).hProcess as *mut c_void, -1);
let result = EnumProcessModules(
(*PI).hProcess as *mut c_void,
buffer.as_ptr() as *mut c_void,
10, null_mut());
println!("EnumProcessModules([...]) = {} - {}", result, GetLastError());
let mut index: usize = 0x0;
let mut modname: [u8;1024] = [0;1024];
while(transmute::<*mut c_void, u32>(buffer[index]) != 0x0){
GetModuleFileNameExA((*PI).hProcess as *mut c_void, buffer[index], modname.as_ptr() as *mut c_void, 1024);
println!("module: {}", std::str::from_utf8_unchecked(&modname));
modname = [0;1024];
index += 1;
}
println!("Dump: {:?}", buffer.to_vec());
I saw that I had to use WaitForInputIdle() after using CreateProcessA before enumerating modules because the process doesn't have the time to "initialize", well when I do that, whatever the process I create (it successfully creates it) the program wait forever.
And when I try to do the same on the main process by replacing all the (*PI).hProcess by GetCurrentProcess() (I removed the WintForInputIdle() line), EnumProcessModules() still returns 0 but now GetLastError() returns 998 (ERROR_NOACCESS), but the modules handles are successfully written in buffer.
So the program output:
A:\Encrypted\Temp\injector\target\i686-pc-windows-msvc\debug\main.exe // (the program)
C:\WINDOWS\SYSTEM32\ntdll.dll
Dump: [0x920000, 0x77180000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]
And if I specify the path of the running program in CreateProcessA(), it will also return 0 with 299 as the windows error code.
I'm really confused...Thanks for reading, I hope I've been clear enough.

First, use the CREATE_NEW_CONSOLE or CREATE_NO_WINDOW instead of CREATE_SUSPENDED(0x00000004), as #Jonathan Potter, the suspend state will block the function WaitForInputIdle.
Second, make sure that the process is not a console application or has a message queue, otherwise WaitForInputIdle returns immediately.
Then, you can try to call SuspendThread after WaitForInputIdle to suspend the process to prevent it from ending.
EDIT:
Pay attention to the last two parameters of EnumProcessModules:
cb
The size of the lphModule array, in bytes.
lpcbNeeded
The number of bytes required to store all module handles in the
lphModule array.
Here is a good sample on msdn: Enumerating All Modules For a Process. Just replace hProcess.

Related

Rust Win32 FFI: User-mode data execution prevention (DEP) violation

I'm trying to pass a ID3D11Device instance from Rust to a C FFI Library (FFMPEG).
I made this sample code:
pub fn create_d3d11_device(&mut self, device: &mut Box<windows::Win32::Graphics::Direct3D11::ID3D11Device>, context: &mut Box<windows::Win32::Graphics::Direct3D11::ID3D11DeviceContext>) {
let av_device : Box<AVBufferRef> = self.alloc(HwDeviceType::D3d11va);
unsafe {
let device_context = Box::from_raw(av_device.data as *mut AVHWDeviceContext);
let mut d3d11_device_context = Box::from_raw(device_context.hwctx as *mut AVD3D11VADeviceContext);
d3d11_device_context.device = device.as_mut() as *mut _;
d3d11_device_context.device_context = context.as_mut() as *mut _;
let avp = Box::into_raw(av_device);
av_hwdevice_ctx_init(avp);
self.av_hwdevice = Some(Box::from_raw(avp));
}
}
On the Rust side the Device does work, but on the C side, when FFMEPG calls ID3D11DeviceContext_QueryInterface the app crashes with the following error: Exception 0xc0000005 encountered at address 0x7ff9fb99ad38: User-mode data execution prevention (DEP) violation at location 0x7ff9fb99ad38
The address is actually the pointer for the lpVtbl of QueryInterface, like seen here:
The disassembly of the address also looks correct (this is done on an another debugging session):
(lldb) disassemble --start-address 0x00007ffffdf3ad38
0x7ffffdf3ad38: addb %ah, 0x7ffffd(%rdi,%riz,8)
0x7ffffdf3ad3f: addb %al, (%rax)
0x7ffffdf3ad41: movabsl -0x591fffff80000219, %eax
0x7ffffdf3ad4a: outl %eax, $0xfd
Do you have any pointer to debug this further?
EDIT: I made a Minimal Reproducion Sample. Interestingly this does not causes a DEP Violation, but simply a Segfault.
On the C side:
int test_ffi(ID3D11Device *device){
ID3D11DeviceContext *context;
device->lpVtbl->GetImmediateContext(device, &context);
if (!context) return 1;
return 0;
}
On the Rust side:
unsafe fn main_rust(){
let mut device = None;
let mut device_context = None;
let _ = match windows::Win32::Graphics::Direct3D11::D3D11CreateDevice(None, D3D_DRIVER_TYPE_HARDWARE, OtherHinstance::default(), D3D11_CREATE_DEVICE_DEBUG, &[], D3D11_SDK_VERSION, &mut device, std::ptr::null_mut(), &mut device_context) {
Ok(e) => e,
Err(e) => panic!("Creation Failed: {}", e)
};
let mut device = match device {
Some(e) => e,
None => panic!("Creation Failed2")
};
let mut f2 : ID3D11Device = transmute_copy(&device); //Transmuting the WinAPI into a bindgen ID3D11Device
test_ffi(&mut f2);
}
The bindgen build.rs:
extern crate bindgen;
use std::env;
use std::path::PathBuf;
fn main() {
// Tell cargo to tell rustc to link the system bzip2
// shared library.
println!("cargo:rustc-link-lib=ffi_demoLIB");
println!("cargo:rustc-link-lib=d3d11");
// Tell cargo to invalidate the built crate whenever the wrapper changes
println!("cargo:rerun-if-changed=library.h");
// The bindgen::Builder is the main entry point
// to bindgen, and lets you build up options for
// the resulting bindings.
let bindings = bindgen::Builder::default()
// The input header we would like to generate
// bindings for.
.header("library.h")
// Tell cargo to invalidate the built crate whenever any of the
// included header files changed.
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
.blacklist_type("_IMAGE_TLS_DIRECTORY64")
.blacklist_type("IMAGE_TLS_DIRECTORY64")
.blacklist_type("PIMAGE_TLS_DIRECTORY64")
.blacklist_type("IMAGE_TLS_DIRECTORY")
.blacklist_type("PIMAGE_TLS_DIRECTORY")
// Finish the builder and generate the bindings.
.generate()
// Unwrap the Result and panic on failure.
.expect("Unable to generate bindings");
// Write the bindings to the $OUT_DIR/bindings.rs file.
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("bindings.rs"))
.expect("Couldn't write bindings!");
}
The Complete Repo can be found over here: https://github.com/TheElixZammuto/demo-ffi
According to https://github.com/microsoft/windows-rs/issues/1710#issuecomment-1111522946 my error was that I was trasmutating the structs, while what I should have done is to cast the references:
let f2 : &mut ID3D11Device = transmute_copy(&mut device); //Transmuting the WinAPI into a bindgen ID3D11Device
test_ffi(f2);

Windows, add user by Rust

I use winapi NetUserAdd to add a user,account added succsess,execute command net user,shows as below picture and cannot find users by control panel.
What wrong with LPSWTR or USER_INFO_1 struct to LPBYTE?
use winapi::um::lmaccess::{USER_INFO_1,NetUserAdd,UF_SCRIPT};
use std::iter::{once};
use std::os::windows::ffi::OsStrExt;
use std::ffi::OsStr;
pub fn winstr(value: &str) -> Vec<u16> {
OsStr::new(value).encode_wide().chain(once(0)).collect()
}
fn main() {
let username:String = "Test".to_string();
let password:String = "Test******".to_string();
let mut user = USER_INFO_1{
usri1_name:winstr(&username).as_mut_ptr(),
usri1_password:winstr(&password).as_mut_ptr(),
usri1_priv:1,
usri1_password_age: 0,
usri1_home_dir: std::ptr::null_mut(),
usri1_comment: std::ptr::null_mut(),
usri1_flags:UF_SCRIPT,
usri1_script_path: std::ptr::null_mut(),
};
let mut error = 0 ;
unsafe{
NetUserAdd(std::ptr::null_mut(),1,&mut user as *mut _ as _,&mut error);
}
println!("{}",error);//result is 0,means success.
}
You're sending dangling pointers.
Your winstr(...).as_mut_ptr() calls create a Vec<u16>, gets a pointer to its data, and drops the Vec<u16> since it was a temporary value. You need to keep those values at least until the call to NetUserAdd has finished:
let mut username = winstr("Test");
let mut password = winstr("Test******");
let mut user = USER_INFO_1{
usri1_name: username.as_mut_ptr(),
usri1_password: password.as_mut_ptr(),
usri1_priv: 1,
usri1_password_age: 0,
usri1_home_dir: std::ptr::null_mut(),
usri1_comment: std::ptr::null_mut(),
usri1_flags: UF_SCRIPT,
usri1_script_path: std::ptr::null_mut(),
};

Cannot get user name for a pid using rust winapi

I'm trying to get the user that is associated with a PID on windows.
I'm looking at the source for NTop https://github.com/gsass1/NTop as an example.
I can build and debug NTop source on Clion and the following code works correctly.
HANDLE ProcessTokenHandle;
if(OpenProcessToken(Process.Handle, TOKEN_READ, &ProcessTokenHandle)) {
DWORD ReturnLength;
GetTokenInformation(ProcessTokenHandle, TokenUser, 0, 0, &ReturnLength);
if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
PTOKEN_USER TokenUserStruct = xmalloc(ReturnLength);
if(GetTokenInformation(ProcessTokenHandle, TokenUser, TokenUserStruct, ReturnLength, &ReturnLength)) {
SID_NAME_USE NameUse;
DWORD NameLength = UNLEN;
TCHAR DomainName[MAX_PATH];
DWORD DomainLength = MAX_PATH;
LookupAccountSid(0, TokenUserStruct->User.Sid, Process.UserName, &NameLength, DomainName, &DomainLength, &NameUse);
// FIXME: we cut user name here for display purposes because something like %9.9s does not work with MS's vsprintf function?
Process.UserName[9] = 0;
}
free(TokenUserStruct);
}
CloseHandle(ProcessTokenHandle);
}
When trying the same thing using rust winapi I get ERROR_NOACCESS every time no matter what I do.
Here's some example code that returns 0 as response code from OpenProcessToken and GetLastError will be ERROR_NOACCESS. It doesn't matter whether or not I run the program as administrator or not.
let pid: u32 = 8664; // process that is owned by me but can be any process, it will never work
let process_handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, 0, pid);
let mut process_token_handle: PHANDLE = null_mut();
let s = OpenProcessToken(process_handle, TOKEN_READ, process_token_handle);
let last_error = GetLastError();
Anyone have any idea why this code would work in NTop using the C api and not work using rust winapi?

Segfault when calling GetBinaryTypeA

I tried to import the GetBinaryTypeA function:
use std::ffi::CString;
use ::std::os::raw::{c_char, c_ulong};
extern { fn GetBinaryTypeA(s: *const c_char, out: *mut c_ulong) -> i32; }
fn main() {
let path = "absolute/path/to/bin.exe";
let cpath = CString::new(path).unwrap();
let mut out: c_ulong = 0;
println!("{:?}", cpath);
unsafe { GetBinaryTypeA(cpath.as_ptr(), out as *mut c_ulong); }
println!("{:?}", cpath);
}
Output:
error: process didn't exit successfully: `target\debug\bin_deploy.exe` (exit code: 3221225477)
Process finished with exit code -1073741819 (0xC0000005)
If I set an invalid path then it executes successfully and GetLastError() returns 2 ("The system cannot find the file specified"), so it looks like the imported function works.
I received the same error using the kernel32-sys crate. Where else can the error be?
You are casting the value 0 to a pointer. On the vast majority of computers in use today, the pointer with the value 0 is known as NULL. Thus, you are trying to write to the NULL pointer, which causes a crash.
You want to write to the address of the value:
&mut out as *mut c_ulong
Which doesn't even need the cast:
unsafe {
GetBinaryTypeA(cpath.as_ptr(), &mut out);
}

Calling the GetUserName WinAPI function with a mutable string doesn't populate the string

This appears to partially work but I cannot get the string value to print
pub fn test() {
let mut buf: Vec<u16> = vec![0; 64];
let mut sz: DWORD = 0;
unsafe {
advapi32::GetUserNameW(buf.as_mut_ptr(), &mut sz);
}
let str1 = OsString::from_wide(&buf).into_string().unwrap();
println!("Here: {} {}", sz, str1);
}
Prints:
Here: 10
When I expect it to also print
Here: 10 <username>
As a test, the C version
TCHAR buf[100];
DWORD sz;
GetUserName(buf, &sz);
seems to populate buf fine.
GetUserName
You should re-read the API documentation for GetUserName to recall how the arguments work:
lpnSize [in, out]
On input, this variable specifies the size of the
lpBuffer buffer, in TCHARs. On output, the variable receives the
number of TCHARs copied to the buffer, including the terminating null
character. If lpBuffer is too small, the function fails and
GetLastError returns ERROR_INSUFFICIENT_BUFFER. This parameter
receives the required buffer size, including the terminating null
character.
TL;DR:
On input: caller tells the API how many spaces the buffer has.
On success: API tells the caller how many spaces were used.
On failure: API tells the caller how many spaces were needed.
C version
This has a fixed-size stack-allocated array of 100 TCHARs.
This code is broken and unsafe because sz is uninitialized. This allows the API to write an undefined number of characters to a buffer that's only 100 long. If the username is over 100 characters, you've just introduced a security hole into your program.
Rust version
The Rust code is broken in a much better way. sz is set to zero, which means "you may write zero entries of data", so it writes zero entries. Thus, the Vec buffer is full of zeros and the resulting string is empty. The buffer is reported too small to receive the username, so GetUserNameW sets sz to the number of characters that the buffer needs to have allocated.
What to do
One "fix" would be to set sz to the length of your array. However, this is likely to have over- or under-allocated the buffer.
If you are ok with a truncated string (and I'm not sure if TCHAR strings can be split arbitrarily, I know UTF-8 cannot), then it would be better to use a fixed-size array like the C code.
If you want to more appropriately allocate memory to call this type of WinAPI function, see What is the right way to allocate data to pass to an FFI call?.
extern crate advapi32;
extern crate winapi;
use std::ptr;
fn get_user_name() -> String {
unsafe {
let mut size = 0;
let retval = advapi32::GetUserNameW(ptr::null_mut(), &mut size);
assert_eq!(retval, 0, "Should have failed");
let mut username = Vec::with_capacity(size as usize);
let retval = advapi32::GetUserNameW(username.as_mut_ptr(), &mut size);
assert_ne!(retval, 0, "Perform better error handling");
assert!((size as usize) <= username.capacity());
username.set_len(size as usize);
// Beware: This leaves the trailing NUL character in the final string,
// you may want to remove it!
String::from_utf16(&username).unwrap()
}
}
fn main() {
println!("{:?}", get_user_name()); // "IEUser\u{0}"
}

Resources