Skip to content

Commit

Permalink
feat: shadow copy
Browse files Browse the repository at this point in the history
  • Loading branch information
thewh1teagle committed Apr 21, 2024
1 parent e7f30c2 commit 6297041
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 12 deletions.
3 changes: 3 additions & 0 deletions rookie-rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ sha1 = "0.10"
[target.'cfg(windows)'.dependencies]
base64 = "0.22"
libesedb = "0.2"
rawcopy-rs-next = "0.1.3"
privilege = "0.3.0"
rand = "0.8.5"
windows = { version = "0.51", features = [
"Win32_Security_Cryptography",
"Win32_Foundation",
Expand Down
3 changes: 1 addition & 2 deletions rookie-rs/examples/logging/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use rookie::chrome;
fn main() {
pretty_env_logger::init();
let cookies = chrome(None).unwrap();
let cookies = rookie::brave(None).unwrap();
println!("Found {} cookies", cookies.len());
}
2 changes: 1 addition & 1 deletion rookie-rs/examples/simple.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
fn main() {
let cookies = rookie::brave(None).unwrap();
println!("{cookies:?}");
println!("Found {} cookies!", cookies.len());
}
43 changes: 34 additions & 9 deletions rookie-rs/src/browser/chromium.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use crate::common::{date, enums::*, sqlite};
use crate::{
common::{date, enums::*, sqlite},
windows,
};
use eyre::{bail, Result};
use std::path::PathBuf;

Expand All @@ -25,8 +28,6 @@ pub fn chromium_based(
db_path: PathBuf,
domains: Option<Vec<&str>>,
) -> Result<Vec<Cookie>> {
// Use DPAPI

let content = std::fs::read_to_string(key)?;
let key_dict: serde_json::Value =
serde_json::from_str(content.as_str()).context("Can't read json file")?;
Expand Down Expand Up @@ -202,18 +203,42 @@ fn decrypt_encrypted_value(
bail!("decrypt_encrypted_value failed")
}

#[cfg(target_os = "windows")]
fn unlock_file(mut path: PathBuf) -> Result<PathBuf> {
let mut shadow_copy_success = false;
// Shadow copy cookies file so we can read session cookies
// Admin rights required
if privilege::user::privileged() {
log::debug!("Admin rights detected");
if let Ok(temp_dir) = windows::shadow_copy::temp_folder(".tmp", "", 10) {
let result = windows::shadow_copy::shadow_copy(path.clone(), temp_dir.clone().to_path_buf());
log::debug!("shadow copy result: {:?}", result);
if result.is_ok() {
shadow_copy_success = true;
path = temp_dir.join(path.file_name().unwrap());
}
}
}

// Elegantly restart the process which lock the cookies file (And unlock it) using restart manager API
if !shadow_copy_success {
log::warn!("Unlocking Chrome database... This may take a while (sometimes up to a minute)");
unsafe {
crate::windows::file_unlock::release_file_lock(path.to_str().unwrap());
}
}
Ok(path)
}

fn query_cookies(
keys: Vec<Vec<u8>>,
db_path: PathBuf,
mut db_path: PathBuf,
domains: Option<Vec<&str>>,
) -> Result<Vec<Cookie>> {
// In windows unlock file locking
#[cfg(target_os = "windows")]
{
let db_path_str = db_path.to_str().context("Can't convert db path to str")?;
log::warn!("Unlocking Chrome database... This may take a while (sometimes up to a minute)");
unsafe {
crate::windows::file_unlock::release_file_lock(db_path_str);
}
db_path = unlock_file(db_path)?;
}

log::info!(
Expand Down
1 change: 1 addition & 0 deletions rookie-rs/src/windows/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod config;
pub(crate) mod dpapi;
pub(crate) mod file_unlock;
pub(crate) mod shadow_copy;
44 changes: 44 additions & 0 deletions rookie-rs/src/windows/shadow_copy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use eyre::{bail, Context, Result};
use privilege::user::privileged;
use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};
use std::path::PathBuf;

/// Create temp folder and return path
pub fn temp_folder(prefix: &str, suffix: &str, rand_len: usize) -> Result<PathBuf> {
let random_string: String = thread_rng()
.sample_iter(&Alphanumeric)
.take(rand_len)
.map(char::from) // From link above, this is needed in later versions
.collect();
let name = format!("{}{}{}", prefix, random_string, suffix);
let tmp = std::env::temp_dir();
let temp_path = tmp.join(name);
std::fs::create_dir(temp_path.clone())?;
log::trace!("created dir {}", temp_path.clone().display());
Ok(temp_path)
}

/// dst should be directory
pub fn shadow_copy(src: PathBuf, dst: PathBuf) -> Result<()> {
if !src.exists() {
bail!("Source file not exists: {}", src.clone().display())
}
if !privileged() {
bail!("No admin rights")
}
log::info!(
"Creating shadow copy to cookies file from {} to {}",
src.display(),
dst.display()
);
rawcopy_rs_next::rawcopy(src.clone().to_str().unwrap(), dst.to_str().unwrap())
.map_err(|err| eyre::eyre!(Box::new(err)))
.context(format!(
"Can't shadow copy from {} to {}",
src.display(),
dst.display(),
))?;

Ok(())
}

0 comments on commit 6297041

Please sign in to comment.