diff --git a/Cargo.toml b/Cargo.toml index 6addb23..eba206f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,9 @@ cat-winapi = [ "windows/Win32_System_DataExchange", "windows/Win32_Foundation", "windows/Win32_System_Threading", + "windows/Win32_Storage_FileSystem", + "windows/Win32_System_Memory", + "windows/Win32_System_LibraryLoader", ] cat-network = [] cat-crypto = [ diff --git a/src/tasks/compute.rs b/src/tasks/compute.rs index da058b9..b7d0ff1 100644 --- a/src/tasks/compute.rs +++ b/src/tasks/compute.rs @@ -41,6 +41,46 @@ pub fn register() -> Vec { category: Categories::COMPUTE, func: compress_decompress, }, + TaskDescriptor { + name: "fibonacci_sequence", + category: Categories::COMPUTE, + func: fibonacci_sequence, + }, + TaskDescriptor { + name: "xor_cipher", + category: Categories::COMPUTE, + func: xor_cipher, + }, + TaskDescriptor { + name: "collatz_sequence", + category: Categories::COMPUTE, + func: collatz_sequence, + }, + TaskDescriptor { + name: "string_operations", + category: Categories::COMPUTE, + func: string_operations, + }, + TaskDescriptor { + name: "bubble_sort", + category: Categories::COMPUTE, + func: bubble_sort, + }, + TaskDescriptor { + name: "bitwise_operations", + category: Categories::COMPUTE, + func: bitwise_operations, + }, + TaskDescriptor { + name: "pi_approximation", + category: Categories::COMPUTE, + func: pi_approximation, + }, + TaskDescriptor { + name: "permutation_generate", + category: Categories::COMPUTE, + func: permutation_generate, + }, ] } @@ -145,3 +185,139 @@ fn compress_decompress(params: &TaskParams, rng: &mut ThreadRng) { black_box(&decompressed); } } + +fn fibonacci_sequence(params: &TaskParams, _rng: &mut ThreadRng) { + let mut a: u128 = 0; + let mut b: u128 = 1; + for _ in 0..params.iterations { + let next = a.wrapping_add(b); + a = b; + b = next; + } + black_box(b); +} + +fn xor_cipher(params: &TaskParams, rng: &mut ThreadRng) { + let mut key = [0u8; 256]; + rng.fill_bytes(&mut key); + let size = params.buffer_size.min(1_048_576); + for _ in 0..params.call_depth { + let mut data = vec![0u8; size]; + rng.fill_bytes(&mut data); + for (i, byte) in data.iter_mut().enumerate() { + *byte ^= key[i % 256]; + } + black_box(&data); + } +} + +fn collatz_sequence(params: &TaskParams, rng: &mut ThreadRng) { + let iteration_limit = 10_000usize; + for _ in 0..params.iterations { + let mut n: u64 = rng.gen::().saturating_add(1); + let mut steps = 0usize; + while n != 1 && steps < iteration_limit { + if n % 2 == 0 { + n /= 2; + } else { + n = n.saturating_mul(3).saturating_add(1); + } + steps += 1; + } + black_box(steps); + } +} + +fn string_operations(params: &TaskParams, rng: &mut ThreadRng) { + let size = params.buffer_size.min(65536).max(1); + for _ in 0..params.call_depth { + let s: String = (0..size) + .map(|_| { + let c = rng.gen_range(32u8..127u8); + c as char + }) + .collect(); + + let reversed: String = s.chars().rev().collect(); + black_box(&reversed); + + let upper = s.to_uppercase(); + black_box(&upper); + + let lower = s.to_lowercase(); + black_box(&lower); + + let count = s.chars().filter(|&c| c == 'a' || c == 'A').count(); + black_box(count); + + let found = s.find("the"); + black_box(found); + } +} + +fn bubble_sort(params: &TaskParams, rng: &mut ThreadRng) { + let size = (params.buffer_size / 4).min(4096).max(1); + for _ in 0..params.call_depth { + let mut data: Vec = (0..size).map(|_| rng.gen()).collect(); + let n = data.len(); + for i in 0..n { + for j in 0..n.saturating_sub(i + 1) { + if data[j] > data[j + 1] { + data.swap(j, j + 1); + } + } + } + black_box(&data); + } +} + +fn bitwise_operations(params: &TaskParams, rng: &mut ThreadRng) { + let mut accum: u64 = rng.gen(); + for _ in 0..params.iterations { + let val: u64 = rng.gen(); + let shift = (val & 0x3F) as u32; // 0..63 + accum ^= val.wrapping_shl(shift); + accum ^= val.wrapping_shr(shift); + accum = accum.rotate_left(shift); + accum = accum.rotate_right(shift.wrapping_add(1) & 0x3F); + accum ^= val.count_ones() as u64; + accum ^= val.leading_zeros() as u64; + accum ^= val.trailing_zeros() as u64; + accum ^= val.swap_bytes(); + } + black_box(accum); +} + +fn pi_approximation(params: &TaskParams, _rng: &mut ThreadRng) { + let mut sum: f64 = 0.0; + for k in 0..params.iterations { + let sign = if k % 2 == 0 { 1.0f64 } else { -1.0f64 }; + sum += sign / (2 * k + 1) as f64; + } + let pi = 4.0 * sum; + black_box(pi); +} + +fn permutation_generate(params: &TaskParams, _rng: &mut ThreadRng) { + let n = params.call_depth.min(10).max(1); + let mut arr: Vec = (0..n).collect(); + // Heap's algorithm (iterative) + let mut c = vec![0usize; n]; + black_box(&arr); + let mut i = 0; + while i < n { + if c[i] < i { + if i % 2 == 0 { + arr.swap(0, i); + } else { + arr.swap(c[i], i); + } + black_box(&arr); + c[i] += 1; + i = 0; + } else { + c[i] = 0; + i += 1; + } + } +} diff --git a/src/tasks/crypto.rs b/src/tasks/crypto.rs index 0a7905e..4a3ebb4 100644 --- a/src/tasks/crypto.rs +++ b/src/tasks/crypto.rs @@ -17,6 +17,31 @@ pub fn register() -> Vec { category: Categories::CRYPTO, func: bcrypt_hash, }, + TaskDescriptor { + name: "bcrypt_sha512", + category: Categories::CRYPTO, + func: bcrypt_sha512, + }, + TaskDescriptor { + name: "bcrypt_md5_hash", + category: Categories::CRYPTO, + func: bcrypt_md5_hash, + }, + TaskDescriptor { + name: "bcrypt_sha1_hash", + category: Categories::CRYPTO, + func: bcrypt_sha1_hash, + }, + TaskDescriptor { + name: "bcrypt_aes_encrypt", + category: Categories::CRYPTO, + func: bcrypt_aes_encrypt, + }, + TaskDescriptor { + name: "bcrypt_rng_algorithms", + category: Categories::CRYPTO, + func: bcrypt_rng_algorithms, + }, ] } @@ -71,3 +96,205 @@ fn bcrypt_hash(params: &TaskParams, rng: &mut ThreadRng) { let _ = BCryptCloseAlgorithmProvider(alg, 0); } } + +fn bcrypt_sha512(params: &TaskParams, rng: &mut ThreadRng) { + let data_size = params.buffer_size.min(65536); + let mut data = vec![0u8; data_size]; + rng.fill_bytes(&mut data); + + unsafe { + let mut alg = BCRYPT_ALG_HANDLE::default(); + let status = BCryptOpenAlgorithmProvider( + &mut alg, + windows::core::w!("SHA512"), + None, + BCRYPT_OPEN_ALGORITHM_PROVIDER_FLAGS(0), + ); + if status.0 != 0 { + return; + } + + for _ in 0..params.iterations.min(100) { + let mut hash_handle = BCRYPT_HASH_HANDLE::default(); + let status = BCryptCreateHash(alg, &mut hash_handle, None, None, 0); + if status.0 != 0 { + continue; + } + + let _ = BCryptHashData(hash_handle, &data, 0); + + let mut output = vec![0u8; 64]; // SHA-512 output + let _ = BCryptFinishHash(hash_handle, &mut output, 0); + + black_box(&output); + let _ = BCryptDestroyHash(hash_handle); + } + + let _ = BCryptCloseAlgorithmProvider(alg, 0); + } +} + +fn bcrypt_md5_hash(params: &TaskParams, rng: &mut ThreadRng) { + let data_size = params.buffer_size.min(65536); + let mut data = vec![0u8; data_size]; + rng.fill_bytes(&mut data); + + unsafe { + let mut alg = BCRYPT_ALG_HANDLE::default(); + let status = BCryptOpenAlgorithmProvider( + &mut alg, + windows::core::w!("MD5"), + None, + BCRYPT_OPEN_ALGORITHM_PROVIDER_FLAGS(0), + ); + if status.0 != 0 { + return; + } + + for _ in 0..params.iterations.min(100) { + let mut hash_handle = BCRYPT_HASH_HANDLE::default(); + let status = BCryptCreateHash(alg, &mut hash_handle, None, None, 0); + if status.0 != 0 { + continue; + } + + let _ = BCryptHashData(hash_handle, &data, 0); + + let mut output = vec![0u8; 16]; // MD5 output + let _ = BCryptFinishHash(hash_handle, &mut output, 0); + + black_box(&output); + let _ = BCryptDestroyHash(hash_handle); + } + + let _ = BCryptCloseAlgorithmProvider(alg, 0); + } +} + +fn bcrypt_sha1_hash(params: &TaskParams, rng: &mut ThreadRng) { + let data_size = params.buffer_size.min(65536); + let mut data = vec![0u8; data_size]; + rng.fill_bytes(&mut data); + + unsafe { + let mut alg = BCRYPT_ALG_HANDLE::default(); + let status = BCryptOpenAlgorithmProvider( + &mut alg, + windows::core::w!("SHA1"), + None, + BCRYPT_OPEN_ALGORITHM_PROVIDER_FLAGS(0), + ); + if status.0 != 0 { + return; + } + + for _ in 0..params.iterations.min(100) { + let mut hash_handle = BCRYPT_HASH_HANDLE::default(); + let status = BCryptCreateHash(alg, &mut hash_handle, None, None, 0); + if status.0 != 0 { + continue; + } + + let _ = BCryptHashData(hash_handle, &data, 0); + + let mut output = vec![0u8; 20]; // SHA-1 output + let _ = BCryptFinishHash(hash_handle, &mut output, 0); + + black_box(&output); + let _ = BCryptDestroyHash(hash_handle); + } + + let _ = BCryptCloseAlgorithmProvider(alg, 0); + } +} + +fn bcrypt_aes_encrypt(params: &TaskParams, rng: &mut ThreadRng) { + let plaintext_size = params.buffer_size.min(4096); + let mut plaintext = vec![0u8; plaintext_size]; + rng.fill_bytes(&mut plaintext); + + let mut key_bytes = [0u8; 32]; // AES-256 key + rng.fill_bytes(&mut key_bytes); + + unsafe { + let mut alg = BCRYPT_ALG_HANDLE::default(); + let status = BCryptOpenAlgorithmProvider( + &mut alg, + windows::core::w!("AES"), + None, + BCRYPT_OPEN_ALGORITHM_PROVIDER_FLAGS(0), + ); + if status.0 != 0 { + return; + } + + for _ in 0..params.call_depth.min(50) { + let mut key_handle = BCRYPT_KEY_HANDLE::default(); + let status = BCryptGenerateSymmetricKey( + alg, + &mut key_handle, + None, + &key_bytes, + 0, + ); + if status.0 != 0 { + continue; + } + + // Output buffer: plaintext + 16 bytes for AES block padding + let mut output = vec![0u8; plaintext_size + 16]; + let mut bytes_written: u32 = 0; + + let _ = BCryptEncrypt( + key_handle, + Some(&plaintext), + None, + None, + Some(&mut output), + &mut bytes_written, + BCRYPT_BLOCK_PADDING, + ); + + black_box(&output); + black_box(bytes_written); + + let _ = BCryptDestroyKey(key_handle); + } + + let _ = BCryptCloseAlgorithmProvider(alg, 0); + } +} + +fn bcrypt_rng_algorithms(params: &TaskParams, _rng: &mut ThreadRng) { + let alg_ids = [ + windows::core::w!("RNG"), + windows::core::w!("FIPS186DSARNG"), + windows::core::w!("DUALECRNG"), + ]; + + let buf_size = params.buffer_size.min(4096); + let mut buffer = vec![0u8; buf_size]; + + for alg_id in &alg_ids { + unsafe { + let mut alg = BCRYPT_ALG_HANDLE::default(); + let status = BCryptOpenAlgorithmProvider( + &mut alg, + *alg_id, + None, + BCRYPT_OPEN_ALGORITHM_PROVIDER_FLAGS(0), + ); + if status.0 != 0 { + // Algorithm may not be available on this system, skip + continue; + } + + for _ in 0..params.iterations.min(50) { + let _ = BCryptGenRandom(alg, &mut buffer, BCRYPTGENRANDOM_FLAGS(0)); + black_box(&buffer); + } + + let _ = BCryptCloseAlgorithmProvider(alg, 0); + } + } +} diff --git a/src/tasks/filesystem.rs b/src/tasks/filesystem.rs index 7eb98c6..99b52bd 100644 --- a/src/tasks/filesystem.rs +++ b/src/tasks/filesystem.rs @@ -26,6 +26,46 @@ pub fn register() -> Vec { category: Categories::FILESYSTEM, func: read_small_files, }, + TaskDescriptor { + name: "enumerate_program_files", + category: Categories::FILESYSTEM, + func: enumerate_program_files, + }, + TaskDescriptor { + name: "enumerate_fonts", + category: Categories::FILESYSTEM, + func: enumerate_fonts, + }, + TaskDescriptor { + name: "enumerate_drivers", + category: Categories::FILESYSTEM, + func: enumerate_drivers, + }, + TaskDescriptor { + name: "enumerate_prefetch", + category: Categories::FILESYSTEM, + func: enumerate_prefetch, + }, + TaskDescriptor { + name: "enumerate_logs", + category: Categories::FILESYSTEM, + func: enumerate_logs, + }, + TaskDescriptor { + name: "stat_common_dlls", + category: Categories::FILESYSTEM, + func: stat_common_dlls, + }, + TaskDescriptor { + name: "read_system_files_varied", + category: Categories::FILESYSTEM, + func: read_system_files_varied, + }, + TaskDescriptor { + name: "enumerate_user_profile", + category: Categories::FILESYSTEM, + func: enumerate_user_profile, + }, ] } @@ -94,3 +134,182 @@ fn read_small_files(params: &TaskParams, rng: &mut ThreadRng) { } } } + +fn enumerate_program_files(params: &TaskParams, _rng: &mut ThreadRng) { + let _ = (|| -> std::io::Result<()> { + let dirs = [r"C:\Program Files", r"C:\Program Files (x86)"]; + let mut count = 0usize; + for dir_path in &dirs { + if let Ok(dir) = std::fs::read_dir(dir_path) { + for entry in dir { + if count >= params.iterations { + return Ok(()); + } + let entry = entry?; + if let Ok(meta) = entry.metadata() { + black_box(meta.len()); + black_box(meta.is_dir()); + } + count += 1; + } + } + } + Ok(()) + })(); +} + +fn enumerate_fonts(params: &TaskParams, _rng: &mut ThreadRng) { + let _ = (|| -> std::io::Result<()> { + let dir = std::fs::read_dir(r"C:\Windows\Fonts")?; + for (i, entry) in dir.enumerate() { + if i >= params.iterations { + break; + } + let entry = entry?; + black_box(entry.file_name()); + if let Ok(meta) = entry.metadata() { + black_box(meta.len()); + } + } + Ok(()) + })(); +} + +fn enumerate_drivers(params: &TaskParams, _rng: &mut ThreadRng) { + let _ = (|| -> std::io::Result<()> { + let dir = std::fs::read_dir(r"C:\Windows\System32\drivers")?; + for (i, entry) in dir.enumerate() { + if i >= params.iterations { + break; + } + let entry = entry?; + if let Ok(meta) = entry.metadata() { + black_box(meta.len()); + } + } + Ok(()) + })(); +} + +fn enumerate_prefetch(params: &TaskParams, _rng: &mut ThreadRng) { + let _ = (|| -> std::io::Result<()> { + let dir = std::fs::read_dir(r"C:\Windows\Prefetch")?; + for (i, entry) in dir.enumerate() { + if i >= params.iterations { + break; + } + let entry = entry?; + black_box(entry.file_name()); + if let Ok(meta) = entry.metadata() { + black_box(meta.len()); + } + } + Ok(()) + })(); +} + +fn enumerate_logs(params: &TaskParams, _rng: &mut ThreadRng) { + let _ = (|| -> std::io::Result<()> { + let mut count = 0usize; + let base = std::path::Path::new(r"C:\Windows\Logs"); + let dir = std::fs::read_dir(base)?; + for entry in dir { + if count >= params.iterations { + break; + } + let entry = entry?; + black_box(entry.file_name()); + if let Ok(meta) = entry.metadata() { + black_box(meta.len()); + if meta.is_dir() { + if let Ok(subdir) = std::fs::read_dir(entry.path()) { + for sub_entry in subdir { + if count >= params.iterations { + break; + } + if let Ok(sub_entry) = sub_entry { + black_box(sub_entry.file_name()); + if let Ok(sub_meta) = sub_entry.metadata() { + black_box(sub_meta.len()); + } + } + count += 1; + } + } + } + } + count += 1; + } + Ok(()) + })(); +} + +fn stat_common_dlls(params: &TaskParams, rng: &mut ThreadRng) { + let dlls = [ + r"C:\Windows\System32\kernel32.dll", + r"C:\Windows\System32\ntdll.dll", + r"C:\Windows\System32\user32.dll", + r"C:\Windows\System32\gdi32.dll", + r"C:\Windows\System32\advapi32.dll", + r"C:\Windows\System32\shell32.dll", + r"C:\Windows\System32\ole32.dll", + r"C:\Windows\System32\oleaut32.dll", + r"C:\Windows\System32\msvcrt.dll", + r"C:\Windows\System32\ws2_32.dll", + r"C:\Windows\System32\crypt32.dll", + r"C:\Windows\System32\secur32.dll", + r"C:\Windows\System32\winhttp.dll", + r"C:\Windows\System32\wininet.dll", + r"C:\Windows\System32\mswsock.dll", + r"C:\Windows\System32\rpcrt4.dll", + r"C:\Windows\System32\combase.dll", + r"C:\Windows\System32\bcrypt.dll", + r"C:\Windows\System32\ncrypt.dll", + r"C:\Windows\System32\shlwapi.dll", + ]; + for _ in 0..params.iterations { + if let Some(path) = dlls.choose(rng) { + if let Ok(meta) = std::fs::metadata(path) { + black_box(meta.len()); + } + } + } +} + +fn read_system_files_varied(params: &TaskParams, rng: &mut ThreadRng) { + let paths = [ + r"C:\Windows\win.ini", + r"C:\Windows\system.ini", + r"C:\Windows\System32\drivers\etc\hosts", + r"C:\Windows\System32\drivers\etc\services", + r"C:\Windows\System32\drivers\etc\protocol", + ]; + for _ in 0..params.iterations { + if let Some(path) = paths.choose(rng) { + if let Ok(data) = std::fs::read(path) { + black_box(data.len()); + } + } + } +} + +fn enumerate_user_profile(params: &TaskParams, _rng: &mut ThreadRng) { + let _ = (|| -> std::io::Result<()> { + let profile = std::env::var("USERPROFILE").map_err(|_| { + std::io::Error::new(std::io::ErrorKind::NotFound, "USERPROFILE not set") + })?; + let dir = std::fs::read_dir(profile)?; + for (i, entry) in dir.enumerate() { + if i >= params.iterations { + break; + } + let entry = entry?; + black_box(entry.file_name()); + if let Ok(meta) = entry.metadata() { + black_box(meta.len()); + black_box(meta.is_dir()); + } + } + Ok(()) + })(); +} diff --git a/src/tasks/memory.rs b/src/tasks/memory.rs index be797c5..a58fd39 100644 --- a/src/tasks/memory.rs +++ b/src/tasks/memory.rs @@ -26,6 +26,36 @@ pub fn register() -> Vec { category: Categories::MEMORY, func: pattern_fill_verify, }, + TaskDescriptor { + name: "heap_fragmentation", + category: Categories::MEMORY, + func: heap_fragmentation, + }, + TaskDescriptor { + name: "ring_buffer_ops", + category: Categories::MEMORY, + func: ring_buffer_ops, + }, + TaskDescriptor { + name: "binary_search_repeated", + category: Categories::MEMORY, + func: binary_search_repeated, + }, + TaskDescriptor { + name: "reverse_buffer", + category: Categories::MEMORY, + func: reverse_buffer, + }, + TaskDescriptor { + name: "interleave_buffers", + category: Categories::MEMORY, + func: interleave_buffers, + }, + TaskDescriptor { + name: "scatter_gather", + category: Categories::MEMORY, + func: scatter_gather, + }, ] } @@ -71,3 +101,131 @@ fn pattern_fill_verify(params: &TaskParams, rng: &mut ThreadRng) { black_box(valid); } } + +fn heap_fragmentation(params: &TaskParams, rng: &mut ThreadRng) { + let count = params.iterations.min(500); + let mut buffers: Vec>> = Vec::with_capacity(count); + + // Allocate many small random-sized buffers + for _ in 0..count { + let size = rng.gen_range(16..=4096); + let mut buf = vec![0u8; size]; + rng.fill_bytes(&mut buf); + buffers.push(Some(buf)); + } + + // Drop roughly 50% at random + for slot in buffers.iter_mut() { + if rng.gen_bool(0.5) { + *slot = None; + } + } + + // Allocate more to fill gaps + let mut total_bytes = 0usize; + for slot in buffers.iter_mut() { + if slot.is_none() { + let size = rng.gen_range(16..=4096); + let mut buf = vec![0u8; size]; + rng.fill_bytes(&mut buf); + total_bytes += size; + *slot = Some(buf); + } else { + total_bytes += slot.as_ref().unwrap().len(); + } + } + + black_box(total_bytes); + black_box(&buffers); +} + +fn ring_buffer_ops(params: &TaskParams, rng: &mut ThreadRng) { + let size = params.buffer_size.min(1_048_576).max(1); + let mut buffer = vec![0u8; size]; + let mut write_pos: usize = 0; + let mut read_pos: usize = 0; + + for _ in 0..params.iterations { + // Write a random byte at write_pos + buffer[write_pos] = rng.gen(); + write_pos = (write_pos + 1) % size; + + // Read at read_pos + let val = buffer[read_pos]; + black_box(val); + read_pos = (read_pos + 1) % size; + } + + black_box(&buffer); +} + +fn binary_search_repeated(params: &TaskParams, rng: &mut ThreadRng) { + let elem_count = (params.buffer_size / 8).max(1); + let mut data: Vec = (0..elem_count).map(|_| rng.gen()).collect(); + data.sort_unstable(); + + let mut hits = 0usize; + for _ in 0..params.iterations { + let target: u64 = rng.gen(); + if data.binary_search(&target).is_ok() { + hits += 1; + } + } + + black_box(hits); +} + +fn reverse_buffer(params: &TaskParams, rng: &mut ThreadRng) { + let size = params.buffer_size.min(1_048_576).max(1); + let mut buf = vec![0u8; size]; + rng.fill_bytes(&mut buf); + + for _ in 0..params.iterations { + buf.reverse(); + } + + black_box(&buf); +} + +fn interleave_buffers(params: &TaskParams, rng: &mut ThreadRng) { + let half_size = (params.buffer_size / 2).max(1); + for _ in 0..params.call_depth { + let mut buf_a = vec![0u8; half_size]; + let mut buf_b = vec![0u8; half_size]; + rng.fill_bytes(&mut buf_a); + rng.fill_bytes(&mut buf_b); + + let mut interleaved = Vec::with_capacity(half_size * 2); + for i in 0..half_size { + interleaved.push(buf_a[i]); + interleaved.push(buf_b[i]); + } + + black_box(&interleaved); + } +} + +fn scatter_gather(params: &TaskParams, rng: &mut ThreadRng) { + let size = params.buffer_size.min(1_048_576).max(1); + let index_count = (size / 4).max(1); + + let mut buffer = vec![0u8; size]; + rng.fill_bytes(&mut buffer); + + for _ in 0..params.iterations.min(100) { + // Generate random index list + let indices: Vec = (0..index_count).map(|_| rng.gen_range(0..size)).collect(); + + // Gather: read at random indices into contiguous output + let gathered: Vec = indices.iter().map(|&idx| buffer[idx]).collect(); + black_box(&gathered); + + // Scatter: write from contiguous input to random indices + let input: Vec = (0..index_count).map(|_| rng.gen()).collect(); + for (i, &idx) in indices.iter().enumerate() { + buffer[idx] = input[i]; + } + } + + black_box(&buffer); +} diff --git a/src/tasks/network.rs b/src/tasks/network.rs index c63714a..cbee3ca 100644 --- a/src/tasks/network.rs +++ b/src/tasks/network.rs @@ -2,6 +2,7 @@ use crate::categories::Categories; use crate::tasks::{TaskDescriptor, TaskParams}; use rand::rngs::ThreadRng; use rand::seq::SliceRandom; +use rand::RngCore; use std::hint::black_box; use std::io::{Read, Write}; use std::net::{TcpStream, ToSocketAddrs, UdpSocket}; @@ -42,6 +43,26 @@ pub fn register() -> Vec { category: Categories::NETWORK, func: ntp_query, }, + TaskDescriptor { + name: "http_head_request", + category: Categories::NETWORK, + func: http_head_request, + }, + TaskDescriptor { + name: "tcp_connect_probe", + category: Categories::NETWORK, + func: tcp_connect_probe, + }, + TaskDescriptor { + name: "dns_varied_ports", + category: Categories::NETWORK, + func: dns_varied_ports, + }, + TaskDescriptor { + name: "http_post_discard", + category: Categories::NETWORK, + func: http_post_discard, + }, ] } @@ -55,6 +76,22 @@ fn dns_lookups(params: &TaskParams, rng: &mut ThreadRng) { "apple.com:80", "mozilla.org:80", "wikipedia.org:80", + "reddit.com:80", + "stackoverflow.com:80", + "twitter.com:80", + "linkedin.com:80", + "facebook.com:80", + "youtube.com:80", + "netflix.com:80", + "twitch.tv:80", + "spotify.com:80", + "dropbox.com:80", + "zoom.us:80", + "slack.com:80", + "discord.com:80", + "akamai.com:80", + "fastly.com:80", + "aws.amazon.com:80", ]; for _ in 0..params.iterations.min(50) { if let Some(host) = hosts.choose(rng) { @@ -72,8 +109,16 @@ fn http_get(params: &TaskParams, rng: &mut ThreadRng) { ("httpbin.org", 80, "/get"), ("ip-api.com", 80, "/json"), ("ifconfig.me", 80, "/ip"), + ("api.ipify.org", 80, "/"), + ("httpbin.org", 80, "/headers"), + ("httpbin.org", 80, "/user-agent"), + ("worldtimeapi.org", 80, "/api/ip"), + ("httpbin.org", 80, "/ip"), + ("icanhazip.com", 80, "/"), + ("checkip.amazonaws.com", 80, "/"), + ("api.myip.com", 80, "/"), ]; - for _ in 0..params.call_depth.min(3) { + for _ in 0..params.call_depth.min(5) { if let Some(&(host, port, path)) = targets.choose(rng) { let addr = format!("{}:{}", host, port); let stream = match TcpStream::connect(&*addr) { @@ -96,8 +141,21 @@ fn http_get(params: &TaskParams, rng: &mut ThreadRng) { } } -fn ntp_query(params: &TaskParams, _rng: &mut ThreadRng) { - for _ in 0..params.call_depth.min(3) { +fn ntp_query(params: &TaskParams, rng: &mut ThreadRng) { + let servers = [ + "pool.ntp.org:123", + "time.google.com:123", + "time.cloudflare.com:123", + "time.windows.com:123", + "time.apple.com:123", + "time.nist.gov:123", + "ntp.ubuntu.com:123", + ]; + for _ in 0..params.call_depth.min(5) { + let server = match servers.choose(rng) { + Some(s) => *s, + None => continue, + }; let socket = match UdpSocket::bind("0.0.0.0:0") { Ok(s) => s, Err(_) => continue, @@ -105,7 +163,7 @@ fn ntp_query(params: &TaskParams, _rng: &mut ThreadRng) { set_socket_timeouts(&socket, 3000); let mut packet = [0u8; 48]; packet[0] = 0x1B; // NTP v3, client mode - if socket.send_to(&packet, "pool.ntp.org:123").is_err() { + if socket.send_to(&packet, server).is_err() { continue; } let mut response = [0u8; 48]; @@ -113,3 +171,132 @@ fn ntp_query(params: &TaskParams, _rng: &mut ThreadRng) { black_box(&response); } } + +fn http_head_request(params: &TaskParams, rng: &mut ThreadRng) { + let targets: &[(&str, u16, &str)] = &[ + ("httpbin.org", 80, "/get"), + ("httpbin.org", 80, "/headers"), + ("httpbin.org", 80, "/ip"), + ("httpbin.org", 80, "/user-agent"), + ("ip-api.com", 80, "/json"), + ("ifconfig.me", 80, "/ip"), + ("worldtimeapi.org", 80, "/api/ip"), + ("checkip.amazonaws.com", 80, "/"), + ("icanhazip.com", 80, "/"), + ("api.ipify.org", 80, "/"), + ]; + for _ in 0..params.call_depth.min(5) { + if let Some(&(host, port, path)) = targets.choose(rng) { + let addr = format!("{}:{}", host, port); + let stream = match TcpStream::connect(&*addr) { + Ok(s) => s, + Err(_) => continue, + }; + set_socket_timeouts(&stream, 3000); + let request = format!( + "HEAD {} HTTP/1.1\r\nHost: {}\r\nConnection: close\r\n\r\n", + path, host + ); + let mut stream = stream; + if stream.write_all(request.as_bytes()).is_err() { + continue; + } + let mut response = vec![0u8; 2048]; + let _ = stream.read(&mut response); + black_box(&response); + } + } +} + +fn tcp_connect_probe(params: &TaskParams, rng: &mut ThreadRng) { + let targets: &[(&str, u16)] = &[ + ("google.com", 80), + ("google.com", 443), + ("cloudflare.com", 80), + ("cloudflare.com", 443), + ("github.com", 443), + ("microsoft.com", 80), + ("microsoft.com", 443), + ("amazon.com", 443), + ("1.1.1.1", 53), + ("8.8.8.8", 53), + ]; + for _ in 0..params.iterations.min(10) { + if let Some(&(host, port)) = targets.choose(rng) { + let addr = format!("{}:{}", host, port); + // Just connect and immediately drop — TCP handshake only + if let Ok(stream) = TcpStream::connect(&*addr) { + set_socket_timeouts(&stream, 2000); + black_box(&stream); + // stream is dropped here, sending FIN + } + } + } +} + +fn dns_varied_ports(params: &TaskParams, rng: &mut ThreadRng) { + let hosts = [ + "example.com:21", + "example.com:22", + "example.com:25", + "example.com:53", + "example.com:110", + "example.com:143", + "example.com:443", + "example.com:993", + "example.com:8080", + "example.com:8443", + "example.org:80", + "example.org:443", + "example.net:80", + "example.net:25", + "example.net:8080", + ]; + for _ in 0..params.iterations.min(40) { + if let Some(host) = hosts.choose(rng) { + let _ = host.to_socket_addrs().map(|addrs| { + for addr in addrs { + black_box(addr); + } + }); + } + } +} + +fn http_post_discard(params: &TaskParams, rng: &mut ThreadRng) { + let targets: &[(&str, u16, &str, &str)] = &[ + ("httpbin.org", 80, "/post", "POST"), + ("httpbin.org", 80, "/anything", "POST"), + ("httpbin.org", 80, "/put", "PUT"), + ("httpbin.org", 80, "/anything", "PUT"), + ("httpbin.org", 80, "/patch", "PATCH"), + ]; + + let body_size = params.buffer_size.min(1024); + let mut body = vec![0u8; body_size]; + rng.fill_bytes(&mut body); + // Encode body as hex string for a safe text payload + let body_hex: String = body.iter().map(|b| format!("{:02x}", b)).collect(); + + for _ in 0..params.call_depth.min(5) { + if let Some(&(host, port, path, method)) = targets.choose(rng) { + let addr = format!("{}:{}", host, port); + let stream = match TcpStream::connect(&*addr) { + Ok(s) => s, + Err(_) => continue, + }; + set_socket_timeouts(&stream, 3000); + let request = format!( + "{} {} HTTP/1.1\r\nHost: {}\r\nContent-Type: text/plain\r\nContent-Length: {}\r\nConnection: close\r\n\r\n{}", + method, path, host, body_hex.len(), body_hex + ); + let mut stream = stream; + if stream.write_all(request.as_bytes()).is_err() { + continue; + } + let mut response = vec![0u8; 4096]; + let _ = stream.read(&mut response); + black_box(&response); + } + } +} diff --git a/src/tasks/registry.rs b/src/tasks/registry.rs index 9978bb1..9dd7653 100644 --- a/src/tasks/registry.rs +++ b/src/tasks/registry.rs @@ -26,6 +26,36 @@ pub fn register() -> Vec { category: Categories::REGISTRY, func: read_timezone_info, }, + TaskDescriptor { + name: "read_environment_vars", + category: Categories::REGISTRY, + func: read_environment_vars, + }, + TaskDescriptor { + name: "read_network_config", + category: Categories::REGISTRY, + func: read_network_config, + }, + TaskDescriptor { + name: "read_hardware_info", + category: Categories::REGISTRY, + func: read_hardware_info, + }, + TaskDescriptor { + name: "read_font_list", + category: Categories::REGISTRY, + func: read_font_list, + }, + TaskDescriptor { + name: "read_startup_programs", + category: Categories::REGISTRY, + func: read_startup_programs, + }, + TaskDescriptor { + name: "read_file_associations", + category: Categories::REGISTRY, + func: read_file_associations, + }, ] } @@ -81,6 +111,31 @@ unsafe fn read_string_value(hkey: HKEY, value_name: &[u16]) { } } +unsafe fn enum_values(hkey: HKEY, max_values: usize) { + let mut name_buf = [0u16; 256]; + let mut data_buf = [0u8; 512]; + for i in 0..max_values as u32 { + let mut name_len = name_buf.len() as u32; + let mut data_len = data_buf.len() as u32; + let mut data_type = 0u32; + let result = RegEnumValueW( + hkey, + i, + windows::core::PWSTR(name_buf.as_mut_ptr()), + &mut name_len, + None, + Some(&mut data_type), + Some(data_buf.as_mut_ptr()), + Some(&mut data_len), + ); + if result.0 != 0 { + break; + } + black_box(&name_buf[..name_len as usize]); + black_box(&data_buf[..data_len as usize]); + } +} + fn read_installed_software(params: &TaskParams, _rng: &mut ThreadRng) { const PATH: &[u16] = &{ let mut arr = [0u16; 60]; @@ -190,6 +245,251 @@ fn read_timezone_info(params: &TaskParams, _rng: &mut ThreadRng) { } } +fn read_environment_vars(params: &TaskParams, _rng: &mut ThreadRng) { + const PATH: &[u16] = &{ + let mut arr = [0u16; 70]; + let bytes = b"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment\0"; + let mut i = 0; + while i < bytes.len() { + arr[i] = bytes[i] as u16; + i += 1; + } + arr + }; + unsafe { + let mut hkey = HKEY::default(); + let result = RegOpenKeyExW( + HKEY_LOCAL_MACHINE, + windows::core::PCWSTR(PATH.as_ptr()), + 0, + KEY_READ, + &mut hkey, + ); + if result.0 != 0 { + return; + } + + let value_names: &[&[u16]] = &[ + &encode_wide_const::<10>(b"Path\0"), + &encode_wide_const::<10>(b"TEMP\0"), + &encode_wide_const::<10>(b"TMP\0"), + &encode_wide_const::<10>(b"OS\0"), + &encode_wide_const::<30>(b"PROCESSOR_ARCHITECTURE\0"), + &encode_wide_const::<20>(b"NUMBER_OF_PROCESSORS\0"), + &encode_wide_const::<20>(b"PATHEXT\0"), + &encode_wide_const::<15>(b"ComSpec\0"), + &encode_wide_const::<15>(b"windir\0"), + ]; + for _ in 0..params.call_depth { + for name in value_names { + read_string_value(hkey, name); + } + } + + let _ = RegCloseKey(hkey); + } +} + +fn read_network_config(params: &TaskParams, _rng: &mut ThreadRng) { + const PATH: &[u16] = &{ + let mut arr = [0u16; 60]; + let bytes = b"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\0"; + let mut i = 0; + while i < bytes.len() { + arr[i] = bytes[i] as u16; + i += 1; + } + arr + }; + const INTERFACES_PATH: &[u16] = &{ + let mut arr = [0u16; 75]; + let bytes = b"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\0"; + let mut i = 0; + while i < bytes.len() { + arr[i] = bytes[i] as u16; + i += 1; + } + arr + }; + unsafe { + let mut hkey = HKEY::default(); + let result = RegOpenKeyExW( + HKEY_LOCAL_MACHINE, + windows::core::PCWSTR(PATH.as_ptr()), + 0, + KEY_READ, + &mut hkey, + ); + if result.0 == 0 { + let value_names: &[&[u16]] = &[ + &encode_wide_const::<15>(b"Hostname\0"), + &encode_wide_const::<15>(b"Domain\0"), + &encode_wide_const::<15>(b"SearchList\0"), + &encode_wide_const::<20>(b"NV Hostname\0"), + &encode_wide_const::<20>(b"ICSDomain\0"), + ]; + for _ in 0..params.call_depth { + for name in value_names { + read_string_value(hkey, name); + } + } + let _ = RegCloseKey(hkey); + } + + enum_subkeys(HKEY_LOCAL_MACHINE, INTERFACES_PATH, params.iterations); + } +} + +fn read_hardware_info(params: &TaskParams, _rng: &mut ThreadRng) { + const PATH: &[u16] = &{ + let mut arr = [0u16; 60]; + let bytes = b"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0\0"; + let mut i = 0; + while i < bytes.len() { + arr[i] = bytes[i] as u16; + i += 1; + } + arr + }; + unsafe { + let mut hkey = HKEY::default(); + let result = RegOpenKeyExW( + HKEY_LOCAL_MACHINE, + windows::core::PCWSTR(PATH.as_ptr()), + 0, + KEY_READ, + &mut hkey, + ); + if result.0 != 0 { + return; + } + + let value_names: &[&[u16]] = &[ + &encode_wide_const::<25>(b"ProcessorNameString\0"), + &encode_wide_const::<10>(b"~MHz\0"), + &encode_wide_const::<15>(b"Identifier\0"), + &encode_wide_const::<20>(b"VendorIdentifier\0"), + &encode_wide_const::<20>(b"FeatureSet\0"), + &encode_wide_const::<15>(b"Update Status\0"), + ]; + for _ in 0..params.call_depth { + for name in value_names { + read_string_value(hkey, name); + } + } + + let _ = RegCloseKey(hkey); + } +} + +fn read_font_list(params: &TaskParams, _rng: &mut ThreadRng) { + const PATH: &[u16] = &{ + let mut arr = [0u16; 60]; + let bytes = b"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts\0"; + let mut i = 0; + while i < bytes.len() { + arr[i] = bytes[i] as u16; + i += 1; + } + arr + }; + unsafe { + let mut hkey = HKEY::default(); + let result = RegOpenKeyExW( + HKEY_LOCAL_MACHINE, + windows::core::PCWSTR(PATH.as_ptr()), + 0, + KEY_READ, + &mut hkey, + ); + if result.0 != 0 { + return; + } + + enum_values(hkey, params.iterations); + + let _ = RegCloseKey(hkey); + } +} + +fn read_startup_programs(params: &TaskParams, _rng: &mut ThreadRng) { + const PATH_HKLM: &[u16] = &{ + let mut arr = [0u16; 50]; + let bytes = b"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\0"; + let mut i = 0; + while i < bytes.len() { + arr[i] = bytes[i] as u16; + i += 1; + } + arr + }; + const PATH_HKCU: &[u16] = &{ + let mut arr = [0u16; 50]; + let bytes = b"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\0"; + let mut i = 0; + while i < bytes.len() { + arr[i] = bytes[i] as u16; + i += 1; + } + arr + }; + unsafe { + // Read HKLM\...\Run + let mut hkey = HKEY::default(); + let result = RegOpenKeyExW( + HKEY_LOCAL_MACHINE, + windows::core::PCWSTR(PATH_HKLM.as_ptr()), + 0, + KEY_READ, + &mut hkey, + ); + if result.0 == 0 { + enum_values(hkey, params.iterations); + let _ = RegCloseKey(hkey); + } + + // Read HKCU\...\Run + let mut hkey = HKEY::default(); + let result = RegOpenKeyExW( + HKEY_CURRENT_USER, + windows::core::PCWSTR(PATH_HKCU.as_ptr()), + 0, + KEY_READ, + &mut hkey, + ); + if result.0 == 0 { + enum_values(hkey, params.iterations); + let _ = RegCloseKey(hkey); + } + } +} + +fn read_file_associations(params: &TaskParams, _rng: &mut ThreadRng) { + unsafe { + let mut name_buf = [0u16; 256]; + for i in 0..params.iterations as u32 { + let mut name_len = name_buf.len() as u32; + let result = RegEnumKeyExW( + HKEY_CLASSES_ROOT, + i, + windows::core::PWSTR(name_buf.as_mut_ptr()), + &mut name_len, + None, + windows::core::PWSTR::null(), + None, + None, + ); + if result.0 != 0 { + break; + } + // Only process entries starting with '.' + if name_len > 0 && name_buf[0] == b'.' as u16 { + black_box(&name_buf[..name_len as usize]); + } + } + } +} + const fn encode_wide_const(bytes: &[u8]) -> [u16; N] { let mut arr = [0u16; N]; let mut i = 0; diff --git a/src/tasks/winapi_tasks.rs b/src/tasks/winapi_tasks.rs index 265bf2a..2846217 100644 --- a/src/tasks/winapi_tasks.rs +++ b/src/tasks/winapi_tasks.rs @@ -1,11 +1,18 @@ use crate::categories::Categories; use crate::tasks::{TaskDescriptor, TaskParams}; use rand::rngs::ThreadRng; +use rand::Rng; use std::hint::black_box; +use windows::core::w; +use windows::core::PCWSTR; use windows::Win32::Foundation::*; -use windows::Win32::System::Diagnostics::ToolHelp::*; -use windows::Win32::System::SystemInformation::*; +use windows::Win32::Storage::FileSystem::*; use windows::Win32::System::DataExchange::*; +use windows::Win32::System::Diagnostics::ToolHelp::*; +use windows::Win32::System::LibraryLoader::*; +use windows::Win32::System::Memory::*; +use windows::Win32::System::SystemInformation::*; +use windows::Win32::System::Threading::*; use windows::Win32::UI::WindowsAndMessaging::*; pub fn register() -> Vec { @@ -30,9 +37,71 @@ pub fn register() -> Vec { category: Categories::WINAPI, func: read_clipboard, }, + TaskDescriptor { + name: "get_system_metrics", + category: Categories::WINAPI, + func: get_system_metrics, + }, + TaskDescriptor { + name: "get_foreground_window_info", + category: Categories::WINAPI, + func: get_foreground_window_info, + }, + TaskDescriptor { + name: "get_cursor_position", + category: Categories::WINAPI, + func: get_cursor_position, + }, + TaskDescriptor { + name: "get_desktop_window_info", + category: Categories::WINAPI, + func: get_desktop_window_info, + }, + TaskDescriptor { + name: "get_logical_drives_info", + category: Categories::WINAPI, + func: get_logical_drives_info, + }, + TaskDescriptor { + name: "get_volume_info", + category: Categories::WINAPI, + func: get_volume_info, + }, + TaskDescriptor { + name: "get_disk_free_space", + category: Categories::WINAPI, + func: get_disk_free_space, + }, + TaskDescriptor { + name: "find_files_pattern", + category: Categories::WINAPI, + func: find_files_pattern, + }, + TaskDescriptor { + name: "get_module_handles", + category: Categories::WINAPI, + func: get_module_handles, + }, + TaskDescriptor { + name: "virtual_query_memory", + category: Categories::WINAPI, + func: virtual_query_memory, + }, + TaskDescriptor { + name: "get_system_directories", + category: Categories::WINAPI, + func: get_system_directories, + }, + TaskDescriptor { + name: "get_process_thread_ids", + category: Categories::WINAPI, + func: get_process_thread_ids, + }, ] } +// ── Existing tasks ────────────────────────────────────────────────────────── + unsafe extern "system" fn enum_window_callback(hwnd: HWND, lparam: LPARAM) -> BOOL { let windows = &mut *(lparam.0 as *mut Vec); windows.push(hwnd); @@ -107,3 +176,284 @@ fn read_clipboard(params: &TaskParams, _rng: &mut ThreadRng) { } } } + +// ── New tasks ─────────────────────────────────────────────────────────────── + +fn get_system_metrics(params: &TaskParams, rng: &mut ThreadRng) { + const METRIC_INDICES: [i32; 10] = [ + 0, // SM_CXSCREEN + 1, // SM_CYSCREEN + 2, // SM_CXVSCROLL + 3, // SM_CYHSCROLL + 4, // SM_CYCAPTION + 43, // SM_CMOUSEBUTTONS + 80, // SM_CMONITORS + 59, // SM_CXMAXTRACK + 60, // SM_CYMAXTRACK + 67, // SM_CLEANBOOT + ]; + + unsafe { + for _ in 0..params.iterations { + let idx = rng.gen_range(0..METRIC_INDICES.len()); + let metric = METRIC_INDICES[idx]; + let value = GetSystemMetrics(SYSTEM_METRICS_INDEX(metric)); + black_box(value); + } + } +} + +fn get_foreground_window_info(params: &TaskParams, _rng: &mut ThreadRng) { + unsafe { + for _ in 0..params.call_depth { + let hwnd = GetForegroundWindow(); + if hwnd.0 == std::ptr::null_mut() { + continue; + } + let mut text = [0u16; 256]; + GetWindowTextW(hwnd, &mut text); + black_box(&text); + + let mut rect = RECT::default(); + let _ = GetWindowRect(hwnd, &mut rect); + black_box(rect.left); + black_box(rect.top); + black_box(rect.right); + black_box(rect.bottom); + } + } +} + +fn get_cursor_position(params: &TaskParams, _rng: &mut ThreadRng) { + unsafe { + for _ in 0..params.iterations { + let mut point = POINT::default(); + let _ = GetCursorPos(&mut point); + black_box(point.x); + black_box(point.y); + } + } +} + +fn get_desktop_window_info(params: &TaskParams, _rng: &mut ThreadRng) { + unsafe { + for _ in 0..params.call_depth { + let hwnd = GetDesktopWindow(); + + let mut rect = RECT::default(); + let _ = GetWindowRect(hwnd, &mut rect); + black_box(rect.left); + black_box(rect.top); + black_box(rect.right); + black_box(rect.bottom); + + let mut client_rect = RECT::default(); + let _ = GetClientRect(hwnd, &mut client_rect); + black_box(client_rect.right); + black_box(client_rect.bottom); + + let mut text = [0u16; 256]; + GetWindowTextW(hwnd, &mut text); + black_box(&text); + } + } +} + +fn get_logical_drives_info(params: &TaskParams, _rng: &mut ThreadRng) { + unsafe { + let mask = GetLogicalDrives(); + if mask == 0 { + return; + } + black_box(mask); + + for bit in 0..26u32 { + if mask & (1 << bit) == 0 { + continue; + } + let letter = (b'A' + bit as u8) as u16; + let path: [u16; 4] = [letter, ':' as u16, '\\' as u16, 0]; + let drive_type = GetDriveTypeW(PCWSTR(path.as_ptr())); + black_box(drive_type); + } + + // Repeat the iteration to burn more cycles based on params + for _ in 1..params.call_depth { + let m = GetLogicalDrives(); + black_box(m); + } + } +} + +fn get_volume_info(params: &TaskParams, _rng: &mut ThreadRng) { + unsafe { + for _ in 0..params.call_depth { + let mut volume_name = [0u16; 260]; + let mut serial_number: u32 = 0; + let mut max_component_length: u32 = 0; + let mut fs_flags: u32 = 0; + let mut fs_name = [0u16; 260]; + + let ok = GetVolumeInformationW( + w!("C:\\"), + Some(&mut volume_name), + Some(&mut serial_number), + Some(&mut max_component_length), + Some(&mut fs_flags), + Some(&mut fs_name), + ); + if ok.is_ok() { + black_box(&volume_name); + black_box(serial_number); + black_box(max_component_length); + black_box(fs_flags); + black_box(&fs_name); + } + } + } +} + +fn get_disk_free_space(params: &TaskParams, _rng: &mut ThreadRng) { + unsafe { + for _ in 0..params.call_depth { + let mut free_bytes_available: u64 = 0; + let mut total_bytes: u64 = 0; + let mut total_free_bytes: u64 = 0; + + let ok = GetDiskFreeSpaceExW( + w!("C:\\"), + Some(&mut free_bytes_available as *mut u64), + Some(&mut total_bytes as *mut u64), + Some(&mut total_free_bytes as *mut u64), + ); + if ok.is_ok() { + black_box(free_bytes_available); + black_box(total_bytes); + black_box(total_free_bytes); + } + } + } +} + +fn find_files_pattern(params: &TaskParams, _rng: &mut ThreadRng) { + unsafe { + let mut find_data = WIN32_FIND_DATAW::default(); + let handle = FindFirstFileW(w!("C:\\Windows\\System32\\*.dll"), &mut find_data); + let handle = match handle { + Ok(h) => h, + Err(_) => return, + }; + + black_box(&find_data.cFileName); + black_box(find_data.nFileSizeHigh); + black_box(find_data.nFileSizeLow); + + for _ in 1..params.iterations { + if FindNextFileW(handle, &mut find_data).is_err() { + break; + } + black_box(&find_data.cFileName); + black_box(find_data.nFileSizeHigh); + black_box(find_data.nFileSizeLow); + } + + let _ = FindClose(handle); + } +} + +fn get_module_handles(params: &TaskParams, rng: &mut ThreadRng) { + let dll_names: &[PCWSTR] = &[ + w!("kernel32.dll"), + w!("ntdll.dll"), + w!("user32.dll"), + w!("advapi32.dll"), + w!("ws2_32.dll"), + w!("shell32.dll"), + w!("ole32.dll"), + w!("crypt32.dll"), + w!("bcrypt.dll"), + w!("msvcrt.dll"), + w!("gdi32.dll"), + w!("combase.dll"), + ]; + + unsafe { + for _ in 0..params.iterations { + let idx = rng.gen_range(0..dll_names.len()); + let result = GetModuleHandleW(dll_names[idx]); + match result { + Ok(h) => { + black_box(h); + } + Err(_) => { + black_box(0u32); + } + } + } + } +} + +fn virtual_query_memory(params: &TaskParams, _rng: &mut ThreadRng) { + unsafe { + let mut addr: usize = 0; + let info_size = std::mem::size_of::(); + + for _ in 0..params.iterations { + let mut info = MEMORY_BASIC_INFORMATION::default(); + let result = VirtualQuery( + Some(addr as *const std::ffi::c_void), + &mut info, + info_size, + ); + if result == 0 { + break; + } + black_box(info.BaseAddress); + black_box(info.RegionSize); + black_box(info.State); + black_box(info.Type); + + // Advance to the next region + let region_size = if info.RegionSize == 0 { + // Avoid infinite loop on zero-size region + 4096 + } else { + info.RegionSize + }; + addr = match addr.checked_add(region_size) { + Some(a) => a, + None => break, + }; + } + } +} + +fn get_system_directories(params: &TaskParams, _rng: &mut ThreadRng) { + unsafe { + for _ in 0..params.call_depth { + let mut sys_dir = [0u16; 260]; + let len = GetSystemDirectoryW(Some(&mut sys_dir)); + if len > 0 { + black_box(&sys_dir[..len as usize]); + } + + let mut win_dir = [0u16; 260]; + let len = GetWindowsDirectoryW(Some(&mut win_dir)); + if len > 0 { + black_box(&win_dir[..len as usize]); + } + } + } +} + +fn get_process_thread_ids(params: &TaskParams, _rng: &mut ThreadRng) { + unsafe { + for _ in 0..params.iterations { + let pid = GetCurrentProcessId(); + black_box(pid); + + let tid = GetCurrentThreadId(); + black_box(tid); + } + } +}