Projects STRLCPY ldr Commits 11f244d1
🤬
  • ■ ■ ■ ■ ■ ■
    .cargo/config.toml
     1 +[alias]
     2 +r = "run"
     3 +br = "build --release"
     4 + 
     5 +[build]
     6 +jobs = 4
     7 +target-dir = "target"
     8 +incremental = true
     9 +pipelining = true
     10 +#target = "x86_64-pc-windows-gnu"
     11 +rustflags = ["-Cembed-bitcode=yes", "-Ctarget-feature=+crt-static"]
     12 + 
     13 +[profile.dev]
     14 +#panic = "abort"
     15 + 
     16 +[profile.release]
     17 +#codegen-units = 1
     18 +opt-level = "z"
     19 +#panic = "abort"
     20 +#lto = true
     21 +strip = true
     22 + 
     23 +[target.x86_64-pc-windows-gnu]
     24 +rustflags = ["-Ctarget-feature=+crt-static"]
     25 +linker="/usr/local/bin/x86_64-w64-mingw32-gcc"
  • ■ ■ ■ ■ ■ ■
    Cargo.toml
     1 +[package]
     2 +name = "ldr"
     3 +version = "0.1.0"
     4 +edition = "2021"
     5 + 
     6 +[[bin]]
     7 +name = "ldr"
     8 +path = "src/main.rs"
     9 + 
     10 +[dependencies]
     11 +printf-compat = "0.1.1"
     12 +windows = { version = "0.44.0", features = ["Win32_System_LibraryLoader", "Win32_System_Memory", "Win32_Foundation", "Win32_System_Com", "Win32_System_Ole", "Win32_Security", "Win32_System_SystemInformation", "Win32_System_Diagnostics_Debug", "Win32_System_Kernel", "Win32_System_SystemServices", "Win32_System_IO", "Win32_System_WindowsProgramming", "Win32_System_Diagnostics_Debug", "Win32_System_Threading", "Win32_Storage_FileSystem", "Win32_System_Memory"] }
  • ■ ■ ■ ■ ■ ■
    src/functions/mod.rs
     1 +use printf_compat::{format as formatter, output};
     2 +use std::alloc::{alloc, dealloc, Layout};
     3 +use std::borrow::{Borrow, BorrowMut};
     4 +use std::collections::HashMap;
     5 +use std::ffi::CStr;
     6 +use std::ffi::{c_char, c_int, c_short};
     7 +use std::{ptr, slice};
     8 +use windows::Win32::Foundation::HANDLE;
     9 +use windows::Win32::System::Threading::{PROCESS_INFORMATION, STARTUPINFOA};
     10 + 
     11 +#[repr(C)]
     12 +#[derive(Debug, Copy, Clone)]
     13 +pub struct DataP {
     14 + pub original: *mut c_char,
     15 + pub buffer: *mut c_char,
     16 + pub length: c_int,
     17 + pub size: c_int,
     18 +}
     19 + 
     20 +#[repr(C)]
     21 +#[derive(Debug, Copy, Clone)]
     22 +pub struct FormatP {
     23 + pub original: *mut c_char,
     24 + pub buffer: *mut c_char,
     25 + pub length: c_int,
     26 + pub size: c_int,
     27 +}
     28 + 
     29 +#[repr(C)]
     30 +#[derive(Debug, Clone)]
     31 +pub struct Carrier {
     32 + pub output: Vec<c_char>,
     33 + pub offset: usize,
     34 +}
     35 + 
     36 +impl Carrier {
     37 + pub const fn new() -> Carrier {
     38 + Carrier {
     39 + output: Vec::new(),
     40 + offset: 0,
     41 + }
     42 + }
     43 + 
     44 + pub fn append_char_array(&mut self, s: *mut c_char, len: c_int) {
     45 + let holder = unsafe { slice::from_raw_parts(s, len as usize) };
     46 + 
     47 + self.output.extend_from_slice(holder);
     48 + self.offset = self.output.len() - holder.len();
     49 + }
     50 + 
     51 + pub fn append_string(&mut self, s: String) {
     52 + let mut mapped = s.bytes().map(|c| c as i8).collect::<Vec<c_char>>();
     53 + 
     54 + self.output.append(&mut mapped);
     55 + self.offset = self.output.len() - s.len() as usize;
     56 + }
     57 + 
     58 + pub fn flush(&mut self) -> String {
     59 + let mut result = String::new();
     60 + 
     61 + for c in self.output.iter() {
     62 + if (*c as u8) == 0 {
     63 + result.push(0x0a as char);
     64 + } else {
     65 + result.push(*c as u8 as char);
     66 + }
     67 + }
     68 + 
     69 + result
     70 + }
     71 + 
     72 + #[allow(dead_code)]
     73 + pub fn get_from_offset(&self, offset: usize) -> &[c_char] {
     74 + if offset >= self.output.len() {
     75 + return &[];
     76 + }
     77 + 
     78 + let (_, tail) = self.output.split_at(offset);
     79 + 
     80 + return tail;
     81 + }
     82 + 
     83 + #[allow(dead_code)]
     84 + pub fn get_from_current_offset(&self) -> &[c_char] {
     85 + let (_, tail) = self.output.split_at(self.offset);
     86 + 
     87 + return tail;
     88 + }
     89 + 
     90 + #[allow(dead_code)]
     91 + pub fn len(&self) -> usize {
     92 + return self.output.len();
     93 + }
     94 +}
     95 + 
     96 +static mut OUTPUT: Carrier = Carrier::new();
     97 + 
     98 +pub fn resolve_internal_functions(name: &str) -> Result<isize, String> {
     99 + match name {
     100 + "BeaconDataParse" => Ok((BeaconDataParse as *const ()) as isize),
     101 + "BeaconDataInt" => Ok((BeaconDataInt as *const ()) as isize),
     102 + "BeaconDataShort" => Ok((BeaconDataShort as *const ()) as isize),
     103 + "BeaconDataLength" => Ok((BeaconDataLength as *const ()) as isize),
     104 + "BeaconDataExtract" => Ok((BeaconDataExtract as *const ()) as isize),
     105 + "BeaconFormatAlloc" => Ok((BeaconFormatAlloc as *const ()) as isize),
     106 + "BeaconFormatReset" => Ok((BeaconFormatReset as *const ()) as isize),
     107 + "BeaconFormatFree" => Ok((BeaconFormatFree as *const ()) as isize),
     108 + "BeaconFormatAppend" => Ok((BeaconFormatAppend as *const ()) as isize),
     109 + "BeaconFormatPrintf" => Ok((BeaconFormatPrintf as *const ()) as isize),
     110 + "BeaconFormatToString" => Ok((BeaconFormatToString as *const ()) as isize),
     111 + "BeaconFormatInt" => Ok((BeaconFormatInt as *const ()) as isize),
     112 + "BeaconPrintf" => Ok((BeaconPrintf as *const ()) as isize),
     113 + "BeaconOutput" => Ok((BeaconOutput as *const ()) as isize),
     114 + "BeaconUseToken" => Ok((BeaconUseToken as *const ()) as isize),
     115 + "BeaconRevertToken" => Ok((BeaconRevertToken as *const ()) as isize),
     116 + "BeaconIsAdmin" => Ok((BeaconIsAdmin as *const ()) as isize),
     117 + "BeaconGetSpawnTo" => Ok((BeaconGetSpawnTo as *const ()) as isize),
     118 + "BeaconSpawnTemporaryProcess" => Ok((BeaconSpawnTemporaryProcess as *const ()) as isize),
     119 + "BeaconInjectProcess" => Ok((BeaconInjectProcess as *const ()) as isize),
     120 + "BeaconInjectTemporaryProcess" => Ok((BeaconInjectTemporaryProcess as *const ()) as isize),
     121 + "BeaconCleanupProcess" => Ok((BeaconCleanupProcess as *const ()) as isize),
     122 + "toWideChar" => Ok((to_wide_char as *const ()) as isize),
     123 + &_ => Err("[!] Couldn't find internal function.".into()),
     124 + }
     125 +}
     126 + 
     127 +#[no_mangle]
     128 +pub extern "C" fn BeaconDataParse(parser: *mut DataP, buffer: *mut c_char, size: c_int) {
     129 + if parser.is_null() {
     130 + return;
     131 + }
     132 + 
     133 + let mut pp: DataP = unsafe { *parser };
     134 + 
     135 + pp.original = buffer;
     136 + pp.buffer = buffer;
     137 + pp.length = size - 4;
     138 + pp.size = size - 4;
     139 + 
     140 + unsafe {
     141 + pp.buffer = pp.buffer.add(4);
     142 + }
     143 + 
     144 + unsafe {
     145 + *parser = pp;
     146 + }
     147 + 
     148 + return;
     149 +}
     150 + 
     151 +#[no_mangle]
     152 +pub extern "C" fn BeaconDataInt(parser: *mut DataP) -> c_int {
     153 + if parser.is_null() {
     154 + return 0;
     155 + }
     156 + 
     157 + let mut pp: DataP = unsafe { *parser };
     158 + 
     159 + if pp.length < 4 {
     160 + return 0;
     161 + }
     162 + 
     163 + let result: &[u8] = unsafe { slice::from_raw_parts(pp.buffer as *const u8, 4) };
     164 + 
     165 + let mut dst = [0u8; 4];
     166 + dst.clone_from_slice(&result[0..4]);
     167 + 
     168 + pp.buffer = unsafe { pp.buffer.add(4) };
     169 + pp.length = pp.length - 4;
     170 + 
     171 + unsafe {
     172 + *parser = pp;
     173 + }
     174 + 
     175 + return i32::from_ne_bytes(dst) as c_int;
     176 +}
     177 + 
     178 +#[no_mangle]
     179 +pub extern "C" fn BeaconDataShort(parser: *mut DataP) -> c_short {
     180 + if parser.is_null() {
     181 + return 0;
     182 + }
     183 + 
     184 + let mut pp: DataP = unsafe { *parser };
     185 + 
     186 + if pp.length < 2 {
     187 + return 0;
     188 + }
     189 + 
     190 + let result: &[u8] = unsafe { slice::from_raw_parts(pp.buffer as *const u8, 4) };
     191 + 
     192 + let mut dst = [0u8; 2];
     193 + dst.clone_from_slice(&result[0..2]);
     194 + 
     195 + pp.buffer = unsafe { pp.buffer.add(2) };
     196 + pp.length = pp.length - 2;
     197 + 
     198 + unsafe {
     199 + *parser = pp;
     200 + }
     201 + 
     202 + return i16::from_ne_bytes(dst);
     203 +}
     204 + 
     205 +#[no_mangle]
     206 +pub extern "C" fn BeaconDataLength(parser: *mut DataP) -> c_int {
     207 + if parser.is_null() {
     208 + return 0;
     209 + }
     210 + 
     211 + let pp: DataP = unsafe { *parser };
     212 + 
     213 + return pp.length;
     214 +}
     215 + 
     216 +#[no_mangle]
     217 +pub extern "C" fn BeaconDataExtract(parser: *mut DataP, size: *mut c_int) -> *mut c_char {
     218 + if parser.is_null() {
     219 + return ptr::null_mut();
     220 + }
     221 + 
     222 + let mut pp: DataP = unsafe { *parser };
     223 + 
     224 + if pp.length < 4 {
     225 + return ptr::null_mut();
     226 + }
     227 + 
     228 + let length_parts: &[u8] = unsafe { slice::from_raw_parts(pp.buffer as *const u8, 4) };
     229 + 
     230 + let mut length_holder = [0u8; 4];
     231 + length_holder.clone_from_slice(&length_parts[0..4]);
     232 + 
     233 + let length: u32 = u32::from_ne_bytes(length_holder);
     234 + 
     235 + pp.buffer = unsafe { pp.buffer.add(4) };
     236 + 
     237 + let result = pp.buffer;
     238 + 
     239 + if result.is_null() {
     240 + return ptr::null_mut();
     241 + }
     242 + 
     243 + pp.length = pp.length - 4;
     244 + 
     245 + pp.length = pp.length - length as i32;
     246 + 
     247 + pp.buffer = unsafe { pp.buffer.add(length as usize) };
     248 + 
     249 + if !size.is_null() && !result.is_null() {
     250 + unsafe {
     251 + *size = length as c_int;
     252 + }
     253 + }
     254 + 
     255 + unsafe {
     256 + *parser = pp;
     257 + }
     258 + 
     259 + return result;
     260 +}
     261 + 
     262 +#[no_mangle]
     263 +pub extern "C" fn BeaconFormatAlloc(format: *mut FormatP, max_size: c_int) {
     264 + if format.is_null() {
     265 + return;
     266 + }
     267 + 
     268 + if max_size == 0 {
     269 + return;
     270 + }
     271 + 
     272 + let mut fp: FormatP = unsafe { *format };
     273 + 
     274 + let mut align: usize = 1;
     275 + 
     276 + while align < max_size as usize {
     277 + align = align * 2;
     278 + }
     279 + 
     280 + let layout = Layout::from_size_align(max_size as usize, align).unwrap();
     281 + let ptr = unsafe { alloc(layout) };
     282 + 
     283 + fp.original = ptr as *mut i8;
     284 + fp.buffer = fp.original;
     285 + fp.length = 0;
     286 + fp.size = max_size;
     287 + 
     288 + unsafe {
     289 + *format = fp;
     290 + }
     291 + 
     292 + return;
     293 +}
     294 + 
     295 +#[no_mangle]
     296 +pub extern "C" fn BeaconFormatReset(format: *mut FormatP) {
     297 + if format.is_null() {
     298 + return;
     299 + }
     300 + 
     301 + let mut fp: FormatP = unsafe { *format };
     302 + 
     303 + let size = fp.size;
     304 + 
     305 + // Free format
     306 + BeaconFormatFree(&mut fp);
     307 + 
     308 + // Alloc format
     309 + BeaconFormatAlloc(&mut fp, size);
     310 + 
     311 + unsafe {
     312 + *format = fp;
     313 + }
     314 + 
     315 + return;
     316 +}
     317 + 
     318 +#[no_mangle]
     319 +pub extern "C" fn BeaconFormatFree(format: *mut FormatP) {
     320 + if format.is_null() {
     321 + return;
     322 + }
     323 + 
     324 + let mut fp: FormatP = unsafe { *format };
     325 + 
     326 + if !fp.original.is_null() {
     327 + let mut align: usize = 1;
     328 + 
     329 + while align < fp.size as usize {
     330 + align = align * 2;
     331 + }
     332 + 
     333 + let layout = Layout::from_size_align(fp.size as usize, align).unwrap();
     334 + 
     335 + unsafe { dealloc(fp.original as *mut u8, layout) };
     336 + }
     337 + 
     338 + fp.original = ptr::null_mut();
     339 + fp.buffer = ptr::null_mut();
     340 + fp.length = 0;
     341 + fp.size = 0;
     342 + 
     343 + unsafe {
     344 + *format = fp;
     345 + }
     346 + 
     347 + return;
     348 +}
     349 + 
     350 +#[no_mangle]
     351 +pub extern "C" fn BeaconFormatAppend(format: *mut FormatP, text: *mut c_char, len: c_int) {
     352 + if format.is_null() {
     353 + return;
     354 + }
     355 + 
     356 + let mut fp: FormatP = unsafe { *format };
     357 + 
     358 + if fp.length + len > fp.size {
     359 + return;
     360 + }
     361 + 
     362 + unsafe {
     363 + ptr::copy_nonoverlapping(text, fp.original, len as usize);
     364 + }
     365 + 
     366 + fp.buffer = unsafe { fp.buffer.add(len as usize) };
     367 + fp.length = fp.length + len;
     368 + 
     369 + unsafe {
     370 + *format = fp;
     371 + }
     372 + 
     373 + return;
     374 +}
     375 + 
     376 +#[no_mangle]
     377 +pub unsafe extern "C" fn BeaconFormatPrintf(format: *mut FormatP, fmt: *mut c_char, mut tail: ...) {
     378 + if format.is_null() {
     379 + return;
     380 + }
     381 + 
     382 + let mut fp: FormatP = *format;
     383 + 
     384 + let mut s = String::new();
     385 + let bytes_written = formatter(fmt, tail.as_va_list(), output::fmt_write(&mut s));
     386 + 
     387 + if fp.length + bytes_written + 1 > fp.size {
     388 + return;
     389 + }
     390 + 
     391 + s.push('\0');
     392 + 
     393 + ptr::copy_nonoverlapping(s.as_ptr(), fp.buffer as *mut u8, s.len());
     394 + 
     395 + fp.length = fp.length + s.len() as i32;
     396 + 
     397 + *format = fp;
     398 + 
     399 + return;
     400 +}
     401 + 
     402 +#[no_mangle]
     403 +pub extern "C" fn BeaconFormatToString(format: *mut FormatP, size: *mut c_int) -> *mut c_char {
     404 + if format.is_null() {
     405 + return ptr::null_mut();
     406 + }
     407 + 
     408 + let fp: FormatP = unsafe { *format };
     409 + 
     410 + if fp.length == 0 {
     411 + return ptr::null_mut();
     412 + }
     413 + 
     414 + unsafe {
     415 + *size = fp.length;
     416 + }
     417 + 
     418 + return fp.original;
     419 +}
     420 + 
     421 +#[no_mangle]
     422 +pub extern "C" fn BeaconFormatInt(format: *mut FormatP, value: c_int) {
     423 + if format.is_null() {
     424 + return;
     425 + }
     426 + 
     427 + let mut fp: FormatP = unsafe { *format };
     428 + 
     429 + if fp.length + 4 > fp.size {
     430 + return;
     431 + }
     432 + 
     433 + let swapped = swap_endianness(value as u32);
     434 + let mut result = swapped.to_be_bytes();
     435 + 
     436 + unsafe {
     437 + ptr::copy_nonoverlapping(result.as_mut_ptr(), fp.original as *mut u8, 4);
     438 + }
     439 + 
     440 + fp.buffer = unsafe { fp.buffer.add(4) };
     441 + fp.length = fp.length + 4;
     442 + 
     443 + unsafe {
     444 + *format = fp;
     445 + }
     446 + 
     447 + return;
     448 +}
     449 + 
     450 +#[no_mangle]
     451 +pub unsafe extern "C" fn BeaconPrintf(_: c_int, fmt: *mut c_char, mut tail: ...) {
     452 + let mut s = String::new();
     453 + 
     454 + formatter(fmt, tail.as_va_list(), output::fmt_write(&mut s));
     455 + 
     456 + s.push('\0');
     457 + 
     458 + OUTPUT.append_string(s);
     459 + 
     460 + return;
     461 +}
     462 + 
     463 +#[no_mangle]
     464 +pub extern "C" fn BeaconOutput(_: c_int, data: *mut c_char, len: c_int) {
     465 + unsafe { OUTPUT.append_char_array(data, len) }
     466 +}
     467 + 
     468 +#[no_mangle]
     469 +fn get_output() -> Carrier {
     470 + return unsafe { OUTPUT.clone() };
     471 +}
     472 + 
     473 +#[no_mangle]
     474 +pub extern "C" fn swap_endianness(src: u32) -> u32 {
     475 + let test: u32 = 0x000000ff;
     476 + 
     477 + // if test is 0xff00, then we are little endian, otherwise big endian
     478 + if (((test >> 24) & 0xff) as u8) == 0xff {
     479 + return src.swap_bytes();
     480 + }
     481 + 
     482 + return src;
     483 +}
     484 + 
     485 +#[no_mangle]
     486 +/// Converts the src string to a UTF16-LE wide-character string, using the target's default encoding.
     487 +///
     488 +/// # Arguments
     489 +///
     490 +/// * `src` - The source string to convert.
     491 +/// * `dst` - The destination string.
     492 +/// * `max` - The size (in bytes!) of the destination buffer
     493 +///
     494 +/// # Safety
     495 +/// This function is unsafe because it dereferences the src pointer.
     496 +pub extern "C" fn to_wide_char(src: *mut c_char, dst: *mut u16, max: c_int) -> i32 {
     497 + if src.is_null() {
     498 + return 0;
     499 + }
     500 + 
     501 + let c_str: &CStr = unsafe { CStr::from_ptr(src) };
     502 + 
     503 + let str_slice: &str = match c_str.to_str() {
     504 + Ok(s) => s,
     505 + Err(_) => return 0,
     506 + };
     507 + 
     508 + let mut size = str_slice.len();
     509 + 
     510 + if size > max as usize {
     511 + size = max as usize - 1;
     512 + }
     513 + 
     514 + let mut v: Vec<u16> = str_slice
     515 + .encode_utf16()
     516 + .take(size)
     517 + .map(|x| x as u16)
     518 + .collect();
     519 + v.push(0);
     520 + 
     521 + unsafe { ptr::copy(v.as_ptr(), dst, size) };
     522 + 
     523 + return 1;
     524 +}
     525 + 
     526 +#[no_mangle]
     527 +pub extern "C" fn BeaconUseToken(token: HANDLE) -> i32 {
     528 + todo!()
     529 +}
     530 + 
     531 +#[no_mangle]
     532 +pub extern "C" fn BeaconRevertToken() {
     533 + todo!()
     534 +}
     535 + 
     536 +#[no_mangle]
     537 +pub extern "C" fn BeaconIsAdmin() -> i32 {
     538 + todo!()
     539 +}
     540 + 
     541 +#[no_mangle]
     542 +pub extern "C" fn BeaconGetSpawnTo(x86: i32, buffer: *mut c_char, length: c_int) {
     543 + todo!()
     544 +}
     545 + 
     546 +#[no_mangle]
     547 +pub extern "C" fn BeaconSpawnTemporaryProcess(
     548 + x86: i32,
     549 + ignoreToken: i32,
     550 + sInfo: *mut STARTUPINFOA,
     551 + pInfo: *mut PROCESS_INFORMATION,
     552 +) -> i32 {
     553 + todo!()
     554 +}
     555 + 
     556 +#[no_mangle]
     557 +pub extern "C" fn BeaconInjectProcess(
     558 + hProc: HANDLE,
     559 + pid: c_int,
     560 + payload: *mut c_char,
     561 + p_len: c_int,
     562 + p_offset: c_int,
     563 + arg: *mut c_char,
     564 + a_len: c_int,
     565 +) {
     566 + todo!()
     567 +}
     568 + 
     569 +#[no_mangle]
     570 +pub extern "C" fn BeaconInjectTemporaryProcess(
     571 + pInfo: *mut PROCESS_INFORMATION,
     572 + payload: *mut c_char,
     573 + p_len: c_int,
     574 + p_offset: c_int,
     575 + arg: *mut c_char,
     576 + a_len: c_int,
     577 +) {
     578 + todo!()
     579 +}
     580 + 
     581 +#[no_mangle]
     582 +pub extern "C" fn BeaconCleanupProcess(pInfo: *mut PROCESS_INFORMATION) {
     583 + todo!()
     584 +}
     585 + 
     586 +#[cfg(test)]
     587 +mod tests {
     588 + use core::ffi::CStr;
     589 + use std::ffi::CString;
     590 + use std::{ptr, slice};
     591 + 
     592 + use crate::functions::*;
     593 + #[cfg(target_os = "windows")]
     594 + use winapi::{shared::minwindef::DWORD, shared::ntdef::c_char};
     595 + 
     596 + #[cfg(not(target_os = "windows"))]
     597 + use super::super::test_types::{c_char, DWORD};
     598 + 
     599 + unsafe fn reset_output() {
     600 + OUTPUT = Carrier::new();
     601 + }
     602 + 
     603 + #[test]
     604 + fn can_parse_beacon_data() {
     605 + let mut buffer: [c_char; 0xff] = [0i8; 0xff];
     606 + 
     607 + let mut parser = super::DataP {
     608 + original: ptr::null_mut(),
     609 + buffer: ptr::null_mut(),
     610 + length: 0,
     611 + size: 0,
     612 + };
     613 + 
     614 + assert_eq!(parser.length, 0);
     615 + assert_eq!(parser.size, 0);
     616 + assert_eq!(parser.buffer, ptr::null_mut());
     617 + 
     618 + BeaconDataParse(&mut parser, buffer.as_mut_ptr(), 0xff);
     619 + 
     620 + assert_ne!(parser.original, ptr::null_mut());
     621 + assert_ne!(parser.buffer, ptr::null_mut());
     622 + assert_eq!(parser.length, 0xff - 4);
     623 + assert_eq!(parser.size, 0xff - 4);
     624 + 
     625 + unsafe {
     626 + assert_eq!(parser.buffer, buffer.as_mut_ptr().add(4));
     627 + }
     628 + }
     629 + 
     630 + #[test]
     631 + fn can_extract_int_from_parser() {
     632 + let mut buffer: [c_char; 0xff] = [0i8; 0xff];
     633 + 
     634 + buffer[4] = 0x1;
     635 + buffer[5] = 0x4;
     636 + 
     637 + let mut parser = super::DataP {
     638 + original: buffer.as_mut_ptr(),
     639 + buffer: buffer.as_mut_ptr(),
     640 + length: 0,
     641 + size: 0,
     642 + };
     643 + 
     644 + BeaconDataParse(&mut parser, buffer.as_mut_ptr(), 0xff);
     645 + 
     646 + let result = BeaconDataInt(&mut parser);
     647 + 
     648 + assert_eq!(1025, result);
     649 + }
     650 + 
     651 + #[test]
     652 + fn can_extract_short_from_parser() {
     653 + let mut buffer: [c_char; 0xff] = [0i8; 0xff];
     654 + 
     655 + buffer[4] = 0x1;
     656 + buffer[5] = 0x4;
     657 + 
     658 + let mut parser = super::DataP {
     659 + original: buffer.as_mut_ptr(),
     660 + buffer: buffer.as_mut_ptr(),
     661 + length: 0,
     662 + size: 0,
     663 + };
     664 + 
     665 + BeaconDataParse(&mut parser, buffer.as_mut_ptr(), 0xff);
     666 + 
     667 + let result = BeaconDataShort(&mut parser);
     668 + 
     669 + assert_eq!(1025, result);
     670 + }
     671 + 
     672 + #[test]
     673 + fn can_extract_data_from_parser() {
     674 + let mut buffer: [c_char; 0xff] = [0i8; 0xff];
     675 + 
     676 + // set our data size
     677 + buffer[4] = 0x5;
     678 + 
     679 + // set our data
     680 + buffer[8] = 104;
     681 + buffer[9] = 101;
     682 + buffer[10] = 108;
     683 + buffer[11] = 108;
     684 + buffer[12] = 111;
     685 + 
     686 + let mut parser = super::DataP {
     687 + original: buffer.as_mut_ptr(),
     688 + buffer: buffer.as_mut_ptr(),
     689 + length: 0,
     690 + size: 0,
     691 + };
     692 + 
     693 + BeaconDataParse(&mut parser, buffer.as_mut_ptr(), 0xff);
     694 + 
     695 + let mut size = 0;
     696 + 
     697 + let result = BeaconDataExtract(&mut parser, &mut size);
     698 + 
     699 + let string: &[u8] = unsafe { slice::from_raw_parts(result as *const u8, size as usize) };
     700 + 
     701 + let result_string = String::from_utf8_lossy(string);
     702 + 
     703 + assert_eq!("hello", result_string);
     704 + assert_eq!(5, size);
     705 + }
     706 + 
     707 + #[test]
     708 + fn can_return_data_length() {
     709 + let mut buffer: [c_char; 0xff] = [0i8; 0xff];
     710 + let expected_length = 0xff - 4;
     711 + 
     712 + let mut parser = super::DataP {
     713 + original: buffer.as_mut_ptr(),
     714 + buffer: buffer.as_mut_ptr(),
     715 + length: 0,
     716 + size: 0,
     717 + };
     718 + 
     719 + BeaconDataParse(&mut parser, buffer.as_mut_ptr(), 0xff);
     720 + 
     721 + let length = BeaconDataLength(&mut parser);
     722 + 
     723 + assert_eq!(length, expected_length);
     724 + }
     725 + 
     726 + #[test]
     727 + fn can_allocate_format_p() {
     728 + let mut format = super::FormatP {
     729 + original: ptr::null_mut(),
     730 + buffer: ptr::null_mut(),
     731 + length: 0,
     732 + size: 0,
     733 + };
     734 + 
     735 + BeaconFormatAlloc(&mut format, 0xff);
     736 + 
     737 + assert_ne!(format.original, ptr::null_mut());
     738 + assert_ne!(format.buffer, ptr::null_mut());
     739 + assert_eq!(format.length, 0);
     740 + assert_eq!(format.size, 0xff);
     741 + }
     742 + 
     743 + #[test]
     744 + fn can_reset_format_p() {
     745 + let mut format = super::FormatP {
     746 + original: ptr::null_mut(),
     747 + buffer: ptr::null_mut(),
     748 + length: 0,
     749 + size: 0,
     750 + };
     751 + 
     752 + BeaconFormatAlloc(&mut format, 0xff);
     753 + 
     754 + assert_ne!(format.original, ptr::null_mut());
     755 + assert_ne!(format.buffer, ptr::null_mut());
     756 + assert_eq!(format.length, 0);
     757 + assert_eq!(format.size, 0xff);
     758 + 
     759 + BeaconFormatReset(&mut format);
     760 + 
     761 + assert_ne!(format.original, ptr::null_mut());
     762 + assert_ne!(format.buffer, ptr::null_mut());
     763 + assert_eq!(format.length, 0);
     764 + assert_eq!(format.size, 0xff);
     765 + }
     766 + 
     767 + #[test]
     768 + fn can_deallocate_format_p() {
     769 + let mut format = super::FormatP {
     770 + original: ptr::null_mut(),
     771 + buffer: ptr::null_mut(),
     772 + length: 0,
     773 + size: 0,
     774 + };
     775 + 
     776 + BeaconFormatAlloc(&mut format, 0xff);
     777 + 
     778 + assert_ne!(format.original, ptr::null_mut());
     779 + assert_ne!(format.buffer, ptr::null_mut());
     780 + assert_eq!(format.length, 0);
     781 + assert_eq!(format.size, 0xff);
     782 + 
     783 + BeaconFormatFree(&mut format);
     784 + 
     785 + assert_eq!(format.original, ptr::null_mut());
     786 + assert_eq!(format.buffer, ptr::null_mut());
     787 + assert_eq!(format.length, 0);
     788 + assert_eq!(format.size, 0);
     789 + }
     790 + 
     791 + #[test]
     792 + fn can_append_text_to_format_p() {
     793 + let mut format = super::FormatP {
     794 + original: ptr::null_mut(),
     795 + buffer: ptr::null_mut(),
     796 + length: 0,
     797 + size: 0,
     798 + };
     799 + 
     800 + BeaconFormatAlloc(&mut format, 0xff);
     801 + 
     802 + assert_ne!(format.original, ptr::null_mut());
     803 + assert_ne!(format.buffer, ptr::null_mut());
     804 + assert_eq!(format.length, 0);
     805 + assert_eq!(format.size, 0xff);
     806 + 
     807 + let mut buffer: [c_char; 5] = [104, 101, 108, 108, 111];
     808 + 
     809 + BeaconFormatAppend(&mut format, buffer.as_mut_ptr(), 5);
     810 + 
     811 + assert_eq!(format.length, 5);
     812 + 
     813 + let string: &[u8] =
     814 + unsafe { slice::from_raw_parts(format.original as *const u8, format.length as usize) };
     815 + 
     816 + let result_string = String::from_utf8_lossy(string);
     817 + assert_eq!("hello", result_string);
     818 + }
     819 + 
     820 + #[test]
     821 + fn can_printf_to_format_p() {
     822 + let mut format = super::FormatP {
     823 + original: ptr::null_mut(),
     824 + buffer: ptr::null_mut(),
     825 + length: 0,
     826 + size: 0,
     827 + };
     828 + 
     829 + BeaconFormatAlloc(&mut format, 0xff);
     830 + 
     831 + assert_ne!(format.original, ptr::null_mut());
     832 + assert_ne!(format.buffer, ptr::null_mut());
     833 + assert_eq!(format.length, 0);
     834 + assert_eq!(format.size, 0xff);
     835 + 
     836 + let fmt = CString::new("%.*f %.3s").unwrap();
     837 + let fmt_slice = fmt.to_bytes_with_nul();
     838 + 
     839 + unsafe {
     840 + BeaconFormatPrintf(
     841 + &mut format,
     842 + fmt_slice.as_ptr() as *mut c_char,
     843 + 2,
     844 + 0.3333,
     845 + "foobar",
     846 + )
     847 + };
     848 + 
     849 + assert_eq!(format.length, 9);
     850 + 
     851 + let string: &[c_char] =
     852 + unsafe { slice::from_raw_parts(format.original, format.length as usize) };
     853 + 
     854 + let result_string = unsafe { CStr::from_ptr(string.as_ptr()) };
     855 + 
     856 + assert_eq!("0.33 foo", result_string.to_str().unwrap());
     857 + }
     858 + 
     859 + #[test]
     860 + fn can_turn_format_p_into_string() {
     861 + let mut format = super::FormatP {
     862 + original: ptr::null_mut(),
     863 + buffer: ptr::null_mut(),
     864 + length: 0,
     865 + size: 0,
     866 + };
     867 + 
     868 + BeaconFormatAlloc(&mut format, 0xff);
     869 + 
     870 + assert_ne!(format.original, ptr::null_mut());
     871 + assert_ne!(format.buffer, ptr::null_mut());
     872 + assert_eq!(format.length, 0);
     873 + assert_eq!(format.size, 0xff);
     874 + 
     875 + let mut buffer: [c_char; 5] = [104, 101, 108, 108, 111];
     876 + 
     877 + BeaconFormatAppend(&mut format, buffer.as_mut_ptr(), 5);
     878 + 
     879 + assert_eq!(format.length, 5);
     880 + 
     881 + let mut length = 0;
     882 + 
     883 + let string_parts = BeaconFormatToString(&mut format, &mut length);
     884 + 
     885 + let string: &[u8] =
     886 + unsafe { slice::from_raw_parts(string_parts as *const u8, length as usize) };
     887 + 
     888 + let result_string = String::from_utf8_lossy(string);
     889 + 
     890 + assert_eq!("hello", result_string);
     891 + }
     892 + 
     893 + #[test]
     894 + fn can_append_int_to_format_p() {
     895 + let mut format = super::FormatP {
     896 + original: ptr::null_mut(),
     897 + buffer: ptr::null_mut(),
     898 + length: 0,
     899 + size: 0,
     900 + };
     901 + 
     902 + BeaconFormatAlloc(&mut format, 0xff);
     903 + 
     904 + assert_ne!(format.original, ptr::null_mut());
     905 + assert_ne!(format.buffer, ptr::null_mut());
     906 + assert_eq!(format.length, 0);
     907 + assert_eq!(format.size, 0xff);
     908 + 
     909 + BeaconFormatInt(&mut format, 5);
     910 + 
     911 + assert_eq!(format.length, 4);
     912 + 
     913 + let result: &[u8] =
     914 + unsafe { slice::from_raw_parts(format.original as *const u8, format.length as usize) };
     915 + 
     916 + assert_eq!(result, &[0, 0, 0, 5]);
     917 + }
     918 + 
     919 + #[test]
     920 + fn can_printf_to_beacon() {
     921 + let fmt = CString::new("%.*f %.3s").unwrap();
     922 + let fmt_slice = fmt.to_bytes_with_nul();
     923 + 
     924 + unsafe { BeaconPrintf(0, fmt_slice.as_ptr() as *mut c_char, 2, 0.3333, "foobar") };
     925 + 
     926 + let result = unsafe { OUTPUT.get_from_current_offset() };
     927 + 
     928 + let result_string = unsafe { CStr::from_ptr(result.as_ptr()) };
     929 + 
     930 + assert_eq!(unsafe { OUTPUT.len() }, 9);
     931 + assert_eq!(&[48, 46, 51, 51, 32, 102, 111, 111, 0], result);
     932 + assert_eq!("0.33 foo", result_string.to_str().unwrap());
     933 + 
     934 + unsafe { reset_output() };
     935 + }
     936 + 
     937 + #[test]
     938 + fn can_append_beacon_output() {
     939 + let mut buffer: [c_char; 6] = [104, 101, 108, 108, 111, 0];
     940 + 
     941 + BeaconOutput(0, buffer.as_mut_ptr(), 6);
     942 + 
     943 + let result = unsafe { OUTPUT.get_from_current_offset() };
     944 + 
     945 + let result_string = unsafe { CStr::from_ptr(result.as_ptr()) };
     946 + 
     947 + assert_eq!(unsafe { OUTPUT.len() }, 6);
     948 + assert_eq!(&[104, 101, 108, 108, 111, 0], result);
     949 + assert_eq!("hello", result_string.to_str().unwrap());
     950 + 
     951 + unsafe { reset_output() };
     952 + }
     953 + 
     954 + #[test]
     955 + fn can_return_beacon_output() {
     956 + let mut buffer: [c_char; 6] = [104, 101, 108, 108, 111, 0];
     957 + BeaconOutput(0, buffer.as_mut_ptr(), 6);
     958 + 
     959 + let fmt = CString::new("%.*f %.3s").unwrap();
     960 + let fmt_slice = fmt.to_bytes_with_nul();
     961 + 
     962 + unsafe { BeaconPrintf(0, fmt_slice.as_ptr() as *mut c_char, 2, 0.3333, "foobar") };
     963 + 
     964 + let mut data = get_output();
     965 + 
     966 + assert_eq!("hello\n0.33 foo\n", data.flush());
     967 + assert_eq!(15, data.len());
     968 + }
     969 + 
     970 + #[test]
     971 + fn can_swap_endianness() {
     972 + let src = 1025_u32.to_le();
     973 + 
     974 + // This test won't work on big endian machines.
     975 + // So I'll just test the code that actually matters.
     976 + assert_eq!(17039360, src.swap_bytes());
     977 + }
     978 + 
     979 + #[test]
     980 + fn can_convert_string_to_wide_string() {
     981 + let before = CString::new("hello world! ハローワールド! ?!").unwrap();
     982 + 
     983 + let c_ptr: *mut c_char = before.into_raw();
     984 + 
     985 + let mut buffer = [0; 0xff];
     986 + let buffer_length: DWORD = buffer.len() as DWORD;
     987 + 
     988 + let success = crate::beacon::to_wide_char(c_ptr, buffer.as_mut_ptr(), buffer_length as i32);
     989 + 
     990 + let buffer_slice: [u16; 0xff] = buffer.map(|b| b as u16);
     991 + let len = buffer.iter().take_while(|&&c| c != 0).count();
     992 + 
     993 + let result = String::from_utf16_lossy(&buffer_slice[..len]);
     994 + 
     995 + assert_eq!("hello world! ハローワールド! ?!", format!("{}", result));
     996 + assert_eq!(success, 1);
     997 + }
     998 + 
     999 + #[test]
     1000 + fn can_limit_characters_when_converting() {
     1001 + let before = CString::new("hello world! ハローワールド! ?!").unwrap();
     1002 + 
     1003 + let c_ptr: *mut c_char = before.into_raw();
     1004 + 
     1005 + let mut buffer = [0; 0xff];
     1006 + 
     1007 + let success = crate::beacon::to_wide_char(c_ptr, buffer.as_mut_ptr(), 5 as i32);
     1008 + 
     1009 + let buffer_slice: [u16; 0xff] = buffer.map(|b| b as u16);
     1010 + let len = buffer.iter().take_while(|&&c| c != 0).count();
     1011 + 
     1012 + let result = String::from_utf16_lossy(&buffer_slice[..len]);
     1013 + 
     1014 + assert_eq!("hell", format!("{}", result));
     1015 + assert_eq!(success, 1);
     1016 + }
     1017 +}
     1018 + 
  • ■ ■ ■ ■ ■ ■
    src/lib.rs
     1 +#![feature(c_variadic)]
     2 + 
  • ■ ■ ■ ■ ■ ■
    src/main.rs
     1 +#![feature(c_variadic)]
     2 + 
     3 +mod functions;
     4 +mod parser;
     5 + 
     6 +use std::process::exit;
     7 +use std::{env, fs};
     8 + 
     9 +fn main() {
     10 + let args: Vec<String> = env::args().collect();
     11 + 
     12 + if args.len() == 1 {
     13 + println!("[!] Please provide a path to a BOF/COFF file");
     14 + 
     15 + exit(1)
     16 + }
     17 + 
     18 + println!("[+] Running `{}`", args[1]);
     19 + 
     20 + let mut file_content_ipconfig = fs::read(&args[1]).expect("[!] Error opening the file");
     21 + 
     22 + match parser::parse(file_content_ipconfig.as_mut_slice()) {
     23 + Ok(_) => {}
     24 + Err(e) => println!("[!] Error while running: {}", e),
     25 + };
     26 +}
     27 + 
  • ■ ■ ■ ■ ■ ■
    src/parser/mod.rs
     1 +use crate::functions::resolve_internal_functions;
     2 +use crate::parser::types::{
     3 + EntrypointFn, FileHeader, Ldr, Relocation, Section, SectionMap, Symbol,
     4 +};
     5 +use std::alloc::{alloc_zeroed, Layout};
     6 +use std::collections::HashMap;
     7 +use std::ffi::{c_void, CStr};
     8 +use std::mem::size_of;
     9 +use std::ops::Index;
     10 +use std::{ptr, slice};
     11 +use windows::core::PCSTR;
     12 +use windows::Win32::System::LibraryLoader::{GetProcAddress, LoadLibraryA};
     13 +use windows::Win32::System::Memory::{
     14 + LocalFree, VirtualFree, VirtualProtect, MEM_RELEASE, PAGE_EXECUTE_READ, PAGE_READWRITE,
     15 +};
     16 +use windows::Win32::System::SystemServices::{
     17 + IMAGE_REL_AMD64_ADDR32NB, IMAGE_REL_AMD64_ADDR64, IMAGE_REL_AMD64_REL32,
     18 + IMAGE_REL_AMD64_REL32_5,
     19 +};
     20 + 
     21 +mod types;
     22 + 
     23 +pub fn parse(bytes: &mut [u8]) -> Result<(), String> {
     24 + let mut ldr = Ldr::new(bytes.as_mut_ptr());
     25 + 
     26 + println!("{:?}", ldr);
     27 + 
     28 + println!("[+] PARSE: Loading FileHeader");
     29 + ldr = load_file_header(ldr)?;
     30 + 
     31 + println!("[+] PARSE: Initializing section map");
     32 + ldr = initialize_section_map(ldr)?;
     33 + 
     34 + println!("[+] PARSE: Initializing function map");
     35 + ldr = initialize_function_map(ldr)?;
     36 + 
     37 + println!("[+] PARSE: Loading sections");
     38 + let sections: &mut [Section] = unsafe {
     39 + slice::from_raw_parts_mut(
     40 + ldr.data.offset(
     41 + (*ldr.header).SizeOfOptionalHeader as isize + size_of::<FileHeader>() as isize,
     42 + ) as *mut _ as *mut Section,
     43 + (*ldr.header).NumberOfSections as usize,
     44 + )
     45 + };
     46 + 
     47 + ldr = ldr.with_sections(sections.as_mut_ptr());
     48 + 
     49 + println!("[+] PARSE: Mapping sections to section map");
     50 + for (i, section) in sections.iter().enumerate() {
     51 + map_sections_to_section_map(&mut ldr, i, section);
     52 + }
     53 + 
     54 + println!("[+] PARSE: Loading symbols");
     55 + let symbols_offset = unsafe { ldr.data.offset((*ldr.header).PointerToSymbolTable as isize) };
     56 + 
     57 + let symbols: &mut [Symbol] = unsafe {
     58 + slice::from_raw_parts_mut(
     59 + symbols_offset as *mut _ as *mut Symbol,
     60 + (*ldr.header).NumberOfSymbols as usize,
     61 + )
     62 + };
     63 + 
     64 + ldr = ldr.with_symbols(symbols.as_mut_ptr());
     65 + 
     66 + println!("[+] PARSE: Building symbol name lookup table");
     67 + let symbol_name_lt = build_symbol_name_lookup_table(symbols_offset, unsafe {
     68 + (*ldr.header).NumberOfSymbols as isize
     69 + });
     70 + 
     71 + process_sections(&ldr, symbol_name_lt)?;
     72 + 
     73 + println!("[+] Processed sections!");
     74 + 
     75 + let mut entrypoint_ptr: *mut c_void = ptr::null_mut();
     76 + 
     77 + let mut section_map =
     78 + unsafe { (*ldr.section_map).as_slice((*ldr.header).NumberOfSections as usize) };
     79 + 
     80 + for symbol in symbols.iter() {
     81 + if unsafe { symbol.N.ShortName } == [103, 111, 0, 0, 0, 0, 0, 0] {
     82 + entrypoint_ptr = unsafe {
     83 + section_map[symbol.SectionNumber as usize - 1]
     84 + .ptr
     85 + .add(symbol.Value as usize)
     86 + } as *mut c_void;
     87 + }
     88 + }
     89 + 
     90 + if entrypoint_ptr.is_null() {
     91 + println!("[!] Couldn't find the `go` address !");
     92 + 
     93 + return Err("[!] Couldn't find the `go` address !".into());
     94 + }
     95 + 
     96 + println!("[+] Found entrypoint!");
     97 + 
     98 + let mut old = PAGE_READWRITE;
     99 + 
     100 + let hr = unsafe {
     101 + VirtualProtect(
     102 + section_map[0].ptr as *const c_void,
     103 + section_map[0].size,
     104 + PAGE_EXECUTE_READ,
     105 + &mut old,
     106 + )
     107 + };
     108 + 
     109 + if hr.0 == 0 {
     110 + println!("[!] Couldn't mark `.text` section as executable!");
     111 + }
     112 + 
     113 + // EntrypointFn
     114 + let entrypoint_fn: EntrypointFn = unsafe { std::mem::transmute(entrypoint_ptr) };
     115 + 
     116 + println!("[+] Calling entrypoint!");
     117 + 
     118 + entrypoint_fn(ptr::null_mut(), 0);
     119 + 
     120 + println!("[+] Done");
     121 + 
     122 + for (i, section) in section_map.iter_mut().enumerate() {
     123 + if !section.ptr.is_null() {
     124 + let hr = unsafe {
     125 + VirtualProtect(
     126 + section.ptr as *const c_void,
     127 + section.size,
     128 + PAGE_READWRITE,
     129 + &mut old,
     130 + )
     131 + };
     132 + 
     133 + if hr.0 == 0 {
     134 + println!("[!] Couldn't change protection to RW for Section `{}`", i);
     135 + }
     136 + 
     137 + unsafe {
     138 + section.ptr.write_bytes(0u8, section.size);
     139 + }
     140 + 
     141 + let hr = unsafe { VirtualFree(section.ptr as *mut c_void, 0, MEM_RELEASE) };
     142 + 
     143 + if hr.0 == 0 {
     144 + println!(
     145 + "[!] Failed to free memory for Section `{}` at ptr `{:p}`",
     146 + i, section.ptr
     147 + );
     148 + }
     149 + 
     150 + section.ptr = ptr::null_mut();
     151 + }
     152 + }
     153 + 
     154 + if !ldr.section_map.is_null() {
     155 + unsafe {
     156 + ldr.section_map.write_bytes(
     157 + 0u8,
     158 + (*ldr.header).NumberOfSections as usize * size_of::<SectionMap>(),
     159 + );
     160 + }
     161 + 
     162 + unsafe {
     163 + LocalFree(ldr.section_map as isize);
     164 + }
     165 + 
     166 + ldr.section_map = ptr::null_mut();
     167 + }
     168 + 
     169 + if !ldr.function_map.is_null() {
     170 + unsafe {
     171 + ldr.function_map.write_bytes(0u8, 2048);
     172 + }
     173 + 
     174 + let hr = unsafe { VirtualFree(ldr.function_map as *mut c_void, 0, MEM_RELEASE) };
     175 + 
     176 + if hr.0 == 0 {
     177 + println!("[!] Failed to free memory for function_map");
     178 + }
     179 + 
     180 + ldr.function_map = ptr::null_mut()
     181 + }
     182 + 
     183 + Ok(())
     184 +}
     185 + 
     186 +pub fn process_sections(ldr: &Ldr, symbol_name_lt: HashMap<u32, String>) -> Result<(), String> {
     187 + let sections = unsafe { (*ldr.sections).as_slice((*ldr.header).NumberOfSections as usize) };
     188 + let section_map =
     189 + unsafe { (*ldr.section_map).as_slice((*ldr.header).NumberOfSections as usize) };
     190 + let symbols = unsafe { (*ldr.symbols).as_slice((*ldr.header).NumberOfSymbols as usize) };
     191 + let mut relocations_ptr: *mut Relocation = ptr::null_mut();
     192 + 
     193 + let mut offset: u32 = 0;
     194 + let mut offset_long: u64 = 0;
     195 + let mut function_count: usize = 0;
     196 + 
     197 + for (i, section) in sections.iter().enumerate() {
     198 + println!(
     199 + "=> Processing section: `{}`",
     200 + std::str::from_utf8(&section.Name).unwrap().trim()
     201 + );
     202 + 
     203 + relocations_ptr = unsafe {
     204 + ldr.data.offset(section.PointerToRelocations as isize) as *mut _ as *mut Relocation
     205 + };
     206 + 
     207 + let relocations =
     208 + unsafe { (*relocations_ptr).as_slice(section.NumberOfRelocations as usize) };
     209 + 
     210 + for relocation in relocations.iter() {
     211 + if relocation.SymbolTableIndex > symbols.len() as u32 {
     212 + println!("[*] Failed relocation: {:?}", relocation);
     213 + return Err("Cannot continue with relocations".into());
     214 + }
     215 + 
     216 + let symbol: Symbol = symbols[relocation.SymbolTableIndex as usize];
     217 + 
     218 + if unsafe { symbol.N.ShortName[0] } != 0 {
     219 + let value = unsafe { symbol.N.ShortName };
     220 + let name = CStr::from_bytes_with_nul(&value).unwrap_or_default();
     221 + 
     222 + match relocation.Type as u32 {
     223 + IMAGE_REL_AMD64_ADDR64 => {
     224 + // Copy the virtual address for the relocation to offset_long.
     225 + // The actual address is the section pointer we cached in SectionMap plus the virtual address.
     226 + unsafe {
     227 + ptr::copy_nonoverlapping(
     228 + section_map[i].ptr.add(relocation.VirtualAddress as usize)
     229 + as *mut u64,
     230 + &mut offset_long as *mut u64,
     231 + size_of::<u64>(),
     232 + )
     233 + }
     234 + 
     235 + // Calculate the actual offset needed for relocation.
     236 + offset_long = unsafe {
     237 + section_map[(symbol.SectionNumber - 1) as usize]
     238 + .ptr
     239 + .add(offset_long as usize) as u64
     240 + };
     241 + 
     242 + // Copy the new offset we calculated into the virtual address for the relocation.
     243 + unsafe {
     244 + ptr::copy_nonoverlapping(
     245 + &mut offset_long as *mut u64,
     246 + section_map[i].ptr.add(relocation.VirtualAddress as usize)
     247 + as *mut u64,
     248 + size_of::<u64>(),
     249 + )
     250 + }
     251 + }
     252 + IMAGE_REL_AMD64_ADDR32NB => {
     253 + // Copy the virtual address for the relocation to offset.
     254 + // The actual address is the section pointer we cached in SectionMap plus the virtual address.
     255 + unsafe {
     256 + ptr::copy_nonoverlapping(
     257 + section_map[i].ptr.add(relocation.VirtualAddress as usize)
     258 + as *mut u32,
     259 + &mut offset as *mut u32,
     260 + size_of::<u32>(),
     261 + )
     262 + }
     263 + 
     264 + // Calculate the actual offset needed for relocation.
     265 + let needed_offset: u32 = unsafe {
     266 + section_map[(symbol.SectionNumber - 1) as usize]
     267 + .ptr
     268 + .add(offset as usize)
     269 + .sub(
     270 + section_map[i]
     271 + .ptr
     272 + .add(relocation.VirtualAddress as usize)
     273 + .add(4) as usize,
     274 + ) as u32
     275 + };
     276 + 
     277 + if needed_offset > u32::MAX {
     278 + println!("[*] Failed relocation: {:?}", relocation);
     279 + return Err("[!] The relocation is out of bounds, something probably went wrong...".into());
     280 + }
     281 + 
     282 + offset = needed_offset;
     283 + 
     284 + // Copy the new offset we calculated into the virtual address for the relocation.
     285 + unsafe {
     286 + ptr::copy_nonoverlapping(
     287 + &mut offset as *mut u32,
     288 + section_map[i].ptr.add(relocation.VirtualAddress as usize)
     289 + as *mut u32,
     290 + size_of::<u32>(),
     291 + )
     292 + }
     293 + }
     294 + IMAGE_REL_AMD64_REL32..=IMAGE_REL_AMD64_REL32_5 => {
     295 + unsafe {
     296 + ptr::copy_nonoverlapping(
     297 + section_map[i].ptr.add(relocation.VirtualAddress as usize)
     298 + as *mut u32,
     299 + &mut offset as *mut u32,
     300 + size_of::<u32>(),
     301 + )
     302 + }
     303 + 
     304 + // Check for overflows
     305 + unsafe {
     306 + if section_map[(symbol.SectionNumber - 1) as usize].ptr.sub(
     307 + section_map[i]
     308 + .ptr
     309 + .add(relocation.VirtualAddress as usize)
     310 + .add(4) as usize,
     311 + ) as u32
     312 + > u32::MAX
     313 + {
     314 + return Err("[!] The relocation is out of bounds, something probably went wrong...".into());
     315 + }
     316 + }
     317 + 
     318 + // Calculate the actual offset needed for relocation.
     319 + offset = unsafe {
     320 + section_map[(symbol.SectionNumber - 1) as usize]
     321 + .ptr
     322 + .sub(relocation.Type as usize - 4)
     323 + .sub(
     324 + section_map[i]
     325 + .ptr
     326 + .add(relocation.VirtualAddress as usize)
     327 + .add(4) as usize,
     328 + ) as u32
     329 + };
     330 + 
     331 + // Copy the new offset we calculated into the virtual address for the relocation.
     332 + unsafe {
     333 + ptr::copy_nonoverlapping(
     334 + &mut offset as *mut u32,
     335 + section_map[i].ptr.add(relocation.VirtualAddress as usize)
     336 + as *mut u32,
     337 + size_of::<u32>(),
     338 + )
     339 + }
     340 + }
     341 + _ => {
     342 + println!("[!] Relocation type not found: {}", relocation.Type)
     343 + }
     344 + }
     345 + } else {
     346 + let value = unsafe { symbol.N.LongName[1] };
     347 + let unknown = "<unknown>".to_string();
     348 + let mut symbol_name: &str = symbol_name_lt.get(&value).unwrap_or(&unknown);
     349 + 
     350 + if symbol_name == &unknown {
     351 + println!("[*] Failed symbol: {:?}", symbol);
     352 + println!("[*] Failed relocation: {:?}", relocation);
     353 + return Err("[!] Unable to resolve symbol".into());
     354 + }
     355 + 
     356 + let func_ptr = get_external_function_ptr(symbol_name)?;
     357 + 
     358 + if relocation.Type as u32 == IMAGE_REL_AMD64_REL32 && func_ptr != 0 {
     359 + let needed_offset = unsafe {
     360 + ldr.function_map.add(function_count * size_of::<u64>()).sub(
     361 + section_map[i]
     362 + .ptr
     363 + .add(relocation.VirtualAddress as usize)
     364 + .add(4) as usize,
     365 + ) as u32
     366 + };
     367 + 
     368 + if needed_offset > u32::MAX {
     369 + println!("[*] Failed relocation: {:?}", relocation);
     370 + return Err(
     371 + "[!] The relocation is out of bounds, something probably went wrong..."
     372 + .into(),
     373 + );
     374 + }
     375 + 
     376 + unsafe {
     377 + ptr::copy_nonoverlapping(
     378 + &func_ptr,
     379 + ldr.function_map.add(function_count * size_of::<u64>()) as *mut isize,
     380 + size_of::<u64>(),
     381 + )
     382 + }
     383 + 
     384 + offset = needed_offset;
     385 + 
     386 + unsafe {
     387 + ptr::copy_nonoverlapping(
     388 + &mut offset as *mut u32,
     389 + section_map[i].ptr.add(relocation.VirtualAddress as usize) as *mut u32,
     390 + size_of::<u32>(),
     391 + )
     392 + }
     393 + 
     394 + function_count = function_count + 1;
     395 + } else if relocation.Type as u32 == IMAGE_REL_AMD64_REL32 {
     396 + unsafe {
     397 + ptr::copy_nonoverlapping(
     398 + section_map[i].ptr.add(relocation.VirtualAddress as usize) as *mut u32,
     399 + &mut offset as *mut u32,
     400 + size_of::<u32>(),
     401 + )
     402 + }
     403 + 
     404 + let needed_offset = unsafe {
     405 + section_map[(symbol.SectionNumber - 1) as usize].ptr.sub(
     406 + section_map[i]
     407 + .ptr
     408 + .add(relocation.VirtualAddress as usize)
     409 + .add(4) as usize,
     410 + ) as u32
     411 + };
     412 + 
     413 + if needed_offset > u32::MAX {
     414 + println!("[*] Failed relocation: {:?}", relocation);
     415 + return Err(
     416 + "[!] The relocation is out of bounds, something probably went wrong..."
     417 + .into(),
     418 + );
     419 + }
     420 + 
     421 + offset = offset + needed_offset;
     422 + 
     423 + unsafe {
     424 + ptr::copy_nonoverlapping(
     425 + &mut offset as *mut u32,
     426 + section_map[i].ptr.add(relocation.VirtualAddress as usize) as *mut u32,
     427 + size_of::<u32>(),
     428 + )
     429 + }
     430 + } else {
     431 + println!("[*] Failed relocation: {:?}", relocation);
     432 + println!("[!] Relocation type not found: {}", relocation.Type)
     433 + }
     434 + }
     435 + }
     436 + }
     437 + 
     438 + Ok(())
     439 +}
     440 + 
     441 +pub fn load_file_header(ldr: Ldr) -> Result<Ldr, String> {
     442 + let mut file_header_slice: &mut [u8] =
     443 + unsafe { slice::from_raw_parts_mut(ldr.data, size_of::<FileHeader>()) };
     444 + 
     445 + let mut file_header_ptr = file_header_slice as *mut _ as *mut FileHeader;
     446 + 
     447 + if file_header_ptr.is_null() {
     448 + return Err("Unable to load file header".into());
     449 + }
     450 + 
     451 + Ok(ldr.with_header(file_header_ptr))
     452 +}
     453 + 
     454 +pub fn initialize_section_map(ldr: Ldr) -> Result<Ldr, String> {
     455 + let section_map_size =
     456 + unsafe { size_of::<Section>() * (*ldr.header).NumberOfSections as usize };
     457 + 
     458 + let mut section_map_vec =
     459 + Vec::<SectionMap>::with_capacity(section_map_size / size_of::<SectionMap>());
     460 + 
     461 + let section_map_ptr = section_map_vec.as_mut_ptr();
     462 + 
     463 + std::mem::forget(section_map_vec);
     464 + 
     465 + Ok(ldr.with_section_map(section_map_ptr))
     466 +}
     467 + 
     468 +pub fn initialize_function_map(ldr: Ldr) -> Result<Ldr, String> {
     469 + let layout = Layout::from_size_align(2048, std::mem::align_of::<i8>()).unwrap();
     470 + let ptr = unsafe { alloc_zeroed(layout) };
     471 + 
     472 + let mut function_map_vec =
     473 + unsafe { Vec::from_raw_parts(ptr as *mut i8, layout.size(), layout.size()) };
     474 + 
     475 + let function_map_ptr = function_map_vec.as_mut_ptr();
     476 + 
     477 + std::mem::forget(function_map_vec);
     478 + 
     479 + Ok(ldr.with_function_map(function_map_ptr))
     480 +}
     481 + 
     482 +pub fn map_sections_to_section_map(ldr: &mut Ldr, index: usize, section: &Section) {
     483 + println!(
     484 + " => Working on section: `{}`",
     485 + std::str::from_utf8(&section.Name).unwrap().trim()
     486 + );
     487 + 
     488 + unsafe { (*ldr.section_map.offset(index as isize)).size = section.SizeOfRawData as usize }
     489 + 
     490 + let mut vec =
     491 + Vec::<u8>::with_capacity(unsafe { (*ldr.section_map.offset(index as isize)).size });
     492 + let ptr = vec.as_mut_ptr() as *mut i8;
     493 + 
     494 + unsafe { (*ldr.section_map.offset(index as isize)).ptr = ptr };
     495 + std::mem::forget(vec);
     496 + 
     497 + let src = ldr.data as *const u8;
     498 + let dest = unsafe { (*ldr.section_map.offset(index as isize)).ptr as *mut u8 };
     499 + 
     500 + unsafe {
     501 + ptr::copy_nonoverlapping(
     502 + src.offset(section.PointerToRawData as isize),
     503 + dest,
     504 + section.SizeOfRawData as usize,
     505 + );
     506 + }
     507 +}
     508 + 
     509 +pub fn build_symbol_name_lookup_table(
     510 + symbols_offset: *mut u8,
     511 + num_of_symbols: isize,
     512 +) -> HashMap<u32, String> {
     513 + let offset = unsafe { symbols_offset.offset(size_of::<Symbol>() as isize * num_of_symbols) };
     514 + 
     515 + let length: u32 = unsafe {
     516 + let length_ptr = slice::from_raw_parts(offset as *const u8, size_of::<u32>());
     517 + 
     518 + *(length_ptr.as_ptr() as *const u32)
     519 + };
     520 + 
     521 + let string_table_slice: &[u8] =
     522 + unsafe { slice::from_raw_parts(offset.offset(4) as *const u8, length as usize - 4) };
     523 + 
     524 + let mut string_table: HashMap<u32, String> = HashMap::new();
     525 + let mut buffer: Vec<u8> = vec![];
     526 + 
     527 + for (off, s) in string_table_slice.iter().enumerate() {
     528 + if *s == 0 {
     529 + string_table.insert(
     530 + (off - buffer.len() + 4) as u32,
     531 + String::from_utf8(buffer).unwrap_or("<unknown>".to_string()),
     532 + );
     533 + buffer = vec![];
     534 + continue;
     535 + }
     536 + 
     537 + buffer.push(*s);
     538 + }
     539 + 
     540 + return string_table;
     541 +}
     542 + 
     543 +pub fn get_external_function_ptr(symbol: &str) -> Result<isize, String> {
     544 + let symbol_prefix = "__imp_";
     545 + let beacon_prefix = "__imp_Beacon";
     546 + let wide_char_prefix = "__imp_toWideChar";
     547 + 
     548 + if symbol == "<unknown>" || symbol.len() < 6 || !symbol.starts_with(symbol_prefix) {
     549 + println!("[!] Function with unknown naming convention! [{}]", symbol);
     550 + 
     551 + return Err(format!(
     552 + "[!] Function with unknown naming convention! [{}]",
     553 + symbol
     554 + ));
     555 + }
     556 + 
     557 + let mut symbol_name = symbol.to_string();
     558 + 
     559 + let _ = symbol_name.drain(0..6);
     560 + 
     561 + if symbol.starts_with(beacon_prefix) || symbol.starts_with(wide_char_prefix) {
     562 + let func_ptr = resolve_internal_functions(&symbol_name)?;
     563 + return Ok(func_ptr);
     564 + }
     565 + 
     566 + let library_function: Vec<_> = symbol_name
     567 + .split(&['$', '@'][..])
     568 + .map(|s| format!("{}\0", s))
     569 + .collect();
     570 + 
     571 + if library_function.len() != 2 {
     572 + println!("[!] Function with unknown naming convention! [{}]", symbol);
     573 + return Err(format!(
     574 + "[!] Function with unknown naming convention! [{}]",
     575 + symbol
     576 + ));
     577 + }
     578 + 
     579 + let mut library_name = library_function.get(0).unwrap().as_bytes();
     580 + let mut function_name = library_function.get(1).unwrap().as_bytes();
     581 + 
     582 + let library_handle =
     583 + unsafe { LoadLibraryA(PCSTR::from_raw(library_name.as_ptr())).unwrap_or_default() };
     584 + 
     585 + if library_handle.is_invalid() {
     586 + println!(
     587 + "[!] Error loading library: [{}]",
     588 + std::str::from_utf8(library_name).unwrap_or_default()
     589 + );
     590 + 
     591 + return Err(format!(
     592 + "[!] Error loading library: [{}]",
     593 + std::str::from_utf8(library_name).unwrap_or_default()
     594 + ));
     595 + }
     596 + 
     597 + return match unsafe { GetProcAddress(library_handle, PCSTR::from_raw(function_name.as_ptr())) }
     598 + {
     599 + None => {
     600 + println!(
     601 + "[!] Error loading function: [{}]",
     602 + std::str::from_utf8(function_name).unwrap_or_default()
     603 + );
     604 + 
     605 + Err(format!(
     606 + "[!] Error loading function: [{}]",
     607 + std::str::from_utf8(function_name).unwrap_or_default()
     608 + ))
     609 + }
     610 + Some(f) => Ok(f as isize),
     611 + };
     612 +}
     613 + 
  • ■ ■ ■ ■ ■ ■
    src/parser/types.rs
     1 +use std::fmt::{Debug, Formatter};
     2 +use std::slice;
     3 + 
     4 +pub type EntrypointFn = fn(*mut i8, u32);
     5 + 
     6 +#[derive(Debug, Clone, Copy)]
     7 +#[repr(C)]
     8 +pub struct Ldr {
     9 + pub data: *mut u8,
     10 + pub header: *mut FileHeader,
     11 + pub sections: *mut Section,
     12 + pub relocations: *mut Relocation,
     13 + pub symbols: *mut Symbol,
     14 + pub section_map: *mut SectionMap,
     15 + pub function_map: *mut i8,
     16 +}
     17 + 
     18 +impl Ldr {
     19 + pub fn new(data: *mut u8) -> Ldr {
     20 + Ldr {
     21 + data,
     22 + header: std::ptr::null_mut(),
     23 + sections: std::ptr::null_mut(),
     24 + relocations: std::ptr::null_mut(),
     25 + symbols: std::ptr::null_mut(),
     26 + section_map: std::ptr::null_mut(),
     27 + function_map: std::ptr::null_mut(),
     28 + }
     29 + }
     30 + 
     31 + pub fn with_data(&self, data: *mut u8) -> Ldr {
     32 + Ldr {
     33 + data,
     34 + header: self.header,
     35 + sections: self.sections,
     36 + relocations: self.relocations,
     37 + symbols: self.symbols,
     38 + section_map: self.section_map,
     39 + function_map: self.function_map,
     40 + }
     41 + }
     42 + pub fn with_header(&self, header: *mut FileHeader) -> Ldr {
     43 + Ldr {
     44 + data: self.data,
     45 + header,
     46 + sections: self.sections,
     47 + relocations: self.relocations,
     48 + symbols: self.symbols,
     49 + section_map: self.section_map,
     50 + function_map: self.function_map,
     51 + }
     52 + }
     53 + pub fn with_sections(&self, sections: *mut Section) -> Ldr {
     54 + Ldr {
     55 + data: self.data,
     56 + header: self.header,
     57 + sections,
     58 + relocations: self.relocations,
     59 + symbols: self.symbols,
     60 + section_map: self.section_map,
     61 + function_map: self.function_map,
     62 + }
     63 + }
     64 + pub fn with_relocations(&self, relocations: *mut Relocation) -> Ldr {
     65 + Ldr {
     66 + data: self.data,
     67 + header: self.header,
     68 + sections: self.sections,
     69 + relocations,
     70 + symbols: self.symbols,
     71 + section_map: self.section_map,
     72 + function_map: self.function_map,
     73 + }
     74 + }
     75 + pub fn with_symbols(&self, symbols: *mut Symbol) -> Ldr {
     76 + Ldr {
     77 + data: self.data,
     78 + header: self.header,
     79 + sections: self.sections,
     80 + relocations: self.relocations,
     81 + symbols,
     82 + section_map: self.section_map,
     83 + function_map: self.function_map,
     84 + }
     85 + }
     86 + pub fn with_section_map(&self, section_map: *mut SectionMap) -> Ldr {
     87 + Ldr {
     88 + data: self.data,
     89 + header: self.header,
     90 + sections: self.sections,
     91 + relocations: self.relocations,
     92 + symbols: self.symbols,
     93 + section_map,
     94 + function_map: self.function_map,
     95 + }
     96 + }
     97 + pub fn with_function_map(&self, function_map: *mut i8) -> Ldr {
     98 + Ldr {
     99 + data: self.data,
     100 + header: self.header,
     101 + sections: self.sections,
     102 + relocations: self.relocations,
     103 + symbols: self.symbols,
     104 + section_map: self.section_map,
     105 + function_map,
     106 + }
     107 + }
     108 +}
     109 + 
     110 +#[derive(Debug, Copy, Clone)]
     111 +#[repr(C)]
     112 +pub struct FileHeader {
     113 + pub Machine: u16,
     114 + pub NumberOfSections: u16,
     115 + pub TimeDateStamp: u32,
     116 + pub PointerToSymbolTable: u32,
     117 + pub NumberOfSymbols: u32,
     118 + pub SizeOfOptionalHeader: u16,
     119 + pub Characteristics: u16,
     120 +}
     121 + 
     122 +#[derive(Debug, Copy, Clone)]
     123 +#[repr(C)]
     124 +pub struct Section {
     125 + pub Name: [u8; 8],
     126 + pub VirtualSize: u32,
     127 + pub VirtualAddress: u32,
     128 + pub SizeOfRawData: u32,
     129 + pub PointerToRawData: u32,
     130 + pub PointerToRelocations: u32,
     131 + pub PointerToLinenumbers: u32,
     132 + pub NumberOfRelocations: u16,
     133 + pub NumberOfLinenumbers: u16,
     134 + pub Characteristics: u32,
     135 +}
     136 + 
     137 +impl Section {
     138 + pub fn as_slice<'module>(&mut self, len: usize) -> &'module mut [Section] {
     139 + unsafe { slice::from_raw_parts_mut(self as *mut Section, len) }
     140 + }
     141 +}
     142 + 
     143 +#[derive(Debug, Copy, Clone)]
     144 +#[repr(C, packed(2))]
     145 +pub struct Relocation {
     146 + pub VirtualAddress: u32,
     147 + pub SymbolTableIndex: u32,
     148 + pub Type: u16,
     149 +}
     150 + 
     151 +impl Relocation {
     152 + pub fn as_slice<'module>(&mut self, len: usize) -> &'module mut [Relocation] {
     153 + unsafe { slice::from_raw_parts_mut(self as *mut Relocation, len) }
     154 + }
     155 +}
     156 + 
     157 +#[derive(Debug, Copy, Clone)]
     158 +#[repr(C, packed(2))]
     159 +pub struct Symbol {
     160 + pub N: ShortOrLongName,
     161 + pub Value: u32,
     162 + pub SectionNumber: i16,
     163 + pub Type: u16,
     164 + pub StorageClass: u8,
     165 + pub NumberOfAuxSymbols: u8,
     166 +}
     167 + 
     168 +impl Symbol {
     169 + pub fn as_slice<'module>(&mut self, len: usize) -> &'module mut [Symbol] {
     170 + unsafe { slice::from_raw_parts_mut(self as *mut Symbol, len) }
     171 + }
     172 +}
     173 + 
     174 +#[derive(Copy, Clone)]
     175 +#[repr(C, packed(2))]
     176 +pub union ShortOrLongName {
     177 + pub ShortName: [u8; 8],
     178 + pub Name: SymbolName,
     179 + pub LongName: [u32; 2],
     180 +}
     181 + 
     182 +impl Debug for ShortOrLongName {
     183 + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
     184 + write!(
     185 + f,
     186 + "ShortOrLongName {{ ShortName: {:?}, LongName: {:?} }}",
     187 + unsafe { self.ShortName },
     188 + // unsafe { self.Name },
     189 + unsafe { self.LongName }
     190 + )
     191 + }
     192 +}
     193 + 
     194 +#[derive(Copy, Clone)]
     195 +#[repr(C, packed(2))]
     196 +pub union SymbolName {
     197 + pub Short: u32,
     198 + pub Long: u32,
     199 +}
     200 + 
     201 +impl Debug for SymbolName {
     202 + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
     203 + write!(
     204 + f,
     205 + "SymbolName {{ Short: {:?}, Long: {:?} }}",
     206 + unsafe { self.Short },
     207 + unsafe { self.Long }
     208 + )
     209 + }
     210 +}
     211 + 
     212 +#[derive(Debug, Copy, Clone)]
     213 +#[repr(C)]
     214 +pub struct SectionMap {
     215 + pub ptr: *mut i8,
     216 + pub size: usize,
     217 +}
     218 + 
     219 +impl SectionMap {
     220 + pub fn as_slice<'module>(&mut self, len: usize) -> &'module mut [SectionMap] {
     221 + unsafe { slice::from_raw_parts_mut(self as *mut SectionMap, len) }
     222 + }
     223 +}
     224 + 
  • ■ ■ ■ ■ ■
    test/Makefile
     1 +all:
     2 + x86_64-w64-mingw32-gcc -Os -o test.o -c test.c
     3 + 
     4 +clean:
     5 + rm test.o
  • ■ ■ ■ ■ ■ ■
    test/test.c
     1 +#include <windows.h>
     2 +#include <stdio.h>
     3 +#include <lm.h>
     4 +#include <dsgetdc.h>
     5 +//#include "beacon.h"
     6 + 
     7 +DECLSPEC_IMPORT DWORD WINAPI NETAPI32$DsGetDcNameA(LPVOID, LPVOID, LPVOID, LPVOID, ULONG, LPVOID);
     8 +DECLSPEC_IMPORT DWORD WINAPI NETAPI32$NetApiBufferFree(LPVOID);
     9 +WINBASEAPI int __cdecl MSVCRT$printf(const char * __restrict__ _Format,...);
     10 + 
     11 +char* TestGlobalString = "This is a global string";
     12 +int testvalue = 0;
     13 + 
     14 +int test(void){
     15 + MSVCRT$printf("Test String from `test`\n");
     16 + testvalue = 1;
     17 + return 0;
     18 +}
     19 + 
     20 +int test2(void){
     21 + MSVCRT$printf("Test String from `test2`\n");
     22 + return 0;
     23 +}
     24 + 
     25 +int go(char * args, unsigned long alen) {
     26 + DWORD dwRet;
     27 + PDOMAIN_CONTROLLER_INFO pdcInfo;
     28 + // BeaconPrintf(1, "This GlobalString \"%s\"\n", TestGlobalString);
     29 + MSVCRT$printf("This GlobalString \"%s\"\n", TestGlobalString);
     30 + MSVCRT$printf("Test Value: %d\n", testvalue);
     31 + (void)test();
     32 + MSVCRT$printf("Test ValueBack: %d\n", testvalue);
     33 + (void)test2();
     34 + dwRet = NETAPI32$DsGetDcNameA(NULL, NULL, NULL, NULL, 0, &pdcInfo);
     35 + 
     36 + if (ERROR_SUCCESS == dwRet) {
     37 + MSVCRT$printf("%s", pdcInfo->DomainName);
     38 + } else {
     39 + MSVCRT$printf("Failed");
     40 + }
     41 + 
     42 + NETAPI32$NetApiBufferFree(pdcInfo);
     43 +}
  • test/test.o
    Binary file.
Please wait...
Page is in error, reload to recover