
गतिशील रूप से मनमाना अनमैनेज्ड कोड लागू करें
यह Dinvoke का Rust पोर्ट है। DInvoke_rs का उपयोग कई उद्देश्यों के लिए किया जा सकता है, जैसे PE पार्सिंग, डायनेमिक एक्सपोर्टेड फ़ंक्शन रिज़ॉल्यूशन, रनटाइम पर PE प्लगइन्स को डायनेमिक रूप से लोड करना, API हुक से बचाव, और बहुत कुछ।
Features:
सारा श्रेय इस टूल के मूल C# इम्प्लीमेंटेशन के रचनाकारों को जाता है:
इस क्रेट को अपने प्रोजेक्ट में इम्पोर्ट करने के लिए अपने cargo.toml में निम्न पंक्ति जोड़ें:```rust
[dependencies]
dinvoke_rs = "0.2.2"
# उदाहरण
## निर्यातित APIs का पता लगाना
नीचे दिया गया उदाहरण दिखाता है कि किसी DLL के एक्सपोर्ट्स को गतिशील रूप से खोजने और कॉल करने के लिए DInvoke_rs का उपयोग कैसे करें (इस मामले में `ntdll.dll`)।
1) ntdll का बेस एड्रेस प्राप्त करें।
2) नाम से `ntdll.dll` के भीतर एक एक्सपोर्ट खोजने के लिए `get_function_address()` का उपयोग करें। यह dll के EAT को स्कैन और पार्स करके पूरा किया जाता है।
3) आप `get_function_address_by_ordinal()` को कॉल करके ऑर्डिनल द्वारा भी एक एक्सपोर्ट खोज सकते हैं।```rust
fn main() {
// Dynamically obtain ntdll.dll's base address.
let ntdll = dinvoke_rs::dinvoke::get_module_base_address("ntdll.dll");
if ntdll != 0
{
println!("ntdll.dll base address is 0x{:X}", ntdll);
// Dynamically obtain the address of a function by name.
let nt_create_thread = dinvoke_rs::dinvoke::get_function_address(ntdll, "NtCreateThread");
if nt_create_thread != 0
{
println!("NtCreateThread is at address 0x{:X}", nt_create_thread);
}
// Dynamically obtain the address of a function by ordinal.
let ordinal_8 = dinvoke_rs::dinvoke::get_function_address_by_ordinal(ntdll, 8);
if ordinal_8 != 0
{
println!("The function with ordinal 8 is located at addresss 0x{:X}", ordinal_8);
}
}
}
नीचे दिए गए उदाहरण में, हम वर्तमान प्रक्रिया के टोकन के लिए SeDebugPrivilege सक्षम करने हेतु RtlAdjustPrivilege को गतिशील रूप से कॉल करने के लिए DInvoke_rs का उपयोग करते हैं। इस प्रकार का निष्पादन Win32 में उपस्थित किसी भी API हुक को बायपास कर देगा। साथ ही, यह अंतिम PE के Import Address Table पर कोई प्रविष्टि नहीं बनाएगा, जिससे PE के व्यवहार का पता लगाना बिना उसे निष्पादित किए और अधिक कठिन हो जाता है।```rust
fn main() {
// Dynamically obtain ntdll.dll's base address.
let ntdll = dinvoke_rs::dinvoke::get_module_base_address("ntdll.dll");
if ntdll != 0
{
unsafe
{
let func_ptr: unsafe extern "system" fn (u32, u8, u8, *mut u8) -> i32; // Function header available at data::RtlAdjustPrivilege
let ret: Option<i32>; // RtlAdjustPrivilege returns an NSTATUS value, which in Rust can be represented as an i32
let privilege: u32 = 20; // This value matches with SeDebugPrivilege
let enable: u8 = 1; // Enable the privilege
let current_thread: u8 = 0; // Enable the privilege for the current process, not only for the current thread
let e = u8::default(); // https://github.com/Kudaes/rust_tips_and_tricks/tree/main#transmute
let enabled: *mut u8 = std::mem::transmute(&e);
dinvoke_rs::dinvoke::dynamic_invoke!(ntdll,"RtlAdjustPrivilege",func_ptr,ret,privilege,enable,current_thread,enabled);
match ret {
Some(x) =>
if x == 0 { println!("NTSTATUS == Success. Privilege enabled."); }
else { println!("[x] NTSTATUS == {:X}", x as u32); },
None => panic!("[x] Error!"),
}
}
}
}
## अप्रत्यक्ष syscall निष्पादित करना
अगले उदाहरण में, हम फ़ंक्शन `NtQueryInformationProcess` के अनुरूप syscall निष्पादित करने के लिए DInvoke_rs का उपयोग करते हैं। चूँकि मैक्रो `execute_syscall!()` वांछित syscall करने के लिए आवश्यक shellcode को गतिशील रूप से आवंटित और निष्पादित करता है, `ntdll.dll` में मौजूद सभी हुक्स बायपास हो जाते हैं। syscall के लौटते ही आवंटित मेमोरी रिलीज़ हो जाती है, जिससे निष्पादन अनुमति वाले मेमोरी पेजों की स्थायी उपस्थिति से बचा जा सके।```rust
use std::mem::size_of;
use windows::Win32::System::Threading::{GetCurrentProcess, PROCESS_BASIC_INFORMATION};
use dinvoke_rs::data::{NtQueryInformationProcess, PVOID};
fn main() {
unsafe
{
let function_type:NtQueryInformationProcess;
let ret: Option<i32>; //NtQueryInformationProcess returns a NTSTATUS, which is a i32.
let handle = GetCurrentProcess();
let p = PROCESS_BASIC_INFORMATION::default();
let process_information: PVOID = std::mem::transmute(&p);
let r = u32::default();
let return_length: *mut u32 = std::mem::transmute(&r);
dinvoke_rs::dinvoke::execute_syscall!(
"NtQueryInformationProcess",
function_type,
ret,
handle,
0,
process_information,
size_of::<PROCESS_BASIC_INFORMATION>() as u32,
return_length
);
let pbi: *mut PROCESS_BASIC_INFORMATION;
match ret {
Some(x) =>
if x == 0 {
pbi = std::mem::transmute(process_information);
let pbi = *pbi;
println!("The Process Environment Block base address is 0x{:X}", pbi.PebBaseAddress as u64);
},
None => println!("[x] Error executing direct syscall for NtQueryInformationProcess."),
}
}
}
इस उदाहरण में, DInvoke_rs का उपयोग ntdll.dll की एक नई कॉपी को मैन्युअल रूप से मैप करने के लिए किया जाता है, बिना किसी EDR हुक के। फिर उस नई ntdll.dll कॉपी का उपयोग किसी भी वांछित फ़ंक्शन को निष्पादित करने के लिए किया जा सकता है।
यह मैनुअल मैप मेमोरी से भी निष्पादित किया जा सकता है (उस स्थिति में manually_map_module() का उपयोग करें), जिससे क्लासिक रिफ्लेक्टिव DLL इंजेक्शन करना संभव हो जाता है।```rust
use dinvoke_rs::data::PeMetadata;
fn main() {
unsafe
{
let ntdll: (PeMetadata, usize) = dinvoke_rs::manualmap::read_and_map_module(r"C:\Windows\System32\ntdll.dll", true, false).unwrap();