Skip to content

Commit dbad1f7

Browse files
committed
Initial commit
0 parents  commit dbad1f7

File tree

22 files changed

+811
-0
lines changed

22 files changed

+811
-0
lines changed

.gitignore

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Generated by Cargo
2+
# will have compiled files and executables
3+
debug/
4+
target/
5+
6+
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
7+
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
8+
Cargo.lock
9+
10+
# These are backup files generated by rustfmt
11+
**/*.rs.bk
12+
13+
# MSVC Windows builds of rustc generate these, which store debugging information
14+
*.pdb

ExportTracer/.cargo/config

Whitespace-only changes.

ExportTracer/.gitignore

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Generated by Cargo
2+
# will have compiled files and executables
3+
debug/
4+
target/
5+
6+
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
7+
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
8+
Cargo.lock
9+
10+
# These are backup files generated by rustfmt
11+
**/*.rs.bk
12+
13+
# MSVC Windows builds of rustc generate these, which store debugging information
14+
*.pdb

ExportTracer/Cargo.toml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[package]
2+
name = "exporttracer"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[lib]
9+
crate-type = ["cdylib"]
10+
11+
[dependencies]
12+
dinvoke_rs= "0.1.4"

ExportTracer/file.def

Whitespace-only changes.

ExportTracer/src/lib.rs

Whitespace-only changes.

Generator/.gitignore

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Generated by Cargo
2+
# will have compiled files and executables
3+
debug/
4+
target/
5+
6+
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
7+
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
8+
Cargo.lock
9+
10+
# These are backup files generated by rustfmt
11+
**/*.rs.bk
12+
13+
# MSVC Windows builds of rustc generate these, which store debugging information
14+
*.pdb

Generator/Cargo.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[package]
2+
name = "generator"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]
9+
dinvoke_rs = "0.1.4"
10+
getopts = "0.2"

Generator/src/main.rs

Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
1+
use std::{env, fs::{self}};
2+
use getopts::Options;
3+
4+
static TEMPLATE1: &str = r#"
5+
#[no_mangle]
6+
fn {FUNC_NAME}()
7+
{
8+
unsafe
9+
{
10+
asm!(
11+
"push rcx",
12+
"push rdx",
13+
"push r8",
14+
"push r9",
15+
"sub rsp, 0x28",
16+
"mov rcx, {INDEX}",
17+
"call {}",
18+
"add rsp, 0x28",
19+
"pop r9",
20+
"pop r8",
21+
"pop rdx",
22+
"pop rcx",
23+
"jmp rax",
24+
sym gateway,
25+
options(nostack)
26+
);
27+
}
28+
}
29+
"#;
30+
static TEMPLATE2: &str = r#"{NUM} => {"{NAME}".to_string()}"#;
31+
32+
static TEMPLATE3: &str = r#"#[no_mangle]
33+
fn {FORWARDED_NAME}() {
34+
}"#;
35+
36+
37+
fn main()
38+
{
39+
40+
let args: Vec<String> = env::args().collect();
41+
let program = args[0].clone();
42+
let mut opts = Options::new();
43+
opts.reqopt("m", "mode", "Create a dll to trace (trace) or proxy (proxy) called exports.", "");
44+
opts.optflag("h", "help", "Print this help menu.");
45+
opts.reqopt("p", "path", "Path to the original dll.", "");
46+
opts.optopt("e", "export", "Exported function in which to execute the payload.", "");
47+
opts.optopt("l", "logpath", r"Path in which to write the log file [default: C:\Windows\Temp\result.log].", "");
48+
opts.optflag("n", "native", "Use NtCreateThreadEx instead of std::thread to run the payload.");
49+
opts.optflag("c", "current-thread", "Hijack the current thread instead of running the payload on a new thread.");
50+
51+
52+
let matches = match opts.parse(&args[1..])
53+
{
54+
Ok(m) => { m }
55+
Err(_) => {print_usage(&program, opts); return; }
56+
};
57+
58+
if matches.opt_present("h")
59+
{
60+
print_usage(&program, opts);
61+
return;
62+
}
63+
let mut log_path = r"C:\Windows\Temp\result.log".to_string();
64+
let mut hijacked_export = String::new();
65+
let mut native = "false".to_string();
66+
let mut hijack = false;
67+
let path = matches.opt_str("p").unwrap();
68+
let mode = matches.opt_str("m").unwrap();
69+
70+
if matches.opt_present("l") {
71+
log_path = matches.opt_str("l").unwrap()
72+
}
73+
74+
if matches.opt_present("e") {
75+
hijacked_export = matches.opt_str("e").unwrap()
76+
}
77+
78+
if matches.opt_present("n") {
79+
native = "true".to_string();
80+
}
81+
82+
if matches.opt_present("c") {
83+
hijack = true;
84+
}
85+
86+
if mode == "trace" {
87+
generate_tracer_dll(path, log_path);
88+
}else {
89+
generate_proxy_dll(path, hijacked_export, native, hijack);
90+
}
91+
92+
println!("[+] Process completed.")
93+
94+
}
95+
96+
fn print_usage(program: &str, opts: Options) {
97+
let brief = format!(r"Usage: {} -m trace|proxy -p C:\Windows\System32\textshaping.dll [options]", program);
98+
print!("{}", opts.usage(&brief));
99+
}
100+
101+
fn generate_tracer_dll(original_dll_path: String, log_path: String)
102+
{
103+
let loaded_dll = dinvoke_rs::dinvoke::load_library_a(&original_dll_path);
104+
if loaded_dll == 0 {
105+
return;
106+
}
107+
108+
let names_info = get_function_info(loaded_dll);
109+
let number_of_functions: String = names_info.len().to_string();
110+
let mut first_string = String::new();
111+
let mut second_string = "\nfn get_function_name(index: i32) -> String\n{\n\tmatch index\n\t{".to_string();
112+
let mut def_file_string = "EXPORTS\n".to_string();
113+
114+
for (i,name) in names_info.iter().enumerate()
115+
{
116+
let template1 = TEMPLATE1.replace("{FUNC_NAME}", &name.0).replace("{INDEX}", &i.to_string());
117+
first_string.push_str(&template1);
118+
let template2 = TEMPLATE2.replace("{NUM}", &i.to_string()).replace("{NAME}", &name.0);
119+
second_string.push_str("\n\t\t");
120+
second_string.push_str(&template2);
121+
122+
let export_string = format!("{} @{}\n",&name.0, name.1);
123+
def_file_string.push_str(&export_string);
124+
}
125+
126+
let ending = "\n\t\t_ => {String::new()}\n\t}\n} ";
127+
second_string.push_str(ending);
128+
129+
let path = env::current_exe().unwrap();
130+
let path = path.to_str().unwrap();
131+
let path = path.replace("generator.exe", "");
132+
let template_path = format!("{}{}", &path, r"..\..\template1.txt");
133+
134+
let mut content = fs::read_to_string(&template_path).expect("[x] Couldn't read template1.txt file.");
135+
content = content.replace("{DLL_NAME}", &original_dll_path)
136+
.replace("{NUM_FUNCTIONS}", &number_of_functions)
137+
.replace("{LOG_PATH}", &log_path);
138+
139+
content.push_str(&first_string);
140+
content.push_str(&second_string);
141+
142+
let lib_path = format!("{}{}", path, r"..\..\..\ExportTracer\src\lib.rs");
143+
let _ = fs::write(lib_path, content);
144+
145+
let def_path = format!("{}{}", path, r"..\..\..\ExportTracer\file.def").replace(r"\", r"\\");
146+
let _ = fs::write(&def_path, def_file_string);
147+
148+
let config_path = format!("{}{}", path, r"..\..\..\ExportTracer\.cargo\config");
149+
let template_path: String = format!("{}{}", &path, r"..\..\template3.txt");
150+
151+
let mut config_content = fs::read_to_string(&template_path).expect("[x] Couldn't read cargo.toml file.");
152+
config_content = config_content.replace("{DEF_PATH}", &def_path);
153+
154+
let _ = fs::write(config_path, config_content);
155+
156+
}
157+
158+
fn generate_proxy_dll(original_dll_path: String, hijacked_export: String, native: String, hijack: bool)
159+
{
160+
let loaded_dll = dinvoke_rs::dinvoke::load_library_a(&original_dll_path);
161+
if loaded_dll == 0 {
162+
return;
163+
}
164+
let names_info = get_function_info(loaded_dll);
165+
let number_of_functions: String = names_info.len().to_string();
166+
let module_name = original_dll_path.replace(".dll","");
167+
let mut first_string = String::new();
168+
let mut second_string = "\nfn get_function_name(index: i32) -> String\n{\n\tmatch index\n\t{".to_string();
169+
let mut third_string: String = String::new();
170+
let mut def_file_string = "EXPORTS\n".to_string();
171+
for (i,name) in names_info.iter().enumerate()
172+
{
173+
if &name.0 == &hijacked_export
174+
{
175+
let template1 = TEMPLATE1.replace("{FUNC_NAME}", &name.0).replace("{INDEX}", &i.to_string());
176+
first_string.push_str(&template1);
177+
let template2 = TEMPLATE2.replace("{NUM}", &i.to_string()).replace("{NAME}", &name.0);
178+
second_string.push_str("\n\t\t");
179+
second_string.push_str(&template2);
180+
let export_string = format!("{} @{}\n",&name.0, name.1);
181+
def_file_string.push_str(&export_string);
182+
}
183+
else
184+
{
185+
let template3 = TEMPLATE3.replace("{FORWARDED_NAME}", &name.0);
186+
third_string.push_str(&template3);
187+
third_string.push('\n');
188+
let export_string = format!("{}={}.{} @{}\n", &name.0, module_name, &name.0, name.1);
189+
def_file_string.push_str(&export_string);
190+
}
191+
192+
}
193+
194+
let ending = "\n\t\t_ => {String::new()}\n\t}\n} ";
195+
second_string.push_str(ending);
196+
let path = env::current_exe().unwrap();
197+
let path = path.to_str().unwrap();
198+
let path = path.replace("generator.exe", "");
199+
let template_path;
200+
if !hijack {
201+
template_path = format!("{}{}", &path, r"..\..\template2.txt");
202+
} else {
203+
template_path = format!("{}{}", &path, r"..\..\template4.txt");
204+
}
205+
let mut content = fs::read_to_string(&template_path).expect("[x] Couldn't read template2.txt file.");
206+
207+
content = content.replace("{DLL_NAME}", &original_dll_path)
208+
.replace("{NUM_FUNCTIONS}", &number_of_functions)
209+
.replace("{NATIVE}", &native);
210+
content.push_str(&first_string);
211+
content.push_str(&third_string);
212+
content.push_str(&second_string);
213+
214+
let lib_path = format!("{}{}", path, r"..\..\..\ProxyDll\src\lib.rs");
215+
let _ = fs::write(lib_path, content);
216+
217+
let def_path = format!("{}{}", path, r"..\..\..\ProxyDll\file.def").replace(r"\", r"\\");
218+
let _ = fs::write(&def_path, def_file_string);
219+
220+
let config_path = format!("{}{}", path, r"..\..\..\ProxyDll\.cargo\config");
221+
let template_path: String = format!("{}{}", &path, r"..\..\template3.txt");
222+
223+
let mut config_content = fs::read_to_string(&template_path).expect("[x] Couldn't read cargo.toml file.");
224+
config_content = config_content.replace("{DEF_PATH}", &def_path);
225+
let _ = fs::write(config_path, config_content);
226+
227+
228+
}
229+
230+
231+
pub fn get_function_info(module_base_address: isize) -> Vec<(String,u32)> {
232+
233+
unsafe
234+
{
235+
let mut functions_info: Vec<(String, u32)> = vec![];
236+
let pe_header = *((module_base_address + 0x3C) as *mut i32);
237+
let opt_header: isize = module_base_address + (pe_header as isize) + 0x18;
238+
let magic = *(opt_header as *mut i16);
239+
let p_export: isize;
240+
241+
if magic == 0x010b {
242+
p_export = opt_header + 0x60;
243+
}
244+
else {
245+
p_export = opt_header + 0x70;
246+
}
247+
248+
let export_rva = *(p_export as *mut i32);
249+
let ordinal_base = *((module_base_address + export_rva as isize + 0x10) as *mut u32);
250+
let number_of_names = *((module_base_address + export_rva as isize + 0x18) as *mut u32);
251+
let names_rva = *((module_base_address + export_rva as isize + 0x20) as *mut u32);
252+
let ordinals_rva = *((module_base_address + export_rva as isize + 0x24) as *mut u32);
253+
for x in 0..number_of_names
254+
{
255+
256+
let address = *((module_base_address + names_rva as isize + x as isize * 4) as *mut i32);
257+
let ordinal = *((module_base_address + ordinals_rva as isize + x as isize * 2) as *mut u16);
258+
let mut function_name_ptr = (module_base_address + address as isize) as *mut u8;
259+
let mut function_name: String = "".to_string();
260+
261+
while *function_name_ptr as char != '\0' // null byte
262+
{
263+
function_name.push(*function_name_ptr as char);
264+
function_name_ptr = function_name_ptr.add(1);
265+
}
266+
267+
let func_ordinal = ordinal_base + ordinal as u32;
268+
functions_info.push((function_name,func_ordinal));
269+
270+
}
271+
272+
functions_info
273+
274+
}
275+
}

0 commit comments

Comments
 (0)