Skip to content

Latest commit

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

memexec

A library for loading and executing PE (Portable Executable) from memory without ever touching the disk

This is my own version for specific projects.
Original crate: https://crates.io/crates/memexec

Features

  • Applicable to EXE and DLL (except .NET assembly)
  • Cross-architecture, applicable to x86 and x86-64
  • Zero-dependency
  • Contains a simple, zero-copy PE parser submodule
  • Provides an IAT hooking interface

Install

# Cargo.toml
[dependencies]
git = "https://github.com/DmitrijVC/memexec"memexec = "0.3"

Usage

Execute from memory

⚠The architecture of target program must be same as current process, otherwise an error will occur

use memexec;use std::fs::File;use std::io::Read;/***********************************************************//* EXE *//***********************************************************/letmut buf = Vec::new();File::open("./test.exe").unwrap().read_to_end(&mut buf).unwrap();unsafe{// If you need to pass command line parameters,// try to modify PEB's command line buffer// Or use `memexec_exe_with_hooks` to hook related functions (see below)
memexec::memexec_exe(&buf).unwrap();}/***********************************************************//* DLL *//***********************************************************/letmut buf = Vec::new();File::open("./test.dll").unwrap().read_to_end(&mut buf).unwrap();use memexec::peloader::def::DLL_PROCESS_ATTACH;unsafe{// DLL's entry point is DllMainmemexec_dll(&buf,0as_,DLL_PROCESS_ATTACH,0as_).unwrap();}

IAT hooking

Add the hook feature in Cargo.toml

[dependencies]
memexec = { git = "https://github.com/DmitrijVC/memexec", version="0.3", features=[ "hook" ] }

Hook the __wgetmainargs function (see example/__wgetmainargs_hook.rs)

letmut buf = Vec::new();File::open("./test.x64.exe").unwrap().read_to_end(&mut buf).unwrap();letmut hooks = HashMap::new();unsafe{
hooks.insert("msvcrt.dll!__wgetmainargs".into(),
mem::transmute::<extern"win64"fn(_, _, _, _, _) -> _,_>(__wgetmainargs),);
memexec::memexec_exe_with_hooks(&buf,&hooks).unwrap();}

The definition of __wgetmainargs (notice the calling convention on different archtectures):

// https://docs.microsoft.com/en-us/cpp/c-runtime-library/getmainargs-wgetmainargs?view=msvc-160/*int __wgetmainargs ( int *_Argc, wchar_t ***_Argv, wchar_t ***_Env, int _DoWildCard, _startupinfo * _StartInfo)*/#[cfg(all(target_arch = "x86_64", target_os = "windows"))]extern"win64"fn__wgetmainargs(_Argc:*muti32,_Argv:*mut*const*constu16,_Env:*constc_void,_DoWildCard:i32,_StartInfo:*constc_void,) -> i32{unsafe{*_Argc = 2;let a0:Vec<_> = "program_name\0".chars().map(|c| (c asu16).to_le()).collect();let a1:Vec<_> = "token::whoami\0".chars().map(|c| (c asu16).to_le()).collect();*_Argv = [a0.as_ptr(), a1.as_ptr()].as_ptr();// Avoid calling destructor
mem::forget(a0);
mem::forget(a1);}0}

PE parser

PE parser could parse programs which have different architectures from current process

use memexec::peparser::PE;// Zero copy// Make sure that the lifetime of `buf` is longer than `pe`let pe = PE::new(&buf);println!("{:?}", pe);

TODO

  • Replace LoadLibrary with calling load_pe_into_mem recursively

  • Replace GetProcAddress with self-implemented LdrpSnapThunk, so as to support resolving proc address by IMAGE_IMPORT_BY_NAME.Hint

License

The GPLv3 license

About

A library for loading and executing PE (Portable Executable) from memory without ever touching the disk

Resources

Stars

9 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages