diff --git a/.gitignore b/.gitignore
index 3ca43ae..1246f29 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,3 +14,5 @@ Cargo.lock
# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb
+# IntelliJ IDEA
+.idea
\ No newline at end of file
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..8bada2c
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "laa_toggle"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
diff --git a/laa_toggle.iml b/laa_toggle.iml
new file mode 100644
index 0000000..2fecef3
--- /dev/null
+++ b/laa_toggle.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..69b990d
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,76 @@
+use std::env;
+use std::error::Error;
+use std::fs::OpenOptions;
+use std::io::stdin;
+use std::os::windows::fs::FileExt;
+use std::process::{Command, exit};
+
+fn pause() {
+ // call pause command to keep the console open, so the user can read infos/errors
+ Command::new("cmd").args(&["/C", "pause"]).spawn().expect("failed to execute pause command");
+}
+
+fn abort(message: &str, error: Option<&dyn Error>) -> ! {
+ if let Some(error) = error {
+ println!("{:}", error);
+ }
+ println!("{}. Abort!", message);
+ pause();
+ exit(1);
+}
+
+fn main() {
+ const IMAGE_DOS_HEADER_E_LFANEW: u64 = 0x3C;
+ const IMAGE_FILE_LARGE_ADDRESS_AWARE: u8 = 0x20;
+ const IMAGE_FILE_MACHINE_AMD64: u16 = 0x8664;
+ const IMAGE_FILE_MACHINE_I386: u16 = 0x14C;
+ let mut buffer2 = [0u8; 2];
+ let mut buffer4 = [0u8; 4];
+ let args= env::args().collect::>();
+ let path = match args.get(1) {
+ None => abort("Didn't receive path to EXE as argument", None),
+ Some(path) => path
+ };
+ if !path.to_lowercase().ends_with(".exe") {
+ abort("Argument is not an EXE", None);
+ }
+ println!("Working on: {}", path);
+ let file = match OpenOptions::new().read(true).write(true).open(path) {
+ Ok(file) => file,
+ Err(error) => abort("Failed to open EXE in read/write mode", Some(&error))
+ };
+ if let Err(error) = file.seek_read(&mut buffer4, IMAGE_DOS_HEADER_E_LFANEW) {
+ abort("Failed to read e_lfanew of MS DOS stub", Some(&error));
+ }
+ let address_coff_machine = (u32::from_le_bytes(buffer4) + 0x4) as u64; // real data starts after "PE\0\0" string
+ if let Err(error) = file.seek_read(&mut buffer2, address_coff_machine) {
+ abort("Failed to read Machine of PE header", Some(&error));
+ }
+ let machine = u16::from_le_bytes(buffer2);
+ match machine {
+ IMAGE_FILE_MACHINE_I386 => {},
+ IMAGE_FILE_MACHINE_AMD64 => abort("This binary is 64 bit - LAA is not needed", None),
+ _ => abort(&*format!("Unsupported machine type: {}", machine), None)
+ }
+ let address_coff_characteristics = address_coff_machine + 0x12;
+ if let Err(error) = file.seek_read(&mut buffer2, address_coff_characteristics) {
+ abort("Failed to read Characteristics from PE header", Some(&error));
+ }
+ let is_laa_enabled = buffer2[0] & IMAGE_FILE_LARGE_ADDRESS_AWARE != 0;
+ println!("LAA currently enabled: {}\nDo you want to change that [y/n]?", is_laa_enabled);
+ let mut input = String::new();
+ if let Err(error) = stdin().read_line(&mut input) {
+ abort("Failed to read user input from stdin", Some(&error));
+ }
+ match input.to_lowercase().trim() {
+ "y" => {},
+ "n" => return,
+ _ => abort("Invalid input", None)
+ }
+ buffer2[0] ^= IMAGE_FILE_LARGE_ADDRESS_AWARE; // flip bit
+ if let Err(error) = file.seek_write(buffer2.as_slice(), address_coff_characteristics) {
+ abort("Failed to write modification back to file", Some(&error));
+ }
+ println!("Modification written to disk.");
+ pause();
+}