use crate::windows::constants::*;
use crate::emu::Emu;
const SYSTEM_TIMEOFDAY_INFORMATION_SIZE: u32 = 56;
const SYSTEM_PROCESS_INFORMATION_SIZE: u32 = 224;
fn write_return_length(emu: &mut Emu, ret_len_ptr: u64, n: u32) {
if ret_len_ptr == 0 {
return;
}
let _ = emu.maps.write_dword(ret_len_ptr, n);
}
const SYSTEM_BASIC_INFORMATION: u64 = 0;
const SYSTEM_PROCESSOR_INFORMATION: u64 = 1;
const SYSTEM_PERFORMANCE_INFORMATION: u64 = 2;
const SYSTEM_TIMEOFDAY_INFORMATION: u64 = 3;
const SYSTEM_PROCESS_INFORMATION: u64 = 5;
const SYSTEM_KERNEL_DEBUGGER_INFORMATION: u64 = 0x23;
const SYSTEM_KERNEL_DEBUGGER_INFORMATION_EX: u64 = 0x3e;
const SYSTEM_CODE_INTEGRITY_INFORMATION: u64 = 103;
const SYSTEM_CODE_INTEGRITY_POLICY_INFORMATION: u64 = 0xC0;
const SYSTEM_EXTENDED_HANDLE_INFORMATION: u64 = 0x37;
const SYSTEM_SUPPORTED_PROCESSOR_ARCHITECTURES2: u64 = 0xC5;
pub fn nt_query_system_information(emu: &mut Emu) {
let class = emu.regs().rcx;
let info = emu.regs().rdx;
let len = emu.regs().r8 as u32;
let ret_len_ptr = emu.regs().r9;
log_orange!(
emu,
"syscall 0x{:x}: NtQuerySystemInformation class: 0x{:x}, buf: 0x{:x}, len: 0x{:x}, ret_len: 0x{:x}",
WIN64_NTQUERYSYSTEMINFORMATION,
class,
info,
len,
ret_len_ptr
);
if info == 0 && len > 0 {
emu.regs_mut().rax = STATUS_INVALID_PARAMETER;
return;
}
if len > 0 && info != 0 {
if !emu.maps.is_mapped(info) || !emu.maps.is_mapped(info + u64::from(len).saturating_sub(1)) {
emu.regs_mut().rax = STATUS_ACCESS_VIOLATION;
return;
}
}
match class {
SYSTEM_BASIC_INFORMATION => {
const NEED: u32 = 0x40;
if len < NEED {
write_return_length(emu, ret_len_ptr, NEED);
emu.regs_mut().rax = STATUS_INFO_LENGTH_MISMATCH;
return;
}
for off in 0..len {
let _ = emu.maps.write_byte(info + u64::from(off), 0);
}
let _ = emu.maps.write_dword(info + 8, 4096); let _ = emu.maps.write_dword(info + 12, 0x1000); let _ = emu.maps.write_qword(info + 28, 0x0000_0000_0001_0000); let _ = emu.maps.write_qword(info + 36, 0x0000_7fff_ffff_ffff); let _ = emu.maps.write_qword(info + 44, 1); let _ = emu.maps.write_byte(info + 52, 1); write_return_length(emu, ret_len_ptr, NEED);
emu.regs_mut().rax = STATUS_SUCCESS;
}
SYSTEM_PROCESSOR_INFORMATION => {
const NEED: u32 = 0x18;
if len < NEED {
write_return_length(emu, ret_len_ptr, NEED);
emu.regs_mut().rax = STATUS_INFO_LENGTH_MISMATCH;
return;
}
for off in 0..len {
let _ = emu.maps.write_byte(info + u64::from(off), 0);
}
write_return_length(emu, ret_len_ptr, NEED);
emu.regs_mut().rax = STATUS_SUCCESS;
}
SYSTEM_PERFORMANCE_INFORMATION => {
if len < 8 {
write_return_length(emu, ret_len_ptr, 0x100);
emu.regs_mut().rax = STATUS_INFO_LENGTH_MISMATCH;
return;
}
for off in 0..len {
let _ = emu.maps.write_byte(info + u64::from(off), 0);
}
write_return_length(emu, ret_len_ptr, len);
emu.regs_mut().rax = STATUS_SUCCESS;
}
SYSTEM_TIMEOFDAY_INFORMATION => {
let need = SYSTEM_TIMEOFDAY_INFORMATION_SIZE;
if len < need {
write_return_length(emu, ret_len_ptr, need);
emu.regs_mut().rax = STATUS_INFO_LENGTH_MISMATCH;
return;
}
for off in 0..len {
let _ = emu.maps.write_byte(info + u64::from(off), 0);
}
let _ = emu.maps.write_qword(info + 8, 1); write_return_length(emu, ret_len_ptr, need);
emu.regs_mut().rax = STATUS_SUCCESS;
}
SYSTEM_PROCESS_INFORMATION => {
let need = SYSTEM_PROCESS_INFORMATION_SIZE;
if len < need {
write_return_length(emu, ret_len_ptr, need);
emu.regs_mut().rax = STATUS_INFO_LENGTH_MISMATCH;
return;
}
for off in 0..len {
let _ = emu.maps.write_byte(info + u64::from(off), 0);
}
let _ = emu.maps.write_dword(info, 0);
let _ = emu.maps.write_dword(info + 4, 0);
write_return_length(emu, ret_len_ptr, need);
emu.regs_mut().rax = STATUS_SUCCESS;
}
SYSTEM_KERNEL_DEBUGGER_INFORMATION | SYSTEM_KERNEL_DEBUGGER_INFORMATION_EX => {
const NEED: u32 = 2;
if len < NEED {
write_return_length(emu, ret_len_ptr, NEED);
emu.regs_mut().rax = STATUS_INFO_LENGTH_MISMATCH;
return;
}
let _ = emu.maps.write_byte(info, 0); let _ = emu.maps.write_byte(info + 1, 1); write_return_length(emu, ret_len_ptr, NEED);
emu.regs_mut().rax = STATUS_SUCCESS;
}
SYSTEM_CODE_INTEGRITY_INFORMATION => {
const NEED: u32 = 8;
if len < NEED {
write_return_length(emu, ret_len_ptr, NEED);
emu.regs_mut().rax = STATUS_INFO_LENGTH_MISMATCH;
return;
}
let _ = emu.maps.write_dword(info, NEED);
let _ = emu.maps.write_dword(info + 4, 0);
write_return_length(emu, ret_len_ptr, NEED);
emu.regs_mut().rax = STATUS_SUCCESS;
}
SYSTEM_CODE_INTEGRITY_POLICY_INFORMATION => {
const MIN: u32 = 0x10;
if len < MIN {
write_return_length(emu, ret_len_ptr, MIN);
emu.regs_mut().rax = STATUS_INFO_LENGTH_MISMATCH;
return;
}
for off in 0..len {
let _ = emu.maps.write_byte(info + u64::from(off), 0);
}
write_return_length(emu, ret_len_ptr, len);
emu.regs_mut().rax = STATUS_SUCCESS;
}
SYSTEM_EXTENDED_HANDLE_INFORMATION => {
const HEADER: u32 = 16; if len < HEADER {
write_return_length(emu, ret_len_ptr, HEADER);
emu.regs_mut().rax = STATUS_INFO_LENGTH_MISMATCH;
return;
}
for off in 0..HEADER {
let _ = emu.maps.write_byte(info + u64::from(off), 0);
}
write_return_length(emu, ret_len_ptr, HEADER);
emu.regs_mut().rax = STATUS_SUCCESS;
}
SYSTEM_SUPPORTED_PROCESSOR_ARCHITECTURES2 => {
const NEED: u32 = 8;
if len < NEED {
write_return_length(emu, ret_len_ptr, NEED);
emu.regs_mut().rax = STATUS_INFO_LENGTH_MISMATCH;
return;
}
for off in 0..NEED {
let _ = emu.maps.write_byte(info + u64::from(off), 0);
}
write_return_length(emu, ret_len_ptr, NEED);
emu.regs_mut().rax = STATUS_SUCCESS;
}
0x73 => {
const NEED: u32 = 3;
if len < NEED {
write_return_length(emu, ret_len_ptr, NEED);
emu.regs_mut().rax = STATUS_INFO_LENGTH_MISMATCH;
return;
}
for off in 0..NEED {
let _ = emu.maps.write_byte(info + u64::from(off), 0);
}
write_return_length(emu, ret_len_ptr, NEED);
emu.regs_mut().rax = STATUS_SUCCESS;
}
_ => {
log_orange!(
emu,
"NtQuerySystemInformation: unhandled class 0x{:x}, returning STATUS_INVALID_INFO_CLASS",
class
);
write_return_length(emu, ret_len_ptr, 0);
emu.regs_mut().rax = STATUS_INVALID_INFO_CLASS;
}
}
}
pub fn nt_manage_hot_patch(emu: &mut Emu) {
let info = emu.regs().rcx;
log_orange!(
emu,
"syscall 0x{:x}: NtManageHotPatch info: 0x{:x}",
WIN64_NTMANAGEHOTPATCH,
info
);
emu.regs_mut().rax = STATUS_NOT_SUPPORTED;
}
pub fn nt_query_debug_filter_state(emu: &mut Emu) {
let component = emu.regs().rcx;
let level = emu.regs().rdx;
log_orange!(
emu,
"syscall 0x{:x}: NtQueryDebugFilterState component: 0x{:x}, level: 0x{:x}",
WIN64_NTQUERYDEBUGFILTERSTATE,
component,
level
);
emu.regs_mut().rax = 0; }
pub fn nt_trace_event(emu: &mut Emu) {
log_orange!(
emu,
"syscall 0x{:x}: NtTraceEvent (stub)",
WIN64_NTTRACEEVENT
);
emu.regs_mut().rax = STATUS_SUCCESS;
}
pub fn nt_query_information_transaction_manager(emu: &mut Emu) {
let _handle = emu.regs().rcx;
let info_class = emu.regs().rdx;
let buffer = emu.regs().r8;
let buffer_len = emu.regs().r9;
let rsp = emu.regs().rsp;
let return_length_ptr = emu.maps.read_qword(rsp + 0x28).unwrap_or(0);
log_orange!(
emu,
"syscall 0x{:x}: NtQueryInformationTransactionManager class: {} buf: 0x{:x} len: {}",
WIN64_NTQUERYINFORMATIONTRANSACTIONMANAGER,
info_class,
buffer,
buffer_len
);
let (needed, _desc): (u64, &str) = match info_class {
0 => (24, "BasicInformation"), 1 => (16, "LogInformation"), _ => {
emu.regs_mut().rax = STATUS_INVALID_INFO_CLASS;
return;
}
};
write_return_length(emu, return_length_ptr, needed as u32);
if buffer == 0 || buffer_len < needed {
emu.regs_mut().rax = STATUS_BUFFER_TOO_SMALL;
return;
}
if !emu.maps.is_mapped(buffer) {
emu.regs_mut().rax = STATUS_ACCESS_VIOLATION;
return;
}
emu.maps.memset(buffer, 0, needed as usize);
emu.regs_mut().rax = STATUS_SUCCESS;
}
pub fn nt_query_io_completion(emu: &mut Emu) {
let handle = emu.regs().rcx;
let info_class = emu.regs().rdx;
let buffer = emu.regs().r8;
let buffer_len = emu.regs().r9;
let rsp = emu.regs().rsp;
let return_length_ptr = emu.maps.read_qword(rsp + 0x28).unwrap_or(0);
log_orange!(
emu,
"syscall 0x{:x}: NtQueryIoCompletion handle: 0x{:x}, class: {}, buf: 0x{:x}, len: {}",
WIN64_NTQUERYIOCOMPLETION,
handle,
info_class,
buffer,
buffer_len,
);
const NEEDED: u64 = 4; write_return_length(emu, return_length_ptr, NEEDED as u32);
if buffer == 0 || buffer_len < NEEDED {
emu.regs_mut().rax = STATUS_BUFFER_TOO_SMALL;
return;
}
if !emu.maps.is_mapped(buffer) {
emu.regs_mut().rax = STATUS_ACCESS_VIOLATION;
return;
}
let _ = emu.maps.write_dword(buffer, 0);
emu.regs_mut().rax = STATUS_SUCCESS;
}