use std::ffi::c_void;
use windows::{
Win32::{
Foundation::CloseHandle,
System::{
Diagnostics::Debug::WriteProcessMemory,
LibraryLoader::GetModuleHandleA,
Memory::{VirtualAllocEx, VirtualFreeEx, MEM_RELEASE, PAGE_READWRITE},
},
},
};
use super::helpers::open_process_full;
use super::DllInjectorError;
#[derive(Debug)]
pub struct DiagnosticReport {
pub pid: u32,
pub process_accessible: bool,
pub kernel32_loaded: bool,
pub memory_allocatable: bool,
pub memory_writable: bool,
}
impl DiagnosticReport {
pub fn is_injection_feasible(&self) -> bool {
self.process_accessible
&& self.kernel32_loaded
&& self.memory_allocatable
&& self.memory_writable
}
pub fn summary(&self) -> String {
let mut lines = Vec::new();
lines.push(format!("🔍 Injection Diagnostic Report for PID {}:", self.pid));
lines.push(String::from("─────────────────────────────────────────"));
lines.push(format!(
"Process Accessible: {}",
if self.process_accessible { "✅ Yes" } else { "❌ No" }
));
lines.push(format!(
"kernel32.dll Loaded: {}",
if self.kernel32_loaded { "✅ Yes" } else { "❌ No" }
));
lines.push(format!(
"Memory Allocatable: {}",
if self.memory_allocatable { "✅ Yes" } else { "❌ No" }
));
lines.push(format!(
"Memory Writable: {}",
if self.memory_writable { "✅ Yes" } else { "❌ No" }
));
lines.push(String::from("─────────────────────────────────────────"));
if self.is_injection_feasible() {
lines.push(String::from("✅ Injection should succeed!"));
} else {
lines.push(String::from("❌ Injection will likely fail. Issues:"));
if !self.process_accessible {
lines.push(String::from(" • Cannot open process - Run as Administrator"));
}
if !self.kernel32_loaded {
lines.push(String::from(" • kernel32.dll not found - Process may be protected"));
}
if !self.memory_allocatable {
lines.push(String::from(" • Cannot allocate memory - Insufficient permissions"));
}
if !self.memory_writable {
lines.push(String::from(" • Cannot write memory - Anti-injection protection?"));
}
}
lines.join("\n")
}
}
pub fn diagnose_injection(pid: u32) -> Result<DiagnosticReport, DllInjectorError> {
let mut report = DiagnosticReport {
pid,
process_accessible: false,
kernel32_loaded: false,
memory_allocatable: false,
memory_writable: false,
};
match open_process_full(pid) {
Ok(handle) => {
report.process_accessible = true;
unsafe {
if GetModuleHandleA(windows::core::PCSTR::from_raw("kernel32.dll\0".as_ptr())).is_ok() {
report.kernel32_loaded = true;
}
let test_size = 64;
let test_addr = VirtualAllocEx(handle, None, test_size, windows::Win32::System::Memory::MEM_COMMIT, PAGE_READWRITE);
if !test_addr.is_null() {
report.memory_allocatable = true;
let test_data: u32 = 0xDEADBEEF;
let mut bytes_written = 0;
let write_ok = WriteProcessMemory(
handle,
test_addr,
&test_data as *const u32 as *const c_void,
4,
Some(&mut bytes_written),
).is_ok();
report.memory_writable = write_ok && bytes_written == 4;
let _ = VirtualFreeEx(handle, test_addr, 0, MEM_RELEASE);
}
let _ = CloseHandle(handle);
}
}
Err(_) => {
report.process_accessible = false;
}
}
Ok(report)
}