From c217fc31b66da1dca5bed562bd4f51ec269b0d0c Mon Sep 17 00:00:00 2001 From: "mr.exodia" Date: Sun, 25 Aug 2013 17:13:57 +0200 Subject: [PATCH] first commit --- .gitignore | 9 + Release/TitanEngine.dll | Bin 0 -> 668672 bytes Release/TitanEngine.exp | Bin 0 -> 59755 bytes Release/TitanEngine.lib | Bin 0 -> 104582 bytes TitanEngine.sln | 26 + TitanEngine/HEADER.BMP | Bin 0 -> 88616 bytes TitanEngine/LOGO.bmp | Bin 0 -> 3656 bytes TitanEngine/LzmaDec.cpp | 1016 + TitanEngine/LzmaDec.h | 223 + TitanEngine/LzmaTypes.h | 211 + TitanEngine/MAINICON.ico | Bin 0 -> 116222 bytes TitanEngine/ReadMe.txt | 41 + TitanEngine/TitanEngine.cbp | 72 + TitanEngine/TitanEngine.cpp | 29032 ++++++++++++++++ TitanEngine/TitanEngine.def | 407 + TitanEngine/TitanEngine.rc | 156 + TitanEngine/TitanEngine.vcproj | 521 + TitanEngine/TitanEngine.vcxproj | 251 + TitanEngine/TitanEngine.vcxproj.filters | 80 + TitanEngine/TitanEngine.vcxproj.user | 3 + TitanEngine/aplib.h | 66 + TitanEngine/aplib.lib | Bin 0 -> 12250 bytes TitanEngine/definitions.h | 448 + TitanEngine/distorm.h | 104 + TitanEngine/distorm_x64.lib | Bin 0 -> 412064 bytes TitanEngine/distorm_x86.lib | Bin 0 -> 412642 bytes TitanEngine/dllmain.cpp | 19 + TitanEngine/resource.h | 36 + TitanEngine/stdafx.cpp | 8 + TitanEngine/stdafx.h | 852 + TitanEngine/targetver.h | 24 + .../LibraryLoader/x32/LibraryLoader.asm | 31 + .../LibraryLoader/x32/LibraryLoader.exe | Bin 0 -> 1536 bytes .../LibraryLoader/x64/LibraryLoader.asm | 31 + .../LibraryLoader/x64/LibraryLoader.exe | Bin 0 -> 1536 bytes x64/Release/TitanEngine.dll | Bin 0 -> 638464 bytes x64/Release/TitanEngine.exp | Bin 0 -> 69539 bytes x64/Release/TitanEngine.lib | Bin 0 -> 129000 bytes 38 files changed, 33667 insertions(+) create mode 100644 .gitignore create mode 100644 Release/TitanEngine.dll create mode 100644 Release/TitanEngine.exp create mode 100644 Release/TitanEngine.lib create mode 100644 TitanEngine.sln create mode 100644 TitanEngine/HEADER.BMP create mode 100644 TitanEngine/LOGO.bmp create mode 100644 TitanEngine/LzmaDec.cpp create mode 100644 TitanEngine/LzmaDec.h create mode 100644 TitanEngine/LzmaTypes.h create mode 100644 TitanEngine/MAINICON.ico create mode 100644 TitanEngine/ReadMe.txt create mode 100644 TitanEngine/TitanEngine.cbp create mode 100644 TitanEngine/TitanEngine.cpp create mode 100644 TitanEngine/TitanEngine.def create mode 100644 TitanEngine/TitanEngine.rc create mode 100644 TitanEngine/TitanEngine.vcproj create mode 100644 TitanEngine/TitanEngine.vcxproj create mode 100644 TitanEngine/TitanEngine.vcxproj.filters create mode 100644 TitanEngine/TitanEngine.vcxproj.user create mode 100644 TitanEngine/aplib.h create mode 100644 TitanEngine/aplib.lib create mode 100644 TitanEngine/definitions.h create mode 100644 TitanEngine/distorm.h create mode 100644 TitanEngine/distorm_x64.lib create mode 100644 TitanEngine/distorm_x86.lib create mode 100644 TitanEngine/dllmain.cpp create mode 100644 TitanEngine/resource.h create mode 100644 TitanEngine/stdafx.cpp create mode 100644 TitanEngine/stdafx.h create mode 100644 TitanEngine/targetver.h create mode 100644 TitanEngineLoaders/LibraryLoader/x32/LibraryLoader.asm create mode 100644 TitanEngineLoaders/LibraryLoader/x32/LibraryLoader.exe create mode 100644 TitanEngineLoaders/LibraryLoader/x64/LibraryLoader.asm create mode 100644 TitanEngineLoaders/LibraryLoader/x64/LibraryLoader.exe create mode 100644 x64/Release/TitanEngine.dll create mode 100644 x64/Release/TitanEngine.exp create mode 100644 x64/Release/TitanEngine.lib diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aa0a9fe --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +/ipch +/TitanEngine/bin +/TitanEngine/obj +/TitanEngine/x64 +/TitanEngine/Release +*.layout +*.depend +*.sdf +*.suo \ No newline at end of file diff --git a/Release/TitanEngine.dll b/Release/TitanEngine.dll new file mode 100644 index 0000000000000000000000000000000000000000..0a2253f4409ca41757c5622b5fcd9e9c93eb97dc GIT binary patch literal 668672 zcmeFa4}4uknKypZo0haqxhW(Npg_S2)gS_`*qVY(;9$0L;U;ihR1j3aSp0*KKvfD2 zHy1cPy^7eZpy(E@S{0;fDS-``Voiz`jo8(`yVZ?uSI+TtwYydg(6#UP`#dw}oST0w ziu>;VKELuI_sq;Q|DJiCXP$Xx=9%ocubrEtS8M{~1B@;U_+R zcxu!1XHM#^xbT^iE^UABjdQQR;e+qF;hpcF`|fvs-~%7*nES44=HAfxfw}Mfz})jM zzGUwEKX~;ur_Y)-W1cDclc(&t?5A(KeWv}t_slsn|A=t!ne%6U-Nf&}@6X>jd*)6F z7iJ!h-@RSGo%wV8_MZ8wnVaPIn3+G3-+J?VqWreK_ucI*dvs57PAYX_#njY^#~j;c z(}q)1PMTRUBb7R9YAW?7VkDLF3iz$TM-FlP;`fwPYHF&2;pjJ&s}>|)w`&HHmm(2> zgpGbRnES!h)K||;rPe<=HMNe(tEy6)9FD-Ke?v1<-4~6DJCq>W*^l;3^zZbJYgTk1 z@#kltKWrcSs$Gq;%uS`PI{k*L-`VlbRO*F?5zW4D#P8YoP5fI5GC5trQgd!&rPETW zkKyN6W8nHvzv0Fk-i;*bEBc(e0DbNNeB$3ymUqK7@B1JC2UZ{fI7od2zmHE(KmjO~ zYA%cT{{w$E2J+sX){?V7=Vhx}57f=iO|2>RcO2{GtJ)6K&C}4djTPaHu=1?_uri!- zR=@XeSA1uC^bh$9d*%!}d)R_Ohav$#`}AkG{`mT{Uw`)Ur?9d*)p@kSuL3-YXVBSA zLJTiPVuejyibTdDkuc#|NStC5hmp86kyxh%CZbPFWm3yi?W+K^JiR=%yux!vOkWqF zcdoOiuyW6VO!p=Lc=;O7+2c-Gp7OGLfQ*F#;Cp#LouBLGeb1@&vc6k|^t|7Ozs|m# zg*`)H_ZL>~PjxhU`FhXU&w}`$m)+g!<@W=hrwP#B!pgm=j-!@WmYlt4%A8i;Z>dZb zwpIhp&C4rU`kXfZQjPPRnn5%Tjmy>!ip25qd)oX9{&e6#VQXbrBk<0goIg+DM-R{T z|Gne0N>j*k$g<}+S)@73-sR`}K{-|_ZxVFRh7?O*kBw7>OB6Set2rbf8vYU{tt}7|EG|W*_^w)_-y9_3|dY{pbN2u6&I#DPK-zD{fP5& z7rOb~o+YqJMkn|P25s^I!uVu1Ppy7i6{xtguCTHy)iE7&%U}gHFi5y}h4090uA9sB zXQOndYA^-$iRsPZxtYzg7BcCle1aROw4!%A6z>U{vw&s*~A30^FDBP zc3)u&TCh(A3u{>H?7M9a@RWA;p?#}s?)rp}iqL4uvp?J(PDN@swO67eodE6a+A{|; zwg{62-$lLcRf4Wk(SPy4ft>%5CPA2uE$#iU0|#3Dt2Gw1F(Wk%w2|q49s{N0WUwf$ z2MVQIvjwN<+WJc`eb+e$rzz;rFu7Iz~6^owQ!323^HDjG{nT6r<5N$1h5DTR^CJKs2}TcxE+ z9r^u*rz+amos#MB?=%H1>LCVDA6pcDHmn5oP1#uCWk(h~<8OB=Q%Q0lJ$LOn4f=Be zzcpwa$|>&rBk_Bz7Tj)PwZDF)#wPGv0nw}Yy$TiU1cbh19<5x4o^)6QN3=Pt2p%AU z^ZQHZA2CHHq*4#7ZS!9d^+(%rpzd;m;d{z4oaydDM5)AV7ze4mxC4P0%YrR8zaQvs zl%$odKzQ7^&ZQBWWiMO?>do$m{KP8)E3S3wy;Mw?S|b_fOz)U~6h z=8LCA0z|>VDqN;$Q!mokE{oxmFp|c^s8bGMe zSKh?MN|h{D#w=B={C;Wp;!?)T|99Z)7fTFH9SmQ+3i#*a>%_-6W(H$NJT8I!eq}gf zZ$W=JWq~gAMBdZ@I+iz}XbgSCfhxb(HyRGCDm*pC&4WJnXCAHk(Jzb?CQ!~lV1TmK zt&!AwpGb*Lk$TXMMe6+ovcyO|)DL~Ne~iA=H<`Y=8)JqQ<1l}yB4oPvsjzdMonCgQ zm*1IgUE=14JPD>-mblqnUVbR^XmkBJGXdE-ebCv?%;8C17SXNsT`$Z84kRAw(1jQD zFL*ZiJiZGnw}Y#mL8RvZw51jWmCm10?>aj)?=&}$1*vMtP@w&a>-y)XogI?C!|NRK znyMB&`^TFWu>lV^FY>ZG(oNM+GeLA-bF~Dk7CXCdtOkJR>`pf?Vq$j4%kNINE?m&> z=C``eHq=0k+HDM2VqtDCt2S1eri3zyk^s>9q?^@5< zRl2aI-p%gt@`z}j2JIgO69-TtA?B`odVV^)L(7V1f;Xt-O1#%|B_e5o6ACg^|-cUJ3qu4wCM8E9sug`F~oZTw-Ne_$*}IbI^p3 z9B}@{c44*iFTsz9U?YyJAo?1xw&GffTDsq>rL?~f3p@|JbfE5fFcHM5OfGB^^^ELu zt^UUpl9d!*cts~>ohn_yjnlSwjc(gNqr?WOa~ShUO{>3DAqJeEbFv}1t#*DMzRHfw z+-PJ5oS(&=`5EU1CAD#ucEEotk~xA{28%tVzSV!r>jh7;@XgmWI#9>8FJ^M6 z>R!GUarI`R>kuK*LE%42aYy-uJ@xG!L=~{&&D!(mv>IUSF62<_52V9-)(*SM15Ct( z*)549oZU0s1t!8EJPGd$ZQ@eKHG7zU3Jh5RKZop zQV!mMI<;%;E3DjipyL$V86TaYHE182wgN?Z`F(BvReRKmK+_w$Hr|Ye{&npsm(PWj zHE8zNP@`EQl!_xFep6=~>Z^hHWfVHY#fnK+jW_e;nyG(88Wfg}x(JNA@Id!eX1ZLc ztHe)3dA6rwV3YM#luwpe#eFRA3I09Mag-;)oPT>Lz1vt3yb_{S#q=@w8e1AQ3bR@p zRa6hlZ1Z0q74=V$Ow#M9Pj{o`#r~V#(|!v`pp_kb z-Z`f7wYKuR{z{cEiYlk#r%bRjG5m@Jzv4_Cev!f)P-~e16=QK(ZCAbtE*J(E05vE} zxd7kF1^56L;4iu0c(24yumJx$)z^Bpxoh3ESq^{rv=Nv11}RK{VLMJ^F?=M%C9>xH zOMYcA95cehuS+n3tZu~KHFiFr27Fq2T+u32HJ1O{u-^c?nOLEpeyzb9ZDtf6jZW=t z$Ei?eFh^d1Aw1`wc!ok6-d*=^mMFdfl2);7C4!3O%pFwW+Se#yfZvY ze6=<{nhtFHPl`mlbiqtm(u=p6{+eF=({9^~FhSaAD;Q=C+6p6*_TuipUN0^Bb5HprXU{tJ5(|~D>ijm!|Y@(34fa~MB!AYW!eC*0C%t_uAOBj3M#9~d3l_P!cxsxLcPptjnGf$YU3m2BOYrz(dbxf zWkTEUH~lp_$!~r+hRK$lRmNnZPgX@6ouask75a@Pj;0;8tB%Ahve+3}c>)Xw;r}`$W zjjKf!?w!7u ziZ3OmRkQa%HbZXSBBUr9dBQf`?F1nGz%4|=nw1dmW73Nz^`X;=XfNNF&TnnVSHYMN zW+0el64M=OF34F2`jL5bcGnBpx4}~JVc@}QS<t*o_g|D@^J0*d;hsxj> znrNk+-H5G(E{M8O#0?Tx`aWY6eHXU&PiFrZLXUxT>R9;c=MTmRX6F*j6s3G0%(}Z| zDPPscjvP!svu}n(&a9rn-$JiV!9|+Olao=>uc!YW43LW|L~f zgm*e%3oAE*UMfjzmF={Wqad$2haMcL+bDvE8`kWlmqiV_DMHGHl|!kUUhe^{8Cp~prn?>KR@ybT z0xI1Clfp9!2#~^4^QF8YG0_i&-?1byKO%|t)G7`HYdBE%AR2CjkAXz#D4MpMKHy_l zo4-ni26hpc-vX)y0Xu1N;B5C=au}c_4us3{+qI9|yw)Y@AIi`jnJ0X2VCsR`M3OBXhCog&I?Z%Lo9Ds01^ug;|DP(>i%4rJtnf0 zi~588PY5iW_7SC_v7J2I?U5=9=?OzA#HX+7<_*rwXWSVWuesK1eAs8)Z zD?eX0il4i-u6w?GzS=crzAE+sghW1Ad@%aj0bNbvoMHaR9$2Z^k93R>xclf6Dru)^*S0tn-`M5t&TF;Pn8NGP zKy$5#h!PPxSmbCBpW$^;x)EEi@k%U}40GMH^F65oMb!#(^~AZ!i6N>YTF?)orPb>p zTG~wK{0IJ75G!KtI-ImDJR#L)iahYE%`SX+1=O(+GSG6pcCmR$y2!c|%4@x))Ga4p zW05G-Qg}jWCe!^Dlwd`q;LK|>B`kRMF-p`w{s&B=a}5G*>0A72Q2LhPYF8*OJWlaV zu_8U)^6Tm?zpQq9NRG=ZFnoeouVn>#D&x_-5M5`V5kW+>`B&h$Dy;H_mBZ-Qvp|w3 z4NXf0Zm}1zrV^|14H^(bUecINhc@51gv>h7nHqG;T1VFpBY;Hr#igbyc)p&Q=TrJ9sLausD71gGS z*12hEq1&?&*$0c;fDECpj3?hT`pbuH5&;@p>sOxP6`8}-P?M;D(Qb`b;%{L~r7Iud zM#Y4i;Dj+uBKS~*H?J@(<|*TP%DA2~u76;sP^gxPovfaFS!wZp{Izpdkx^a`qXL}3 zN`c*sui+B{BV1;gXr855foYoCAbl<8BghryBY{~~Jziba zrmmK`X=$y}a~Y@fkSWBx#}C^!;gl9~itv_^K{FD(Dx5My8L7};=?X`IQ%pTFktFyf zF>^?JrMs?lJrYIZiSuXwQJF=G#U^R#ZZb>H+9b0u%9E(@mY7q7O3hSiwZ^fWBIQPk zqi)!#RP~B%4~E%@TF#wqezUg6vSTz^kE0`HcR@?3fYh{FiZND3>yK4q^p&+(&Lr2@ zWAzo)NT93$5~KySMb@485~T`SL2(F4Ie+?bLb(IF*fbg!lb{9CG|>#3Y6z z4#lki0SobO5C3xUAxlOKQ z^&9M$*({YLOzDUY-hrlNHcJO^tkRT-)~8!nxINnd0Wr_Nuqn07aZ5B#cp482QS)4A zDvT)!40FxHfzPl7<7zSqbGn)y=bPgerKC9DT(?I`iffzaW_QP9z^x*Vhj0-;OuI__ zZfvQ~l#T{&GMjt2(#N*#VSH`ewLTmUas zuC^_c_RUViF4Du%huFp61y5rR!LM6dhriKG!YHqYQNiJ8Mfg!qI|CH)C>yuNqROQg zP*F?OIdl-~mCU14z|hEBs_k;66%dRp5LUb@=$BHqRE}wEEkbVbUi^(JXO!2&sNfSA zZ^&wV%Dl>t;Jf%USX_g@N(^_~FG~ze@_HB@UTS%GaWvZv7Q1bR;$8O3W@VDs!|3oB zn-v?(c2B(*2p_Ym5stn1_^}+T>x*@x__eTgcw&3Ofb-KxIpooyT|6g}-z97Lomhk+ zC`WLB=AAMBOk=iiK91`c-5M;=$;gTjhb4Z@644`^K=^UMsTl^gpMo{!0p9RMei%kF zC~sbC4fGhNMn3D^n(&nvS5ll3Jpl66SQcaX>CTWVAo#3zXAC&cM#dcH*|5Q4E_uq~ zM{z5D6vE&jE#e`jiI1=={`yDbZ%yG&b;?I0sDULSo$aho8U zHMKYTx)kRUG;W8bjbdMvdVZ98S5(Rp6E{%2jd8F^v8sXMof>+WA&_eX|6ugBF8W%^ zGN3ID78l-xFZ>%6fy^(nG28Bc4QDCeTPO0_OeCe^B7kGR%fzlamutaNX(Q@v_0KV} zvTW|T3ez1##u_e=iws~%cp0h%C+85?zLq;O7K-~yw0n1)sx}^2P)jA&)#|@TONGvl z*7I^R7IsCe?Yk+G8PjfVpty1B^8R9&m@yMLf&zJhjwAJh!!{=0auE z?m%`Rxz&F@Q<>u0v~do#FsY8a>imFafxm8%qXm7O-zAPAlpB`Z*Tc3#RUHQY3Qq`5 zGsSNcnSzYs^)JXAEm_t|$DjwY)||f*wYJ|+WRwUM3%bL#aJPrWg`MpiWD845iiF{n zX2z793h#AGW2pE^uZ~9fr5<7)qd@}(j*1W*y=NrwTwZOpt(LPe6fO3TD-?bN)!^#P z<`PK_c7vjui7*wRpp$Weu0|m#u)QEmHl75RidvJQb82uNau{Ncv;*m;A0DC9r-m5Q zNhxDgC(k;Zog@J457gYCQ3;hXCnM~(7Dh@tP`4d0)IdIm zl14S}!b5G|eY2wG*#bM}L|h?lvqPFG{u{^!N5T8v%4--M*F^o9N`*I;WO>4+G;r7EUn15a zs9DL{E{d{h$(|CjyLPJ7X3OPwHP-4_?PX{mEb1w>8oUggL zU8JX+h;lj#9 zZ_)3lx7s=XJjfXBZ4Y}3*(SXmuJlGV>DC$LO={G1)7uCQilcNw_@m7R|Rt)y0LU*)OX|GYKfb-=J74 z%NQ1jWz5pJ2U4pCQ=lb<_p!YZt(GL%IwwkQK_kPa1c0<%4IwX~h{56p^qK9(5=_2j zLS>|MbuArt>0D4%=4(qIh5 znOmg#Y!HTJLl5;@pw}H#X{u8Vl9N5=-is4Z9~g#w!u>5gr{u zz!ZkUUHKbM3BQPyK1(bTPo?U+-I5?I5?2zB#pW6j-K~D*b`-m{QqLOCOW;kiaX86I zZPH2AQxY&`Lq4Ho@k)e~H7Y-X_2`jZ1;O11XiYBe3b9bpH_HP90y#9RqZWTFGIxAK zbuWvaD;D;gf1QFHz?KjX02 zP3*@|3eZ7Rjge6zxI`Lil3167`IFKKS*>(Rg%@}|D!8IOZWU=Fx9&x^$^V1J`|X#N zTTFrp9e;yopa(;_7JhxY^VVnpR3v)XfKUQ+jnJ?fMN!zfWloeVBouYuB+reKM-i{) zo);wxx8IhiT{^BN;{Ub=fHtRe9EHD?9atFFPnEfIR;Kt_Aia#~g)_yZr7SAFDe=3p z1@g2V@QJPnX2_@{#6}QPaRC4lvMIvaC^hY;6{BQR4#JAGFZIK~McHI9U892Ikef-_ zBoYXAtVWS?kWD3#OnZVz>(u+}Sz{Gml%b;BiNQ)|it|SglQdG6 zfHF)yGE5@88=EmqJn|FEiBWCl8L)VH^q4TL4mNQ_E1=*g!jQ^Fu?4biiP0S;QzA|I z`2*?lndb(GCYgC+a!R+005bN>@ID-ROW7+YOP} zE}I0OOG{JA1-ME_nd>-!LHk~eDi$olGSh`+s)S``WQr$IYF9wL!+AgaHA}o2S>n~Y z#T@66CurEHxOv8)SU4~RL;iBX?+V5+w@O!evO_+UY#Mu*D|354)yo8GNod#sLAwf1 z@GoW#k03n^sNR{JMW$&75581t`cwMPlKcPoQ!yE(+{a$v1aki{ zoFW4zDj?GNOMA&8D9f0+j7D~AjI=}3Ob?=Pl`F1^!i9)iN9l97B>)apuYEZiP$nKl z5=@}FK|D|?Of*-xEmEWWo~JmzP`Bh{Nxv27H2YljN3K}bW6Z(LhOJ6H8$pL{{>L;H zW*7j$48~YUgh(JtEs;R z|BbWDj4fs;Uf$VdS3Yq!`M;Ypt0rR6U$yPVfJ@S38w}pV&Ji s`m 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�o=f4TEa(ztFY4W? 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≶S#3!ChnhArq_m|usSN!Wvmsvcj+SIFKT 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 A-P@#a?jF-V1uxmF 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 literal 0 HcmV?d00001 diff --git a/TitanEngine/dllmain.cpp b/TitanEngine/dllmain.cpp new file mode 100644 index 0000000..7f04770 --- /dev/null +++ b/TitanEngine/dllmain.cpp @@ -0,0 +1,19 @@ +// dllmain.cpp : Defines the entry point for the DLL application. +#include "stdafx.h" + +/*BOOL APIENTRY DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + engineHandle = hModule; + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +}*/ \ No newline at end of file diff --git a/TitanEngine/resource.h b/TitanEngine/resource.h new file mode 100644 index 0000000..13eea5b --- /dev/null +++ b/TitanEngine/resource.h @@ -0,0 +1,36 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by TitanEngine.rc +// +#define ID_MANIFEST_RESOURCE 1 +#define IDD_UNPACKERTITLE 101 +#define IDD_MAINWINDOW 103 +#define IDM_ABOUT 104 +#define IDM_EXIT 105 +#define IDI_MYUNPACKER 107 +#define IDI_SMALL 108 +#define IDC_MYUNPACKER 109 +#define IDI_ICON2 113 +#define IDR_MAINFRAME 128 +#define IDB_BITMAP1 130 +#define IDB_BITMAP2 131 +#define IDI_ICON1 132 +#define IDC_REALING 700 +#define IDC_UNPACK 701 +#define IDC_BROWSE 702 +#define IDC_ABOUT 703 +#define IDC_EXIT 704 +#define IDC_FILENAME 705 +#define IDC_COPYOVERLAY 706 +#define IDC_LISTBOX 800 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 114 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 102 +#endif +#endif diff --git a/TitanEngine/stdafx.cpp b/TitanEngine/stdafx.cpp new file mode 100644 index 0000000..2c8a553 --- /dev/null +++ b/TitanEngine/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// UnpackerEngine.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/TitanEngine/stdafx.h b/TitanEngine/stdafx.h new file mode 100644 index 0000000..cbec521 --- /dev/null +++ b/TitanEngine/stdafx.h @@ -0,0 +1,852 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once +#include "targetver.h" + +// Build switches +//#define TITANENGINE_BUILD_ASM_LIB + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files: +#include +#include + +#if !defined(_WIN64) + #include "aplib.h" +#endif +#include "LzmaDec.h" + +#define UE_PLATFORM_x86 1 +#define UE_PLATFORM_x64 2 +#define UE_PLATFORM_ALL 3 + +#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) // ntsubauth + +// Engine.Internal: +#define TITANENGINE_PAGESIZE 0x1000 +#define MAX_IMPORT_ALLOC 256 * 256 +#define MAX_RELOC_ALLOC 1024 * 1024 +#define UE_MAX_RESERVED_MEMORY_LEFT 32 +#define MAXIMUM_SECTION_NUMBER 32 +#define MAX_DECODE_INSTRUCTIONS 32 +#define MAX_INSTRUCTIONS (1000) +#define MAXIMUM_BREAKPOINTS 1000 +#define MAXIMUM_INSTRUCTION_SIZE 40 +#define MAX_RET_SEARCH_INSTRUCTIONS 100 + +#define UE_OPTION_IMPORTER_REALIGN_LOCAL_APIADDRESS 0 +#define UE_OPTION_IMPORTER_REALIGN_APIADDRESS 1 +#define UE_OPTION_IMPORTER_RETURN_APINAME 2 +#define UE_OPTION_IMPORTER_RETURN_APIADDRESS 3 +#define UE_OPTION_IMPORTER_RETURN_DLLNAME 4 +#define UE_OPTION_IMPORTER_RETURN_DLLINDEX 5 +#define UE_OPTION_IMPORTER_RETURN_DLLBASE 6 +#define UE_OPTION_IMPORTER_RETURN_FORWARDER_DLLNAME 7 +#define UE_OPTION_IMPORTER_RETURN_FORWARDER_DLLINDEX 8 +#define UE_OPTION_IMPORTER_RETURN_FORWARDER_APINAME 9 +#define UE_OPTION_IMPORTER_RETURN_FORWARDER_API_ORDINAL_NUMBER 10 +#define UE_OPTION_IMPORTER_RETURN_NEAREST_APIADDRESS 11 +#define UE_OPTION_IMPORTER_RETURN_NEAREST_APINAME 12 +#define UE_OPTION_IMPORTER_RETURN_API_ORDINAL_NUMBER 13 + +typedef struct{ + char PluginName[64]; + DWORD PluginMajorVersion; + DWORD PluginMinorVersion; + HMODULE PluginBaseAddress; + void* TitanDebuggingCallBack; + void* TitanRegisterPlugin; + void* TitanReleasePlugin; + void* TitanResetPlugin; + bool PluginDisabled; +}PluginInformation, *PPluginInformation; + +typedef struct{ + ULONG_PTR BreakPointAddress; + ULONG_PTR Parameter1; + ULONG_PTR Parameter2; + int SnapShotNumber; + bool SingleBreak; +}UnpackerInformation, *PUnpackerInformation; + +typedef struct{ + bool ExpertModeActive; + wchar_t* szFileName; + bool ReserveModuleBase; + wchar_t* szCommandLine; + wchar_t* szCurrentFolder; + LPVOID EntryCallBack; +}ExpertDebug, *PExpertDebug; + +typedef struct{ + ULONG_PTR fLoadLibrary; + ULONG_PTR fFreeLibrary; + ULONG_PTR fGetModuleHandle; + ULONG_PTR fGetProcAddress; + ULONG_PTR fVirtualFree; + ULONG_PTR fExitProcess; + HMODULE fFreeLibraryHandle; + DWORD fExitProcessCode; +}InjectCodeData, *PInjectCodeData; + +typedef struct{ + ULONG_PTR fTrace; + ULONG_PTR fCreateFileA; + ULONG_PTR fCloseHandle; + ULONG_PTR fCreateFileMappingA; + ULONG_PTR AddressToTrace; +}InjectImpRecCodeData, *PInjectImpRecCodeData; + +#define UE_MAX_BREAKPOINT_SIZE 2 +#define UE_BREAKPOINT_INT3 1 +#define UE_BREAKPOINT_LONG_INT3 2 +#define UE_BREAKPOINT_UD2 3 + +typedef struct{ + BYTE BreakPointActive; + ULONG_PTR BreakPointAddress; + DWORD BreakPointSize; + BYTE OriginalByte[10]; + int BreakPointType; + int AdvancedBreakPointType; + int MemoryBpxRestoreOnHit; + DWORD NumberOfExecutions; + DWORD CmpRegister; + int CmpCondition; + ULONG_PTR CmpValue; + ULONG_PTR ExecuteCallBack; + ULONG_PTR CompareCallBack; + ULONG_PTR RemoveCallBack; + DWORD UniqueLinkId; +}BreakPointDetail, *PBreakPointDetail; + +typedef struct{ + bool DrxEnabled; + bool DrxExecution; + DWORD DrxBreakPointType; + DWORD DrxBreakPointSize; + ULONG_PTR DrxBreakAddress; + ULONG_PTR DrxCallBack; +}HARDWARE_DATA, *PHARDWARE_DATA; + +typedef struct{ + ULONG_PTR chBreakPoint; + ULONG_PTR chSingleStep; + ULONG_PTR chAccessViolation; + ULONG_PTR chIllegalInstruction; + ULONG_PTR chNonContinuableException; + ULONG_PTR chArrayBoundsException; + ULONG_PTR chFloatDenormalOperand; + ULONG_PTR chFloatDevideByZero; + ULONG_PTR chIntegerDevideByZero; + ULONG_PTR chIntegerOverflow; + ULONG_PTR chPrivilegedInstruction; + ULONG_PTR chPageGuard; + ULONG_PTR chEverythingElse; + ULONG_PTR chCreateThread; + ULONG_PTR chExitThread; + ULONG_PTR chCreateProcess; + ULONG_PTR chExitProcess; + ULONG_PTR chLoadDll; + ULONG_PTR chUnloadDll; + ULONG_PTR chOutputDebugString; + ULONG_PTR chAfterException; + ULONG_PTR chSystemBreakpoint; + ULONG_PTR chUnhandledException; + ULONG_PTR chAfterUnhandledException; +}CustomHandler, *PCustomHandler; + +typedef struct{ + DWORD OrdinalBase; + DWORD NumberOfExportFunctions; + char FileName[512]; +}EXPORT_DATA, *PEXPORT_DATA; + +typedef struct{ + DWORD ExportedItem; +}EXPORTED_DATA, *PEXPORTED_DATA; + +typedef struct{ + WORD OrdinalNumber; +}EXPORTED_DATA_WORD, *PEXPORTED_DATA_WORD; + +typedef struct{ + BYTE DataByte[50]; +}MEMORY_CMP_HANDLER, *PMEMORY_CMP_HANDLER; + +typedef struct{ + BYTE DataByte; +}MEMORY_CMP_BYTE_HANDLER, *PMEMORY_CMP_BYTE_HANDLER; + +typedef struct MEMORY_COMPARE_HANDLER{ + union { + BYTE bArrayEntry[1]; + WORD wArrayEntry[1]; + DWORD dwArrayEntry[1]; + DWORD64 qwArrayEntry[1]; + } Array; +}MEMORY_COMPARE_HANDLER, *PMEMORY_COMPARE_HANDLER; + +#define MAX_DEBUG_DATA 512 + +typedef struct{ + HANDLE hThread; + DWORD dwThreadId; + void* ThreadStartAddress; + void* ThreadLocalBase; +}THREAD_ITEM_DATA, *PTHREAD_ITEM_DATA; + +typedef struct{ + HANDLE hProcess; + DWORD dwProcessId; + HANDLE hThread; + DWORD dwThreadId; + HANDLE hFile; + void* BaseOfImage; + void* ThreadStartAddress; + void* ThreadLocalBase; +}PROCESS_ITEM_DATA, *PPROCESS_ITEM_DATA; + +typedef struct{ + HANDLE hFile; + void* BaseOfDll; + HANDLE hFileMapping; + void* hFileMappingView; + char szLibraryPath[MAX_PATH]; + char szLibraryName[MAX_PATH]; +}LIBRARY_ITEM_DATA, *PLIBRARY_ITEM_DATA; + +typedef struct{ + HANDLE hFile; + void* BaseOfDll; + HANDLE hFileMapping; + void* hFileMappingView; + wchar_t szLibraryPath[MAX_PATH]; + wchar_t szLibraryName[MAX_PATH]; +}LIBRARY_ITEM_DATAW, *PLIBRARY_ITEM_DATAW; + +#define MAX_LIBRARY_BPX 64 +#define UE_ON_LIB_LOAD 1 +#define UE_ON_LIB_UNLOAD 2 +#define UE_ON_LIB_ALL 3 + +typedef struct{ + char szLibraryName[128]; + void* bpxCallBack; + bool bpxSingleShoot; + int bpxType; +}LIBRARY_BREAK_DATA, *PLIBRARY_BREAK_DATA; + +#define TEE_MAXIMUM_HOOK_SIZE 14 +#if defined(_WIN64) + #define TEE_MAXIMUM_HOOK_INSERT_SIZE 14 +#else + #define TEE_MAXIMUM_HOOK_INSERT_SIZE 5 +#endif + +#define TEE_HOOK_NRM_JUMP 1 +#define TEE_HOOK_NRM_CALL 3 +#define TEE_HOOK_IAT 5 +#define TEE_MAXIMUM_HOOK_RELOCS 7 + +typedef struct HOOK_ENTRY{ + bool IATHook; + BYTE HookType; + DWORD HookSize; + void* HookAddress; + void* RedirectionAddress; + BYTE HookBytes[TEE_MAXIMUM_HOOK_SIZE]; + BYTE OriginalBytes[TEE_MAXIMUM_HOOK_SIZE]; + void* IATHookModuleBase; + DWORD IATHookNameHash; + bool HookIsEnabled; + bool HookIsRemote; + void* PatchedEntry; + DWORD RelocationInfo[TEE_MAXIMUM_HOOK_RELOCS]; + int RelocationCount; +}HOOK_ENTRY, *PHOOK_ENTRY; + +// Engine.External: +#define UE_ACCESS_READ 0 +#define UE_ACCESS_WRITE 1 +#define UE_ACCESS_ALL 2 + +#define UE_HIDE_BASIC 1 + +#define UE_PLUGIN_CALL_REASON_PREDEBUG 1 +#define UE_PLUGIN_CALL_REASON_EXCEPTION 2 +#define UE_PLUGIN_CALL_REASON_POSTDEBUG 3 + +#define UE_ENGINE_ALOW_MODULE_LOADING 1 +#define UE_ENGINE_AUTOFIX_FORWARDERS 2 +#define UE_ENGINE_PASS_ALL_EXCEPTIONS 3 +#define UE_ENGINE_NO_CONSOLE_WINDOW 4 +#define UE_ENGINE_BACKUP_FOR_CRITICAL_FUNCTIONS 5 +#define UE_ENGINE_CALL_PLUGIN_CALLBACK 6 +#define UE_ENGINE_RESET_CUSTOM_HANDLER 7 +#define UE_ENGINE_CALL_PLUGIN_DEBUG_CALLBACK 8 + +#define UE_OPTION_REMOVEALL 1 +#define UE_OPTION_DISABLEALL 2 +#define UE_OPTION_REMOVEALLDISABLED 3 +#define UE_OPTION_REMOVEALLENABLED 4 + +#define UE_STATIC_DECRYPTOR_XOR 1 +#define UE_STATIC_DECRYPTOR_SUB 2 +#define UE_STATIC_DECRYPTOR_ADD 3 + +#define UE_STATIC_DECRYPTOR_FOREWARD 1 +#define UE_STATIC_DECRYPTOR_BACKWARD 2 + +#define UE_STATIC_KEY_SIZE_1 1 +#define UE_STATIC_KEY_SIZE_2 2 +#define UE_STATIC_KEY_SIZE_4 4 +#define UE_STATIC_KEY_SIZE_8 8 + +#define UE_STATIC_APLIB 1 +#define UE_STATIC_APLIB_DEPACK 2 +#define UE_STATIC_LZMA 3 + +#define UE_STATIC_HASH_MD5 1 +#define UE_STATIC_HASH_SHA1 2 +#define UE_STATIC_HASH_CRC32 3 + +#define UE_RESOURCE_LANGUAGE_ANY -1 + +#define UE_PE_OFFSET 0 +#define UE_IMAGEBASE 1 +#define UE_OEP 2 +#define UE_SIZEOFIMAGE 3 +#define UE_SIZEOFHEADERS 4 +#define UE_SIZEOFOPTIONALHEADER 5 +#define UE_SECTIONALIGNMENT 6 +#define UE_IMPORTTABLEADDRESS 7 +#define UE_IMPORTTABLESIZE 8 +#define UE_RESOURCETABLEADDRESS 9 +#define UE_RESOURCETABLESIZE 10 +#define UE_EXPORTTABLEADDRESS 11 +#define UE_EXPORTTABLESIZE 12 +#define UE_TLSTABLEADDRESS 13 +#define UE_TLSTABLESIZE 14 +#define UE_RELOCATIONTABLEADDRESS 15 +#define UE_RELOCATIONTABLESIZE 16 +#define UE_TIMEDATESTAMP 17 +#define UE_SECTIONNUMBER 18 +#define UE_CHECKSUM 19 +#define UE_SUBSYSTEM 20 +#define UE_CHARACTERISTICS 21 +#define UE_NUMBEROFRVAANDSIZES 22 +#define UE_SECTIONNAME 23 +#define UE_SECTIONVIRTUALOFFSET 24 +#define UE_SECTIONVIRTUALSIZE 25 +#define UE_SECTIONRAWOFFSET 26 +#define UE_SECTIONRAWSIZE 27 +#define UE_SECTIONFLAGS 28 + +#define UE_CH_BREAKPOINT 1 +#define UE_CH_SINGLESTEP 2 +#define UE_CH_ACCESSVIOLATION 3 +#define UE_CH_ILLEGALINSTRUCTION 4 +#define UE_CH_NONCONTINUABLEEXCEPTION 5 +#define UE_CH_ARRAYBOUNDSEXCEPTION 6 +#define UE_CH_FLOATDENORMALOPERAND 7 +#define UE_CH_FLOATDEVIDEBYZERO 8 +#define UE_CH_INTEGERDEVIDEBYZERO 9 +#define UE_CH_INTEGEROVERFLOW 10 +#define UE_CH_PRIVILEGEDINSTRUCTION 11 +#define UE_CH_PAGEGUARD 12 +#define UE_CH_EVERYTHINGELSE 13 +#define UE_CH_CREATETHREAD 14 +#define UE_CH_EXITTHREAD 15 +#define UE_CH_CREATEPROCESS 16 +#define UE_CH_EXITPROCESS 17 +#define UE_CH_LOADDLL 18 +#define UE_CH_UNLOADDLL 19 +#define UE_CH_OUTPUTDEBUGSTRING 20 +#define UE_CH_AFTEREXCEPTIONPROCESSING 21 +#define UE_CH_ALLEVENTS 22 +#define UE_CH_SYSTEMBREAKPOINT 23 +#define UE_CH_UNHANDLEDEXCEPTION 24 +#define UE_CH_AFTERUNHANDLEDEXCEPTION 25 + +#define UE_OPTION_HANDLER_RETURN_HANDLECOUNT 1 +#define UE_OPTION_HANDLER_RETURN_ACCESS 2 +#define UE_OPTION_HANDLER_RETURN_FLAGS 3 +#define UE_OPTION_HANDLER_RETURN_TYPENAME 4 +#define UE_OPTION_HANDLER_RETURN_TYPENAME_UNICODE 5 + +typedef struct{ + ULONG ProcessId; + HANDLE hHandle; +}HandlerArray, *PHandlerArray; + +#define UE_BPXREMOVED 0 +#define UE_BPXACTIVE 1 +#define UE_BPXINACTIVE 2 + +#define UE_BREAKPOINT 0 +#define UE_SINGLESHOOT 1 +#define UE_HARDWARE 2 +#define UE_MEMORY 3 +#define UE_MEMORY_READ 4 +#define UE_MEMORY_WRITE 5 +#define UE_BREAKPOINT_TYPE_INT3 0x10000000 +#define UE_BREAKPOINT_TYPE_LONG_INT3 0x20000000 +#define UE_BREAKPOINT_TYPE_UD2 0x30000000 + +#define UE_HARDWARE_EXECUTE 4 +#define UE_HARDWARE_WRITE 5 +#define UE_HARDWARE_READWRITE 6 + +#define UE_HARDWARE_SIZE_1 7 +#define UE_HARDWARE_SIZE_2 8 +#define UE_HARDWARE_SIZE_4 9 + +#define UE_APISTART 0 +#define UE_APIEND 1 + +#define UE_FUNCTION_STDCALL 1 +#define UE_FUNCTION_CCALL 2 +#define UE_FUNCTION_FASTCALL 3 +#define UE_FUNCTION_STDCALL_RET 4 +#define UE_FUNCTION_CCALL_RET 5 +#define UE_FUNCTION_FASTCALL_RET 6 +#define UE_FUNCTION_STDCALL_CALL 7 +#define UE_FUNCTION_CCALL_CALL 8 +#define UE_FUNCTION_FASTCALL_CALL 9 +#define UE_PARAMETER_BYTE 0 +#define UE_PARAMETER_WORD 1 +#define UE_PARAMETER_DWORD 2 +#define UE_PARAMETER_QWORD 3 +#define UE_PARAMETER_PTR_BYTE 4 +#define UE_PARAMETER_PTR_WORD 5 +#define UE_PARAMETER_PTR_DWORD 6 +#define UE_PARAMETER_PTR_QWORD 7 +#define UE_PARAMETER_STRING 8 +#define UE_PARAMETER_UNICODE 9 + +#define UE_CMP_NOCONDITION 0 +#define UE_CMP_EQUAL 1 +#define UE_CMP_NOTEQUAL 2 +#define UE_CMP_GREATER 3 +#define UE_CMP_GREATEROREQUAL 4 +#define UE_CMP_LOWER 5 +#define UE_CMP_LOWEROREQUAL 6 +#define UE_CMP_REG_EQUAL 7 +#define UE_CMP_REG_NOTEQUAL 8 +#define UE_CMP_REG_GREATER 9 +#define UE_CMP_REG_GREATEROREQUAL 10 +#define UE_CMP_REG_LOWER 11 +#define UE_CMP_REG_LOWEROREQUAL 12 +#define UE_CMP_ALWAYSFALSE 13 + +#define UE_EAX 1 +#define UE_EBX 2 +#define UE_ECX 3 +#define UE_EDX 4 +#define UE_EDI 5 +#define UE_ESI 6 +#define UE_EBP 7 +#define UE_ESP 8 +#define UE_EIP 9 +#define UE_EFLAGS 10 +#define UE_DR0 11 +#define UE_DR1 12 +#define UE_DR2 13 +#define UE_DR3 14 +#define UE_DR6 15 +#define UE_DR7 16 +#define UE_RAX 17 +#define UE_RBX 18 +#define UE_RCX 19 +#define UE_RDX 20 +#define UE_RDI 21 +#define UE_RSI 22 +#define UE_RBP 23 +#define UE_RSP 24 +#define UE_RIP 25 +#define UE_RFLAGS 26 +#define UE_R8 27 +#define UE_R9 28 +#define UE_R10 29 +#define UE_R11 30 +#define UE_R12 31 +#define UE_R13 32 +#define UE_R14 33 +#define UE_R15 34 +#define UE_CIP 35 +#define UE_CSP 36 +#define UE_SEG_GS 37 +#define UE_SEG_FS 38 +#define UE_SEG_ES 39 +#define UE_SEG_DS 40 +#define UE_SEG_CS 41 +#define UE_SEG_SS 42 + +typedef struct{ + DWORD PE32Offset; + DWORD ImageBase; + DWORD OriginalEntryPoint; + DWORD NtSizeOfImage; + DWORD NtSizeOfHeaders; + WORD SizeOfOptionalHeaders; + DWORD FileAlignment; + DWORD SectionAligment; + DWORD ImportTableAddress; + DWORD ImportTableSize; + DWORD ResourceTableAddress; + DWORD ResourceTableSize; + DWORD ExportTableAddress; + DWORD ExportTableSize; + DWORD TLSTableAddress; + DWORD TLSTableSize; + DWORD RelocationTableAddress; + DWORD RelocationTableSize; + DWORD TimeDateStamp; + WORD SectionNumber; + DWORD CheckSum; + WORD SubSystem; + WORD Characteristics; + DWORD NumberOfRvaAndSizes; +}PE32Struct, *PPE32Struct; + +typedef struct{ + DWORD PE64Offset; + DWORD64 ImageBase; + DWORD OriginalEntryPoint; + DWORD NtSizeOfImage; + DWORD NtSizeOfHeaders; + WORD SizeOfOptionalHeaders; + DWORD FileAlignment; + DWORD SectionAligment; + DWORD ImportTableAddress; + DWORD ImportTableSize; + DWORD ResourceTableAddress; + DWORD ResourceTableSize; + DWORD ExportTableAddress; + DWORD ExportTableSize; + DWORD TLSTableAddress; + DWORD TLSTableSize; + DWORD RelocationTableAddress; + DWORD RelocationTableSize; + DWORD TimeDateStamp; + WORD SectionNumber; + DWORD CheckSum; + WORD SubSystem; + WORD Characteristics; + DWORD NumberOfRvaAndSizes; +}PE64Struct, *PPE64Struct; + +typedef struct{ + bool NewDll; + int NumberOfImports; + ULONG_PTR ImageBase; + ULONG_PTR BaseImportThunk; + ULONG_PTR ImportThunk; + char* APIName; + char* DLLName; +}ImportEnumData, *PImportEnumData; + +#define UE_DEPTH_SURFACE 0 +#define UE_DEPTH_DEEP 1 + +#define UE_UNPACKER_CONDITION_SEARCH_FROM_EP 1 + +#define UE_UNPACKER_CONDITION_LOADLIBRARY 1 +#define UE_UNPACKER_CONDITION_GETPROCADDRESS 2 +#define UE_UNPACKER_CONDITION_ENTRYPOINTBREAK 3 +#define UE_UNPACKER_CONDITION_RELOCSNAPSHOT1 4 +#define UE_UNPACKER_CONDITION_RELOCSNAPSHOT2 5 + +#define UE_FIELD_OK 0 +#define UE_FIELD_BROKEN_NON_FIXABLE 1 +#define UE_FIELD_BROKEN_NON_CRITICAL 2 +#define UE_FIELD_BROKEN_FIXABLE_FOR_STATIC_USE 3 +#define UE_FIELD_BROKEN_BUT_CAN_BE_EMULATED 4 +#define UE_FILED_FIXABLE_NON_CRITICAL 5 +#define UE_FILED_FIXABLE_CRITICAL 6 +#define UE_FIELD_NOT_PRESET 7 +#define UE_FIELD_NOT_PRESET_WARNING 8 + +#define UE_RESULT_FILE_OK 10 +#define UE_RESULT_FILE_INVALID_BUT_FIXABLE 11 +#define UE_RESULT_FILE_INVALID_AND_NON_FIXABLE 12 +#define UE_RESULT_FILE_INVALID_FORMAT 13 + +typedef struct{ + BYTE OveralEvaluation; + bool EvaluationTerminatedByException; + bool FileIs64Bit; + bool FileIsDLL; + bool FileIsConsole; + bool MissingDependencies; + bool MissingDeclaredAPIs; + BYTE SignatureMZ; + BYTE SignaturePE; + BYTE EntryPoint; + BYTE ImageBase; + BYTE SizeOfImage; + BYTE FileAlignment; + BYTE SectionAlignment; + BYTE ExportTable; + BYTE RelocationTable; + BYTE ImportTable; + BYTE ImportTableSection; + BYTE ImportTableData; + BYTE IATTable; + BYTE TLSTable; + BYTE LoadConfigTable; + BYTE BoundImportTable; + BYTE COMHeaderTable; + BYTE ResourceTable; + BYTE ResourceData; + BYTE SectionTable; +}FILE_STATUS_INFO, *PFILE_STATUS_INFO; + +typedef struct{ + BYTE OveralEvaluation; + bool FixingTerminatedByException; + bool FileFixPerformed; + bool StrippedRelocation; + bool DontFixRelocations; + DWORD OriginalRelocationTableAddress; + DWORD OriginalRelocationTableSize; + bool StrippedExports; + bool DontFixExports; + DWORD OriginalExportTableAddress; + DWORD OriginalExportTableSize; + bool StrippedResources; + bool DontFixResources; + DWORD OriginalResourceTableAddress; + DWORD OriginalResourceTableSize; + bool StrippedTLS; + bool DontFixTLS; + DWORD OriginalTLSTableAddress; + DWORD OriginalTLSTableSize; + bool StrippedLoadConfig; + bool DontFixLoadConfig; + DWORD OriginalLoadConfigTableAddress; + DWORD OriginalLoadConfigTableSize; + bool StrippedBoundImports; + bool DontFixBoundImports; + DWORD OriginalBoundImportTableAddress; + DWORD OriginalBoundImportTableSize; + bool StrippedIAT; + bool DontFixIAT; + DWORD OriginalImportAddressTableAddress; + DWORD OriginalImportAddressTableSize; + bool StrippedCOM; + bool DontFixCOM; + DWORD OriginalCOMTableAddress; + DWORD OriginalCOMTableSize; +}FILE_FIX_INFO, *PFILE_FIX_INFO; + +typedef struct{ + void* AllocatedSection; + DWORD SectionVirtualOffset; + DWORD SectionVirtualSize; + DWORD SectionAttributes; + DWORD SectionDataHash; + bool AccessedAlready; + bool WriteCheckMode; +}TracerSectionData, *PTracerSectionData; + +typedef struct{ + int SectionNumber; + TracerSectionData SectionData[MAXIMUM_SECTION_NUMBER]; + int OriginalEntryPointNum; + ULONG_PTR OriginalImageBase; + ULONG_PTR OriginalEntryPoint; + ULONG_PTR LoadedImageBase; + ULONG_PTR SizeOfImage; + ULONG_PTR CurrentIntructionPointer; + ULONG_PTR MemoryAccessedFrom; + ULONG_PTR MemoryAccessed; + ULONG_PTR AccessType; + void* InitCallBack; + void* EPCallBack; + bool FileIsDLL; + bool FileIs64bit; +}GenericOEPTracerData, *PGenericOEPTracerData; + +// UnpackEngine.Handler: + +#define NTDLL_SystemHandleInfo 0x10 +#define ObjectBasicInformation 0 +#define ObjectNameInformation 1 +#define ObjectTypeInformation 2 + +/*typedef enum _POOL_TYPE { + NonPagedPool, + PagedPool, + NonPagedPoolMustSucceed, + DontUseThisType, + NonPagedPoolCacheAligned, + PagedPoolCacheAligned, + NonPagedPoolCacheAlignedMustS, + MaxPoolType, + NonPagedPoolSession, + PagedPoolSession, + NonPagedPoolMustSucceedSession, + DontUseThisTypeSession, + NonPagedPoolCacheAlignedSession, + PagedPoolCacheAlignedSession, + NonPagedPoolCacheAlignedMustSSession +} POOL_TYPE;*/ + +typedef struct{ + ULONG ProcessId; + UCHAR ObjectTypeNumber; + UCHAR Flags; // 0x01 = PROTECT_FROM_CLOSE, 0x02 = INHERIT + USHORT hHandle; + PVOID Object; + ACCESS_MASK GrantedAccess; +}NTDLL_QUERY_HANDLE_INFO, *PNTDLL_QUERY_HANDLE_INFO; + +/*typedef struct _PUBLIC_OBJECT_BASIC_INFORMATION { + ULONG Attributes; + ACCESS_MASK GrantedAccess; + ULONG HandleCount; + ULONG PointerCount; + ULONG PagedPoolUsage; + ULONG NonPagedPoolUsage; + ULONG Reserved[3]; + ULONG NameInformationLength; + ULONG TypeInformationLength; + ULONG SecurityDescriptorLength; + LARGE_INTEGER CreateTime; +} PUBLIC_OBJECT_BASIC_INFORMATION, *PPUBLIC_OBJECT_BASIC_INFORMATION;*/ + +typedef struct _PUBLIC_OBJECT_NAME_INFORMATION { // Information Class 1 + UNICODE_STRING Name; +} PUBLIC_OBJECT_NAME_INFORMATION, *PPUBLIC_OBJECT_NAME_INFORMATION; + +/*typedef struct _PUBLIC_OBJECT_TYPE_INFORMATION { // Information Class 2 + UNICODE_STRING Name; + ULONG ObjectCount; + ULONG HandleCount; + ULONG Reserved1[4]; + ULONG PeakObjectCount; + ULONG PeakHandleCount; + ULONG Reserved2[4]; + ULONG InvalidAttributes; + GENERIC_MAPPING GenericMapping; + ULONG ValidAccess; + UCHAR Unknown; + BOOLEAN MaintainHandleDatabase; + POOL_TYPE PoolType; + ULONG PagedPoolUsage; + ULONG NonPagedPoolUsage; +} PUBLIC_OBJECT_TYPE_INFORMATION, *PPUBLIC_OBJECT_TYPE_INFORMATION;*/ + +typedef void (*PPEBLOCKROUTINE)( + PVOID PebLock +); + +/*typedef struct _PEB_LDR_DATA { + ULONG Length; + BOOLEAN Initialized; + PVOID SsHandle; + LIST_ENTRY InLoadOrderModuleList; + LIST_ENTRY InMemoryOrderModuleList; + LIST_ENTRY InInitializationOrderModuleList; +} PEB_LDR_DATA, *PPEB_LDR_DATA;*/ + +/*typedef struct _RTL_DRIVE_LETTER_CURDIR { + USHORT Flags; + USHORT Length; + ULONG TimeStamp; + UNICODE_STRING DosPath; +} RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR; + +typedef struct _RTL_USER_PROCESS_PARAMETERS { + ULONG MaximumLength; + ULONG Length; + ULONG Flags; + ULONG DebugFlags; + PVOID ConsoleHandle; + ULONG ConsoleFlags; + HANDLE StdInputHandle; + HANDLE StdOutputHandle; + HANDLE StdErrorHandle; + UNICODE_STRING CurrentDirectoryPath; + HANDLE CurrentDirectoryHandle; + UNICODE_STRING DllPath; + UNICODE_STRING ImagePathName; + UNICODE_STRING CommandLine; + PVOID Environment; + ULONG StartingPositionLeft; + ULONG StartingPositionTop; + ULONG Width; + ULONG Height; + ULONG CharWidth; + ULONG CharHeight; + ULONG ConsoleTextAttributes; + ULONG WindowFlags; + ULONG ShowWindowFlags; + UNICODE_STRING WindowTitle; + UNICODE_STRING DesktopName; + UNICODE_STRING ShellInfo; + UNICODE_STRING RuntimeData; + RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20]; +} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;*/ + +typedef struct _NTPEB { + BOOLEAN InheritedAddressSpace; + BOOLEAN ReadImageFileExecOptions; + BOOLEAN BeingDebugged; + BOOLEAN Spare; + HANDLE Mutant; + PVOID ImageBaseAddress; + PPEB_LDR_DATA LoaderData; + PRTL_USER_PROCESS_PARAMETERS ProcessParameters; + PVOID SubSystemData; + PVOID ProcessHeap; + PVOID FastPebLock; + void* FastPebLockRoutine; + void* FastPebUnlockRoutine; + ULONG EnvironmentUpdateCount; + PVOID* KernelCallbackTable; + PVOID EventLogSection; + PVOID EventLog; + void* FreeList; + ULONG TlsExpansionCounter; + PVOID TlsBitmap; + ULONG TlsBitmapBits[0x2]; + PVOID ReadOnlySharedMemoryBase; + PVOID ReadOnlySharedMemoryHeap; + PVOID* ReadOnlyStaticServerData; + PVOID AnsiCodePageData; + PVOID OemCodePageData; + PVOID UnicodeCaseTableData; + ULONG NumberOfProcessors; + ULONG NtGlobalFlag; + BYTE Spare2[0x4]; + LARGE_INTEGER CriticalSectionTimeout; + ULONG HeapSegmentReserve; + ULONG HeapSegmentCommit; + ULONG HeapDeCommitTotalFreeThreshold; + ULONG HeapDeCommitFreeBlockThreshold; + ULONG NumberOfHeaps; + ULONG MaximumNumberOfHeaps; + PVOID* *ProcessHeaps; + PVOID GdiSharedHandleTable; + PVOID ProcessStarterHelper; + PVOID GdiDCAttributeList; + PVOID LoaderLock; + ULONG OSMajorVersion; + ULONG OSMinorVersion; + ULONG OSBuildNumber; + ULONG OSPlatformId; + ULONG ImageSubSystem; + ULONG ImageSubSystemMajorVersion; + ULONG ImageSubSystemMinorVersion; + ULONG GdiHandleBuffer[0x22]; + ULONG PostProcessInitRoutine; + ULONG TlsExpansionBitmap; + BYTE TlsExpansionBitmapBits[0x80]; + ULONG SessionId; +} NTPEB, *PNTPEB; diff --git a/TitanEngine/targetver.h b/TitanEngine/targetver.h new file mode 100644 index 0000000..f583181 --- /dev/null +++ b/TitanEngine/targetver.h @@ -0,0 +1,24 @@ +#pragma once + +// The following macros define the minimum required platform. The minimum required platform +// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run +// your application. The macros work by enabling all features available on platform versions up to and +// including the version specified. + +// Modify the following defines if you have to target a platform prior to the ones specified below. +// Refer to MSDN for the latest info on corresponding values for different platforms. +#ifndef WINVER // Specifies that the minimum required platform is Windows Vista. +#define WINVER 0x0600 // Change this to the appropriate value to target other versions of Windows. +#endif + +#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista. +#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows. +#endif + +#ifndef _WIN32_WINDOWS // Specifies that the minimum required platform is Windows 98. +#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later. +#endif + +#ifndef _WIN32_IE // Specifies that the minimum required platform is Internet Explorer 7.0. +#define _WIN32_IE 0x0700 // Change this to the appropriate value to target other versions of IE. +#endif diff --git a/TitanEngineLoaders/LibraryLoader/x32/LibraryLoader.asm b/TitanEngineLoaders/LibraryLoader/x32/LibraryLoader.asm new file mode 100644 index 0000000..071dae1 --- /dev/null +++ b/TitanEngineLoaders/LibraryLoader/x32/LibraryLoader.asm @@ -0,0 +1,31 @@ +format PE GUI +entry start + +section '.text' code readable executable + start: + push szLibraryName + call [LoadLibraryW] + cmp eax,1 + sbb ecx,ecx + and ecx,61703078h + push ecx + call [ExitProcess] + +section '.data' data readable writeable + szLibraryName dw 512 dup (?) + +section '.idata' import data readable writeable + dd 0,0,0,rva kernel_name,rva kernel_table + dd 0,0,0,0,0 + + kernel_table: + ExitProcess dd rva _ExitProcess + LoadLibraryW dd rva _LoadLibraryW + dd 0 + + kernel_name db 'kernel32.dll',0 + + _ExitProcess dw 0 + db 'ExitProcess',0 + _LoadLibraryW dw 0 + db 'LoadLibraryW',0 \ No newline at end of file diff --git a/TitanEngineLoaders/LibraryLoader/x32/LibraryLoader.exe b/TitanEngineLoaders/LibraryLoader/x32/LibraryLoader.exe new file mode 100644 index 0000000000000000000000000000000000000000..0d738b183ecdc061382ff1837b334d2f41c2d936 GIT binary patch literal 1536 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%0DG~BA;Z5r;<@JS6{*YF(;|Ei&dKc@~i zTEnRt7HL?b;UWz$*04>(D>S@O!<`!L)^NXu?`U{T!%VlT_cRR`Xt-3vRt>MvaI1#j z)o_=Fk7)RUhJVuVxP~^(*IW%x)38WGkA_tmN@n1{8_reqP1kzk4jq0(!{;@8M?;Iw zm#?9T=Y%ZvcoQDE z#)czZflq2F_?d>TP8D`&Sg2v1h7aj{3(RyKuGeszhC4OfrJ+c1o?lpH{r3(kD9%*% zreqVo3>E)st%7~0$Y+*I^Dkanv)m&HF9u9ka2eBW?&^R~XUtqV$5Yk5ezL2wQdnzh zJ&d-N`4p_Ft<+%!Yii4MSVCK+r*bLtDSrtmB1r`VRkRGV1s4K6K z?O|TF)3c;b*!}M1$S&-lNkV^Rm4r2QrGy!%uQpJlYf$yq)D+dQemm%wdEFk5gwW(f7^An9j$$spvD_!A=7o~nd$GJj=J43PurH5Hz^fUE`dFzi!dJD=GW zpNCD8j^zWM82OT4;Gg6dGdM_lU1@-1ThOYs3KdGLKmuaZ!47YAZ7jdyqfhct@(zrU zydxy<2+2D#2u{-PQS?iGF`aelbj25su$NVr%_)lKPv#F0=m^apU0UY{f6NG`do+6_ zKagOntg6LAQo78=b+sp$zFRxP%LW)t1b9DfD*gwEah_J*PU_68o@%D1|8`D`2;|UpG zUhTygN>lYo=w9jttgfkDT#a;+WtOW%e2up@;Ag(ds>)izGM{%jpx0B0&ajnxtJo#! zv(NoTss3fvszDkZ)AE54%T0V#I&@<6p0b}7C<#gfG&26ur2qwiO^Q#_HmN1y4?~lpyaTvvf3-t z(MR|;n6T=;vIDy2pd6CR5pVZ-DgMIlt*Z5+eyh*J<^p;ZRA?~AXG8DGs$oTsSgFmHGrQzPOrUn*wZx zNOM zm(c8>v;aB_3{w#GtNA@8y;Nk7uh2hcLRvsET0!tthD%{rmHNC@9zFWee=-f6hsCNb1vHT$M9Dej8rd;9C|D}20o4vA=Zr^vGMy0P0(`21*h~4s z@<`&ZP=gD!FI}kGuymnp1C#ozD8|I2$Ra!;&YqfM$})k8#KRs5dFU49on) zAmtSb(TtFEVYwmsNdAF%Hw+8R6MP0}wk4nrpHJJaj{l6S-1Wvi0fX!tstx>X3TEi(CVYSX>`o&E5EtJE=>MK{U zv{vPpt3{Roy_z0A+bYqge1J=vuU%3yWt8$@yO|5@~(>(^5xQ4u)%&|TR^j-t-40pO|WMeZz-+CS}agkiGU4D0M7SzK$yM~E(Bye z>1BKs`hsEFdNK^G3==t_9CLuQ)MYx1RL0X*W!SCpv0G$1EEA^FK(Q=Zh&32%2EB_| zGvj=CX03b<@L9IQvZw}OH^OR7fOuAcxQh|TTKJ6du&7GfK9)riP>z;WSJujO=1E)X zulB;Ew0Zr0BG!7CtdUNK6XYEo>0KhF3S-;nQ)9eZLrzT`^VPIc33b@V6|{`kP_3vr zu4wQq6SNDd3kX@coG)tP^F@ZXXUvJf44az53@b}Om&dr%;;-7ZQ0?EaVS4^cZr8$E zGrL)Tth~n0DM>mroKn9}>Nwh0V5YRM2swijV(6PQJM}*Ib;xr%ZEs0EFYPPl$1s%T zXkQ^r`^wC(>?`d1(7s|`?8OkOeVAA_ZFkkg>@JqKbIB-opum4VL*yic$jLMay9`6@ zWEj$?!l;k=Ssx*UUB*KMRr;yA{dfSbV6_5z6YS{{VvD#bitu3plEt2)b!?RPug)*FF=C6{fOU?%s zz)L&D#|Q09JH(7I?GQ6edVIQE1s}9yd>!LCx7L}xN`7-*gZ-rXH#QC(fpSQ4rKH{- z(2HTTv%%^DbshI; z{L9?tNP+wSowCJV;Kt54Y?Hq1;chdq2oqg^U&0g12~<@{=+t;{@9Dws=% zoxfM-3EO_A&L1K_Rj{t@vbOg1ZLZ*k#$YJY(%z=Bi=MYt{@h$%{>H~gb^cWiO|FL4 z*7n8*mHCjy`|d7%uA$4j=BLSWJsOs^hrJtGB7tywV{qL%A=Zj@qEWPqun6LBmS_^K z_!EM^;m-O}olQr$aE~lCEir7z)tRh>2wtTz%QE`ADdBE}9SQlrl@h)wCA=*q{Oy$R z_LT5fyk^$cXpA8=t9imM{L<=|;6fXEM{>V2MQiaG7_;M>;t?-G( zq6UA7dCXLS_)1YF7M>y%FI1tlU$|wip)ts6M720q6pA_cBkq~N=LU5V(6v_JhdvOF zfI8f`L;sRqzpUAZC-!!ejBA!HSS$0cLCeGqktq!**CMXa`Pvbm39gvvW;E4vC-XF4WsDYb8A){1Kxn z(SnpV$f*k)Vk;HZYZ1FnhMDs+(57gQpkB6~(!CBCTV+yL5abXBNM9j z%ubOfQbml^4@&1ye^GY+-dqrur`ZYeM0!ugw-#Kd79=Ou$o^=Mx=rbb%T8I3N$-D0 zev)fylKgK-;fjerK2F&y)EW`!UFzF4D90IU6MzaGkU5V5+$~ulCsoVyeOya*U7-1DFR8@<^i8_6{14S1KzdxpO&HNnjla7I~zIu`j1*q#cTxS z{KHqK@OO@kKS#$1)TIvF+!_+62NFtMNxPG_wdtzRM%tRG@r$L7Y>(xxK_1$@sX5)? zF2@?@FuFx}rfq0ChN&k_=azh>&8HkKu`uddqr>IM%iduxn*GD1MF_Vg#H#iP*!rYj zz^bQCr~OYlag82%SIcswN72PKAL}D^iVhVfH&nf5J;cLVj58|rX}mqg-K?Vq>B(WzLHbxP*FUV!#LqDCu^q%ix>+8V z(ktezT|18}Q01E7&UX3XTzuFFClmbsbDEmYQ2|`15pE?q!V_!^u3Z(32})J_c7lxT7H)W9*`aHW@^{ z0(A-CCvE|p#0TGo@*4$k5sxSjt`aCCY8oOP;U*-&m4{pO6Zo>GBfKsa0>6SyZNY?y z+71=+x3|e$H60o@M2LswSwl(u?Av24sv|(LPXL5(b4I6dA#Q1m-S3|@#UDaE=F%(Qi zhLn14QM9_&MX*oN=!&cf2eEOn8mw$mi0jujv^A^_Hn}bbvF%}3V|!>L{%czo33ted zmIx>{sRKTp@A6fo^B?7o=l@4J>zg*VHLL}R4Ur)BM_f(87zNEB%VeL3qD(u}{HkI=7)fKMB*7kKB z;h=2mN$E+c;A{KZwiXwu> z4IQnKQ}sl=eh9@-m$n=X5}pfxjAl`k4YYiV!Fw zEg=-=Z&-+F@aMqKyx=T>BCy2pOppI&AaIsU6QVt&)DMD!GCdjP&xfCk@B$#Z0Ol2f zru<9UXWo@7JKCTfR<}V%t8kbar3KT54u>M)bBmEL*sux{=gO6htzoi4B_rJ2ur3mh zSh+H?riFd0Gpt;>F47baB7dlX$+|f4H3b`60jVgPl#(_R0rMYIc5kkRLc^m6RD7R? zy&Cptc)y0bG~B7-HVwNq+^S)xhF5C1LBoiKAq`tKT%%!=hRZdq)i9u;Ps0igJsOs1 zxIn}6G%VJzP{Xq|oUY+i4P6?J*DznhJPmU-%+}DMp-n@f;b)I3J|5HXBMpyg_^yWi z8os4rpN6k$*sEcWhWBgu6Aia%*s0+f4J$O9uAxK2{{4!sLmKYXuv5e38lIQ>Q%goQ|N>rr!25wkIgv-v0Y>YD$z zCBV2g_Gf%SXZ9fBbw>QpVtlbbv;4`e|F6dUqY=QG^6+QY$WZ(_SA4++>ujm{zgTPI zxpGDPSv?s>;vnd}_PR}*w|w*Ztz9=nZ|wfoP20Y`{W~}R%Xe?taqIWKf7`$Q+wD95 z{f-~}@JBzs^Cv(3*?;`}KYwx8uDf^NbMJk>+;jf}5B}<*hacJ7vv2>S2OfL;;Grj; zeCpS~dHR{&XAeL3{BK`)@yJUrzw+v9um7&^jW>V))*t@(cK^UTgYUlgr}vNk`GXHX z`paKGKK9A+Pe1$H=O=_=vD)lu>5h!dtn8d&&fMW6M&^wgJtn_k?6~n0CQfoqK5fd> zX{Vnt{mipwoIP{aIfb)}<`jSF+%KOuci#L3=U;GPNy91_V9l%7w0!Nd*0pWzp|6M6 zMLI5DzhUDQU%h0-r7P=Co&Jq0ue$o0|LOMsPuKr{%zt-jna5kcu%dF&MLs_+GcCb& zPJ9D*`ByGh{6BU2KL!8)PsQ)l&HF;)CraK@_SJGjLG#{8&neb!ta9bf$xRygFgxnV?wy#OW^C_ zJK=Z2_rUkT3oFv$OW^C_JK=Z2_rUkT3meklJK=lag&kq|PWT>pk%lmQCwvdQNJkjH z6TSytIPeV53o)JWJdWt(feY$f&%beW1js`Q_Hs_uQ6 z(C1R|_b*kDpADm^yk)fuiqwIlHj06G7tjSr$M_zN@7I%5xsNnV#aHsSN-uFKXq%#- znJ-tzr`Egt&#K-|Ko{zxW4)>QdUd{Ifad0fnU5m5`2(9QR{=;7dkFA;KsqxYVa10O zc;z@00tmZwnCYgwWtLhvkk>a7JNaAu>JGXYClt49W)~s-c>qDWF@ULvcXliK2W7GxUXEZG1LyutZZyp#Y3RhCY6rlW&}mEiWbeS z?Q%dh2IUcrh~P}6u^lIoEjaH)pa^*hS*C#rgiM4(^cq4$ONeL*LEdck1)vDEuNSPj z3@3C|@O3z`nu;`h=MV0}G7TS{J!MIiyGn@JQ!1;uC@Mu~o?d?r4fPX5G$(oeSPy2w~538t$yDl>g7d zIU(cd7RyuHFyx#khqX8ZR4HX^f{m9|2iLYof}Y^2j@7G!;Q$mi&LLzm&6hZ*u+LK4 z(s)@}dxy$#@%kkl!SKd}9T~PoUS$<7pg0Ybti%5<33;x}9Tp!>A9>G(C(E<&{|0#F zc=^~{y#YJ1xbuVi&-(Rd!A}?9br^WBz-uq?fMtN{GX+9_wm|657zn&3Blyb9A}=BG zE(FB;4|v@M92*;{YwO}R-UwF7kT-OS-qli!t%Eio!Zc*OR);JB?$~_OfUhJpJz_~mEaMTxmX${Jt&~jO`aUG7E6Qon6 z3Nu~pCnD0{0qq1nULr~%nY?jZ1<3mwO~AZLd<{>$F|bZ*5#+~s<4rZ*6rsC#JvuR= zo?3abn#6zEC*|Q_Q1^!{hjz=s-_%4iDb}ydCesu8Px54SLwFVTFE6QF8>$XA&Wdc% zg3_`!)E8}(!9D)X$f=%;sGH1FHh;mJ9nI-?ZR&8WutcGan+Cs2AahBZJj#5mVCg-wdv=Il> z!CAo#vV*?5VFix#V`I!!8d&a{d4bN%b|F2vkCU_fopd=WneJ_igg3eZ?JYPQZivit zk?)#K5`O?2-$7Tv>so`ud`|efUag5;O&x1P!KTS#R>Ht0-b#0^YfZyC*Q#K!&DGqp zfq7(o8z@Wcp>WWAqhZ}-RU^}@gYqPe8ORQqqT=Nx0LHmm)r1B zjjl+$t3z?ODWQB#MNg;C&|EgXaw^QMVJxnwrmpc2Tp@ zl29dPLI3eyBOUMl^QIKT)P)=H-b1m*$#h~(oZ;k9tA;@l3AA=V3os9zj+ecan4;rX zw?L%B2?;V@St#i3GMu}Xaybb~c<*Z!{$GvO)523u9osLcy#Srv?rLpsTWzLbJtDUf zZT58KGU-lBS&uz$vCH+?XMiqU)BsG)=d-GO5x~Ef?;)MvYC-Tm{@L`lDm??RbTF_@Uo_V}60;;db1f_W5KnjE`BXG8D{+!$xB@I#4JhA#JM#geJ7rW z;sbG+xD)Fq{zPZyVO&We`XA}o6G_aH^vwDle~hQQ@H|xg#AV`6te^N3otcMmA(ROL zANE)hvm`w;|JH=`9SP6ONF1h1te1EbU1GgEQKld1Jt=t-^UJ<`JB}kCTYKXIA3 z6YD4bL}%tUBxXr^X8oNB={rtQKXIA36YD4bL}%t<+&1Wkex&!LhW4_2an$?%lo8Ds&+3KwUOJV(eR&fXw8<{qd8LZfG(XSN~(HSazpX1g6==<$6d{?JujBNu`vk?;HWSj9ugdpn?{ zE88Nn4fQ633`=@I3))don+}@NNK=pDL|@_AS(FtTK0Z_Nycj$W$N6p2bk{>x@$kb| z@v^4LaAo7J*>K^i%@r<`afQbp9ov`RJGv(?G@P;lyl7L1|fyJ=viw?2~Z3^x1K&Ff&Vx zYg!`4;R`F{iWiG<#v-94TIDGLlMLC<=wHaxDDV$sqG$NYalK}rT=ue6{1m=cw=ctH z2wN#^Of6?;zG4+K;VA=zsp(aStJdj+!^dQbF-^n77>v0w)gzA%?{oI%^km8YAdZ1o ztz!LaRuMi$eS2QFig)0*A)S!UNVkY|kmeKbU}PqC+^hpR5Nf*d9H0jbRostSGavU}lbYQe*`B zdN}x)D@K+L+n#yU(U;b1>#^uIupIJzX%b|29Q526jGvKnhJ{n}6%xOcIVWUpm~iff z%(0J0AU-!ue88E4 zuV5zhjIk$qUMaN5zS+rfa+*V&Rz30P_`b2d`8}gUqv};1)FD61!q09&C(pVyb`qq+9VFJI-RLXQV@n{2=>iW}l-st;ZI!)+>2rJx>m^ ziNC<#gmQ!ohoLKP`i8DY>eFoKQ^*i>K|yu0e!n@_Ci;e}bD_5YGb9hwW4hKHpG6~V z;tqKBnS>mFwIih5jM+Z2Z+Ne>hclwV`ie)1g59Hz#$(a1)3U_0;t66J^jGry4H=OA zISl;IL4Rh8{BT|$=g$HquYo3;O}Kt*69suT%wG=b&5#*KUeZZf0z87Vxe`WbH}OiF z97msxw@DlRf(eQ*HvrNWVLIImKqZe3F``!M>FrW8))!=1MOJBgAPs%NdUuc(_C0j( zMCjhJped(1qsL6sRmW&*#d%zb83{NWb#YwXJXz835FlOtX)4Tgx(hW;iG1i`-B_P- z9vh+QW4(+woym*0QtDj=eAFq0x}L89(tV`EOs8ufqTYViJ1I?!G$x4bp3G22y`zxz zGM@FZB&|lu508*RJ)!~N#NzHF`c-}OXzXOo&Djg<`D#9k)F%osKu33O|^*TI! zlnwJ;mT-h^QU-HhP;@jS{YKzod!Ey{2X$E4SV?2>sA*%dovWtX#E;>_x~?&-Fz(j1$}Dz=G-HQwRF z)5LJ-gyBV;Ipg`BL!L2TvWXYWd{QT5Kqp{sfh}R;yA*j2!@qCRDd*4OLhIc^WuFX( zt&t1+#0h(2n3%A=;3(~rf^lim?n|`QL*Rum7UKzX(%9nRV(j+VydIExC6WU@20qqm zT^0tOe7nea)5N0qP!Bu>6Vk-650cjc5`TsvGFG9UahYP=0jC%j8HRZ+M~s8s8Mi$z zAm=dHoiSTe&cConBd|wd>u7tl&*Z_Zg*LGmKJ#iNC$jBDmcVdnuL4g|oL}oJY~ot@ zX=dJW4%DB4`T=22jw?d_od2%F{E*1=1RPBg}5I6|coExXNU^@7>#wkV{lSNjq zoNw#xg*G{7^^w2$dFf$m>>_i1dxCq{q7uf~~cEL2v5wKau>`sUgqlAlBdxd0DtsQRuzhS3lezYLD?KUB7?A;e4-eTMaWuDAX?*pr zN~qK-cEEdBHpeD%aE@cg+AuNRY^yOTLrl7E+)-tHj|`2dA0EgpL>qB~B;Dwiwsim^ zQZNB?iE)~+A&q>X^2*>k@j!-{0vVeE8JmJOOevZav+;iTszvOAr=Hsnm@(FYF#?ag zW07}k(dgKEZ7R|Wb>1%nk_S6qvWQpV3y+~42=n<*@Z%YVy)f*pG_)%xIi9?Feppgj zBgZasR!Iv4QUTJXjOsN8?5zyBmcpCSVYQYbz1xmh#EbBJCMU6~$VuZo+?U>K@3Dp~^|IV8 zs2_g%C#vmyw(PKoJci|7K&DJjio?D@XF@q6%g*_qSnJtt;&px3BK`%wQ{(0HBk-*; zybhV36bBnDv7C_sd#gy&8Yq~^^;+C^HSPbQ;vqVchR&-k;%4}_SSNV`d9Xts6658% zuU4=7re}!JP0PjT;$_ee)k3Y9aKCB2niH?s2s`--)mMbqqEAkxhhE=c5r2SZze>2w zCYD7qX>S)69JY(Yk;Njz@Cn+la=Zf<`4;k8#4GS09cOBcc+C6t_fg&kL0>-x3axS`?hZwVi)`|(muf^CLGAax6?-^#Y>quoEEaz+X^!# zWr|5n1!7WhzL@kue2rz!Z;>ku@g}?h+=Np193FiX8n!pLXILnwK0CIqTDrjyx4<*6 zgtFg;qYbz>kA084-D=+|aG4>7w;E!{XQ0tx5ss#jA~DVw?topACx-9N>C{@1s?B&U2lHzEAVr&TPRdg;j#P8vE5PvrJ>@qQClj93U z!UniQ$q&~FvYyCSto2ofcn9A0Im#kFHOw^YVnZAyZt}Hwx%H&D6g&k}?P7#cZ8dcp z$7(0;loEf5-w^)}-=yo~^MmjKh9&+w>q&8urPjo91(U793H+9N)gBY~(M5*1;vz%b zD{(^)M5?Vxaol4=oTK*Qr1*lLZyeW zH&?7|YF-gG$6RAE_7C7exr7C0V=ip^66V8VG1fR+#H`{_TzA*a!L?vrhHwcA(~iqA z<_L4ofO;OB7Kf&Te%zlVe!?%q|C`tj1)9$SG3xsoCzd@j|=;Pr3-@9^h$;FQj`3);HboOefq4 z|EdlX7EFSDQtU&UD?}Q2!~QEoLDC;65Ml@Xbb~q`9e5xY<8fGWJoZ9z5pPe4Hyk$M z*e>^7q#o+b7veCy;)QyC3*j}y%{d2rV0uy<_>x-AHAaZ1;15Zf)boc3?_yZ$MW?~^ zSRB`$wZjZYagLE#R>^0kVbN_aai});;J)~3+!vpY^KtTk&o{y6GEDrDo08)s{%=8V zbc@8Y3jYnlQm=SgLirz^20J24j4t9%jWecKFGHO-z_X7Cl}(tu|M_wrcn8lsghS=I z81bz-4`JdS$gVfB7g2z70onu@KjwZA<4s50^!;dSi5UqPx?1mn6kFw5y&8~iy$&;- z?kYf*PptRIDe7gs>CAfTafhJ9j0D`K>+PMR>iqzaZj7#%>2&`(M7`qoXm1Ym{wlTq z#IWhi`g&99+okK{egyNHuv6E+P1nC)hnb)5;UVgu&iW<4v%&8y+IVvBgYl*_=~#}t z4kczJV6Ub_6sdN<2uSyi4l|wZwIS*aoT6UFo6fAaH>KXAy53!ds@~1BRlT&3SBtP^Xj&talH-u44{QC0ZcWaU7{|WO zH%5!t=}Ns-?ro5FJ5l~r=h>8l$8N&e^)}Tvgt_obbeOQ<>AaTIzBe7 zSi6sbXI~S#i_!j>*bl57W*t|YV;u*fH20&VEd!f^?XF*K5u4yYW4om-!?gw0qlxj= z4pIHQP57Z(G7oT#k({p2moRc6Pa}Bdq4&V_xMDrI=Uc=^_)9Wb4_aKCnH&fEa#AE4 zc3&3kzT`Ax81`R_VyA?K#21)v5qsc!WB77Y;)G0p3V9x4o{>0jh+yvmZJhfRq!F~6-}0VF*rXc&P<9=*hf-)m;3Ko z+<(W(Symv`4&qEv`yE59h9^CQcf$ARFyXA54KWv<>4YWli*#5*c|QebsMt>%4|)>M zQAv02m4^5W{Mp%{n>O8B!-V7cF~Zg~Iw{RSdiI-+9_$(fxOb`cCvYDHazh)8cT&{& zRCg)VnstoWw!#pf^;P1nVTu* zBE1ml)8x4Y4A4|OoRd@H4DJzsAmy)K?Q>=uaVb%HHUJhV9rs)4xTllmhI$;Ju}^Z# z4RI0t&40nVmGywXNpZ-t(}Om_zsferJef&xa$oum)Ft;7aUPF72HXn>QIAxhyzKiq zhDa+m#PbE@3wTwWEqW8YL|P--TR;*bN^U#`3VO6T>(w9)Wx|@HR1Cp7+;| z79&2$>d6Q>>QAL#4dAZAqeRz%cm#Qpb3H+TpOsMu?<9oxjd06L? zd$C@CCyj(Zg#U{U6DoZI{aGEq+jQtI$j&ZRhVV}Kuivf0gs18c*7wp+VBh>qisU#9qK^Vl=u0rhQ`1!0<0zlc@_Dc?k=KE|#2JgHZb>Pt#&fm6zLUOP zsO=^&MxG@$jlsM<8s~U>zVy5rdzLPUK8|xFSRcZk- z|4c5LaCBUsvRBzYam*ropIF3CMxZ~&;M}=s8Rqq+N$~~KaMv#K73}LS$Nhs^+&@sf zhlzzV#tg)tX^b>ZGg8~eckhjf*9+R{So{_5ee*dQ#sPvVW!RJ_WY>X|Ua4 z!y98yvfU4%n+m3;ixEv#SbO=gU%W_Ug;XDupbs)~F+UxSSRh_TBJPA|Il>R%FZiYk6RNo`SM0pTB7&Vb7ahgEMjeS^2lvmD^BD5ZA?`e(e{kn1 zcIQx*4OzsRuUo_qB`&laHu27+IO-+H3E~CTZAobtrHPA>b{^vGDdpr?-W|KoSD3;5 zf^f1%G1tJqXa#TK*>3Mzvz--U*BbC0K7X`oXHr%5#O^aItfc{ z7ID5^g$Xmpa{qlC=KQhPf6q(We>Zu5@8^a%|Aewt2-Tkbe3Y4oGDS&c%=6Y|9~xr% zUsV~xYteBTV=}~;)cX*HYR+K4-q&x4mj+cCLh_RzJ}HLp9|L~M{`^r=oa)aXqd)J6 z^{23_z9{*jAufSWJeN$0qoo1+Q`~Nd`S2m!w_%-p-U5FK!{CwqK*q^&DdprodQp5I zy=R9Z*4}D}ohA;fB@*L|TO8sR;274F$+e^$=W5-7HAgM?P;fTNvr>7+f^!svdEbWg z6>c#^H~eSBO`b$XCdJ7+shF#C5917?9(PhFW#b$aXP~%eJqdSK63;@7sTpGG9j>Dj z`^NW~sUIB}g+5WVU{4hDN*?4kFRactJ7K%u34deEu6Bx~IPweUp^0(w?m}&@ z$l0#WMA!zG7wZ7{MEg7`PU6Ac_Jn+j7qIthmA#)Kb=D{`25lX4IIgoyxxM}ZLmaxh9l@F4lWs z^4@#KXoncR9XEOUhV`2F6iqt5H_H%3g^CWsj44@SO4Bslx0x!YK(EE$3W$%lo2D6J z`5CGVp|S&S6eq3gw0*h_YlZ)S-!YEk1d-CV$P!8MYaC(?;)lP5-^b88FEL&6w%Xpy zeO0wLgLejCQQY?42?e=+t~}5cysZN=Q4QWCCq5WyZ7)66DqtnCgD}~Jg91# zVCz|lwPU>yKN+vbYD!$eoD6YV@g&=6#%Nn?9}RPX+@o_TJ+=*|e$FLWyO}ti|DG)| zu3%<5Z1L?j-EW2F{r1kOpil0b`jhreIcF%lxCVByFWD|;nmm(z4f_36==bMO((mN= z{Bv*@mU;rugahzr6sa)bw;{_JBe3_jd)U$JzLV{k&(8vTW~lsx&%n<*&B1Ue) zJvY{oi*wjW2z9h4#VZ=W4jNlUn(qGqP^fr6;upo*Sb}-9J;xziBq;1}RbSv_5QIn zzI-8gQL4g(r5@R5s(n|3_9)gAql-t0(I4n{q$X# z;w1Z5ou9hop5jpV<#(bj?3-}JPS`gN+{c|?)%6+s8!&bysNMmcNHGNI^kio{UNmd{*&%1 z%&}O-6?pHBxCrmY8dbHK_y0$q#1G02wxor6R}i)-))M2fmKeV~Zlfw2ZVB3Q@;N+t z<7%^rx$w)+Ag?m9j|YDs3;TH4FurmifVs(e=4Xoe$m2quY~*oB9g>{KAde5@ZfzdV z#>Qhzj}|ezwO+|IwkE|zmsrHY6-p2I07LM9(%}yQ$6RU=KZYki{sZtC_;1#$a1`(^ z_&p6O{1D))@aL>j;bOq$@Jkw1cq!oJ@K5OQ(|{-77Y9{3A^Fkyo*{0Bub)nSVBK%> zqY3-~FOt$J7f8rKB4f(53s8E|s`nGDPFchS)~jxH zLk-5{NWC$+X{9l__)=rCaj~H^ma=8e2K~SLxgq`xPo5DzbC)4rhG&@YOS^DJ3ePa% zPWa#HFyUwL>36Gi!t>!PbeJ#%{|y}`{I`1z@l$x>Bh0$b5ToH4CiKBC(_z9Hzcj?T z@J#=|*n1cFxTM zhaev%7o7GrN6m#uyx;)j5puyVJ?5xEh{Oxt{5bCUg$NhCGV7>oA;JY`eBDteLxcK5QMC=8>j_F6=_lkMbonzl@a#S-8!X=I1 z5y14JXe-Fh<}F_uS);+Wy0bz_V0Sxb41hh~o`A@OYfh zID0#L=JEVZR$n74o?~MgG28a_*tSzR*1N8F9LVF?H0Fvs_P}|pyN}uuRo*Z&kAGs! zYg9+b6PqtQcaqxj{7I_ghbP5aO4PJg+>djD%wagj@bcrwspFCMNTjW>(jIu?c)Snc zg_HDZbE0@3Q1Wv3_#(W+Jo_f7BuTE)w14F@R32B zSs#CPyY+E7zjVf9-g}kD4?lL)7a`tz4^y5nxKhEBV1%E0UuiY;Atgsz{@l9h64}Ou8Yf z9(6N|?SC2cz8lI^?~Gzt{j74ebyJxd4Hd)AI<;IirOH&!lWx-7autN_h$meHVRcBC z@q}$fm_k_AV>^Pd0Bm>kON$MDDdMHXPGXe!5YhE>qQ#e@F7kU1@gm~Y#7_{@#D|Gb z5nmv_P8=mx)EU3~5`)C)#Cl?s*g?FA_+jFW#M_AX6CWc!LmVdNiEk74o^8r;9C0Qw zLTn`_h)Lom;%&r1;xojTh;ID8^4pgfBu*#R6FVX%-9^M}i2cO-h)K5FX7V?=9qcvF*dInbkvNCAlz0KL zk9adNL;M!;72+?5eE<;`fQaCjOaN#&!)5ClRL->xoN=x^waOVa~NRoHuSGe~kD7 z@fXArrmH5pe!g$bYaiqIxQN(Eyob1%_zdwS;v2+269e>nCHXBxH{aDPSCr_6Pr?@) z67quK`CT3Qo#o3nuA8rp93!+v>37d|u1%QNqgNH*E$w+fvwZl%eX(kH_ab>)t$1IG zSNqP#3bktJ+PIGI&o%F*#yaG?ik>2P$t=@OEQY!s^ee3==y1GbIo{!hx5#@;Jf7p- z`1HmON`bV|<@2M9POM+NSdEtPecyP^^7?kXDWC*a=1t$eIyEcrdz||`Z+o7v{^Y<$ zN}|7*@gYxK@lDWYmO@{-CVug<)sj+u+>@#WueUs-Yn?B?rwnhsmX!MC#PaIlHVJ9y z>YxL4R{2_dX0ttU30gI#b-X_r`epQ7zh*;RzR@A^6;dntil2U$FMPS_(H2+O=@I6X zvsLsf=o_#y{gl*kf&cyEt)>L)5^Gx2=|*qsL2lnD#e0l(*WhkPXCXfOf!EZo-?*V2 z17Ja^yoA@~N81MJTr?da!jw1bb@inDO@ZH%p zkxP2wE7rHH>4-1r#CNg}6#r(#yQ3Cu)lz7~`D(GG@V&GA;G&HgldzbpTaa%$2k&&e zZ$5v=EeZU{`|G9et}I=ah@cl4#tuC|suJ`8(u}kss4Lo~UwtQnZ>eRsm`-k@dM=UodSgJwmHOuPTlb<4 z^=(h6F+`yHo7-lnx%ooEt)+UJs9)b*AHQggY~{CEAuZ|+RlhNTuNk37%t%&myMAQ& zqUm4ojKKLSUW#{{b2QG=bBG=nW=N{jbcl=v6EIzKJwvN;7z^uQTbK#ZU-P}&4ERCP z%l>T(JAv;$_pEMFCl~bj>U|~4F$|d!V?6K3{I;ll zJ*MIt5Z8lmi!8#25>}wB^YL9~y@y3uWMfYcKEA46!d|PRUVps=cgLYrzVyd>Lh!`0 zv#7gZsvX7AANML_jt{R!+cvae-+jjNhGw@Gd&*u=Hh*_(MH%shhx)~hZi+8r6kU?Q z_g&w+5qk^{U9`rROt|^1K~r0Ir~0-DX~sl>owPg1x0+B%QI9vrtA`D*mybZNzeF3V zEhY>_5w44==GU*pPS`EQp{jmE+xdDNNl8)4N~UX5>q;CUW%tbwUQ>{`?&85_%sBf&ifIqJZJnni!5*?hC@CI`!{)9U~n2-f6t`{N#k{Yq7S-%^!9SOU*6%euMT(~t(wT!#Cw@m#3f^NoS8lDIEi zu6d?$y>EC8p2dWuR%5L^fiOrCdh9^F2N;q$2=C9pyHCQ0;XS#yFCvG0<(cUqp0Cbc zjI!V;C)J6vt$|#I>w51)8(?iVbO~@69BalYU=+t$c}NiPp*K-)NMJM0H6S58!x+Q6 zrt*;R2IyUA|8;1yD^O2J5)u=+68cAA|3Tob=)1dMdpG>tj5fL*Ww{M`d?ng*A9-Q~J_RBniALfY3*&Yw6c_%pO2t_$S%fz5tE=%H~aR{-h8qpYtY?>{5m zUr?tiguQ|B1)E`@T%%3r5%(LkAucSWpoe~ka7gBlNDs^jB7GR5kYC_Wut!(`aVcQp zEu?{DASp-|=@JOfLk}R|G}2`uVc5kW0r&_bE~Zdc$S~4p%ArH#Jz2vjZyutSBh3nw zEsC&agh3Lgqiib?{sMgLgM1;W>mlgx)H4bn7DPWIy}a)z-HZ0P1bwg(?R+r=9H(Iz zU(g|;E3h4j^dgUoVT0ouh2zo$uHneDt{IHEv&kVJS!&l3fG73J8&B zR^|EG1llfj5qxwbYy;xac45p-`QM^V(578?aN zNbKXtH-)^eM?d5F9C=13eHGGO4ZH?;E#za+>(OotQP26PAFh|CAvs74JQ#*FV2mMN zA#7Nr5%q$E7a$C_p$KfCN1-R7#}JnjJR5a`1iyp21Tb&6Ag@oLT$@l=jEBHeXhTST zF|N}s!F|?em8)N4-}5$P!t!!;C}av`7GwdW8S);;g^(oVM#%k;Es&QXBalBpCafsO zeM9AH5@aSM3^@~WA>;#)O^~}G4@15Qc@FXlKz3~~$PcE~-D2Otka zo`(Do@^i=^AcvssLy!hY3*-XGMo1szX2`ve&5#`Ahmb!(_C6bJ1epd|2ss;aK4c^0 zYRD~+MHtU$mheT zz7BaA;=HF^9RoQ95`}a?HbSn1d=~O$$cvEQLMqNfpFkpzb0C*M`XLWOz76>)`GWH$d)(Y=OK4c>|(Wm8<mheQo`AdpDeb_uLdYCQE2JBeg4_dn z3i2A{uaN3^xjG6m2eJaP4)T7;4UqdG+aN!NyagGz8ufu3200Eg3lf1WgS11|L3$w{ zh1>yo81gja2aw-DD$d6kgq#dn0a*{}gWLvr1hNe>4EYu0ZO9&Ym+pa(!y(5&Y9XgW z-VN!1Tn4!Tau?(qkRL-vA$zYWS0_SFgLFc!h1>wS7xDz;N07H62VH>i1DOjs9nucD z2=WogXCR-43_`MyZ$Vy${035TA?6QAEo3R=0?0=o_d{}!*CBs{?64IDX z*#x;0av$W&kZ(YqgZu>YCrHIQY-^AcA#)(jkP9FeL#}~*4stK#5y)1^k0EbED!Wi0 z$P~yd$RfzOkadtNA=g80g=8RE$af(>f&30qvc6pH134ZNfvkkAg%AD4kdq+uAWI=@AlE=X z3&}!$1o;DG&kZOOqzQ69L_)zItE`>K2{y4j#pFgCAkyTNh+jj z)l_@~b-J3NW~y0uTl{Q%yYmz^N1cilr+F%@=BtQWpz2kFTBsWFCW%Gr-Rd-aD|U(g z5^z+VuA0?yeC_TGwNkaHR&}O2OP!5xzMYHj-Nsa#TBX{Rd{cHc)+syjg}Mvyb-uOu zhG!SPHk-iPjW*zmbv;-$zDQk+@77(SE>-Wtb%^(?%hd;P7mVt0z50auq}rrzP&cZZRKNO^`n39tx>>)kEsbSbO>kzK#8edQ^Q?ZN_@@W9o60 zRbN+6sBd5m>Pf7pep78#PpfZXEo+ibv+A5#B?Rkr|E9ysTSp8VNs(zwgQ$JO&tDmV6^>g(L^-HX1{tBy4zrk_yZ*lhid-bOJgZiWT zlNwcTsXwc~sJGQ$)!)=R=zPa1aY}JpZMicJH|$h6mChc{p3Vg4UCv(4L?_@>;SQ{Q zoPC}Boc)~xoNDJl=OE``=Md*m=P>7RC+HmEOmdENCObztM?1$jHO{flanAA16z2rz zMCT+Y@0DXI?J4>bGp;)EO%BoXE-aJ7N^xY6L)By?VRJB=bY=j$B8*@&MK$f>2TuC zYUg~X(^=zO;9Tgeb=Emu&Uz=|yw};_bUQuHM&}~uVyD-+#JSXYpL3b>e&=%M15VPp z!nxA9%DLM4pmU9Lt<&dx$oa7I5$8JRqt3^ik2@*ndgl|)C!I~s4bF{@{u-hAs;R!n zh|e-EjpGZjdUZ(o7*@6{-r^6?R6bmfZ(~XfRRs6+w6%A-i+5`N#-8E&V+b^WX zP?~R{#y6Pjmy6e*&ua-tE1&i?tBp(6bjx>r>*I3GE8f+<21{~(CtfluI`HShDAT>7;98qQD!vdvHSqzGSPH_1#pm#@m4p;~H*O!reG&%YwOF zXfhH0(pllf{L!rXb_}`20$zIJUGmlNC2d_;G~U4N5v$bZ+puWRu~YEVv39H(+B-2f z33gzON}CwH&~5u()NLY-i;nF|=Eh6SaY@WJKcj0cB6d{t~y4T|*DUCaw_k`m zezp%mqV>3C!(3FAL5W@PMRCrDxDdR3P>Y0No9&7B_UKE2eu}ab0~SWlkR&Ed@4Q?K zP0o*Z;O-n5sP5(sQ#VFmV(>?~*S94H_bQvd%!peWHb~&RF|*6H8o4JxCY0@iOi`ra z+>*GuKSuUAuy!LC;>+uDn~%8{X~!{sCj}QAN9NcxJK4VW=l z0dp^dxy&O*%W<1Y+&#+KEDcP@axw7jINE{aa^&pj}m0hCLfSi z=3?FkJv^{!$vrzJsCy?-ExtHYeqI%%Kbghj_+EH?42NUI6+9LqnrKgYE5>W&_IO82=bH9T z?xVFAkNu7l6^7-QG9K!YQkMi-2Bk> zxR{L_t@QC5zI5Ll@6flJ$*A;3?Lv4rrWkV@hOsmg{8&Cs%yurf3${I?{iRI$aG}tP zQhr3BhU*gR*WxJ4on&x_#S5+W0hkEk=VNZw%e6-Q8zPjW28T%Am(nBvGOu8 zZu&y=ZWnCVd3oFFIO>MIyPhd@F8(mLxXaty-z{k=##H?ylB z+scmfH>rt5?etlTrzE}zkBvTdcGF>3=V{?W+sKK6Nn%c&+~ihxal4Y65xpCv@MU9c z|5kX>0dAU;^26wJ^nddk3=C^}z zk1KaaSxmWpU7~G6e8t7<-J89;J?^)U^!W1c9Sa`Kj*rw=T02Hp*lc%L#+9R!qLr@! z8aK49Dn^+(p^)DgkzU8LVHIm6J?d6;>`+ey-7L%jR0JixuxQh=CK2CZnZ}3|zw2;E zw)Z|z6CyWzaywuePl#(KQ=dPPC&VPWNQQ55!C3lHMm|fAg!aC?Pue*iohoI@R`eUY};o$Mq=t zaw(9<^VkV|{>M(@$wdy%+$@T&y`f%z-f*uI>1(|V<}aayNeFg_ZXRb~70}f;j2+*i zPBFCOl_X(b0DF(`@u_!Vv_|R(!e(H@j%dVdECcsT1ix7Gc z8xJn^Mw=d?hwY9Y7;X~DV*%?D8{|rX@mC0zrys@&D>R2MSp zVFZ05>SHZBQmz>;>so*%YDqUn5K1U!{&ccCl~B24f~6C)3$+7i=}kjB*~hwBx&^bt zbOvUpB1u=Vbp8-eqCy!=3QZY}d1OP}iI69Yk}>-q_V8 z2j{wEJ}XlMJX^uTc6m~ukkMF?o(f{!s_PQt)2x#g4Z91MqZi>S(wZ)l$`ii>GZVbL z2bW4%=7LSM4a?3r$}mZajitl6M&(azWr`gd7LdpAU?OZ6Ce-qQdDIL=*0oNP)44HYJb^3Mw4q0vl z3)0oS7Q=QaruK{UQ`2gUuoiVjmv8-64jwsUD39KvIIV=trn9ak&AQLgZ2* z?qvGU@88`5Q-b~y1VbSe4AnxWLZ(5cLuNo`LS{kgAhRKDkX4X&NCzYiS*?P#u&;%E zE$nMyUkm$M*w@0o7WTEUuZ4Xr>}z3P3;SBw*TTLQ_ETX$74}nMKNa>9C&;`{}Ts4*Th_ zp8@+Bu%7|@8L*!L`x&sG0s9%Sp8@+Bu%7|@8L*!L`x&sG0s9%Sp9%Y!u%8M0nXt!p z6PyYAnXsP;`|8@F*w*GI^ z|Eu(WyZ*0U{!wcD zqulsM$?=b};~%BRzb?PbAfaBFL-4Qt%RB;I`s`1YP@=nFzY}FS8MJ?O$dj=-U5u?O*04glPXVH$m6_Wqu0v$_#~n?O$do=-R)` zRM545nXRB}|1x7i*ZyZ{|1xhOMEjSy3%d3%^H-=>W-$C~|1yg~*ZyTDgRcF{YzAHX zml+MZ_CHhmmw62#+P}e_ezs#u6wf{ElU*=VWX#X;|Lf8Ifehu}?42ys5UuIe8+P}=S z(6xV=ZJ}%bGUGzm{#R-LGVdZp`U#hVEk+UG7Cf3{$(bHuKmkw3|;$| z85z3v->&`3yo?a-U*=}$+P}=tp0(6xV= z-!Y47|1!rz*ZyUmhpzq0Tn}CQm-!yL_AhfjbnRc}edyZ1%>B@{f6V`(+Nsl~&zL!@ zZg$(M_Kx^!JQ=5!@emPD->Ib}628D2P9ouWTv`8gdJ@qi4JKUD%r~kMeK~cVo~1I-@pp!a8^L;tbo>80TXU2V8TtIwayBN-dtB- z@ZUV!=q$e`Mz8hgQ$6}Lk3QX_&(ON|?0VFzfP<(EEc zuG7WW{o9P=aQW#pIMOca#d)F`N8QEnX&&9oOU4!l`uK^yWJ%G_k|jkyOO_P70d<`Lb)5lq-9prL3(1_1 ze02-Cx@7F?lCi5x#;z_IySijN4sv#+^?2zTSC_6adejphJzm14JOATyFqIHyLZ48-UTx1|W4j8xv?fkhkWXq-T;hGvjG_0Q+{p$CfrkgZU77~mcQ9FoC!DO*X_v-!02WJFlo#N zK)o=oP_M$cf?gO`&&=_`E&DLj`$HT zNBpptBYw!@TfH3V2Q7Y|#qY3qzs0Y!_|+EgwfI_#$1EPTc$3BFSUhC$$ri7+c!igv zeUz6=``+tm@AAgTNP(k2$|H?_zA!RWh?gGCk!>SNFKW9fZjA1C_{|pVB)&0{@$rR` zbb*USKiT$v-5BFn9oJW|6Tj-XUW<2Hyw%GcRTU*S+s9#hH5K9mn2!#(_+E$kB@nMS(Sv+U)trpK(e9+<bcj1efo;=j8ue11ci%+q5jm3i&ueSKUem-#mxgJlBnpkG>x9@Vt4f+A` zZ(95fi@#>^mo5H+#kW~}i^Vrv{2`0qXYo5MezV0l`FY{|uc89g^PK;IOMTUKOs~fw z&OiHn_LWu10^iB@2Rm=N+QRnjZs**-k-vLBT7k{fSDt_=Pp?&;1o?roogkmiT`Z3` z-A>ALT&&^S@C!a>j8Okx4wRUROM^M z^rg}sFZOOc~J16~e)_-3T{{K|2x@!(YX`@^yFcd9n~%2R3a zs>+9a`Bzom=i?JA@9^<}m!o`GFR}dlIQFZX3ik6cVp3$*I2?!hwvbMhI^_q=O&0i0 z#(DX?J$ei2_TKUF8p@FI}Z zJG{_s{@mjJ5b42R^UizV#r+xLar_eW`a^uRm!sYl1upwnoJZf`8MojgUS5v#W-mwl z3l`sM@j)+#ea6dSe}|VN{$?*nd~tto>Ra5OgCqSWZ+h@PFNb~7%gg6Z>Gg8NCoJCS zbu1oKW_fq8q2=g%aLEe$LGye1M>$Ev zd)7fUA3t%>%HPi?j`#DbNqdRqkO|Y-Vn+8czq=6;|n7h zA8&}HeSBdg<>hF;x!hpF7TZkm!cjOyOgdW zGMaYVduRR@Mn-li9k%;jOt*Cx(+%!QI?NZUus!aq9+87HyW+1ha!Bz!VW7UF?=M>ZJqWf1$IU*MQ;v7Z~U_^`!au=qBM zZ?X7hi)SpJw)iHCUuW^FEqMl|w*HOdUb`RMdb32StkOKRa31!S-C7*LRi<$HRs4@1z~Dj#E)c zXX-tAOIh*w1>?#;J{lwb{%?%<`xnPcg>@SEgS~GZXIx}qz&HLE_}6uiezdR-VC+XM zK5TK{x(@8OTJeJx_pR$7y>DFy+_$a+?%y67BmVJ@^*+mgpT(0FAMv$s zY_;k;>N_vP@w3H8EIw@UA&ciMzSYYeRq8np#(8XU{o8zp#N94kRQiYW<8cMMAjYL- zS3GXA?Pky1%=*U4#IDFYG@mj1AveB6;)}dPb5-MBKa+x>95wFsGnaR8{&V>`7H_q< zd;QE!?_NK1dA*h1y?*A#*IDt?Ek4EK?)5X*-o1Y2@@gynzCP|)_a{2m{eq6QZs%C* zXpXh6`GZs%<+@F7` zwN5n7Q~xB&GtN_g!;ASFUd-R{V*Z8~^EbShzv0FDYi`wlT%rEv`p`J5{^P9rkE?R? zcheX1S5luUH-9(2n7_o2pLid)57Qr&RenBx;vI~4*KPfL{6zQuCD-21Cyw{?s!Bf( z9_r`ERo?6?Pax=zS5@x18uHWYYVQ44X1pIc-7Vk0hAXv+-9R-N#RwMej{e|Q|bI6U?`D=a?x88iOe_8YPI%NEaBe2c{gEk0oJw8i@^p7Qhk`^eqx zBWdwoizh7JY4MoFTP+^-@=`UYiCiDQfrl*~vUrV`W6r21cej@SxvtN6wSNUUk01Ac z`_umU;7vcT9%lcsJ*snFj`EE#y<6TPi*L2~pqHb(8FF_#3|KsE@qUY^{CrLyxm%v3 zmzSsm-1&_4Il!IIT<*?iE_dfIm%HttG^Ez@|WiTUw`6!qL=N(`W=_Bc&DGA5+i5+r?~!I?)rDj+v-oR zEPhJVinsWFecth0qV}`4&;6|Jb3beQ+^^HJx39b0Xw`+11-)ix!%foV>JxG>uLuFXXdDo=-JR#td z{d|&hhcAAz#nrJl`{LEHoBaIfz5-9`a$E7Lw-7JonQi5d`-Ob*lV|(OqtrRxc--H) zf}HmUE%fp6xG%#OzfYvD$V;6)BU5UM9M=^VPN**OQsEU|zQ@D~s>qeIN0pzWJfr<( zp6eV7BX3yzHH!~fe4E9$SbVd^AM$Zr$13ohT%W;ps{TT{{m~EZ`m&39xG2Y$4%ZQI zJu6kPL;r#Ic{%FuuCtlzQdcw9@(a6OpWTAFods^LSF{$mUeikK`=A#p0VS{*afC zYlsZ^IPUZEa`;bKywBoEi}!jtu9qY%9xL#jj1%;y|GHYF(dTE6s>;@aAM_KhUqs3E zJc)Aq$HQXATH^uN3+ugp#?6b=6}XHC+&@*|$Y-2Vhmh;}6PfKxZss|qCiu8xt@q-2 z8OEFST{ZD-zR$qrZ<6bJ;Q5)idHvDlZ&>lK`FN?do~){@{Hm<{s;vB~to*91{Hpx< z;rUhO@7DhXi*K{|7K?AT_(Og^vDbHfK}}5fd6gAk<&R%fLNNNr64#A+3ts4lMVLo{VMm^Q<6-0*Ip9? zReSGaCEs^HU%>tc_~<`CswM4#@^_H@9V~yv-yua+Ylm8Vdz$*5>5nuqL(CF$#9?Bd zsJ?IP0>mIOL<|$7#27I_OcGPXG%-WW5_7~+Vg>uRnpi`uBdQ;mawW)<#L^%mf-jo{ z+c$+bq&T3wq5neN-kkqcSqFY-nkVJ9TZjRnS9Yb{{#C{Nm*=zH{K^tkykMH8nphfR zJH>vq)Alm+%~;jYyNN=?4yPVDdBAUvJtrucattf}%Q1ocWG1pE9~1Ep|L^a!FcX-b zjXdFcV$xjCPM#Q7?SI}h%K&kZxRp3W93hSpd)b^dZ09;+6S0-pN$e%|5&MY)#2j&y zSiyO%npi`O5@W;!F-a^eLiv9|6h%rKQ_%$nxv9^bRiRw8MA0P&aA!3*q{UQs!YY4ZU%rOFv5)MA((8CT79x>_2$wwW1OwF;!9Y5uS6Hh9>4Z3WY?G%1(%=Sv; zOmLEzBBqHMVwRXA4ioc4<+igG?#Ay31GEbgUB0UrqFtC6wYVGp_b^7g1kvTYib>j~ zh%Vn%Ow%qybos8L9xn6gQoVWr5etfJhMC2x9746P+ezh*@He zI84kFl{-#$69cr{T@2EGcQHi!Fwy0^ic#9dh%Vn%{JZl3`{%&1ySXqSl;wYBIxsq7 z(CXjJGbT7o%n^r)d7@&!28cmo=%2(e?ROWWwBKEf(SCO^LHpgsB<*(>%R;{}9hf4r ze`WmOg}}uLVrLTrZ2WtXlTUGnNm=3z<3C4qBZ%qmnCJ{KOUx06iFu-O$J1_NfOfl! zLE7&whG@UL7^Z!c7$YW#Nn+}s#5C=97k4!O*z-+cI2>Ehd`emH*JgkuiN08+a@$Pw zFfmV594`T4kQgF{iP3)&W3=C0OwfLJF-iN~#T4z`bwBrbps=}H?R_9lF-Qy%!^9{tMobWs#1t`2%n-9g+`wi|xa<=MdxPEXjN#-{ z=A1frUU+_FL4Cu*M%Pd5X$}Kol9(c6G+J%T=Vw4yoCWuL5 zideFhesg~R_QF)^DN~PI+qN1MwF-Q!# z{`=@RHMajS{X~f|VuF|?rif``hFCH}zj@2Q+t2^U(eBqBRX6ty(~qUmKNuzYM}t0t z;%a$@>9fR=UZziuW#@D9e~c8{WM>siv7ORxJ7?HVnLq8cofAx-blZ8D=|{%0+gSq73>6&p3px|Pk;&*qL1OM^@he9PDV_V$u|!bF$En6A^G-kk?aQVh@d zVPe65lztO_|55sj z5fj8DF-1%hGsG;h;6FpZIluqh<19ZhPgJxI5QD@JF-$a_U+lHeSB<}tz+a3~P2?yk zrewgQOdn>tCVzU|B7#e{SVQ42^@vHICT56PVo8Gbz1#WG1K9NwWBLR!>Dmv{F1vI4 z5YvZ=QP+OdwR_tX)XmUB_cTF*E#`9TRarIcB&UD2vXn{{J$jzhs(cD=|;3 ze#nG}iJin0agaDntoX7?A0oCAlf(gHjyOsTK5XoohzVjpF-sgFmWJ7%;lCO~Hm=)` zZXdo2;pjqr-B@l{aj&Au^01hgYewGFeLDJI4!s%EEPcd&;s9}wxRp3W93hSpE52y_ zR1<56b;KC4kC-85i8?#JDPo$KA!dm=;xI8!R2<&{ zVvrajhKW&PjF=!Mi78@f;BTzZI|g?!e%$eCN4v`tZg`a%dtTXRU#0Yg;GJLJQ23m) zk`)Zs-|pjFC5s@gyZK46-qkJwKfAPy3@5{HN*#8F}e$7MCKhFC{zBDNAciG6BZQucMD zoGt=iG35yoL&PvKN{kT`#3V6AOcOK2EHOtMCgzE1ki&!+B!-A#Vw4yoCWuL5ikK#5 zh*@HeI7+PG{xHaCbC|ouG%?5cVPc-x%J>={7t|4(h^@pVF-06C4ihWBYU*7>e_`?{ zF-A-flf)D;P0SFp#2j&$m?x^uY-eJS7$Sy=QDTgkASQ_^Vw#vCW{ElCFfmV5Ut|8n zATdM?6Qjf!F+ofcQ^YheL(CF$#9?Bds2*ef#L_f3fV5*agu<5TQ?@%C^u_)kCN<@z zSxUoH!sGnyq+3ScJgZwF^m)_1t;9}ZNhj?RmOZRw?suCocek-0CgzE1z=W3!&_3h$ zLm%a?pTCE=9bf;(6Wtq+%JTFZ9q+Fv(`D{5<;W6q#9?Bds95d*G3eGqNrM&d?i{+! z_!}XX^fTYIoxeG;WiiwM(+?82y7oER4ei{%m+AY6{jPnW!qmH(=w|50|KDy8q0gEA zDvh#zqLpKg6Zd$=J>K><-`_iT@}~XYu7__i?G+`)hzVknm?EZ$8Df^0BMuYuM8*CH z5QA?2B-t;?J$(IR58S|KP5DZy_cZB(L^iy4Zjzwf%_jXYF;7&kpC;Nz{eHatXs-ko zXFqSM|0!Lj$Z_(43sr$LdZpyC1>8f7|GkvlM=W;^@2%tkhJA5F4Uk)X?Hhd&w0pnw zr%n51h*@HeI84kF)n`ol05M1m5yQkNF-A-flf)D;P0SFp#2j&$m?tXsZ-7{uV!x&) z_{UXoO4kjOVEL28lEk}A`d*^de0sjX?Kes;$Rloobcp9?o+{b#o!ssdC1n}<5A5YD zpX(~wZ`w0OOcOK2EHOtMCgzFiQ|u37kQgF{iBV#Vm>?#JDPo$KA!dm=;xN(7r*18j z3bH&QVwe~u#)t`GNsjF?GW|@o2-u4DeU{9 zyw}L>(?WcqzIbBTF6O>-!}o6J?%8s&elvt5A+haAchFC{zBDNAciM_-=Vn1wWG5-WJzT1^ZSqr^HMrj7D&c#t^C_=?+Eeqs%= zj@U$OB_@d}Vw#vCW{ElCFfmV5cX0kB28khJm>4C-hzVknm?EZ$8Df^0BMuYuM0F?g zCkBZjVwe~u#)t`Gl9(c4TZu!&5#lJZ;$G%YtRdDBn~1H%PGT>y zkJwKfAPy3@5{HN*#8G0!eaxR&Lo5w(M;8i=d7Na9HwuqS6mF07-yWyhAr05M1m5yQkN zF-A-flf)D;P0SFp#KAwCd|HX4ZyDZC%zfSPVPc-Bo?!WiL1Ks)CPs-dVuIL9|0(h` zF+XY{=t+d_ol({QwF2N7%}0Zn~s=fc!roI=7__@JW+j<^>>keGQVfO z#Qg6J4?b-$L<|$7#Li!v_`x>}_Wr_PHL-5Q@YdH2*1TqL^i_k2=L{x^DPo$ql{iEk zA&wF&o;UW@#2R89v5DA9>?HOQ`-mx)r|A{rFa4sy3^DhT;R#}Ti1EZMF-IIG=7|B? z_5YW#D-Cl;8m{&o=TtmUmh`TLo;Yv*%AQLS@$=SntzI7vtEspB=!8#UY2!QR2A^B~ z!aMrs9uo+fkaylmVg>Pk;wNR3#Yb6I6Op&G2+D;bS&WobOj#n6>p1dExU6T&%}H_{ zM^M59rFar2Yie$s_!V10xr<5s%8f7*W>!CC1=NHe!SEU6^T`*GM}cC~%<$#J7NGb) z6C!!9g^2%kkRU|v0Fbw}Y=B5vr5=(#36U~iLA(+u@mE14{%VN$xgK&Xg~r2juPJ_=810*M~K73A!3f0C1!|s5c`Rnh$-TA z#6IHH#3b=DVlT0Wm>{ktb`oR6D6yV6hv@pBPCkV=nOIE>5EU{1HPb#L#Mg*J#4IsG zti*)s9n%90PZRrzDPkWnN$e$d5?hH)#1OHXSV7EhW;uz#pixRsbC4iYoO0b-ii zPfQV$#7<%>v5DyVuOqJ^RudI5|5a1oA!3&J5b-`@KQTdUC3@S~H?IGiNp`YtH@}_t ze|NmJ!_L|wdg9pS&pvJ1Kl+Tp+_Oa1H+9U|cH1?;e@j4Mhd<*!xWnInOZNYECv7`i zwlYQI!=d(tFRXn1+l&6+R)8H20XdY!Z-+x5sH6X{{rztr633eP!zn4#hr@T^gd=w4 zC08E7e!A;NM!EG)gI9cR_-)a`mnSt2ApO^Gf9dw1iQex2iocnlF!9T~n0`LfKaBLx z-uBvU2dSUlHgen9JNAG1t=i&roFJY4(tBPCs`FmD;H9bCr+Dc(|%rj!-n-6!reU`;V|sROc(Duzo*lmQ2eKHGU>MTSaz%0I?jvtw#O4aYu0xa za)2R!a!xINM7-x@5^a}1^Ma{onwTOch^@phF+{8;D&olV#*ceGFDUu#sQeel+b%pW z(X%1kv!T{og|X6~*BoDcUidq+RnF1;o@O6P`4dV5=ThZ(B!jNhC54e}uQ2)V2i%5Rul))3`4MDD)dI!Atp ziB?<5-4}Fb$z@GaeuL!IhN=v?taZw7fcyYMRhoPf`OV}hu1$feBIBJPd7gL$$|NsKX~C8$ISld zpAy5DMK=HNW3RmR*}weq@_SBSaO>+A{bbwkjy>t>D~_(O2^?_G=>378Jh|o1^}oFP zh2Q__mp^{@r8hj=5a0IA>-W0r{`7%Axqacg;s;FFc*QjvFM7IZNh`jn{>j;=%ou#| zSId{&{nK+#ee&E>K61+^&U)wEyYjaNvn%erZdTiO|N4=$J~DLFxgUD#2j|~&!|3mi zdHlAm=l(F+wfO1J+!Xw9Npoz=Q5#WT^_^|s*=Bx!nfKmP_jvL4g#3-pJFDZAA1(Xn zO`FwOQBva^AF4 zH%Bi0>Gw80{{5fLd*ZKueWvZ|s*AVX``Wyd7N7m&C0icbbi?aU&-=ud<)>_{|IWUT zefoiUubltrrr8Z&IP8nhZkjjw$fsW2{OBpQZ6CRGUfUUGe*N+#l6PX;A(3#ZzAHYppo=iz7d|=C0CHp1QgrGXCLD zZJhOk6HlJ@-b0={@&{9Yy(o3o?7OagEZg$Zombv<+n1-l+WBDB-OZn?Kl3YrDMu}O z?Sz@rmo2~lnG28l_?cyQWM6sW{eKyG>abgW)^}FR^>ZGNUNxzD>1pv*f4%DC4~*ON z{;Jnbc;$1?Jh!#%hj$I>D?TMSD%pmwB76s5LYTOxqeA0&yc5NCfcDoL2mbW2OK8W( zljac3J=z{S-Oi4grLX_<+r9+?n6ef@q7%wh47dr>bX2)Y14}U3FW$Rc1%Q`e$0K?Y zScaY2mOqrK0PsVQzLIj40#;&j?|>cvehD%MdKP#-Cg~dJf**$jpbO?9Z#(50<>`Sp zpbH)hc^P^T_-)8m=z_n8WS|Q+W1_qny5K6vb&;3<%L=z@zN)1gO!{g4{yf(h)T1JDI~AfvddD0n$!1bPx!iXC?jdI0z{NE&(` z_)F~IdPN6r#LmA1dJ?z_JJva9&jj#I?Bpjymr4Is?64}J=Yf;3&lssHS0P|MMCu}V zJ!CQb2;L5%wM3x>n* zl&LK6i&Jnd@lf<5u;~PhlSybF;LmXaI|t!;;EL(k{~~=1ct7Mi=o#SfyU|BTFZkip zlzQ!Gj1%D9E3jsQyfVN~o`Gt^Pa1f{O8CS$3;}Z@1uS>m0PzA>|s^or}6d7feC6LKp0L5B9kzTN3D;$MFn&1TrOv`T`R% z)C=hazqJb626Vw+K$6h&z~|c0r&34Yc^$@23^)o2AdQN{4l)Jh7yL7%8oJ<`^RYcb z7kn=yA1K%Oap)Q7f(Lgh^#XLkrI0Li!K)yWCI!4`4aPR|N&=r;i!lH_2W(wu`YQ%p z(1Ui9z5|Xxq-=R$_F}a2!Kg2ApcmsFJ~P1gUV=KHJq6!)Df$k&U_T@WUGNb|7J3#q z@IKlCPreLu0{jSeydP~1UGNi-7<9ojBnn-y?{Z_C0(N~ssSxI$1aK50<4q2ZCS75+ zmk@9eBH>x!DIdi4jxvOSe}nXlmML`&+9ajaw#jG{;LVU2#$Fn@nR*tu1{cR=%p`#C zxe@&WJq@h6$@mWekNOPSALAhe{2pZMVd!h%gqx8DV=n-_=vK^Q7?Vlhz-=fW+A{+j zy4~o*z(3xJ{y@FdU3eDcZd`vynh@};0i(x&uil4esn8~Q;L-QP_8_DIu71Gi3E-7q z#CA0i{SJKeL1UW*{^CnU&jYKzjB+4N5crLUaZdsC9Pp2W7>Cf+BiJ4v#dzBbet`Ev z`cWRi8@`J93cBFqkQj8q=cx<60*N9#uo>lt$o?V*yoY)Qc+uk+pYWdq9*{NTEeM?O z6t+XOX8`yJMA|shl6hJlmc#MnC=?Eu^gk#U;?PT$8-*P(yIz^_B1 zC_@f-`o2bw0lyDPAdTQ%`#b6!=z>o}>YxjrUG1nQ=z^;t5}p7abD*Ox!#oxRehRYb z*JUaVtU1Wh`@Rrx)xnPHL7Eis4~IDFYSdR9>Zngc0#h)SfLkD~$CPV~9`2|&j>k3# zybQ7xy5QB2LFg%9XV6g{@Rj#Xh8o$ z7u*Lj2t5cq4I=F(_-jZOy5R31_dypdTj;2pp$CAcK{nx7OYjoN9q=QVlyK;RcSEj2 zdcmefv>|lC#gGo@g6Bb2Ku-W)fYhKJhJn9@NIR$|N7X}gy?~#ko(G<_$Wi?mpE2N* zkbPk*_zFZp7d-Uc7~6j<)0l$(GIYULAlsnlftQ}|eKo=~Jn(!d-g40np^hE;ry=LSGT`hOinJXM@(`Yx~ zF)NWq<}u&}5Iy#QKY{ear{Kq0(67)1zX0iko&ip1#kLGxaNL>bN9cm{AYthLAA9El z-&6hn@nf4iS)vrOYBIAi_iNvc5D{}Ja%--U#S)^MxfPXKH>uFlh2*lNs8mF`Gt7OM z8Fs_m@BE*i@B8c1`JeChZJX)h_dSn&zVG*WpU>s}xt!PMecqqXISYYKC8#)x_U^*{ z2(Rc=LNWMg=w3o7x+(flSK10*(MP+}zVM0;BAjB(EBYEC0X_=4l@JTBXuBTN9bVDN zVfl<`ctvLuqTm%>PKbb4bR(e~d@S^fUfhqDuq~l&`sFhUfi0oX#RKSz`-lU5`zgvI zj-s^(QWm_Tj}Yd-heB@+r`_Nc{f#gVUeTR|q3{XN-B0H;!W0i}KS=K7FleJ8!iPXV zaPZO4`=1qg5cJLAg7Z<(vku}s8aR@?s84g^z@8AgJf5Sm+Kv3fpq0im28a^`okX})CcmAIodEvAD?0Rba34MjI__=ys3`H@ zMYs3pQ}|fu(f7eL;$%SmKLB6Uc!oYch5H)$Qs~nkG9KU+Jw>D;n^*@QOBc@FCD{1of<>=vQCR zhNM-r#!T7}J_PzKp%MBkx{Kfkujqqc)0glOP}>H^n;$&%eS*TqXz1{b+*hjapvMWJ z^otS8xF96ok>5^RZUSfF6%8k>fR9kJ&5ZLv=2mFuINBUO3R+<+V}(3@pt}eiu~!qI z&+SAv_(*8)UGxR|D7v2TBD|t)c2fp?DD?e!bSBSe=#o8*G43fveG|CH;1zv^Fbh5! z8nvJH!KPC58-l8%qQw$PQYJ_C9-jeKYy900~Hf@;qM=<`Qp-j9TSLI|Uditazk_=i`t z__2J354@tc6TIPlpuGqY=%8qY4B8rA(eZ>9@X^pd#~EYr5zrDRXlHnDXb?d?FDM%7 z;1wO>;3J{a9egzO7YDx-`s5kLpXzJqn*^0l6m*`0kAZG*@UhSg2e0TYXC=Njw1$HZ zf%b6lVbG4}xbJAUFlabI^_QY!3H6XGn*Tg~2e0Vugi`Q|HX?Yzhd}!flx`8wHywNw zbe@Bcfo^c{vCs?$ujnlo9C|{lI`|-HnTudD&o4gEFjg1+Xa_};3Cf<#fPR|a!$`j! zdlH&PP<@>Ntx`bvAn18QEOCs29)``^!&nF(0u8;@!#KzDm!gTcc^DZ*NDD1g+QW!q z%zHyWsO-W29HD=q8H8etTSY_sg;(_5Djr5WX``VR37?a{qK^i87~|j-eTOg!V4i|5BE(XbqH76D z;1!K)-nk;YD~wi$36Cgu{D7M-sZhD>}zUec%;cMhJjcbQ7T*d;)ZP zi0F_2ZPnPrIE6ln7H@){@QU6_SO>4@eS{_OLC`)A(x&7S0e!NWP#FNL0ZNb)gSco^f`dKk56w;C|f-W z`gUIr{ABr!Xz1{MG7h7l?Vt3pV_g_@Ea6gN=1S;m{YeY2=rqC#ctyV?EQF7No+OlE zY$)1tfQR7)ujo^RQ>F9U=_>dHcttlluBZ|D?)y6>W){hwi+lc%D|&w3aW;1%^4${2%JG=R_c-Js9BOkco9Lf<1K5ns`hgmv(W8lxDi@QO|$sQD`z+BcH>5uFvCJDM>D zujoobF?dDy6V8=l?tm5* zJdCB}84dM&)ggzzGZ8#da;V>H4mq^io3t(RAZWX{kXK|pL!XYKt*Cnh^scw5JNJbT zbox8!1|JRW^d9}F+7McHGFSxf1AU(m39slcgm8F8%YHx~!7DnH&;nl3QG|N%kbXGL|W8xIbZ>ROA5(hp6T5g)e zQMBqO^doXbUmz@jkA&_c#FD3?@zEZ}Vt7SU2(#cbpeH`3?q}%tFBoHl7}7>S{l8?a zzz0E_%?5wqL!p-l0kpI6HREj_I>2W@r_L97G<4#(vw6Ew2VT*5 zf;W5uboe3}Z;{ZQi|M1=kVE_bApIKw-TpJ>6+{l5@eA0F{xQ(21ZC$Nzj_#L35pMe zeoIjI*HUO4LCrM@&<0B-P6#xOpnPQ+(BD@OhcOcieeri0Cy~%LYdnk*$U~vGt_R2A zeH7hHyD@$upbfV$9*~DX?~J40!DJukK7#U{CO{i(rOwn#(Nlya@QRk(M!Uc(x{VM8 zujp<_@%UeUQ1(HlMnI`tCqsEeX6U1e;;EBYzH7d{5MFrTMUOw||qbRkcpzZxgd$%Q?Q zIm|oJ(9er_+ObH{kwra?DaaLFO_%^53r!}JVk{~8S}{-K9P^H%Q;Ks9J_fp$pvHDA zboDKsMz~4~ebC#}XbrFEgi@YHJ$OZr5d7dXprNHb?e?mo>u&cn`p_n^(7|_j+I{a4 z(B%Ys{?OOUc-rr;C}@v6g-?Lay-WC@vYy6eg8hChhYo~d^o62@%X=E>1@hZzDfoDJ zA85_HJ&lF%AU*E35eu*ALxiPjoeMgH5JG%KXA=V874`Dz2FsnhM;tdgsvgX@noDp{cCv| zwcvxGuMw7ba34YYG-3QO9wMMq2u=sWZ2FXZn*zb2^r-7AK%O;B;lK_4P0c?)P7 zq4Oy(BOO}t8!6Wh+MHmI1N~?Lnae)wt{1WsDHs!0b z!k{k^R6dc=HEg~gN1S!gz(o=#2zrQM$C<^nHzA5RiXJ3n9Pu)eq5Xa!ALRX^X%0Re z`pl0a9}1nTc*=@_rVx}4=}?cK9Ce32;o!rd?-J&a=X=og1l8uT&{0c-kA#-^#nV_! zoB(Khg37ZawB1tr7kL~gS!IOU*S2uj`! zy2rsML(8sk=nS1t2q%6FwA}BW#*6Sl&;&v>yrK(MG5+8eLMyG7_Vj~xUgK%^wJKU^ z9hgZRKj_`-!EJaSXsHdf17kqZ)&!-qqT?LAqPqyHj`7e74*n8!U94b50`%QYjBWD# z9C~as7z>{Py=RN0^@YAmP`=;ypbH4f$8rf;E>7Yo+Q`8xI)k?i>UJu%xFcm%w z`VzrDuAqr~xZjbVg8J{3v@y`*gmmQI`?yyK-i+H2XlFth_%LWsLOJ*d=raT#_|FqO zjq-`2vk&w+f~xNb=n;Z1aWbGU9uWN%4L`{Jk6h9F4}rb#e$dqfm3AGp+hMt{72TA= zoJ*WI=z=uH3H(B6Ji*?l&`#;hq1cDv(4j{?jX2^cdY+*2yaZi)O!#DIhYaC6Lf=z? zzECvI!C!)=o?;A;Pdc>oX}Omb?R7@veV|p(gJYx(g8o5JYrCtU_g@6hk^4cvB!t4x zg6<=zvNE8yON<}*5UAf}Y%>)f`ZPgdS_E{FgO7!Na0Q$vP7Ji~RqzVFKlFRU%NPg0 z1A3lduP?MlKI#O%)q*}sQ1Z^uR|#soMMJ$k7z@l(idH8m-D*L5I`}@&HlAQ7@=$1B zf{N20`jUf>gnmp=`A>x|a`20xy}iI%;`f235n|!fp_B4cZ`LfLp!*5Q$djPO3wjxa zj-d~<13~545&DXQp8!2XQ2HlBcN78xh_7hN!pMo=8rp}T^c)JEtK`Iwfo>^+9Nde8 zRxB!U{Gi_yLm%>42t7l15x!h;FXI?Nt(9azJ-q2d3j+LMS1!e`7CIM3gmyByr63c zD(yPxaR+}2THHs{dP5%|s5q^mLmd22=vxjx3i_LaUjZF-kMuco}a%3*FB+Iw|xWc!gb4q00%XjBmQFO{058#_!wxEjr`#itsLTIpR)p>mkBG78;xnRCd^UrimoQ8`DGn6gP`tZ zMO!||JxiR{&}B^-FYxQ2Rho(Z0nlXxHRe}92Q_E>kTwFEL{N29bmBu^hA;Ak(5fvY zeh_prp&Rlk(9c_W8Ikact|cfP)V{M1VZOCl+y|9>PBC{r$ZO@ z5`HoC&Vi&uUJm-lFxm-z6?Fe|Q1~S1h!K>VN<8RfLdVlWmpFJucR6@PuQ+%`?;I)d z?}pZQ@OJ9pJ3@yzctxWeyrK&nyrSzJyrRhtUeT)0Q%~AN(WV5YTN~(e4qnl>9K51q zUywL&LGON%{sjXStxkvruN3V?@B=Fp9ZQ%6{~7dGg35n6^n`;y32pQeZ47R7fcA6n zL!ciKRQwsxpB=oS+Z?>2#~i$(MP8QpidJ;+iUvD)MF%?g2y}8s>irNr`d3xa?ZrSNs7^S~o1-9CD(Bclqh++8cf>tDh+G_>O)h zs+A8{l2^AOQD=kH*(ZolXqTV>U<^94?n=)8#(YY6$(K6RymDi2z*spP`7$5p~zghb>i zP-LC+cPydebuQmp;vw%`(MNa{e<$H!vzn_L7Qc9lJz_i&mNzZYW_63v%P^sg7R&b6 zYCS1`pi0uX#N%E|TQn>ls`6}HqO;d>`|ocn#R&zIPmwyJ*rX?QS*|cH#Ct-(`mMqi0 z?x&7x`8`q-O-fHDLd%uQXlG+o;OJ#F=>L`_TC8fhWq-@pMI%X^GLTm-{$F~fPYY6~ zwBt&N3aTxOm*Ko$ixPu=Yx;WrgyQTMo}Yf6QY>ATNEw*kR!nwGJIVn=%EsnDp4Usm6v}OqLfX%DMk6$TFl;9?w=dp0&2)` zYa0x4`{BX6X%5yz5=NO$GGQ~+U28v7e&!=~=dpdwLtb5aP3Cyt$C_WGYuANdd%y0Q zG{d4(p=%c$G$Z8y3D#vSy>@o=UfQ2XVRDB zH=hVDy{LMTD+NvlU%kE0f2Cx09LEV|poD4qu$-!E?XPykcw^qs4U+z5_>|gcl zJw(^7kGXtg#UvU0Z@R+vK9;;I8bnvc9 z-_?0&@af>n9b4=v`1R@F7Wd38J^1kH;PH<(hP9~lWzHLM64<}YU z7kuQMrXTO@e=c};w11O>bIt|Vd9L(_^NybjKKT3kn7Vb(2Zy%V`^lJ>&Id|SC@mI`1pmIA6&W|d?xty!&O7C1n-Lae8&9GuLM`>((`E93s-_e znhokYJoIYtj;QIQm(9HD7zg(IBS`f><0Dq}Kh#_GKQv7BKQu`7zq+pa9~!OtU&&Sf zLlad0t8>-=&`8z)&@k2iimLvHW~ly$MyvjZ8mj*xF{=NeL8|{1Rs9bQQT-3~QT-3K z_dhg7^*=OL^*=O1^*=OJ^*=O7^}o8V`XB18`X6fVe`uuYe`uKMe`t{Ee`td0e`u)c ze`tj2e|25;KQv19zoM%Dp&_dO)w$|_sJ;Kyx$1vtr0RcYgzA5FUG+aSRP{eJO7*{z ztNw>(sQy=S)&I~~)&Ec*)&J^T^*=O3^}jk-{SP%%|3iXQ|3ed0|3jly|EqJ=|Ikp? z|Io-k`=4d>z46P8W8pS`+xAbZ%xPi!<&|5b>ZXO+hE)Ik?vf`5*zRcH?LBFFbK70N zrhOjT^~3|7WBUEtwf)n!^S}IXdd7wRw(3uhOr5;1pDnU$iqvr1)Rgy!o}Adp*6f3raW9POXdC8h1Qv_xYWsRqSN}o1``Ch#`dnD#^PsI` zyQ%&&Q@h!G2hZ9)YH|mgZ~uW!`}_8{b*(Y(lf)sxw%FY(LR$4IV|%ke+mMr9ooqdB z88&s+j*hlo8y9}GU}zUx3I7)h+J<$pEnV>OfKTGO*uviVrv0p_r)=*I{_&pi3m>z2 zzI3khZ~nz?8*LMPZ~dx??U#TiHI7|+-1d9pr0%uW^tbJA{^Q|acJ#D8_2cDxKPmjU zZS<^P>J;nT)>dR_;|cX2=xV$5lhPHZe%Q;_a8-f zZNM!*cbWNJFWaZ1j-0MCJ(1mi5tGuG2N{_`*m47T$>5~jC042LfMbx3LtD5lYoKYqd`7_9a zGLftDT4W+u<%eY=$5m*IP!}D?wQ`kwLKgBVS;%K)Azz$@d{q|m9a+eevyh+5LSE>a zF-YCa^(vEv+%F4xy)5J{kVlOzZ2y>Tk`w^wTh8AqY~0m_edvzsb5e>J4H$ga&Xdm; zF``2LJRec7sNq-W&-l?H#SFhDe_mfTrkF9S;-BXcvp8oEU(2t|557qb+<>qZ#L& zjXFjxCs{qDhVe+3Nc-5wo4~vAh7qC$CP#?<*Y!^%mv5=?<1K7LTz}8ve682t)3N`6 zXMG}u41RJ*&!>HQ_Z&26@KB##eSL-u8{{)!kWbUL9ekc1+^28V;zfL~SWK$5-)^!Eykw%wU|`=G_HlKr7QT*aO~*5bM@%`BZ4A&UM-y; ziTn5;X@L;NiJuxPnH-Ne%_BRgf1r(5*Tx4^#v|6Au{jogI)2}X&0Me}8W|30eCLNrER!+%fv*XiYw z!n&4IP5AGv(p-yanhKPd@!UhvzxlX^_vKZ&O20h9dwX5fJ*x7{1n-glzoWn569V!F z1cj(qd9DF}yQ`)BkhqWksTQckxXB9t8*{C#8dn?x`wkh@Hyq6G6V6vZ+?a1~l>g|D zAA0jTq@f(*yisSb#fiuB8728xoC?>DrcIkZ^w2}yx^-*WvLy`1!l>Xut>sZgN;-{_LO z@4D-*YlRptc;Xi>T$p^woO1cCUAs0#BQIF6V7YSTTDNX3N=mutLj;O$)v8ssYSl`Y zE}cJrejgv7^5x4nXwU#v(Vt8>9a?|24YjtWi}yeyZ@~UdFpUjCZ;jQC*D1lRKO{ zeUym%_wNr5R(@$0N71514;?ym_Uzd*WdwR$#JwSx0Hxu>hyVQZ&nHiw)OC!HkN@C< z55SXR#foLWRL}{mi;j*?OH0#P?b@|#(xgfL{{E8BKZ`BEW0x*n0C2%@ct8>e1(5H( z_g*?3c&t&QMu!d^hzT$Pq{QJDw4^JMlr3A9$VG}2x$nOF3KS^d>FEjlBGj$)m%N9E z$36Gl!$ffZ{r5L)*zmE(9%BXplgShLZMWS3&ZC>ISMe)!=kRjLFA23D?I z89b+*L2~dMCDBS$1$!sdkXvQop;_@ zy?XWWJ#*!p5gQjzM8eg1^X750>svc3Mlk%;sZ-q4S;hH# zeQ)&92l2!Yt^a+=7a4OD^>)h(UYeD z2AE6)8t|DzsTA!@XHmpI-r%&1TL&2)?soWBwFA$>z}?ufV}ZNW)KralW(ExJ-Mcr& zylW)qUORmF@UdgZFak9c{NoI!V0d`=qD6~9V_m6z`}R$lG6kzoRK*&^8}P{|pBz1^ z9y;XMxpOC0H%8;Xs=q{;_%m05Vo(tbXF7(bE||6Y8G&d_WZ216jXREL0*NH)+O?~s z1y^xvh}ld`7y*CMn!!9f{M~oojsJuhgn0p=rmU(}tKtmdSwPHe3~#J-Fc}4C>PH@V zgt>#9QJC3`p{x`<}55HJPFTecq z{Q2|u?Adeak}|^0M^aK!OiT>+EjOvNvCR`S7=Gl)5pG@?Lb>?GD$7Nx>?GmozGu&# z=x=`Xz&OXngp)*9lQ{@52NHdKeRa0~w()>s;zH@(y*u~}FamcR+Ft}9i}Jv-xHW)5 z%;Qd-Isv3$I0s-(60CG0`1$z(l0+tzPMafMEPt??10$ai!UVyH0>e2d9jhC^H~0)V z^GmtFIG9gy_)-9Hu$q`8VKQRVIeKzvz?ZC;ETmpJ(oK@&u3ql6?sof+jsZ*~Zl5Qf zcmhcO=%bIeY}sOVGJ|-)HLi(w-+lL)XP)711?7qtFP@Q+fm|br)IIyZ+{ietvmZZq zF>xSt?AUS4m@#b<-x!%46m7 zlmv$JFooNho)v2xBqwcXXeeoA4e>fb68{Oq00#~&OwKq`c+kT?FJ?A_goi%hUGSN5 zf$@?hOWuC_?bz*1-%JF=f7z6Y& zHz4bSzx?t`a&odpKVeRsIKh8+!(Wk*kbprh4U*Ge@bk$h)e8lG&+*}hAEG=D4(-~t z1H^Qp|B3P3qelON5&_2Xt^nhh z0U$phPYwV+8n$oW9$?2^gLOgXy0fycn;zZQGeEBjU^Iz;!kPYu^@SwD|#)(hA@ZdmXo*K}QI%1+TNYD_Rr#KfnT#x?lwC=Y3pBe+)cij6d zdM;eJ5LDc;V+XdJZh;&z_^V%f=_ThRJZpnL&hp$zfERYBpek-3W}^Qh4p4EB4J#UF z7r%fZMlaw7LQ0!p&FaRn@U$dWE?A9E0|S_Zz#|g@lL8Vj6N#A3JQh(37CXOqGq{8m z4aSnQB~RzF#OlV04OWvgAj~+S<&l#X27G3{k|zlCCx5`1135)g3zZd`)~#E)^>oE^#JvCh`_6Va<{1W9 zj`DF4nXNVA24^*sr}+Qwy$@oGKU^@JML=L#FdQ$0Zh=gBj93sAfF%h?NDgcZ1iArg zoHHD3uzdE}XPHl*fByNQLx(=~)Kg5a6oJ_fl4Bw3&6(y$7)x2eHTqy+v&I2RV{)_H z$#jo3jsiTa0q^)#@B%RhF?irH(UD`86Nls+^b!6O<{FH7vBtr3U>sGoHEt=_b=|q@ zjxSB*ZU=WeSjGVNI2axq8!OMb`c}$5!~Vwp{rg+u^P&p3zeSk4Q;^}yFTX@dy!RM& z7X5Xe{|Py3696NiiYEkcW10g_F_N>XJn+a=3k(9tz$_0V0Bl4=#N^47X(C>3VzGcX z2zX!_H*OqAK4{ROUcGwp*n)cmyPZvdEKp($>qe8cU^z8g$oOr@AJiokKrOCsIs&&3 z&uhFT3QFV70>-HhI*3o6iV%mopeGXn_CGTVxGn3Us6jrIi2i2xQ8w$Yb#}*>rf|1| zyB%Z z7u?2##%2~@3N^yI)-7WOH#4t&M|2Z73|i9iYy$c0v(J9|>8J0$`;Ik^ufF<<)2UOZ zzWw&wuf6sf`{d!-migOnztO*OadDeAZCbHn1#w1>90{~y&+Br{U@qk{r{le0(m_wA zV%T{-Mn;%yB*x^ zkfSkxsRlx>S+hpp&N*UmhmssHF{i>9n>KA4hMZZL3m$uK^XARu&zn0`Do6FAxPM!G z-ths7>({FffCJ;8U%k5Zn3%9j(KervPj7Cw@EUB93lC1>Em^yE?H_;q!E+EW{{8pg zfAh^ZGiT2H{PWLwH)`9qZRQ>Iw4voVbLI@F&K}gVca_zy74kRp7~A3`2?-9t1q5QV zEbis$#agEze7Uma#P6-F@qj>Zp04Nc$mc;_1no=RR*HuXCUmv!@Ikfh5E#c{Ubs+U zy{*Vn->ll<#>sg?;oS;pB6ez(ytU+wE6a6XyUTUAPfo|c8*jY9&|SH5B~6!$LtHUt zv?LQAqNh)vE{0Yv@{}an2hPV&YSyTk(|Y|o&@RBpy@I$oSeUVQ@<%&0=w@k^T=MW z28sFVCKhYF|DH$pg^u1aZQX|Cv&RI+`Nfz=87auD13VxMjMD{RFHaCy)btJj4lD!a zJVY>M5~W%Tl-ZxLqylmX9vb+lr~BMWUe&G@GU@GoJ4Vu!P1gkKi>IAxCqpa&ju z2rvSG9K5w8jOHXCc?!8aAA!DO;@g9YdemONA`3Wx6`P##|T_*RNY_% z?e(gWSh!wNp*jbQpd=%3yAiO$sJzgqv7!Cg9lK5*l4RtGTbr^#ExRs%>VtYr(`XAy z1I5flpe1e=#~+iHUwGOOo+WjW6PbKO0t47G-@z~e zA>^rtoQX^kv>0*@ir`UH^5K`V$VAi@9V9J03XqT_^5{xrnYoBe9CAiZi5$eCl_(Ll z;Uym!H!qFgZil>W2bR4UZ0y|2KE~>p+{FxRT;Ey(!_CV#Z}AnFh1ur;5H>oZ62=(d za5Ig68i6I+s)1FpW--{nL%gI=|gjH-!7)dVA8uMxP*|gNCIC1;beem76^>GLqeutPZe6hrK`o<2bTt zE;**GUT4%?Zv_16RU=8^cHl0fO040(#;CkX{rRnS{Q0l83)iWuRW=)bzZx~at}|fI zxy$Ft2ah_Q6V$-Tb4?uw&#pqT#<90SFrbXSW~U<2s1#|zC7_HchJ{P|4hf9pgOLD+ zv+VNer=Kzr@NyYf@r^T=Q4w4#%wkd;+i4gB!dsSQL04>eu97Fe@JPtVe2|b+#w2m% zssJwol1ro-HEI-cDS|jC#wiD2E`^$TBuq?X2!rPbaF(Y4Bs^9Slgzm!Wl2_CLP#{G z40g_I&^80OndfOs%9VWFyt^H8ItH+d7r(wFma*a9H12Li=5WwUmm~bJy&_MpkBZN<}SF0Z<$AO{LJ7XRxTjP z0s85R0C#FSE>M6?9qc6G>txvB>FMdfxcui1nwkSQigKO=%vYv$;9kRjy;1oOJ9Mu% zs%$Z;Y%~0KnEtjImA4p`HyZwHjmj&H$}5cfml$pFMjv3~7l& zK1?5SiTMI}mm<)a1zD1FD*B@*65^mI$vH?XlM(#l#f!-eMywQm&H11nr<5ykFn$=u z8o+5Z7d&&cl*O+clzWZ+f9>yX}O(w5SIA(*tzxerN3mrHxgoj<2rEG^Csv!S^$&-6KEFpOXEZZqQN?F3?ADI zxC12l<)FR@`31lMH~dR{C5C_10gMAXSmU~D&RxC`&;uvQJiBjXt>L%aP?q*)qsn%} zA7I~O`0q6W_N%`txKs8S{_#eYoko?d>d$|Z9m!W16%~v(c}DH8JAdvR?ha8y>%*z= zD1)k);tT*l4;aVmt49dSE6n(u@?~KD3l(3^luN)VIe?8EBI(z!AE*e=#LWgpdK|wB zaX>=w5IO5C%y;}sd@Otb79Q{|K5&iqO$ zosTG~>x&NLKw7gh#1U1o-X$Rt^5Kx8DUn{ri$W)|fm3f>Br7@arBiDn$ibK=Lphw= z+%0#vNmgS3l*XcCP;rA~im|M@GbYUs?AOMigR;rZoRD#AiNMXvFgC}@ikEGQFTVKV z&Dvj7oH@?l&!2}B>{zVXJ8r)NY{8wvEAypFmSPqIAvuZ`E()eeuN5g&gijertMY|O zvBq_eT)uLpN|${`^|^-MO2h9r!|!(m%YN&PO2GIIJ7^y^0@J*L(hAf_FH|$FaGmrb zwbKgKPAga|)uws~o{QTr?7{+|rLrFQc>4p=T$KXvMwZ5xjyY{@vV{lvlDr;_)bPE9&{ zB>CL2)bq#F&mTW>;l#0vr#2r;tllNj@WU}~hjE-Ll@}O6u_rH`K6UaG4+vTZvp$*! zZ|QvwaR>1dC|W5{vcF}IdBA&}T*cwW7I#Jw4-`~Toc#Q+^Z#I*@Ej^%6ldw*8Bud5!T*`nSmob3 zgVLCnndZ#x%)VmYH{ss@2ixR^j!7yGAh5W`f*=?UNCJZ#+;M&T_7&eUMl5k?4LRWT zs)TdHez0;Q4iLlddj;T?*BAi+cwCV>sflOPog-%|IePkdzH0l7%G>Q8@-;@KWk$_8 zV;8D-V_CD)I$Tqym{~U_7v45v$rWRp4`g8^P!}+Py*I!G7(!RdhqH(YGN^YvuN}mJ zm1yiR#2N?fX%i+g@R_udkHpbDOfGml?UFDTX+=*-o)zyRfAOnG%fs_PN>=!w@P_H` zkiCd`r5iBLI|ZU}R(S%*-21NMWSW-D842bw;O1T5BR9HzSmXVnVt8cB4mROq$1loByZU1S1f; zmx07iS__=!`gHvG@p@#sW*E0P5X=Sf${R^=xnznJH^(@kzJMNkhB0yRsDRSu1p)V;eb83uho_kT-j_9tin#h14fm7OOn*< zQ5P>?I(jA}{q(W4(??TI9XWh5?ZENmea8;%K6+sLk%UdDd*agf$!kH?pTH%)L#=h< zQSn=A-2XH4!lt7Mn`1ZQ>Olt%t&fEVmQfb-j9u<#CFx(}fI0E~E31Fd#vDyu%yIC@ z5eHb{0LB>)?5{RQz{cPbab%CTzQhg_oEXUY)j~?N=aio}hO`i`z6kj>yEWiNPR=^A zYex2dlPX8~6CXXf#ZXW3XV(f3TzZ2dLTM|}$E<^HA4_D(lV5Z7NvP$L6${FgWzJBy zn?&GO-tRNV$%?0;B!BKi%NWRNY`En#)D3Mb+1$l|q-)Gr>dez?pbZaS`oOs2sSwMG z8)vx12OnFHT1 zHYXBnCt8?=&Q`5j;gP@!#TrM>!OEa>(;-=#wp(pPsq~#udAVAb3}E?^w|LTwDrsxd z)V7cpX00*&58PopbZ1C%*^uPBLQ=}u(n>Wpsxa|9Qu^Kd=$rXjX59C5247-k>N$oVADCcW+X{Y^C!L; zfprmVJJh_~gQAZX!szxf=RobqQzBb1T+6v?p0Lb$!qb>cBE%s+TZJuGvpS_0B!6{d z{{Jyx9uIEb_5G5E?E?a{OO5{GE7N8m&6H;?gO75^t~NHdvChu_S!P+y{Bn0zUGGB9 ze}~k?0b*>HBTv?Mq!Dh)aYB6oZ2%1;oFzP*58M|VR3C`r6vPJMv0A|{xx~l7Gi^iL zz`aI|Id+?Qwb~+x6{k&i8=Jz zw}&PzJ`nX&;+sDte7()Sjqt*Svdy;TuW>Yg^)w^kpaaGOV?rZ$vl7i$$58{FMHy$F z`Caft-W1TPvcFUoF`18e%HS6_3rm(d0*o18Ss*Z95}pWT0ysNga+UySsE0Dn7%p;W z3`d?LJ3JTpV}U!XYLTF@v?2MMFX{FH%(dJM_`LI_<419pq%Oa zsAFn|$xia;#&j_rsDd2sI5)Z-c+G*{;US$))IjQj!8o+MF{e8>*9@LdT_W&BJ}j`Z zN#jP>{U6M~a*?)xGu~rd-+lV@VRGb@gExKHjKSNQ80UP=gDpVx3&4&U%)3|4EqwUw zQ6umdqtds^2>0J$-voZpD=58i?IUF#%s71R&sXoA(^@3Q&K$q1>CV!&j1mpg3)W6G z0uS4r>WhQI5}37lG(ZPYl3!;YtBhNlCbfVtuWHhjR0<~v30ZLAyElv?bLoOnq$LLn z*0KGG*_>G(&l1thsTeB6$CAV|V3q@D0x}j1m;AY8!EljhAH%i#B}e(2l@tS*axM0= zV7TaGu90pZa|=jhs^grGR9|i-oe%C5k@F6M8LlOBE?Fi5ozTM2P?8VJ7B0qvTyh>K zZh79e3D6-vy&P>vVbRU?PFG8(|K%ySp~i4t>mxqa{>|OjMql;KtNZS~5APGs2MqGt zO5R52BE(p&R<#N!XT2Bk_T>>oe#%GZD}r@zfLP^ zh}^6U3Yhh@#Ai~r4~HzrLssL&EzjF_oABxcdWtWX(m@(Uv%_FIn#b66^4OfZP#(~@ zHF)LIr-IrtowxP<_lzIv%UuAtVTWU9V%q@JNaR4s%a0i0c*S{(lP%4-AlQNL+|CW3 z+GBsIhfOK=<;W@rJgTM_t#heBo|uS<^)8omS)9UipSm6o=CR@CZ%|u-8}dlS zrzbRoW|QF)*4ZB+&SSqEU0deM=#Z6h3Lic9cWBgIS{9G4J}vn>=~!3hR_t zt|p()NWXmQ#MN_Wu3o%w_41{wS1(^hY(3T|@4WZngnB)W26jxZ*e11n^ORD-$wswp z)qC#2)yC_SqMKbuhn{Ah`&#gs>X@?z6L{QXO5*ViFA6K0L?fX&4*w-Y(vpe1uCA}r z2(%LI!+Zx4;+ElCE0#DqvM^i~Wy}~$>&e`~uel|`aFMenYsp8)hsl)Be*Ts=!GWps zjSz=wH6oV~)v}uXtO>c}V0`!fnpj&^a@rc}jtl7X`we&BSfQSDc| zGn_4je9wxHgs0$0xwWCf@Qx$Xq$5&K9ocvEK>U#dJJJ&3Quo9r@7{QL*M{U>>kq5H zl?S#ZpH^EIS0312rF}w3|0A`#qy~0M^?fAe?uQQ?AkG0h+*e$-#opBm^{=#eflVpj@JnT*|`yAif22 z_|_IzIV^I(AE8A(FkH%Y#&ENSnkP?*pQHROnX^@r~7GT;nfSYo3HFHZ6fHUDy#t%Jjc4Z{P#qK15`$lTYti%!Ylga|x_xs+@tL6MZ0@nEMDsvZhCPI$8%iT@$GIe6XRu8JqzqSF=`A3(6lx~ z(jE>^Yd#?5!6#D#+NFKFX9qEV+8bN5%Yhby(jMrOQoCD9z+;CicQ|AOtdE=@_uI1H zv~G9aac8DHzHYg}Eg&hN2aK}=s&%W@Jhro}X~A&*)wM<#3x)$wMCLJsLfPkRZUJI~ zDuoIbvh0M>a*JEQoL2LEgi{cVbq6hU!HB&f<>n~=V@Lm7UxpXU)>2vX1YyJegL^cV9i@|>Pp+$q2;Iq;8ZZbaSx4SCYe+)&J1 z934A$1lh1rk;s7u7`vA>O>RSOcEFtX7Qg)ROG~RRIlzD6nP>Rf7c|wk2NPJ(EK>K# zZH+QY)Ia{*4E52-wA07lTN*!a=fTB^2bZNBTAh)+?nKJ^6DjMCA6}PnXzkI1zo#BJ za`7ZFzuB>_L0D3|7m}L}Jp4f4!?k-Hs^0maQFZ;#N!uv;nrda3O)}+qLk+OyKvlDz z03AYh1~St4Rshum%-O_Zj>BhKdEmn2HVe%>E0W|-J1}C+@=SS}juHVPvvq25r0ayB zs8YI6Atnngbit6P#LsE|W~(@>{H3iVe{&q3Q$%RS@T_XYKL6m2HPC9f+4NW$Csee=USjrn3E@ z9kd*tO6gP0U=>JYsTYv0FIgA>ocqh%cg{R66mu#xkvPo4dJM>rVB8Ahmj4ay!2h_U zU-%{!U%Aw<>4LFr*){iR9`bx?)~tiPJ<3NBZ_2SjO#y1w_y9D%o<|)4F<=}E961Nj z&F#beNF3bb*y?x^nAFS-zAl~bf#Xa0LH&yde_pXv8w-onK2o+>MwyTkQ&y-K?Xx;I zB*(w8c=hbK^~(~s?#?)P^8D$~*8kCFcw*P_NgZEGY(4xyt6_;HY)KD~jOTR#9tTiK z>!x{bWC02@XjtrUGw2bGJ#0K=@g#0m3^<~`ywGG8nt7lD4-8F2gD{=3gvbB*Ge>|Y z4lQQZhoW^H;12M?>IS$(NPMv>1(cjI+!@fMnp&Qt{3Wf~8t3sAh0V=nZY!<1R88uI z&RPzSkR0@5GSdMQs1(Hdg4UBF_;Q6#2*YebQ!uUQI8-0qbpCt-Lh|7kcau(w?I&^` ztenS#8n~H_6Sq8X+X~x{fBQnGu;;;ynJ#$Vu+W`&;~2I$^6r3EgM~cGVpMbI-h5+# zYJ%9l_xiFQo&)&ux!Z@mC6dnx^^}nQ0{&9J#ys(Xt^Kv$tpY!KA`Ina_Gh&w5z6c6CRh800qBt00=PbhcpiodQjvN z2cHQKSvW>8s#&wfh6fGUsK!)9M}zSCU&c!&G=d}~8khsr&@#LUg`8{=a@CxFu6fI& z0i{d1d6oa)oDVB3w5?PjJ8fcdCGj|;)0!=LWo_2`~hF`pL$*7rR-&@GPdx+(=O3!L(w>@y=-j+uzG(RpM zyvnql`N-AVKX2BTQcoX!e&*`_@9cm2gMIzp-rIB1-mo|J)a`lTp7zS4&Oa$;YajY( z-Gl)d1RQvP(phDP0eHcG{A1LJ9O!6(9rWf26lTnrG3HEwRt+XBj53=8{xlaDg-SdK zhz>dq3?3VPo#o~@nx}N(Eg)vr!NODD9OVz(Q8jEQDJc7Ca~+>XlRm-$<+>ffd0If? zm>(;^YUX0(mKhlXUi7CgEaQPw#;pk5{0(gfS?1uMUa?nS1Ey;Rmy3MW-!ho<{FJ9Q zvnJwB;f08sZ){La>`9DIpbR^_M~@!xfD$l{oL_h(yx_yiCR>9z#dFR+Lq1bOvumeH z^I^M(~SYfdp75CFr?y0JeTFadj+ zs(9$r?hfKeDPR#uNTDDh^BPS7MMC>Cx6va*ZLF%P(#vEC@{#%6cTt2L?7qQePU4 zd?Zhq(HK!usFVwsSjr_WLK5;^LmXCKB+pE}>t;3Ji6do^T-QsAGmi~7e?!|uo{ae4 ze`d7&Oa3oEo@43j+@10XT)b^s8QC-T&LwO=c?E{939ORU0=1E!7R?K2j z9m=I37ZsPuOCr;5d8k9~`Yxw^eRITTz~gqNo3MN|RAz@^i?WN(&BIH$7qmWrHg9?J zKV+}-KK&Q=9d!hg`Cbb16m~ePP8EGC3Q!~GI|G=SFc^oAw0?wLD;P^UKL1=80OudE z(d=g~pEqjkF{-dHWwQ~ORJ=iQ*=DJJp{c<5yj|O}>X(JPVs{=-n!R~d_=g)OEZqC* zxAEf_>>3-h4@ZviOon(Kc)$l+fD~piiC?~4c_|l_>ei{tq8rVHy^TuF?PhL6*F09M zTt^2lB5F*UGzq7Q zjzj#v%=1R*>CTf*XFmX_NWaii8Y;8HU<&e2c+KM~uXvWiM~xcAt3xc0%7Z&DUQ!b-GrU!{1*KH!E(7QTMEe1r|Nw&G~Su+XR&u4>Se8 zB;+vx4H25#El0eiEOWW8d9;;o(z@lS+)UHbAQYNaxp+VFuq;tPbaq{?Ss&(+8>E9- zA2%=k;@l1lc;pWp^^Ed~j6p8>GKnY$1)8&fmfN!Tb z*Cneu{wL&A5EKG@@aux%Y}CgN6f8mxBFVubFVimg$xA>YCk`>kjvdQfEHKW$ZzyC- zEL`t^Z<~V!Yaix2CsiIzuHQ2yq<`vz;rpI^hYuC589rmp^IxtRHFwRJdFx*Ne)ZUI zHca?#=i9&TjQV*ye{U_>hWR}+F7C&~okeVklYZTZucl*%j-mtQvMYwUhQ|TiK3L;e z=J=wKV~>Hu9N6T-MsIa$+2Bbk4 zInq8_XLEelysV|>RDbH8i?T@KT2FZf(RDYsCl4vE(_W`OxXm*y*Q^8nt{bYuU$)P6 z*6}9DUmkmNw4kZs)cnsJF^_R{U^?>8>({MY$1ay#V>qkfX3*Bf3DdiGZ*t}(qnoVn zs2#8aAOp@%Km9bDPXrhNG30Uxpea{I+qU35kwuO-7)0fB1kAbt*5 z_<^!b4_AC7xqk0M%?BT9_d?R6FCXka{y_hC6Cys^_uPzqFMqXX{5QMb_;FX%&pY1# zZTtJnx4pY;>xV11EI+*a$HeW$n97z&D0~qHQDCUWSrwpn|S*)UpolpLjHj#39FyXm?OMp3EapH@d-%R7XmQ#wT z^p_xp+UQSwDJ~af{iU7^33K~UBBxokgX?ZriVw<1qQ0Hd-etJlD1f{?@aK3{-ZF}}Y14@!K$U?y7) z@2_~j$myWQA&o!({BynMbLN&~MuLpPTJ)OEfecwaFv3u$?Ug zmb6)&G9%z-aYk%siDg^3IYW$R95rkhmi@pt%~+z201iL|hJ#vs5sp3Zpb!#~!w3(W z;W=UZ3LV5A3@s-zhzGXwJwy6bS~d3Q-qLO2agRSgJ8t3LZQt(M_C;LWw6&W*UL6;` zVe?m86Le$ijy?t!ti}D?9&ulet6h zMX_YaLOeOJUxi!sW*QGv6TsnMEw5j{e&X82$`#;}OTvRx#Np8i*u+!Hsg`4i;+@8Z z=Tq?JT|;mEw(ic3d&-3FZ9jI`q$OLv-4nMWc{d-bU7Nml>A_uJY}qpGi_P`J<12OF zJM_!VDQAz;_3=A*GfkMw&5B0>%B4^YU`pp%0N_RQtm5ZL&cp;7^X@9^mGB%ScWx8O zlcy3Qv&6=nBEB8e(Cw3>awW2hva-^_EqAx`-#G?wgLAjC`O|`vSXTH?Koab8_5fI} zx;|y$35O)LV51j?5Oxu8#K+|@ELlJ0D?0ouE}0!%{IZP=BR|uE*z&|xeC8m`-`Q3- zx-1V51GMq0eZ1zq!}sxGInDzqixA`yNZE*fF7U*L?v`?5)!)aqx`IKP1LoyrQi46UR?Xn>vkY z!ns_t4i+952Ru<*z9i4&f*;!w$E;`edHnyZ;quH#5%8|_Wau`i-vBju901P)0|IHQ z?3YFRyUssHZQ?H1-JUmk3@lr=jC&S<%@i$jC*-AF>@nW6%MMm&1>?8^*jkXO0z5MC z;6Oqqg&W;Ie`o$wmf`>qP>5eph;KE+iw+uCBo5{%AjxA9|HhPt;#B1Pl7w{%7NAMO z!Dk+EJ(-c5raN`%EHCUFK6^CnT*kS}fBxU4qiIK2RTXro@7;_SqGI<2%zXI`(!m*t7eu+$R8#PXyI%S5Mtd?2% zlHt~^Tge1(@PDG6MM-{L-xo9;ULL+8(*&)yPjU7e4)tZecCEQ5+1 zPz?RSPbM0(ZrRKyQypj)z?rd1hOYCWW!TU{v*6W19}>Eb&s8}xEtgAfxx0P-onrtO z2S~{M%PUuA?9G%1Ik~}kk%UD_-p$7n=1V60k4qR{sAL-nw+!1>Gfj(-_w4YJQ6ldM zW1{n-E^lIDNMo>pRP0)T;VUS5Lj{VlO)k^i%ou(%-Ct*py)AbNm?PUfaESm}Sq&cC zEZEz`1f@A7t!@yoi?{Xp9uX)im&k{u(wAR;na|_!-KsTf*09DwN8tJ(A05Y%PcGy@ zDATJPz&OYC=SdDs5VVY7a#n33a(NQLKhM4$OmPme-g8kGlDIC*ou|8f{=qQ-gaVa2 zcI=REbmPQkGrt8ky}Z0wg#>T;Cul@=eJ~w>58wuOvH3$)mOL$|ye7a)m;7r^OXl0Q zZKHHcWKPW(elv|9qpyJpjlUN_#t*=JhmDQpiI4+1KxF1YD%zRvmheIleT4hk90xxz zo6P0QRQ&%<0NAdpEPhUDh@n)xdJ zRfvO8K{HmXT21zflf)dy&F7;1U9`EoJ^zvR{?_Sp)-c#y^+rv z^X&hRwA=M#QKt6-H3ep9dC(Zc7_Ty~u>;N+pCVT%WIu=_43}`5Dr{z)?4i|bd2~rjV7*`Tt&a(`S zL-nt-+??v^j_;z6+#d!L}sy!TLX~czF=z~|G&vO znppxwGZ8FUuz+{)xuJMtmyIjD6^?sW?_oB_H}e3LGlt`q!Dz>Gj%OfG+TmYvuTfL! zQ1FMvJFIK47a(#CK19Ip4NwD;mWq%N_+nXs*Y=4S$O7Oo(u44vxo^;k=7iCw9K|lb}+!HC9RyA z!kAv+MUFBs79M{u%bK7)#&)fmwMc7;g9&PTz=l;X{+6nNRWr?pa&Lqjeds106Z-V- zgKwPa2J<+tba0&y?MBgjSDdFmc;!*~d+UB9+S8q z`}cQ&x|1hQw!o>J^0jB)C2^53cbC{|h(69G@^p+NW&5`6&Up2o?q6z({tO=MMlgrv zT0oCy4Zug_{K}yR7^m>;zQAZ_V>YfQ0eq25WU)d4Pe7h!K3vlxH^;f5JSyRQV-mp{ z$FD-Ycp^Y6QNvP~Jk*VHX&D?%3>bKtQ4g3KTHhO8FL(YoZp{1_+ZHnqfMtK6d>GfkCiAzpO+^X4Kn4;+y#ULa|3es7LGy~PLvWB@k~Fo&)I z@$f%jxN13hc)h`rxcV|I#4dVdid-iNKTb`u91r8RsQaL^0vR+?U}pw1R_97ToY{Y(;(@* zOv&P-<lmAiKMH;f;?TL|pP zfwc_ivBetX!N$HOR&O0T^FR~$jK6~TfH_GrjY9@SZ6)+RtE~jn}ScCNd%sQwz_e3ltS$ov#~kTB19-Y{P6JbyuIIL;QfPn+G`iu*bf>?P}@E88D;F! zl6*O)B=1kDaP8n6(p;CTv^wA(C^a)i>>s^Gi&L1|wGyiacrCPf{;3gpo|RMDn@gYDy^x ziAGkW6^37X23L_F|I7ZxtmCy&Dz58=jfsR)E^%nNX8y9i=s;zqg1>#%k3Uq(w7#Mw zm-r)Qi zr8SxT;+}+GWRt(BPR(lNt>Pe9zA-L+g7?*Ml9o5?&92yXWix~j7s(jIc_d^wBi?S z(TxcF!N{M~m#b8P8qpwgVlxlyA&FKyd3aDLL%?YjoPwC%~cf!}@q zy?>#?g`2&>s`{MZeI47i+cfc!TT7Nq?O*)P8eT2mF&2OI?(TbiedCsGPCL!#R=0fi zP>D_X3Keel(d@6ko;YbzMVoE!51#!83^?9pbkgSJ&AWOItKa?Buos$ipSh>>r{~HJ zJJ}#TweX3WMIL?N(|K#>ZSdZ9NB=!6;tx+*u%JfC+isiq=9|Nh8dawU5B_27&;!l) zZocx~>BC(sLq(4d3!w z;(}Xt4?Vu~+d18S*gW&qhkYJy-MY_#KPJTwSsNI>`};{xP9OOS-_02QL#OAqjW2pf z`euA6O`A1)`@Q#?zPGlD*QKgy5o=!eId^&ez&d3*FB(+7z}S4v+U+{{MECCHzkY0P zuP1um^ZFfui5dHsH@cAg*^%MD9=))!9j@gvlbZMWKlZ)@D#|2Xn~Wks1qDIGfFuDg6a(llu)lM8Mo|e+%$}w^daf=tvU$l=EfVGvS(bSBCVM>O^ z##!P*0ipV?fpCieM$=OcPc&%%^o?x&#_UGv_TEZeuktc^Cg~Fv7J^yTC(fT|Q3X{V znI6DBD?3}#jjiWtB3a%H7Jh9pHL|MspqBxK`(hFH*3yiT1Uf?Jm3H<$p*)L|ViAYJ zl;}Amo(Po^?#Ql92XOD*Yj>uoFpD?~Uu;!i=#UV7udMSNpGS9QoJNd2TyZM3@cEkS zLWc=oh)S8E@HEbgX(r?ODQ&k#>8Q06lQVnB$T6N+tdw@h(nzEGz5TVed439eOxx23 z`W|tplVx}KnF$9zd-lOV+zdC{C~Gp@6c^Q9C%6miN=D(1f#TgDPayAcnUZdZmOiT$ zxWAS-d`kAK7n2OxNp(r`+WVJ#z7%Yiw!X_7;~I3mc5%ZGLPKrii9$OhN6%Fg^D%C}fPf+R0$*zw3k57~_}rVb(cZ<5{e zDK`)*H@kZ}U|j;KHstMC`FFzXO(6{JX?nHo1|Ib@ z1GSO~^>OEiNzcgczFrj18)<3;F33-}m*!9l`w-`xm$8cHU&#iB?VH+HKvcOCPfN5M^I#!Fd7krH;kc4KXJ zw!!l8O{CY7CX#X4YcyhnZeG8RgZh|wE~3YgPd(-sFRnz8$t_Y*Bk>(^DJnopj z%Y>-D+x!K38hM{Q>7z$GEFxx`;^a>&E6+PVLXM-#MW3pI>9K(tY$7rArU!jGrXShSBkI4{HY-alezB3lPgrK#cT2$KDN;SAcw9N$(&=LJwfBCn zyPnLYS-RD-du-(7R5mtF6cv(@i9U4geX_YVThzrafzvxwuUoGg??evZWRJ;}wYmJ( zkI*$_8#8dZ6XLqV$fHX!o$IC4gWlesvxPFMuCIp+DBoQ|%P3}_dP6IjSp;Y$%Y?~pK-KV?q%=@Z&WBM6twQ1pH^2DfH)NjXUUM{DI=dMnVOuAN> z)7UY|&&U@?#*5!@E_Lq^h2$8$Y%p_-I@P5j|5o{C_ zF;~Tkq>EH_u4I({oa_SDjfokBkv(Q()x@z7*I@Y+mMIX08OqYZ3u6%hx}QG3E*yl)idTdv_BN zHzXVj4RESJ_edF&+Qo~C$xp+>YgVR8PTAXw72cyMC47A-xN3}bnJnw| zlGK5>kcs~OJrz79%a$#h1iC%IYX9Wta$LFBA)SViP-PyZIu+g<Ri3 z7S6~@DEBdv`_pTA0i|2F6hlD#^XE$gLLSuyV20Ise$>eAw2yX3>%gItS5}wj^=7V5 zvKqK&aN$G9)^tIEzlajx+ zq?fjE#B#Urjt98U?cq_0WNVR@Pl*Ao}L z2rrCx$SWw&7;C>bylrqOLa#^b*lI-a^m`7yuTgFfS%r8+M4Ig)rEOgZfV(T&-eEI`E3kiK;I0dMr>=0s&~ z9-fyOZFHO6C$cpq_{DG?CNa5PDR6G(?}wnf(aHwB71vKBgG}M#)rBtNayy1cK;X>$ zoDMGkPG6#h){WHqAWar;a!MNfr?Wy%W~cZ>uf3-qY>cri@iS(PJ^? z4zF=ckdls2$?WdgoTSow8f}wfQ2J$gv$A%GJR>H=-`DqRnk+G{`x>Q1!NAtZH+_tv zo5=C<8*4o&*6`j26-AU*4UtF12Z>t=-K_)s=DALa&-q+UYgpXpo^v^wX=G-(Ew5~z zPYN#-B5uS9$9l>Z_tH)=mTlRm`NdIQMY19zVav(hf}!YZO|i#zbZtpaR0^xeGOE=b zv@;=;aMF)1qVEuUPtA;z`T6?~!nmO+K6^cspe~-*PIv|<=SVGwW2bzh%*v~IZUcjc zfeo~T@odPvqUb)$PVNKP5HzPw=3we|k{0ItTD7g8&3 zexBMu#8sg?S>rO&U(OI{cA66`=bx;o=eG`8c3#zB@zyeMdwTaSRsO`Rme8B~O951b z@+x$f{xYFnr!_84&iazY?sk5>*Iu!m2OfnQxObRytbT+sQrm5+#9kgK-sW<}!#ruv z26yhpS@7!Bewgl0FwWu=EV`Cg&lF|ymt6~xR?yT8>9Svb$*S*IzMNfD#?{K=j`w2a z^7NFQ!O=FJ^-R^uDDB4LHz zBM__@$--$phfuD2VC@55aKiu^sE(D8)`>9mdDy_UT} z+uH|HYlJ=`%mi#Y^evrXT7*gxj`^gXtXUk~0K>RFU9W#&KwV7@H)nD0Y^dPtYgLTz z{W)uyJP7h_ueAGeEGu-Xc0LUW>3sUedBE3G_Jp17DFXSu0Jhuu8CB|#={DY3(7aeF zy?u1?=tP2FT3T-IQ`#MlWrAh}Z{DzZmE&66bsn*c`ZDvXY}~TN$W1Twxdi)K24*ch zO40$Icd2-cEaR%Gq9V=(yRt)7dY(nzhcUOpW1wbBku_Wl^&&AbC^~vliee-Flo(N~ zwnn#tDY?=JUrj!I5z}}>$Y{HHiSztdm~m?z%hR_oSc8G>LzW*^PEMZn*SG6oe7Nbh z?68%%vM{knNGPD9;y6qYd{mNbblO-)Y$e(<3>snLr42o#{ps z`(|&kHK>LkuAVI1CSv@BZ|L|0Ic9(Dcz03zvTggC;6#GQ+H4FF`ar`^FJO8X18j8~ z3Mexb%eb7Nv$M0IxvZ(V)r*!%K`d;%7}PsU)B5@zu^rw>%e15aL*O1rdpx2CV8Vch zVA1VQ4BY2T z6Zc5rd2QB2N?%ogOPxap(qLxy^+zV&lfSVYIj6>Q=Iq&yd=FV4M$Y)m%*P@!JJ{o^ zuOAMIh&T%?GF92t!_W_2n~p#Es&HtB!Xx&976nsgPBZ@-9=#4ZDXr9u7?q?wva&I7 zp2r@SN`9zbf6;0FrKhZ?L`tWxh*(NFJ>Gm}np5CM1Rx#=_d8PVO zg801=#tHkUjBSbGL@xlvqKR{u>ZyOg%&QB|>B+&<3hi&`@W$HEUe>+|)nNxwadYK8 z2AeUeam9qh#4PyyA%fZ!cf2>Gjjcvedl(rdY$0$;+B<&P_p!A| zdK?(oYuEF6)64X9V|WR(&zZLg1joU;u*#aJ`?QN44?&`BoAm@W7}%%vp|No&HKX(@ z%xNKwi)v+`_X)@zevy=<)2#6PoDx#SMcgbkrkrK-Mm@)?*3SEQ=X!prIr~D0ZWw#Lr z?VuG-ZfwIz$fH#pZKjQX9wz0K)g5@%q#^Q3l|QGZj~--ICFNkB9>!&7XNSQ@gYm)L zds!l6e&0sLVC0id1&v2qb{`vRj2R*>%_6N$nt|aA23mLqO;^K#Sv{DTT%P{=4(_*l z&|y;dYhT~QPJ60O4U@~=ABV5L?K_k1Mn?PjZ>?gyA6!c0E5c9Gi3(y7#+Et2##Z-e8jU+bP7+G8f^+0f)kPWhp_`pU?s zgt{on_P&C9ah}+A(=r|ISWk@nY^+Uh`zPpsiWhra)=?*xx~&Mq`5UZ{s0!M9mhGtZ z3)ObJ!$chaX05f13HZSDAL%JqT-iOaVyCb>ibW(H2JD$%s%RI^35)_r)Ru+uj-rr=O2OmQr zV28QMSw+Rn&cl!O^f>4U<-tsHWn6)H(~(!NUd2j!!Z7FuOT4Hs5tB>iG+wu%tgYsT z)yFUm!z`bgn+u%hZx)R=r6wm^NtE!mjCSP<`7m)ACoAtfzq9I&lL1U8PHiWWi5$1W zC8{L#HLJ=F+@{@;*$LCulQ7lp=;#R1IinI)5xD16XNiU*?l$fHfB-Fnb)Oh=t$L4R zaf^$JnPXzJGBEg72$36~yaI#zv5YXR`^tnFwzPYsNx6E)E4L4}{_;V!^XCo4 z&#fDvi9Dc_XEhY%kOi+|Kh?vTAjrNoZ(SSl5BgP1mA5FQ}Dpf~HQ-C8i|pe0C*EfbPV}xM%fkS?WQC-AUL~Eg@th!NJ$e zWArnIAbe&2+*?l4`$lsjIf6xmZ+zm$G-Ah;ZkVjy9^%CaF;lcpLBl_Fm>8a@8l#dK zWE92)2vytjJA^X2tCo56YY$yBuKlRrxyitH;N9~}VX&|W4i2sqX_Ts5nZh(ejiPim zdXrZ}-h}b+fDt$<)}zt?9JbVLX++h7j*3b4jkA!ar$L$JX`gsXG8B`cR@Oxx4F)T- zF*mG_Se8xqT=I$KlzVAMmp25$>WyKZFPoCYyuxpe@uF$^`tD)ZYHMHIr-wqNis#M+ zt;Aut@LmBKG#VaIew&Gk=M;O2uccnA@}GVitO}!HL!sT+XN(7?xkN9QHgjwv%gMNc zf-ubLge7@yUz?7lT~^6Lr>Ro-VgA@aV%)0k%B3YcbP?`B3DK~lX&OGq zA^VazVd-&gjkxqh*qj~A$^v;ky{OuSH`%LwTwtAJk44e`6wL#hU@3Qs%k2c@K*`zV zB`q&Z)ap5OzcW~yVI8YhREhHBAe0w%|u?;b=4>txA2(NaT9tj znMhG4S*7U8JpIt;(B`qq!FnS9v}%k@lmpf+bRp#9^?r!HEjjinDEP6JBlCM6ATyeC zVQb6tbfz6rY)x*7$`QtP+Y9NM^&q}u;5NSn0+aN~YjRH>KQ5~a6Dfdsy58hotH`OY z+niLyjdI+vRZ`?07t5JGa~^9|hkHWyCWPvLeX6B@r8;OYf(ZBP7hg1w;GQ0gu%yw= z7xJ$c$GQfut}Nzvy}k@jMzk+8HMhu2=i7&xd11MwM;Lr%X7)k6;0kUgHa1z;BS&zAgSnpg9;(h=f+6=@C4|%K+JvFy& zhnp+a!g&Z2HQfp~PWS>%P{qjg-kQSg*k0PmJ>+9%{%1DhS3+rfsWA)9Zj0E)JoBz~ zv`<4rgF`|FH?vett<(x(>h@(6e_fQ$@sff8Ag#*PsjGEJK$aW7k8X?Dkn3@>Ku-w6 zVQhBX-=^dcq=Ig%fmmpgAs#f%Isrpw6o zE{g5IOHf-WZ6HL=?sV;?E$luPH`#BoHbv)-Qqr}xMNDv5*bRsK*KKWcwm6zAPB~gz z9(?S;Lc|RykxJ~NOcfmNo+J4^XW#-4#lgxbel2pjNnHEPJx0!&2+PuH4$I;zoS%^M zX>%l3wV8jsWAGy*-pl6#*+%>Z!Udg-&lh10`~haL!wuHks~x=z;5>9!!7+3`u~KE` z1}~vpgD(?VYOuwWXY7I|d=-r(mE7Zf`-qb*=D0=i%^RtR6z)U9oeLe4FHZ;aX!}eA zQepBxdJe%18^Sgx*Z;17Tc!0N;XLmwwv4?6XogYiJcKyM=)=0PEutWrY~&>NoABP%cv=USnCEt_Y;Ve z1vCm3j-RpiBV)m1ACEEL&WWLhZ{Q=`ePAa%Qn<5$oDY|;rML%`rwo|8ivv07iFI{K zF%+JMy*Y`TTh{a8V5T4V!XjU!DU@uda_>41pA!^xggun*p6bsP0v|t?a|pDjcr1Q$ zH*w<~MN)ypG#cqV+LB_+x+Hw{!Fj^259njV@{A7MiPS0I85Xh^{Nufg?GT}Jh#C^( zyaHj&?nFxb!W=BJC^t}1kYj{K*4^bQY}|AOMj(q>D&k9`KNWO!VnnoGZCj|8tx>^P zG8Iw0UkiqMgR+bceb?!eg;_bwp4<20@^Td>${^4PQk9<$82= zPi(fbI?LJ^X6<3RKvl2DiwdsC%xYy*yAR+Tvg%`GViCnfcD&@&Bdnc5m5%d7RT+n&ZrprA4wd3?vUKbPo7IL}nZAhvV?y|MZf%dPk zLph(;^n)0TpX@ONQg+!D;{KHm)6S`&8U4j6ogC3!T zKpttpWU-PB#W1ypNQSb%ftsg87#yr>#`uoD-}{ClJ0<18*RNM$SElOUY=6-tce8g#K&VOkrOBD36a(ZAcuS?|jUK?se|hlPHf-5d+s_ z5<~T!Q*=t@-mPC|bVY>Daqi=( zrFu*E=7iAY<3p60tJ-B#8h;^VmP-Ut?@GSQFzYQ|8jP^7bT>WK#ED~Sf%XIyH7Em5 z36=1Eu4#MWek|wVD-~2S1RNziYqIbFk$j2tOjppsM3U^ie18{L1ia&McVd=?GMlyhCL&Lb8tqm{lNqc7Yl9+C%q3O`NQ8$#SVZtD-WPk`!$nf$cb>qGCKdSpT-F$^o-8 zh77t< zb8Nzf_sA~FGk!P4ab`bv(cmE=;cd+ zfPvk|yl5D?kM5=R+$DeSaZscm1#wUuvkMZ$9SK{!-zV}Exoq9CB``evjI(oLsQfW% zVrf#zlj(%$%jPdrOe>k1U~25XkR3A(wa@VY$E3hMp`=&E+dW~auQP$l_WDXDS_X`` z9YHv@%LNwx6z=BFRx7#I9z#IV@c>tfGwcio#+%{kH@ai`U>6@F3-OgdJ*y1f%Qh4FPGK`3?QxYdP zU_us4rrZMN=4>S zd25bzNP*0ay-gU$J`uci>b! zd-mGg@JG07&q1ddLue;wm+xLN(vaz@#PHn^@kY%o{VC4-lcg&bs4rw}%mc}- zbEB;rVE?!n-wd0rE2<%Z2V`rr{Px$Xh-L3jmDMq8b7mQ$RA4!I1-2r|b4y;m@?+*z zeYxHvnmCb5Kb-dp1r{nI83b{-B_+E|If&}Ewuke(?IW0nv#2lYWTrWZ$re#^SREar zeQXpaZQy1Uin$C^b`Kv97$w`LZt&rJ$U@1Fl}(v$^DukKpVix*V_eUkF@ZmYCYGPS zn(j4k=9Y)uae*?NeYv2F91$8`TMwL}Vc7mb&jDMXa5nVSQnN)#tHcCe%fNkUFI;0M zUb;aam+|uDS6s{;H9se)K#+(8HGac0Kp$<3Zdk z*dN@@W z0HFD_9mVhx#zseBn+XBM-9-*AQrkXjMM>DvbsZ?lSBg-8a?jeoqSsy>%v*3tQ{mF3 z@Z4_ric$b_N^X5X6;Fct~ZNTm8gZq||I%|*n~Duxuoc&@0c zyWP2@XR7dv3ORgrk`_W=72LboU3C$!h0t@bIw;;h(OnBm&dA+;633HNqRyS#9fCET zdBR`3xVA#xYDd6dft09`h$mFZ`#7E}Jo*Zg$b}-oPz_joeRHsz@m+>Fl0>;s#|KwqKjvPa9S>bnzvmdlTTtV)tUb_@k?A=NU=3<$%*<+iV|XHTlLG2dO(4>7Wz{Bncyf*;$V z-LcNalPJ!3Vll;!%ed}wR#Y?dmKn2eRH7xzge{Psn;O;HLSpqp7K> z*DUpSbkbO%8P81#!qc+_wGtivq?ExDUPmMS21#5Cg6MB z^@b41i52fslqij3(vbCpfDQyX+OXoHd-rnB!{6-_w*0vph5%%97<=(S%fq zD@XTiB*BrpQnF)XJvE;Pesou0Ekw+vZ+E5THs323#J$YJOUqI@l^hbX750Ct6;&6< zB-+1E2gRDFU1!$jSTg8PU);4~KX|!}40iF{N_pO>U6%c%8R3adkbWkmOtCf@2ZO>L zZtWy;*yG=Dx&-!-$xiR?4p5iF#g)0gNE3r|?{d&7oQl|e3NGLs-EeZhM>cerk6U!~ z^;Oi>0}XbS$8|7{?=sI_Ptfc1s%~bn$NP-Xd8YYuN*YJeaP#u|yy}5&b2+#E2w|dZ z$DeQByADHf%ra?j)bD+L=2G%^g zWCRr7Jt`4GY_uC~1d=p@esjSIAy{f9~DnYxwtE2&+&1 z$Y#w&mVC;4$yw^6qT8Qu0sF&`_t!!a!RGafN{Z`lAlD}|B}^a2RCbdYUz9@|oOBwt z%$En}Zg8L8{c*-OLoFpC!8`)# zOw9&@S4bZJ2d<2g3`i%!r|7E5kfkb@O?}#-6rFhgu56ta*2 zi1+;A=>o|-269b5WR2$@=uN(Nk0xEWlz!qc9sXoP2JNY`sk2V13zugOd+#HzEKVWJ zc>8{V_+i{JNT1{r64KfOcCT|+uJY&NH7_G`c6f?HL`g9(l4u3>8r129DXc2Yc_Fwy z2q{PlsxA+6FsEOXGmV}pgXpc~fw_)>b?`f--@a40kErlG(Cg&M?U`k8*T5675!JQO z`SSJaKnP=Xq)#e-d=Sk0An1i)3sl$c5LjyPsA@Re!MwSVeic8;?lMna^u>$x8?87DtoLCZ|IkpXYRZBpRRwlS|3_MwQj=!NPK*c- zV?&pvq-C@kZra7jDRIKwJS~aGM>nhbh1kb7wksO98-jGWV5?NR11faOHoONE5Tw_r zU%dDMz5t(~;6i7^f~JN>@O}Dm?t&fUFg}uA^;Ee~gi`TxrztdbAD9HiHjfnNr9Iz^ zo04*J6Y@k|-EUO~az-1saMnWt0leB|5Weel8Mb$ZpilN^P=sY0UQ3Mah-*r?a+Top zLXU{<%Ny2qx3?t1wxKnAaL5}i$;)W&->q~pd38%MQ`y;V2BYg?i?M=vEj)2+jjeNf zi@1hnYSOFHurqqhT4UjS8STwH`<{%2YfIfan9rcvDq!Orl$e+}GZ1PpGuNy-yU=Cn zVs3h>#!T$t4LM%^BV3-}aU5@2;-drRPg=(c&SfMOr-x-pNE;O@2-wy?X&2Yf&q#_d z?MO)%pH;E$|0KHRHc2(fCV8Kab>dJ&Jrt}L6*I}-=1@Dmj zg_dGH!K%vQoWo z=jj$vjsnw9YR-#qra#_XY+nP59>C#!07um-c1;ZWDgCjjb*Ev5K1Ef)NVOSH8))c5@Cwun4wHP(V0a$LER31?-q|*9De8#7%((qXS-7a_ z=bRfFMLAWx518*rD6cJ%>2~bizE(J>S*zBwR_&gvqUuz#obj?8mzTcK)E;V@Y(WeU zHfoiUvZ2?m)CkPvx@x+|EBeqOR|vuoN3}3tp+F~_>~9L69KO9%?^x*yx*+{pVw+ga zSVX}~4W9`kQD*_$M^CixO%KdF3)s~^GtBNPlssc(=iDQ0#rV8hNiRE)`Z;aWp3W<+ zS{w||>ZMl3vyli-?QpuA$irIeJHc0?@A3RJr?UxS0;ii@VZ?kiEbR@&1)e0|lPb@4kL~N2x{Qlj~I|Pgb6)0;%4_t%&=Px#m(y#|@ zYj*8jBu1mZn-*8I)fm6ew=hIsA8VFRrIl`)Lt&te^=oJn4XGyv#+N0XI-6{2k*MpL%=p5e;zul+(xMZVYCvqA#eBcE>FkGaE{c^Le!l%G- za9fY_Sen0iGHlUq!QbAQZl<@%J*r$$+f78v&RJk|zs=$@&%R-!`TFy1V|r~{EF>;y zo;v9!vfQQ_qOwE9-dWb7;#Q#Cu|pAo@$nZi?$WS?Lll+?_QQs0I+5#}dg+GcHfrUi zlVReN6Lpgq`)c>cWp63u5!kO%NEcN|WpdcAG&nu`e5&Pu$86)}C-rQ8JjNz-dm4DI zD{?UK8H)sQzaH%M*(U9Lc(L2TU?q~`uJhN&^9y1V8*h3nx$V5aPsgOpGN@jlzt9*u zhnmrF{tU~kyY-`Kstd-~+U-8sh4}G^c<}SRzkK-P&7iPD@m#B4UG8+auUCQ3y!Qbt zxl#>quy~qi6VxF{jyYN4{fny?^iy5Ny4*c*?2Ufi}wxB z_Pw=qT-%SRrj>5dR{ya5bLgh(Y4PY{F?aIpj=I=mUZ2AvYCG-52!y_Xu8b>J**6OR zi7yafuX-773#2YJNEjluIY8-`If*s z&WQJfwe=@@$64jn?~il@BV=?vGY_e@lj@V@gN{ZMrg?}3;jmv<5%NojTRd#~tmmv>>;)_u8 zrpJ3PD^kuu2yJ~Zuj*i&&knlNO^-ibx4mcJ+9P8M+vauA(h;!66}A|^n95XTCf3|G z=;ZOBU2dmVo?Ne`Xtnt6k)E)aIGExb)y=y~-;1Sk7FJ5r7oGjm8 zn-iw=tlro#c)fN=pix+aRIyFjb0#thAFP=spXEWdL{m*KvzrkIIIf2Cm8P$H z?d;-)^z~X7+Qg=@U5wfGJ^7F8>9)D`ZEH$m72DgweL({d;sElW=G4%%fSZ zva#y|vCOwe!*x=cw4*2IX$08mpR|jr>9;4#bdRy8w4GG2Qa$t65+salY<})T zSJLt7cm}yp?K7io9cG&HZ??Q!Rt*+{kTWmEHf7^cdWDzlm-yR7ZSuZKgl3E#G0?7> zry+Mgl3dR{TV0-gn9c81v`mO*c17mhp1DW4iyN*7dOJKT}w^qhGzLZ$+9oeIBx$Sb>y#=vKX9h>OT%)5`+SeZ+8uA3ydk_~R;GYM4 z$t#~?zD@RN`E5{0Q^Ytulxsq+@{=~PTWgmnSyRUfT=l9tX4up9+dp34Xgb?{fiAOe z?BQXte0-#+tJokH}@;oA5PrgRhL8#dt8vu z5{gvbq+$Df+J`)Omkq;+jw_tPd57BZ-7AGm37PKPI1k8#@LpMXZ91ebFf%!;~Y`bUrfW)2$I_=7d(e$bA{TpXQwfwOZ{Sl*}AoyWuf? zVKkgxDo7-3SBhKH;#osOY>y&t`_W`R$bLsJ9_>1Fy2k^!Wz72&Q699ZVHp&6T z!!WV>`c>UCQqq=L1nTX(X|FlY;Z!Y4-rZf#?AYtgDn-L^gZ9pG$1*HL*Umu_i_;J zwR3fb-0uTh#(0tfJ+*@l?xRC3dPqtb_;`vdAw9jp?%kD*REJ#&R*>iQ9(4&tOc-Gy zsrgK~v#BRb%A`oiL^6kVsKE7Md0FY|N;RY}FHUyv!am-jw(~JUiL?P%w5v#Eu%&VN zFgcr&@ZR=_BU)*FS1;@deK~eSOJDi)fL*$7YC`UYm^|i`m*&^MHWr*B*xT*cL?W%ihe#&W(vL>Xuh%F>q}=p(W4BPiENj$y&n>?;Bs)8b6r0~oeHq6tX+LP z@0k=0iJm9OMk5}vXo*`*J5wgKDn}kj?YF*gAmOQ~Zb6%9Lk25_d}<)ZZC)sxKCMp7 zKbB|2c$C3hX*6RJm+jqQwj^%$`5@f}IzodNQ10y^<78@g7l&8I7_pIeH%YOXmh4GpaQSF2LoEkd9&d(pDP%=Mw z;BRexshWowMm0m|EsN(qoh3qcf`hiD7RP!eNG+k>ur>4g$K5=t(XN!n8|Jbo@twLo zUBY@0wu7)+K|uiv%T~mOTaVF`JVKtfuyK2z=>DV8z5L>p*RP8jsaH zyk70Q83Dm3dVSUdcJyhxU%U~?85^@{Iehq5``j(RgNuEh+Pyj{)7fkwtW+v|~ zz)p}u1#0@$=;P+G5N5jeIZ!#z((kogyXGI(Us$o)L#nLXHBVsJmlJ<~z z_l71W*-&Ls{ zu7l4dLF2B){)DXx_rj5^(@Av1niX%Il-}EZ^UZnnlhX;Qx+%%=)jLBty5w8! zB-R|dWOh6YK5g^x_S=XRwRSUZmlJg2+A?AcoaWq3;zz?Sq-tuDYi#h|u?9=wEW_%} zTLmx5K>@y97`3|=rs9&-b)r|>XFmGgLde|G?9dW~#LyzJ-bx?&o`r?;ijkf#Q)Y1v zbz_@2-wm&=_nV9n0&MWKDx@(O#@4NSa zGWgl`2P(yFmt)_YIdwxBIxPQ5MF7pAHOjmPAW^TAf_QJcX`*Cp%0hN!dWuEuva_1Is` zs2_0S?9|e_Fx?t04XNhA6>cjObVU=sbTv?Hg^S^Y+KD9AS8Nmo(ZrZwANpE?*IUPRW@-L&?3x(@-r8KujJ(oVHV zI}%U#89fRY(ccM1=aCdQMb(MQiq~G(#lratdK7Ox_1|!T0lKI9f}q+bx@owZ+Itm* zOkS<;7{iUg+=1hwv}EuJ`3 zDSUTepC)4W4mO0z2RviT^-GN_snqT1Zq{2V$cn#X-jyF58hYx=mAH2K!NtCoo&U9&v4qyGs9K`|-8WDxYPC`niB!`IU6LX#XEZF-}@Mrh7KU^>v=D=z(R@+pXoP1x}$q6o; z92hUK;auV!Wv<-2p zzMB@yu{1N|#>9G}HN=qo-(q|2v$;vN1}!d|S&h_`8E)MZ{`$rPKjmgIkw;(6=1&Of zTfTVlGVq~R`b9~vTCH?va~E#KAZ|u|J`+O)331+edEuN`OVN~9H@PyDhYy;YtC-F} zpi<~*$jrO8G>FC7#6G;+ZGUp9A6goPdjx&x*$eAmOTV$ZPM3cvo;jn<$ZE}*GBjQM zR(jSwIHzxH2LxCJ_2bh^d(2%bl=)Mt{kF?Q&Rvn;cGPxf<;wfuX!geYFM8(gpOe)J zl_AUC7HkAOzg9NMzz$c*(vn$s;ZtbaMPh`R)sg*n#-9tDSuR7Ka)UP&F>jk-uY-2a zg$_A$nGkX*gCY6ObpMSnC=1(sq(Y6lBpa2FsydOkZ<0Hz<>VF|JTW7!LN4GcrKF~q z+*Lhz?CJ{HSm8CV1+6EGyN@3~-YY;_R-bu-b|*K>gSc9>U#cwH7ofb5UsUwz=;%#B z{bEJ9fc>+X^~TMctUt09bAZ?TMIv>Q=Omej(|)Rv;+^3FECZx?-`j& zhL<8ceNyE_`ti$m&|Y?)=mWS70Xf`yfb?%2+LPeF{Nsk7n8Fe8$M}z%15+Fh2mToU znR9^b{SVpyXUZPQ{SW#7=gR)C$)7-20!vHZ2HamBd><<-E8zQpo4kYX108PtZr{hH|K_j{qAbJJsB@XH6#@!Zx^_H zj1m~gQT(ps>Iqtq7;FyWAL@XdaAWWx%LnxLegQ*6!=wSv?FLg*Qvi?0gUQJ$fR4IC zpA8QWgRZVFke;3a937niB;)|Ngcb1d@qz8zw*zKoW&o*Z0G`SMC@CocJdE&vW&G&x ze{KH+0s;JA>%bCW9*p<5fS$%o&{*IHisQ{e?A$|4O1mX5EpPA zJn=jS0_`L~RmN?A>!^pa9U;lLs_Fxjh zg8*(l3LZax4B#p`05`k`@LU_PbLUO~50D3pjErF2x^=(k0+bc<*Z=hRZTbKHI)EST z0e$VopsgYTRKBzWss0y0ptT6FJHH9sP$2)87`7VBAT`_uJa#+*!rhL6+Pp_#;OiGC z&oKb^O$Q?*qoB036u=`jNHRjU43A0x@Dx1I+1d3cU6}qw7skhtE{y$27Y0CMV-tvq ziUO9FRsbH_0pOtr01}x2Jh&R5t%)I96+og9$tV0Xdhj#(!vjU2{UiDR@9F?yZUPK_ zc?UYHUx2zCFOVIo45y!14_FzudTeWhZzY;{bvkWI*g41@N&f7L1MzLAj4Z zA3ynvpZ`(*KgtOCa=0i4z`g{490TYRrb%OJ>U)g%(Ju_ZIPnE!X1)d<9v&neLU982 z$^a)P=U>DL3JQvU*dP3s{Qoy}0B+I=CI?#qwkZ>QEPMn?pPPXM?^D3vlm|GTqXo9g zIga;@<=fq*)NLo$o5feM}Pk<`TwX3==ZH#w*q*QE=Wj7 z1iihz&?ij8Yav~jBwgowjOgzl0AIiM!RulGI{6qLP7Yv$2*B4DFmJ4l}+Ieqv4zn1ym`WyKMbPaTd zM{R8#DL(vK7m$8^(}k~~sp%t#kADu}(tpzTkY9nDs{wX)b^w=pfejlr{4`GdT>cB- zzpDdtaBszd&T`OE6$k3FZ-d-W9T4v+1s)l11McU^|E-3HCKX70cn-V{yAF~coB?%t z55e$256RwlKcwtG3eUg z^97^}=*+I(-mj#*;`Qq+;N|57)YQ}fJm?Py2ndj_@nb#lW1RSH`Tu=7Fh4s9MtU1T zS4}c#$h!|p;;w@fA9?WX7B}#|L=C*O$p0;ej~*S!3Nr+mAqF7T_YC+{76~TCM@e>x zY<_lj7Cd_vM)J8xcF5+syL(8!8-pqPhwcAI`TzQNl=GoF(cj-6w6?aA^zWN4pqlbq z+(C5&(giFQ2P!Hm(E)34%V|RZ&(H;M!6bki;saJzR?>5!IPo+2!>%y2e0UwJ3K}C`k$O<|Kq8;~xM^_nu&n5DI`{8f62^7ScgWQN~AS+k{bTwv^ zVl$Ha%*-rF_7)Zv;75BxcGlB_<)Q&(6-lI&BER)3yIg{qd&mKZ1CX0gP+>}+}u1s z@<(HOas&)v8=<}Dk>p>SbqAEjUkBMiY9Q&h7>KyV0Rpa20e=JXfBO;RzzfP!>_Of$ z9T@9A~3ALsYiza#mhx&2p>|F549VTLIF`}p{fFvg$RKk|3~9Ub_wXS76E1d}7(V4$Od zR2wuE`h$0=HlQd%8@%?D1BtFYAkvHhgc_0mpN(fGR3PJlG|XWwKuy+d(BJie;^5!^g9MB63syae2(#T|t8dBRPQAEFM@?umnV`|aSFF~$F=PDGkBf!rr50Q3AhDSw&8kNpYnB#`>v zsD4Aex4$Omzx5dl3k%6-q8bs^-~TB7_qVS5zxDZV$^ZA%fnRd~7G_4lc;83R+nfv9 zVK1;Q%M+A6HwL*uXF#ggArNc5^}nqT@eZ6Me_s-N6?E0U0*edtzx2A0u0DMl@(ZT( zkIX%iKZ+Zu&x>;Je`ooB!#QStseS$@@`2y-1HaaRA2}k3Loz=-1V*tnq~1{r<|!$^ zEQ!7hvi(njWRHCy+KTx%bt2`qAgIst0Vo&g@2n)*`gfiK%J)o7P5-V~|JU^5yZn*e z{Qn^Te?=YmkxR5nTn01aIM_da3%=B*KrAu<=9jiGzq|zV%VYl~zs!Osk~YEr2g!aC z_N0(LqI?zoMA#`jE%fh>^*@*Y?7zMIQ6Cb?|6g4PkUsqACzc3vu;17L^Ggiqggh~L z5G|-oG6$GAL(l*@M9r9IV18!&7d{)3eN$7@-^6tOnw%T>|GnjpFwFm-bl}H&}RMK^_?&J_gw2|`9GSQ{{$WQ?gx-BfNOS1 zJWSL#MdxWtNlB4-xu}nhdZ&ng_uWVQnuCYz|GWIZ`Txq_RsQJyh$D*p7Yz-~-&ME% zO#Y~c`Jbo*NDsban5h5J(9i&}^CaNr<_0u0G)SB)#K%PaSH#ai7ydVc!m5G;(pN6)Bg|1{~MR_KV1hC zHw`24@ML6UNIf%T|G&5VQGAk=lmyAi$s}F;XZ=6o6MW~h{-FbZsRKw45I62yk6?jR zKfsfOAultSWc#zTzrX#X90hU3A|oUJF8fFE;%ELJaR~m%g~OA@cqI zH~t^xnt_3V03Omr%2$78|0qvH@#1IlM;yaHbl}^%x9|DDKcWM_xBo|ZX>M*Vske*j z*PqEB$sX0aKbQYFiD&wU4*d6Yps=v$cgz2fJtKL-6R1h+N>DEFGx?)B0dYcqCV#Y^ z1@VUd@B@Ed`}&Xg0kod)_p1LE;DK`$mGm*jBHA-U#cV#v89VuFU7i(XEG z1Pv;QqahwNL_xuTA`UPp8iJ!Ch9FTis9-Sm`~4t@I^YPy!-xtB@^C;vL{wB_P>Dh1 z?tRx+-PKdmbnl)Qk9($vU$J+0??+Xwf33A@)mp2{7?Aj7y>{3d3>+=`qt6W)GDNM_ zJ@(jRMQy*D_Y))J^?Fqf33vMMRk1^53>42t|utPvjR@vnJ0v8JrmU48Y{Md$vk zQQvvzol2j_&xL#4>Hmhr5SKBK?@QKFK0yALQuN0b$9Sc1UWjkIeW&fd_^mMh$p-^n z^Y7u=_^#lS1WlO(a*Z4P@rNabyo`aC=O;AzKuhS4-Hu!>&)f}p&OFV{hNJ1r zb>xF09|5_CG+p)Y`pA382Z9}E?b@}YG9|kfWpVE&%{zPE_KSOXp`TO6SV*y|Mr=EJsdGNsp z9obbx`TF7Shb@;l4d_`&_XC6E31WVLEgyR>w*5tm7L}m?Yhq6>V?fiNV{0%lbLPx~ z<1wEPV7rIzU_k4S`F;kPHy|Ule=&ABVw9o%_U+pX%6{-gOcK6G_y#ckO$@k=e{x5$ zo>0bsiGY@20H3Lr#*V|YS-bt?A0@_FbaQ-o%r%COJ~Dj}4=Su^9-;kD@%coS?+4x6OTBkeEti~7vcTr4#*DHhFK#rF;I&BWej9=|3V-rh5^PGx>+&WcGUM^g!mJ3 z`C;47f3DX1SrfuG#Q4w0fE)dH?Rr(^k}PAObr>K{s6AsppN?()jNXq=Amg3*4dj15 z2Hfe-ekf%OnB%+@A3!H7W`k=h9ouprya9XvFMs(<6~E8;NB_^qfE)eEA)EQVjDeP7 z;Feo%IjUnHnGf&Rh5T;leAtz+5n%6Ue!%!IgaLQ@zhdNwEMuS)2FM9pYQ4v8EJI6d zd*qNte<)R$U$ACC-f`?e6!Zc7|A=ZuH-|6Z)4iVA}iKFhCCeLOQq` z&CTB!!_bsG-Nc;}OX^ne^S$Vzi`4vpIRXX0-rCw)WmCkyL+%#FKl*Yj%xQkS;Rh0PO58Dp{8JR2zo!@m zO3}ZJfsF5;$pbjg$3T7_cynC0=A3!Mym|9-7{K;(Br)Jd|Lxm%sJ#rz7;wh`GO}B@ zmgQS$2^Nq8R@vF(!kg)jl0$VqmjG2ljj_8ntg zp^Sm%xoS-eY~8xGWUPH5`j+~R`8#?%w!|Ze0XO<@+xD{BOQMW{Ozc-7K5*4lS9SQ< z*Vq69>@kA;KT;SdMgKAeK5pjgZDQc1mtJbq*oUsH)iKw{KLC3TGQZH=k?)2L8>V~% zm=jPsQXg=m|5n-04*HidP#6OvMvN#(Gd+Hb9icTgV)k>zP6MCER);MIn-BIM=92gZ zf)NUNeKZfiN1#;fc}wSprRZPAKvV7qJ^nau*s!6XuU#>ko8LqKpZ-+#I*@&#*~jya zJMM7MA+hDK*DrfNv!=(so~+%26EH$-2efZm_jS)n)e;Q2(Z8{AtJ>4DjDf>3z#iR& z__ayrV&~k)UR~OTVCs{cqi=yPa{1uXdDmTcITI&NR6bwq1KE)naHoHx+RGIBmodC*~RGFlJDX5@bh9AF!c3Q&{a<-{v7l9z|p{f8~wLPoM;&X_}hJyleufwtZDby2NUoQeD?S|mKZ2S|1t(L{+1d8 zKl;&++CBE6KX!g>2m0?=VZe?4n>TM!vEpS6WH7K|#mYA8{P}VK`9U0q`FAWZ;7faLpu=GgzW95`AS zaHIbVFRT|I#0{!+WUCqR--$48| z>&3HX%~C#Ig>rO2-`j7$y&3(XA+f~7_L=W6&v_Sk;9hXTI<@8p`54eR$j5*i{nxE~ zUh;`|ZVa%OVoP#35o=GpHRBwgE%K|9({I(PRcf3<8}{V^OZhwiUO}v;Ni)vL)ti5< zN&ozFaK!%g;9>dl%no-7g zB;z~8KI8az7SaRo2jY57EBpf6yVe9I&pr2CwI3XL9C>y=2HfbscI`R``gdjwoO8}O zMaLlYf%fF=L?%D;%rk1N|KlH-^rLZ5LwBuraoo6Zqv8wb1BG}xy5a*5JfPyVTe8l` zGr%9bNf-D({D^uXvvkq=2)V`d_}6uFqyKZyt(AOa>s0BCd|=tK<*s%g`gh{QNm(A> zG}c)&4+H|rXP5YW`afS*=YM95;#2GvQ@}OQm*){9z`R1|ebBid&^hrJhtE)mFJMn{ za7u0f=x<`cjsDL*`<&C6F@WE7A$?ubj`4?oHhXE|pWRYg>-+PMrSweRhn!%|2s&SU z@x=-+_@$s*5<@V3`gG^+yYFsRQmK^kB_|IUc_2&-l%juU#sK>y71Gu6>2|a}!`Ip8 zhrFV!8M*!Gc_2rvQ|hCpKSwwEKl9A9@}B2Z>1=#}Jb8?-2Gmgo*|Fy4uP37e#u8$ntkw{d{6VVZ|Eh3M#Z#jMj z#1{E{K6Nd&oPM&m2bcjnJWuZr0pis6&G@a}7`y;j8;lJ}KAlm6HQ-01)G)6Y1a z6$9k*g8s~{(6t$ldQ6%$;CFDrwS13Gj^2$e2w6RS`mM@VPaX%ItNFtZGybI5@69=5 z##Yock6?bzypdcmnfvtVqilY9-o>1qv5Kvq{T#6SvL^@YM+Xl4UFB?Ne1m}u-J4>H zw2esTe>d$${HEvX9ElB0BofZ8Vs9c|7#TvGFk>C;p+it__!a!25FYrBb}^T5qyJM+ zJuUR_oEX6F&v>S<;N8%Ud}{atu_nTpga(&hda3jCpZ{F>@L;#odDnCvHgd9=7=Zqa z`3%i7`5a98a?WpV7%=sB^3FZ-$Rp0LfBkEfCxUec=K9zG&O}e7M>Vj(tIpNjf(upP4trWWR7X`mbL7l0r);Nfd`y>?sCHmBr0#FsY7 zfR4ccbT0H)ivFust(N@JPpQ%w`2c&VqSvD{XJo(*#oP5>3a#Y>=#J1hUk5ioH|GK5 zcPXSNHrEMT!Uu|Bz-|1mT)A5971miXfDF~XKiK0~pF^M1GJw4lT7m)e2IM_Dw@K?l z=iq}mL=z7zP`d&L!3xY`Z# zF@TMcd1Xcq%<%ssg@ID^@5~r@?X^A1XVc`{$bmon;SX61Xq!N0PMFUJm=iKLXa0~+ z<5Hio-;n>eIS=S~KHx@w_LPVIof!k@Y|z4_7vq!ME$9K*_K@$;+T;V+1@PZ(i7$`& zY<b7O#Y0Cay%7kxw~oORY&O12{pzyR_9 zn-KE@u+iSVfJ`0${q=f5N6G?s`ZqY89Ruj?*nu_O%_A7VKY!)Ql_C#5%<2U1E862X zq34d~J*_!!;sF^uz>&a!8~v9pgZ`Zx1IRws*`P%++CgX5i%kr$map~3V)wP=dw9U6 zO`DVqz^@n{(2;z=o&L*ZZ~D%S0oGUW*+utvqZjyKeGokW{m|4I-R>*(8@eNYn|kc$ zuN}8n7P!&>$tR(I83W|rcC*`R8ZzD)_bs_r-{W=!Q~3X|#*04T?my6!pVnL>FwYCw z3Ek*euMVl2>2mqy zmn;7Q`~WHFCiovb^w2}9xY7TKC+da%WelJLhC(4V4=A>F-w_zlw1=kHmsq>Uu0Ub@ zYu}+)Uwu{iZ@A4#T3Vk{^e@{CHS9g7#YOBkzd| zMkg%xoYsEtM*pQtpOCyG^{SNlz-wxs7JR}wV%(W@GHHLMzy?Xi=5T< zDQ8uEGE<(AW45e(BH^gARE|B26$z4MU=L)_px&(tEmCux%rsS~I#qSTOymG8V6Bo%mK>Ht>erVeFQ2UqJwyp9^ zIP%B2{$Bg29oYYtv-z1tPW*uh&h6LqaYmnel5^$2idL84eG{A~|9r0#zhCm5Jv7yM zb;o9vx0pOkGqp`crERNk3agm^ZLtcoMrJD z&iywJbf#SLIp^9RR^-a)!4*zx$}fhT$`WT*fWpEquNJ~D%Kf7p|D`# zRn-@)X)a#;s6%{Hv7FR}`p0a)_C<5U!6%=5?7aKtR%c!Pd?)(*OPxEe`l2)C#}!3O z^@SBqOH0kgCp)P>PI8vU?rt)@X$9y+Aj|XmXRzEsV){XbeJ}ob({BYP9=gyrgYe~Mt+MnMp{28vl z{(8v~xKLq(b&f4tw#YbnSZvf+sQ6d&9<%)!pVSYX_xJB}c5Pnntcp)_g14RR{Qj!X zIKRETqD^JS@Cv6?nKklr&eGsi=ZWZVoXu;OC?6So8o{}a)qLQAc`A>hS@%-s_;+4( zQI+zMWZy&j0-nJ*nLN2h<#&t6g~w+3pU&&`{(J8_Z|>UQytv|F=SkmqCw%)^&i&VZ z!MST>g>%=Htt+#ysBqlM+;RWpEQ?K7ZQt|CCXpHMD8CV66p1;}Ym&qxkq5L?n~VL< zS_A%W?0oz4vbo(=Yi8{Ys^Re*3d+#`J?0DAMu`_R_d0tT8=M!G{N7nQf4CF+<=34D$8~ic7*mle^RB6I z3YFBXbDZawJ?N}m=5s#$duC5M)}S@sb-Q%?eUd|zwPgK$M;*=auYJ_qaDZGaCL0eO z`o#I*-965$8y|PpK61PB*dKo6c&44{JT&<$3M;xF>K2T2wyb;1*}A@7$u;tFgZDx{ zIJ*7lFGsrl#N@QM573899cjz6k2tFyxyMJi)J}5y|C1Ieb;7{Qxe}3 zHy>2pe&_@SI*RW4IVSz_P3!1BFm=Qa4@h2xeS4hu{`QvQ!}zkZ=1M#+u`ysjKh93K zAK&=)@IT$&{G-`^boe9P2k6P4e3IG24IaW+LOz4<8*aG488Bdg%JE3PVQ``S1kv@| z(|-J1^V`m6v;BI$b0qqp*nENch32R91-d73vE*5K>Z!k|eGkZcNRB(^E`{3AlJAK5 zD|DUNem(a)QaEUBA21(5AH`=Fnbg+ylQWb&f%)x+-G9YH#JIb) z9e-Nv2*h8I+X?>1=hIF*O|6BH!)3^j^A$hH* zHH$8P-+lKr%PD2@L+p9*MD{NspOM)IX8T`$dAsaKa(wl{?AfzjX|Hhs2C!?BOHt?5 zYDpiM?ccWTWs#%DPaj~5L|*AOmO8R`5Iny%ePFhq^?>8450GW0+MNG8b9%j&-4Yz^ z*|R4%{u>*&sx^`0p%1XdLC^g5nV-oiO)j}dAAQuh|Ni?`EGw}H>>J9M*S55LJCex{ z%=WX+dc5?(t+E%7+15hmtP$q>9~84E7V87E{lsh?4}GwA?^|lWxk7C=zrzQ>w6AL) zjMnsl+5SzNHao{dALzN6+15hm?5o&bn=1YSTK;d`xJky-vF`(X77DdD|2yP9w(9ou zf!Y2SU)(7B(;eGBzz3le-!uDxJ&+j#ZS4cI{TnvOn*TBG1LD!m_LVyS)vtclY`w9y z{J?BK?>^RjKz`m*Z8m==#x{S=wKaWUw*UF(Ul5<0W7`Mh4lvtS>YUs`@O%1zxdQve zop;`O4l(V2`O9C_oPggl>yC%7wPEkm{BPa5=ha?#$FdJt4=>ba)`8jM4Bs8(o_P&A z5N*8fy6c*K&o!(ov(F}bzu@b^8l#qvoSW@myLO%I({b$j09~AUjM+AF2BHTuPe+GA zr+eiiOWPMMTIAH$)~a^1bn;E^UxK* zkf|q{?bmw)AFDoKJ+c_h^1nw%U=Kuc>3;XS-_7|+B`WVN1H;f(x8M zg9fRblI&-q+s~eG$FdKw*^!3>9qf;PT%ht~vu+KJw~Jkhd8_u#({0CJ341PmK!L9@ zw&@>y#o?Wdg+e);k)7=SqualFb!LCeW7P-nG1e*Z?RWFVfq%0Wpw~26+ofOf`+$C6 ztb=v>1-bG2-~V3iMTEV8{xtEwa%ElN>_M6@xQzu92WI=(8{=5^0qbt2|1WbJ)+BWwl(LDzKbZrx zrVq^aFO$6ij&&a(%T2n{CivF#&p+R+Z_I1Vb7ExjWuqw_On*Pd_l*t;LDawrj(4w4?xc) z&>6H2Y_@;t(oBBrW8DW}zEJzzzC(9J-_be}{yoGE6}tx+LVOH!F0KD8Sweo;W8Vkt zqh74ug}%p68r+}*Z`=0rVZM%q?$O_w{x5ZPIydIA?E`!^S~{Oa&tJ6Y5v4EOb=O@5 z^<3T7LPxXxncQ&4M<3jNdua^NcKkWe*O>vzFjm2 z9pjyxb=VBB6EL3JQq1;i*_YWPu4$jhRjc&8;4flR%*+v=e)^g0Tp9nV!|g`vCAV^u zEqSBjz2@4=OD{DRTx)E~&9+O;XU{(SY?UXQqb~S!;0wq;topmw9(e|Z^#gPZ>>!=B z5cekIr2N;3dw@I4I+vdZEm%ZRVF*8-tB)G#mG06aPfXey6T`>&@5fmpA>zS@qZ-oyh!O+MYSp4&~uF z)vo8^`M+{j*Lm!n+ct^~YrC?&i~YvN7D>(qS*NkdK~CJh-*eBs_OM~Y zY_V0_qKnzGhG7eAnibkc{po-9zmYkrv>|7+vp*60)ZgEG%XxjYl7~=eH z^p~8eRTZ`rIa=9c%g%pu)&H>54~%hkY+8jq(Z)7yJctM-}RAr_~PfkxlCe*Cw;?N>Z`Wjcy){NX%pLyjeno9zD3_^eaFTQh;L_A zRh5nH4Ez0-Eic*l!?9*EXwVOAbZU(s@dLEq``bQy_m&3xnMJ>`<1+`@f1LPbd(KrS z*>_!OwX682pJ6}u_}%uq@4R8ppFiK0I7WqodGqGk(yz@hk&hAmS@b$v^f~*+8*h|0 zEU_iWg)RC*4nOS4PfaGjH$^?k=Xa<{&T`LHcJhw@?RX~rtHhX} zZ0i_v+V$YICp(YLy~ug3aixv#Dt2VSce6S^EHMz|g=kCt<(?e=;Xh)Vv_)sIvu%J5 zcBT!C>Ee9pqkjnQ-q~rty0OlF{_)@0OXgi_M{YgM{!8K}``x|UZOPGKi+!&kM#QdT zGghffTZ+kl@ck7G(FQ$VZiXd;FJUWzw_-bnscQSNI>&zW(LWB@idOP0$@^^MyMqs+ z%&l#B2YiP5l8>h~{V!v>8U2t68b8Kk*y+UbMf|I zN!hQnSQ7bQjEBscj;2F1T2O!5m2Cs^P_2W2L+qgN2YH{(J6ZSD^>M2|bOSG0+Nn0O zHlg{a=nuBg0G)w0*fO5mG#&sEf7v!D84li{1F}8a1~su9y+uXKY|^u&Ea2i+9>&_`yagn z8qkL3bWmfu)qE*Kh0=6rY5$A=tu1TLx&D{j`LHPCsN7i;#{qc8^SWg@M zTH{Az-0at1e?#f7SvnjQEJ^?8Fo8}W{#l}LhHc6FVAJ1X^HVzXqmMq8)1lF;C5M}R z>#euu#xLtc;?F@Fpo1HhkPn)-7L##WKDc5DzAE}6`YFi@Me({ zY3H7M?o~V!x}bM3R=028k;4ybTH@UMG zO`Cja_!%&6Z@cX_ZA-Mlm*~-oSAuzsADP35PP*I9wxI-;{wDIF{d@@?0=`>P(EXT$ zU3%$%Dj5ZT0q=VJ?%b*NzMu^%HrfSCIXRujms*7-v9D1d-S-L`&;ec}zKS+FMz+}O zp@N=-?$3H~CRXWP8{3?&f7V7Qy6!HuKI(!c)=t&jzJ>bIVORq9jKM5!bQ^M?FTM0q z=&RP<(SaEU==JEv=u+rtyqk3?vL?2DW>>0pj&Q$CowhSEjh`4?VzVGb{v2C_zO zvmY+=cXS=rO4vseIfveeu90nn((h>lG5xy!#5qZ^n_|5b9SUK|`O{^(vPg$;om4WCncw|ZD@uibT*A2=EAZ@WM|r-=-`5-H{q>q(wAf| zQxG@s7g=v>vEB-nr2aYlz*D728#3`$E?7c7fIX8AEy9wl_cqhtHFmN`rO$}Iq-0)J zUs7{D#yhyn=-y3OLeJ6o!FGqNqaE2c6vL7!r;EwBg7Y|emx&qkT#W~Oys3XFolj$l z`H#kr#CX`0Y#Us$B)SH2x`d2l4%A%6WqD>n{0I$f@!`eJnyr3m-J3a_?*A9XKXAi_ z7ij}@aKjQ~8aZv!p(K{TTkqbz%|18JRsXX`5ITimN6ky&^_&;O624rz{u{)9Q`X09 zX@iQlalw+4l@Be|mlT%BeE^Ttm}k7=S0rt6zAw3u_{?wkn^9+cX3%xSZbTo;y51UP zA7}nRfv=kNCqCf$=U=d;4bXu$D0_BhJSe_o#L?z>tEPiFrgQQ^+u@P-5q@REA zgCE#`lKiFQy2UnueUSR&2T0!;F|xTf|J%R)n~hFK?i*=?;@ukm=p$>_uCudkfDSDl z4=vI8Og*2vZ``;M8?%~|)5kJLp`Nz*_A9-ga|-Pe+mS7D&6Yfvw)jHX*IaXrlFiaT zIs8lAvGHPqSMeGySTf~wOY|k?LCP;UTPKx+4tXV?mG09;a*|5kARFD89Cg$gJzwbM zQ0HmWreQl$c*V|%E`;rgxuM2C_G$68w>f6pPy|a#K4{*GjAJ~QWBM>G5&ujM0MYf; zToAoe>TKidOa4>VS|nD&ZfIyw@gQQCv+=pYxB8#|`JdG|VQwQiWo+^j;#c~oKmAFq zA87ngckvUqvu)^5EFsrVJ@r&u#sHXS-fG`*#~t#%HHya~OGTFv*}oO}sq93IPxLqD zB{C;d>on-q@L2jm)-k|N4nM5j%Q`-7fDUe0GI^_}gCle(iY4@1=2POQE;P@qp_#fj zdc5RiU|m4rXWhDWv_Z*S+5o@7mWTevSZ6Lz+fDrq9|ZBymHG42+F!pImJB)Fj4!!j zNpyO~fa0atinDe;(OdWHJbJnDAQ(Y!ZnE7Mv1^E|%gJBrzH;R%JKKg1$C8XebRUJA z?EFW~1D7s+Lh%^QZ#2&lIi_rlZnk@5wI09tgREGwk~TmGH!PWQx+VIOvI$@-7oMW{ z%Fli_Lh%x8X6%=q~)~pPz+0^oGvEg z4#N_BjWL(4t6=H7%Kl``fpfo6f7TiCO=SLvzGl`xJ05cNe?`_`==&$1TyAIE(BW8O zd?UB0Td4wX{rS(YK)xzFHS$<|)NS-{$zRSqN7+eaEa&ipk8yqdGTHzg+^|GE8gkmC zgE6L?$%kfq>F&GlHf;`Oe=GeB+90=n^rIiKzNqG6w~CF8cp-knW-hW#`O{&SyZPpu zbMkAM_(?zUM7^|gnaDcThGJMUd210FSC}t}9D{!s!n>+Jb!V-KwNYXM`biF`EUgON z(`^0j$tRcDOO`AZnWoxs#IS_i(z=d`BQPU=%1Zwd9nR*n`Fo*rbN#NNVFiB5HgquY z17CXTsf=7e#%bAxzJ$)#6xZ5(?tm{EHi2#1m`iV$_?w*yOXNbp{(xTtad;HbD~Ut3 z@vkLT$^6ajeERh1IsVTW{{OKE|8Ef5l>d%l58$U&DP^FPoS#;A`H=S~ex2K-yml;# zVEs9<+bEp~dy3ZSY}-~gi;w>CfwQ~uDQ9W8*131e0H^w*&pOx0J}HID{p#Nbq_d8>K<47CJUcZ&qqf5f7i5hCJq7;2+(EzpgZJNa zUfsORdG!9_4*NW~?E{hjo9|cOab8|ur{*8bf#Em${X%NZ<5k;}y`ZKzMKG*L@ z=VZ>%nmRD|VZ6{!^cQv))W1aEF`*-eqMa8UlL>< z8AKnu)q(djkI1Y~w7m|jX_|en&+%o}GOJKO@P5`dS!ZZZ9nfj?J2^7OIO0pp`?0N~ zXR+pC%B;-$Usks1_SAv(UEW7*JM$;zxzvF<8FoQECfV~0zPo(+awRu;Kl^-T=6x@; zsUOIvjV$FI;@7Es5{MUq2cvW1Z%y6My~wGI&jLA@klXtG%s<;&2W(*QHQq-(h}C4i zFE$FrbKw7s1?=$HTk)?X2M~S4`^7%2;^Nv`2VxT@Oqd`(K8s{M#xL{Xor=fcD-XYC zjh(ilXW;XLe_dhDiJhat|9KBur3RC9f@NtesKzftg+ zu}`+84#-aEj9!f$8~uk|O#1!g9;6Qn)q(f3zMrv8w7m}KHM~!3RHpA_t`5uz;Coqn zVQ!wK-!C?jcGbZx29vP~kD;AllKfh%m5`&J_p=To_9g5zZLWjZ4;AippX;NnkI1-M ztHvdV>c2Btdq)%0_2`RU0{jqFKEslDP$NpD8nZzDcQuSPswL*12^BeRo zcmd-OdCWd|``+BC?u9S1ws?ias+#xXv&8$+>)|i?&p^IXM|dn_9A2XD2aoVZ?q^=| z_S>bO!5mV{67hLdc~rO`zar)crJk{P@nR+Om}}q*%sAkFd?lD`xjlnE(Q7y27b5(k zR_V*!&w3y_s@pU4zPCI>`~sE!h2F{i;0OC{v1g!{GAE_)c(>W7+z+3}pQP9`&|i?h z*a65d&zJ>w$R+Ma{;`H#>>0>PY$CiHodI11Il^b|r`>DTJX`b`vu53?ayu`TJXP>l zVwI8etg~}J^DN|Sv1h=Kc^CE@aDxxN#wqv1XTVmmXP`fR<}=;2A6u^8@Ov+8M%^}IU%O!&_* zYn)YMjj|?K=Sum7e41d5vCfoVelFK^<+_SX<(o;?Xm!;nb*KLCbCy-b`8gH;E^p%R zb~)aze^$p&Srt_$S_`cAtj}5XCkW7-TI&*d;wWppyzLkAzDjw>xz=~oTd$Gt#>=mj z*3Z;cS6eq&*UP^#a@}b8f3(#{e!I$=BDJnmb+5FpRyC`%s->1U$Q4uM8=gR0Zp^-C zw0zdjo~+u|RLK*p+OAgBH?99|`K@l&3RTD3ntrxUuqwJ+RVP^g)B4!@v^<$M+-{vN zPb}VhQ{>&%^6smx>*S6}a_#BH6EmkLRDDX`*-M^Toqgudtn;$%pCI?rYN*ik_ur(y zPq2naJ*usV@-=<=Q{zpQa>rCDSF8RRC%r-M@|?-?ZlXXc-@t>O%!&&AdU)`eE( zr+DVC%?m8+zgJZK(5klv2>qVS(vNpmWn0(mV!8H3>wj6j<=SQ0YX>Q++$8U%=ghx~ zs$XZHyF7dCIYQYRRNc+%IIpN$p1rmqd+oW>Qm||OfyWcA<<_^XlcgORkImbY!DB?> zab@;dKajUpTQ^HzX^d3LH#bU+CkYxysb7lWk$Y}X6b8}b$5TpD=h1?a|Uv(t>ynpt9RE5LE1p|oqQT(S)a1{_Rahjky!ICR%K=OlMLq*t?u$a z_l*_3;Uuf-oP8(svn=aUdHa>}|G6@Heqx<(U1a@OKA$iDpC{-1J=x`NvYsgKm$&f_ zef(EB<>eq@9eaU*vFlzI>wnmi6!In!Z*)iIhJ}N^a}}7ama|Jvu?&1U?w4>gXO&yg3wX&R$b#J z6j{O#LEtd?6{$2?>Saq5&w6V9G|_1H1j zkD7e?_2aIdbi?EuuBkcw>Km>i5=j1V0Pnk5X=4SOAQGhB3Od2zBio9ja z=&DKMZX7p$%rC}F&i!cqeC|}awMHs3bj*!o##fH#|Nl63)a3Ig+<3!vV4q`Ll|ja z4b}!{2ImCl1wBEx+Vu=oW@|VwG$dQgv7zeF)KG0`W@t`mUdR)QgcgSCLJgrcq4lB0 z(5}$l(EiZDkQMG4?jG(Lt_=4M_YLnwc(lJIpKL>PdE}@ z7_JL9gx7@Eha1DY!h6H}!w17wq-&&mq-Ufu(mT>OB8^zz#bWGKd53#PddGUJy;Hrt zeSLlXeFJ@K0_y{ffr9}n*frQa*t1|u=Y-_uIVW0uh4pU_?F)SzIw9O6+%G&hJS;pq zToaxVo*NE?7l&7eH--0v4}`l!dPI6f`b7puhDAn4Y9cctb0dMs;>haArpTVifk>BV zk7%!Gzv$rTu;}P$O>{C@j!fWe06+Nd{6v9yi1}-qF16{VsPS; z#N~5maZc6S+ z9!Pdc^+@$f^-B#-4NHwq)ud*m=B5Iv#i`Y)O{qPp1F0_Q9_e1`e(6E!3(_OfZF+lpU;0qm@|rXMks@XM|_GXPRfWXMrc-srRh)Z1?Q* z9P)JYp5pD}9pD}69pN4Co#vhGUEoc4>%D8e+r9g|hrHc*hbj-^V||Kh!_Mf31I#e};dqKj2^NU+v%I-{U{v?-J+{ z=oRP}7#tWD7#*ky%m~btBu|S2s{@+?djbanU4lJ=y@LIMgM-6@qk}cU8Ns>1KyYzz zb#PN~cku1tq2Q-OUkLRI^$QIS4GWD9O$yx-njLyD=&6E=LD37MBckJ@)1tGZ3!;f=eROSfdvss)P_$d@ zlvtnGfY{L3h}ihpwAk#}f>yvAf+mri}hmze=r=Q z-&|k7x7fGZx5>B1cfi-h-^1U_-_JkTKg>VcUz5eeBL7nVTK_ixZb8Kfflmic34Akf zrr_d|z~zDQfm;H%3o?9xSfD=eY~V$~#`}Sf1KomO3Z5$H7!xK9ClE+i;@QO|a6%)5Fut)6X;5 zGt4vEQ{$Q8nd=F77JF8EHhK1V4tTnFdw6?!`*{a@hY40{yfeIWy@6IDTbl_u>&Ln&F}f`#=bTAM`n9vLhw z@+~bWOUC=B`DgnV_!Itm;Tqfh`}~Le-GpcK2@D7f4U7|yYGCU8)WxZ>>FV^&>Dw6JyG~S7=y_sO2jeHJh13B>8 zD*tf*NdH)WwSTI=)<4rf$3M^S@kjg%{dN8Z{~G^#f202!finU_0#$+Gfsui+f$G52 zKy6@VU`}9Oz!QiB76$494S|eaxGS(Xu;0)QD}%j*ZPkb`3ynI$y6;($b0WhdBO_xY z)sd-@+Q`hvoXEV0N0xIIM(QFBku{O^k;cfb$ll2Q$iave?HcVK?HR3%_Kx*5XZHSzWF z#`v!I-uV9b!MK&^n&_VBnW#+kJ`96P5-al1);-xXS()se?3?VL9GD!EtV#|~j!ceC zRwt(>Ym+mRbCUCto@6AsFj<#uNUlk)Pc|lZCHE%xCl4mARM%AZRL|77)Wp=x)ST43 zlqVHY^Qnf^n$-I2tZIMipqg2AS97c0>Avay>4E7X>8kYb^vLvBLHN{kZF**UPI_M2 zla8bprt8uT={4!~>BjV~^xpLT^g-~y|3qtm$T!Q=)zjV6(^Ku4>Z$e2^vv=gVlD7`XYck+vbQ^{`QPM)0iQa2YY<)Le0X$Q!DY zdEPVO4Qhs05ji>1JB!-$qZbQaZ;sv;h0iU_L+VG-3PEYlSf$Kw`)2vwWwBAQYMJHM z$~<>Y7P(7eD`M;OP+J-QM*IxH>Sgg!Ih1npYT47kPNk=}r?02KXP{?@r^++jGtx6Qi>Kdt?(uXy7WVrN`YeA}e?A^s!h20z zbPx0lR0etn`U*M*wwWV;BX~w|Na*6wWm)cePiTJ5rm!{iYUr%+IfvN}B4RgK5?+zD z7)bR8?wtYGi6`sya0_Ra<}`?Gg)*=0%@Re-WP2{UmF#n57FLVdinm zS&lC>^=`9#?;h&eZj0Af!`}!GiBuhRDc+nvR%P|Ud>&b7Bv?mKx>vVQ!#sRswO;18 zX5@9KCQx~j)l23!mgi*8=RK94LfR-6%8t}TGf3?p8h8ZkvIoOGBmD)xQ$^!kpVKz` zCJXbkeC;a3&niWmsx@_`z9-2lPm`{Myc;MI&LeY$DsQdmJXKhM@_%|%q)R1p5-}Q5IvB(|0K z{H}$AXBsN<@9`o-XGAXZ??~x4dRS9Ot}(wf7x`R_FIOPF)ZYolrM5&oz?Vnyq5r@B z_j(DuUIMR|!0RROdI`K<0m~4d3A|ncub068pGx3%7#qk5(o1^FiE@&hEPdn@ zd4s%B`pT(tnw&2Ey$;C2AE|E*+G8rtF%N25^ z43VqkYPm*+%C#~~u9G4umJ%tIGAWk|sgx?Imh0sP87?=sLq zGF~RgM42R$Wr|FdX);}ImKicrX31=sBehZ|x5%w>o6MCrOTEmK2AMC7(j+-qAPZ%Y zG|L^bSXyL>v`U+_%bn68osyR>St`q*f9Om^>~ULH;O*VsljQ%=|R8XjNr`Rte}5zc5qH` zZZIG?FE~HAAQ%{27+e%w91IFB2`&vT3kC<52Ui4F21A0Yf~$jTf}z2+!LZ=EpeQH~ zN`lg$EGQ2ug36#Os1B|VZU}}4HwJGCMg${+QNie7Oi&Yy4aNmG1>=JW!Ng!vFgchK zObw<5(}SCX8Ntk8Rxmr56VwKE!7ah9!EM3ZpgwqWaCXb9#9jX_h83l;XbF}CtwCGR9^4sp1f4-X=n9qw%YyD;d2my3Whm7jVx6z?7 zCf{piOiQkzV{CV0u3b}~+O=dp)MMIO5oLZ{b4za8f(4zq{H(S)qp~UD3)OQ*<=c`F z*_7(`<&nW-+T!o9q^qMN*P3^2q1BVy+S(=lhFEHHExCMd)bt6XJ8}(+r?)k?=0i4m zdR_Q!d_zamvWAYFCz;&PnU9LwL}ZaT@)WBL ziNo(I>RQr1CAXxlW4ZM;#m9CdsaO?$Z)@t(s1);S6e4ukD)W7MM_XgAvy(x>?_rqO zl@c1qjNC#r3ll2*9)^ltDPgUQZH@A5nm8Ke?AG>%#>Kgg+UC}#wq=vs7EXa74GVM7 z>P0XHRhZ9BY3}T7Ze3WDYtOYd?a}kNhXJHs_nEDCiN{8U>k|%d=hL;%P!)T=*t0mjBq+e8+M&ZIoe$ z*4^0Ft|eh@JyrZfP=XmeyMw z$n`+2M~V1e$XsZEb|&b3Y-TUw&y4O8}*rqew>hr;R@vnbcNcxKlU zpFq^s(U=?4(uUTejS@rf(p-3jO=!wMwaReK=5yWo8hw_KcEXkfjGI1NC5CbEibBw_ zFxONwd9pUt=<-I;$VW5gc#Z9DM#@bzbX->}XA9FCIvSQ>Aned&Ct@(D$>D-)ZD5Du zBV&pdTx3b~J?*0-4njws<2u@wOlfFu&o!x8g?-YI#8HIp$jmJ?F3cqu`{>DSjj^dw zspI14K#!q4B1AJVGUjtL^Bvmh!aZ{l2J~o_;{hf)GvCmW?`qep%!+7Mu4749Fj3xT zw{~^rn*3RUj%=M;rsEr0n_AF*w0Yptg0+hc>g>U*HsxpRH=!aA?ZtB)=oB*|%<_w4 zj6J7ejC3qX`Az9U`^5MeW&q`8TDEbU{xZ(Z!f4nh9w-_^ddMj~Atf z-562+Y7?gmaV@I-@IVfiw70cjmKAj}G=D;CC+7FK>&UXBfG4i*bXd>Q37uggk&o7g z8lqRh(p*+r#wXIp#p_`=&odhqFd2zF}HsWbDbW zP!u|ehBc-~x6M%xG)B)OyvfFG5#}yd02Imu+;%064+cgooheW^^C2o=B>F$xg&RZN zkhWjJ!iYtYLAK$xryIN8teXbu+pJTM78G67Em~zU6;~3bQOELhQ!_(-b|}{`U8Ker zx#L}nWl74z3d6Z`q{C2Wm2g}(dZS<@=Eg3PJ3P6rrkE}|jzHbhGOmAzClSoZwdi~< zmwnx&?#v=%0B5%@Zf#rE8n#H>{Gl9pwTR|2av&9T>2g-`O-m%AI%SO=_}Yn8m*`%~ zOa?~hxV*pxu_g#~(tzlbZyHMH&^KWn4pzSD}v_q5_lkB)JSX5h=R*7aeA&2@)mT%DaHp;85KQ%A%6#LM&vae5h^ zcEoyNB{|X>jWU`|tqevCB6ANF~sxkZ=qQN>* zZ`uN*3nv2^Sr?WoI^ugh4XA|jY%gO2Rem@-PP66{#i(Ps8f3+sEl9u(XBBlwdfF(wL2Po#=Z&}r%{Lg$ug0Ox;pc1OTwF2jf6vui&9bYdHz1PeA_N<;i6L^@-lj&v7`)j-$c?Bb*NDNUL!T6w z_+s3#ygkZOip9l|qBGlbjd+|9Mlz#eneo*dzbrPkyP~WRk8+ZVBu>?#nc@hBT_f@s zW+sOvzI+=J&b4cIj4y3i{?rNLtjRM+LkzWP+s=GlaSz3~6h^a5~0DNk)dbj0u=QMWypY>(ay$#WolPouN1Sk&c{6XA$zD z>)`k&kMUMV&{k#ve1ze2xG~>3DUGq2A5Uv-Sw5ll4lIu4nv7Rx91<6lULU4A zLl0p5ZEr(TW+ITGsnpCJ!;G%hR-K&FvQ#Kz!l+hE#5rx}O1aVHIi3}W4?b-B@+ zb<)_v37zrd=m~g=)ZA)RmVbd@2G7jnQAucX9AKajL(mfZ2~);Y&t$aMz$HO zAK5H?ZX(+Pb_Q7;K0i*j73@s1x%m79**37V$mZemlVsb$`ja)`b2Hfvu(Qb);qy~u zJHgH&Yr*HI$##LAOV*Ch&yei~8$g!F=N7U(VCRu_;TwBWNYyGG}%Eg{k2aoyxS%64A~*DL1gRjxsB{F z*d=7^@%crvBVd=3ZNTT3$X*4zjBF!5zf5)%Oxs&8ycZ_2olG0mU{{cB z#^+bb`hZb>0s4luj2EEWV67oCp(JI=gI28ZXm;plJX<6xnRS|dc(b! zY#!K+WPRX%fvgGaO=NxH{xR7iun}ba;C_*;1#Bc)f4KLNwS$c!8vyrD$ns#L$p*sx zQ?hQbF=T__eu-=aSPj`=xc8H-1RF~>1n!@atpXcIHWcokldT53iL40jUy!W<8&6gS z_se8!!6uMZ!Tn3Jbzl?8hQs|Uvh`q-$VS5bYqAYslgVn}K0vk+Yzom_sH{sY-IF#Wk;FPR7T zAIY|Z%_3`p`w-akY$@3xu+zxK zgDoS|c6K`1WUy{BZ7coArh_df)A~MxY!=vEWLjrulGTB|g-px+EV8*^E6B9$`jgEA zdn=jd|7@}*u)E1L59g3A0=tJy?KqdL1#Bgm#x;Pf9qesn>OPMw5B7GlfpDKs)(v(q z*&w(tAX@>pifl04s_i8!!R{j)0{4YvtH9ntHWcoQ$X0{hPgVr?#bj&1R+E*%t?6L) z0QLY`72KDQtpj_IY&hJPlC1}Oh-@U>myvA%TSHa@x7yfCHiEsAY&_hTlRXLcFxh0d zuOQn5_AavNa9>Hb8Eh@tEVwm)y<`j6yUFU{zKU!s*n7z4!hJQ_Hn2y?=D~dp*>nKS!L9Y#OAdp5h-^LF)nrG&K1{X&?(4~31^WouM!0VvI|}wB*^_W_ZYH)V4KNy!d*i)2<%g2yWk#6HW=*FWV_)WM>YiPGh}<U|%3R2=^4S8nCCy z4#7Q@Y&_UAWQXCNMm8C28`%-Kr;|+w`y$z^aNkTe3+zi|N8z49RtNTFGOfg!WOKo` zll2ChMK%xYD`b7ZW|K96eU+>)*c`G&U|%Ea2Ubhg0=9#!KUf`EJJ_>i1Hf(}%Y%KL zY#`XJWZhujAR7dB8`%o5on(W-=8~-hdyZ@f*qg~#fqj!~DA?^}tHHiSRs>d0wgzk$ zneN9hk8Ca2x5=u&8pzgxeTQr~*nG0}VBaMh3D!uq0c(E7>lv7s=Ye+Q@c;?IX*BwUg}u`w3Y$*qvm1!G21% z0<42YK*{fi`Cff-17P6yY2gsfTTS2A^BflZr1ol?4-eA8a z+YEL$Ss$?9k!=CHhpaEyL9(r2E6MtS{hn+a*xShZgZ+VQJJ{RF27vvMYzNrAWCOtt zk?jOqMK%cRPh`8m?jsuv_Ghx)VDBIs0`?cOJz)2f4Fx+)wij$QSrOP@$@YOgKvo9! zH?sX;50X`Z{hjP(u!qQogB>9|0Jer~B-lU54uZXttOo2AvO{1GlZ^-aC)r`Jcacp7 zdzI`6*jlpbVE-a}73|$)v%vmMb`9>2=*9RH&`#SL12%Q ztpMvyHW+LJ*-Eez$%cSELADC)B(kAkA0S%|b~0HJ*aykhfb}6O1KUWp7VH$VDzFcc ztpj@l*>JEAldT7PBiTr>kC1Hu>q}Mx_9WRxuv5v#gFQv|B-m+Wlfgbpwh8QXvgu$S zBijttk8Bp$CbBJHXOPu_eVlA7*qLN=!9GE@4eTtkd0?L;+YZ*BtO;y0*$%L?$rgcq zifkv?Ib_W2DU|%3R0Co}C8nCCy4uV}wwifIevO{2l$ku^vBRdRs3E6tE zFOnSryOeAL*q6v&1-p!FBiNV8j)Dy)dlGCrnJxlfPPPf`D`dUFt{~eC_EoYzU{{iD z0s9(RU$7x$Tfuga^#i+#Y#Z3KWc|UeCfg47b+Q3q*O2W1`v%!Su%To-!FG}j0=t%M z7ua)TgTaQ8?FRcM*$}Yn$o7DJi)<)Z5!qg_U1UXI#bo=yzD-sJRzkKP>^o#tV5MX) zgMF85I9M6k0kGX=4-Z$;N|Kk{t&70oi1*DzYPBd&s7PRg=96 z_CvB+VAqo!1$&;X4(tXpeSGjEvbkWx$$EqBC7TC!BUvA?7s#5x-bB_H?8jt_z($bu z1ACFI1#Bc)f3SUI?O>zG27vv9EDtuCY#`WA$-2SDkPQNRiEIT}4cTC@{bVb_#*z&I z`x)6PuyJHV!G2D*8tf*rBCubOtpOWPRtEMm*;=p(WL03lBwGhIk!(2FugKPeO(Gi! z_G_{YV3Wyezz&dY1e-!O9_%+{Pl8P)n+*0_vQ1#q$fkq+j%+j7bh24s2g$a8-Aq;o z_It9eU^B?(g8hMP8`w;;d0>Ae+YUC1tO@K8*$%MTWQ)N5M79%b4p|G>pUHNC)snS? z{e^5dSRGj&>@e9Luv^Hw!Tw6N7wlHD6<~iO+Xr?V*-Eg#lkEqaOSTH^2-(YEZzfv} z_7AcHV7HU40egk)AXq)wTCjhT9Riz2whru7vcq5vWb48HMRo*iKG_Daf0Mlm)=0Jy z>_22j!J5dP1UpKm54>_@o521{)*EaA*=DfU$ohaSB-;Y^KeE1Hi^#TuVVZ#d`hhi* zZ37F)`h(p;wjJyQvH@U=$##JCA{z+SLbemEH`yStC1kt6P9z%))=IV;>?E=wU~Oc3 zz)mI`3f4}x7pxCi5!jt%`@l{iD+B8w+Yj~zvMR7nvX{Z$NH!cSPj&#TFWE@2F0zAQ zr;^oxEhReyb{g4uuw`V2!A>We4AxC{1gsy~bg<=QuY#RHHVf=7vZG*UlGTB|g-lMu zOo41J*b1`VVExJFfxVTi57^mcO<;GE^#wbJY!TQ!Wc|R-C2Ij&N!A~109iZO+sFoh zokx}jdpp@cu=B~f!R{p+1a<-03b0jVgTV%ptpvM|YzWweWUIj5K{gcZBC^$B_mdTY zT}-wHY&BUK*dVgCU=NU0fn7qj4(vg);b51Ntp|IEY$VuaWE;TNkkx<o-jwgv3nWOZOyk!=Ng57}I>tI4*3Jwi4Q z>>9G|VC%@5z=o3T0DCXlBCu=8c7nZ+tOaZs*)Fh0$=boLBijwOo-7YmM79U){bb!> z#bkTI9wS=;rh7W#=^@zTWGlf+$@YV7Aj2@tyQ~%C^{G&B2AneH`nmcJ3Ex=loNMjb zFn1>3rc5Ec0W}vdvgR5(b2cBA>u$$m)8S{Fj0kmU!Te!fCvCXmrZhKpv~{*E$PXGa zbI? ztD$Ak%zRf&^k&R;K~v6 z#So&;p)h<$m%kyNN;@IA1OhYwTfk`QRZ(AC1j!YUXnl=HZ=qr0nM7e-F?4EFAL{Ts zExveWa$Bcq)lV(rFP7^dyb3}rWgx;t$V63HUu#P*gH&6`h^%cn)PlM?Q`8t5A=k;#?uOFow&8c1|h)dCP2LJ zhbh*mdbFkWa};j$1p(C<44ABTDqLcFqFL*{V{F=j=p^mw%0*K8oj@#M6Hz*JxF$89FzSS}%(y2|_jmvH_X0u&CL{HA1b# z^9m^K(p0Us;`1}Lwh}_Uv@S40d)JdB8+vIC^aYV|n%F={E~F&h8O16xjo_llH~hVf zdZTgZm7NTGHRMJhBuL`!!NW$-LEp1Ow(hSq577k8T+ z%@79_q+NkfB}pjrN^i#2IdLJ>m2K-oJ5#W@T!rybjk43M#dP;6O^8gwnBZ}O$#&vwmk&rAr~ ze+}d#Y`ME_kkMkI61J9+J&B{Mm6d}4T9u=E4q!KB4Tew`A=GF)RQOXqmI@k(_7h`l z|J2X(RHZWu?aFFw72a6q&x}nO@Hf|yRy+BzwpJS(lS55M!;lu$I9sH@IWdv(jega0 z-l=)eYPhKfv7K$mwTHxA4f>$4g39`UwXaiRhhA~oE@t{7yY;9{uZUTe zEPSWlic7l&9XV(Fs#IjEyAZlLs>5ArOB_d?UI)6hlinZHM&8yHUl(uw^e7Z{M$y_d za>QW$!PH2Eo>M=op>y$=ww4yNNz2G4vzyIG+#)q{U%|%ZBPlE{DIJ;Zd-K>)+9YOA z#xDe>;?94hN=J<8CJG)!rQYnP0A^5}c$rXIh81J1Qq7>a>#TBi(GqBi^et)SG#28{)Ami0?T4ssD4&7`)qxQ@hrFQ575~9@ZzdKgP`?aY;vlV7d z%V2q=GTV&m7#r@s7Ku^!+Q-}#3eE2j&CYJjxh`MS6%~y~vbqfPmQa`axo;R(4dPPM zR%B_IWyDoq3zeGo)<~6iH-@uJ)9CIFh0#ym@N+QddcnriXWSF2j#BCXlwWx4VH%QJa+GRMegmXNA-W(0y4UlOKw5_BWBsDpAqBqfm%&r@P2T-6s;}X&-aH z6(sJzO&KIJbQS9Wv^p&|vT!domYC)vj9m2(Wa;(Ci7Hm9k+ZMSd$I=$>7&MK2he%t zL+JooIM)7pmPtrR?+WyOXibk{Oj|MeKp+lC+MM5+4izr;Oz=15i^^D&t46?wk2j#z z5D-+yk#|`^?Vb9VFD_%6)~ub?+5%dWAG2(4)H+zaJEb=DsD)=@W}AWy+AF-rDASt& zCIyRb7(yK<9-+|M95A+$mx6ZG>nJI>Wndg2T#V6+^u2Bn>&LONzK#uOH01B=L7wc5 z7YCd@e!|q5vqnuFGq%2dq|Q(EvU@a+!`yCRueGd1LnF29*E=Dy*}#M3S6?fL!Z5=q2?~SwvZ*gt{%7b_+4;%uR|w*u4HY90~FZhFfPKHXeCSA`V+?r zmJG%kESemsi68KTW)>p{J}vYQCIS5Y6l3#rz}HIM7^}?|0LQM>4>=(+tzpB{O8szQ z_3>1yPB1?bN0Hv4G06*4)4V@fKpGXVR{!|8SA8l`XK(VTDMXVLz34uAtNM4uqF^M+ zCTw~UeKMtuH<45oyMJw<^^;22!RbK0Ia_baA`VepKeeQOQfcX=NhKvZHPq$JPZbIo zcllcS=4o#I)YAG%Wo45Pg$CEQ`|0f9PT@-bHQ{9%SvaZ$| zwNEd-FBVYRdC{taT${$1Y`N|OrF$=>ckQGtxK9Z~d^saTY9~UYx6;_|hR_`t3#Or? z$5-4C$u*dfRD6+t)efd}QL}%j8f4lYvY;L1*Rpk{IE_+^Q!Uw%Ew#4bjAD;d&{}xb z50=_?(<;;9kbnIcawj>nRXek-Gpuj8q3zvDH6>jRP~pxjVYGXxEqu-q+Pj$=(-EVV zL{qer$({myYp-3jR8Dy_oV( z?KewrS+o@2UwpWz)9ylIx#6$Z9vL zg|)v2xt%&E^$4RA`k&chqU|mH?td!FLsxWvZU@MI{H9~+FC3Y@F)p*n2z4^}GL^dX zZMapgdg~RT%}8G-)9+!`{nFJkTcOyzd={$pUiVkAS~pU&qvbS5JL_MkB+1yMX~!vR zAAGX~h#KLIp zLa)a^Wom6>BemN5XH|PU2Wrfm+#`Lh*S}<{jIq?|HKUjJVG5)DhjprHZ9uHCMw3mo z^shaMX>g?0tM_jyHD*dq%wef(WUDu8jN0&frvjvRq>l4yIw_6+#2(~H;h}feY-zW5 zQaXS+q>FZ-U(}_JlhXo!&+6C;y;VkTYf7}^x&cA^94lyIQ5d$qmVtF_JS7!4^K~07 zpEsms&OX=1Hk77zQ96ZuV~=vHZE(`1llH#H2$AH$tY#n~oe!Uy3Z}bxCe@st?;z`1 z8T!EGv||Ob4CKND!tvGVR5*K@7UjENN@4HQom8LJ9o~RNoH_y0_xf=)ge}z$k>pt0 zs=f^v*?(p#OcdDc5zC)TMD@XWh*==fS~)8fE@OM|*huZ*)w=%23XvGePC~n#vrQOh zoA5YluG#Co?Kz3g+B`hbA=BykwH6$g9^Zt}=VpdZ%+WIQf`{*q>L5BG39mEcaGXn} zZW7bhe_p0Iomd#RUQ_2sa(6Rx6TMcWc4QYMvas%w7uZ#!v!Q{B#``%1Bs%TVUrVC} z=`QJ^Br%MYq9*Cjry=6*=t(BgFXKOylnyUC6zDIiBbj{>=u0$d`AntotI_n>`0;1;eBwV%-)?{W7eh;JuuKle|gVAOu1-x zf^a%b(SGQPp2N^Ea~X$$^vU0q=|I_=w8WWh=E4)(idG zbkNk+^|8%SH4aOOwPVm*0jvaJ4`2T14ExzL5El%PH66P2XY{yejG)ja_i-p*lG>>h zX|MuY-^YfT-*)K?qBt#2zss%}Eunymn_2T+Qzx2HeF?BM6kE|m%~`vPvc%h}9?a4> zqOdh+EaizT+;(3LubYTOwDYP6z1>%>rkaHfo%mMzk|;sFP>fJ}rmD2C!0T3ew^bb} z?VbE-SCm8THLnj<@sE?j?fs1q8Boy;p(wrIzmaex(zTo6ktjX_fCBpK4TD6FQiE@DLfCeM`O;D!AIiL!q&TRAnV*m)VuWT$fJ__GM9SjR6igw9dDg<2 zME|^V#DdCH6biK`n4Bpz*;HAaQJsZMNyOUM@x3S}9Y(0PJ5$pdtPAjxZsm*grrGGV zg?=Ad(HXYx>@XrZltDXEjnh0~GYw6n*DxjcU^CGtq0{|vse)$&UPv|Z=5)y9l@q9I z)VMelOw@_N3_n0BDJO_t$urYI%p2oLzQTgQLs}%E^X*w#dOML+2%Z1TPC`USQ6%x> zw=Mc^p4RXjUuVawc{XBQ2dqttO$QN2ibfNkYYJz1jt7(P;*6DVWjK-#od zq@vS8-GL)3h@QTY3Z|uxF!~@{cjzb-CaEyJ$3!5`474rJD;O$CheL)YqXp1VFo2ba znN{g8Bz3|%zd#TxKwJVeOlzev36wq!ghh-FSAROCMXW!(YcgVUN(cqWqYgysnTtI2 zmc{lw51tE*XLy>3$upKobV{*My;28?81JymwM$;)Ns>GhoWWco{16{3e_-P185rU1p+vUu$xB^9airQgP8kOJpn_HSV>ZVOozIT zOqm@oggSb4riAGgAH6zsLYVh8PE0!bcEzgr;1**RTAmJR*e(L4Q}84gYO#=My7aJ+ z^wwor&*8!f zlT(u`t#7TBw>SZeCVIt1TQ$l`ubCB@Lg!~+TnN%(Qn#ClOSZrw z_D%ZW86#JVxagsqj<#=42QbBH ze&>>80Cs30-J7MgkGDyMP|H`@A)GUBjF`75dWGEQNmD;LN3Cl0zr#~mjf79rV5{cq zep_fxzex_uv69vfVYRPy)7Jj_0biDpxGpq2Xe)6)q7)u>ACHrFOz=A0ipbtJCs=iQ;EwKIMEk4p8*(zGDedBJ-MNZHMX zS`NKBK0l)3^l3p%oh?Xnt_H4Ck#%lRtf(<>pK7apucNU$b)z~Ls`o(^9WfN2Idl#@ z9<@B8vxoHgWnwNvi_7WcFZt4yiSDQ|Lfg>QkxSsem63X)+_2`Rwxy5D|L}ONmki4_;WuPzgt4=i zbl#<}%wXrRei7+d*uGT#hs2tWg+{gNq(rj}Zzy3Oz`hX~j5imGs>`M1+!QG)mW$$; zsVORvp$;jP;SMR2DGn)@xelq2g$}8dPKQ*<+Z|FZ52s0Skv#5@V%g%568WY>O6BJc zDU%}(DVM%yq)MZ>LIyabQZ9E$6}Fs8hpLuwX;M-oGaOPZ3mj4+?G7oG2OLr+k2|DX zKI4!I+3Ao_>g%Rkekv`9`kGnKE>VmZwrB{I+W{LLX%(&y}y%@x%$I87>xq}U zlg~J$T)yg%3i-Z6D&Mq*{KFCe=mqTZa_OzZ_B`r>4i9>QXt+A!Ty8Ln>sl zLn>vSL#m|9A=Pq!iWCPCWn+sokPmy4u@38N{3X+BMzyOXB<*3&!-7Sy+1po zSWZ4am5b66xy&J@GSVSsGS?yH((RB6S?7>S+3b)idDbD-@?x4`)cdPLily%bDVxhm zq}U;)QtOa1S?rKNwP107N>MGmQuu@0$}CWlnX+Z<9Y8`A`% z-cE-U%Zm;vkwXrF&4W@lSC`2Z4k?!@4ylj@4ylxT98x8ZI;2`YnIa_^2cLCFvFvq7 ziTuqWrE=OOw#_9)Wm4*pa+&Us3TbgjrL1;Hm3+h@)v_Z^Fb@9IA;t2FLrSFor6~)G zOXXUJl*xF9l*?>~z-EV3$|{GTJv#*LIZZGQKIag$XNQ!?QHPYu8JDGUQBo#XIiy@F z98w`Q4ylx>4ylq`9a1d|(*)ySheL|x9*303BMvE*Cmd2Hn;cRuUvWr<>~%<`{MI2= z@-K%}%Nqx$$_L}%#SX!pltW5nhC@o_4u_Po)GQ=U3GTI?ka=SySL(1hPhg8U)9a1SL3`^y` zqDszjNVQy(CKv~AbV#vGcSwoUJET~=_{9B@dLyylQm5=eQyo$& zjSeZ34u_P>-43acha6HV8)AY9h4j{s@b3ivJ1BDEUqfmiR>F=+6*+^*Q=8L|P%g%p|`+avou@*j^3 zJk7PR+#|C*veY9Fd*rhodBG#U_sD6dyY>`$WR6Gf^vGI|eAXlTJkqP5oBAM+jPpp7 zNAB~;QyzKNBfs#7oZ;GYkw>O^3T$ZH-c!uuxCpK0^AdgMNje8MBod*t69 zxeV`;M1Ll&X&!m2M?US5UwTB}Ns0bU%-48iibq;K@_jsb1d*ptPe9y+?m0tt&iI z=&WdgKL<{Ldp-;kkPBXY8r-NVi8G_sDlV@>h>siRaXG#x+3t~FdE~zyx#$v!|4eC&^2qHT zS?ZBTJhIs%-}1qyY^h-k%=C;(<6_0Ws?>utSRc>0B zdgMlr-0G3#9(mj&U-8HcunIgk9z zBPR}X?J4uf%^vCW$a_8VIgk9%BY*SAdDpr2jPb~PkKE&t4|wEhkG$xSqaGPh?YO5L<3d8FGTPk7{W9{H9>e(I5bc;w77*Pb$u-0G3Hd*msPeAgqdc;w=8H}#1g zY4*s29{H$8c6wyLNBUN{sgLl;e2+Zrk!L)z&m*sSWJsl(`Yey!>yeLo;-vk|Z_PtrZcC*SE_1!qn)EM!}Yc0(9p z)MIe1=5te;J3FzRTTKq<-!RQJ~5rY>PVqht__N8GVvMI}e)h~U~b zHgzot+kLLHwmHAZ+9;TH9v5?Xy1SVIn6uuK`Y>^&B;n~WwlcIYl#SLcp}a%r&2c#K zVe+mhx+++>%s_$I#&+9HOXarOIXx>*E^~kI*jGcc!B+C%t7wq z6>3b*lx7_GjuJ>qO-FJ(ks9Uk#EH^1GG`y9u;S7NOz1RP6TP+hqA8+mv6gJ^7+SOG z;qm0mC=28ad*~WF2o$zhfP1pCPh~NxL&nc{SsRE52Oyf*^CJ!3e=4RBT@-#>7AKxO#-_ z9^KKlIM*7Ty<*h`_nZqY@>EVbk>%Yz980f>rM>M)^yCDH7T(vs;pz#BiZpD$KI3P>I-0lcCc($ zCfSZSg=F_dPC=66*S)w^nSJbfBt>bP{>mhh%*5=JAu`?tj#;-NGdlNNzGz7%%t;)d z>Y~P@b7bx?te0dWjI&@6C(0bo;wfQ4t*O&kZ0>FobvRi+#_{QvDTM=A6=zxB({brh zw6@0Bt9NC38_JO^w01(L`J#nkZWXv>VAAUOSo9I&3m%6)LQn1P45zg{A4Z*$TDuFz z_bujV@j|lWIeyxNHM7v;F~%s5Ws9deep9rS_I#|lF&VmJ9cONY$9;@>kMd+N;fjx5 zHEai3mvIW2#lmCD!?=%eT)9!1t#^;7GK?}aRkIYqrsk=RzcP9}j@($AmPEy*6>AEL5kHN`S(gcn< z5Tn11jt7s`?!rb?tX#)0bR2jRI(=xk-L&xqQr zz(r+(4jH!EbC5#*rdUjCNflfYMNelz$C)Z-5GLPT31*nM$SbFZ(o`gLBt{=ztNMcG&ACCEg9!nh&sK1kEEq+r4PIS1v?)g}4 z+kRV|Q4u{S5aq0g%*XMEnNVp#%X>IB+qQXfkH=-(%3~dqovpPiBeMX^Z4E9KYdO0> z6Lh6vkHV|kZ3jk+f{IpDO`I?xea@a!->G0${MtHFJx9FMWKIEzGmpu%)nv4W%%idN zRj6y1rmOG|0f?h=M0Ve3TkRZc9S2ul_&DoAGCP&{abDD`MTa-~-JdyEIgYfza&{CC zyt9w19-+mGO5-Y#)x0sDC(np%4b2U&0rT))9V{M=Df3urlZbkm3J!xO$5GpYbOMeM z8iy-j+S$iWk1%&yqce}24n2|ixY2}9GfgOX*mV=Or_LUZl}3!dZ`h{!q!N#FP5;^% zEoBxwMjCNB8rzuoPO!&gc>F`9jWO)%dHtHlRm}~pIwf%qbB-q^g+w&SS7E?&Vv6cp zYbuT`ElV{FHm8C@yZ(Dp+B&lg5J#z<&eB}g8xtJ5V;wG=Op)nfG&{#Q<~hUPu0|6> z&&N6=ibRlVOv!Q1$2!J2?VnhX9N!E@_OZ>zBb6?mmxe19GqR3p##x7Win|c2^+{_p z$1~eLG(sCt@U^wCMUyqM%GY?69B^8fMJV_4vXN|M#$N>9UBC}x?)gwx57>G+l>)<6}$JmZPd zk?T~z)Tj2Wc>bI8o8cq#IAcq5VVNgyXIXyUQ{N=k&?`weD$JgaEk>!(+ira6Er(=mV4#(e)B#Pnqjv;1b*;12FTwn1NK@-l_(g1B5e1Vi>X(B$p z!np$=CrBd$fQs_&CQ2XNR&a z>M5bZ#|J0z>V>9HRB_u9<-$ES_*i0Nju}0*ba`wX==@QyT||PNwn@G@9@}P$193hV+`;7lCXsyd#j@0@xGcs{3@+` ztgm{S*V5)RbTsR$Kia~OGOuy<%s9qZ0~LCcR-Y5wMd<7798#^N#~u;U`dy_}?y+YS zg$7UNrU>5i@w{qx^zb^lkiug&ZO56i$Pax``4`FVW&t{qQG7Nway zKew#4)3fYNJ)maAsl~iPoG06iz;u1|&OTN*Je$*cJ6I#t491ys&)YR-tG8u1MS9J9 z$LEGAs2^^Kcu8a*n`;TR1F@=$6&~7@9GC0pQw4U+5XmD)#Ooc8YelWXRMgPNrm$e+ ztoL{vt`()x*^!zSJ;@xL8!8JPf9v?$@n~MmS+8fI=;I}N-LVbw7+V~^R)ac<%N~7YbQ~@6Ai*r!$nAotuxj<(h_Zlam>vSgS=r!MXC^9&QpHJl)yYjhdtu4zZ z@a)rElku|NU5>OEbF>RLFPdQZHJt6xyn$#5&DZFWrB<=N7Ul^eyHue6n>q_~Y}TV^ zbhWl(z)eSpi;=YxDUW?@Yn-;pX8MR%tLcWvwI=d{$Fy3K_-9!Y@G5w7tFhHwpmw$= zbQ+(GV_B`pjHcjmtg*82F|27xYSq9thY{GeY7N-MiaU<3C3=5uL}8OKvs;65dRGEX z!8D9_Pl;fn7IkT8Q^z<~HO^V|dSK>ps^LMUco!|#h<6y9nmh1sxCRzpEzBklTRo2B zQ^WY6v?4p^v8fryrG_Z;m{j#U#__0G5_UV`c#00uq%355JV(Y|5- literal 0 HcmV?d00001 diff --git a/x64/Release/TitanEngine.lib b/x64/Release/TitanEngine.lib new file mode 100644 index 0000000000000000000000000000000000000000..16d0a9f49e800c2d80a9fec36b3353f1df84f60b GIT binary patch literal 129000 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 literal 0 HcmV?d00001

@_uqZ`C^hId*vtOm*fvf9%NDERuole6`sT|n<{$K7#gdX zPUGkv=WvCUHf0OtK;8(};sE(0zzf1I! zsk5kas`IOhs>`ZtsT-<&)dNUQ%~P*c2a()~B3boHonG^+rhrDFsi>)?X{hO@8K@bd znWC9Pn(S815sim7vo@DDzg9s~wjR;8hjy@bl-5tXm_}%*_JTH=q;5vtk2F>blFnE| z*HSl8w_g{ndqR5Sw|b4fn7*t&M$hya4RX@6+8cZg3k_!sdSgdpH={q%OE6|9IyEzO zB0jjlw9OQ5x@$^n9%cTAM&)s$M<&bnmQt2(mT*fJYc^{&lFxIjfh3<(+P<;nv6ZAA z?`Rup`v?7e+(TB5`Z<@ph`gA*s=N{D6w^r;+A2RIzbB8C7gDH58>&J*+g{OAF-CDw zaaSQzexv+FSzK9H*;(03>8D(y+@!p%e57Q`%%pD=RvA>4R1H+iRGU=?RA)%@xK7%C zX7vy1+UiE6IrUQyRZmgxqMi(=(Qr%sv*u5YQe)PXC9T?5Gn%y5K+OrwO&S|NXbWpg z5m)Q19YNB4v-W`YEcM(=Z3bOVT@hVnU0vNglJi?=W^hCop}VR}um4H^J89h}eHDFE zeOJ=EXOryTs}I-T*2@f8NfR>}DjS*_x*CQOFIj5XVmL_JKs0Hk%us|RjxT8*Q;jo? ztBgO9&Qs0Q#WcsX-V|o4Z60afOL}J-!gxVK`B{=0-&*z7rq*uOnbtbCDYk1i*+maN z-%dej?I<5B-zmQ)Pp$Y#p`l)zrU+MLRW?%&S1wfUR7NPDD6mW14TZdGy`&+o;}O8FCs58q}me?lD|2Y_#sf{N=uf>=hkes#9yS z)4c{wNlhJ1Q_V2a{a0(YXu>oXG-rVAvU zGnoG{8_b^O79^7=lg6^k9B#fx@;HY@McPI+OCw7w(&523rdbwR_E|zK=Pl{1-;#bb zz&h4i)>g~b)HV)yC7TxJo9X1)<%Q%%d2#tP`8@d&`F@Vp^om^6;|CNc6cL2fTZ)dP z2~Sh5RECo*idKHB`cth`n+S(Z)U9YlFV(Cgtew_eB(!DG=F`ckUux2&8T&nzC+ zbfis`vQ?%!@1U8+F`Fz)3fWQ`V>#uyX_WPr4pgB2HCb-A>(J)17$HXw4+e3_{XU%^FRB<`B(NUlJmICyrD^tI-xCeYv*wZ*51K zZBHW!?62KH=s2i7M*8zP?RD*K?L+M|t-!I8jb^n9>XimGv+bC5Zu=)Lt_^n*wa&HcZ2&OWTlGF|&?WNBz^E~VM zSkL#OA|oZm!m=VoGb4uz&5Dc~YABgPr9va4BD4I$v=PgUij2w(la$m7iwqMBi;B{W zsr`Fyo!NV)*B*+g+0r?)4j)i(0v4*{fm1N{$!GO6SLswDvL;z7J;|rzh#EZtLgjnM{dm=yDbMSDd;UPQ$~Dr$TQI&ka8kUd80! z#YrDWe@lmd{Kx9ojr zW5qeo8SRWm5zXPgKHyY1k2@Q1pIe>jwyGtfG&cCnT(bj}mnO6^r`kM@JsLqA?0q^IZ?>QiAv1?ZednABVO20r61 zM}>#tMl$IhGs6q$8_$Mc4}Ti&3(BrV{yS4-=p7o}IFccc%c{nA0{JL!12zdQ)0 zm?B$frit=R^!7iGL>93xmp2f7fK%J`QLvH3loK~VieLi=9-g1-yq-kTdY%N#&qgFw`->AKVcG{(V ztbIer59+=30eS+g=S=#HiI#d;sHYRrPiL^K=7i6s%jAXU;V){?P@cn2XF7y7f=c%K_F<2$n;)&Z5`kTMr9=UQe(79C!W~D@aAe+m4+^ z&z@voWB(p6ajSi&eZO5!H+qulsOEdxXun}M*e&*c`)9i+o%|H%4Cide5IyQD=V}<> zY&g?gr_6c8dDnR#Ch;R4<9PQpcceScy_C9{gHm_^t?&dcqXufWh3WgDdyx723-oV@ zH;gJ$ysNw!-dy^<@8TQi_J_PIeEXy5wS$q)NFb+2U@2wPQyM4@k>_~B*c0Ry2AMeJyI-K$(;pE=*-tqQ$1$ee^V01kK@%-Ic(zW{4_?P*{ zT4OlOHBi-qt$;w_IO##DMjC+Aoe;hbD)AaVC)Fr2mKnS7sR8pue%qSQ}pom}q99Z;Uf`90r;rherd zagKL~xaUCq=R;I$-3Ey8dbP4+zIYAuxEkR1&by~4Q-mb*~&oIOrE z{O}Z9!X&o~4cJ_4MMPOy`N)xZV54J09KPK%^(5Jr+imM%F`+0(CtE2TPI8 zldh8P;67I3a^FRP3}FOZG44-qrFRc zR9TPn`ds-=>8TE)hm2M)fj_*?=jl>=)6LURBz}6aPOHJ{zodIWFL#O6n>geI4$v{xL65sW{bRy(F zS~*!+&Xnt|=BX*#Xc+yE+G+ZYXoC~Nap9B1T(bCd7f`2vn(i20qbjOdH~(;6ni-Cpw!+< zmNSyBHVV}>)w$KV6B;=m<@Ew?@_kZ_gAmDRZt74Jfs7*X@a$vVTp#UJ*_7?Y>+n;XJK)RF2vK%@s@aNyqCP!ye-}?GJ;>czLA0Ggi(X8su?{gysAN*crMS|~jyZNfEem3E+VPmoWQN5Ud~r+=w@HPrbIxmbRH4!B-^ zN#2B``bgd@9|tc!DKtEEZs@|$bQDEl=pNzzYar6w$j{nCouOXJK)zj9odGXdr*32p zMd=@#L#-Q_)JH7MzQCSEEiba4W(vGUJ-0Cdq8!&b-^p|S%(=Wr^3_HK9q$fyQ#h5Y z+-uzD-Iq9xZ{45VTfE!7dEN%Pd3NLvkuUtu78~WqPJyA4BHbYMfuvp|-z`5Y{~-S) z$Kji*l>%tPqp;F%(2n=vYj@yB7Mt&xpP2(KUop=>AFM-reTnwsFG`FGH1VU4sJDCN z`{l>vdifn3<)`v@sMW7RKQpZ#SD&Sp7U-4wO8sU1b>W-#;jX{adxZNPyI*I9JqX2Q zlutqU?(qHL#n6g%DEazuQ}~DQPvnE6$t)kTmZ4eRws+XgB$g*R$?&z&Bw$6(W@jgg z@vw8Ud$v0smQ%*GTS7mnabJNyM0qE9$=*fY6mK991CRMVYc7oOa;E?7@WpE9 zb4b=neDFQgMZ;D654s6Zz_hC!jP;gg;M z6-?zmUn}1yzb5aHPoi5+!E4+Qx`m#37d+-!G}!J?ZzWB+OnF}U64kYUo3dT~Ngb!< zXfw5P+}ajs-T?erh5nfS6yNus(YG(-m-mx3^+!R?K|i&JhZ-uRsRLdko1^%2xn?!< z;$3c8r+E%)DT6faN-M{jZe7pkT!voiZ710G+KMinb|P&JwSiyOzL`yR83V!!JP_7fa>JT z(1g%r6y^^hPZ`H|Ia8U3vs$AJ4!+%gW=xc6T$d2$LTDh*`7ClE z(t%El5_wJ!={Tvc6o(JET)GYy@Q}2I4!T!5gyYg>TRu-tC(D_@^!by#Mt+{Ic^q{$ zkh&TkQbJ>d2YZM){Smtn{gpwmQc2MiTRB(BQZ82}qbiG(`H<*ZWjh?YAFeDJ)xR8- z`579szcx%8t>2|Tq~8ZU*>S9UO|c5m+(Yf>=>l85d(k(KMFROzV!z=yd8nMs#Ov-0)();uwxVLM= z_o3N#gohbtam#a={%;rqVLDI1BtK>gU=rli=cX%3mIm2l(fzlh_ZO0rjO_Zl|&VP_k2n`O6L!0M@9;9cjVhVkaKJLdStcM=-Le07Ag|M+w=)o6! z&SB8{8?--Y3$!Ze-)n-Do}fpdFEij_w^HBF>znj<@vr;z@AU|ud{KA_H@}X1KiD`! z(1UbR*UQOWt~c&9?lr27O~wbt0J_>m=9S#}>&@BR`}u+$^u({~DC;@atJd2PtwFZR zt-c8@`x;dA2>KueDmn)i`n?keySmc7o6~s}C)4G|z+H52A{!t#d+WHj9b_hbBO{sa z*^%q;scbKlMFp}rqh!+cDbn3gt0$=cS~|eH>@gf7uNp!JwAjhHjBSSNNLfj*cpW9#tn5<`bDD$I(^W@3 zUmd4Tz?IHa=co(Ra+Ku@Xyr!kXsULhHi6E$7>d6J4*jv<&A*+*f+sz}8Uz&>XD|e0MKjeNsEQI=G75%ek~&RhlH5pg`;0uDnNg2p|B~t*s>qzw zMNEyWl`ZNF?IuB8@7K!UBDLCP5}*&XWZi-6jbkQWug})+B1(-RK5hL# zKQ0_g$32zLe>T+5rSpy^4Z0G)QG)7zJp2;=aew&da3A>USjgYCbl8o?eiUjSa}ZNz z206yFY?i!b_O=qBsHxQAE!OSUJkrtktUcEEOqoRbX&RZ{Lejh!?Ok>lYI+46{ys;- zrJPU4obE1!xQ|3rPKT4u#o2wrPET|snXG$CS{>SkK}5x+8~t0aP3S@g7l4sZpkWFN-lX%3)kO)<@jNVjYRKoa2b8dUFKE~mt8W3Eo8=LZ_2gy(n@hwtmz zA4qbaSKd;_L%)`(GLHIIX8$w#dVN&*vas)aMv^p0q?C2tx|vpQeyqw!?|Wv03w-8ATrS82tGi z>qjfbK9!Au8&Guqme=PnoFh)6cP0*IJm)csdlis^!h=5wZLj4#P9*8r#*F$ll&)kz z!?NJO*{GIjN-n9#2=%x6;A6dGt8S4=-MFCWsdJ=&ygKwc zzt0CGo1@8HuER}6k?eaU!dukuxT!0&W;lL~o}pg~{hSZ^d`f?nsoA7YLNP54zZ(99 zbmTmP(zclM83sSao>6DlL#`X_M!Shbxfwp!ia%>7`|o65 zt&9DdpcC!HII&I~`!xn>UKaVw3;2-&uh1)krRD4M=lo!xfggW>y3QrbSwMGs7^U@eE~ZDDn#WiCf_!7 z2fpYd^%Hd3e(L6HZpR@!L=?O=llr(m+=L5otQ%2CYxyo;W^ZK|-T52qID0bROuKD5 z8K{5?Jis!tm;|a*MaO2lQ(#C(+!Qa3{N)m~K(?1dmcK?M1G~LuYPS_q*p4=^@P28L zbkxDoEs9S_2-OGKDyWZXCZX(Ir23Ku%_u>b>A=CQVJWx?To(ey*2~+PZ_T zcpv>>k@qwjVXgO~_W={}kT)kX56u-6JoZYdkaYRQ&;+$fi=sEX=)cMKC47S`@p11v zA3-9=vUxn6oAv?>u)!VRC3>gxO-^IKjLTIO3i4=cBL2+gl)5N7#z!=ME%490ME9bKk?YPVjE@3cN?y zw_eS*&)Z_cbb5o>o(q#0jwfrm9>4w`S|S+O%ux(SzfRx`IwV6bmB+!^zh{#q5l^(A zon~8Ig{Jxej?|Z_pG1Ov3u@{i6yyQDlazW8EKg-qd;w%-SNH<9p;oiCV4G{rT63HE zsoBMTcno~OAvc-=q0AS19;=v_`$+O_`$2XHx6(tp>{FeP^Lr>=8J**65{Eb{ahNNS zD9?27)Dk*56zu}`^!^q2p7Rkma+ra%${|?_^pvdTIpxL zc}$NoV~J72bkq49a)9;IjTiU6@%3JI_ORf%wvLfrFIS4;}P`xD(=iCbZndUmDb7JpA;@f zk*)}zz^wh+I30%b0QsChv%WHW*eA1x*?_wI$f zk-o2>p6bZnKcaKRa3}noyD^;S(#Seaw8ftnEx|wuKTZ%E!%vdQtioxp7g^iu(q`Pv zcJ?Qlao(SkD0fJ|mCwf0jATplU}z7jaLE}Vj^e4Cljosh* z5b6!qCv0+jLx!7=PuRo__{9F!KASXQmeb{39I5bskB*?&Up}n9s1>mLzBHV{{0_25 zRLC~s5`4&KWMV^Ln~V4x-(gA(r#dDvarfG{d7t=dnLj-PMf@|Cy`Zz%e;%kLvyttm zH@7RR*fq=HJwc&n^WMRyX4jDT-^*)$IYPccRsW5`HvXOrRsa?p6|RPvE` z`Mu9!axAo0FuQ+40`eR?*&9j0cA{>5UwsWHy3qgc$NDcbeXc$xbTV5C$?Dl^1fEx+ zE`fA?Msnm*TVLoSVEtj(&k8zvBKsV^!@b6sNhe=|7kiCOq~qw^gV44k%#i8f#x6y@ z$WYqt5?EuvN8U1R~p*Pv&eAn3y75$KX&b=tg zFUWen<#xa39)OV#HtdNE${eXh`Qu>C#v>c&9Tp%cZ4|^Y!fUz6Foq zm*+L2FB$65t_}3#CU{~qZn~AEuszfP5kDLXD$(p4#^QhyN#K)}Kn`#F_;+@rA6tC? zkl!xfiY&BnP4WFDL7*XZ=7Lf!BeNP zsWh9rSqxP@9O+_K^%Oi5oh?PPiyRBPiszk9BHlKc?J0@9Rzq^w`%B{!W{_=XNfV`P z_AIBdyOH-RwNS>VuOO4E;tZBU8rG8PZ9uu#N%d4^1Lx5s>hh?f@GG;EiPnXZ4$9GT zj2sKOiI)@D(Mp0#rN|PgmLWSZ+BC>n2K$>?aGh*9N1i6KDfh+!Gbu)?ae zqIvJ}kBUx0D;ciirjnj;NL4)p@jU{8jp{4vCNjJl_Te^b4e;sRycFm}ttXIlsk))3 zquaCeJiSma(#!DXOPPw*dJRspS#Qxhm@S8S)e|314yTZmr?Qii4hzeL<`;%bsnH51 zW}TqQgTu;WPq9RtNi}+MgH_8c z+YR;bchfqAR`&gY?+$!V;5!1}2ly_)*Z#ip_w~N7_I-`-D|}zq`>Ni*Zw3j3uj_M| zEQRC{zLs9>XXwcxG-UILoO@lu6u z^&Num4}5pvdxKi0z-ChUCU3XUvA&8u>~*ncA03H}#6=P!i4cgCh{~H1U)yFtBPNPn z;as*?XOrd@G0RFL?-y{t05*E z*bVXfiQhx~-r@I*G$md5;CyAaQp(G^3Z+u1VgIZS&e_ZsPn*)N1l4FYi4LE}`;2L7 zE?XnB;htsm`bwtz1~$@mtDWj$w$CLzeHz=QB_te`sH+yOUDQULs1Bc8rRfv(X%NwJ zHg6lK20tH2q5`tm7Fp zyAo=#mV4dCy$)K@q^ZfgggbhxGq}}->{eB>TUEzB4sdrR{8py z7u9|bj-?N#`+YpNSD+Lbz2H$JB{W+scNF|B2(MbN^HOuPd@4 z;9c zKVOTFZ=$x_@$Eq>JAqlEa%LISwSR7fRCPIT>#ErStmpLn%(avG9D`R*Lh(9oI^HFR zeZU*U8I}oVQbT1ouv6YD*hw@wTq0XG2A(F93eWXsbGD^a_fkAlEw$Z5UAI%yLFzey zT2`s!3~G29^;<~oK1kwHMcqD6;!;n|HdC)6uTJcB^w~O<8c&r)fC>kT2x}DdIkDASDmHaq86$5sq=;MdPZHV)~cJS$QHGo ziVQ+M6Hq)Vq%DJ8?rH4V6^iPt(yEzY^~|qklz1m^DP#0_T#!VKrZc~Cm|*_aT^U*Q za;8@u)w)}66%`vz5}nBO^6#|2gO^L1SH$e9K*_Ep$=gg4-9mPGm=rJ8NMLTMygbNY zk9QjNTxgUqzpAL}4Msgx-ON6CC-W=D^lMu}cce4Da+qHQD2_5w;Wc>12If~Qv#ZOD zw&LLODO7oy*zL__H?@dqUP1cz43ldk?tZhi-P%dbw==hbkgWuWmP++!h@Ibjs8tEH zs)`=4fqB))#A<^^1)xyzyz`QnRq0HtNszug=N1@>zhUv9Q^~8*mCUPG$ebF4V)Wms zd`pk$#S5@F_JoJQf^^ps8y6Qdzov87XS4fyH+yA^+{NsmKMNzQg^O>&_kE0hY=;~i zL0R`>D?I@xKN6DZkzQqZmwH#=>htL>B}}&}ubK^odQydE98M>xO$={cl2E-4d?t&$ zF%R8YEcTF=M{3wM+(g#6JF=IJ!wz4yF{63~HZ!ZD(QAqHCj)(!i7v~9-V{M?7DNQ0%m_(US*<9vO5tC?< zvRGNFtR-)Ih1VWUOrmy@q98A55|~6P+q)TTlulz76+$J-)hg1W4PvjfS#4t)1=uBs z=M96zL`r8%I)^Q~0&>VQ=F)PlhW(@llv^v>t&1(CIJ8>|+AU3FNx9@IMbPL9wA)&} zmK2}~<<^dF3zDlOpxi=X9pyHfjy@5_kqZUZq%DU*P>D0iKsUN{g#R5&P8z-p|>l@xz|D*HlyEKm~n@h zaHkD)8swo6-B!+&t46iev)$Ir9&so0E(X1pB*;oS>^27nSpcgoWBM&; z_SNC6cf(>kU=-1)v_y28;iSP|v&HsX5elsWjkZ?I!Y0U5JNhh$QchqRs?5U-=HWEv zVIefC9F0~jreY&Ht&P2kfENP|OY$VNS~}bEIbI(8rWm(g3Bj#Fr!}C_TG3}+q(X7% zvJ^B~8hR|77uB=TVWq-FtwnupMtQZs9fjsf?G?!79tY7|31}@9ot1&cnufkAL|c`k ztE$md^*D!S7-T1!Dh7v;gfnn(1X<{+JRCr=Tqakdt7_P2Xn;+&@}{&)jz&=>qNxn@ zR3@7pxu~fklvD*OYAp(CGw+{w;>6m81B+D>P*EzoXBngl)0BLrkau6@N|jQLimF!{ zQBiHY?GC6hYCI}RBIit3FD5z8VVCI!HlmABQkCj6?BLd@b!r1zs#WbEBZ=1H$g5H` z14Wf7c5!Dzu}j&mzX>srZkHLSq%`B|>LalZe)n zV>Rn-xQ{?M2KSM~s}x7*uAG0ONLuh6ZFKMsZt-EZF@A$GiD!e?-$pUG&8aAqbUONY zV*)BAkFGwOn_Y-nxrbK-mBy3C(}wRkYU$hc+}#HBi0?m|g#+=mS_j(XFugor`KrzL zBXPo!B%)PDus!8FjPvaap*|C#?^B#SZrN-!L*X&XUdrB5IeEYD43?6+RJ&{0VA>#D zLOo=*!EJ=i@l4b5IJobW30D7YMyyEEIp4(EOD`^{f-?GV1-H0LID~2xNe#WYmK*K6g$Cglb_>VQDm+66 z{rNDr{5PSV-0d9U7xIK-C=i~ZSh$8V;TtN2b676CLyd3`b;3XVdpx2`WH8akm_$64 zagpl?(N&yq%E;wW}ny8i8&`x#vZl#ME z5!9lY6R}iUJUS_nd67)TN$4fx@6yREv{N=SWEy!=9vW&kv!qbFi(S`dJWeYLs$Eck z!%UNa9@L{zQ?X2yc;S1JcpsI5vhwMGLw%+RMv#fhn#krt4z-$#+RA6@6bNciOx>0W zc2I%(s$vSQ&{tEp!EiLS8;kmiX9^`!!^x;H2}*7JjU;5C$g-G9*}U?ZhBC`zI?Wbr zp$OMeA_zk{O0AMU7%aFfDK`)vGzi7kNe8Y>bXtS@`9~C%)|4#)6 zZ{xF!3_&v{npd$YozGPCnMM)Hu!QOOfVt3IN-n$_A5+gJ%vQ@M5BtccyU=nyo!+qa zctI0}yCZNP=fJD8m{~qon8rq|-&JmgUzecH{%t>5!S=t;8~)l!ns6t3*tYIqsvQ;t zBIrdk-THecvMqU*C*xHvWNR`9y_U57w5u|AUInOHmKkNwyLC!N?po^TQz>jCloL9F1Ud=6z?Ca)bH8b_-lop%sZBUth|L} z?$v0&_4<#e zvHbaH<>ce`3;x~I|7ay`5R9*0P`*aN`I`StV%;fdUm)W1z8FFL;sx_d64Xx;+|T)2 zs{P;51j_{rtPwP@PVm70pq}%41>*l{JtzHNF>*h(s`)QX_&_KKAB+)%FdiD3;h4yQEJiZ^^leZ_7i>n`9H5Nig2qX=>0O@_CBKdjI-c> zc-JN#e&_FSse;X?;{4Jfd6|OJXA4fB3;oC^1uPK6zF08(G6-JH5Q%ruV++_ zFREnsb}8PzS&K(URl%)%1@Y?)s~o1Z6i!-$KdHx?G~rA9T%_|@rXPpDPJ%D-Yj*$X zK7sBN=stn&6X-sH?i1)ff$kINK7sBN=stn&6X-sH?i1)ff$kINK7sBN=stn&6X-sH z?i1)ff$kINK7sBN=stn&6X-sH?i1)ff$kINK7sBN=stn&6X-sH?i1)ff$kINK7sBN J_%EEmzW~_@Jq-W= literal 0 HcmV?d00001 diff --git a/Release/TitanEngine.exp b/Release/TitanEngine.exp new file mode 100644 index 0000000000000000000000000000000000000000..2c83bb06106427d4da34c725079a742d2a6c2533 GIT binary patch literal 59755 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 literal 0 HcmV?d00001 diff --git a/Release/TitanEngine.lib b/Release/TitanEngine.lib new file mode 100644 index 0000000000000000000000000000000000000000..488ccb650f35a6906d46a889914c323acadfc8de GIT binary patch literal 104582 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 F{C|S%JF)-( literal 0 HcmV?d00001 diff --git a/TitanEngine.sln b/TitanEngine.sln new file mode 100644 index 0000000..8b4e093 --- /dev/null +++ b/TitanEngine.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TitanEngine", "TitanEngine\TitanEngine.vcxproj", "{9C7B8246-FDDA-48C7-9634-044969701E40}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9C7B8246-FDDA-48C7-9634-044969701E40}.Debug|Win32.ActiveCfg = Debug|Win32 + {9C7B8246-FDDA-48C7-9634-044969701E40}.Debug|Win32.Build.0 = Debug|Win32 + {9C7B8246-FDDA-48C7-9634-044969701E40}.Debug|x64.ActiveCfg = Debug|x64 + {9C7B8246-FDDA-48C7-9634-044969701E40}.Debug|x64.Build.0 = Debug|x64 + {9C7B8246-FDDA-48C7-9634-044969701E40}.Release|Win32.ActiveCfg = Release|Win32 + {9C7B8246-FDDA-48C7-9634-044969701E40}.Release|Win32.Build.0 = Release|Win32 + {9C7B8246-FDDA-48C7-9634-044969701E40}.Release|x64.ActiveCfg = Release|x64 + {9C7B8246-FDDA-48C7-9634-044969701E40}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/TitanEngine/HEADER.BMP b/TitanEngine/HEADER.BMP new file mode 100644 index 0000000000000000000000000000000000000000..fbd165c2deeed4bfbd255aee28c709df7673fba2 GIT binary patch literal 88616 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 + +#define kNumTopBits 24 +#define kTopValue ((UInt32)1 << kNumTopBits) + +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kNumMoveBits 5 + +#define RC_INIT_SIZE 5 + +#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } + +#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) +#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); +#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); +#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \ + { UPDATE_0(p); i = (i + i); A0; } else \ + { UPDATE_1(p); i = (i + i) + 1; A1; } +#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;) + +#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); } +#define TREE_DECODE(probs, limit, i) \ + { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; } + +/* #define _LZMA_SIZE_OPT */ + +#ifdef _LZMA_SIZE_OPT +#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i) +#else +#define TREE_6_DECODE(probs, i) \ + { i = 1; \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + i -= 0x40; } +#endif + +#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } + +#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) +#define UPDATE_0_CHECK range = bound; +#define UPDATE_1_CHECK range -= bound; code -= bound; +#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \ + { UPDATE_0_CHECK; i = (i + i); A0; } else \ + { UPDATE_1_CHECK; i = (i + i) + 1; A1; } +#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;) +#define TREE_DECODE_CHECK(probs, limit, i) \ + { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; } + + +#define kNumPosBitsMax 4 +#define kNumPosStatesMax (1 << kNumPosBitsMax) + +#define kLenNumLowBits 3 +#define kLenNumLowSymbols (1 << kLenNumLowBits) +#define kLenNumMidBits 3 +#define kLenNumMidSymbols (1 << kLenNumMidBits) +#define kLenNumHighBits 8 +#define kLenNumHighSymbols (1 << kLenNumHighBits) + +#define LenChoice 0 +#define LenChoice2 (LenChoice + 1) +#define LenLow (LenChoice2 + 1) +#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) +#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) +#define kNumLenProbs (LenHigh + kLenNumHighSymbols) + + +#define kNumStates 12 +#define kNumLitStates 7 + +#define kStartPosModelIndex 4 +#define kEndPosModelIndex 14 +#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) + +#define kNumPosSlotBits 6 +#define kNumLenToPosStates 4 + +#define kNumAlignBits 4 +#define kAlignTableSize (1 << kNumAlignBits) + +#define kMatchMinLen 2 +#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) + +#define IsMatch 0 +#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) +#define IsRepG0 (IsRep + kNumStates) +#define IsRepG1 (IsRepG0 + kNumStates) +#define IsRepG2 (IsRepG1 + kNumStates) +#define IsRep0Long (IsRepG2 + kNumStates) +#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) +#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) +#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) +#define LenCoder (Align + kAlignTableSize) +#define RepLenCoder (LenCoder + kNumLenProbs) +#define Literal (RepLenCoder + kNumLenProbs) + +#define LZMA_BASE_SIZE 1846 +#define LZMA_LIT_SIZE 768 + +#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) + +#if Literal != LZMA_BASE_SIZE +StopCompilingDueBUG +#endif + +static const Byte kLiteralNextStates[kNumStates * 2] = +{ + 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5, + 7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10 +}; + +#define LZMA_DIC_MIN (1 << 12) + +/* First LZMA-symbol is always decoded. +And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization +Out: + Result: + SZ_OK - OK + SZ_ERROR_DATA - Error + p->remainLen: + < kMatchSpecLenStart : normal remain + = kMatchSpecLenStart : finished + = kMatchSpecLenStart + 1 : Flush marker + = kMatchSpecLenStart + 2 : State Init Marker +*/ + +static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit) +{ + CLzmaProb *probs = p->probs; + + unsigned state = p->state; + UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3]; + unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1; + unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1; + unsigned lc = p->prop.lc; + + Byte *dic = p->dic; + SizeT dicBufSize = p->dicBufSize; + SizeT dicPos = p->dicPos; + + UInt32 processedPos = p->processedPos; + UInt32 checkDicSize = p->checkDicSize; + unsigned len = 0; + + const Byte *buf = p->buf; + UInt32 range = p->range; + UInt32 code = p->code; + + do + { + CLzmaProb *prob; + UInt32 bound; + unsigned ttt; + unsigned posState = processedPos & pbMask; + + prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; + IF_BIT_0(prob) + { + unsigned symbol; + UPDATE_0(prob); + prob = probs + Literal; + if (checkDicSize != 0 || processedPos != 0) + prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) + + (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc)))); + + if (state < kNumLitStates) + { + symbol = 1; + do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100); + } + else + { + unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + unsigned offs = 0x100; + symbol = 1; + do + { + unsigned bit; + CLzmaProb *probLit; + matchByte <<= 1; + bit = (matchByte & offs); + probLit = prob + offs + bit + symbol; + GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit) + } + while (symbol < 0x100); + } + dic[dicPos++] = (Byte)symbol; + processedPos++; + + state = kLiteralNextStates[state]; + /* if (state < 4) state = 0; else if (state < 10) state -= 3; else state -= 6; */ + continue; + } + else + { + UPDATE_1(prob); + prob = probs + IsRep + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + state += kNumStates; + prob = probs + LenCoder; + } + else + { + UPDATE_1(prob); + if (checkDicSize == 0 && processedPos == 0) + return SZ_ERROR_DATA; + prob = probs + IsRepG0 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; + IF_BIT_0(prob) + { + UPDATE_0(prob); + dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + dicPos++; + processedPos++; + state = state < kNumLitStates ? 9 : 11; + continue; + } + UPDATE_1(prob); + } + else + { + UInt32 distance; + UPDATE_1(prob); + prob = probs + IsRepG1 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + distance = rep1; + } + else + { + UPDATE_1(prob); + prob = probs + IsRepG2 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + distance = rep2; + } + else + { + UPDATE_1(prob); + distance = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = distance; + } + state = state < kNumLitStates ? 8 : 11; + prob = probs + RepLenCoder; + } + { + unsigned limit, offset; + CLzmaProb *probLen = prob + LenChoice; + IF_BIT_0(probLen) + { + UPDATE_0(probLen); + probLen = prob + LenLow + (posState << kLenNumLowBits); + offset = 0; + limit = (1 << kLenNumLowBits); + } + else + { + UPDATE_1(probLen); + probLen = prob + LenChoice2; + IF_BIT_0(probLen) + { + UPDATE_0(probLen); + probLen = prob + LenMid + (posState << kLenNumMidBits); + offset = kLenNumLowSymbols; + limit = (1 << kLenNumMidBits); + } + else + { + UPDATE_1(probLen); + probLen = prob + LenHigh; + offset = kLenNumLowSymbols + kLenNumMidSymbols; + limit = (1 << kLenNumHighBits); + } + } + TREE_DECODE(probLen, limit, len); + len += offset; + } + + if (state >= kNumStates) + { + UInt32 distance; + prob = probs + PosSlot + + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); + TREE_6_DECODE(prob, distance); + if (distance >= kStartPosModelIndex) + { + unsigned posSlot = (unsigned)distance; + int numDirectBits = (int)(((distance >> 1) - 1)); + distance = (2 | (distance & 1)); + if (posSlot < kEndPosModelIndex) + { + distance <<= numDirectBits; + prob = probs + SpecPos + distance - posSlot - 1; + { + UInt32 mask = 1; + unsigned i = 1; + do + { + GET_BIT2(prob + i, i, ; , distance |= mask); + mask <<= 1; + } + while (--numDirectBits != 0); + } + } + else + { + numDirectBits -= kNumAlignBits; + do + { + NORMALIZE + range >>= 1; + + { + UInt32 t; + code -= range; + t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */ + distance = (distance << 1) + (t + 1); + code += range & t; + } + /* + distance <<= 1; + if (code >= range) + { + code -= range; + distance |= 1; + } + */ + } + while (--numDirectBits != 0); + prob = probs + Align; + distance <<= kNumAlignBits; + { + unsigned i = 1; + GET_BIT2(prob + i, i, ; , distance |= 1); + GET_BIT2(prob + i, i, ; , distance |= 2); + GET_BIT2(prob + i, i, ; , distance |= 4); + GET_BIT2(prob + i, i, ; , distance |= 8); + } + if (distance == (UInt32)0xFFFFFFFF) + { + len += kMatchSpecLenStart; + state -= kNumStates; + break; + } + } + } + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + rep0 = distance + 1; + if (checkDicSize == 0) + { + if (distance >= processedPos) + return SZ_ERROR_DATA; + } + else if (distance >= checkDicSize) + return SZ_ERROR_DATA; + state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; + /* state = kLiteralNextStates[state]; */ + } + + len += kMatchMinLen; + + if (limit == dicPos) + return SZ_ERROR_DATA; + { + SizeT rem = limit - dicPos; + unsigned curLen = ((rem < len) ? (unsigned)rem : len); + SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0); + + processedPos += curLen; + + len -= curLen; + if (pos + curLen <= dicBufSize) + { + Byte *dest = dic + dicPos; + ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos; + const Byte *lim = dest + curLen; + dicPos += curLen; + do + *(dest) = (Byte)*(dest + src); + while (++dest != lim); + } + else + { + do + { + dic[dicPos++] = dic[pos]; + if (++pos == dicBufSize) + pos = 0; + } + while (--curLen != 0); + } + } + } + } + while (dicPos < limit && buf < bufLimit); + NORMALIZE; + p->buf = buf; + p->range = range; + p->code = code; + p->remainLen = len; + p->dicPos = dicPos; + p->processedPos = processedPos; + p->reps[0] = rep0; + p->reps[1] = rep1; + p->reps[2] = rep2; + p->reps[3] = rep3; + p->state = state; + + return SZ_OK; +} + +static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) +{ + if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart) + { + Byte *dic = p->dic; + SizeT dicPos = p->dicPos; + SizeT dicBufSize = p->dicBufSize; + unsigned len = p->remainLen; + UInt32 rep0 = p->reps[0]; + if (limit - dicPos < len) + len = (unsigned)(limit - dicPos); + + if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) + p->checkDicSize = p->prop.dicSize; + + p->processedPos += len; + p->remainLen -= len; + while (len-- != 0) + { + dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + dicPos++; + } + p->dicPos = dicPos; + } +} + +static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit) +{ + do + { + SizeT limit2 = limit; + if (p->checkDicSize == 0) + { + UInt32 rem = p->prop.dicSize - p->processedPos; + if (limit - p->dicPos > rem) + limit2 = p->dicPos + rem; + } + RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit)); + if (p->processedPos >= p->prop.dicSize) + p->checkDicSize = p->prop.dicSize; + LzmaDec_WriteRem(p, limit); + } + while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart); + + if (p->remainLen > kMatchSpecLenStart) + { + p->remainLen = kMatchSpecLenStart; + } + return 0; +} + +typedef enum +{ + DUMMY_ERROR, /* unexpected end of input stream */ + DUMMY_LIT, + DUMMY_MATCH, + DUMMY_REP +} ELzmaDummy; + +static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize) +{ + UInt32 range = p->range; + UInt32 code = p->code; + const Byte *bufLimit = buf + inSize; + CLzmaProb *probs = p->probs; + unsigned state = p->state; + ELzmaDummy res; + + { + CLzmaProb *prob; + UInt32 bound; + unsigned ttt; + unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1); + + prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK + + /* if (bufLimit - buf >= 7) return DUMMY_LIT; */ + + prob = probs + Literal; + if (p->checkDicSize != 0 || p->processedPos != 0) + prob += (LZMA_LIT_SIZE * + ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + + (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); + + if (state < kNumLitStates) + { + unsigned symbol = 1; + do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100); + } + else + { + unsigned matchByte = p->dic[p->dicPos - p->reps[0] + + ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)]; + unsigned offs = 0x100; + unsigned symbol = 1; + do + { + unsigned bit; + CLzmaProb *probLit; + matchByte <<= 1; + bit = (matchByte & offs); + probLit = prob + offs + bit + symbol; + GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit) + } + while (symbol < 0x100); + } + res = DUMMY_LIT; + } + else + { + unsigned len; + UPDATE_1_CHECK; + + prob = probs + IsRep + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + state = 0; + prob = probs + LenCoder; + res = DUMMY_MATCH; + } + else + { + UPDATE_1_CHECK; + res = DUMMY_REP; + prob = probs + IsRepG0 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + NORMALIZE_CHECK; + return DUMMY_REP; + } + else + { + UPDATE_1_CHECK; + } + } + else + { + UPDATE_1_CHECK; + prob = probs + IsRepG1 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + } + else + { + UPDATE_1_CHECK; + prob = probs + IsRepG2 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + } + else + { + UPDATE_1_CHECK; + } + } + } + state = kNumStates; + prob = probs + RepLenCoder; + } + { + unsigned limit, offset; + CLzmaProb *probLen = prob + LenChoice; + IF_BIT_0_CHECK(probLen) + { + UPDATE_0_CHECK; + probLen = prob + LenLow + (posState << kLenNumLowBits); + offset = 0; + limit = 1 << kLenNumLowBits; + } + else + { + UPDATE_1_CHECK; + probLen = prob + LenChoice2; + IF_BIT_0_CHECK(probLen) + { + UPDATE_0_CHECK; + probLen = prob + LenMid + (posState << kLenNumMidBits); + offset = kLenNumLowSymbols; + limit = 1 << kLenNumMidBits; + } + else + { + UPDATE_1_CHECK; + probLen = prob + LenHigh; + offset = kLenNumLowSymbols + kLenNumMidSymbols; + limit = 1 << kLenNumHighBits; + } + } + TREE_DECODE_CHECK(probLen, limit, len); + len += offset; + } + + if (state < 4) + { + unsigned posSlot; + prob = probs + PosSlot + + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << + kNumPosSlotBits); + TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot); + if (posSlot >= kStartPosModelIndex) + { + int numDirectBits = ((posSlot >> 1) - 1); + + /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */ + + if (posSlot < kEndPosModelIndex) + { + prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1; + } + else + { + numDirectBits -= kNumAlignBits; + do + { + NORMALIZE_CHECK + range >>= 1; + code -= range & (((code - range) >> 31) - 1); + /* if (code >= range) code -= range; */ + } + while (--numDirectBits != 0); + prob = probs + Align; + numDirectBits = kNumAlignBits; + } + { + unsigned i = 1; + do + { + GET_BIT_CHECK(prob + i, i); + } + while (--numDirectBits != 0); + } + } + } + } + } + NORMALIZE_CHECK; + return res; +} + + +static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data) +{ + p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]); + p->range = 0xFFFFFFFF; + p->needFlush = 0; +} + +void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) +{ + p->needFlush = 1; + p->remainLen = 0; + p->tempBufSize = 0; + + if (initDic) + { + p->processedPos = 0; + p->checkDicSize = 0; + p->needInitState = 1; + } + if (initState) + p->needInitState = 1; +} + +void LzmaDec_Init(CLzmaDec *p) +{ + p->dicPos = 0; + LzmaDec_InitDicAndState(p, True, True); +} + +static void LzmaDec_InitStateReal(CLzmaDec *p) +{ + UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp)); + UInt32 i; + CLzmaProb *probs = p->probs; + for (i = 0; i < numProbs; i++) + probs[i] = kBitModelTotal >> 1; + p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1; + p->state = 0; + p->needInitState = 0; +} + +SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, + ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT inSize = *srcLen; + (*srcLen) = 0; + LzmaDec_WriteRem(p, dicLimit); + + *status = LZMA_STATUS_NOT_SPECIFIED; + + while (p->remainLen != kMatchSpecLenStart) + { + int checkEndMarkNow; + + if (p->needFlush != 0) + { + for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) + p->tempBuf[p->tempBufSize++] = *src++; + if (p->tempBufSize < RC_INIT_SIZE) + { + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (p->tempBuf[0] != 0) + return SZ_ERROR_DATA; + + LzmaDec_InitRc(p, p->tempBuf); + p->tempBufSize = 0; + } + + checkEndMarkNow = 0; + if (p->dicPos >= dicLimit) + { + if (p->remainLen == 0 && p->code == 0) + { + *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK; + return SZ_OK; + } + if (finishMode == LZMA_FINISH_ANY) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_OK; + } + if (p->remainLen != 0) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + checkEndMarkNow = 1; + } + + if (p->needInitState) + LzmaDec_InitStateReal(p); + + if (p->tempBufSize == 0) + { + SizeT processed; + const Byte *bufLimit; + if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) + { + int dummyRes = LzmaDec_TryDummy(p, src, inSize); + if (dummyRes == DUMMY_ERROR) + { + memcpy(p->tempBuf, src, inSize); + p->tempBufSize = (unsigned)inSize; + (*srcLen) += inSize; + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (checkEndMarkNow && dummyRes != DUMMY_MATCH) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + bufLimit = src; + } + else + bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX; + p->buf = src; + if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0) + return SZ_ERROR_DATA; + processed = (SizeT)(p->buf - src); + (*srcLen) += processed; + src += processed; + inSize -= processed; + } + else + { + unsigned rem = p->tempBufSize, lookAhead = 0; + while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize) + p->tempBuf[rem++] = src[lookAhead++]; + p->tempBufSize = rem; + if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) + { + int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem); + if (dummyRes == DUMMY_ERROR) + { + (*srcLen) += lookAhead; + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (checkEndMarkNow && dummyRes != DUMMY_MATCH) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + } + p->buf = p->tempBuf; + if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0) + return SZ_ERROR_DATA; + lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf)); + (*srcLen) += lookAhead; + src += lookAhead; + inSize -= lookAhead; + p->tempBufSize = 0; + } + } + if (p->code == 0) + *status = LZMA_STATUS_FINISHED_WITH_MARK; + return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA; +} + +SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT outSize = *destLen; + SizeT inSize = *srcLen; + *srcLen = *destLen = 0; + for (;;) + { + SizeT inSizeCur = inSize, outSizeCur, dicPos; + ELzmaFinishMode curFinishMode; + SRes res; + if (p->dicPos == p->dicBufSize) + p->dicPos = 0; + dicPos = p->dicPos; + if (outSize > p->dicBufSize - dicPos) + { + outSizeCur = p->dicBufSize; + curFinishMode = LZMA_FINISH_ANY; + } + else + { + outSizeCur = dicPos + outSize; + curFinishMode = finishMode; + } + + res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); + src += inSizeCur; + inSize -= inSizeCur; + *srcLen += inSizeCur; + outSizeCur = p->dicPos - dicPos; + memcpy(dest, p->dic + dicPos, outSizeCur); + dest += outSizeCur; + outSize -= outSizeCur; + *destLen += outSizeCur; + if (res != 0) + return res; + if (outSizeCur == 0 || outSize == 0) + return SZ_OK; + } +} + +void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->probs); + p->probs = 0; +} + +static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->dic); + p->dic = 0; +} + +void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc) +{ + LzmaDec_FreeProbs(p, alloc); + LzmaDec_FreeDict(p, alloc); +} + +SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) +{ + UInt32 dicSize; + Byte d; + + if (size < LZMA_PROPS_SIZE) + return SZ_ERROR_UNSUPPORTED; + else + dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24); + + if (dicSize < LZMA_DIC_MIN) + dicSize = LZMA_DIC_MIN; + p->dicSize = dicSize; + + d = data[0]; + if (d >= (9 * 5 * 5)) + return SZ_ERROR_UNSUPPORTED; + + p->lc = d % 9; + d /= 9; + p->pb = d / 5; + p->lp = d % 5; + + return SZ_OK; +} + +static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc) +{ + UInt32 numProbs = LzmaProps_GetNumProbs(propNew); + if (p->probs == 0 || numProbs != p->numProbs) + { + LzmaDec_FreeProbs(p, alloc); + p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb)); + p->numProbs = numProbs; + if (p->probs == 0) + return SZ_ERROR_MEM; + } + return SZ_OK; +} + +SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) +{ + CLzmaProps propNew; + RINOK(LzmaProps_Decode(&propNew, props, propsSize)); + RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); + p->prop = propNew; + return SZ_OK; +} + +SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) +{ + CLzmaProps propNew; + SizeT dicBufSize; + RINOK(LzmaProps_Decode(&propNew, props, propsSize)); + RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); + dicBufSize = propNew.dicSize; + if (p->dic == 0 || dicBufSize != p->dicBufSize) + { + LzmaDec_FreeDict(p, alloc); + p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize); + if (p->dic == 0) + { + LzmaDec_FreeProbs(p, alloc); + return SZ_ERROR_MEM; + } + } + p->dicBufSize = dicBufSize; + p->prop = propNew; + return SZ_OK; +} + +SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, + ELzmaStatus *status, ISzAlloc *alloc) +{ + CLzmaDec p; + SRes res; + SizeT inSize = *srcLen; + SizeT outSize = *destLen; + *srcLen = *destLen = 0; + if (inSize < RC_INIT_SIZE) + return SZ_ERROR_INPUT_EOF; + + LzmaDec_Construct(&p); + res = LzmaDec_AllocateProbs(&p, propData, propSize, alloc); + if (res != 0) + return res; + p.dic = dest; + p.dicBufSize = outSize; + + LzmaDec_Init(&p); + + *srcLen = inSize; + res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); + + if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) + res = SZ_ERROR_INPUT_EOF; + + (*destLen) = p.dicPos; + LzmaDec_FreeProbs(&p, alloc); + return res; +} + +void* LzmaAllocMem(void *p, size_t size){ + return(VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE)); +} + +void LzmaFreeMem(void *p, void *address){ + VirtualFree(address, NULL, MEM_RELEASE); +} \ No newline at end of file diff --git a/TitanEngine/LzmaDec.h b/TitanEngine/LzmaDec.h new file mode 100644 index 0000000..256cb18 --- /dev/null +++ b/TitanEngine/LzmaDec.h @@ -0,0 +1,223 @@ +/* LzmaDec.h -- LZMA Decoder +2008-10-04 : Igor Pavlov : Public domain */ + +#ifndef __LZMADEC_H +#define __LZMADEC_H + +#include "LzmaTypes.h" + +/* #define _LZMA_PROB32 */ +/* _LZMA_PROB32 can increase the speed on some CPUs, + but memory usage for CLzmaDec::probs will be doubled in that case */ + +#ifdef _LZMA_PROB32 +#define CLzmaProb UInt32 +#else +#define CLzmaProb UInt16 +#endif + + +/* ---------- LZMA Properties ---------- */ + +#define LZMA_PROPS_SIZE 5 + +typedef struct _CLzmaProps +{ + unsigned lc, lp, pb; + UInt32 dicSize; +} CLzmaProps; + +/* LzmaProps_Decode - decodes properties +Returns: + SZ_OK + SZ_ERROR_UNSUPPORTED - Unsupported properties +*/ + +SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); + + +/* ---------- LZMA Decoder state ---------- */ + +/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case. + Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */ + +#define LZMA_REQUIRED_INPUT_MAX 20 + +typedef struct +{ + CLzmaProps prop; + CLzmaProb *probs; + Byte *dic; + const Byte *buf; + UInt32 range, code; + SizeT dicPos; + SizeT dicBufSize; + UInt32 processedPos; + UInt32 checkDicSize; + unsigned state; + UInt32 reps[4]; + unsigned remainLen; + int needFlush; + int needInitState; + UInt32 numProbs; + unsigned tempBufSize; + Byte tempBuf[LZMA_REQUIRED_INPUT_MAX]; +} CLzmaDec; + +#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; } + +void LzmaDec_Init(CLzmaDec *p); + +/* There are two types of LZMA streams: + 0) Stream with end mark. That end mark adds about 6 bytes to compressed size. + 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */ + +typedef enum +{ + LZMA_FINISH_ANY, /* finish at any point */ + LZMA_FINISH_END /* block must be finished at the end */ +} ELzmaFinishMode; + +/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!! + + You must use LZMA_FINISH_END, when you know that current output buffer + covers last bytes of block. In other cases you must use LZMA_FINISH_ANY. + + If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK, + and output value of destLen will be less than output buffer size limit. + You can check status result also. + + You can use multiple checks to test data integrity after full decompression: + 1) Check Result and "status" variable. + 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. + 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. + You must use correct finish mode in that case. */ + +typedef enum +{ + LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */ + LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ + LZMA_STATUS_NOT_FINISHED, /* stream was not finished */ + LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */ + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */ +} ELzmaStatus; + +/* ELzmaStatus is used only as output value for function call */ + + +/* ---------- Interfaces ---------- */ + +/* There are 3 levels of interfaces: + 1) Dictionary Interface + 2) Buffer Interface + 3) One Call Interface + You can select any of these interfaces, but don't mix functions from different + groups for same object. */ + + +/* There are two variants to allocate state for Dictionary Interface: + 1) LzmaDec_Allocate / LzmaDec_Free + 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs + You can use variant 2, if you set dictionary buffer manually. + For Buffer Interface you must always use variant 1. + +LzmaDec_Allocate* can return: + SZ_OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - Unsupported properties +*/ + +SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc); +void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc); + +SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc); +void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc); + +/* ---------- Dictionary Interface ---------- */ + +/* You can use it, if you want to eliminate the overhead for data copying from + dictionary to some other external buffer. + You must work with CLzmaDec variables directly in this interface. + + STEPS: + LzmaDec_Constr() + LzmaDec_Allocate() + for (each new stream) + { + LzmaDec_Init() + while (it needs more decompression) + { + LzmaDec_DecodeToDic() + use data from CLzmaDec::dic and update CLzmaDec::dicPos + } + } + LzmaDec_Free() +*/ + +/* LzmaDec_DecodeToDic + + The decoding to internal dictionary buffer (CLzmaDec::dic). + You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! + +finishMode: + It has meaning only if the decoding reaches output limit (dicLimit). + LZMA_FINISH_ANY - Decode just dicLimit bytes. + LZMA_FINISH_END - Stream must be finished after dicLimit. + +Returns: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + LZMA_STATUS_NEEDS_MORE_INPUT + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + SZ_ERROR_DATA - Data error +*/ + +SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); + + +/* ---------- Buffer Interface ---------- */ + +/* It's zlib-like interface. + See LzmaDec_DecodeToDic description for information about STEPS and return results, + but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need + to work with CLzmaDec variables manually. + +finishMode: + It has meaning only if the decoding reaches output limit (*destLen). + LZMA_FINISH_ANY - Decode just destLen bytes. + LZMA_FINISH_END - Stream must be finished after (*destLen). +*/ + +SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); + + +/* ---------- One Call Interface ---------- */ + +/* LzmaDecode + +finishMode: + It has meaning only if the decoding reaches output limit (*destLen). + LZMA_FINISH_ANY - Decode just destLen bytes. + LZMA_FINISH_END - Stream must be finished after (*destLen). + +Returns: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + SZ_ERROR_DATA - Data error + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - Unsupported properties + SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). +*/ + +SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, + ELzmaStatus *status, ISzAlloc *alloc); + +#endif diff --git a/TitanEngine/LzmaTypes.h b/TitanEngine/LzmaTypes.h new file mode 100644 index 0000000..6c6ccf5 --- /dev/null +++ b/TitanEngine/LzmaTypes.h @@ -0,0 +1,211 @@ +/* Types.h -- Basic types +2008-11-23 : Igor Pavlov : Public domain */ + +#ifndef __7Z_TYPES_H +#define __7Z_TYPES_H + +#include + +#ifdef _WIN32 +#include +#endif + +#define SZ_OK 0 + +#define SZ_ERROR_DATA 1 +#define SZ_ERROR_MEM 2 +#define SZ_ERROR_CRC 3 +#define SZ_ERROR_UNSUPPORTED 4 +#define SZ_ERROR_PARAM 5 +#define SZ_ERROR_INPUT_EOF 6 +#define SZ_ERROR_OUTPUT_EOF 7 +#define SZ_ERROR_READ 8 +#define SZ_ERROR_WRITE 9 +#define SZ_ERROR_PROGRESS 10 +#define SZ_ERROR_FAIL 11 +#define SZ_ERROR_THREAD 12 + +#define SZ_ERROR_ARCHIVE 16 +#define SZ_ERROR_NO_ARCHIVE 17 + +typedef int SRes; + +#ifdef _WIN32 +typedef DWORD WRes; +#else +typedef int WRes; +#endif + +#ifndef RINOK +#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; } +#endif + +typedef unsigned char Byte; +typedef short Int16; +typedef unsigned short UInt16; + +#ifdef _LZMA_UINT32_IS_ULONG +typedef long Int32; +typedef unsigned long UInt32; +#else +typedef int Int32; +typedef unsigned int UInt32; +#endif + +#ifdef _SZ_NO_INT_64 + +/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers. + NOTES: Some code will work incorrectly in that case! */ + +typedef long Int64; +typedef unsigned long UInt64; + +#else + +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef __int64 Int64; +typedef unsigned __int64 UInt64; +#else +typedef long long int Int64; +typedef unsigned long long int UInt64; +#endif + +#endif + +#ifdef _LZMA_NO_SYSTEM_SIZE_T +typedef UInt32 SizeT; +#else +typedef size_t SizeT; +#endif + +typedef int Bool; +#define True 1 +#define False 0 + + +#ifdef _MSC_VER + +#if _MSC_VER >= 1300 +#define MY_NO_INLINE __declspec(noinline) +#else +#define MY_NO_INLINE +#endif + +#define MY_CDECL __cdecl +#define MY_STD_CALL __stdcall +#define MY_FAST_CALL MY_NO_INLINE __fastcall + +#else + +#define MY_CDECL +#define MY_STD_CALL +#define MY_FAST_CALL + +#endif + + +/* The following interfaces use first parameter as pointer to structure */ + +typedef struct +{ + SRes (*Read)(void *p, void *buf, size_t *size); + /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. + (output(*size) < input(*size)) is allowed */ +} ISeqInStream; + +/* it can return SZ_ERROR_INPUT_EOF */ +SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size); +SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType); +SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf); + +typedef struct +{ + size_t (*Write)(void *p, const void *buf, size_t size); + /* Returns: result - the number of actually written bytes. + (result < size) means error */ +} ISeqOutStream; + +typedef enum +{ + SZ_SEEK_SET = 0, + SZ_SEEK_CUR = 1, + SZ_SEEK_END = 2 +} ESzSeek; + +typedef struct +{ + SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */ + SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); +} ISeekInStream; + +typedef struct +{ + SRes (*Look)(void *p, void **buf, size_t *size); + /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. + (output(*size) > input(*size)) is not allowed + (output(*size) < input(*size)) is allowed */ + SRes (*Skip)(void *p, size_t offset); + /* offset must be <= output(*size) of Look */ + + SRes (*Read)(void *p, void *buf, size_t *size); + /* reads directly (without buffer). It's same as ISeqInStream::Read */ + SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); +} ILookInStream; + +SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size); +SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset); + +/* reads via ILookInStream::Read */ +SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType); +SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size); + +#define LookToRead_BUF_SIZE (1 << 14) + +typedef struct +{ + ILookInStream s; + ISeekInStream *realStream; + size_t pos; + size_t size; + Byte buf[LookToRead_BUF_SIZE]; +} CLookToRead; + +void LookToRead_CreateVTable(CLookToRead *p, int lookahead); +void LookToRead_Init(CLookToRead *p); + +typedef struct +{ + ISeqInStream s; + ILookInStream *realStream; +} CSecToLook; + +void SecToLook_CreateVTable(CSecToLook *p); + +typedef struct +{ + ISeqInStream s; + ILookInStream *realStream; +} CSecToRead; + +void SecToRead_CreateVTable(CSecToRead *p); + +typedef struct +{ + SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize); + /* Returns: result. (result != SZ_OK) means break. + Value (UInt64)(Int64)-1 for size means unknown value. */ +} ICompressProgress; + +typedef struct +{ + void *(*Alloc)(void *p, size_t size); + void (*Free)(void *p, void *address); /* address can be 0 */ +} ISzAlloc; + +#define IAlloc_Alloc(p, size) (p)->Alloc((p), size) +#define IAlloc_Free(p, a) (p)->Free((p), a) + +void* LzmaAllocMem(void *p, size_t size); +void LzmaFreeMem(void *p, void *address); + +#endif diff --git a/TitanEngine/MAINICON.ico b/TitanEngine/MAINICON.ico new file mode 100644 index 0000000000000000000000000000000000000000..a076621f40a9b722b8f506494735a6a402a5a0ff GIT binary patch literal 116222 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 z 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 f80p+qI#1999!5 + + + + + diff --git a/TitanEngine/TitanEngine.cpp b/TitanEngine/TitanEngine.cpp new file mode 100644 index 0000000..e794bfe --- /dev/null +++ b/TitanEngine/TitanEngine.cpp @@ -0,0 +1,29032 @@ +// +// TitanEngine SDK 2.0.3 +// TitanEngine.cpp : Defines the exported functions for the DLL application. +// + +// Global.constants +#include "stdafx.h" +// Disassembler.engine +#include "distorm.h" +// Windows libs +#include +#include +#include +#include +#include +#include +#include +#include +#include +// Global.Engine: +#include "definitions.h" +#include "resource.h" + +#define TE_VER_MAJOR 2 +#define TE_VER_MIDDLE 0 +#define TE_VER_MINOR 3 + +/*#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0'" \ + "processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")*/ + +// Global.variables: +char* szSharedOverlay = 0; +wchar_t* szSharedOverlayW = 0; +STARTUPINFOW dbgStartupInfo = {}; +PROCESS_INFORMATION dbgProcessInformation = {}; +DWORD DBGCode = DBG_CONTINUE; +DWORD CurrentExceptionsNumber = 0; +int BreakPointSetCount = 0; +BreakPointDetail BreakPointBuffer[MAXIMUM_BREAKPOINTS] = {}; +BYTE INT3BreakPoint = 0xCC; +BYTE INT3LongBreakPoint[2] = {0xCD, 0x03}; +BYTE UD2BreakPoint[2] = {0x0F, 0x0B}; +CustomHandler myDBGCustomHandler = {}; +PCustomHandler DBGCustomHandler = &myDBGCustomHandler; +DEBUG_EVENT DBGEvent = {}; +DEBUG_EVENT TerminateDBGEvent = {}; +CONTEXT DBGContext = {}; +HANDLE DBGFileHandle; +DWORD ProcessExitCode = 0; +LPVOID hListProcess = 0; +LPVOID hListThread = 0; +LPVOID hListLibrary = 0; +ULONG_PTR impDeltaStart = NULL; +ULONG_PTR impDeltaCurrent = NULL; +ULONG_PTR impImageBase = 0; +DWORD impAllocSize = 20 * 1024; +DWORD impDLLNumber = 0; +bool impMoveIAT = false; +ULONG_PTR impDLLDataList[1000][2]; +ULONG_PTR impDLLStringList[1000][2]; +ULONG_PTR impOrdinalList[1000][2]; +LPVOID expTableData = NULL; +LPVOID expTableDataCWP = NULL; +ULONG_PTR expImageBase = 0; +DWORD expExportNumber = 0; +bool expNamePresent = false; +DWORD expExportAddress[1000]; +DWORD expSortedNamePointers[1000]; +ULONG_PTR expNamePointers[1000]; +DWORD expNameHashes[1000]; +WORD expOrdinals[1000]; +IMAGE_EXPORT_DIRECTORY expExportData; +ULONG_PTR tlsCallBackList[100]; +int engineCurrentPlatform = UE_PLATFORM_x86; +ULONG_PTR engineTLSBreakOnCallBackAddress; +bool engineBackupTLSx64 = false; +bool engineTLSBreakOnCallBack = false; +LPVOID engineBackupArrayOfCallBacks = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE); +DWORD engineBackupNumberOfCallBacks = NULL; +DWORD engineBackupTLSAddress = NULL; +IMAGE_TLS_DIRECTORY32 engineBackupTLSDataX86 = {}; +IMAGE_TLS_DIRECTORY64 engineBackupTLSDataX64 = {}; +bool engineAlowModuleLoading = false; +bool engineCheckForwarders = true; +bool enginePassAllExceptions = true; +bool engineRemoveConsoleForDebugee = false; +bool engineBackupForCriticalFunctions = true; +bool engineCreatePathForFiles = true; // hardcoded +bool engineResetCustomHandler = true; +bool engineExecutePluginCallBack = true; +bool engineFileIsBeingDebugged = false; +ULONG_PTR engineReserveModuleBase = NULL; +DWORD engineWaitForDebugEventTimeOut = INFINITE; +LPVOID engineStepCallBack = NULL; +int engineStepCount = INFINITE; +bool engineStepActive = false; +bool engineAttachedToProcess = false; +bool engineProcessIsNowDetached = false; +ULONG_PTR engineAttachedProcessCallBack = NULL; +LPVOID engineAttachedProcessDebugInfo = NULL; +LPVOID engineExitThreadOneShootCallBack = NULL; +bool engineResumeProcessIfNoThreadIsActive = false; +bool engineAutoHideFromDebugger = false; +long engineDefaultBreakPointType = UE_BREAKPOINT_INT3; +bool engineDebuggingDLL = false; +wchar_t* engineDebuggingDLLFullFileName; +wchar_t* engineDebuggingDLLFileName; +//wchar_t* engineDebuggingDLLReserveFileName; +ULONG_PTR engineDebuggingDLLBase = NULL; +unsigned long long engineDebuggingMainModuleBase = NULL; +ULONG_PTR engineFakeDLLHandle = NULL; +char engineDisassembledInstruction[128]; +ExpertDebug engineExpertDebug = {}; +ULONG_PTR engineReservedMemoryLeft[UE_MAX_RESERVED_MEMORY_LEFT]; +HANDLE engineReservedMemoryProcess = NULL; +void* engineFindOEPCallBack = NULL; +void* engineFindOEPUserCallBack = NULL; +ULONG_PTR DebugModuleEntryPoint; +ULONG_PTR DebugModuleImageBase; +LPVOID DebugModuleEntryPointCallBack; +LPVOID DebugExeFileEntryPointCallBack; +HMODULE engineHandle; +HARDWARE_DATA DebugRegister0 = {}; +HARDWARE_DATA DebugRegister1 = {}; +HARDWARE_DATA DebugRegister2 = {}; +HARDWARE_DATA DebugRegister3 = {}; +LPVOID RelocationData = NULL; +LPVOID RelocationLastPage = NULL; +LPVOID RelocationStartPosition = NULL; +LPVOID RelocationWritePosition = NULL; +ULONG_PTR RelocationOldImageBase; +ULONG_PTR RelocationNewImageBase; +char engineExtractedFolderName[512]; +char engineExtractedFileName[512]; +wchar_t engineExtractedFileNameW[512]; +char engineFoundAPIName[512]; +char engineFoundDLLName[512]; +wchar_t szBackupDebuggedFileName[512]; +//wchar_t szReserveModuleName[512]; +wchar_t szDebuggerName[512]; +char szParameterString[512]; +// Global.Engine.Strings: +wchar_t engineSzEngineFile[MAX_PATH]; +wchar_t engineSzEngineFolder[MAX_PATH]; +wchar_t engineSzEngineGarbageFolder[MAX_PATH]; +// Global.Engine.Librarian: +LIBRARY_ITEM_DATA LibraryInfoData = {}; +LPVOID LibrarianData = VirtualAlloc(NULL, MAX_LIBRARY_BPX * sizeof LIBRARY_BREAK_DATA, MEM_COMMIT, PAGE_READWRITE); +// Global.Engine.TraceOEP: +GenericOEPTracerData glbEntryTracerData = {}; +// Global.Engine.Dependency: +LPVOID engineDependencyFiles; +LPVOID engineDependencyFilesCWP; +// Global.Engine.Window: +HWND EngineBoxHandle; +HWND EngineWindowHandle; +char szWindowUnpackerName[128]; +char szWindowUnpackerTitle[128]; +char szWindowUnpackerLongTitle[128]; +char szWindowUnpackerAuthor[128]; +void* EngineStartUnpackingCallBack; +// Global.Engine.Simplify +bool EngineUnpackerOptionLogData; +bool EngineUnpackerFileImporterInit; +bool EngineUnpackerOptionRealingFile; +bool EngineUnpackerOptionMoveOverlay; +bool EngineUnpackerOptionRelocationFix; +ULONG_PTR EngineUnpackerOptionUnpackedOEP; +wchar_t szEngineUnpackerInputFile[MAX_PATH]; +wchar_t szEngineUnpackerOutputFile[MAX_PATH]; +wchar_t szEngineUnpackerSnapShot1[MAX_PATH]; +wchar_t szEngineUnpackerSnapShot2[MAX_PATH]; +FILE_STATUS_INFO EngineUnpackerFileStatus = {}; +LPPROCESS_INFORMATION pEngineUnpackerProcessHandle; +std::vector EngineUnpackerBreakInfo; +// Global.Engine.Hooks: +DWORD buffPatchedEntrySize = 0x3000; +void* CwpBuffPatchedEntry; +void* buffPatchedEntry; +std::vector hookEntry; +// Global.Engine.Plugins: +std::vector Plugin; + +// Global.Engine.Hash: +unsigned long Crc32Table[256]; + +// Global.Engine.Constants: +#define UE_MODULEx86 0x2000; +#define UE_MODULEx64 0x2000; + +// Global.Handle.functions: +bool EngineCloseHandle(HANDLE myHandle) +{ + + DWORD HandleFlags; + + if(GetHandleInformation(myHandle, &HandleFlags)) + { + if(CloseHandle(myHandle)) + { + return(true); + } + else + { + return(false); + } + } + else + { + return(false); + } +} +// Global.Mapping.functions: +bool MapFileEx(char* szFileName, DWORD ReadOrWrite, LPHANDLE FileHandle, LPDWORD FileSize, LPHANDLE FileMap, LPVOID FileMapVA, DWORD SizeModifier) +{ + + HANDLE hFile = 0; + DWORD FileAccess = 0; + DWORD FileMapType = 0; + DWORD FileMapViewType = 0; + DWORD mfFileSize = 0; + HANDLE mfFileMap = 0; + LPVOID mfFileMapVA = 0; + + if(ReadOrWrite == UE_ACCESS_READ) + { + FileAccess = GENERIC_READ; + FileMapType = PAGE_READONLY; + FileMapViewType = FILE_MAP_READ; + } + else if(ReadOrWrite == UE_ACCESS_WRITE) + { + FileAccess = GENERIC_WRITE; + FileMapType = PAGE_READWRITE; + FileMapViewType = FILE_MAP_WRITE; + } + else if(ReadOrWrite == UE_ACCESS_ALL) + { + FileAccess = GENERIC_READ+GENERIC_WRITE+GENERIC_EXECUTE; + FileMapType = PAGE_EXECUTE_READWRITE; + FileMapViewType = FILE_MAP_WRITE; + } + else + { + FileAccess = GENERIC_READ+GENERIC_WRITE+GENERIC_EXECUTE; + FileMapType = PAGE_EXECUTE_READWRITE; + FileMapViewType = FILE_MAP_ALL_ACCESS; + } + + hFile = CreateFileA(szFileName, FileAccess, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if(hFile != INVALID_HANDLE_VALUE) + { + *FileHandle = hFile; + mfFileSize = GetFileSize(hFile,NULL); + mfFileSize = mfFileSize + SizeModifier; + *FileSize = mfFileSize; + mfFileMap = CreateFileMappingA(hFile, NULL, FileMapType, NULL, mfFileSize, NULL); + if(mfFileMap != NULL) + { + *FileMap = mfFileMap; + mfFileMapVA = MapViewOfFile(mfFileMap, FileMapViewType, NULL, NULL, NULL); + if(mfFileMapVA != NULL) + { + RtlMoveMemory(FileMapVA, &mfFileMapVA, sizeof ULONG_PTR); + return(true); + } + } + RtlZeroMemory(FileMapVA, sizeof ULONG_PTR); + *FileHandle = NULL; + *FileSize = NULL; + EngineCloseHandle(hFile); + } + else + { + RtlZeroMemory(FileMapVA, sizeof ULONG_PTR); + } + return(false); +} + +bool MapFileExW(wchar_t* szFileName, DWORD ReadOrWrite, LPHANDLE FileHandle, LPDWORD FileSize, LPHANDLE FileMap, LPVOID FileMapVA, DWORD SizeModifier) +{ + + HANDLE hFile = 0; + DWORD FileAccess = 0; + DWORD FileMapType = 0; + DWORD FileMapViewType = 0; + DWORD mfFileSize = 0; + HANDLE mfFileMap = 0; + LPVOID mfFileMapVA = 0; + + if(ReadOrWrite == UE_ACCESS_READ) + { + FileAccess = GENERIC_READ; + FileMapType = PAGE_READONLY; + FileMapViewType = FILE_MAP_READ; + } + else if(ReadOrWrite == UE_ACCESS_WRITE) + { + FileAccess = GENERIC_WRITE; + FileMapType = PAGE_READWRITE; + FileMapViewType = FILE_MAP_WRITE; + } + else if(ReadOrWrite == UE_ACCESS_ALL) + { + FileAccess = GENERIC_READ+GENERIC_WRITE+GENERIC_EXECUTE; + FileMapType = PAGE_EXECUTE_READWRITE; + FileMapViewType = FILE_MAP_WRITE; + } + else + { + FileAccess = GENERIC_READ+GENERIC_WRITE+GENERIC_EXECUTE; + FileMapType = PAGE_EXECUTE_READWRITE; + FileMapViewType = FILE_MAP_ALL_ACCESS; + } + + hFile = CreateFileW(szFileName, FileAccess, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if(hFile != INVALID_HANDLE_VALUE) + { + *FileHandle = hFile; + mfFileSize = GetFileSize(hFile,NULL); + mfFileSize = mfFileSize + SizeModifier; + *FileSize = mfFileSize; + mfFileMap = CreateFileMappingA(hFile, NULL, FileMapType, NULL, mfFileSize, NULL); + if(mfFileMap != NULL) + { + *FileMap = mfFileMap; + mfFileMapVA = MapViewOfFile(mfFileMap, FileMapViewType, NULL, NULL, NULL); + if(mfFileMapVA != NULL) + { + RtlMoveMemory(FileMapVA, &mfFileMapVA, sizeof ULONG_PTR); + return(true); + } + } + RtlZeroMemory(FileMapVA, sizeof ULONG_PTR); + *FileHandle = NULL; + *FileSize = NULL; + EngineCloseHandle(hFile); + } + else + { + RtlZeroMemory(FileMapVA, sizeof ULONG_PTR); + } + return(false); +} + +void UnMapFileEx(HANDLE FileHandle, DWORD FileSize, HANDLE FileMap, ULONG_PTR FileMapVA) +{ + + LPVOID ufFileMapVA = (void*)FileMapVA; + + if(UnmapViewOfFile(ufFileMapVA)) + { + EngineCloseHandle(FileMap); + SetFilePointer(FileHandle,FileSize,NULL,FILE_BEGIN); + SetEndOfFile(FileHandle); + EngineCloseHandle(FileHandle); + } +} +// Global.Engine.functions: +void EngineGlobalTestFunction() +{ + MessageBoxA(NULL, "TitanEngine test message!", "TitanEngine2:", 0x40); +} +void EngineExecutePluginReleaseCallBack() +{ + + typedef void(__stdcall *fPluginReleaseExec)(); + fPluginReleaseExec myPluginReleaseExec; + + for(unsigned int i = 0; i < Plugin.size(); i++) + { + __try + { + if(Plugin[i].TitanReleasePlugin != NULL) + { + myPluginReleaseExec = (fPluginReleaseExec)Plugin[i].TitanReleasePlugin; + myPluginReleaseExec(); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + + } + } +} +void EngineExecutePluginResetCallBack() +{ + + typedef void(__stdcall *fPluginResetExec)(); + fPluginResetExec myPluginResetExec; + + for(unsigned int i = 0; i < Plugin.size(); i++) + { + __try + { + if(Plugin[i].TitanResetPlugin != NULL) + { + myPluginResetExec = (fPluginResetExec)Plugin[i].TitanResetPlugin; + myPluginResetExec(); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + + } + } +} +void EngineExecutePluginDebugCallBack(LPDEBUG_EVENT debugEvent, int CallReason) +{ + + typedef void(__stdcall *fPluginDebugExec)(LPDEBUG_EVENT debugEvent, int CallReason); + fPluginDebugExec myPluginDebugExec; + + for(unsigned int i = 0; i < Plugin.size(); i++) + { + __try + { + if(!Plugin[i].PluginDisabled) + { + if(Plugin[i].TitanDebuggingCallBack != NULL) + { + myPluginDebugExec = (fPluginDebugExec)Plugin[i].TitanDebuggingCallBack; + myPluginDebugExec(debugEvent, CallReason); + } + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + + } + } +} +bool EngineIsThereFreeHardwareBreakSlot(LPDWORD FreeRegister) +{ + + if(DebugRegister0.DrxEnabled == false) + { + if(FreeRegister != NULL) + { + *FreeRegister = UE_DR0; + } + return(true); + } + else if(DebugRegister1.DrxEnabled == false) + { + if(FreeRegister != NULL) + { + *FreeRegister = UE_DR1; + } + return(true); + } + else if(DebugRegister2.DrxEnabled == false) + { + if(FreeRegister != NULL) + { + *FreeRegister = UE_DR2; + } + return(true); + } + else if(DebugRegister3.DrxEnabled == false) + { + if(FreeRegister != NULL) + { + *FreeRegister = UE_DR3; + } + return(true); + } + return(false); +} +bool EngineFileExists(char* szFileName) +{ + + HANDLE hFile; + + hFile = CreateFileA(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if(hFile != INVALID_HANDLE_VALUE) + { + EngineCloseHandle(hFile); + return(true); + } + else + { + return(false); + } +} +char* EngineExtractPath(char* szFileName) +{ + + int i; + + RtlZeroMemory(&engineExtractedFolderName, 512); + lstrcpyA(engineExtractedFolderName, szFileName); + i = lstrlenA(engineExtractedFolderName); + while(i > 0 && engineExtractedFolderName[i] != 0x5C) + { + engineExtractedFolderName[i] = 0x00; + i--; + } + return(engineExtractedFolderName); +} +char* EngineExtractFileName(char* szFileName) +{ + + int i; + int j; + int x = 0; + + i = lstrlenA(szFileName); + RtlZeroMemory(&engineExtractedFileName, 512); + while(i > 0 && szFileName[i] != 0x5C) + { + i--; + } + if(szFileName[i] == 0x5C) + { + for(j = i + 1; j <= lstrlenA(szFileName); j++) + { + engineExtractedFileName[x] = szFileName[j]; + x++; + } + } + else + { + return(szFileName); + } + return(engineExtractedFileName); +} +bool EngineCreatePathForFile(char* szFileName) +{ + + int i,j; + char szFolderName[2 * MAX_PATH] = {}; + char szCreateFolder[2 * MAX_PATH] = {}; + + if(engineCreatePathForFiles) + { + i = lstrlenA(szFileName); + while(szFileName[i] != '\\' && i > NULL) + { + i--; + } + if(i != NULL) + { + RtlMoveMemory(szFolderName, szFileName, i + 1); + if(!CreateDirectoryA(szFolderName, NULL)) + { + if(GetLastError() != ERROR_ALREADY_EXISTS) + { + j = lstrlenA(szFolderName); + for(i = 4; i < j; i++) + { + if(szFileName[i] == '\\') + { + RtlZeroMemory(szCreateFolder, 2 * MAX_PATH); + RtlMoveMemory(szCreateFolder, szFileName, i + 1); + CreateDirectoryA(szCreateFolder, NULL); + } + } + } + } + } + else + { + return(true); + } + } + return(true); +} +bool EngineCreatePathForFileW(wchar_t* szFileName) +{ + + int i,j; + wchar_t szFolderName[2 * MAX_PATH] = {}; + wchar_t szCreateFolder[2 * MAX_PATH] = {}; + + if(engineCreatePathForFiles) + { + i = lstrlenW(szFileName); + while(szFileName[i] != '\\' && i > NULL) + { + i--; + } + if(i != NULL) + { + RtlMoveMemory(szFolderName, szFileName, (i * 2) + 2); + if(!CreateDirectoryW(szFolderName, NULL)) + { + if(GetLastError() != ERROR_ALREADY_EXISTS) + { + j = lstrlenW(szFolderName); + for(i = 4; i < j; i++) + { + if(szFileName[i] == '\\') + { + RtlZeroMemory(szCreateFolder, 2 * MAX_PATH); + RtlMoveMemory(szCreateFolder, szFileName, (i * 2) + 1); + CreateDirectoryW(szCreateFolder, NULL); + } + } + } + } + } + else + { + return(true); + } + } + return(true); +} +wchar_t* EngineExtractFileNameW(wchar_t* szFileName) +{ + + int i; + int j; + int x = 0; + + i = lstrlenW(szFileName); + RtlZeroMemory(&engineExtractedFileNameW, sizeof engineExtractedFileNameW); + while(i > 0 && szFileName[i] != 0x5C) + { + i--; + } + if(szFileName[i] == 0x5C) + { + for(j = i + 1; j <= lstrlenW(szFileName); j++) + { + engineExtractedFileNameW[x] = szFileName[j]; + x++; + } + } + else + { + return(szFileName); + } + return(engineExtractedFileNameW); +} +bool EngineIsPointedMemoryString(ULONG_PTR PossibleStringPtr) +{ + + bool StringIsValid = true; + unsigned int i = 512; + MEMORY_BASIC_INFORMATION MemInfo; + DWORD MaxDisassmSize; + BYTE TestChar; + + VirtualQueryEx(GetCurrentProcess(), (LPVOID)PossibleStringPtr, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + if(MemInfo.State == MEM_COMMIT) + { + if((ULONG_PTR)MemInfo.BaseAddress + (ULONG_PTR)MemInfo.RegionSize - PossibleStringPtr <= 512) + { + MaxDisassmSize = (DWORD)((ULONG_PTR)MemInfo.BaseAddress + (ULONG_PTR)MemInfo.RegionSize - PossibleStringPtr - 1); + VirtualQueryEx(GetCurrentProcess(), (LPVOID)(PossibleStringPtr + (ULONG_PTR)MemInfo.RegionSize), &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + if(MemInfo.State != MEM_COMMIT) + { + i = MaxDisassmSize; + } + else + { + MaxDisassmSize = 512; + } + } + else + { + MaxDisassmSize = 512; + } + RtlMoveMemory(&TestChar, (LPVOID)PossibleStringPtr, 1); + while(i > NULL && StringIsValid == true && TestChar != 0x00) + { + RtlMoveMemory(&TestChar, (LPVOID)PossibleStringPtr, 1); + if(TestChar < 32 || TestChar > 126) + { + if(TestChar != 0x00) + { + StringIsValid = false; + } + } + PossibleStringPtr++; + i--; + } + if(StringIsValid == true && MaxDisassmSize - i > 4) + { + return(true); + } + else + { + return(false); + } + } + return(false); +} +int EnginePointedMemoryStringLength(ULONG_PTR PossibleStringPtr) +{ + + bool StringIsValid = true; + unsigned int i = 512; + MEMORY_BASIC_INFORMATION MemInfo; + DWORD MaxDisassmSize; + BYTE TestChar; + + VirtualQueryEx(GetCurrentProcess(), (LPVOID)PossibleStringPtr, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + if(MemInfo.State == MEM_COMMIT) + { + if((ULONG_PTR)MemInfo.BaseAddress + (ULONG_PTR)MemInfo.RegionSize - PossibleStringPtr <= 512) + { + MaxDisassmSize = (DWORD)((ULONG_PTR)MemInfo.BaseAddress + (ULONG_PTR)MemInfo.RegionSize - PossibleStringPtr - 1); + VirtualQueryEx(GetCurrentProcess(), (LPVOID)(PossibleStringPtr + (ULONG_PTR)MemInfo.RegionSize), &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + if(MemInfo.State != MEM_COMMIT) + { + i = MaxDisassmSize; + } + else + { + MaxDisassmSize = 512; + } + } + else + { + MaxDisassmSize = 512; + } + RtlMoveMemory(&TestChar, (LPVOID)PossibleStringPtr, 1); + while(i > NULL && StringIsValid == true && TestChar != 0x00) + { + RtlMoveMemory(&TestChar, (LPVOID)PossibleStringPtr, 1); + if(TestChar < 32 || TestChar > 126) + { + if(TestChar != 0x00) + { + StringIsValid = false; + } + } + PossibleStringPtr++; + i--; + } + if(StringIsValid == true && 512 - i > 4) + { + i = 512 - i; + return(i); + } + else + { + return(NULL); + } + } + return(NULL); +} +bool EngineCompareResourceString(wchar_t* String1, wchar_t* String2) +{ + + PMEMORY_COMPARE_HANDLER memData = (PMEMORY_COMPARE_HANDLER)String1; + wchar_t StringCmp[MAX_PATH] = {}; + + String1 = (wchar_t*)((ULONG_PTR)String1 + 2); + RtlMoveMemory(&StringCmp[0], &String1[0], memData->Array.wArrayEntry[0] * 2); + if(lstrcmpiW(StringCmp, String2) == NULL) + { + return(true); + } + return(false); +} +long long EngineEstimateNewSectionRVA(ULONG_PTR FileMapVA) +{ + + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + PIMAGE_SECTION_HEADER PESections; + DWORD NewSectionVirtualOffset = 0; + DWORD SectionNumber = 0; + BOOL FileIs64; + + if(FileMapVA != NULL) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + return(0); + } + if(!FileIs64) + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader32 + PEHeader32->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + SectionNumber = PEHeader32->FileHeader.NumberOfSections; + __try + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + (SectionNumber - 1) * IMAGE_SIZEOF_SECTION_HEADER); + NewSectionVirtualOffset = PESections->VirtualAddress + (PESections->Misc.VirtualSize / PEHeader32->OptionalHeader.SectionAlignment) * PEHeader32->OptionalHeader.SectionAlignment; + if(NewSectionVirtualOffset < PESections->VirtualAddress + PESections->Misc.VirtualSize) + { + NewSectionVirtualOffset = NewSectionVirtualOffset + PEHeader32->OptionalHeader.SectionAlignment; + } + return((ULONG_PTR)(NewSectionVirtualOffset + PEHeader32->OptionalHeader.ImageBase)); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return(0); + } + } + else + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader64 + PEHeader64->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + SectionNumber = PEHeader64->FileHeader.NumberOfSections; + __try + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + (SectionNumber - 1) * IMAGE_SIZEOF_SECTION_HEADER); + NewSectionVirtualOffset = PESections->VirtualAddress + (PESections->Misc.VirtualSize / PEHeader64->OptionalHeader.SectionAlignment) * PEHeader64->OptionalHeader.SectionAlignment; + if(NewSectionVirtualOffset < PESections->VirtualAddress + PESections->Misc.VirtualSize) + { + NewSectionVirtualOffset = NewSectionVirtualOffset + PEHeader32->OptionalHeader.SectionAlignment; + } + return((ULONG_PTR)(NewSectionVirtualOffset + PEHeader64->OptionalHeader.ImageBase)); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return(0); + } + } + } + return(0); +} +bool EngineExtractForwarderData(ULONG_PTR PossibleStringPtr, LPVOID szFwdDLLName, LPVOID szFwdAPIName) +{ + + __try + { + LPVOID lpPossibleStringPtr = (LPVOID)PossibleStringPtr; + BYTE TestChar; + + RtlMoveMemory(&TestChar, (LPVOID)PossibleStringPtr, 1); + while(TestChar != 0x2E && TestChar != 0x00) + { + RtlMoveMemory(&TestChar, (LPVOID)PossibleStringPtr, 1); + PossibleStringPtr++; + } + if(TestChar == 0x00) + { + return(false); + } + PossibleStringPtr--; + RtlMoveMemory(szFwdDLLName, lpPossibleStringPtr, PossibleStringPtr - (ULONG_PTR)lpPossibleStringPtr); + lstrcatA((LPSTR)szFwdDLLName, ".dll"); + lpPossibleStringPtr = (LPVOID)(PossibleStringPtr + 1); + RtlMoveMemory(&TestChar, (LPVOID)PossibleStringPtr, 1); + if(TestChar == 0x23) + { + lpPossibleStringPtr = (LPVOID)(PossibleStringPtr + 1); + } + while(TestChar != 0x00) + { + RtlMoveMemory(&TestChar, (LPVOID)PossibleStringPtr, 1); + PossibleStringPtr++; + } + RtlMoveMemory(szFwdAPIName, lpPossibleStringPtr, PossibleStringPtr - (ULONG_PTR)lpPossibleStringPtr); + return(true); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return(false); + } +} +bool EngineGrabDataFromMappedFile(HANDLE hFile, ULONG_PTR FileMapVA, ULONG_PTR FileOffset, DWORD CopySize, LPVOID CopyToMemory) +{ + + DWORD rfNumberOfBytesRead = NULL; + + RtlZeroMemory(CopyToMemory, CopySize); + SetFilePointer(hFile, (DWORD)(FileOffset - FileMapVA), NULL, FILE_BEGIN); + if(ReadFile(hFile, CopyToMemory, CopySize, &rfNumberOfBytesRead, NULL)) + { + return(true); + } + else + { + return(false); + } +} +bool EngineExtractResource(char* szResourceName, wchar_t* szExtractedFileName) +{ + + HRSRC hResource; + HGLOBAL hResourceGlobal; + DWORD ResourceSize; + LPVOID ResourceData; + DWORD NumberOfBytesWritten; + HANDLE hFile; + + hResource = FindResourceA(engineHandle, (LPCSTR)szResourceName, "BINARY"); + if(hResource != NULL) + { + hResourceGlobal = LoadResource(engineHandle, hResource); + if(hResourceGlobal != NULL) + { + ResourceSize = SizeofResource(engineHandle, hResource); + ResourceData = LockResource(hResourceGlobal); + if(EngineCreatePathForFileW(szExtractedFileName)) + { + hFile = CreateFileW(szExtractedFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if(hFile != INVALID_HANDLE_VALUE) + { + WriteFile(hFile, ResourceData, ResourceSize, &NumberOfBytesWritten, NULL); + EngineCloseHandle(hFile); + } + else + { + return(false); + } + } + } + return(true); + } + return(false); +} +bool EngineIsDependencyPresent(char* szFileName, char* szDependencyForFile, char* szPresentInFolder) +{ + + int i,j; + HANDLE hFile; + char szTryFileName[512]; + + if(szPresentInFolder != NULL) + { + RtlZeroMemory(&szTryFileName, 512); + lstrcpyA(szTryFileName, szPresentInFolder); + if(szTryFileName[lstrlenA(szTryFileName)-1] != 0x5C) + { + szTryFileName[lstrlenA(szTryFileName)] = 0x5C; + } + lstrcatA(szTryFileName, szFileName); + hFile = CreateFileA(szTryFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if(hFile != INVALID_HANDLE_VALUE) + { + EngineCloseHandle(hFile); + return(true); + } + } + if(szFileName != NULL) + { + hFile = CreateFileA(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if(hFile != INVALID_HANDLE_VALUE) + { + EngineCloseHandle(hFile); + return(true); + } + if(GetSystemDirectoryA(szTryFileName, 512) > NULL) + { + lstrcatA(szTryFileName, "\\"); + lstrcatA(szTryFileName, szFileName); + hFile = CreateFileA(szTryFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if(hFile != INVALID_HANDLE_VALUE) + { + EngineCloseHandle(hFile); + return(true); + } + } + if(GetWindowsDirectoryA(szTryFileName, 512) > NULL) + { + lstrcatA(szTryFileName, "\\"); + lstrcatA(szTryFileName, szFileName); + hFile = CreateFileA(szTryFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if(hFile != INVALID_HANDLE_VALUE) + { + EngineCloseHandle(hFile); + return(true); + } + } + if(szDependencyForFile != NULL) + { + RtlZeroMemory(&szTryFileName, 512); + i = lstrlenA(szDependencyForFile); + while(i > 0 && szDependencyForFile[i] != 0x5C) + { + i--; + } + for(j = 0; j <= i; j++) + { + szTryFileName[j] = szDependencyForFile[j]; + } + lstrcatA(szTryFileName, szFileName); + hFile = CreateFileA(szTryFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if(hFile != INVALID_HANDLE_VALUE) + { + EngineCloseHandle(hFile); + return(true); + } + } + } + return(false); +} +bool EngineIsDependencyPresentW(wchar_t* szFileName, wchar_t* szDependencyForFile, wchar_t* szPresentInFolder) +{ + + int i,j; + HANDLE hFile; + wchar_t szTryFileName[512]; + + if(szPresentInFolder != NULL) + { + RtlZeroMemory(&szTryFileName, 512); + lstrcpyW(szTryFileName, szPresentInFolder); + if(szTryFileName[lstrlenW(szTryFileName)-1] != 0x5C) + { + szTryFileName[lstrlenW(szTryFileName)] = 0x5C; + } + lstrcatW(szTryFileName, szFileName); + hFile = CreateFileW(szTryFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if(hFile != INVALID_HANDLE_VALUE) + { + EngineCloseHandle(hFile); + return(true); + } + } + if(szFileName != NULL) + { + hFile = CreateFileW(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if(hFile != INVALID_HANDLE_VALUE) + { + EngineCloseHandle(hFile); + return(true); + } + if(GetSystemDirectoryW(szTryFileName, 512) > NULL) + { + lstrcatW(szTryFileName, L"\\"); + lstrcatW(szTryFileName, szFileName); + hFile = CreateFileW(szTryFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if(hFile != INVALID_HANDLE_VALUE) + { + EngineCloseHandle(hFile); + return(true); + } + } + if(GetWindowsDirectoryW(szTryFileName, 512) > NULL) + { + lstrcatW(szTryFileName, L"\\"); + lstrcatW(szTryFileName, szFileName); + hFile = CreateFileW(szTryFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if(hFile != INVALID_HANDLE_VALUE) + { + EngineCloseHandle(hFile); + return(true); + } + } + if(szDependencyForFile != NULL) + { + RtlZeroMemory(&szTryFileName, 512); + i = lstrlenW(szDependencyForFile); + while(i > 0 && szDependencyForFile[i] != 0x5C) + { + i--; + } + for(j = 0; j <= i; j++) + { + szTryFileName[j] = szDependencyForFile[j]; + } + lstrcatW(szTryFileName, szFileName); + hFile = CreateFileW(szTryFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if(hFile != INVALID_HANDLE_VALUE) + { + EngineCloseHandle(hFile); + return(true); + } + } + } + return(false); +} +bool EngineGetDependencyLocation(char* szFileName, char* szDependencyForFile, void* szLocationOfTheFile, int MaxStringSize) +{ + + int i,j; + HANDLE hFile; + char szTryFileName[512]; + + if(szFileName != NULL) + { + hFile = CreateFileA(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if(hFile != INVALID_HANDLE_VALUE) + { + RtlZeroMemory(szLocationOfTheFile, MaxStringSize); + if(lstrlenA(szFileName) <= MaxStringSize) + { + RtlMoveMemory(szLocationOfTheFile, szFileName, lstrlenA(szFileName)); + } + EngineCloseHandle(hFile); + return(true); + } + if(GetSystemDirectoryA(szTryFileName, 512) > NULL) + { + lstrcatA(szTryFileName, "\\"); + lstrcatA(szTryFileName, szFileName); + hFile = CreateFileA(szTryFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if(hFile != INVALID_HANDLE_VALUE) + { + RtlZeroMemory(szLocationOfTheFile, MaxStringSize); + if(lstrlenA(szTryFileName) <= MaxStringSize) + { + RtlMoveMemory(szLocationOfTheFile, &szTryFileName, lstrlenA(szTryFileName)); + } + EngineCloseHandle(hFile); + return(true); + } + } + if(GetWindowsDirectoryA(szTryFileName, 512) > NULL) + { + lstrcatA(szTryFileName, "\\"); + lstrcatA(szTryFileName, szFileName); + hFile = CreateFileA(szTryFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if(hFile != INVALID_HANDLE_VALUE) + { + RtlZeroMemory(szLocationOfTheFile, MaxStringSize); + if(lstrlenA(szTryFileName) <= MaxStringSize) + { + RtlMoveMemory(szLocationOfTheFile, &szTryFileName, lstrlenA(szTryFileName)); + } + EngineCloseHandle(hFile); + return(true); + } + } + if(szDependencyForFile != NULL) + { + RtlZeroMemory(&szTryFileName, 512); + i = lstrlenA(szDependencyForFile); + while(i > 0 && szDependencyForFile[i] != 0x5C) + { + i--; + } + for(j = 0; j <= i; j++) + { + szTryFileName[j] = szDependencyForFile[j]; + } + lstrcatA(szTryFileName, szFileName); + hFile = CreateFileA(szTryFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if(hFile != INVALID_HANDLE_VALUE) + { + RtlZeroMemory(szLocationOfTheFile, MaxStringSize); + if(lstrlenA(szTryFileName) <= MaxStringSize) + { + RtlMoveMemory(szLocationOfTheFile, &szTryFileName, lstrlenA(szTryFileName)); + } + EngineCloseHandle(hFile); + return(true); + } + } + } + return(false); +} +long EngineHashString(char* szStringToHash) +{ + + int i = NULL; + DWORD HashValue = NULL; + + if(szStringToHash != NULL) + { + for(i = 0; i < lstrlenA(szStringToHash); i++) + { + HashValue = (((HashValue << 7) | (HashValue >> (32 - 7))) ^ szStringToHash[i]); + } + } + return(HashValue); +} +long EngineHashMemory(char* MemoryAddress, int MemorySize, DWORD InitialHashValue) +{ + + int i = NULL; + DWORD HashValue = InitialHashValue; + + for(i = 0; i < MemorySize; i++) + { + if(MemoryAddress[i] != NULL) + { + HashValue = (((HashValue << 7) | (HashValue >> (32 - 7))) ^ MemoryAddress[i]); + } + } + return(HashValue); +} +bool EngineIsBadReadPtrEx(LPVOID DataPointer, DWORD DataSize) +{ + + MEMORY_BASIC_INFORMATION MemInfo; + + while(DataSize > NULL) + { + VirtualQuery(DataPointer, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + if(MemInfo.AllocationProtect == MEM_FREE || MemInfo.AllocationProtect == MEM_PRIVATE) + { + return(false); + } + DataPointer = (LPVOID)((ULONG_PTR)DataPointer + MemInfo.RegionSize); + if(MemInfo.RegionSize > DataSize) + { + DataSize = NULL; + } + else + { + DataSize = DataSize - (DWORD)MemInfo.RegionSize; + } + } + return(true); +} +bool EngineValidateResource(HMODULE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG_PTR lParam) +{ + + HRSRC hResource; + HGLOBAL hResourceGlobal; + DWORD ResourceSize; + LPVOID ResourceData; + BYTE ReturnData = UE_FILED_FIXABLE_CRITICAL; + + hResource = FindResourceA(hModule, (LPCSTR)lpszName, (LPCSTR)lpszType); + if(hResource != NULL) + { + hResourceGlobal = LoadResource(hModule, hResource); + if(hResourceGlobal != NULL) + { + ResourceSize = SizeofResource(hModule, hResource); + ResourceData = LockResource(hResourceGlobal); + if(ResourceData != NULL) + { + if(!EngineIsBadReadPtrEx(ResourceData, ResourceSize)) + { + RtlMoveMemory((LPVOID)lParam, &ReturnData, 1); + return(false); + } + } + else + { + RtlMoveMemory((LPVOID)lParam, &ReturnData, 1); + return(false); + } + } + return(true); + } + RtlMoveMemory((LPVOID)lParam, &ReturnData, 1); + return(false); +} +bool EngineValidateHeader(ULONG_PTR FileMapVA, HANDLE hFileProc, LPVOID ImageBase, PIMAGE_DOS_HEADER DOSHeader, bool IsFile) +{ + + MODULEINFO ModuleInfo; + DWORD MemorySize = NULL; + PIMAGE_NT_HEADERS32 PEHeader32; + IMAGE_NT_HEADERS32 RemotePEHeader32; + MEMORY_BASIC_INFORMATION MemoryInfo; + ULONG_PTR NumberOfBytesRW = NULL; + + if(IsFile) + { + if(hFileProc == NULL) + { + VirtualQueryEx(GetCurrentProcess(), (LPVOID)FileMapVA, &MemoryInfo, sizeof MEMORY_BASIC_INFORMATION); + VirtualQueryEx(GetCurrentProcess(), MemoryInfo.AllocationBase, &MemoryInfo, sizeof MEMORY_BASIC_INFORMATION); + MemorySize = (DWORD)((ULONG_PTR)MemoryInfo.AllocationBase + (ULONG_PTR)MemoryInfo.RegionSize - (ULONG_PTR)FileMapVA); + } + else + { + MemorySize = GetFileSize(hFileProc, NULL); + } + __try + { + if(DOSHeader->e_magic == 0x5A4D) + { + if(DOSHeader->e_lfanew + sizeof IMAGE_DOS_HEADER + sizeof IMAGE_NT_HEADERS64 < MemorySize) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->Signature != 0x4550) + { + return(false); + } + else + { + return(true); + } + } + else + { + return(false); + } + } + else + { + return(false); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return(false); + } + } + else + { + RtlZeroMemory(&ModuleInfo, sizeof MODULEINFO); + GetModuleInformation(hFileProc, (HMODULE)ImageBase, &ModuleInfo, sizeof MODULEINFO); + __try + { + if(DOSHeader->e_magic == 0x5A4D) + { + if(DOSHeader->e_lfanew + sizeof IMAGE_DOS_HEADER + sizeof IMAGE_NT_HEADERS64 < ModuleInfo.SizeOfImage) + { + if(ReadProcessMemory(hFileProc, (LPVOID)((ULONG_PTR)ImageBase + DOSHeader->e_lfanew), &RemotePEHeader32, sizeof IMAGE_NT_HEADERS32, &NumberOfBytesRW)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)(&RemotePEHeader32); + if(PEHeader32->Signature != 0x4550) + { + return(false); + } + else + { + return(true); + } + } + else + { + return(false); + } + } + else + { + return(false); + } + } + else + { + return(false); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return(false); + } + } +} +long long EngineSimulateNtLoaderW(wchar_t* szFileName) +{ + + DWORD PeHeaderSize; + LPVOID AllocatedFile; + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + PIMAGE_SECTION_HEADER PESections; + DWORD SectionNumber = 0; + DWORD SectionRawOffset = 0; + DWORD SectionRawSize = 0; + BOOL FileIs64; + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + + if(MapFileExW(szFileName, UE_ACCESS_READ, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, FileHandle, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(NULL); + } + if(!FileIs64) + { + AllocatedFile = VirtualAlloc(NULL, PEHeader32->OptionalHeader.SizeOfImage, MEM_COMMIT, PAGE_READWRITE); + __try + { + PeHeaderSize = DOSHeader->e_lfanew + PEHeader32->FileHeader.SizeOfOptionalHeader + (sizeof(IMAGE_SECTION_HEADER) * PEHeader32->FileHeader.NumberOfSections) + sizeof(IMAGE_FILE_HEADER) + 4; + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader32 + PEHeader32->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + SectionNumber = PEHeader32->FileHeader.NumberOfSections; + RtlMoveMemory(AllocatedFile, (LPVOID)FileMapVA, PeHeaderSize); + while(SectionNumber > 0) + { + RtlMoveMemory((LPVOID)((ULONG_PTR)AllocatedFile + PESections->VirtualAddress), (LPVOID)(FileMapVA + PESections->PointerToRawData), PESections->SizeOfRawData); + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + IMAGE_SIZEOF_SECTION_HEADER); + SectionNumber--; + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + VirtualFree(AllocatedFile, NULL, MEM_RELEASE); + AllocatedFile = NULL; + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return((ULONG_PTR)AllocatedFile); + } + else + { + AllocatedFile = VirtualAlloc(NULL, PEHeader64->OptionalHeader.SizeOfImage, MEM_COMMIT, PAGE_READWRITE); + __try + { + PeHeaderSize = DOSHeader->e_lfanew + PEHeader64->FileHeader.SizeOfOptionalHeader + (sizeof(IMAGE_SECTION_HEADER) * PEHeader64->FileHeader.NumberOfSections) + sizeof(IMAGE_FILE_HEADER) + 4; + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader64 + PEHeader64->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + SectionNumber = PEHeader64->FileHeader.NumberOfSections; + RtlMoveMemory(AllocatedFile, (LPVOID)FileMapVA, PeHeaderSize); + while(SectionNumber > 0) + { + RtlMoveMemory((LPVOID)((ULONG_PTR)AllocatedFile + PESections->VirtualAddress), (LPVOID)(FileMapVA + PESections->PointerToRawData), PESections->SizeOfRawData); + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + IMAGE_SIZEOF_SECTION_HEADER); + SectionNumber--; + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + VirtualFree(AllocatedFile, NULL, MEM_RELEASE); + AllocatedFile = NULL; + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return((ULONG_PTR)AllocatedFile); + } + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(NULL); + } + } + return(NULL); +} +long long EngineSimulateNtLoader(char* szFileName) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + + if(szFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + return(EngineSimulateNtLoaderW(uniFileName)); + } + else + { + return(NULL); + } +} +long long EngineSimulateDllLoader(HANDLE hProcess, char* szFileName) +{ + + int n; + BOOL FileIs64; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + HANDLE FileHandle; + LPVOID DLLMemory = NULL; + DWORD ExportDelta = NULL; + DWORD PEHeaderSize = NULL; + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + PIMAGE_EXPORT_DIRECTORY PEExports; + PEXPORTED_DATA ExportedFunctionNames; + ULONG_PTR ConvertedExport = NULL; + char szFileRemoteProc[1024]; + char szDLLFileLocation[512]; + char* szTranslatedProcName; + + GetProcessImageFileNameA(hProcess, szFileRemoteProc, 1024); + szTranslatedProcName = (char*)TranslateNativeName(szFileRemoteProc); + if(EngineIsDependencyPresent(szFileName, NULL, NULL)) + { + if(EngineGetDependencyLocation(szFileName, szTranslatedProcName, &szDLLFileLocation, 512)) + { + VirtualFree((void*)szTranslatedProcName, NULL, MEM_RELEASE); + if(MapFileEx(szDLLFileLocation, UE_ACCESS_READ, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, FileHandle, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + PEHeaderSize = PEHeader32->FileHeader.NumberOfSections * IMAGE_SIZEOF_SECTION_HEADER + PEHeader32->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4; + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + PEHeaderSize = PEHeader64->FileHeader.NumberOfSections * IMAGE_SIZEOF_SECTION_HEADER + PEHeader64->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4; + FileIs64 = true; + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(NULL); + } + if(!FileIs64) + { + if(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress != NULL) + { + DLLMemory = VirtualAlloc(NULL, DOSHeader->e_lfanew + PEHeaderSize + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size + 0x1000, MEM_COMMIT, PAGE_READWRITE); + if(DLLMemory != NULL) + { + __try + { + if((DOSHeader->e_lfanew + PEHeaderSize) % 0x1000 != 0) + { + ExportDelta = (((DOSHeader->e_lfanew + PEHeaderSize) / 0x1000) + 1) * 0x1000; + } + else + { + ExportDelta = ((DOSHeader->e_lfanew + PEHeaderSize) / 0x1000) * 0x1000; + } + ConvertedExport = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, PEHeader32->OptionalHeader.ImageBase, PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress, true, true); + if(ConvertedExport != NULL) + { + PEExports = (PIMAGE_EXPORT_DIRECTORY)((ULONG_PTR)DLLMemory + ExportDelta); + RtlMoveMemory(DLLMemory, (LPVOID)FileMapVA, PEHeaderSize + DOSHeader->e_lfanew); + RtlMoveMemory((LPVOID)((ULONG_PTR)DLLMemory + ExportDelta), (LPVOID)ConvertedExport, PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size); + PEExports->AddressOfFunctions = PEExports->AddressOfFunctions - PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + ExportDelta; + PEExports->AddressOfNameOrdinals = PEExports->AddressOfNameOrdinals - PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + ExportDelta; + PEExports->AddressOfNames = PEExports->AddressOfNames - PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + ExportDelta; + PEExports->Name = PEExports->Name - PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + ExportDelta; + ExportedFunctionNames = (PEXPORTED_DATA)(PEExports->AddressOfNames + (ULONG_PTR)DLLMemory); + for(n = 0; n < (int)PEExports->NumberOfNames; n++) + { + ExportedFunctionNames->ExportedItem = ExportedFunctionNames->ExportedItem - PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + ExportDelta; + ExportedFunctionNames = (PEXPORTED_DATA)((ULONG_PTR)ExportedFunctionNames + 4); + } + DOSHeader = (PIMAGE_DOS_HEADER)DLLMemory; + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = ExportDelta; + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return((ULONG_PTR)DLLMemory); + } + else + { + VirtualFree(DLLMemory, NULL, MEM_RELEASE); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + VirtualFree(DLLMemory, NULL, MEM_RELEASE); + } + } + } + } + else + { + if(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress != NULL) + { + DLLMemory = VirtualAlloc(NULL, DOSHeader->e_lfanew + PEHeaderSize + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size + 0x1000, MEM_COMMIT, PAGE_READWRITE); + if(DLLMemory != NULL) + { + __try + { + if((DOSHeader->e_lfanew + PEHeaderSize) % 0x1000 != 0) + { + ExportDelta = (((DOSHeader->e_lfanew + PEHeaderSize) % 0x1000) + 1) * 0x1000; + } + else + { + ExportDelta = ((DOSHeader->e_lfanew + PEHeaderSize) % 0x1000) * 0x1000; + } + ConvertedExport = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress, true, true); + if(ConvertedExport != NULL) + { + PEExports = (PIMAGE_EXPORT_DIRECTORY)((ULONG_PTR)DLLMemory + ExportDelta); + RtlMoveMemory(DLLMemory, (LPVOID)FileMapVA, PEHeaderSize + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size); + RtlMoveMemory((LPVOID)((ULONG_PTR)DLLMemory + ExportDelta), (LPVOID)ConvertedExport, PEHeaderSize + DOSHeader->e_lfanew); + PEExports->AddressOfFunctions = PEExports->AddressOfFunctions - PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + ExportDelta; + PEExports->AddressOfNameOrdinals = PEExports->AddressOfNameOrdinals - PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + ExportDelta; + PEExports->AddressOfNames = PEExports->AddressOfNames - PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + ExportDelta; + PEExports->Name = PEExports->Name - PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + ExportDelta; + ExportedFunctionNames = (PEXPORTED_DATA)(PEExports->AddressOfNames + (ULONG_PTR)DLLMemory); + for(n = 0; n < (int)PEExports->NumberOfNames; n++) + { + ExportedFunctionNames->ExportedItem = ExportedFunctionNames->ExportedItem - PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + ExportDelta; + ExportedFunctionNames = (PEXPORTED_DATA)((ULONG_PTR)ExportedFunctionNames + 4); + } + DOSHeader = (PIMAGE_DOS_HEADER)DLLMemory; + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = ExportDelta; + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return((ULONG_PTR)DLLMemory); + } + else + { + VirtualFree(DLLMemory, NULL, MEM_RELEASE); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + VirtualFree(DLLMemory, NULL, MEM_RELEASE); + } + } + } + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + } + } + } + } + VirtualFree((void*)szTranslatedProcName, NULL, MEM_RELEASE); + return(NULL); +} +long long EngineGetProcAddress(ULONG_PTR ModuleBase, char* szAPIName) +{ + + int i = 0; + int j = 0; + ULONG_PTR APIFoundAddress = 0; + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + PIMAGE_EXPORT_DIRECTORY PEExports; + PEXPORTED_DATA ExportedFunctions; + PEXPORTED_DATA ExportedFunctionNames; + PEXPORTED_DATA_WORD ExportedFunctionOrdinals; + char szModuleName[MAX_PATH] = {}; + bool FileIs64 = false; + + if(GetModuleFileNameA((HMODULE)ModuleBase, szModuleName, MAX_PATH) == NULL) + { + __try + { + DOSHeader = (PIMAGE_DOS_HEADER)ModuleBase; + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + return(NULL); + } + if(!FileIs64) + { + PEExports = (PIMAGE_EXPORT_DIRECTORY)(ModuleBase + (ULONG_PTR)PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); + ExportedFunctions = (PEXPORTED_DATA)(ModuleBase + (ULONG_PTR)PEExports->AddressOfFunctions); + ExportedFunctionNames = (PEXPORTED_DATA)(ModuleBase + (ULONG_PTR)PEExports->AddressOfNames); + ExportedFunctionOrdinals = (PEXPORTED_DATA_WORD)(ModuleBase + (ULONG_PTR)PEExports->AddressOfNameOrdinals); + } + else + { + PEExports = (PIMAGE_EXPORT_DIRECTORY)(ModuleBase + (ULONG_PTR)PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); + ExportedFunctions = (PEXPORTED_DATA)(ModuleBase + (ULONG_PTR)PEExports->AddressOfFunctions); + ExportedFunctionNames = (PEXPORTED_DATA)(ModuleBase + (ULONG_PTR)PEExports->AddressOfNames); + ExportedFunctionOrdinals = (PEXPORTED_DATA_WORD)(ModuleBase + (ULONG_PTR)PEExports->AddressOfNameOrdinals); + } + for(j = 0; j < (int)PEExports->NumberOfNames; j++) + { + if(!FileIs64) + { + if(lstrcmpiA((LPCSTR)szAPIName, (LPCSTR)(ModuleBase + (ULONG_PTR)ExportedFunctionNames->ExportedItem)) == NULL) + { + ExportedFunctionOrdinals = (PEXPORTED_DATA_WORD)((ULONG_PTR)ExportedFunctionOrdinals + j * 2); + ExportedFunctions = (PEXPORTED_DATA)((ULONG_PTR)ExportedFunctions + (ExportedFunctionOrdinals->OrdinalNumber) * 4); + APIFoundAddress = ExportedFunctions->ExportedItem + (ULONG_PTR)ModuleBase; + return((ULONG_PTR)APIFoundAddress); + } + } + else + { + if(lstrcmpiA((LPCSTR)szAPIName, (LPCSTR)(ModuleBase + (ULONG_PTR)ExportedFunctionNames->ExportedItem)) == NULL) + { + ExportedFunctionOrdinals = (PEXPORTED_DATA_WORD)((ULONG_PTR)ExportedFunctionOrdinals + j * 2); + ExportedFunctions = (PEXPORTED_DATA)((ULONG_PTR)ExportedFunctions + (ExportedFunctionOrdinals->OrdinalNumber) * 4); + APIFoundAddress = ExportedFunctions->ExportedItem + (ULONG_PTR)ModuleBase; + return((ULONG_PTR)APIFoundAddress); + } + } + ExportedFunctionNames = (PEXPORTED_DATA)((ULONG_PTR)ExportedFunctionNames + 4); + } + return(NULL); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return(NULL); + } + } + else + { + return((ULONG_PTR)GetProcAddress((HMODULE)ModuleBase, szAPIName)); + } +} +bool EngineGetLibraryOrdinalData(ULONG_PTR ModuleBase, LPDWORD ptrOrdinalBase, LPDWORD ptrOrdinalCount) +{ + + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + PIMAGE_EXPORT_DIRECTORY PEExports; + bool FileIs64 = false; + + __try + { + DOSHeader = (PIMAGE_DOS_HEADER)ModuleBase; + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + return(false); + } + if(!FileIs64) + { + PEExports = (PIMAGE_EXPORT_DIRECTORY)(ModuleBase + (ULONG_PTR)PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); + *ptrOrdinalBase = PEExports->Base; + *ptrOrdinalCount = PEExports->NumberOfNames; + } + else + { + PEExports = (PIMAGE_EXPORT_DIRECTORY)(ModuleBase + (ULONG_PTR)PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); + *ptrOrdinalBase = PEExports->Base; + *ptrOrdinalCount = PEExports->NumberOfNames; + } + return(true); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return(false); + } + return(false); +} +long long EngineGlobalAPIHandler(HANDLE handleProcess, ULONG_PTR EnumedModulesBases, ULONG_PTR APIAddress, char* szAPIName, DWORD ReturnType) +{ + + unsigned int i = 0; + unsigned int j = 0; + unsigned int n = 0; + unsigned int x = 0; + unsigned int y = 0; + unsigned int z = 0; + DWORD Dummy = NULL; + HANDLE hProcess = NULL; + ULONG_PTR EnumeratedModules[0x2000]; + ULONG_PTR LoadedModules[1000][4]; + char RemoteDLLName[MAX_PATH]; + char FullRemoteDLLName[MAX_PATH]; + char szWindowsSideBySide[MAX_PATH]; + char szWindowsSideBySideCmp[MAX_PATH]; + char szWindowsKernelBase[MAX_PATH]; + HANDLE hLoadedModule = NULL; + HANDLE ModuleHandle = NULL; + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + PIMAGE_EXPORT_DIRECTORY PEExports; + PEXPORTED_DATA ExportedFunctions; + PEXPORTED_DATA ExportedFunctionNames; + PEXPORTED_DATA_WORD ExportedFunctionOrdinals; + ULONG_PTR APIFoundAddress = NULL; + MODULEINFO RemoteModuleInfo; + bool ValidateHeader = false; + bool FileIs64 = false; + bool APINameFound = false; + bool SkipModule = false; + unsigned int FoundIndex = 0; + unsigned int FoundOrdinalNumber = 0; + ULONG_PTR FileMapVA; + char szFwdDLLName[512]; + char szFwdAPIName[512]; + ULONG_PTR RealignedAPIAddress; + ULONG_PTR ForwarderData = NULL; + unsigned int ClosestAPI = 0x1000; + int Vista64UserForwarderFix = 0; + int Windows7KernelBase = 0; + + RtlZeroMemory(&engineFoundDLLName, 512); + RtlZeroMemory(&EnumeratedModules, 0x2000 * sizeof ULONG_PTR); + RtlZeroMemory(&LoadedModules, 1000 * 4 * sizeof ULONG_PTR); + GetWindowsDirectoryA(szWindowsSideBySide, MAX_PATH); + lstrcpyA(szWindowsKernelBase, szWindowsSideBySide); + lstrcatA(szWindowsSideBySide, "\\WinSxS"); + if(EnumedModulesBases != NULL) + { + RtlMoveMemory(&EnumeratedModules, (LPVOID)EnumedModulesBases, 0x1000); + i--; + } + if(handleProcess == NULL) + { + if(dbgProcessInformation.hProcess == NULL) + { + hProcess = GetCurrentProcess(); + } + else + { + hProcess = dbgProcessInformation.hProcess; + } + } + else + { + hProcess = handleProcess; + } + if(EnumedModulesBases != NULL || EnumProcessModules(hProcess, (HMODULE*)EnumeratedModules, 0x2000, &Dummy)) + { + i++; + z = i; + y = i; + while(EnumeratedModules[y] != NULL) + { + // Vista x64 fix + if(Vista64UserForwarderFix == NULL) + { + GetModuleBaseNameA(hProcess, (HMODULE)EnumeratedModules[y], (LPSTR)RemoteDLLName, MAX_PATH); + if(lstrcmpiA(RemoteDLLName, "user32.dll") == NULL) + { + Vista64UserForwarderFix = y; + } + else if(lstrcmpiA(RemoteDLLName, "kernelbase.dll") == NULL) + { + GetModuleFileNameExA(hProcess, (HMODULE)EnumeratedModules[y], (LPSTR)RemoteDLLName, MAX_PATH); + RemoteDLLName[lstrlenA(szWindowsKernelBase)] = 0x00; + if(lstrcmpiA(RemoteDLLName, szWindowsKernelBase) == NULL) + { + Windows7KernelBase = y; + } + } + } + y++; + } + while(APINameFound == false && EnumeratedModules[i] != NULL) + { + if(i == Windows7KernelBase) + { + i++; + if(EnumeratedModules[i] == NULL) + { + break; + } + } + ValidateHeader = false; + RtlZeroMemory(&RemoteDLLName, MAX_PATH); + GetModuleFileNameExA(hProcess, (HMODULE)EnumeratedModules[i], (LPSTR)RemoteDLLName, MAX_PATH); + lstrcpyA(FullRemoteDLLName, RemoteDLLName); + RtlZeroMemory(&szWindowsSideBySideCmp, MAX_PATH); + RtlMoveMemory(&szWindowsSideBySideCmp, FullRemoteDLLName, lstrlenA(szWindowsSideBySide)); + if(GetModuleHandleA(RemoteDLLName) == NULL) + { + RtlZeroMemory(&RemoteDLLName, MAX_PATH); + GetModuleBaseNameA(hProcess, (HMODULE)EnumeratedModules[i], (LPSTR)RemoteDLLName, MAX_PATH); + if(GetModuleHandleA(RemoteDLLName) == NULL || lstrcmpiA(szWindowsSideBySideCmp, szWindowsSideBySide) == NULL) + { + if(engineAlowModuleLoading) + { + hLoadedModule = LoadLibraryA(FullRemoteDLLName); + if(hLoadedModule != NULL) + { + LoadedModules[i][0] = EnumeratedModules[i]; + LoadedModules[i][1] = (ULONG_PTR)hLoadedModule; + LoadedModules[i][2] = 1; + } + } + else + { + hLoadedModule = (HANDLE)EngineSimulateDllLoader(hProcess, FullRemoteDLLName); + if(hLoadedModule != NULL) + { + LoadedModules[i][0] = EnumeratedModules[i]; + LoadedModules[i][1] = (ULONG_PTR)hLoadedModule; + LoadedModules[i][2] = 1; + ValidateHeader = true; + } + } + } + else + { + LoadedModules[i][0] = EnumeratedModules[i]; + LoadedModules[i][1] = (ULONG_PTR)GetModuleHandleA(RemoteDLLName); + LoadedModules[i][2] = 0; + } + } + else + { + LoadedModules[i][0] = EnumeratedModules[i]; + LoadedModules[i][1] = (ULONG_PTR)GetModuleHandleA(RemoteDLLName); + LoadedModules[i][2] = 0; + } + + + if(ReturnType != UE_OPTION_IMPORTER_RETURN_FORWARDER_DLLNAME && ReturnType != UE_OPTION_IMPORTER_RETURN_FORWARDER_DLLINDEX && ReturnType != UE_OPTION_IMPORTER_RETURN_FORWARDER_APINAME) + { + if(szAPIName == NULL && ReturnType == UE_OPTION_IMPORTER_REALIGN_APIADDRESS) + { + RtlZeroMemory(&RemoteModuleInfo, sizeof MODULEINFO); + //GetModuleInformation(GetCurrentProcess(), (HMODULE)LoadedModules[i][1], &RemoteModuleInfo, sizeof MODULEINFO); + GetModuleInformation(hProcess, (HMODULE)LoadedModules[i][0], &RemoteModuleInfo, sizeof MODULEINFO); + if(APIAddress >= LoadedModules[i][1] && APIAddress <= LoadedModules[i][1] + RemoteModuleInfo.SizeOfImage) + { + GetModuleBaseNameA(hProcess, (HMODULE)LoadedModules[i][0], (LPSTR)engineFoundDLLName, 512); + APIFoundAddress = (ULONG_PTR)(APIAddress - LoadedModules[i][1] + LoadedModules[i][0]); + APINameFound = true; + FoundIndex = i; + break; + } + } + else if(szAPIName == NULL && ReturnType == UE_OPTION_IMPORTER_REALIGN_LOCAL_APIADDRESS) + { + RtlZeroMemory(&RemoteModuleInfo, sizeof MODULEINFO); + GetModuleInformation(hProcess, (HMODULE)LoadedModules[i][0], &RemoteModuleInfo, sizeof MODULEINFO); + if(APIAddress >= LoadedModules[i][0] && APIAddress <= LoadedModules[i][0] + RemoteModuleInfo.SizeOfImage) + { + GetModuleBaseNameA(hProcess, (HMODULE)LoadedModules[i][0], (LPSTR)engineFoundDLLName, 512); + APIFoundAddress = (ULONG_PTR)(APIAddress - LoadedModules[i][0] + LoadedModules[i][1]); + APINameFound = true; + FoundIndex = i; + break; + } + } + else if(szAPIName == NULL && ReturnType == UE_OPTION_IMPORTER_RETURN_DLLBASE) + { + if(APIAddress == LoadedModules[i][1]) + { + APIFoundAddress = LoadedModules[i][0]; + APINameFound = true; + FoundIndex = i; + break; + } + } + else if(ReturnType == UE_OPTION_IMPORTER_RETURN_NEAREST_APIADDRESS || ReturnType == UE_OPTION_IMPORTER_RETURN_NEAREST_APINAME) + { + RtlZeroMemory(&RemoteModuleInfo, sizeof MODULEINFO); + GetModuleInformation(hProcess, (HMODULE)LoadedModules[i][0], &RemoteModuleInfo, sizeof MODULEINFO); + if(APIAddress >= LoadedModules[i][0] && APIAddress <= LoadedModules[i][0] + RemoteModuleInfo.SizeOfImage) + { + DOSHeader = (PIMAGE_DOS_HEADER)LoadedModules[i][1]; + if(ValidateHeader || EngineValidateHeader((ULONG_PTR)LoadedModules[i][1], GetCurrentProcess(), RemoteModuleInfo.lpBaseOfDll, DOSHeader, false)) + { + __try + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + return(NULL); + } + if(!FileIs64) + { + PEExports = (PIMAGE_EXPORT_DIRECTORY)(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + LoadedModules[i][1]); + ExportedFunctions = (PEXPORTED_DATA)(PEExports->AddressOfFunctions + LoadedModules[i][1]); + } + else + { + PEExports = (PIMAGE_EXPORT_DIRECTORY)(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + LoadedModules[i][1]); + ExportedFunctions = (PEXPORTED_DATA)(PEExports->AddressOfFunctions + LoadedModules[i][1]); + } + for(n = 0; n < PEExports->NumberOfFunctions; n++) //NumberOfNames + { + if(APIAddress - (ExportedFunctions->ExportedItem + LoadedModules[i][0]) < ClosestAPI) + { + ClosestAPI = (unsigned int)(APIAddress - (ExportedFunctions->ExportedItem + LoadedModules[i][0])); + if(!FileIs64) + { + ExportedFunctionNames = (PEXPORTED_DATA)(PEExports->AddressOfNames + LoadedModules[i][1]); + ExportedFunctionOrdinals = (PEXPORTED_DATA_WORD)(PEExports->AddressOfNameOrdinals + LoadedModules[i][1]); + } + else + { + ExportedFunctionNames = (PEXPORTED_DATA)(PEExports->AddressOfNames + LoadedModules[i][1]); + ExportedFunctionOrdinals = (PEXPORTED_DATA_WORD)(PEExports->AddressOfNameOrdinals + LoadedModules[i][1]); + } + GetModuleBaseNameA(hProcess, (HMODULE)LoadedModules[i][0], (LPSTR)engineFoundDLLName, 512); + RtlZeroMemory(&engineFoundAPIName, 512); + x = n; + FoundOrdinalNumber = (unsigned int)PEExports->Base; + for(j = 0; j < PEExports->NumberOfNames; j++) + { + if(ExportedFunctionOrdinals->OrdinalNumber != x) + { + ExportedFunctionOrdinals = (PEXPORTED_DATA_WORD)((ULONG_PTR)ExportedFunctionOrdinals + 2); + } + else + { + FoundOrdinalNumber = FoundOrdinalNumber + (unsigned int)ExportedFunctionOrdinals->OrdinalNumber; + break; + } + } + ExportedFunctionNames = (PEXPORTED_DATA)((ULONG_PTR)ExportedFunctionNames + j * 4); + if(EngineIsPointedMemoryString((ULONG_PTR)(ExportedFunctionNames->ExportedItem + LoadedModules[i][1]))) + { + lstrcpyA((LPSTR)engineFoundAPIName, (LPCSTR)(ExportedFunctionNames->ExportedItem + LoadedModules[i][1])); + } + APIFoundAddress = ExportedFunctions->ExportedItem + LoadedModules[i][0]; + APINameFound = true; + FoundIndex = i; + } + ExportedFunctions = (PEXPORTED_DATA)((ULONG_PTR)ExportedFunctions + 4); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + ClosestAPI = 0x1000; + APINameFound = false; + } + } + } + } + + if((ReturnType == UE_OPTION_IMPORTER_RETURN_API_ORDINAL_NUMBER || (ReturnType > UE_OPTION_IMPORTER_REALIGN_APIADDRESS && ReturnType < UE_OPTION_IMPORTER_RETURN_FORWARDER_DLLNAME)) && ReturnType != UE_OPTION_IMPORTER_RETURN_DLLBASE && LoadedModules[i][1] != NULL) + { + RtlZeroMemory(&RemoteModuleInfo, sizeof MODULEINFO); + DOSHeader = (PIMAGE_DOS_HEADER)LoadedModules[i][1]; + //GetModuleInformation(GetCurrentProcess(), (HMODULE)LoadedModules[i][1], &RemoteModuleInfo, sizeof MODULEINFO); + GetModuleInformation(hProcess, (HMODULE)LoadedModules[i][0], &RemoteModuleInfo, sizeof MODULEINFO); + if(APIAddress >= LoadedModules[i][0] && APIAddress <= LoadedModules[i][0] + RemoteModuleInfo.SizeOfImage) + { + if(ValidateHeader || EngineValidateHeader((ULONG_PTR)LoadedModules[i][1], GetCurrentProcess(), RemoteModuleInfo.lpBaseOfDll, DOSHeader, false)) + { + __try + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + return(NULL); + } + if(!FileIs64) + { + PEExports = (PIMAGE_EXPORT_DIRECTORY)(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + LoadedModules[i][1]); + ExportedFunctions = (PEXPORTED_DATA)(PEExports->AddressOfFunctions + LoadedModules[i][1]); + ExportedFunctionNames = (PEXPORTED_DATA)(PEExports->AddressOfNames + LoadedModules[i][1]); + ExportedFunctionOrdinals = (PEXPORTED_DATA_WORD)(PEExports->AddressOfNameOrdinals + LoadedModules[i][1]); + } + else + { + PEExports = (PIMAGE_EXPORT_DIRECTORY)(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + LoadedModules[i][1]); + ExportedFunctions = (PEXPORTED_DATA)(PEExports->AddressOfFunctions + LoadedModules[i][1]); + ExportedFunctionNames = (PEXPORTED_DATA)(PEExports->AddressOfNames + LoadedModules[i][1]); + ExportedFunctionOrdinals = (PEXPORTED_DATA_WORD)(PEExports->AddressOfNameOrdinals + LoadedModules[i][1]); + } + if(ReturnType == UE_OPTION_IMPORTER_RETURN_APINAME || ReturnType == UE_OPTION_IMPORTER_RETURN_DLLNAME || ReturnType == UE_OPTION_IMPORTER_RETURN_DLLINDEX || ReturnType == UE_OPTION_IMPORTER_RETURN_API_ORDINAL_NUMBER) + { + for(j = 0; j < PEExports->NumberOfFunctions; j++) //NumberOfNames + { + if(ExportedFunctions->ExportedItem + LoadedModules[i][0] == APIAddress) + { + GetModuleBaseNameA(hProcess, (HMODULE)LoadedModules[i][0], (LPSTR)engineFoundDLLName, 512); + RtlZeroMemory(&engineFoundAPIName, 512); + x = j; + FoundOrdinalNumber = (unsigned int)PEExports->Base; + for(j = 0; j < PEExports->NumberOfNames; j++) + { + if(ExportedFunctionOrdinals->OrdinalNumber != x) + { + ExportedFunctionOrdinals = (PEXPORTED_DATA_WORD)((ULONG_PTR)ExportedFunctionOrdinals + 2); + } + else + { + FoundOrdinalNumber = FoundOrdinalNumber + (unsigned int)ExportedFunctionOrdinals->OrdinalNumber; + break; + } + } + ExportedFunctionNames = (PEXPORTED_DATA)((ULONG_PTR)ExportedFunctionNames + j * 4); + if(EngineIsPointedMemoryString((ULONG_PTR)(ExportedFunctionNames->ExportedItem + LoadedModules[i][1]))) + { + lstrcpyA((LPSTR)engineFoundAPIName, (LPCSTR)(ExportedFunctionNames->ExportedItem + LoadedModules[i][1])); + } + APINameFound = true; + FoundIndex = i; + break; + } + ExportedFunctions = (PEXPORTED_DATA)((ULONG_PTR)ExportedFunctions + 4); + } + } + else if(ReturnType == UE_OPTION_IMPORTER_RETURN_APIADDRESS) + { + for(j = 0; j < PEExports->NumberOfFunctions; j++) //NumberOfNames + { + if(lstrcmpiA((LPCSTR)szAPIName, (LPCSTR)(ExportedFunctionNames->ExportedItem + LoadedModules[i][1])) == NULL) + { + ExportedFunctionOrdinals = (PEXPORTED_DATA_WORD)((ULONG_PTR)ExportedFunctionOrdinals + j * 2); + ExportedFunctions = (PEXPORTED_DATA)((ULONG_PTR)ExportedFunctions + (ExportedFunctionOrdinals->OrdinalNumber) * 4); + GetModuleBaseNameA(hProcess, (HMODULE)LoadedModules[i][0], (LPSTR)engineFoundDLLName, 512); + RtlZeroMemory(&engineFoundAPIName, 512); + ExportedFunctions = (PEXPORTED_DATA)((ULONG_PTR)ExportedFunctions + (j + PEExports->Base) * 4); + APIFoundAddress = ExportedFunctions->ExportedItem + LoadedModules[i][0]; + APINameFound = true; + FoundIndex = i; + break; + } + ExportedFunctionNames = (PEXPORTED_DATA)((ULONG_PTR)ExportedFunctionNames + 4); + } + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + RtlZeroMemory(&engineFoundAPIName, 512); + APINameFound = false; + } + } + } + } + } + i++; + } + + if(ReturnType == UE_OPTION_IMPORTER_RETURN_FORWARDER_DLLNAME || ReturnType == UE_OPTION_IMPORTER_RETURN_FORWARDER_APINAME || ReturnType == UE_OPTION_IMPORTER_RETURN_FORWARDER_DLLINDEX || ReturnType == UE_OPTION_IMPORTER_RETURN_FORWARDER_API_ORDINAL_NUMBER) + { + RealignedAPIAddress = (ULONG_PTR)EngineGlobalAPIHandler(hProcess, NULL, APIAddress, NULL, UE_OPTION_IMPORTER_REALIGN_APIADDRESS); + if(z <= 1) + { + z = 2; + } + for(i = y; i >= z; i--) + { + FileMapVA = LoadedModules[i][1]; + if(FileMapVA != NULL) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + RtlZeroMemory(&RemoteModuleInfo, sizeof MODULEINFO); + //GetModuleInformation(GetCurrentProcess(), (HMODULE)LoadedModules[i][1], &RemoteModuleInfo, sizeof MODULEINFO); + GetModuleInformation(hProcess, (HMODULE)LoadedModules[i][0], &RemoteModuleInfo, sizeof MODULEINFO); + if(ValidateHeader || EngineValidateHeader((ULONG_PTR)LoadedModules[i][1], GetCurrentProcess(), RemoteModuleInfo.lpBaseOfDll, DOSHeader, false)) + { + __try + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + SkipModule = true; + } + if(!SkipModule) + { + if(!FileIs64) + { + PEExports = (PIMAGE_EXPORT_DIRECTORY)(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + LoadedModules[i][1]); + ExportedFunctionNames = (PEXPORTED_DATA)(PEExports->AddressOfNames + LoadedModules[i][1]); + ExportedFunctions = (PEXPORTED_DATA)(PEExports->AddressOfFunctions + LoadedModules[i][1]); + ExportedFunctionOrdinals = (PEXPORTED_DATA_WORD)(PEExports->AddressOfNameOrdinals + LoadedModules[i][1]); + } + else + { + PEExports = (PIMAGE_EXPORT_DIRECTORY)(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + LoadedModules[i][1]); + ExportedFunctionNames = (PEXPORTED_DATA)(PEExports->AddressOfNames + LoadedModules[i][1]); + ExportedFunctions = (PEXPORTED_DATA)(PEExports->AddressOfFunctions + LoadedModules[i][1]); + ExportedFunctionOrdinals = (PEXPORTED_DATA_WORD)(PEExports->AddressOfNameOrdinals + LoadedModules[i][1]); + } + for(j = 0; j < PEExports->NumberOfFunctions; j++) + { + if(EngineIsPointedMemoryString((ULONG_PTR)ExportedFunctions->ExportedItem + LoadedModules[i][1])) + { + RtlZeroMemory(&szFwdAPIName, 512); + RtlZeroMemory(&szFwdDLLName, 512); + if(EngineExtractForwarderData((ULONG_PTR)ExportedFunctions->ExportedItem + LoadedModules[i][1], &szFwdDLLName, &szFwdAPIName)) + { + if((ULONG_PTR)GetProcAddress(GetModuleHandleA(szFwdDLLName), szFwdAPIName) == RealignedAPIAddress) + { + GetModuleBaseNameA(hProcess, (HMODULE)LoadedModules[i][0], (LPSTR)engineFoundDLLName, 512); + RtlZeroMemory(&engineFoundAPIName, 512); + x = j; + FoundOrdinalNumber = (unsigned int)PEExports->Base; + for(j = 0; j < PEExports->NumberOfNames; j++) + { + if(ExportedFunctionOrdinals->OrdinalNumber != x) + { + ExportedFunctionOrdinals = (PEXPORTED_DATA_WORD)((ULONG_PTR)ExportedFunctionOrdinals + 2); + } + else + { + FoundOrdinalNumber = FoundOrdinalNumber + (unsigned int)ExportedFunctionOrdinals->OrdinalNumber; + break; + } + } + ExportedFunctionNames = (PEXPORTED_DATA)((ULONG_PTR)ExportedFunctionNames + j * 4); + if(EngineIsPointedMemoryString((ULONG_PTR)(ExportedFunctionNames->ExportedItem + LoadedModules[i][1]))) + { + lstrcpyA((LPSTR)engineFoundAPIName, (LPCSTR)(ExportedFunctionNames->ExportedItem + LoadedModules[i][1])); + } + APINameFound = true; + FoundIndex = i; + break; + } + } + } + ExportedFunctions = (PEXPORTED_DATA)((ULONG_PTR)ExportedFunctions + 4); + } + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + RtlZeroMemory(&szFwdAPIName, 512); + RtlZeroMemory(&szFwdDLLName, 512); + APINameFound = false; + } + } + } + if(APINameFound) + { + break; + } + } + } + i = 1; + while(EnumeratedModules[i] != NULL) + { + if(engineAlowModuleLoading) + { + if(LoadedModules[i][2] == 1) + { + FreeLibrary((HMODULE)LoadedModules[i][1]); + } + } + else + { + if(LoadedModules[i][2] == 1) + { + VirtualFree((void*)LoadedModules[i][1], NULL, MEM_RELEASE); + } + } + i++; + } + if(APINameFound) + { + // + // Vista/w7 x64 fix + // + if(lstrcmpiA(engineFoundAPIName, "NtdllDefWindowProc_A") == NULL) + { + lstrcpyA(engineFoundAPIName, "DefWindowProcA"); + lstrcpyA(engineFoundDLLName, "user32.dll"); + FoundIndex = Vista64UserForwarderFix; + } + else if(lstrcmpiA(engineFoundAPIName, "NtdllDefWindowProc_W") == NULL) + { + lstrcpyA(engineFoundAPIName, "DefWindowProcW"); + lstrcpyA(engineFoundDLLName, "user32.dll"); + FoundIndex = Vista64UserForwarderFix; + } + else if(lstrcmpiA(engineFoundAPIName, "NtdllDialogWndProc_A") == NULL) + { + lstrcpyA(engineFoundAPIName, "DefDlgProcA"); + lstrcpyA(engineFoundDLLName, "user32.dll"); + FoundIndex = Vista64UserForwarderFix; + } + else if(lstrcmpiA(engineFoundAPIName, "NtdllDialogWndProc_W") == NULL) + { + lstrcpyA(engineFoundAPIName, "DefDlgProcW"); + lstrcpyA(engineFoundDLLName, "user32.dll"); + FoundIndex = Vista64UserForwarderFix; + } + if(ReturnType == UE_OPTION_IMPORTER_RETURN_APINAME || ReturnType == UE_OPTION_IMPORTER_RETURN_FORWARDER_APINAME) + { + if(ReturnType == UE_OPTION_IMPORTER_RETURN_APINAME && engineCheckForwarders == true) + { + if(engineAlowModuleLoading == true || (engineAlowModuleLoading == false && LoadedModules[FoundIndex][2] != 1)) + { + if(lstrcmpiA(engineFoundDLLName, "ntdll.dll") == NULL) + { + ForwarderData = (ULONG_PTR)EngineGlobalAPIHandler(handleProcess, EnumedModulesBases, APIAddress, NULL, UE_OPTION_IMPORTER_RETURN_FORWARDER_APINAME); + } + else + { + ForwarderData = NULL; + } + if(ForwarderData != NULL) + { + return(ForwarderData); + } + else + { + if(engineFoundAPIName[0] != 0x00) + { + return((ULONG_PTR)engineFoundAPIName); + } + else + { + return(NULL); + } + } + } + else + { + if(engineFoundAPIName[0] != 0x00) + { + return((ULONG_PTR)engineFoundAPIName); + } + else + { + return(NULL); + } + } + } + else + { + if(engineFoundAPIName[0] != 0x00) + { + return((ULONG_PTR)engineFoundAPIName); + } + else + { + return(NULL); + } + } + } + else if(ReturnType == UE_OPTION_IMPORTER_RETURN_APIADDRESS) + { + return(APIFoundAddress); + } + else if(ReturnType == UE_OPTION_IMPORTER_RETURN_API_ORDINAL_NUMBER || ReturnType == UE_OPTION_IMPORTER_RETURN_FORWARDER_API_ORDINAL_NUMBER) + { + return((ULONG_PTR)FoundOrdinalNumber); + } + else if(ReturnType == UE_OPTION_IMPORTER_RETURN_DLLNAME || ReturnType == UE_OPTION_IMPORTER_RETURN_FORWARDER_DLLNAME) + { + if(ReturnType == UE_OPTION_IMPORTER_RETURN_DLLNAME && engineCheckForwarders == true) + { + if(engineAlowModuleLoading == true || (engineAlowModuleLoading == false && LoadedModules[FoundIndex][2] != 1)) + { + if(lstrcmpiA(engineFoundDLLName, "ntdll.dll") == NULL) + { + ForwarderData = (ULONG_PTR)EngineGlobalAPIHandler(handleProcess, EnumedModulesBases, APIAddress, NULL, UE_OPTION_IMPORTER_RETURN_FORWARDER_DLLNAME); + } + else + { + ForwarderData = NULL; + } + if(ForwarderData != NULL) + { + return(ForwarderData); + } + else + { + if(engineFoundDLLName[0] != 0x00) + { + return((ULONG_PTR)engineFoundDLLName); + } + else + { + return(NULL); + } + } + } + else + { + if(engineFoundDLLName[0] != 0x00) + { + return((ULONG_PTR)engineFoundDLLName); + } + else + { + return(NULL); + } + } + } + else + { + if(engineFoundDLLName[0] != 0x00) + { + return((ULONG_PTR)engineFoundDLLName); + } + else + { + return(NULL); + } + } + } + else if(ReturnType == UE_OPTION_IMPORTER_RETURN_DLLINDEX || ReturnType == UE_OPTION_IMPORTER_RETURN_FORWARDER_DLLINDEX) + { + if(ReturnType == UE_OPTION_IMPORTER_RETURN_DLLINDEX && engineCheckForwarders == true) + { + if(engineAlowModuleLoading == true || (engineAlowModuleLoading == false && LoadedModules[FoundIndex][2] != 1)) + { + if(lstrcmpiA(engineFoundDLLName, "ntdll.dll") == NULL) + { + ForwarderData = (ULONG_PTR)EngineGlobalAPIHandler(handleProcess, EnumedModulesBases, APIAddress, NULL, UE_OPTION_IMPORTER_RETURN_FORWARDER_DLLINDEX); + } + else + { + ForwarderData = NULL; + } + if(ForwarderData != NULL) + { + return(ForwarderData); + } + else + { + return(FoundIndex); + } + } + else + { + return(FoundIndex); + } + } + else + { + return(FoundIndex); + } + } + else if(ReturnType == UE_OPTION_IMPORTER_RETURN_DLLBASE) + { + return(APIFoundAddress); + } + else if(ReturnType == UE_OPTION_IMPORTER_RETURN_NEAREST_APIADDRESS) + { + return(APIFoundAddress); + } + else if(ReturnType == UE_OPTION_IMPORTER_RETURN_NEAREST_APINAME) + { + if(engineCheckForwarders) + { + if(engineAlowModuleLoading == true || (engineAlowModuleLoading == false && LoadedModules[FoundIndex][2] != 1)) + { + if(lstrcmpiA(engineFoundDLLName, "ntdll.dll") == NULL) + { + ForwarderData = (ULONG_PTR)EngineGlobalAPIHandler(handleProcess, EnumedModulesBases, APIAddress, NULL, UE_OPTION_IMPORTER_RETURN_FORWARDER_APINAME); + } + else + { + ForwarderData = NULL; + } + if(ForwarderData != NULL) + { + return(ForwarderData); + } + else + { + if(engineFoundAPIName[0] != 0x00) + { + return((ULONG_PTR)engineFoundAPIName); + } + else + { + return(NULL); + } + } + } + else + { + if(engineFoundAPIName[0] != 0x00) + { + return((ULONG_PTR)engineFoundAPIName); + } + else + { + return(NULL); + } + } + } + else + { + if(engineFoundAPIName[0] != 0x00) + { + return((ULONG_PTR)engineFoundAPIName); + } + else + { + return(NULL); + } + } + } + else + { + return(APIFoundAddress); + } + } + else + { + if(ReturnType == UE_OPTION_IMPORTER_RETURN_API_ORDINAL_NUMBER || ReturnType == UE_OPTION_IMPORTER_RETURN_FORWARDER_API_ORDINAL_NUMBER) + { + return((ULONG_PTR)-1); + } + else + { + return(NULL); + } + } + } + else + { + return(NULL); + } + return(NULL); +} +// Global.Engine.Hash.functions: +unsigned long EngineCrc32Reflect(unsigned long ulReflect, const char cChar) +{ + + unsigned long ulValue = 0; + + // Swap bit 0 for bit 7, bit 1 For bit 6, etc.... + for(int iPos = 1; iPos < (cChar + 1); iPos++) + { + if(ulReflect & 1) + { + ulValue |= (1 << (cChar - iPos)); + } + ulReflect >>= 1; + } + return ulValue; +} +void EngineCrc32PartialCRC(unsigned long *ulCRC, const unsigned char *sData, unsigned long ulDataLength) +{ + + while(ulDataLength--) + { + //If your compiler complains about the following line, try changing each + // occurrence of *ulCRC with "((unsigned long)*ulCRC)" or "*(unsigned long *)ulCRC". + *(unsigned long *)ulCRC = ((*(unsigned long *)ulCRC) >> 8) ^ Crc32Table[((*(unsigned long *)ulCRC) & 0xFF) ^ *sData++]; + } +} +// TitanEngine.Dumper.functions: +__declspec(dllexport) bool __stdcall DumpProcess(HANDLE hProcess, LPVOID ImageBase, char* szDumpFileName, ULONG_PTR EntryPoint) +{ + + wchar_t uniDumpFileName[MAX_PATH] = {}; + + if(szDumpFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szDumpFileName, lstrlenA(szDumpFileName)+1, uniDumpFileName, sizeof(uniDumpFileName)/(sizeof(uniDumpFileName[0]))); + return(DumpProcessW(hProcess, ImageBase, uniDumpFileName, EntryPoint)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall DumpProcessW(HANDLE hProcess, LPVOID ImageBase, wchar_t* szDumpFileName, ULONG_PTR EntryPoint) +{ + + int i = 0; + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_DOS_HEADER DOSFixHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + PIMAGE_NT_HEADERS32 PEFixHeader32; + PIMAGE_NT_HEADERS64 PEFixHeader64; + PIMAGE_SECTION_HEADER PESections; + PIMAGE_SECTION_HEADER PEFixSection; + ULONG_PTR ueNumberOfBytesRead = 0; + DWORD uedNumberOfBytesRead = 0; + DWORD SizeOfImageDump = 0; + int NumberOfSections = 0; + BOOL FileIs64 = false; + HANDLE hFile = 0; + DWORD RealignedVirtualSize = 0; + ULONG_PTR ProcReadBase = 0; + LPVOID ReadBase = ImageBase; + SIZE_T CalculatedHeaderSize = NULL; + SIZE_T AlignedHeaderSize = NULL; + LPVOID ueReadBuffer = VirtualAlloc(NULL, 0x2000, MEM_COMMIT, PAGE_READWRITE); + LPVOID ueCopyBuffer = VirtualAlloc(NULL, 0x2000, MEM_COMMIT, PAGE_READWRITE); + MEMORY_BASIC_INFORMATION MemInfo; + + if(ReadProcessMemory(hProcess, ImageBase, ueReadBuffer, 0x1000, &ueNumberOfBytesRead)) + { + DOSHeader = (PIMAGE_DOS_HEADER)ueReadBuffer; + CalculatedHeaderSize = DOSHeader->e_lfanew + sizeof IMAGE_DOS_HEADER + sizeof IMAGE_NT_HEADERS64; + if(CalculatedHeaderSize > 0x1000) + { + if(CalculatedHeaderSize % 0x1000 == NULL) + { + AlignedHeaderSize = 0x1000; + } + else + { + AlignedHeaderSize = ((CalculatedHeaderSize / 0x1000) + 1) * 0x1000; + } + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + VirtualFree(ueCopyBuffer, NULL, MEM_RELEASE); + ueReadBuffer = VirtualAlloc(NULL, AlignedHeaderSize, MEM_COMMIT, PAGE_READWRITE); + ueCopyBuffer = VirtualAlloc(NULL, AlignedHeaderSize, MEM_COMMIT, PAGE_READWRITE); + if(!ReadProcessMemory(hProcess, ImageBase, ueReadBuffer, AlignedHeaderSize, &ueNumberOfBytesRead)) + { + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + VirtualFree(ueCopyBuffer, NULL, MEM_RELEASE); + return(false); + } + else + { + DOSHeader = (PIMAGE_DOS_HEADER)ueReadBuffer; + } + } + else + { + CalculatedHeaderSize = 0x1000; + AlignedHeaderSize = 0x1000; + } + if(EngineValidateHeader((ULONG_PTR)ueReadBuffer, hProcess, ImageBase, DOSHeader, false)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + VirtualFree(ueCopyBuffer, NULL, MEM_RELEASE); + return(false); + } + if(!FileIs64) + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader32 + PEHeader32->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + NumberOfSections = PEHeader32->FileHeader.NumberOfSections; + NumberOfSections++; + if(PEHeader32->OptionalHeader.SizeOfImage % PEHeader32->OptionalHeader.SectionAlignment == NULL) + { + SizeOfImageDump = ((PEHeader32->OptionalHeader.SizeOfImage / PEHeader32->OptionalHeader.SectionAlignment)) * PEHeader32->OptionalHeader.SectionAlignment; + } + else + { + SizeOfImageDump = ((PEHeader32->OptionalHeader.SizeOfImage / PEHeader32->OptionalHeader.SectionAlignment) + 1) * PEHeader32->OptionalHeader.SectionAlignment; + } + SizeOfImageDump = SizeOfImageDump - (DWORD)AlignedHeaderSize; + if(EngineCreatePathForFileW(szDumpFileName)) + { + hFile = CreateFileW(szDumpFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if(hFile != INVALID_HANDLE_VALUE) + { + if(ReadProcessMemory(hProcess, ImageBase, ueCopyBuffer, AlignedHeaderSize, &ueNumberOfBytesRead)) + { + __try + { + DOSFixHeader = (PIMAGE_DOS_HEADER)ueCopyBuffer; + PEFixHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSFixHeader + DOSFixHeader->e_lfanew); + PEFixSection = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEFixHeader32 + PEHeader32->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + if(PEFixHeader32->OptionalHeader.FileAlignment > 0x200) + { + PEFixHeader32->OptionalHeader.FileAlignment = PEHeader32->OptionalHeader.SectionAlignment; + } + PEFixHeader32->OptionalHeader.AddressOfEntryPoint = (DWORD)(EntryPoint - (ULONG_PTR)ImageBase); + PEFixHeader32->OptionalHeader.ImageBase = (DWORD)((ULONG_PTR)ImageBase); + i = NumberOfSections; + while(i >= 1) + { + PEFixSection->PointerToRawData = PEFixSection->VirtualAddress; + RealignedVirtualSize = (PEFixSection->Misc.VirtualSize / PEHeader32->OptionalHeader.SectionAlignment) * PEHeader32->OptionalHeader.SectionAlignment; + if(RealignedVirtualSize < PEFixSection->Misc.VirtualSize) + { + RealignedVirtualSize = RealignedVirtualSize + PEHeader32->OptionalHeader.SectionAlignment; + } + PEFixSection->SizeOfRawData = RealignedVirtualSize; + PEFixSection->Misc.VirtualSize = RealignedVirtualSize; + PEFixSection = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEFixSection + IMAGE_SIZEOF_SECTION_HEADER); + i--; + } + WriteFile(hFile, ueCopyBuffer, (DWORD)AlignedHeaderSize, &uedNumberOfBytesRead, NULL); + ReadBase = (LPVOID)((ULONG_PTR)ReadBase + AlignedHeaderSize - TITANENGINE_PAGESIZE); + while(SizeOfImageDump > NULL) + { + ProcReadBase = (ULONG_PTR)ReadBase + TITANENGINE_PAGESIZE; + ReadBase = (LPVOID)ProcReadBase; + if(SizeOfImageDump >= TITANENGINE_PAGESIZE) + { + RtlZeroMemory(ueCopyBuffer, AlignedHeaderSize); + if(!ReadProcessMemory(hProcess, ReadBase, ueCopyBuffer, TITANENGINE_PAGESIZE, &ueNumberOfBytesRead)) + { + VirtualQueryEx(hProcess, ReadBase, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + VirtualProtectEx(hProcess, ReadBase, TITANENGINE_PAGESIZE, PAGE_EXECUTE_READWRITE, &MemInfo.Protect); + ReadProcessMemory(hProcess, ReadBase, ueCopyBuffer, TITANENGINE_PAGESIZE, &ueNumberOfBytesRead); + VirtualProtectEx(hProcess, ReadBase, TITANENGINE_PAGESIZE, MemInfo.Protect, &MemInfo.Protect); + } + WriteFile(hFile, ueCopyBuffer, TITANENGINE_PAGESIZE, &uedNumberOfBytesRead, NULL); + SizeOfImageDump = SizeOfImageDump - TITANENGINE_PAGESIZE; + } + else + { + RtlZeroMemory(ueCopyBuffer, AlignedHeaderSize); + if(!ReadProcessMemory(hProcess, ReadBase, ueCopyBuffer, SizeOfImageDump, &ueNumberOfBytesRead)) + { + VirtualQueryEx(hProcess, ReadBase, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + VirtualProtectEx(hProcess, ReadBase, TITANENGINE_PAGESIZE, PAGE_EXECUTE_READWRITE, &MemInfo.Protect); + ReadProcessMemory(hProcess, ReadBase, ueCopyBuffer, TITANENGINE_PAGESIZE, &ueNumberOfBytesRead); + VirtualProtectEx(hProcess, ReadBase, TITANENGINE_PAGESIZE, MemInfo.Protect, &MemInfo.Protect); + } + WriteFile(hFile, ueCopyBuffer, SizeOfImageDump, &uedNumberOfBytesRead, NULL); + SizeOfImageDump = NULL; + } + } + EngineCloseHandle(hFile); + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + VirtualFree(ueCopyBuffer, NULL, MEM_RELEASE); + return(true); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + EngineCloseHandle(hFile); + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + VirtualFree(ueCopyBuffer, NULL, MEM_RELEASE); + return(false); + } + } + else + { + EngineCloseHandle(hFile); + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + VirtualFree(ueCopyBuffer, NULL, MEM_RELEASE); + return(false); + } + } + else + { + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + VirtualFree(ueCopyBuffer, NULL, MEM_RELEASE); + return(false); + } + } + } + else + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader64 + PEHeader64->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + NumberOfSections = PEHeader64->FileHeader.NumberOfSections; + NumberOfSections++; + if(PEHeader64->OptionalHeader.SizeOfImage % PEHeader64->OptionalHeader.SectionAlignment == NULL) + { + SizeOfImageDump = ((PEHeader64->OptionalHeader.SizeOfImage / PEHeader64->OptionalHeader.SectionAlignment)) * PEHeader64->OptionalHeader.SectionAlignment; + } + else + { + SizeOfImageDump = ((PEHeader64->OptionalHeader.SizeOfImage / PEHeader64->OptionalHeader.SectionAlignment) + 1) * PEHeader64->OptionalHeader.SectionAlignment; + } + SizeOfImageDump = SizeOfImageDump - (DWORD)AlignedHeaderSize; + if(EngineCreatePathForFileW(szDumpFileName)) + { + hFile = CreateFileW(szDumpFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if(hFile != INVALID_HANDLE_VALUE) + { + if(ReadProcessMemory(hProcess, ImageBase, ueCopyBuffer, AlignedHeaderSize, &ueNumberOfBytesRead)) + { + __try + { + DOSFixHeader = (PIMAGE_DOS_HEADER)ueCopyBuffer; + PEFixHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSFixHeader + DOSFixHeader->e_lfanew); + PEFixSection = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEFixHeader64 + PEHeader64->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + if(PEFixHeader64->OptionalHeader.FileAlignment > 0x200) + { + PEFixHeader64->OptionalHeader.FileAlignment = PEHeader64->OptionalHeader.SectionAlignment; + } + PEFixHeader64->OptionalHeader.AddressOfEntryPoint = (DWORD)(EntryPoint - (ULONG_PTR)ImageBase); + PEFixHeader64->OptionalHeader.ImageBase = (DWORD64)((ULONG_PTR)ImageBase); + i = NumberOfSections; + while(i >= 1) + { + PEFixSection->PointerToRawData = PEFixSection->VirtualAddress; + RealignedVirtualSize = (PEFixSection->Misc.VirtualSize / PEHeader64->OptionalHeader.SectionAlignment) * PEHeader64->OptionalHeader.SectionAlignment; + if(RealignedVirtualSize < PEFixSection->Misc.VirtualSize) + { + RealignedVirtualSize = RealignedVirtualSize + PEHeader64->OptionalHeader.SectionAlignment; + } + PEFixSection->SizeOfRawData = RealignedVirtualSize; + PEFixSection->Misc.VirtualSize = RealignedVirtualSize; + PEFixSection = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEFixSection + IMAGE_SIZEOF_SECTION_HEADER); + i--; + } + WriteFile(hFile,ueCopyBuffer, (DWORD)AlignedHeaderSize, &uedNumberOfBytesRead, NULL); + ReadBase = (LPVOID)((ULONG_PTR)ReadBase + (DWORD)AlignedHeaderSize - TITANENGINE_PAGESIZE); + while(SizeOfImageDump > NULL) + { + ProcReadBase = (ULONG_PTR)ReadBase + TITANENGINE_PAGESIZE; + ReadBase = (LPVOID)ProcReadBase; + if(SizeOfImageDump >= TITANENGINE_PAGESIZE) + { + RtlZeroMemory(ueCopyBuffer, AlignedHeaderSize); + if(!ReadProcessMemory(hProcess, ReadBase, ueCopyBuffer, TITANENGINE_PAGESIZE, &ueNumberOfBytesRead)) + { + VirtualQueryEx(hProcess, ReadBase, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + VirtualProtectEx(hProcess, ReadBase, TITANENGINE_PAGESIZE, PAGE_EXECUTE_READWRITE, &MemInfo.Protect); + ReadProcessMemory(hProcess, ReadBase, ueCopyBuffer, TITANENGINE_PAGESIZE, &ueNumberOfBytesRead); + VirtualProtectEx(hProcess, ReadBase, TITANENGINE_PAGESIZE, MemInfo.Protect, &MemInfo.Protect); + } + WriteFile(hFile, ueCopyBuffer, TITANENGINE_PAGESIZE, &uedNumberOfBytesRead, NULL); + SizeOfImageDump = SizeOfImageDump - TITANENGINE_PAGESIZE; + } + else + { + RtlZeroMemory(ueCopyBuffer, AlignedHeaderSize); + if(!ReadProcessMemory(hProcess, ReadBase, ueCopyBuffer, SizeOfImageDump, &ueNumberOfBytesRead)) + { + VirtualQueryEx(hProcess, ReadBase, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + VirtualProtectEx(hProcess, ReadBase, TITANENGINE_PAGESIZE, PAGE_EXECUTE_READWRITE, &MemInfo.Protect); + ReadProcessMemory(hProcess, ReadBase, ueCopyBuffer, TITANENGINE_PAGESIZE, &ueNumberOfBytesRead); + VirtualProtectEx(hProcess, ReadBase, TITANENGINE_PAGESIZE, MemInfo.Protect, &MemInfo.Protect); + } + WriteFile(hFile, ueCopyBuffer, SizeOfImageDump, &uedNumberOfBytesRead, NULL); + SizeOfImageDump = NULL; + } + } + EngineCloseHandle(hFile); + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + VirtualFree(ueCopyBuffer, NULL, MEM_RELEASE); + return(true); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + VirtualFree(ueCopyBuffer, NULL, MEM_RELEASE); + return(false); + } + } + else + { + EngineCloseHandle(hFile); + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + VirtualFree(ueCopyBuffer, NULL, MEM_RELEASE); + return(false); + } + } + else + { + EngineCloseHandle(hFile); + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + VirtualFree(ueCopyBuffer, NULL, MEM_RELEASE); + return(false); + } + } + } + } + else + { + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + VirtualFree(ueCopyBuffer, NULL, MEM_RELEASE); + return(false); + } + } + else + { + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + VirtualFree(ueCopyBuffer, NULL, MEM_RELEASE); + return(false); + } + return(false); +} +__declspec(dllexport) bool __stdcall DumpProcessEx(DWORD ProcessId, LPVOID ImageBase, char* szDumpFileName, ULONG_PTR EntryPoint) +{ + + wchar_t uniDumpFileName[MAX_PATH] = {}; + + if(szDumpFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szDumpFileName, lstrlenA(szDumpFileName)+1, uniDumpFileName, sizeof(uniDumpFileName)/(sizeof(uniDumpFileName[0]))); + return(DumpProcessExW(ProcessId, ImageBase, uniDumpFileName, EntryPoint)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall DumpProcessExW(DWORD ProcessId, LPVOID ImageBase, wchar_t* szDumpFileName, ULONG_PTR EntryPoint) +{ + + HANDLE hProcess = 0; + BOOL ReturnValue = false; + + hProcess = OpenProcess(PROCESS_VM_READ, FALSE, ProcessId); + if(hProcess != INVALID_HANDLE_VALUE) + { + ReturnValue = DumpProcessW(hProcess, ImageBase, szDumpFileName, EntryPoint); + EngineCloseHandle(hProcess); + if(ReturnValue) + { + return(true); + } + else + { + return(false); + } + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall DumpMemory(HANDLE hProcess, LPVOID MemoryStart, ULONG_PTR MemorySize, char* szDumpFileName) +{ + + wchar_t uniDumpFileName[MAX_PATH] = {}; + + if(szDumpFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szDumpFileName, lstrlenA(szDumpFileName)+1, uniDumpFileName, sizeof(uniDumpFileName)/(sizeof(uniDumpFileName[0]))); + return(DumpMemoryW(hProcess, MemoryStart, MemorySize, uniDumpFileName)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall DumpMemoryW(HANDLE hProcess, LPVOID MemoryStart, ULONG_PTR MemorySize, wchar_t* szDumpFileName) +{ + + ULONG_PTR ueNumberOfBytesRead = 0; + DWORD uedNumberOfBytesRead = 0; + HANDLE hFile = 0; + LPVOID ReadBase = MemoryStart; + ULONG_PTR ProcReadBase = (ULONG_PTR)ReadBase; + LPVOID ueCopyBuffer = VirtualAlloc(NULL, 0x2000, MEM_COMMIT, PAGE_READWRITE); + MEMORY_BASIC_INFORMATION MemInfo; + + if(EngineCreatePathForFileW(szDumpFileName)) + { + hFile = CreateFileW(szDumpFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if(hFile != INVALID_HANDLE_VALUE) + { + while(MemorySize > NULL) + { + ReadBase = (LPVOID)ProcReadBase; + if(MemorySize >= 0x1000) + { + RtlZeroMemory(ueCopyBuffer,0x2000); + if(!ReadProcessMemory(hProcess, ReadBase, ueCopyBuffer, 0x1000, &ueNumberOfBytesRead)) + { + VirtualQueryEx(hProcess, ReadBase, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + VirtualProtectEx(hProcess, ReadBase, 0x1000, PAGE_EXECUTE_READWRITE, &MemInfo.Protect); + ReadProcessMemory(hProcess, ReadBase, ueCopyBuffer, 0x1000, &ueNumberOfBytesRead); + VirtualProtectEx(hProcess, ReadBase, 0x1000, MemInfo.Protect, &MemInfo.Protect); + } + WriteFile(hFile,ueCopyBuffer, 0x1000, &uedNumberOfBytesRead, NULL); + MemorySize = MemorySize - 0x1000; + } + else + { + RtlZeroMemory(ueCopyBuffer,0x2000); + if(!ReadProcessMemory(hProcess, ReadBase, ueCopyBuffer, MemorySize, &ueNumberOfBytesRead)) + { + VirtualQueryEx(hProcess, ReadBase, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + VirtualProtectEx(hProcess, ReadBase, 0x1000, PAGE_EXECUTE_READWRITE, &MemInfo.Protect); + ReadProcessMemory(hProcess, ReadBase, ueCopyBuffer, 0x1000, &ueNumberOfBytesRead); + VirtualProtectEx(hProcess, ReadBase, 0x1000, MemInfo.Protect, &MemInfo.Protect); + } + WriteFile(hFile, ueCopyBuffer, (DWORD)MemorySize, &uedNumberOfBytesRead, NULL); + MemorySize = NULL; + } + ProcReadBase = (ULONG_PTR)ReadBase + 0x1000; + } + EngineCloseHandle(hFile); + VirtualFree(ueCopyBuffer, NULL, MEM_RELEASE); + return(true); + } + else + { + VirtualFree(ueCopyBuffer, NULL, MEM_RELEASE); + return(false); + } + } + return(true); +} +__declspec(dllexport) bool __stdcall DumpMemoryEx(DWORD ProcessId, LPVOID MemoryStart, ULONG_PTR MemorySize, char* szDumpFileName) +{ + + wchar_t uniDumpFileName[MAX_PATH] = {}; + + if(szDumpFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szDumpFileName, lstrlenA(szDumpFileName)+1, uniDumpFileName, sizeof(uniDumpFileName)/(sizeof(uniDumpFileName[0]))); + return(DumpMemoryExW(ProcessId, MemoryStart, MemorySize, uniDumpFileName)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall DumpMemoryExW(DWORD ProcessId, LPVOID MemoryStart, ULONG_PTR MemorySize, wchar_t* szDumpFileName) +{ + + HANDLE hProcess = 0; + BOOL ReturnValue = false; + + hProcess = OpenProcess(PROCESS_VM_READ, FALSE, ProcessId); + if(hProcess != INVALID_HANDLE_VALUE) + { + ReturnValue = DumpMemoryW(hProcess, MemoryStart, MemorySize, szDumpFileName); + EngineCloseHandle(hProcess); + if(ReturnValue) + { + return(true); + } + else + { + return(false); + } + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall DumpRegions(HANDLE hProcess, char* szDumpFolder, bool DumpAboveImageBaseOnly) +{ + + wchar_t uniDumpFolder[MAX_PATH] = {}; + + if(szDumpFolder != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szDumpFolder, lstrlenA(szDumpFolder)+1, uniDumpFolder, sizeof(uniDumpFolder)/(sizeof(uniDumpFolder[0]))); + return(DumpRegionsW(hProcess, uniDumpFolder, DumpAboveImageBaseOnly)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall DumpRegionsW(HANDLE hProcess, wchar_t* szDumpFolder, bool DumpAboveImageBaseOnly) +{ + + int i; + DWORD Dummy = NULL; + wchar_t szDumpName[MAX_PATH]; + wchar_t szDumpFileName[MAX_PATH]; + MEMORY_BASIC_INFORMATION MemInfo; + ULONG_PTR DumpAddress = NULL; + ULONG_PTR EnumeratedModules[1024]; + bool AddressIsModuleBase = false; + + if(hProcess != NULL) + { + EnumProcessModules(hProcess, (HMODULE*)EnumeratedModules, sizeof(EnumeratedModules), &Dummy); + while(VirtualQueryEx(hProcess, (LPVOID)DumpAddress, &MemInfo, sizeof MEMORY_BASIC_INFORMATION) != NULL) + { + AddressIsModuleBase = false; + for(i = 0; i < 1024; i++) + { + if(EnumeratedModules[i] == (ULONG_PTR)MemInfo.AllocationBase) + { + AddressIsModuleBase = true; + i = 1024; + } + else if(EnumeratedModules[i] == 0) + { + i = 1024; + } + } + if(!(MemInfo.Protect & PAGE_NOACCESS) && AddressIsModuleBase == false) + { + if(DumpAboveImageBaseOnly == false || (DumpAboveImageBaseOnly == true && EnumeratedModules[0] < (ULONG_PTR)MemInfo.BaseAddress)) + { + RtlZeroMemory(&szDumpName, MAX_PATH); + RtlZeroMemory(&szDumpFileName, MAX_PATH); + lstrcpyW(szDumpFileName, szDumpFolder); + if(szDumpFileName[lstrlenW(szDumpFileName)-1] != 0x5C) + { + szDumpFileName[lstrlenW(szDumpFileName)] = 0x5C; + } + wsprintfW(szDumpName, L"Dump-%x_%x.dmp", (ULONG_PTR)MemInfo.BaseAddress, (ULONG_PTR)MemInfo.RegionSize); + lstrcatW(szDumpFileName, szDumpName); + DumpMemoryW(hProcess, (LPVOID)MemInfo.BaseAddress, (ULONG_PTR)MemInfo.RegionSize, szDumpFileName); + } + } + DumpAddress = DumpAddress + (ULONG_PTR)MemInfo.RegionSize; + } + return(true); + } + return(false); +} +__declspec(dllexport) bool __stdcall DumpRegionsEx(DWORD ProcessId, char* szDumpFolder, bool DumpAboveImageBaseOnly) +{ + + wchar_t uniDumpFolder[MAX_PATH] = {}; + + if(szDumpFolder != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szDumpFolder, lstrlenA(szDumpFolder)+1, uniDumpFolder, sizeof(uniDumpFolder)/(sizeof(uniDumpFolder[0]))); + return(DumpRegionsExW(ProcessId, uniDumpFolder, DumpAboveImageBaseOnly)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall DumpRegionsExW(DWORD ProcessId, wchar_t* szDumpFolder, bool DumpAboveImageBaseOnly) +{ + + HANDLE hProcess = 0; + BOOL ReturnValue = false; + + hProcess = OpenProcess(PROCESS_VM_READ, FALSE, ProcessId); + if(hProcess != INVALID_HANDLE_VALUE) + { + ReturnValue = DumpRegionsW(hProcess, szDumpFolder, DumpAboveImageBaseOnly); + EngineCloseHandle(hProcess); + if(ReturnValue) + { + return(true); + } + else + { + return(false); + } + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall DumpModule(HANDLE hProcess, LPVOID ModuleBase, char* szDumpFileName) +{ + + wchar_t uniDumpFileName[MAX_PATH] = {}; + + if(szDumpFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szDumpFileName, lstrlenA(szDumpFileName)+1, uniDumpFileName, sizeof(uniDumpFileName)/(sizeof(uniDumpFileName[0]))); + return(DumpModuleW(hProcess, ModuleBase, uniDumpFileName)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall DumpModuleW(HANDLE hProcess, LPVOID ModuleBase, wchar_t* szDumpFileName) +{ + + int i; + DWORD Dummy = NULL; + MODULEINFO RemoteModuleInfo; + ULONG_PTR EnumeratedModules[1024]; + + if(EnumProcessModules(hProcess, (HMODULE*)EnumeratedModules, sizeof(EnumeratedModules), &Dummy)) + { + for(i = 0; i < 512; i++) + { + if(EnumeratedModules[i] == (ULONG_PTR)ModuleBase) + { + GetModuleInformation(hProcess, (HMODULE)EnumeratedModules[i], &RemoteModuleInfo, sizeof MODULEINFO); + return(DumpMemoryW(hProcess, (LPVOID)EnumeratedModules[i], RemoteModuleInfo.SizeOfImage, szDumpFileName)); + } + } + } + return(false); +} +__declspec(dllexport) bool __stdcall DumpModuleEx(DWORD ProcessId, LPVOID ModuleBase, char* szDumpFileName) +{ + + wchar_t uniDumpFileName[MAX_PATH] = {}; + + if(szDumpFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szDumpFileName, lstrlenA(szDumpFileName)+1, uniDumpFileName, sizeof(uniDumpFileName)/(sizeof(uniDumpFileName[0]))); + return(DumpModuleExW(ProcessId, ModuleBase, uniDumpFileName)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall DumpModuleExW(DWORD ProcessId, LPVOID ModuleBase, wchar_t* szDumpFileName) +{ + + HANDLE hProcess = 0; + BOOL ReturnValue = false; + + hProcess = OpenProcess(PROCESS_VM_READ, FALSE, ProcessId); + if(hProcess != INVALID_HANDLE_VALUE) + { + ReturnValue = DumpModuleW(hProcess, ModuleBase, szDumpFileName); + EngineCloseHandle(hProcess); + if(ReturnValue) + { + return(true); + } + else + { + return(false); + } + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall PastePEHeader(HANDLE hProcess, LPVOID ImageBase, char* szDebuggedFileName) +{ + + wchar_t uniDebuggedFileName[MAX_PATH] = {}; + + if(szDebuggedFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szDebuggedFileName, lstrlenA(szDebuggedFileName)+1, uniDebuggedFileName, sizeof(uniDebuggedFileName)/(sizeof(uniDebuggedFileName[0]))); + return(PastePEHeaderW(hProcess, ImageBase, uniDebuggedFileName)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall PastePEHeaderW(HANDLE hProcess, LPVOID ImageBase, wchar_t* szDebuggedFileName) +{ + + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + IMAGE_NT_HEADERS32 RemotePEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + IMAGE_NT_HEADERS64 RemotePEHeader64; + ULONG_PTR ueNumberOfBytesRead = 0; + DWORD uedNumberOfBytesRead = 0; + DWORD FileSize = 0; + DWORD PEHeaderSize = 0; + ULONG_PTR dwImageBase = (ULONG_PTR)ImageBase; + BOOL FileIs64 = false; + HANDLE hFile = 0; + SIZE_T CalculatedHeaderSize = NULL; + LPVOID ueReadBuffer = VirtualAlloc(NULL, 0x2000, MEM_COMMIT, PAGE_READWRITE); + DWORD OldProtect = PAGE_READWRITE; + + hFile = CreateFileW(szDebuggedFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if(hFile != INVALID_HANDLE_VALUE) + { + FileSize = GetFileSize(hFile, NULL); + if(FileSize < 0x1000) + { + ReadFile(hFile, ueReadBuffer, FileSize, &uedNumberOfBytesRead, NULL); + } + else + { + ReadFile(hFile, ueReadBuffer, 0x1000, &uedNumberOfBytesRead, NULL); + } + if(FileSize > 0x200) + { + DOSHeader = (PIMAGE_DOS_HEADER)ueReadBuffer; + if(EngineValidateHeader((ULONG_PTR)ueReadBuffer, hProcess, ImageBase, DOSHeader, false)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + CalculatedHeaderSize = DOSHeader->e_lfanew + sizeof IMAGE_DOS_HEADER + sizeof IMAGE_NT_HEADERS64; + if(CalculatedHeaderSize > 0x1000) + { + SetFilePointer(hFile, NULL, NULL, FILE_BEGIN); + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + ueReadBuffer = VirtualAlloc(NULL, CalculatedHeaderSize, MEM_COMMIT, PAGE_READWRITE); + if(!ReadFile(hFile, ueReadBuffer, (DWORD)CalculatedHeaderSize, &uedNumberOfBytesRead, NULL)) + { + EngineCloseHandle(hFile); + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + return(false); + } + } + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + if(ReadProcessMemory(hProcess, (LPVOID)((ULONG_PTR)ImageBase + DOSHeader->e_lfanew), &RemotePEHeader32, sizeof IMAGE_NT_HEADERS32, &ueNumberOfBytesRead)) + { + PEHeaderSize = PEHeader32->FileHeader.NumberOfSections * IMAGE_SIZEOF_SECTION_HEADER + PEHeader32->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4; + FileIs64 = false; + } + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + if(ReadProcessMemory(hProcess, (LPVOID)((ULONG_PTR)ImageBase + DOSHeader->e_lfanew), &RemotePEHeader64, sizeof IMAGE_NT_HEADERS32, &ueNumberOfBytesRead)) + { + PEHeaderSize = PEHeader64->FileHeader.NumberOfSections * IMAGE_SIZEOF_SECTION_HEADER + PEHeader64->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4; + FileIs64 = true; + } + } + else + { + EngineCloseHandle(hFile); + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + return(false); + } + if(!FileIs64) + { + PEHeader32->OptionalHeader.ImageBase = (DWORD)(dwImageBase); + if(VirtualProtectEx(hProcess, ImageBase, PEHeaderSize, PAGE_READWRITE, &OldProtect)) + { + if(WriteProcessMemory(hProcess, ImageBase, ueReadBuffer, PEHeaderSize, &ueNumberOfBytesRead)) + { + EngineCloseHandle(hFile); + VirtualProtectEx(hProcess, ImageBase, PEHeaderSize, OldProtect, &OldProtect); + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + return(true); + } + else + { + EngineCloseHandle(hFile); + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + return(false); + } + } + else + { + EngineCloseHandle(hFile); + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + return(false); + } + } + else + { + PEHeader64->OptionalHeader.ImageBase = dwImageBase; + if(VirtualProtectEx(hProcess, ImageBase, PEHeaderSize, PAGE_READWRITE, &OldProtect)) + { + if(WriteProcessMemory(hProcess, ImageBase, ueReadBuffer, PEHeaderSize, &ueNumberOfBytesRead)) + { + EngineCloseHandle(hFile); + VirtualProtectEx(hProcess, ImageBase, PEHeaderSize, OldProtect, &OldProtect); + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + return(true); + } + else + { + EngineCloseHandle(hFile); + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + return(false); + } + } + else + { + EngineCloseHandle(hFile); + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + return(false); + } + } + } + else + { + EngineCloseHandle(hFile); + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + return(false); + } + } + else + { + EngineCloseHandle(hFile); + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + return(false); + } + } + else + { + EngineCloseHandle(hFile); + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + return(false); + } + return(false); +} +__declspec(dllexport) bool __stdcall ExtractSection(char* szFileName, char* szDumpFileName, DWORD SectionNumber) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + wchar_t uniDumpFileName[MAX_PATH] = {}; + + if(szFileName != NULL && szDumpFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + MultiByteToWideChar(CP_ACP, NULL, szDumpFileName, lstrlenA(szDumpFileName)+1, uniDumpFileName, sizeof(uniDumpFileName)/(sizeof(uniDumpFileName[0]))); + return(ExtractSectionW(uniFileName, uniDumpFileName, SectionNumber)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall ExtractSectionW(wchar_t* szFileName, wchar_t* szDumpFileName, DWORD SectionNumber) +{ + + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + PIMAGE_SECTION_HEADER PESections; + DWORD NumberOfBytesWritten; + BOOL FileIs64; + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + HANDLE hFile; + + if(MapFileExW(szFileName, UE_ACCESS_READ, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, FileHandle, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + if(!FileIs64) + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader32 + PEHeader32->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + if(SectionNumber <= PEHeader32->FileHeader.NumberOfSections) + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + SectionNumber * IMAGE_SIZEOF_SECTION_HEADER); + if(EngineCreatePathForFileW(szDumpFileName)) + { + hFile = CreateFileW(szDumpFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if(hFile != INVALID_HANDLE_VALUE) + { + __try + { + WriteFile(hFile, (LPCVOID)(FileMapVA + PESections->PointerToRawData), PESections->SizeOfRawData, &NumberOfBytesWritten, NULL); + EngineCloseHandle(hFile); + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(true); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + EngineCloseHandle(hFile); + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + DeleteFileW(szDumpFileName); + return(false); + } + } + } + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + else + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader64 + PEHeader64->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + if(SectionNumber <= PEHeader64->FileHeader.NumberOfSections) + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + SectionNumber * IMAGE_SIZEOF_SECTION_HEADER); + if(EngineCreatePathForFileW(szDumpFileName)) + { + hFile = CreateFileW(szDumpFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if(hFile != INVALID_HANDLE_VALUE) + { + __try + { + WriteFile(hFile, (LPCVOID)(FileMapVA + PESections->PointerToRawData), PESections->SizeOfRawData, &NumberOfBytesWritten, NULL); + EngineCloseHandle(hFile); + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(true); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + EngineCloseHandle(hFile); + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + DeleteFileW(szDumpFileName); + return(false); + } + } + } + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + return(false); +} +__declspec(dllexport) bool __stdcall ResortFileSections(char* szFileName) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + + if(szFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + return(ResortFileSectionsW(uniFileName)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall ResortFileSectionsW(wchar_t* szFileName) +{ + + int i = 0; + int j = 0; + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + PIMAGE_SECTION_HEADER PESections; + DWORD SectionNumber = 0; + BOOL FileIs64; + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + wchar_t szBackupFile[MAX_PATH] = {}; + wchar_t szBackupItem[MAX_PATH] = {}; + ULONG_PTR fileSectionData[MAXIMUM_SECTION_NUMBER][3]; + ULONG_PTR fileSectionTemp; + LPVOID sortedFileName; + + if(engineBackupForCriticalFunctions && CreateGarbageItem(&szBackupItem, sizeof szBackupItem)) + { + if(!FillGarbageItem(szBackupItem, szFileName, &szBackupFile, sizeof szBackupItem)) + { + RtlZeroMemory(&szBackupItem, sizeof szBackupItem); + lstrcpyW(szBackupFile, szFileName); + } + } + else + { + RtlZeroMemory(&szBackupItem, sizeof szBackupItem); + lstrcpyW(szBackupFile, szFileName); + } + if(MapFileExW(szBackupFile, UE_ACCESS_ALL, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, FileHandle, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(false); + } + if(!FileIs64) + { + sortedFileName = VirtualAlloc(NULL, FileSize, MEM_COMMIT, PAGE_READWRITE); + __try + { + RtlMoveMemory(sortedFileName, (LPVOID)FileMapVA, FileSize); + SectionNumber = PEHeader32->FileHeader.NumberOfSections; + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader32 + PEHeader32->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + while(SectionNumber > 0) + { + fileSectionData[i][0] = (ULONG_PTR)(PESections->PointerToRawData); + fileSectionData[i][1] = PESections->SizeOfRawData; + fileSectionData[i][2] = PEHeader32->FileHeader.NumberOfSections - SectionNumber; + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + IMAGE_SIZEOF_SECTION_HEADER); + SectionNumber--; + i++; + } + for(j = 0; j < PEHeader32->FileHeader.NumberOfSections; j++) + { + for(i = 0; i < PEHeader32->FileHeader.NumberOfSections; i++) + { + if(fileSectionData[i][0] > fileSectionData[j][0]) + { + fileSectionTemp = fileSectionData[j][0]; + fileSectionData[j][0] = fileSectionData[i][0]; + fileSectionData[i][0] = fileSectionTemp; + fileSectionTemp = fileSectionData[j][1]; + fileSectionData[j][1] = fileSectionData[i][1]; + fileSectionData[i][1] = fileSectionTemp; + } + } + } + for(i = 0; i < PEHeader32->FileHeader.NumberOfSections; i++) + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader32 - FileMapVA + (ULONG_PTR)sortedFileName + PEHeader32->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + fileSectionData[i][2] * IMAGE_SIZEOF_SECTION_HEADER); + RtlMoveMemory((LPVOID)((ULONG_PTR)sortedFileName + fileSectionData[i][0]), (LPVOID)((ULONG_PTR)FileMapVA + PESections->PointerToRawData), fileSectionData[i][1]); + PESections->PointerToRawData = (DWORD)fileSectionData[i][0]; + PESections->SizeOfRawData = (DWORD)fileSectionData[i][1]; + } + RtlMoveMemory((LPVOID)FileMapVA, sortedFileName, FileSize); + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + VirtualFree(sortedFileName, NULL, MEM_RELEASE); + if(szBackupItem[0] != NULL) + { + if(CopyFileW(szBackupFile, szFileName, false)) + { + RemoveGarbageItem(szBackupItem, true); + return(true); + } + else + { + RemoveGarbageItem(szBackupItem, true); + return(false); + } + } + else + { + return(true); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + VirtualFree(sortedFileName, NULL, MEM_RELEASE); + RemoveGarbageItem(szBackupItem, true); + return(false); + } + } + else + { + sortedFileName = VirtualAlloc(NULL, FileSize, MEM_COMMIT, PAGE_READWRITE); + __try + { + RtlMoveMemory(sortedFileName, (LPVOID)FileMapVA, FileSize); + SectionNumber = PEHeader64->FileHeader.NumberOfSections; + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader64 + PEHeader64->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + while(SectionNumber > 0) + { + fileSectionData[i][0] = (ULONG_PTR)(PESections->PointerToRawData); + fileSectionData[i][1] = PESections->SizeOfRawData; + fileSectionData[i][2] = PEHeader64->FileHeader.NumberOfSections - SectionNumber; + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + IMAGE_SIZEOF_SECTION_HEADER); + SectionNumber--; + i++; + } + for(j = 0; j < PEHeader64->FileHeader.NumberOfSections; j++) + { + for(i = 0; i < PEHeader64->FileHeader.NumberOfSections; i++) + { + if(fileSectionData[i][0] > fileSectionData[j][0]) + { + fileSectionTemp = fileSectionData[j][0]; + fileSectionData[j][0] = fileSectionData[i][0]; + fileSectionData[i][0] = fileSectionTemp; + fileSectionTemp = fileSectionData[j][1]; + fileSectionData[j][1] = fileSectionData[i][1]; + fileSectionData[i][1] = fileSectionTemp; + } + } + } + for(i = 0; i < PEHeader64->FileHeader.NumberOfSections; i++) + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader64 - FileMapVA + (ULONG_PTR)sortedFileName + PEHeader64->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + fileSectionData[i][2] * IMAGE_SIZEOF_SECTION_HEADER); + RtlMoveMemory((LPVOID)((ULONG_PTR)sortedFileName + fileSectionData[i][0]), (LPVOID)((ULONG_PTR)FileMapVA + PESections->PointerToRawData), fileSectionData[i][1]); + PESections->PointerToRawData = (DWORD)fileSectionData[i][0]; + PESections->SizeOfRawData = (DWORD)fileSectionData[i][1]; + } + RtlMoveMemory((LPVOID)FileMapVA, sortedFileName, FileSize); + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + VirtualFree(sortedFileName, NULL, MEM_RELEASE); + if(szBackupItem[0] != NULL) + { + if(CopyFileW(szBackupFile, szFileName, false)) + { + RemoveGarbageItem(szBackupItem, true); + return(true); + } + else + { + RemoveGarbageItem(szBackupItem, true); + return(false); + } + } + else + { + return(true); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + VirtualFree(sortedFileName, NULL, MEM_RELEASE); + RemoveGarbageItem(szBackupItem, true); + return(false); + } + } + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(false); + } + } + RemoveGarbageItem(szBackupItem, true); + return(false); +} +__declspec(dllexport) bool __stdcall FindOverlay(char* szFileName, LPDWORD OverlayStart, LPDWORD OverlaySize) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + + if(szFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + return(FindOverlayW(uniFileName, OverlayStart, OverlaySize)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall FindOverlayW(wchar_t* szFileName, LPDWORD OverlayStart, LPDWORD OverlaySize) +{ + + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + PIMAGE_SECTION_HEADER PESections; + DWORD SectionNumber = 0; + DWORD SectionRawOffset = 0; + DWORD SectionRawSize = 0; + BOOL FileIs64; + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + + if(MapFileExW(szFileName, UE_ACCESS_READ, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, FileHandle, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + if(!FileIs64) + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader32 + PEHeader32->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + SectionNumber = PEHeader32->FileHeader.NumberOfSections; + __try + { + while(SectionNumber > 0) + { + if(PESections->PointerToRawData >= SectionRawOffset) + { + if(PESections->SizeOfRawData != NULL || (SectionRawOffset != PESections->PointerToRawData)) + { + SectionRawSize = PESections->SizeOfRawData; + } + SectionRawOffset = PESections->PointerToRawData; + } + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + IMAGE_SIZEOF_SECTION_HEADER); + SectionNumber--; + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + if(SectionRawOffset + SectionRawSize < FileSize) + { + if(OverlayStart != NULL && OverlaySize != NULL) + { + *OverlayStart = (DWORD)(SectionRawOffset + SectionRawSize); + *OverlaySize = (DWORD)(FileSize - SectionRawOffset - SectionRawSize); + } + return(true); + } + else + { + return(false); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + else + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader64 + PEHeader64->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + SectionNumber = PEHeader64->FileHeader.NumberOfSections; + __try + { + while(SectionNumber > 0) + { + if(PESections->PointerToRawData >= SectionRawOffset) + { + if(PESections->SizeOfRawData != NULL || (SectionRawOffset != PESections->PointerToRawData)) + { + SectionRawSize = PESections->SizeOfRawData; + } + SectionRawOffset = PESections->PointerToRawData; + } + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + IMAGE_SIZEOF_SECTION_HEADER); + SectionNumber--; + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + if(SectionRawOffset + SectionRawSize < FileSize) + { + if(OverlayStart != NULL && OverlaySize != NULL) + { + *OverlayStart = (DWORD)(SectionRawOffset + SectionRawSize); + *OverlaySize = (DWORD)(FileSize - SectionRawOffset - SectionRawSize); + } + return(true); + } + else + { + return(false); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + return(false); +} +__declspec(dllexport) bool __stdcall ExtractOverlay(char* szFileName, char* szExtactedFileName) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + wchar_t uniExtactedFileName[MAX_PATH] = {}; + + if(szFileName != NULL && szExtactedFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + MultiByteToWideChar(CP_ACP, NULL, szExtactedFileName, lstrlenA(szExtactedFileName)+1, uniExtactedFileName, sizeof(uniExtactedFileName)/(sizeof(uniExtactedFileName[0]))); + return(ExtractOverlayW(uniFileName, uniExtactedFileName)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall ExtractOverlayW(wchar_t* szFileName, wchar_t* szExtactedFileName) +{ + + HANDLE hFile = 0; + HANDLE hFileWrite = 0; + BOOL Return = false; + DWORD OverlayStart = 0; + DWORD OverlaySize = 0; + DWORD ueNumberOfBytesRead = 0; + LPVOID ueReadBuffer = VirtualAlloc(NULL, 0x2000, MEM_COMMIT, PAGE_READWRITE); + + Return = FindOverlayW(szFileName, &OverlayStart, &OverlaySize); + if(Return) + { + hFile = CreateFileW(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if(hFile != INVALID_HANDLE_VALUE) + { + if(EngineCreatePathForFileW(szExtactedFileName)) + { + hFileWrite = CreateFileW(szExtactedFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if(hFileWrite != INVALID_HANDLE_VALUE) + { + SetFilePointer(hFile, OverlayStart, NULL, FILE_BEGIN); + while(OverlaySize > 0) + { + if(OverlaySize > 0x1000) + { + RtlZeroMemory(ueReadBuffer, 0x2000); + ReadFile(hFile, ueReadBuffer, 0x1000, &ueNumberOfBytesRead, NULL); + WriteFile(hFileWrite, ueReadBuffer, 0x1000, &ueNumberOfBytesRead, NULL); + OverlaySize = OverlaySize - 0x1000; + } + else + { + RtlZeroMemory(ueReadBuffer, 0x2000); + ReadFile(hFile, ueReadBuffer, OverlaySize, &ueNumberOfBytesRead, NULL); + WriteFile(hFileWrite, ueReadBuffer, OverlaySize, &ueNumberOfBytesRead, NULL); + OverlaySize = 0; + } + } + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + EngineCloseHandle(hFile); + EngineCloseHandle(hFileWrite); + return(true); + } + else + { + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + EngineCloseHandle(hFile); + return(false); + } + } + } + } + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + return(false); +} +__declspec(dllexport) bool __stdcall AddOverlay(char* szFileName, char* szOverlayFileName) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + wchar_t uniOverlayFileName[MAX_PATH] = {}; + + if(szFileName != NULL && szOverlayFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + MultiByteToWideChar(CP_ACP, NULL, szOverlayFileName, lstrlenA(szOverlayFileName)+1, uniOverlayFileName, sizeof(uniOverlayFileName)/(sizeof(uniOverlayFileName[0]))); + return(AddOverlayW(uniFileName, uniOverlayFileName)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall AddOverlayW(wchar_t* szFileName, wchar_t* szOverlayFileName) +{ + + HANDLE hFile = 0; + HANDLE hFileRead = 0; + DWORD FileSize = 0; + DWORD OverlaySize = 0; + ULONG_PTR ueNumberOfBytesRead = 0; + DWORD uedNumberOfBytesRead = 0; + LPVOID ueReadBuffer = VirtualAlloc(NULL, 0x2000, MEM_COMMIT, PAGE_READWRITE); + + hFile = CreateFileW(szFileName, GENERIC_READ+GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if(hFile != INVALID_HANDLE_VALUE) + { + hFileRead = CreateFileW(szOverlayFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if(hFileRead != INVALID_HANDLE_VALUE) + { + FileSize = GetFileSize(hFile, NULL); + OverlaySize = GetFileSize(hFileRead, NULL); + SetFilePointer(hFile, FileSize, NULL, FILE_BEGIN); + while(OverlaySize > 0) + { + if(OverlaySize > 0x1000) + { + RtlZeroMemory(ueReadBuffer, 0x2000); + ReadFile(hFileRead, ueReadBuffer, 0x1000, &uedNumberOfBytesRead, NULL); + WriteFile(hFile, ueReadBuffer, 0x1000, &uedNumberOfBytesRead, NULL); + OverlaySize = OverlaySize - 0x1000; + } + else + { + RtlZeroMemory(ueReadBuffer, 0x2000); + ReadFile(hFileRead, ueReadBuffer, OverlaySize, &uedNumberOfBytesRead, NULL); + WriteFile(hFile, ueReadBuffer, OverlaySize, &uedNumberOfBytesRead, NULL); + OverlaySize = 0; + } + } + EngineCloseHandle(hFile); + EngineCloseHandle(hFileRead); + return(true); + } + else + { + EngineCloseHandle(hFile); + return(false); + } + } + return(false); +} +__declspec(dllexport) bool __stdcall CopyOverlay(char* szInFileName, char* szOutFileName) +{ + + wchar_t uniInFileName[MAX_PATH] = {}; + wchar_t uniOutFileName[MAX_PATH] = {}; + + if(szInFileName != NULL && szOutFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szInFileName, lstrlenA(szInFileName)+1, uniInFileName, sizeof(uniInFileName)/(sizeof(uniInFileName[0]))); + MultiByteToWideChar(CP_ACP, NULL, szOutFileName, lstrlenA(szOutFileName)+1, uniOutFileName, sizeof(uniOutFileName)/(sizeof(uniOutFileName[0]))); + return(CopyOverlayW(uniInFileName, uniOutFileName)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall CopyOverlayW(wchar_t* szInFileName, wchar_t* szOutFileName) +{ + + wchar_t szTempName[MAX_PATH] = {}; + wchar_t szTempFolder[MAX_PATH] = {}; + + if(GetTempPathW(MAX_PATH, szTempFolder) < MAX_PATH) + { + if(GetTempFileNameW(szTempFolder, L"OverlayTemp", GetTickCount() + 101, szTempName)) + { + if(ExtractOverlayW(szInFileName, szTempName)) + { + AddOverlayW(szOutFileName, szTempName); + DeleteFileW(szTempName); + return(true); + } + } + } + return(false); +} +__declspec(dllexport) bool __stdcall RemoveOverlay(char* szFileName) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + + if(szFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + return(RemoveOverlayW(uniFileName)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall RemoveOverlayW(wchar_t* szFileName) +{ + + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + DWORD OverlayStart = 0; + DWORD OverlaySize = 0; + + if(FindOverlayW(szFileName, &OverlayStart, &OverlaySize)) + { + if(MapFileExW(szFileName, UE_ACCESS_ALL, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + FileSize = FileSize - OverlaySize; + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(true); + } + } + return(false); +} +__declspec(dllexport) bool __stdcall MakeAllSectionsRWE(char* szFileName) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + + if(szFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + return(MakeAllSectionsRWEW(uniFileName)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall MakeAllSectionsRWEW(wchar_t* szFileName) +{ + + wchar_t szBackupFile[MAX_PATH] = {}; + wchar_t szBackupItem[MAX_PATH] = {}; + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + PIMAGE_SECTION_HEADER PESections; + DWORD SectionNumber = 0; + BOOL FileIs64; + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + + if(engineBackupForCriticalFunctions && CreateGarbageItem(&szBackupItem, sizeof szBackupItem)) + { + if(!FillGarbageItem(szBackupItem, szFileName, &szBackupFile, sizeof szBackupItem)) + { + RtlZeroMemory(&szBackupItem, sizeof szBackupItem); + lstrcpyW(szBackupFile, szFileName); + } + } + else + { + RtlZeroMemory(&szBackupItem, sizeof szBackupItem); + lstrcpyW(szBackupFile, szFileName); + } + if(MapFileExW(szBackupFile, UE_ACCESS_ALL, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, FileHandle, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(false); + } + if(!FileIs64) + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader32 + PEHeader32->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + SectionNumber = PEHeader32->FileHeader.NumberOfSections; + __try + { + while(SectionNumber > 0) + { + PESections->Characteristics = 0xE0000020; + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + IMAGE_SIZEOF_SECTION_HEADER); + SectionNumber--; + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + if(szBackupItem[0] != NULL) + { + if(CopyFileW(szBackupFile, szFileName, false)) + { + RemoveGarbageItem(szBackupItem, true); + return(true); + } + else + { + RemoveGarbageItem(szBackupItem, true); + return(false); + } + } + else + { + return(true); + } + return(true); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(false); + } + } + else + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader64 + PEHeader64->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + SectionNumber = PEHeader64->FileHeader.NumberOfSections; + __try + { + while(SectionNumber > 0) + { + PESections->Characteristics = 0xE0000020; + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + IMAGE_SIZEOF_SECTION_HEADER); + SectionNumber--; + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + if(szBackupItem[0] != NULL) + { + if(CopyFileW(szBackupFile, szFileName, false)) + { + RemoveGarbageItem(szBackupItem, true); + return(true); + } + else + { + RemoveGarbageItem(szBackupItem, true); + return(false); + } + } + else + { + return(true); + } + return(true); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(false); + } + } + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(false); + } + } + RemoveGarbageItem(szBackupItem, true); + return(false); +} +__declspec(dllexport) long __stdcall AddNewSectionEx(char* szFileName, char* szSectionName, DWORD SectionSize, DWORD SectionAttributes, LPVOID SectionContent, DWORD ContentSize) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + + if(szFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + return(AddNewSectionExW(uniFileName, szSectionName, SectionSize, SectionAttributes, SectionContent, ContentSize)); + } + else + { + return(NULL); + } +} +__declspec(dllexport) long __stdcall AddNewSectionExW(wchar_t* szFileName, char* szSectionName, DWORD SectionSize, DWORD SectionAttributes, LPVOID SectionContent, DWORD ContentSize) +{ + + bool OverlayHasBeenRemoved = false; + wchar_t szBackupOverlayFile[MAX_PATH] = {}; + wchar_t szBackupFile[MAX_PATH] = {}; + wchar_t szBackupItem[MAX_PATH] = {}; + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + PIMAGE_SECTION_HEADER PESections; + DWORD SectionNameLength = 0; + DWORD NewSectionVirtualOffset = 0; + DWORD FileResizeValue = 0; + DWORD LastSectionRawSize = 0; + DWORD alignedSectionSize = 0; + DWORD NtSizeOfImage = 0; + DWORD SectionNumber = 0; + DWORD SpaceLeft = 0; + LPVOID NameOffset; + BOOL FileIs64; + HANDLE FileHandle; + DWORD FileSize; + DWORD OldFileSize = 0; + HANDLE FileMap; + ULONG_PTR FileMapVA; + + if(ContentSize < SectionSize && ContentSize != 0) + { + ContentSize = SectionSize; + } + else if(ContentSize > SectionSize) + { + SectionSize = ContentSize; + } + + if(engineBackupForCriticalFunctions && CreateGarbageItem(&szBackupItem, sizeof szBackupItem)) + { + if(!FillGarbageItem(szBackupItem, szFileName, &szBackupFile, sizeof szBackupItem)) + { + RtlZeroMemory(&szBackupItem, sizeof szBackupItem); + lstrcpyW(szBackupFile, szFileName); + } + if(FindOverlayW(szBackupFile, NULL, NULL)) + { + if(!FillGarbageItem(szBackupItem, NULL, &szBackupOverlayFile, sizeof szBackupItem)) + { + RtlZeroMemory(&szBackupOverlayFile, sizeof szBackupOverlayFile); + } + else + { + if(ExtractOverlayW(szBackupFile, szBackupOverlayFile) && RemoveOverlayW(szBackupFile)) + { + OverlayHasBeenRemoved = true; + } + } + } + } + else + { + RtlZeroMemory(&szBackupItem, sizeof szBackupItem); + lstrcpyW(szBackupFile, szFileName); + } + if(MapFileExW(szBackupFile, UE_ACCESS_READ, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + OldFileSize = FileSize; + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, FileHandle, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(0); + } + if(!FileIs64) + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader32 + PEHeader32->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + SectionNumber = PEHeader32->FileHeader.NumberOfSections; + __try + { + alignedSectionSize = ((DWORD)SectionSize / PEHeader32->OptionalHeader.FileAlignment) * PEHeader32->OptionalHeader.FileAlignment; + if(alignedSectionSize < SectionSize) + { + SectionSize = alignedSectionSize + PEHeader32->OptionalHeader.FileAlignment; + } + else + { + SectionSize = alignedSectionSize; + } + SpaceLeft = PESections->PointerToRawData - (SectionNumber * IMAGE_SIZEOF_SECTION_HEADER) - DOSHeader->e_lfanew - sizeof IMAGE_NT_HEADERS32; + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + (SectionNumber - 1) * IMAGE_SIZEOF_SECTION_HEADER); + LastSectionRawSize = (PESections->SizeOfRawData / PEHeader32->OptionalHeader.FileAlignment) * PEHeader32->OptionalHeader.FileAlignment; + if(LastSectionRawSize < PESections->SizeOfRawData) + { + LastSectionRawSize = LastSectionRawSize + PEHeader32->OptionalHeader.FileAlignment; + } + LastSectionRawSize = LastSectionRawSize - PESections->SizeOfRawData; + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + FileResizeValue = LastSectionRawSize + SectionSize; + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(0); + } + } + else + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader64 + PEHeader64->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + SectionNumber = PEHeader64->FileHeader.NumberOfSections; + __try + { + alignedSectionSize = ((DWORD)SectionSize / PEHeader64->OptionalHeader.FileAlignment) * PEHeader64->OptionalHeader.FileAlignment; + if(alignedSectionSize < SectionSize) + { + SectionSize = alignedSectionSize + PEHeader64->OptionalHeader.FileAlignment; + } + else + { + SectionSize = alignedSectionSize; + } + SpaceLeft = PESections->PointerToRawData - (SectionNumber * IMAGE_SIZEOF_SECTION_HEADER) - DOSHeader->e_lfanew - sizeof IMAGE_NT_HEADERS64; + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + (SectionNumber - 1) * IMAGE_SIZEOF_SECTION_HEADER); + LastSectionRawSize = (PESections->SizeOfRawData / PEHeader64->OptionalHeader.FileAlignment) * PEHeader64->OptionalHeader.FileAlignment; + if(LastSectionRawSize < PESections->SizeOfRawData) + { + LastSectionRawSize = LastSectionRawSize + PEHeader64->OptionalHeader.FileAlignment; + } + LastSectionRawSize = LastSectionRawSize - PESections->SizeOfRawData; + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + FileResizeValue = LastSectionRawSize + SectionSize; + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(0); + } + } + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(0); + } + } + if(SpaceLeft > IMAGE_SIZEOF_SECTION_HEADER) + { + if(MapFileExW(szBackupFile, UE_ACCESS_ALL, &FileHandle, &FileSize, &FileMap, &FileMapVA, FileResizeValue)) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, FileHandle, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(0); + } + if(!FileIs64) + { + __try + { + if(SectionSize == 0) + { + SectionSize = PEHeader32->OptionalHeader.FileAlignment; + } + alignedSectionSize = ((DWORD)SectionSize / PEHeader32->OptionalHeader.SectionAlignment) * PEHeader32->OptionalHeader.SectionAlignment; + if(alignedSectionSize < SectionSize) + { + alignedSectionSize = alignedSectionSize + PEHeader32->OptionalHeader.SectionAlignment; + } + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader32 + PEHeader32->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + SectionNumber = PEHeader32->FileHeader.NumberOfSections; + PEHeader32->FileHeader.NumberOfSections = PEHeader32->FileHeader.NumberOfSections + 1; + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + (SectionNumber - 1)* IMAGE_SIZEOF_SECTION_HEADER); + NewSectionVirtualOffset = PESections->VirtualAddress + (PESections->Misc.VirtualSize / PEHeader32->OptionalHeader.SectionAlignment) * PEHeader32->OptionalHeader.SectionAlignment; + if(NewSectionVirtualOffset < PESections->VirtualAddress + PESections->Misc.VirtualSize) + { + NewSectionVirtualOffset = NewSectionVirtualOffset + PEHeader32->OptionalHeader.SectionAlignment; + } + PESections->SizeOfRawData = PESections->SizeOfRawData + LastSectionRawSize; + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + IMAGE_SIZEOF_SECTION_HEADER); + PEHeader32->OptionalHeader.SizeOfImage = NewSectionVirtualOffset + alignedSectionSize; + NameOffset = &PESections->Name; + if(lstrlenA(szSectionName) >= 8) + { + SectionNameLength = 8; + } + else + { + SectionNameLength = lstrlenA(szSectionName); + } + RtlMoveMemory(NameOffset, szSectionName, SectionNameLength); + if(SectionAttributes == 0) + { + PESections->Characteristics = 0xE0000020; + } + else + { + PESections->Characteristics = (DWORD)(SectionAttributes); + } + PESections->Misc.VirtualSize = alignedSectionSize; + PESections->SizeOfRawData = (DWORD)(SectionSize); + PESections->VirtualAddress = NewSectionVirtualOffset; + PESections->PointerToRawData = OldFileSize + LastSectionRawSize; + if(SectionContent != NULL) + { + RtlMoveMemory((LPVOID)(FileMapVA + OldFileSize), SectionContent, ContentSize); + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + if(szBackupItem[0] != NULL) + { + if(CopyFileW(szBackupFile, szFileName, false)) + { + if(OverlayHasBeenRemoved && !AddOverlayW(szFileName, szBackupOverlayFile)) + { + RemoveGarbageItem(szBackupItem, true); + return(0); + } + RemoveGarbageItem(szBackupItem, true); + return(NewSectionVirtualOffset); + } + else + { + RemoveGarbageItem(szBackupItem, true); + return(0); + } + } + else + { + return(NewSectionVirtualOffset); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(0); + } + } + else + { + __try + { + if(SectionSize == 0) + { + SectionSize = PEHeader64->OptionalHeader.FileAlignment; + } + alignedSectionSize = ((DWORD)SectionSize / PEHeader64->OptionalHeader.SectionAlignment) * PEHeader64->OptionalHeader.SectionAlignment; + if(alignedSectionSize < SectionSize) + { + alignedSectionSize = alignedSectionSize + PEHeader64->OptionalHeader.SectionAlignment; + } + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader64 + PEHeader64->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + SectionNumber = PEHeader64->FileHeader.NumberOfSections; + PEHeader32->FileHeader.NumberOfSections = PEHeader32->FileHeader.NumberOfSections + 1; + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + (SectionNumber - 1)* IMAGE_SIZEOF_SECTION_HEADER); + NewSectionVirtualOffset = PESections->VirtualAddress + (PESections->Misc.VirtualSize / PEHeader64->OptionalHeader.SectionAlignment) * PEHeader64->OptionalHeader.SectionAlignment; + if(NewSectionVirtualOffset < PESections->VirtualAddress + PESections->Misc.VirtualSize) + { + NewSectionVirtualOffset = NewSectionVirtualOffset + PEHeader64->OptionalHeader.SectionAlignment; + } + PESections->SizeOfRawData = PESections->SizeOfRawData + LastSectionRawSize; + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + IMAGE_SIZEOF_SECTION_HEADER); + PEHeader64->OptionalHeader.SizeOfImage = NewSectionVirtualOffset + alignedSectionSize; + NameOffset = &PESections->Name; + if(lstrlenA(szSectionName) >= 8) + { + SectionNameLength = 8; + } + else + { + SectionNameLength = lstrlenA(szSectionName); + } + RtlMoveMemory(NameOffset, szSectionName, SectionNameLength); + if(SectionAttributes == 0) + { + PESections->Characteristics = 0xE0000020; + } + else + { + PESections->Characteristics = (DWORD)(SectionAttributes); + } + PESections->Misc.VirtualSize = alignedSectionSize; + PESections->SizeOfRawData = (DWORD)(SectionSize); + PESections->VirtualAddress = NewSectionVirtualOffset; + PESections->PointerToRawData = OldFileSize + LastSectionRawSize; + if(SectionContent != NULL) + { + RtlMoveMemory((LPVOID)(FileMapVA + OldFileSize), SectionContent, ContentSize); + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + if(szBackupItem[0] != NULL) + { + if(CopyFileW(szBackupFile, szFileName, false)) + { + if(OverlayHasBeenRemoved && !AddOverlayW(szFileName, szBackupOverlayFile)) + { + RemoveGarbageItem(szBackupItem, true); + return(0); + } + RemoveGarbageItem(szBackupItem, true); + return(NewSectionVirtualOffset); + } + else + { + RemoveGarbageItem(szBackupItem, true); + return(0); + } + } + else + { + return(NewSectionVirtualOffset); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(0); + } + } + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(0); + } + } + } + RemoveGarbageItem(szBackupItem, true); + return(0); +} +__declspec(dllexport) long __stdcall AddNewSection(char* szFileName, char* szSectionName, DWORD SectionSize) +{ + return(AddNewSectionEx(szFileName, szSectionName, SectionSize, NULL, NULL, NULL)); +} +__declspec(dllexport) long __stdcall AddNewSectionW(wchar_t* szFileName, char* szSectionName, DWORD SectionSize) +{ + return(AddNewSectionExW(szFileName, szSectionName, SectionSize, NULL, NULL, NULL)); +} +__declspec(dllexport) bool __stdcall ResizeLastSection(char* szFileName, DWORD NumberOfExpandBytes, bool AlignResizeData) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + + if(szFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + return(ResizeLastSectionW(uniFileName, NumberOfExpandBytes, AlignResizeData)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall ResizeLastSectionW(wchar_t* szFileName, DWORD NumberOfExpandBytes, bool AlignResizeData) +{ + + wchar_t szBackupFile[MAX_PATH] = {}; + wchar_t szBackupItem[MAX_PATH] = {}; + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + PIMAGE_SECTION_HEADER PESections; + DWORD SectionNumber = 0; + DWORD SectionRawSize = 0; + BOOL FileIs64; + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + + if(engineBackupForCriticalFunctions && CreateGarbageItem(&szBackupItem, sizeof szBackupItem)) + { + if(!FillGarbageItem(szBackupItem, szFileName, &szBackupFile, sizeof szBackupItem)) + { + RtlZeroMemory(&szBackupItem, sizeof szBackupItem); + lstrcpyW(szBackupFile, szFileName); + } + } + else + { + RtlZeroMemory(&szBackupItem, sizeof szBackupItem); + lstrcpyW(szBackupFile, szFileName); + } + if(MapFileExW(szBackupFile, UE_ACCESS_ALL, &FileHandle, &FileSize, &FileMap, &FileMapVA, NumberOfExpandBytes)) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, FileHandle, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + FileSize = FileSize - NumberOfExpandBytes; + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(false); + } + if(!FileIs64) + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader32 + PEHeader32->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + SectionNumber = PEHeader32->FileHeader.NumberOfSections; + SectionNumber--; + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + SectionNumber * IMAGE_SIZEOF_SECTION_HEADER); + __try + { + if(AlignResizeData) + { + SectionRawSize = PESections->SizeOfRawData; + if((PESections->SizeOfRawData + NumberOfExpandBytes) % PEHeader32->OptionalHeader.FileAlignment == NULL) + { + PESections->SizeOfRawData = (((PESections->SizeOfRawData + NumberOfExpandBytes) / PEHeader32->OptionalHeader.FileAlignment)) * PEHeader32->OptionalHeader.FileAlignment; + } + else + { + PESections->SizeOfRawData = (((PESections->SizeOfRawData + NumberOfExpandBytes) / PEHeader32->OptionalHeader.FileAlignment) + 1) * PEHeader32->OptionalHeader.FileAlignment; + } + if(SectionRawSize < NULL) + { + SectionRawSize = NULL; + } + SectionRawSize = PESections->SizeOfRawData - SectionRawSize - NumberOfExpandBytes; + PEHeader32->OptionalHeader.SizeOfImage = PEHeader32->OptionalHeader.SizeOfImage - PESections->Misc.VirtualSize; + if((PESections->Misc.VirtualSize + NumberOfExpandBytes + SectionRawSize) % PEHeader32->OptionalHeader.SectionAlignment == NULL) + { + PESections->Misc.VirtualSize = (((PESections->Misc.VirtualSize + NumberOfExpandBytes + SectionRawSize) / PEHeader32->OptionalHeader.SectionAlignment)) * PEHeader32->OptionalHeader.SectionAlignment; + } + else + { + PESections->Misc.VirtualSize = (((PESections->Misc.VirtualSize + NumberOfExpandBytes + SectionRawSize) / PEHeader32->OptionalHeader.SectionAlignment) + 1) * PEHeader32->OptionalHeader.SectionAlignment; + } + PEHeader32->OptionalHeader.SizeOfImage = PEHeader32->OptionalHeader.SizeOfImage + PESections->Misc.VirtualSize; + if(SectionRawSize > NULL) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + MapFileExW(szFileName, UE_ACCESS_ALL, &FileHandle, &FileSize, &FileMap, &FileMapVA, SectionRawSize); + } + } + else + { + PESections->SizeOfRawData = PESections->SizeOfRawData + NumberOfExpandBytes; + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + if(szBackupItem[0] != NULL) + { + if(CopyFileW(szBackupFile, szFileName, false)) + { + RemoveGarbageItem(szBackupItem, true); + return(true); + } + else + { + RemoveGarbageItem(szBackupItem, true); + return(false); + } + } + else + { + return(true); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(false); + } + } + else + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader64 + PEHeader64->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + SectionNumber = PEHeader64->FileHeader.NumberOfSections; + SectionNumber--; + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + SectionNumber * IMAGE_SIZEOF_SECTION_HEADER); + __try + { + if(AlignResizeData) + { + SectionRawSize = PESections->SizeOfRawData; + if((PESections->SizeOfRawData + NumberOfExpandBytes) % PEHeader64->OptionalHeader.FileAlignment == NULL) + { + PESections->SizeOfRawData = (((PESections->SizeOfRawData + NumberOfExpandBytes) / PEHeader64->OptionalHeader.FileAlignment)) * PEHeader64->OptionalHeader.FileAlignment; + } + else + { + PESections->SizeOfRawData = (((PESections->SizeOfRawData + NumberOfExpandBytes) / PEHeader64->OptionalHeader.FileAlignment) + 1) * PEHeader64->OptionalHeader.FileAlignment; + } + if(SectionRawSize < NULL) + { + SectionRawSize = NULL; + } + SectionRawSize = PESections->SizeOfRawData - SectionRawSize - NumberOfExpandBytes; + PEHeader64->OptionalHeader.SizeOfImage = PEHeader64->OptionalHeader.SizeOfImage - PESections->Misc.VirtualSize; + if((PESections->Misc.VirtualSize + NumberOfExpandBytes) % PEHeader64->OptionalHeader.SectionAlignment == NULL) + { + PESections->Misc.VirtualSize = (((PESections->Misc.VirtualSize + NumberOfExpandBytes + SectionRawSize) / PEHeader32->OptionalHeader.SectionAlignment)) * PEHeader64->OptionalHeader.SectionAlignment; + } + else + { + PESections->Misc.VirtualSize = (((PESections->Misc.VirtualSize + NumberOfExpandBytes + SectionRawSize) / PEHeader32->OptionalHeader.SectionAlignment) + 1) * PEHeader64->OptionalHeader.SectionAlignment; + } + PEHeader64->OptionalHeader.SizeOfImage = PEHeader64->OptionalHeader.SizeOfImage + PESections->Misc.VirtualSize; + if(SectionRawSize > NULL) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + MapFileExW(szFileName, UE_ACCESS_ALL, &FileHandle, &FileSize, &FileMap, &FileMapVA, SectionRawSize); + } + } + else + { + PESections->SizeOfRawData = PESections->SizeOfRawData + NumberOfExpandBytes; + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + if(szBackupItem[0] != NULL) + { + if(CopyFileW(szBackupFile, szFileName, false)) + { + RemoveGarbageItem(szBackupItem, true); + return(true); + } + else + { + RemoveGarbageItem(szBackupItem, true); + return(false); + } + } + else + { + return(true); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(false); + } + } + } + else + { + FileSize = FileSize - NumberOfExpandBytes; + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(false); + } + } + RemoveGarbageItem(szBackupItem, true); + return(false); +} +__declspec(dllexport) void __stdcall SetSharedOverlay(char* szFileName) +{ + szSharedOverlay = szFileName; +} +__declspec(dllexport) void __stdcall SetSharedOverlayW(wchar_t* szFileName) +{ + szSharedOverlayW = szFileName; +} +__declspec(dllexport) char* __stdcall GetSharedOverlay() +{ + return(szSharedOverlay); +} +__declspec(dllexport) wchar_t* __stdcall GetSharedOverlayW() +{ + return(szSharedOverlayW); +} +__declspec(dllexport) bool __stdcall DeleteLastSection(char* szFileName) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + + if(szFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + return(DeleteLastSectionW(uniFileName)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall DeleteLastSectionW(wchar_t* szFileName) +{ + + wchar_t szBackupFile[MAX_PATH] = {}; + wchar_t szBackupItem[MAX_PATH] = {}; + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + PIMAGE_SECTION_HEADER PESections; + DWORD SectionNumber = 0; + BOOL FileIs64; + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + + if(engineBackupForCriticalFunctions && CreateGarbageItem(&szBackupItem, sizeof szBackupItem)) + { + if(!FillGarbageItem(szBackupItem, szFileName, &szBackupFile, sizeof szBackupItem)) + { + RtlZeroMemory(&szBackupItem, sizeof szBackupItem); + lstrcpyW(szBackupFile, szFileName); + } + } + else + { + RtlZeroMemory(&szBackupItem, sizeof szBackupItem); + lstrcpyW(szBackupFile, szFileName); + } + if(MapFileExW(szBackupFile, UE_ACCESS_ALL, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, FileHandle, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(false); + } + if(!FileIs64) + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader32 + PEHeader32->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + SectionNumber = PEHeader32->FileHeader.NumberOfSections; + __try + { + if(SectionNumber > 1) + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + (SectionNumber - 1) * IMAGE_SIZEOF_SECTION_HEADER); + PEHeader32->OptionalHeader.SizeOfImage = PEHeader32->OptionalHeader.SizeOfImage - PESections->Misc.VirtualSize; + FileSize = PESections->PointerToRawData; + RtlZeroMemory(PESections, IMAGE_SIZEOF_SECTION_HEADER); + PEHeader32->FileHeader.NumberOfSections--; + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + if(szBackupItem[0] != NULL) + { + if(CopyFileW(szBackupFile, szFileName, false)) + { + RemoveGarbageItem(szBackupItem, true); + return(true); + } + else + { + RemoveGarbageItem(szBackupItem, true); + return(false); + } + } + else + { + return(true); + } + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(false); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(false); + } + } + else + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader64 + PEHeader64->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + SectionNumber = PEHeader64->FileHeader.NumberOfSections; + __try + { + if(SectionNumber > 1) + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + (SectionNumber - 1) * IMAGE_SIZEOF_SECTION_HEADER); + PEHeader64->OptionalHeader.SizeOfImage = PEHeader64->OptionalHeader.SizeOfImage - PESections->Misc.VirtualSize; + FileSize = PESections->PointerToRawData; + RtlZeroMemory(PESections, IMAGE_SIZEOF_SECTION_HEADER); + PEHeader64->FileHeader.NumberOfSections--; + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + if(szBackupItem[0] != NULL) + { + if(CopyFileW(szBackupFile, szFileName, false)) + { + RemoveGarbageItem(szBackupItem, true); + return(true); + } + else + { + RemoveGarbageItem(szBackupItem, true); + return(false); + } + } + else + { + return(true); + } + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(false); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(false); + } + } + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(false); + } + } + RemoveGarbageItem(szBackupItem, true); + return(false); +} +__declspec(dllexport) bool __stdcall DeleteLastSectionEx(char* szFileName, DWORD NumberOfSections) +{ + + while(NumberOfSections > 0) + { + DeleteLastSection(szFileName); + NumberOfSections--; + } + return(true); +} +__declspec(dllexport) bool __stdcall DeleteLastSectionExW(wchar_t* szFileName, DWORD NumberOfSections) +{ + + while(NumberOfSections > 0) + { + DeleteLastSectionW(szFileName); + NumberOfSections--; + } + return(true); +} +__declspec(dllexport) long long __stdcall GetPE32DataFromMappedFile(ULONG_PTR FileMapVA, DWORD WhichSection, DWORD WhichData) +{ + + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + PIMAGE_SECTION_HEADER PESections; + DWORD SectionNumber = 0; + BOOL FileIs64; + + if(FileMapVA != NULL) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, NULL, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + return(0); + } + if(!FileIs64) + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader32 + PEHeader32->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + SectionNumber = PEHeader32->FileHeader.NumberOfSections; + if(WhichData < UE_SECTIONNAME) + { + if(WhichData == UE_PE_OFFSET) + { + return(DOSHeader->e_lfanew); + } + else if(WhichData == UE_IMAGEBASE) + { + return(PEHeader32->OptionalHeader.ImageBase); + } + else if(WhichData == UE_OEP) + { + return(PEHeader32->OptionalHeader.AddressOfEntryPoint); + } + else if(WhichData == UE_SIZEOFIMAGE) + { + return(PEHeader32->OptionalHeader.SizeOfImage); + } + else if(WhichData == UE_SIZEOFHEADERS) + { + return(PEHeader32->OptionalHeader.SizeOfHeaders); + } + else if(WhichData == UE_SIZEOFOPTIONALHEADER) + { + return(PEHeader32->FileHeader.SizeOfOptionalHeader); + } + else if(WhichData == UE_SECTIONALIGNMENT) + { + return(PEHeader32->OptionalHeader.SectionAlignment); + } + else if(WhichData == UE_IMPORTTABLEADDRESS) + { + return(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); + } + else if(WhichData == UE_IMPORTTABLESIZE) + { + return(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size); + } + else if(WhichData == UE_RESOURCETABLEADDRESS) + { + return(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress); + } + else if(WhichData == UE_RESOURCETABLESIZE) + { + return(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size); + } + else if(WhichData == UE_EXPORTTABLEADDRESS) + { + return(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); + } + else if(WhichData == UE_EXPORTTABLESIZE) + { + return(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size); + } + else if(WhichData == UE_TLSTABLEADDRESS) + { + return(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress); + } + else if(WhichData == UE_TLSTABLESIZE) + { + return(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size); + } + else if(WhichData == UE_RELOCATIONTABLEADDRESS) + { + return(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress); + } + else if(WhichData == UE_RELOCATIONTABLESIZE) + { + return(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size); + } + else if(WhichData == UE_TIMEDATESTAMP) + { + return(PEHeader32->FileHeader.TimeDateStamp); + } + else if(WhichData == UE_SECTIONNUMBER) + { + return(PEHeader32->FileHeader.NumberOfSections); + } + else if(WhichData == UE_CHECKSUM) + { + return(PEHeader32->OptionalHeader.CheckSum); + } + else if(WhichData == UE_SUBSYSTEM) + { + return(PEHeader32->OptionalHeader.Subsystem); + } + else if(WhichData == UE_CHARACTERISTICS) + { + return(PEHeader32->FileHeader.Characteristics); + } + else if(WhichData == UE_NUMBEROFRVAANDSIZES) + { + return(PEHeader32->OptionalHeader.NumberOfRvaAndSizes); + } + else + { + return(0); + } + } + else + { + if(SectionNumber >= WhichSection) + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + WhichSection * IMAGE_SIZEOF_SECTION_HEADER); + if(WhichData == UE_SECTIONNAME) + { + return((ULONG_PTR)PESections->Name); + } + else if(WhichData == UE_SECTIONVIRTUALOFFSET) + { + return(PESections->VirtualAddress); + } + else if(WhichData == UE_SECTIONVIRTUALSIZE) + { + return(PESections->Misc.VirtualSize); + } + else if(WhichData == UE_SECTIONRAWOFFSET) + { + return(PESections->PointerToRawData); + } + else if(WhichData == UE_SECTIONRAWSIZE) + { + return(PESections->SizeOfRawData); + } + else if(WhichData == UE_SECTIONFLAGS) + { + return(PESections->Characteristics); + } + else + { + return(0); + } + } + } + return(0); + } + else + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader64 + PEHeader64->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + SectionNumber = PEHeader64->FileHeader.NumberOfSections; + if(WhichData < UE_SECTIONNAME) + { + if(WhichData == UE_PE_OFFSET) + { + return(DOSHeader->e_lfanew); + } + else if(WhichData == UE_IMAGEBASE) + { + return(PEHeader64->OptionalHeader.ImageBase); + } + else if(WhichData == UE_OEP) + { + return(PEHeader64->OptionalHeader.AddressOfEntryPoint); + } + else if(WhichData == UE_SIZEOFIMAGE) + { + return(PEHeader64->OptionalHeader.SizeOfImage); + } + else if(WhichData == UE_SIZEOFHEADERS) + { + return(PEHeader64->OptionalHeader.SizeOfHeaders); + } + else if(WhichData == UE_SIZEOFOPTIONALHEADER) + { + return(PEHeader64->FileHeader.SizeOfOptionalHeader); + } + else if(WhichData == UE_SECTIONALIGNMENT) + { + return(PEHeader64->OptionalHeader.SectionAlignment); + } + else if(WhichData == UE_IMPORTTABLEADDRESS) + { + return(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); + } + else if(WhichData == UE_IMPORTTABLESIZE) + { + return(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size); + } + else if(WhichData == UE_RESOURCETABLEADDRESS) + { + return(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress); + } + else if(WhichData == UE_RESOURCETABLESIZE) + { + return(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size); + } + else if(WhichData == UE_EXPORTTABLEADDRESS) + { + return(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); + } + else if(WhichData == UE_EXPORTTABLESIZE) + { + return(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size); + } + else if(WhichData == UE_TLSTABLEADDRESS) + { + return(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress); + } + else if(WhichData == UE_TLSTABLESIZE) + { + return(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size); + } + else if(WhichData == UE_RELOCATIONTABLEADDRESS) + { + return(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress); + } + else if(WhichData == UE_RELOCATIONTABLESIZE) + { + return(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size); + } + else if(WhichData == UE_TIMEDATESTAMP) + { + return(PEHeader64->FileHeader.TimeDateStamp); + } + else if(WhichData == UE_SECTIONNUMBER) + { + return(PEHeader64->FileHeader.NumberOfSections); + } + else if(WhichData == UE_CHECKSUM) + { + return(PEHeader64->OptionalHeader.CheckSum); + } + else if(WhichData == UE_SUBSYSTEM) + { + return(PEHeader64->OptionalHeader.Subsystem); + } + else if(WhichData == UE_CHARACTERISTICS) + { + return(PEHeader64->FileHeader.Characteristics); + } + else if(WhichData == UE_NUMBEROFRVAANDSIZES) + { + return(PEHeader64->OptionalHeader.NumberOfRvaAndSizes); + } + else + { + return(0); + } + } + else + { + if(SectionNumber >= WhichSection) + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + WhichSection * IMAGE_SIZEOF_SECTION_HEADER); + if(WhichData == UE_SECTIONNAME) + { + return((ULONG_PTR)PESections->Name); + } + else if(WhichData == UE_SECTIONVIRTUALOFFSET) + { + return(PESections->VirtualAddress); + } + else if(WhichData == UE_SECTIONVIRTUALSIZE) + { + return(PESections->Misc.VirtualSize); + } + else if(WhichData == UE_SECTIONRAWOFFSET) + { + return(PESections->PointerToRawData); + } + else if(WhichData == UE_SECTIONRAWSIZE) + { + return(PESections->SizeOfRawData); + } + else if(WhichData == UE_SECTIONFLAGS) + { + return(PESections->Characteristics); + } + else + { + return(0); + } + } + } + return(0); + } + } + else + { + return(0); + } + } + return(0); +} +__declspec(dllexport) long long __stdcall GetPE32Data(char* szFileName, DWORD WhichSection, DWORD WhichData) +{ + + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + long long ReturnValue = 0; + + if(MapFileEx(szFileName, UE_ACCESS_READ, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + ReturnValue = GetPE32DataFromMappedFile(FileMapVA, WhichSection, WhichData); + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(ReturnValue); + } + else + { + return(0); + } +} +__declspec(dllexport) long long __stdcall GetPE32DataW(wchar_t* szFileName, DWORD WhichSection, DWORD WhichData) +{ + + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + long long ReturnValue = 0; + + if(MapFileExW(szFileName, UE_ACCESS_READ, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + ReturnValue = GetPE32DataFromMappedFile(FileMapVA, WhichSection, WhichData); + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(ReturnValue); + } + else + { + return(0); + } +} +__declspec(dllexport) bool __stdcall GetPE32DataFromMappedFileEx(ULONG_PTR FileMapVA, LPVOID DataStorage) +{ + + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + BOOL FileIs64; + PPE32Struct PE32Structure = (PPE32Struct)DataStorage; + PPE64Struct PE64Structure = (PPE64Struct)DataStorage; + + if(FileMapVA != NULL) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, NULL, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + return(false); + } + if(!FileIs64) + { + PE32Structure->PE32Offset = DOSHeader->e_lfanew; + PE32Structure->ImageBase = PEHeader32->OptionalHeader.ImageBase; + PE32Structure->OriginalEntryPoint = PEHeader32->OptionalHeader.AddressOfEntryPoint; + PE32Structure->NtSizeOfImage = PEHeader32->OptionalHeader.SizeOfImage; + PE32Structure->NtSizeOfHeaders = PEHeader32->OptionalHeader.SizeOfHeaders; + PE32Structure->SizeOfOptionalHeaders = PEHeader32->FileHeader.SizeOfOptionalHeader; + PE32Structure->FileAlignment = PEHeader32->OptionalHeader.FileAlignment; + PE32Structure->SectionAligment = PEHeader32->OptionalHeader.SectionAlignment; + PE32Structure->ImportTableAddress = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; + PE32Structure->ImportTableSize = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size; + PE32Structure->ResourceTableAddress = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress; + PE32Structure->ResourceTableSize = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size; + PE32Structure->ExportTableAddress = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + PE32Structure->ExportTableSize = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; + PE32Structure->TLSTableAddress = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress; + PE32Structure->TLSTableSize = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size; + PE32Structure->RelocationTableAddress = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress; + PE32Structure->RelocationTableSize = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; + PE32Structure->TimeDateStamp = PEHeader32->FileHeader.TimeDateStamp; + PE32Structure->SectionNumber = PEHeader32->FileHeader.NumberOfSections; + PE32Structure->CheckSum = PEHeader32->OptionalHeader.CheckSum; + PE32Structure->SubSystem = PEHeader32->OptionalHeader.Subsystem; + PE32Structure->Characteristics = PEHeader32->FileHeader.Characteristics; + PE32Structure->NumberOfRvaAndSizes = PEHeader32->OptionalHeader.NumberOfRvaAndSizes; + return(true); + } + else + { + PE64Structure->PE64Offset = DOSHeader->e_lfanew; + PE64Structure->ImageBase = PEHeader64->OptionalHeader.ImageBase; + PE64Structure->OriginalEntryPoint = PEHeader64->OptionalHeader.AddressOfEntryPoint; + PE64Structure->NtSizeOfImage = PEHeader64->OptionalHeader.SizeOfImage; + PE64Structure->NtSizeOfHeaders = PEHeader64->OptionalHeader.SizeOfHeaders; + PE64Structure->SizeOfOptionalHeaders = PEHeader64->FileHeader.SizeOfOptionalHeader; + PE64Structure->FileAlignment = PEHeader64->OptionalHeader.FileAlignment; + PE64Structure->SectionAligment = PEHeader64->OptionalHeader.SectionAlignment; + PE64Structure->ImportTableAddress = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; + PE64Structure->ImportTableSize = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size; + PE64Structure->ResourceTableAddress = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress; + PE64Structure->ResourceTableSize = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size; + PE64Structure->ExportTableAddress = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + PE64Structure->ExportTableSize = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; + PE64Structure->TLSTableAddress = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress; + PE64Structure->TLSTableSize = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size; + PE64Structure->RelocationTableAddress = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress; + PE64Structure->RelocationTableSize = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; + PE64Structure->TimeDateStamp = PEHeader64->FileHeader.TimeDateStamp; + PE64Structure->SectionNumber = PEHeader64->FileHeader.NumberOfSections; + PE64Structure->CheckSum = PEHeader64->OptionalHeader.CheckSum; + PE64Structure->SubSystem = PEHeader64->OptionalHeader.Subsystem; + PE64Structure->Characteristics = PEHeader64->FileHeader.Characteristics; + PE64Structure->NumberOfRvaAndSizes = PEHeader64->OptionalHeader.NumberOfRvaAndSizes; + return(true); + } + } + else + { + return(false); + } + } + return(false); +} +__declspec(dllexport) bool __stdcall GetPE32DataEx(char* szFileName, LPVOID DataStorage) +{ + + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + long long ReturnValue = 0; + + if(MapFileEx(szFileName, UE_ACCESS_READ, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + ReturnValue = GetPE32DataFromMappedFileEx(FileMapVA, DataStorage); + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + if(ReturnValue) + { + return(true); + } + else + { + return(false); + } + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall GetPE32DataExW(wchar_t* szFileName, LPVOID DataStorage) +{ + + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + long long ReturnValue = 0; + + if(MapFileExW(szFileName, UE_ACCESS_READ, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + ReturnValue = GetPE32DataFromMappedFileEx(FileMapVA, DataStorage); + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + if(ReturnValue) + { + return(true); + } + else + { + return(false); + } + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall SetPE32DataForMappedFile(ULONG_PTR FileMapVA, DWORD WhichSection, DWORD WhichData, ULONG_PTR NewDataValue) +{ + + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + PIMAGE_SECTION_HEADER PESections; + DWORD SectionNumber = 0; + BOOL FileIs64; + + if(FileMapVA != NULL) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, NULL, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + return(false); + } + if(!FileIs64) + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader32 + PEHeader32->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + SectionNumber = PEHeader32->FileHeader.NumberOfSections; + __try + { + if(WhichData < UE_SECTIONNAME) + { + if(WhichData == UE_PE_OFFSET) + { + DOSHeader->e_lfanew = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_IMAGEBASE) + { + PEHeader32->OptionalHeader.ImageBase = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_OEP) + { + PEHeader32->OptionalHeader.AddressOfEntryPoint = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_SIZEOFIMAGE) + { + PEHeader32->OptionalHeader.SizeOfImage = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_SIZEOFHEADERS) + { + PEHeader32->OptionalHeader.SizeOfHeaders = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_SIZEOFOPTIONALHEADER) + { + PEHeader32->FileHeader.SizeOfOptionalHeader = (WORD)NewDataValue; + return(true); + } + else if(WhichData == UE_SECTIONALIGNMENT) + { + PEHeader32->OptionalHeader.SectionAlignment = (WORD)NewDataValue; + return(true); + } + else if(WhichData == UE_IMPORTTABLEADDRESS) + { + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_IMPORTTABLESIZE) + { + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_RESOURCETABLEADDRESS) + { + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_RESOURCETABLESIZE) + { + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_EXPORTTABLEADDRESS) + { + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_EXPORTTABLESIZE) + { + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_TLSTABLEADDRESS) + { + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_TLSTABLESIZE) + { + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_RELOCATIONTABLEADDRESS) + { + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_RELOCATIONTABLESIZE) + { + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_TIMEDATESTAMP) + { + PEHeader32->FileHeader.TimeDateStamp = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_SECTIONNUMBER) + { + PEHeader32->FileHeader.NumberOfSections = (WORD)NewDataValue; + return(true); + } + else if(WhichData == UE_CHECKSUM) + { + PEHeader32->OptionalHeader.CheckSum = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_SUBSYSTEM) + { + PEHeader32->OptionalHeader.Subsystem = (WORD)NewDataValue; + return(true); + } + else if(WhichData == UE_CHARACTERISTICS) + { + PEHeader32->FileHeader.Characteristics = (WORD)NewDataValue; + return(true); + } + else if(WhichData == UE_NUMBEROFRVAANDSIZES) + { + PEHeader32->OptionalHeader.NumberOfRvaAndSizes = (DWORD)NewDataValue; + return(true); + } + else + { + return(false); + } + } + else + { + if(WhichSection <= SectionNumber) + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + WhichSection * IMAGE_SIZEOF_SECTION_HEADER); + if(WhichData == UE_SECTIONNAME) + { + return(false); + } + else if(WhichData == UE_SECTIONVIRTUALOFFSET) + { + PESections->VirtualAddress = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_SECTIONVIRTUALSIZE) + { + PESections->Misc.VirtualSize = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_SECTIONRAWOFFSET) + { + PESections->PointerToRawData = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_SECTIONRAWSIZE) + { + PESections->SizeOfRawData = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_SECTIONFLAGS) + { + PESections->Characteristics = (DWORD)NewDataValue; + return(true); + } + else + { + return(false); + } + } + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return(false); + } + return(false); + } + else + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader64 + PEHeader64->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + SectionNumber = PEHeader64->FileHeader.NumberOfSections; + __try + { + if(WhichData < UE_SECTIONNAME) + { + if(WhichData == UE_PE_OFFSET) + { + DOSHeader->e_lfanew = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_IMAGEBASE) + { + PEHeader64->OptionalHeader.ImageBase = NewDataValue; + return(true); + } + else if(WhichData == UE_OEP) + { + PEHeader64->OptionalHeader.AddressOfEntryPoint = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_SIZEOFIMAGE) + { + PEHeader64->OptionalHeader.SizeOfImage = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_SIZEOFHEADERS) + { + PEHeader64->OptionalHeader.SizeOfHeaders = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_SIZEOFOPTIONALHEADER) + { + PEHeader64->FileHeader.SizeOfOptionalHeader = (WORD)NewDataValue; + return(true); + } + else if(WhichData == UE_SECTIONALIGNMENT) + { + PEHeader64->OptionalHeader.SectionAlignment = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_IMPORTTABLEADDRESS) + { + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_IMPORTTABLESIZE) + { + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_RESOURCETABLEADDRESS) + { + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_RESOURCETABLESIZE) + { + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_EXPORTTABLEADDRESS) + { + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_EXPORTTABLESIZE) + { + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_TLSTABLEADDRESS) + { + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_TLSTABLESIZE) + { + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_RELOCATIONTABLEADDRESS) + { + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_RELOCATIONTABLESIZE) + { + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_TIMEDATESTAMP) + { + PEHeader64->FileHeader.TimeDateStamp = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_SECTIONNUMBER) + { + PEHeader64->FileHeader.NumberOfSections = (WORD)NewDataValue; + return(true); + } + else if(WhichData == UE_CHECKSUM) + { + PEHeader64->OptionalHeader.CheckSum = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_SUBSYSTEM) + { + PEHeader64->OptionalHeader.Subsystem = (WORD)NewDataValue; + return(true); + } + else if(WhichData == UE_CHARACTERISTICS) + { + PEHeader64->FileHeader.Characteristics = (WORD)NewDataValue; + return(true); + } + else if(WhichData == UE_NUMBEROFRVAANDSIZES) + { + PEHeader64->OptionalHeader.NumberOfRvaAndSizes = (DWORD)NewDataValue; + return(true); + } + else + { + return(0); + } + } + else + { + if(WhichSection <= SectionNumber) + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + WhichSection * IMAGE_SIZEOF_SECTION_HEADER); + if(WhichData == UE_SECTIONNAME) + { + return(false); + } + else if(WhichData == UE_SECTIONVIRTUALOFFSET) + { + PESections->VirtualAddress = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_SECTIONVIRTUALSIZE) + { + PESections->Misc.VirtualSize = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_SECTIONRAWOFFSET) + { + PESections->PointerToRawData = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_SECTIONRAWSIZE) + { + PESections->SizeOfRawData = (DWORD)NewDataValue; + return(true); + } + else if(WhichData == UE_SECTIONFLAGS) + { + PESections->Characteristics = (DWORD)NewDataValue; + return(true); + } + else + { + return(false); + } + } + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return(false); + } + return(false); + } + } + else + { + return(false); + } + } + return(false); +} +__declspec(dllexport) bool __stdcall SetPE32Data(char* szFileName, DWORD WhichSection, DWORD WhichData, ULONG_PTR NewDataValue) +{ + + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + long long ReturnValue = 0; + + if(MapFileEx(szFileName, UE_ACCESS_ALL, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + ReturnValue = SetPE32DataForMappedFile(FileMapVA, WhichSection, WhichData, NewDataValue); + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + if(ReturnValue) + { + return(true); + } + else + { + return(false); + } + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall SetPE32DataW(wchar_t* szFileName, DWORD WhichSection, DWORD WhichData, ULONG_PTR NewDataValue) +{ + + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + long long ReturnValue = 0; + + if(MapFileExW(szFileName, UE_ACCESS_ALL, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + ReturnValue = SetPE32DataForMappedFile(FileMapVA, WhichSection, WhichData, NewDataValue); + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + if(ReturnValue) + { + return(true); + } + else + { + return(false); + } + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall SetPE32DataForMappedFileEx(ULONG_PTR FileMapVA, LPVOID DataStorage) +{ + + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + BOOL FileIs64; + PPE32Struct PE32Structure = (PPE32Struct)DataStorage; + PPE64Struct PE64Structure = (PPE64Struct)DataStorage; + + if(FileMapVA != NULL) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, NULL, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + return(false); + } + if(!FileIs64) + { + __try + { + DOSHeader->e_lfanew = PE32Structure->PE32Offset; + PEHeader32->OptionalHeader.ImageBase = PE32Structure->ImageBase; + PEHeader32->OptionalHeader.AddressOfEntryPoint = PE32Structure->OriginalEntryPoint; + PEHeader32->OptionalHeader.SizeOfImage = PE32Structure->NtSizeOfImage; + PEHeader32->OptionalHeader.SizeOfHeaders = PE32Structure->NtSizeOfHeaders; + PEHeader32->FileHeader.SizeOfOptionalHeader = PE32Structure->SizeOfOptionalHeaders; + PEHeader32->OptionalHeader.FileAlignment = PE32Structure->FileAlignment; + PEHeader32->OptionalHeader.SectionAlignment = PE32Structure->SectionAligment; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = PE32Structure->ImportTableAddress; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = PE32Structure->ImportTableSize; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = PE32Structure->ResourceTableAddress; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = PE32Structure->ResourceTableSize; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = PE32Structure->ExportTableAddress; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = PE32Structure->ExportTableSize; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress = PE32Structure->TLSTableAddress; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size = PE32Structure->TLSTableSize; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = PE32Structure->RelocationTableAddress; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = PE32Structure->RelocationTableSize; + PEHeader32->FileHeader.TimeDateStamp = PE32Structure->TimeDateStamp; + PEHeader32->FileHeader.NumberOfSections = PE32Structure->SectionNumber; + PEHeader32->OptionalHeader.CheckSum = PE32Structure->CheckSum; + PEHeader32->OptionalHeader.Subsystem = PE32Structure->SubSystem; + PEHeader32->FileHeader.Characteristics = PE32Structure->Characteristics; + PEHeader32->OptionalHeader.NumberOfRvaAndSizes = PE32Structure->NumberOfRvaAndSizes; + return(true); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return(false); + } + } + else + { + __try + { + DOSHeader->e_lfanew = PE64Structure->PE64Offset; + PEHeader64->OptionalHeader.ImageBase = PE64Structure->ImageBase; + PEHeader64->OptionalHeader.AddressOfEntryPoint = PE64Structure->OriginalEntryPoint; + PEHeader64->OptionalHeader.SizeOfImage = PE64Structure->NtSizeOfImage; + PEHeader64->OptionalHeader.SizeOfHeaders = PE64Structure->NtSizeOfHeaders; + PEHeader64->FileHeader.SizeOfOptionalHeader = PE64Structure->SizeOfOptionalHeaders; + PEHeader64->OptionalHeader.FileAlignment = PE64Structure->FileAlignment; + PEHeader64->OptionalHeader.SectionAlignment = PE64Structure->SectionAligment; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = PE64Structure->ImportTableAddress; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = PE64Structure->ImportTableSize; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = PE64Structure->ResourceTableAddress; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = PE64Structure->ResourceTableSize; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = PE64Structure->ExportTableAddress; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = PE64Structure->ExportTableSize; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress = PE64Structure->TLSTableAddress; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size = PE64Structure->TLSTableSize; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = PE64Structure->RelocationTableAddress; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = PE64Structure->RelocationTableSize; + PEHeader64->FileHeader.TimeDateStamp = PE64Structure->TimeDateStamp; + PEHeader64->FileHeader.NumberOfSections = PE64Structure->SectionNumber; + PEHeader64->OptionalHeader.CheckSum = PE64Structure->CheckSum; + PEHeader64->OptionalHeader.Subsystem = PE64Structure->SubSystem; + PEHeader64->FileHeader.Characteristics = PE64Structure->Characteristics; + PEHeader64->OptionalHeader.NumberOfRvaAndSizes = PE64Structure->NumberOfRvaAndSizes; + return(true); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return(false); + } + } + } + else + { + return(false); + } + } + return(false); +} +__declspec(dllexport) bool __stdcall SetPE32DataEx(char* szFileName, LPVOID DataStorage) +{ + + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + long long ReturnValue = 0; + + if(MapFileEx(szFileName, UE_ACCESS_ALL, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + ReturnValue = SetPE32DataForMappedFileEx(FileMapVA, DataStorage); + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + if(ReturnValue) + { + return(true); + } + else + { + return(false); + } + } + else + { + return(false); + } +} + +__declspec(dllexport) bool __stdcall SetPE32DataExW(wchar_t* szFileName, LPVOID DataStorage) +{ + + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + long long ReturnValue = 0; + + if(MapFileExW(szFileName, UE_ACCESS_ALL, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + ReturnValue = SetPE32DataForMappedFileEx(FileMapVA, DataStorage); + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + if(ReturnValue) + { + return(true); + } + else + { + return(false); + } + } + else + { + return(false); + } +} + +__declspec(dllexport) long __stdcall GetPE32SectionNumberFromVA(ULONG_PTR FileMapVA, ULONG_PTR AddressToConvert) +{ + + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + PIMAGE_SECTION_HEADER PESections; + ULONG_PTR FoundInSection = -1; + DWORD SectionNumber = 0; + DWORD ConvertAddress = 0; + BOOL FileIs64; + + if(FileMapVA != NULL) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, NULL, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + return(-2); + } + if(!FileIs64) + { + __try + { + ConvertAddress = (DWORD)((DWORD)AddressToConvert - PEHeader32->OptionalHeader.ImageBase); + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader32 + PEHeader32->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + SectionNumber = PEHeader32->FileHeader.NumberOfSections; + while(SectionNumber > 0) + { + if(PESections->VirtualAddress <= ConvertAddress && ConvertAddress < PESections->VirtualAddress + PESections->Misc.VirtualSize) + { + FoundInSection = PEHeader32->FileHeader.NumberOfSections - SectionNumber; + } + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + IMAGE_SIZEOF_SECTION_HEADER); + SectionNumber--; + } + return((DWORD)FoundInSection); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return(-2); + } + } + else + { + __try + { + ConvertAddress = (DWORD)(AddressToConvert - PEHeader64->OptionalHeader.ImageBase); + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader64 + PEHeader64->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + SectionNumber = PEHeader64->FileHeader.NumberOfSections; + while(SectionNumber > 0) + { + if(PESections->VirtualAddress <= ConvertAddress && ConvertAddress < PESections->VirtualAddress + PESections->Misc.VirtualSize) + { + FoundInSection = PEHeader64->FileHeader.NumberOfSections - SectionNumber; + } + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + IMAGE_SIZEOF_SECTION_HEADER); + SectionNumber--; + } + return((DWORD)FoundInSection); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return(-2); + } + } + } + else + { + return(-2); + } + } + return(-2); +} +__declspec(dllexport) long long __stdcall ConvertVAtoFileOffset(ULONG_PTR FileMapVA, ULONG_PTR AddressToConvert, bool ReturnType) +{ + + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + PIMAGE_SECTION_HEADER PESections; + DWORD SectionNumber = 0; + ULONG_PTR ConvertedAddress = 0; + ULONG_PTR ConvertAddress = 0; + BOOL FileIs64; + + if(FileMapVA != NULL) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, NULL, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + return(0); + } + if(!FileIs64) + { + ConvertAddress = (DWORD)((DWORD)AddressToConvert - PEHeader32->OptionalHeader.ImageBase); + if(ConvertAddress < PEHeader32->OptionalHeader.SectionAlignment) + { + ConvertedAddress = ConvertAddress; + } + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader32 + PEHeader32->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + SectionNumber = PEHeader32->FileHeader.NumberOfSections; + __try + { + while(SectionNumber > 0) + { + if(PESections->VirtualAddress <= ConvertAddress && ConvertAddress <= PESections->VirtualAddress + PESections->Misc.VirtualSize) + { + if(ConvertAddress - PESections->VirtualAddress <= PESections->SizeOfRawData) + { + ConvertedAddress = PESections->PointerToRawData + (ConvertAddress - PESections->VirtualAddress); + } + } + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + IMAGE_SIZEOF_SECTION_HEADER); + SectionNumber--; + } + if(ReturnType) + { + if(ConvertedAddress != NULL) + { + ConvertedAddress = ConvertedAddress + FileMapVA; + } + else if(ConvertAddress == NULL) + { + ConvertedAddress = FileMapVA; + } + } + return(ConvertedAddress); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return(0); + } + } + else + { + ConvertAddress = (DWORD)(AddressToConvert - PEHeader64->OptionalHeader.ImageBase); + if(ConvertAddress < PEHeader64->OptionalHeader.SectionAlignment) + { + ConvertedAddress = ConvertAddress; + } + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader64 + PEHeader64->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + SectionNumber = PEHeader64->FileHeader.NumberOfSections; + __try + { + while(SectionNumber > 0) + { + if(PESections->VirtualAddress <= ConvertAddress && ConvertAddress <= PESections->VirtualAddress + PESections->Misc.VirtualSize) + { + if(ConvertAddress - PESections->VirtualAddress <= PESections->SizeOfRawData) + { + ConvertedAddress = PESections->PointerToRawData + (ConvertAddress - PESections->VirtualAddress); + } + } + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + IMAGE_SIZEOF_SECTION_HEADER); + SectionNumber--; + } + if(ReturnType) + { + if(ConvertedAddress != NULL) + { + ConvertedAddress = ConvertedAddress + FileMapVA; + } + else if(ConvertAddress == NULL) + { + ConvertedAddress = FileMapVA; + } + } + return(ConvertedAddress); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return(0); + } + } + } + else + { + return(0); + } + } + return(0); +} +__declspec(dllexport) long long __stdcall ConvertVAtoFileOffsetEx(ULONG_PTR FileMapVA, DWORD FileSize, ULONG_PTR ImageBase, ULONG_PTR AddressToConvert, bool AddressIsRVA, bool ReturnType) +{ + + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + PIMAGE_SECTION_HEADER PESections; + DWORD SectionNumber = 0; + ULONG_PTR ConvertedAddress = 0; + ULONG_PTR ConvertAddress = 0; + BOOL FileIs64; + + if(FileMapVA != NULL) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, NULL, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + return(0); + } + if(!FileIs64) + { + if(!AddressIsRVA) + { + if(ImageBase == NULL) + { + ConvertAddress = (DWORD)((DWORD)AddressToConvert - PEHeader32->OptionalHeader.ImageBase); + } + else + { + ConvertAddress = (DWORD)((DWORD)AddressToConvert - ImageBase); + } + } + else + { + ConvertAddress = (DWORD)AddressToConvert; + } + if(ConvertAddress < PEHeader32->OptionalHeader.SectionAlignment) + { + ConvertedAddress = ConvertAddress; + } + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader32 + PEHeader32->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + SectionNumber = PEHeader32->FileHeader.NumberOfSections; + __try + { + while(SectionNumber > 0) + { + if(PESections->VirtualAddress <= ConvertAddress && ConvertAddress <= PESections->VirtualAddress + PESections->Misc.VirtualSize) + { + if(ConvertAddress - PESections->VirtualAddress <= PESections->SizeOfRawData) + { + ConvertedAddress = PESections->PointerToRawData + (ConvertAddress - PESections->VirtualAddress); + } + } + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + IMAGE_SIZEOF_SECTION_HEADER); + SectionNumber--; + } + if(ReturnType) + { + if(ConvertedAddress != NULL) + { + ConvertedAddress = ConvertedAddress + FileMapVA; + } + } + if(ReturnType) + { + if(ConvertedAddress >= FileMapVA && ConvertedAddress <= FileMapVA + FileSize) + { + return((ULONG_PTR)ConvertedAddress); + } + else + { + return(NULL); + } + } + else + { + if(ConvertedAddress > NULL && ConvertedAddress <= FileSize) + { + return((ULONG_PTR)ConvertedAddress); + } + else + { + return(NULL); + } + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return(NULL); + } + } + else + { + if(!AddressIsRVA) + { + if(ImageBase == NULL) + { + ConvertAddress = (DWORD)(AddressToConvert - PEHeader64->OptionalHeader.ImageBase); + } + else + { + ConvertAddress = (DWORD)(AddressToConvert - ImageBase); + } + } + else + { + ConvertAddress = (DWORD)AddressToConvert; + } + if(ConvertAddress < PEHeader64->OptionalHeader.SectionAlignment) + { + ConvertedAddress = ConvertAddress; + } + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader64 + PEHeader64->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + SectionNumber = PEHeader64->FileHeader.NumberOfSections; + __try + { + while(SectionNumber > 0) + { + if(PESections->VirtualAddress <= ConvertAddress && ConvertAddress <= PESections->VirtualAddress + PESections->Misc.VirtualSize) + { + if(ConvertAddress - PESections->VirtualAddress <= PESections->SizeOfRawData) + { + ConvertedAddress = PESections->PointerToRawData + (ConvertAddress - PESections->VirtualAddress); + } + } + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + IMAGE_SIZEOF_SECTION_HEADER); + SectionNumber--; + } + if(ReturnType) + { + if(ConvertedAddress != NULL) + { + ConvertedAddress = ConvertedAddress + FileMapVA; + } + } + if(ReturnType) + { + if(ConvertedAddress >= FileMapVA && ConvertedAddress <= FileMapVA + FileSize) + { + return((ULONG_PTR)ConvertedAddress); + } + else + { + return(NULL); + } + } + else + { + if(ConvertedAddress > NULL && ConvertedAddress <= FileSize) + { + return((ULONG_PTR)ConvertedAddress); + } + else + { + return(NULL); + } + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return(NULL); + } + } + } + else + { + return(0); + } + } + return(0); +} +__declspec(dllexport) long long __stdcall ConvertFileOffsetToVA(ULONG_PTR FileMapVA, ULONG_PTR AddressToConvert, bool ReturnType) +{ + + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + PIMAGE_SECTION_HEADER PESections; + DWORD SectionNumber = 0; + ULONG_PTR ConvertedAddress = 0; + ULONG_PTR ConvertAddress = 0; + BOOL FileIs64; + + if(FileMapVA != NULL) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, NULL, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + return(0); + } + if(!FileIs64) + { + ConvertAddress = (DWORD)((DWORD)AddressToConvert - FileMapVA); + if(ConvertAddress < PEHeader32->OptionalHeader.FileAlignment) + { + ConvertedAddress = ConvertAddress; + } + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader32 + PEHeader32->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + SectionNumber = PEHeader32->FileHeader.NumberOfSections; + __try + { + while(SectionNumber > 0) + { + if(PESections->PointerToRawData <= ConvertAddress && ConvertAddress <= PESections->PointerToRawData + PESections->SizeOfRawData) + { + ConvertedAddress = PESections->VirtualAddress + (ConvertAddress - PESections->PointerToRawData); + } + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + IMAGE_SIZEOF_SECTION_HEADER); + SectionNumber--; + } + if(ReturnType) + { + if(ConvertedAddress != NULL) + { + ConvertedAddress = ConvertedAddress + PEHeader32->OptionalHeader.ImageBase; + } + } + else if(ConvertAddress == NULL) + { + ConvertedAddress = PEHeader32->OptionalHeader.ImageBase; + } + return(ConvertedAddress); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return(0); + } + } + else + { + ConvertAddress = (DWORD)(AddressToConvert - FileMapVA); + if(ConvertAddress < PEHeader64->OptionalHeader.FileAlignment) + { + ConvertedAddress = ConvertAddress; + } + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader64 + PEHeader64->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + SectionNumber = PEHeader64->FileHeader.NumberOfSections; + __try + { + while(SectionNumber > 0) + { + if(PESections->PointerToRawData <= ConvertAddress && ConvertAddress <= PESections->PointerToRawData + PESections->SizeOfRawData) + { + ConvertedAddress = PESections->VirtualAddress + (ConvertAddress - PESections->PointerToRawData); + } + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + IMAGE_SIZEOF_SECTION_HEADER); + SectionNumber--; + } + if(ReturnType) + { + if(ConvertedAddress != NULL) + { + ConvertedAddress = ConvertedAddress + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase; + } + } + else if(ConvertAddress == NULL) + { + ConvertedAddress = (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase; + } + return(ConvertedAddress); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return(0); + } + } + } + else + { + return(0); + } + } + return(0); +} +__declspec(dllexport) long long __stdcall ConvertFileOffsetToVAEx(ULONG_PTR FileMapVA, DWORD FileSize, ULONG_PTR ImageBase, ULONG_PTR AddressToConvert, bool ReturnType) +{ + + ULONG_PTR ConvertedAddress = NULL; + DWORD cnvSectionAlignment = NULL; + ULONG_PTR cnvImageBase = NULL; + DWORD cnvSizeOfImage = NULL; + + if(FileMapVA != NULL) + { + if(ImageBase == NULL) + { + cnvImageBase = (ULONG_PTR)GetPE32DataFromMappedFile(FileMapVA, NULL, UE_IMAGEBASE); + } + else + { + cnvImageBase = ImageBase; + } + cnvSizeOfImage = (DWORD)GetPE32DataFromMappedFile(FileMapVA, NULL, UE_SIZEOFIMAGE); + cnvSectionAlignment = (DWORD)GetPE32DataFromMappedFile(FileMapVA, NULL, UE_SECTIONALIGNMENT); + ConvertedAddress = (ULONG_PTR)ConvertFileOffsetToVA(FileMapVA, AddressToConvert, ReturnType); + if(ReturnType) + { + if(ConvertedAddress >= cnvImageBase + cnvSectionAlignment && ConvertedAddress <= cnvImageBase + cnvSizeOfImage) + { + return((ULONG_PTR)ConvertedAddress); + } + else + { + return(NULL); + } + } + else + { + if(ConvertedAddress >= cnvSectionAlignment && ConvertedAddress <= cnvSizeOfImage) + { + return((ULONG_PTR)ConvertedAddress); + } + else + { + return(NULL); + } + } + } + return(NULL); +} +// Global.Realigner.functions: +void SetOverallFileStatus(PFILE_STATUS_INFO myFileInfo, BYTE FiledStatus, bool FiledCritical) +{ + + if(myFileInfo->OveralEvaluation == UE_RESULT_FILE_OK || myFileInfo->OveralEvaluation == UE_RESULT_FILE_INVALID_BUT_FIXABLE) + { + if(FiledStatus == UE_FILED_FIXABLE_CRITICAL || FiledStatus == UE_FIELD_BROKEN_FIXABLE_FOR_STATIC_USE || FiledStatus == UE_FIELD_BROKEN_BUT_CAN_BE_EMULATED) + { + myFileInfo->OveralEvaluation = UE_RESULT_FILE_INVALID_BUT_FIXABLE; + } + else if(FiledStatus == UE_FIELD_BROKEN_NON_FIXABLE && FiledCritical == true) + { + myFileInfo->OveralEvaluation = UE_RESULT_FILE_INVALID_AND_NON_FIXABLE; + } + else if(FiledStatus == UE_FIELD_BROKEN_FIXABLE_FOR_STATIC_USE) + { + myFileInfo->OveralEvaluation = UE_RESULT_FILE_INVALID_BUT_FIXABLE; + } + } +} +// TitanEngine.Realigner.functions: +__declspec(dllexport) bool __stdcall FixHeaderCheckSum(char* szFileName) +{ + + DWORD HeaderSum = NULL; + DWORD CheckSum = NULL; + + if(MapFileAndCheckSumA(szFileName, &HeaderSum, &CheckSum) == NULL) + { + SetPE32Data(szFileName, NULL, UE_CHECKSUM, (ULONG_PTR)CheckSum); + return(true); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall FixHeaderCheckSumW(wchar_t* szFileName) +{ + + DWORD HeaderSum = NULL; + DWORD CheckSum = NULL; + + if(MapFileAndCheckSumW(szFileName, &HeaderSum, &CheckSum) == NULL) + { + SetPE32DataW(szFileName, NULL, UE_CHECKSUM, (ULONG_PTR)CheckSum); + return(true); + } + else + { + return(false); + } +} +__declspec(dllexport) long __stdcall RealignPE(ULONG_PTR FileMapVA, DWORD FileSize, DWORD RealingMode) +{ + + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + PIMAGE_SECTION_HEADER PESections; + DWORD NewVirtualSectionSize = 0; + DWORD NewSectionRawPointer = 0; + DWORD OldSectionDataRawPtr = 0; + DWORD OldSectionDataPtr = 0; + DWORD SectionDataPtr = 0; + DWORD SectionNumber = 0; + DWORD CurrentSection = 0; + DWORD FileAlignment = 0; + BOOL FileIs64; + + if(FileMapVA != NULL) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, NULL, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + return(-1); + } + if(!FileIs64) + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader32 + PEHeader32->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + SectionNumber = PEHeader32->FileHeader.NumberOfSections; + FileAlignment = PEHeader32->OptionalHeader.FileAlignment; + if(FileAlignment == 0x1000) + { + FileAlignment = 0x200; + } + __try + { + PEHeader32->OptionalHeader.FileAlignment = FileAlignment; + while(SectionNumber > 0) + { + SectionDataPtr = PESections->PointerToRawData + PESections->SizeOfRawData; + if(PESections->SizeOfRawData > NULL) + { + SectionDataPtr--; + while(*(PUCHAR)(FileMapVA + SectionDataPtr) == 0x00 && SectionDataPtr > PESections->PointerToRawData) + { + SectionDataPtr--; + } + } + SectionDataPtr = SectionDataPtr - PESections->PointerToRawData; + OldSectionDataPtr = SectionDataPtr; + SectionDataPtr = (SectionDataPtr / FileAlignment) * FileAlignment; + if(SectionDataPtr < OldSectionDataPtr) + { + SectionDataPtr = SectionDataPtr + FileAlignment; + } + if(CurrentSection == NULL) + { + PEHeader32->OptionalHeader.SizeOfHeaders = PESections->PointerToRawData; + PEHeader32->OptionalHeader.SectionAlignment = PESections->VirtualAddress; + PESections->SizeOfRawData = SectionDataPtr; + } + else + { + OldSectionDataRawPtr = PESections->PointerToRawData; + PESections->SizeOfRawData = SectionDataPtr; + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections - IMAGE_SIZEOF_SECTION_HEADER); + NewSectionRawPointer = PESections->PointerToRawData + PESections->SizeOfRawData; + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + IMAGE_SIZEOF_SECTION_HEADER); + PESections->PointerToRawData = NewSectionRawPointer; + RtlMoveMemory((LPVOID)((ULONG_PTR)FileMapVA + NewSectionRawPointer), (LPVOID)((ULONG_PTR)FileMapVA + OldSectionDataRawPtr), SectionDataPtr); + } + NewVirtualSectionSize = (PESections->Misc.VirtualSize / PEHeader32->OptionalHeader.SectionAlignment) * PEHeader32->OptionalHeader.SectionAlignment; + if(NewVirtualSectionSize < PESections->Misc.VirtualSize) + { + NewVirtualSectionSize = NewVirtualSectionSize + PEHeader32->OptionalHeader.SectionAlignment; + } + PESections->Misc.VirtualSize = NewVirtualSectionSize; + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + IMAGE_SIZEOF_SECTION_HEADER); + CurrentSection++; + SectionNumber--; + } + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections - IMAGE_SIZEOF_SECTION_HEADER); + return(PESections->PointerToRawData + PESections->SizeOfRawData); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return(-1); + } + } + else + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader64 + PEHeader64->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + SectionNumber = PEHeader64->FileHeader.NumberOfSections; + FileAlignment = PEHeader64->OptionalHeader.FileAlignment; + if(FileAlignment == 0x1000) + { + FileAlignment = 0x200; + } + __try + { + PEHeader64->OptionalHeader.FileAlignment = FileAlignment; + while(SectionNumber > 0) + { + SectionDataPtr = PESections->PointerToRawData + PESections->SizeOfRawData; + if(PESections->SizeOfRawData > NULL) + { + SectionDataPtr--; + while(*(PUCHAR)(FileMapVA + SectionDataPtr) == 0x00 && SectionDataPtr > PESections->PointerToRawData) + { + SectionDataPtr--; + } + } + SectionDataPtr = SectionDataPtr - PESections->PointerToRawData; + OldSectionDataPtr = SectionDataPtr; + SectionDataPtr = (SectionDataPtr / FileAlignment) * FileAlignment; + if(SectionDataPtr < OldSectionDataPtr) + { + SectionDataPtr = SectionDataPtr + FileAlignment; + } + if(CurrentSection == NULL) + { + PEHeader64->OptionalHeader.SizeOfHeaders = PESections->PointerToRawData; + PEHeader64->OptionalHeader.SectionAlignment = PESections->VirtualAddress; + PESections->SizeOfRawData = SectionDataPtr; + } + else + { + OldSectionDataRawPtr = PESections->PointerToRawData; + PESections->SizeOfRawData = SectionDataPtr; + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections - IMAGE_SIZEOF_SECTION_HEADER); + NewSectionRawPointer = PESections->PointerToRawData + PESections->SizeOfRawData; + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + IMAGE_SIZEOF_SECTION_HEADER); + PESections->PointerToRawData = NewSectionRawPointer; + RtlMoveMemory((LPVOID)((ULONG_PTR)FileMapVA + NewSectionRawPointer), (LPVOID)((ULONG_PTR)FileMapVA + OldSectionDataRawPtr), SectionDataPtr); + } + NewVirtualSectionSize = (PESections->Misc.VirtualSize / PEHeader64->OptionalHeader.SectionAlignment) * PEHeader64->OptionalHeader.SectionAlignment; + if(NewVirtualSectionSize < PESections->Misc.VirtualSize) + { + NewVirtualSectionSize = NewVirtualSectionSize + PEHeader64->OptionalHeader.SectionAlignment; + } + PESections->Misc.VirtualSize = NewVirtualSectionSize; + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + IMAGE_SIZEOF_SECTION_HEADER); + CurrentSection++; + SectionNumber--; + } + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections - IMAGE_SIZEOF_SECTION_HEADER); + return(PESections->PointerToRawData + PESections->SizeOfRawData); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return(-1); + } + } + } + else + { + return(-1); + } + } + return(-1); +} +__declspec(dllexport) long __stdcall RealignPEEx(char* szFileName, DWORD RealingFileSize, DWORD ForcedFileAlignment) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + + if(szFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + return(RealignPEExW(uniFileName, RealingFileSize, ForcedFileAlignment)); + } + else + { + return(-1); + } +} +__declspec(dllexport) long __stdcall RealignPEExW(wchar_t* szFileName, DWORD RealingFileSize, DWORD ForcedFileAlignment) +{ + + wchar_t szBackupFile[MAX_PATH] = {}; + wchar_t szBackupItem[MAX_PATH] = {}; + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + PIMAGE_SECTION_HEADER PESections; + DWORD NewVirtualSectionSize = 0; + DWORD NewSectionRawPointer = 0; + DWORD OldSectionDataRawPtr = 0; + DWORD OldSectionDataPtr = 0; + DWORD SectionDataPtr = 0; + DWORD SectionNumber = 0; + DWORD CurrentSection = 0; + BOOL FileIs64; + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + + if(engineBackupForCriticalFunctions && CreateGarbageItem(&szBackupItem, sizeof szBackupItem)) + { + if(!FillGarbageItem(szBackupItem, szFileName, &szBackupFile, sizeof szBackupItem)) + { + RtlZeroMemory(&szBackupItem, sizeof szBackupItem); + lstrcpyW(szBackupFile, szFileName); + } + } + else + { + RtlZeroMemory(&szBackupItem, sizeof szBackupItem); + lstrcpyW(szBackupFile, szFileName); + } + if(MapFileExW(szBackupFile, UE_ACCESS_ALL, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, FileHandle, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(-1); + } + if(!FileIs64) + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader32 + PEHeader32->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + SectionNumber = PEHeader32->FileHeader.NumberOfSections; + if(ForcedFileAlignment == 0x0) + { + ForcedFileAlignment = 0x200; + } + __try + { + PEHeader32->OptionalHeader.FileAlignment = ForcedFileAlignment; + while(SectionNumber > 0) + { + SectionDataPtr = PESections->PointerToRawData + PESections->SizeOfRawData; + if(PESections->SizeOfRawData > NULL) + { + SectionDataPtr--; + while(*(PUCHAR)(FileMapVA + SectionDataPtr) == 0x00 && SectionDataPtr > PESections->PointerToRawData) + { + SectionDataPtr--; + } + } + SectionDataPtr = SectionDataPtr - PESections->PointerToRawData; + OldSectionDataPtr = SectionDataPtr; + SectionDataPtr = (SectionDataPtr / ForcedFileAlignment) * ForcedFileAlignment; + if(SectionDataPtr < OldSectionDataPtr) + { + SectionDataPtr = SectionDataPtr + ForcedFileAlignment; + } + if(CurrentSection == NULL) + { + PEHeader32->OptionalHeader.SizeOfHeaders = PESections->PointerToRawData; + PEHeader32->OptionalHeader.SectionAlignment = PESections->VirtualAddress; + PESections->SizeOfRawData = SectionDataPtr; + } + else + { + OldSectionDataRawPtr = PESections->PointerToRawData; + PESections->SizeOfRawData = SectionDataPtr; + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections - IMAGE_SIZEOF_SECTION_HEADER); + NewSectionRawPointer = PESections->PointerToRawData + PESections->SizeOfRawData; + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + IMAGE_SIZEOF_SECTION_HEADER); + PESections->PointerToRawData = NewSectionRawPointer; + RtlMoveMemory((LPVOID)((ULONG_PTR)FileMapVA + NewSectionRawPointer), (LPVOID)((ULONG_PTR)FileMapVA + OldSectionDataRawPtr), SectionDataPtr); + } + NewVirtualSectionSize = (PESections->Misc.VirtualSize / PEHeader32->OptionalHeader.SectionAlignment) * PEHeader32->OptionalHeader.SectionAlignment; + if(NewVirtualSectionSize < PESections->Misc.VirtualSize) + { + NewVirtualSectionSize = NewVirtualSectionSize + PEHeader32->OptionalHeader.SectionAlignment; + } + PESections->Misc.VirtualSize = NewVirtualSectionSize; + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + IMAGE_SIZEOF_SECTION_HEADER); + CurrentSection++; + SectionNumber--; + } + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections - IMAGE_SIZEOF_SECTION_HEADER); + if(RealingFileSize == NULL) + { + FileSize = PESections->PointerToRawData + PESections->SizeOfRawData; + } + else + { + FileSize = RealingFileSize; + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + if(szBackupItem[0] != NULL) + { + if(CopyFileW(szBackupFile, szFileName, false)) + { + RemoveGarbageItem(szBackupItem, true); + return(FileSize); + } + else + { + RemoveGarbageItem(szBackupItem, true); + return(-1); + } + } + else + { + return(FileSize); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(-1); + } + } + else + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader64 + PEHeader64->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + SectionNumber = PEHeader64->FileHeader.NumberOfSections; + if(ForcedFileAlignment == 0x0) + { + ForcedFileAlignment = 0x200; + } + __try + { + PEHeader64->OptionalHeader.FileAlignment = ForcedFileAlignment; + while(SectionNumber > 0) + { + SectionDataPtr = PESections->PointerToRawData + PESections->SizeOfRawData; + if(PESections->SizeOfRawData > NULL) + { + SectionDataPtr--; + while(*(PUCHAR)(FileMapVA + SectionDataPtr) == 0x00 && SectionDataPtr > PESections->PointerToRawData) + { + SectionDataPtr--; + } + } + SectionDataPtr = SectionDataPtr - PESections->PointerToRawData; + OldSectionDataPtr = SectionDataPtr; + SectionDataPtr = (SectionDataPtr / ForcedFileAlignment) * ForcedFileAlignment; + if(SectionDataPtr < OldSectionDataPtr) + { + SectionDataPtr = SectionDataPtr + ForcedFileAlignment; + } + if(CurrentSection == NULL) + { + PEHeader64->OptionalHeader.SizeOfHeaders = PESections->PointerToRawData; + PEHeader64->OptionalHeader.SectionAlignment = PESections->VirtualAddress; + PESections->SizeOfRawData = SectionDataPtr; + } + else + { + OldSectionDataRawPtr = PESections->PointerToRawData; + PESections->SizeOfRawData = SectionDataPtr; + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections - IMAGE_SIZEOF_SECTION_HEADER); + NewSectionRawPointer = PESections->PointerToRawData + PESections->SizeOfRawData; + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + IMAGE_SIZEOF_SECTION_HEADER); + PESections->PointerToRawData = NewSectionRawPointer; + RtlMoveMemory((LPVOID)((ULONG_PTR)FileMapVA + NewSectionRawPointer), (LPVOID)((ULONG_PTR)FileMapVA + OldSectionDataRawPtr), SectionDataPtr); + } + NewVirtualSectionSize = (PESections->Misc.VirtualSize / PEHeader64->OptionalHeader.SectionAlignment) * PEHeader64->OptionalHeader.SectionAlignment; + if(NewVirtualSectionSize < PESections->Misc.VirtualSize) + { + NewVirtualSectionSize = NewVirtualSectionSize + PEHeader64->OptionalHeader.SectionAlignment; + } + PESections->Misc.VirtualSize = NewVirtualSectionSize; + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + IMAGE_SIZEOF_SECTION_HEADER); + CurrentSection++; + SectionNumber--; + } + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections - IMAGE_SIZEOF_SECTION_HEADER); + if(RealingFileSize == NULL) + { + FileSize = PESections->PointerToRawData + PESections->SizeOfRawData; + } + else + { + FileSize = RealingFileSize; + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + if(szBackupItem[0] != NULL) + { + if(CopyFileW(szBackupFile, szFileName, false)) + { + RemoveGarbageItem(szBackupItem, true); + return(FileSize); + } + else + { + RemoveGarbageItem(szBackupItem, true); + return(-1); + } + } + else + { + return(FileSize); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(-1); + } + } + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(-1); + } + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(-1); +} +__declspec(dllexport) bool __stdcall WipeSection(char* szFileName, int WipeSectionNumber, bool RemovePhysically) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + + if(szFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + return(WipeSectionW(uniFileName, WipeSectionNumber, RemovePhysically)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall WipeSectionW(wchar_t* szFileName, int WipeSectionNumber, bool RemovePhysically) +{ + + wchar_t szBackupFile[MAX_PATH] = {}; + wchar_t szBackupItem[MAX_PATH] = {}; + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + PIMAGE_SECTION_HEADER PESections; + DWORD NewVirtualSectionSize = 0; + DWORD NewSectionRawPointer = 0; + DWORD OldSectionDataRawPtr = 0; + DWORD OldSectionDataPtr = 0; + DWORD CurrentSectionPSize = 0; + DWORD WipeSectionVirSize = 0; + DWORD WipeSectionSize = 0; + DWORD SectionDataPtr = 0; + DWORD FileAlignment = 0; + int SectionNumber = 0; + BOOL FileIs64; + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + + if(engineBackupForCriticalFunctions && CreateGarbageItem(&szBackupItem, sizeof szBackupItem)) + { + if(!FillGarbageItem(szBackupItem, szFileName, &szBackupFile, sizeof szBackupItem)) + { + RtlZeroMemory(&szBackupItem, sizeof szBackupItem); + lstrcpyW(szBackupFile, szFileName); + } + } + else + { + RtlZeroMemory(&szBackupItem, sizeof szBackupItem); + lstrcpyW(szBackupFile, szFileName); + } + if(MapFileExW(szBackupFile, UE_ACCESS_ALL, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, FileHandle, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(false); + } + if(!FileIs64) + { + if(WipeSectionNumber != -1 && WipeSectionNumber <= PEHeader32->FileHeader.NumberOfSections) + { + WipeSectionVirSize = (DWORD)GetPE32DataFromMappedFile(FileMapVA, WipeSectionNumber, UE_SECTIONVIRTUALSIZE); + WipeSectionSize = (DWORD)GetPE32DataFromMappedFile(FileMapVA, WipeSectionNumber, UE_SECTIONRAWSIZE); + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader32 + PEHeader32->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + FileAlignment = PEHeader32->OptionalHeader.FileAlignment; + __try + { + while(SectionNumber < PEHeader32->FileHeader.NumberOfSections) + { + if(SectionNumber == WipeSectionNumber - 1) + { + CurrentSectionPSize = PESections->SizeOfRawData; + if(CurrentSectionPSize % FileAlignment == NULL) + { + CurrentSectionPSize = ((CurrentSectionPSize / FileAlignment)) * FileAlignment; + } + else + { + CurrentSectionPSize = ((CurrentSectionPSize / FileAlignment) + 1) * FileAlignment; + } + PESections->SizeOfRawData = CurrentSectionPSize; + WipeSectionVirSize = WipeSectionVirSize + PESections->Misc.VirtualSize; + if(WipeSectionVirSize % PEHeader32->OptionalHeader.SectionAlignment == NULL) + { + WipeSectionVirSize = ((WipeSectionVirSize / PEHeader32->OptionalHeader.SectionAlignment)) * PEHeader32->OptionalHeader.SectionAlignment; + } + else + { + WipeSectionVirSize = ((WipeSectionVirSize / PEHeader32->OptionalHeader.SectionAlignment) + 1) * PEHeader32->OptionalHeader.SectionAlignment; + } + PESections->Misc.VirtualSize = WipeSectionVirSize; + CurrentSectionPSize = CurrentSectionPSize - PESections->SizeOfRawData; + WipeSectionSize = WipeSectionSize - CurrentSectionPSize; + } + else if(SectionNumber > WipeSectionNumber) + { + RtlMoveMemory((LPVOID)((ULONG_PTR)PESections - IMAGE_SIZEOF_SECTION_HEADER), (LPVOID)PESections, IMAGE_SIZEOF_SECTION_HEADER); + } + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + IMAGE_SIZEOF_SECTION_HEADER); + SectionNumber++; + } + RtlZeroMemory((LPVOID)PESections, IMAGE_SIZEOF_SECTION_HEADER); + PEHeader32->FileHeader.NumberOfSections--; + if(RemovePhysically) + { + FileSize = RealignPE(FileMapVA, FileSize, NULL); + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + if(szBackupItem[0] != NULL) + { + if(CopyFileW(szBackupFile, szFileName, false)) + { + RemoveGarbageItem(szBackupItem, true); + return(true); + } + else + { + RemoveGarbageItem(szBackupItem, true); + return(false); + } + } + else + { + return(true); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(false); + } + } + } + else + { + if(WipeSectionNumber != -1 && WipeSectionNumber <= PEHeader64->FileHeader.NumberOfSections) + { + WipeSectionVirSize = (DWORD)GetPE32DataFromMappedFile(FileMapVA, WipeSectionNumber, UE_SECTIONVIRTUALOFFSET); + WipeSectionVirSize = WipeSectionVirSize + (DWORD)GetPE32DataFromMappedFile(FileMapVA, WipeSectionNumber, UE_SECTIONVIRTUALSIZE); + if(WipeSectionVirSize % PEHeader32->OptionalHeader.SectionAlignment == NULL) + { + WipeSectionVirSize = ((WipeSectionVirSize / PEHeader32->OptionalHeader.SectionAlignment)) * PEHeader32->OptionalHeader.SectionAlignment; + } + else + { + WipeSectionVirSize = ((WipeSectionVirSize / PEHeader32->OptionalHeader.SectionAlignment) + 1) * PEHeader32->OptionalHeader.SectionAlignment; + } + WipeSectionSize = (DWORD)GetPE32DataFromMappedFile(FileMapVA, WipeSectionNumber, UE_SECTIONRAWSIZE); + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader64 + PEHeader64->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + FileAlignment = PEHeader64->OptionalHeader.FileAlignment; + __try + { + while(SectionNumber < PEHeader64->FileHeader.NumberOfSections) + { + if(SectionNumber == WipeSectionNumber - 1) + { + CurrentSectionPSize = PESections->SizeOfRawData; + if(CurrentSectionPSize % FileAlignment == NULL) + { + CurrentSectionPSize = ((CurrentSectionPSize / FileAlignment)) * FileAlignment; + } + else + { + CurrentSectionPSize = ((CurrentSectionPSize / FileAlignment) + 1) * FileAlignment; + } + PESections->SizeOfRawData = CurrentSectionPSize; + WipeSectionVirSize = WipeSectionVirSize + PESections->Misc.VirtualSize; + if(WipeSectionVirSize % PEHeader64->OptionalHeader.SectionAlignment == NULL) + { + WipeSectionVirSize = ((WipeSectionVirSize / PEHeader64->OptionalHeader.SectionAlignment)) * PEHeader64->OptionalHeader.SectionAlignment; + } + else + { + WipeSectionVirSize = ((WipeSectionVirSize / PEHeader64->OptionalHeader.SectionAlignment) + 1) * PEHeader64->OptionalHeader.SectionAlignment; + } + PESections->Misc.VirtualSize = WipeSectionVirSize; + CurrentSectionPSize = CurrentSectionPSize - PESections->SizeOfRawData; + WipeSectionSize = WipeSectionSize - CurrentSectionPSize; + } + else if(SectionNumber > WipeSectionNumber) + { + RtlMoveMemory((LPVOID)((ULONG_PTR)PESections - IMAGE_SIZEOF_SECTION_HEADER), (LPVOID)PESections, IMAGE_SIZEOF_SECTION_HEADER); + } + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + IMAGE_SIZEOF_SECTION_HEADER); + SectionNumber++; + } + RtlZeroMemory((LPVOID)PESections, IMAGE_SIZEOF_SECTION_HEADER); + PEHeader64->FileHeader.NumberOfSections--; + if(RemovePhysically) + { + FileSize = RealignPE(FileMapVA, FileSize, NULL); + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + if(szBackupItem[0] != NULL) + { + if(CopyFileW(szBackupFile, szFileName, false)) + { + RemoveGarbageItem(szBackupItem, true); + return(true); + } + else + { + RemoveGarbageItem(szBackupItem, true); + return(false); + } + } + else + { + return(true); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(false); + } + } + } + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(false); + } + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(false); +} +__declspec(dllexport) bool __stdcall IsPE32FileValidEx(char* szFileName, DWORD CheckDepth, LPVOID FileStatusInfo) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + + if(szFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + return(IsPE32FileValidExW(uniFileName, CheckDepth, FileStatusInfo)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall IsPE32FileValidExW(wchar_t* szFileName, DWORD CheckDepth, LPVOID FileStatusInfo) +{ + + unsigned int i; + DWORD ReadData = NULL; + DWORD ReadSize = NULL; + WORD ReadDataWORD = NULL; + ULONG_PTR hSimulatedFileLoad; + DWORD SectionNumber = NULL; + DWORD SectionAttributes = NULL; + ULONG_PTR ConvertedAddress = NULL; + DWORD CorrectedImageSize = NULL; + DWORD SectionVirtualSize = NULL; + DWORD SectionVirtualSizeFixed = NULL; + DWORD NumberOfSections = NULL; + FILE_STATUS_INFO myFileStatusInfo; + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + PIMAGE_SECTION_HEADER PESections; + PIMAGE_EXPORT_DIRECTORY PEExports; + PIMAGE_TLS_DIRECTORY32 PETls32; + PIMAGE_TLS_DIRECTORY64 PETls64; + PIMAGE_IMPORT_DESCRIPTOR ImportIID; + PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundIID; + PIMAGE_THUNK_DATA32 ThunkData32; + PIMAGE_THUNK_DATA64 ThunkData64; + bool hLoadedModuleSimulated = false; + HMODULE hLoadedModule; + ULONG_PTR ImportNamePtr; + ULONG_PTR CurrentThunk; + BOOL FileIsDLL = false; + BOOL FileIs64; + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + WORD ResourceNamesTable[22] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 21, 22, 23, 24}; + + RtlZeroMemory(&myFileStatusInfo, sizeof FILE_STATUS_INFO); + if(MapFileExW(szFileName, UE_ACCESS_READ, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + myFileStatusInfo.OveralEvaluation = UE_RESULT_FILE_OK; + if(EngineValidateHeader(FileMapVA, FileHandle, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->Signature == 0x4550 && PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->Signature == 0x4550 && PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + myFileStatusInfo.FileIs64Bit = true; + } + else + { + myFileStatusInfo.OveralEvaluation = UE_RESULT_FILE_INVALID_FORMAT; + myFileStatusInfo.SignaturePE = UE_FIELD_BROKEN_NON_FIXABLE; + if(FileStatusInfo != NULL) + { + RtlMoveMemory(FileStatusInfo, &myFileStatusInfo, sizeof FILE_STATUS_INFO); + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + if(!FileIs64) + { + /* + x86 Surface check + */ + __try + { + if(PEHeader32->OptionalHeader.SizeOfImage % PEHeader32->OptionalHeader.SectionAlignment == NULL) + { + CorrectedImageSize = ((PEHeader32->OptionalHeader.SizeOfImage / PEHeader32->OptionalHeader.SectionAlignment)) * PEHeader32->OptionalHeader.SectionAlignment; + } + else + { + CorrectedImageSize = ((PEHeader32->OptionalHeader.SizeOfImage / PEHeader32->OptionalHeader.SectionAlignment) + 1) * PEHeader32->OptionalHeader.SectionAlignment; + } + if(PEHeader32->OptionalHeader.SectionAlignment != NULL && PEHeader32->OptionalHeader.SectionAlignment >= PEHeader32->OptionalHeader.FileAlignment) + { + myFileStatusInfo.SectionAlignment = UE_FIELD_OK; + if(PEHeader32->OptionalHeader.SizeOfImage % PEHeader32->OptionalHeader.SectionAlignment == NULL) + { + myFileStatusInfo.SizeOfImage = UE_FIELD_OK; + } + else + { + if(CorrectedImageSize < PEHeader32->OptionalHeader.AddressOfEntryPoint) + { + myFileStatusInfo.SizeOfImage = UE_FIELD_BROKEN_NON_FIXABLE; + } + else + { + myFileStatusInfo.SizeOfImage = UE_FILED_FIXABLE_NON_CRITICAL; + } + } + } + else + { + myFileStatusInfo.SectionAlignment = UE_FILED_FIXABLE_CRITICAL; + } + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.SectionAlignment, true); + if(PEHeader32->OptionalHeader.ImageBase % 0x1000 == NULL) + { + myFileStatusInfo.ImageBase = UE_FIELD_OK; + } + else + { + myFileStatusInfo.ImageBase = UE_FIELD_BROKEN_NON_FIXABLE; + } + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.ImageBase, true); + if(PEHeader32->OptionalHeader.FileAlignment % 2 == NULL) + { + myFileStatusInfo.FileAlignment = UE_FIELD_OK; + } + else + { + myFileStatusInfo.FileAlignment = UE_FILED_FIXABLE_CRITICAL; + } + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.FileAlignment, false); + /* + Get the console flag + */ + if(PEHeader32->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI) + { + myFileStatusInfo.FileIsConsole = true; + } + /* + Export and relocation checks [for DLL and EXE] + */ + if(PEHeader32->FileHeader.Characteristics & 0x2000) + { + /* + Export table check + */ + FileIsDLL = true; + myFileStatusInfo.FileIsDLL = true; + if(PEHeader32->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_EXPORT && PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress != NULL) + { + if(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress > CorrectedImageSize || PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size > CorrectedImageSize) + { + myFileStatusInfo.ExportTable = UE_FIELD_BROKEN_NON_FIXABLE; + } + else + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + PEHeader32->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress != NULL) + { + if(EngineIsBadReadPtrEx((LPVOID)ConvertedAddress, PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)) + { + PEExports = (PIMAGE_EXPORT_DIRECTORY)ConvertedAddress; + if(PEExports->AddressOfFunctions > CorrectedImageSize || PEExports->AddressOfFunctions + 4 * PEExports->NumberOfFunctions > CorrectedImageSize) + { + myFileStatusInfo.ExportTable = UE_FIELD_BROKEN_NON_FIXABLE; + } + else if(PEExports->AddressOfNameOrdinals > CorrectedImageSize || PEExports->AddressOfNameOrdinals + 4 * PEExports->NumberOfNames > CorrectedImageSize) + { + myFileStatusInfo.ExportTable = UE_FIELD_BROKEN_NON_FIXABLE; + } + else if(PEExports->AddressOfNames > CorrectedImageSize || PEExports->AddressOfNames + 4 * PEExports->NumberOfNames > CorrectedImageSize) + { + myFileStatusInfo.ExportTable = UE_FIELD_BROKEN_NON_FIXABLE; + } + else if(PEExports->Name > CorrectedImageSize) + { + myFileStatusInfo.ExportTable = UE_FIELD_BROKEN_NON_FIXABLE; + } + else + { + if(CheckDepth == UE_DEPTH_DEEP) + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEExports->AddressOfFunctions + PEHeader32->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress != NULL) + { + for(i = 0; i < PEExports->NumberOfFunctions; i++) + { + RtlMoveMemory(&ReadData, (LPVOID)ConvertedAddress, 4); + if(ReadData > CorrectedImageSize || ReadData < PEHeader32->OptionalHeader.SectionAlignment) + { + myFileStatusInfo.ExportTable = UE_FIELD_BROKEN_NON_FIXABLE; + i = PEExports->NumberOfFunctions; + } + else + { + ConvertedAddress = ConvertedAddress + 4; + } + } + } + else + { + myFileStatusInfo.ExportTable = UE_FIELD_BROKEN_NON_FIXABLE; + } + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEExports->AddressOfNames + PEHeader32->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress != NULL) + { + for(i = 0; i < PEExports->NumberOfNames; i++) + { + RtlMoveMemory(&ReadData, (LPVOID)ConvertedAddress, 4); + if(ReadData > CorrectedImageSize || ReadData < PEHeader32->OptionalHeader.SectionAlignment) + { + myFileStatusInfo.ExportTable = UE_FIELD_BROKEN_NON_FIXABLE; + i = PEExports->NumberOfNames; + } + else + { + ConvertedAddress = ConvertedAddress + 4; + } + } + } + else + { + myFileStatusInfo.ExportTable = UE_FIELD_BROKEN_NON_FIXABLE; + } + } + } + } + else + { + myFileStatusInfo.ExportTable = UE_FIELD_BROKEN_NON_FIXABLE; + } + } + else + { + myFileStatusInfo.ExportTable = UE_FIELD_BROKEN_NON_FIXABLE; + } + } + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.ExportTable, true); + } + else + { + myFileStatusInfo.ExportTable = UE_FIELD_NOT_PRESET; + } + /* + Relocation table check + */ + if(PEHeader32->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_BASERELOC && PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress != NULL) + { + if(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress > CorrectedImageSize || PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size > CorrectedImageSize) + { + myFileStatusInfo.RelocationTable = UE_FIELD_BROKEN_NON_FIXABLE; + } + else + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress + PEHeader32->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress != NULL) + { + if(EngineIsBadReadPtrEx((LPVOID)ConvertedAddress, PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size)) + { + RtlMoveMemory(&ReadData, (LPVOID)ConvertedAddress, 4); + RtlMoveMemory(&ReadSize, (LPVOID)(ConvertedAddress + 4), 4); + while(ReadData != NULL) + { + ReadSize = ReadSize - 8; + ConvertedAddress = ConvertedAddress + 8; + while(ReadSize > NULL) + { + RtlMoveMemory(&ReadDataWORD, (LPVOID)ConvertedAddress, 2); + if(ReadDataWORD > 0xCFFF) + { + myFileStatusInfo.RelocationTable = UE_FIELD_BROKEN_FIXABLE_FOR_STATIC_USE; + } + ConvertedAddress = ConvertedAddress + 2; + ReadSize = ReadSize - 2; + } + RtlMoveMemory(&ReadData, (LPVOID)ConvertedAddress, 4); + RtlMoveMemory(&ReadSize, (LPVOID)(ConvertedAddress + 4), 4); + } + } + else + { + myFileStatusInfo.RelocationTable = UE_FIELD_BROKEN_FIXABLE_FOR_STATIC_USE; + } + } + else + { + myFileStatusInfo.RelocationTable = UE_FIELD_BROKEN_FIXABLE_FOR_STATIC_USE; + } + } + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.RelocationTable, true); + } + else + { + myFileStatusInfo.RelocationTable = UE_FIELD_NOT_PRESET_WARNING; + } + } + else + { + /* + Export table check + */ + if(PEHeader32->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_EXPORT && PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress != NULL) + { + if(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress > CorrectedImageSize || PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size > CorrectedImageSize) + { + myFileStatusInfo.ExportTable = UE_FIELD_BROKEN_NON_CRITICAL; + } + else + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + PEHeader32->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress != NULL) + { + if(EngineIsBadReadPtrEx((LPVOID)ConvertedAddress, PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)) + { + PEExports = (PIMAGE_EXPORT_DIRECTORY)ConvertedAddress; + if(PEExports->AddressOfFunctions > CorrectedImageSize || PEExports->AddressOfFunctions + 4 * PEExports->NumberOfFunctions > CorrectedImageSize) + { + myFileStatusInfo.ExportTable = UE_FIELD_BROKEN_NON_CRITICAL; + } + else if(PEExports->AddressOfNameOrdinals > CorrectedImageSize || PEExports->AddressOfNameOrdinals + 4 * PEExports->NumberOfNames > CorrectedImageSize) + { + myFileStatusInfo.ExportTable = UE_FIELD_BROKEN_NON_CRITICAL; + } + else if(PEExports->AddressOfNames > CorrectedImageSize || PEExports->AddressOfNames + 4 * PEExports->NumberOfNames > CorrectedImageSize) + { + myFileStatusInfo.ExportTable = UE_FIELD_BROKEN_NON_CRITICAL; + } + else if(PEExports->Name > CorrectedImageSize) + { + myFileStatusInfo.ExportTable = UE_FIELD_BROKEN_NON_CRITICAL; + } + } + else + { + myFileStatusInfo.ExportTable = UE_FIELD_BROKEN_NON_CRITICAL; + } + } + } + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.ExportTable, false); + } + else + { + myFileStatusInfo.ExportTable = UE_FIELD_NOT_PRESET; + } + /* + Relocation table check + */ + if(PEHeader32->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_BASERELOC && PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress != NULL) + { + if(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress > CorrectedImageSize || PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size > CorrectedImageSize) + { + myFileStatusInfo.RelocationTable = UE_FIELD_BROKEN_NON_FIXABLE; + } + else + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress + PEHeader32->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress == NULL || ConvertedAddress - FileMapVA > FileSize) + { + myFileStatusInfo.RelocationTable = UE_FILED_FIXABLE_NON_CRITICAL; + } + } + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.RelocationTable, false); + } + else + { + myFileStatusInfo.RelocationTable = UE_FIELD_NOT_PRESET; + } + } + /* + Import table check + */ + if(PEHeader32->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_IMPORT && PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress != NULL) + { + if(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress > CorrectedImageSize) + { + myFileStatusInfo.ImportTable = UE_FIELD_BROKEN_NON_FIXABLE; + } + else + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + PEHeader32->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress == NULL || ConvertedAddress - FileMapVA > FileSize) + { + myFileStatusInfo.ImportTable = UE_FIELD_BROKEN_NON_FIXABLE; + } + else + { + SectionNumber = GetPE32SectionNumberFromVA(FileMapVA, PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + PEHeader32->OptionalHeader.ImageBase); + if(SectionNumber >= NULL) + { + SectionAttributes = (DWORD)GetPE32DataFromMappedFile(FileMapVA, SectionNumber, UE_SECTIONFLAGS); + if(SectionAttributes & IMAGE_SCN_MEM_EXECUTE || SectionAttributes & IMAGE_SCN_CNT_CODE || SectionAttributes & IMAGE_SCN_MEM_WRITE || SectionAttributes & IMAGE_SCN_CNT_INITIALIZED_DATA) + { + myFileStatusInfo.ImportTableSection = UE_FIELD_OK; + } + else + { + myFileStatusInfo.ImportTableSection = UE_FILED_FIXABLE_CRITICAL; + } + if(CheckDepth == UE_DEPTH_DEEP) + { + if(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress != NULL) + { + ImportIID = (PIMAGE_IMPORT_DESCRIPTOR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, (ULONG_PTR)PEHeader32->OptionalHeader.ImageBase, (ULONG_PTR)(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + PEHeader32->OptionalHeader.ImageBase), false, true); + while(myFileStatusInfo.ImportTableData == UE_FIELD_OK && ImportIID->FirstThunk != NULL) + { + hLoadedModule = NULL; + ImportNamePtr = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, (ULONG_PTR)PEHeader32->OptionalHeader.ImageBase, (ULONG_PTR)((ULONG_PTR)ImportIID->Name + PEHeader32->OptionalHeader.ImageBase), false, true); + if(ImportNamePtr != NULL) + { + if(!EngineIsDependencyPresent((char*)ImportNamePtr, NULL, NULL)) + { + myFileStatusInfo.MissingDependencies = true; + hLoadedModuleSimulated = false; + } + else + { + hLoadedModuleSimulated = false; + hLoadedModule = GetModuleHandleA((char*)ImportNamePtr); + if(hLoadedModule == NULL) + { + hLoadedModule = (HMODULE)EngineSimulateDllLoader(GetCurrentProcess(), (char*)ImportNamePtr); + hLoadedModuleSimulated = true; + } + } + } + else + { + myFileStatusInfo.ImportTableData = UE_FIELD_BROKEN_NON_FIXABLE; + } + if(ImportIID->OriginalFirstThunk != NULL) + { + ThunkData32 = (PIMAGE_THUNK_DATA32)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, (ULONG_PTR)PEHeader32->OptionalHeader.ImageBase, (ULONG_PTR)((ULONG_PTR)ImportIID->OriginalFirstThunk + PEHeader32->OptionalHeader.ImageBase), false, true); + CurrentThunk = (ULONG_PTR)ImportIID->OriginalFirstThunk; + } + else + { + ThunkData32 = (PIMAGE_THUNK_DATA32)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, (ULONG_PTR)PEHeader32->OptionalHeader.ImageBase, (ULONG_PTR)((ULONG_PTR)ImportIID->FirstThunk + PEHeader32->OptionalHeader.ImageBase), false, true); + CurrentThunk = (ULONG_PTR)ImportIID->FirstThunk; + } + if(ThunkData32 != NULL) + { + while(myFileStatusInfo.ImportTableData == UE_FIELD_OK && ThunkData32->u1.AddressOfData != NULL) + { + if(ThunkData32->u1.Ordinal & IMAGE_ORDINAL_FLAG32) + { + if((int)(ThunkData32->u1.Ordinal ^ IMAGE_ORDINAL_FLAG32) >= 0x10000) + { + myFileStatusInfo.ImportTableData = UE_FIELD_BROKEN_NON_FIXABLE; + } + } + else + { + ImportNamePtr = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, (ULONG_PTR)PEHeader32->OptionalHeader.ImageBase, (ULONG_PTR)((ULONG_PTR)ThunkData32->u1.AddressOfData + 2 + PEHeader32->OptionalHeader.ImageBase), false, true); + if(ImportNamePtr != NULL) + { + if(!EngineIsBadReadPtrEx((LPVOID)ImportNamePtr, 8)) + { + myFileStatusInfo.ImportTableData = UE_FIELD_BROKEN_NON_FIXABLE; + } + else + { + if(hLoadedModule != NULL) + { + if(EngineGetProcAddress((ULONG_PTR)hLoadedModule, (char*)ImportNamePtr) == NULL) + { + myFileStatusInfo.MissingDeclaredAPIs = true; + SetOverallFileStatus(&myFileStatusInfo, UE_FILED_FIXABLE_CRITICAL, true); + } + } + } + } + else + { + myFileStatusInfo.ImportTableData = UE_FIELD_BROKEN_NON_FIXABLE; + } + } + CurrentThunk = CurrentThunk + 4; + ThunkData32 = (PIMAGE_THUNK_DATA32)((ULONG_PTR)ThunkData32 + sizeof IMAGE_THUNK_DATA32); + } + } + else + { + myFileStatusInfo.ImportTableData = UE_FIELD_BROKEN_NON_FIXABLE; + } + if(hLoadedModuleSimulated) + { + VirtualFree((LPVOID)hLoadedModule, NULL, MEM_RELEASE); + } + ImportIID = (PIMAGE_IMPORT_DESCRIPTOR)((ULONG_PTR)ImportIID + sizeof IMAGE_IMPORT_DESCRIPTOR); + } + } + } + } + else + { + myFileStatusInfo.ImportTable = UE_FIELD_BROKEN_NON_FIXABLE; + } + } + } + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.ImportTable, true); + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.ImportTableData, true); + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.ImportTableSection, true); + } + else + { + myFileStatusInfo.ImportTable = UE_FIELD_NOT_PRESET; + } + /* + TLS table check + */ + if(PEHeader32->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_TLS && PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress != NULL) + { + if(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress > CorrectedImageSize || PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size > CorrectedImageSize) + { + myFileStatusInfo.TLSTable = UE_FILED_FIXABLE_CRITICAL; + } + else + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress + PEHeader32->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress == NULL || ConvertedAddress - FileMapVA > FileSize) + { + myFileStatusInfo.TLSTable = UE_FILED_FIXABLE_CRITICAL; + } + else + { + PETls32 = (PIMAGE_TLS_DIRECTORY32)ConvertedAddress; + if(PETls32->StartAddressOfRawData != NULL && (PETls32->StartAddressOfRawData < PEHeader32->OptionalHeader.ImageBase || PETls32->StartAddressOfRawData > CorrectedImageSize + PEHeader32->OptionalHeader.ImageBase)) + { + myFileStatusInfo.TLSTable = UE_FILED_FIXABLE_CRITICAL; + } + else if(PETls32->EndAddressOfRawData != NULL && (PETls32->EndAddressOfRawData < PEHeader32->OptionalHeader.ImageBase || PETls32->EndAddressOfRawData > CorrectedImageSize + PEHeader32->OptionalHeader.ImageBase)) + { + myFileStatusInfo.TLSTable = UE_FILED_FIXABLE_CRITICAL; + } + else if(PETls32->AddressOfIndex != NULL && (PETls32->AddressOfIndex < PEHeader32->OptionalHeader.ImageBase || PETls32->AddressOfIndex > CorrectedImageSize + PEHeader32->OptionalHeader.ImageBase)) + { + myFileStatusInfo.TLSTable = UE_FILED_FIXABLE_CRITICAL; + } + else if(PETls32->AddressOfCallBacks != NULL && (PETls32->AddressOfCallBacks < PEHeader32->OptionalHeader.ImageBase || PETls32->AddressOfCallBacks > CorrectedImageSize + PEHeader32->OptionalHeader.ImageBase)) + { + myFileStatusInfo.TLSTable = UE_FILED_FIXABLE_CRITICAL; + } + if(PETls32->AddressOfCallBacks != NULL && CheckDepth == UE_DEPTH_DEEP) + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PETls32->AddressOfCallBacks + PEHeader32->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress != NULL) + { + while(ReadData != NULL) + { + RtlMoveMemory(&ReadData, (LPVOID)ConvertedAddress, 4); + if(ReadData < PEHeader32->OptionalHeader.ImageBase || ReadData > CorrectedImageSize + PEHeader32->OptionalHeader.ImageBase) + { + myFileStatusInfo.TLSTable = UE_FILED_FIXABLE_CRITICAL; + } + ConvertedAddress = ConvertedAddress + 4; + } + } + } + } + } + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.TLSTable, false); + } + else + { + myFileStatusInfo.TLSTable = UE_FIELD_NOT_PRESET; + } + /* + Load config table check + */ + if(PEHeader32->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG && PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress != NULL) + { + if(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress > CorrectedImageSize || PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size > CorrectedImageSize) + { + myFileStatusInfo.LoadConfigTable = UE_FILED_FIXABLE_CRITICAL; + } + else + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress + PEHeader32->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress == NULL || ConvertedAddress - FileMapVA > FileSize) + { + myFileStatusInfo.LoadConfigTable = UE_FILED_FIXABLE_CRITICAL; + } + } + } + else + { + myFileStatusInfo.LoadConfigTable = UE_FIELD_NOT_PRESET; + } + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.LoadConfigTable, false); + /* + Bound import table check + */ + if(PEHeader32->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT && PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress != NULL) + { + if(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress > CorrectedImageSize || PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size > CorrectedImageSize) + { + myFileStatusInfo.BoundImportTable = UE_FILED_FIXABLE_CRITICAL; + } + else + { + ConvertedAddress = (ULONG_PTR)PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress + FileMapVA; + if(ConvertedAddress == NULL || ConvertedAddress - FileMapVA > FileSize) + { + myFileStatusInfo.BoundImportTable = UE_FILED_FIXABLE_CRITICAL; + } + else + { + BoundIID = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)ConvertedAddress; + while(BoundIID->TimeDateStamp != NULL) + { + if(BoundIID->OffsetModuleName > PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size) + { + myFileStatusInfo.BoundImportTable = UE_FILED_FIXABLE_CRITICAL; + } + else if(!EngineIsPointedMemoryString(ConvertedAddress + BoundIID->OffsetModuleName)) + { + myFileStatusInfo.BoundImportTable = UE_FILED_FIXABLE_CRITICAL; + } + BoundIID = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)((ULONG_PTR)BoundIID + sizeof IMAGE_BOUND_IMPORT_DESCRIPTOR); + } + } + } + } + else + { + myFileStatusInfo.BoundImportTable = UE_FIELD_NOT_PRESET; + } + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.BoundImportTable, false); + /* + IAT check + */ + if(PEHeader32->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_IAT && PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress != NULL) + { + if(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress > CorrectedImageSize || PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size > CorrectedImageSize) + { + myFileStatusInfo.IATTable = UE_FILED_FIXABLE_NON_CRITICAL; + } + else + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress + PEHeader32->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress == NULL || ConvertedAddress - FileMapVA > FileSize) + { + myFileStatusInfo.IATTable = UE_FILED_FIXABLE_NON_CRITICAL; + } + } + } + else + { + myFileStatusInfo.IATTable = UE_FIELD_NOT_PRESET; + } + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.IATTable, false); + /* + COM header check + */ + if(PEHeader32->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR && PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress != NULL) + { + if(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress > CorrectedImageSize || PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size > CorrectedImageSize) + { + myFileStatusInfo.COMHeaderTable = UE_FILED_FIXABLE_NON_CRITICAL; + } + else + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress + PEHeader32->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress == NULL || ConvertedAddress - FileMapVA > FileSize) + { + myFileStatusInfo.COMHeaderTable = UE_FILED_FIXABLE_NON_CRITICAL; + } + } + } + else + { + myFileStatusInfo.COMHeaderTable = UE_FIELD_NOT_PRESET; + } + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.COMHeaderTable, false); + /* + Resource header check + */ + if(PEHeader32->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_RESOURCE && PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress != NULL) + { + if(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress > CorrectedImageSize || PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size > CorrectedImageSize) + { + myFileStatusInfo.ResourceTable = UE_FILED_FIXABLE_NON_CRITICAL; + } + else + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress + PEHeader32->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress == NULL || ConvertedAddress - FileMapVA > FileSize || ConvertedAddress - FileMapVA + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size > FileSize) + { + myFileStatusInfo.ResourceTable = UE_FIELD_BROKEN_BUT_CAN_BE_EMULATED; + } + if(CheckDepth == UE_DEPTH_DEEP) + { + hSimulatedFileLoad = (ULONG_PTR)EngineSimulateNtLoaderW(szFileName); + if(hSimulatedFileLoad != NULL) + { + for(i = 0; i < 22; i++) + { + if(myFileStatusInfo.ResourceData == UE_FIELD_OK) + { + EnumResourceNamesA((HMODULE)hSimulatedFileLoad, MAKEINTRESOURCEA(ResourceNamesTable[i]), (ENUMRESNAMEPROCA)EngineValidateResource, (ULONG_PTR)&myFileStatusInfo.ResourceData); + } + else + { + i = 22; + } + } + VirtualFree((LPVOID)hSimulatedFileLoad, NULL, MEM_RELEASE); + } + } + } + if(myFileStatusInfo.ResourceTable == UE_FIELD_BROKEN_BUT_CAN_BE_EMULATED && myFileStatusInfo.ResourceData == UE_FIELD_OK) + { + myFileStatusInfo.ResourceTable = UE_FIELD_OK; + } + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.ResourceTable, true); + } + else + { + myFileStatusInfo.ResourceTable = UE_FIELD_NOT_PRESET; + } + /* + Section check + */ + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader32 + PEHeader32->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + NumberOfSections = PEHeader32->FileHeader.NumberOfSections; + while(NumberOfSections > NULL) + { + SectionVirtualSize = PESections->VirtualAddress + PESections->Misc.VirtualSize; + if(PESections->Misc.VirtualSize % PEHeader32->OptionalHeader.SectionAlignment == NULL) + { + SectionVirtualSizeFixed = SectionVirtualSize; + } + else + { + SectionVirtualSizeFixed = PESections->VirtualAddress + (((PESections->Misc.VirtualSize / PEHeader32->OptionalHeader.SectionAlignment) + 1) * PEHeader32->OptionalHeader.SectionAlignment); + } + if(NumberOfSections > 1) + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + sizeof IMAGE_SECTION_HEADER); + if(SectionVirtualSize > PESections->VirtualAddress || SectionVirtualSizeFixed > PESections->VirtualAddress) + { + myFileStatusInfo.SectionTable = UE_FILED_FIXABLE_CRITICAL; + } + } + NumberOfSections--; + } + if(PESections->PointerToRawData + PESections->SizeOfRawData > FileSize && PESections->SizeOfRawData != NULL) + { + myFileStatusInfo.SectionTable = UE_FIELD_BROKEN_NON_FIXABLE; + } + SectionVirtualSizeFixed = SectionVirtualSizeFixed + 0xF000; + if(PEHeader32->OptionalHeader.SizeOfImage > SectionVirtualSizeFixed) + { + myFileStatusInfo.SizeOfImage = UE_FILED_FIXABLE_CRITICAL; + } + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.SizeOfImage, true); + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.SectionTable, true); + /* + Entry point check + */ + SectionNumber = GetPE32SectionNumberFromVA(FileMapVA, PEHeader32->OptionalHeader.AddressOfEntryPoint + PEHeader32->OptionalHeader.ImageBase); + if(SectionNumber != -1) + { + SectionAttributes = (DWORD)GetPE32DataFromMappedFile(FileMapVA, SectionNumber, UE_SECTIONFLAGS); + if(SectionAttributes & IMAGE_SCN_MEM_EXECUTE || SectionAttributes & IMAGE_SCN_CNT_CODE) + { + myFileStatusInfo.EntryPoint = UE_FIELD_OK; + } + else + { + myFileStatusInfo.EntryPoint = UE_FIELD_BROKEN_NON_CRITICAL; + } + } + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader32->OptionalHeader.AddressOfEntryPoint + PEHeader32->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress == NULL) + { + myFileStatusInfo.EntryPoint = UE_FIELD_BROKEN_NON_FIXABLE; + } + else + { + ReadData = NULL; + if(memcmp(&ReadData, (LPVOID)ConvertedAddress, 4) == NULL) + { + myFileStatusInfo.EntryPoint = UE_FIELD_BROKEN_NON_FIXABLE; + } + } + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.EntryPoint, true); + /* + Return data + */ + if(FileStatusInfo != NULL) + { + RtlMoveMemory(FileStatusInfo, &myFileStatusInfo, sizeof FILE_STATUS_INFO); + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + if(myFileStatusInfo.OveralEvaluation == UE_RESULT_FILE_OK) + { + return(true); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + myFileStatusInfo.EvaluationTerminatedByException = true; + myFileStatusInfo.OveralEvaluation = UE_RESULT_FILE_INVALID_FORMAT; + myFileStatusInfo.SignaturePE = UE_FIELD_BROKEN_NON_FIXABLE; + if(FileStatusInfo != NULL) + { + RtlMoveMemory(FileStatusInfo, &myFileStatusInfo, sizeof FILE_STATUS_INFO); + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + else + { + /* + x64 Surface check + */ + __try + { + if(PEHeader64->OptionalHeader.SizeOfImage % PEHeader64->OptionalHeader.SectionAlignment == NULL) + { + CorrectedImageSize = ((PEHeader64->OptionalHeader.SizeOfImage / PEHeader64->OptionalHeader.SectionAlignment)) * PEHeader64->OptionalHeader.SectionAlignment; + } + else + { + CorrectedImageSize = ((PEHeader64->OptionalHeader.SizeOfImage / PEHeader64->OptionalHeader.SectionAlignment) + 1) * PEHeader64->OptionalHeader.SectionAlignment; + } + if(PEHeader64->OptionalHeader.SectionAlignment != NULL && PEHeader64->OptionalHeader.SectionAlignment >= PEHeader64->OptionalHeader.FileAlignment) + { + myFileStatusInfo.SectionAlignment = UE_FIELD_OK; + if(PEHeader64->OptionalHeader.SizeOfImage % PEHeader64->OptionalHeader.SectionAlignment == NULL) + { + myFileStatusInfo.SizeOfImage = UE_FIELD_OK; + } + else + { + if(CorrectedImageSize < PEHeader64->OptionalHeader.AddressOfEntryPoint) + { + myFileStatusInfo.SizeOfImage = UE_FIELD_BROKEN_NON_FIXABLE; + } + else + { + myFileStatusInfo.SizeOfImage = UE_FILED_FIXABLE_NON_CRITICAL; + } + } + } + else + { + myFileStatusInfo.SectionAlignment = UE_FILED_FIXABLE_CRITICAL; + } + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.SectionAlignment, true); + if((ULONG_PTR)PEHeader64->OptionalHeader.ImageBase % 0x1000 == NULL) + { + myFileStatusInfo.ImageBase = UE_FIELD_OK; + } + else + { + myFileStatusInfo.ImageBase = UE_FIELD_BROKEN_NON_FIXABLE; + } + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.ImageBase, true); + if(PEHeader64->OptionalHeader.FileAlignment % 2 == NULL) + { + myFileStatusInfo.FileAlignment = UE_FIELD_OK; + } + else + { + myFileStatusInfo.FileAlignment = UE_FILED_FIXABLE_CRITICAL; + } + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.FileAlignment, false); + /* + Get the console flag + */ + if(PEHeader64->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI) + { + myFileStatusInfo.FileIsConsole = true; + } + /* + Export and relocation checks [for DLL and EXE] + */ + if(PEHeader64->FileHeader.Characteristics & 0x2000) + { + /* + Export table check + */ + FileIsDLL = true; + myFileStatusInfo.FileIsDLL = true; + if(PEHeader64->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_EXPORT && PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress != NULL) + { + if(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress > CorrectedImageSize || PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size > CorrectedImageSize) + { + myFileStatusInfo.ExportTable = UE_FIELD_BROKEN_NON_FIXABLE; + } + else + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress != NULL) + { + if(EngineIsBadReadPtrEx((LPVOID)ConvertedAddress, PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)) + { + PEExports = (PIMAGE_EXPORT_DIRECTORY)ConvertedAddress; + if(PEExports->AddressOfFunctions > CorrectedImageSize || PEExports->AddressOfFunctions + 4 * PEExports->NumberOfFunctions > CorrectedImageSize) + { + myFileStatusInfo.ExportTable = UE_FIELD_BROKEN_NON_FIXABLE; + } + else if(PEExports->AddressOfNameOrdinals > CorrectedImageSize || PEExports->AddressOfNameOrdinals + 4 * PEExports->NumberOfNames > CorrectedImageSize) + { + myFileStatusInfo.ExportTable = UE_FIELD_BROKEN_NON_FIXABLE; + } + else if(PEExports->AddressOfNames > CorrectedImageSize || PEExports->AddressOfNames + 4 * PEExports->NumberOfNames > CorrectedImageSize) + { + myFileStatusInfo.ExportTable = UE_FIELD_BROKEN_NON_FIXABLE; + } + else if(PEExports->Name > CorrectedImageSize) + { + myFileStatusInfo.ExportTable = UE_FIELD_BROKEN_NON_FIXABLE; + } + else + { + if(CheckDepth == UE_DEPTH_DEEP) + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEExports->AddressOfFunctions + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress != NULL) + { + for(i = 0; i < PEExports->NumberOfFunctions; i++) + { + RtlMoveMemory(&ReadData, (LPVOID)ConvertedAddress, 4); + if(ReadData > CorrectedImageSize || ReadData < PEHeader64->OptionalHeader.SectionAlignment) + { + myFileStatusInfo.ExportTable = UE_FIELD_BROKEN_NON_FIXABLE; + i = PEExports->NumberOfFunctions; + } + else + { + ConvertedAddress = ConvertedAddress + 4; + } + } + } + else + { + myFileStatusInfo.ExportTable = UE_FIELD_BROKEN_NON_FIXABLE; + } + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEExports->AddressOfNames + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress != NULL) + { + for(i = 0; i < PEExports->NumberOfNames; i++) + { + RtlMoveMemory(&ReadData, (LPVOID)ConvertedAddress, 4); + if(ReadData > CorrectedImageSize || ReadData < PEHeader64->OptionalHeader.SectionAlignment) + { + myFileStatusInfo.ExportTable = UE_FIELD_BROKEN_NON_FIXABLE; + i = PEExports->NumberOfNames; + } + else + { + ConvertedAddress = ConvertedAddress + 4; + } + } + } + else + { + myFileStatusInfo.ExportTable = UE_FIELD_BROKEN_NON_FIXABLE; + } + } + } + } + else + { + myFileStatusInfo.ExportTable = UE_FIELD_BROKEN_NON_FIXABLE; + } + } + else + { + myFileStatusInfo.ExportTable = UE_FIELD_BROKEN_NON_FIXABLE; + } + } + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.ExportTable, true); + } + else + { + myFileStatusInfo.ExportTable = UE_FIELD_NOT_PRESET; + } + /* + Relocation table check + */ + if(PEHeader64->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_BASERELOC && PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress != NULL) + { + if(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress > CorrectedImageSize || PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size > CorrectedImageSize) + { + myFileStatusInfo.RelocationTable = UE_FIELD_BROKEN_NON_FIXABLE; + } + else + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress != NULL) + { + if(EngineIsBadReadPtrEx((LPVOID)ConvertedAddress, PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size)) + { + RtlMoveMemory(&ReadData, (LPVOID)ConvertedAddress, 4); + RtlMoveMemory(&ReadSize, (LPVOID)(ConvertedAddress + 4), 4); + while(ReadData != NULL) + { + ReadSize = ReadSize - 8; + ConvertedAddress = ConvertedAddress + 8; + while(ReadSize > NULL) + { + RtlMoveMemory(&ReadDataWORD, (LPVOID)ConvertedAddress, 2); + if(ReadDataWORD > 0xCFFF) + { + myFileStatusInfo.RelocationTable = UE_FIELD_BROKEN_FIXABLE_FOR_STATIC_USE; + } + ConvertedAddress = ConvertedAddress + 2; + ReadSize = ReadSize - 2; + } + RtlMoveMemory(&ReadData, (LPVOID)ConvertedAddress, 4); + RtlMoveMemory(&ReadSize, (LPVOID)(ConvertedAddress + 4), 4); + } + } + else + { + myFileStatusInfo.RelocationTable = UE_FIELD_BROKEN_FIXABLE_FOR_STATIC_USE; + } + } + else + { + myFileStatusInfo.RelocationTable = UE_FIELD_BROKEN_FIXABLE_FOR_STATIC_USE; + } + } + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.RelocationTable, true); + } + else + { + myFileStatusInfo.RelocationTable = UE_FIELD_NOT_PRESET_WARNING; + } + } + else + { + /* + Export table check + */ + if(PEHeader64->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_EXPORT && PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress != NULL) + { + if(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress > CorrectedImageSize || PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size > CorrectedImageSize) + { + myFileStatusInfo.ExportTable = UE_FIELD_BROKEN_NON_CRITICAL; + } + else + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress != NULL) + { + if(EngineIsBadReadPtrEx((LPVOID)ConvertedAddress, PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)) + { + PEExports = (PIMAGE_EXPORT_DIRECTORY)ConvertedAddress; + if(PEExports->AddressOfFunctions > CorrectedImageSize || PEExports->AddressOfFunctions + 4 * PEExports->NumberOfFunctions > CorrectedImageSize) + { + myFileStatusInfo.ExportTable = UE_FIELD_BROKEN_NON_CRITICAL; + } + else if(PEExports->AddressOfNameOrdinals > CorrectedImageSize || PEExports->AddressOfNameOrdinals + 4 * PEExports->NumberOfNames > CorrectedImageSize) + { + myFileStatusInfo.ExportTable = UE_FIELD_BROKEN_NON_CRITICAL; + } + else if(PEExports->AddressOfNames > CorrectedImageSize || PEExports->AddressOfNames + 4 * PEExports->NumberOfNames > CorrectedImageSize) + { + myFileStatusInfo.ExportTable = UE_FIELD_BROKEN_NON_CRITICAL; + } + else if(PEExports->Name > CorrectedImageSize) + { + myFileStatusInfo.ExportTable = UE_FIELD_BROKEN_NON_CRITICAL; + } + } + else + { + myFileStatusInfo.ExportTable = UE_FIELD_BROKEN_NON_CRITICAL; + } + } + } + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.ExportTable, false); + } + else + { + myFileStatusInfo.ExportTable = UE_FIELD_NOT_PRESET; + } + /* + Relocation table check + */ + if(PEHeader64->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_BASERELOC && PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress != NULL) + { + if(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress > CorrectedImageSize || PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size > CorrectedImageSize) + { + myFileStatusInfo.RelocationTable = UE_FIELD_BROKEN_NON_FIXABLE; + } + else + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress == NULL || ConvertedAddress - FileMapVA > FileSize) + { + myFileStatusInfo.RelocationTable = UE_FILED_FIXABLE_NON_CRITICAL; + } + } + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.RelocationTable, false); + } + else + { + myFileStatusInfo.RelocationTable = UE_FIELD_NOT_PRESET; + } + } + /* + Import table check + */ + if(PEHeader64->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_IMPORT && PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress != NULL) + { + if(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress > CorrectedImageSize) + { + myFileStatusInfo.ImportTable = UE_FIELD_BROKEN_NON_FIXABLE; + } + else + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress == NULL || ConvertedAddress - FileMapVA > FileSize) + { + myFileStatusInfo.ImportTable = UE_FIELD_BROKEN_NON_FIXABLE; + } + else + { + SectionNumber = GetPE32SectionNumberFromVA(FileMapVA, PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase); + if(SectionNumber >= NULL) + { + SectionAttributes = (DWORD)GetPE32DataFromMappedFile(FileMapVA, SectionNumber, UE_SECTIONFLAGS); + if(SectionAttributes & IMAGE_SCN_MEM_EXECUTE || SectionAttributes & IMAGE_SCN_CNT_CODE || SectionAttributes & IMAGE_SCN_MEM_WRITE || SectionAttributes & IMAGE_SCN_CNT_INITIALIZED_DATA) + { + myFileStatusInfo.ImportTableSection = UE_FIELD_OK; + } + else + { + myFileStatusInfo.ImportTableSection = UE_FILED_FIXABLE_CRITICAL; + } + if(CheckDepth == UE_DEPTH_DEEP) + { + if(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress != NULL) + { + ImportIID = (PIMAGE_IMPORT_DESCRIPTOR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, (ULONG_PTR)(ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, (ULONG_PTR)(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase), false, true); + while(myFileStatusInfo.ImportTableData == UE_FIELD_OK && ImportIID->FirstThunk != NULL) + { + hLoadedModule = NULL; + ImportNamePtr = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, (ULONG_PTR)(ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, (ULONG_PTR)((ULONG_PTR)ImportIID->Name + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase), false, true); + if(ImportNamePtr != NULL) + { + if(!EngineIsDependencyPresent((char*)ImportNamePtr, NULL, NULL)) + { + myFileStatusInfo.MissingDependencies = true; + hLoadedModuleSimulated = false; + } + else + { + hLoadedModuleSimulated = false; + hLoadedModule = GetModuleHandleA((char*)ImportNamePtr); + if(hLoadedModule == NULL) + { + hLoadedModule = (HMODULE)EngineSimulateDllLoader(GetCurrentProcess(), (char*)ImportNamePtr); + hLoadedModuleSimulated = true; + } + } + } + else + { + myFileStatusInfo.ImportTableData = UE_FIELD_BROKEN_NON_FIXABLE; + } + if(ImportIID->OriginalFirstThunk != NULL) + { + ThunkData64 = (PIMAGE_THUNK_DATA64)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, (ULONG_PTR)((ULONG_PTR)ImportIID->OriginalFirstThunk + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase), false, true); + CurrentThunk = (ULONG_PTR)ImportIID->OriginalFirstThunk; + } + else + { + ThunkData32 = (PIMAGE_THUNK_DATA32)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, (ULONG_PTR)PEHeader32->OptionalHeader.ImageBase, (ULONG_PTR)((ULONG_PTR)ImportIID->FirstThunk + PEHeader32->OptionalHeader.ImageBase), false, true); + CurrentThunk = (ULONG_PTR)ImportIID->FirstThunk; + } + if(ThunkData64 != NULL) + { + while(myFileStatusInfo.ImportTableData == UE_FIELD_OK && ThunkData64->u1.AddressOfData != NULL) + { + if(ThunkData64->u1.Ordinal & IMAGE_ORDINAL_FLAG64) + { + if((int)(ThunkData64->u1.Ordinal ^ IMAGE_ORDINAL_FLAG64) >= 0x10000) + { + myFileStatusInfo.ImportTableData = UE_FIELD_BROKEN_NON_FIXABLE; + } + } + else + { + ImportNamePtr = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, (ULONG_PTR)(ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, (ULONG_PTR)((ULONG_PTR)ThunkData64->u1.AddressOfData + 2 + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase), false, true); + if(ImportNamePtr != NULL) + { + if(!EngineIsBadReadPtrEx((LPVOID)ImportNamePtr, 8)) + { + myFileStatusInfo.ImportTableData = UE_FIELD_BROKEN_NON_FIXABLE; + } + else + { + if(hLoadedModule != NULL) + { + if(EngineGetProcAddress((ULONG_PTR)hLoadedModule, (char*)ImportNamePtr) == NULL) + { + myFileStatusInfo.MissingDeclaredAPIs = true; + SetOverallFileStatus(&myFileStatusInfo, UE_FILED_FIXABLE_CRITICAL, true); + } + } + } + } + else + { + myFileStatusInfo.ImportTableData = UE_FIELD_BROKEN_NON_FIXABLE; + } + } + CurrentThunk = CurrentThunk + 8; + ThunkData64 = (PIMAGE_THUNK_DATA64)((ULONG_PTR)ThunkData64 + sizeof IMAGE_THUNK_DATA64); + } + } + else + { + myFileStatusInfo.ImportTableData = UE_FIELD_BROKEN_NON_FIXABLE; + } + if(hLoadedModuleSimulated) + { + VirtualFree((LPVOID)hLoadedModule, NULL, MEM_RELEASE); + } + ImportIID = (PIMAGE_IMPORT_DESCRIPTOR)((ULONG_PTR)ImportIID + sizeof IMAGE_IMPORT_DESCRIPTOR); + } + } + } + } + else + { + myFileStatusInfo.ImportTable = UE_FIELD_BROKEN_NON_FIXABLE; + } + } + } + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.ImportTable, true); + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.ImportTableData, true); + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.ImportTableSection, true); + } + else + { + myFileStatusInfo.ImportTable = UE_FIELD_NOT_PRESET; + } + /* + TLS table check + */ + if(PEHeader64->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_TLS && PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress != NULL) + { + if(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress > CorrectedImageSize || PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size > CorrectedImageSize) + { + myFileStatusInfo.TLSTable = UE_FILED_FIXABLE_CRITICAL; + } + else + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress == NULL || ConvertedAddress - FileMapVA > FileSize) + { + myFileStatusInfo.TLSTable = UE_FILED_FIXABLE_CRITICAL; + } + else + { + PETls64 = (PIMAGE_TLS_DIRECTORY64)ConvertedAddress; + if(PETls64->StartAddressOfRawData != NULL && (PETls64->StartAddressOfRawData < (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase || PETls64->StartAddressOfRawData > CorrectedImageSize + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase)) + { + myFileStatusInfo.TLSTable = UE_FILED_FIXABLE_CRITICAL; + } + else if(PETls64->EndAddressOfRawData != NULL && (PETls64->EndAddressOfRawData < (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase || PETls64->EndAddressOfRawData > CorrectedImageSize + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase)) + { + myFileStatusInfo.TLSTable = UE_FILED_FIXABLE_CRITICAL; + } + else if(PETls64->AddressOfIndex != NULL && (PETls64->AddressOfIndex < (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase || PETls64->AddressOfIndex > CorrectedImageSize + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase)) + { + myFileStatusInfo.TLSTable = UE_FILED_FIXABLE_CRITICAL; + } + else if(PETls64->AddressOfCallBacks != NULL && (PETls64->AddressOfCallBacks < (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase || PETls64->AddressOfCallBacks > CorrectedImageSize + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase)) + { + myFileStatusInfo.TLSTable = UE_FILED_FIXABLE_CRITICAL; + } + if(PETls64->AddressOfCallBacks != NULL && CheckDepth == UE_DEPTH_DEEP) + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, (ULONG_PTR)PETls64->AddressOfCallBacks + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress != NULL) + { + while(ReadData != NULL) + { + RtlMoveMemory(&ReadData, (LPVOID)ConvertedAddress, 8); + if(ReadData < (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase || ReadData > CorrectedImageSize + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase) + { + myFileStatusInfo.TLSTable = UE_FILED_FIXABLE_CRITICAL; + } + ConvertedAddress = ConvertedAddress + 8; + } + } + } + } + } + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.TLSTable, false); + } + else + { + myFileStatusInfo.TLSTable = UE_FIELD_NOT_PRESET; + } + /* + Load config table check + */ + if(PEHeader64->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG && PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress != NULL) + { + if(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress > CorrectedImageSize || PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size > CorrectedImageSize) + { + myFileStatusInfo.LoadConfigTable = UE_FILED_FIXABLE_CRITICAL; + } + else + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress == NULL || ConvertedAddress - FileMapVA > FileSize) + { + myFileStatusInfo.LoadConfigTable = UE_FILED_FIXABLE_CRITICAL; + } + } + } + else + { + myFileStatusInfo.LoadConfigTable = UE_FIELD_NOT_PRESET; + } + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.LoadConfigTable, false); + /* + Bound import table check + */ + if(PEHeader64->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT && PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress != NULL) + { + if(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress > CorrectedImageSize || PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size > CorrectedImageSize) + { + myFileStatusInfo.BoundImportTable = UE_FILED_FIXABLE_CRITICAL; + } + else + { + ConvertedAddress = (ULONG_PTR)PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress + FileMapVA; + if(ConvertedAddress == NULL || ConvertedAddress - FileMapVA > FileSize) + { + myFileStatusInfo.BoundImportTable = UE_FILED_FIXABLE_CRITICAL; + } + else + { + BoundIID = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)ConvertedAddress; + while(BoundIID->TimeDateStamp != NULL) + { + if(BoundIID->OffsetModuleName > PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size) + { + myFileStatusInfo.BoundImportTable = UE_FILED_FIXABLE_CRITICAL; + } + else if(!EngineIsPointedMemoryString(ConvertedAddress + BoundIID->OffsetModuleName)) + { + myFileStatusInfo.BoundImportTable = UE_FILED_FIXABLE_CRITICAL; + } + BoundIID = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)((ULONG_PTR)BoundIID + sizeof IMAGE_BOUND_IMPORT_DESCRIPTOR); + } + } + } + } + else + { + myFileStatusInfo.BoundImportTable = UE_FIELD_NOT_PRESET; + } + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.BoundImportTable, false); + /* + IAT check + */ + if(PEHeader64->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_IAT && PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress != NULL) + { + if(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress > CorrectedImageSize || PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size > CorrectedImageSize) + { + myFileStatusInfo.IATTable = UE_FILED_FIXABLE_NON_CRITICAL; + } + else + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress == NULL || ConvertedAddress - FileMapVA > FileSize) + { + myFileStatusInfo.IATTable = UE_FILED_FIXABLE_NON_CRITICAL; + } + } + } + else + { + myFileStatusInfo.IATTable = UE_FIELD_NOT_PRESET; + } + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.IATTable, false); + /* + COM header check + */ + if(PEHeader64->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR && PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress != NULL) + { + if(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress > CorrectedImageSize || PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size > CorrectedImageSize) + { + myFileStatusInfo.COMHeaderTable = UE_FILED_FIXABLE_NON_CRITICAL; + } + else + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress == NULL || ConvertedAddress - FileMapVA > FileSize) + { + myFileStatusInfo.COMHeaderTable = UE_FILED_FIXABLE_NON_CRITICAL; + } + } + } + else + { + myFileStatusInfo.COMHeaderTable = UE_FIELD_NOT_PRESET; + } + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.COMHeaderTable, false); + /* + Resource header check + */ + if(PEHeader64->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_RESOURCE && PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress != NULL) + { + if(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress > CorrectedImageSize || PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size > CorrectedImageSize) + { + myFileStatusInfo.ResourceTable = UE_FILED_FIXABLE_NON_CRITICAL; + } + else + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress == NULL || ConvertedAddress - FileMapVA > FileSize || ConvertedAddress - FileMapVA + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size > FileSize) + { + myFileStatusInfo.ResourceTable = UE_FIELD_BROKEN_BUT_CAN_BE_EMULATED; + } + if(CheckDepth == UE_DEPTH_DEEP) + { + hSimulatedFileLoad = (ULONG_PTR)EngineSimulateNtLoaderW(szFileName); + if(hSimulatedFileLoad != NULL) + { + for(i = 0; i < 22; i++) + { + if(myFileStatusInfo.ResourceData == UE_FIELD_OK) + { + EnumResourceNamesA((HMODULE)hSimulatedFileLoad, MAKEINTRESOURCEA(ResourceNamesTable[i]), (ENUMRESNAMEPROCA)EngineValidateResource, (ULONG_PTR)&myFileStatusInfo.ResourceData); + } + else + { + i = 22; + } + } + VirtualFree((LPVOID)hSimulatedFileLoad, NULL, MEM_RELEASE); + } + } + } + if(myFileStatusInfo.ResourceTable == UE_FIELD_BROKEN_BUT_CAN_BE_EMULATED && myFileStatusInfo.ResourceData == UE_FIELD_OK) + { + myFileStatusInfo.ResourceTable = UE_FIELD_OK; + } + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.ResourceTable, true); + } + else + { + myFileStatusInfo.ResourceTable = UE_FIELD_NOT_PRESET; + } + /* + Section check + */ + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader64 + PEHeader64->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + NumberOfSections = PEHeader64->FileHeader.NumberOfSections; + while(NumberOfSections > NULL) + { + SectionVirtualSize = PESections->VirtualAddress + PESections->Misc.VirtualSize; + if(PESections->Misc.VirtualSize % PEHeader64->OptionalHeader.SectionAlignment == NULL) + { + SectionVirtualSizeFixed = SectionVirtualSize; + } + else + { + SectionVirtualSizeFixed = PESections->VirtualAddress + (((PESections->Misc.VirtualSize / PEHeader64->OptionalHeader.SectionAlignment) + 1) * PEHeader64->OptionalHeader.SectionAlignment); + } + if(NumberOfSections > 1) + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + sizeof IMAGE_SECTION_HEADER); + if(SectionVirtualSize > PESections->VirtualAddress || SectionVirtualSizeFixed > PESections->VirtualAddress) + { + myFileStatusInfo.SectionTable = UE_FILED_FIXABLE_CRITICAL; + } + } + NumberOfSections--; + } + if(PESections->PointerToRawData + PESections->SizeOfRawData > FileSize && PESections->SizeOfRawData != NULL) + { + myFileStatusInfo.SectionTable = UE_FIELD_BROKEN_NON_FIXABLE; + } + SectionVirtualSizeFixed = SectionVirtualSizeFixed + 0xF000; + if(PEHeader64->OptionalHeader.SizeOfImage > SectionVirtualSizeFixed) + { + myFileStatusInfo.SizeOfImage = UE_FILED_FIXABLE_CRITICAL; + } + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.SizeOfImage, true); + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.SectionTable, true); + /* + Entry point check + */ + SectionNumber = GetPE32SectionNumberFromVA(FileMapVA, PEHeader64->OptionalHeader.AddressOfEntryPoint + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase); + if(SectionNumber != -1) + { + SectionAttributes = (DWORD)GetPE32DataFromMappedFile(FileMapVA, SectionNumber, UE_SECTIONFLAGS); + if(SectionAttributes & IMAGE_SCN_MEM_EXECUTE || SectionAttributes & IMAGE_SCN_CNT_CODE) + { + myFileStatusInfo.EntryPoint = UE_FIELD_OK; + } + else + { + myFileStatusInfo.EntryPoint = UE_FIELD_BROKEN_NON_CRITICAL; + } + } + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader64->OptionalHeader.AddressOfEntryPoint + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress == NULL) + { + myFileStatusInfo.EntryPoint = UE_FIELD_BROKEN_NON_FIXABLE; + } + else + { + ReadData = NULL; + if(memcmp(&ReadData, (LPVOID)ConvertedAddress, 4) == NULL) + { + myFileStatusInfo.EntryPoint = UE_FIELD_BROKEN_NON_FIXABLE; + } + } + SetOverallFileStatus(&myFileStatusInfo, myFileStatusInfo.EntryPoint, true); + /* + Return data + */ + if(FileStatusInfo != NULL) + { + RtlMoveMemory(FileStatusInfo, &myFileStatusInfo, sizeof FILE_STATUS_INFO); + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + if(myFileStatusInfo.OveralEvaluation == UE_RESULT_FILE_OK) + { + return(true); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + myFileStatusInfo.EvaluationTerminatedByException = true; + myFileStatusInfo.OveralEvaluation = UE_RESULT_FILE_INVALID_FORMAT; + myFileStatusInfo.SignaturePE = UE_FIELD_BROKEN_NON_FIXABLE; + if(FileStatusInfo != NULL) + { + RtlMoveMemory(FileStatusInfo, &myFileStatusInfo, sizeof FILE_STATUS_INFO); + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + } + else + { + myFileStatusInfo.OveralEvaluation = UE_RESULT_FILE_INVALID_FORMAT; + myFileStatusInfo.SignatureMZ = UE_FIELD_BROKEN_NON_FIXABLE; + if(FileStatusInfo != NULL) + { + RtlMoveMemory(FileStatusInfo, &myFileStatusInfo, sizeof FILE_STATUS_INFO); + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + if(FileStatusInfo != NULL) + { + RtlMoveMemory(FileStatusInfo, &myFileStatusInfo, sizeof FILE_STATUS_INFO); + } + return(false); +} +__declspec(dllexport) bool __stdcall FixBrokenPE32FileEx(char* szFileName, LPVOID FileStatusInfo, LPVOID FileFixInfo) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + + if(szFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + return(FixBrokenPE32FileExW(uniFileName, FileStatusInfo, FileFixInfo)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall FixBrokenPE32FileExW(wchar_t* szFileName, LPVOID FileStatusInfo, LPVOID FileFixInfo) +{ + + DWORD ReadData = NULL; + DWORD ReadSize = NULL; + WORD ReadDataWORD = NULL; + ULONG_PTR ReadDataQWORD = NULL; + DWORD OrdinalBase = NULL; + DWORD OrdinalCount = NULL; + DWORD SectionNumber = NULL; + DWORD SectionAttributes = NULL; + ULONG_PTR ConvertedAddress = NULL; + DWORD CorrectedImageSize = NULL; + DWORD SectionVirtualSize = NULL; + DWORD SectionVirtualSizeFixed = NULL; + DWORD NumberOfSections = NULL; + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + PIMAGE_SECTION_HEADER PESections; + PIMAGE_EXPORT_DIRECTORY PEExports; + PIMAGE_TLS_DIRECTORY32 PETls32; + PIMAGE_TLS_DIRECTORY64 PETls64; + PIMAGE_IMPORT_DESCRIPTOR ImportIID; + PIMAGE_THUNK_DATA32 ThunkData32; + PIMAGE_THUNK_DATA64 ThunkData64; + PFILE_STATUS_INFO myFileStatusInfo = (PFILE_STATUS_INFO)FileStatusInfo; + PFILE_FIX_INFO myFileFixInfo = (PFILE_FIX_INFO)FileFixInfo; + bool hLoadedModuleSimulated = false; + HMODULE hLoadedModule; + ULONG_PTR ImportNamePtr; + ULONG_PTR CurrentThunk; + BOOL FileIs64; + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + bool FileFixed = true; + bool FeatureFixed = false; + + if(myFileStatusInfo == NULL) + { + IsPE32FileValidExW(szFileName, UE_DEPTH_DEEP, FileStatusInfo); + } + if(myFileFixInfo->FileFixPerformed == false && myFileStatusInfo->OveralEvaluation == UE_RESULT_FILE_INVALID_BUT_FIXABLE) + { + if(MapFileExW(szFileName, UE_ACCESS_ALL, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + myFileFixInfo->OveralEvaluation = UE_RESULT_FILE_INVALID_AND_NON_FIXABLE; + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, FileHandle, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->Signature == 0x4550 && PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->Signature == 0x4550 && PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + if(myFileStatusInfo->SignatureMZ != UE_FIELD_OK) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + else if(myFileStatusInfo->SignaturePE != UE_FIELD_OK) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + else if(myFileStatusInfo->SectionAlignment != UE_FIELD_OK) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + else if(myFileStatusInfo->FileAlignment != UE_FIELD_OK) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + else if(myFileStatusInfo->ImportTable != UE_FIELD_OK) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + else if(myFileStatusInfo->ImportTableData != UE_FIELD_OK) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + if(!FileIs64) + { + /* + x86 Surface check + */ + __try + { + if(PEHeader32->OptionalHeader.SizeOfImage % PEHeader32->OptionalHeader.SectionAlignment == NULL) + { + CorrectedImageSize = (PEHeader32->OptionalHeader.SizeOfImage / PEHeader32->OptionalHeader.SectionAlignment) * PEHeader32->OptionalHeader.SectionAlignment; + } + else + { + CorrectedImageSize = ((PEHeader32->OptionalHeader.SizeOfImage / PEHeader32->OptionalHeader.SectionAlignment) + 1) * PEHeader32->OptionalHeader.SectionAlignment; + } + /* + Fixing import table + */ + if(myFileStatusInfo->MissingDeclaredAPIs) + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + PEHeader32->OptionalHeader.ImageBase, false, true); + SectionNumber = GetPE32SectionNumberFromVA(FileMapVA, PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + PEHeader32->OptionalHeader.ImageBase); + if(SectionNumber >= NULL) + { + SectionAttributes = (DWORD)GetPE32DataFromMappedFile(FileMapVA, SectionNumber, UE_SECTIONFLAGS); + if(SectionAttributes & IMAGE_SCN_MEM_EXECUTE || SectionAttributes & IMAGE_SCN_CNT_CODE || SectionAttributes & IMAGE_SCN_MEM_WRITE || SectionAttributes & IMAGE_SCN_CNT_INITIALIZED_DATA) + { + // Should not execute! + } + else + { + if(!SetPE32DataForMappedFile(FileMapVA, SectionAttributes, UE_SECTIONFLAGS, 0xE0000020)) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + if(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress != NULL) + { + ImportIID = (PIMAGE_IMPORT_DESCRIPTOR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, (ULONG_PTR)PEHeader32->OptionalHeader.ImageBase, (ULONG_PTR)(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + PEHeader32->OptionalHeader.ImageBase), false, true); + while(ImportIID->FirstThunk != NULL) + { + hLoadedModule = NULL; + ImportNamePtr = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, (ULONG_PTR)PEHeader32->OptionalHeader.ImageBase, (ULONG_PTR)((ULONG_PTR)ImportIID->Name + PEHeader32->OptionalHeader.ImageBase), false, true); + if(ImportNamePtr != NULL) + { + if(!EngineIsDependencyPresent((char*)ImportNamePtr, NULL, NULL)) + { + hLoadedModuleSimulated = false; + } + else + { + hLoadedModuleSimulated = false; + hLoadedModule = GetModuleHandleA((char*)ImportNamePtr); + if(hLoadedModule == NULL) + { + hLoadedModule = (HMODULE)EngineSimulateDllLoader(GetCurrentProcess(), (char*)ImportNamePtr); + hLoadedModuleSimulated = true; + } + } + } + if(ImportIID->OriginalFirstThunk != NULL) + { + ThunkData32 = (PIMAGE_THUNK_DATA32)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, (ULONG_PTR)PEHeader32->OptionalHeader.ImageBase, (ULONG_PTR)((ULONG_PTR)ImportIID->OriginalFirstThunk + PEHeader32->OptionalHeader.ImageBase), false, true); + CurrentThunk = (ULONG_PTR)ImportIID->OriginalFirstThunk; + } + else + { + ThunkData32 = (PIMAGE_THUNK_DATA32)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, (ULONG_PTR)PEHeader32->OptionalHeader.ImageBase, (ULONG_PTR)((ULONG_PTR)ImportIID->FirstThunk + PEHeader32->OptionalHeader.ImageBase), false, true); + CurrentThunk = (ULONG_PTR)ImportIID->FirstThunk; + } + if(ThunkData32 != NULL) + { + while(ThunkData32->u1.AddressOfData != NULL) + { + if(ThunkData32->u1.Ordinal & IMAGE_ORDINAL_FLAG32) + { + if((int)(ThunkData32->u1.Ordinal ^ IMAGE_ORDINAL_FLAG32) >= 0x10000) + { + FileFixed = false; + } + } + else + { + ImportNamePtr = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, (ULONG_PTR)PEHeader32->OptionalHeader.ImageBase, (ULONG_PTR)((ULONG_PTR)ThunkData32->u1.AddressOfData + 2 + PEHeader32->OptionalHeader.ImageBase), false, true); + if(ImportNamePtr != NULL) + { + if(EngineIsBadReadPtrEx((LPVOID)ImportNamePtr, 8)) + { + if(hLoadedModule != NULL) + { + if(EngineGetProcAddress((ULONG_PTR)hLoadedModule, (char*)ImportNamePtr) == NULL) + { + OrdinalBase = NULL; + OrdinalCount = NULL; + if(EngineGetLibraryOrdinalData((ULONG_PTR)hLoadedModule, &OrdinalBase, &OrdinalCount)) + { + if(OrdinalBase != NULL && OrdinalCount != NULL) + { + ThunkData32->u1.Ordinal = (OrdinalBase + 1) ^ IMAGE_ORDINAL_FLAG32; + } + else + { + FileFixed = false; + } + } + } + } + } + } + } + CurrentThunk = CurrentThunk + 4; + ThunkData32 = (PIMAGE_THUNK_DATA32)((ULONG_PTR)ThunkData32 + sizeof IMAGE_THUNK_DATA32); + } + } + if(hLoadedModuleSimulated) + { + VirtualFree((LPVOID)hLoadedModule, NULL, MEM_RELEASE); + } + ImportIID = (PIMAGE_IMPORT_DESCRIPTOR)((ULONG_PTR)ImportIID + sizeof IMAGE_IMPORT_DESCRIPTOR); + } + } + } + } + /* + Fixing Export table + */ + if(myFileStatusInfo->ExportTable == UE_FIELD_NOT_PRESET_WARNING) + { + FileFixed = false; + } + else if(myFileFixInfo->DontFixExports == false && myFileStatusInfo->ExportTable != UE_FIELD_OK && myFileStatusInfo->ExportTable != UE_FIELD_NOT_PRESET) + { + if(PEHeader32->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_EXPORT && PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress != NULL) + { + if(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress > CorrectedImageSize || PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size > CorrectedImageSize) + { + myFileFixInfo->StrippedExports = true; + myFileFixInfo->OriginalExportTableAddress = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + myFileFixInfo->OriginalExportTableSize = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = NULL; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = NULL; + } + else + { + FeatureFixed = true; + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + PEHeader32->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress != NULL) + { + if(EngineIsBadReadPtrEx((LPVOID)ConvertedAddress, PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)) + { + PEExports = (PIMAGE_EXPORT_DIRECTORY)ConvertedAddress; + if(PEExports->AddressOfFunctions > CorrectedImageSize || PEExports->AddressOfFunctions + 4 * PEExports->NumberOfFunctions > CorrectedImageSize) + { + FeatureFixed = false; + } + else if(PEExports->AddressOfNameOrdinals > CorrectedImageSize || PEExports->AddressOfNameOrdinals + 4 * PEExports->NumberOfNames > CorrectedImageSize) + { + FeatureFixed = false; + } + else if(PEExports->AddressOfNames > CorrectedImageSize || PEExports->AddressOfNames + 4 * PEExports->NumberOfNames > CorrectedImageSize) + { + FeatureFixed = false; + } + else if(PEExports->Name > CorrectedImageSize) + { + FeatureFixed = false; + } + if(!FeatureFixed) + { + myFileFixInfo->StrippedExports = true; + myFileFixInfo->OriginalExportTableAddress = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + myFileFixInfo->OriginalExportTableSize = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = NULL; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = NULL; + } + } + else + { + myFileFixInfo->StrippedExports = true; + myFileFixInfo->OriginalExportTableAddress = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + myFileFixInfo->OriginalExportTableSize = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = NULL; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = NULL; + } + } + } + } + } + /* + Fixing Relocation table + */ + if(myFileStatusInfo->FileIsDLL == true && myFileStatusInfo->RelocationTable == UE_FIELD_BROKEN_NON_FIXABLE) + { + FileFixed = false; + } + else if(myFileFixInfo->DontFixRelocations == false && myFileStatusInfo->RelocationTable != UE_FIELD_OK) + { + if(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress > CorrectedImageSize || PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size > CorrectedImageSize) + { + if(myFileStatusInfo->FileIsDLL) + { + FileFixed = false; + } + else + { + myFileFixInfo->StrippedRelocation = true; + myFileFixInfo->OriginalRelocationTableAddress = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress; + myFileFixInfo->OriginalRelocationTableSize = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = NULL; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = NULL; + } + } + else + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress + PEHeader32->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress != NULL) + { + if(EngineIsBadReadPtrEx((LPVOID)ConvertedAddress, PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size)) + { + RtlMoveMemory(&ReadData, (LPVOID)ConvertedAddress, 4); + RtlMoveMemory(&ReadSize, (LPVOID)(ConvertedAddress + 4), 4); + while(ReadData != NULL) + { + ReadSize = ReadSize - 8; + ConvertedAddress = ConvertedAddress + 8; + while(ReadSize > NULL) + { + RtlMoveMemory(&ReadDataWORD, (LPVOID)ConvertedAddress, 2); + if(ReadDataWORD > 0xCFFF) + { + RtlZeroMemory((LPVOID)ConvertedAddress, 2); + } + ConvertedAddress = ConvertedAddress + 2; + ReadSize = ReadSize - 2; + } + RtlMoveMemory(&ReadData, (LPVOID)ConvertedAddress, 4); + RtlMoveMemory(&ReadSize, (LPVOID)(ConvertedAddress + 4), 4); + } + } + else + { + if(myFileStatusInfo->FileIsDLL) + { + FileFixed = false; + } + else + { + myFileFixInfo->StrippedRelocation = true; + myFileFixInfo->OriginalRelocationTableAddress = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress; + myFileFixInfo->OriginalRelocationTableSize = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = NULL; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = NULL; + } + } + } + else + { + if(myFileStatusInfo->FileIsDLL) + { + FileFixed = false; + } + else + { + myFileFixInfo->StrippedRelocation = true; + myFileFixInfo->OriginalRelocationTableAddress = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress; + myFileFixInfo->OriginalRelocationTableSize = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = NULL; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = NULL; + } + } + } + } + else if(myFileStatusInfo->RelocationTable == UE_FIELD_OK) + { + // Filter case! + } + else + { + FileFixed = false; + } + /* + Fixing Resource table + */ + if(myFileFixInfo->DontFixResources == false && myFileStatusInfo->ResourceData != UE_FIELD_OK && myFileStatusInfo->ResourceData != UE_FIELD_NOT_PRESET) + { + myFileFixInfo->StrippedResources = true; + myFileFixInfo->OriginalResourceTableAddress = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress; + myFileFixInfo->OriginalResourceTableSize = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = NULL; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = NULL; + } + else if(myFileFixInfo->DontFixResources == false && myFileStatusInfo->ResourceTable != UE_FIELD_OK && myFileStatusInfo->ResourceTable != UE_FIELD_NOT_PRESET) + { + if(PEHeader32->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_RESOURCE && PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress != NULL) + { + if(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress > CorrectedImageSize || PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size > CorrectedImageSize) + { + myFileFixInfo->StrippedResources = true; + myFileFixInfo->OriginalResourceTableAddress = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress; + myFileFixInfo->OriginalResourceTableSize = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = NULL; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = NULL; + } + else + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress + PEHeader32->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress == NULL || ConvertedAddress - FileMapVA > FileSize || ConvertedAddress - FileMapVA + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size > FileSize) + { + myFileFixInfo->StrippedResources = true; + myFileFixInfo->OriginalResourceTableAddress = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress; + myFileFixInfo->OriginalResourceTableSize = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = NULL; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = NULL; + } + } + } + } + /* + Fixing TLS table + */ + if(myFileFixInfo->DontFixTLS == false && myFileStatusInfo->TLSTable != UE_FIELD_OK && myFileStatusInfo->TLSTable != UE_FIELD_NOT_PRESET) + { + if(PEHeader32->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_TLS && PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress != NULL) + { + if(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress > CorrectedImageSize || PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size > CorrectedImageSize) + { + myFileFixInfo->StrippedTLS = true; + myFileFixInfo->OriginalTLSTableAddress = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress; + myFileFixInfo->OriginalTLSTableSize = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress = NULL; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size = NULL; + } + else + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress + PEHeader32->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress == NULL || ConvertedAddress - FileMapVA > FileSize) + { + myFileFixInfo->StrippedTLS = true; + myFileFixInfo->OriginalTLSTableAddress = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress; + myFileFixInfo->OriginalTLSTableSize = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress = NULL; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size = NULL; + } + else + { + FeatureFixed = true; + PETls32 = (PIMAGE_TLS_DIRECTORY32)ConvertedAddress; + if(PETls32->StartAddressOfRawData != NULL && (PETls32->StartAddressOfRawData < PEHeader32->OptionalHeader.ImageBase || PETls32->StartAddressOfRawData > CorrectedImageSize + PEHeader32->OptionalHeader.ImageBase)) + { + FeatureFixed = false; + } + else if(PETls32->EndAddressOfRawData != NULL && (PETls32->EndAddressOfRawData < PEHeader32->OptionalHeader.ImageBase || PETls32->EndAddressOfRawData > CorrectedImageSize + PEHeader32->OptionalHeader.ImageBase)) + { + FeatureFixed = false; + } + else if(PETls32->AddressOfIndex != NULL && (PETls32->AddressOfIndex < PEHeader32->OptionalHeader.ImageBase || PETls32->AddressOfIndex > CorrectedImageSize + PEHeader32->OptionalHeader.ImageBase)) + { + FeatureFixed = false; + } + else if(PETls32->AddressOfCallBacks != NULL && (PETls32->AddressOfCallBacks < PEHeader32->OptionalHeader.ImageBase || PETls32->AddressOfCallBacks > CorrectedImageSize + PEHeader32->OptionalHeader.ImageBase)) + { + FeatureFixed = false; + } + if(!FeatureFixed) + { + myFileFixInfo->StrippedTLS = true; + myFileFixInfo->OriginalTLSTableAddress = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress; + myFileFixInfo->OriginalTLSTableSize = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress = NULL; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size = NULL; + } + else + { + if(PETls32->AddressOfCallBacks != NULL) + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PETls32->AddressOfCallBacks + PEHeader32->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress != NULL) + { + while(ReadData != NULL) + { + RtlMoveMemory(&ReadData, (LPVOID)ConvertedAddress, 4); + if(ReadData < PEHeader32->OptionalHeader.ImageBase || ReadData > CorrectedImageSize + PEHeader32->OptionalHeader.ImageBase) + { + RtlZeroMemory((LPVOID)ConvertedAddress, 4); + } + ConvertedAddress = ConvertedAddress + 4; + } + } + } + } + } + } + } + } + /* + Fix Load config table + */ + if(myFileFixInfo->DontFixLoadConfig == false && myFileStatusInfo->LoadConfigTable != UE_FIELD_OK && myFileStatusInfo->LoadConfigTable != UE_FIELD_NOT_PRESET) + { + if(PEHeader32->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG && PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress != NULL) + { + if(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress > CorrectedImageSize || PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size > CorrectedImageSize) + { + myFileFixInfo->StrippedLoadConfig = true; + myFileFixInfo->OriginalLoadConfigTableAddress = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress; + myFileFixInfo->OriginalLoadConfigTableSize = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress = NULL; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size = NULL; + } + else + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress + PEHeader32->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress == NULL || ConvertedAddress - FileMapVA > FileSize) + { + myFileFixInfo->StrippedLoadConfig = true; + myFileFixInfo->OriginalLoadConfigTableAddress = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress; + myFileFixInfo->OriginalLoadConfigTableSize = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress = NULL; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size = NULL; + } + } + } + } + /* + Fix Bound import table + */ + if(myFileFixInfo->DontFixBoundImports == false && myFileStatusInfo->BoundImportTable != UE_FIELD_OK && myFileStatusInfo->BoundImportTable != UE_FIELD_NOT_PRESET) + { + if(PEHeader32->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT && PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress != NULL) + { + if(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress > CorrectedImageSize || PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size > CorrectedImageSize) + { + myFileFixInfo->StrippedBoundImports = true; + myFileFixInfo->OriginalBoundImportTableAddress = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress; + myFileFixInfo->OriginalBoundImportTableSize = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = NULL; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = NULL; + } + else + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress + PEHeader32->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress == NULL || ConvertedAddress - FileMapVA > FileSize) + { + myFileFixInfo->StrippedBoundImports = true; + myFileFixInfo->OriginalBoundImportTableAddress = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress; + myFileFixInfo->OriginalBoundImportTableSize = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = NULL; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = NULL; + } + } + } + } + /* + Fix IAT + */ + if(myFileFixInfo->DontFixIAT == false && myFileStatusInfo->IATTable != UE_FIELD_OK && myFileStatusInfo->IATTable != UE_FIELD_NOT_PRESET) + { + if(PEHeader32->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_IAT && PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress != NULL) + { + if(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress > CorrectedImageSize || PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size > CorrectedImageSize) + { + myFileFixInfo->StrippedIAT = true; + myFileFixInfo->OriginalImportAddressTableAddress = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress; + myFileFixInfo->OriginalImportAddressTableSize = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = NULL; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = NULL; + } + else + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress + PEHeader32->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress == NULL || ConvertedAddress - FileMapVA > FileSize) + { + myFileFixInfo->StrippedIAT = true; + myFileFixInfo->OriginalImportAddressTableAddress = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress; + myFileFixInfo->OriginalImportAddressTableSize = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = NULL; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = NULL; + } + } + } + } + /* + Fix COM header + */ + if(myFileFixInfo->DontFixCOM == false && myFileStatusInfo->COMHeaderTable != UE_FIELD_OK && myFileStatusInfo->COMHeaderTable != UE_FIELD_NOT_PRESET) + { + if(PEHeader32->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR && PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress != NULL) + { + if(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress > CorrectedImageSize || PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size > CorrectedImageSize) + { + myFileFixInfo->StrippedCOM = true; + myFileFixInfo->OriginalCOMTableAddress = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress; + myFileFixInfo->OriginalCOMTableSize = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = NULL; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size = NULL; + } + else + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress + PEHeader32->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress == NULL || ConvertedAddress - FileMapVA > FileSize) + { + myFileFixInfo->StrippedCOM = true; + myFileFixInfo->OriginalCOMTableAddress = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress; + myFileFixInfo->OriginalCOMTableSize = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = NULL; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size = NULL; + } + } + } + } + /* + Fix sections and SizeOfImage + */ + if(myFileStatusInfo->SectionTable != UE_FIELD_OK || myFileStatusInfo->SizeOfImage != UE_FIELD_OK) + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader32 + PEHeader32->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + NumberOfSections = PEHeader32->FileHeader.NumberOfSections; + while(NumberOfSections > NULL) + { + SectionVirtualSize = PESections->VirtualAddress + PESections->Misc.VirtualSize; + if(PESections->Misc.VirtualSize % PEHeader32->OptionalHeader.SectionAlignment == NULL) + { + SectionVirtualSizeFixed = SectionVirtualSize; + } + else + { + SectionVirtualSizeFixed = PESections->VirtualAddress + (((PESections->Misc.VirtualSize / PEHeader32->OptionalHeader.SectionAlignment) + 1) * PEHeader32->OptionalHeader.SectionAlignment); + } + if(NumberOfSections > 1) + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + sizeof IMAGE_SECTION_HEADER); + if(SectionVirtualSize > PESections->VirtualAddress || SectionVirtualSizeFixed > PESections->VirtualAddress) + { + PESections->Misc.VirtualSize = SectionVirtualSizeFixed; + } + } + NumberOfSections--; + } + if(PESections->PointerToRawData + PESections->SizeOfRawData > FileSize && PESections->SizeOfRawData != NULL) + { + PESections->SizeOfRawData = FileSize - PESections->PointerToRawData; + } + if(myFileStatusInfo->SizeOfImage != UE_FIELD_OK) + { + SectionVirtualSizeFixed = SectionVirtualSizeFixed + 0xF000; + if(PEHeader32->OptionalHeader.SizeOfImage > SectionVirtualSizeFixed) + { + PEHeader32->OptionalHeader.SizeOfImage = SectionVirtualSizeFixed - 0xF000; + } + } + } + /* + Entry point check + */ + if(myFileStatusInfo->EntryPoint != UE_FIELD_OK) + { + SectionNumber = GetPE32SectionNumberFromVA(FileMapVA, PEHeader32->OptionalHeader.AddressOfEntryPoint + (ULONG_PTR)PEHeader32->OptionalHeader.ImageBase); + if(SectionNumber != -1) + { + SectionAttributes = (DWORD)GetPE32DataFromMappedFile(FileMapVA, SectionNumber, UE_SECTIONFLAGS); + if(SectionAttributes & IMAGE_SCN_MEM_EXECUTE || SectionAttributes & IMAGE_SCN_CNT_CODE) + { + // Should never execute + } + else + { + if(!SetPE32DataForMappedFile(FileMapVA, SectionNumber, UE_SECTIONFLAGS, 0xE0000020)) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + } + } + /* + Fix end + */ + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + if(FileFixed) + { + myFileFixInfo->OveralEvaluation = UE_RESULT_FILE_OK; + myFileFixInfo->FileFixPerformed = FileFixed; + } + return(true); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + myFileFixInfo->FixingTerminatedByException = true; + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + else + { + /* + x64 Surface check + */ + __try + { + if(PEHeader64->OptionalHeader.SizeOfImage % PEHeader64->OptionalHeader.SectionAlignment == NULL) + { + CorrectedImageSize = (PEHeader64->OptionalHeader.SizeOfImage / PEHeader64->OptionalHeader.SectionAlignment) * PEHeader64->OptionalHeader.SectionAlignment; + } + else + { + CorrectedImageSize = ((PEHeader64->OptionalHeader.SizeOfImage / PEHeader64->OptionalHeader.SectionAlignment) + 1) * PEHeader64->OptionalHeader.SectionAlignment; + } + /* + Fixing import table + */ + if(myFileStatusInfo->MissingDeclaredAPIs) + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, false, true); + SectionNumber = GetPE32SectionNumberFromVA(FileMapVA, PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase); + if(SectionNumber >= NULL) + { + SectionAttributes = (DWORD)GetPE32DataFromMappedFile(FileMapVA, SectionNumber, UE_SECTIONFLAGS); + if(SectionAttributes & IMAGE_SCN_MEM_EXECUTE || SectionAttributes & IMAGE_SCN_CNT_CODE || SectionAttributes & IMAGE_SCN_MEM_WRITE || SectionAttributes & IMAGE_SCN_CNT_INITIALIZED_DATA) + { + // Should not execute! + } + else + { + if(!SetPE32DataForMappedFile(FileMapVA, SectionAttributes, UE_SECTIONFLAGS, 0xE0000020)) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + if(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress != NULL) + { + ImportIID = (PIMAGE_IMPORT_DESCRIPTOR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, (ULONG_PTR)(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase), false, true); + while(ImportIID->FirstThunk != NULL) + { + hLoadedModule = NULL; + ImportNamePtr = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, (ULONG_PTR)((ULONG_PTR)ImportIID->Name + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase), false, true); + if(ImportNamePtr != NULL) + { + if(!EngineIsDependencyPresent((char*)ImportNamePtr, NULL, NULL)) + { + hLoadedModuleSimulated = false; + } + else + { + hLoadedModuleSimulated = false; + hLoadedModule = GetModuleHandleA((char*)ImportNamePtr); + if(hLoadedModule == NULL) + { + hLoadedModule = (HMODULE)EngineSimulateDllLoader(GetCurrentProcess(), (char*)ImportNamePtr); + hLoadedModuleSimulated = true; + } + } + } + if(ImportIID->OriginalFirstThunk != NULL) + { + ThunkData64 = (PIMAGE_THUNK_DATA64)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, (ULONG_PTR)((ULONG_PTR)ImportIID->OriginalFirstThunk + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase), false, true); + CurrentThunk = (ULONG_PTR)ImportIID->OriginalFirstThunk; + } + else + { + ThunkData32 = (PIMAGE_THUNK_DATA32)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, (ULONG_PTR)PEHeader32->OptionalHeader.ImageBase, (ULONG_PTR)((ULONG_PTR)ImportIID->FirstThunk + PEHeader32->OptionalHeader.ImageBase), false, true); + CurrentThunk = (ULONG_PTR)ImportIID->FirstThunk; + } + if(ThunkData64 != NULL) + { + while(ThunkData64->u1.AddressOfData != NULL) + { + if(ThunkData64->u1.Ordinal & IMAGE_ORDINAL_FLAG64) + { + if((int)(ThunkData64->u1.Ordinal ^ IMAGE_ORDINAL_FLAG64) >= 0x10000) + { + FileFixed = false; + } + } + else + { + ImportNamePtr = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, (ULONG_PTR)((ULONG_PTR)ThunkData64->u1.AddressOfData + 2 + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase), false, true); + if(ImportNamePtr != NULL) + { + if(EngineIsBadReadPtrEx((LPVOID)ImportNamePtr, 8)) + { + if(hLoadedModule != NULL) + { + if(EngineGetProcAddress((ULONG_PTR)hLoadedModule, (char*)ImportNamePtr) == NULL) + { + OrdinalBase = NULL; + OrdinalCount = NULL; + if(EngineGetLibraryOrdinalData((ULONG_PTR)hLoadedModule, &OrdinalBase, &OrdinalCount)) + { + if(OrdinalBase != NULL && OrdinalCount != NULL) + { + ThunkData64->u1.Ordinal = (OrdinalBase + 1) ^ IMAGE_ORDINAL_FLAG64; + } + else + { + FileFixed = false; + } + } + } + } + } + } + } + CurrentThunk = CurrentThunk + 8; + ThunkData64 = (PIMAGE_THUNK_DATA64)((ULONG_PTR)ThunkData64 + sizeof IMAGE_THUNK_DATA64); + } + } + if(hLoadedModuleSimulated) + { + VirtualFree((LPVOID)hLoadedModule, NULL, MEM_RELEASE); + } + ImportIID = (PIMAGE_IMPORT_DESCRIPTOR)((ULONG_PTR)ImportIID + sizeof IMAGE_IMPORT_DESCRIPTOR); + } + } + } + } + /* + Fixing Export table + */ + if(myFileStatusInfo->ExportTable == UE_FIELD_NOT_PRESET_WARNING) + { + FileFixed = false; + } + else if(myFileFixInfo->DontFixExports == false && myFileStatusInfo->ExportTable != UE_FIELD_OK && myFileStatusInfo->ExportTable != UE_FIELD_NOT_PRESET) + { + if(PEHeader64->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_EXPORT && PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress != NULL) + { + if(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress > CorrectedImageSize || PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size > CorrectedImageSize) + { + myFileFixInfo->StrippedExports = true; + myFileFixInfo->OriginalExportTableAddress = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + myFileFixInfo->OriginalExportTableSize = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = NULL; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = NULL; + } + else + { + FeatureFixed = true; + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress != NULL) + { + if(EngineIsBadReadPtrEx((LPVOID)ConvertedAddress, PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)) + { + PEExports = (PIMAGE_EXPORT_DIRECTORY)ConvertedAddress; + if(PEExports->AddressOfFunctions > CorrectedImageSize || PEExports->AddressOfFunctions + 4 * PEExports->NumberOfFunctions > CorrectedImageSize) + { + FeatureFixed = false; + } + else if(PEExports->AddressOfNameOrdinals > CorrectedImageSize || PEExports->AddressOfNameOrdinals + 4 * PEExports->NumberOfNames > CorrectedImageSize) + { + FeatureFixed = false; + } + else if(PEExports->AddressOfNames > CorrectedImageSize || PEExports->AddressOfNames + 4 * PEExports->NumberOfNames > CorrectedImageSize) + { + FeatureFixed = false; + } + else if(PEExports->Name > CorrectedImageSize) + { + FeatureFixed = false; + } + if(!FeatureFixed) + { + myFileFixInfo->StrippedExports = true; + myFileFixInfo->OriginalExportTableAddress = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + myFileFixInfo->OriginalExportTableSize = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = NULL; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = NULL; + } + } + else + { + myFileFixInfo->StrippedExports = true; + myFileFixInfo->OriginalExportTableAddress = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + myFileFixInfo->OriginalExportTableSize = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = NULL; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = NULL; + } + } + } + } + } + /* + Fixing Relocation table + */ + if(myFileStatusInfo->FileIsDLL == true && myFileStatusInfo->RelocationTable == UE_FIELD_BROKEN_NON_FIXABLE) + { + FileFixed = false; + } + else if(myFileFixInfo->DontFixRelocations == false && myFileStatusInfo->RelocationTable != UE_FIELD_OK) + { + if(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress > CorrectedImageSize || PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size > CorrectedImageSize) + { + if(myFileStatusInfo->FileIsDLL) + { + FileFixed = false; + } + else + { + myFileFixInfo->StrippedRelocation = true; + myFileFixInfo->OriginalRelocationTableAddress = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress; + myFileFixInfo->OriginalRelocationTableSize = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = NULL; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = NULL; + } + } + else + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress != NULL) + { + if(EngineIsBadReadPtrEx((LPVOID)ConvertedAddress, PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size)) + { + RtlMoveMemory(&ReadData, (LPVOID)ConvertedAddress, 4); + RtlMoveMemory(&ReadSize, (LPVOID)(ConvertedAddress + 4), 4); + while(ReadData != NULL) + { + ReadSize = ReadSize - 8; + ConvertedAddress = ConvertedAddress + 8; + while(ReadSize > NULL) + { + RtlMoveMemory(&ReadDataWORD, (LPVOID)ConvertedAddress, 2); + if(ReadDataWORD > 0xCFFF) + { + RtlZeroMemory((LPVOID)ConvertedAddress, 2); + } + ConvertedAddress = ConvertedAddress + 2; + ReadSize = ReadSize - 2; + } + RtlMoveMemory(&ReadData, (LPVOID)ConvertedAddress, 4); + RtlMoveMemory(&ReadSize, (LPVOID)(ConvertedAddress + 4), 4); + } + } + else + { + if(myFileStatusInfo->FileIsDLL) + { + FileFixed = false; + } + else + { + myFileFixInfo->StrippedRelocation = true; + myFileFixInfo->OriginalRelocationTableAddress = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress; + myFileFixInfo->OriginalRelocationTableSize = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = NULL; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = NULL; + } + } + } + else + { + if(myFileStatusInfo->FileIsDLL) + { + FileFixed = false; + } + else + { + myFileFixInfo->StrippedRelocation = true; + myFileFixInfo->OriginalRelocationTableAddress = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress; + myFileFixInfo->OriginalRelocationTableSize = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = NULL; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = NULL; + } + } + } + } + else if(myFileStatusInfo->RelocationTable == UE_FIELD_OK) + { + // Filter case! + } + else + { + FileFixed = false; + } + /* + Fixing Resource table + */ + if(myFileFixInfo->DontFixResources == false && myFileStatusInfo->ResourceData != UE_FIELD_OK && myFileStatusInfo->ResourceData != UE_FIELD_NOT_PRESET) + { + myFileFixInfo->StrippedResources = true; + myFileFixInfo->OriginalResourceTableAddress = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress; + myFileFixInfo->OriginalResourceTableSize = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = NULL; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = NULL; + } + else if(myFileFixInfo->DontFixResources == false && myFileStatusInfo->ResourceTable != UE_FIELD_OK && myFileStatusInfo->ResourceTable != UE_FIELD_NOT_PRESET) + { + if(PEHeader64->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_RESOURCE && PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress != NULL) + { + if(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress > CorrectedImageSize || PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size > CorrectedImageSize) + { + myFileFixInfo->StrippedResources = true; + myFileFixInfo->OriginalResourceTableAddress = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress; + myFileFixInfo->OriginalResourceTableSize = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = NULL; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = NULL; + } + else + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress == NULL || ConvertedAddress - FileMapVA > FileSize || ConvertedAddress - FileMapVA + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size > FileSize) + { + myFileFixInfo->StrippedResources = true; + myFileFixInfo->OriginalResourceTableAddress = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress; + myFileFixInfo->OriginalResourceTableSize = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = NULL; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = NULL; + } + } + } + } + /* + Fixing TLS table + */ + if(myFileFixInfo->DontFixTLS == false && myFileStatusInfo->TLSTable != UE_FIELD_OK && myFileStatusInfo->TLSTable != UE_FIELD_NOT_PRESET) + { + if(PEHeader64->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_TLS && PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress != NULL) + { + if(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress > CorrectedImageSize || PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size > CorrectedImageSize) + { + myFileFixInfo->StrippedTLS = true; + myFileFixInfo->OriginalTLSTableAddress = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress; + myFileFixInfo->OriginalTLSTableSize = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress = NULL; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size = NULL; + } + else + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress == NULL || ConvertedAddress - FileMapVA > FileSize) + { + myFileFixInfo->StrippedTLS = true; + myFileFixInfo->OriginalTLSTableAddress = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress; + myFileFixInfo->OriginalTLSTableSize = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress = NULL; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size = NULL; + } + else + { + FeatureFixed = true; + PETls64 = (PIMAGE_TLS_DIRECTORY64)ConvertedAddress; + if(PETls64->StartAddressOfRawData != NULL && (PETls64->StartAddressOfRawData < (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase || PETls64->StartAddressOfRawData > CorrectedImageSize + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase)) + { + FeatureFixed = false; + } + else if(PETls64->EndAddressOfRawData != NULL && (PETls64->EndAddressOfRawData < (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase || PETls64->EndAddressOfRawData > CorrectedImageSize + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase)) + { + FeatureFixed = false; + } + else if(PETls64->AddressOfIndex != NULL && (PETls64->AddressOfIndex < (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase || PETls64->AddressOfIndex > CorrectedImageSize + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase)) + { + FeatureFixed = false; + } + else if(PETls64->AddressOfCallBacks != NULL && (PETls64->AddressOfCallBacks < (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase || PETls64->AddressOfCallBacks > CorrectedImageSize + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase)) + { + FeatureFixed = false; + } + if(!FeatureFixed) + { + myFileFixInfo->StrippedTLS = true; + myFileFixInfo->OriginalTLSTableAddress = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress; + myFileFixInfo->OriginalTLSTableSize = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress = NULL; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size = NULL; + } + else + { + if(PETls64->AddressOfCallBacks != NULL) + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, (ULONG_PTR)PETls64->AddressOfCallBacks + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress != NULL) + { + while(ReadData != NULL) + { + RtlMoveMemory(&ReadDataQWORD, (LPVOID)ConvertedAddress, 8); + if(ReadDataQWORD < (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase || ReadDataQWORD > CorrectedImageSize + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase) + { + RtlZeroMemory((LPVOID)ConvertedAddress, 8); + } + ConvertedAddress = ConvertedAddress + 8; + } + } + } + } + } + } + } + } + /* + Fix Load config table + */ + if(myFileFixInfo->DontFixLoadConfig == false && myFileStatusInfo->LoadConfigTable != UE_FIELD_OK && myFileStatusInfo->LoadConfigTable != UE_FIELD_NOT_PRESET) + { + if(PEHeader64->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG && PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress != NULL) + { + if(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress > CorrectedImageSize || PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size > CorrectedImageSize) + { + myFileFixInfo->StrippedLoadConfig = true; + myFileFixInfo->OriginalLoadConfigTableAddress = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress; + myFileFixInfo->OriginalLoadConfigTableSize = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress = NULL; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size = NULL; + } + else + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress == NULL || ConvertedAddress - FileMapVA > FileSize) + { + myFileFixInfo->StrippedLoadConfig = true; + myFileFixInfo->OriginalLoadConfigTableAddress = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress; + myFileFixInfo->OriginalLoadConfigTableSize = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress = NULL; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size = NULL; + } + } + } + } + /* + Fix Bound import table + */ + if(myFileFixInfo->DontFixBoundImports == false && myFileStatusInfo->BoundImportTable != UE_FIELD_OK && myFileStatusInfo->BoundImportTable != UE_FIELD_NOT_PRESET) + { + if(PEHeader64->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT && PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress != NULL) + { + if(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress > CorrectedImageSize || PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size > CorrectedImageSize) + { + myFileFixInfo->StrippedBoundImports = true; + myFileFixInfo->OriginalBoundImportTableAddress = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress; + myFileFixInfo->OriginalBoundImportTableSize = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = NULL; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = NULL; + } + else + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress == NULL || ConvertedAddress - FileMapVA > FileSize) + { + myFileFixInfo->StrippedBoundImports = true; + myFileFixInfo->OriginalBoundImportTableAddress = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress; + myFileFixInfo->OriginalBoundImportTableSize = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = NULL; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = NULL; + } + } + } + } + /* + Fix IAT + */ + if(myFileFixInfo->DontFixIAT == false && myFileStatusInfo->IATTable != UE_FIELD_OK && myFileStatusInfo->IATTable != UE_FIELD_NOT_PRESET) + { + if(PEHeader64->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_IAT && PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress != NULL) + { + if(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress > CorrectedImageSize || PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size > CorrectedImageSize) + { + myFileFixInfo->StrippedIAT = true; + myFileFixInfo->OriginalImportAddressTableAddress = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress; + myFileFixInfo->OriginalImportAddressTableSize = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = NULL; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = NULL; + } + else + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress == NULL || ConvertedAddress - FileMapVA > FileSize) + { + myFileFixInfo->StrippedIAT = true; + myFileFixInfo->OriginalImportAddressTableAddress = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress; + myFileFixInfo->OriginalImportAddressTableSize = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = NULL; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = NULL; + } + } + } + } + /* + Fix COM header + */ + if(myFileFixInfo->DontFixCOM == false && myFileStatusInfo->COMHeaderTable != UE_FIELD_OK && myFileStatusInfo->COMHeaderTable != UE_FIELD_NOT_PRESET) + { + if(PEHeader64->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR && PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress != NULL) + { + if(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress > CorrectedImageSize || PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size > CorrectedImageSize) + { + myFileFixInfo->StrippedCOM = true; + myFileFixInfo->OriginalCOMTableAddress = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress; + myFileFixInfo->OriginalCOMTableSize = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = NULL; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size = NULL; + } + else + { + ConvertedAddress = (ULONG_PTR)ConvertVAtoFileOffsetEx(FileMapVA, FileSize, NULL, PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, false, true); + if(ConvertedAddress == NULL || ConvertedAddress - FileMapVA > FileSize) + { + myFileFixInfo->StrippedCOM = true; + myFileFixInfo->OriginalCOMTableAddress = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress; + myFileFixInfo->OriginalCOMTableSize = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = NULL; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size = NULL; + } + } + } + } + /* + Fix sections and SizeOfImage + */ + if(myFileStatusInfo->SectionTable != UE_FIELD_OK || myFileStatusInfo->SizeOfImage != UE_FIELD_OK) + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader64 + PEHeader64->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + NumberOfSections = PEHeader64->FileHeader.NumberOfSections; + while(NumberOfSections > NULL) + { + SectionVirtualSize = PESections->VirtualAddress + PESections->Misc.VirtualSize; + if(PESections->Misc.VirtualSize % PEHeader64->OptionalHeader.SectionAlignment == NULL) + { + SectionVirtualSizeFixed = SectionVirtualSize; + } + else + { + SectionVirtualSizeFixed = PESections->VirtualAddress + (((PESections->Misc.VirtualSize / PEHeader64->OptionalHeader.SectionAlignment) + 1) * PEHeader64->OptionalHeader.SectionAlignment); + } + if(NumberOfSections > 1) + { + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + sizeof IMAGE_SECTION_HEADER); + if(SectionVirtualSize > PESections->VirtualAddress || SectionVirtualSizeFixed > PESections->VirtualAddress) + { + PESections->Misc.VirtualSize = SectionVirtualSizeFixed; + } + } + NumberOfSections--; + } + if(PESections->PointerToRawData + PESections->SizeOfRawData > FileSize && PESections->SizeOfRawData != NULL) + { + PESections->SizeOfRawData = FileSize - PESections->PointerToRawData; + } + if(myFileStatusInfo->SizeOfImage != UE_FIELD_OK) + { + SectionVirtualSizeFixed = SectionVirtualSizeFixed + 0xF000; + if(PEHeader64->OptionalHeader.SizeOfImage > SectionVirtualSizeFixed) + { + PEHeader64->OptionalHeader.SizeOfImage = SectionVirtualSizeFixed - 0xF000; + } + } + } + /* + Entry point check + */ + if(myFileStatusInfo->EntryPoint != UE_FIELD_OK) + { + SectionNumber = GetPE32SectionNumberFromVA(FileMapVA, PEHeader64->OptionalHeader.AddressOfEntryPoint + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase); + if(SectionNumber != -1) + { + SectionAttributes = (DWORD)GetPE32DataFromMappedFile(FileMapVA, SectionNumber, UE_SECTIONFLAGS); + if(SectionAttributes & IMAGE_SCN_MEM_EXECUTE || SectionAttributes & IMAGE_SCN_CNT_CODE) + { + // Should never execute + } + else + { + if(!SetPE32DataForMappedFile(FileMapVA, SectionNumber, UE_SECTIONFLAGS, 0xE0000020)) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + } + } + /* + Fix end + */ + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + if(FileFixed) + { + myFileFixInfo->OveralEvaluation = UE_RESULT_FILE_OK; + myFileFixInfo->FileFixPerformed = FileFixed; + } + return(true); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + myFileFixInfo->FixingTerminatedByException = true; + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + } + else if(myFileFixInfo->FileFixPerformed) + { + if(MapFileExW(szFileName, UE_ACCESS_ALL, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, FileHandle, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->Signature == 0x4550 && PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->Signature == 0x4550 && PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + if(!FileIs64) + { + if(myFileFixInfo->StrippedRelocation) + { + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = myFileFixInfo->OriginalRelocationTableAddress; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = myFileFixInfo->OriginalRelocationTableSize; + } + if(myFileFixInfo->StrippedExports) + { + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = myFileFixInfo->OriginalExportTableAddress; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = myFileFixInfo->OriginalExportTableSize; + } + if(myFileFixInfo->StrippedResources) + { + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = myFileFixInfo->OriginalResourceTableAddress; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = myFileFixInfo->OriginalResourceTableSize; + } + if(myFileFixInfo->StrippedTLS) + { + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress = myFileFixInfo->OriginalTLSTableAddress; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size = myFileFixInfo->OriginalTLSTableSize; + } + if(myFileFixInfo->StrippedLoadConfig) + { + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress = myFileFixInfo->OriginalLoadConfigTableAddress; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size = myFileFixInfo->OriginalLoadConfigTableSize; + } + if(myFileFixInfo->StrippedBoundImports) + { + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = myFileFixInfo->OriginalBoundImportTableAddress; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = myFileFixInfo->OriginalBoundImportTableSize; + } + if(myFileFixInfo->StrippedIAT) + { + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = myFileFixInfo->OriginalImportAddressTableAddress; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = myFileFixInfo->OriginalImportAddressTableSize; + } + if(myFileFixInfo->StrippedCOM) + { + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = myFileFixInfo->OriginalCOMTableAddress; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size = myFileFixInfo->OriginalCOMTableSize; + } + } + else + { + if(myFileFixInfo->StrippedRelocation) + { + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = myFileFixInfo->OriginalRelocationTableAddress; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = myFileFixInfo->OriginalRelocationTableSize; + } + if(myFileFixInfo->StrippedExports) + { + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = myFileFixInfo->OriginalExportTableAddress; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = myFileFixInfo->OriginalExportTableSize; + } + if(myFileFixInfo->StrippedResources) + { + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = myFileFixInfo->OriginalResourceTableAddress; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = myFileFixInfo->OriginalResourceTableSize; + } + if(myFileFixInfo->StrippedTLS) + { + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress = myFileFixInfo->OriginalTLSTableAddress; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size = myFileFixInfo->OriginalTLSTableSize; + } + if(myFileFixInfo->StrippedLoadConfig) + { + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress = myFileFixInfo->OriginalLoadConfigTableAddress; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size = myFileFixInfo->OriginalLoadConfigTableSize; + } + if(myFileFixInfo->StrippedBoundImports) + { + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = myFileFixInfo->OriginalBoundImportTableAddress; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = myFileFixInfo->OriginalBoundImportTableSize; + } + if(myFileFixInfo->StrippedIAT) + { + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = myFileFixInfo->OriginalImportAddressTableAddress; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = myFileFixInfo->OriginalImportAddressTableSize; + } + if(myFileFixInfo->StrippedCOM) + { + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = myFileFixInfo->OriginalCOMTableAddress; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size = myFileFixInfo->OriginalCOMTableSize; + } + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(true); + } + } + } + return(false); +} +__declspec(dllexport) bool __stdcall IsFileDLL(char* szFileName, ULONG_PTR FileMapVA) +{ + + if(szFileName != NULL) + { + if((DWORD)GetPE32Data(szFileName, NULL, UE_CHARACTERISTICS) & 0x2000) + { + return(true); + } + } + else if(FileMapVA != NULL) + { + if((DWORD)GetPE32DataFromMappedFile(FileMapVA, NULL, UE_CHARACTERISTICS) & 0x2000) + { + return(true); + } + } + return(false); +} +__declspec(dllexport) bool __stdcall IsFileDLLW(wchar_t* szFileName, ULONG_PTR FileMapVA) +{ + + if(szFileName != NULL) + { + if((DWORD)GetPE32DataW(szFileName, NULL, UE_CHARACTERISTICS) & 0x2000) + { + return(true); + } + } + else if(FileMapVA != NULL) + { + if((DWORD)GetPE32DataFromMappedFile(FileMapVA, NULL, UE_CHARACTERISTICS) & 0x2000) + { + return(true); + } + } + return(false); +} +// Global.Engine.Hider.functions: +bool ChangeHideDebuggerState(HANDLE hProcess, DWORD PatchAPILevel, bool Hide) +{ + + ULONG_PTR AddressOfPEB = NULL; + ULONG_PTR ueNumberOfBytesRead = NULL; + BYTE patchCheckRemoteDebuggerPresent[5] = {0x33, 0xC0, 0xC2, 0x08, 0x00}; + BYTE patchGetTickCount[3] = {0x33, 0xC0, 0xC3}; + MEMORY_BASIC_INFORMATION MemInfo; + ULONG_PTR APIPatchAddress = NULL; + DWORD OldProtect; + NTPEB myPEB = {}; + + if(hProcess != NULL) + { + AddressOfPEB = (ULONG_PTR)GetPEBLocation(hProcess); + if(ReadProcessMemory(hProcess, (void*)AddressOfPEB, (void*)&myPEB, sizeof NTPEB, &ueNumberOfBytesRead)) + { + if(Hide) + { + myPEB.BeingDebugged = false; + myPEB.NtGlobalFlag = NULL; + if(WriteProcessMemory(hProcess, (void*)AddressOfPEB, (void*)&myPEB, sizeof NTPEB, &ueNumberOfBytesRead)) + { + if(PatchAPILevel >= 1) + { + APIPatchAddress = (ULONG_PTR)EngineGlobalAPIHandler(hProcess, NULL, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"),"CheckRemoteDebuggerPresent"), NULL, UE_OPTION_IMPORTER_REALIGN_APIADDRESS); + VirtualQueryEx(dbgProcessInformation.hProcess, (LPVOID)APIPatchAddress, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + OldProtect = MemInfo.AllocationProtect; + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)APIPatchAddress, 5, PAGE_EXECUTE_READWRITE, &OldProtect); + WriteProcessMemory(hProcess, (LPVOID)(APIPatchAddress), &patchCheckRemoteDebuggerPresent, 5, &ueNumberOfBytesRead); + + APIPatchAddress = (ULONG_PTR)EngineGlobalAPIHandler(hProcess, NULL, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"),"GetTickCount"), NULL, UE_OPTION_IMPORTER_REALIGN_APIADDRESS); + VirtualQueryEx(dbgProcessInformation.hProcess, (LPVOID)APIPatchAddress, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + OldProtect = MemInfo.AllocationProtect; + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)APIPatchAddress, 3, PAGE_EXECUTE_READWRITE, &OldProtect); + WriteProcessMemory(hProcess, (LPVOID)(APIPatchAddress), &patchGetTickCount, 3, &ueNumberOfBytesRead); + } + return(true); + } + else + { + return(false); + } + } + else + { + myPEB.BeingDebugged = true; + if(WriteProcessMemory(hProcess, (void*)AddressOfPEB, (void*)&myPEB, sizeof NTPEB, &ueNumberOfBytesRead)) + { + if(PatchAPILevel >= 1) + { + APIPatchAddress = (ULONG_PTR)EngineGlobalAPIHandler(hProcess, NULL, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"),"CheckRemoteDebuggerPresent"), NULL, UE_OPTION_IMPORTER_REALIGN_APIADDRESS); + VirtualQueryEx(dbgProcessInformation.hProcess, (LPVOID)APIPatchAddress, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + OldProtect = MemInfo.AllocationProtect; + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)APIPatchAddress, 5, PAGE_EXECUTE_READWRITE, &OldProtect); + WriteProcessMemory(hProcess, (LPVOID)(APIPatchAddress), (void*)GetProcAddress(GetModuleHandleA("kernel32.dll"),"CheckRemoteDebuggerPresent"), 5, &ueNumberOfBytesRead); + + APIPatchAddress = (ULONG_PTR)EngineGlobalAPIHandler(hProcess, NULL, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"),"GetTickCount"), NULL, UE_OPTION_IMPORTER_REALIGN_APIADDRESS); + VirtualQueryEx(dbgProcessInformation.hProcess, (LPVOID)APIPatchAddress, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + OldProtect = MemInfo.AllocationProtect; + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)APIPatchAddress, 3, PAGE_EXECUTE_READWRITE, &OldProtect); + WriteProcessMemory(hProcess, (LPVOID)(APIPatchAddress), (void*)GetProcAddress(GetModuleHandleA("kernel32.dll"),"GetTickCount"), 3, &ueNumberOfBytesRead); + } + return(true); + } + else + { + return(false); + } + } + } + else + { + return(false); + } + } + else + { + return(false); + } + return(false); +} +// TitanEngine.Hider.functions: +__declspec(dllexport) void* __stdcall GetPEBLocation(HANDLE hProcess) +{ + + ULONG RequiredLen = NULL; + PPROCESS_BASIC_INFORMATION myProcessBasicInformation = (PPROCESS_BASIC_INFORMATION)VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE); +#if !defined(_WIN64) + typedef NTSTATUS(__stdcall *fZwQueryInformationProcess)(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength); +#else + typedef NTSTATUS(__fastcall *fZwQueryInformationProcess)(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength); +#endif + LPVOID ZwQueryInformationProcess = (LPVOID)GetProcAddress(GetModuleHandleA("ntdll.dll"),"ZwQueryInformationProcess"); + fZwQueryInformationProcess cZwQueryInformationProcess = (fZwQueryInformationProcess)(ZwQueryInformationProcess); + + if(cZwQueryInformationProcess != NULL) + { + if(cZwQueryInformationProcess(hProcess, ProcessBasicInformation, myProcessBasicInformation, sizeof PROCESS_BASIC_INFORMATION, &RequiredLen) == STATUS_SUCCESS) + { + return((void*)myProcessBasicInformation->PebBaseAddress); + } + else + { + if(cZwQueryInformationProcess(hProcess, ProcessBasicInformation, myProcessBasicInformation, RequiredLen, &RequiredLen) == STATUS_SUCCESS) + { + return((void*)myProcessBasicInformation->PebBaseAddress); + } + } + } + return(NULL); +} +__declspec(dllexport) bool __stdcall HideDebugger(HANDLE hProcess, DWORD PatchAPILevel) +{ + return(ChangeHideDebuggerState(hProcess, PatchAPILevel, true)); +} +__declspec(dllexport) bool __stdcall UnHideDebugger(HANDLE hProcess, DWORD PatchAPILevel) +{ + return(ChangeHideDebuggerState(hProcess, PatchAPILevel, false)); +} +// TitanEngine.Relocater.functions: +__declspec(dllexport) void __stdcall RelocaterCleanup() +{ + + if(RelocationData != NULL) + { + VirtualFree(RelocationData, NULL, MEM_RELEASE); + RelocationLastPage = NULL; + RelocationStartPosition = NULL; + RelocationWritePosition = NULL; + RelocationOldImageBase = NULL; + RelocationNewImageBase = NULL; + } +} +__declspec(dllexport) void __stdcall RelocaterInit(DWORD MemorySize, ULONG_PTR OldImageBase, ULONG_PTR NewImageBase) +{ + + if(RelocationData != NULL) + { + VirtualFree(RelocationData, NULL, MEM_RELEASE); + } + RelocationData = VirtualAlloc(NULL, MemorySize, MEM_COMMIT, PAGE_READWRITE); + RelocationLastPage = NULL; + RelocationStartPosition = RelocationData; + RelocationWritePosition = (LPVOID)((ULONG_PTR)RelocationData + 8); + RelocationOldImageBase = OldImageBase; + RelocationNewImageBase = NewImageBase; +} +__declspec(dllexport) void __stdcall RelocaterAddNewRelocation(HANDLE hProcess, ULONG_PTR RelocateAddress, DWORD RelocateState) +{ + + MEMORY_BASIC_INFORMATION MemInfo; + DWORD CompareDummy = NULL; + DWORD CopyDummy = NULL; + + VirtualQueryEx(hProcess, (LPVOID)RelocateAddress, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + if(MemInfo.BaseAddress != RelocationLastPage || RelocationLastPage == NULL) + { + RelocationLastPage = MemInfo.BaseAddress; + if(memcmp(RelocationStartPosition, &CompareDummy, 4) == NULL) + { + CopyDummy = (DWORD)((ULONG_PTR)MemInfo.BaseAddress - (ULONG_PTR)RelocationNewImageBase); + RtlMoveMemory(RelocationStartPosition, &CopyDummy, 4); + } + else + { + CopyDummy = (DWORD)((ULONG_PTR)RelocationWritePosition - (ULONG_PTR)RelocationStartPosition); + if(CopyDummy % 4 == NULL) + { + RtlMoveMemory((LPVOID)((ULONG_PTR)RelocationStartPosition + 4), &CopyDummy, 4); + } + else + { + RelocationWritePosition = (LPVOID)((ULONG_PTR)RelocationWritePosition + 2); + CopyDummy = (DWORD)((ULONG_PTR)RelocationWritePosition - (ULONG_PTR)RelocationStartPosition); + if(CopyDummy % 4 == NULL) + { + RtlMoveMemory((LPVOID)((ULONG_PTR)RelocationStartPosition + 4), &CopyDummy, 4); + } + else + { + RelocationWritePosition = (LPVOID)((ULONG_PTR)RelocationWritePosition + 2); + CopyDummy = (DWORD)((ULONG_PTR)RelocationWritePosition - (ULONG_PTR)RelocationStartPosition); + RtlMoveMemory((LPVOID)((ULONG_PTR)RelocationStartPosition + 4), &CopyDummy, 4); + } + } + RelocationStartPosition = RelocationWritePosition; + CopyDummy = (DWORD)((ULONG_PTR)RelocationLastPage - (ULONG_PTR)RelocationNewImageBase); + RtlMoveMemory(RelocationWritePosition, &CopyDummy, 4); + RelocationWritePosition = (LPVOID)((ULONG_PTR)RelocationWritePosition + 8); + } + } +#if !defined(_WIN64) + CopyDummy = (DWORD)((RelocateAddress - (ULONG_PTR)RelocationLastPage) ^ 0x3000); +#else + CopyDummy = (DWORD)((RelocateAddress - (ULONG_PTR)RelocationLastPage) ^ 0x8000); +#endif + RtlMoveMemory(RelocationWritePosition, &CopyDummy, 2); + RelocationWritePosition = (LPVOID)((ULONG_PTR)RelocationWritePosition + 2); +} +__declspec(dllexport) long __stdcall RelocaterEstimatedSize() +{ + return((DWORD)((ULONG_PTR)RelocationWritePosition - (ULONG_PTR)RelocationData + 8)); +} +__declspec(dllexport) bool __stdcall RelocaterExportRelocation(ULONG_PTR StorePlace, DWORD StorePlaceRVA, ULONG_PTR FileMapVA) +{ + + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + BOOL FileIs64 = false; + DWORD CopyDummy = NULL; + + __try + { + if((ULONG_PTR)RelocationStartPosition != -1) + { + CopyDummy = (DWORD)((ULONG_PTR)RelocationWritePosition - (ULONG_PTR)RelocationStartPosition); + if(CopyDummy % 4 == NULL) + { + RtlMoveMemory((LPVOID)((ULONG_PTR)RelocationStartPosition + 4), &CopyDummy, 4); + } + else + { + RelocationWritePosition = (LPVOID)((ULONG_PTR)RelocationWritePosition + 2); + CopyDummy = (DWORD)((ULONG_PTR)RelocationWritePosition - (ULONG_PTR)RelocationStartPosition); + if(CopyDummy % 4 == NULL) + { + RtlMoveMemory((LPVOID)((ULONG_PTR)RelocationStartPosition + 4), &CopyDummy, 4); + } + else + { + RelocationWritePosition = (LPVOID)((ULONG_PTR)RelocationWritePosition + 2); + CopyDummy = (DWORD)((ULONG_PTR)RelocationWritePosition - (ULONG_PTR)RelocationStartPosition); + RtlMoveMemory((LPVOID)((ULONG_PTR)RelocationStartPosition + 4), &CopyDummy, 4); + } + } + } + RtlMoveMemory((LPVOID)StorePlace, RelocationData, (DWORD)((ULONG_PTR)RelocationWritePosition - (ULONG_PTR)RelocationData)); + VirtualFree(RelocationData, NULL, MEM_RELEASE); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return(false); + } + + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, NULL, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + RelocationData = NULL; + return(false); + } + if(!FileIs64) + { + PEHeader32->OptionalHeader.ImageBase = (DWORD)RelocationNewImageBase; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = StorePlaceRVA; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = (DWORD)((ULONG_PTR)RelocationWritePosition - (ULONG_PTR)RelocationData); + } + else + { + PEHeader64->OptionalHeader.ImageBase = (ULONG_PTR)RelocationNewImageBase; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = StorePlaceRVA; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = (DWORD)((ULONG_PTR)RelocationWritePosition - (ULONG_PTR)RelocationData); + } + RelocationData = NULL; + return(true); + } + RelocationData = NULL; + return(false); +} +__declspec(dllexport) bool __stdcall RelocaterExportRelocationEx(char* szFileName, char* szSectionName) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + + if(szFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + return(RelocaterExportRelocationExW(uniFileName, szSectionName)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall RelocaterExportRelocationExW(wchar_t* szFileName, char* szSectionName) +{ + + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + DWORD NewSectionVO = NULL; + DWORD NewSectionFO = NULL; + bool ReturnValue = false; + + if(RelocaterEstimatedSize() > NULL) + { + NewSectionVO = AddNewSectionW(szFileName, szSectionName, RelocaterEstimatedSize()); + if(MapFileExW(szFileName, UE_ACCESS_ALL, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + NewSectionFO = (DWORD)ConvertVAtoFileOffset(FileMapVA, NewSectionVO + (ULONG_PTR)GetPE32DataFromMappedFile(FileMapVA, NULL, UE_IMAGEBASE), true); + ReturnValue = RelocaterExportRelocation(NewSectionFO, NewSectionVO, FileMapVA); + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + if(ReturnValue) + { + return(true); + } + else + { + return(false); + } + } + else + { + return(false); + } + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall RelocaterGrabRelocationTable(HANDLE hProcess, ULONG_PTR MemoryStart, DWORD MemorySize) +{ + + MEMORY_BASIC_INFORMATION MemInfo; + ULONG_PTR ueNumberOfBytesRead = NULL; + DWORD OldProtect; + + if(RelocationData != NULL) + { + VirtualQueryEx(hProcess, (LPVOID)MemoryStart, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + OldProtect = MemInfo.AllocationProtect; + VirtualProtectEx(hProcess, (LPVOID)MemoryStart, MemorySize, PAGE_EXECUTE_READWRITE, &OldProtect); + if(ReadProcessMemory(hProcess, (LPVOID)MemoryStart, RelocationData, MemorySize, &ueNumberOfBytesRead)) + { + RelocationWritePosition = (LPVOID)((ULONG_PTR)RelocationData + MemorySize); + RelocationStartPosition = (LPVOID)(-1); + return(true); + } + } + return(false); +} +__declspec(dllexport) bool __stdcall RelocaterGrabRelocationTableEx(HANDLE hProcess, ULONG_PTR MemoryStart, ULONG_PTR MemorySize, DWORD NtSizeOfImage) +{ + + MEMORY_BASIC_INFORMATION MemInfo; + LPVOID ReadMemoryStorage = NULL; + LPVOID mReadMemoryStorage = NULL; + ULONG_PTR ueNumberOfBytesRead = NULL; + DWORD CompareDummy = NULL; + DWORD RelocationBase = NULL; + DWORD RelocationSize = NULL; + DWORD OldProtect; + + if(RelocationData != NULL) + { + VirtualQueryEx(hProcess, (LPVOID)MemoryStart, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + OldProtect = MemInfo.AllocationProtect; + VirtualQueryEx(hProcess, (LPVOID)MemInfo.BaseAddress, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + if(MemInfo.RegionSize < MemorySize || MemorySize == NULL) + { + MemorySize = MemInfo.RegionSize; + } + VirtualProtectEx(hProcess, (LPVOID)MemoryStart, MemorySize, PAGE_EXECUTE_READWRITE, &OldProtect); + ReadMemoryStorage = VirtualAlloc(NULL, MemorySize, MEM_COMMIT, PAGE_READWRITE); + mReadMemoryStorage = ReadMemoryStorage; + if(ReadProcessMemory(hProcess, (LPVOID)MemoryStart, ReadMemoryStorage, MemorySize, &ueNumberOfBytesRead)) + { + RtlMoveMemory(&RelocationBase, ReadMemoryStorage, 4); + RtlMoveMemory(&RelocationSize, (LPVOID)((ULONG_PTR)ReadMemoryStorage + 4), 4); + while(memcmp(ReadMemoryStorage, &CompareDummy, 4) != NULL && RelocationBase < NtSizeOfImage && RelocationSize < 0x2000) + { + ReadMemoryStorage = (LPVOID)((ULONG_PTR)ReadMemoryStorage + RelocationSize); + RtlMoveMemory(&RelocationBase, ReadMemoryStorage, 4); + RtlMoveMemory(&RelocationSize, (LPVOID)((ULONG_PTR)ReadMemoryStorage + 4), 4); + } + VirtualFree(mReadMemoryStorage, NULL, MEM_RELEASE); + return(RelocaterGrabRelocationTable(hProcess, MemoryStart, (DWORD)((ULONG_PTR)ReadMemoryStorage - (ULONG_PTR)mReadMemoryStorage))); + } + else + { + VirtualFree(ReadMemoryStorage, NULL, MEM_RELEASE); + return(false); + } + } + return(false); +} + +__declspec(dllexport) bool __stdcall RelocaterMakeSnapshot(HANDLE hProcess, char* szSaveFileName, LPVOID MemoryStart, ULONG_PTR MemorySize) +{ + return(DumpMemory(hProcess, MemoryStart, MemorySize, szSaveFileName)); +} +__declspec(dllexport) bool __stdcall RelocaterMakeSnapshotW(HANDLE hProcess, wchar_t* szSaveFileName, LPVOID MemoryStart, ULONG_PTR MemorySize) +{ + return(DumpMemoryW(hProcess, MemoryStart, MemorySize, szSaveFileName)); +} +__declspec(dllexport) bool __stdcall RelocaterCompareTwoSnapshots(HANDLE hProcess, ULONG_PTR LoadedImageBase, ULONG_PTR NtSizeOfImage, char* szDumpFile1, char* szDumpFile2, ULONG_PTR MemStart) +{ + + wchar_t uniDumpFile1[MAX_PATH] = {}; + wchar_t uniDumpFile2[MAX_PATH] = {}; + + if(szDumpFile1 != NULL && szDumpFile2 != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szDumpFile1, lstrlenA(szDumpFile1)+1, uniDumpFile1, sizeof(uniDumpFile1)/(sizeof(uniDumpFile1[0]))); + MultiByteToWideChar(CP_ACP, NULL, szDumpFile2, lstrlenA(szDumpFile2)+1, uniDumpFile2, sizeof(uniDumpFile2)/(sizeof(uniDumpFile2[0]))); + return(RelocaterCompareTwoSnapshotsW(hProcess, LoadedImageBase, NtSizeOfImage, uniDumpFile1, uniDumpFile2, MemStart)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall RelocaterCompareTwoSnapshotsW(HANDLE hProcess, ULONG_PTR LoadedImageBase, ULONG_PTR NtSizeOfImage, wchar_t* szDumpFile1, wchar_t* szDumpFile2, ULONG_PTR MemStart) +{ + + int i = NULL; + ULONG_PTR DeltaByte = NULL; + int RelativeBase = NULL; + ULONG_PTR ReadData = NULL; + HANDLE FileHandle1; + DWORD FileSize1; + HANDLE FileMap1; + ULONG_PTR FileMapVA1; + HANDLE FileHandle2; + DWORD FileSize2; + HANDLE FileMap2; + ULONG_PTR FileMapVA2; + DWORD SearchSize; + LPVOID Search1; + LPVOID Search2; + DWORD bkSearchSize; + LPVOID bkSearch1; + LPVOID bkSearch2; + + if(MapFileExW(szDumpFile1, UE_ACCESS_READ, &FileHandle1, &FileSize1, &FileMap1, &FileMapVA1, NULL)) + { + if(MapFileExW(szDumpFile2, UE_ACCESS_READ, &FileHandle2, &FileSize2, &FileMap2, &FileMapVA2, NULL)) + { + if(RelocationOldImageBase != NULL && RelocationNewImageBase != NULL && RelocationOldImageBase != RelocationNewImageBase) + { + __try + { + if(RelocationOldImageBase > RelocationNewImageBase) + { + DeltaByte = (ULONG_PTR)((ULONG_PTR)RelocationOldImageBase - (ULONG_PTR)RelocationNewImageBase); + } + else + { + DeltaByte = (ULONG_PTR)((ULONG_PTR)RelocationNewImageBase - (ULONG_PTR)RelocationOldImageBase); + } + while((BYTE)DeltaByte == NULL) + { + DeltaByte = DeltaByte / 0x10; + i++; + } + DeltaByte = i - 1; + Search1 = (LPVOID)FileMapVA1; + Search2 = (LPVOID)FileMapVA2; + NtSizeOfImage = NtSizeOfImage + LoadedImageBase; + SearchSize = FileSize2; + SearchSize--; + while((int)SearchSize > NULL) + { + if(memcmp(Search1, Search2, 1) != 0) + { + i = sizeof HANDLE; + RelativeBase = NULL; + bkSearch1 = Search1; + bkSearch2 = Search2; + bkSearchSize = SearchSize; + if(Search1 >= (void*)((ULONG_PTR)FileMapVA1 + DeltaByte)) + { + Search1 = (LPVOID)((ULONG_PTR)Search1 - DeltaByte); + Search2 = (LPVOID)((ULONG_PTR)Search2 - DeltaByte); + SearchSize = SearchSize + (DWORD)DeltaByte; + } + while(i > NULL && RelativeBase == NULL) + { + RtlMoveMemory(&ReadData, Search2, sizeof HANDLE); + if(ReadData >= LoadedImageBase && ReadData <= NtSizeOfImage) + { + RelativeBase++; + } + else + { + Search1 = (LPVOID)((ULONG_PTR)Search1 + 1); + Search2 = (LPVOID)((ULONG_PTR)Search2 + 1); + SearchSize = SearchSize - 1; + i--; + } + } + if(RelativeBase == NULL) + { + Search1 = bkSearch1; + Search2 = bkSearch2; + SearchSize = bkSearchSize; + } + else + { + RelocaterAddNewRelocation(hProcess, MemStart + ((ULONG_PTR)Search2 - (ULONG_PTR)FileMapVA2), NULL); + Search1 = (LPVOID)((ULONG_PTR)Search1 + sizeof HANDLE - 1); + Search2 = (LPVOID)((ULONG_PTR)Search2 + sizeof HANDLE - 1); + SearchSize = SearchSize - sizeof HANDLE + 1; + } + } + Search1 = (LPVOID)((ULONG_PTR)Search1 + 1); + Search2 = (LPVOID)((ULONG_PTR)Search2 + 1); + SearchSize = SearchSize - 1; + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + RelocaterCleanup(); + UnMapFileEx(FileHandle2, FileSize2, FileMap2, FileMapVA2); + UnMapFileEx(FileHandle1, FileSize1, FileMap1, FileMapVA1); + return(false); + } + } + UnMapFileEx(FileHandle2, FileSize2, FileMap2, FileMapVA2); + } + UnMapFileEx(FileHandle1, FileSize1, FileMap1, FileMapVA1); + return(true); + } + return(false); +} +__declspec(dllexport) bool __stdcall RelocaterChangeFileBase(char* szFileName, ULONG_PTR NewImageBase) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + + if(szFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + return(RelocaterChangeFileBaseW(uniFileName, NewImageBase)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall RelocaterChangeFileBaseW(wchar_t* szFileName, ULONG_PTR NewImageBase) +{ + + DWORD RelocSize; + ULONG_PTR RelocData; + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + BOOL FileIs64; + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + DWORD CompareDummy = NULL; + DWORD RelocDelta = NULL; + DWORD RelocDeltaSize = NULL; + WORD RelocAddressData = NULL; + ULONG_PTR RelocWriteAddress = NULL; + ULONG_PTR RelocWriteData = NULL; + DWORD64 RelocWriteData64 = NULL; + wchar_t szBackupFile[MAX_PATH] = {}; + wchar_t szBackupItem[MAX_PATH] = {}; + + if(engineBackupForCriticalFunctions && CreateGarbageItem(&szBackupItem, sizeof szBackupItem)) + { + if(!FillGarbageItem(szBackupItem, szFileName, &szBackupFile, sizeof szBackupItem)) + { + RtlZeroMemory(&szBackupItem, sizeof szBackupItem); + lstrcpyW(szBackupFile, szFileName); + } + } + else + { + RtlZeroMemory(&szBackupItem, sizeof szBackupItem); + lstrcpyW(szBackupFile, szFileName); + } + if(MapFileExW(szBackupFile, UE_ACCESS_ALL, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, FileHandle, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(false); + } + if(!FileIs64) + { + if(PEHeader32->OptionalHeader.ImageBase == (DWORD)NewImageBase) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(true); + } + RelocData = (ULONG_PTR)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress + PEHeader32->OptionalHeader.ImageBase), true); + RelocSize = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; + } + else + { + if((ULONG_PTR)PEHeader64->OptionalHeader.ImageBase == NewImageBase) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(true); + } + RelocData = (ULONG_PTR)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress + PEHeader64->OptionalHeader.ImageBase), true); + RelocSize = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; + } + __try + { + while(memcmp((LPVOID)RelocData, &CompareDummy, 4)) + { + RtlMoveMemory(&RelocDelta, (LPVOID)RelocData, 4); + RtlMoveMemory(&RelocDeltaSize, (LPVOID)((ULONG_PTR)RelocData + 4), 4); + RelocDeltaSize = RelocDeltaSize - 8; + RelocData = RelocData + 8; + while(RelocDeltaSize > NULL) + { + RtlMoveMemory(&RelocAddressData, (LPVOID)RelocData, 2); + if(RelocAddressData != NULL) + { + if(RelocAddressData & 0x8000) + { + RelocAddressData = RelocAddressData ^ 0x8000; + RelocWriteAddress = (ULONG_PTR)(RelocAddressData + RelocDelta); + RelocWriteAddress = (ULONG_PTR)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)((DWORD64)PEHeader64->OptionalHeader.ImageBase + RelocWriteAddress), true); + RtlMoveMemory(&RelocWriteData64, (LPVOID)RelocWriteAddress, 8); + RelocWriteData64 = RelocWriteData64 - (DWORD64)PEHeader64->OptionalHeader.ImageBase + (DWORD64)NewImageBase; + RtlMoveMemory((LPVOID)RelocWriteAddress, &RelocWriteData64, 8); + } + else if(RelocAddressData & 0x3000) + { + RelocAddressData = RelocAddressData ^ 0x3000; + RelocWriteAddress = (ULONG_PTR)(RelocAddressData + RelocDelta); + RelocWriteAddress = (ULONG_PTR)ConvertVAtoFileOffset(FileMapVA, PEHeader32->OptionalHeader.ImageBase + RelocWriteAddress, true); + RtlMoveMemory(&RelocWriteData, (LPVOID)RelocWriteAddress, 4); + RelocWriteData = RelocWriteData - PEHeader32->OptionalHeader.ImageBase + NewImageBase; + RtlMoveMemory((LPVOID)RelocWriteAddress, &RelocWriteData, 4); + } + } + RelocDeltaSize = RelocDeltaSize - 2; + RelocData = RelocData + 2; + } + } + if(!FileIs64) + { + PEHeader32->OptionalHeader.ImageBase = (DWORD)NewImageBase; + } + else + { + PEHeader64->OptionalHeader.ImageBase = (ULONG_PTR)NewImageBase; + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + if(szBackupItem[0] != NULL) + { + if(CopyFileW(szBackupFile, szFileName, false)) + { + RemoveGarbageItem(szBackupItem, true); + return(true); + } + else + { + RemoveGarbageItem(szBackupItem, true); + return(false); + } + } + else + { + return(true); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(false); + } + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + RemoveGarbageItem(szBackupItem, true); + return(false); + } + } + RemoveGarbageItem(szBackupItem, true); + return(false); +} +__declspec(dllexport) bool __stdcall RelocaterRelocateMemoryBlock(ULONG_PTR FileMapVA, ULONG_PTR MemoryLocation, void* RelocateMemory, DWORD RelocateMemorySize, ULONG_PTR CurrentLoadedBase, ULONG_PTR RelocateBase) +{ + + BOOL FileIs64; + DWORD RelocSize; + ULONG_PTR RelocData; + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + DWORD CompareDummy = NULL; + DWORD RelocDelta = NULL; + DWORD RelocDeltaSize = NULL; + WORD RelocAddressData = NULL; + ULONG_PTR RelocWriteAddress = NULL; + ULONG_PTR RelocWriteData = NULL; + DWORD64 RelocWriteData64 = NULL; + + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + MemoryLocation = MemoryLocation - CurrentLoadedBase; + if(EngineValidateHeader(FileMapVA, NULL, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + return(false); + } + if(!FileIs64) + { + if(PEHeader32->OptionalHeader.ImageBase == (DWORD)RelocateBase) + { + return(true); + } + RelocData = (ULONG_PTR)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress + PEHeader32->OptionalHeader.ImageBase), true); + RelocSize = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; + } + else + { + if((ULONG_PTR)PEHeader64->OptionalHeader.ImageBase == RelocateBase) + { + return(true); + } + RelocData = (ULONG_PTR)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress + PEHeader64->OptionalHeader.ImageBase), true); + RelocSize = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; + } + __try + { + while(memcmp((LPVOID)RelocData, &CompareDummy, 4)) + { + RtlMoveMemory(&RelocDelta, (LPVOID)RelocData, 4); + RtlMoveMemory(&RelocDeltaSize, (LPVOID)((ULONG_PTR)RelocData + 4), 4); + RelocDeltaSize = RelocDeltaSize - 8; + RelocData = RelocData + 8; + while(RelocDeltaSize > NULL) + { + RtlMoveMemory(&RelocAddressData, (LPVOID)RelocData, 2); + if(RelocAddressData != NULL) + { + if(RelocAddressData & 0x8000) + { + RelocAddressData = RelocAddressData ^ 0x8000; + if(RelocAddressData >= MemoryLocation && RelocAddressData < MemoryLocation + RelocateMemorySize) + { + RelocWriteAddress = (ULONG_PTR)(RelocAddressData + RelocDelta - MemoryLocation + (ULONG_PTR)RelocateMemory); + RtlMoveMemory(&RelocWriteData64, (LPVOID)RelocWriteAddress, 8); + RelocWriteData64 = RelocWriteData64 - (DWORD64)PEHeader64->OptionalHeader.ImageBase + (DWORD64)RelocateBase; + RtlMoveMemory((LPVOID)RelocWriteAddress, &RelocWriteData64, 8); + } + } + else if(RelocAddressData & 0x3000) + { + RelocAddressData = RelocAddressData ^ 0x3000; + if(RelocAddressData >= MemoryLocation && RelocAddressData < MemoryLocation + RelocateMemorySize) + { + RelocWriteAddress = (ULONG_PTR)(RelocAddressData + RelocDelta - MemoryLocation + (ULONG_PTR)RelocateMemory); + RtlMoveMemory(&RelocWriteData, (LPVOID)RelocWriteAddress, 4); + RelocWriteData = RelocWriteData - PEHeader32->OptionalHeader.ImageBase + RelocateBase; + RtlMoveMemory((LPVOID)RelocWriteAddress, &RelocWriteData, 4); + } + } + } + RelocDeltaSize = RelocDeltaSize - 2; + RelocData = RelocData + 2; + } + } + return(true); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return(false); + } + } + else + { + return(false); + } + return(false); +} +__declspec(dllexport) bool __stdcall RelocaterWipeRelocationTable(char* szFileName) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + + if(szFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + return(RelocaterWipeRelocationTableW(uniFileName)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall RelocaterWipeRelocationTableW(wchar_t* szFileName) +{ + + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + DWORD WipeSectionNumber = NULL; + ULONG_PTR Characteristics; + BOOL FileIs64; + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + + if(MapFileExW(szFileName, UE_ACCESS_READ, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, FileHandle, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + if(!FileIs64) + { + if(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress != NULL) + { + Characteristics = (ULONG_PTR)GetPE32DataFromMappedFile(FileMapVA, NULL, UE_CHARACTERISTICS) ^ 1; + SetPE32DataForMappedFile(FileMapVA, NULL, UE_CHARACTERISTICS, Characteristics); + WipeSectionNumber = GetPE32SectionNumberFromVA(FileMapVA, (ULONG_PTR)((ULONG_PTR)PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress + (ULONG_PTR)PEHeader32->OptionalHeader.ImageBase)); + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(WipeSectionW(szFileName, (int)WipeSectionNumber, true)); + } + } + else + { + if(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress != NULL) + { + Characteristics = (ULONG_PTR)GetPE32DataFromMappedFile(FileMapVA, NULL, UE_CHARACTERISTICS) ^ 1; + SetPE32DataForMappedFile(FileMapVA, NULL, UE_CHARACTERISTICS, Characteristics); + WipeSectionNumber = GetPE32SectionNumberFromVA(FileMapVA, (ULONG_PTR)((ULONG_PTR)PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase)); + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(WipeSectionW(szFileName, (int)WipeSectionNumber, true)); + } + } + } + } + return(false); +} +// TitanEngine.Resourcer.functions: +__declspec(dllexport) long long __stdcall ResourcerLoadFileForResourceUse(char* szFileName) +{ + return((ULONG_PTR)EngineSimulateNtLoader(szFileName)); +} +__declspec(dllexport) long long __stdcall ResourcerLoadFileForResourceUseW(wchar_t* szFileName) +{ + return((ULONG_PTR)EngineSimulateNtLoaderW(szFileName)); +} +__declspec(dllexport) bool __stdcall ResourcerFreeLoadedFile(LPVOID LoadedFileBase) +{ + if(VirtualFree(LoadedFileBase, NULL, MEM_RELEASE)) + { + return(true); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall ResourcerExtractResourceFromFileEx(ULONG_PTR FileMapVA, char* szResourceType, char* szResourceName, char* szExtractedFileName) +{ + + HRSRC hResource; + HGLOBAL hResourceGlobal; + DWORD ResourceSize; + LPVOID ResourceData; + DWORD NumberOfBytesWritten; + HANDLE hFile; + + hResource = FindResourceA((HMODULE)FileMapVA, (LPCSTR)szResourceName, (LPCSTR)szResourceType); + if(hResource != NULL) + { + hResourceGlobal = LoadResource((HMODULE)FileMapVA, hResource); + if(hResourceGlobal != NULL) + { + ResourceSize = SizeofResource((HMODULE)FileMapVA, hResource); + ResourceData = LockResource(hResourceGlobal); + if(EngineCreatePathForFile(szExtractedFileName)) + { + hFile = CreateFileA(szExtractedFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if(hFile != INVALID_HANDLE_VALUE) + { + WriteFile(hFile, ResourceData, ResourceSize, &NumberOfBytesWritten, NULL); + EngineCloseHandle(hFile); + } + else + { + return(false); + } + } + } + return(true); + } + return(false); +} +__declspec(dllexport) bool __stdcall ResourcerExtractResourceFromFile(char* szFileName, char* szResourceType, char* szResourceName, char* szExtractedFileName) +{ + + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + bool bReturn; + + if(MapFileEx(szFileName, UE_ACCESS_READ, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + bReturn = ResourcerExtractResourceFromFileEx(FileMapVA, szResourceType, szResourceName, szExtractedFileName); + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + if(bReturn) + { + return(true); + } + } + return(false); +} +__declspec(dllexport) bool __stdcall ResourcerExtractResourceFromFileW(wchar_t* szFileName, char* szResourceType, char* szResourceName, char* szExtractedFileName) +{ + + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + bool bReturn; + + if(MapFileExW(szFileName, UE_ACCESS_READ, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + bReturn = ResourcerExtractResourceFromFileEx(FileMapVA, szResourceType, szResourceName, szExtractedFileName); + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + if(bReturn) + { + return(true); + } + } + return(false); +} +__declspec(dllexport) bool __stdcall ResourcerFindResource(char* szFileName, char* szResourceType, DWORD ResourceType, char* szResourceName, DWORD ResourceName, DWORD ResourceLanguage, PULONG_PTR pResourceData, LPDWORD pResourceSize) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + wchar_t* PtrResourceType = NULL; + wchar_t uniResourceType[MAX_PATH] = {}; + wchar_t* PtrResourceName = NULL; + wchar_t uniResourceName[MAX_PATH] = {}; + + if(szFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + if(szResourceName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szResourceName, lstrlenA(szResourceName)+1, uniResourceName, sizeof(uniResourceName)/(sizeof(uniResourceName[0]))); + } + else + { + PtrResourceType = &uniResourceType[0]; + } + if(szResourceType != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szResourceType, lstrlenA(szResourceType)+1, uniResourceType, sizeof(uniResourceType)/(sizeof(uniResourceType[0]))); + } + else + { + PtrResourceName = &uniResourceName[0]; + } + return(ResourcerFindResourceW(uniFileName, PtrResourceType, ResourceType, PtrResourceName, ResourceName, ResourceLanguage, pResourceData, pResourceSize)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall ResourcerFindResourceW(wchar_t* szFileName, wchar_t* szResourceType, DWORD ResourceType, wchar_t* szResourceName, DWORD ResourceName, DWORD ResourceLanguage, PULONG_PTR pResourceData, LPDWORD pResourceSize) +{ + + bool ReturnValue; + ULONG_PTR FileMapVA; + HANDLE FileHandle; + HANDLE FileMap; + DWORD FileSize; + + if(MapFileExW(szFileName, UE_ACCESS_ALL, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + ReturnValue = ResourcerFindResourceEx(FileMapVA, FileSize, szResourceType, ResourceType, szResourceName, ResourceName, ResourceLanguage, pResourceData, pResourceSize); + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + if(ReturnValue) + { + return(true); + } + } + else + { + return(false); + } + return(false); +} +__declspec(dllexport) bool __stdcall ResourcerFindResourceEx(ULONG_PTR FileMapVA, DWORD FileSize, wchar_t* szResourceType, DWORD ResourceType, wchar_t* szResourceName, DWORD ResourceName, DWORD ResourceLanguage, PULONG_PTR pResourceData, LPDWORD pResourceSize) +{ + + int i,j,n; + wchar_t* uniResourceName; + wchar_t* uniResourceType; + PIMAGE_RESOURCE_DIRECTORY PEResource; + PIMAGE_RESOURCE_DIRECTORY PEResourcePtr; + PIMAGE_RESOURCE_DIRECTORY_ENTRY PEResourceDir; + PIMAGE_RESOURCE_DIRECTORY PESubResourcePtr1; + PIMAGE_RESOURCE_DIRECTORY_ENTRY PEResourceDir1; + PIMAGE_RESOURCE_DIRECTORY PESubResourcePtr2; + PIMAGE_RESOURCE_DIRECTORY_ENTRY PEResourceDir2; + PIMAGE_RESOURCE_DATA_ENTRY PEResourceItem; + + __try + { + if(FileMapVA != NULL && FileSize != NULL) + { + PEResource = (PIMAGE_RESOURCE_DIRECTORY)(ConvertVAtoFileOffsetEx(FileMapVA, FileSize, (ULONG_PTR)GetPE32DataFromMappedFile(FileMapVA, NULL, UE_IMAGEBASE), (ULONG_PTR)GetPE32DataFromMappedFile(FileMapVA, NULL, UE_RESOURCETABLEADDRESS), true, true)); + if(PEResource != NULL) + { + PEResourceDir = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((ULONG_PTR)PEResource + sizeof IMAGE_RESOURCE_DIRECTORY); + i = PEResource->NumberOfIdEntries + PEResource->NumberOfNamedEntries; + PEResourcePtr = PEResource; + while(i > NULL) + { + PESubResourcePtr1 = (PIMAGE_RESOURCE_DIRECTORY)((ULONG_PTR)PEResourcePtr + (PEResourceDir->OffsetToData ^ IMAGE_RESOURCE_DATA_IS_DIRECTORY)); + PEResourceDir1 = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((ULONG_PTR)PESubResourcePtr1 + sizeof IMAGE_RESOURCE_DIRECTORY); + j = PESubResourcePtr1->NumberOfIdEntries + PESubResourcePtr1->NumberOfNamedEntries; + uniResourceType = (wchar_t*)((ULONG_PTR)PEResourcePtr + PEResourceDir->NameOffset); + if(((bool)PEResourceDir->NameIsString == true && EngineCompareResourceString(uniResourceType, szResourceType) == true) || ((bool)PEResourceDir->NameIsString == false && PEResourceDir->Id == ResourceType)) + { + while(j > NULL) + { + PESubResourcePtr2 = (PIMAGE_RESOURCE_DIRECTORY)((ULONG_PTR)PEResourcePtr + (PEResourceDir1->OffsetToData ^ IMAGE_RESOURCE_DATA_IS_DIRECTORY)); + PEResourceDir2 = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((ULONG_PTR)PESubResourcePtr2 + sizeof IMAGE_RESOURCE_DIRECTORY); + n = PESubResourcePtr2->NumberOfIdEntries + PESubResourcePtr2->NumberOfNamedEntries; + uniResourceName = (wchar_t*)((ULONG_PTR)PEResourcePtr + PEResourceDir1->NameOffset); + if(((bool)PEResourceDir1->NameIsString == true && EngineCompareResourceString(uniResourceName, szResourceName) == true) || ((bool)PEResourceDir1->NameIsString == false && PEResourceDir1->Id == ResourceName)) + { + while(n > NULL) + { + PEResourceItem = (PIMAGE_RESOURCE_DATA_ENTRY)((ULONG_PTR)PEResourcePtr + PEResourceDir2->OffsetToData); + if(ResourceLanguage == UE_RESOURCE_LANGUAGE_ANY || ResourceLanguage == PEResourceDir2->Id) + { + *pResourceData = PEResourceItem->OffsetToData; + *pResourceSize = PEResourceItem->Size; + return(true); + } + PEResourceDir2 = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((ULONG_PTR)PEResourceDir2 + sizeof IMAGE_RESOURCE_DIRECTORY_ENTRY); + n--; + } + } + else + { + PEResourceDir2 = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((ULONG_PTR)PEResourceDir2 + sizeof IMAGE_RESOURCE_DIRECTORY_ENTRY * n); + } + PEResourceDir1 = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((ULONG_PTR)PEResourceDir1 + sizeof IMAGE_RESOURCE_DIRECTORY_ENTRY); + j--; + } + } + else + { + PEResourceDir1 = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((ULONG_PTR)PEResourceDir1 + sizeof IMAGE_RESOURCE_DIRECTORY_ENTRY * j); + } + PEResourceDir = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((ULONG_PTR)PEResourceDir + sizeof IMAGE_RESOURCE_DIRECTORY_ENTRY); + i--; + } + } + } + else + { + return(false); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + + } + return(false); +} +__declspec(dllexport) void __stdcall ResourcerEnumerateResource(char* szFileName, void* CallBack) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + + if(szFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + ResourcerEnumerateResourceW(uniFileName, CallBack); + } +} +__declspec(dllexport) void __stdcall ResourcerEnumerateResourceW(wchar_t* szFileName, void* CallBack) +{ + + ULONG_PTR FileMapVA; + HANDLE FileHandle; + HANDLE FileMap; + DWORD FileSize; + + if(MapFileExW(szFileName, UE_ACCESS_ALL, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + ResourcerEnumerateResourceEx(FileMapVA, FileSize, CallBack); + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + } +} +__declspec(dllexport) void __stdcall ResourcerEnumerateResourceEx(ULONG_PTR FileMapVA, DWORD FileSize, void* CallBack) +{ + + int i,j,n; + wchar_t* uniResourceName; + wchar_t* uniResourceType; + PIMAGE_RESOURCE_DIRECTORY PEResource; + PIMAGE_RESOURCE_DIRECTORY PEResourcePtr; + PIMAGE_RESOURCE_DIRECTORY_ENTRY PEResourceDir; + PIMAGE_RESOURCE_DIRECTORY PESubResourcePtr1; + PIMAGE_RESOURCE_DIRECTORY_ENTRY PEResourceDir1; + PIMAGE_RESOURCE_DIRECTORY PESubResourcePtr2; + PIMAGE_RESOURCE_DIRECTORY_ENTRY PEResourceDir2; + PIMAGE_RESOURCE_DATA_ENTRY PEResourceItem; + typedef bool(__stdcall *fResourceEnumerator)(wchar_t* szResourceType, DWORD ResourceType, wchar_t* szResourceName, DWORD ResourceName, DWORD ResourceLanguage, DWORD ResourceData, DWORD ResourceSize); + fResourceEnumerator myResourceEnumerator = (fResourceEnumerator)CallBack; + + __try + { + if(CallBack != NULL) + { + if(FileMapVA != NULL && FileSize != NULL) + { + PEResource = (PIMAGE_RESOURCE_DIRECTORY)(ConvertVAtoFileOffsetEx(FileMapVA, FileSize, (ULONG_PTR)GetPE32DataFromMappedFile(FileMapVA, NULL, UE_IMAGEBASE), (ULONG_PTR)GetPE32DataFromMappedFile(FileMapVA, NULL, UE_RESOURCETABLEADDRESS), true, true)); + if(PEResource != NULL) + { + PEResourceDir = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((ULONG_PTR)PEResource + sizeof IMAGE_RESOURCE_DIRECTORY); + i = PEResource->NumberOfIdEntries + PEResource->NumberOfNamedEntries; + PEResourcePtr = PEResource; + while(i > NULL) + { + PESubResourcePtr1 = (PIMAGE_RESOURCE_DIRECTORY)((ULONG_PTR)PEResourcePtr + (PEResourceDir->OffsetToData ^ IMAGE_RESOURCE_DATA_IS_DIRECTORY)); + PEResourceDir1 = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((ULONG_PTR)PESubResourcePtr1 + sizeof IMAGE_RESOURCE_DIRECTORY); + j = PESubResourcePtr1->NumberOfIdEntries + PESubResourcePtr1->NumberOfNamedEntries; + while(j > NULL) + { + PESubResourcePtr2 = (PIMAGE_RESOURCE_DIRECTORY)((ULONG_PTR)PEResourcePtr + (PEResourceDir1->OffsetToData ^ IMAGE_RESOURCE_DATA_IS_DIRECTORY)); + PEResourceDir2 = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((ULONG_PTR)PESubResourcePtr2 + sizeof IMAGE_RESOURCE_DIRECTORY); + n = PESubResourcePtr2->NumberOfIdEntries + PESubResourcePtr2->NumberOfNamedEntries; + while(n > NULL) + { + PEResourceItem = (PIMAGE_RESOURCE_DATA_ENTRY)((ULONG_PTR)PEResourcePtr + PEResourceDir2->OffsetToData); + if(PEResourceDir->NameIsString) + { + uniResourceType = (wchar_t*)((ULONG_PTR)PEResourcePtr + PEResourceDir->NameOffset); + } + else + { + uniResourceType = NULL; + } + if(PEResourceDir1->NameIsString) + { + uniResourceName = (wchar_t*)((ULONG_PTR)PEResourcePtr + PEResourceDir1->NameOffset); + } + else + { + uniResourceName = NULL; + } + if(!myResourceEnumerator(uniResourceType, PEResourceDir->Id, uniResourceName, PEResourceDir1->Id, PEResourceDir2->Id, PEResourceItem->OffsetToData, PEResourceItem->Size)) + { + return; + } + PEResourceDir2 = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((ULONG_PTR)PEResourceDir2 + sizeof IMAGE_RESOURCE_DIRECTORY_ENTRY); + n--; + } + PEResourceDir1 = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((ULONG_PTR)PEResourceDir1 + sizeof IMAGE_RESOURCE_DIRECTORY_ENTRY); + j--; + } + PEResourceDir = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((ULONG_PTR)PEResourceDir + sizeof IMAGE_RESOURCE_DIRECTORY_ENTRY); + i--; + } + } + } + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + + } +} +// TitanEngine.Threader.functions: +__declspec(dllexport) bool __stdcall ThreaderImportRunningThreadData(DWORD ProcessId) +{ + + HANDLE hSnapShot; + THREADENTRY32 ThreadEntry = {}; + PTHREAD_ITEM_DATA hListThreadPtr = NULL; + + if(dbgProcessInformation.hProcess == NULL && ProcessId != NULL) + { + if(hListThread == NULL) + { + hListThread = VirtualAlloc(NULL, MAX_DEBUG_DATA * sizeof THREAD_ITEM_DATA, MEM_COMMIT, PAGE_READWRITE); + } + else + { + RtlZeroMemory(hListThread, MAX_DEBUG_DATA * sizeof THREAD_ITEM_DATA); + } + ThreadEntry.dwSize = sizeof THREADENTRY32; + hListThreadPtr = (PTHREAD_ITEM_DATA)hListThread; + hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, ProcessId); + if(hSnapShot != INVALID_HANDLE_VALUE) + { + if(Thread32First(hSnapShot, &ThreadEntry)) + { + do + { + if(ThreadEntry.th32OwnerProcessID == ProcessId) + { + hListThreadPtr->dwThreadId = ThreadEntry.th32ThreadID; + hListThreadPtr->hThread = OpenThread(THREAD_GET_CONTEXT+THREAD_SET_CONTEXT+THREAD_QUERY_INFORMATION+THREAD_SUSPEND_RESUME, false, hListThreadPtr->dwThreadId); + hListThreadPtr = (PTHREAD_ITEM_DATA)((ULONG_PTR)hListThreadPtr + sizeof THREAD_ITEM_DATA); + } + } + while(Thread32Next(hSnapShot, &ThreadEntry)); + } + EngineCloseHandle(hSnapShot); + return(true); + } + } + return(false); +} +__declspec(dllexport) void* __stdcall ThreaderGetThreadInfo(HANDLE hThread, DWORD ThreadId) +{ + + PTHREAD_ITEM_DATA hListThreadPtr = (PTHREAD_ITEM_DATA)hListThread; + + if(hListThreadPtr != NULL) + { + if(hThread != NULL) + { + while(hListThreadPtr->hThread != NULL && hListThreadPtr->hThread != hThread) + { + hListThreadPtr = (PTHREAD_ITEM_DATA)((ULONG_PTR)hListThreadPtr + sizeof THREAD_ITEM_DATA); + } + if(hListThreadPtr->hThread == hThread) + { + return((void*)hListThreadPtr); + } + } + else if(ThreadId != NULL) + { + while(hListThreadPtr->hThread != NULL && hListThreadPtr->dwThreadId != ThreadId) + { + hListThreadPtr = (PTHREAD_ITEM_DATA)((ULONG_PTR)hListThreadPtr + sizeof THREAD_ITEM_DATA); + } + if(hListThreadPtr->dwThreadId == ThreadId) + { + return((void*)hListThreadPtr); + } + } + } + return(NULL); +} +__declspec(dllexport) void __stdcall ThreaderEnumThreadInfo(void* EnumCallBack) +{ + + PTHREAD_ITEM_DATA hListThreadPtr = (PTHREAD_ITEM_DATA)hListThread; + typedef void(__stdcall *fEnumCallBack)(LPVOID fThreadDetail); + fEnumCallBack myEnumCallBack = (fEnumCallBack)EnumCallBack; + + if(hListThreadPtr != NULL) + { + while(EnumCallBack != NULL && hListThreadPtr->hThread != NULL) + { + if(hListThreadPtr->hThread != NULL) + { + __try + { + myEnumCallBack((void*)hListThreadPtr); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + EnumCallBack = NULL; + } + } + hListThreadPtr = (PTHREAD_ITEM_DATA)((ULONG_PTR)hListThreadPtr + sizeof THREAD_ITEM_DATA); + } + } +} +__declspec(dllexport) bool __stdcall ThreaderPauseThread(HANDLE hThread) +{ + + PTHREAD_ITEM_DATA hListThreadPtr = (PTHREAD_ITEM_DATA)hListThread; + + if(hListThreadPtr != NULL) + { + if(hThread != NULL) + { + while(hListThreadPtr->hThread != NULL && hListThreadPtr->hThread != hThread) + { + hListThreadPtr = (PTHREAD_ITEM_DATA)((ULONG_PTR)hListThreadPtr + sizeof THREAD_ITEM_DATA); + } + if(hListThreadPtr->hThread == hThread) + { + if(SuspendThread(hThread) != -1) + { + return(true); + } + else + { + return(false); + } + } + else + { + return(false); + } + } + } + return(false); +} +__declspec(dllexport) bool __stdcall ThreaderResumeThread(HANDLE hThread) +{ + + PTHREAD_ITEM_DATA hListThreadPtr = (PTHREAD_ITEM_DATA)hListThread; + + if(hListThreadPtr != NULL) + { + if(hThread != NULL) + { + while(hListThreadPtr->hThread != NULL && hListThreadPtr->hThread != hThread) + { + hListThreadPtr = (PTHREAD_ITEM_DATA)((ULONG_PTR)hListThreadPtr + sizeof THREAD_ITEM_DATA); + } + if(hListThreadPtr->hThread == hThread) + { + if(ResumeThread(hThread) != -1) + { + return(true); + } + else + { + return(false); + } + } + else + { + return(false); + } + } + } + return(false); +} +__declspec(dllexport) bool __stdcall ThreaderTerminateThread(HANDLE hThread, DWORD ThreadExitCode) +{ + + PTHREAD_ITEM_DATA hListThreadPtr = (PTHREAD_ITEM_DATA)hListThread; + + if(hListThreadPtr != NULL) + { + if(hThread != NULL) + { + while(hListThreadPtr->hThread != NULL && hListThreadPtr->hThread != hThread) + { + hListThreadPtr = (PTHREAD_ITEM_DATA)((ULONG_PTR)hListThreadPtr + sizeof THREAD_ITEM_DATA); + } + if(hListThreadPtr->hThread == hThread) + { + if(TerminateThread(hThread, ThreadExitCode) != NULL) + { + hListThreadPtr->hThread = (HANDLE)-1; + hListThreadPtr->dwThreadId = NULL; + hListThreadPtr->ThreadLocalBase = NULL; + hListThreadPtr->ThreadStartAddress = NULL; + return(true); + } + else + { + return(false); + } + } + else + { + return(false); + } + } + } + return(false); +} +__declspec(dllexport) bool __stdcall ThreaderPauseAllThreads(bool LeaveMainRunning) +{ + + PTHREAD_ITEM_DATA hListThreadPtr = (PTHREAD_ITEM_DATA)hListThread; + + if(hListThreadPtr != NULL) + { + while(hListThreadPtr->hThread != NULL) + { + if(LeaveMainRunning) + { + if(hListThreadPtr->hThread != dbgProcessInformation.hThread) + { + SuspendThread((HANDLE)hListThreadPtr->hThread); + } + } + else + { + SuspendThread(hListThreadPtr->hThread); + } + hListThreadPtr = (PTHREAD_ITEM_DATA)((ULONG_PTR)hListThreadPtr + sizeof THREAD_ITEM_DATA); + } + return(true); + } + return(false); +} +__declspec(dllexport) bool __stdcall ThreaderResumeAllThreads(bool LeaveMainPaused) +{ + + PTHREAD_ITEM_DATA hListThreadPtr = (PTHREAD_ITEM_DATA)hListThread; + + if(hListThreadPtr != NULL) + { + while(hListThreadPtr->hThread != NULL) + { + if(LeaveMainPaused) + { + if(hListThreadPtr->hThread != dbgProcessInformation.hThread) + { + ResumeThread(hListThreadPtr->hThread); + } + } + else + { + ResumeThread(hListThreadPtr->hThread); + } + hListThreadPtr = (PTHREAD_ITEM_DATA)((ULONG_PTR)hListThreadPtr + sizeof THREAD_ITEM_DATA); + } + return(true); + } + return(false); +} +__declspec(dllexport) bool __stdcall ThreaderPauseProcess() +{ + return(ThreaderPauseAllThreads(false)); +} +__declspec(dllexport) bool __stdcall ThreaderResumeProcess() +{ + return(ThreaderResumeAllThreads(false)); +} +__declspec(dllexport) long long __stdcall ThreaderCreateRemoteThread(ULONG_PTR ThreadStartAddress, bool AutoCloseTheHandle, LPVOID ThreadPassParameter, LPDWORD ThreadId) +{ + + HANDLE myThread; + + if(dbgProcessInformation.hProcess != NULL) + { + if(!AutoCloseTheHandle) + { + return((ULONG_PTR)CreateRemoteThread(dbgProcessInformation.hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)ThreadStartAddress, ThreadPassParameter, NULL, ThreadId)); + } + else + { + myThread = CreateRemoteThread(dbgProcessInformation.hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)ThreadStartAddress, ThreadPassParameter, NULL, ThreadId); + EngineCloseHandle(myThread); + return(NULL); + } + } + return(NULL); +} +__declspec(dllexport) bool __stdcall ThreaderInjectAndExecuteCode(LPVOID InjectCode, DWORD StartDelta, DWORD InjectSize) +{ + + LPVOID ThreadBase = 0; + ULONG_PTR ueNumberOfBytesRead = 0; + + if(dbgProcessInformation.hProcess != NULL) + { + ThreadBase = VirtualAllocEx(dbgProcessInformation.hProcess, NULL, InjectSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if(WriteProcessMemory(dbgProcessInformation.hProcess, ThreadBase, InjectCode, InjectSize, &ueNumberOfBytesRead)) + { + ThreaderCreateRemoteThread((ULONG_PTR)((ULONG_PTR)InjectCode + StartDelta), true, NULL, NULL); + return(true); + } + else + { + return(false); + } + } + return(false); +} +__declspec(dllexport) long long __stdcall ThreaderCreateRemoteThreadEx(HANDLE hProcess, ULONG_PTR ThreadStartAddress, bool AutoCloseTheHandle, LPVOID ThreadPassParameter, LPDWORD ThreadId) +{ + + HANDLE myThread; + + if(hProcess != NULL) + { + if(!AutoCloseTheHandle) + { + return((ULONG_PTR)CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)ThreadStartAddress, ThreadPassParameter, NULL, ThreadId)); + } + else + { + myThread = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)ThreadStartAddress, ThreadPassParameter, NULL, ThreadId); + EngineCloseHandle(myThread); + return(NULL); + } + } + return(NULL); +} +__declspec(dllexport) bool __stdcall ThreaderInjectAndExecuteCodeEx(HANDLE hProcess, LPVOID InjectCode, DWORD StartDelta, DWORD InjectSize) +{ + + LPVOID ThreadBase = 0; + ULONG_PTR ueNumberOfBytesRead = 0; + + if(hProcess != NULL) + { + ThreadBase = VirtualAllocEx(hProcess, NULL, InjectSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if(WriteProcessMemory(hProcess, ThreadBase, InjectCode, InjectSize, &ueNumberOfBytesRead)) + { + ThreaderCreateRemoteThread((ULONG_PTR)((ULONG_PTR)InjectCode + StartDelta), true, NULL, NULL); + return(true); + } + else + { + return(false); + } + } + return(false); +} +__declspec(dllexport) void __stdcall ThreaderSetCallBackForNextExitThreadEvent(LPVOID exitThreadCallBack) +{ + engineExitThreadOneShootCallBack = exitThreadCallBack; +} +__declspec(dllexport) bool __stdcall ThreaderIsThreadStillRunning(HANDLE hThread) +{ + + CONTEXT myDBGContext; + + RtlZeroMemory(&myDBGContext, sizeof CONTEXT); + myDBGContext.ContextFlags = CONTEXT_ALL; + if(GetThreadContext(hThread, &myDBGContext)) + { + return(true); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall ThreaderIsThreadActive(HANDLE hThread) +{ + + if(SuspendThread(hThread) < 0) + { + ResumeThread(hThread); + return(true); + } + return(false); +} +__declspec(dllexport) bool __stdcall ThreaderIsAnyThreadActive() +{ + + PTHREAD_ITEM_DATA hListThreadPtr = (PTHREAD_ITEM_DATA)hListThread; + + if(hListThreadPtr != NULL) + { + while(hListThreadPtr->hThread != NULL) + { + if(hListThreadPtr->hThread != (HANDLE)-1) + { + if(ThreaderIsThreadActive(hListThreadPtr->hThread)) + { + return(true); + } + } + hListThreadPtr = (PTHREAD_ITEM_DATA)((ULONG_PTR)hListThreadPtr + sizeof THREAD_ITEM_DATA); + } + } + return(false); +} +__declspec(dllexport) bool __stdcall ThreaderExecuteOnlyInjectedThreads() +{ + + if(ThreaderPauseProcess()) + { + engineResumeProcessIfNoThreadIsActive = true; + return(true); + } + return(false); +} +__declspec(dllexport) long long __stdcall ThreaderGetOpenHandleForThread(DWORD ThreadId) +{ + + PTHREAD_ITEM_DATA hListThreadPtr = (PTHREAD_ITEM_DATA)hListThread; + + if(hListThread != NULL) + { + while(hListThreadPtr->hThread != NULL) + { + if(hListThreadPtr->hThread != (HANDLE)-1 && hListThreadPtr->dwThreadId == ThreadId) + { + return((ULONG_PTR)hListThreadPtr->hThread); + } + hListThreadPtr = (PTHREAD_ITEM_DATA)((ULONG_PTR)hListThreadPtr + sizeof THREAD_ITEM_DATA); + } + } + return(NULL); +} +__declspec(dllexport) void* __stdcall ThreaderGetThreadData() +{ + return(hListThread); +} +__declspec(dllexport) bool __stdcall ThreaderIsExceptionInMainThread() +{ + + LPDEBUG_EVENT myDBGEvent; + + myDBGEvent = (LPDEBUG_EVENT)GetDebugData(); + if(myDBGEvent->dwThreadId == dbgProcessInformation.dwThreadId) + { + return(true); + } + return(false); +} +// Global.Debugger.functions: +long DebugLoopInSecondThread(LPVOID InputParameter) +{ + __try + { + if(InputParameter == NULL) + { + InitDebugExW(engineExpertDebug.szFileName, engineExpertDebug.szCommandLine, engineExpertDebug.szCurrentFolder, engineExpertDebug.EntryCallBack); + } + else + { + InitDLLDebugW(engineExpertDebug.szFileName, engineExpertDebug.ReserveModuleBase, engineExpertDebug.szCommandLine, engineExpertDebug.szCurrentFolder, engineExpertDebug.EntryCallBack); + } + DebugLoop(); + return(NULL); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return(-1); + } +} +void DebuggerReset() +{ + + if(engineResetCustomHandler) + { + RtlZeroMemory(&myDBGCustomHandler, sizeof CustomHandler); + } +} +// TitanEngine.Debugger.functions: +__declspec(dllexport) void* __stdcall StaticDisassembleEx(ULONG_PTR DisassmStart, LPVOID DisassmAddress) +{ + _DecodeResult DecodingResult; + _DecodedInst engineDecodedInstructions[MAX_DECODE_INSTRUCTIONS]; + unsigned int DecodedInstructionsCount = 0; +#if !defined(_WIN64) + _DecodeType DecodingType = Decode32Bits; +#else + _DecodeType DecodingType = Decode64Bits; +#endif + MEMORY_BASIC_INFORMATION MemInfo; + DWORD MaxDisassmSize; + + VirtualQueryEx(GetCurrentProcess(), DisassmAddress, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + if(MemInfo.State == MEM_COMMIT) + { + if((ULONG_PTR)MemInfo.BaseAddress + (ULONG_PTR)MemInfo.RegionSize - (ULONG_PTR)DisassmAddress <= MAXIMUM_INSTRUCTION_SIZE) + { + MaxDisassmSize = (DWORD)((ULONG_PTR)MemInfo.BaseAddress + (ULONG_PTR)MemInfo.RegionSize - (ULONG_PTR)DisassmAddress - 1); + VirtualQueryEx(GetCurrentProcess(), (LPVOID)((ULONG_PTR)DisassmAddress + (ULONG_PTR)MemInfo.RegionSize), &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + if(MemInfo.State == MEM_COMMIT) + { + MaxDisassmSize = MAXIMUM_INSTRUCTION_SIZE; + } + } + else + { + MaxDisassmSize = MAXIMUM_INSTRUCTION_SIZE; + } + DecodingResult = distorm_decode((ULONG_PTR)DisassmStart, (const unsigned char*)DisassmAddress, MaxDisassmSize, DecodingType, engineDecodedInstructions, MAX_DECODE_INSTRUCTIONS, &DecodedInstructionsCount); + RtlZeroMemory(&engineDisassembledInstruction, 128); + lstrcpyA(engineDisassembledInstruction, (LPCSTR)engineDecodedInstructions[0].mnemonic.p); + if(engineDecodedInstructions[0].size != NULL) + { + lstrcatA(engineDisassembledInstruction, " "); + } + lstrcatA(engineDisassembledInstruction, (LPCSTR)engineDecodedInstructions[0].operands.p); + return((char*)engineDisassembledInstruction); + } + else + { + return(NULL); + } +} +__declspec(dllexport) void* __stdcall StaticDisassemble(LPVOID DisassmAddress) +{ + return(StaticDisassembleEx((ULONG_PTR)DisassmAddress, DisassmAddress)); +} +__declspec(dllexport) void* __stdcall DisassembleEx(HANDLE hProcess, LPVOID DisassmAddress, bool ReturnInstructionType) +{ + + _DecodeResult DecodingResult; + _DecodedInst engineDecodedInstructions[MAX_DECODE_INSTRUCTIONS]; + unsigned int DecodedInstructionsCount = 0; +#if !defined(_WIN64) + _DecodeType DecodingType = Decode32Bits; +#else + _DecodeType DecodingType = Decode64Bits; +#endif + ULONG_PTR ueNumberOfBytesRead = 0; + LPVOID ueReadBuffer = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE); + MEMORY_BASIC_INFORMATION MemInfo; + DWORD MaxDisassmSize; + + if(hProcess != NULL) + { + VirtualQueryEx(hProcess, DisassmAddress, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + if(MemInfo.State == MEM_COMMIT) + { + if((ULONG_PTR)MemInfo.BaseAddress + (ULONG_PTR)MemInfo.RegionSize - (ULONG_PTR)DisassmAddress <= MAXIMUM_INSTRUCTION_SIZE) + { + MaxDisassmSize = (DWORD)((ULONG_PTR)MemInfo.BaseAddress + (ULONG_PTR)MemInfo.RegionSize - (ULONG_PTR)DisassmAddress - 1); + VirtualQueryEx(hProcess, (LPVOID)((ULONG_PTR)DisassmAddress + (ULONG_PTR)MemInfo.RegionSize), &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + if(MemInfo.State == MEM_COMMIT) + { + MaxDisassmSize = MAXIMUM_INSTRUCTION_SIZE; + } + } + else + { + MaxDisassmSize = MAXIMUM_INSTRUCTION_SIZE; + } + bool isbp=false; + if(IsBPXEnabled((ULONG_PTR)DisassmAddress)) + { + isbp=true; + DisableBPX((ULONG_PTR)DisassmAddress); + } + BOOL rpm=ReadProcessMemory(hProcess, (LPVOID)DisassmAddress, ueReadBuffer, MaxDisassmSize, &ueNumberOfBytesRead); + if(isbp) + { + EnableBPX((ULONG_PTR)DisassmAddress); + } + if(rpm) + { + DecodingResult = distorm_decode((ULONG_PTR)DisassmAddress, (const unsigned char*)ueReadBuffer, MaxDisassmSize, DecodingType, engineDecodedInstructions, MAX_DECODE_INSTRUCTIONS, &DecodedInstructionsCount); + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + RtlZeroMemory(&engineDisassembledInstruction, 128); + lstrcpyA(engineDisassembledInstruction, (LPCSTR)engineDecodedInstructions[0].mnemonic.p); + if(!ReturnInstructionType) + { + if(engineDecodedInstructions[0].size != NULL) + { + lstrcatA(engineDisassembledInstruction, " "); + } + lstrcatA(engineDisassembledInstruction, (LPCSTR)engineDecodedInstructions[0].operands.p); + } + return((char*)engineDisassembledInstruction); + } + else + { + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + return(NULL); + } + } + else + { + return(NULL); + } + } + else + { + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + return(NULL); + } +} +__declspec(dllexport) void* __stdcall Disassemble(LPVOID DisassmAddress) +{ + return(DisassembleEx(dbgProcessInformation.hProcess, DisassmAddress, false)); +} +__declspec(dllexport) long __stdcall StaticLengthDisassemble(LPVOID DisassmAddress) +{ + + _DecodeResult DecodingResult; + _DecodedInst DecodedInstructions[MAX_DECODE_INSTRUCTIONS]; + unsigned int DecodedInstructionsCount = 0; +#if !defined(_WIN64) + _DecodeType DecodingType = Decode32Bits; +#else + _DecodeType DecodingType = Decode64Bits; +#endif + MEMORY_BASIC_INFORMATION MemInfo; + DWORD MaxDisassmSize; + + VirtualQueryEx(GetCurrentProcess(), DisassmAddress, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + if(MemInfo.State == MEM_COMMIT) + { + if((ULONG_PTR)MemInfo.BaseAddress + (ULONG_PTR)MemInfo.RegionSize - (ULONG_PTR)DisassmAddress <= MAXIMUM_INSTRUCTION_SIZE) + { + MaxDisassmSize = (DWORD)((ULONG_PTR)MemInfo.BaseAddress + (ULONG_PTR)MemInfo.RegionSize - (ULONG_PTR)DisassmAddress - 1); + VirtualQueryEx(GetCurrentProcess(), (LPVOID)((ULONG_PTR)DisassmAddress + (ULONG_PTR)MemInfo.RegionSize), &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + if(MemInfo.State == MEM_COMMIT) + { + MaxDisassmSize = MAXIMUM_INSTRUCTION_SIZE; + } + } + else + { + MaxDisassmSize = MAXIMUM_INSTRUCTION_SIZE; + } + DecodingResult = distorm_decode(NULL, (const unsigned char*)DisassmAddress, MaxDisassmSize, DecodingType, DecodedInstructions, MAX_DECODE_INSTRUCTIONS, &DecodedInstructionsCount); + return(DecodedInstructions[0].size); + } + else + { + return(NULL); + } +} +__declspec(dllexport) long __stdcall LengthDisassembleEx(HANDLE hProcess, LPVOID DisassmAddress) +{ + + _DecodeResult DecodingResult; + _DecodedInst DecodedInstructions[MAX_DECODE_INSTRUCTIONS]; + unsigned int DecodedInstructionsCount = 0; +#if !defined(_WIN64) + _DecodeType DecodingType = Decode32Bits; +#else + _DecodeType DecodingType = Decode64Bits; +#endif + ULONG_PTR ueNumberOfBytesRead = 0; + LPVOID ueReadBuffer = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE); + MEMORY_BASIC_INFORMATION MemInfo; + DWORD MaxDisassmSize; + + if(hProcess != NULL) + { + VirtualQueryEx(GetCurrentProcess(), DisassmAddress, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + if(MemInfo.State == MEM_COMMIT) + { + if((ULONG_PTR)MemInfo.BaseAddress + (ULONG_PTR)MemInfo.RegionSize - (ULONG_PTR)DisassmAddress <= MAXIMUM_INSTRUCTION_SIZE) + { + MaxDisassmSize = (DWORD)((ULONG_PTR)MemInfo.BaseAddress + (ULONG_PTR)MemInfo.RegionSize - (ULONG_PTR)DisassmAddress - 1); + VirtualQueryEx(GetCurrentProcess(), (LPVOID)((ULONG_PTR)DisassmAddress + (ULONG_PTR)MemInfo.RegionSize), &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + if(MemInfo.State == MEM_COMMIT) + { + MaxDisassmSize = MAXIMUM_INSTRUCTION_SIZE; + } + } + else + { + MaxDisassmSize = MAXIMUM_INSTRUCTION_SIZE; + } + if(ReadProcessMemory(hProcess, (LPVOID)DisassmAddress, ueReadBuffer, MaxDisassmSize, &ueNumberOfBytesRead)) + { + DecodingResult = distorm_decode(NULL, (const unsigned char*)ueReadBuffer, MaxDisassmSize, DecodingType, DecodedInstructions, MAX_DECODE_INSTRUCTIONS, &DecodedInstructionsCount); + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + return(DecodedInstructions[0].size); + } + else + { + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + return(-1); + } + } + else + { + return(NULL); + } + } + else + { + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + return(-1); + } +} +__declspec(dllexport) long __stdcall LengthDisassemble(LPVOID DisassmAddress) +{ + return(LengthDisassembleEx(dbgProcessInformation.hProcess, DisassmAddress)); +} +__declspec(dllexport) void* __stdcall InitDebug(char* szFileName, char* szCommandLine, char* szCurrentFolder) +{ + + wchar_t* PtrUniFileName = NULL; + wchar_t uniFileName[MAX_PATH] = {}; + wchar_t* PtrUniCommandLine = NULL; + wchar_t uniCommandLine[MAX_PATH] = {}; + wchar_t* PtrUniCurrentFolder = NULL; + wchar_t uniCurrentFolder[MAX_PATH] = {}; + + if(szFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + MultiByteToWideChar(CP_ACP, NULL, szCommandLine, lstrlenA(szCommandLine)+1, uniCommandLine, sizeof(uniCommandLine)/(sizeof(uniCommandLine[0]))); + MultiByteToWideChar(CP_ACP, NULL, szCurrentFolder, lstrlenA(szCurrentFolder)+1, uniCurrentFolder, sizeof(uniCurrentFolder)/(sizeof(uniCurrentFolder[0]))); + if(szFileName != NULL) + { + PtrUniFileName = &uniFileName[0]; + } + if(szCommandLine != NULL) + { + PtrUniCommandLine = &uniCommandLine[0]; + } + if(szCurrentFolder != NULL) + { + PtrUniCurrentFolder = &uniCurrentFolder[0]; + } + return(InitDebugW(PtrUniFileName, PtrUniCommandLine, PtrUniCurrentFolder)); + } + else + { + return(false); + } +} +__declspec(dllexport) void* __stdcall InitDebugW(wchar_t* szFileName, wchar_t* szCommandLine, wchar_t* szCurrentFolder) +{ + + wchar_t szCreateWithCmdLine[1024]; + int DebugConsoleFlag = NULL; + + DebuggerReset(); + if(engineRemoveConsoleForDebugee) + { + DebugConsoleFlag = CREATE_NO_WINDOW; + } + BreakPointSetCount = 0; + RtlZeroMemory(&BreakPointBuffer, sizeof BreakPointBuffer); + if(szCommandLine == NULL) + { + if(CreateProcessW(szFileName, NULL, NULL, NULL, false, DEBUG_PROCESS+DEBUG_ONLY_THIS_PROCESS+DebugConsoleFlag+CREATE_NEW_CONSOLE, NULL, szCurrentFolder, &dbgStartupInfo, &dbgProcessInformation)) + { + engineAttachedToProcess = false; + engineAttachedProcessCallBack = NULL; + RtlZeroMemory(&BreakPointBuffer, sizeof BreakPointBuffer); + return(&dbgProcessInformation); + } + else + { + RtlZeroMemory(&dbgProcessInformation,sizeof PROCESS_INFORMATION); + return(0); + } + } + else + { + wsprintfW(szCreateWithCmdLine, L"\"%s\" %s", szFileName, szCommandLine); + if(CreateProcessW(NULL, szCreateWithCmdLine, NULL, NULL, false, DEBUG_PROCESS+DEBUG_ONLY_THIS_PROCESS+DebugConsoleFlag+CREATE_NEW_CONSOLE, NULL, szCurrentFolder, &dbgStartupInfo, &dbgProcessInformation)) + { + engineAttachedToProcess = false; + engineAttachedProcessCallBack = NULL; + RtlZeroMemory(&BreakPointBuffer, sizeof BreakPointBuffer); + return(&dbgProcessInformation); + } + else + { + RtlZeroMemory(&dbgProcessInformation,sizeof PROCESS_INFORMATION); + return(0); + } + } +} +__declspec(dllexport) void* __stdcall InitDebugEx(char* szFileName, char* szCommandLine, char* szCurrentFolder, LPVOID EntryCallBack) +{ + DebugExeFileEntryPointCallBack = EntryCallBack; + return(InitDebug(szFileName, szCommandLine, szCurrentFolder)); +} +__declspec(dllexport) void* __stdcall InitDebugExW(wchar_t* szFileName, wchar_t* szCommandLine, wchar_t* szCurrentFolder, LPVOID EntryCallBack) +{ + DebugExeFileEntryPointCallBack = EntryCallBack; + return(InitDebugW(szFileName, szCommandLine, szCurrentFolder)); +} +__declspec(dllexport) void* __stdcall InitDLLDebug(char* szFileName, bool ReserveModuleBase, char* szCommandLine, char* szCurrentFolder, LPVOID EntryCallBack) +{ + + wchar_t* PtrUniFileName = NULL; + wchar_t uniFileName[MAX_PATH] = {}; + wchar_t* PtrUniCommandLine = NULL; + wchar_t uniCommandLine[MAX_PATH] = {}; + wchar_t* PtrUniCurrentFolder = NULL; + wchar_t uniCurrentFolder[MAX_PATH] = {}; + + if(szFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + MultiByteToWideChar(CP_ACP, NULL, szCommandLine, lstrlenA(szCommandLine)+1, uniCommandLine, sizeof(uniCommandLine)/(sizeof(uniCommandLine[0]))); + MultiByteToWideChar(CP_ACP, NULL, szCurrentFolder, lstrlenA(szCurrentFolder)+1, uniCurrentFolder, sizeof(uniCurrentFolder)/(sizeof(uniCurrentFolder[0]))); + if(szFileName != NULL) + { + PtrUniFileName = &uniFileName[0]; + } + if(szCommandLine != NULL) + { + PtrUniCommandLine = &uniCommandLine[0]; + } + if(szCurrentFolder != NULL) + { + PtrUniCurrentFolder = &uniCurrentFolder[0]; + } + return(InitDLLDebugW(PtrUniFileName, ReserveModuleBase, PtrUniCommandLine, PtrUniCurrentFolder, EntryCallBack)); + } + else + { + return(false); + } +} +__declspec(dllexport) void* __stdcall InitDLLDebugW(wchar_t* szFileName, bool ReserveModuleBase, wchar_t* szCommandLine, wchar_t* szCurrentFolder, LPVOID EntryCallBack) +{ + + int i = NULL; + int j = NULL; + bool ReturnData = false; + engineReserveModuleBase = NULL; + + RtlZeroMemory(&szDebuggerName, sizeof szDebuggerName); + if(lstrlenW(szFileName) < 512) + { + RtlZeroMemory(&szBackupDebuggedFileName, sizeof szBackupDebuggedFileName); + lstrcpyW(szBackupDebuggedFileName, szFileName); + szFileName = &szBackupDebuggedFileName[0]; + } + lstrcpyW(szDebuggerName, szFileName); + i = lstrlenW(szDebuggerName); + while(szDebuggerName[i] != 0x5C && i >= NULL) + { + i--; + } + if(i > NULL) + { + szDebuggerName[i+1] = 0x00; + lstrcatW(szDebuggerName, L"DLLLoader.exe"); + } + else + { + lstrcpyW(szDebuggerName, L"DLLLoader.exe"); + } + //RtlZeroMemory(&szReserveModuleName, sizeof szReserveModuleName); + //lstrcpyW(szReserveModuleName, szFileName); + //lstrcatW(szReserveModuleName, L".module"); +#if defined(_WIN64) + ReturnData = EngineExtractResource("LOADERx64", szDebuggerName); + /*if(ReserveModuleBase) + { + EngineExtractResource("MODULEx64", szReserveModuleName); + }*/ +#else + ReturnData = EngineExtractResource("LOADERx86", szDebuggerName); + /*if(ReserveModuleBase) + { + EngineExtractResource("MODULEx86", szReserveModuleName); + }*/ +#endif + if(ReturnData) + { + engineDebuggingDLL = true; + i = lstrlenW(szFileName); + while(szFileName[i] != 0x5C && i >= NULL) + { + i--; + } + /*j = lstrlenW(szReserveModuleName); + while(szReserveModuleName[j] != 0x5C && j >= NULL) + { + j--; + }*/ + engineDebuggingDLLBase = NULL; + engineDebuggingMainModuleBase = NULL; + engineDebuggingDLLFullFileName = szFileName; + engineDebuggingDLLFileName = &szFileName[i+1]; + //engineDebuggingDLLReserveFileName = &szReserveModuleName[j+1]; + DebugModuleImageBase = (ULONG_PTR)GetPE32DataW(szFileName, NULL, UE_IMAGEBASE); + engineReserveModuleBase = DebugModuleImageBase; + DebugModuleEntryPoint = (ULONG_PTR)GetPE32DataW(szFileName, NULL, UE_OEP); + DebugModuleEntryPointCallBack = EntryCallBack; + /*if(ReserveModuleBase) + { + RelocaterChangeFileBaseW(szReserveModuleName, DebugModuleImageBase); + }*/ + return(InitDebugW(szDebuggerName, szCommandLine, szCurrentFolder)); + } + else + { + return(NULL); + } + return(NULL); +} +__declspec(dllexport) bool __stdcall StopDebug() +{ + if(dbgProcessInformation.hProcess != NULL) + { + TerminateThread(dbgProcessInformation.hThread, NULL); + TerminateProcess(dbgProcessInformation.hProcess, NULL); + return(true); + } + else + { + return(false); + } +} +__declspec(dllexport) void __stdcall SetBPXOptions(long DefaultBreakPointType) +{ + engineDefaultBreakPointType = DefaultBreakPointType; +} +__declspec(dllexport) bool __stdcall IsBPXEnabled(ULONG_PTR bpxAddress) +{ + + int i; + ULONG_PTR NumberOfBytesReadWritten = 0; + DWORD MaximumBreakPoints = 0; + BYTE ReadData[10] = {}; + + for(i = 0; i < BreakPointSetCount; i++) + { + if(BreakPointBuffer[i].BreakPointAddress == bpxAddress) + { + if(BreakPointBuffer[i].BreakPointActive != UE_BPXINACTIVE && BreakPointBuffer[i].BreakPointActive != UE_BPXREMOVED) + { + if(ReadProcessMemory(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, &ReadData[0], UE_MAX_BREAKPOINT_SIZE, &NumberOfBytesReadWritten)) + { + if(BreakPointBuffer[i].AdvancedBreakPointType == UE_BREAKPOINT_INT3 && ReadData[0] == INT3BreakPoint) + { + return(true); + } + else if(BreakPointBuffer[i].AdvancedBreakPointType == UE_BREAKPOINT_LONG_INT3 && ReadData[0] == INT3LongBreakPoint[0] && ReadData[1] == INT3LongBreakPoint[1]) + { + return(true); + } + else if(BreakPointBuffer[i].AdvancedBreakPointType == UE_BREAKPOINT_UD2 && ReadData[0] == UD2BreakPoint[0] && ReadData[1] == UD2BreakPoint[1]) + { + return(true); + } + else + { + return(false); + } + } + else + { + return(false); + } + } + else + { + return(false); + } + } + } + return(false); +} +__declspec(dllexport) bool __stdcall EnableBPX(ULONG_PTR bpxAddress) +{ + + int i; + MEMORY_BASIC_INFORMATION MemInfo; + ULONG_PTR NumberOfBytesReadWritten = 0; + DWORD MaximumBreakPoints = 0; + bool testWrite = false; + DWORD OldProtect; + + for(i = 0; i < BreakPointSetCount; i++) + { + if(BreakPointBuffer[i].BreakPointAddress == bpxAddress) + { + VirtualQueryEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + OldProtect = MemInfo.AllocationProtect; + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer[i].BreakPointSize, PAGE_EXECUTE_READWRITE, &OldProtect); + if(BreakPointBuffer[i].BreakPointActive == UE_BPXINACTIVE && (BreakPointBuffer[i].BreakPointType == UE_BREAKPOINT || BreakPointBuffer[i].BreakPointType == UE_SINGLESHOOT)) + { + if(BreakPointBuffer[i].AdvancedBreakPointType == UE_BREAKPOINT_INT3) + { + if(WriteProcessMemory(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, &INT3BreakPoint, 1, &NumberOfBytesReadWritten)) + { + testWrite = true; + } + } + else if(BreakPointBuffer[i].AdvancedBreakPointType == UE_BREAKPOINT_LONG_INT3) + { + if(WriteProcessMemory(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, &INT3LongBreakPoint, 2, &NumberOfBytesReadWritten)) + { + testWrite = true; + } + } + else if(BreakPointBuffer[i].AdvancedBreakPointType == UE_BREAKPOINT_UD2) + { + if(WriteProcessMemory(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, &UD2BreakPoint, 2, &NumberOfBytesReadWritten)) + { + testWrite = true; + } + } + if(testWrite) + { + BreakPointBuffer[i].BreakPointActive = UE_BPXACTIVE; + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer[i].BreakPointSize, MemInfo.AllocationProtect, &OldProtect); + return(true); + } + else + { + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer[i].BreakPointSize, MemInfo.AllocationProtect, &OldProtect); + return(false); + } + } + else + { + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer[i].BreakPointSize, MemInfo.AllocationProtect, &OldProtect); + return(false); + } + } + } + return(false); +} +__declspec(dllexport) bool __stdcall DisableBPX(ULONG_PTR bpxAddress) +{ + + int i; + MEMORY_BASIC_INFORMATION MemInfo; + ULONG_PTR NumberOfBytesReadWritten = 0; + DWORD MaximumBreakPoints = 0; + DWORD OldProtect; + + for(i = 0; i < BreakPointSetCount; i++) + { + if(BreakPointBuffer[i].BreakPointAddress == bpxAddress) + { + VirtualQueryEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + OldProtect = MemInfo.AllocationProtect; + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer[i].BreakPointSize, PAGE_EXECUTE_READWRITE, &OldProtect); + if(BreakPointBuffer[i].BreakPointActive == UE_BPXACTIVE && (BreakPointBuffer[i].BreakPointType == UE_BREAKPOINT || BreakPointBuffer[i].BreakPointType == UE_SINGLESHOOT)) + { + if(WriteProcessMemory(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, &BreakPointBuffer[i].OriginalByte[0], BreakPointBuffer[i].BreakPointSize, &NumberOfBytesReadWritten)) + { + BreakPointBuffer[i].BreakPointActive = UE_BPXINACTIVE; + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer[i].BreakPointSize, MemInfo.AllocationProtect, &OldProtect); + return(true); + } + else + { + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer[i].BreakPointSize, MemInfo.AllocationProtect, &OldProtect); + return(false); + } + } + else + { + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer[i].BreakPointSize, MemInfo.AllocationProtect, &OldProtect); + return(false); + } + } + } + return(false); +} +__declspec(dllexport) bool __stdcall SetBPX(ULONG_PTR bpxAddress, DWORD bpxType, LPVOID bpxCallBack) +{ + + int i = 0; + int j = -1; + void* bpxDataPrt; + PMEMORY_COMPARE_HANDLER bpxDataCmpPtr; + MEMORY_BASIC_INFORMATION MemInfo; + ULONG_PTR NumberOfBytesReadWritten = 0; + BYTE SelectedBreakPointType; + DWORD checkBpxType; + DWORD OldProtect; + + if(bpxCallBack == NULL) + { + return(false); + } + for(i = 0; i < BreakPointSetCount; i++) + { + if(BreakPointBuffer[i].BreakPointAddress == bpxAddress && BreakPointBuffer[i].BreakPointActive == UE_BPXACTIVE) + { + return(false); + } + else if(BreakPointBuffer[i].BreakPointAddress == bpxAddress && BreakPointBuffer[i].BreakPointActive == UE_BPXINACTIVE) + { + return(EnableBPX(bpxAddress)); + } + else if(j == -1 && BreakPointBuffer[i].BreakPointActive == UE_BPXREMOVED) + { + j = i; + } + } + if(j == -1) + { + BreakPointSetCount++; + } + else + { + i = j; + } + if(i < MAXIMUM_BREAKPOINTS) + { + RtlZeroMemory(&BreakPointBuffer[i], sizeof BreakPointDetail); + if(bpxType < UE_BREAKPOINT_TYPE_INT3) + { + if(engineDefaultBreakPointType == UE_BREAKPOINT_INT3) + { + SelectedBreakPointType = UE_BREAKPOINT_INT3; + BreakPointBuffer[i].BreakPointSize = 1; + bpxDataPrt = &INT3BreakPoint; + } + else if(engineDefaultBreakPointType == UE_BREAKPOINT_LONG_INT3) + { + SelectedBreakPointType = UE_BREAKPOINT_LONG_INT3; + BreakPointBuffer[i].BreakPointSize = 2; + bpxDataPrt = &INT3LongBreakPoint; + } + else if(engineDefaultBreakPointType == UE_BREAKPOINT_UD2) + { + SelectedBreakPointType = UE_BREAKPOINT_UD2; + BreakPointBuffer[i].BreakPointSize = 2; + bpxDataPrt = &UD2BreakPoint; + } + } + else + { + checkBpxType = bpxType >> 24; + checkBpxType = checkBpxType << 24; + if(checkBpxType == UE_BREAKPOINT_TYPE_INT3) + { + SelectedBreakPointType = UE_BREAKPOINT_INT3; + BreakPointBuffer[i].BreakPointSize = 1; + bpxDataPrt = &INT3BreakPoint; + } + else if(checkBpxType == UE_BREAKPOINT_TYPE_LONG_INT3) + { + SelectedBreakPointType = UE_BREAKPOINT_LONG_INT3; + BreakPointBuffer[i].BreakPointSize = 2; + bpxDataPrt = &INT3LongBreakPoint; + } + else if(checkBpxType == UE_BREAKPOINT_TYPE_UD2) + { + SelectedBreakPointType = UE_BREAKPOINT_UD2; + BreakPointBuffer[i].BreakPointSize = 2; + bpxDataPrt = &UD2BreakPoint; + } + } + bpxDataCmpPtr = (PMEMORY_COMPARE_HANDLER)bpxDataPrt; + VirtualQueryEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + OldProtect = MemInfo.AllocationProtect; + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer[i].BreakPointSize, PAGE_EXECUTE_READWRITE, &OldProtect); + if(ReadProcessMemory(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, &BreakPointBuffer[i].OriginalByte[0], BreakPointBuffer[i].BreakPointSize, &NumberOfBytesReadWritten)) + { + /*if(BreakPointBuffer[i].OriginalByte[0] != bpxDataCmpPtr->Array.bArrayEntry[0]) + {*/ + if(WriteProcessMemory(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, bpxDataPrt, BreakPointBuffer[i].BreakPointSize, &NumberOfBytesReadWritten)) + { + BreakPointBuffer[i].AdvancedBreakPointType = (BYTE)SelectedBreakPointType; + BreakPointBuffer[i].BreakPointActive = UE_BPXACTIVE; + BreakPointBuffer[i].BreakPointAddress = bpxAddress; + BreakPointBuffer[i].BreakPointType = (BYTE)bpxType; + BreakPointBuffer[i].NumberOfExecutions = -1; + BreakPointBuffer[i].ExecuteCallBack = (ULONG_PTR)bpxCallBack; + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer[i].BreakPointSize, MemInfo.AllocationProtect, &OldProtect); + return(true); + } + else + { + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer[i].BreakPointSize, MemInfo.AllocationProtect, &OldProtect); + return(false); + } + /*} + else + { + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer[i].BreakPointSize, MemInfo.AllocationProtect, &OldProtect); + return(false); + }*/ + } + else + { + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer[i].BreakPointSize, MemInfo.AllocationProtect, &OldProtect); + return(false); + } + } + else + { + BreakPointSetCount--; + return(false); + } +} +__declspec(dllexport) bool __stdcall SetBPXEx(ULONG_PTR bpxAddress, DWORD bpxType, DWORD NumberOfExecution, DWORD CmpRegister, DWORD CmpCondition, ULONG_PTR CmpValue, LPVOID bpxCallBack, LPVOID bpxCompareCallBack, LPVOID bpxRemoveCallBack) +{ + + int i = 0; + int j = -1; + void* bpxDataPrt; + PMEMORY_COMPARE_HANDLER bpxDataCmpPtr; + MEMORY_BASIC_INFORMATION MemInfo; + ULONG_PTR NumberOfBytesReadWritten = 0; + BYTE SelectedBreakPointType; + DWORD checkBpxType; + DWORD OldProtect; + + if(bpxCallBack == NULL) + { + return(false); + } + for(i = 0; i < BreakPointSetCount; i++) + { + if(BreakPointBuffer[i].BreakPointAddress == bpxAddress && BreakPointBuffer[i].BreakPointActive == UE_BPXACTIVE) + { + return(true); + } + else if(BreakPointBuffer[i].BreakPointAddress == bpxAddress && BreakPointBuffer[i].BreakPointActive == UE_BPXINACTIVE) + { + return(EnableBPX(bpxAddress)); + } + else if(j == -1 && BreakPointBuffer[i].BreakPointActive == UE_BPXREMOVED) + { + j = i; + } + } + if(j == -1) + { + BreakPointSetCount++; + } + else + { + i = j; + } + if(i < MAXIMUM_BREAKPOINTS) + { + RtlZeroMemory(&BreakPointBuffer[i], sizeof BreakPointDetail); + if(bpxType < UE_BREAKPOINT_TYPE_INT3) + { + if(engineDefaultBreakPointType == UE_BREAKPOINT_INT3) + { + SelectedBreakPointType = UE_BREAKPOINT_INT3; + BreakPointBuffer[i].BreakPointSize = 1; + bpxDataPrt = &INT3BreakPoint; + } + else if(engineDefaultBreakPointType == UE_BREAKPOINT_LONG_INT3) + { + SelectedBreakPointType = UE_BREAKPOINT_LONG_INT3; + BreakPointBuffer[i].BreakPointSize = 2; + bpxDataPrt = &INT3LongBreakPoint; + } + else if(engineDefaultBreakPointType == UE_BREAKPOINT_UD2) + { + SelectedBreakPointType = UE_BREAKPOINT_UD2; + BreakPointBuffer[i].BreakPointSize = 2; + bpxDataPrt = &UD2BreakPoint; + } + } + else + { + checkBpxType = bpxType >> 24; + checkBpxType = checkBpxType << 24; + if(checkBpxType == UE_BREAKPOINT_TYPE_INT3) + { + SelectedBreakPointType = UE_BREAKPOINT_INT3; + BreakPointBuffer[i].BreakPointSize = 1; + bpxDataPrt = &INT3BreakPoint; + } + else if(checkBpxType == UE_BREAKPOINT_TYPE_LONG_INT3) + { + SelectedBreakPointType = UE_BREAKPOINT_LONG_INT3; + BreakPointBuffer[i].BreakPointSize = 2; + bpxDataPrt = &INT3LongBreakPoint; + } + else if(checkBpxType == UE_BREAKPOINT_TYPE_UD2) + { + SelectedBreakPointType = UE_BREAKPOINT_UD2; + BreakPointBuffer[i].BreakPointSize = 2; + bpxDataPrt = &UD2BreakPoint; + } + } + bpxDataCmpPtr = (PMEMORY_COMPARE_HANDLER)bpxDataPrt; + VirtualQueryEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + OldProtect = MemInfo.AllocationProtect; + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer[i].BreakPointSize, PAGE_EXECUTE_READWRITE, &OldProtect); + if(ReadProcessMemory(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, &BreakPointBuffer[i].OriginalByte[0], BreakPointBuffer[i].BreakPointSize, &NumberOfBytesReadWritten)) + { + /*if(BreakPointBuffer[i].OriginalByte[0] != bpxDataCmpPtr->Array.bArrayEntry[0]) + {*/ + if(WriteProcessMemory(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, bpxDataPrt, BreakPointBuffer[i].BreakPointSize, &NumberOfBytesReadWritten)) + { + BreakPointBuffer[i].AdvancedBreakPointType = (BYTE)SelectedBreakPointType; + BreakPointBuffer[i].BreakPointActive = UE_BPXACTIVE; + BreakPointBuffer[i].BreakPointAddress = bpxAddress; + BreakPointBuffer[i].BreakPointType = (BYTE)bpxType; + BreakPointBuffer[i].NumberOfExecutions = NumberOfExecution; + BreakPointBuffer[i].CmpRegister = CmpRegister; + BreakPointBuffer[i].CmpCondition = (BYTE)CmpCondition; + BreakPointBuffer[i].CmpValue = CmpValue; + BreakPointBuffer[i].ExecuteCallBack = (ULONG_PTR)bpxCallBack; + BreakPointBuffer[i].RemoveCallBack = (ULONG_PTR)bpxRemoveCallBack; + BreakPointBuffer[i].CompareCallBack = (ULONG_PTR)bpxCompareCallBack; + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer[i].BreakPointSize, MemInfo.AllocationProtect, &OldProtect); + return(true); + } + else + { + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer[i].BreakPointSize, MemInfo.AllocationProtect, &OldProtect); + return(false); + } + /*} + else + { + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer[i].BreakPointSize, MemInfo.AllocationProtect, &OldProtect); + return(false); + }*/ + } + else + { + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer[i].BreakPointSize, MemInfo.AllocationProtect, &OldProtect); + return(false); + } + } + else + { + BreakPointSetCount--; + return(false); + } +} +__declspec(dllexport) bool __stdcall DeleteBPX(ULONG_PTR bpxAddress) +{ + + int i; + typedef void(__stdcall *fCustomBreakPoint)(void* myBreakPointAddress); + fCustomBreakPoint myCustomBreakPoint; + MEMORY_BASIC_INFORMATION MemInfo; + ULONG_PTR NumberOfBytesReadWritten = 0; + DWORD OldProtect; + + for(i = 0; i < BreakPointSetCount; i++) + { + if(BreakPointBuffer[i].BreakPointAddress == bpxAddress) + { + if(i - 1 == BreakPointSetCount) + { + BreakPointSetCount--; + } + break; + } + } + if(BreakPointBuffer[i].BreakPointAddress == bpxAddress) + { + VirtualQueryEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + OldProtect = MemInfo.AllocationProtect; + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer[i].BreakPointSize, PAGE_EXECUTE_READWRITE, &OldProtect); + if(BreakPointBuffer[i].BreakPointType == UE_BREAKPOINT || BreakPointBuffer[i].BreakPointType == UE_SINGLESHOOT) + { + if(BreakPointBuffer[i].BreakPointActive == UE_BPXACTIVE) + { + if(WriteProcessMemory(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, &BreakPointBuffer[i].OriginalByte[0], BreakPointBuffer[i].BreakPointSize, &NumberOfBytesReadWritten)) + { + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer[i].BreakPointSize, MemInfo.AllocationProtect, &OldProtect); + if(BreakPointBuffer[i].RemoveCallBack != NULL) + { + __try + { + myCustomBreakPoint = (fCustomBreakPoint)((LPVOID)BreakPointBuffer[i].RemoveCallBack); + myCustomBreakPoint((void*)BreakPointBuffer[i].BreakPointAddress); + RtlZeroMemory(&BreakPointBuffer[i], sizeof BreakPointDetail); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + RtlZeroMemory(&BreakPointBuffer[i], sizeof BreakPointDetail); + return(true); + } + } + else + { + RtlZeroMemory(&BreakPointBuffer[i], sizeof BreakPointDetail); + } + return(true); + } + else + { + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer[i].BreakPointSize, MemInfo.AllocationProtect, &OldProtect); + return(false); + } + } + else + { + RtlZeroMemory(&BreakPointBuffer[i], sizeof BreakPointDetail); + return(true); + } + } + else + { + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxAddress, BreakPointBuffer[i].BreakPointSize, MemInfo.AllocationProtect, &OldProtect); + return(false); + } + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall SafeDeleteBPX(ULONG_PTR bpxAddress) +{ + return(DeleteBPX(bpxAddress)); +} +__declspec(dllexport) bool __stdcall SetAPIBreakPoint(char* szDLLName, char* szAPIName, DWORD bpxType, DWORD bpxPlace, LPVOID bpxCallBack) +{ + + BYTE ReadByte = NULL; + HMODULE hModule = NULL; + DWORD ReadMemSize = NULL; + ULONG_PTR APIAddress = NULL; + ULONG_PTR tryAPIAddress = NULL; + ULONG_PTR QueryAPIAddress = NULL; + int i = MAX_RET_SEARCH_INSTRUCTIONS; + ULONG_PTR ueNumberOfReadWrite = NULL; + int currentInstructionLen = NULL; + bool ModuleLoaded = false; + void* CmdBuffer = NULL; + bool RemovedBpx = false; + + if(szDLLName != NULL && szAPIName != NULL) + { + hModule = GetModuleHandleA(szDLLName); + if(hModule == NULL) + { + if(engineAlowModuleLoading) + { + hModule = LoadLibraryA(szDLLName); + ModuleLoaded = true; + } + else + { + ReadMemSize = MAX_RET_SEARCH_INSTRUCTIONS * MAXIMUM_INSTRUCTION_SIZE; + APIAddress = (ULONG_PTR)EngineGlobalAPIHandler(dbgProcessInformation.hProcess, NULL, NULL, szAPIName, UE_OPTION_IMPORTER_RETURN_APIADDRESS); + if(APIAddress != NULL) + { + CmdBuffer = VirtualAlloc(NULL, ReadMemSize, MEM_COMMIT, PAGE_READWRITE); + while(ReadProcessMemory(dbgProcessInformation.hProcess, (void*)APIAddress, CmdBuffer, ReadMemSize, &ueNumberOfReadWrite) == false && ReadMemSize > NULL) + { + ReadMemSize = ReadMemSize - (MAXIMUM_INSTRUCTION_SIZE * 10); + } + if(ReadMemSize == NULL) + { + VirtualFree(CmdBuffer, NULL, MEM_RELEASE); + APIAddress = NULL; + } + else + { + tryAPIAddress = (ULONG_PTR)CmdBuffer; + } + } + } + } + if(hModule != NULL || APIAddress != NULL) + { + if(hModule != NULL) + { + APIAddress = (ULONG_PTR)GetProcAddress(hModule, szAPIName); + } + if(bpxPlace == UE_APIEND) + { + if(tryAPIAddress == NULL) + { + tryAPIAddress = APIAddress; + } + QueryAPIAddress = APIAddress; + RtlMoveMemory(&ReadByte, (LPVOID)tryAPIAddress, 1); + while(i > 0 && ReadByte != 0xC3 && ReadByte != 0xC2) + { + if(engineAlowModuleLoading == false && CmdBuffer != NULL) + { + if(IsBPXEnabled(QueryAPIAddress)) + { + DisableBPX(QueryAPIAddress); + ReadProcessMemory(dbgProcessInformation.hProcess, (void*)APIAddress, CmdBuffer, ReadMemSize, &ueNumberOfReadWrite); + RemovedBpx = true; + } + } + currentInstructionLen = StaticLengthDisassemble((LPVOID)tryAPIAddress); + tryAPIAddress = tryAPIAddress + currentInstructionLen; + RtlMoveMemory(&ReadByte, (LPVOID)tryAPIAddress, 1); + QueryAPIAddress = QueryAPIAddress + currentInstructionLen; + if(!engineAlowModuleLoading) + { + if(RemovedBpx) + { + EnableBPX(QueryAPIAddress - currentInstructionLen); + } + } + RemovedBpx = false; + i--; + } + if(i != NULL) + { + if((engineAlowModuleLoading == true && ModuleLoaded == true) || (engineAlowModuleLoading == true && ModuleLoaded == false)) + { + APIAddress = tryAPIAddress; + } + else if(!engineAlowModuleLoading) + { + if(CmdBuffer != NULL) + { + APIAddress = tryAPIAddress - (ULONG_PTR)CmdBuffer + APIAddress; + } + else + { + APIAddress = tryAPIAddress; + } + } + } + else + { + if(ModuleLoaded) + { + FreeLibrary(hModule); + } + if(CmdBuffer != NULL) + { + VirtualFree(CmdBuffer, NULL, MEM_RELEASE); + } + return(false); + } + } + if(engineAlowModuleLoading) + { + APIAddress = (ULONG_PTR)EngineGlobalAPIHandler(dbgProcessInformation.hProcess, NULL, APIAddress, NULL, UE_OPTION_IMPORTER_REALIGN_APIADDRESS); + if(ModuleLoaded) + { + FreeLibrary(hModule); + } + } + else + { + if(CmdBuffer != NULL) + { + VirtualFree(CmdBuffer, NULL, MEM_RELEASE); + } + } + return(SetBPX(APIAddress, bpxType, bpxCallBack)); + } + else + { + if(engineAlowModuleLoading) + { + if(ModuleLoaded) + { + FreeLibrary(hModule); + } + } + else + { + if(CmdBuffer != NULL) + { + VirtualFree(CmdBuffer, NULL, MEM_RELEASE); + } + } + return(false); + } + } + else + { + return(false); + } + return(false); +} +__declspec(dllexport) bool __stdcall DeleteAPIBreakPoint(char* szDLLName, char* szAPIName, DWORD bpxPlace) +{ + + BYTE ReadByte = NULL; + HMODULE hModule = NULL; + DWORD ReadMemSize = NULL; + ULONG_PTR APIAddress = NULL; + ULONG_PTR tryAPIAddress = NULL; + ULONG_PTR QueryAPIAddress = NULL; + int i = MAX_RET_SEARCH_INSTRUCTIONS; + ULONG_PTR ueNumberOfReadWrite = NULL; + int currentInstructionLen = NULL; + bool ModuleLoaded = false; + void* CmdBuffer = NULL; + bool RemovedBpx = false; + + if(szDLLName != NULL && szAPIName != NULL) + { + hModule = GetModuleHandleA(szDLLName); + if(hModule == NULL) + { + if(engineAlowModuleLoading) + { + hModule = LoadLibraryA(szDLLName); + ModuleLoaded = true; + } + else + { + ReadMemSize = MAX_RET_SEARCH_INSTRUCTIONS * MAXIMUM_INSTRUCTION_SIZE; + APIAddress = (ULONG_PTR)EngineGlobalAPIHandler(dbgProcessInformation.hProcess, NULL, NULL, szAPIName, UE_OPTION_IMPORTER_RETURN_APIADDRESS); + if(APIAddress != NULL) + { + CmdBuffer = VirtualAlloc(NULL, ReadMemSize, MEM_COMMIT, PAGE_READWRITE); + while(ReadProcessMemory(dbgProcessInformation.hProcess, (void*)APIAddress, CmdBuffer, ReadMemSize, &ueNumberOfReadWrite) == false && ReadMemSize > NULL) + { + ReadMemSize = ReadMemSize - (MAXIMUM_INSTRUCTION_SIZE * 10); + } + if(ReadMemSize == NULL) + { + VirtualFree(CmdBuffer, NULL, MEM_RELEASE); + APIAddress = NULL; + } + else + { + tryAPIAddress = (ULONG_PTR)CmdBuffer; + } + } + } + } + if(hModule != NULL || APIAddress != NULL) + { + if(hModule != NULL) + { + APIAddress = (ULONG_PTR)GetProcAddress(hModule, szAPIName); + } + if(bpxPlace == UE_APIEND) + { + if(tryAPIAddress == NULL) + { + tryAPIAddress = APIAddress; + } + QueryAPIAddress = APIAddress; + RtlMoveMemory(&ReadByte, (LPVOID)tryAPIAddress, 1); + while(i > 0 && ReadByte != 0xC3 && ReadByte != 0xC2) + { + if(engineAlowModuleLoading == false && CmdBuffer != NULL) + { + if(IsBPXEnabled(QueryAPIAddress)) + { + DisableBPX(QueryAPIAddress); + ReadProcessMemory(dbgProcessInformation.hProcess, (void*)APIAddress, CmdBuffer, ReadMemSize, &ueNumberOfReadWrite); + RemovedBpx = true; + } + } + currentInstructionLen = StaticLengthDisassemble((LPVOID)tryAPIAddress); + tryAPIAddress = tryAPIAddress + currentInstructionLen; + RtlMoveMemory(&ReadByte, (LPVOID)tryAPIAddress, 1); + QueryAPIAddress = QueryAPIAddress + currentInstructionLen; + if(!engineAlowModuleLoading) + { + if(RemovedBpx) + { + EnableBPX(QueryAPIAddress - currentInstructionLen); + } + } + RemovedBpx = false; + i--; + } + if(i != NULL) + { + if((engineAlowModuleLoading == true && ModuleLoaded == true) || (engineAlowModuleLoading == true && ModuleLoaded == false)) + { + APIAddress = tryAPIAddress; + } + else if(!engineAlowModuleLoading) + { + if(CmdBuffer != NULL) + { + APIAddress = tryAPIAddress - (ULONG_PTR)CmdBuffer + APIAddress; + } + else + { + APIAddress = tryAPIAddress; + } + } + } + else + { + if(ModuleLoaded) + { + FreeLibrary(hModule); + } + if(CmdBuffer != NULL) + { + VirtualFree(CmdBuffer, NULL, MEM_RELEASE); + } + return(false); + } + } + if(engineAlowModuleLoading) + { + APIAddress = (ULONG_PTR)EngineGlobalAPIHandler(dbgProcessInformation.hProcess, NULL, APIAddress, NULL, UE_OPTION_IMPORTER_REALIGN_APIADDRESS); + if(ModuleLoaded) + { + FreeLibrary(hModule); + } + } + else + { + if(CmdBuffer != NULL) + { + VirtualFree(CmdBuffer, NULL, MEM_RELEASE); + } + } + return(DeleteBPX(APIAddress)); + } + else + { + if(engineAlowModuleLoading) + { + if(ModuleLoaded) + { + FreeLibrary(hModule); + } + } + else + { + if(CmdBuffer != NULL) + { + VirtualFree(CmdBuffer, NULL, MEM_RELEASE); + } + } + return(false); + } + } + else + { + return(false); + } + return(false); +} +__declspec(dllexport) bool __stdcall SafeDeleteAPIBreakPoint(char* szDLLName, char* szAPIName, DWORD bpxPlace) +{ + return(DeleteAPIBreakPoint(szDLLName, szAPIName, bpxPlace)); +} +__declspec(dllexport) bool __stdcall SetMemoryBPX(ULONG_PTR MemoryStart, DWORD SizeOfMemory, LPVOID bpxCallBack) +{ + int i = 0; + int j = -1; + MEMORY_BASIC_INFORMATION MemInfo; + ULONG_PTR NumberOfBytesReadWritten = 0; + DWORD NewProtect = 0; + DWORD OldProtect = 0; + + for(i = 0; i < BreakPointSetCount; i++) + { + if(BreakPointBuffer[i].BreakPointAddress == MemoryStart) + { + if(BreakPointBuffer[i].BreakPointActive == UE_BPXACTIVE) + { + RemoveMemoryBPX(BreakPointBuffer[i].BreakPointAddress, BreakPointBuffer[i].BreakPointSize); + } + j = i; + break; + } + else if(j == -1 && BreakPointBuffer[i].BreakPointActive == UE_BPXREMOVED) + { + j = i; + } + } + if(BreakPointBuffer[i].BreakPointAddress != MemoryStart) + { + if(j != -1) + { + i = j; + } + else + { + BreakPointSetCount++; + } + } + if(i < MAXIMUM_BREAKPOINTS) + { + RtlZeroMemory(&BreakPointBuffer[i], sizeof BreakPointDetail); + VirtualQueryEx(dbgProcessInformation.hProcess, (LPVOID)MemoryStart, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + OldProtect = MemInfo.Protect; + if(!(OldProtect & PAGE_GUARD)) + { + NewProtect = OldProtect ^ PAGE_GUARD; + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)MemoryStart, SizeOfMemory, NewProtect, &OldProtect); + BreakPointBuffer[i].BreakPointActive = UE_BPXACTIVE; + BreakPointBuffer[i].BreakPointAddress = MemoryStart; + BreakPointBuffer[i].BreakPointType = UE_MEMORY; + BreakPointBuffer[i].BreakPointSize = SizeOfMemory; + BreakPointBuffer[i].NumberOfExecutions = -1; + BreakPointBuffer[i].ExecuteCallBack = (ULONG_PTR)bpxCallBack; + } + return(true); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall SetMemoryBPXEx(ULONG_PTR MemoryStart, DWORD SizeOfMemory, DWORD BreakPointType, bool RestoreOnHit, LPVOID bpxCallBack) +{ + + int i = 0; + int j = -1; + MEMORY_BASIC_INFORMATION MemInfo; + ULONG_PTR NumberOfBytesReadWritten = 0; + DWORD NewProtect = 0; + DWORD OldProtect = 0; + + for(i = 0; i < BreakPointSetCount; i++) + { + if(BreakPointBuffer[i].BreakPointAddress == MemoryStart) + { + if(BreakPointBuffer[i].BreakPointActive == UE_BPXACTIVE) + { + RemoveMemoryBPX(BreakPointBuffer[i].BreakPointAddress, BreakPointBuffer[i].BreakPointSize); + } + j = i; + break; + } + else if(j == -1 && BreakPointBuffer[i].BreakPointActive == UE_BPXREMOVED) + { + j = i; + } + } + if(BreakPointBuffer[i].BreakPointAddress != MemoryStart) + { + if(j != -1) + { + i = j; + } + else + { + BreakPointSetCount++; + } + } + if(i < MAXIMUM_BREAKPOINTS) + { + RtlZeroMemory(&BreakPointBuffer[i], sizeof BreakPointDetail); + VirtualQueryEx(dbgProcessInformation.hProcess, (LPVOID)MemoryStart, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + OldProtect = MemInfo.Protect; + if(!(OldProtect & PAGE_GUARD)) + { + NewProtect = OldProtect ^ PAGE_GUARD; + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)MemoryStart, SizeOfMemory, NewProtect, &OldProtect); + BreakPointBuffer[i].BreakPointActive = UE_BPXACTIVE; + BreakPointBuffer[i].BreakPointAddress = MemoryStart; + BreakPointBuffer[i].BreakPointType = BreakPointType; + BreakPointBuffer[i].BreakPointSize = SizeOfMemory; + BreakPointBuffer[i].NumberOfExecutions = -1; + BreakPointBuffer[i].MemoryBpxRestoreOnHit = (BYTE)RestoreOnHit; + BreakPointBuffer[i].ExecuteCallBack = (ULONG_PTR)bpxCallBack; + } + return(true); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall RemoveMemoryBPX(ULONG_PTR MemoryStart, DWORD SizeOfMemory) +{ + + int i = 0; + MEMORY_BASIC_INFORMATION MemInfo; + ULONG_PTR NumberOfBytesReadWritten = 0; + DWORD NewProtect = 0; + DWORD OldProtect = 0; + + for(i = 0; i < BreakPointSetCount; i++) + { + if(BreakPointBuffer[i].BreakPointAddress == MemoryStart && BreakPointBuffer[i].BreakPointType == UE_MEMORY) + { + if(i - 1 == BreakPointSetCount) + { + BreakPointSetCount--; + } + break; + } + } + if(BreakPointBuffer[i].BreakPointAddress == MemoryStart) + { + VirtualQueryEx(dbgProcessInformation.hProcess, (LPVOID)MemoryStart, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + OldProtect = MemInfo.AllocationProtect; + if(OldProtect & PAGE_GUARD) + { + NewProtect = OldProtect ^ PAGE_GUARD; + } + else + { + NewProtect = OldProtect; + } + if(SizeOfMemory != NULL) + { + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)MemoryStart, SizeOfMemory, NewProtect, &OldProtect); + } + else + { + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)MemoryStart, BreakPointBuffer[i].BreakPointSize, NewProtect, &OldProtect); + } + RtlZeroMemory(&BreakPointBuffer[i], sizeof BreakPointDetail); + return(true); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall GetContextFPUDataEx(HANDLE hActiveThread, void* FPUSaveArea) +{ + + if(FPUSaveArea != NULL) + { + RtlZeroMemory(&DBGContext, sizeof CONTEXT); + DBGContext.ContextFlags = CONTEXT_ALL; + GetThreadContext(hActiveThread, &DBGContext); +#if !defined (_WIN64) + RtlMoveMemory(FPUSaveArea, &DBGContext.FloatSave, sizeof FLOATING_SAVE_AREA); +#else + RtlMoveMemory(FPUSaveArea, &DBGContext.FltSave, sizeof XMM_SAVE_AREA32); +#endif + return(true); + } + else + { + return(false); + } +} +__declspec(dllexport) long long __stdcall GetContextDataEx(HANDLE hActiveThread, DWORD IndexOfRegister) +{ + + RtlZeroMemory(&DBGContext, sizeof CONTEXT); + DBGContext.ContextFlags = CONTEXT_ALL; +#if defined(_WIN64) + GetThreadContext(hActiveThread, &DBGContext); + if(IndexOfRegister == UE_EAX) + { + return((DWORD)DBGContext.Rax); + } + else if(IndexOfRegister == UE_EBX) + { + return((DWORD)DBGContext.Rbx); + } + else if(IndexOfRegister == UE_ECX) + { + return((DWORD)DBGContext.Rcx); + } + else if(IndexOfRegister == UE_EDX) + { + return((DWORD)DBGContext.Rdx); + } + else if(IndexOfRegister == UE_EDI) + { + return((DWORD)DBGContext.Rdi); + } + else if(IndexOfRegister == UE_ESI) + { + return((DWORD)DBGContext.Rsi); + } + else if(IndexOfRegister == UE_EBP) + { + return((DWORD)DBGContext.Rbp); + } + else if(IndexOfRegister == UE_ESP) + { + return((DWORD)DBGContext.Rsp); + } + else if(IndexOfRegister == UE_EIP) + { + return((DWORD)DBGContext.Rip); + } + else if(IndexOfRegister == UE_EFLAGS) + { + return((DWORD)DBGContext.EFlags); + } + else if(IndexOfRegister == UE_RAX) + { + return(DBGContext.Rax); + } + else if(IndexOfRegister == UE_RBX) + { + return(DBGContext.Rbx); + } + else if(IndexOfRegister == UE_RCX) + { + return(DBGContext.Rcx); + } + else if(IndexOfRegister == UE_RDX) + { + return(DBGContext.Rdx); + } + else if(IndexOfRegister == UE_RDI) + { + return(DBGContext.Rdi); + } + else if(IndexOfRegister == UE_RSI) + { + return(DBGContext.Rsi); + } + else if(IndexOfRegister == UE_RBP) + { + return(DBGContext.Rbp); + } + else if(IndexOfRegister == UE_RSP) + { + return(DBGContext.Rsp); + } + else if(IndexOfRegister == UE_RIP) + { + return(DBGContext.Rip); + } + else if(IndexOfRegister == UE_RFLAGS) + { + return(DBGContext.EFlags); + } + else if(IndexOfRegister == UE_DR0) + { + return(DBGContext.Dr0); + } + else if(IndexOfRegister == UE_DR1) + { + return(DBGContext.Dr1); + } + else if(IndexOfRegister == UE_DR2) + { + return(DBGContext.Dr2); + } + else if(IndexOfRegister == UE_DR3) + { + return(DBGContext.Dr3); + } + else if(IndexOfRegister == UE_DR6) + { + return(DBGContext.Dr6); + } + else if(IndexOfRegister == UE_DR7) + { + return(DBGContext.Dr7); + } + else if(IndexOfRegister == UE_R8) + { + return(DBGContext.R8); + } + else if(IndexOfRegister == UE_R9) + { + return(DBGContext.R9); + } + else if(IndexOfRegister == UE_R10) + { + return(DBGContext.R10); + } + else if(IndexOfRegister == UE_R11) + { + return(DBGContext.R11); + } + else if(IndexOfRegister == UE_R12) + { + return(DBGContext.R12); + } + else if(IndexOfRegister == UE_R13) + { + return(DBGContext.R13); + } + else if(IndexOfRegister == UE_R14) + { + return(DBGContext.R14); + } + else if(IndexOfRegister == UE_R15) + { + return(DBGContext.R15); + } + else if(IndexOfRegister == UE_CIP) + { + return(DBGContext.Rip); + } + else if(IndexOfRegister == UE_CSP) + { + return(DBGContext.Rsp); + } + else if(IndexOfRegister == UE_SEG_GS) + { + return(DBGContext.SegGs); + } + else if(IndexOfRegister == UE_SEG_FS) + { + return(DBGContext.SegFs); + } + else if(IndexOfRegister == UE_SEG_ES) + { + return(DBGContext.SegEs); + } + else if(IndexOfRegister == UE_SEG_DS) + { + return(DBGContext.SegDs); + } + else if(IndexOfRegister == UE_SEG_CS) + { + return(DBGContext.SegCs); + } + else if(IndexOfRegister == UE_SEG_SS) + { + return(DBGContext.SegSs); + } +#else + GetThreadContext(hActiveThread, &DBGContext); + if(IndexOfRegister == UE_EAX) + { + return(DBGContext.Eax); + } + else if(IndexOfRegister == UE_EBX) + { + return(DBGContext.Ebx); + } + else if(IndexOfRegister == UE_ECX) + { + return(DBGContext.Ecx); + } + else if(IndexOfRegister == UE_EDX) + { + return(DBGContext.Edx); + } + else if(IndexOfRegister == UE_EDI) + { + return(DBGContext.Edi); + } + else if(IndexOfRegister == UE_ESI) + { + return(DBGContext.Esi); + } + else if(IndexOfRegister == UE_EBP) + { + return(DBGContext.Ebp); + } + else if(IndexOfRegister == UE_ESP) + { + return(DBGContext.Esp); + } + else if(IndexOfRegister == UE_EIP) + { + return(DBGContext.Eip); + } + else if(IndexOfRegister == UE_EFLAGS) + { + return(DBGContext.EFlags); + } + else if(IndexOfRegister == UE_DR0) + { + return(DBGContext.Dr0); + } + else if(IndexOfRegister == UE_DR1) + { + return(DBGContext.Dr1); + } + else if(IndexOfRegister == UE_DR2) + { + return(DBGContext.Dr2); + } + else if(IndexOfRegister == UE_DR3) + { + return(DBGContext.Dr3); + } + else if(IndexOfRegister == UE_DR6) + { + return(DBGContext.Dr6); + } + else if(IndexOfRegister == UE_DR7) + { + return(DBGContext.Dr7); + } + else if(IndexOfRegister == UE_CIP) + { + return(DBGContext.Eip); + } + else if(IndexOfRegister == UE_CSP) + { + return(DBGContext.Esp); + } + else if(IndexOfRegister == UE_SEG_GS) + { + return(DBGContext.SegGs); + } + else if(IndexOfRegister == UE_SEG_FS) + { + return(DBGContext.SegFs); + } + else if(IndexOfRegister == UE_SEG_ES) + { + return(DBGContext.SegEs); + } + else if(IndexOfRegister == UE_SEG_DS) + { + return(DBGContext.SegDs); + } + else if(IndexOfRegister == UE_SEG_CS) + { + return(DBGContext.SegCs); + } + else if(IndexOfRegister == UE_SEG_SS) + { + return(DBGContext.SegSs); + } +#endif + return(NULL); +} +__declspec(dllexport) long long __stdcall GetContextData(DWORD IndexOfRegister) +{ + + HANDLE hActiveThread = 0; + long long ContextReturn; + + hActiveThread = OpenThread(THREAD_GET_CONTEXT+THREAD_SET_CONTEXT+THREAD_QUERY_INFORMATION, false, DBGEvent.dwThreadId); + ContextReturn = GetContextDataEx(hActiveThread, IndexOfRegister); + EngineCloseHandle(hActiveThread); + return(ContextReturn); +} +__declspec(dllexport) bool __stdcall SetContextFPUDataEx(HANDLE hActiveThread, void* FPUSaveArea) +{ + + if(FPUSaveArea != NULL) + { + RtlZeroMemory(&DBGContext, sizeof CONTEXT); + DBGContext.ContextFlags = CONTEXT_ALL; + GetThreadContext(hActiveThread, &DBGContext); +#if !defined (_WIN64) + RtlMoveMemory(&DBGContext.FloatSave, FPUSaveArea, sizeof FLOATING_SAVE_AREA); +#else + RtlMoveMemory(&DBGContext.FltSave, FPUSaveArea, sizeof XMM_SAVE_AREA32); +#endif + if(SetThreadContext(hActiveThread, &DBGContext)) + { + return(true); + } + } + return(false); +} +__declspec(dllexport) bool __stdcall SetContextDataEx(HANDLE hActiveThread, DWORD IndexOfRegister, ULONG_PTR NewRegisterValue) +{ + + RtlZeroMemory(&DBGContext, sizeof CONTEXT); + DBGContext.ContextFlags = CONTEXT_ALL; +#if defined(_WIN64) + GetThreadContext(hActiveThread, &DBGContext); + if(IndexOfRegister == UE_EAX) + { + NewRegisterValue = DBGContext.Rax - (DWORD)DBGContext.Rax + NewRegisterValue; + DBGContext.Rax = NewRegisterValue; + } + else if(IndexOfRegister == UE_EBX) + { + NewRegisterValue = DBGContext.Rbx - (DWORD)DBGContext.Rbx + NewRegisterValue; + DBGContext.Rbx = NewRegisterValue; + } + else if(IndexOfRegister == UE_ECX) + { + NewRegisterValue = DBGContext.Rcx - (DWORD)DBGContext.Rcx + NewRegisterValue; + DBGContext.Rcx = NewRegisterValue; + } + else if(IndexOfRegister == UE_EDX) + { + NewRegisterValue = DBGContext.Rdx - (DWORD)DBGContext.Rdx + NewRegisterValue; + DBGContext.Rdx = NewRegisterValue; + } + else if(IndexOfRegister == UE_EDI) + { + NewRegisterValue = DBGContext.Rdi - (DWORD)DBGContext.Rdi + NewRegisterValue; + DBGContext.Rdi = NewRegisterValue; + } + else if(IndexOfRegister == UE_ESI) + { + NewRegisterValue = DBGContext.Rsi - (DWORD)DBGContext.Rsi + NewRegisterValue; + DBGContext.Rsi = NewRegisterValue; + } + else if(IndexOfRegister == UE_EBP) + { + NewRegisterValue = DBGContext.Rbp - (DWORD)DBGContext.Rbp + NewRegisterValue; + DBGContext.Rbp = NewRegisterValue; + } + else if(IndexOfRegister == UE_ESP) + { + NewRegisterValue = DBGContext.Rsp - (DWORD)DBGContext.Rsp + NewRegisterValue; + DBGContext.Rsp = NewRegisterValue; + } + else if(IndexOfRegister == UE_EIP) + { + NewRegisterValue = DBGContext.Rip - (DWORD)DBGContext.Rip + NewRegisterValue; + DBGContext.Rip = NewRegisterValue; + } + else if(IndexOfRegister == UE_EFLAGS) + { + DBGContext.EFlags = (DWORD)NewRegisterValue; + } + else if(IndexOfRegister == UE_RAX) + { + DBGContext.Rax = NewRegisterValue; + } + else if(IndexOfRegister == UE_RBX) + { + DBGContext.Rbx = NewRegisterValue; + } + else if(IndexOfRegister == UE_RCX) + { + DBGContext.Rcx = NewRegisterValue; + } + else if(IndexOfRegister == UE_RDX) + { + DBGContext.Rdx = NewRegisterValue; + } + else if(IndexOfRegister == UE_RDI) + { + DBGContext.Rdi = NewRegisterValue; + } + else if(IndexOfRegister == UE_RSI) + { + DBGContext.Rsi = NewRegisterValue; + } + else if(IndexOfRegister == UE_RBP) + { + DBGContext.Rbp = NewRegisterValue; + } + else if(IndexOfRegister == UE_RSP) + { + DBGContext.Rsp = NewRegisterValue; + } + else if(IndexOfRegister == UE_RIP) + { + DBGContext.Rip = NewRegisterValue; + } + else if(IndexOfRegister == UE_RFLAGS) + { + DBGContext.EFlags = (DWORD)NewRegisterValue; + } + else if(IndexOfRegister == UE_DR0) + { + DBGContext.Dr0 = NewRegisterValue; + } + else if(IndexOfRegister == UE_DR1) + { + DBGContext.Dr1 = NewRegisterValue; + } + else if(IndexOfRegister == UE_DR2) + { + DBGContext.Dr2 = NewRegisterValue; + } + else if(IndexOfRegister == UE_DR3) + { + DBGContext.Dr3 = NewRegisterValue; + } + else if(IndexOfRegister == UE_DR6) + { + DBGContext.Dr6 = NewRegisterValue; + } + else if(IndexOfRegister == UE_DR7) + { + DBGContext.Dr7 = NewRegisterValue; + } + else if(IndexOfRegister == UE_R8) + { + DBGContext.R8 = NewRegisterValue; + } + else if(IndexOfRegister == UE_R9) + { + DBGContext.R9 = NewRegisterValue; + } + else if(IndexOfRegister == UE_R10) + { + DBGContext.R10 = NewRegisterValue; + } + else if(IndexOfRegister == UE_R11) + { + DBGContext.R11 = NewRegisterValue; + } + else if(IndexOfRegister == UE_R12) + { + DBGContext.R12 = NewRegisterValue; + } + else if(IndexOfRegister == UE_R13) + { + DBGContext.R13 = NewRegisterValue; + } + else if(IndexOfRegister == UE_R14) + { + DBGContext.R14 = NewRegisterValue; + } + else if(IndexOfRegister == UE_R15) + { + DBGContext.R15 = NewRegisterValue; + } + else if(IndexOfRegister == UE_CIP) + { + DBGContext.Rip = NewRegisterValue; + } + else if(IndexOfRegister == UE_CSP) + { + DBGContext.Rsp = NewRegisterValue; + } + else if(IndexOfRegister == UE_SEG_GS) + { + DBGContext.SegGs = (WORD)NewRegisterValue; + } + else if(IndexOfRegister == UE_SEG_FS) + { + DBGContext.SegFs = (WORD)NewRegisterValue; + } + else if(IndexOfRegister == UE_SEG_ES) + { + DBGContext.SegEs = (WORD)NewRegisterValue; + } + else if(IndexOfRegister == UE_SEG_DS) + { + DBGContext.SegDs = (WORD)NewRegisterValue; + } + else if(IndexOfRegister == UE_SEG_CS) + { + DBGContext.SegCs = (WORD)NewRegisterValue; + } + else if(IndexOfRegister == UE_SEG_SS) + { + DBGContext.SegSs = (WORD)NewRegisterValue; + } + else + { + return(false); + } + if(SetThreadContext(hActiveThread, &DBGContext)) + { + return(true); + } +#else + GetThreadContext(hActiveThread, &DBGContext); + if(IndexOfRegister == UE_EAX) + { + DBGContext.Eax = NewRegisterValue; + } + else if(IndexOfRegister == UE_EBX) + { + DBGContext.Ebx = NewRegisterValue; + } + else if(IndexOfRegister == UE_ECX) + { + DBGContext.Ecx = NewRegisterValue; + } + else if(IndexOfRegister == UE_EDX) + { + DBGContext.Edx = NewRegisterValue; + } + else if(IndexOfRegister == UE_EDI) + { + DBGContext.Edi = NewRegisterValue; + } + else if(IndexOfRegister == UE_ESI) + { + DBGContext.Esi = NewRegisterValue; + } + else if(IndexOfRegister == UE_EBP) + { + DBGContext.Ebp = NewRegisterValue; + } + else if(IndexOfRegister == UE_ESP) + { + DBGContext.Esp = NewRegisterValue; + } + else if(IndexOfRegister == UE_EIP) + { + DBGContext.Eip = NewRegisterValue; + } + else if(IndexOfRegister == UE_EFLAGS) + { + DBGContext.EFlags = NewRegisterValue; + } + else if(IndexOfRegister == UE_DR0) + { + DBGContext.Dr0 = NewRegisterValue; + } + else if(IndexOfRegister == UE_DR1) + { + DBGContext.Dr1 = NewRegisterValue; + } + else if(IndexOfRegister == UE_DR2) + { + DBGContext.Dr2 = NewRegisterValue; + } + else if(IndexOfRegister == UE_DR3) + { + DBGContext.Dr3 = NewRegisterValue; + } + else if(IndexOfRegister == UE_DR6) + { + DBGContext.Dr6 = NewRegisterValue; + } + else if(IndexOfRegister == UE_DR7) + { + DBGContext.Dr7 = NewRegisterValue; + } + else if(IndexOfRegister == UE_CIP) + { + DBGContext.Eip = NewRegisterValue; + } + else if(IndexOfRegister == UE_CSP) + { + DBGContext.Esp = NewRegisterValue; + } + else if(IndexOfRegister == UE_SEG_GS) + { + DBGContext.SegGs = NewRegisterValue; + } + else if(IndexOfRegister == UE_SEG_FS) + { + DBGContext.SegFs = NewRegisterValue; + } + else if(IndexOfRegister == UE_SEG_ES) + { + DBGContext.SegEs = NewRegisterValue; + } + else if(IndexOfRegister == UE_SEG_DS) + { + DBGContext.SegDs = NewRegisterValue; + } + else if(IndexOfRegister == UE_SEG_CS) + { + DBGContext.SegCs = NewRegisterValue; + } + else if(IndexOfRegister == UE_SEG_SS) + { + DBGContext.SegSs = NewRegisterValue; + } + else + { + return(false); + } + if(SetThreadContext(hActiveThread, &DBGContext)) + { + return(true); + } +#endif + return(false); +} +__declspec(dllexport) bool __stdcall SetContextData(DWORD IndexOfRegister, ULONG_PTR NewRegisterValue) +{ + + HANDLE hActiveThread = 0; + bool ContextReturn; + + hActiveThread = OpenThread(THREAD_GET_CONTEXT+THREAD_SET_CONTEXT+THREAD_QUERY_INFORMATION, false, DBGEvent.dwThreadId); + ContextReturn = SetContextDataEx(hActiveThread, IndexOfRegister, NewRegisterValue); + EngineCloseHandle(hActiveThread); + return(ContextReturn); +} +__declspec(dllexport) void __stdcall ClearExceptionNumber() +{ + CurrentExceptionsNumber = 0; +} +__declspec(dllexport) long __stdcall CurrentExceptionNumber() +{ + return(CurrentExceptionsNumber); +} +__declspec(dllexport) bool __stdcall MatchPatternEx(HANDLE hProcess, void* MemoryToCheck, int SizeOfMemoryToCheck, void* PatternToMatch, int SizeOfPatternToMatch, PBYTE WildCard) +{ + + int i = NULL; + BYTE intWildCard = NULL; + LPVOID ueReadBuffer = NULL; + ULONG_PTR ueNumberOfBytesRead = NULL; + MEMORY_BASIC_INFORMATION memoryInformation = {}; + PMEMORY_COMPARE_HANDLER memCmp = (PMEMORY_COMPARE_HANDLER)MemoryToCheck; + PMEMORY_COMPARE_HANDLER memPattern = (PMEMORY_COMPARE_HANDLER)PatternToMatch; + + if(WildCard == NULL) + { + WildCard = &intWildCard; + } + if(SizeOfMemoryToCheck >= SizeOfPatternToMatch) + { + if(hProcess != GetCurrentProcess()) + { + ueReadBuffer = VirtualAlloc(NULL, SizeOfMemoryToCheck, MEM_COMMIT, PAGE_READWRITE); + if(!ReadProcessMemory(hProcess, MemoryToCheck, ueReadBuffer, SizeOfMemoryToCheck, &ueNumberOfBytesRead)) + { + if(ueNumberOfBytesRead == NULL) + { + if(VirtualQueryEx(hProcess, MemoryToCheck, &memoryInformation, sizeof memoryInformation) != NULL) + { + SizeOfMemoryToCheck = (int)((ULONG_PTR)memoryInformation.BaseAddress + memoryInformation.RegionSize - (ULONG_PTR)MemoryToCheck); + if(!ReadProcessMemory(hProcess, MemoryToCheck, ueReadBuffer, SizeOfMemoryToCheck, &ueNumberOfBytesRead)) + { + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + return(NULL); + } + else + { + memCmp = (PMEMORY_COMPARE_HANDLER)ueReadBuffer; + } + } + else + { + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + return(NULL); + } + } + else + { + memCmp = (PMEMORY_COMPARE_HANDLER)ueReadBuffer; + } + } + else + { + memCmp = (PMEMORY_COMPARE_HANDLER)ueReadBuffer; + } + } + __try + { + while(SizeOfPatternToMatch > NULL) + { + if(memCmp->Array.bArrayEntry[i] != memPattern->Array.bArrayEntry[i] && memPattern->Array.bArrayEntry[i] != *WildCard) + { + return(false); + } + SizeOfPatternToMatch--; + i++; + } + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + return(true); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + return(false); + } + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall MatchPattern(void* MemoryToCheck, int SizeOfMemoryToCheck, void* PatternToMatch, int SizeOfPatternToMatch, PBYTE WildCard) +{ + + if(dbgProcessInformation.hProcess != NULL) + { + return(MatchPatternEx(dbgProcessInformation.hProcess, MemoryToCheck, SizeOfMemoryToCheck, PatternToMatch, SizeOfPatternToMatch, WildCard)); + } + else + { + return(MatchPatternEx(GetCurrentProcess(), MemoryToCheck, SizeOfMemoryToCheck, PatternToMatch, SizeOfPatternToMatch, WildCard)); + } +} +__declspec(dllexport) long long __stdcall FindEx(HANDLE hProcess, LPVOID MemoryStart, DWORD MemorySize, LPVOID SearchPattern, DWORD PatternSize, LPBYTE WildCard) +{ + + int i = NULL; + int j = NULL; + ULONG_PTR Return = NULL; + LPVOID ueReadBuffer = NULL; + PUCHAR SearchBuffer = NULL; + PUCHAR CompareBuffer = NULL; + MEMORY_BASIC_INFORMATION memoryInformation = {}; + ULONG_PTR ueNumberOfBytesRead = NULL; + LPVOID currentSearchPosition = NULL; + DWORD currentSizeOfSearch = NULL; + BYTE nWildCard = NULL; + + if(WildCard == NULL) + { + WildCard = &nWildCard; + } + if(hProcess != NULL && MemoryStart != NULL && MemorySize != NULL) + { + if(hProcess != GetCurrentProcess()) + { + ueReadBuffer = VirtualAlloc(NULL, MemorySize, MEM_COMMIT, PAGE_READWRITE); + if(!ReadProcessMemory(hProcess, MemoryStart, ueReadBuffer, MemorySize, &ueNumberOfBytesRead)) + { + if(ueNumberOfBytesRead == NULL) + { + if(VirtualQueryEx(hProcess, MemoryStart, &memoryInformation, sizeof memoryInformation) != NULL) + { + MemorySize = (DWORD)((ULONG_PTR)memoryInformation.BaseAddress + memoryInformation.RegionSize - (ULONG_PTR)MemoryStart); + if(!ReadProcessMemory(hProcess, MemoryStart, ueReadBuffer, MemorySize, &ueNumberOfBytesRead)) + { + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + return(NULL); + } + else + { + SearchBuffer = (PUCHAR)ueReadBuffer; + } + } + else + { + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + return(NULL); + } + } + else + { + SearchBuffer = (PUCHAR)ueReadBuffer; + } + } + else + { + SearchBuffer = (PUCHAR)ueReadBuffer; + } + } + else + { + SearchBuffer = (PUCHAR)MemoryStart; + } + __try + { + CompareBuffer = (PUCHAR)SearchPattern; + for(i = 0; i < (int)MemorySize && Return == NULL; i++) + { + for(j = 0; j < (int)PatternSize; j++) + { + if(CompareBuffer[j] != *(PUCHAR)WildCard && SearchBuffer[i + j] != CompareBuffer[j]) + { + break; + } + } + if(j == (int)PatternSize) + { + Return = (ULONG_PTR)MemoryStart + i; + } + } + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + return(Return); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + VirtualFree(ueReadBuffer, NULL, MEM_RELEASE); + return(NULL); + } + } + else + { + return(NULL); + } +} +__declspec(dllexport) long long __stdcall FindU(LPVOID MemoryStart, DWORD MemorySize, LPVOID SearchPattern, DWORD PatternSize, LPBYTE WildCard) +{ + + if(dbgProcessInformation.hProcess != NULL) + { + return(FindEx(dbgProcessInformation.hProcess, MemoryStart, MemorySize, SearchPattern, PatternSize, WildCard)); + } + else + { + return(FindEx(GetCurrentProcess(), MemoryStart, MemorySize, SearchPattern, PatternSize, WildCard)); + } +} +__declspec(dllexport) bool __stdcall FillEx(HANDLE hProcess, LPVOID MemoryStart, DWORD MemorySize, PBYTE FillByte) +{ + + unsigned int i; + MEMORY_BASIC_INFORMATION MemInfo; + ULONG_PTR ueNumberOfBytesRead; + BYTE defFillByte = 0x90; + DWORD OldProtect; + + if(hProcess != NULL) + { + if(FillByte == NULL) + { + FillByte = &defFillByte; + } + VirtualQueryEx(hProcess, MemoryStart, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + OldProtect = MemInfo.AllocationProtect; + VirtualProtectEx(hProcess, MemoryStart, MemorySize, PAGE_EXECUTE_READWRITE, &OldProtect); + for(i = 0; i < MemorySize; i++) + { + WriteProcessMemory(hProcess, MemoryStart, FillByte, 1, &ueNumberOfBytesRead); + MemoryStart = (LPVOID)((ULONG_PTR)MemoryStart + 1); + } + VirtualProtectEx(hProcess, MemoryStart, MemorySize, MemInfo.AllocationProtect, &OldProtect); + return(true); + } + return(false); +} +__declspec(dllexport) bool __stdcall Fill(LPVOID MemoryStart, DWORD MemorySize, PBYTE FillByte) +{ + + if(dbgProcessInformation.hProcess != NULL) + { + return(FillEx(dbgProcessInformation.hProcess, MemoryStart, MemorySize, FillByte)); + } + else + { + return(FillEx(GetCurrentProcess(), MemoryStart, MemorySize, FillByte)); + } +} +__declspec(dllexport) bool __stdcall PatchEx(HANDLE hProcess, LPVOID MemoryStart, DWORD MemorySize, LPVOID ReplacePattern, DWORD ReplaceSize, bool AppendNOP, bool PrependNOP) +{ + + unsigned int i,recalcSize; + LPVOID lpMemoryStart = MemoryStart; + MEMORY_BASIC_INFORMATION MemInfo; + ULONG_PTR ueNumberOfBytesRead; + BYTE FillByte = 0x90; + DWORD OldProtect; + + if(hProcess != NULL) + { + VirtualQueryEx(hProcess, MemoryStart, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + OldProtect = MemInfo.AllocationProtect; + VirtualProtectEx(hProcess, MemoryStart, MemorySize, PAGE_EXECUTE_READWRITE, &OldProtect); + + if(MemorySize - ReplaceSize != NULL) + { + recalcSize = abs((long)(MemorySize - ReplaceSize)); + if(AppendNOP) + { + WriteProcessMemory(hProcess, MemoryStart, ReplacePattern, ReplaceSize, &ueNumberOfBytesRead); + lpMemoryStart = (LPVOID)((ULONG_PTR)MemoryStart + ReplaceSize); + for(i = 0; i < recalcSize; i++) + { + WriteProcessMemory(hProcess, lpMemoryStart, &FillByte, 1, &ueNumberOfBytesRead); + lpMemoryStart = (LPVOID)((ULONG_PTR)lpMemoryStart + 1); + } + } + else if(PrependNOP) + { + lpMemoryStart = MemoryStart; + for(i = 0; i < recalcSize; i++) + { + WriteProcessMemory(hProcess, lpMemoryStart, &FillByte, 1, &ueNumberOfBytesRead); + lpMemoryStart = (LPVOID)((ULONG_PTR)lpMemoryStart + 1); + } + WriteProcessMemory(hProcess, lpMemoryStart, ReplacePattern, ReplaceSize, &ueNumberOfBytesRead); + } + else + { + WriteProcessMemory(hProcess, MemoryStart, ReplacePattern, ReplaceSize, &ueNumberOfBytesRead); + } + } + else + { + WriteProcessMemory(hProcess, MemoryStart, ReplacePattern, ReplaceSize, &ueNumberOfBytesRead); + } + VirtualProtectEx(hProcess, MemoryStart, MemorySize, MemInfo.AllocationProtect, &OldProtect); + return(true); + } + return(false); +} +__declspec(dllexport) bool __stdcall Patch(LPVOID MemoryStart, DWORD MemorySize, LPVOID ReplacePattern, DWORD ReplaceSize, bool AppendNOP, bool PrependNOP) +{ + + if(dbgProcessInformation.hProcess != NULL) + { + return(PatchEx(dbgProcessInformation.hProcess, MemoryStart, MemorySize, ReplacePattern, ReplaceSize, AppendNOP, PrependNOP)); + } + else + { + return(PatchEx(GetCurrentProcess(), MemoryStart, MemorySize, ReplacePattern, ReplaceSize, AppendNOP, PrependNOP)); + } +} +__declspec(dllexport) bool __stdcall ReplaceEx(HANDLE hProcess, LPVOID MemoryStart, DWORD MemorySize, LPVOID SearchPattern, DWORD PatternSize, DWORD NumberOfRepetitions, LPVOID ReplacePattern, DWORD ReplaceSize, PBYTE WildCard) +{ + + unsigned int i; + ULONG_PTR ueNumberOfBytesRead; + ULONG_PTR CurrentFoundPattern; + LPVOID cMemoryStart = MemoryStart; + DWORD cMemorySize = MemorySize; + LPVOID lpReadMemory = VirtualAlloc(NULL, PatternSize, MEM_COMMIT, PAGE_READWRITE); + + CurrentFoundPattern = (ULONG_PTR)FindEx(hProcess, cMemoryStart, cMemorySize, SearchPattern, PatternSize, WildCard); + NumberOfRepetitions--; + while(CurrentFoundPattern != NULL && NumberOfRepetitions != NULL) + { + if(ReadProcessMemory(hProcess, (LPVOID)CurrentFoundPattern, lpReadMemory, PatternSize, &ueNumberOfBytesRead)) + { + for(i = 0; i < ReplaceSize; i++) + { + if(memcmp((LPVOID)((ULONG_PTR)ReplacePattern + i), WildCard, 1) != NULL) + { + RtlMoveMemory((LPVOID)((ULONG_PTR)lpReadMemory + i), (LPVOID)((ULONG_PTR)ReplacePattern + i), 1); + } + } + PatchEx(hProcess, (LPVOID)CurrentFoundPattern, PatternSize, lpReadMemory, ReplaceSize, true, false); + } + cMemoryStart = (LPVOID)(CurrentFoundPattern + PatternSize); + cMemorySize = (DWORD)((ULONG_PTR)MemoryStart + MemorySize - CurrentFoundPattern); + CurrentFoundPattern = (ULONG_PTR)FindEx(hProcess, cMemoryStart, cMemorySize, SearchPattern, PatternSize, WildCard); + NumberOfRepetitions--; + } + VirtualFree(lpReadMemory, NULL, MEM_RELEASE); + if(NumberOfRepetitions != NULL) + { + return(false); + } + else + { + return(true); + } +} +__declspec(dllexport) bool __stdcall Replace(LPVOID MemoryStart, DWORD MemorySize, LPVOID SearchPattern, DWORD PatternSize, DWORD NumberOfRepetitions, LPVOID ReplacePattern, DWORD ReplaceSize, PBYTE WildCard) +{ + + if(dbgProcessInformation.hProcess != NULL) + { + return(ReplaceEx(dbgProcessInformation.hProcess, MemoryStart, MemorySize, SearchPattern, PatternSize, NumberOfRepetitions, ReplacePattern, ReplaceSize, WildCard)); + } + else + { + return(ReplaceEx(GetCurrentProcess(), MemoryStart, MemorySize, SearchPattern, PatternSize, NumberOfRepetitions, ReplacePattern, ReplaceSize, WildCard)); + } +} +__declspec(dllexport) void* __stdcall GetDebugData() +{ + return(&DBGEvent); +} +__declspec(dllexport) void* __stdcall GetTerminationData() +{ + return(&TerminateDBGEvent); +} +__declspec(dllexport) long __stdcall GetExitCode() +{ + return(ProcessExitCode); +} +__declspec(dllexport) long long __stdcall GetDebuggedDLLBaseAddress() +{ + return((ULONG_PTR)engineDebuggingDLLBase); +} +__declspec(dllexport) unsigned long long __stdcall GetDebuggedFileBaseAddress() +{ + return (unsigned long long)engineDebuggingMainModuleBase; +} +__declspec(dllexport) bool __stdcall GetRemoteString(HANDLE hProcess, LPVOID StringAddress, LPVOID StringStorage, int MaximumStringSize) +{ + + MEMORY_BASIC_INFORMATION MemInfo; + ULONG_PTR ueNumberOfBytesRW = NULL; + DWORD StringReadSize = NULL; + + if(MaximumStringSize == NULL) + { + MaximumStringSize = 512; + } + VirtualQueryEx(hProcess, (LPVOID)StringAddress, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + if((int)((ULONG_PTR)MemInfo.BaseAddress + (ULONG_PTR)MemInfo.RegionSize - (ULONG_PTR)StringAddress) < MaximumStringSize) + { + StringReadSize = (DWORD)((ULONG_PTR)StringAddress - (ULONG_PTR)MemInfo.BaseAddress); + VirtualQueryEx(hProcess, (LPVOID)((ULONG_PTR)StringAddress + (ULONG_PTR)MemInfo.RegionSize), &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + if(MemInfo.State == MEM_COMMIT) + { + StringReadSize = MaximumStringSize; + } + } + else + { + StringReadSize = MaximumStringSize; + } + RtlZeroMemory(StringStorage, MaximumStringSize); + if(ReadProcessMemory(hProcess, (LPVOID)StringAddress, StringStorage, StringReadSize, &ueNumberOfBytesRW)) + { + return(true); + } + else + { + return(false); + } +} +__declspec(dllexport) long long __stdcall GetFunctionParameter(HANDLE hProcess, DWORD FunctionType, DWORD ParameterNumber, DWORD ParameterType) +{ + + MEMORY_BASIC_INFORMATION MemInfo; + ULONG_PTR ueNumberOfBytesRW = NULL; + ULONG_PTR StackReadBuffer = NULL; + ULONG_PTR StackFinalBuffer = NULL; + ULONG_PTR StackReadAddress = NULL; + DWORD StackSecondReadSize = NULL; + DWORD StackReadSize = 512; + DWORD StringReadSize = 512; + bool ValueIsPointer = false; + + if(ParameterType == UE_PARAMETER_BYTE) + { + StackReadSize = 1; + } + else if(ParameterType == UE_PARAMETER_WORD) + { + StackReadSize = 2; + } + else if(ParameterType == UE_PARAMETER_DWORD) + { + StackReadSize = 4; + } + else if(ParameterType == UE_PARAMETER_QWORD) + { + StackReadSize = 8; + } + else + { + if(ParameterType >= UE_PARAMETER_PTR_BYTE && ParameterType <= UE_PARAMETER_UNICODE) + { + ValueIsPointer = true; + } + if(ParameterType == UE_PARAMETER_PTR_BYTE) + { + StackSecondReadSize = 1; + } + else if(ParameterType == UE_PARAMETER_PTR_WORD) + { + StackSecondReadSize = 2; + } + else if(ParameterType == UE_PARAMETER_PTR_DWORD) + { + StackSecondReadSize = 4; + } + else if(ParameterType == UE_PARAMETER_PTR_QWORD) + { + StackSecondReadSize = 8; + } + else + { + StackSecondReadSize = 0; + } + StackReadSize = sizeof ULONG_PTR; + } + if(FunctionType >= UE_FUNCTION_STDCALL && FunctionType <= UE_FUNCTION_CCALL_CALL && FunctionType != UE_FUNCTION_FASTCALL_RET) + { + StackReadAddress = (ULONG_PTR)GetContextData(UE_CSP); + if(FunctionType != UE_FUNCTION_FASTCALL_CALL) + { + StackReadAddress = StackReadAddress + (ParameterNumber * sizeof ULONG_PTR); + if(FunctionType >= UE_FUNCTION_STDCALL_CALL) + { + StackReadAddress = StackReadAddress - sizeof ULONG_PTR; + } + } + else + { + if(ParameterNumber <= 4) + { + if(!ValueIsPointer) + { + if(ParameterNumber == 1) + { + return((ULONG_PTR)GetContextData(UE_RCX)); + } + else if(ParameterNumber == 2) + { + return((ULONG_PTR)GetContextData(UE_RDX)); + } + else if(ParameterNumber == 3) + { + return((ULONG_PTR)GetContextData(UE_R8)); + } + else if(ParameterNumber == 4) + { + return((ULONG_PTR)GetContextData(UE_R9)); + } + } + else + { + if(ParameterNumber == 1) + { + StackReadAddress = (ULONG_PTR)GetContextData(UE_RCX); + } + else if(ParameterNumber == 2) + { + StackReadAddress = (ULONG_PTR)GetContextData(UE_RDX); + } + else if(ParameterNumber == 3) + { + StackReadAddress = (ULONG_PTR)GetContextData(UE_R8); + } + else if(ParameterNumber == 4) + { + StackReadAddress = (ULONG_PTR)GetContextData(UE_R9); + } + } + } + else + { + StackReadAddress = StackReadAddress + 0x20 + ((ParameterNumber - 4) * sizeof ULONG_PTR) - sizeof ULONG_PTR; + } + } + if(ReadProcessMemory(hProcess, (LPVOID)StackReadAddress, &StackReadBuffer, sizeof ULONG_PTR, &ueNumberOfBytesRW)) + { + if(!ValueIsPointer) + { + RtlMoveMemory((LPVOID)((ULONG_PTR)&StackFinalBuffer + sizeof ULONG_PTR - StackReadSize), (LPVOID)((ULONG_PTR)&StackReadBuffer + sizeof ULONG_PTR - StackReadSize), StackReadSize); + } + else + { + StackReadAddress = StackReadBuffer; + if(StackSecondReadSize > NULL) + { + if(ReadProcessMemory(hProcess, (LPVOID)StackReadAddress, &StackReadBuffer, sizeof ULONG_PTR, &ueNumberOfBytesRW)) + { + RtlMoveMemory((LPVOID)((ULONG_PTR)&StackFinalBuffer + sizeof ULONG_PTR - StackSecondReadSize), (LPVOID)((ULONG_PTR)&StackReadBuffer + sizeof ULONG_PTR - StackSecondReadSize), StackSecondReadSize); + } + else + { + return(-1); + } + } + else + { + VirtualQueryEx(hProcess, (LPVOID)StackReadAddress, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + if((ULONG_PTR)MemInfo.BaseAddress + (ULONG_PTR)MemInfo.RegionSize - StackReadAddress < 512) + { + StringReadSize = (DWORD)((ULONG_PTR)StackReadAddress - (ULONG_PTR)MemInfo.BaseAddress); + VirtualQueryEx(hProcess, (LPVOID)(StackReadAddress + (ULONG_PTR)MemInfo.RegionSize), &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + if(MemInfo.State == MEM_COMMIT) + { + StringReadSize = 512; + } + } + RtlZeroMemory(&szParameterString, 512); + if(ReadProcessMemory(hProcess, (LPVOID)StackReadAddress, &szParameterString, StringReadSize, &ueNumberOfBytesRW)) + { + return((ULONG_PTR)&szParameterString); + } + else + { + return(-1); + } + } + } + return(StackFinalBuffer); + } + else + { + return(-1); + } + } + return(-1); +} +__declspec(dllexport) long long __stdcall GetJumpDestinationEx(HANDLE hProcess, ULONG_PTR InstructionAddress, bool JustJumps) +{ + + LPVOID ReadMemory; + MEMORY_BASIC_INFORMATION MemInfo; + ULONG_PTR ueNumberOfBytesRead = NULL; + PMEMORY_CMP_HANDLER CompareMemory; + ULONG_PTR TargetedAddress = NULL; + DWORD CurrentInstructionSize; + int ReadMemData = NULL; + BYTE ReadByteData = NULL; + + if(hProcess != NULL) + { + VirtualQueryEx(hProcess, (LPVOID)InstructionAddress, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + if(MemInfo.RegionSize > NULL) + { + ReadMemory = VirtualAlloc(NULL, MAXIMUM_INSTRUCTION_SIZE, MEM_COMMIT, PAGE_READWRITE); + if(ReadProcessMemory(hProcess, (LPVOID)InstructionAddress, ReadMemory, MAXIMUM_INSTRUCTION_SIZE, &ueNumberOfBytesRead)) + { + CompareMemory = (PMEMORY_CMP_HANDLER)ReadMemory; + CurrentInstructionSize = StaticLengthDisassemble(ReadMemory); + if(CompareMemory->DataByte[0] == 0xE9 && CurrentInstructionSize == 5) + { + RtlMoveMemory(&ReadMemData, (LPVOID)((ULONG_PTR)ReadMemory + 1), 4); + TargetedAddress = ReadMemData + InstructionAddress + CurrentInstructionSize; + } + else if(CompareMemory->DataByte[0] == 0xEB && CurrentInstructionSize == 2) + { + RtlMoveMemory(&ReadByteData, (LPVOID)((ULONG_PTR)ReadMemory + 1), 1); + if(ReadByteData > 0x7F) + { + ReadByteData = 0xFF - ReadByteData; + ReadMemData = NULL - ReadByteData - CurrentInstructionSize + 1; + } + else + { + ReadMemData = ReadByteData; + } + TargetedAddress = InstructionAddress + ReadMemData + CurrentInstructionSize; + } + else if(CompareMemory->DataByte[0] == 0xE3 && CurrentInstructionSize == 2) + { + RtlMoveMemory(&ReadByteData, (LPVOID)((ULONG_PTR)ReadMemory + 1), 1); + if(ReadByteData > 0x7F) + { + ReadByteData = 0xFF - ReadByteData; + ReadMemData = NULL - ReadByteData - CurrentInstructionSize + 1; + } + else + { + ReadMemData = ReadByteData; + } + TargetedAddress = InstructionAddress + ReadMemData + CurrentInstructionSize; + } + else if(CompareMemory->DataByte[0] >= 0x71 && CompareMemory->DataByte[0] <= 0x7F && CurrentInstructionSize == 2) + { + RtlMoveMemory(&ReadByteData, (LPVOID)((ULONG_PTR)ReadMemory + 1), 1); + if(ReadByteData > 0x7F) + { + ReadByteData = 0xFF - ReadByteData; + ReadMemData = NULL - ReadByteData - CurrentInstructionSize + 1; + } + TargetedAddress = InstructionAddress + ReadMemData + CurrentInstructionSize; + } + else if(CompareMemory->DataByte[0] >= 0xE0 && CompareMemory->DataByte[0] <= 0xE2 && CurrentInstructionSize == 2) + { + RtlMoveMemory(&ReadByteData, (LPVOID)((ULONG_PTR)ReadMemory + 1), 1); + if(ReadByteData > 0x7F) + { + ReadByteData = 0xFF - ReadByteData; + ReadMemData = NULL - ReadByteData - CurrentInstructionSize + 1; + } + else + { + ReadMemData = ReadByteData; + } + TargetedAddress = InstructionAddress + ReadMemData + CurrentInstructionSize; + } + else if(CompareMemory->DataByte[0] == 0x0F && CompareMemory->DataByte[1] >= 0x81 && CompareMemory->DataByte[1] <= 0x8F && CurrentInstructionSize == 6) + { + RtlMoveMemory(&ReadMemData, (LPVOID)((ULONG_PTR)ReadMemory + 2), 4); + TargetedAddress = ReadMemData + InstructionAddress + CurrentInstructionSize; + } + else if(CompareMemory->DataByte[0] == 0x0F && CompareMemory->DataByte[1] >= 0x81 && CompareMemory->DataByte[1] <= 0x8F && CurrentInstructionSize == 4) + { + RtlMoveMemory(&ReadMemData, (LPVOID)((ULONG_PTR)ReadMemory + 2), 2); + TargetedAddress = ReadMemData + InstructionAddress + CurrentInstructionSize; + } + else if(CompareMemory->DataByte[0] == 0xE8 && CurrentInstructionSize == 5 && JustJumps == false) + { + RtlMoveMemory(&ReadMemData, (LPVOID)((ULONG_PTR)ReadMemory + 1), 4); + TargetedAddress = ReadMemData + InstructionAddress + CurrentInstructionSize; + } + else if(CompareMemory->DataByte[0] == 0xFF && CompareMemory->DataByte[1] == 0x25 && CurrentInstructionSize == 6) + { + RtlMoveMemory(&ReadMemData, (LPVOID)((ULONG_PTR)ReadMemory + 2), 4); + TargetedAddress = ReadMemData; + if(sizeof HANDLE == 8) + { + TargetedAddress = TargetedAddress + InstructionAddress; + } + } + else if(CompareMemory->DataByte[0] == 0xFF && CompareMemory->DataByte[1] == 0x15 && CurrentInstructionSize == 6 && JustJumps == false) + { + RtlMoveMemory(&ReadMemData, (LPVOID)((ULONG_PTR)ReadMemory + 2), 4); + TargetedAddress = ReadMemData; + if(sizeof HANDLE == 8) + { + TargetedAddress = TargetedAddress + InstructionAddress; + } + } + else if(CompareMemory->DataByte[0] == 0xFF && CompareMemory->DataByte[1] != 0x64 && CompareMemory->DataByte[1] >= 0x60 && CompareMemory->DataByte[1] <= 0x67 && CurrentInstructionSize == 3) + { + RtlMoveMemory(&ReadMemData, (LPVOID)((ULONG_PTR)ReadMemory + 2), 1); + TargetedAddress = ReadMemData; + if(CompareMemory->DataByte[1] == 0x60) + { + TargetedAddress = TargetedAddress + (ULONG_PTR)GetContextData(UE_EAX); + } + else if(CompareMemory->DataByte[1] == 0x61) + { + TargetedAddress = TargetedAddress + (ULONG_PTR)GetContextData(UE_ECX); + } + else if(CompareMemory->DataByte[1] == 0x62) + { + TargetedAddress = TargetedAddress + (ULONG_PTR)GetContextData(UE_EDX); + } + else if(CompareMemory->DataByte[1] == 0x63) + { + TargetedAddress = TargetedAddress + (ULONG_PTR)GetContextData(UE_EBX); + } + else if(CompareMemory->DataByte[1] == 0x65) + { + TargetedAddress = TargetedAddress + (ULONG_PTR)GetContextData(UE_EBP); + } + else if(CompareMemory->DataByte[1] == 0x66) + { + TargetedAddress = TargetedAddress + (ULONG_PTR)GetContextData(UE_ESI); + } + else if(CompareMemory->DataByte[1] == 0x67) + { + TargetedAddress = TargetedAddress + (ULONG_PTR)GetContextData(UE_EDI); + } + ReadProcessMemory(hProcess, (LPVOID)TargetedAddress, &TargetedAddress, 4, &ueNumberOfBytesRead); + } + } + VirtualFree(ReadMemory, NULL, MEM_RELEASE); + return((ULONG_PTR)TargetedAddress); + } + return(NULL); + } + else + { + CompareMemory = (PMEMORY_CMP_HANDLER)InstructionAddress; + CurrentInstructionSize = StaticLengthDisassemble((LPVOID)InstructionAddress); + if(CompareMemory->DataByte[0] == 0xE9 && CurrentInstructionSize == 5) + { + RtlMoveMemory(&ReadMemData, (LPVOID)((ULONG_PTR)InstructionAddress + 1), 4); + TargetedAddress = ReadMemData + InstructionAddress + CurrentInstructionSize; + } + else if(CompareMemory->DataByte[0] == 0xEB && CurrentInstructionSize == 2) + { + RtlMoveMemory(&ReadByteData, (LPVOID)((ULONG_PTR)InstructionAddress + 1), 1); + if(ReadByteData > 0x7F) + { + ReadByteData = 0xFF - ReadByteData; + ReadMemData = NULL - ReadByteData - CurrentInstructionSize + 1; + } + else + { + ReadMemData = ReadByteData; + } + TargetedAddress = InstructionAddress + ReadMemData + CurrentInstructionSize; + } + else if(CompareMemory->DataByte[0] == 0xE3 && CurrentInstructionSize == 2) + { + RtlMoveMemory(&ReadByteData, (LPVOID)((ULONG_PTR)InstructionAddress + 1), 1); + if(ReadByteData > 0x7F) + { + ReadByteData = 0xFF - ReadByteData; + ReadMemData = NULL - ReadByteData - CurrentInstructionSize + 1; + } + else + { + ReadMemData = ReadByteData; + } + TargetedAddress = InstructionAddress + ReadMemData + CurrentInstructionSize; + } + else if(CompareMemory->DataByte[0] >= 0x71 && CompareMemory->DataByte[0] <= 0x7F && CurrentInstructionSize == 2) + { + RtlMoveMemory(&ReadByteData, (LPVOID)((ULONG_PTR)InstructionAddress + 1), 1); + if(ReadByteData > 0x7F) + { + ReadByteData = 0xFF - ReadByteData; + ReadMemData = NULL - ReadByteData - CurrentInstructionSize + 1; + } + TargetedAddress = InstructionAddress + ReadMemData + CurrentInstructionSize; + } + else if(CompareMemory->DataByte[0] >= 0xE0 && CompareMemory->DataByte[0] <= 0xE2 && CurrentInstructionSize == 2) + { + RtlMoveMemory(&ReadByteData, (LPVOID)((ULONG_PTR)InstructionAddress + 1), 1); + if(ReadByteData > 0x7F) + { + ReadByteData = 0xFF - ReadByteData; + ReadMemData = NULL - ReadByteData - CurrentInstructionSize + 1; + } + else + { + ReadMemData = ReadByteData; + } + TargetedAddress = InstructionAddress + ReadMemData + CurrentInstructionSize; + } + else if(CompareMemory->DataByte[0] == 0x0F && CompareMemory->DataByte[1] >= 0x81 && CompareMemory->DataByte[1] <= 0x8F && CurrentInstructionSize == 6) + { + RtlMoveMemory(&ReadMemData, (LPVOID)((ULONG_PTR)InstructionAddress + 2), 4); + TargetedAddress = ReadMemData + InstructionAddress + CurrentInstructionSize; + } + else if(CompareMemory->DataByte[0] == 0x0F && CompareMemory->DataByte[1] >= 0x81 && CompareMemory->DataByte[1] <= 0x8F && CurrentInstructionSize == 4) + { + RtlMoveMemory(&ReadMemData, (LPVOID)((ULONG_PTR)InstructionAddress + 2), 2); + TargetedAddress = ReadMemData + InstructionAddress + CurrentInstructionSize; + } + else if(CompareMemory->DataByte[0] == 0xE8 && CurrentInstructionSize == 5 && JustJumps == false) + { + RtlMoveMemory(&ReadMemData, (LPVOID)((ULONG_PTR)InstructionAddress + 1), 4); + TargetedAddress = ReadMemData + InstructionAddress + CurrentInstructionSize; + } + else if(CompareMemory->DataByte[0] == 0xFF && CompareMemory->DataByte[1] == 0x25 && CurrentInstructionSize == 6) + { + RtlMoveMemory(&ReadMemData, (LPVOID)((ULONG_PTR)InstructionAddress + 2), 4); + TargetedAddress = ReadMemData; + if(sizeof HANDLE == 8) + { + TargetedAddress = TargetedAddress + InstructionAddress; + } + } + else if(CompareMemory->DataByte[0] == 0xFF && CompareMemory->DataByte[1] == 0x15 && CurrentInstructionSize == 6 && JustJumps == false) + { + RtlMoveMemory(&ReadMemData, (LPVOID)((ULONG_PTR)InstructionAddress + 2), 4); + TargetedAddress = ReadMemData; + if(sizeof HANDLE == 8) + { + TargetedAddress = TargetedAddress + InstructionAddress; + } + } + else if(CompareMemory->DataByte[0] == 0xFF && CompareMemory->DataByte[1] != 0x64 && CompareMemory->DataByte[1] >= 0x60 && CompareMemory->DataByte[1] <= 0x67 && CurrentInstructionSize == 3) + { + RtlMoveMemory(&ReadMemData, (LPVOID)((ULONG_PTR)InstructionAddress + 2), 1); + TargetedAddress = ReadMemData; + if(CompareMemory->DataByte[1] == 0x60) + { + TargetedAddress = TargetedAddress + (ULONG_PTR)GetContextData(UE_EAX); + } + else if(CompareMemory->DataByte[1] == 0x61) + { + TargetedAddress = TargetedAddress + (ULONG_PTR)GetContextData(UE_ECX); + } + else if(CompareMemory->DataByte[1] == 0x62) + { + TargetedAddress = TargetedAddress + (ULONG_PTR)GetContextData(UE_EDX); + } + else if(CompareMemory->DataByte[1] == 0x63) + { + TargetedAddress = TargetedAddress + (ULONG_PTR)GetContextData(UE_EBX); + } + else if(CompareMemory->DataByte[1] == 0x65) + { + TargetedAddress = TargetedAddress + (ULONG_PTR)GetContextData(UE_EBP); + } + else if(CompareMemory->DataByte[1] == 0x66) + { + TargetedAddress = TargetedAddress + (ULONG_PTR)GetContextData(UE_ESI); + } + else if(CompareMemory->DataByte[1] == 0x67) + { + TargetedAddress = TargetedAddress + (ULONG_PTR)GetContextData(UE_EDI); + } + RtlMoveMemory(&TargetedAddress, (LPVOID)((ULONG_PTR)TargetedAddress), 4); + } + return((ULONG_PTR)TargetedAddress); + } + return(NULL); +} +__declspec(dllexport) long long __stdcall GetJumpDestination(HANDLE hProcess, ULONG_PTR InstructionAddress) +{ + return((ULONG_PTR)GetJumpDestinationEx(hProcess, InstructionAddress, false)); +} +__declspec(dllexport) bool __stdcall IsJumpGoingToExecuteEx(HANDLE hProcess, HANDLE hThread, ULONG_PTR InstructionAddress, ULONG_PTR RegFlags) +{ + ULONG_PTR ThreadCIP = NULL; + DWORD ThreadEflags = NULL; + char* DisassembledString; + bool bCF = false; + bool bPF = false; + bool bAF = false; + bool bZF = false; + bool bSF = false; + bool bTF = false; + bool bIF = false; + bool bDF = false; + bool bOF = false; + + if(hProcess != NULL && hThread != NULL) + { + if(InstructionAddress == NULL) + { + ThreadCIP = (ULONG_PTR)GetContextDataEx(hThread, UE_CIP); + } + else + { + ThreadCIP = InstructionAddress; + } + if(RegFlags == NULL) + { + ThreadEflags = (DWORD)GetContextDataEx(hThread, UE_EFLAGS); + } + else + { + ThreadEflags = (DWORD)RegFlags; + } + DisassembledString = (char*)DisassembleEx(hProcess, (LPVOID)ThreadCIP, true); + if(DisassembledString != NULL) + { + if(ThreadEflags & (1 << 0)) + { + bCF = true; + } + if(ThreadEflags & (1 << 2)) + { + bPF = true; + } + if(ThreadEflags & (1 << 4)) + { + bAF = true; + } + if(ThreadEflags & (1 << 6)) + { + bZF = true; + } + if(ThreadEflags & (1 << 7)) + { + bSF = true; + } + if(ThreadEflags & (1 << 8)) + { + bTF = true; + } + if(ThreadEflags & (1 << 9)) + { + bIF = true; + } + if(ThreadEflags & (1 << 10)) + { + bDF = true; + } + if(ThreadEflags & (1 << 11)) + { + bOF = true; + } + if(lstrcmpiA(DisassembledString, "RET") == NULL) + { + return (true); + } + else if(lstrcmpiA(DisassembledString, "RETF") == NULL) + { + return (true); + } + else if(lstrcmpiA(DisassembledString, "JMP") == NULL) + { + return(true); + } + else if(lstrcmpiA(DisassembledString, "JA") == NULL) + { + if(bCF == false && bZF == false) + { + return(true); + } + } + else if(lstrcmpiA(DisassembledString, "JAE") == NULL) + { + if(!bCF) + { + return(true); + } + } + else if(lstrcmpiA(DisassembledString, "JB") == NULL) + { + if(bCF) + { + return(true); + } + } + else if(lstrcmpiA(DisassembledString, "JBE") == NULL) + { + if(bCF == true || bZF == true) + { + return(true); + } + } + else if(lstrcmpiA(DisassembledString, "JC") == NULL) + { + if(bCF) + { + return(true); + } + } + else if(lstrcmpiA(DisassembledString, "JCXZ") == NULL) + { + if((WORD)GetContextDataEx(hThread, UE_ECX) == NULL) + { + return(true); + } + } + else if(lstrcmpiA(DisassembledString, "JECXZ") == NULL) + { + if((DWORD)GetContextDataEx(hThread, UE_ECX) == NULL) + { + return(true); + } + } + else if(lstrcmpiA(DisassembledString, "JRCXZ") == NULL) + { + if((ULONG_PTR)GetContextDataEx(hThread, UE_RCX) == NULL) + { + return(true); + } + } + else if(lstrcmpiA(DisassembledString, "JZ") == NULL) + { + if(bZF) + { + return(true); + } + } + else if(lstrcmpiA(DisassembledString, "JNZ") == NULL) + { + if(!bZF) + { + return(true); + } + } + else if(lstrcmpiA(DisassembledString, "JE") == NULL) + { + if(bZF) + { + return(true); + } + } + else if(lstrcmpiA(DisassembledString, "JNE") == NULL) + { + if(!bZF) + { + return(true); + } + } + else if(lstrcmpiA(DisassembledString, "JG") == NULL) + { + if(bZF == false && bSF == bOF) + { + return(true); + } + } + else if(lstrcmpiA(DisassembledString, "JGE") == NULL) + { + if(bSF == bOF) + { + return(true); + } + } + else if(lstrcmpiA(DisassembledString, "JL") == NULL) + { + if(bSF != bOF) + { + return(true); + } + } + else if(lstrcmpiA(DisassembledString, "JLE") == NULL) + { + if(bZF == true || bSF != bOF) + { + return(true); + } + } + else if(lstrcmpiA(DisassembledString, "JNA") == NULL) + { + if(bCF == true || bZF == true) + { + return(true); + } + } + else if(lstrcmpiA(DisassembledString, "JNAE") == NULL) + { + if(bCF) + { + return(true); + } + } + else if(lstrcmpiA(DisassembledString, "JNB") == NULL) + { + if(!bCF) + { + return(true); + } + } + else if(lstrcmpiA(DisassembledString, "JNBE") == NULL) + { + if(bCF == false && bZF == false) + { + return(true); + } + } + else if(lstrcmpiA(DisassembledString, "JNC") == NULL) + { + if(!bCF) + { + return(true); + } + } + else if(lstrcmpiA(DisassembledString, "JNG") == NULL) + { + if(bZF == true || bSF != bOF) + { + return(true); + } + } + else if(lstrcmpiA(DisassembledString, "JNGE") == NULL) + { + if(bSF != bOF) + { + return(true); + } + } + else if(lstrcmpiA(DisassembledString, "JNL") == NULL) + { + if(bSF == bOF) + { + return(true); + } + } + else if(lstrcmpiA(DisassembledString, "JNLE") == NULL) + { + if(bZF == false && bSF == bOF) + { + return(true); + } + } + else if(lstrcmpiA(DisassembledString, "JNO") == NULL) + { + if(!bOF) + { + return(true); + } + } + else if(lstrcmpiA(DisassembledString, "JNP") == NULL) + { + if(!bPF) + { + return(true); + } + } + else if(lstrcmpiA(DisassembledString, "JNS") == NULL) + { + if(!bSF) + { + return(true); + } + } + else if(lstrcmpiA(DisassembledString, "JO") == NULL) + { + if(bOF) + { + return(true); + } + } + else if(lstrcmpiA(DisassembledString, "JP") == NULL) + { + if(bPF) + { + return(true); + } + } + else if(lstrcmpiA(DisassembledString, "JPE") == NULL) + { + if(bPF) + { + return(true); + } + } + else if(lstrcmpiA(DisassembledString, "JPO") == NULL) + { + if(!bPF) + { + return(true); + } + } + else if(lstrcmpiA(DisassembledString, "JS") == NULL) + { + if(bSF) + { + return(true); + } + } + else if(lstrcmpiA(DisassembledString, "JC") == NULL) + { + if(bCF) + { + return(true); + } + } + } + } + return(false); +} +__declspec(dllexport) bool __stdcall IsJumpGoingToExecute() +{ + return(IsJumpGoingToExecuteEx(dbgProcessInformation.hProcess, dbgProcessInformation.hThread, NULL, NULL)); +} +__declspec(dllexport) void __stdcall SetCustomHandler(DWORD ExceptionId, LPVOID CallBack) +{ + + if(ExceptionId == UE_CH_BREAKPOINT) + { + DBGCustomHandler->chBreakPoint = (ULONG_PTR)CallBack; + } + else if(ExceptionId == UE_CH_SINGLESTEP) + { + DBGCustomHandler->chSingleStep = (ULONG_PTR)CallBack; + } + else if(ExceptionId == UE_CH_ACCESSVIOLATION) + { + DBGCustomHandler->chAccessViolation = (ULONG_PTR)CallBack; + } + else if(ExceptionId == UE_CH_ILLEGALINSTRUCTION) + { + DBGCustomHandler->chIllegalInstruction = (ULONG_PTR)CallBack; + } + else if(ExceptionId == UE_CH_NONCONTINUABLEEXCEPTION) + { + DBGCustomHandler->chNonContinuableException = (ULONG_PTR)CallBack; + } + else if(ExceptionId == UE_CH_ARRAYBOUNDSEXCEPTION) + { + DBGCustomHandler->chArrayBoundsException = (ULONG_PTR)CallBack; + } + else if(ExceptionId == UE_CH_FLOATDENORMALOPERAND) + { + DBGCustomHandler->chFloatDenormalOperand = (ULONG_PTR)CallBack; + } + else if(ExceptionId == UE_CH_FLOATDEVIDEBYZERO) + { + DBGCustomHandler->chFloatDevideByZero = (ULONG_PTR)CallBack; + } + else if(ExceptionId == UE_CH_INTEGERDEVIDEBYZERO) + { + DBGCustomHandler->chIntegerDevideByZero = (ULONG_PTR)CallBack; + } + else if(ExceptionId == UE_CH_INTEGEROVERFLOW) + { + DBGCustomHandler->chIntegerOverflow = (ULONG_PTR)CallBack; + } + else if(ExceptionId == UE_CH_PRIVILEGEDINSTRUCTION) + { + DBGCustomHandler->chPrivilegedInstruction = (ULONG_PTR)CallBack; + } + else if(ExceptionId == UE_CH_PAGEGUARD) + { + DBGCustomHandler->chPageGuard = (ULONG_PTR)CallBack; + } + else if(ExceptionId == UE_CH_EVERYTHINGELSE) + { + DBGCustomHandler->chEverythingElse = (ULONG_PTR)CallBack; + } + else if(ExceptionId == UE_CH_CREATETHREAD) + { + DBGCustomHandler->chCreateThread = (ULONG_PTR)CallBack; + } + else if(ExceptionId == UE_CH_EXITTHREAD) + { + DBGCustomHandler->chExitThread = (ULONG_PTR)CallBack; + } + else if(ExceptionId == UE_CH_CREATEPROCESS) + { + DBGCustomHandler->chCreateProcess = (ULONG_PTR)CallBack; + } + else if(ExceptionId == UE_CH_EXITPROCESS) + { + DBGCustomHandler->chExitProcess = (ULONG_PTR)CallBack; + } + else if(ExceptionId == UE_CH_LOADDLL) + { + DBGCustomHandler->chLoadDll = (ULONG_PTR)CallBack; + } + else if(ExceptionId == UE_CH_UNLOADDLL) + { + DBGCustomHandler->chUnloadDll = (ULONG_PTR)CallBack; + } + else if(ExceptionId == UE_CH_OUTPUTDEBUGSTRING) + { + DBGCustomHandler->chOutputDebugString = (ULONG_PTR)CallBack; + } + else if(ExceptionId == UE_CH_AFTEREXCEPTIONPROCESSING) + { + DBGCustomHandler->chAfterException = (ULONG_PTR)CallBack; + } + else if(ExceptionId == UE_CH_SYSTEMBREAKPOINT) + { + DBGCustomHandler->chSystemBreakpoint = (ULONG_PTR)CallBack; + } + else if(ExceptionId == UE_CH_UNHANDLEDEXCEPTION) + { + DBGCustomHandler->chUnhandledException = (ULONG_PTR)CallBack; + } + else if(ExceptionId == UE_CH_AFTERUNHANDLEDEXCEPTION) + { + DBGCustomHandler->chAfterUnhandledException = (ULONG_PTR)CallBack; + } + else if(ExceptionId == UE_CH_ALLEVENTS) + { + DBGCustomHandler->chEverythingElse = (ULONG_PTR)CallBack; + DBGCustomHandler->chCreateThread = (ULONG_PTR)CallBack; + DBGCustomHandler->chExitThread = (ULONG_PTR)CallBack; + DBGCustomHandler->chCreateProcess = (ULONG_PTR)CallBack; + DBGCustomHandler->chExitProcess = (ULONG_PTR)CallBack; + DBGCustomHandler->chLoadDll = (ULONG_PTR)CallBack; + DBGCustomHandler->chUnloadDll = (ULONG_PTR)CallBack; + DBGCustomHandler->chOutputDebugString = (ULONG_PTR)CallBack; + DBGCustomHandler->chSystemBreakpoint = (ULONG_PTR)CallBack; + } +} +__declspec(dllexport) void __stdcall ForceClose() +{ + /*wchar_t szTempName[MAX_PATH]; + wchar_t szTempFolder[MAX_PATH];*/ + PPROCESS_ITEM_DATA hListProcessPtr = NULL; + PTHREAD_ITEM_DATA hListThreadPtr = NULL; + PLIBRARY_ITEM_DATAW hListLibraryPtr = NULL; + + if(hListProcess != NULL) + { + hListProcessPtr = (PPROCESS_ITEM_DATA)hListProcess; + while(hListProcessPtr->hProcess != NULL) + { + __try + { + EngineCloseHandle(hListProcessPtr->hFile); + EngineCloseHandle(hListProcessPtr->hProcess); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + + } + hListProcessPtr = (PPROCESS_ITEM_DATA)((ULONG_PTR)hListProcessPtr + sizeof PROCESS_ITEM_DATA); + } + RtlZeroMemory(hListProcess, MAX_DEBUG_DATA * sizeof PROCESS_ITEM_DATA); + } + if(hListThread != NULL) + { + hListThreadPtr = (PTHREAD_ITEM_DATA)hListThread; + while(hListThreadPtr->hThread != NULL) + { + if(hListThreadPtr->hThread != (HANDLE)-1) + { + __try + { + if(EngineCloseHandle(hListThreadPtr->hThread)) + { + hListThreadPtr->hThread = NULL; + hListThreadPtr->dwThreadId = NULL; + hListThreadPtr->ThreadLocalBase = NULL; + hListThreadPtr->ThreadStartAddress = NULL; + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + hListThreadPtr->hThread = NULL; + hListThreadPtr->dwThreadId = NULL; + hListThreadPtr->ThreadLocalBase = NULL; + hListThreadPtr->ThreadStartAddress = NULL; + } + } + hListThreadPtr = (PTHREAD_ITEM_DATA)((ULONG_PTR)hListThreadPtr + sizeof THREAD_ITEM_DATA); + } + RtlZeroMemory(hListThread, MAX_DEBUG_DATA * sizeof THREAD_ITEM_DATA); + } + if(hListLibrary != NULL) + { + hListLibraryPtr = (PLIBRARY_ITEM_DATAW)hListLibrary; + while(hListLibraryPtr->hFile != NULL) + { + if(hListLibraryPtr->hFile != (HANDLE)-1) + { + if(hListLibraryPtr->hFileMappingView != NULL) + { + UnmapViewOfFile(hListLibraryPtr->hFileMappingView); + __try + { + EngineCloseHandle(hListLibraryPtr->hFileMapping); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + + } + } + __try + { + EngineCloseHandle(hListLibraryPtr->hFile); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + + } + } + hListLibraryPtr = (PLIBRARY_ITEM_DATAW)((ULONG_PTR)hListLibraryPtr + sizeof LIBRARY_ITEM_DATAW); + } + RtlZeroMemory(hListLibrary, MAX_DEBUG_DATA * sizeof LIBRARY_ITEM_DATAW); + } + if(!engineProcessIsNowDetached) + { + StopDebug(); + } + RtlZeroMemory(&dbgProcessInformation, sizeof PROCESS_INFORMATION); + /*if(engineDebuggingDLL) + { + RtlZeroMemory(&szTempName, sizeof szTempName); + RtlZeroMemory(&szTempFolder, sizeof szTempFolder); + if(GetTempPathW(MAX_PATH, szTempFolder) < MAX_PATH) + { + if(GetTempFileNameW(szTempFolder, L"DeleteTempFile", GetTickCount(), szTempName)) + { + DeleteFileW(szTempName); + if(!MoveFileW(szDebuggerName, szTempName)) + { + DeleteFileW(szDebuggerName); + } + else + { + DeleteFileW(szTempName); + } + } + RtlZeroMemory(&szTempName, sizeof szTempName); + if(GetTempFileNameW(szTempFolder, L"DeleteTempFile", GetTickCount() + 1, szTempName)) + { + DeleteFileW(szTempName); + if(!MoveFileW(szReserveModuleName, szTempName)) + { + DeleteFileW(szReserveModuleName); + } + else + { + DeleteFileW(szTempName); + } + } + } + }*/ + engineDebuggingDLL = false; + DebugExeFileEntryPointCallBack = NULL; +} +__declspec(dllexport) void __stdcall StepInto(LPVOID StepCallBack) +{ + ULONG_PTR ueContext = NULL; + + ueContext = (ULONG_PTR)GetContextData(UE_EFLAGS); + if(!(ueContext & 0x100)) + { + ueContext = ueContext ^ 0x100; + } + SetContextData(UE_EFLAGS, ueContext); + engineStepActive = true; + engineStepCallBack = StepCallBack; + engineStepCount = NULL; +} +__declspec(dllexport) void __stdcall StepOver(LPVOID StepCallBack) +{ + ULONG_PTR ueCurrentPosition = NULL; +#if !defined(_WIN64) + ueCurrentPosition = (ULONG_PTR)GetContextData(UE_EIP); +#else + ueCurrentPosition = GetContextData(UE_RIP); +#endif + unsigned char instr[16]; + ReadProcessMemory(dbgProcessInformation.hProcess, (void*)ueCurrentPosition, instr, sizeof(instr), 0); + char* DisassembledString=(char*)StaticDisassembleEx(ueCurrentPosition, (LPVOID)instr); + if(strstr(DisassembledString, "CALL")||strstr(DisassembledString, "REP")||strstr(DisassembledString, "PUSHF")) + { + ueCurrentPosition+=StaticLengthDisassemble((void*)instr); + SetBPX(ueCurrentPosition, UE_BREAKPOINT_TYPE_INT3+UE_SINGLESHOOT, StepCallBack); + } + else + StepInto(StepCallBack); +} + +__declspec(dllexport) void __stdcall SingleStep(DWORD StepCount, LPVOID StepCallBack) +{ + + ULONG_PTR ueContext = NULL; + + ueContext = (ULONG_PTR)GetContextData(UE_EFLAGS); + if(!(ueContext & 0x100)) + { + ueContext = ueContext ^ 0x100; + } + SetContextData(UE_EFLAGS, ueContext); + engineStepActive = true; + engineStepCount = (int)StepCount; + engineStepCallBack = StepCallBack; + engineStepCount--; +} +__declspec(dllexport) bool __stdcall GetUnusedHardwareBreakPointRegister(LPDWORD RegisterIndex) +{ + return(EngineIsThereFreeHardwareBreakSlot(RegisterIndex)); +} +__declspec(dllexport) bool __stdcall SetHardwareBreakPointEx(HANDLE hActiveThread, ULONG_PTR bpxAddress, DWORD IndexOfRegister, DWORD bpxType, DWORD bpxSize, LPVOID bpxCallBack, LPDWORD IndexOfSelectedRegister) +{ + + ULONG_PTR HardwareBPX = NULL; + + if(bpxSize == UE_HARDWARE_SIZE_2) + { + if(bpxAddress % 2 != 0) + { + return(false); + } + } + else if(bpxSize == UE_HARDWARE_SIZE_4) + { + if(bpxAddress % 4 != 0) + { + return(false); + } + } + + if(IndexOfRegister == NULL) + { + if(!DebugRegister0.DrxEnabled) + { + IndexOfRegister = UE_DR0; + } + else if(!DebugRegister1.DrxEnabled) + { + IndexOfRegister = UE_DR1; + } + else if(!DebugRegister2.DrxEnabled) + { + IndexOfRegister = UE_DR2; + } + else if(!DebugRegister3.DrxEnabled) + { + IndexOfRegister = UE_DR3; + } + else + { + IndexOfRegister = UE_DR3; + } + } + + *IndexOfSelectedRegister = IndexOfRegister; + if(IndexOfRegister == UE_DR0) + { + DebugRegister0.DrxExecution = false; + DebugRegister0.DrxBreakPointType = bpxType; + DebugRegister0.DrxBreakPointSize = bpxSize; + HardwareBPX = (ULONG_PTR)GetContextData(UE_DR7); + HardwareBPX = HardwareBPX | (1 << 0); + HardwareBPX = HardwareBPX &~ (1 << 1); + if(bpxType == UE_HARDWARE_EXECUTE) + { + DebugRegister0.DrxExecution = true; + HardwareBPX = HardwareBPX &~ (1 << 17); + HardwareBPX = HardwareBPX &~ (1 << 16); + } + else if(bpxType == UE_HARDWARE_WRITE) + { + HardwareBPX = HardwareBPX &~ (1 << 17); + HardwareBPX = HardwareBPX | (1 << 16); + } + else if(bpxType == UE_HARDWARE_READWRITE) + { + HardwareBPX = HardwareBPX | (1 << 17); + HardwareBPX = HardwareBPX | (1 << 16); + } + if(bpxSize == UE_HARDWARE_SIZE_1 || bpxType == UE_HARDWARE_EXECUTE) + { + HardwareBPX = HardwareBPX &~ (1 << 19); + HardwareBPX = HardwareBPX &~ (1 << 18); + } + else if(bpxSize == UE_HARDWARE_SIZE_2) + { + HardwareBPX = HardwareBPX &~ (1 << 19); + HardwareBPX = HardwareBPX | (1 << 18); + } + else if(bpxSize == UE_HARDWARE_SIZE_4) + { + HardwareBPX = HardwareBPX | (1 << 19); + HardwareBPX = HardwareBPX | (1 << 18); + } + HardwareBPX = HardwareBPX | (1 << 10); + HardwareBPX = HardwareBPX &~ (1 << 11); + HardwareBPX = HardwareBPX &~ (1 << 12); + HardwareBPX = HardwareBPX &~ (1 << 14); + HardwareBPX = HardwareBPX &~ (1 << 15); + SetContextDataEx(hActiveThread, UE_DR0, (ULONG_PTR)bpxAddress); + SetContextDataEx(hActiveThread, UE_DR7, HardwareBPX); + DebugRegister0.DrxEnabled = true; + DebugRegister0.DrxBreakAddress = (ULONG_PTR)bpxAddress; + DebugRegister0.DrxCallBack = (ULONG_PTR)bpxCallBack; + return(true); + } + else if(IndexOfRegister == UE_DR1) + { + DebugRegister1.DrxExecution = false; + DebugRegister1.DrxBreakPointType = bpxType; + DebugRegister1.DrxBreakPointSize = bpxSize; + HardwareBPX = (ULONG_PTR)GetContextData(UE_DR7); + HardwareBPX = HardwareBPX | (1 << 2); + HardwareBPX = HardwareBPX &~ (1 << 3); + if(bpxType == UE_HARDWARE_EXECUTE) + { + DebugRegister1.DrxExecution = true; + HardwareBPX = HardwareBPX &~ (1 << 21); + HardwareBPX = HardwareBPX &~ (1 << 20); + } + else if(bpxType == UE_HARDWARE_WRITE) + { + HardwareBPX = HardwareBPX &~ (1 << 21); + HardwareBPX = HardwareBPX | (1 << 20); + } + else if(bpxType == UE_HARDWARE_READWRITE) + { + HardwareBPX = HardwareBPX | (1 << 21); + HardwareBPX = HardwareBPX | (1 << 20); + } + if(bpxSize == UE_HARDWARE_SIZE_1 || bpxType == UE_HARDWARE_EXECUTE) + { + HardwareBPX = HardwareBPX &~ (1 << 23); + HardwareBPX = HardwareBPX &~ (1 << 22); + } + else if(bpxSize == UE_HARDWARE_SIZE_2) + { + HardwareBPX = HardwareBPX &~ (1 << 23); + HardwareBPX = HardwareBPX | (1 << 22); + } + else if(bpxSize == UE_HARDWARE_SIZE_4) + { + HardwareBPX = HardwareBPX | (1 << 23); + HardwareBPX = HardwareBPX | (1 << 22); + } + HardwareBPX = HardwareBPX | (1 << 10); + HardwareBPX = HardwareBPX &~ (1 << 11); + HardwareBPX = HardwareBPX &~ (1 << 12); + HardwareBPX = HardwareBPX &~ (1 << 14); + HardwareBPX = HardwareBPX &~ (1 << 15); + SetContextDataEx(hActiveThread, UE_DR1, (ULONG_PTR)bpxAddress); + SetContextDataEx(hActiveThread, UE_DR7, HardwareBPX); + DebugRegister1.DrxEnabled = true; + DebugRegister1.DrxBreakAddress = (ULONG_PTR)bpxAddress; + DebugRegister1.DrxCallBack = (ULONG_PTR)bpxCallBack; + return(true); + } + else if(IndexOfRegister == UE_DR2) + { + DebugRegister2.DrxExecution = false; + DebugRegister2.DrxBreakPointType = bpxType; + DebugRegister2.DrxBreakPointSize = bpxSize; + HardwareBPX = (ULONG_PTR)GetContextData(UE_DR7); + HardwareBPX = HardwareBPX | (1 << 4); + HardwareBPX = HardwareBPX &~ (1 << 5); + if(bpxType == UE_HARDWARE_EXECUTE) + { + DebugRegister2.DrxExecution = true; + HardwareBPX = HardwareBPX &~ (1 << 25); + HardwareBPX = HardwareBPX &~ (1 << 24); + } + else if(bpxType == UE_HARDWARE_WRITE) + { + HardwareBPX = HardwareBPX &~ (1 << 25); + HardwareBPX = HardwareBPX | (1 << 24); + } + else if(bpxType == UE_HARDWARE_READWRITE) + { + HardwareBPX = HardwareBPX | (1 << 25); + HardwareBPX = HardwareBPX | (1 << 24); + } + if(bpxSize == UE_HARDWARE_SIZE_1 || bpxType == UE_HARDWARE_EXECUTE) + { + HardwareBPX = HardwareBPX &~ (1 << 27); + HardwareBPX = HardwareBPX &~ (1 << 26); + } + else if(bpxSize == UE_HARDWARE_SIZE_2) + { + HardwareBPX = HardwareBPX &~ (1 << 27); + HardwareBPX = HardwareBPX | (1 << 26); + } + else if(bpxSize == UE_HARDWARE_SIZE_4) + { + HardwareBPX = HardwareBPX | (1 << 27); + HardwareBPX = HardwareBPX | (1 << 26); + } + HardwareBPX = HardwareBPX | (1 << 10); + HardwareBPX = HardwareBPX &~ (1 << 11); + HardwareBPX = HardwareBPX &~ (1 << 12); + HardwareBPX = HardwareBPX &~ (1 << 14); + HardwareBPX = HardwareBPX &~ (1 << 15); + SetContextDataEx(hActiveThread, UE_DR2, (ULONG_PTR)bpxAddress); + SetContextDataEx(hActiveThread, UE_DR7, HardwareBPX); + DebugRegister2.DrxEnabled = true; + DebugRegister2.DrxBreakAddress = (ULONG_PTR)bpxAddress; + DebugRegister2.DrxCallBack = (ULONG_PTR)bpxCallBack; + return(true); + } + else if(IndexOfRegister == UE_DR3) + { + DebugRegister3.DrxExecution = false; + DebugRegister3.DrxBreakPointType = bpxType; + DebugRegister3.DrxBreakPointSize = bpxSize; + HardwareBPX = (ULONG_PTR)GetContextData(UE_DR7); + HardwareBPX = HardwareBPX | (1 << 6); + HardwareBPX = HardwareBPX &~ (1 << 7); + if(bpxType == UE_HARDWARE_EXECUTE) + { + DebugRegister3.DrxExecution = true; + HardwareBPX = HardwareBPX &~ (1 << 29); + HardwareBPX = HardwareBPX &~ (1 << 28); + } + else if(bpxType == UE_HARDWARE_WRITE) + { + HardwareBPX = HardwareBPX &~ (1 << 29); + HardwareBPX = HardwareBPX | (1 << 28); + } + else if(bpxType == UE_HARDWARE_READWRITE) + { + HardwareBPX = HardwareBPX | (1 << 29); + HardwareBPX = HardwareBPX | (1 << 28); + } + if(bpxSize == UE_HARDWARE_SIZE_1 || bpxType == UE_HARDWARE_EXECUTE) + { + HardwareBPX = HardwareBPX &~ (1 << 31); + HardwareBPX = HardwareBPX &~ (1 << 30); + } + else if(bpxSize == UE_HARDWARE_SIZE_2) + { + HardwareBPX = HardwareBPX &~ (1 << 31); + HardwareBPX = HardwareBPX | (1 << 30); + } + else if(bpxSize == UE_HARDWARE_SIZE_4) + { + HardwareBPX = HardwareBPX | (1 << 31); + HardwareBPX = HardwareBPX | (1 << 30); + } + HardwareBPX = HardwareBPX | (1 << 10); + HardwareBPX = HardwareBPX &~ (1 << 11); + HardwareBPX = HardwareBPX &~ (1 << 12); + HardwareBPX = HardwareBPX &~ (1 << 14); + HardwareBPX = HardwareBPX &~ (1 << 15); + SetContextDataEx(hActiveThread, UE_DR3, (ULONG_PTR)bpxAddress); + SetContextDataEx(hActiveThread, UE_DR7, HardwareBPX); + DebugRegister3.DrxEnabled = true; + DebugRegister3.DrxBreakAddress = (ULONG_PTR)bpxAddress; + DebugRegister3.DrxCallBack = (ULONG_PTR)bpxCallBack; + return(true); + } + else + { + return(false); + } + return(false); +} +__declspec(dllexport) bool __stdcall SetHardwareBreakPoint(ULONG_PTR bpxAddress, DWORD IndexOfRegister, DWORD bpxType, DWORD bpxSize, LPVOID bpxCallBack) +{ + + ULONG_PTR HardwareBPX = NULL; + + if(bpxSize == UE_HARDWARE_SIZE_2) + { + if(bpxAddress % 2 != 0) + { + return(false); + } + } + else if(bpxSize == UE_HARDWARE_SIZE_4) + { + if(bpxAddress % 4 != 0) + { + return(false); + } + } + + if(IndexOfRegister == NULL) + { + if(!DebugRegister0.DrxEnabled) + { + IndexOfRegister = UE_DR0; + } + else if(!DebugRegister1.DrxEnabled) + { + IndexOfRegister = UE_DR1; + } + else if(!DebugRegister2.DrxEnabled) + { + IndexOfRegister = UE_DR2; + } + else if(!DebugRegister3.DrxEnabled) + { + IndexOfRegister = UE_DR3; + } + else + { + IndexOfRegister = UE_DR3; + } + } + + if(IndexOfRegister == UE_DR0) + { + DebugRegister0.DrxExecution = false; + DebugRegister0.DrxBreakPointType = bpxType; + DebugRegister0.DrxBreakPointSize = bpxSize; + HardwareBPX = (ULONG_PTR)GetContextData(UE_DR7); + HardwareBPX = HardwareBPX | (1 << 0); + HardwareBPX = HardwareBPX &~ (1 << 1); + if(bpxType == UE_HARDWARE_EXECUTE) + { + DebugRegister0.DrxExecution = true; + HardwareBPX = HardwareBPX &~ (1 << 17); + HardwareBPX = HardwareBPX &~ (1 << 16); + } + else if(bpxType == UE_HARDWARE_WRITE) + { + HardwareBPX = HardwareBPX &~ (1 << 17); + HardwareBPX = HardwareBPX | (1 << 16); + } + else if(bpxType == UE_HARDWARE_READWRITE) + { + HardwareBPX = HardwareBPX | (1 << 17); + HardwareBPX = HardwareBPX | (1 << 16); + } + if(bpxSize == UE_HARDWARE_SIZE_1 || bpxType == UE_HARDWARE_EXECUTE) + { + HardwareBPX = HardwareBPX &~ (1 << 19); + HardwareBPX = HardwareBPX &~ (1 << 18); + } + else if(bpxSize == UE_HARDWARE_SIZE_2) + { + HardwareBPX = HardwareBPX &~ (1 << 19); + HardwareBPX = HardwareBPX | (1 << 18); + } + else if(bpxSize == UE_HARDWARE_SIZE_4) + { + HardwareBPX = HardwareBPX | (1 << 19); + HardwareBPX = HardwareBPX | (1 << 18); + } + HardwareBPX = HardwareBPX | (1 << 10); + HardwareBPX = HardwareBPX &~ (1 << 11); + HardwareBPX = HardwareBPX &~ (1 << 12); + HardwareBPX = HardwareBPX &~ (1 << 14); + HardwareBPX = HardwareBPX &~ (1 << 15); + SetContextData(UE_DR0, (ULONG_PTR)bpxAddress); + SetContextData(UE_DR7, HardwareBPX); + DebugRegister0.DrxEnabled = true; + DebugRegister0.DrxBreakAddress = (ULONG_PTR)bpxAddress; + DebugRegister0.DrxCallBack = (ULONG_PTR)bpxCallBack; + return(true); + } + else if(IndexOfRegister == UE_DR1) + { + DebugRegister1.DrxExecution = false; + DebugRegister1.DrxBreakPointType = bpxType; + DebugRegister1.DrxBreakPointSize = bpxSize; + HardwareBPX = (ULONG_PTR)GetContextData(UE_DR7); + HardwareBPX = HardwareBPX | (1 << 2); + HardwareBPX = HardwareBPX &~ (1 << 3); + if(bpxType == UE_HARDWARE_EXECUTE) + { + DebugRegister1.DrxExecution = true; + HardwareBPX = HardwareBPX &~ (1 << 21); + HardwareBPX = HardwareBPX &~ (1 << 20); + } + else if(bpxType == UE_HARDWARE_WRITE) + { + HardwareBPX = HardwareBPX &~ (1 << 21); + HardwareBPX = HardwareBPX | (1 << 20); + } + else if(bpxType == UE_HARDWARE_READWRITE) + { + HardwareBPX = HardwareBPX | (1 << 21); + HardwareBPX = HardwareBPX | (1 << 20); + } + if(bpxSize == UE_HARDWARE_SIZE_1 || bpxType == UE_HARDWARE_EXECUTE) + { + HardwareBPX = HardwareBPX &~ (1 << 23); + HardwareBPX = HardwareBPX &~ (1 << 22); + } + else if(bpxSize == UE_HARDWARE_SIZE_2) + { + HardwareBPX = HardwareBPX &~ (1 << 23); + HardwareBPX = HardwareBPX | (1 << 22); + } + else if(bpxSize == UE_HARDWARE_SIZE_4) + { + HardwareBPX = HardwareBPX | (1 << 23); + HardwareBPX = HardwareBPX | (1 << 22); + } + HardwareBPX = HardwareBPX | (1 << 10); + HardwareBPX = HardwareBPX &~ (1 << 11); + HardwareBPX = HardwareBPX &~ (1 << 12); + HardwareBPX = HardwareBPX &~ (1 << 14); + HardwareBPX = HardwareBPX &~ (1 << 15); + SetContextData(UE_DR1, (ULONG_PTR)bpxAddress); + SetContextData(UE_DR7, HardwareBPX); + DebugRegister1.DrxEnabled = true; + DebugRegister1.DrxBreakAddress = (ULONG_PTR)bpxAddress; + DebugRegister1.DrxCallBack = (ULONG_PTR)bpxCallBack; + return(true); + } + else if(IndexOfRegister == UE_DR2) + { + DebugRegister2.DrxExecution = false; + DebugRegister2.DrxBreakPointType = bpxType; + DebugRegister2.DrxBreakPointSize = bpxSize; + HardwareBPX = (ULONG_PTR)GetContextData(UE_DR7); + HardwareBPX = HardwareBPX | (1 << 4); + HardwareBPX = HardwareBPX &~ (1 << 5); + if(bpxType == UE_HARDWARE_EXECUTE) + { + DebugRegister2.DrxExecution = true; + HardwareBPX = HardwareBPX &~ (1 << 25); + HardwareBPX = HardwareBPX &~ (1 << 24); + } + else if(bpxType == UE_HARDWARE_WRITE) + { + HardwareBPX = HardwareBPX &~ (1 << 25); + HardwareBPX = HardwareBPX | (1 << 24); + } + else if(bpxType == UE_HARDWARE_READWRITE) + { + HardwareBPX = HardwareBPX | (1 << 25); + HardwareBPX = HardwareBPX | (1 << 24); + } + if(bpxSize == UE_HARDWARE_SIZE_1 || bpxType == UE_HARDWARE_EXECUTE) + { + HardwareBPX = HardwareBPX &~ (1 << 27); + HardwareBPX = HardwareBPX &~ (1 << 26); + } + else if(bpxSize == UE_HARDWARE_SIZE_2) + { + HardwareBPX = HardwareBPX &~ (1 << 27); + HardwareBPX = HardwareBPX | (1 << 26); + } + else if(bpxSize == UE_HARDWARE_SIZE_4) + { + HardwareBPX = HardwareBPX | (1 << 27); + HardwareBPX = HardwareBPX | (1 << 26); + } + HardwareBPX = HardwareBPX | (1 << 10); + HardwareBPX = HardwareBPX &~ (1 << 11); + HardwareBPX = HardwareBPX &~ (1 << 12); + HardwareBPX = HardwareBPX &~ (1 << 14); + HardwareBPX = HardwareBPX &~ (1 << 15); + SetContextData(UE_DR2, (ULONG_PTR)bpxAddress); + SetContextData(UE_DR7, HardwareBPX); + DebugRegister2.DrxEnabled = true; + DebugRegister2.DrxBreakAddress = (ULONG_PTR)bpxAddress; + DebugRegister2.DrxCallBack = (ULONG_PTR)bpxCallBack; + return(true); + } + else if(IndexOfRegister == UE_DR3) + { + DebugRegister3.DrxExecution = false; + DebugRegister3.DrxBreakPointType = bpxType; + DebugRegister3.DrxBreakPointSize = bpxSize; + HardwareBPX = (ULONG_PTR)GetContextData(UE_DR7); + HardwareBPX = HardwareBPX | (1 << 6); + HardwareBPX = HardwareBPX &~ (1 << 7); + if(bpxType == UE_HARDWARE_EXECUTE) + { + DebugRegister3.DrxExecution = true; + HardwareBPX = HardwareBPX &~ (1 << 29); + HardwareBPX = HardwareBPX &~ (1 << 28); + } + else if(bpxType == UE_HARDWARE_WRITE) + { + HardwareBPX = HardwareBPX &~ (1 << 29); + HardwareBPX = HardwareBPX | (1 << 28); + } + else if(bpxType == UE_HARDWARE_READWRITE) + { + HardwareBPX = HardwareBPX | (1 << 29); + HardwareBPX = HardwareBPX | (1 << 28); + } + if(bpxSize == UE_HARDWARE_SIZE_1 || bpxType == UE_HARDWARE_EXECUTE) + { + HardwareBPX = HardwareBPX &~ (1 << 31); + HardwareBPX = HardwareBPX &~ (1 << 30); + } + else if(bpxSize == UE_HARDWARE_SIZE_2) + { + HardwareBPX = HardwareBPX &~ (1 << 31); + HardwareBPX = HardwareBPX | (1 << 30); + } + else if(bpxSize == UE_HARDWARE_SIZE_4) + { + HardwareBPX = HardwareBPX | (1 << 31); + HardwareBPX = HardwareBPX | (1 << 30); + } + HardwareBPX = HardwareBPX | (1 << 10); + HardwareBPX = HardwareBPX &~ (1 << 11); + HardwareBPX = HardwareBPX &~ (1 << 12); + HardwareBPX = HardwareBPX &~ (1 << 14); + HardwareBPX = HardwareBPX &~ (1 << 15); + SetContextData(UE_DR3, (ULONG_PTR)bpxAddress); + SetContextData(UE_DR7, HardwareBPX); + DebugRegister3.DrxEnabled = true; + DebugRegister3.DrxBreakAddress = (ULONG_PTR)bpxAddress; + DebugRegister3.DrxCallBack = (ULONG_PTR)bpxCallBack; + return(true); + } + else + { + return(false); + } + return(false); +} +__declspec(dllexport) bool __stdcall DeleteHardwareBreakPoint(DWORD IndexOfRegister) +{ + + ULONG_PTR HardwareBPX = NULL; + ULONG_PTR bpxAddress = NULL; + + if(IndexOfRegister == UE_DR0) + { + HardwareBPX = (ULONG_PTR)GetContextData(UE_DR7); + HardwareBPX = HardwareBPX &~ (1 << 0); + HardwareBPX = HardwareBPX &~ (1 << 1); + SetContextData(UE_DR0, (ULONG_PTR)bpxAddress); + SetContextData(UE_DR7, HardwareBPX); + DebugRegister0.DrxEnabled = false; + DebugRegister0.DrxBreakAddress = NULL; + DebugRegister0.DrxCallBack = NULL; + return(true); + } + else if(IndexOfRegister == UE_DR1) + { + HardwareBPX = (ULONG_PTR)GetContextData(UE_DR7); + HardwareBPX = HardwareBPX &~ (1 << 2); + HardwareBPX = HardwareBPX &~ (1 << 3); + SetContextData(UE_DR1, (ULONG_PTR)bpxAddress); + SetContextData(UE_DR7, HardwareBPX); + DebugRegister1.DrxEnabled = false; + DebugRegister1.DrxBreakAddress = NULL; + DebugRegister1.DrxCallBack = NULL; + return(true); + } + else if(IndexOfRegister == UE_DR2) + { + HardwareBPX = (ULONG_PTR)GetContextData(UE_DR7); + HardwareBPX = HardwareBPX &~ (1 << 4); + HardwareBPX = HardwareBPX &~ (1 << 5); + SetContextData(UE_DR2, (ULONG_PTR)bpxAddress); + SetContextData(UE_DR7, HardwareBPX); + DebugRegister2.DrxEnabled = false; + DebugRegister2.DrxBreakAddress = NULL; + DebugRegister2.DrxCallBack = NULL; + return(true); + } + else if(IndexOfRegister == UE_DR3) + { + HardwareBPX = (ULONG_PTR)GetContextData(UE_DR7); + HardwareBPX = HardwareBPX &~ (1 << 6); + HardwareBPX = HardwareBPX &~ (1 << 7); + SetContextData(UE_DR3, (ULONG_PTR)bpxAddress); + SetContextData(UE_DR7, HardwareBPX); + DebugRegister3.DrxEnabled = false; + DebugRegister3.DrxBreakAddress = NULL; + DebugRegister3.DrxCallBack = NULL; + return(true); + } + else + { + return(false); + } + return(false); +} +__declspec(dllexport) bool __stdcall RemoveAllBreakPoints(DWORD RemoveOption) +{ + + int i = 0; + int CurrentBreakPointSetCount = -1; + + if(RemoveOption == UE_OPTION_REMOVEALL) + { + for(i = BreakPointSetCount - 1; i >= 0; i--) + { + if(BreakPointBuffer[i].BreakPointType == UE_BREAKPOINT) + { + DeleteBPX((ULONG_PTR)BreakPointBuffer[i].BreakPointAddress); + } + else if(BreakPointBuffer[i].BreakPointType >= UE_MEMORY && BreakPointBuffer[i].BreakPointType <= UE_MEMORY_WRITE) + { + RemoveMemoryBPX((ULONG_PTR)BreakPointBuffer[i].BreakPointAddress, BreakPointBuffer[i].BreakPointSize); + } + else if(CurrentBreakPointSetCount == -1 && BreakPointBuffer[i].BreakPointActive != UE_BPXREMOVED) + { + CurrentBreakPointSetCount = BreakPointSetCount; + } + RtlZeroMemory(&BreakPointBuffer[i], sizeof BreakPointDetail); + } + DeleteHardwareBreakPoint(UE_DR0); + DeleteHardwareBreakPoint(UE_DR1); + DeleteHardwareBreakPoint(UE_DR2); + DeleteHardwareBreakPoint(UE_DR3); + BreakPointSetCount = 0; + return(true); + } + else if(RemoveOption == UE_OPTION_DISABLEALL) + { + for(i = BreakPointSetCount - 1; i >= 0; i--) + { + if(BreakPointBuffer[i].BreakPointType == UE_BREAKPOINT && BreakPointBuffer[i].BreakPointActive == UE_BPXACTIVE) + { + DisableBPX((ULONG_PTR)BreakPointBuffer[i].BreakPointAddress); + } + else if(BreakPointBuffer[i].BreakPointType >= UE_MEMORY && BreakPointBuffer[i].BreakPointType <= UE_MEMORY_WRITE) + { + RemoveMemoryBPX((ULONG_PTR)BreakPointBuffer[i].BreakPointAddress, BreakPointBuffer[i].BreakPointSize); + RtlZeroMemory(&BreakPointBuffer[i], sizeof BreakPointDetail); + } + } + return(true); + } + else if(RemoveOption == UE_OPTION_REMOVEALLDISABLED) + { + for(i = BreakPointSetCount - 1; i >= 0; i--) + { + if(BreakPointBuffer[i].BreakPointType == UE_BREAKPOINT && BreakPointBuffer[i].BreakPointActive == UE_BPXINACTIVE) + { + DeleteBPX((ULONG_PTR)BreakPointBuffer[i].BreakPointAddress); + } + else if(CurrentBreakPointSetCount == -1 && BreakPointBuffer[i].BreakPointActive != UE_BPXREMOVED) + { + CurrentBreakPointSetCount = BreakPointSetCount; + } + } + if(CurrentBreakPointSetCount == -1) + { + BreakPointSetCount = 0; + } + else + { + BreakPointSetCount = CurrentBreakPointSetCount; + } + return(true); + } + else if(RemoveOption == UE_OPTION_REMOVEALLENABLED) + { + for(i = BreakPointSetCount - 1; i >= 0; i--) + { + if(BreakPointBuffer[i].BreakPointType == UE_BREAKPOINT && BreakPointBuffer[i].BreakPointActive == UE_BPXACTIVE) + { + DeleteBPX((ULONG_PTR)BreakPointBuffer[i].BreakPointAddress); + } + else if(CurrentBreakPointSetCount == -1 && BreakPointBuffer[i].BreakPointActive != UE_BPXREMOVED) + { + CurrentBreakPointSetCount = BreakPointSetCount; + } + } + if(CurrentBreakPointSetCount == -1) + { + BreakPointSetCount = 0; + } + else + { + BreakPointSetCount = CurrentBreakPointSetCount; + } + return(true); + } + return(false); +} +__declspec(dllexport) void* __stdcall GetProcessInformation() +{ + return(&dbgProcessInformation); +} +__declspec(dllexport) void* __stdcall GetStartupInformation() +{ + return(&dbgStartupInfo); +} +__declspec(dllexport) void __stdcall DebugLoop() +{ + + int i = NULL; + int j = NULL; + int k = NULL; + bool FirstBPX = true; + bool ResetBPX = false; + bool BreakDBG = false; + bool ResetHwBPX = false; + bool CompareResult = false; + bool SecondChance = false; + ULONG_PTR CmpValue1 = NULL; + ULONG_PTR CmpValue2 = NULL; + bool hListProcessFirst = true; + bool hListThreadFirst = true; + bool hListLibraryFirst = true; + PPROCESS_ITEM_DATA hListProcessPtr = NULL; + PTHREAD_ITEM_DATA hListThreadPtr = NULL; + PLIBRARY_ITEM_DATAW hListLibraryPtr = NULL; + PLIBRARY_ITEM_DATAW hLoadedLibData = NULL; + PLIBRARY_BREAK_DATA ptrLibrarianData = NULL; + typedef void(__stdcall *fCustomBreakPoint)(void); + typedef void(__stdcall *fCustomHandler)(void* SpecialDBG); + typedef void(__stdcall *fFindOEPHandler)(LPPROCESS_INFORMATION fProcessInfo, LPVOID fCallBack); + fCustomHandler myCustomHandler; + fCustomBreakPoint myCustomBreakPoint; + fFindOEPHandler myFindOEPHandler; + ULONG_PTR MemoryBpxCallBack = 0; + DWORD ResetBPXSize = 0; + ULONG_PTR ResetBPXAddressTo = 0; + int MaximumBreakPoints = 0; + ULONG_PTR NumberOfBytesReadWritten = 0; + MEMORY_BASIC_INFORMATION MemInfo; + HANDLE hActiveThread; + CONTEXT myDBGContext; + DWORD OldProtect; + DWORD NewProtect; + DWORD DebugRegisterXId = NULL; + HARDWARE_DATA DebugRegisterX; + wchar_t DLLDebugFileName[512]; + char szAnsiLibraryName[MAX_PATH]; + ULONG_PTR DLLPatchAddress; + HANDLE hFileMapping; + LPVOID hFileMappingView; + LPVOID DBGEntryPoint; + bool MemoryBpxFound = false; + wchar_t* szTranslatedNativeName; + + DBGFileHandle = NULL; + DBGCode = DBG_CONTINUE; + engineFakeDLLHandle = NULL; + DebugRegister0.DrxEnabled = false; + DebugRegister1.DrxEnabled = false; + DebugRegister2.DrxEnabled = false; + DebugRegister3.DrxEnabled = false; + engineProcessIsNowDetached = false; + engineResumeProcessIfNoThreadIsActive = false; + RtlZeroMemory(&DBGEvent, sizeof DEBUG_EVENT); + RtlZeroMemory(&TerminateDBGEvent, sizeof DEBUG_EVENT); + RtlZeroMemory(&DLLDebugFileName, 512); + EngineExecutePluginResetCallBack(); + engineFileIsBeingDebugged = true; + if(engineExecutePluginCallBack) + { + EngineExecutePluginDebugCallBack(&DBGEvent, UE_PLUGIN_CALL_REASON_PREDEBUG); + } + while(!BreakDBG) + { + WaitForDebugEvent(&DBGEvent, engineWaitForDebugEventTimeOut); + if(engineExecutePluginCallBack) + { + EngineExecutePluginDebugCallBack(&DBGEvent, UE_PLUGIN_CALL_REASON_EXCEPTION); + } + if(engineFindOEPCallBack != NULL) + { + myFindOEPHandler = (fFindOEPHandler)engineFindOEPCallBack; + engineFindOEPCallBack = NULL; + __try + { + myFindOEPHandler(&dbgProcessInformation, engineFindOEPUserCallBack); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + + } + } + if(DBGEvent.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT) + { + if(DBGFileHandle == NULL) + { + DBGEntryPoint = DBGEvent.u.CreateProcessInfo.lpStartAddress; + DBGFileHandle = DBGEvent.u.CreateProcessInfo.hFile; + engineDebuggingMainModuleBase = (unsigned long long) DBGEvent.u.CreateProcessInfo.lpBaseOfImage; + if(engineAttachedToProcess) + { + dbgProcessInformation.hProcess = DBGEvent.u.CreateProcessInfo.hProcess; + dbgProcessInformation.hThread = DBGEvent.u.CreateProcessInfo.hThread; + dbgProcessInformation.dwThreadId = NULL; + if(engineAttachedProcessDebugInfo != NULL) + { + RtlMoveMemory(engineAttachedProcessDebugInfo, &dbgProcessInformation, sizeof PROCESS_INFORMATION); + } + } + if(engineDebuggingDLL) + { +#if defined(_WIN64) + DLLPatchAddress = (ULONG_PTR)DBGEvent.u.CreateProcessInfo.lpBaseOfImage; + DLLPatchAddress = (ULONG_PTR)DLLPatchAddress + UE_MODULEx64; +#else + DLLPatchAddress = (ULONG_PTR)DBGEvent.u.CreateProcessInfo.lpBaseOfImage; + DLLPatchAddress = (ULONG_PTR)DLLPatchAddress + UE_MODULEx86; +#endif + if(!WriteProcessMemory(DBGEvent.u.CreateProcessInfo.hProcess, (LPVOID)DLLPatchAddress, engineDebuggingDLLFullFileName, lstrlenW(engineDebuggingDLLFullFileName) * 2, &NumberOfBytesReadWritten)) + { + StopDebug(); + } + if(engineReserveModuleBase) //reserve original image base + { + VirtualAllocEx(dbgProcessInformation.hProcess, (void*)engineReserveModuleBase, 0x1000, MEM_RESERVE, PAGE_READWRITE); + } + } + if(hListProcess == NULL) + { + hListProcess = VirtualAlloc(NULL, MAX_DEBUG_DATA * sizeof PROCESS_ITEM_DATA, MEM_COMMIT, PAGE_READWRITE); + } + else + { + if(hListProcessFirst == true) + { + RtlZeroMemory(hListProcess, MAX_DEBUG_DATA * sizeof PROCESS_ITEM_DATA); + } + } + if(hListThread == NULL) + { + hListThread = VirtualAlloc(NULL, MAX_DEBUG_DATA * sizeof THREAD_ITEM_DATA, MEM_COMMIT, PAGE_READWRITE); + } + else + { + if(hListThreadFirst == true) + { + RtlZeroMemory(hListThread, MAX_DEBUG_DATA * sizeof THREAD_ITEM_DATA); + } + } + hListProcessPtr = (PPROCESS_ITEM_DATA)hListProcess; + hListProcessPtr->hFile = DBGEvent.u.CreateProcessInfo.hFile; + hListProcessPtr->hProcess = DBGEvent.u.CreateProcessInfo.hProcess; + hListProcessPtr->hThread = DBGEvent.u.CreateProcessInfo.hThread; + hListProcessPtr->dwProcessId = DBGEvent.dwProcessId; + hListProcessPtr->dwThreadId = DBGEvent.dwThreadId; + hListProcessPtr->BaseOfImage = (void*)DBGEvent.u.CreateProcessInfo.lpBaseOfImage; + hListProcessPtr->ThreadStartAddress = (void*)DBGEvent.u.CreateProcessInfo.lpStartAddress; + hListProcessPtr->ThreadLocalBase = (void*)DBGEvent.u.CreateProcessInfo.lpThreadLocalBase; + + hListThreadPtr = (PTHREAD_ITEM_DATA)hListThread; + hListThreadPtr->dwThreadId = DBGEvent.dwThreadId; + hListThreadPtr->hThread = DBGEvent.u.CreateProcessInfo.hThread; + hListThreadPtr->ThreadStartAddress = (void*)DBGEvent.u.CreateProcessInfo.lpStartAddress; + hListThreadPtr->ThreadLocalBase = (void*)DBGEvent.u.CreateProcessInfo.lpThreadLocalBase; + hListThreadFirst = false; + } + else + { + hListProcessPtr = (PPROCESS_ITEM_DATA)hListProcess; + while(hListProcessPtr->hProcess != NULL) + { + hListProcessPtr = (PPROCESS_ITEM_DATA)((ULONG_PTR)hListProcessPtr + sizeof PROCESS_ITEM_DATA); + } + if(hListProcessPtr->hProcess == NULL) + { + hListProcessPtr->hFile = DBGEvent.u.CreateProcessInfo.hFile; + hListProcessPtr->hProcess = DBGEvent.u.CreateProcessInfo.hProcess; + hListProcessPtr->hThread = DBGEvent.u.CreateProcessInfo.hThread; + hListProcessPtr->dwProcessId = DBGEvent.dwProcessId; + hListProcessPtr->dwThreadId = DBGEvent.dwThreadId; + hListProcessPtr->BaseOfImage = (void*)DBGEvent.u.CreateProcessInfo.lpBaseOfImage; + hListProcessPtr->ThreadStartAddress = (void*)DBGEvent.u.CreateProcessInfo.lpStartAddress; + hListProcessPtr->ThreadLocalBase = (void*)DBGEvent.u.CreateProcessInfo.lpThreadLocalBase; + hListProcessFirst = false; + } + } + if(DBGCustomHandler->chCreateProcess != NULL) + { + myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chCreateProcess); + __try + { + myCustomHandler(&DBGEvent.u.CreateProcessInfo); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + DBGCustomHandler->chCreateProcess = NULL; + } + } + } + else if(DBGEvent.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT) + { + ProcessExitCode = DBGEvent.u.ExitProcess.dwExitCode; + if(DBGEvent.dwProcessId == dbgProcessInformation.dwProcessId) + { + DBGCode = DBG_CONTINUE; + BreakDBG = true; + } + else + { + DBGCode = DBG_CONTINUE; + } + if(DBGCustomHandler->chExitProcess != NULL) + { + myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chExitProcess); + __try + { + myCustomHandler(&DBGEvent.u.ExitProcess); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + DBGCustomHandler->chExitProcess = NULL; + } + } + } + else if(DBGEvent.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT) + { + if(hListThread == NULL) + { + hListThread = VirtualAlloc(NULL, MAX_DEBUG_DATA * sizeof THREAD_ITEM_DATA, MEM_COMMIT, PAGE_READWRITE); + } + hListThreadPtr = (PTHREAD_ITEM_DATA)hListThread; + __try + { + while(hListThreadPtr->hThread != NULL) + { + hListThreadPtr = (PTHREAD_ITEM_DATA)((ULONG_PTR)hListThreadPtr + sizeof THREAD_ITEM_DATA); + } + hListThreadPtr->dwThreadId = DBGEvent.dwThreadId; + hListThreadPtr->hThread = DBGEvent.u.CreateThread.hThread; + hListThreadPtr->ThreadStartAddress = (void*)DBGEvent.u.CreateThread.lpStartAddress; + hListThreadPtr->ThreadLocalBase = (void*)DBGEvent.u.CreateThread.lpThreadLocalBase; + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + + } + if(DBGCustomHandler->chCreateThread != NULL) + { + myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chCreateThread); + __try + { + myCustomHandler(&DBGEvent.u.CreateThread); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + DBGCustomHandler->chCreateThread = NULL; + } + } + } + else if(DBGEvent.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT) + { + if(DBGCustomHandler->chExitThread != NULL) + { + myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chExitThread); + __try + { + myCustomHandler(&DBGEvent.u.ExitThread); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + DBGCustomHandler->chExitThread = NULL; + } + } + if(engineExitThreadOneShootCallBack != NULL) + { + myCustomHandler = (fCustomHandler)(engineExitThreadOneShootCallBack); + __try + { + myCustomHandler(&DBGEvent.u.ExitThread); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + + } + engineExitThreadOneShootCallBack = NULL; + } + hListThreadPtr = (PTHREAD_ITEM_DATA)hListThread; + while(hListThreadPtr->hThread != NULL && hListThreadPtr->dwThreadId != DBGEvent.dwThreadId) + { + hListThreadPtr = (PTHREAD_ITEM_DATA)((ULONG_PTR)hListThreadPtr + sizeof THREAD_ITEM_DATA); + } + if(hListThreadPtr->dwThreadId == DBGEvent.dwThreadId) + { + hListThreadPtr->hThread = (HANDLE)-1; + hListThreadPtr->dwThreadId = NULL; + hListThreadPtr->ThreadLocalBase = NULL; + hListThreadPtr->ThreadStartAddress = NULL; + } + } + else if(DBGEvent.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT) + { + if(hListLibrary == NULL) + { + hListLibrary = VirtualAlloc(NULL, MAX_DEBUG_DATA * sizeof LIBRARY_ITEM_DATAW, MEM_COMMIT, PAGE_READWRITE); + } + else + { + if(hListLibraryFirst == true) + { + RtlZeroMemory(hListLibrary, MAX_DEBUG_DATA * sizeof LIBRARY_ITEM_DATAW); + } + } + hListLibraryFirst = false; + hListLibraryPtr = (PLIBRARY_ITEM_DATAW)hListLibrary; + while(hListLibraryPtr->hFile != NULL) + { + hListLibraryPtr = (PLIBRARY_ITEM_DATAW)((ULONG_PTR)hListLibraryPtr + sizeof LIBRARY_ITEM_DATAW); + } + hListLibraryPtr->hFile = DBGEvent.u.LoadDll.hFile; + hListLibraryPtr->BaseOfDll = DBGEvent.u.LoadDll.lpBaseOfDll; + hFileMapping = CreateFileMappingA(DBGEvent.u.LoadDll.hFile, NULL, PAGE_READONLY, NULL, GetFileSize(DBGEvent.u.LoadDll.hFile, NULL), NULL); + if(hFileMapping != NULL) + { + hFileMappingView = MapViewOfFile(hFileMapping, FILE_MAP_READ, NULL, NULL, NULL); + if(hFileMappingView != NULL) + { + hListLibraryPtr->hFileMapping = hFileMapping; + hListLibraryPtr->hFileMappingView = hFileMappingView; + if(GetMappedFileNameW(GetCurrentProcess(), hFileMappingView, DLLDebugFileName, sizeof DLLDebugFileName) > NULL) + { + i = lstrlenW(DLLDebugFileName); + while(DLLDebugFileName[i] != 0x5C && i >= NULL) + { + i--; + } + if(engineDebuggingDLL) + { + if(lstrcmpiW(&DLLDebugFileName[i+1], engineDebuggingDLLFileName) == NULL) + { + SetBPX(DebugModuleEntryPoint + (ULONG_PTR)DBGEvent.u.LoadDll.lpBaseOfDll, UE_SINGLESHOOT, DebugModuleEntryPointCallBack); + engineDebuggingDLLBase = (ULONG_PTR)DBGEvent.u.LoadDll.lpBaseOfDll; + } + /*else if(lstrcmpiW(&DLLDebugFileName[i+1], engineDebuggingDLLReserveFileName) == NULL) + { + if((ULONG_PTR)DBGEvent.u.LoadDll.lpBaseOfDll != DebugModuleImageBase) + { + VirtualAllocEx(dbgProcessInformation.hProcess, (void*)DebugModuleImageBase, 0x1000, MEM_RESERVE, PAGE_READWRITE); + } + }*/ + } + if(engineFakeDLLHandle == NULL) + { + if(lstrcmpiW(&DLLDebugFileName[i+1], L"kernel32.dll") == NULL) + { + engineFakeDLLHandle = (ULONG_PTR)DBGEvent.u.LoadDll.lpBaseOfDll; + } + } + lstrcpyW(hListLibraryPtr->szLibraryName, &DLLDebugFileName[i+1]); + szTranslatedNativeName = (wchar_t*)TranslateNativeNameW(DLLDebugFileName); + lstrcpyW(hListLibraryPtr->szLibraryPath, szTranslatedNativeName); + VirtualFree((void*)szTranslatedNativeName, NULL, MEM_RELEASE); + RtlZeroMemory(szAnsiLibraryName, sizeof szAnsiLibraryName); + WideCharToMultiByte(CP_ACP, NULL, hListLibraryPtr->szLibraryName, -1, szAnsiLibraryName, sizeof szAnsiLibraryName, NULL, NULL); + ptrLibrarianData = (PLIBRARY_BREAK_DATA)LibrarianData; + k = NULL; + if(ptrLibrarianData != NULL) + { + while(k < MAX_LIBRARY_BPX) + { + if(ptrLibrarianData->szLibraryName[0] != 0x00) + { + if(lstrcmpiA(ptrLibrarianData->szLibraryName, szAnsiLibraryName) == NULL) + { + if(ptrLibrarianData->bpxType == UE_ON_LIB_LOAD || ptrLibrarianData->bpxType == UE_ON_LIB_ALL) + { + myCustomHandler = (fCustomHandler)(ptrLibrarianData->bpxCallBack); + __try + { + myCustomHandler(&DBGEvent.u.LoadDll); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + LibrarianRemoveBreakPoint(ptrLibrarianData->szLibraryName, ptrLibrarianData->bpxType); + } + if(ptrLibrarianData->bpxSingleShoot) + { + LibrarianRemoveBreakPoint(ptrLibrarianData->szLibraryName, ptrLibrarianData->bpxType); + } + } + } + } + ptrLibrarianData = (PLIBRARY_BREAK_DATA)((ULONG_PTR)ptrLibrarianData + sizeof LIBRARY_BREAK_DATA); + k++; + } + } + } + } + } + if(DBGCustomHandler->chLoadDll != NULL) + { + myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chLoadDll); + __try + { + myCustomHandler(&DBGEvent.u.LoadDll); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + DBGCustomHandler->chLoadDll = NULL; + } + } + } + else if(DBGEvent.dwDebugEventCode == UNLOAD_DLL_DEBUG_EVENT) + { + if(DBGCustomHandler->chUnloadDll != NULL) + { + myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chUnloadDll); + __try + { + myCustomHandler(&DBGEvent.u.UnloadDll); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + DBGCustomHandler->chUnloadDll = NULL; + } + } + k = NULL; + ptrLibrarianData = (PLIBRARY_BREAK_DATA)LibrarianData; + hLoadedLibData = (PLIBRARY_ITEM_DATAW)LibrarianGetLibraryInfoEx(DBGEvent.u.UnloadDll.lpBaseOfDll); + if(hLoadedLibData != NULL) + { + RtlZeroMemory(szAnsiLibraryName, sizeof szAnsiLibraryName); + WideCharToMultiByte(CP_ACP, NULL, hLoadedLibData->szLibraryName, -1, szAnsiLibraryName, sizeof szAnsiLibraryName, NULL, NULL); + if(ptrLibrarianData != NULL) + { + while(k < MAX_LIBRARY_BPX) + { + if(ptrLibrarianData->szLibraryName[0] != 0x00) + { + if(lstrcmpiA(ptrLibrarianData->szLibraryName, szAnsiLibraryName) == NULL) + { + if(ptrLibrarianData->bpxType == UE_ON_LIB_UNLOAD || ptrLibrarianData->bpxType == UE_ON_LIB_ALL) + { + myCustomHandler = (fCustomHandler)(ptrLibrarianData->bpxCallBack); + __try + { + myCustomHandler(&DBGEvent.u.UnloadDll); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + LibrarianRemoveBreakPoint(ptrLibrarianData->szLibraryName, ptrLibrarianData->bpxType); + } + if(ptrLibrarianData->bpxSingleShoot) + { + LibrarianRemoveBreakPoint(ptrLibrarianData->szLibraryName, ptrLibrarianData->bpxType); + } + } + } + } + ptrLibrarianData = (PLIBRARY_BREAK_DATA)((ULONG_PTR)ptrLibrarianData + sizeof LIBRARY_BREAK_DATA); + k++; + } + } + } + hListLibraryPtr = (PLIBRARY_ITEM_DATAW)hListLibrary; + if(hListLibraryPtr != NULL) + { + while(hListLibraryPtr->hFile != NULL) + { + if(hListLibraryPtr->BaseOfDll == DBGEvent.u.UnloadDll.lpBaseOfDll) + { + if(hListLibraryPtr->hFile != (HANDLE)-1) + { + if(hListLibraryPtr->hFileMappingView != NULL) + { + UnmapViewOfFile(hListLibraryPtr->hFileMappingView); + EngineCloseHandle(hListLibraryPtr->hFileMapping); + } + EngineCloseHandle(hListLibraryPtr->hFile); + RtlZeroMemory(hListLibraryPtr, sizeof LIBRARY_ITEM_DATAW); + hListLibraryPtr->hFile = (HANDLE)-1; + } + } + hListLibraryPtr = (PLIBRARY_ITEM_DATAW)((ULONG_PTR)hListLibraryPtr + sizeof LIBRARY_ITEM_DATAW); + } + } + } + else if(DBGEvent.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT) + { + if(DBGCustomHandler->chOutputDebugString != NULL) + { + myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chOutputDebugString); + __try + { + myCustomHandler(&DBGEvent.u.DebugString); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + DBGCustomHandler->chOutputDebugString = NULL; + } + } + } + else if(DBGEvent.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) + { + bool firstchance=false; + if(DBGCustomHandler->chEverythingElse != NULL) + { + myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chEverythingElse); + __try + { + myCustomHandler(&DBGEvent.u.Exception.ExceptionRecord); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + DBGCustomHandler->chEverythingElse = NULL; + } + } + if(DBGEvent.u.Exception.dwFirstChance == FALSE) + { + if(!enginePassAllExceptions) + { + firstchance=true; + DBGCode = DBG_CONTINUE; + } + else + { + DBGCode = DBG_EXCEPTION_NOT_HANDLED; + } + RtlMoveMemory(&TerminateDBGEvent, &DBGEvent, sizeof DEBUG_EVENT); + } + if(DBGEvent.u.Exception.ExceptionRecord.ExceptionCode == STATUS_BREAKPOINT) + { + /*if(DBGCustomHandler->chBreakPoint != NULL) + { + myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chBreakPoint); + __try + { + myCustomHandler(&DBGEvent.u.Exception.ExceptionRecord); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + DBGCustomHandler->chBreakPoint = NULL; + } + }*/ + MaximumBreakPoints = 0; + for(MaximumBreakPoints = 0; MaximumBreakPoints < BreakPointSetCount; MaximumBreakPoints++) + { + if(BreakPointBuffer[MaximumBreakPoints].BreakPointAddress == (ULONG_PTR)DBGEvent.u.Exception.ExceptionRecord.ExceptionAddress - (BreakPointBuffer[MaximumBreakPoints].BreakPointSize - 1)) + { + break; + } + } + if(BreakPointBuffer[MaximumBreakPoints].BreakPointActive == UE_BPXACTIVE && MaximumBreakPoints < MAXIMUM_BREAKPOINTS) + { + VirtualQueryEx(dbgProcessInformation.hProcess, (LPVOID)BreakPointBuffer[MaximumBreakPoints].BreakPointAddress, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + OldProtect = MemInfo.AllocationProtect; + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)BreakPointBuffer[MaximumBreakPoints].BreakPointAddress, BreakPointBuffer[MaximumBreakPoints].BreakPointSize, PAGE_EXECUTE_READWRITE, &OldProtect); + if(BreakPointBuffer[MaximumBreakPoints].BreakPointActive == UE_BPXACTIVE && (BreakPointBuffer[MaximumBreakPoints].BreakPointType == UE_BREAKPOINT || BreakPointBuffer[MaximumBreakPoints].BreakPointType == UE_SINGLESHOOT) && (BreakPointBuffer[MaximumBreakPoints].NumberOfExecutions == -1 || BreakPointBuffer[MaximumBreakPoints].NumberOfExecutions > 0)) + { + if(WriteProcessMemory(dbgProcessInformation.hProcess, (LPVOID)BreakPointBuffer[MaximumBreakPoints].BreakPointAddress, &BreakPointBuffer[MaximumBreakPoints].OriginalByte[0], BreakPointBuffer[MaximumBreakPoints].BreakPointSize, &NumberOfBytesReadWritten)) + { + DBGCode = DBG_CONTINUE; + hActiveThread = OpenThread(THREAD_GET_CONTEXT+THREAD_SET_CONTEXT+THREAD_QUERY_INFORMATION, false, DBGEvent.dwThreadId); + myDBGContext.ContextFlags = CONTEXT_ALL; + GetThreadContext(hActiveThread, &myDBGContext); + if(BreakPointBuffer[MaximumBreakPoints].BreakPointType != UE_SINGLESHOOT) + { + if(!(myDBGContext.EFlags & 0x100)) + { + myDBGContext.EFlags = myDBGContext.EFlags ^ 0x100; + } + } + if(!(myDBGContext.EFlags & 0x10000)) + { + myDBGContext.EFlags = myDBGContext.EFlags ^ 0x10000; + } +#if defined(_WIN64) + myDBGContext.Rip = myDBGContext.Rip - BreakPointBuffer[MaximumBreakPoints].BreakPointSize; +#else + myDBGContext.Eip = myDBGContext.Eip - BreakPointBuffer[MaximumBreakPoints].BreakPointSize; +#endif + SetThreadContext(hActiveThread, &myDBGContext); + EngineCloseHandle(hActiveThread); + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)BreakPointBuffer[MaximumBreakPoints].BreakPointAddress, BreakPointBuffer[MaximumBreakPoints].BreakPointSize, MemInfo.AllocationProtect, &OldProtect); + myCustomBreakPoint = (fCustomBreakPoint)((LPVOID)BreakPointBuffer[MaximumBreakPoints].ExecuteCallBack); + if(BreakPointBuffer[MaximumBreakPoints].NumberOfExecutions != -1 && BreakPointBuffer[MaximumBreakPoints].NumberOfExecutions != 0) + { + BreakPointBuffer[MaximumBreakPoints].NumberOfExecutions--; + } + if(BreakPointBuffer[MaximumBreakPoints].CmpCondition != UE_CMP_NOCONDITION) + { + CompareResult = false; + CmpValue1 = (ULONG_PTR)GetContextData((DWORD)BreakPointBuffer[MaximumBreakPoints].CmpRegister); + myCustomBreakPoint = (fCustomBreakPoint)((LPVOID)BreakPointBuffer[MaximumBreakPoints].CompareCallBack); + if(BreakPointBuffer[MaximumBreakPoints].CmpCondition == UE_CMP_EQUAL) + { + CmpValue2 = BreakPointBuffer[MaximumBreakPoints].CmpValue; + if(CmpValue1 == CmpValue2) + { + CompareResult = true; + } + } + else if(BreakPointBuffer[MaximumBreakPoints].CmpCondition == UE_CMP_NOTEQUAL) + { + CmpValue2 = BreakPointBuffer[MaximumBreakPoints].CmpValue; + if(CmpValue1 != CmpValue2) + { + CompareResult = true; + } + } + else if(BreakPointBuffer[MaximumBreakPoints].CmpCondition == UE_CMP_GREATER) + { + CmpValue2 = BreakPointBuffer[MaximumBreakPoints].CmpValue; + if(CmpValue1 > CmpValue2) + { + CompareResult = true; + } + } + else if(BreakPointBuffer[MaximumBreakPoints].CmpCondition == UE_CMP_GREATEROREQUAL) + { + CmpValue2 = BreakPointBuffer[MaximumBreakPoints].CmpValue; + if(CmpValue1 >= CmpValue2) + { + CompareResult = true; + } + } + else if(BreakPointBuffer[MaximumBreakPoints].CmpCondition == UE_CMP_LOWER) + { + CmpValue2 = BreakPointBuffer[MaximumBreakPoints].CmpValue; + if(CmpValue1 < CmpValue2) + { + CompareResult = true; + } + } + else if(BreakPointBuffer[MaximumBreakPoints].CmpCondition == UE_CMP_LOWEROREQUAL) + { + CmpValue2 = BreakPointBuffer[MaximumBreakPoints].CmpValue; + if(CmpValue1 <= CmpValue2) + { + CompareResult = true; + } + } + else if(BreakPointBuffer[MaximumBreakPoints].CmpCondition == UE_CMP_REG_EQUAL) + { + CmpValue2 = (ULONG_PTR)GetContextData((DWORD)BreakPointBuffer[MaximumBreakPoints].CmpValue); + if(CmpValue1 == CmpValue2) + { + CompareResult = true; + } + } + else if(BreakPointBuffer[MaximumBreakPoints].CmpCondition == UE_CMP_REG_NOTEQUAL) + { + CmpValue2 = (ULONG_PTR)GetContextData((DWORD)BreakPointBuffer[MaximumBreakPoints].CmpValue); + if(CmpValue1 != CmpValue2) + { + CompareResult = true; + } + } + else if(BreakPointBuffer[MaximumBreakPoints].CmpCondition == UE_CMP_REG_GREATER) + { + CmpValue2 = (ULONG_PTR)GetContextData((DWORD)BreakPointBuffer[MaximumBreakPoints].CmpValue); + if(CmpValue1 > CmpValue2) + { + CompareResult = true; + } + } + else if(BreakPointBuffer[MaximumBreakPoints].CmpCondition == UE_CMP_REG_GREATEROREQUAL) + { + CmpValue2 = (ULONG_PTR)GetContextData((DWORD)BreakPointBuffer[MaximumBreakPoints].CmpValue); + if(CmpValue1 >= CmpValue2) + { + CompareResult = true; + } + } + else if(BreakPointBuffer[MaximumBreakPoints].CmpCondition == UE_CMP_REG_LOWER) + { + CmpValue2 = (ULONG_PTR)GetContextData((DWORD)BreakPointBuffer[MaximumBreakPoints].CmpValue); + if(CmpValue1 < CmpValue2) + { + CompareResult = true; + } + } + else if(BreakPointBuffer[MaximumBreakPoints].CmpCondition == UE_CMP_REG_LOWEROREQUAL) + { + CmpValue2 = (ULONG_PTR)GetContextData((DWORD)BreakPointBuffer[MaximumBreakPoints].CmpValue); + if(CmpValue1 <= CmpValue2) + { + CompareResult = true; + } + } + if(CompareResult) + { + __try + { + myCustomBreakPoint(); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + + } + } + } + else + { + __try + { + myCustomBreakPoint(); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + + } + } + if(BreakPointBuffer[MaximumBreakPoints].BreakPointType != UE_SINGLESHOOT) + { + DisableBPX((ULONG_PTR)BreakPointBuffer[MaximumBreakPoints].BreakPointAddress); + ResetBPXSize = BreakPointBuffer[MaximumBreakPoints].BreakPointSize - 1; + ResetBPXAddressTo = (ULONG_PTR)BreakPointBuffer[MaximumBreakPoints].BreakPointAddress; + ResetBPX = true; + } + else + { + DeleteBPX((ULONG_PTR)BreakPointBuffer[MaximumBreakPoints].BreakPointAddress); + ResetBPXSize = BreakPointBuffer[MaximumBreakPoints].BreakPointSize - 1; + ResetBPXAddressTo = NULL; + ResetBPX = false; + } + } + else + { + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)BreakPointBuffer[MaximumBreakPoints].BreakPointAddress, BreakPointBuffer[MaximumBreakPoints].BreakPointSize, MemInfo.AllocationProtect, &OldProtect); + DBGCode = DBG_CONTINUE; + } + } + else + { + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)BreakPointBuffer[MaximumBreakPoints].BreakPointAddress, BreakPointBuffer[MaximumBreakPoints].BreakPointSize, MemInfo.AllocationProtect, &OldProtect); + DBGCode = DBG_EXCEPTION_NOT_HANDLED; + } + } + else + { + if(!FirstBPX) + { + DBGCode = DBG_EXCEPTION_NOT_HANDLED; + if(DBGCustomHandler->chBreakPoint != NULL) + { + myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chBreakPoint); + __try + { + myCustomHandler(&DBGEvent.u.Exception.ExceptionRecord); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + DBGCustomHandler->chBreakPoint = NULL; + } + } + } + else //first breakpoint + { + DBGCode = DBG_CONTINUE; + if(engineAttachedToProcess) + { + myCustomBreakPoint = (fCustomBreakPoint)(engineAttachedProcessCallBack); + __try + { + myCustomBreakPoint(); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + + } + } + if(engineAutoHideFromDebugger) + { + HideDebugger(dbgProcessInformation.hProcess, NULL); + } + if(DebugExeFileEntryPointCallBack != NULL) + { + SetBPX((ULONG_PTR)DBGEntryPoint, UE_SINGLESHOOT, DebugExeFileEntryPointCallBack); + } + if(engineTLSBreakOnCallBack) + { + i = NULL; + while(tlsCallBackList[i] != NULL) + { + SetBPX((ULONG_PTR)tlsCallBackList[i], UE_SINGLESHOOT, (LPVOID)engineTLSBreakOnCallBackAddress); + tlsCallBackList[i] = NULL; + i++; + } + engineTLSBreakOnCallBackAddress = NULL; + engineTLSBreakOnCallBack = false; + } + FirstBPX = false; + if(DBGCustomHandler->chSystemBreakpoint != NULL) + { + myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chSystemBreakpoint); + __try + { + myCustomHandler(&DBGEvent); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + DBGCustomHandler->chSystemBreakpoint = NULL; + } + } + } + } + } + else if(DBGEvent.u.Exception.ExceptionRecord.ExceptionCode == STATUS_SINGLE_STEP) + { + /*if(DBGCustomHandler->chSingleStep != NULL) + { + myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chSingleStep); + __try + { + myCustomHandler(&DBGEvent.u.Exception.ExceptionRecord); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + DBGCustomHandler->chSingleStep = NULL; + } + }*/ + if(ResetBPX == true || ResetHwBPX == true) + { + DBGCode = DBG_CONTINUE; + if(!ResetHwBPX) + { + if(ResetBPXAddressTo + ResetBPXSize != (ULONG_PTR)DBGEvent.u.Exception.ExceptionRecord.ExceptionAddress) + { + EnableBPX(ResetBPXAddressTo); + ResetBPXAddressTo = NULL; + ResetBPX = false; + if(engineStepActive) + { + if(engineStepCount == NULL) + { + myCustomBreakPoint = (fCustomBreakPoint)(engineStepCallBack); + __try + { + engineStepActive = false; + engineStepCallBack = NULL; + myCustomBreakPoint(); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + + } + } + else + { + SingleStep(engineStepCount, engineStepCallBack); + } + } + } + else + { + hActiveThread = OpenThread(THREAD_GET_CONTEXT+THREAD_SET_CONTEXT+THREAD_QUERY_INFORMATION, false, DBGEvent.dwThreadId); + myDBGContext.ContextFlags = CONTEXT_ALL; + GetThreadContext(hActiveThread, &myDBGContext); + if(!(myDBGContext.EFlags & 0x100)) + { + myDBGContext.EFlags = myDBGContext.EFlags ^ 0x100; + } + SetThreadContext(hActiveThread, &myDBGContext); + EngineCloseHandle(hActiveThread); + } + } + else + { + ResetHwBPX = false; + SetHardwareBreakPoint(DebugRegisterX.DrxBreakAddress, DebugRegisterXId, DebugRegisterX.DrxBreakPointType, DebugRegisterX.DrxBreakPointSize, (LPVOID)DebugRegisterX.DrxCallBack); + if(engineStepActive) + { + if(engineStepCount == NULL) + { + myCustomBreakPoint = (fCustomBreakPoint)(engineStepCallBack); + __try + { + engineStepActive = false; + engineStepCallBack = NULL; + myCustomBreakPoint(); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + + } + } + else + { + SingleStep(engineStepCount, engineStepCallBack); + } + } + } + } + else + { + if(engineStepActive) + { + DBGCode = DBG_CONTINUE; + if(engineStepCount == NULL) + { + myCustomBreakPoint = (fCustomBreakPoint)(engineStepCallBack); + __try + { + engineStepActive = false; + engineStepCallBack = NULL; + myCustomBreakPoint(); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + + } + } + else + { + SingleStep(engineStepCount, engineStepCallBack); + } + } + else + { + hActiveThread = OpenThread(THREAD_GET_CONTEXT+THREAD_SET_CONTEXT+THREAD_QUERY_INFORMATION, false, DBGEvent.dwThreadId); + myDBGContext.ContextFlags = CONTEXT_ALL; + GetThreadContext(hActiveThread, &myDBGContext); + if((ULONG_PTR)DBGEvent.u.Exception.ExceptionRecord.ExceptionAddress == myDBGContext.Dr0 || (myDBGContext.Dr6 & 0x1)) + { + if(DebugRegister0.DrxEnabled) + { + DBGCode = DBG_CONTINUE; + if(!(myDBGContext.EFlags & 0x100)) + { + myDBGContext.EFlags = myDBGContext.EFlags ^ 0x100; + } + SetThreadContext(hActiveThread, &myDBGContext); + myCustomBreakPoint = (fCustomBreakPoint)(DebugRegister0.DrxCallBack); + __try + { + myCustomBreakPoint(); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + + } + RtlZeroMemory(&DebugRegisterX, sizeof HARDWARE_DATA); + RtlMoveMemory(&DebugRegisterX, &DebugRegister0, sizeof HARDWARE_DATA); + DeleteHardwareBreakPoint(UE_DR0); + DebugRegisterXId = UE_DR0; + ResetHwBPX = true; + } + else + { + //TODO: everytingelkse + DBGCode = DBG_EXCEPTION_NOT_HANDLED; + } + } + else if((ULONG_PTR)DBGEvent.u.Exception.ExceptionRecord.ExceptionAddress == myDBGContext.Dr1 || (myDBGContext.Dr6 & 0x2)) + { + if(DebugRegister1.DrxEnabled) + { + DBGCode = DBG_CONTINUE; + if(!(myDBGContext.EFlags & 0x100)) + { + myDBGContext.EFlags = myDBGContext.EFlags ^ 0x100; + } + SetThreadContext(hActiveThread, &myDBGContext); + myCustomBreakPoint = (fCustomBreakPoint)(DebugRegister1.DrxCallBack); + __try + { + myCustomBreakPoint(); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + + } + RtlZeroMemory(&DebugRegisterX, sizeof HARDWARE_DATA); + RtlMoveMemory(&DebugRegisterX, &DebugRegister1, sizeof HARDWARE_DATA); + DeleteHardwareBreakPoint(UE_DR1); + DebugRegisterXId = UE_DR1; + ResetHwBPX = true; + } + else + { + DBGCode = DBG_EXCEPTION_NOT_HANDLED; + } + } + else if((ULONG_PTR)DBGEvent.u.Exception.ExceptionRecord.ExceptionAddress == myDBGContext.Dr2 || (myDBGContext.Dr6 & 0x4)) + { + if(DebugRegister2.DrxEnabled) + { + DBGCode = DBG_CONTINUE; + if(!(myDBGContext.EFlags & 0x100)) + { + myDBGContext.EFlags = myDBGContext.EFlags ^ 0x100; + } + SetThreadContext(hActiveThread, &myDBGContext); + myCustomBreakPoint = (fCustomBreakPoint)(DebugRegister2.DrxCallBack); + __try + { + myCustomBreakPoint(); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + + } + RtlZeroMemory(&DebugRegisterX, sizeof HARDWARE_DATA); + RtlMoveMemory(&DebugRegisterX, &DebugRegister2, sizeof HARDWARE_DATA); + DeleteHardwareBreakPoint(UE_DR2); + DebugRegisterXId = UE_DR2; + ResetHwBPX = true; + } + else + { + DBGCode = DBG_EXCEPTION_NOT_HANDLED; + } + } + else if((ULONG_PTR)DBGEvent.u.Exception.ExceptionRecord.ExceptionAddress == myDBGContext.Dr3 || (myDBGContext.Dr6 & 0x8)) + { + if(DebugRegister3.DrxEnabled) + { + DBGCode = DBG_CONTINUE; + if(!(myDBGContext.EFlags & 0x100)) + { + myDBGContext.EFlags = myDBGContext.EFlags ^ 0x100; + } + SetThreadContext(hActiveThread, &myDBGContext); + myCustomBreakPoint = (fCustomBreakPoint)(DebugRegister3.DrxCallBack); + __try + { + myCustomBreakPoint(); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + + } + RtlZeroMemory(&DebugRegisterX, sizeof HARDWARE_DATA); + RtlMoveMemory(&DebugRegisterX, &DebugRegister3, sizeof HARDWARE_DATA); + DeleteHardwareBreakPoint(UE_DR3); + DebugRegisterXId = UE_DR3; + ResetHwBPX = true; + } + else + { + DBGCode = DBG_EXCEPTION_NOT_HANDLED; + } + } + else + { + DBGCode = DBG_EXCEPTION_NOT_HANDLED; + } + EngineCloseHandle(hActiveThread); + } + } + if(DBGCode==DBG_EXCEPTION_NOT_HANDLED || firstchance) + { + if(DBGCustomHandler->chSingleStep != NULL) + { + myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chSingleStep); + __try + { + myCustomHandler(&DBGEvent.u.Exception.ExceptionRecord); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + DBGCustomHandler->chSingleStep = NULL; + } + } + } + } + else if(DBGEvent.u.Exception.ExceptionRecord.ExceptionCode == STATUS_GUARD_PAGE_VIOLATION) + { + /*if(DBGCustomHandler->chPageGuard != NULL) + { + myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chPageGuard); + __try + { + myCustomHandler(&DBGEvent.u.Exception.ExceptionRecord); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + DBGCustomHandler->chPageGuard = NULL; + } + }*/ + MemoryBpxFound = false; + MaximumBreakPoints = 0; + for(MaximumBreakPoints = 0; MaximumBreakPoints < BreakPointSetCount; MaximumBreakPoints++) + { + ULONG_PTR addr=BreakPointBuffer[MaximumBreakPoints].BreakPointAddress; + ULONG_PTR bpaddr=(ULONG_PTR)DBGEvent.u.Exception.ExceptionRecord.ExceptionAddress; + if(((BreakPointBuffer[MaximumBreakPoints].BreakPointType >= UE_MEMORY) && (BreakPointBuffer[MaximumBreakPoints].BreakPointType <= UE_MEMORY_WRITE)) && bpaddr>=addr && bpaddr<=(addr+BreakPointBuffer[MaximumBreakPoints].BreakPointSize)) + { + MemoryBpxFound = true; + break; + } + } + if(MaximumBreakPoints < MAXIMUM_BREAKPOINTS || MemoryBpxFound == true) + { + if(BreakPointBuffer[MaximumBreakPoints].BreakPointActive == UE_BPXACTIVE) + { + DBGCode = DBG_CONTINUE; + MemoryBpxCallBack = BreakPointBuffer[MaximumBreakPoints].ExecuteCallBack; + if(BreakPointBuffer[MaximumBreakPoints].BreakPointType == UE_MEMORY) + { + if(BreakPointBuffer[MaximumBreakPoints].MemoryBpxRestoreOnHit != 1) + { + RemoveMemoryBPX(BreakPointBuffer[MaximumBreakPoints].BreakPointAddress, BreakPointBuffer[MaximumBreakPoints].BreakPointSize); + } + else + { + VirtualQueryEx(dbgProcessInformation.hProcess, (LPVOID)BreakPointBuffer[MaximumBreakPoints].BreakPointAddress, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + OldProtect = MemInfo.AllocationProtect; + NewProtect = OldProtect ^ PAGE_GUARD; + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)BreakPointBuffer[MaximumBreakPoints].BreakPointAddress, BreakPointBuffer[MaximumBreakPoints].BreakPointSize, NewProtect, &OldProtect); + } + myCustomBreakPoint = (fCustomBreakPoint)((LPVOID)MemoryBpxCallBack); + __try + { + myCustomBreakPoint(); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + + } + } + else if(BreakPointBuffer[MaximumBreakPoints].BreakPointType == UE_MEMORY_READ) + { + if(BreakPointBuffer[MaximumBreakPoints].MemoryBpxRestoreOnHit != 1) + { + RemoveMemoryBPX(BreakPointBuffer[MaximumBreakPoints].BreakPointAddress, BreakPointBuffer[MaximumBreakPoints].BreakPointSize); + } + else + { + VirtualQueryEx(dbgProcessInformation.hProcess, (LPVOID)BreakPointBuffer[MaximumBreakPoints].BreakPointAddress, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + OldProtect = MemInfo.AllocationProtect; + NewProtect = OldProtect ^ PAGE_GUARD; + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)BreakPointBuffer[MaximumBreakPoints].BreakPointAddress, BreakPointBuffer[MaximumBreakPoints].BreakPointSize, NewProtect, &OldProtect); + } + if(DBGEvent.u.Exception.ExceptionRecord.ExceptionInformation[0] == 0) + { + myCustomBreakPoint = (fCustomBreakPoint)((LPVOID)MemoryBpxCallBack); + __try + { + myCustomBreakPoint(); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + + } + } + else + { + if(BreakPointBuffer[MaximumBreakPoints].BreakPointAddress >= (ULONG_PTR)DBGEvent.u.Exception.ExceptionRecord.ExceptionAddress && (ULONG_PTR)DBGEvent.u.Exception.ExceptionRecord.ExceptionAddress <= BreakPointBuffer[MaximumBreakPoints].BreakPointAddress + BreakPointBuffer[MaximumBreakPoints].BreakPointSize) + { + VirtualQueryEx(dbgProcessInformation.hProcess, (LPVOID)BreakPointBuffer[MaximumBreakPoints].BreakPointAddress, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + OldProtect = MemInfo.AllocationProtect; + NewProtect = OldProtect ^ PAGE_GUARD; + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)BreakPointBuffer[MaximumBreakPoints].BreakPointAddress, BreakPointBuffer[MaximumBreakPoints].BreakPointSize, NewProtect, &OldProtect); + } + } + } + else if(BreakPointBuffer[MaximumBreakPoints].BreakPointType == UE_MEMORY_WRITE) + { + if(BreakPointBuffer[MaximumBreakPoints].MemoryBpxRestoreOnHit != 1) + { + RemoveMemoryBPX(BreakPointBuffer[MaximumBreakPoints].BreakPointAddress, BreakPointBuffer[MaximumBreakPoints].BreakPointSize); + } + else + { + VirtualQueryEx(dbgProcessInformation.hProcess, (LPVOID)BreakPointBuffer[MaximumBreakPoints].BreakPointAddress, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + OldProtect = MemInfo.AllocationProtect; + NewProtect = OldProtect ^ PAGE_GUARD; + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)BreakPointBuffer[MaximumBreakPoints].BreakPointAddress, BreakPointBuffer[MaximumBreakPoints].BreakPointSize, NewProtect, &OldProtect); + } + if(DBGEvent.u.Exception.ExceptionRecord.ExceptionInformation[0] == 1) + { + myCustomBreakPoint = (fCustomBreakPoint)((LPVOID)MemoryBpxCallBack); + __try + { + myCustomBreakPoint(); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + + } + } + else + { + if(BreakPointBuffer[MaximumBreakPoints].BreakPointAddress >= (ULONG_PTR)DBGEvent.u.Exception.ExceptionRecord.ExceptionAddress && (ULONG_PTR)DBGEvent.u.Exception.ExceptionRecord.ExceptionAddress <= BreakPointBuffer[MaximumBreakPoints].BreakPointAddress + BreakPointBuffer[MaximumBreakPoints].BreakPointSize) + { + VirtualQueryEx(dbgProcessInformation.hProcess, (LPVOID)BreakPointBuffer[MaximumBreakPoints].BreakPointAddress, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + OldProtect = MemInfo.AllocationProtect; + NewProtect = OldProtect ^ PAGE_GUARD; + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)BreakPointBuffer[MaximumBreakPoints].BreakPointAddress, BreakPointBuffer[MaximumBreakPoints].BreakPointSize, NewProtect, &OldProtect); + } + } + } + } + else + { + DBGCode = DBG_EXCEPTION_NOT_HANDLED; + } + } + else + { + DBGCode = DBG_EXCEPTION_NOT_HANDLED; + } + if(DBGCode==DBG_EXCEPTION_NOT_HANDLED || firstchance) + { + if(DBGCustomHandler->chPageGuard != NULL) + { + myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chPageGuard); + __try + { + myCustomHandler(&DBGEvent.u.Exception.ExceptionRecord); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + DBGCustomHandler->chPageGuard = NULL; + } + } + } + } + else if(DBGEvent.u.Exception.ExceptionRecord.ExceptionCode == STATUS_ACCESS_VIOLATION) + { + DBGCode = DBG_EXCEPTION_NOT_HANDLED; + if(DBGCustomHandler->chAccessViolation != NULL) + { + myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chAccessViolation); + __try + { + myCustomHandler(&DBGEvent.u.Exception.ExceptionRecord); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + DBGCustomHandler->chAccessViolation = NULL; + } + } + } + else if(DBGEvent.u.Exception.ExceptionRecord.ExceptionCode == STATUS_ILLEGAL_INSTRUCTION) + { + if(DBGCustomHandler->chIllegalInstruction != NULL) + { + myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chIllegalInstruction); + __try + { + myCustomHandler(&DBGEvent.u.Exception.ExceptionRecord); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + DBGCustomHandler->chIllegalInstruction = NULL; + } + } + MaximumBreakPoints = 0; + for(MaximumBreakPoints = 0; MaximumBreakPoints < BreakPointSetCount; MaximumBreakPoints++) + { + if(BreakPointBuffer[MaximumBreakPoints].BreakPointAddress == (ULONG_PTR)DBGEvent.u.Exception.ExceptionRecord.ExceptionAddress) + { + break; + } + } + if(BreakPointBuffer[MaximumBreakPoints].BreakPointActive == UE_BPXACTIVE && MaximumBreakPoints < MAXIMUM_BREAKPOINTS) + { + VirtualQueryEx(dbgProcessInformation.hProcess, (LPVOID)BreakPointBuffer[MaximumBreakPoints].BreakPointAddress, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + OldProtect = MemInfo.AllocationProtect; + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)BreakPointBuffer[MaximumBreakPoints].BreakPointAddress, BreakPointBuffer[MaximumBreakPoints].BreakPointSize, PAGE_EXECUTE_READWRITE, &OldProtect); + if(BreakPointBuffer[MaximumBreakPoints].BreakPointActive == UE_BPXACTIVE && (BreakPointBuffer[MaximumBreakPoints].BreakPointType == UE_BREAKPOINT || BreakPointBuffer[MaximumBreakPoints].BreakPointType == UE_SINGLESHOOT) && (BreakPointBuffer[MaximumBreakPoints].NumberOfExecutions == -1 || BreakPointBuffer[MaximumBreakPoints].NumberOfExecutions > 0)) + { + if(WriteProcessMemory(dbgProcessInformation.hProcess, (LPVOID)BreakPointBuffer[MaximumBreakPoints].BreakPointAddress, &BreakPointBuffer[MaximumBreakPoints].OriginalByte[0], BreakPointBuffer[MaximumBreakPoints].BreakPointSize, &NumberOfBytesReadWritten)) + { + DBGCode = DBG_CONTINUE; + hActiveThread = OpenThread(THREAD_GET_CONTEXT+THREAD_SET_CONTEXT+THREAD_QUERY_INFORMATION, false, DBGEvent.dwThreadId); + myDBGContext.ContextFlags = CONTEXT_ALL; + GetThreadContext(hActiveThread, &myDBGContext); + if(BreakPointBuffer[MaximumBreakPoints].BreakPointType != UE_SINGLESHOOT) + { + if(!(myDBGContext.EFlags & 0x100)) + { + myDBGContext.EFlags = myDBGContext.EFlags ^ 0x100; + } + } + if(!(myDBGContext.EFlags & 0x10000)) + { + myDBGContext.EFlags = myDBGContext.EFlags ^ 0x10000; + } + SetThreadContext(hActiveThread, &myDBGContext); + EngineCloseHandle(hActiveThread); + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)BreakPointBuffer[MaximumBreakPoints].BreakPointAddress, BreakPointBuffer[MaximumBreakPoints].BreakPointSize, MemInfo.AllocationProtect, &OldProtect); + myCustomBreakPoint = (fCustomBreakPoint)((LPVOID)BreakPointBuffer[MaximumBreakPoints].ExecuteCallBack); + if(BreakPointBuffer[MaximumBreakPoints].NumberOfExecutions != -1 && BreakPointBuffer[MaximumBreakPoints].NumberOfExecutions != 0) + { + BreakPointBuffer[MaximumBreakPoints].NumberOfExecutions--; + } + if(BreakPointBuffer[MaximumBreakPoints].CmpCondition != UE_CMP_NOCONDITION) + { + CompareResult = false; + CmpValue1 = (ULONG_PTR)GetContextData((DWORD)BreakPointBuffer[MaximumBreakPoints].CmpRegister); + myCustomBreakPoint = (fCustomBreakPoint)((LPVOID)BreakPointBuffer[MaximumBreakPoints].CompareCallBack); + if(BreakPointBuffer[MaximumBreakPoints].CmpCondition == UE_CMP_EQUAL) + { + CmpValue2 = BreakPointBuffer[MaximumBreakPoints].CmpValue; + if(CmpValue1 == CmpValue2) + { + CompareResult = true; + } + } + else if(BreakPointBuffer[MaximumBreakPoints].CmpCondition == UE_CMP_NOTEQUAL) + { + CmpValue2 = BreakPointBuffer[MaximumBreakPoints].CmpValue; + if(CmpValue1 != CmpValue2) + { + CompareResult = true; + } + } + else if(BreakPointBuffer[MaximumBreakPoints].CmpCondition == UE_CMP_GREATER) + { + CmpValue2 = BreakPointBuffer[MaximumBreakPoints].CmpValue; + if(CmpValue1 > CmpValue2) + { + CompareResult = true; + } + } + else if(BreakPointBuffer[MaximumBreakPoints].CmpCondition == UE_CMP_GREATEROREQUAL) + { + CmpValue2 = BreakPointBuffer[MaximumBreakPoints].CmpValue; + if(CmpValue1 >= CmpValue2) + { + CompareResult = true; + } + } + else if(BreakPointBuffer[MaximumBreakPoints].CmpCondition == UE_CMP_LOWER) + { + CmpValue2 = BreakPointBuffer[MaximumBreakPoints].CmpValue; + if(CmpValue1 < CmpValue2) + { + CompareResult = true; + } + } + else if(BreakPointBuffer[MaximumBreakPoints].CmpCondition == UE_CMP_LOWEROREQUAL) + { + CmpValue2 = BreakPointBuffer[MaximumBreakPoints].CmpValue; + if(CmpValue1 <= CmpValue2) + { + CompareResult = true; + } + } + else if(BreakPointBuffer[MaximumBreakPoints].CmpCondition == UE_CMP_REG_EQUAL) + { + CmpValue2 = (ULONG_PTR)GetContextData((DWORD)BreakPointBuffer[MaximumBreakPoints].CmpValue); + if(CmpValue1 == CmpValue2) + { + CompareResult = true; + } + } + else if(BreakPointBuffer[MaximumBreakPoints].CmpCondition == UE_CMP_REG_NOTEQUAL) + { + CmpValue2 = (ULONG_PTR)GetContextData((DWORD)BreakPointBuffer[MaximumBreakPoints].CmpValue); + if(CmpValue1 != CmpValue2) + { + CompareResult = true; + } + } + else if(BreakPointBuffer[MaximumBreakPoints].CmpCondition == UE_CMP_REG_GREATER) + { + CmpValue2 = (ULONG_PTR)GetContextData((DWORD)BreakPointBuffer[MaximumBreakPoints].CmpValue); + if(CmpValue1 > CmpValue2) + { + CompareResult = true; + } + } + else if(BreakPointBuffer[MaximumBreakPoints].CmpCondition == UE_CMP_REG_GREATEROREQUAL) + { + CmpValue2 = (ULONG_PTR)GetContextData((DWORD)BreakPointBuffer[MaximumBreakPoints].CmpValue); + if(CmpValue1 >= CmpValue2) + { + CompareResult = true; + } + } + else if(BreakPointBuffer[MaximumBreakPoints].CmpCondition == UE_CMP_REG_LOWER) + { + CmpValue2 = (ULONG_PTR)GetContextData((DWORD)BreakPointBuffer[MaximumBreakPoints].CmpValue); + if(CmpValue1 < CmpValue2) + { + CompareResult = true; + } + } + else if(BreakPointBuffer[MaximumBreakPoints].CmpCondition == UE_CMP_REG_LOWEROREQUAL) + { + CmpValue2 = (ULONG_PTR)GetContextData((DWORD)BreakPointBuffer[MaximumBreakPoints].CmpValue); + if(CmpValue1 <= CmpValue2) + { + CompareResult = true; + } + } + if(CompareResult) + { + __try + { + myCustomBreakPoint(); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + + } + } + } + else + { + __try + { + myCustomBreakPoint(); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + + } + } + if(BreakPointBuffer[MaximumBreakPoints].BreakPointType != UE_SINGLESHOOT) + { + DisableBPX((ULONG_PTR)BreakPointBuffer[MaximumBreakPoints].BreakPointAddress); + ResetBPXSize = BreakPointBuffer[MaximumBreakPoints].BreakPointSize - 1; + ResetBPXAddressTo = (ULONG_PTR)BreakPointBuffer[MaximumBreakPoints].BreakPointAddress; + ResetBPX = true; + } + else + { + DeleteBPX((ULONG_PTR)BreakPointBuffer[MaximumBreakPoints].BreakPointAddress); + ResetBPXSize = BreakPointBuffer[MaximumBreakPoints].BreakPointSize - 1; + ResetBPXAddressTo = NULL; + ResetBPX = false; + } + } + else + { + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)BreakPointBuffer[MaximumBreakPoints].BreakPointAddress, BreakPointBuffer[MaximumBreakPoints].BreakPointSize, MemInfo.AllocationProtect, &OldProtect); + DBGCode = DBG_CONTINUE; + } + } + else + { + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)BreakPointBuffer[MaximumBreakPoints].BreakPointAddress, BreakPointBuffer[MaximumBreakPoints].BreakPointSize, MemInfo.AllocationProtect, &OldProtect); + DBGCode = DBG_EXCEPTION_NOT_HANDLED; + } + } + else + { + DBGCode = DBG_EXCEPTION_NOT_HANDLED; + } + } + else if(DBGEvent.u.Exception.ExceptionRecord.ExceptionCode == STATUS_NONCONTINUABLE_EXCEPTION) + { + DBGCode = DBG_EXCEPTION_NOT_HANDLED; + if(DBGCustomHandler->chNonContinuableException != NULL) + { + myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chNonContinuableException); + __try + { + myCustomHandler(&DBGEvent.u.Exception.ExceptionRecord); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + DBGCustomHandler->chNonContinuableException = NULL; + } + } + } + else if(DBGEvent.u.Exception.ExceptionRecord.ExceptionCode == STATUS_ARRAY_BOUNDS_EXCEEDED) + { + DBGCode = DBG_EXCEPTION_NOT_HANDLED; + if(DBGCustomHandler->chArrayBoundsException != NULL) + { + myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chArrayBoundsException); + __try + { + myCustomHandler(&DBGEvent.u.Exception.ExceptionRecord); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + DBGCustomHandler->chArrayBoundsException = NULL; + } + } + } + else if(DBGEvent.u.Exception.ExceptionRecord.ExceptionCode == STATUS_FLOAT_DENORMAL_OPERAND) + { + DBGCode = DBG_EXCEPTION_NOT_HANDLED; + if(DBGCustomHandler->chFloatDenormalOperand != NULL) + { + myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chFloatDenormalOperand); + __try + { + myCustomHandler(&DBGEvent.u.Exception.ExceptionRecord); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + DBGCustomHandler->chFloatDenormalOperand = NULL; + } + } + } + else if(DBGEvent.u.Exception.ExceptionRecord.ExceptionCode == STATUS_FLOAT_DIVIDE_BY_ZERO) + { + DBGCode = DBG_EXCEPTION_NOT_HANDLED; + if(DBGCustomHandler->chFloatDevideByZero != NULL) + { + myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chFloatDevideByZero); + __try + { + myCustomHandler(&DBGEvent.u.Exception.ExceptionRecord); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + DBGCustomHandler->chFloatDevideByZero = NULL; + } + } + } + else if(DBGEvent.u.Exception.ExceptionRecord.ExceptionCode == STATUS_INTEGER_DIVIDE_BY_ZERO) + { + DBGCode = DBG_EXCEPTION_NOT_HANDLED; + if(DBGCustomHandler->chIntegerDevideByZero != NULL) + { + myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chIntegerDevideByZero); + __try + { + myCustomHandler(&DBGEvent.u.Exception.ExceptionRecord); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + DBGCustomHandler->chIntegerDevideByZero = NULL; + } + } + } + else if(DBGEvent.u.Exception.ExceptionRecord.ExceptionCode == STATUS_INTEGER_OVERFLOW) + { + DBGCode = DBG_EXCEPTION_NOT_HANDLED; + if(DBGCustomHandler->chIntegerOverflow != NULL) + { + myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chIntegerOverflow); + __try + { + myCustomHandler(&DBGEvent.u.Exception.ExceptionRecord); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + DBGCustomHandler->chIntegerOverflow = NULL; + } + } + } + else if(DBGEvent.u.Exception.ExceptionRecord.ExceptionCode == STATUS_PRIVILEGED_INSTRUCTION) + { + DBGCode = DBG_EXCEPTION_NOT_HANDLED; + if(DBGCustomHandler->chPrivilegedInstruction != NULL) + { + myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chPrivilegedInstruction); + __try + { + myCustomHandler(&DBGEvent.u.Exception.ExceptionRecord); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + DBGCustomHandler->chPrivilegedInstruction = NULL; + } + } + } + if(DBGCode==DBG_EXCEPTION_NOT_HANDLED || firstchance) + { + if(DBGCustomHandler->chUnhandledException != NULL) + { + myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chUnhandledException); + __try + { + myCustomHandler(&DBGEvent.u.Exception.ExceptionRecord); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + DBGCustomHandler->chUnhandledException = NULL; + } + } + if(DBGCustomHandler->chAfterUnhandledException != NULL) + { + myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chAfterUnhandledException); + __try + { + myCustomHandler(&DBGEvent.u.Exception.ExceptionRecord); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + DBGCustomHandler->chAfterUnhandledException = NULL; + } + } + } + if(DBGCustomHandler->chAfterException != NULL) + { + myCustomHandler = (fCustomHandler)((LPVOID)DBGCustomHandler->chAfterException); + __try + { + myCustomHandler(&DBGEvent.u.Exception.ExceptionRecord); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + DBGCustomHandler->chAfterException = NULL; + } + } + } + if(engineResumeProcessIfNoThreadIsActive) + { + if(!ThreaderIsAnyThreadActive()) + { + ThreaderResumeProcess(); + } + } + if(!ContinueDebugEvent(DBGEvent.dwProcessId, DBGEvent.dwThreadId, DBGCode)) + { + break; + } + } + if(!SecondChance) + { + RtlMoveMemory(&TerminateDBGEvent, &DBGEvent, sizeof DEBUG_EVENT); + } + ForceClose(); + engineFileIsBeingDebugged = false; + if(engineExecutePluginCallBack) + { + EngineExecutePluginDebugCallBack(&DBGEvent, UE_PLUGIN_CALL_REASON_POSTDEBUG); + } +} +__declspec(dllexport) void __stdcall SetDebugLoopTimeOut(DWORD TimeOut) +{ + + if(TimeOut == NULL) + { + TimeOut = INFINITE; + } + engineWaitForDebugEventTimeOut = TimeOut; +} +__declspec(dllexport) void __stdcall SetNextDbgContinueStatus(DWORD SetDbgCode) +{ + + if(SetDbgCode != DBG_CONTINUE) + { + DBGCode = DBG_EXCEPTION_NOT_HANDLED; + } + else + { + DBGCode = DBG_CONTINUE; + } +} +__declspec(dllexport) void __stdcall DebugLoopEx(DWORD TimeOut) +{ + SetDebugLoopTimeOut(TimeOut); + DebugLoop(); + SetDebugLoopTimeOut(INFINITE); +} +__declspec(dllexport) bool __stdcall AttachDebugger(DWORD ProcessId, bool KillOnExit, LPVOID DebugInfo, LPVOID CallBack) +{ + + typedef void(__stdcall *fDebugSetProcessKillOnExit)(bool KillExitingDebugee); + fDebugSetProcessKillOnExit myDebugSetProcessKillOnExit; + LPVOID funcDebugSetProcessKillOnExit = NULL; + + if(ProcessId != NULL && dbgProcessInformation.hProcess == NULL) + { + RtlZeroMemory(&BreakPointBuffer, sizeof BreakPointBuffer); + if(DebugActiveProcess(ProcessId)) + { + if(KillOnExit) + { + funcDebugSetProcessKillOnExit = GetProcAddress(GetModuleHandleA("kernel32.dll"), "DebugSetProcessKillOnExit"); + if(funcDebugSetProcessKillOnExit != NULL) + { + myDebugSetProcessKillOnExit = (fDebugSetProcessKillOnExit)(funcDebugSetProcessKillOnExit); + myDebugSetProcessKillOnExit(KillOnExit); + } + } + BreakPointSetCount = 0; + engineDebuggingDLL = false; + engineAttachedToProcess = true; + engineAttachedProcessCallBack = (ULONG_PTR)CallBack; + engineAttachedProcessDebugInfo = DebugInfo; + dbgProcessInformation.dwProcessId = ProcessId; + DebugLoop(); + engineAttachedToProcess = false; + engineAttachedProcessCallBack = NULL; + return(true); + } + } + else + { + return(false); + } + return(false); +} +__declspec(dllexport) bool __stdcall DetachDebugger(DWORD ProcessId) +{ + + typedef bool(__stdcall *fDebugActiveProcessStop)(DWORD dwProcessId); + fDebugActiveProcessStop myDebugActiveProcessStop; + LPVOID funcDebugActiveProcessStop = NULL; + bool FuncReturn = false; + + if(ProcessId != NULL) + { + funcDebugActiveProcessStop = GetProcAddress(GetModuleHandleA("kernel32.dll"), "DebugActiveProcessStop"); + if(funcDebugActiveProcessStop != NULL) + { + myDebugActiveProcessStop = (fDebugActiveProcessStop)(funcDebugActiveProcessStop); + FuncReturn = myDebugActiveProcessStop(ProcessId); + engineProcessIsNowDetached = true; + Sleep(250); + } + engineAttachedToProcess = false; + if(FuncReturn) + { + return(true); + } + else + { + return(false); + } + } + return(false); +} +__declspec(dllexport) bool __stdcall DetachDebuggerEx(DWORD ProcessId) +{ + + HANDLE hActiveThread; + CONTEXT myDBGContext; + PTHREAD_ITEM_DATA hListThreadPtr = (PTHREAD_ITEM_DATA)hListThread; + + if(hListThreadPtr != NULL) + { + ThreaderPauseProcess(); + while(hListThreadPtr->hThread != NULL) + { + hActiveThread = OpenThread(THREAD_GET_CONTEXT+THREAD_SET_CONTEXT+THREAD_QUERY_INFORMATION, false, hListThreadPtr->dwThreadId); + myDBGContext.ContextFlags = CONTEXT_ALL; + GetThreadContext(hActiveThread, &myDBGContext); + if((myDBGContext.EFlags & 0x100)) + { + myDBGContext.EFlags = myDBGContext.EFlags ^ 0x100; + } + if(!(myDBGContext.EFlags & 0x10000)) + { + myDBGContext.EFlags = myDBGContext.EFlags ^ 0x10000; + } + SetThreadContext(hActiveThread, &myDBGContext); + EngineCloseHandle(hActiveThread); + hListThreadPtr = (PTHREAD_ITEM_DATA)((ULONG_PTR)hListThreadPtr + sizeof THREAD_ITEM_DATA); + } + ContinueDebugEvent(DBGEvent.dwProcessId, DBGEvent.dwThreadId, DBG_CONTINUE); + ThreaderResumeProcess(); + return(DetachDebugger(ProcessId)); + } + else + { + return(false); + } +} +__declspec(dllexport) void __stdcall AutoDebugEx(char* szFileName, bool ReserveModuleBase, char* szCommandLine, char* szCurrentFolder, DWORD TimeOut, LPVOID EntryCallBack) +{ + + wchar_t* PtrUniFileName = NULL; + wchar_t uniFileName[MAX_PATH] = {}; + wchar_t* PtrUniCommandLine = NULL; + wchar_t uniCommandLine[MAX_PATH] = {}; + wchar_t* PtrUniCurrentFolder = NULL; + wchar_t uniCurrentFolder[MAX_PATH] = {}; + + if(szFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + MultiByteToWideChar(CP_ACP, NULL, szCommandLine, lstrlenA(szCommandLine)+1, uniCommandLine, sizeof(uniCommandLine)/(sizeof(uniCommandLine[0]))); + MultiByteToWideChar(CP_ACP, NULL, szCurrentFolder, lstrlenA(szCurrentFolder)+1, uniCurrentFolder, sizeof(uniCurrentFolder)/(sizeof(uniCurrentFolder[0]))); + if(szFileName != NULL) + { + PtrUniFileName = &uniFileName[0]; + } + if(szCommandLine != NULL) + { + PtrUniCommandLine = &uniCommandLine[0]; + } + if(szCurrentFolder != NULL) + { + PtrUniCurrentFolder = &uniCurrentFolder[0]; + } + return(AutoDebugExW(PtrUniFileName, ReserveModuleBase, PtrUniCommandLine, PtrUniCurrentFolder, TimeOut, EntryCallBack)); + } +} +__declspec(dllexport) void __stdcall AutoDebugExW(wchar_t* szFileName, bool ReserveModuleBase, wchar_t* szCommandLine, wchar_t* szCurrentFolder, DWORD TimeOut, LPVOID EntryCallBack) +{ + engineReserveModuleBase = NULL; + DWORD ThreadId; + DWORD ExitCode = 0; + HANDLE hSecondThread; + bool FileIsDll = false; +#if !defined(_WIN64) + PE32Struct PEStructure; +#else + PE64Struct PEStructure; +#endif + + if(TimeOut == NULL) + { + TimeOut = INFINITE; + } + + if(szFileName != NULL) + { + RtlZeroMemory(&engineExpertDebug, sizeof ExpertDebug); + engineExpertDebug.ExpertModeActive = true; + engineExpertDebug.szFileName = szFileName; + engineExpertDebug.szCommandLine = szCommandLine; + engineExpertDebug.szCurrentFolder = szCurrentFolder; + engineExpertDebug.ReserveModuleBase = ReserveModuleBase; + engineExpertDebug.EntryCallBack = EntryCallBack; + GetPE32DataExW(szFileName, (LPVOID)&PEStructure); + if(PEStructure.Characteristics & 0x2000) + { + FileIsDll = true; + } + SetDebugLoopTimeOut(TimeOut); + hSecondThread = CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)DebugLoopInSecondThread, (LPVOID)FileIsDll, NULL, &ThreadId); + WaitForSingleObject(hSecondThread, INFINITE); + if(GetExitCodeThread(hSecondThread, &ExitCode)) + { + if(ExitCode == -1) + { + ForceClose(); + } + } + RtlZeroMemory(&engineExpertDebug, sizeof ExpertDebug); + SetDebugLoopTimeOut(INFINITE); + } +} +__declspec(dllexport) bool __stdcall IsFileBeingDebugged() +{ + return(engineFileIsBeingDebugged); +} +__declspec(dllexport) void __stdcall SetErrorModel(bool DisplayErrorMessages) +{ + + if(DisplayErrorMessages) + { + SetErrorMode(NULL); + } + else + { + SetErrorMode(SEM_FAILCRITICALERRORS); + } +} +// Global.FindOEP.functions: +void __stdcall GenericOEPVirtualProtectHit() +{ + + PBreakPointDetail bpxList = (PBreakPointDetail)BreakPointBuffer; + MEMORY_BASIC_INFORMATION MemInfo; + DWORD MaximumBreakPoints = 0; + DWORD NewProtect = 0; + DWORD OldProtect = 0; + + while(MaximumBreakPoints < MAXIMUM_BREAKPOINTS) + { + bpxList = (PBreakPointDetail)((ULONG_PTR)bpxList + sizeof BreakPointDetail); + if(bpxList->BreakPointType == UE_MEMORY && bpxList->BreakPointActive == UE_BPXACTIVE) + { + VirtualQueryEx(dbgProcessInformation.hProcess, (LPVOID)bpxList->BreakPointAddress, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + OldProtect = MemInfo.Protect; + if(!(OldProtect & PAGE_GUARD)) + { + NewProtect = OldProtect ^ PAGE_GUARD; + VirtualProtectEx(dbgProcessInformation.hProcess, (LPVOID)bpxList->BreakPointAddress, bpxList->BreakPointSize, NewProtect, &OldProtect); + } + } + MaximumBreakPoints++; + } +} +void __stdcall GenericOEPTraceHit() +{ + + char* szInstructionType; + typedef void(__stdcall *fEPCallBack)(); + fEPCallBack myEPCallBack = (fEPCallBack)glbEntryTracerData.EPCallBack; + LPDEBUG_EVENT myDbgEvent = (LPDEBUG_EVENT)GetDebugData(); + + glbEntryTracerData.MemoryAccessedFrom = (ULONG_PTR)GetContextData(UE_CIP); + glbEntryTracerData.MemoryAccessed = myDbgEvent->u.Exception.ExceptionRecord.ExceptionInformation[1]; + glbEntryTracerData.AccessType = myDbgEvent->u.Exception.ExceptionRecord.ExceptionInformation[0]; + szInstructionType = (char*)DisassembleEx(dbgProcessInformation.hProcess, (void*)glbEntryTracerData.MemoryAccessedFrom, true); + StepInto(&GenericOEPTraceHited); +} +void __stdcall GenericOEPTraceHited() +{ + + int i; + void* lpHashBuffer; + bool FakeEPDetected = false; + ULONG_PTR NumberOfBytesRW; + LPDEBUG_EVENT myDbgEvent = (LPDEBUG_EVENT)GetDebugData(); + typedef void(__stdcall *fEPCallBack)(); + fEPCallBack myEPCallBack = (fEPCallBack)glbEntryTracerData.EPCallBack; + PMEMORY_COMPARE_HANDLER myCmpHandler; + ULONG_PTR memBpxAddress; + ULONG_PTR memBpxSize; + DWORD originalHash; + DWORD currentHash; + + if(myDbgEvent->u.Exception.ExceptionRecord.ExceptionCode == STATUS_SINGLE_STEP) + { + if(glbEntryTracerData.MemoryAccessed >= glbEntryTracerData.LoadedImageBase && glbEntryTracerData.MemoryAccessed <= glbEntryTracerData.LoadedImageBase + glbEntryTracerData.SizeOfImage) + { + for(i = 0; i < glbEntryTracerData.SectionNumber; i++) + { + if(glbEntryTracerData.MemoryAccessed >= glbEntryTracerData.SectionData[i].SectionVirtualOffset + glbEntryTracerData.LoadedImageBase && glbEntryTracerData.MemoryAccessed < glbEntryTracerData.SectionData[i].SectionVirtualOffset + glbEntryTracerData.SectionData[i].SectionVirtualSize + glbEntryTracerData.LoadedImageBase) + { + if(glbEntryTracerData.AccessType == 1) + { + glbEntryTracerData.SectionData[i].AccessedAlready = true; + } + if(glbEntryTracerData.MemoryAccessedFrom >= glbEntryTracerData.SectionData[i].SectionVirtualOffset + glbEntryTracerData.LoadedImageBase && glbEntryTracerData.MemoryAccessedFrom <= glbEntryTracerData.SectionData[i].SectionVirtualOffset + glbEntryTracerData.SectionData[i].SectionVirtualSize + glbEntryTracerData.LoadedImageBase) + { + if(i != glbEntryTracerData.OriginalEntryPointNum) + { + glbEntryTracerData.SectionData[i].AccessedAlready = true; + } + lpHashBuffer = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE); + memBpxAddress = (glbEntryTracerData.MemoryAccessed / 0x1000) * 0x1000; + memBpxSize = glbEntryTracerData.SectionData[i].SectionVirtualOffset + glbEntryTracerData.SectionData[i].SectionVirtualSize + glbEntryTracerData.LoadedImageBase - memBpxAddress; + if(memBpxSize > 0x1000) + { + memBpxSize = 0x1000; + } + if(ReadProcessMemory(dbgProcessInformation.hProcess, (void*)(memBpxAddress), lpHashBuffer, memBpxSize, &NumberOfBytesRW)) + { + currentHash = EngineHashMemory((char*)lpHashBuffer, (DWORD)memBpxSize, NULL); + originalHash = EngineHashMemory((char*)((ULONG_PTR)glbEntryTracerData.SectionData[i].AllocatedSection + memBpxAddress - glbEntryTracerData.LoadedImageBase - glbEntryTracerData.SectionData[i].SectionVirtualOffset), (DWORD)memBpxSize, NULL); + if(ReadProcessMemory(dbgProcessInformation.hProcess, (void*)(glbEntryTracerData.CurrentIntructionPointer), lpHashBuffer, MAXIMUM_INSTRUCTION_SIZE, &NumberOfBytesRW)) + { + myCmpHandler = (PMEMORY_COMPARE_HANDLER)(lpHashBuffer); + if(myCmpHandler->Array.bArrayEntry[0] == 0xC3) // RET + { + FakeEPDetected = true; + } + else if(myCmpHandler->Array.bArrayEntry[0] == 0x33 && myCmpHandler->Array.bArrayEntry[1] == 0xC0 && myCmpHandler->Array.bArrayEntry[2] == 0xC3) // XOR EAX,EAX; RET + { + FakeEPDetected = true; + } + } + VirtualFree(lpHashBuffer, NULL, MEM_RELEASE); + if(currentHash != originalHash && glbEntryTracerData.SectionData[i].AccessedAlready == true && i != glbEntryTracerData.OriginalEntryPointNum && FakeEPDetected == false) + { + __try + { + if(glbEntryTracerData.EPCallBack != NULL) + { + glbEntryTracerData.CurrentIntructionPointer = (ULONG_PTR)GetContextData(UE_CIP); + SetContextData(UE_CIP, glbEntryTracerData.MemoryAccessedFrom); + DeleteAPIBreakPoint("kernel32.dll", "VirtualProtect", UE_APIEND); + RemoveAllBreakPoints(UE_OPTION_REMOVEALL); + myEPCallBack(); + SetContextData(UE_CIP, glbEntryTracerData.CurrentIntructionPointer); + } + else + { + StopDebug(); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + StopDebug(); + } + } + } + } + else + { + SetMemoryBPXEx((ULONG_PTR)(glbEntryTracerData.SectionData[i].SectionVirtualOffset + glbEntryTracerData.LoadedImageBase), glbEntryTracerData.SectionData[i].SectionVirtualSize, UE_MEMORY, false, &GenericOEPTraceHit); + } + } + else + { + SetMemoryBPXEx((ULONG_PTR)(glbEntryTracerData.SectionData[i].SectionVirtualOffset + glbEntryTracerData.LoadedImageBase), glbEntryTracerData.SectionData[i].SectionVirtualSize, UE_MEMORY, false, &GenericOEPTraceHit); + } + } + } + } + else + { + StopDebug(); + } +} +void __stdcall GenericOEPLibraryDetailsHit() +{ + + int i; + bool memBreakPointSet = false; + char szModuleName[2 * MAX_PATH] = {}; +#if !defined(_WIN64) + int inReg = UE_EAX; +#else + int inReg = UE_RAX; +#endif + + if(GetModuleBaseNameA(dbgProcessInformation.hProcess, (HMODULE)GetContextData(inReg), szModuleName, sizeof szModuleName) > NULL) + { + if(lstrcmpiA(szModuleName, "kernel32.dll") != NULL) + { + if(glbEntryTracerData.FileIsDLL) + { + glbEntryTracerData.LoadedImageBase = (ULONG_PTR)GetDebuggedDLLBaseAddress(); + } + else + { + glbEntryTracerData.LoadedImageBase = (ULONG_PTR)GetDebuggedFileBaseAddress(); + } + for(i = 0; i < glbEntryTracerData.SectionNumber; i++) + { + if(glbEntryTracerData.SectionData[i].SectionAttributes & IMAGE_SCN_MEM_EXECUTE || glbEntryTracerData.SectionData[i].SectionAttributes & IMAGE_SCN_CNT_CODE) + { + SetMemoryBPXEx((ULONG_PTR)(glbEntryTracerData.SectionData[i].SectionVirtualOffset + glbEntryTracerData.LoadedImageBase), glbEntryTracerData.SectionData[i].SectionVirtualSize, UE_MEMORY, false, &GenericOEPTraceHit); + memBreakPointSet = true; + } + } + if(!memBreakPointSet) + { + StopDebug(); + } + else + { + DeleteAPIBreakPoint("kernel32.dll", "GetModuleHandleW", UE_APIEND); + DeleteAPIBreakPoint("kernel32.dll", "LoadLibraryExW", UE_APIEND); + } + } + } +} +void __stdcall GenericOEPTraceInit() +{ + + int i; + void* lpHashBuffer; + ULONG_PTR NumberOfBytesRW; + typedef void(__stdcall *fInitCallBack)(); + fInitCallBack myInitCallBack = (fInitCallBack)glbEntryTracerData.InitCallBack; + + if(glbEntryTracerData.FileIsDLL) + { + glbEntryTracerData.LoadedImageBase = (ULONG_PTR)GetDebuggedDLLBaseAddress(); + } + else + { + glbEntryTracerData.LoadedImageBase = (ULONG_PTR)GetDebuggedFileBaseAddress(); + } + for(i = 0; i < glbEntryTracerData.SectionNumber; i++) + { + lpHashBuffer = VirtualAlloc(NULL, glbEntryTracerData.SectionData[i].SectionVirtualSize, MEM_COMMIT, PAGE_READWRITE); + if(lpHashBuffer != NULL) + { + if(ReadProcessMemory(dbgProcessInformation.hProcess, (void*)(glbEntryTracerData.SectionData[i].SectionVirtualOffset + glbEntryTracerData.LoadedImageBase), lpHashBuffer, glbEntryTracerData.SectionData[i].SectionVirtualSize, &NumberOfBytesRW)) + { + glbEntryTracerData.SectionData[i].AllocatedSection = lpHashBuffer; + } + } + } + SetAPIBreakPoint("kernel32.dll", "VirtualProtect", UE_BREAKPOINT, UE_APIEND, &GenericOEPVirtualProtectHit); + SetAPIBreakPoint("kernel32.dll", "GetModuleHandleW", UE_BREAKPOINT, UE_APIEND, &GenericOEPLibraryDetailsHit); + SetAPIBreakPoint("kernel32.dll", "LoadLibraryExW", UE_BREAKPOINT, UE_APIEND, &GenericOEPLibraryDetailsHit); + if(glbEntryTracerData.InitCallBack != NULL) + { + __try + { + myInitCallBack(); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + StopDebug(); + } + } +} +bool __stdcall GenericOEPFileInitW(wchar_t* szFileName, LPVOID TraceInitCallBack, LPVOID CallBack) +{ + + int i; +#if defined(_WIN64) + PE64Struct PEStruct = {}; +#else + PE32Struct PEStruct = {}; +#endif + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + + if(MapFileExW(szFileName, UE_ACCESS_READ, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + if(GetPE32DataFromMappedFileEx(FileMapVA, &PEStruct)) + { + RtlZeroMemory(&glbEntryTracerData, sizeof GenericOEPTracerData); + glbEntryTracerData.OriginalImageBase = PEStruct.ImageBase; + glbEntryTracerData.OriginalEntryPoint = PEStruct.OriginalEntryPoint; + glbEntryTracerData.SizeOfImage = PEStruct.NtSizeOfImage; + glbEntryTracerData.SectionNumber = PEStruct.SectionNumber; + glbEntryTracerData.FileIsDLL = IsFileDLL(NULL, FileMapVA); + glbEntryTracerData.OriginalEntryPointNum = GetPE32SectionNumberFromVA(FileMapVA, glbEntryTracerData.OriginalImageBase + glbEntryTracerData.OriginalEntryPoint); + for(i = 0; i < glbEntryTracerData.SectionNumber; i++) + { + glbEntryTracerData.SectionData[i].SectionVirtualOffset = (DWORD)GetPE32DataFromMappedFile(FileMapVA, i, UE_SECTIONVIRTUALOFFSET); + glbEntryTracerData.SectionData[i].SectionVirtualSize = (DWORD)GetPE32DataFromMappedFile(FileMapVA, i, UE_SECTIONVIRTUALSIZE); + if(glbEntryTracerData.SectionData[i].SectionVirtualSize % 0x1000 != 0) + { + glbEntryTracerData.SectionData[i].SectionVirtualSize = ((glbEntryTracerData.SectionData[i].SectionVirtualSize / 0x1000) + 1) * 0x1000; + } + else + { + glbEntryTracerData.SectionData[i].SectionVirtualSize = (glbEntryTracerData.SectionData[i].SectionVirtualSize / 0x1000) * 0x1000; + } + glbEntryTracerData.SectionData[i].SectionAttributes = (DWORD)GetPE32DataFromMappedFile(FileMapVA, i, UE_SECTIONFLAGS); + } + glbEntryTracerData.EPCallBack = CallBack; + glbEntryTracerData.InitCallBack = TraceInitCallBack; + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + if(glbEntryTracerData.FileIsDLL) + { + return(false); + } + else + { + return(true); + } + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + } + } + return(false); +} +// TitanEngine.FindOEP.functions: +__declspec(dllexport) void __stdcall FindOEPInit() +{ + RemoveAllBreakPoints(UE_OPTION_REMOVEALL); +} +__declspec(dllexport) bool __stdcall FindOEPGenerically(char* szFileName, LPVOID TraceInitCallBack, LPVOID CallBack) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + + if(szFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + return(FindOEPGenericallyW(uniFileName, TraceInitCallBack, CallBack)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall FindOEPGenericallyW(wchar_t* szFileName, LPVOID TraceInitCallBack, LPVOID CallBack) +{ + + int i; + + if(GenericOEPFileInitW(szFileName, TraceInitCallBack, CallBack)) + { + InitDebugExW(szFileName, NULL, NULL, &GenericOEPTraceInit); + DebugLoop(); + for(i = 0; i < glbEntryTracerData.SectionNumber; i++) + { + VirtualFree(glbEntryTracerData.SectionData[i].AllocatedSection, NULL, MEM_RELEASE); + } + } + return(false); +} +// TitanEngine.Importer.functions: +__declspec(dllexport) void __stdcall ImporterCleanup() +{ + + int i = 0; + + for(i = 0; i < 1000; i++) + { + if(impDLLDataList[i][0] != NULL) + { + VirtualFree((LPVOID)(impDLLDataList[i][0]), NULL, MEM_RELEASE); + impDLLDataList[i][0] = 0; + impDLLDataList[i][1] = 0; + } + if(impDLLStringList[i][0] != NULL) + { + VirtualFree((LPVOID)(impDLLStringList[i][0]), NULL, MEM_RELEASE); + impDLLStringList[i][0] = 0; + impDLLStringList[i][1] = 0; + } + impOrdinalList[i][0] = 0; + impOrdinalList[i][1] = 0; + } +} +__declspec(dllexport) void __stdcall ImporterSetImageBase(ULONG_PTR ImageBase) +{ + impImageBase = ImageBase; +} +__declspec(dllexport) void __stdcall ImporterSetUnknownDelta(ULONG_PTR DeltaAddress) +{ + + impDeltaStart = DeltaAddress; + impDeltaCurrent = DeltaAddress; +} +__declspec(dllexport) long long __stdcall ImporterGetCurrentDelta() +{ + return((ULONG_PTR)impDeltaCurrent); +} +__declspec(dllexport) void __stdcall ImporterInit(DWORD MemorySize, ULONG_PTR ImageBase) +{ + + impImageBase = ImageBase; + if(MemorySize != NULL) + { + impAllocSize = MemorySize; + } + else + { + impAllocSize = 20 * 1024; + } + ImporterCleanup(); + impMoveIAT = false; + impDLLNumber = -1; + impDeltaStart = NULL; + impDeltaCurrent = NULL; +} +__declspec(dllexport) void __stdcall ImporterAddNewDll(char* szDLLName, ULONG_PTR FirstThunk) +{ + + int CopyDummy = 1; + + impDLLNumber++; + impDLLDataList[impDLLNumber][0] = (ULONG_PTR)(VirtualAlloc(NULL, 0x2000, MEM_COMMIT, PAGE_READWRITE)); + impDLLDataList[impDLLNumber][1] = impDLLDataList[impDLLNumber][0]; + impDLLStringList[impDLLNumber][0] = (ULONG_PTR)(VirtualAlloc(NULL, impAllocSize, MEM_COMMIT, PAGE_READWRITE)); + impDLLStringList[impDLLNumber][1] = impDLLStringList[impDLLNumber][0]; + RtlMoveMemory((LPVOID)(impDLLDataList[impDLLNumber][1]), &FirstThunk, sizeof ULONG_PTR); + RtlMoveMemory((LPVOID)(impDLLDataList[impDLLNumber][1] + sizeof ULONG_PTR), &FirstThunk, sizeof ULONG_PTR); + RtlMoveMemory((LPVOID)(impDLLDataList[impDLLNumber][1] + 2 * sizeof ULONG_PTR), &CopyDummy, 4); +#if !defined(_WIN64) + impDLLDataList[impDLLNumber][1] = impDLLDataList[impDLLNumber][0] + 12; +#else + impDLLDataList[impDLLNumber][1] = impDLLDataList[impDLLNumber][0] + 20; +#endif + RtlMoveMemory((LPVOID)(impDLLStringList[impDLLNumber][1]), szDLLName, lstrlenA((LPCSTR)szDLLName)); + impDLLStringList[impDLLNumber][1] = impDLLStringList[impDLLNumber][1] + lstrlenA((LPCSTR)szDLLName) + 3; + if(FirstThunk == NULL && impDeltaStart != NULL) + { + impDeltaCurrent = impDeltaCurrent + sizeof ULONG_PTR; + } +} +__declspec(dllexport) void __stdcall ImporterAddNewAPI(char* szAPIName, ULONG_PTR ThunkValue) +{ + + int i = NULL; + int CopyDummy = NULL; + ULONG_PTR LastThunkValue = NULL; + + RtlMoveMemory(&LastThunkValue, (LPVOID)(impDLLDataList[impDLLNumber][0] + sizeof ULONG_PTR), sizeof ULONG_PTR); + if(ThunkValue == NULL && impDeltaCurrent != NULL) + { + ThunkValue = impDeltaCurrent; + impDeltaCurrent = impDeltaCurrent + sizeof ULONG_PTR; + } + if(LastThunkValue != NULL && LastThunkValue != ThunkValue) + { + ImporterAddNewDll((char*)(LPVOID)impDLLStringList[impDLLNumber][0], ThunkValue); + } + else + { + if(LastThunkValue != NULL) + { + LastThunkValue = LastThunkValue + sizeof ULONG_PTR; + } + else + { + RtlMoveMemory((LPVOID)(impDLLDataList[impDLLNumber][0]), &ThunkValue, sizeof ULONG_PTR); + LastThunkValue = ThunkValue + sizeof ULONG_PTR; + } + RtlMoveMemory((LPVOID)(impDLLDataList[impDLLNumber][0] + sizeof ULONG_PTR), &LastThunkValue, sizeof ULONG_PTR); + } + CopyDummy = (int)(impDLLStringList[impDLLNumber][1] - impDLLStringList[impDLLNumber][0]); + RtlMoveMemory((LPVOID)(impDLLDataList[impDLLNumber][1]), &CopyDummy, 4); + impDLLDataList[impDLLNumber][1] = impDLLDataList[impDLLNumber][1] + 4; + if((ULONG_PTR)szAPIName > 0x10000) + { + RtlMoveMemory((LPVOID)(impDLLStringList[impDLLNumber][1] + 2), szAPIName, lstrlenA((LPCSTR)szAPIName)); + impDLLStringList[impDLLNumber][1] = impDLLStringList[impDLLNumber][1] + lstrlenA((LPCSTR)szAPIName) + 3; + } + else + { + for(i = 0; i < 1000; i++) + { + if(impOrdinalList[i][0] == NULL && impOrdinalList[i][1] == NULL) + { + break; + } + } + if(i < 1000) + { + impOrdinalList[i][0] = ThunkValue; + if(sizeof ULONG_PTR == 4) + { + impOrdinalList[i][1] = (ULONG_PTR)szAPIName ^ IMAGE_ORDINAL_FLAG32; + } + else + { + impOrdinalList[i][1] = (ULONG_PTR)((ULONG_PTR)szAPIName ^ IMAGE_ORDINAL_FLAG64); + } + } + } + RtlMoveMemory(&CopyDummy, (LPVOID)(impDLLDataList[impDLLNumber][0] + 2 * sizeof ULONG_PTR), 4); + CopyDummy++; + RtlMoveMemory((LPVOID)(impDLLDataList[impDLLNumber][0] + 2 * sizeof ULONG_PTR), &CopyDummy, 4); +} +__declspec(dllexport) void __stdcall ImporterAddNewOrdinalAPI(ULONG_PTR OrdinalNumber, ULONG_PTR ThunkValue) +{ + + if(OrdinalNumber & IMAGE_ORDINAL_FLAG) + { + OrdinalNumber = OrdinalNumber ^ IMAGE_ORDINAL_FLAG; + ImporterAddNewAPI((char*)OrdinalNumber, ThunkValue); + } + else + { + ImporterAddNewAPI((char*)OrdinalNumber, ThunkValue); + } +} +__declspec(dllexport) long __stdcall ImporterGetAddedDllCount() +{ + return(impDLLNumber + 1); +} +__declspec(dllexport) long __stdcall ImporterGetAddedAPICount() +{ + + int i = 0; + int CopyDummy = NULL; + DWORD DLLNumber = NULL; + long APINumber = NULL; + + DLLNumber = impDLLNumber + 1; + while(DLLNumber > NULL) + { + RtlMoveMemory(&CopyDummy, (LPVOID)(impDLLDataList[i][0] + 2 * sizeof ULONG_PTR), 4); + APINumber = APINumber + CopyDummy - 1; + DLLNumber--; + i++; + } + return(APINumber); +} +__declspec(dllexport) void* __stdcall ImporterGetLastAddedDLLName() +{ + + if(impDLLNumber != -1) + { + return((void*)impDLLStringList[impDLLNumber][0]); + } + else + { + return(NULL); + } +} +__declspec(dllexport) void __stdcall ImporterMoveIAT() +{ + impMoveIAT = true; +} +__declspec(dllexport) bool __stdcall ImporterExportIAT(ULONG_PTR StorePlace, ULONG_PTR FileMapVA) +{ + + int i = 0; + int j = 0; + int x = 0; + int NumberOfAPIs = NULL; + DWORD DLLNumber = NULL; + DWORD APINumber = NULL; + PIMAGE_IMPORT_DESCRIPTOR StoreIID = (PIMAGE_IMPORT_DESCRIPTOR)StorePlace; + ULONG_PTR StorePlaceVA = (ULONG_PTR)ConvertFileOffsetToVA(FileMapVA, StorePlace, true); + ULONG_PTR OriginalStorePlaceRVA = (DWORD)(StorePlaceVA - impImageBase); + ULONG_PTR StringStorePlaceFO = StorePlace + ((impDLLNumber + 2) * sizeof IMAGE_IMPORT_DESCRIPTOR); + ULONG_PTR StringStorePlaceVA = StorePlaceVA + ((impDLLNumber + 2) * sizeof IMAGE_IMPORT_DESCRIPTOR); + ULONG_PTR ThunkStorePlaceFO = NULL; + ULONG_PTR ThunkReadValue = NULL; + LPVOID ThunkReadPlace = NULL; + ULONG_PTR FirstThunk = NULL; + ULONG_PTR CurrentThunk = NULL; + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + bool FileIs64 = false; + bool OrdinalImport = false; + + if(ImporterGetAddedDllCount() > NULL) + { + if(impMoveIAT) + { + NumberOfAPIs = ImporterGetAddedAPICount() + ImporterGetAddedDllCount(); + StorePlaceVA = StorePlaceVA + (NumberOfAPIs * sizeof ULONG_PTR); + StringStorePlaceFO = StringStorePlaceFO + (NumberOfAPIs * sizeof ULONG_PTR); + StringStorePlaceVA = StringStorePlaceVA + (NumberOfAPIs * sizeof ULONG_PTR); + OriginalStorePlaceRVA = OriginalStorePlaceRVA + (NumberOfAPIs * sizeof ULONG_PTR); + StoreIID = (PIMAGE_IMPORT_DESCRIPTOR)((ULONG_PTR)StorePlace + (NumberOfAPIs * sizeof ULONG_PTR)); + } + + __try + { + DLLNumber = impDLLNumber + 1; + while(DLLNumber > NULL) + { + RtlMoveMemory(&FirstThunk, (LPVOID)impDLLDataList[i][0], sizeof ULONG_PTR); + StoreIID->FirstThunk = (DWORD)(FirstThunk - impImageBase); + StoreIID->Name = (DWORD)(StringStorePlaceVA - impImageBase); + RtlMoveMemory((LPVOID)StringStorePlaceFO, (LPVOID)impDLLStringList[i][0], (int)(impDLLStringList[i][1] - impDLLStringList[i][0])); + StringStorePlaceFO = StringStorePlaceFO + (int)(impDLLStringList[i][1] - impDLLStringList[i][0]); +#if !defined(_WIN64) + ThunkReadPlace = (LPVOID)(impDLLDataList[i][0] + 12); +#else + ThunkReadPlace = (LPVOID)(impDLLDataList[i][0] + 20); +#endif + ThunkStorePlaceFO = (ULONG_PTR)ConvertVAtoFileOffset(FileMapVA, FirstThunk, true); + RtlMoveMemory(&APINumber, (LPVOID)(impDLLDataList[i][0] + 2 * sizeof ULONG_PTR), 4); + CurrentThunk = FirstThunk; + APINumber--; + while(APINumber > NULL) + { + OrdinalImport = false; + for(j = 0; j < 1000; j++) + { + if(impOrdinalList[j][0] == CurrentThunk) + { + OrdinalImport = true; + x = j; + j = 1000; + } + else if(impOrdinalList[j][0] == NULL) + { + j = 1000; + } + } + if(!OrdinalImport) + { + RtlMoveMemory(&ThunkReadValue, ThunkReadPlace, 4); + ThunkReadValue = ThunkReadValue + StringStorePlaceVA - impImageBase; + RtlMoveMemory((LPVOID)ThunkStorePlaceFO, &ThunkReadValue, sizeof ULONG_PTR); + ThunkReadPlace = (LPVOID)((ULONG_PTR)ThunkReadPlace + 4); + ThunkStorePlaceFO = ThunkStorePlaceFO + sizeof ULONG_PTR; + } + else + { + j = x; + ThunkReadValue = impOrdinalList[j][1]; + RtlMoveMemory((LPVOID)ThunkStorePlaceFO, &ThunkReadValue, sizeof ULONG_PTR); + ThunkReadPlace = (LPVOID)((ULONG_PTR)ThunkReadPlace + 4); + ThunkStorePlaceFO = ThunkStorePlaceFO + sizeof ULONG_PTR; + } + CurrentThunk = CurrentThunk + sizeof ULONG_PTR; + APINumber--; + } + ThunkReadValue = 0; + RtlMoveMemory((LPVOID)ThunkStorePlaceFO, &ThunkReadValue, sizeof ULONG_PTR); + + StorePlaceVA = StorePlaceVA + (int)(impDLLStringList[i][1] - impDLLStringList[i][0]); + StringStorePlaceVA = StringStorePlaceVA + (int)(impDLLStringList[i][1] - impDLLStringList[i][0]); + StoreIID = (PIMAGE_IMPORT_DESCRIPTOR)((ULONG_PTR)StoreIID + sizeof IMAGE_IMPORT_DESCRIPTOR); + DLLNumber--; + i++; + } + + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, NULL, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + if(!FileIs64) + { + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = (DWORD)OriginalStorePlaceRVA; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = (DWORD)((impDLLNumber + 2) * sizeof IMAGE_IMPORT_DESCRIPTOR); + } + else + { + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = (DWORD)OriginalStorePlaceRVA; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = (DWORD)((impDLLNumber + 2) * sizeof IMAGE_IMPORT_DESCRIPTOR); + } + } + ImporterCleanup(); + return(true); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + ImporterCleanup(); + return(false); + } + } + else + { + return(false); + } +} +__declspec(dllexport) long __stdcall ImporterEstimatedSize() +{ + + int i = 0; + DWORD DLLNumber = NULL; + long EstimatedSize = 0x200; + + if(impMoveIAT) + { + EstimatedSize = EstimatedSize + (ImporterGetAddedAPICount() * sizeof ULONG_PTR) + ((impDLLNumber + 1) * sizeof ULONG_PTR); + } + EstimatedSize = EstimatedSize + ((impDLLNumber + 2) * sizeof IMAGE_IMPORT_DESCRIPTOR); + DLLNumber = impDLLNumber + 1; + while(DLLNumber > NULL) + { + EstimatedSize = EstimatedSize + (DWORD)(impDLLStringList[i][1] - impDLLStringList[i][0]); + DLLNumber--; + i++; + } + for(i = 0; i < 1000; i++) + { + if(impOrdinalList[i][0] != NULL && impOrdinalList[i][1] != NULL) + { + EstimatedSize = EstimatedSize + sizeof ULONG_PTR; + } + } + return(EstimatedSize); +} +__declspec(dllexport) bool __stdcall ImporterExportIATEx(char* szExportFileName, char* szSectionName) +{ + + wchar_t uniExportFileName[MAX_PATH] = {}; + + if(szExportFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szExportFileName, lstrlenA(szExportFileName)+1, uniExportFileName, sizeof(uniExportFileName)/(sizeof(uniExportFileName[0]))); + return(ImporterExportIATExW(uniExportFileName, szSectionName)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall ImporterExportIATExW(wchar_t* szExportFileName, char* szSectionName) +{ + + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + DWORD NewSectionVO = NULL; + DWORD NewSectionFO = NULL; + bool ReturnValue = false; + + if(ImporterGetAddedDllCount() > NULL) + { + NewSectionVO = AddNewSectionW(szExportFileName, szSectionName, ImporterEstimatedSize()); + if(MapFileExW(szExportFileName, UE_ACCESS_ALL, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + NewSectionFO = (DWORD)ConvertVAtoFileOffset(FileMapVA, NewSectionVO + impImageBase, true); + ReturnValue = ImporterExportIAT(NewSectionFO, FileMapVA); + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + if(ReturnValue) + { + return(true); + } + else + { + return(false); + } + } + else + { + return(false); + } + } + else + { + return(false); + } +} +__declspec(dllexport) long long __stdcall ImporterFindAPIWriteLocation(char* szAPIName) +{ + + int i = 0; + int j = 0; + DWORD DLLNumber = NULL; + DWORD NumberOfAPIs = NULL; + LPVOID NameReadPlace = NULL; + ULONG_PTR CurrentAPILocation = NULL; + DWORD APINameRelativeOffset = NULL; + ULONG_PTR APIWriteLocation = NULL; + + if(ImporterGetAddedDllCount() > NULL) + { + if((ULONG_PTR)szAPIName > 0x10000) + { + DLLNumber = impDLLNumber + 1; + while(DLLNumber > NULL) + { +#if !defined(_WIN64) + NameReadPlace = (LPVOID)(impDLLDataList[i][0] + 12); +#else + NameReadPlace = (LPVOID)(impDLLDataList[i][0] + 20); +#endif + RtlMoveMemory(&CurrentAPILocation, (LPVOID)(impDLLDataList[i][0]), sizeof ULONG_PTR); + RtlMoveMemory(&NumberOfAPIs, (LPVOID)(impDLLDataList[i][0] + 2 * sizeof ULONG_PTR), 4); + while(NumberOfAPIs > NULL) + { + RtlMoveMemory(&APINameRelativeOffset, NameReadPlace, 4); + if(lstrcmpiA((LPCSTR)((ULONG_PTR)impDLLStringList[i][0] + APINameRelativeOffset + 2), (LPCSTR)szAPIName) == NULL) + { + APIWriteLocation = CurrentAPILocation; + break; + } + CurrentAPILocation = CurrentAPILocation + sizeof ULONG_PTR; + NameReadPlace = (LPVOID)((ULONG_PTR)NameReadPlace + sizeof ULONG_PTR); + NumberOfAPIs--; + } + DLLNumber--; + i++; + } + return(APIWriteLocation); + } + else + { + for(j = 0; j < 1000; j++) + { + if(impOrdinalList[j][1] == ((ULONG_PTR)szAPIName ^ IMAGE_ORDINAL_FLAG)) + { + return(impOrdinalList[j][0]); + } + } + } + } + return(NULL); +} +__declspec(dllexport) long long __stdcall ImporterFindOrdinalAPIWriteLocation(ULONG_PTR OrdinalNumber) +{ + return(ImporterFindAPIWriteLocation((char*)OrdinalNumber)); +} +__declspec(dllexport) long long __stdcall ImporterFindAPIByWriteLocation(ULONG_PTR APIWriteLocation) +{ + + int i = 0; + DWORD DLLNumber = NULL; + LPVOID NameReadPlace = NULL; + ULONG_PTR MinAPILocation = NULL; + ULONG_PTR MaxAPILocation = NULL; + DWORD APINameRelativeOffset = NULL; + ULONG_PTR APINameOffset = NULL; + + if(ImporterGetAddedDllCount() > NULL) + { + DLLNumber = impDLLNumber + 1; + while(DLLNumber > NULL) + { +#if !defined(_WIN64) + NameReadPlace = (LPVOID)(impDLLDataList[i][0] + 12); +#else + NameReadPlace = (LPVOID)(impDLLDataList[i][0] + 20); +#endif + RtlMoveMemory(&MinAPILocation, (LPVOID)(impDLLDataList[i][0]), sizeof ULONG_PTR); + RtlMoveMemory(&MaxAPILocation, (LPVOID)(impDLLDataList[i][0] + sizeof ULONG_PTR), sizeof ULONG_PTR); + if(MinAPILocation <= APIWriteLocation && APIWriteLocation <= MaxAPILocation) + { + RtlMoveMemory(&APINameRelativeOffset, (LPVOID)((ULONG_PTR)NameReadPlace + (APIWriteLocation - MinAPILocation)), 4); + return((ULONG_PTR)(impDLLStringList[i][0] + APINameRelativeOffset + 2)); + } + DLLNumber--; + i++; + } + } + return(NULL); +} +__declspec(dllexport) long long __stdcall ImporterFindDLLByWriteLocation(ULONG_PTR APIWriteLocation) +{ + + int i = 0; + DWORD DLLNumber = NULL; + LPVOID NameReadPlace = NULL; + ULONG_PTR MinAPILocation = NULL; + ULONG_PTR MaxAPILocation = NULL; + DWORD APINameRelativeOffset = NULL; + ULONG_PTR APINameOffset = NULL; + + if(ImporterGetAddedDllCount() > NULL) + { + DLLNumber = impDLLNumber + 1; + while(DLLNumber > NULL) + { +#if !defined(_WIN64) + NameReadPlace = (LPVOID)(impDLLDataList[i][0] + 12); +#else + NameReadPlace = (LPVOID)(impDLLDataList[i][0] + 20); +#endif + RtlMoveMemory(&MinAPILocation, (LPVOID)(impDLLDataList[i][0]), sizeof ULONG_PTR); + RtlMoveMemory(&MaxAPILocation, (LPVOID)(impDLLDataList[i][0] + sizeof ULONG_PTR), sizeof ULONG_PTR); + if(MinAPILocation <= APIWriteLocation && APIWriteLocation <= MaxAPILocation) + { + return((ULONG_PTR)(impDLLStringList[i][0])); + } + DLLNumber--; + i++; + } + } + return(NULL); +} +__declspec(dllexport) void* __stdcall ImporterGetDLLName(ULONG_PTR APIAddress) +{ + return((LPVOID)EngineGlobalAPIHandler(NULL, NULL, APIAddress, NULL, UE_OPTION_IMPORTER_RETURN_DLLNAME)); +} +__declspec(dllexport) void* __stdcall ImporterGetAPIName(ULONG_PTR APIAddress) +{ + return((LPVOID)EngineGlobalAPIHandler(NULL, NULL, APIAddress, NULL, UE_OPTION_IMPORTER_RETURN_APINAME)); +} +__declspec(dllexport) long long __stdcall ImporterGetAPIOrdinalNumber(ULONG_PTR APIAddress) +{ + return((long)EngineGlobalAPIHandler(NULL, NULL, APIAddress, NULL, UE_OPTION_IMPORTER_RETURN_API_ORDINAL_NUMBER)); +} +__declspec(dllexport) void* __stdcall ImporterGetAPINameEx(ULONG_PTR APIAddress, ULONG_PTR DLLBasesList) +{ + return((LPVOID)EngineGlobalAPIHandler(NULL, DLLBasesList, APIAddress, NULL, UE_OPTION_IMPORTER_RETURN_APINAME)); +} +__declspec(dllexport) long long __stdcall ImporterGetRemoteAPIAddress(HANDLE hProcess, ULONG_PTR APIAddress) +{ + return((ULONG_PTR)EngineGlobalAPIHandler(hProcess, NULL, APIAddress, NULL, UE_OPTION_IMPORTER_REALIGN_APIADDRESS)); +} +__declspec(dllexport) long long __stdcall ImporterGetRemoteAPIAddressEx(char* szDLLName, char* szAPIName) +{ + + int i = 0; + int j = 0; + char szAnsiLibraryName[MAX_PATH]; + PLIBRARY_ITEM_DATAW hListLibraryPtr = NULL; + ULONG_PTR APIFoundAddress = 0; + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + PIMAGE_EXPORT_DIRECTORY PEExports; + PEXPORTED_DATA ExportedFunctions; + PEXPORTED_DATA ExportedFunctionNames; + PEXPORTED_DATA_WORD ExportedFunctionOrdinals; + bool FileIs64 = false; + + hListLibraryPtr = (PLIBRARY_ITEM_DATAW)hListLibrary; + if(hListLibraryPtr != NULL) + { + while(hListLibraryPtr->hFile != NULL) + { + WideCharToMultiByte(CP_ACP, NULL, hListLibraryPtr->szLibraryName, -1, szAnsiLibraryName, sizeof szAnsiLibraryName, NULL, NULL); + if(lstrcmpiA(szAnsiLibraryName, szDLLName) == NULL) + { + __try + { + DOSHeader = (PIMAGE_DOS_HEADER)hListLibraryPtr->hFileMappingView; + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + return(NULL); + } + if(!FileIs64) + { + PEExports = (PIMAGE_EXPORT_DIRECTORY)((ULONG_PTR)ConvertVAtoFileOffsetEx((ULONG_PTR)hListLibraryPtr->hFileMappingView, GetFileSize(hListLibraryPtr->hFile, NULL), (ULONG_PTR)PEHeader32->OptionalHeader.ImageBase, PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress, true, true)); + ExportedFunctions = (PEXPORTED_DATA)((ULONG_PTR)ConvertVAtoFileOffsetEx((ULONG_PTR)hListLibraryPtr->hFileMappingView, GetFileSize(hListLibraryPtr->hFile, NULL), (ULONG_PTR)PEHeader32->OptionalHeader.ImageBase, PEExports->AddressOfFunctions, true, true)); + ExportedFunctionNames = (PEXPORTED_DATA)((ULONG_PTR)ConvertVAtoFileOffsetEx((ULONG_PTR)hListLibraryPtr->hFileMappingView, GetFileSize(hListLibraryPtr->hFile, NULL), (ULONG_PTR)PEHeader32->OptionalHeader.ImageBase, PEExports->AddressOfNames, true, true)); + ExportedFunctionOrdinals = (PEXPORTED_DATA_WORD)((ULONG_PTR)ConvertVAtoFileOffsetEx((ULONG_PTR)hListLibraryPtr->hFileMappingView, GetFileSize(hListLibraryPtr->hFile, NULL), (ULONG_PTR)PEHeader32->OptionalHeader.ImageBase, PEExports->AddressOfNameOrdinals, true, true)); + } + else + { + PEExports = (PIMAGE_EXPORT_DIRECTORY)((ULONG_PTR)ConvertVAtoFileOffsetEx((ULONG_PTR)hListLibraryPtr->hFileMappingView, GetFileSize(hListLibraryPtr->hFile, NULL), (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress, true, true)); + ExportedFunctions = (PEXPORTED_DATA)((ULONG_PTR)ConvertVAtoFileOffsetEx((ULONG_PTR)hListLibraryPtr->hFileMappingView, GetFileSize(hListLibraryPtr->hFile, NULL), (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, PEExports->AddressOfFunctions, true, true)); + ExportedFunctionNames = (PEXPORTED_DATA)((ULONG_PTR)ConvertVAtoFileOffsetEx((ULONG_PTR)hListLibraryPtr->hFileMappingView, GetFileSize(hListLibraryPtr->hFile, NULL), (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, PEExports->AddressOfNames, true, true)); + ExportedFunctionOrdinals = (PEXPORTED_DATA_WORD)((ULONG_PTR)ConvertVAtoFileOffsetEx((ULONG_PTR)hListLibraryPtr->hFileMappingView, GetFileSize(hListLibraryPtr->hFile, NULL), (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, PEExports->AddressOfNameOrdinals, true, true)); + } + for(j = 0; j <= (int)PEExports->NumberOfNames; j++) + { + if(!FileIs64) + { + if(lstrcmpiA((LPCSTR)szAPIName, (LPCSTR)((ULONG_PTR)ConvertVAtoFileOffsetEx((ULONG_PTR)hListLibraryPtr->hFileMappingView, GetFileSize(hListLibraryPtr->hFile, NULL), (ULONG_PTR)PEHeader32->OptionalHeader.ImageBase, ExportedFunctionNames->ExportedItem, true, true))) == NULL) + { + ExportedFunctionOrdinals = (PEXPORTED_DATA_WORD)((ULONG_PTR)ExportedFunctionOrdinals + j * 2); + ExportedFunctions = (PEXPORTED_DATA)((ULONG_PTR)ExportedFunctions + (ExportedFunctionOrdinals->OrdinalNumber) * 4); + APIFoundAddress = ExportedFunctions->ExportedItem + (ULONG_PTR)hListLibraryPtr->BaseOfDll; + return((ULONG_PTR)APIFoundAddress); + } + } + else + { + if(lstrcmpiA((LPCSTR)szAPIName, (LPCSTR)((ULONG_PTR)ConvertVAtoFileOffsetEx((ULONG_PTR)hListLibraryPtr->hFileMappingView, GetFileSize(hListLibraryPtr->hFile, NULL), (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, ExportedFunctionNames->ExportedItem, true, true))) == NULL) + { + ExportedFunctionOrdinals = (PEXPORTED_DATA_WORD)((ULONG_PTR)ExportedFunctionOrdinals + j * 2); + ExportedFunctions = (PEXPORTED_DATA)((ULONG_PTR)ExportedFunctions + (ExportedFunctionOrdinals->OrdinalNumber) * 4); + APIFoundAddress = ExportedFunctions->ExportedItem + (ULONG_PTR)hListLibraryPtr->BaseOfDll; + return((ULONG_PTR)APIFoundAddress); + } + } + ExportedFunctionNames = (PEXPORTED_DATA)((ULONG_PTR)ExportedFunctionNames + 4); + } + return(NULL); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return(NULL); + } + } + hListLibraryPtr = (PLIBRARY_ITEM_DATAW)((ULONG_PTR)hListLibraryPtr + sizeof LIBRARY_ITEM_DATAW); + } + } + return(NULL); +} +__declspec(dllexport) long long __stdcall ImporterGetLocalAPIAddress(HANDLE hProcess, ULONG_PTR APIAddress) +{ + return((ULONG_PTR)EngineGlobalAPIHandler(hProcess, NULL, APIAddress, NULL, UE_OPTION_IMPORTER_REALIGN_LOCAL_APIADDRESS)); +} +__declspec(dllexport) void* __stdcall ImporterGetDLLNameFromDebugee(HANDLE hProcess, ULONG_PTR APIAddress) +{ + return((LPVOID)EngineGlobalAPIHandler(hProcess, NULL, APIAddress, NULL, UE_OPTION_IMPORTER_RETURN_DLLNAME)); +} +__declspec(dllexport) void* __stdcall ImporterGetAPINameFromDebugee(HANDLE hProcess, ULONG_PTR APIAddress) +{ + return((LPVOID)EngineGlobalAPIHandler(hProcess, NULL, APIAddress, NULL, UE_OPTION_IMPORTER_RETURN_APINAME)); +} +__declspec(dllexport) long long __stdcall ImporterGetAPIOrdinalNumberFromDebugee(HANDLE hProcess, ULONG_PTR APIAddress) +{ + return((long)EngineGlobalAPIHandler(hProcess, NULL, APIAddress, NULL, UE_OPTION_IMPORTER_RETURN_API_ORDINAL_NUMBER)); +} +__declspec(dllexport) long __stdcall ImporterGetDLLIndexEx(ULONG_PTR APIAddress, ULONG_PTR DLLBasesList) +{ + return((DWORD)EngineGlobalAPIHandler(NULL, DLLBasesList, APIAddress, NULL, UE_OPTION_IMPORTER_RETURN_DLLINDEX)); +} +__declspec(dllexport) long __stdcall ImporterGetDLLIndex(HANDLE hProcess, ULONG_PTR APIAddress, ULONG_PTR DLLBasesList) +{ + return((DWORD)EngineGlobalAPIHandler(hProcess, DLLBasesList, APIAddress, NULL, UE_OPTION_IMPORTER_RETURN_DLLINDEX)); +} +__declspec(dllexport) long long __stdcall ImporterGetRemoteDLLBase(HANDLE hProcess, HMODULE LocalModuleBase) +{ + return((ULONG_PTR)EngineGlobalAPIHandler(hProcess, NULL, (ULONG_PTR)LocalModuleBase, NULL, UE_OPTION_IMPORTER_RETURN_DLLBASE)); +} +__declspec(dllexport) long long __stdcall ImporterGetRemoteDLLBaseEx(HANDLE hProcess, char* szModuleName) +{ + + int i = 1; + DWORD Dummy = NULL; + ULONG_PTR EnumeratedModules[0x2000]; + char RemoteDLLName[MAX_PATH]; + + if(EnumProcessModules(hProcess, (HMODULE*)EnumeratedModules, 0x2000, &Dummy)) + { + RtlZeroMemory(&RemoteDLLName, MAX_PATH); + while(EnumeratedModules[i] != NULL) + { + if(GetModuleBaseNameA(hProcess, (HMODULE)EnumeratedModules[i], (LPSTR)RemoteDLLName, MAX_PATH) > NULL) + { + if(lstrcmpiA((LPCSTR)RemoteDLLName, (LPCSTR)szModuleName)) + { + return((ULONG_PTR)EnumeratedModules[i]); + } + } + i++; + } + } + return(NULL); +} +__declspec(dllexport) bool __stdcall ImporterRelocateWriteLocation(ULONG_PTR AddValue) +{ + + unsigned int i; + ULONG_PTR RealignData = NULL; + + if(impDLLNumber >= NULL) + { + for(i = 0; i < impDLLNumber + 1; i++) + { + RtlMoveMemory(&RealignData, (LPVOID)impDLLDataList[i][0], sizeof ULONG_PTR); + RealignData = RealignData + AddValue; + RtlMoveMemory((LPVOID)impDLLDataList[i][0], &RealignData, sizeof ULONG_PTR); + RtlMoveMemory(&RealignData, (LPVOID)((ULONG_PTR)impDLLDataList[i][0] + sizeof ULONG_PTR), sizeof ULONG_PTR); + RealignData = RealignData + AddValue; + RtlMoveMemory((LPVOID)((ULONG_PTR)impDLLDataList[i][0] + sizeof ULONG_PTR), &RealignData, sizeof ULONG_PTR); + } + for(i = 0; i < 1000; i++) + { + if(impOrdinalList[i][0] != NULL && impOrdinalList[i][1] != NULL) + { + impOrdinalList[i][0] = impOrdinalList[i][0] + AddValue; + } + } + return(true); + } + else + { + return(false); + } + return(false); +} +__declspec(dllexport) bool __stdcall ImporterIsForwardedAPI(HANDLE hProcess, ULONG_PTR APIAddress) +{ + if((ULONG_PTR)EngineGlobalAPIHandler(hProcess, NULL, APIAddress, NULL, UE_OPTION_IMPORTER_RETURN_FORWARDER_DLLINDEX) > NULL) + { + return(true); + } + else + { + return(false); + } +} +__declspec(dllexport) void* __stdcall ImporterGetForwardedAPIName(HANDLE hProcess, ULONG_PTR APIAddress) +{ + return((LPVOID)EngineGlobalAPIHandler(hProcess, NULL, APIAddress, NULL, UE_OPTION_IMPORTER_RETURN_FORWARDER_APINAME)); +} +__declspec(dllexport) void* __stdcall ImporterGetForwardedDLLName(HANDLE hProcess, ULONG_PTR APIAddress) +{ + return((LPVOID)EngineGlobalAPIHandler(hProcess, NULL, APIAddress, NULL, UE_OPTION_IMPORTER_RETURN_FORWARDER_DLLNAME)); +} +__declspec(dllexport) long __stdcall ImporterGetForwardedDLLIndex(HANDLE hProcess, ULONG_PTR APIAddress, ULONG_PTR DLLBasesList) +{ + return((DWORD)EngineGlobalAPIHandler(hProcess, NULL, APIAddress, NULL, UE_OPTION_IMPORTER_RETURN_FORWARDER_DLLINDEX)); +} +__declspec(dllexport) long long __stdcall ImporterGetForwardedAPIOrdinalNumber(HANDLE hProcess, ULONG_PTR APIAddress) +{ + return((DWORD)EngineGlobalAPIHandler(hProcess, NULL, APIAddress, NULL, UE_OPTION_IMPORTER_RETURN_FORWARDER_API_ORDINAL_NUMBER)); +} +__declspec(dllexport) long long __stdcall ImporterGetNearestAPIAddress(HANDLE hProcess, ULONG_PTR APIAddress) +{ + return((ULONG_PTR)EngineGlobalAPIHandler(hProcess, NULL, APIAddress, NULL, UE_OPTION_IMPORTER_RETURN_NEAREST_APIADDRESS)); +} +__declspec(dllexport) void* __stdcall ImporterGetNearestAPIName(HANDLE hProcess, ULONG_PTR APIAddress) +{ + return((LPVOID)EngineGlobalAPIHandler(hProcess, NULL, APIAddress, NULL, UE_OPTION_IMPORTER_RETURN_NEAREST_APINAME)); +} +__declspec(dllexport) bool __stdcall ImporterCopyOriginalIAT(char* szOriginalFile, char* szDumpFile) +{ + + wchar_t uniDumpFile[MAX_PATH] = {}; + wchar_t uniOriginalFile[MAX_PATH] = {}; + + if(szOriginalFile != NULL && szDumpFile != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szDumpFile, lstrlenA(szDumpFile)+1, uniDumpFile, sizeof(uniDumpFile)/(sizeof(uniDumpFile[0]))); + MultiByteToWideChar(CP_ACP, NULL, szOriginalFile, lstrlenA(szOriginalFile)+1, uniOriginalFile, sizeof(uniOriginalFile)/(sizeof(uniOriginalFile[0]))); + return(ImporterCopyOriginalIATW(uniOriginalFile, uniDumpFile)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall ImporterCopyOriginalIATW(wchar_t* szOriginalFile, wchar_t* szDumpFile) +{ + + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + BOOL FileIs64; + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + HANDLE FileHandle1; + DWORD FileSize1; + HANDLE FileMap1; + ULONG_PTR FileMapVA1; + ULONG_PTR IATPointer; + ULONG_PTR IATWritePointer; + ULONG_PTR IATCopyStart; + DWORD IATSection; + DWORD IATCopySize; + DWORD IATHeaderData; + + if(MapFileExW(szOriginalFile, UE_ACCESS_READ, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + if(MapFileExW(szDumpFile, UE_ACCESS_ALL, &FileHandle1, &FileSize1, &FileMap1, &FileMapVA1, NULL)) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, FileHandle, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + UnMapFileEx(FileHandle1, FileSize1, FileMap1, FileMapVA1); + return(false); + } + if(!FileIs64) + { + IATPointer = (ULONG_PTR)(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + PEHeader32->OptionalHeader.ImageBase); + } + else + { + IATPointer = (ULONG_PTR)(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + PEHeader64->OptionalHeader.ImageBase); + } + IATSection = GetPE32SectionNumberFromVA(FileMapVA, IATPointer); + IATPointer = (ULONG_PTR)ConvertVAtoFileOffset(FileMapVA, IATPointer, true); + if((int)IATSection >= NULL) + { + IATWritePointer = (ULONG_PTR)GetPE32DataFromMappedFile(FileMapVA1, IATSection, UE_SECTIONRAWOFFSET) + FileMapVA1; + IATCopyStart = (ULONG_PTR)GetPE32DataFromMappedFile(FileMapVA, IATSection, UE_SECTIONRAWOFFSET) + FileMapVA; + IATCopySize = (DWORD)GetPE32DataFromMappedFile(FileMapVA1, IATSection, UE_SECTIONRAWSIZE); + __try + { + RtlMoveMemory((LPVOID)IATWritePointer, (LPVOID)IATCopyStart, IATCopySize); + IATHeaderData = (DWORD)GetPE32DataFromMappedFile(FileMapVA, NULL, UE_IMPORTTABLEADDRESS); + SetPE32DataForMappedFile(FileMapVA1, NULL, UE_IMPORTTABLEADDRESS, (ULONG_PTR)IATHeaderData); + IATHeaderData = (DWORD)GetPE32DataFromMappedFile(FileMapVA, NULL, UE_IMPORTTABLESIZE); + SetPE32DataForMappedFile(FileMapVA1, NULL, UE_IMPORTTABLESIZE, (ULONG_PTR)IATHeaderData); + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + UnMapFileEx(FileHandle1, FileSize1, FileMap1, FileMapVA1); + return(true); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + UnMapFileEx(FileHandle1, FileSize1, FileMap1, FileMapVA1); + return(false); + } + } + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + UnMapFileEx(FileHandle1, FileSize1, FileMap1, FileMapVA1); + return(false); + } + } + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + UnMapFileEx(FileHandle1, FileSize1, FileMap1, FileMapVA1); + return(false); +} +__declspec(dllexport) bool __stdcall ImporterLoadImportTable(char* szFileName) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + + if(szFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + return(ImporterLoadImportTableW(uniFileName)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall ImporterLoadImportTableW(wchar_t* szFileName) +{ + + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + PIMAGE_IMPORT_DESCRIPTOR ImportIID; + PIMAGE_THUNK_DATA32 ThunkData32; + PIMAGE_THUNK_DATA64 ThunkData64; + ULONG_PTR CurrentThunk; + BOOL FileIs64; + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + + if(MapFileExW(szFileName, UE_ACCESS_READ, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, FileHandle, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + if(!FileIs64) + { + if(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress != NULL) + { + ImporterInit(MAX_IMPORT_ALLOC, (ULONG_PTR)PEHeader32->OptionalHeader.ImageBase); + ImportIID = (PIMAGE_IMPORT_DESCRIPTOR)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + PEHeader32->OptionalHeader.ImageBase), true); + __try + { + while(ImportIID->FirstThunk != NULL) + { + ImporterAddNewDll((char*)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)((ULONG_PTR)ImportIID->Name + PEHeader32->OptionalHeader.ImageBase), true), NULL); + if(ImportIID->OriginalFirstThunk != NULL) + { + ThunkData32 = (PIMAGE_THUNK_DATA32)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)((ULONG_PTR)ImportIID->OriginalFirstThunk + PEHeader32->OptionalHeader.ImageBase), true); + CurrentThunk = (ULONG_PTR)ImportIID->FirstThunk; + } + else + { + ThunkData32 = (PIMAGE_THUNK_DATA32)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)((ULONG_PTR)ImportIID->FirstThunk + PEHeader32->OptionalHeader.ImageBase), true); + CurrentThunk = (ULONG_PTR)ImportIID->FirstThunk; + } + while(ThunkData32->u1.AddressOfData != NULL) + { + if(ThunkData32->u1.Ordinal & IMAGE_ORDINAL_FLAG32) + { + ImporterAddNewAPI((char*)(ThunkData32->u1.Ordinal ^ IMAGE_ORDINAL_FLAG32), (ULONG_PTR)CurrentThunk + PEHeader32->OptionalHeader.ImageBase); + } + else + { + ImporterAddNewAPI((char*)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)((ULONG_PTR)ThunkData32->u1.AddressOfData + 2 + PEHeader32->OptionalHeader.ImageBase), true), (ULONG_PTR)CurrentThunk + PEHeader32->OptionalHeader.ImageBase); + } + CurrentThunk = CurrentThunk + 4; + ThunkData32 = (PIMAGE_THUNK_DATA32)((ULONG_PTR)ThunkData32 + sizeof IMAGE_THUNK_DATA32); + } + ImportIID = (PIMAGE_IMPORT_DESCRIPTOR)((ULONG_PTR)ImportIID + sizeof IMAGE_IMPORT_DESCRIPTOR); + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(true); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + ImporterCleanup(); + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + } + else + { + if(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress != NULL) + { + ImporterInit(MAX_IMPORT_ALLOC, (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase); + ImportIID = (PIMAGE_IMPORT_DESCRIPTOR)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + PEHeader64->OptionalHeader.ImageBase), true); + __try + { + while(ImportIID->FirstThunk != NULL) + { + ImporterAddNewDll((char*)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)((ULONG_PTR)ImportIID->Name + PEHeader64->OptionalHeader.ImageBase), true), NULL); + if(ImportIID->OriginalFirstThunk != NULL) + { + ThunkData64 = (PIMAGE_THUNK_DATA64)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)((ULONG_PTR)ImportIID->OriginalFirstThunk + PEHeader64->OptionalHeader.ImageBase), true); + CurrentThunk = (ULONG_PTR)ImportIID->OriginalFirstThunk; + } + else + { + ThunkData64 = (PIMAGE_THUNK_DATA64)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)((ULONG_PTR)ImportIID->FirstThunk + PEHeader64->OptionalHeader.ImageBase), true); + CurrentThunk = (ULONG_PTR)ImportIID->FirstThunk; + } + while(ThunkData64->u1.AddressOfData != NULL) + { + if(ThunkData64->u1.Ordinal & IMAGE_ORDINAL_FLAG64) + { + ImporterAddNewAPI((char*)(ThunkData64->u1.Ordinal ^ (ULONG_PTR)IMAGE_ORDINAL_FLAG64), (ULONG_PTR)CurrentThunk + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase); + } + else + { + ImporterAddNewAPI((char*)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)((ULONG_PTR)ThunkData64->u1.AddressOfData + 2 + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase), true), (ULONG_PTR)CurrentThunk + (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase); + } + CurrentThunk = CurrentThunk + 8; + ThunkData64 = (PIMAGE_THUNK_DATA64)((ULONG_PTR)ThunkData64 + sizeof IMAGE_THUNK_DATA64); + } + ImportIID = (PIMAGE_IMPORT_DESCRIPTOR)((ULONG_PTR)ImportIID + sizeof IMAGE_IMPORT_DESCRIPTOR); + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(true); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + ImporterCleanup(); + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + } + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + else + { + return(false); + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); +} +__declspec(dllexport) bool __stdcall ImporterMoveOriginalIAT(char* szOriginalFile, char* szDumpFile, char* szSectionName) +{ + + if(ImporterLoadImportTable(szOriginalFile)) + { + return(ImporterExportIATEx(szDumpFile, szSectionName)); + } + return(false); +} +__declspec(dllexport) bool __stdcall ImporterMoveOriginalIATW(wchar_t* szOriginalFile, wchar_t* szDumpFile, char* szSectionName) +{ + + if(ImporterLoadImportTableW(szOriginalFile)) + { + return(ImporterExportIATExW(szDumpFile, szSectionName)); + } + return(false); +} +__declspec(dllexport) void __stdcall ImporterAutoSearchIAT(HANDLE hProcess, char* szFileName, ULONG_PTR ImageBase, ULONG_PTR SearchStart, DWORD SearchSize, LPVOID pIATStart, LPVOID pIATSize) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + + if(szFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + return(ImporterAutoSearchIATW(hProcess, uniFileName, ImageBase, SearchStart, SearchSize, pIATStart, pIATSize)); + } +} +__declspec(dllexport) void __stdcall ImporterAutoSearchIATW(HANDLE hProcess, wchar_t* szFileName, ULONG_PTR ImageBase, ULONG_PTR SearchStart, DWORD SearchSize, LPVOID pIATStart, LPVOID pIATSize) +{ + + int i = NULL; + int j = NULL; + int MaximumBlankSpaces; + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + MEMORY_BASIC_INFORMATION MemInfo; + PMEMORY_COMPARE_HANDLER cmpHandler; + BOOL FileIs64; + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + ULONG_PTR IATThunkSize; + ULONG_PTR SearchStartFO; + ULONG_PTR OriginalSearchStartFO; + LPVOID SearchMemory = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE); + LPVOID memSearchMemory = SearchMemory; + LPVOID CheckMemory = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE); + LPVOID memCheckMemory = CheckMemory; + ULONG_PTR IATThunkPossiblePointer = NULL; + DWORD IATThunkPossiblePointerFO = NULL; + WORD IATCmpNearCall = 0x15FF; + WORD IATCmpNearJump = 0x25FF; + DWORD NtSizeOfImage = NULL; + ULONG_PTR IATHigh = NULL; + ULONG_PTR IATHighestFound = NULL; + ULONG_PTR IATLow = NULL; + ULONG_PTR IATLowestFound = NULL; + ULONG_PTR SearchStartX64 = SearchStart; + DWORD CurrentSearchSize; + char* CompareBuffer[12]; + void* LastValidPtr; + bool ValidPointer; + + RtlZeroMemory(&CompareBuffer, 10 * sizeof ULONG_PTR); + if(MapFileExW(szFileName, UE_ACCESS_READ, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, FileHandle, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + VirtualFree(SearchMemory, NULL, MEM_RELEASE); + VirtualFree(CheckMemory, NULL, MEM_RELEASE); + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return; + } + if(!FileIs64) + { + IATThunkSize = 4; + NtSizeOfImage = PEHeader32->OptionalHeader.SizeOfImage; + } + else + { + IATThunkSize = 8; + NtSizeOfImage = PEHeader64->OptionalHeader.SizeOfImage; + } + SearchStartFO = (ULONG_PTR)ConvertVAtoFileOffset(FileMapVA, SearchStart, true); + OriginalSearchStartFO = SearchStartFO; + if(SearchSize > 0x1000) + { + CurrentSearchSize = 0x1000; + } + else + { + CurrentSearchSize = SearchSize; + } + while(SearchSize > NULL && EngineGrabDataFromMappedFile(FileHandle, FileMapVA, SearchStartFO, CurrentSearchSize, SearchMemory) == true) + { + memSearchMemory = SearchMemory; + i = CurrentSearchSize - 6; + while(i > NULL) + { + if(memcmp(memSearchMemory, &IATCmpNearCall, 2) == NULL || memcmp(memSearchMemory, &IATCmpNearJump, 2) == NULL) + { + RtlMoveMemory(&IATThunkPossiblePointer, (LPVOID)((ULONG_PTR)memSearchMemory + 2), 4); + if(!FileIs64) + { + if(IATThunkPossiblePointer >= (DWORD)ImageBase && IATThunkPossiblePointer <= (DWORD)ImageBase + NtSizeOfImage) + { + if(IATHigh == NULL && IATLow == NULL) + { + IATThunkPossiblePointerFO = (DWORD)ConvertVAtoFileOffset(FileMapVA, IATThunkPossiblePointer, true); + if(IATThunkPossiblePointerFO - FileMapVA > 0x1000 && FileSize - (IATThunkPossiblePointerFO - FileMapVA) > 0x1000) + { + j = NULL; + while(j == NULL) + { + EngineGrabDataFromMappedFile(FileHandle, FileMapVA, IATThunkPossiblePointerFO, 0x1000, CheckMemory); + memCheckMemory = CheckMemory; + LastValidPtr = memCheckMemory; + MaximumBlankSpaces = 4; + ValidPointer = true; + j = 0x1000 - 2 * 4; + while(j > NULL && ValidPointer == true && MaximumBlankSpaces > NULL) + { + if(memcmp(memCheckMemory, &CompareBuffer, sizeof ULONG_PTR) != NULL) + { + cmpHandler = (PMEMORY_COMPARE_HANDLER)memCheckMemory; + VirtualQueryEx(hProcess, (void*)cmpHandler->Array.dwArrayEntry[0], &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + if(MemInfo.State != MEM_COMMIT) + { + ValidPointer = false; + memCheckMemory = LastValidPtr; + } + else + { + LastValidPtr = memCheckMemory; + memCheckMemory = (LPVOID)((ULONG_PTR)memCheckMemory + 4); + MaximumBlankSpaces = 4; + } + } + else + { + memCheckMemory = (LPVOID)((ULONG_PTR)memCheckMemory + 4); + MaximumBlankSpaces--; + } + j = j - 4; + } + IATThunkPossiblePointerFO = IATThunkPossiblePointerFO + 0x1000; + } + if(MaximumBlankSpaces == NULL) + { + memCheckMemory = (LPVOID)((ULONG_PTR)memCheckMemory - (5 * sizeof ULONG_PTR)); + } + IATHigh = (DWORD)ConvertFileOffsetToVA(FileMapVA, IATThunkPossiblePointerFO + (ULONG_PTR)memCheckMemory - (ULONG_PTR)CheckMemory - 0x1000, true); + IATThunkPossiblePointerFO = (DWORD)ConvertVAtoFileOffset(FileMapVA, IATThunkPossiblePointer, true) - 0x1000; + j = NULL; + while(j == NULL) + { + EngineGrabDataFromMappedFile(FileHandle, FileMapVA, IATThunkPossiblePointerFO, 0x1000, CheckMemory); + memCheckMemory = (LPVOID)((ULONG_PTR)CheckMemory + 0x1000 - 8); + LastValidPtr = (LPVOID)((ULONG_PTR)CheckMemory + 0x1000); + MaximumBlankSpaces = 4; + ValidPointer = true; + j = 0x1000 - 2 * 4; + while(j > NULL && ValidPointer == true && MaximumBlankSpaces > NULL) + { + if(memcmp(memCheckMemory, &CompareBuffer, sizeof ULONG_PTR) != NULL) + { + cmpHandler = (PMEMORY_COMPARE_HANDLER)memCheckMemory; + VirtualQueryEx(hProcess, (void*)cmpHandler->Array.dwArrayEntry[0], &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + if(MemInfo.State != MEM_COMMIT) + { + ValidPointer = false; + memCheckMemory = LastValidPtr; + } + else + { + LastValidPtr = memCheckMemory; + memCheckMemory = (LPVOID)((ULONG_PTR)memCheckMemory - 4); + MaximumBlankSpaces = 4; + } + } + else + { + memCheckMemory = (LPVOID)((ULONG_PTR)memCheckMemory - 4); + MaximumBlankSpaces--; + } + j = j - 4; + } + IATThunkPossiblePointerFO = IATThunkPossiblePointerFO - 0x1000; + } + if(MaximumBlankSpaces == NULL) + { + memCheckMemory = (LPVOID)((ULONG_PTR)memCheckMemory + (5 * sizeof ULONG_PTR)); + } + IATLow = (DWORD)ConvertFileOffsetToVA(FileMapVA, IATThunkPossiblePointerFO + (ULONG_PTR)memCheckMemory - (ULONG_PTR)CheckMemory + 0x1000, true); + memSearchMemory = (LPVOID)((ULONG_PTR)memSearchMemory + 6); + i = i - 6; + } + else + { + memSearchMemory = (LPVOID)((ULONG_PTR)memSearchMemory + 2); + i = i - 2; + } + } + else + { + if(IATHighestFound < IATThunkPossiblePointer || IATHighestFound == NULL) + { + if(IATThunkPossiblePointer < IATHigh || IATHighestFound == NULL) + { + IATHighestFound = IATThunkPossiblePointer; + } + } + if(IATLowestFound > IATThunkPossiblePointer || IATLowestFound == NULL) + { + if(IATThunkPossiblePointer > IATLow || IATLowestFound == NULL) + { + IATLowestFound = IATThunkPossiblePointer; + } + } + } + } + else + { + memSearchMemory = (LPVOID)((ULONG_PTR)memSearchMemory + 2); + i = i - 2; + } + } + else + { + SearchStartX64 = SearchStartFO - OriginalSearchStartFO + ((ULONG_PTR)memSearchMemory - (ULONG_PTR)SearchMemory) + SearchStart; + IATThunkPossiblePointer = IATThunkPossiblePointer + SearchStartX64 + 6; + if(IATThunkPossiblePointer >= ImageBase && IATThunkPossiblePointer <= ImageBase + NtSizeOfImage) + { + if(IATHigh == NULL && IATLow == NULL) + { + IATThunkPossiblePointerFO = (DWORD)ConvertVAtoFileOffset(FileMapVA, IATThunkPossiblePointer, true); + if(IATThunkPossiblePointerFO - FileMapVA > 0x1000 && FileSize - (IATThunkPossiblePointerFO - FileMapVA) > 0x1000) + { + j = NULL; + while(j == NULL) + { + EngineGrabDataFromMappedFile(FileHandle, FileMapVA, IATThunkPossiblePointerFO, 0x1000, CheckMemory); + memCheckMemory = CheckMemory; + LastValidPtr = memCheckMemory; + MaximumBlankSpaces = 4; + ValidPointer = true; + j = 0x1000 - 2 * 8; + while(j > NULL && ValidPointer == true && MaximumBlankSpaces > NULL) + { + if(memcmp(memCheckMemory, &CompareBuffer, sizeof ULONG_PTR) != NULL) + { + cmpHandler = (PMEMORY_COMPARE_HANDLER)memCheckMemory; + VirtualQueryEx(hProcess, (void*)cmpHandler->Array.dwArrayEntry[0], &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + if(MemInfo.State != MEM_COMMIT) + { + ValidPointer = false; + memCheckMemory = LastValidPtr; + } + else + { + LastValidPtr = memCheckMemory; + memCheckMemory = (LPVOID)((ULONG_PTR)memCheckMemory + 8); + MaximumBlankSpaces = 4; + } + } + else + { + memCheckMemory = (LPVOID)((ULONG_PTR)memCheckMemory + 8); + MaximumBlankSpaces--; + } + j = j - 8; + } + IATThunkPossiblePointerFO = IATThunkPossiblePointerFO + 0x1000; + } + if(MaximumBlankSpaces == NULL) + { + memCheckMemory = (LPVOID)((ULONG_PTR)memCheckMemory - (5 * sizeof ULONG_PTR)); + } + IATHigh = (DWORD)ConvertFileOffsetToVA(FileMapVA, IATThunkPossiblePointerFO + (ULONG_PTR)memCheckMemory - (ULONG_PTR)CheckMemory - 0x1000, true); + IATThunkPossiblePointerFO = (DWORD)ConvertVAtoFileOffset(FileMapVA, IATThunkPossiblePointer, true) - 0x1000; + j = NULL; + while(j == NULL) + { + EngineGrabDataFromMappedFile(FileHandle, FileMapVA, IATThunkPossiblePointerFO, 0x1000, CheckMemory); + memCheckMemory = (LPVOID)((ULONG_PTR)CheckMemory + 0x1000 - 8); + LastValidPtr = (LPVOID)((ULONG_PTR)CheckMemory + 0x1000); + MaximumBlankSpaces = 4; + ValidPointer = true; + j = 0x1000 - 2 * 8; + while(j > NULL && ValidPointer == true && MaximumBlankSpaces > NULL) + { + if(memcmp(memCheckMemory, &CompareBuffer, sizeof ULONG_PTR) != NULL) + { + cmpHandler = (PMEMORY_COMPARE_HANDLER)memCheckMemory; + VirtualQueryEx(hProcess, (void*)cmpHandler->Array.dwArrayEntry[0], &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + if(MemInfo.State != MEM_COMMIT) + { + ValidPointer = false; + memCheckMemory = LastValidPtr; + } + else + { + LastValidPtr = memCheckMemory; + memCheckMemory = (LPVOID)((ULONG_PTR)memCheckMemory - 8); + MaximumBlankSpaces = 4; + } + } + else + { + memCheckMemory = (LPVOID)((ULONG_PTR)memCheckMemory - 8); + MaximumBlankSpaces--; + } + j = j - 8; + } + IATThunkPossiblePointerFO = IATThunkPossiblePointerFO - 0x1000; + } + if(MaximumBlankSpaces == NULL) + { + memCheckMemory = (LPVOID)((ULONG_PTR)memCheckMemory + (5 * sizeof ULONG_PTR)); + } + IATLow = (DWORD)ConvertFileOffsetToVA(FileMapVA, IATThunkPossiblePointerFO + (ULONG_PTR)memCheckMemory - (ULONG_PTR)CheckMemory + 0x1000, true); + memSearchMemory = (LPVOID)((ULONG_PTR)memSearchMemory + 6); + i = i - 6; + } + else + { + memSearchMemory = (LPVOID)((ULONG_PTR)memSearchMemory + 2); + i = i - 2; + } + } + else + { + if(IATHighestFound < IATThunkPossiblePointer || IATHighestFound == NULL) + { + if(IATThunkPossiblePointer < IATHigh || IATHighestFound == NULL) + { + IATHighestFound = IATThunkPossiblePointer; + } + } + if(IATLowestFound > IATThunkPossiblePointer || IATLowestFound == NULL) + { + if(IATThunkPossiblePointer > IATLow || IATLowestFound == NULL) + { + IATLowestFound = IATThunkPossiblePointer; + } + } + } + } + else + { + memSearchMemory = (LPVOID)((ULONG_PTR)memSearchMemory + 2); + i = i - 2; + } + } + } + memSearchMemory = (LPVOID)((ULONG_PTR)memSearchMemory + 1); + i--; + } + if(SearchSize > 0x1000) + { + SearchSize = SearchSize - 0x1000; + CurrentSearchSize = 0x1000; + } + else + { + SearchSize = NULL; + CurrentSearchSize = SearchSize; + } + SearchStartFO = SearchStartFO + CurrentSearchSize; + } + IATHigh = IATHigh - IATLow + sizeof ULONG_PTR; + RtlMoveMemory(pIATStart, &IATLow, sizeof ULONG_PTR); + RtlMoveMemory(pIATSize, &IATHigh, sizeof ULONG_PTR); + VirtualFree(SearchMemory, NULL, MEM_RELEASE); + VirtualFree(CheckMemory, NULL, MEM_RELEASE); + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return; + } + else + { + VirtualFree(SearchMemory, NULL, MEM_RELEASE); + VirtualFree(CheckMemory, NULL, MEM_RELEASE); + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return; + } + } + VirtualFree(SearchMemory, NULL, MEM_RELEASE); + VirtualFree(CheckMemory, NULL, MEM_RELEASE); + return; +} +__declspec(dllexport) void __stdcall ImporterAutoSearchIATEx(HANDLE hProcess, ULONG_PTR ImageBase, ULONG_PTR SearchStart, DWORD SearchSize, LPVOID pIATStart, LPVOID pIATSize) +{ + + wchar_t szTempName[MAX_PATH]; + wchar_t szTempFolder[MAX_PATH]; + + RtlZeroMemory(&szTempName, sizeof szTempName); + RtlZeroMemory(&szTempFolder, sizeof szTempFolder); + if(GetTempPathW(MAX_PATH, szTempFolder) < MAX_PATH) + { + if(GetTempFileNameW(szTempFolder, L"DumpTemp", GetTickCount() + 102, szTempName)) + { + DumpProcessW(hProcess, (LPVOID)ImageBase, szTempName, NULL); + ImporterAutoSearchIATW(hProcess, szTempName, ImageBase, SearchStart, SearchSize, pIATStart, pIATSize); + DeleteFileW(szTempName); + } + } +} +__declspec(dllexport) void __stdcall ImporterEnumAddedData(LPVOID EnumCallBack) +{ + + int i = 0; + int j = 0; + int x = 0; + bool OrdinalImport; + DWORD DLLNumber = NULL; + DWORD NumberOfAPIs = NULL; + LPVOID NameReadPlace = NULL; + ULONG_PTR CurrentAPILocation = NULL; + DWORD APINameRelativeOffset = NULL; + typedef void(__stdcall *fEnumCallBack)(LPVOID fImportDetail); + fEnumCallBack myEnumCallBack = (fEnumCallBack)EnumCallBack; + ImportEnumData myImportEnumData; + char szOrdinalAPIName[MAX_PATH]; + + if(EnumCallBack != NULL && ImporterGetAddedDllCount() > NULL) + { + DLLNumber = impDLLNumber + 1; + while(DLLNumber > NULL) + { +#if !defined(_WIN64) + NameReadPlace = (LPVOID)(impDLLDataList[i][0] + 12); +#else + NameReadPlace = (LPVOID)(impDLLDataList[i][0] + 20); +#endif + RtlMoveMemory(&CurrentAPILocation, (LPVOID)(impDLLDataList[i][0]), sizeof ULONG_PTR); + RtlMoveMemory(&NumberOfAPIs, (LPVOID)(impDLLDataList[i][0] + 2 * sizeof ULONG_PTR), 4); + RtlZeroMemory(&myImportEnumData, sizeof ImportEnumData); + myImportEnumData.NumberOfImports = (int)(NumberOfAPIs - 1); + myImportEnumData.BaseImportThunk = CurrentAPILocation; + myImportEnumData.ImageBase = impImageBase; + myImportEnumData.NewDll = true; + while(NumberOfAPIs > 1) + { + RtlMoveMemory(&APINameRelativeOffset, NameReadPlace, 4); + myImportEnumData.ImportThunk = CurrentAPILocation; + OrdinalImport = false; + for(j = 0; j < 1000; j++) + { + if(impOrdinalList[j][0] == CurrentAPILocation) + { + OrdinalImport = true; + x = j; + j = 1000; + } + else if(impOrdinalList[j][0] == NULL) + { + j = 1000; + } + } + if(OrdinalImport) + { + wsprintfA(szOrdinalAPIName, "%08X", impOrdinalList[x][1] & IMAGE_ORDINAL_FLAG); + myImportEnumData.APIName = (char*)(szOrdinalAPIName); + } + else + { + myImportEnumData.APIName = (char*)((ULONG_PTR)impDLLStringList[i][0] + APINameRelativeOffset + 2); + } + myImportEnumData.DLLName = (char*)((ULONG_PTR)impDLLStringList[i][0]); + __try + { + myEnumCallBack(&myImportEnumData); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + NumberOfAPIs = 2; + } + myImportEnumData.NewDll = false; + CurrentAPILocation = CurrentAPILocation + sizeof ULONG_PTR; + NameReadPlace = (LPVOID)((ULONG_PTR)NameReadPlace + sizeof ULONG_PTR); + NumberOfAPIs--; + } + DLLNumber--; + i++; + } + } +} +__declspec(dllexport) long __stdcall ImporterAutoFixIATEx(HANDLE hProcess, char* szDumpedFile, char* szSectionName, bool DumpRunningProcess, bool RealignFile, ULONG_PTR EntryPointAddress, ULONG_PTR ImageBase, ULONG_PTR SearchStart, DWORD SearchSize, DWORD SearchStep, bool TryAutoFix, bool FixEliminations, LPVOID UnknownPointerFixCallback) +{ + + wchar_t uniDumpedFile[MAX_PATH] = {}; + + if(szDumpedFile != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szDumpedFile, lstrlenA(szDumpedFile)+1, uniDumpedFile, sizeof(uniDumpedFile)/(sizeof(uniDumpedFile[0]))); + return(ImporterAutoFixIATExW(hProcess, uniDumpedFile, szSectionName, DumpRunningProcess, RealignFile, EntryPointAddress, ImageBase, SearchStart, SearchSize, SearchStep, TryAutoFix, FixEliminations, UnknownPointerFixCallback)); + } + else + { + return(NULL); // Critical error! *just to be safe, but it should never happen! + } +} +__declspec(dllexport) long __stdcall ImporterAutoFixIATExW(HANDLE hProcess, wchar_t* szDumpedFile, char* szSectionName, bool DumpRunningProcess, bool RealignFile, ULONG_PTR EntryPointAddress, ULONG_PTR ImageBase, ULONG_PTR SearchStart, DWORD SearchSize, DWORD SearchStep, bool TryAutoFix, bool FixEliminations, LPVOID UnknownPointerFixCallback) +{ + + int i; + int j; + int delta; + int currentSectionSize; +#if !defined(_WIN64) + PE32Struct PEStructure; +#else + PE64Struct PEStructure; +#endif + typedef void*(__stdcall *fFixerCallback)(LPVOID fIATPointer); + fFixerCallback myFixerCallback = (fFixerCallback)UnknownPointerFixCallback; + MEMORY_BASIC_INFORMATION MemInfo; + DWORD SectionFlags; + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + LPVOID aSearchMemory; + LPVOID cSearchMemory; + LPVOID aEnumeratedModules; + ULONG_PTR ueNumberOfBytesRead; + DWORD dwPossibleIATPointer; + ULONG_PTR qwPossibleIATPointer; + ULONG_PTR PossibleIATPointer; + ULONG_PTR TracedIATPointer; + PMEMORY_COMPARE_HANDLER currentSearchPos; + DWORD SetionVirtualOffset; + ULONG_PTR TestReadData; + DWORD LastDllId = 1024; + bool FileIs64 = false; + bool PossibleThunk = false; + bool UpdateJump = false; + DWORD CurrentDllId; + char* szDLLName; + char* szAPIName; + DWORD TraceIndex; + DWORD Dummy; + + if(hProcess == NULL) + { + return(0x401); // Error, process terminated + } + if(SearchStep == NULL) + { + SearchStep++; + } + if(DumpRunningProcess) + { + if(!DumpProcessW(hProcess, (LPVOID)ImageBase, szDumpedFile, EntryPointAddress)) + { + return(NULL); // Critical error! *just to be safe, but it should never happen! + } + } + + aEnumeratedModules = VirtualAlloc(NULL, 0x2000, MEM_COMMIT, PAGE_READWRITE); + if(EnumProcessModules(hProcess, (HMODULE*)aEnumeratedModules, 0x2000, &Dummy)) + { + aSearchMemory = VirtualAlloc(NULL, SearchSize, MEM_COMMIT, PAGE_READWRITE); + cSearchMemory = aSearchMemory; + __try + { + if(SearchStart == NULL || ReadProcessMemory(hProcess, (LPVOID)SearchStart, aSearchMemory, SearchSize, &ueNumberOfBytesRead)) + { + ImporterInit(MAX_IMPORT_ALLOC, ImageBase); + if(SearchStart != NULL) + { + //SearchSize = SearchSize / SearchStep; + while((int)SearchSize > NULL) + { + RtlMoveMemory(&PossibleIATPointer, cSearchMemory, sizeof ULONG_PTR); + if(ReadProcessMemory(hProcess, (LPVOID)PossibleIATPointer, &TestReadData, sizeof ULONG_PTR, &ueNumberOfBytesRead)) + { + //CurrentDllId = ImporterGetDLLIndexEx(PossibleIATPointer, (ULONG_PTR)aEnumeratedModules); + CurrentDllId = ImporterGetDLLIndex(hProcess, PossibleIATPointer, (ULONG_PTR)aEnumeratedModules); + if(CurrentDllId == NULL && TryAutoFix == true) + { + TraceIndex = TracerDetectRedirection(hProcess, PossibleIATPointer); + if(TraceIndex > NULL) + { + PossibleIATPointer = (ULONG_PTR)TracerFixKnownRedirection(hProcess, PossibleIATPointer, TraceIndex); + if(PossibleIATPointer != NULL) + { + //CurrentDllId = ImporterGetDLLIndexEx(PossibleIATPointer, (ULONG_PTR)aEnumeratedModules); + CurrentDllId = ImporterGetDLLIndex(hProcess, PossibleIATPointer, (ULONG_PTR)aEnumeratedModules); + } + } + else + { + TracedIATPointer = (ULONG_PTR)TracerLevel1(hProcess, PossibleIATPointer); + if(TracedIATPointer > 0x1000) + { + PossibleIATPointer = TracedIATPointer; + //CurrentDllId = ImporterGetDLLIndexEx(PossibleIATPointer, (ULONG_PTR)aEnumeratedModules); + CurrentDllId = ImporterGetDLLIndex(hProcess, PossibleIATPointer, (ULONG_PTR)aEnumeratedModules); + } + else + { + if(TracedIATPointer != NULL) + { + TracedIATPointer = (ULONG_PTR)HashTracerLevel1(hProcess, PossibleIATPointer, (DWORD)TracedIATPointer); + if(TracedIATPointer != NULL) + { + PossibleIATPointer = TracedIATPointer; + //CurrentDllId = ImporterGetDLLIndexEx(PossibleIATPointer, (ULONG_PTR)aEnumeratedModules); + CurrentDllId = ImporterGetDLLIndex(hProcess, PossibleIATPointer, (ULONG_PTR)aEnumeratedModules); + } + } + } + } + } + if(CurrentDllId == NULL && UnknownPointerFixCallback != NULL) + { + __try + { + PossibleIATPointer = (ULONG_PTR)myFixerCallback((LPVOID)PossibleIATPointer); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + UnknownPointerFixCallback = NULL; + PossibleIATPointer = NULL; + } + if(PossibleIATPointer != NULL) + { + //CurrentDllId = ImporterGetDLLIndexEx(PossibleIATPointer, (ULONG_PTR)aEnumeratedModules); + CurrentDllId = ImporterGetDLLIndex(hProcess, PossibleIATPointer, (ULONG_PTR)aEnumeratedModules); + } + } + if(CurrentDllId != NULL) + { + if(LastDllId != CurrentDllId) + { + LastDllId = CurrentDllId; + szDLLName = (char*)ImporterGetDLLNameFromDebugee(hProcess, PossibleIATPointer); + szAPIName = (char*)ImporterGetAPINameFromDebugee(hProcess, PossibleIATPointer); + if(szDLLName != NULL && szAPIName != NULL) + { + ImporterAddNewDll(szDLLName, (ULONG_PTR)((ULONG_PTR)cSearchMemory - (ULONG_PTR)aSearchMemory + SearchStart)); + ImporterAddNewAPI(szAPIName, (ULONG_PTR)((ULONG_PTR)cSearchMemory - (ULONG_PTR)aSearchMemory + SearchStart)); + } + else if(szDLLName != NULL && szAPIName == NULL) + { + ImporterAddNewDll(szDLLName, (ULONG_PTR)((ULONG_PTR)cSearchMemory - (ULONG_PTR)aSearchMemory + SearchStart)); + ImporterAddNewAPI((char*)ImporterGetAPIOrdinalNumberFromDebugee(hProcess, PossibleIATPointer), (ULONG_PTR)((ULONG_PTR)cSearchMemory - (ULONG_PTR)aSearchMemory + SearchStart)); + } + } + else + { + szAPIName = (char*)ImporterGetAPINameFromDebugee(hProcess, PossibleIATPointer); + if(szAPIName != NULL) + { + ImporterAddNewAPI(szAPIName, (ULONG_PTR)((ULONG_PTR)cSearchMemory - (ULONG_PTR)aSearchMemory + SearchStart)); + } + else + { + szAPIName = (char*)ImporterGetAPIOrdinalNumberFromDebugee(hProcess, PossibleIATPointer); + if(szAPIName != NULL) + { + ImporterAddNewAPI(szAPIName, (ULONG_PTR)((ULONG_PTR)cSearchMemory - (ULONG_PTR)aSearchMemory + SearchStart)); + } + } + } + } + } + else + { + if(PossibleIATPointer == NULL) + { + LastDllId = NULL; + } + } + cSearchMemory = (LPVOID)((ULONG_PTR)cSearchMemory + SearchStep); + SearchSize = SearchSize - SearchStep; + } + } + if(FixEliminations) + { + LastDllId = 1024; + if(ImporterGetAddedDllCount() == NULL) + { + ImporterCleanup(); + ImporterInit(MAX_IMPORT_ALLOC, ImageBase); + } + if(GetPE32DataExW(szDumpedFile, &PEStructure)) + { + if(MapFileExW(szDumpedFile, UE_ACCESS_ALL, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + ImporterMoveIAT(); + ImporterSetUnknownDelta((ULONG_PTR)EngineEstimateNewSectionRVA(FileMapVA)); + for(i = 0; i < PEStructure.SectionNumber; i++) + { + if(GetPE32DataFromMappedFile(FileMapVA, i, UE_SECTIONRAWSIZE) > 4) + { + SectionFlags = (DWORD)GetPE32DataFromMappedFile(FileMapVA, i, UE_SECTIONFLAGS); + SetionVirtualOffset = (DWORD)GetPE32DataFromMappedFile(FileMapVA, i, UE_SECTIONVIRTUALOFFSET); + if(SectionFlags & IMAGE_SCN_MEM_EXECUTE || SectionFlags & IMAGE_SCN_CNT_CODE || SectionFlags & IMAGE_SCN_MEM_WRITE || SectionFlags & IMAGE_SCN_CNT_INITIALIZED_DATA) + { + currentSearchPos = (PMEMORY_COMPARE_HANDLER)(FileMapVA + GetPE32DataFromMappedFile(FileMapVA, i, UE_SECTIONRAWOFFSET)); + currentSectionSize = (int)GetPE32DataFromMappedFile(FileMapVA, i, UE_SECTIONRAWSIZE) - 6; + for(j = 0; j < currentSectionSize; j++) + { + if(!FileIs64) + { + // x86 + delta = 0; + PossibleThunk = false; + UpdateJump = false; + if(currentSearchPos->Array.bArrayEntry[0] == 0xFF && (currentSearchPos->Array.bArrayEntry[1] == 0x15 || currentSearchPos->Array.bArrayEntry[1] == 0x25)) + { + currentSearchPos = (PMEMORY_COMPARE_HANDLER)((ULONG_PTR)currentSearchPos + 2); + PossibleIATPointer = currentSearchPos->Array.dwArrayEntry[0]; + currentSearchPos = (PMEMORY_COMPARE_HANDLER)((ULONG_PTR)currentSearchPos - 2); + if(PossibleIATPointer > PEStructure.ImageBase && PossibleIATPointer < PEStructure.ImageBase + PEStructure.NtSizeOfImage) + { + PossibleThunk = true; + delta = 2; + } + else + { + VirtualQueryEx(hProcess, (LPVOID)PossibleIATPointer, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + if(MemInfo.State == MEM_COMMIT && (MemInfo.Protect & PAGE_READWRITE || MemInfo.Protect & PAGE_EXECUTE_READWRITE || MemInfo.Protect & PAGE_EXECUTE)) + { + PossibleIATPointer = currentSearchPos->Array.dwArrayEntry[0]; + PossibleThunk = true; + delta = 2; + } + } + } + else if(currentSearchPos->Array.bArrayEntry[0] == 0xE8 || currentSearchPos->Array.bArrayEntry[0] == 0xE9) + { + currentSearchPos = (PMEMORY_COMPARE_HANDLER)((ULONG_PTR)currentSearchPos + 1); + PossibleIATPointer = currentSearchPos->Array.dwArrayEntry[0] + j + SetionVirtualOffset + ImageBase; + currentSearchPos = (PMEMORY_COMPARE_HANDLER)((ULONG_PTR)currentSearchPos - 1); + if(PossibleIATPointer > PEStructure.ImageBase && PossibleIATPointer < PEStructure.ImageBase + PEStructure.NtSizeOfImage) + { + PossibleThunk = true; + UpdateJump = true; + delta = 1; + } + else + { + VirtualQueryEx(hProcess, (LPVOID)PossibleIATPointer, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + if(MemInfo.State == MEM_COMMIT && (MemInfo.Protect & PAGE_READWRITE || MemInfo.Protect & PAGE_EXECUTE_READWRITE || MemInfo.Protect & PAGE_EXECUTE)) + { + PossibleIATPointer = currentSearchPos->Array.dwArrayEntry[0]; + PossibleThunk = true; + UpdateJump = true; + delta = 1; + } + } + } + else if(currentSearchPos->Array.dwArrayEntry[0] > PEStructure.ImageBase && currentSearchPos->Array.dwArrayEntry[0] < PEStructure.ImageBase + PEStructure.NtSizeOfImage) + { + PossibleIATPointer = currentSearchPos->Array.dwArrayEntry[0]; + PossibleThunk = true; + delta = 0; + } + else + { + VirtualQueryEx(hProcess, (LPVOID)currentSearchPos->Array.dwArrayEntry[0], &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + if(MemInfo.State == MEM_COMMIT && (MemInfo.Protect & PAGE_READWRITE || MemInfo.Protect & PAGE_EXECUTE_READWRITE || MemInfo.Protect & PAGE_EXECUTE)) + { + PossibleIATPointer = currentSearchPos->Array.dwArrayEntry[0]; + PossibleThunk = true; + delta = 0; + } + } + if(PossibleThunk) + { + if(ReadProcessMemory(hProcess, (LPVOID)PossibleIATPointer, &dwPossibleIATPointer, 4, &ueNumberOfBytesRead)) + { + VirtualQueryEx(hProcess, (LPVOID)dwPossibleIATPointer, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + if(MemInfo.State == MEM_COMMIT && (MemInfo.Protect >= PAGE_READONLY || MemInfo.Protect <= PAGE_EXECUTE_READWRITE)) + { + PossibleIATPointer = (ULONG_PTR)dwPossibleIATPointer; + //CurrentDllId = ImporterGetDLLIndexEx(PossibleIATPointer, (ULONG_PTR)aEnumeratedModules); + CurrentDllId = ImporterGetDLLIndex(hProcess, PossibleIATPointer, (ULONG_PTR)aEnumeratedModules); + if(CurrentDllId == NULL && TryAutoFix == true) + { + TraceIndex = TracerDetectRedirection(hProcess, PossibleIATPointer); + if(TraceIndex > NULL) + { + PossibleIATPointer = (ULONG_PTR)TracerFixKnownRedirection(hProcess, PossibleIATPointer, TraceIndex); + if(PossibleIATPointer != NULL) + { + //CurrentDllId = ImporterGetDLLIndexEx(PossibleIATPointer, (ULONG_PTR)aEnumeratedModules); + CurrentDllId = ImporterGetDLLIndex(hProcess, PossibleIATPointer, (ULONG_PTR)aEnumeratedModules); + } + } + else + { + TracedIATPointer = (ULONG_PTR)TracerLevel1(hProcess, PossibleIATPointer); + if(TracedIATPointer > 0x1000) + { + PossibleIATPointer = TracedIATPointer; + //CurrentDllId = ImporterGetDLLIndexEx(PossibleIATPointer, (ULONG_PTR)aEnumeratedModules); + CurrentDllId = ImporterGetDLLIndex(hProcess, PossibleIATPointer, (ULONG_PTR)aEnumeratedModules); + } + else + { + if(TracedIATPointer != NULL) + { + TracedIATPointer = (ULONG_PTR)HashTracerLevel1(hProcess, PossibleIATPointer, (DWORD)TracedIATPointer); + if(TracedIATPointer != NULL) + { + PossibleIATPointer = TracedIATPointer; + //CurrentDllId = ImporterGetDLLIndexEx(PossibleIATPointer, (ULONG_PTR)aEnumeratedModules); + CurrentDllId = ImporterGetDLLIndex(hProcess, PossibleIATPointer, (ULONG_PTR)aEnumeratedModules); + } + } + } + } + } + if(CurrentDllId == NULL && UnknownPointerFixCallback != NULL) + { + __try + { + PossibleIATPointer = (ULONG_PTR)myFixerCallback((LPVOID)PossibleIATPointer); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + UnknownPointerFixCallback = NULL; + PossibleIATPointer = NULL; + } + if(PossibleIATPointer != NULL) + { + //CurrentDllId = ImporterGetDLLIndexEx(PossibleIATPointer, (ULONG_PTR)aEnumeratedModules); + CurrentDllId = ImporterGetDLLIndex(hProcess, PossibleIATPointer, (ULONG_PTR)aEnumeratedModules); + } + } + if(CurrentDllId != NULL) + { + szDLLName = (char*)ImporterGetDLLNameFromDebugee(hProcess, PossibleIATPointer); + szAPIName = (char*)ImporterGetAPINameFromDebugee(hProcess, PossibleIATPointer); + if(szAPIName == NULL) + { + szAPIName = (char*)ImporterGetAPIOrdinalNumberFromDebugee(hProcess, PossibleIATPointer); + } + if(szDLLName != NULL && szAPIName != NULL) + { + if(ImporterGetAddedDllCount() > NULL) + { + PossibleIATPointer = (ULONG_PTR)ImporterFindAPIWriteLocation(szAPIName); + } + else + { + PossibleIATPointer = NULL; + } + if(PossibleIATPointer != NULL) + { + dwPossibleIATPointer = (DWORD)(PossibleIATPointer); + if(!UpdateJump) + { + RtlMoveMemory(¤tSearchPos->Array.dwArrayEntry[0 + delta], &dwPossibleIATPointer, 4); + } + else + { + dwPossibleIATPointer = dwPossibleIATPointer - (j + SetionVirtualOffset) - (DWORD)ImageBase - 5; + RtlMoveMemory(¤tSearchPos->Array.dwArrayEntry[0 + delta], &dwPossibleIATPointer, 4); + } + currentSearchPos = (PMEMORY_COMPARE_HANDLER)((ULONG_PTR)currentSearchPos + delta + 4 - 1); + } + else + { + if(CurrentDllId != LastDllId) + { + LastDllId = CurrentDllId; + ImporterAddNewDll(szDLLName, NULL); + dwPossibleIATPointer = (DWORD)(ImporterGetCurrentDelta()); + if(!UpdateJump) + { + RtlMoveMemory(¤tSearchPos->Array.dwArrayEntry[0 + delta], &dwPossibleIATPointer, 4); + } + else + { + dwPossibleIATPointer = dwPossibleIATPointer - (j + SetionVirtualOffset) - (DWORD)ImageBase - 5; + RtlMoveMemory(¤tSearchPos->Array.dwArrayEntry[0 + delta], &dwPossibleIATPointer, 4); + } + ImporterAddNewAPI(szAPIName, NULL); + currentSearchPos = (PMEMORY_COMPARE_HANDLER)((ULONG_PTR)currentSearchPos + delta + 4 - 1); + } + else + { + dwPossibleIATPointer = (DWORD)(ImporterGetCurrentDelta()); + if(!UpdateJump) + { + RtlMoveMemory(¤tSearchPos->Array.dwArrayEntry[0 + delta], &dwPossibleIATPointer, 4); + } + else + { + dwPossibleIATPointer = dwPossibleIATPointer - (j + SetionVirtualOffset) - (DWORD)ImageBase - 5; + RtlMoveMemory(¤tSearchPos->Array.dwArrayEntry[0 + delta], &dwPossibleIATPointer, 4); + } + ImporterAddNewAPI(szAPIName, NULL); + currentSearchPos = (PMEMORY_COMPARE_HANDLER)((ULONG_PTR)currentSearchPos + delta + 4 - 1); + } + } + } + } + } + } + else + { + if(PossibleIATPointer == NULL) + { + LastDllId = NULL; + } + } + } + } + else + { + // x64 + delta = 0; + PossibleThunk = false; + UpdateJump = false; + if(currentSearchPos->Array.bArrayEntry[0] == 0xFF && (currentSearchPos->Array.bArrayEntry[1] == 0x15 || currentSearchPos->Array.bArrayEntry[1] == 0x25)) + { + currentSearchPos = (PMEMORY_COMPARE_HANDLER)((ULONG_PTR)currentSearchPos + 2); + PossibleIATPointer = currentSearchPos->Array.dwArrayEntry[0] + j + SetionVirtualOffset + ImageBase; + currentSearchPos = (PMEMORY_COMPARE_HANDLER)((ULONG_PTR)currentSearchPos - 2); + if(PossibleIATPointer > PEStructure.ImageBase && PossibleIATPointer < PEStructure.ImageBase + PEStructure.NtSizeOfImage) + { + PossibleThunk = true; + delta = 2; + } + else + { + VirtualQueryEx(hProcess, (LPVOID)PossibleIATPointer, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + if(MemInfo.State == MEM_COMMIT && (MemInfo.Protect & PAGE_READWRITE || MemInfo.Protect & PAGE_EXECUTE_READWRITE || MemInfo.Protect & PAGE_EXECUTE)) + { + PossibleIATPointer = currentSearchPos->Array.dwArrayEntry[0]; + PossibleThunk = true; + delta = 2; + } + } + } + else if(currentSearchPos->Array.bArrayEntry[0] == 0xE8 || currentSearchPos->Array.bArrayEntry[0] == 0xE9) + { + currentSearchPos = (PMEMORY_COMPARE_HANDLER)((ULONG_PTR)currentSearchPos + 1); + PossibleIATPointer = currentSearchPos->Array.dwArrayEntry[0] + j + SetionVirtualOffset + ImageBase; + currentSearchPos = (PMEMORY_COMPARE_HANDLER)((ULONG_PTR)currentSearchPos - 1); + if(PossibleIATPointer > PEStructure.ImageBase && PossibleIATPointer < PEStructure.ImageBase + PEStructure.NtSizeOfImage) + { + PossibleThunk = true; + UpdateJump = true; + delta = 1; + } + else + { + VirtualQueryEx(hProcess, (LPVOID)PossibleIATPointer, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + if(MemInfo.State == MEM_COMMIT && (MemInfo.Protect & PAGE_READWRITE || MemInfo.Protect & PAGE_EXECUTE_READWRITE || MemInfo.Protect & PAGE_EXECUTE)) + { + PossibleIATPointer = currentSearchPos->Array.dwArrayEntry[0]; + PossibleThunk = true; + UpdateJump = true; + delta = 1; + } + } + } + else if(currentSearchPos->Array.dwArrayEntry[0] + j + SetionVirtualOffset > PEStructure.ImageBase && currentSearchPos->Array.dwArrayEntry[0] + j + SetionVirtualOffset < PEStructure.ImageBase + PEStructure.NtSizeOfImage) + { + PossibleIATPointer = currentSearchPos->Array.dwArrayEntry[0] + j + SetionVirtualOffset + ImageBase; + PossibleThunk = true; + delta = 0; + } + else + { + VirtualQueryEx(hProcess, (LPVOID)(currentSearchPos->Array.dwArrayEntry[0] + j + SetionVirtualOffset), &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + if(MemInfo.State == MEM_COMMIT && (MemInfo.Protect & PAGE_READWRITE || MemInfo.Protect & PAGE_EXECUTE_READWRITE || MemInfo.Protect & PAGE_EXECUTE)) + { + PossibleIATPointer = currentSearchPos->Array.dwArrayEntry[0] + j + SetionVirtualOffset + ImageBase; + PossibleThunk = true; + delta = 0; + } + } + if(PossibleThunk) + { + if(ReadProcessMemory(hProcess, (LPVOID)PossibleIATPointer, &qwPossibleIATPointer, 8, &ueNumberOfBytesRead)) + { + VirtualQueryEx(hProcess, (LPVOID)qwPossibleIATPointer, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + if(MemInfo.State == MEM_COMMIT && (MemInfo.Protect >= PAGE_READONLY || MemInfo.Protect <= PAGE_EXECUTE_READWRITE)) + { + PossibleIATPointer = qwPossibleIATPointer; + //CurrentDllId = ImporterGetDLLIndexEx(PossibleIATPointer, (ULONG_PTR)aEnumeratedModules); + CurrentDllId = ImporterGetDLLIndex(hProcess, PossibleIATPointer, (ULONG_PTR)aEnumeratedModules); + if(CurrentDllId == NULL && TryAutoFix == true) + { + TraceIndex = TracerDetectRedirection(hProcess, PossibleIATPointer); + if(TraceIndex > NULL) + { + PossibleIATPointer = (ULONG_PTR)TracerFixKnownRedirection(hProcess, PossibleIATPointer, TraceIndex); + if(PossibleIATPointer != NULL) + { + //CurrentDllId = ImporterGetDLLIndexEx(PossibleIATPointer, (ULONG_PTR)aEnumeratedModules); + CurrentDllId = ImporterGetDLLIndex(hProcess, PossibleIATPointer, (ULONG_PTR)aEnumeratedModules); + } + } + else + { + TracedIATPointer = (ULONG_PTR)TracerLevel1(hProcess, PossibleIATPointer); + if(TracedIATPointer > 0x1000) + { + PossibleIATPointer = TracedIATPointer; + //CurrentDllId = ImporterGetDLLIndexEx(PossibleIATPointer, (ULONG_PTR)aEnumeratedModules); + CurrentDllId = ImporterGetDLLIndex(hProcess, PossibleIATPointer, (ULONG_PTR)aEnumeratedModules); + } + else + { + if(TracedIATPointer != NULL) + { + TracedIATPointer = (ULONG_PTR)HashTracerLevel1(hProcess, PossibleIATPointer, (DWORD)TracedIATPointer); + if(TracedIATPointer != NULL) + { + PossibleIATPointer = TracedIATPointer; + //CurrentDllId = ImporterGetDLLIndexEx(PossibleIATPointer, (ULONG_PTR)aEnumeratedModules); + CurrentDllId = ImporterGetDLLIndex(hProcess, PossibleIATPointer, (ULONG_PTR)aEnumeratedModules); + } + } + } + } + } + if(CurrentDllId == NULL && UnknownPointerFixCallback != NULL) + { + __try + { + PossibleIATPointer = (ULONG_PTR)myFixerCallback((LPVOID)PossibleIATPointer); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + UnknownPointerFixCallback = NULL; + PossibleIATPointer = NULL; + } + if(PossibleIATPointer != NULL) + { + //CurrentDllId = ImporterGetDLLIndexEx(PossibleIATPointer, (ULONG_PTR)aEnumeratedModules); + CurrentDllId = ImporterGetDLLIndex(hProcess, PossibleIATPointer, (ULONG_PTR)aEnumeratedModules); + } + } + if(CurrentDllId != NULL) + { + szDLLName = (char*)ImporterGetDLLNameFromDebugee(hProcess, PossibleIATPointer); + szAPIName = (char*)ImporterGetAPINameFromDebugee(hProcess, PossibleIATPointer); + if(szAPIName == NULL) + { + szAPIName = (char*)ImporterGetAPIOrdinalNumberFromDebugee(hProcess, PossibleIATPointer); + } + if(szDLLName != NULL && szAPIName != NULL) + { + if(ImporterGetAddedDllCount() > NULL) + { + PossibleIATPointer = (ULONG_PTR)ImporterFindAPIWriteLocation(szAPIName); + } + else + { + PossibleIATPointer = NULL; + } + if(PossibleIATPointer != NULL) + { + if(!UpdateJump) + { + dwPossibleIATPointer = (DWORD)(PossibleIATPointer - j - SetionVirtualOffset - ImageBase); + RtlMoveMemory(¤tSearchPos->Array.dwArrayEntry[0 + delta], &dwPossibleIATPointer, 4); + } + else + { + dwPossibleIATPointer = (DWORD)(PossibleIATPointer); + dwPossibleIATPointer = (DWORD)(dwPossibleIATPointer - (j + SetionVirtualOffset) - (ULONG_PTR)ImageBase - 5); + RtlMoveMemory(¤tSearchPos->Array.dwArrayEntry[0 + delta], &dwPossibleIATPointer, 4); + } + currentSearchPos = (PMEMORY_COMPARE_HANDLER)((ULONG_PTR)currentSearchPos + delta + 4 - 1); + } + else + { + if(CurrentDllId != LastDllId) + { + LastDllId = CurrentDllId; + ImporterAddNewDll(szDLLName, NULL); + qwPossibleIATPointer = (ULONG_PTR)(ImporterGetCurrentDelta()); + if(!UpdateJump) + { + qwPossibleIATPointer = (DWORD)(qwPossibleIATPointer - j - SetionVirtualOffset - ImageBase); + RtlMoveMemory(¤tSearchPos->Array.dwArrayEntry[0 + delta], &qwPossibleIATPointer, 4); + } + else + { + qwPossibleIATPointer = (DWORD)(qwPossibleIATPointer - j - SetionVirtualOffset - ImageBase - 5); + RtlMoveMemory(¤tSearchPos->Array.dwArrayEntry[0 + delta], &qwPossibleIATPointer, 4); + } + ImporterAddNewAPI(szAPIName, NULL); + currentSearchPos = (PMEMORY_COMPARE_HANDLER)((ULONG_PTR)currentSearchPos + delta + 4 - 1); + } + else + { + qwPossibleIATPointer = (ULONG_PTR)(ImporterGetCurrentDelta()); + if(!UpdateJump) + { + qwPossibleIATPointer = (DWORD)(qwPossibleIATPointer - j - SetionVirtualOffset - ImageBase); + RtlMoveMemory(¤tSearchPos->Array.dwArrayEntry[0 + delta], &qwPossibleIATPointer, 4); + } + else + { + qwPossibleIATPointer = (DWORD)(qwPossibleIATPointer - j - SetionVirtualOffset - ImageBase - 5); + RtlMoveMemory(¤tSearchPos->Array.dwArrayEntry[0 + delta], &qwPossibleIATPointer, 4); + } + ImporterAddNewAPI(szAPIName, NULL); + currentSearchPos = (PMEMORY_COMPARE_HANDLER)((ULONG_PTR)currentSearchPos + delta + 4 - 1); + } + } + } + } + } + } + else + { + if(PossibleIATPointer == NULL) + { + LastDllId = NULL; + } + } + } + } + currentSearchPos = (PMEMORY_COMPARE_HANDLER)((ULONG_PTR)currentSearchPos + 1); + } + } + } + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + } + else + { + return(0x405); // Error, no API found! + } + } + } + VirtualFree(aEnumeratedModules, NULL, MEM_RELEASE); + VirtualFree(aSearchMemory, NULL, MEM_RELEASE); + if(ImporterGetAddedDllCount() > NULL && ImporterGetAddedAPICount() > NULL) + { + if(!ImporterExportIATExW(szDumpedFile, szSectionName)) + { + return(NULL); // Critical error! *just to be safe, but it should never happen! + } + } + else + { + return(0x405); // Error, no API found! + } + if(RealignFile) + { + if(MapFileExW(szDumpedFile, UE_ACCESS_ALL, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + FileSize = RealignPE(FileMapVA, FileSize, NULL); + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + } + else + { + return(0x406); // Success, but realign failed! + } + } + return(0x400); // Success! + } + else + { + VirtualFree(aEnumeratedModules, NULL, MEM_RELEASE); + VirtualFree(aSearchMemory, NULL, MEM_RELEASE); + return(0x404); // Error, memory could not be read! + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + ImporterCleanup(); + VirtualFree(aEnumeratedModules, NULL, MEM_RELEASE); + VirtualFree(aSearchMemory, NULL, MEM_RELEASE); + return(NULL); // Critical error! *just to be safe, but it should never happen! + } + } + VirtualFree(aEnumeratedModules, NULL, MEM_RELEASE); + return(NULL); // Critical error! *just te bo safe, but it should never happen! +} +__declspec(dllexport) long __stdcall ImporterAutoFixIAT(HANDLE hProcess, char* szDumpedFile, ULONG_PTR ImageBase, ULONG_PTR SearchStart, DWORD SearchSize, DWORD SearchStep) +{ + return(ImporterAutoFixIATEx(hProcess, szDumpedFile, ".RL!TEv2", false, false, NULL, ImageBase, SearchStart, SearchSize, SearchStep, false, false, NULL)); +} +__declspec(dllexport) long __stdcall ImporterAutoFixIATW(HANDLE hProcess, wchar_t* szDumpedFile, ULONG_PTR ImageBase, ULONG_PTR SearchStart, DWORD SearchSize, DWORD SearchStep) +{ + return(ImporterAutoFixIATExW(hProcess, szDumpedFile, ".RL!TEv2", false, false, NULL, ImageBase, SearchStart, SearchSize, SearchStep, false, false, NULL)); +} +// Internal.Engine.Hook.functions: +bool ProcessHookScanAddNewHook(PHOOK_ENTRY HookDetails, void* ptrOriginalInstructions, PLIBRARY_ITEM_DATAW ModuleInformation, DWORD SizeOfImage) +{ + + HOOK_ENTRY MyhookEntry = {}; + + RtlMoveMemory(&MyhookEntry, HookDetails, sizeof HOOK_ENTRY); + hookEntry.push_back(MyhookEntry); + return(true); +} +// Global.Engine.Hook.functions: +__declspec(dllexport) bool __stdcall HooksSafeTransitionEx(LPVOID HookAddressArray, int NumberOfHooks, bool TransitionStart) +{ + + int i; + ULONG_PTR CurrentIP; + ULONG_PTR HookAddress; + PTHREAD_ITEM_DATA hListThreadPtr = (PTHREAD_ITEM_DATA)hListThread; + PMEMORY_COMPARE_HANDLER myHookAddressArray; + + if(dbgProcessInformation.hProcess == NULL) + { + if(!TransitionStart || ThreaderImportRunningThreadData(GetCurrentProcessId())) + { + hListThreadPtr = (PTHREAD_ITEM_DATA)hListThread; + if(hListThreadPtr != NULL) + { + while(hListThreadPtr->hThread != NULL) + { + if(hListThreadPtr->hThread != INVALID_HANDLE_VALUE) + { + if(TransitionStart) + { + if(hListThreadPtr->dwThreadId != GetCurrentThreadId()) + { + SuspendThread(hListThreadPtr->hThread); + CurrentIP = (ULONG_PTR)GetContextDataEx(hListThreadPtr->hThread, UE_CIP); + myHookAddressArray = (PMEMORY_COMPARE_HANDLER)HookAddressArray; + for(i = 0; i < NumberOfHooks; i++) + { +#if defined (_WIN64) + HookAddress = (ULONG_PTR)myHookAddressArray->Array.qwArrayEntry[0]; + myHookAddressArray = (PMEMORY_COMPARE_HANDLER)((ULONG_PTR)myHookAddressArray + sizeof ULONG_PTR); +#else + HookAddress = (ULONG_PTR)myHookAddressArray->Array.dwArrayEntry[0]; + myHookAddressArray = (PMEMORY_COMPARE_HANDLER)((ULONG_PTR)myHookAddressArray + sizeof ULONG_PTR); +#endif + while(CurrentIP >= (ULONG_PTR)HookAddress && CurrentIP <= (ULONG_PTR)HookAddress + 5) + { + ResumeThread(hListThreadPtr->hThread); + Sleep(5); + SuspendThread(hListThreadPtr->hThread); + CurrentIP = (ULONG_PTR)GetContextDataEx(hListThreadPtr->hThread, UE_CIP); + i = 0; + } + } + } + } + else + { + ResumeThread(hListThreadPtr->hThread); + EngineCloseHandle(hListThreadPtr->hThread); + } + } + hListThreadPtr = (PTHREAD_ITEM_DATA)((ULONG_PTR)hListThreadPtr + sizeof THREAD_ITEM_DATA); + } + if(!TransitionStart) + { + VirtualFree(hListThread, NULL, MEM_RELEASE); + hListThread = NULL; + } + return(true); + } + } + else + { + return(false); + } + } + return(false); +} +__declspec(dllexport) bool __stdcall HooksSafeTransition(LPVOID HookAddress, bool TransitionStart) +{ + + void* aHookAddress[1]; + aHookAddress[0] = HookAddress; + + return(HooksSafeTransitionEx(&aHookAddress[0], sizeof aHookAddress, TransitionStart)); +} +__declspec(dllexport) bool __stdcall HooksIsAddressRedirected(LPVOID HookAddress) +{ + + for(unsigned int i = 0; i < hookEntry.size(); i++) + { + if(hookEntry[i].HookAddress == HookAddress && hookEntry[i].IATHook == false && hookEntry[i].HookIsEnabled == true) + { + return(true); + } + } + return(false); +} +__declspec(dllexport) void* __stdcall HooksGetTrampolineAddress(LPVOID HookAddress) +{ + + for(unsigned int i = 0; i < hookEntry.size(); i++) + { + if(hookEntry[i].HookAddress == HookAddress) + { + return(hookEntry[i].PatchedEntry); + } + } + return(NULL); +} +__declspec(dllexport) void* __stdcall HooksGetHookEntryDetails(LPVOID HookAddress) +{ + + for(unsigned int i = 0; i < hookEntry.size(); i++) + { + if(hookEntry[i].HookAddress == HookAddress) + { + return(&hookEntry[i]); + } + } + return(NULL); +} +__declspec(dllexport) bool __stdcall HooksInsertNewRedirection(LPVOID HookAddress, LPVOID RedirectTo, int HookType) +{ + +#if !defined(_WIN64) + int j; + unsigned int i; +#endif + HOOK_ENTRY myHook = {}; + DWORD CalculatedRealingJump; + ULONG_PTR x64CalculatedRealingJump; + ULONG_PTR RealignAddressTarget; + int ProcessedBufferSize = NULL; + int CurrentInstructionSize = NULL; + PMEMORY_COMPARE_HANDLER WriteMemory = (PMEMORY_COMPARE_HANDLER)CwpBuffPatchedEntry; + PMEMORY_COMPARE_HANDLER CompareMemory; +#if !defined(_WIN64) + PMEMORY_COMPARE_HANDLER RelocateMemory; +#endif + void* cHookAddress = HookAddress; + DWORD OldProtect = PAGE_READONLY; + void* TempBuffPatchedEntry; + bool returnData; + + x64CalculatedRealingJump = NULL; + if(buffPatchedEntry == NULL || (ULONG_PTR)CwpBuffPatchedEntry - (ULONG_PTR)buffPatchedEntry + TEE_MAXIMUM_HOOK_SIZE > buffPatchedEntrySize) + { + buffPatchedEntrySize = buffPatchedEntrySize + 0x1000; + CwpBuffPatchedEntry = (void*)((ULONG_PTR)CwpBuffPatchedEntry - (ULONG_PTR)buffPatchedEntry); + TempBuffPatchedEntry = VirtualAlloc(NULL, buffPatchedEntrySize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if(TempBuffPatchedEntry != NULL) + { + if(hookEntry.size() > NULL) + { + RtlMoveMemory(TempBuffPatchedEntry, buffPatchedEntry, (ULONG_PTR)CwpBuffPatchedEntry); + } +#if !defined(_WIN64) + for(i = 0; i < hookEntry.size(); i++) + { + hookEntry[i].PatchedEntry = (void*)((ULONG_PTR)hookEntry[i].PatchedEntry - (ULONG_PTR)buffPatchedEntry + (ULONG_PTR)TempBuffPatchedEntry); + CalculatedRealingJump = (DWORD)((ULONG_PTR)hookEntry[i].PatchedEntry - (ULONG_PTR)hookEntry[i].HookAddress - 5); + RtlMoveMemory(&hookEntry[i].HookBytes[1], &CalculatedRealingJump, 4); + if(hookEntry[i].RelocationCount > NULL) + { + for(j = 0; j < hookEntry[i].RelocationCount; j++) + { + CompareMemory = (PMEMORY_COMPARE_HANDLER)((ULONG_PTR)buffPatchedEntry + hookEntry[i].RelocationInfo[j]); + RelocateMemory = (PMEMORY_COMPARE_HANDLER)((ULONG_PTR)TempBuffPatchedEntry + hookEntry[i].RelocationInfo[j]); + CurrentInstructionSize = StaticLengthDisassemble((void*)CompareMemory); + RealignAddressTarget = (ULONG_PTR)GetJumpDestination(GetCurrentProcess(), (ULONG_PTR)CompareMemory); + if(RealignAddressTarget != NULL) + { + if(CompareMemory->Array.bArrayEntry[0] == 0xE9 && CurrentInstructionSize == 5) + { + CalculatedRealingJump = (DWORD)((ULONG_PTR)RealignAddressTarget - (ULONG_PTR)RelocateMemory - CurrentInstructionSize); + RtlMoveMemory(&RelocateMemory->Array.bArrayEntry[1], &CalculatedRealingJump, sizeof CalculatedRealingJump); + } + else if(CompareMemory->Array.bArrayEntry[0] >= 0x70 && CompareMemory->Array.bArrayEntry[0] <= 0x7F && CurrentInstructionSize == 2) + { + CalculatedRealingJump = (DWORD)((ULONG_PTR)RealignAddressTarget - (ULONG_PTR)RelocateMemory - CurrentInstructionSize); + RtlMoveMemory(&RelocateMemory->Array.bArrayEntry[2], &CalculatedRealingJump, sizeof CalculatedRealingJump); + } + else if(CompareMemory->Array.bArrayEntry[0] == 0x0F && CompareMemory->Array.bArrayEntry[1] >= 0x80 && CompareMemory->Array.bArrayEntry[1] <= 0x8F && CurrentInstructionSize == 6) + { + CalculatedRealingJump = (DWORD)((ULONG_PTR)RealignAddressTarget - (ULONG_PTR)RelocateMemory - CurrentInstructionSize); + RtlMoveMemory(&RelocateMemory->Array.bArrayEntry[2], &CalculatedRealingJump, sizeof CalculatedRealingJump); + } + else if(CompareMemory->Array.bArrayEntry[0] == 0xE8 && CurrentInstructionSize == 5) + { + CalculatedRealingJump = (DWORD)((ULONG_PTR)RealignAddressTarget - (ULONG_PTR)RelocateMemory - CurrentInstructionSize); + RtlMoveMemory(&RelocateMemory->Array.bArrayEntry[1], &CalculatedRealingJump, sizeof CalculatedRealingJump); + } + } + } + } + } +#endif + if(hookEntry.size() > NULL) + { + VirtualFree(buffPatchedEntry, NULL, MEM_RELEASE); + } + CwpBuffPatchedEntry = (void*)((ULONG_PTR)CwpBuffPatchedEntry + (ULONG_PTR)TempBuffPatchedEntry); + WriteMemory = (PMEMORY_COMPARE_HANDLER)CwpBuffPatchedEntry; + buffPatchedEntry = TempBuffPatchedEntry; + } + } + while(ProcessedBufferSize < TEE_MAXIMUM_HOOK_INSERT_SIZE) + { + CompareMemory = (PMEMORY_COMPARE_HANDLER)cHookAddress; + CurrentInstructionSize = StaticLengthDisassemble(cHookAddress); + RealignAddressTarget = (ULONG_PTR)GetJumpDestination(GetCurrentProcess(), (ULONG_PTR)cHookAddress); + if(RealignAddressTarget != NULL) + { + if(CompareMemory->Array.bArrayEntry[0] == 0xE9 && CurrentInstructionSize == 5) + { + if(cHookAddress == HookAddress) + { + if(HooksIsAddressRedirected(HookAddress)) + { + if(HooksRemoveRedirection(HookAddress, false)) + { + returnData = HooksInsertNewRedirection(HookAddress, RedirectTo, HookType); + if(returnData) + { + return(true); + } + else + { + return(false); + } + } + } + } + CalculatedRealingJump = (DWORD)((ULONG_PTR)RealignAddressTarget - (ULONG_PTR)WriteMemory - CurrentInstructionSize); + WriteMemory->Array.bArrayEntry[0] = 0xE9; + RtlMoveMemory(&WriteMemory->Array.bArrayEntry[1], &CalculatedRealingJump, sizeof CalculatedRealingJump); + myHook.RelocationInfo[myHook.RelocationCount] = (DWORD)((ULONG_PTR)WriteMemory - (ULONG_PTR)buffPatchedEntry); + WriteMemory = (PMEMORY_COMPARE_HANDLER)((ULONG_PTR)WriteMemory + CurrentInstructionSize); + myHook.RelocationCount++; + } + else if(CompareMemory->Array.bArrayEntry[0] == 0xEB && CurrentInstructionSize == 2) + { + CalculatedRealingJump = (DWORD)((ULONG_PTR)RealignAddressTarget - (ULONG_PTR)WriteMemory - 5); + WriteMemory->Array.bArrayEntry[0] = 0xE9; + RtlMoveMemory(&WriteMemory->Array.bArrayEntry[1], &CalculatedRealingJump, sizeof CalculatedRealingJump); + myHook.RelocationInfo[myHook.RelocationCount] = (DWORD)((ULONG_PTR)WriteMemory - (ULONG_PTR)buffPatchedEntry); + WriteMemory = (PMEMORY_COMPARE_HANDLER)((ULONG_PTR)WriteMemory + 5); + myHook.RelocationCount++; + } + else if(CompareMemory->Array.bArrayEntry[0] >= 0x70 && CompareMemory->Array.bArrayEntry[0] <= 0x7F && CurrentInstructionSize == 2) + { +#if !defined(_WIN64) + CalculatedRealingJump = (DWORD)((ULONG_PTR)RealignAddressTarget - (ULONG_PTR)WriteMemory - 6); + WriteMemory->Array.bArrayEntry[0] = 0x0F; + WriteMemory->Array.bArrayEntry[1] = CompareMemory->Array.bArrayEntry[0] + 0x10; + RtlMoveMemory(&WriteMemory->Array.bArrayEntry[2], &CalculatedRealingJump, sizeof CalculatedRealingJump); + myHook.RelocationInfo[myHook.RelocationCount] = (DWORD)((ULONG_PTR)WriteMemory - (ULONG_PTR)buffPatchedEntry); + WriteMemory = (PMEMORY_COMPARE_HANDLER)((ULONG_PTR)WriteMemory + 6); + myHook.RelocationCount++; +#else + x64CalculatedRealingJump = RealignAddressTarget; + WriteMemory->Array.bArrayEntry[0] = CompareMemory->Array.bArrayEntry[0]; + WriteMemory->Array.bArrayEntry[1] = 0x02; + WriteMemory->Array.bArrayEntry[2] = 0xEB; + WriteMemory->Array.bArrayEntry[3] = 0x0E; + WriteMemory->Array.bArrayEntry[4] = 0xFF; + WriteMemory->Array.bArrayEntry[5] = 0x25; + RtlZeroMemory(&WriteMemory->Array.bArrayEntry[6], 4); + RtlMoveMemory(&WriteMemory->Array.bArrayEntry[10], &x64CalculatedRealingJump, sizeof x64CalculatedRealingJump); + WriteMemory = (PMEMORY_COMPARE_HANDLER)((ULONG_PTR)WriteMemory + 18); +#endif + } + else if(CompareMemory->Array.bArrayEntry[0] == 0x0F && CompareMemory->Array.bArrayEntry[1] >= 0x80 && CompareMemory->Array.bArrayEntry[1] <= 0x8F && CurrentInstructionSize == 6) + { +#if !defined(_WIN64) + CalculatedRealingJump = (DWORD)((ULONG_PTR)RealignAddressTarget - (ULONG_PTR)WriteMemory - CurrentInstructionSize); + RtlMoveMemory(&WriteMemory->Array.bArrayEntry[0], &CompareMemory->Array.bArrayEntry[0], 2); + RtlMoveMemory(&WriteMemory->Array.bArrayEntry[2], &CalculatedRealingJump, sizeof CalculatedRealingJump); + myHook.RelocationInfo[myHook.RelocationCount] = (DWORD)((ULONG_PTR)WriteMemory - (ULONG_PTR)buffPatchedEntry); + WriteMemory = (PMEMORY_COMPARE_HANDLER)((ULONG_PTR)WriteMemory + CurrentInstructionSize); + myHook.RelocationCount++; +#else + x64CalculatedRealingJump = RealignAddressTarget; + WriteMemory->Array.bArrayEntry[0] = CompareMemory->Array.bArrayEntry[0]; + WriteMemory->Array.bArrayEntry[1] = CompareMemory->Array.bArrayEntry[1]; + WriteMemory->Array.bArrayEntry[2] = 0x02; + WriteMemory->Array.bArrayEntry[3] = 0x00; + WriteMemory->Array.bArrayEntry[4] = 0x00; + WriteMemory->Array.bArrayEntry[5] = 0x00; + WriteMemory->Array.bArrayEntry[6] = 0xEB; + WriteMemory->Array.bArrayEntry[7] = 0x0E; + WriteMemory->Array.bArrayEntry[8] = 0xFF; + WriteMemory->Array.bArrayEntry[9] = 0x25; + RtlZeroMemory(&WriteMemory->Array.bArrayEntry[10], 4); + RtlMoveMemory(&WriteMemory->Array.bArrayEntry[14], &x64CalculatedRealingJump, sizeof x64CalculatedRealingJump); + WriteMemory = (PMEMORY_COMPARE_HANDLER)((ULONG_PTR)WriteMemory + 22); +#endif + } + else if(CompareMemory->Array.bArrayEntry[0] == 0xE8 && CurrentInstructionSize == 5) + { + CalculatedRealingJump = (DWORD)((ULONG_PTR)RealignAddressTarget - (ULONG_PTR)WriteMemory - CurrentInstructionSize); + WriteMemory->Array.bArrayEntry[0] = 0xE8; + RtlMoveMemory(&WriteMemory->Array.bArrayEntry[1], &CalculatedRealingJump, sizeof CalculatedRealingJump); + myHook.RelocationInfo[myHook.RelocationCount] = (DWORD)((ULONG_PTR)WriteMemory - (ULONG_PTR)buffPatchedEntry); + WriteMemory = (PMEMORY_COMPARE_HANDLER)((ULONG_PTR)WriteMemory + CurrentInstructionSize); + myHook.RelocationCount++; +#if defined(_WIN64) + } + else if(CompareMemory->Array.bArrayEntry[0] == 0xFF && (CompareMemory->Array.bArrayEntry[1] == 0x15 || CompareMemory->Array.bArrayEntry[1] == 0x25) && CurrentInstructionSize == 6) + { + CalculatedRealingJump = (DWORD)((ULONG_PTR)RealignAddressTarget - (ULONG_PTR)WriteMemory - CurrentInstructionSize); + RtlMoveMemory(&WriteMemory->Array.bArrayEntry[0], &CompareMemory->Array.bArrayEntry[0], 2); + RtlMoveMemory(&WriteMemory->Array.bArrayEntry[2], &CalculatedRealingJump, sizeof CalculatedRealingJump); + WriteMemory = (PMEMORY_COMPARE_HANDLER)((ULONG_PTR)WriteMemory + CurrentInstructionSize); +#endif + } + else + { + RtlMoveMemory(&WriteMemory->Array.bArrayEntry[0], cHookAddress, CurrentInstructionSize); + WriteMemory = (PMEMORY_COMPARE_HANDLER)((ULONG_PTR)WriteMemory + CurrentInstructionSize); + } + } + else + { + RtlMoveMemory(&WriteMemory->Array.bArrayEntry[0], cHookAddress, CurrentInstructionSize); + WriteMemory = (PMEMORY_COMPARE_HANDLER)((ULONG_PTR)WriteMemory + CurrentInstructionSize); + } + cHookAddress = (void*)((ULONG_PTR)cHookAddress + CurrentInstructionSize); + ProcessedBufferSize = ProcessedBufferSize + CurrentInstructionSize; + } + if(ProcessedBufferSize >= TEE_MAXIMUM_HOOK_INSERT_SIZE) + { + WriteMemory->Array.bArrayEntry[0] = 0xFF; + WriteMemory->Array.bArrayEntry[1] = 0x25; +#if !defined(_WIN64) + CalculatedRealingJump = (DWORD)((ULONG_PTR)WriteMemory + 6); +#else + CalculatedRealingJump = NULL; +#endif + RtlMoveMemory(&WriteMemory->Array.bArrayEntry[2], &CalculatedRealingJump, sizeof CalculatedRealingJump); + RtlMoveMemory(&WriteMemory->Array.bArrayEntry[6], &cHookAddress, sizeof CalculatedRealingJump); + WriteMemory = (PMEMORY_COMPARE_HANDLER)((ULONG_PTR)WriteMemory + 6 + sizeof ULONG_PTR); + myHook.HookIsEnabled = true; + myHook.HookType = (BYTE)HookType; + myHook.HookAddress = HookAddress; + myHook.RedirectionAddress = RedirectTo; + myHook.PatchedEntry = CwpBuffPatchedEntry; + myHook.HookSize = TEE_MAXIMUM_HOOK_SIZE; + RtlMoveMemory(&myHook.OriginalBytes[0], HookAddress, TEE_MAXIMUM_HOOK_SIZE); + CalculatedRealingJump = (DWORD)((ULONG_PTR)RedirectTo - (ULONG_PTR)HookAddress); + CwpBuffPatchedEntry = (void*)((ULONG_PTR)WriteMemory); + WriteMemory = (PMEMORY_COMPARE_HANDLER)HookAddress; + if(HookType == TEE_HOOK_NRM_JUMP) + { +#if !defined(_WIN64) + CalculatedRealingJump = CalculatedRealingJump - 5; + if(VirtualProtect(HookAddress, TEE_MAXIMUM_HOOK_SIZE, PAGE_EXECUTE_READWRITE, &OldProtect)) + { + WriteMemory->Array.bArrayEntry[0] = 0xE9; + RtlMoveMemory(&WriteMemory->Array.bArrayEntry[1], &CalculatedRealingJump, sizeof CalculatedRealingJump); + RtlMoveMemory(&myHook.HookBytes[0], HookAddress, TEE_MAXIMUM_HOOK_SIZE); + VirtualProtect(HookAddress, TEE_MAXIMUM_HOOK_SIZE, OldProtect, &OldProtect); + hookEntry.push_back(myHook); + return(true); + } +#else + if(VirtualProtect(HookAddress, TEE_MAXIMUM_HOOK_SIZE, PAGE_EXECUTE_READWRITE, &OldProtect)) + { + WriteMemory->Array.bArrayEntry[0] = 0xFF; + WriteMemory->Array.bArrayEntry[1] = 0x25; + RtlZeroMemory(&WriteMemory->Array.bArrayEntry[2], 4); + RtlMoveMemory(&WriteMemory->Array.bArrayEntry[6], &RedirectTo, sizeof RedirectTo); + RtlMoveMemory(&myHook.HookBytes[0], HookAddress, TEE_MAXIMUM_HOOK_SIZE); + VirtualProtect(HookAddress, TEE_MAXIMUM_HOOK_SIZE, OldProtect, &OldProtect); + hookEntry.push_back(myHook); + return(true); + } +#endif + } + else if(HookType == TEE_HOOK_NRM_CALL) + { +#if !defined(_WIN64) + CalculatedRealingJump = CalculatedRealingJump - 5; + if(VirtualProtect(HookAddress, TEE_MAXIMUM_HOOK_SIZE, PAGE_EXECUTE_READWRITE, &OldProtect)) + { + WriteMemory->Array.bArrayEntry[0] = 0xE8; + RtlMoveMemory(&WriteMemory->Array.bArrayEntry[1], &CalculatedRealingJump, sizeof CalculatedRealingJump); + RtlMoveMemory(&myHook.HookBytes[0], HookAddress, TEE_MAXIMUM_HOOK_SIZE); + VirtualProtect(HookAddress, TEE_MAXIMUM_HOOK_SIZE, OldProtect, &OldProtect); + hookEntry.push_back(myHook); + return(true); + } +#else + if(VirtualProtect(HookAddress, TEE_MAXIMUM_HOOK_SIZE, PAGE_EXECUTE_READWRITE, &OldProtect)) + { + WriteMemory->Array.bArrayEntry[0] = 0xFF; + WriteMemory->Array.bArrayEntry[1] = 0x15; + RtlZeroMemory(&WriteMemory->Array.bArrayEntry[2], 4); + RtlMoveMemory(&WriteMemory->Array.bArrayEntry[6], &RedirectTo, sizeof RedirectTo); + RtlMoveMemory(&myHook.HookBytes[0], HookAddress, TEE_MAXIMUM_HOOK_SIZE); + VirtualProtect(HookAddress, TEE_MAXIMUM_HOOK_SIZE, OldProtect, &OldProtect); + hookEntry.push_back(myHook); + return(true); + } +#endif + } + } + return(false); +} +__declspec(dllexport) bool __stdcall HooksInsertNewIATRedirectionEx(ULONG_PTR FileMapVA, ULONG_PTR LoadedModuleBase, char* szHookFunction, LPVOID RedirectTo) +{ + + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + PIMAGE_IMPORT_DESCRIPTOR ImportIID; + PIMAGE_THUNK_DATA32 ThunkData32; + PIMAGE_THUNK_DATA64 ThunkData64; + DWORD OldProtect = PAGE_READONLY; + ULONG_PTR CurrentThunk; + HOOK_ENTRY myHook = {}; + BOOL FileIs64; + + if(FileMapVA != NULL && LoadedModuleBase != NULL) + { + myHook.IATHook = true; + myHook.HookIsEnabled = true; + myHook.HookType = TEE_HOOK_IAT; + myHook.HookSize = sizeof ULONG_PTR; + myHook.RedirectionAddress = RedirectTo; + myHook.IATHookModuleBase = (void*)LoadedModuleBase; + myHook.IATHookNameHash = EngineHashString(szHookFunction); + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, NULL, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + return(false); + } + if(!FileIs64) + { + if(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress != NULL) + { + ImportIID = (PIMAGE_IMPORT_DESCRIPTOR)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + PEHeader32->OptionalHeader.ImageBase), true); + __try + { + while(ImportIID->FirstThunk != NULL) + { + if(ImportIID->OriginalFirstThunk != NULL) + { + ThunkData32 = (PIMAGE_THUNK_DATA32)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)((ULONG_PTR)ImportIID->OriginalFirstThunk + PEHeader32->OptionalHeader.ImageBase), true); + CurrentThunk = (ULONG_PTR)ImportIID->FirstThunk; + } + else + { + ThunkData32 = (PIMAGE_THUNK_DATA32)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)((ULONG_PTR)ImportIID->FirstThunk + PEHeader32->OptionalHeader.ImageBase), true); + CurrentThunk = (ULONG_PTR)ImportIID->FirstThunk; + } + while(ThunkData32->u1.AddressOfData != NULL) + { + if(!(ThunkData32->u1.Ordinal & IMAGE_ORDINAL_FLAG32)) + { + if(lstrcmpiA((char*)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)((ULONG_PTR)ThunkData32->u1.AddressOfData + 2 + PEHeader32->OptionalHeader.ImageBase), true), szHookFunction) == NULL) + { + myHook.HookAddress = (void*)(CurrentThunk + LoadedModuleBase); + if(VirtualProtect(myHook.HookAddress, myHook.HookSize, PAGE_EXECUTE_READWRITE, &OldProtect)) + { + RtlMoveMemory(&myHook.OriginalBytes[0], myHook.HookAddress, myHook.HookSize); + RtlMoveMemory(&myHook.HookBytes[0], &myHook.RedirectionAddress, myHook.HookSize); + RtlMoveMemory(myHook.HookAddress, &myHook.RedirectionAddress, myHook.HookSize); + VirtualProtect(myHook.HookAddress, myHook.HookSize, OldProtect, &OldProtect); + } + hookEntry.push_back(myHook); + } + } + CurrentThunk = CurrentThunk + 4; + ThunkData32 = (PIMAGE_THUNK_DATA32)((ULONG_PTR)ThunkData32 + sizeof IMAGE_THUNK_DATA32); + } + ImportIID = (PIMAGE_IMPORT_DESCRIPTOR)((ULONG_PTR)ImportIID + sizeof IMAGE_IMPORT_DESCRIPTOR); + } + return(true); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return(false); + } + } + } + else + { + if(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress != NULL) + { + ImportIID = (PIMAGE_IMPORT_DESCRIPTOR)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + PEHeader64->OptionalHeader.ImageBase), true); + __try + { + while(ImportIID->FirstThunk != NULL) + { + if(ImportIID->OriginalFirstThunk != NULL) + { + ThunkData64 = (PIMAGE_THUNK_DATA64)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)((ULONG_PTR)ImportIID->OriginalFirstThunk + PEHeader64->OptionalHeader.ImageBase), true); + CurrentThunk = (ULONG_PTR)ImportIID->OriginalFirstThunk; + } + else + { + ThunkData64 = (PIMAGE_THUNK_DATA64)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)((ULONG_PTR)ImportIID->FirstThunk + PEHeader64->OptionalHeader.ImageBase), true); + CurrentThunk = (ULONG_PTR)ImportIID->FirstThunk; + } + while(ThunkData64->u1.AddressOfData != NULL) + { + if(!(ThunkData64->u1.Ordinal & IMAGE_ORDINAL_FLAG64)) + { + if(lstrcmpiA((char*)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)((ULONG_PTR)ThunkData64->u1.AddressOfData + 2 + PEHeader64->OptionalHeader.ImageBase), true), szHookFunction) == NULL) + { + myHook.HookAddress = (void*)(CurrentThunk + LoadedModuleBase); + if(VirtualProtect(myHook.HookAddress, myHook.HookSize, PAGE_EXECUTE_READWRITE, &OldProtect)) + { + RtlMoveMemory(&myHook.OriginalBytes[0], myHook.HookAddress, myHook.HookSize); + RtlMoveMemory(&myHook.HookBytes[0], &myHook.RedirectionAddress, myHook.HookSize); + RtlMoveMemory(myHook.HookAddress, &myHook.RedirectionAddress, myHook.HookSize); + VirtualProtect(myHook.HookAddress, myHook.HookSize, OldProtect, &OldProtect); + } + hookEntry.push_back(myHook); + } + } + CurrentThunk = CurrentThunk + 8; + ThunkData64 = (PIMAGE_THUNK_DATA64)((ULONG_PTR)ThunkData64 + sizeof IMAGE_THUNK_DATA64); + } + ImportIID = (PIMAGE_IMPORT_DESCRIPTOR)((ULONG_PTR)ImportIID + sizeof IMAGE_IMPORT_DESCRIPTOR); + } + return(true); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return(false); + } + } + } + } + else + { + return(false); + } + } + else + { + return(false); + } + return(false); +} +__declspec(dllexport) bool __stdcall HooksInsertNewIATRedirection(char* szModuleName, char* szHookFunction, LPVOID RedirectTo) +{ + + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + DWORD NewSectionVO = NULL; + DWORD NewSectionFO = NULL; + HMODULE SelectedModule = NULL; + + SelectedModule = GetModuleHandleA(szModuleName); + if(SelectedModule != NULL) + { + if(MapFileEx(szModuleName, UE_ACCESS_READ, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + if(HooksInsertNewIATRedirectionEx(FileMapVA, (ULONG_PTR)SelectedModule, szHookFunction, RedirectTo)) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(true); + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + } + } + } + return(false); +} +__declspec(dllexport) bool __stdcall HooksRemoveRedirection(LPVOID HookAddress, bool RemoveAll) +{ + + DWORD OldProtect = PAGE_READONLY; + + if(!RemoveAll) + { + for(unsigned int i = 0; i < hookEntry.size(); i++) + { + if(hookEntry[i].HookAddress == HookAddress && hookEntry[i].IATHook == false) + { + if(VirtualProtect(HookAddress, TEE_MAXIMUM_HOOK_SIZE, PAGE_EXECUTE_READWRITE, &OldProtect)) + { + RtlMoveMemory(HookAddress, &hookEntry[i].OriginalBytes, hookEntry[i].HookSize); + VirtualProtect(HookAddress, TEE_MAXIMUM_HOOK_SIZE, OldProtect, &OldProtect); + hookEntry.erase(hookEntry.begin() + i); + return(true); + } + } + } + return(false); + } + else + { + for(unsigned int i = 0; i < hookEntry.size(); i++) + { + if(VirtualProtect(hookEntry[i].HookAddress, TEE_MAXIMUM_HOOK_SIZE, PAGE_EXECUTE_READWRITE, &OldProtect)) + { + RtlMoveMemory(hookEntry[i].HookAddress, &hookEntry[i].OriginalBytes, hookEntry[i].HookSize); + VirtualProtect(hookEntry[i].HookAddress, TEE_MAXIMUM_HOOK_SIZE, OldProtect, &OldProtect); + } + } + hookEntry.clear(); + return(true); + } +} +__declspec(dllexport) bool __stdcall HooksRemoveRedirectionsForModule(HMODULE ModuleBase) +{ + + int j = NULL; + unsigned int i = (unsigned int)hookEntry.size(); + DWORD OldProtect = PAGE_READONLY; + MODULEINFO RemoteModuleInfo; + + if(GetModuleInformation(GetCurrentProcess(), ModuleBase, &RemoteModuleInfo, sizeof MODULEINFO)) + { + while(i > NULL) + { + if((ULONG_PTR)hookEntry[i].HookAddress >= (ULONG_PTR)ModuleBase && (ULONG_PTR)hookEntry[i].HookAddress <= (ULONG_PTR)ModuleBase + RemoteModuleInfo.SizeOfImage) + { + if(VirtualProtect(hookEntry[i].HookAddress, TEE_MAXIMUM_HOOK_SIZE, PAGE_EXECUTE_READWRITE, &OldProtect)) + { + RtlMoveMemory(hookEntry[i].HookAddress, &hookEntry[i].OriginalBytes, hookEntry[i].HookSize); + VirtualProtect(hookEntry[i].HookAddress, TEE_MAXIMUM_HOOK_SIZE, OldProtect, &OldProtect); + hookEntry.erase(hookEntry.begin() + i); + j++; + } + } + i--; + } + if(j == NULL) + { + return(false); + } + } + else + { + return(false); + } + return(true); +} +__declspec(dllexport) bool __stdcall HooksRemoveIATRedirection(char* szModuleName, char* szHookFunction, bool RemoveAll) +{ + + unsigned int i = (unsigned int)hookEntry.size() - 1; + DWORD OldProtect = PAGE_READONLY; + HMODULE ModuleBase = GetModuleHandleA(szModuleName); + DWORD FunctionNameHash = EngineHashString(szHookFunction); + + if(ModuleBase != NULL) + { + while(i > 0) + { + if((hookEntry[i].IATHookModuleBase == (void*)ModuleBase && RemoveAll == true) || (hookEntry[i].IATHookNameHash == FunctionNameHash && hookEntry[i].IATHook == true)) + { + if(VirtualProtect(hookEntry[i].HookAddress, TEE_MAXIMUM_HOOK_SIZE, PAGE_EXECUTE_READWRITE, &OldProtect)) + { + RtlMoveMemory(hookEntry[i].HookAddress, &hookEntry[i].OriginalBytes, hookEntry[i].HookSize); + VirtualProtect(hookEntry[i].HookAddress, TEE_MAXIMUM_HOOK_SIZE, OldProtect, &OldProtect); + hookEntry.erase(hookEntry.begin() + i); + } + } + i--; + } + } + return(false); +} +__declspec(dllexport) bool __stdcall HooksDisableRedirection(LPVOID HookAddress, bool DisableAll) +{ + + DWORD OldProtect = PAGE_READONLY; + + if(!DisableAll) + { + for(unsigned int i = 0; i < hookEntry.size(); i++) + { + if(hookEntry[i].HookAddress == HookAddress && hookEntry[i].HookIsEnabled == true) + { + if(VirtualProtect(HookAddress, TEE_MAXIMUM_HOOK_SIZE, PAGE_EXECUTE_READWRITE, &OldProtect)) + { + RtlMoveMemory(HookAddress, &hookEntry[i].OriginalBytes, hookEntry[i].HookSize); + VirtualProtect(HookAddress, TEE_MAXIMUM_HOOK_SIZE, OldProtect, &OldProtect); + hookEntry[i].HookIsEnabled = false; + return(true); + } + } + } + return(false); + } + else + { + for(unsigned int i = 0; i < hookEntry.size(); i++) + { + if(VirtualProtect(hookEntry[i].HookAddress, TEE_MAXIMUM_HOOK_SIZE, PAGE_EXECUTE_READWRITE, &OldProtect)) + { + RtlMoveMemory(hookEntry[i].HookAddress, &hookEntry[i].OriginalBytes, hookEntry[i].HookSize); + VirtualProtect(hookEntry[i].HookAddress, TEE_MAXIMUM_HOOK_SIZE, OldProtect, &OldProtect); + hookEntry[i].HookIsEnabled = false; + } + } + return(true); + } +} +__declspec(dllexport) bool __stdcall HooksDisableRedirectionsForModule(HMODULE ModuleBase) +{ + + int j = NULL; + unsigned int i = (unsigned int)hookEntry.size(); + DWORD OldProtect = PAGE_READONLY; + MODULEINFO RemoteModuleInfo; + + if(GetModuleInformation(GetCurrentProcess(), ModuleBase, &RemoteModuleInfo, sizeof MODULEINFO)) + { + while(i > NULL) + { + if((ULONG_PTR)hookEntry[i].HookAddress >= (ULONG_PTR)ModuleBase && (ULONG_PTR)hookEntry[i].HookAddress <= (ULONG_PTR)ModuleBase + RemoteModuleInfo.SizeOfImage) + { + if(VirtualProtect(hookEntry[i].HookAddress, TEE_MAXIMUM_HOOK_SIZE, PAGE_EXECUTE_READWRITE, &OldProtect)) + { + RtlMoveMemory(hookEntry[i].HookAddress, &hookEntry[i].OriginalBytes, hookEntry[i].HookSize); + VirtualProtect(hookEntry[i].HookAddress, TEE_MAXIMUM_HOOK_SIZE, OldProtect, &OldProtect); + hookEntry[i].HookIsEnabled = false; + j++; + } + } + i--; + } + if(j == NULL) + { + return(false); + } + } + else + { + return(false); + } + return(true); +} +__declspec(dllexport) bool __stdcall HooksDisableIATRedirection(char* szModuleName, char* szHookFunction, bool DisableAll) +{ + + unsigned int i = (unsigned int)hookEntry.size() - 1; + DWORD OldProtect = PAGE_READONLY; + HMODULE ModuleBase = GetModuleHandleA(szModuleName); + DWORD FunctionNameHash = EngineHashString(szHookFunction); + + if(ModuleBase != NULL) + { + while(i > 0) + { + if((hookEntry[i].IATHookModuleBase == (void*)ModuleBase && DisableAll == true) || (hookEntry[i].IATHookNameHash == FunctionNameHash && hookEntry[i].IATHook == true)) + { + if(hookEntry[i].HookIsEnabled) + { + if(VirtualProtect(hookEntry[i].HookAddress, TEE_MAXIMUM_HOOK_SIZE, PAGE_EXECUTE_READWRITE, &OldProtect)) + { + RtlMoveMemory(hookEntry[i].HookAddress, &hookEntry[i].OriginalBytes, hookEntry[i].HookSize); + VirtualProtect(hookEntry[i].HookAddress, TEE_MAXIMUM_HOOK_SIZE, OldProtect, &OldProtect); + hookEntry[i].HookIsEnabled = false; + } + } + } + i--; + } + } + return(false); +} +__declspec(dllexport) bool __stdcall HooksEnableRedirection(LPVOID HookAddress, bool EnableAll) +{ + + DWORD OldProtect = PAGE_READONLY; + + if(!EnableAll) + { + for(unsigned int i = 0; i < hookEntry.size(); i++) + { + if(hookEntry[i].HookAddress == HookAddress && hookEntry[i].HookIsEnabled == false) + { + if(VirtualProtect(HookAddress, TEE_MAXIMUM_HOOK_SIZE, PAGE_EXECUTE_READWRITE, &OldProtect)) + { + RtlMoveMemory(HookAddress, &hookEntry[i].HookBytes, hookEntry[i].HookSize); + VirtualProtect(HookAddress, TEE_MAXIMUM_HOOK_SIZE, OldProtect, &OldProtect); + hookEntry[i].HookIsEnabled = true; + return(true); + } + } + } + return(false); + } + else + { + for(unsigned int i = 0; i < hookEntry.size(); i++) + { + if(VirtualProtect(hookEntry[i].HookAddress, TEE_MAXIMUM_HOOK_SIZE, PAGE_EXECUTE_READWRITE, &OldProtect)) + { + RtlMoveMemory(hookEntry[i].HookAddress, &hookEntry[i].HookBytes, hookEntry[i].HookSize); + VirtualProtect(hookEntry[i].HookAddress, TEE_MAXIMUM_HOOK_SIZE, OldProtect, &OldProtect); + hookEntry[i].HookIsEnabled = true; + } + } + return(true); + } +} +__declspec(dllexport) bool __stdcall HooksEnableRedirectionsForModule(HMODULE ModuleBase) +{ + + int j = NULL; + unsigned int i = (unsigned int)hookEntry.size(); + DWORD OldProtect = PAGE_READONLY; + MODULEINFO RemoteModuleInfo; + + if(GetModuleInformation(GetCurrentProcess(), ModuleBase, &RemoteModuleInfo, sizeof MODULEINFO)) + { + while(i > NULL) + { + if((ULONG_PTR)hookEntry[i].HookAddress >= (ULONG_PTR)ModuleBase && (ULONG_PTR)hookEntry[i].HookAddress <= (ULONG_PTR)ModuleBase + RemoteModuleInfo.SizeOfImage) + { + if(VirtualProtect(hookEntry[i].HookAddress, TEE_MAXIMUM_HOOK_SIZE, PAGE_EXECUTE_READWRITE, &OldProtect)) + { + RtlMoveMemory(hookEntry[i].HookAddress, &hookEntry[i].HookBytes, hookEntry[i].HookSize); + VirtualProtect(hookEntry[i].HookAddress, TEE_MAXIMUM_HOOK_SIZE, OldProtect, &OldProtect); + hookEntry[i].HookIsEnabled = true; + j++; + } + } + i--; + } + if(j == NULL) + { + return(false); + } + } + else + { + return(false); + } + return(true); +} +__declspec(dllexport) bool __stdcall HooksEnableIATRedirection(char* szModuleName, char* szHookFunction, bool EnableAll) +{ + + unsigned int i = (unsigned int)hookEntry.size() - 1; + DWORD OldProtect = PAGE_READONLY; + HMODULE ModuleBase = GetModuleHandleA(szModuleName); + DWORD FunctionNameHash = EngineHashString(szHookFunction); + + if(ModuleBase != NULL) + { + while(i > 0) + { + if((hookEntry[i].IATHookModuleBase == (void*)ModuleBase && EnableAll == true) || (hookEntry[i].IATHookNameHash == FunctionNameHash && hookEntry[i].IATHook == true)) + { + if(!hookEntry[i].HookIsEnabled) + { + if(VirtualProtect(hookEntry[i].HookAddress, TEE_MAXIMUM_HOOK_SIZE, PAGE_EXECUTE_READWRITE, &OldProtect)) + { + RtlMoveMemory(hookEntry[i].HookAddress, &hookEntry[i].HookBytes, hookEntry[i].HookSize); + VirtualProtect(hookEntry[i].HookAddress, TEE_MAXIMUM_HOOK_SIZE, OldProtect, &OldProtect); + hookEntry[i].HookIsEnabled = true; + } + } + } + i--; + } + } + return(false); +} +__declspec(dllexport) void __stdcall HooksScanModuleMemory(HMODULE ModuleBase, LPVOID CallBack) +{ + + unsigned int i; + bool FileIs64 = false; + bool FileError = false; + void* pOriginalInstruction; + bool ManuallyMapped = false; + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + PIMAGE_EXPORT_DIRECTORY PEExports; + HANDLE hProcess = GetCurrentProcess(); + LIBRARY_ITEM_DATA RemoteLibInfo = {}; + PLIBRARY_ITEM_DATA pRemoteLibInfo = (PLIBRARY_ITEM_DATA)LibrarianGetLibraryInfoEx((void*)ModuleBase); + typedef bool(__stdcall *fEnumCallBack)(PHOOK_ENTRY HookDetails, void* ptrOriginalInstructions, PLIBRARY_ITEM_DATA ModuleInformation, DWORD SizeOfImage); + fEnumCallBack myEnumCallBack = (fEnumCallBack)CallBack; + BYTE CheckHookMemory[TEE_MAXIMUM_HOOK_SIZE]; + PMEMORY_COMPARE_HANDLER ExportedFunctions; + PMEMORY_COMPARE_HANDLER FunctionMemory; + ULONG_PTR lpNumberOfBytesWritten; + HOOK_ENTRY MyhookEntry = {}; + ULONG_PTR HookDestination; + MODULEINFO ModuleInfo; + BYTE HookType = NULL; + DWORD hSize; + + if(pRemoteLibInfo == NULL) + { + RemoteLibInfo.BaseOfDll = (void*)ModuleBase; + GetModuleBaseNameA(hProcess, ModuleBase, &RemoteLibInfo.szLibraryName[0], MAX_PATH); + GetModuleFileNameExA(hProcess, ModuleBase, &RemoteLibInfo.szLibraryPath[0], MAX_PATH); + RemoteLibInfo.hFile = CreateFileA(RemoteLibInfo.szLibraryPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if(RemoteLibInfo.hFile != INVALID_HANDLE_VALUE) + { + RemoteLibInfo.hFileMapping = CreateFileMappingA(RemoteLibInfo.hFile, NULL, 2, NULL, GetFileSize(RemoteLibInfo.hFile, NULL), NULL); + if(RemoteLibInfo.hFileMapping != NULL) + { + RemoteLibInfo.hFileMappingView = MapViewOfFile(RemoteLibInfo.hFileMapping, 4, NULL, NULL, NULL); + if(RemoteLibInfo.hFileMappingView == NULL) + { + CloseHandle(RemoteLibInfo.hFile); + CloseHandle(RemoteLibInfo.hFileMapping); + FileError = true; + } + else + { + ManuallyMapped = true; + } + } + else + { + CloseHandle(RemoteLibInfo.hFile); + FileError = true; + } + } + else + { + FileError = true; + } + } + else + { + RtlMoveMemory(&RemoteLibInfo, pRemoteLibInfo, sizeof LIBRARY_ITEM_DATA); + } + if(!FileError) + { + hSize = GetFileSize(RemoteLibInfo.hFile, NULL); + GetModuleInformation(hProcess, ModuleBase, &ModuleInfo, sizeof MODULEINFO); + DOSHeader = (PIMAGE_DOS_HEADER)RemoteLibInfo.hFileMappingView; + __try + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + FileError = true; + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + FileError = true; + } + if(!FileError) + { + FunctionMemory = (PMEMORY_COMPARE_HANDLER)&CheckHookMemory[0]; + if(!FileIs64) + { + __try + { + if(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress != NULL) + { + PEExports = (PIMAGE_EXPORT_DIRECTORY)ConvertVAtoFileOffsetEx((ULONG_PTR)RemoteLibInfo.hFileMappingView, hSize, PEHeader32->OptionalHeader.ImageBase, PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress, true, true); + if(PEExports != NULL) + { + ExportedFunctions = (PMEMORY_COMPARE_HANDLER)(ConvertVAtoFileOffsetEx((ULONG_PTR)RemoteLibInfo.hFileMappingView, hSize, PEHeader32->OptionalHeader.ImageBase, PEExports->AddressOfFunctions, true, true)); + for(i = 0; i < PEExports->NumberOfFunctions; i++) + { + if(ReadProcessMemory(hProcess, (void*)((ULONG_PTR)RemoteLibInfo.BaseOfDll + ExportedFunctions->Array.dwArrayEntry[i]), &CheckHookMemory[0], TEE_MAXIMUM_HOOK_SIZE, &lpNumberOfBytesWritten)) + { + if(FunctionMemory->Array.bArrayEntry[0] == 0xE9 || FunctionMemory->Array.bArrayEntry[0] == 0xE8) + { + HookDestination = (ULONG_PTR)GetJumpDestination(hProcess, (ULONG_PTR)RemoteLibInfo.BaseOfDll + ExportedFunctions->Array.dwArrayEntry[i]); + if(HookDestination >= (ULONG_PTR)RemoteLibInfo.BaseOfDll && HookDestination <= (ULONG_PTR)RemoteLibInfo.BaseOfDll + (ULONG_PTR)ModuleInfo.SizeOfImage) + { + if(CallBack != NULL) + { + if(FunctionMemory->Array.bArrayEntry[0] == 0xE9) + { + HookType = TEE_HOOK_NRM_JUMP; + } + else + { + HookType = TEE_HOOK_NRM_CALL; + } + MyhookEntry.HookSize = 5; + MyhookEntry.HookType = HookType; + MyhookEntry.HookIsEnabled = true; + MyhookEntry.RedirectionAddress = (void*)HookDestination; + MyhookEntry.HookAddress = (void*)((ULONG_PTR)RemoteLibInfo.BaseOfDll + ExportedFunctions->Array.dwArrayEntry[i]); + pOriginalInstruction = (void*)ConvertVAtoFileOffsetEx((ULONG_PTR)RemoteLibInfo.hFileMappingView, hSize, PEHeader32->OptionalHeader.ImageBase, ExportedFunctions->Array.dwArrayEntry[i], true, true); + RtlZeroMemory(&MyhookEntry.HookBytes[0], TEE_MAXIMUM_HOOK_SIZE); + RtlMoveMemory(&MyhookEntry.HookBytes[0], &CheckHookMemory[0], MyhookEntry.HookSize); + RtlZeroMemory(&MyhookEntry.OriginalBytes[0], TEE_MAXIMUM_HOOK_SIZE); + RtlMoveMemory(&MyhookEntry.OriginalBytes[0], pOriginalInstruction, MyhookEntry.HookSize); + RelocaterRelocateMemoryBlock((ULONG_PTR)RemoteLibInfo.hFileMappingView, (ULONG_PTR)PEHeader32->OptionalHeader.ImageBase + ExportedFunctions->Array.dwArrayEntry[i], &MyhookEntry.OriginalBytes[0], MyhookEntry.HookSize, (ULONG_PTR)PEHeader32->OptionalHeader.ImageBase, (ULONG_PTR)RemoteLibInfo.BaseOfDll); + if(!myEnumCallBack(&MyhookEntry, pOriginalInstruction, &RemoteLibInfo, ModuleInfo.SizeOfImage)) + { + break; + } + } + } + } + } + } + } + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + + } + } + else + { + __try + { + if(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress != NULL) + { + PEExports = (PIMAGE_EXPORT_DIRECTORY)ConvertVAtoFileOffsetEx((ULONG_PTR)RemoteLibInfo.hFileMappingView, hSize, (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress, true, true); + if(PEExports != NULL) + { + ExportedFunctions = (PMEMORY_COMPARE_HANDLER)(ConvertVAtoFileOffsetEx((ULONG_PTR)RemoteLibInfo.hFileMappingView, hSize, (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, PEExports->AddressOfFunctions, true, true)); + for(i = 0; i < PEExports->NumberOfFunctions; i++) + { + if(ReadProcessMemory(hProcess, (void*)((ULONG_PTR)RemoteLibInfo.BaseOfDll + ExportedFunctions->Array.dwArrayEntry[i]), &CheckHookMemory[0], TEE_MAXIMUM_HOOK_SIZE, &lpNumberOfBytesWritten)) + { + if(FunctionMemory->Array.bArrayEntry[0] == 0xE9 || FunctionMemory->Array.bArrayEntry[0] == 0xE8) + { + HookDestination = (ULONG_PTR)GetJumpDestination(hProcess, (ULONG_PTR)RemoteLibInfo.BaseOfDll + ExportedFunctions->Array.dwArrayEntry[i]); + if(HookDestination >= (ULONG_PTR)RemoteLibInfo.BaseOfDll && HookDestination <= (ULONG_PTR)RemoteLibInfo.BaseOfDll + (ULONG_PTR)ModuleInfo.SizeOfImage) + { + if(CallBack != NULL) + { + if(FunctionMemory->Array.bArrayEntry[0] == 0xE9) + { + HookType = TEE_HOOK_NRM_JUMP; + } + else + { + HookType = TEE_HOOK_NRM_CALL; + } + MyhookEntry.HookSize = 5; + MyhookEntry.HookType = HookType; + MyhookEntry.HookIsEnabled = true; + MyhookEntry.RedirectionAddress = (void*)HookDestination; + MyhookEntry.HookAddress = (void*)((ULONG_PTR)RemoteLibInfo.BaseOfDll + ExportedFunctions->Array.dwArrayEntry[i]); + pOriginalInstruction = (void*)ConvertVAtoFileOffsetEx((ULONG_PTR)RemoteLibInfo.hFileMappingView, hSize, (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, ExportedFunctions->Array.dwArrayEntry[i], true, true); + RtlZeroMemory(&MyhookEntry.HookBytes[0], TEE_MAXIMUM_HOOK_SIZE); + RtlMoveMemory(&MyhookEntry.HookBytes[0], &CheckHookMemory[0], MyhookEntry.HookSize); + RtlZeroMemory(&MyhookEntry.OriginalBytes[0], TEE_MAXIMUM_HOOK_SIZE); + RtlMoveMemory(&MyhookEntry.OriginalBytes[0], pOriginalInstruction, MyhookEntry.HookSize); + RelocaterRelocateMemoryBlock((ULONG_PTR)RemoteLibInfo.hFileMappingView, (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase + ExportedFunctions->Array.dwArrayEntry[i], &MyhookEntry.OriginalBytes[0], MyhookEntry.HookSize, (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, (ULONG_PTR)RemoteLibInfo.BaseOfDll); + if(!myEnumCallBack(&MyhookEntry, pOriginalInstruction, &RemoteLibInfo, ModuleInfo.SizeOfImage)) + { + break; + } + } + } + } + } + } + } + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + + } + } + } + if(ManuallyMapped) + { + if(UnmapViewOfFile(RemoteLibInfo.hFileMappingView)) + { + CloseHandle(RemoteLibInfo.hFileMapping); + CloseHandle(RemoteLibInfo.hFile); + } + } + } +} +__declspec(dllexport) void __stdcall HooksScanEntireProcessMemory(LPVOID CallBack) +{ + + unsigned int i; + DWORD ModulesLoaded; + HMODULE EnumeratedModules[1024]; + + hookEntry.clear(); + if(EnumProcessModules(GetCurrentProcess(), &EnumeratedModules[0], sizeof EnumeratedModules, &ModulesLoaded)) + { + ModulesLoaded = ModulesLoaded / sizeof HANDLE; + for(i = 1; i < ModulesLoaded; i++) + { + HooksScanModuleMemory(EnumeratedModules[i], CallBack); + } + } +} +__declspec(dllexport) void __stdcall HooksScanEntireProcessMemoryEx() +{ + HooksScanEntireProcessMemory(&ProcessHookScanAddNewHook); +} +// Global.Engine.Tracer.functions: +long long EngineGlobalTracerHandler1(HANDLE hProcess, ULONG_PTR AddressToTrace, bool HashInstructions, DWORD InputNumberOfInstructions) +{ + + SIZE_T memSize = 0; + int NumberOfInstructions = 0; + int LengthOfValidInstruction = 0; + int CurrentNumberOfInstructions = 0; + MEMORY_BASIC_INFORMATION MemInfo; + LPVOID TraceMemory, cTraceMemory; + ULONG_PTR ueNumberOfBytesRead = NULL; + DWORD LastPushValue = NULL; + ULONG_PTR TraceStartAddress; + ULONG_PTR TraceTestAddress; + ULONG_PTR TraceTestReadAddress; + DWORD CurrentInstructionSize; + PMEMORY_CMP_HANDLER CompareMemory; + PMEMORY_COMPARE_HANDLER longCompareMemory; + DWORD InstructionHash = NULL; + bool FoundValidAPI = false; + bool SkipThisInstruction = false; + bool LoopCondition = true; + bool SkipHashing = false; + BYTE EmptyCall[5] = {0xE8, 0x00, 0x00, 0x00, 0x00}; + + if(VirtualQueryEx(hProcess, (LPVOID)AddressToTrace, &MemInfo, sizeof MEMORY_BASIC_INFORMATION) != NULL) + { + if(MemInfo.RegionSize > NULL) + { + memSize = MemInfo.RegionSize; + if(memSize > 0x4000) + { + memSize = 0x4000; + } + TraceMemory = VirtualAlloc(NULL, memSize, MEM_COMMIT, PAGE_READWRITE); + cTraceMemory = TraceMemory; + if(ReadProcessMemory(hProcess, (LPVOID)MemInfo.BaseAddress, TraceMemory, memSize, &ueNumberOfBytesRead)) + { + TraceStartAddress = AddressToTrace - (ULONG_PTR)MemInfo.BaseAddress + (ULONG_PTR)TraceMemory; + if(HashInstructions) + { + if(InputNumberOfInstructions > NULL) + { + LoopCondition = true; + } + else + { + LoopCondition = false; + } + } + else + { + if(CurrentNumberOfInstructions < 1000 && FoundValidAPI == false) + { + LoopCondition = true; + } + else + { + LoopCondition = false; + } + } + while(LoopCondition) + { + SkipHashing = false; + SkipThisInstruction = false; + CompareMemory = (PMEMORY_CMP_HANDLER)TraceStartAddress; + CurrentInstructionSize = StaticLengthDisassemble((LPVOID)TraceStartAddress); + CurrentNumberOfInstructions++; + /* + Long JUMP (0xE9) + */ + if(HashInstructions == false && CompareMemory->DataByte[0] == 0xE9 && CurrentInstructionSize == 5) + { + TraceTestAddress = (ULONG_PTR)GetJumpDestination(NULL, TraceStartAddress) - (ULONG_PTR)TraceMemory + (ULONG_PTR)MemInfo.BaseAddress; + if(TraceTestAddress <= (ULONG_PTR)MemInfo.BaseAddress || TraceTestAddress >= (ULONG_PTR)MemInfo.BaseAddress + MemInfo.RegionSize) + { + if(LengthOfValidInstruction == NULL) + { + if(ImporterGetAPINameFromDebugee(hProcess, TraceTestAddress) != NULL) + { + FoundValidAPI = true; + break; + } + } + if(ImporterGetAPINameFromDebugee(hProcess, TraceTestAddress) != NULL) + { + FoundValidAPI = true; + break; + } + else + { + if(ImporterGetAPINameFromDebugee(hProcess, TraceTestAddress - LengthOfValidInstruction) != NULL) + { + FoundValidAPI = true; + TraceTestAddress = TraceTestAddress - LengthOfValidInstruction; + break; + } + } + } + /* + Near JUMP (0xFF25) + */ + } + else if(HashInstructions == false && CompareMemory->DataByte[0] == 0xFF && CompareMemory->DataByte[1] == 0x25 && CurrentInstructionSize == 6) + { + TraceTestAddress = (ULONG_PTR)GetJumpDestination(NULL, TraceStartAddress); + if(ReadProcessMemory(hProcess, (LPVOID)TraceTestAddress, &TraceTestAddress, 4, &ueNumberOfBytesRead)) + { + if(TraceTestAddress <= (ULONG_PTR)MemInfo.BaseAddress || TraceTestAddress >= (ULONG_PTR)MemInfo.BaseAddress + MemInfo.RegionSize) + { + if(LengthOfValidInstruction == NULL) + { + if(ImporterGetAPINameFromDebugee(hProcess, TraceTestAddress) != NULL) + { + FoundValidAPI = true; + break; + } + } + if(ImporterGetAPINameFromDebugee(hProcess, TraceTestAddress) != NULL) + { + FoundValidAPI = true; + break; + } + else + { + if(ImporterGetAPINameFromDebugee(hProcess, TraceTestAddress - LengthOfValidInstruction) != NULL) + { + FoundValidAPI = true; + TraceTestAddress = TraceTestAddress - LengthOfValidInstruction; + break; + } + } + } + } + /* + PUSH then RET (0x68 ???????? 0xC3) + */ + } + else if(HashInstructions == false && CompareMemory->DataByte[0] == 0x68 && CompareMemory->DataByte[5] == 0xC3 && CurrentInstructionSize == 5) + { + longCompareMemory = (PMEMORY_COMPARE_HANDLER)((ULONG_PTR)CompareMemory + 1); + TraceTestAddress = (DWORD)(longCompareMemory->Array.dwArrayEntry[0]); + if(ReadProcessMemory(hProcess, (LPVOID)TraceTestAddress, &TraceTestReadAddress, 4, &ueNumberOfBytesRead)) + { + if(TraceTestAddress <= (ULONG_PTR)MemInfo.BaseAddress || TraceTestAddress >= (ULONG_PTR)MemInfo.BaseAddress + MemInfo.RegionSize) + { + if(LengthOfValidInstruction == NULL) + { + if(ImporterGetAPINameFromDebugee(hProcess, TraceTestAddress) != NULL) + { + FoundValidAPI = true; + break; + } + } + if(ImporterGetAPINameFromDebugee(hProcess, TraceTestAddress) != NULL) + { + FoundValidAPI = true; + break; + } + else + { + if(ImporterGetAPINameFromDebugee(hProcess, TraceTestAddress - LengthOfValidInstruction) != NULL) + { + FoundValidAPI = true; + TraceTestAddress = TraceTestAddress - LengthOfValidInstruction; + break; + } + } + } + else + { + TraceStartAddress = TraceStartAddress - (ULONG_PTR)MemInfo.BaseAddress + (ULONG_PTR)TraceMemory; + } + } + /* + CALL (0xE8) + */ + } + else if(HashInstructions == true && CompareMemory->DataByte[0] == 0xE8 && CurrentInstructionSize == 5) + { + SkipHashing = true; + InstructionHash = EngineHashMemory((char*)&EmptyCall, CurrentInstructionSize, InstructionHash); + /* + PUSH (0x68) + */ + } + else if(CompareMemory->DataByte[0] == 0x68 && CurrentInstructionSize == 5) + { + LastPushValue = (DWORD)(CompareMemory->DataByte[1] + CompareMemory->DataByte[2] * 0x1000 + CompareMemory->DataByte[3] * 0x100000 + CompareMemory->DataByte[4] * 0x10000000); + /* + ADD BYTE PTR[AL],AL (0x00, 0x00) -> End of page! + */ + } + else if(CompareMemory->DataByte[0] == 0x00 && CurrentInstructionSize == 2) + { + FoundValidAPI = false; + break; + /* + RET (0xC3) + */ + } + else if(CompareMemory->DataByte[0] == 0xC3 && CurrentInstructionSize == 1) + { + NumberOfInstructions++; + break; + /* + RET (0xC2) + */ + } + else if(CompareMemory->DataByte[0] == 0xC2 && CurrentInstructionSize == 3) + { + NumberOfInstructions++; + break; + /* + Short JUMP (0xEB) + */ + } + else if(CompareMemory->DataByte[0] == 0xEB && CurrentInstructionSize == 2) + { + TraceStartAddress = TraceStartAddress + CompareMemory->DataByte[1]; + SkipThisInstruction = true; + /* + CLC (0xF8) + */ + } + else if(CompareMemory->DataByte[0] == 0xF8 && CurrentInstructionSize == 1) + { + SkipThisInstruction = true; + /* + STC (0xF9) + */ + } + else if(CompareMemory->DataByte[0] == 0xF9 && CurrentInstructionSize == 1) + { + SkipThisInstruction = true; + /* + NOP (0x90) + */ + } + else if(CompareMemory->DataByte[0] == 0x90 && CurrentInstructionSize == 1) + { + SkipThisInstruction = true; + /* + FNOP (0xD9 0xD0) + */ + } + else if(CompareMemory->DataByte[0] == 0xD9 && CompareMemory->DataByte[1] == 0xD0 && CurrentInstructionSize == 2) + { + SkipThisInstruction = true; + /* + Multiple MOV + */ + } + else if(CompareMemory->DataByte[0] >= 0x8A && CompareMemory->DataByte[0] <= 0x8B) + { + /* + MOV EAX,EAX (0x8B 0xC8) + */ + if(CompareMemory->DataByte[0] == 0x8B && CompareMemory->DataByte[1] == 0xC8 && CurrentInstructionSize == 2) + { + SkipThisInstruction = true; + /* + MOV EBX,EBX (0x8B 0xC9) + */ + } + else if(CompareMemory->DataByte[0] == 0x8B && CompareMemory->DataByte[1] == 0xC9 && CurrentInstructionSize == 2) + { + SkipThisInstruction = true; + /* + MOV ECX,ECX (0x8B 0xDB) + */ + } + else if(CompareMemory->DataByte[0] == 0x8B && CompareMemory->DataByte[1] == 0xDB && CurrentInstructionSize == 2) + { + SkipThisInstruction = true; + /* + MOV (0x8B 0xED) + */ + } + else if(CompareMemory->DataByte[0] == 0x8B && CompareMemory->DataByte[1] == 0xED && CurrentInstructionSize == 2) + { + SkipThisInstruction = true; + /* + MOV (0x8B 0xF6) + */ + } + else if(CompareMemory->DataByte[0] == 0x8B && CompareMemory->DataByte[1] == 0xF6 && CurrentInstructionSize == 2) + { + SkipThisInstruction = true; + /* + MOV (0x8B 0xE4) + */ + } + else if(CompareMemory->DataByte[0] == 0x8B && CompareMemory->DataByte[1] == 0xE4 && CurrentInstructionSize == 2) + { + SkipThisInstruction = true; + /* + MOV EDX,EDX (0x8B 0xD2) + */ + } + else if(CompareMemory->DataByte[0] == 0x8B && CompareMemory->DataByte[1] == 0xD2 && CurrentNumberOfInstructions != 1 && CurrentInstructionSize == 2) + { + SkipThisInstruction = true; + /* + MOV EDI,EDI (0x8B 0xFF) + */ + } + else if(CompareMemory->DataByte[0] == 0x8B && CompareMemory->DataByte[1] == 0xFF && CurrentNumberOfInstructions != 1 && CurrentInstructionSize == 2) + { + SkipThisInstruction = true; + /* + MOV AL,AL (0x8A 0xC0) + */ + } + else if(CompareMemory->DataByte[0] == 0x8A && CompareMemory->DataByte[1] == 0xC0 && CurrentInstructionSize == 2) + { + SkipThisInstruction = true; + /* + MOV BL,BL (0x8A 0xDB) + */ + } + else if(CompareMemory->DataByte[0] == 0x8A && CompareMemory->DataByte[1] == 0xDB && CurrentInstructionSize == 2) + { + SkipThisInstruction = true; + /* + MOV CL,CL (0x8A 0xC9) + */ + } + else if(CompareMemory->DataByte[0] == 0x8A && CompareMemory->DataByte[1] == 0xC9 && CurrentInstructionSize == 2) + { + SkipThisInstruction = true; + /* + MOV (0x8A 0xD2) + */ + } + else if(CompareMemory->DataByte[0] == 0x8A && CompareMemory->DataByte[1] == 0xD2 && CurrentInstructionSize == 2) + { + SkipThisInstruction = true; + /* + MOV (0x8A 0xE4) + */ + } + else if(CompareMemory->DataByte[0] == 0x8A && CompareMemory->DataByte[1] == 0xE4 && CurrentInstructionSize == 2) + { + SkipThisInstruction = true; + /* + MOV (0x8A 0xED) + */ + } + else if(CompareMemory->DataByte[0] == 0x8A && CompareMemory->DataByte[1] == 0xED && CurrentInstructionSize == 2) + { + SkipThisInstruction = true; + /* + MOV (0x8A 0xFF) + */ + } + else if(CompareMemory->DataByte[0] == 0x8A && CompareMemory->DataByte[1] == 0xFF && CurrentInstructionSize == 2) + { + SkipThisInstruction = true; + /* + MOV (0x8A 0xF6) + */ + } + else if(CompareMemory->DataByte[0] == 0x8A && CompareMemory->DataByte[1] == 0xF6 && CurrentInstructionSize == 2) + { + SkipThisInstruction = true; + /* + MOV AX,AX (0x8B 0xC0) + */ + } + else if(CompareMemory->DataByte[0] == 0x8B && CompareMemory->DataByte[1] == 0xC0 && CurrentInstructionSize == 2) + { + SkipThisInstruction = true; + /* + MOV (0x8B 0xDB) + */ + } + else if(CompareMemory->DataByte[0] == 0x8B && CompareMemory->DataByte[1] == 0xDB && CurrentInstructionSize == 2) + { + SkipThisInstruction = true; + /* + MOV (0x8B 0xC9) + */ + } + else if(CompareMemory->DataByte[0] == 0x8B && CompareMemory->DataByte[1] == 0xC9 && CurrentInstructionSize == 2) + { + SkipThisInstruction = true; + /* + MOV (0x8B 0xF6) + */ + } + else if(CompareMemory->DataByte[0] == 0x8B && CompareMemory->DataByte[1] == 0xF6 && CurrentInstructionSize == 2) + { + SkipThisInstruction = true; + /* + MOV (0x8B 0xED) + */ + } + else if(CompareMemory->DataByte[0] == 0x8B && CompareMemory->DataByte[1] == 0xED && CurrentInstructionSize == 2) + { + SkipThisInstruction = true; + } + /* + RDTSC (0x0F 0x31) + */ + } + else if(CompareMemory->DataByte[0] == 0x0F && CompareMemory->DataByte[1] == 0x31 && CurrentInstructionSize == 2) + { + SkipThisInstruction = true; + /* + CPUID (0x0F 0xA2) + */ + } + else if(CompareMemory->DataByte[0] == 0x0F && CompareMemory->DataByte[1] == 0xA2 && CurrentInstructionSize == 2) + { + SkipThisInstruction = true; + /* + XCHG EAX,EAX (0x87 0xC0) + */ + } + else if(CompareMemory->DataByte[0] == 0x87 && CompareMemory->DataByte[1] == 0xC0 && CurrentInstructionSize == 2) + { + SkipThisInstruction = true; + /* + SHL EAX,0 - SHL EDI,0 && SHR EAX,0 - SHR EDI,0 + */ + } + else if(CompareMemory->DataByte[0] == 0xC1 && CurrentInstructionSize == 3) + { + if(CompareMemory->DataByte[1] >= 0xE0 && CompareMemory->DataByte[1] <= 0xEF && CompareMemory->DataByte[2] == 0x00) + { + SkipThisInstruction = true; + } + /* + ROR EAX,0 - ROR EDI,0 && ROL EAX,0 - ROL EDI,0 + */ + } + else if(CompareMemory->DataByte[0] == 0xC1 && CurrentInstructionSize == 3) + { + if(CompareMemory->DataByte[1] >= 0xC0 && CompareMemory->DataByte[1] <= 0xCF && CompareMemory->DataByte[2] == 0x00) + { + SkipThisInstruction = true; + } + /* + LEA EAX,DWORD PTR[EAX] -> LEA EDI,DWORD PTR[EDI] + */ + } + else if(CompareMemory->DataByte[0] == 0x8D && CurrentInstructionSize == 2) + { + if(CompareMemory->DataByte[1] == 0x00 || CompareMemory->DataByte[1] == 0x09 || CompareMemory->DataByte[1] == 0x1B || CompareMemory->DataByte[1] == 0x12) + { + SkipThisInstruction = true; + } + if(CompareMemory->DataByte[1] == 0x36 || CompareMemory->DataByte[1] == 0x3F) + { + SkipThisInstruction = true; + } + if(CompareMemory->DataByte[1] == 0x6D && CompareMemory->DataByte[2] == 0x00) + { + SkipThisInstruction = true; + } + } + if(!SkipThisInstruction) + { + if(HashInstructions == true && SkipHashing == false) + { + InstructionHash = EngineHashMemory((char*)TraceStartAddress, CurrentInstructionSize, InstructionHash); + } + LengthOfValidInstruction = LengthOfValidInstruction + CurrentInstructionSize; + NumberOfInstructions++; + } + if(HashInstructions) + { + InputNumberOfInstructions--; + if(InputNumberOfInstructions > NULL) + { + LoopCondition = true; + } + else + { + LoopCondition = false; + } + } + else + { + if(CurrentNumberOfInstructions < 1000 && FoundValidAPI == false) + { + LoopCondition = true; + } + else + { + LoopCondition = false; + } + } + TraceStartAddress = TraceStartAddress + CurrentInstructionSize; + } + VirtualFree(TraceMemory, NULL, MEM_RELEASE); + if(!HashInstructions) + { + if(FoundValidAPI == true) + { + return((ULONG_PTR)TraceTestAddress); + } + else if(CurrentNumberOfInstructions < 1000) + { + if(ImporterGetAPINameFromDebugee(hProcess, LastPushValue) != NULL) + { + return((ULONG_PTR)LastPushValue); + } + else if(ImporterGetAPINameFromDebugee(hProcess, LastPushValue - LengthOfValidInstruction) != NULL) + { + return((ULONG_PTR)(LastPushValue - LengthOfValidInstruction)); + } + return((DWORD)NumberOfInstructions); + } + } + else + { + return((DWORD)InstructionHash); + } + } + else + { + VirtualFree(TraceMemory, NULL, MEM_RELEASE); + } + } + } + return(NULL); +} +// TitanEngine.Tracer.functions: +__declspec(dllexport) void __stdcall TracerInit() +{ + return; // UE 1.5 compatibility mode +} +__declspec(dllexport) long long __stdcall TracerLevel1(HANDLE hProcess, ULONG_PTR AddressToTrace) +{ + return((ULONG_PTR)EngineGlobalTracerHandler1(hProcess, AddressToTrace, false, NULL)); +} +__declspec(dllexport) long long __stdcall HashTracerLevel1(HANDLE hProcess, ULONG_PTR AddressToTrace, DWORD InputNumberOfInstructions) +{ + + unsigned int i = 0; + unsigned int j = 0; + DWORD Dummy = NULL; + MODULEINFO RemoteModuleInfo; + ULONG_PTR EnumeratedModules[0x2000]; + ULONG_PTR LoadedModules[1000][4]; + char RemoteDLLName[MAX_PATH]; + HANDLE hLoadedModule = NULL; + HANDLE ModuleHandle = NULL; + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + PIMAGE_EXPORT_DIRECTORY PEExports; + PEXPORTED_DATA ExportedFunctions; + ULONG_PTR APIFoundAddress = NULL; + bool ValidateHeader = false; + bool FileIs64 = false; + bool FoundAPI = false; + DWORD CompareHash = NULL; + DWORD TestHash = NULL; + + if(InputNumberOfInstructions > NULL) + { + CompareHash = (DWORD)EngineGlobalTracerHandler1(hProcess, AddressToTrace, true, InputNumberOfInstructions); + } + else + { + InputNumberOfInstructions = (DWORD)TracerLevel1(hProcess, AddressToTrace); + if(InputNumberOfInstructions < 1000) + { + CompareHash = (DWORD)EngineGlobalTracerHandler1(hProcess, AddressToTrace, true, InputNumberOfInstructions); + } + else + { + return(NULL); + } + } + RtlZeroMemory(&EnumeratedModules, 0x2000 * sizeof ULONG_PTR); + RtlZeroMemory(&LoadedModules, 1000 * 4 * sizeof ULONG_PTR); + if(hProcess == NULL) + { + if(dbgProcessInformation.hProcess == NULL) + { + hProcess = GetCurrentProcess(); + } + else + { + hProcess = dbgProcessInformation.hProcess; + } + } + if(EnumProcessModules(hProcess, (HMODULE*)EnumeratedModules, 0x2000, &Dummy)) + { + i++; + while(FoundAPI == false && EnumeratedModules[i] != NULL) + { + ValidateHeader = false; + RtlZeroMemory(&RemoteDLLName, MAX_PATH); + GetModuleFileNameExA(hProcess, (HMODULE)EnumeratedModules[i], (LPSTR)RemoteDLLName, MAX_PATH); + if(GetModuleHandleA(RemoteDLLName) == NULL) + { + RtlZeroMemory(&RemoteDLLName, MAX_PATH); + GetModuleBaseNameA(hProcess, (HMODULE)EnumeratedModules[i], (LPSTR)RemoteDLLName, MAX_PATH); + if(GetModuleHandleA(RemoteDLLName) == NULL) + { + if(engineAlowModuleLoading) + { + hLoadedModule = LoadLibraryA(RemoteDLLName); + if(hLoadedModule != NULL) + { + LoadedModules[i][0] = EnumeratedModules[i]; + LoadedModules[i][1] = (ULONG_PTR)hLoadedModule; + LoadedModules[i][2] = 1; + } + } + else + { + hLoadedModule = (HANDLE)EngineSimulateDllLoader(hProcess, RemoteDLLName); + if(hLoadedModule != NULL) + { + LoadedModules[i][0] = EnumeratedModules[i]; + LoadedModules[i][1] = (ULONG_PTR)hLoadedModule; + LoadedModules[i][2] = 1; + ValidateHeader = true; + } + } + } + else + { + LoadedModules[i][0] = EnumeratedModules[i]; + LoadedModules[i][1] = (ULONG_PTR)GetModuleHandleA(RemoteDLLName); + LoadedModules[i][2] = 0; + } + } + else + { + LoadedModules[i][0] = EnumeratedModules[i]; + LoadedModules[i][1] = (ULONG_PTR)GetModuleHandleA(RemoteDLLName); + LoadedModules[i][2] = 0; + } + + if(!FoundAPI) + { + DOSHeader = (PIMAGE_DOS_HEADER)LoadedModules[i][1]; + RtlZeroMemory(&RemoteModuleInfo, sizeof MODULEINFO); + GetModuleInformation(hProcess, (HMODULE)LoadedModules[i][1], &RemoteModuleInfo, sizeof MODULEINFO); + if(ValidateHeader || EngineValidateHeader((ULONG_PTR)LoadedModules[i][1], hProcess, RemoteModuleInfo.lpBaseOfDll, DOSHeader, false)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + return(NULL); + } + if(!FileIs64) + { + PEExports = (PIMAGE_EXPORT_DIRECTORY)(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + LoadedModules[i][1]); + ExportedFunctions = (PEXPORTED_DATA)(PEExports->AddressOfFunctions + LoadedModules[i][1]); + } + else + { + PEExports = (PIMAGE_EXPORT_DIRECTORY)(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + LoadedModules[i][1]); + ExportedFunctions = (PEXPORTED_DATA)(PEExports->AddressOfFunctions + LoadedModules[i][1]); + } + for(j = 0; j < PEExports->NumberOfFunctions; j++) + { + TestHash = (DWORD)EngineGlobalTracerHandler1(hProcess, (ULONG_PTR)(ExportedFunctions->ExportedItem + LoadedModules[i][1]), true, InputNumberOfInstructions); + if(TestHash == CompareHash) + { + APIFoundAddress = (ULONG_PTR)(ExportedFunctions->ExportedItem + LoadedModules[i][0]); + FoundAPI = true; + } + ExportedFunctions = (PEXPORTED_DATA)((ULONG_PTR)ExportedFunctions + 4); + } + } + } + i++; + } + i = 1; + while(EnumeratedModules[i] != NULL) + { + if(engineAlowModuleLoading) + { + if(LoadedModules[i][2] == 1) + { + FreeLibrary((HMODULE)LoadedModules[i][1]); + } + } + else + { + if(LoadedModules[i][2] == 1) + { + VirtualFree((void*)LoadedModules[i][1], NULL, MEM_RELEASE); + } + } + i++; + } + } + return((ULONG_PTR)APIFoundAddress); +} +__declspec(dllexport) long __stdcall TracerDetectRedirection(HANDLE hProcess, ULONG_PTR AddressToTrace) +{ + + int i,j; + MEMORY_BASIC_INFORMATION MemInfo; + DWORD KnownRedirectionIndex = NULL; + ULONG_PTR ueNumberOfBytesRead = NULL; + PMEMORY_CMP_HANDLER cMem; + DWORD MemoryHash = NULL; + DWORD MaximumReadSize; + DWORD TestAddressX86; + LPVOID TraceMemory; + bool HashCheck = false; + + VirtualQueryEx(hProcess, (LPVOID)AddressToTrace, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + if(MemInfo.RegionSize > NULL) + { + MaximumReadSize = (DWORD)((ULONG_PTR)MemInfo.AllocationBase + MemInfo.RegionSize - AddressToTrace); + if(MaximumReadSize > 0x1000) + { + MaximumReadSize = 0x1000; + HashCheck = true; + } + else if(MaximumReadSize > 256) + { + HashCheck = true; + } + if(sizeof HANDLE == 4) + { + TraceMemory = VirtualAlloc(NULL, MaximumReadSize, MEM_COMMIT, PAGE_READWRITE); + if(ReadProcessMemory(hProcess, (LPVOID)AddressToTrace, TraceMemory, MaximumReadSize, &ueNumberOfBytesRead)) + { + cMem = (PMEMORY_CMP_HANDLER)TraceMemory; + if(cMem->DataByte[0] == 0xEB && cMem->DataByte[1] == 0x01 && ((cMem->DataByte[3] >= 0x50 && cMem->DataByte[3] <= 0x5F) || cMem->DataByte[3] == 0x6A || cMem->DataByte[3] == 0x68)) + { + KnownRedirectionIndex = NULL; // ; PeX 0.99 fail safe! + } + else if(cMem->DataByte[0] == 0x68 && cMem->DataByte[5] == 0x81 && cMem->DataByte[12] == 0xC3) + { + KnownRedirectionIndex = 1; // ; RLP 0.7.4 & CryptoPeProtector 0.9.x & ACProtect + /* ;$ ==> > 68 904B4013 PUSH 13404B90 + ;$+5 > 812C24 0A9E589B SUB DWORD PTR SS:[ESP],9B589E0A + ;$+C > C3 RET + ;$+D > 68 E21554DF PUSH DF5415E2 + ;$+12 > 813424 B6DCB2A8 XOR DWORD PTR SS:[ESP],A8B2DCB6 + ;$+19 > C3 RET + ;$+1A > 68 34B2C6B1 PUSH B1C6B234 + ;$+1F > 810424 4A2C21C6 ADD DWORD PTR SS:[ESP],C6212C4A + ;$+26 > C3 RET */ + } + else if(cMem->DataByte[0] == 0xFF && cMem->DataByte[1] == 0x25) + { + KnownRedirectionIndex = 2; // ; tELock 0.80 - 0.85 + // ;$ ==> >- FF25 48018E00 JMP NEAR DWORD PTR DS:[8E0148] + } + else if((cMem->DataByte[0] == 0xFF && cMem->DataByte[1] == 0x35) || (cMem->DataByte[1] == 0xFF && cMem->DataByte[2] == 0x35) && (cMem->DataByte[8] == 0xC3 || cMem->DataByte[9] == 0xC3)) + { + KnownRedirectionIndex = 3; // ; tELock 0.90 - 0.95 + /* ;$ ==> > FF35 AE018E00 PUSH DWORD PTR DS:[8E01AE] ; kernel32.InitializeCriticalSection + ;$+6 > A8 C3 TEST AL,0C3 + ;$+8 > C3 RET + ;$+9 > F9 STC + ;$+A > FF35 B2018E00 PUSH DWORD PTR DS:[8E01B2] ; kernel32.VirtualFree + ;$+10 > 80FA C3 CMP DL,0C3 + ;$+13 > C3 RET */ + } + else if(cMem->DataByte[0] == 0xEB && cMem->DataByte[1] == 0x01 && cMem->DataByte[2] == 0xC9 && cMem->DataByte[3] == 0x60 && cMem->DataByte[4] == 0x0F && cMem->DataByte[5] == 0x31) + { + KnownRedirectionIndex = 8; // ; AlexProtector 1.x + /* ;$ ==> > /EB 01 JMP SHORT 008413F9 + ;$+2 > |C9 LEAVE + ;$+3 > \60 PUSHAD + ;$+4 > 0F31 RDTSC + ;$+6 > EB 01 JMP SHORT 008413FF + ;$+8 > C9 LEAVE + ;$+9 > 8BD8 MOV EBX,EAX + ;$+B > EB 01 JMP SHORT 00841404 + ;... + ;$+33 > 68 E9B9D477 PUSH USER32.PostQuitMessage + ;$+38 > EB 01 JMP SHORT 00841431 + ;$+3A >- E9 C3EB01E9 JMP E985FFF8 */ + } + else if((cMem->DataByte[0] == 0x0B && cMem->DataByte[1] == 0xC5) || (cMem->DataByte[0] == 0x05 && cMem->DataByte[5] == 0xB8 && cMem->DataByte[10] == 0xEB && cMem->DataByte[11] == 0x02)) + { + KnownRedirectionIndex = 5; // ; tELock 0.99 - 1.0 Private! + /* ;008E0122 05 F9DEBE71 ADD EAX,71BEDEF9 + ;008E0127 B8 28018E00 MOV EAX,8E0128 + ;008E012C EB 02 JMP SHORT 008E0130 + ;008E012E CD 20 INT 20 + ;008E0130 05 18000000 ADD EAX,18 + ;008E0135 8B00 MOV EAX,DWORD PTR DS:[EAX] + ;008E0137 35 22018E00 XOR EAX,8E0122 + ;008E013C 90 NOP + ;008E013D 90 NOP + ;008E013E 50 PUSH EAX + ;008E013F C3 RET + ; + ;00850036 13C4 ADC EAX,ESP + ;00850038 E8 0A000000 CALL 00850047 + ;0085003D 90 NOP + ;0085003E 1BC2 SBB EAX,EDX + ;00850040 E9 09000000 JMP 0085004E + ;00850045 1BC3 SBB EAX,EBX + ;00850047 83F8 74 CMP EAX,74 + ;0085004A C3 RET + ;0085004B 98 CWDE + ;0085004C 33C7 XOR EAX,EDI + ;0085004E D6 SALC + ;0085004F B8 50008500 MOV EAX,850050 + ;00850054 EB 02 JMP SHORT 00850058 + ;00850056 CD 20 INT 20 + ;00850058 05 18000000 ADD EAX,18 + ;0085005D 8B00 MOV EAX,DWORD PTR DS:[EAX] + ;0085005F 35 36008500 XOR EAX,850036 + ;00850064 90 NOP + ;00850065 90 NOP + ;00850066 50 PUSH EAX + ;00850067 C3 RET */ + } + else if((cMem->DataByte[0] == 0x13 && cMem->DataByte[1] == 0xC4 && cMem->DataByte[2] == 0xE8) || (cMem->DataByte[0] == 0x83 && cMem->DataByte[3] == 0xE8)) + { + KnownRedirectionIndex = 5; // ; tELock 0.99 - 1.0 Private! + } + else if((cMem->DataByte[0] == 0xB8 || cMem->DataByte[0] == 0x1D || cMem->DataByte[0] == 0x0D || cMem->DataByte[0] == 0x2D) && cMem->DataByte[5] == 0xB8 && cMem->DataByte[10] == 0xEB && cMem->DataByte[11] == 0x02) + { + KnownRedirectionIndex = 5; // ; tELock 0.99 - 1.0 Private! + /* ;011F0000 B8 2107F205 MOV EAX,5F20721 + ;011F0005 B8 06008D00 MOV EAX,8D0006 + ;011F000A EB 02 JMP SHORT 011F000E + ;011F000C CD 20 INT 20 + ;011F000E 05 18000000 ADD EAX,18 + ;011F0013 8B00 MOV EAX,DWORD PTR DS:[EAX] + ;011F0015 35 00008D00 XOR EAX,8D0000 + ;011F001A 90 NOP + ;011F001B 90 NOP + ;011F001C 50 PUSH EAX + ;011F001D C3 RET + ; + ;01360000 1D A508F205 SBB EAX,5F208A5 + ;01360005 B8 28008D00 MOV EAX,8D0028 + ;0136000A EB 02 JMP SHORT 0136000E + ;0136000C CD 20 INT 20 + ;0136000E 05 18000000 ADD EAX,18 + ;01360013 8B00 MOV EAX,DWORD PTR DS:[EAX] + ;01360015 35 22008D00 XOR EAX,8D0022 + ;0136001A 90 NOP + ;0136001B 90 NOP + ;0136001C 50 PUSH EAX + ;0136001D C3 RET + ; + ;014B0000 0D F918F205 OR EAX,5F218F9 + ;014B0005 B8 4A008D00 MOV EAX,8D004A + ;014B000A EB 02 JMP SHORT 014B000E + ;014B000C CD 20 INT 20 + ;014B000E 05 18000000 ADD EAX,18 + ;014B0013 8B00 MOV EAX,DWORD PTR DS:[EAX] + ;014B0015 35 44008D00 XOR EAX,8D0044 + ;014B001A 90 NOP + ;014B001B 90 NOP + ;014B001C 50 PUSH EAX + ;014B001D C3 RET + ; + ;01750000 2D 0B37F205 SUB EAX,5F2370B + ;01750005 B8 8E008D00 MOV EAX,8D008E + ;0175000A EB 02 JMP SHORT 0175000E + ;0175000C CD 20 INT 20 + ;0175000E 05 18000000 ADD EAX,18 + ;01750013 8B00 MOV EAX,DWORD PTR DS:[EAX] + ;01750015 35 88008D00 XOR EAX,8D0088 + ;0175001A 90 NOP + ;0175001B 90 NOP + ;0175001C 50 PUSH EAX + ;0175001D C3 RET + ; + ;019F0000 0BC4 OR EAX,ESP + ;019F0002 F9 STC + ;019F0003 E8 0B000000 CALL 019F0013 + ;019F0008 90 NOP + ;019F0009 13C4 ADC EAX,ESP + ;019F000B E9 0A000000 JMP 019F001A + ;019F0010 F9 STC + ;019F0011 13C3 ADC EAX,EBX + ;019F0013 98 CWDE + ;019F0014 03C2 ADD EAX,EDX + ;019F0016 C3 RET + ; + ;01B40000 48 DEC EAX + ;01B40001 E8 0D000000 CALL 01B40013 + ;01B40006 03C5 ADD EAX,EBP + ;01B40008 FC CLD + ;01B40009 E9 0A000000 JMP 01B40018 + ;01B4000E 35 D82FF205 XOR EAX,5F22FD8 + ;01B40013 C1C8 9A ROR EAX,9A + ;01B40016 C3 RET */ + } + else if((cMem->DataByte[0] == 0x0B && cMem->DataByte[1] == 0xC4 && cMem->DataByte[2] == 0xF9 && cMem->DataByte[3] == 0xE8) || (cMem->DataByte[0] == 0x48 && cMem->DataByte[1] == 0xE8)) + { + KnownRedirectionIndex = 5; // ; tELock 0.99 - 1.0 Private! + } + else if((cMem->DataByte[0] == 0xB8 && cMem->DataByte[5] == 0xE8 && cMem->DataByte[10] == 0xF9 && cMem->DataByte[11] == 0xE9) && (cMem->DataByte[0] == 0xE8 && cMem->DataByte[1] == 0x0B && cMem->DataByte[10] == 0xE9 && cMem->DataByte[11] == 0x05 && cMem->DataByte[15] == 0x90 && cMem->DataByte[16] == 0xC3)) + { + KnownRedirectionIndex = 5; // ; tELock 0.99 - 1.0 Private! + /* ;01C90000 B8 B853F205 MOV EAX,5F253B8 + ;01C90005 E8 07000000 CALL 01C90011 + ;01C9000A F9 STC + ;01C9000B E9 07000000 JMP 01C90017 + ;01C90010 90 NOP + ;01C90011 23C3 AND EAX,EBX + ;01C90013 C3 RET + ; + ;00A40022 1BC2 SBB EAX,EDX + ;00A40024 E8 08000000 CALL 00A40031 + ;00A40029 40 INC EAX + ;00A4002A E9 09000000 JMP 00A40038 + ;00A4002F 33C7 XOR EAX,EDI + ;00A40031 C1E8 92 SHR EAX,92 + ;00A40034 C3 RET + ;00A40035 83E0 25 AND EAX,25 + ;00A40038 25 E5AE65DD AND EAX,DD65AEE5 + ;00A4003D B8 3E00A400 MOV EAX,0A4003E + ;00A40042 EB 02 JMP SHORT 00A40046 + ;00A40044 CD 20 INT 20 + ;00A40046 05 18000000 ADD EAX,18 + ;00A4004B 8B00 MOV EAX,DWORD PTR DS:[EAX] + ;00A4004D 35 2200A400 XOR EAX,0A40022 + ;00A40052 90 NOP + ;00A40053 90 NOP + ;00A40054 50 PUSH EAX + ;00A40055 C3 RET + ; + ;00A4005A E8 0B000000 CALL 00A4006A + ;00A4005F 15 06F265DD ADC EAX,DD65F206 + ;00A40064 E9 05000000 JMP 00A4006E + ;00A40069 90 NOP + ;00A4006A C3 RET + ;00A4006B 1BC5 SBB EAX,EBP + ;00A4006D 40 INC EAX + ;00A4006E 1BC0 SBB EAX,EAX + ;00A40070 F9 STC + ;00A40071 B8 7200A400 MOV EAX,0A40072 + ;00A40076 EB 02 JMP SHORT 00A4007A + ;00A40078 CD 20 INT 20 + ;00A4007A 05 18000000 ADD EAX,18 + ;00A4007F 8B00 MOV EAX,DWORD PTR DS:[EAX] + ;00A40081 35 5A00A400 XOR EAX,0A4005A + ;00A40086 90 NOP + ;00A40087 90 NOP + ;00A40088 50 PUSH EAX + ;00A40089 C3 RET */ + } + else if(cMem->DataByte[0] == 0x1B && cMem->DataByte[1] == 0xC2 && cMem->DataByte[2] == 0xE8 && cMem->DataByte[3] == 0x08 && cMem->DataByte[7] == 0x40 && cMem->DataByte[8] == 0xE9 && cMem->DataByte[9] == 0x09 && cMem->DataByte[10] == 0x00) + { + KnownRedirectionIndex = 5; // ; tELock 0.99 - 1.0 Private! + } + else if(cMem->DataByte[0] == 0x68 && cMem->DataByte[5] == 0xE9) + { + RtlMoveMemory(&TestAddressX86, &cMem->DataByte[1], 4); + if(TestAddressX86 > AddressToTrace) + { + if(ImporterGetAPIName((ULONG_PTR)TestAddressX86) != NULL) + { + KnownRedirectionIndex = 6; // ; ReCrypt 0.74 + /* ;001739F1 68 E9D9D477 PUSH User32.EndDialog + ;001739F6 ^ E9 FDFEFFFF JMP 001738F8 */ + } + } + } + else if((cMem->DataByte[0] == 0xE8 && cMem->DataByte[5] == 0x58 && cMem->DataByte[6] == 0xEB && cMem->DataByte[7] == 0x01) || (cMem->DataByte[0] == 0xC8 && cMem->DataByte[4] == 0xE8 && cMem->DataByte[9] == 0x5B)) + { + KnownRedirectionIndex = 7; // ; Orien 2.1x + /* ;GetCommandLineA + ;$ ==> >/$ E8 00000000 CALL crackme_.0040DF8F + ;$+5 >|$ 58 POP EAX + ;$+6 >|. EB 01 JMP SHORT crackme_.0040DF93 + ;$+8 >| B8 DB B8 + ;$+9 >|> 85DB TEST EBX,EBX + ;$+B >|. 2D 8F1F0000 SUB EAX,1F8F + ;$+10 >|. EB 01 JMP SHORT crackme_.0040DF9D + ;$+12 >| A8 DB A8 + ;$+13 >|> 8D80 F0550000 LEA EAX,DWORD PTR DS:[EAX+55F0] + ;$+19 >\. C3 RET + ;GetCommandLineW + ;$ ==> > . E8 00000000 CALL crackme_.0040DFA9 + ;$+5 >/$ 58 POP EAX + ;$+6 >|. EB 01 JMP SHORT crackme_.0040DFAD + ;$+8 >| B8 DB B8 + ;$+9 >|> 85DB TEST EBX,EBX + ;$+B >|. 2D A91F0000 SUB EAX,1FA9 + ;$+10 >|. EB 01 JMP SHORT crackme_.0040DFB7 + ;$+12 >| A8 DB A8 + ;$+13 >|> 8D80 F4560000 LEA EAX,DWORD PTR DS:[EAX+56F4] + ;$+19 >\. C3 RET + ;ExitProcess + ;$ ==> > $ C8 000000 ENTER 0,0 + ;$+4 > . E8 00000000 CALL crackme_.0040DF2A + ;$+9 > $ 5B POP EBX + ;$+A > . EB 01 JMP SHORT crackme_.0040DF2E + ;$+C > B8 DB B8 + ;$+D > > 85DB TEST EBX,EBX + ;$+F > . 81EB 2A1F0000 SUB EBX,1F2A + ;$+15 > . EB 01 JMP SHORT crackme_.0040DF39 + ;$+17 > A8 DB A8 + ;$+18 > > 8D83 4D310000 LEA EAX,DWORD PTR DS:[EBX+314D] + ;$+1E > . 8038 00 CMP BYTE PTR DS:[EAX],0 + ;$+21 > . 74 29 JE SHORT crackme_.0040DF6D + ;$+23 > . EB 01 JMP SHORT crackme_.0040DF47 + ;$+25 > A8 DB A8 + ;$+26 > > 8D93 55380000 LEA EDX,DWORD PTR DS:[EBX+3855] + ;$+2C > . E8 01000000 CALL crackme_.0040DF53 + ;$+31 > E9 DB E9 + ;$+32 > $ 83EC FC SUB ESP,-4 + ;$+35 > . 6A 00 PUSH 0 + ;$+37 > . 52 PUSH EDX + ;$+38 > . 50 PUSH EAX + ;$+39 > . 6A 00 PUSH 0 + ;$+3B > . E8 05000000 CALL crackme_.0040DF66 + ;$+40 > . EB 0A JMP SHORT crackme_.0040DF6D + ;$+42 > 88 DB 88 + ;$+43 > FC DB FC + ;$+44 > B6 DB B6 + ;$+45 > $ FFA3 FF3A0000 JMP NEAR DWORD PTR DS:[EBX+3AFF] + ;$+4B > CD DB CD + ;$+4C > > E8 01000000 CALL crackme_.0040DF73 + ;$+51 > E9 DB E9 + ;$+52 > $ 83EC FC SUB ESP,-4 + ;$+55 > . FF75 08 PUSH DWORD PTR SS:[EBP+8] + ;$+58 > . E8 05000000 CALL crackme_.0040DF83 + ;$+5D > . EB 0A JMP SHORT crackme_.0040DF8A + ;$+5F > 88 DB 88 + ;$+60 > FC DB FC + ;$+61 > B6 DB B6 + ;$+62 > $ FFA3 BF3A0000 JMP NEAR DWORD PTR DS:[EBX+3ABF] */ + } + else if((cMem->DataByte[0] == 0xEB && cMem->DataByte[1] == 0x01 && cMem->DataByte[2] == 0x66 && cMem->DataByte[3] == 0x1B) || (cMem->DataByte[0] == 0xEB && cMem->DataByte[1] == 0x02 && cMem->DataByte[2] == 0xCD && cMem->DataByte[3] == 0x20) || (cMem->DataByte[0] == 0xEB && cMem->DataByte[1] == 0x01 && cMem->DataByte[2] == 0xB8 && cMem->DataByte[3] == 0xEB)) + { + KnownRedirectionIndex = 4; // ; tELock 0.96 - 0.98 + /* ;(BYTE PTR[ESI] == 0EBh && (BYTE PTR[ESI+3] == 0EBh || BYTE PTR[ESI+2] == 0EBh)) + ;017B0000 0BE4 OR ESP,ESP + ;017B0002 75 01 JNZ SHORT 017B0005 + ; + ;15940000 85E4 TEST ESP,ESP + ;15940002 79 03 JNS SHORT 15940007 + ; + ;008E0359 B8 8DE44500 MOV EAX,45E48D + ;008E035E 90 NOP + ;008E035F FF30 PUSH DWORD PTR DS:[EAX] + ;008E0361 C3 RET + ; + ;008F0033 B8 AF008F00 MOV EAX,8F00AF + ;008F0038 40 INC EAX + ;008F0039 FF30 PUSH DWORD PTR DS:[EAX] + ;008F003B C3 RET + ; + ;008E02F7 B8 20078E00 MOV EAX,8E0720 + ;008E02FC FF20 JMP NEAR DWORD PTR DS:[EAX] */ + } + else if((cMem->DataByte[0] == 0xEB && cMem->DataByte[1] == 0x03 && cMem->DataByte[2] == 0xFF && cMem->DataByte[3] == 0xEB) || (cMem->DataByte[0] == 0xEB && cMem->DataByte[1] == 0x01 && cMem->DataByte[2] == 0xB8 && cMem->DataByte[3] == 0x05) || (cMem->DataByte[0] == 0xEB && cMem->DataByte[1] == 0x02 && cMem->DataByte[2] == 0xFF && cMem->DataByte[3] == 0x20)) + { + KnownRedirectionIndex = 4; // ; tELock 0.96 - 0.98 + } + else if((cMem->DataByte[0] == 0xF9 || cMem->DataByte[0] == 0xF8) || (cMem->DataByte[0] == 0x0B && cMem->DataByte[1] == 0xE4) || (cMem->DataByte[0] == 0x85 && cMem->DataByte[1] == 0xE4)) + { + KnownRedirectionIndex = 4; // ; tELock 0.96 - 0.98 + } + else if(cMem->DataByte[0] == 0xEB && (cMem->DataByte[1] > NULL && cMem->DataByte[1] < 4)) + { + i = 2; + j = 30; + while(j > NULL) + { + if(cMem->DataByte[i] == 0xB8 && (cMem->DataByte[i+5] == 0x40 || cMem->DataByte[i+5] == 0x90) && cMem->DataByte[i+6] == 0xFF && cMem->DataByte[i+7] == 0x30 && cMem->DataByte[i+8] == 0xC3) + { + KnownRedirectionIndex = 4; // ; tELock 0.96 - 0.98 + j = 1; + } + i++; + j--; + } + } + else if(HashCheck) + { + if(cMem->DataByte[0] == 0x9C || cMem->DataByte[0] == 0xEB) + { + MemoryHash = EngineHashMemory((char*)TraceMemory, 192, MemoryHash); + if(MemoryHash == 0x5AF7E209 || MemoryHash == 0xEB480CAC || MemoryHash == 0x86218561 || MemoryHash == 0xCA9ABD85) + { + KnownRedirectionIndex = 9; // ; SVKP 1.x + } + else if(MemoryHash == 0xF1F84A98 || MemoryHash == 0x91823290 || MemoryHash == 0xBEE6BAA0 || MemoryHash == 0x79603232) + { + KnownRedirectionIndex = 9; // ; SVKP 1.x + } + } + } + VirtualFree(TraceMemory, NULL, MEM_RELEASE); + return(KnownRedirectionIndex); + } + else + { + VirtualFree(TraceMemory, NULL, MEM_RELEASE); + } + } + } + return(NULL); +} +__declspec(dllexport) long long __stdcall TracerFixKnownRedirection(HANDLE hProcess, ULONG_PTR AddressToTrace, DWORD RedirectionId) +{ + + int i = NULL; + DWORD TestAddressX86; + DWORD ReadAddressX86; + DWORD MaximumReadSize; + DWORD MemoryHash = NULL; + PMEMORY_CMP_HANDLER cMem; + MEMORY_BASIC_INFORMATION MemInfo; + ULONG_PTR ueNumberOfBytesRead = NULL; + LPVOID TracerReadMemory = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE); + cMem = (PMEMORY_CMP_HANDLER)TracerReadMemory; + + VirtualQueryEx(hProcess, (LPVOID)AddressToTrace, &MemInfo, sizeof MEMORY_BASIC_INFORMATION); + if(MemInfo.RegionSize > NULL) + { + MaximumReadSize = (DWORD)((ULONG_PTR)MemInfo.BaseAddress + MemInfo.RegionSize - AddressToTrace); + if(MaximumReadSize > 0x1000) + { + MaximumReadSize = 0x1000; + } + } + if(RedirectionId == NULL) + { + RedirectionId = (DWORD)TracerDetectRedirection(hProcess, AddressToTrace); + } + if(RedirectionId == 1) // TracerFix_ACProtect + { + __try + { + if(ReadProcessMemory(hProcess, (LPVOID)AddressToTrace, TracerReadMemory, MaximumReadSize, &ueNumberOfBytesRead)) + { + RtlMoveMemory(&TestAddressX86, &cMem->DataByte[1], 4); + if(cMem->DataByte[5] == 0x81 && cMem->DataByte[6] == 0x2C) + { + RtlMoveMemory(&ReadAddressX86, &cMem->DataByte[8], 4); + TestAddressX86 = TestAddressX86 - ReadAddressX86; + } + else if(cMem->DataByte[5] == 0x81 && cMem->DataByte[6] == 0x34) + { + RtlMoveMemory(&ReadAddressX86, &cMem->DataByte[8], 4); + TestAddressX86 = TestAddressX86 ^ ReadAddressX86; + } + else if(cMem->DataByte[5] == 0x81 && cMem->DataByte[6] == 0x04) + { + RtlMoveMemory(&ReadAddressX86, &cMem->DataByte[8], 4); + TestAddressX86 = TestAddressX86 + ReadAddressX86; + } + VirtualFree(TracerReadMemory, NULL, MEM_RELEASE); + return((DWORD)TestAddressX86); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + VirtualFree(TracerReadMemory, NULL, MEM_RELEASE); + return(NULL); + } + } + else if(RedirectionId == 2) // TracerFix_tELock_varA + { + __try + { + if(ReadProcessMemory(hProcess, (LPVOID)AddressToTrace, TracerReadMemory, MaximumReadSize, &ueNumberOfBytesRead)) + { + RtlMoveMemory(&TestAddressX86, &cMem->DataByte[2], 4); + if(ReadProcessMemory(hProcess, (LPVOID)TestAddressX86, &TestAddressX86, 4, &ueNumberOfBytesRead)) + { + VirtualFree(TracerReadMemory, NULL, MEM_RELEASE); + return((DWORD)TestAddressX86); + } + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + VirtualFree(TracerReadMemory, NULL, MEM_RELEASE); + return(NULL); + } + } + else if(RedirectionId == 3) // TracerFix_tELock_varB + { + __try + { + if(ReadProcessMemory(hProcess, (LPVOID)AddressToTrace, TracerReadMemory, MaximumReadSize, &ueNumberOfBytesRead)) + { + if(cMem->DataByte[0] == 0xFF && cMem->DataByte[1] == 0x35) + { + RtlMoveMemory(&TestAddressX86, &cMem->DataByte[2], 4); + } + else + { + RtlMoveMemory(&TestAddressX86, &cMem->DataByte[3], 4); + } + if(ReadProcessMemory(hProcess, (LPVOID)TestAddressX86, &TestAddressX86, 4, &ueNumberOfBytesRead)) + { + VirtualFree(TracerReadMemory, NULL, MEM_RELEASE); + return((DWORD)TestAddressX86); + } + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + VirtualFree(TracerReadMemory, NULL, MEM_RELEASE); + return(NULL); + } + } + else if(RedirectionId == 4) // TracerFix_tELock_varC + { + __try + { + if(ReadProcessMemory(hProcess, (LPVOID)AddressToTrace, TracerReadMemory, MaximumReadSize, &ueNumberOfBytesRead)) + { + i = 100; + if(cMem->DataByte[0] == 0xEB && (cMem->DataByte[1] > 0 && cMem->DataByte[1] < 4)) + { + cMem = (PMEMORY_CMP_HANDLER)((ULONG_PTR)cMem + cMem->DataByte[1] + 2); + } + while(i > NULL && (cMem->DataByte[0] != 0xFF && (cMem->DataByte[1] != 0x20 || cMem->DataByte[1] != 0x30))) + { + cMem = (PMEMORY_CMP_HANDLER)((ULONG_PTR)cMem + 1); + i--; + } + if(i != NULL && cMem->DataByte[0] == 0xFF && cMem->DataByte[1] == 0x20) + { + if(cMem->DataByte[2] != 0x90) + { + cMem = (PMEMORY_CMP_HANDLER)((ULONG_PTR)cMem + 1); + while(i > NULL && (cMem->DataByte[0] != 0xFF && (cMem->DataByte[1] != 0x20 || cMem->DataByte[1] != 0x30))) + { + cMem = (PMEMORY_CMP_HANDLER)((ULONG_PTR)cMem + 1); + i--; + } + } + } + if(i != NULL && cMem->DataByte[0] == 0xFF && cMem->DataByte[1] == 0x30) + { + cMem = (PMEMORY_CMP_HANDLER)((ULONG_PTR)cMem - 6); + if(cMem->DataByte[0] == 0xB8) + { + RtlMoveMemory(&TestAddressX86, &cMem->DataByte[1], 4); + if(cMem->DataByte[5] == 0x40) + { + TestAddressX86++; + } + } + else + { + RtlMoveMemory(&TestAddressX86, &cMem->DataByte[2], 4); + } + if(ReadProcessMemory(hProcess, (LPVOID)TestAddressX86, &TestAddressX86, 4, &ueNumberOfBytesRead)) + { + VirtualFree(TracerReadMemory, NULL, MEM_RELEASE); + return((DWORD)TestAddressX86); + } + } + else if(i != NULL && cMem->DataByte[0] == 0xFF && cMem->DataByte[1] == 0x20) + { + cMem = (PMEMORY_CMP_HANDLER)((ULONG_PTR)cMem - 6); + RtlMoveMemory(&TestAddressX86, &cMem->DataByte[2], 4); + if(ReadProcessMemory(hProcess, (LPVOID)TestAddressX86, &TestAddressX86, 4, &ueNumberOfBytesRead)) + { + VirtualFree(TracerReadMemory, NULL, MEM_RELEASE); + return((DWORD)TestAddressX86); + } + } + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + VirtualFree(TracerReadMemory, NULL, MEM_RELEASE); + return(NULL); + } + } + else if(RedirectionId == 5) // TracerFix_tELock_varD + { + __try + { + if(ReadProcessMemory(hProcess, (LPVOID)AddressToTrace, TracerReadMemory, MaximumReadSize, &ueNumberOfBytesRead)) + { + i = 100; + while(i > NULL && (cMem->DataByte[0] != 0x50 || cMem->DataByte[1] != 0xC3)) + { + cMem = (PMEMORY_CMP_HANDLER)((ULONG_PTR)cMem + 1); + i--; + } + if(i != NULL && cMem->DataByte[0] == 0x50 && cMem->DataByte[1] == 0xC3) + { + cMem = (PMEMORY_CMP_HANDLER)((ULONG_PTR)cMem - 0x16); + RtlMoveMemory(&ReadAddressX86, &cMem->DataByte[0x10], 4); + RtlMoveMemory(&TestAddressX86, &cMem->DataByte[0], 4); + TestAddressX86 = TestAddressX86 + 0x18; + if(ReadProcessMemory(hProcess, (LPVOID)TestAddressX86, &TestAddressX86, 4, &ueNumberOfBytesRead)) + { + TestAddressX86 = TestAddressX86 ^ ReadAddressX86; + VirtualFree(TracerReadMemory, NULL, MEM_RELEASE); + return((DWORD)TestAddressX86); + } + } + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + VirtualFree(TracerReadMemory, NULL, MEM_RELEASE); + return(NULL); + } + } + else if(RedirectionId == 6) // TracerFix_ReCrypt + { + __try + { + if(ReadProcessMemory(hProcess, (LPVOID)AddressToTrace, TracerReadMemory, MaximumReadSize, &ueNumberOfBytesRead)) + { + RtlMoveMemory(&TestAddressX86, &cMem->DataByte[1], 4); + VirtualFree(TracerReadMemory, NULL, MEM_RELEASE); + return((DWORD)TestAddressX86); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + VirtualFree(TracerReadMemory, NULL, MEM_RELEASE); + return(NULL); + } + } + else if(RedirectionId == 7) // TracerFix_Orien + { + __try + { + if(ReadProcessMemory(hProcess, (LPVOID)AddressToTrace, TracerReadMemory, MaximumReadSize, &ueNumberOfBytesRead)) + { + if(cMem->DataByte[0] == 0xE8) + { + RtlMoveMemory(&ReadAddressX86, &cMem->DataByte[0x15], 4); + if(ReadAddressX86 == 0x55F0) + { + TestAddressX86 = (DWORD)ImporterGetRemoteAPIAddress(hProcess, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetCommandLineA")); + } + else + { + TestAddressX86 = (DWORD)ImporterGetRemoteAPIAddress(hProcess, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetCommandLineW")); + } + VirtualFree(TracerReadMemory, NULL, MEM_RELEASE); + return((DWORD)TestAddressX86); + } + else if(cMem->DataByte[0] == 0xC8) + { + TestAddressX86 = (DWORD)ImporterGetRemoteAPIAddress(hProcess, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"), "ExitProcess")); + VirtualFree(TracerReadMemory, NULL, MEM_RELEASE); + return((DWORD)TestAddressX86); + } + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + VirtualFree(TracerReadMemory, NULL, MEM_RELEASE); + return(NULL); + } + } + else if(RedirectionId == 8) // TracerFix_AlexProtector + { + __try + { + if(ReadProcessMemory(hProcess, (LPVOID)AddressToTrace, TracerReadMemory, MaximumReadSize, &ueNumberOfBytesRead)) + { + cMem = (PMEMORY_CMP_HANDLER)((ULONG_PTR)cMem + 0x34); + RtlMoveMemory(&TestAddressX86, &cMem->DataByte[0], 4); + VirtualFree(TracerReadMemory, NULL, MEM_RELEASE); + return((DWORD)TestAddressX86); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + VirtualFree(TracerReadMemory, NULL, MEM_RELEASE); + return(NULL); + } + } + else if(RedirectionId == 9 && MaximumReadSize > 192) // TracerFix_SVKP + { + __try + { + if(ReadProcessMemory(hProcess, (LPVOID)AddressToTrace, TracerReadMemory, MaximumReadSize, &ueNumberOfBytesRead)) + { + if(cMem->DataByte[0] == 0x9C || cMem->DataByte[0] == 0xEB) + { + MemoryHash = EngineHashMemory((char*)TracerReadMemory, 192, MemoryHash); + if(MemoryHash == 0x5AF7E209) + { + TestAddressX86 = (DWORD)ImporterGetRemoteAPIAddress(hProcess, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetCommandLineA")); + } + else if(MemoryHash == 0xEB480CAC) + { + TestAddressX86 = (DWORD)ImporterGetRemoteAPIAddress(hProcess, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"), "ExitProcess")); + } + else if(MemoryHash == 0x86218561) + { + TestAddressX86 = (DWORD)ImporterGetRemoteAPIAddress(hProcess, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetCurrentProcess")); + } + else if(MemoryHash == 0xCA9ABD85) + { + TestAddressX86 = (DWORD)ImporterGetRemoteAPIAddress(hProcess, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetVersion")); + } + else if(MemoryHash == 0xF1F84A98) + { + TestAddressX86 = (DWORD)ImporterGetRemoteAPIAddress(hProcess, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetVersionExA")); + } + else if(MemoryHash == 0x91823290) + { + TestAddressX86 = (DWORD)ImporterGetRemoteAPIAddress(hProcess, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetModuleHandleA")); + } + else if(MemoryHash == 0xBEE6BAA0) + { + TestAddressX86 = (DWORD)ImporterGetRemoteAPIAddress(hProcess, (ULONG_PTR)GetProcAddress(GetModuleHandleA("user32.dll"), "MessageBoxA")); + } + else if(MemoryHash == 0x79603232) + { + TestAddressX86 = (DWORD)ImporterGetRemoteAPIAddress(hProcess, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetModuleHandleA")); + } + VirtualFree(TracerReadMemory, NULL, MEM_RELEASE); + return((DWORD)TestAddressX86); + } + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + VirtualFree(TracerReadMemory, NULL, MEM_RELEASE); + return(NULL); + } + } + VirtualFree(TracerReadMemory, NULL, MEM_RELEASE); + return(NULL); +} +// TitanEngine.Exporter.functions: +__declspec(dllexport) void __stdcall ExporterCleanup() +{ + + int i = NULL; + + for(i = 0; i < 1000; i++) + { + expExportAddress[i] = 0; + expSortedNamePointers[i] = 0; + expNamePointers[i] = 0; + expNameHashes[i] = 0; + expOrdinals[i] = 0; + } + //RtlZeroMemory(&szExportFileName, 512); + RtlZeroMemory(&expExportData, sizeof IMAGE_EXPORT_DIRECTORY); + VirtualFree(expTableData, NULL, MEM_RELEASE); + expExportNumber = NULL; + expTableData = NULL; + expImageBase = NULL; +} +__declspec(dllexport) void __stdcall ExporterSetImageBase(ULONG_PTR ImageBase) +{ + expImageBase = ImageBase; +} +__declspec(dllexport) void __stdcall ExporterInit(DWORD MemorySize, ULONG_PTR ImageBase, DWORD ExportOrdinalBase, char* szExportModuleName) +{ + + if(expTableData != NULL) + { + ExporterCleanup(); + } + expExportData.Base = ExportOrdinalBase; + expTableData = VirtualAlloc(NULL, MemorySize, MEM_COMMIT, PAGE_READWRITE); + if(szExportModuleName != NULL) + { + RtlMoveMemory(expTableData, szExportModuleName, lstrlenA(szExportModuleName)); + expTableDataCWP = (LPVOID)((ULONG_PTR)expTableData + lstrlenA(szExportModuleName) + 2); + expNamePresent = true; + } + else + { + expTableDataCWP = expTableData; + expNamePresent = false; + } + expImageBase = ImageBase; +} +__declspec(dllexport) bool __stdcall ExporterAddNewExport(char* szExportName, DWORD ExportRelativeAddress) +{ + + unsigned int i; + DWORD NameHash; + + if(expTableDataCWP != NULL && szExportName != NULL) + { + NameHash = (DWORD)EngineHashString(szExportName); + for(i = 0; i < expExportNumber; i++) + { + if(expNameHashes[i] == NameHash) + { + return(true); + } + } + expExportAddress[expExportNumber] = ExportRelativeAddress; + expNamePointers[expExportNumber] = (ULONG_PTR)expTableDataCWP; + expNameHashes[expExportNumber] = (DWORD)EngineHashString(szExportName); + expOrdinals[expExportNumber] = (WORD)(expExportNumber); + RtlMoveMemory(expTableDataCWP, szExportName, lstrlenA(szExportName)); + expTableDataCWP = (LPVOID)((ULONG_PTR)expTableDataCWP + lstrlenA(szExportName) + 2); + expExportNumber++; + return(true); + } + return(false); +} +__declspec(dllexport) bool __stdcall ExporterAddNewOrdinalExport(DWORD OrdinalNumber, DWORD ExportRelativeAddress) +{ + + unsigned int i = NULL; + char szExportFunctionName[512]; + + RtlZeroMemory(&szExportFunctionName, 512); + if(expTableDataCWP != NULL) + { + if(expExportNumber == NULL) + { + expExportData.Base = OrdinalNumber; + wsprintfA(szExportFunctionName, "Func%d", expExportNumber + 1); + return(ExporterAddNewExport(szExportFunctionName, ExportRelativeAddress)); + } + else + { + if(OrdinalNumber == expExportData.Base + expExportNumber - 1) + { + wsprintfA(szExportFunctionName, "Func%d", expExportNumber + 1); + return(ExporterAddNewExport(szExportFunctionName, ExportRelativeAddress)); + } + else if(OrdinalNumber > expExportData.Base + expExportNumber - 1) + { + for(i = expExportData.Base + expExportNumber - 1; i <= OrdinalNumber; i++) + { + RtlZeroMemory(&szExportFunctionName, 512); + wsprintfA(szExportFunctionName, "Func%d", expExportNumber + 1); + ExporterAddNewExport(szExportFunctionName, ExportRelativeAddress); + } + return(true); + } + else + { + return(true); + } + } + } + return(false); +} +__declspec(dllexport) long __stdcall ExporterGetAddedExportCount() +{ + return(expExportNumber); +} +__declspec(dllexport) long __stdcall ExporterEstimatedSize() +{ + + DWORD EstimatedSize = NULL; + + EstimatedSize = (DWORD)((ULONG_PTR)expTableDataCWP - (ULONG_PTR)expTableData); + EstimatedSize = EstimatedSize + (expExportNumber * 12) + sizeof IMAGE_EXPORT_DIRECTORY; + return(EstimatedSize); +} +__declspec(dllexport) bool __stdcall ExporterBuildExportTable(ULONG_PTR StorePlace, ULONG_PTR FileMapVA) +{ + + unsigned int i = NULL; + unsigned int j = NULL; + LPVOID expBuildExportDataOld; + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + LPVOID expBuildExportData; + LPVOID expBuildExportDataCWP; + DWORD StorePlaceRVA = (DWORD)ConvertFileOffsetToVA(FileMapVA, StorePlace, false); + ULONG_PTR TempULONG; + DWORD TempDWORD; + BOOL FileIs64; + + if(expTableDataCWP != NULL) + { + expBuildExportData = VirtualAlloc(NULL, ExporterEstimatedSize(), MEM_COMMIT, PAGE_READWRITE); + expBuildExportDataCWP = (LPVOID)((ULONG_PTR)expBuildExportData + sizeof IMAGE_EXPORT_DIRECTORY); + + expExportData.NumberOfNames = expExportNumber; + expExportData.NumberOfFunctions = expExportNumber; + for(i = 0; i < expExportNumber; i++) + { + for(j = 0; j < expExportNumber; j++) + { + if(lstrcmpiA((PCHAR)expNamePointers[i], (PCHAR)expNamePointers[j]) < NULL) + { + TempULONG = expNamePointers[j]; + expNamePointers[j] = expNamePointers[i]; + expNamePointers[i] = TempULONG; + TempDWORD = expExportAddress[j]; + expExportAddress[j] = expExportAddress[i]; + expExportAddress[i] = TempDWORD; + } + } + } + + if(expNamePresent) + { + expExportData.Name = StorePlaceRVA + (DWORD)((ULONG_PTR)expBuildExportDataCWP - (ULONG_PTR)expBuildExportData); + RtlMoveMemory(expBuildExportDataCWP, (LPVOID)expTableData, lstrlenA((PCHAR)expTableData)); + expBuildExportDataCWP = (LPVOID)((ULONG_PTR)expBuildExportDataCWP + lstrlenA((PCHAR)expTableData) + 2); + } + for(i = 0; i < expExportNumber; i++) + { + RtlMoveMemory(expBuildExportDataCWP, (LPVOID)expNamePointers[i], lstrlenA((PCHAR)expNamePointers[i])); + expBuildExportDataOld = expBuildExportDataCWP; + expBuildExportDataCWP = (LPVOID)((ULONG_PTR)expBuildExportDataCWP + lstrlenA((PCHAR)expNamePointers[i]) + 2); + expSortedNamePointers[i] = (DWORD)((ULONG_PTR)expBuildExportDataOld - (ULONG_PTR)expBuildExportData) + StorePlaceRVA; + } + expExportData.AddressOfFunctions = StorePlaceRVA + (DWORD)((ULONG_PTR)expBuildExportDataCWP - (ULONG_PTR)expBuildExportData); + RtlMoveMemory(expBuildExportDataCWP, &expExportAddress, 4 * expExportNumber); + expBuildExportDataCWP = (LPVOID)((ULONG_PTR)expBuildExportDataCWP + 4 * expExportNumber); + expExportData.AddressOfNames = StorePlaceRVA + (DWORD)((ULONG_PTR)expBuildExportDataCWP - (ULONG_PTR)expBuildExportData); + RtlMoveMemory(expBuildExportDataCWP, &expSortedNamePointers, 4 * expExportNumber); + expBuildExportDataCWP = (LPVOID)((ULONG_PTR)expBuildExportDataCWP + 4 * expExportNumber); + expExportData.AddressOfNameOrdinals = StorePlaceRVA + (DWORD)((ULONG_PTR)expBuildExportDataCWP - (ULONG_PTR)expBuildExportData); + RtlMoveMemory(expBuildExportDataCWP, &expOrdinals, 2 * expExportNumber); + expBuildExportDataCWP = (LPVOID)((ULONG_PTR)expBuildExportDataCWP + 2 * expExportNumber); + RtlMoveMemory(expBuildExportData, &expExportData, sizeof IMAGE_EXPORT_DIRECTORY); + __try + { + RtlMoveMemory((LPVOID)StorePlace, expBuildExportData, (DWORD)((ULONG_PTR)expBuildExportDataCWP - (ULONG_PTR)expBuildExportData)); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + VirtualFree(expBuildExportData, NULL, MEM_RELEASE); + ExporterCleanup(); + return(false); + } + + if(FileMapVA != NULL) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, NULL, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + if(!FileIs64) + { + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = (DWORD)StorePlaceRVA; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = (DWORD)((ULONG_PTR)expBuildExportDataCWP - (ULONG_PTR)expBuildExportData); + } + else + { + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = (DWORD)StorePlaceRVA; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = (DWORD)((ULONG_PTR)expBuildExportDataCWP - (ULONG_PTR)expBuildExportData); + } + } + } + VirtualFree(expBuildExportData, NULL, MEM_RELEASE); + ExporterCleanup(); + return(true); + } + return(false); +} +__declspec(dllexport) bool __stdcall ExporterBuildExportTableEx(char* szExportFileName, char* szSectionName) +{ + + wchar_t uniExportFileName[MAX_PATH] = {}; + + if(szExportFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szExportFileName, lstrlenA(szExportFileName)+1, uniExportFileName, sizeof(uniExportFileName)/(sizeof(uniExportFileName[0]))); + return(ExporterBuildExportTableExW(uniExportFileName, szSectionName)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall ExporterBuildExportTableExW(wchar_t* szExportFileName, char* szSectionName) +{ + + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + DWORD NewSectionVO = NULL; + DWORD NewSectionFO = NULL; + bool ReturnValue = false; + + if(ExporterGetAddedExportCount() > NULL) + { + NewSectionVO = AddNewSectionW(szExportFileName, szSectionName, ExporterEstimatedSize()); + if(MapFileExW(szExportFileName, UE_ACCESS_ALL, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + NewSectionFO = (DWORD)ConvertVAtoFileOffset(FileMapVA, NewSectionVO + (ULONG_PTR)GetPE32DataFromMappedFile(FileMapVA, NULL, UE_IMAGEBASE), true); + ReturnValue = ExporterBuildExportTable(NewSectionFO, FileMapVA); + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + if(ReturnValue) + { + return(true); + } + else + { + return(false); + } + } + else + { + return(false); + } + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall ExporterLoadExportTable(char* szFileName) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + + if(szFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + return(ExporterLoadExportTableW(uniFileName)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall ExporterLoadExportTableW(wchar_t* szFileName) +{ + + unsigned int i = 0; + unsigned int j = 0; + unsigned int n = 0; + unsigned int x = 0; + bool ExportPresent = false; + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + PIMAGE_EXPORT_DIRECTORY PEExports; + PEXPORTED_DATA ExportedFunctions; + PEXPORTED_DATA ExportedFunctionNames; + PEXPORTED_DATA_WORD ExportedFunctionOrdinals; + char* ExportName = NULL; + BOOL FileIs64; + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + + if(MapFileExW(szFileName, UE_ACCESS_READ, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, FileHandle, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + if(!FileIs64) + { + if(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress != NULL) + { + PEExports = (PIMAGE_EXPORT_DIRECTORY)(ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + PEHeader32->OptionalHeader.ImageBase), true)); + ExportedFunctions = (PEXPORTED_DATA)(ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)(PEExports->AddressOfFunctions + PEHeader32->OptionalHeader.ImageBase), true)); + ExporterInit(50 * 1024, (ULONG_PTR)PEHeader32->OptionalHeader.ImageBase, PEExports->Base, NULL); + ExportPresent = true; + } + } + else + { + if(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress != NULL) + { + PEExports = (PIMAGE_EXPORT_DIRECTORY)(ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + PEHeader64->OptionalHeader.ImageBase), true)); + ExportedFunctions = (PEXPORTED_DATA)(ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)(PEExports->AddressOfFunctions + PEHeader64->OptionalHeader.ImageBase), true)); + ExporterInit(50 * 1024, (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase, PEExports->Base, NULL); + ExportPresent = true; + } + } + if(ExportPresent) + { + for(n = 0; n <= PEExports->NumberOfNames; n++) + { + ExportPresent = false; + x = n; + if(!FileIs64) + { + ExportedFunctionNames = (PEXPORTED_DATA)(ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)(PEExports->AddressOfNames + PEHeader32->OptionalHeader.ImageBase), true)); + ExportedFunctionOrdinals = (PEXPORTED_DATA_WORD)(ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)(PEExports->AddressOfNameOrdinals + PEHeader32->OptionalHeader.ImageBase), true)); + } + else + { + ExportedFunctionNames = (PEXPORTED_DATA)(ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)(PEExports->AddressOfNames + PEHeader64->OptionalHeader.ImageBase), true)); + ExportedFunctionOrdinals = (PEXPORTED_DATA_WORD)(ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)(PEExports->AddressOfNameOrdinals + PEHeader64->OptionalHeader.ImageBase), true)); + } + for(j = 0; j <= PEExports->NumberOfNames; j++) + { + if(ExportedFunctionOrdinals->OrdinalNumber != x) + { + ExportedFunctionOrdinals = (PEXPORTED_DATA_WORD)((ULONG_PTR)ExportedFunctionOrdinals + 2); + } + else + { + ExportPresent = true; + break; + } + } + if(ExportPresent) + { + ExportedFunctionNames = (PEXPORTED_DATA)((ULONG_PTR)ExportedFunctionNames + j * 4); + if(!FileIs64) + { + ExportName = (char*)(ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)(ExportedFunctionNames->ExportedItem + PEHeader32->OptionalHeader.ImageBase), true)); + } + else + { + ExportName = (char*)(ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)(ExportedFunctionNames->ExportedItem + PEHeader64->OptionalHeader.ImageBase), true)); + } + ExporterAddNewExport(ExportName, ExportedFunctions->ExportedItem); + } + ExportedFunctions = (PEXPORTED_DATA)((ULONG_PTR)ExportedFunctions + 4); + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(true); + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + else + { + return(false); + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); +} +// TitanEngine.Librarian.functions: +__declspec(dllexport) bool __stdcall LibrarianSetBreakPoint(char* szLibraryName, DWORD bpxType, bool SingleShoot, LPVOID bpxCallBack) +{ + + int i = MAX_LIBRARY_BPX; + PLIBRARY_BREAK_DATA ptrLibrarianData = (PLIBRARY_BREAK_DATA)LibrarianData; + + if(szLibraryName != NULL && ptrLibrarianData != NULL) + { + while(i > NULL && ptrLibrarianData->szLibraryName[0] != 0x00) + { + ptrLibrarianData = (PLIBRARY_BREAK_DATA)((ULONG_PTR)ptrLibrarianData + sizeof LIBRARY_BREAK_DATA); + i--; + } + lstrcpyA(&ptrLibrarianData->szLibraryName[0], szLibraryName); + ptrLibrarianData->bpxCallBack = bpxCallBack; + ptrLibrarianData->bpxSingleShoot = SingleShoot; + ptrLibrarianData->bpxType = bpxType; + return(true); + } + return(false); +} +__declspec(dllexport) bool __stdcall LibrarianRemoveBreakPoint(char* szLibraryName, DWORD bpxType) +{ + + int i = MAX_LIBRARY_BPX; + PLIBRARY_BREAK_DATA ptrLibrarianData = (PLIBRARY_BREAK_DATA)LibrarianData; + + if(szLibraryName != NULL && ptrLibrarianData != NULL) + { + while(i > NULL) + { + if(ptrLibrarianData->szLibraryName[0] != 0x00) + { + if(lstrcmpiA(szLibraryName, ptrLibrarianData->szLibraryName) == NULL && (ptrLibrarianData->bpxType == bpxType || bpxType == UE_ON_LIB_ALL)) + { + RtlZeroMemory(ptrLibrarianData, sizeof LIBRARY_BREAK_DATA); + } + } + ptrLibrarianData = (PLIBRARY_BREAK_DATA)((ULONG_PTR)ptrLibrarianData + sizeof LIBRARY_BREAK_DATA); + i--; + } + return(true); + } + return(false); +} +__declspec(dllexport) void* __stdcall LibrarianGetLibraryInfo(char* szLibraryName) +{ + + wchar_t uniLibraryName[MAX_PATH] = {}; + PLIBRARY_ITEM_DATAW LibInfo; + + if(szLibraryName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szLibraryName, lstrlenA(szLibraryName)+1, uniLibraryName, sizeof(uniLibraryName)/(sizeof(uniLibraryName[0]))); + LibInfo = (PLIBRARY_ITEM_DATAW)LibrarianGetLibraryInfoW(uniLibraryName); + if(LibInfo != NULL) + { + RtlZeroMemory(&LibraryInfoData, sizeof LIBRARY_ITEM_DATA); + LibraryInfoData.hFile = LibInfo->hFile; + LibraryInfoData.BaseOfDll = LibInfo->BaseOfDll; + LibraryInfoData.hFileMapping = LibInfo->hFileMapping; + LibraryInfoData.hFileMappingView = LibInfo->hFileMappingView; + WideCharToMultiByte(CP_ACP, NULL, LibInfo->szLibraryName, -1, &LibraryInfoData.szLibraryName[0], sizeof LibraryInfoData.szLibraryName, NULL, NULL); + WideCharToMultiByte(CP_ACP, NULL, LibInfo->szLibraryPath, -1, &LibraryInfoData.szLibraryPath[0], sizeof LibraryInfoData.szLibraryPath, NULL, NULL); + return((void*)&LibraryInfoData); + } + else + { + return(NULL); + } + } + else + { + return(NULL); + } +} +__declspec(dllexport) void* __stdcall LibrarianGetLibraryInfoW(wchar_t* szLibraryName) +{ + + PLIBRARY_ITEM_DATAW hListLibraryPtr = NULL; + + if(hListLibrary != NULL) + { + hListLibraryPtr = (PLIBRARY_ITEM_DATAW)hListLibrary; + while(hListLibraryPtr->hFile != NULL) + { + if(hListLibraryPtr->hFile != (HANDLE)-1) + { + if(lstrcmpiW(hListLibraryPtr->szLibraryName, szLibraryName) == NULL) + { + return((void*)hListLibraryPtr); + } + } + hListLibraryPtr = (PLIBRARY_ITEM_DATAW)((ULONG_PTR)hListLibraryPtr + sizeof LIBRARY_ITEM_DATAW); + } + } + return(NULL); +} +__declspec(dllexport) void* __stdcall LibrarianGetLibraryInfoEx(void* BaseOfDll) +{ + + PLIBRARY_ITEM_DATAW LibInfo; + + LibInfo = (PLIBRARY_ITEM_DATAW)LibrarianGetLibraryInfoExW(BaseOfDll); + if(LibInfo != NULL) + { + RtlZeroMemory(&LibraryInfoData, sizeof LIBRARY_ITEM_DATA); + LibraryInfoData.hFile = LibInfo->hFile; + LibraryInfoData.BaseOfDll = LibInfo->BaseOfDll; + LibraryInfoData.hFileMapping = LibInfo->hFileMapping; + LibraryInfoData.hFileMappingView = LibInfo->hFileMappingView; + WideCharToMultiByte(CP_ACP, NULL, LibInfo->szLibraryName, -1, &LibraryInfoData.szLibraryName[0], sizeof LibraryInfoData.szLibraryName, NULL, NULL); + WideCharToMultiByte(CP_ACP, NULL, LibInfo->szLibraryPath, -1, &LibraryInfoData.szLibraryPath[0], sizeof LibraryInfoData.szLibraryPath, NULL, NULL); + return((void*)&LibraryInfoData); + } + else + { + return(NULL); + } +} +__declspec(dllexport) void* __stdcall LibrarianGetLibraryInfoExW(void* BaseOfDll) +{ + + PLIBRARY_ITEM_DATAW hListLibraryPtr = NULL; + + if(hListLibrary != NULL) + { + hListLibraryPtr = (PLIBRARY_ITEM_DATAW)hListLibrary; + while(hListLibraryPtr->hFile != NULL) + { + if(hListLibraryPtr->hFile != (HANDLE)-1) + { + if(hListLibraryPtr->BaseOfDll == BaseOfDll) + { + return((void*)hListLibraryPtr); + } + } + hListLibraryPtr = (PLIBRARY_ITEM_DATAW)((ULONG_PTR)hListLibraryPtr + sizeof LIBRARY_ITEM_DATAW); + } + } + return(NULL); +} +__declspec(dllexport) void __stdcall LibrarianEnumLibraryInfo(void* EnumCallBack) +{ + + PLIBRARY_ITEM_DATAW hListLibraryPtr = NULL; + typedef void(__stdcall *fEnumCallBack)(LPVOID fLibraryDetail); + fEnumCallBack myEnumCallBack = (fEnumCallBack)EnumCallBack; + + if(hListLibrary != NULL) + { + hListLibraryPtr = (PLIBRARY_ITEM_DATAW)hListLibrary; + while(EnumCallBack != NULL && hListLibraryPtr->hFile != NULL) + { + if(hListLibraryPtr->hFile != (HANDLE)-1) + { + __try + { + myEnumCallBack((void*)hListLibraryPtr); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + EnumCallBack = NULL; + } + } + hListLibraryPtr = (PLIBRARY_ITEM_DATAW)((ULONG_PTR)hListLibraryPtr + sizeof LIBRARY_ITEM_DATAW); + } + } +} +__declspec(dllexport) void __stdcall LibrarianEnumLibraryInfoW(void* EnumCallBack) +{ + + LIBRARY_ITEM_DATA myLibraryInfoData; + PLIBRARY_ITEM_DATAW hListLibraryPtr = NULL; + typedef void(__stdcall *fEnumCallBack)(LPVOID fLibraryDetail); + fEnumCallBack myEnumCallBack = (fEnumCallBack)EnumCallBack; + + if(hListLibrary != NULL) + { + hListLibraryPtr = (PLIBRARY_ITEM_DATAW)hListLibrary; + while(EnumCallBack != NULL && hListLibraryPtr->hFile != NULL) + { + if(hListLibraryPtr->hFile != (HANDLE)-1) + { + __try + { + RtlZeroMemory(&myLibraryInfoData, sizeof LIBRARY_ITEM_DATA); + myLibraryInfoData.hFile = hListLibraryPtr->hFile; + myLibraryInfoData.BaseOfDll = hListLibraryPtr->BaseOfDll; + myLibraryInfoData.hFileMapping = hListLibraryPtr->hFileMapping; + myLibraryInfoData.hFileMappingView = hListLibraryPtr->hFileMappingView; + WideCharToMultiByte(CP_ACP, NULL, hListLibraryPtr->szLibraryName, -1, &myLibraryInfoData.szLibraryName[0], sizeof myLibraryInfoData.szLibraryName, NULL, NULL); + WideCharToMultiByte(CP_ACP, NULL, hListLibraryPtr->szLibraryPath, -1, &myLibraryInfoData.szLibraryPath[0], sizeof myLibraryInfoData.szLibraryPath, NULL, NULL); + myEnumCallBack((void*)&myLibraryInfoData); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + EnumCallBack = NULL; + } + } + hListLibraryPtr = (PLIBRARY_ITEM_DATAW)((ULONG_PTR)hListLibraryPtr + sizeof LIBRARY_ITEM_DATAW); + } + } +} +// TitanEngine.Process.functions: +__declspec(dllexport) long __stdcall GetActiveProcessId(char* szImageName) +{ + + wchar_t uniImageName[MAX_PATH] = {}; + + if(szImageName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szImageName, lstrlenA(szImageName)+1, uniImageName, sizeof(uniImageName)/(sizeof(uniImageName[0]))); + return(GetActiveProcessIdW(uniImageName)); + } + else + { + return(NULL); + } +} +__declspec(dllexport) long __stdcall GetActiveProcessIdW(wchar_t* szImageName) +{ + + int i; + wchar_t* szTranslatedProcName; + DWORD bProcessId[1024] = {}; + wchar_t szProcessPath[1024] = {}; + DWORD pProcessIdCount = NULL; + HANDLE hProcess; + + if(EnumProcesses(bProcessId, sizeof bProcessId, &pProcessIdCount)) + { + for(i = 0; i < (int)pProcessIdCount; i++) + { + if(bProcessId[i] != NULL) + { + hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, false, bProcessId[i]); + if(hProcess != NULL) + { + if(GetProcessImageFileNameW(hProcess, szProcessPath, 1024) > NULL) + { + szTranslatedProcName = (wchar_t*)TranslateNativeNameW(szProcessPath); + lstrcpyW(szProcessPath, szTranslatedProcName); + VirtualFree((void*)szTranslatedProcName, NULL, MEM_RELEASE); + EngineCloseHandle(hProcess); + if(lstrcmpiW(szProcessPath, szImageName) == NULL) + { + return(bProcessId[i]); + } + else if(lstrcmpiW(EngineExtractFileNameW(szProcessPath), szImageName) == NULL) + { + return(bProcessId[i]); + } + } + else + { + EngineCloseHandle(hProcess); + } + } + } + } + } + return(NULL); +} +__declspec(dllexport) void __stdcall EnumProcessesWithLibrary(char* szLibraryName, void* EnumFunction) +{ + + int i; + int j; + typedef void(__stdcall *fEnumFunction)(DWORD ProcessId, HMODULE ModuleBaseAddress); + fEnumFunction myEnumFunction = (fEnumFunction)EnumFunction; + HMODULE EnumeratedModules[1024] = {}; + DWORD bProcessId[1024] = {}; + char szModuleName[1024] = {}; + DWORD pProcessIdCount = NULL; + DWORD pModuleCount; + HANDLE hProcess; + + if(EnumFunction != NULL) + { + if(EnumProcesses(bProcessId, sizeof bProcessId, &pProcessIdCount)) + { + for(i = 0; i < (int)pProcessIdCount; i++) + { + if(bProcessId[i] != NULL) + { + hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, false, bProcessId[i]); + if(hProcess != NULL) + { + RtlZeroMemory(&EnumeratedModules[0], sizeof EnumeratedModules); + if(EnumProcessModules(hProcess, (HMODULE*)EnumeratedModules, sizeof EnumeratedModules, &pModuleCount)) + { + for(j = 0; j < (int)pModuleCount; j++) + { + if(EnumeratedModules[j] != NULL) + { + if(GetModuleBaseNameA(hProcess, EnumeratedModules[j], szModuleName, 1024) > NULL) + { + if(lstrcmpiA(szModuleName, szLibraryName) == NULL) + { + __try + { + myEnumFunction(bProcessId[i], EnumeratedModules[j]); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + EngineCloseHandle(hProcess); + return; + } + } + } + } + } + } + EngineCloseHandle(hProcess); + } + } + } + } + } +} +// TitanEngine.TLSFixer.functions: +__declspec(dllexport) bool __stdcall TLSBreakOnCallBack(LPVOID ArrayOfCallBacks, DWORD NumberOfCallBacks, LPVOID bpxCallBack) +{ + + unsigned int i; + LPVOID ReadArrayOfCallBacks = ArrayOfCallBacks; + + if(NumberOfCallBacks > NULL) + { + for(i = 0; i < NumberOfCallBacks; i++) + { + RtlMoveMemory(&tlsCallBackList[i], ReadArrayOfCallBacks, sizeof ULONG_PTR); + ReadArrayOfCallBacks = (LPVOID)((ULONG_PTR)ReadArrayOfCallBacks + sizeof ULONG_PTR); + } + engineTLSBreakOnCallBackAddress = (ULONG_PTR)bpxCallBack; + engineTLSBreakOnCallBack = true; + return(true); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall TLSGrabCallBackData(char* szFileName, LPVOID ArrayOfCallBacks, LPDWORD NumberOfCallBacks) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + + if(szFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + return(TLSGrabCallBackDataW(uniFileName, ArrayOfCallBacks, NumberOfCallBacks)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall TLSGrabCallBackDataW(wchar_t* szFileName, LPVOID ArrayOfCallBacks, LPDWORD NumberOfCallBacks) +{ + + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + BOOL FileIs64; + PIMAGE_TLS_DIRECTORY32 TLSDirectoryX86; + PIMAGE_TLS_DIRECTORY64 TLSDirectoryX64; + ULONG_PTR TLSDirectoryAddress; + ULONG_PTR TLSCallBackAddress; + ULONG_PTR TLSCompareData = NULL; + DWORD NumberOfTLSCallBacks = NULL; + + if(MapFileExW(szFileName, UE_ACCESS_READ, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, FileHandle, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + if(!FileIs64) + { + if(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress != NULL) + { + TLSDirectoryAddress = (ULONG_PTR)((ULONG_PTR)PEHeader32->OptionalHeader.ImageBase + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress); + TLSDirectoryX86 = (PIMAGE_TLS_DIRECTORY32)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)TLSDirectoryAddress, true); + if(TLSDirectoryX86->AddressOfCallBacks != NULL) + { + TLSCallBackAddress = (ULONG_PTR)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)TLSDirectoryX86->AddressOfCallBacks, true); + while(memcmp((LPVOID)TLSCallBackAddress, &TLSCompareData, sizeof ULONG_PTR) != NULL) + { + RtlMoveMemory(ArrayOfCallBacks, (LPVOID)TLSCallBackAddress, sizeof ULONG_PTR); + ArrayOfCallBacks = (LPVOID)((ULONG_PTR)ArrayOfCallBacks + sizeof ULONG_PTR); + TLSCallBackAddress = TLSCallBackAddress + sizeof ULONG_PTR; + NumberOfTLSCallBacks++; + } + *NumberOfCallBacks = NumberOfTLSCallBacks; + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(true); + } + else + { + *NumberOfCallBacks = NULL; + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + else + { + *NumberOfCallBacks = NULL; + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + else + { + if(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress != NULL) + { + TLSDirectoryAddress = (ULONG_PTR)((ULONG_PTR)PEHeader64->OptionalHeader.ImageBase + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress); + TLSDirectoryX64 = (PIMAGE_TLS_DIRECTORY64)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)TLSDirectoryAddress, true); + if(TLSDirectoryX64->AddressOfCallBacks != NULL) + { + TLSCallBackAddress = (ULONG_PTR)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)TLSDirectoryX64->AddressOfCallBacks, true); + while(memcmp((LPVOID)TLSCallBackAddress, &TLSCompareData, sizeof ULONG_PTR) != NULL) + { + RtlMoveMemory(ArrayOfCallBacks, (LPVOID)TLSCallBackAddress, sizeof ULONG_PTR); + ArrayOfCallBacks = (LPVOID)((ULONG_PTR)ArrayOfCallBacks + sizeof ULONG_PTR); + TLSCallBackAddress = TLSCallBackAddress + sizeof ULONG_PTR; + NumberOfTLSCallBacks++; + } + *NumberOfCallBacks = NumberOfTLSCallBacks; + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(true); + } + else + { + *NumberOfCallBacks = NULL; + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + else + { + *NumberOfCallBacks = NULL; + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + } + else + { + *NumberOfCallBacks = NULL; + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + return(false); +} +__declspec(dllexport) bool __stdcall TLSBreakOnCallBackEx(char* szFileName, LPVOID bpxCallBack) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + + if(szFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + return(TLSBreakOnCallBackExW(uniFileName, bpxCallBack)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall TLSBreakOnCallBackExW(wchar_t* szFileName, LPVOID bpxCallBack) +{ + + ULONG_PTR TlsArrayOfCallBacks[100]; + DWORD TlsNumberOfCallBacks; + + RtlZeroMemory(&TlsArrayOfCallBacks, 100 * sizeof ULONG_PTR); + if(szFileName != NULL) + { + if(TLSGrabCallBackDataW(szFileName, &TlsArrayOfCallBacks, &TlsNumberOfCallBacks)) + { + TLSBreakOnCallBack(&TlsArrayOfCallBacks, TlsNumberOfCallBacks, bpxCallBack); + return(true); + } + else + { + return(false); + } + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall TLSRemoveCallback(char* szFileName) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + + if(szFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + return(TLSRemoveCallbackW(uniFileName)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall TLSRemoveCallbackW(wchar_t* szFileName) +{ + + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + BOOL FileIs64; + PIMAGE_TLS_DIRECTORY32 TLSDirectoryX86; + PIMAGE_TLS_DIRECTORY64 TLSDirectoryX64; + ULONG_PTR TLSDirectoryAddress; + + if(MapFileExW(szFileName, UE_ACCESS_ALL, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, FileHandle, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + if(!FileIs64) + { + if(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress != NULL) + { + __try + { + TLSDirectoryAddress = (ULONG_PTR)((ULONG_PTR)PEHeader32->OptionalHeader.ImageBase + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress); + TLSDirectoryX86 = (PIMAGE_TLS_DIRECTORY32)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)TLSDirectoryAddress, true); + if(TLSDirectoryX86->AddressOfCallBacks != NULL) + { + TLSDirectoryX86->AddressOfCallBacks = NULL; + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(true); + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + else + { + if(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress != NULL) + { + __try + { + TLSDirectoryAddress = (ULONG_PTR)((ULONG_PTR)PEHeader64->OptionalHeader.ImageBase + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress); + TLSDirectoryX64 = (PIMAGE_TLS_DIRECTORY64)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)TLSDirectoryAddress, true); + if(TLSDirectoryX64->AddressOfCallBacks != NULL) + { + TLSDirectoryX64->AddressOfCallBacks = NULL; + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(true); + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + return(false); +} +__declspec(dllexport) bool __stdcall TLSRemoveTable(char* szFileName) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + + if(szFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + return(TLSRemoveTableW(uniFileName)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall TLSRemoveTableW(wchar_t* szFileName) +{ + + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + BOOL FileIs64; + PIMAGE_TLS_DIRECTORY32 TLSDirectoryX86; + PIMAGE_TLS_DIRECTORY64 TLSDirectoryX64; + ULONG_PTR TLSDirectoryAddress; + + if(MapFileExW(szFileName, UE_ACCESS_ALL, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, FileHandle, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + if(!FileIs64) + { + if(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress != NULL) + { + __try + { + TLSDirectoryAddress = (ULONG_PTR)((ULONG_PTR)PEHeader32->OptionalHeader.ImageBase + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress); + TLSDirectoryX86 = (PIMAGE_TLS_DIRECTORY32)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)TLSDirectoryAddress, true); + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress = NULL; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size = NULL; + RtlZeroMemory(TLSDirectoryX86, sizeof IMAGE_TLS_DIRECTORY32); + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(true); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + else + { + if(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress != NULL) + { + __try + { + TLSDirectoryAddress = (ULONG_PTR)((ULONG_PTR)PEHeader64->OptionalHeader.ImageBase + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress); + TLSDirectoryX64 = (PIMAGE_TLS_DIRECTORY64)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)TLSDirectoryAddress, true); + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress = NULL; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size = NULL; + RtlZeroMemory(TLSDirectoryX64, sizeof IMAGE_TLS_DIRECTORY64); + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(true); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + return(false); +} +__declspec(dllexport) bool __stdcall TLSBackupData(char* szFileName) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + + if(szFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + return(TLSBackupDataW(uniFileName)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall TLSBackupDataW(wchar_t* szFileName) +{ + + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + BOOL FileIs64; + PIMAGE_TLS_DIRECTORY32 TLSDirectoryX86; + PIMAGE_TLS_DIRECTORY64 TLSDirectoryX64; + ULONG_PTR TLSDirectoryAddress; + ULONG_PTR TLSCallBackAddress; + ULONG_PTR TLSCompareData = NULL; + DWORD NumberOfTLSCallBacks = NULL; + LPVOID ArrayOfCallBacks = &engineBackupArrayOfCallBacks; + LPDWORD NumberOfCallBacks = &engineBackupNumberOfCallBacks; + + engineBackupTLSAddress = NULL; + RtlZeroMemory(engineBackupArrayOfCallBacks, 0x1000); + RtlZeroMemory(&engineBackupTLSDataX86, sizeof IMAGE_TLS_DIRECTORY32); + RtlZeroMemory(&engineBackupTLSDataX64, sizeof IMAGE_TLS_DIRECTORY64); + if(MapFileExW(szFileName, UE_ACCESS_READ, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, FileHandle, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + if(!FileIs64) + { + if(PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress != NULL) + { + __try + { + engineBackupTLSx64 = false; + engineBackupTLSAddress = PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress; + TLSDirectoryAddress = (ULONG_PTR)((ULONG_PTR)PEHeader32->OptionalHeader.ImageBase + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress); + TLSDirectoryX86 = (PIMAGE_TLS_DIRECTORY32)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)TLSDirectoryAddress, true); + RtlMoveMemory(&engineBackupTLSDataX86, (LPVOID)TLSDirectoryX86, sizeof IMAGE_TLS_DIRECTORY32); + if(TLSDirectoryX86->AddressOfCallBacks != NULL) + { + TLSCallBackAddress = (ULONG_PTR)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)TLSDirectoryX86->AddressOfCallBacks, true); + while(memcmp((LPVOID)TLSCallBackAddress, &TLSCompareData, sizeof ULONG_PTR) != NULL) + { + RtlMoveMemory(ArrayOfCallBacks, (LPVOID)TLSCallBackAddress, sizeof ULONG_PTR); + ArrayOfCallBacks = (LPVOID)((ULONG_PTR)ArrayOfCallBacks + sizeof ULONG_PTR); + TLSCallBackAddress = TLSCallBackAddress + sizeof ULONG_PTR; + NumberOfTLSCallBacks++; + } + *NumberOfCallBacks = NumberOfTLSCallBacks; + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(true); + } + else + { + *NumberOfCallBacks = NULL; + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + *NumberOfCallBacks = NULL; + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + else + { + *NumberOfCallBacks = NULL; + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + else + { + if(PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress != NULL) + { + __try + { + engineBackupTLSx64 = true; + engineBackupTLSAddress = PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress; + TLSDirectoryAddress = (ULONG_PTR)((ULONG_PTR)PEHeader64->OptionalHeader.ImageBase + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress); + TLSDirectoryX64 = (PIMAGE_TLS_DIRECTORY64)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)TLSDirectoryAddress, true); + RtlMoveMemory(&engineBackupTLSDataX64, (LPVOID)TLSDirectoryX64, sizeof IMAGE_TLS_DIRECTORY64); + if(TLSDirectoryX64->AddressOfCallBacks != NULL) + { + TLSCallBackAddress = (ULONG_PTR)ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)TLSDirectoryX64->AddressOfCallBacks, true); + while(memcmp((LPVOID)TLSCallBackAddress, &TLSCompareData, sizeof ULONG_PTR) != NULL) + { + RtlMoveMemory(ArrayOfCallBacks, (LPVOID)TLSCallBackAddress, sizeof ULONG_PTR); + ArrayOfCallBacks = (LPVOID)((ULONG_PTR)ArrayOfCallBacks + sizeof ULONG_PTR); + TLSCallBackAddress = TLSCallBackAddress + sizeof ULONG_PTR; + NumberOfTLSCallBacks++; + } + *NumberOfCallBacks = NumberOfTLSCallBacks; + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(true); + } + else + { + *NumberOfCallBacks = NULL; + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + *NumberOfCallBacks = NULL; + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + else + { + *NumberOfCallBacks = NULL; + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + } + else + { + *NumberOfCallBacks = NULL; + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + return(false); +} +__declspec(dllexport) bool __stdcall TLSRestoreData() +{ + + ULONG_PTR ueNumberOfBytesRead = NULL; + + if(dbgProcessInformation.hProcess != NULL && engineBackupTLSAddress != NULL) + { + if(engineBackupTLSx64) + { + if(WriteProcessMemory(dbgProcessInformation.hProcess, (LPVOID)(engineBackupTLSAddress + GetDebuggedFileBaseAddress()), &engineBackupTLSDataX64, sizeof IMAGE_TLS_DIRECTORY64, &ueNumberOfBytesRead)) + { + if(engineBackupTLSDataX64.AddressOfCallBacks != NULL && engineBackupNumberOfCallBacks != NULL) + { + if(WriteProcessMemory(dbgProcessInformation.hProcess, (LPVOID)(engineBackupTLSDataX64.AddressOfCallBacks + GetDebuggedFileBaseAddress()), engineBackupArrayOfCallBacks, sizeof IMAGE_TLS_DIRECTORY64, &ueNumberOfBytesRead)) + { + engineBackupTLSAddress = NULL; + return(true); + } + } + else + { + engineBackupTLSAddress = NULL; + return(true); + } + } + } + else + { + if(WriteProcessMemory(dbgProcessInformation.hProcess, (LPVOID)(engineBackupTLSAddress + GetDebuggedFileBaseAddress()), &engineBackupTLSDataX86, sizeof IMAGE_TLS_DIRECTORY32, &ueNumberOfBytesRead)) + { + if(engineBackupTLSDataX86.AddressOfCallBacks != NULL && engineBackupNumberOfCallBacks != NULL) + { + if(WriteProcessMemory(dbgProcessInformation.hProcess, (LPVOID)(engineBackupTLSDataX86.AddressOfCallBacks + GetDebuggedFileBaseAddress()), engineBackupArrayOfCallBacks, sizeof IMAGE_TLS_DIRECTORY32, &ueNumberOfBytesRead)) + { + engineBackupTLSAddress = NULL; + return(true); + } + } + else + { + engineBackupTLSAddress = NULL; + return(true); + } + } + } + } + return(false); +} +__declspec(dllexport) bool __stdcall TLSBuildNewTable(ULONG_PTR FileMapVA, ULONG_PTR StorePlace, ULONG_PTR StorePlaceRVA, LPVOID ArrayOfCallBacks, DWORD NumberOfCallBacks) +{ + + BOOL FileIs64; + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + PIMAGE_TLS_DIRECTORY32 TLSDirectoryX86; + PIMAGE_TLS_DIRECTORY64 TLSDirectoryX64; + ULONG_PTR TLSWriteData = StorePlaceRVA; + + if(FileMapVA != NULL) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(EngineValidateHeader(FileMapVA, NULL, NULL, DOSHeader, true)) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + return(false); + } + if(!FileIs64) + { + __try + { + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress = (DWORD)StorePlaceRVA; + PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size = sizeof IMAGE_TLS_DIRECTORY32; + TLSDirectoryX86 = (PIMAGE_TLS_DIRECTORY32)StorePlace; + TLSDirectoryX86->StartAddressOfRawData = (DWORD)TLSWriteData; + TLSDirectoryX86->EndAddressOfRawData = (DWORD)TLSWriteData + 0x10; + TLSDirectoryX86->AddressOfIndex = (DWORD)TLSWriteData + 0x14; + TLSDirectoryX86->AddressOfCallBacks = (DWORD)TLSWriteData + sizeof IMAGE_TLS_DIRECTORY32 + 8; + RtlMoveMemory((LPVOID)(StorePlace + sizeof IMAGE_TLS_DIRECTORY32 + 8), ArrayOfCallBacks, NumberOfCallBacks * 4); + return(true); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return(false); + } + } + else + { + __try + { + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress = (DWORD)StorePlaceRVA; + PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size = sizeof IMAGE_TLS_DIRECTORY64; + TLSDirectoryX64 = (PIMAGE_TLS_DIRECTORY64)StorePlace; + TLSDirectoryX64->StartAddressOfRawData = TLSWriteData; + TLSDirectoryX64->EndAddressOfRawData = TLSWriteData + 0x20; + TLSDirectoryX64->AddressOfIndex = TLSWriteData + 0x28; + TLSDirectoryX64->AddressOfCallBacks = TLSWriteData + sizeof IMAGE_TLS_DIRECTORY64 + 12; + RtlMoveMemory((LPVOID)(StorePlace + sizeof IMAGE_TLS_DIRECTORY64 + 12), ArrayOfCallBacks, NumberOfCallBacks * 8); + return(true); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return(false); + } + } + } + else + { + return(false); + } + } + return(false); +} +__declspec(dllexport) bool __stdcall TLSBuildNewTableEx(char* szFileName, char* szSectionName, LPVOID ArrayOfCallBacks, DWORD NumberOfCallBacks) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + + if(szFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + return(TLSBuildNewTableExW(uniFileName, szSectionName, ArrayOfCallBacks, NumberOfCallBacks)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall TLSBuildNewTableExW(wchar_t* szFileName, char* szSectionName, LPVOID ArrayOfCallBacks, DWORD NumberOfCallBacks) +{ + + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + DWORD NewSectionVO = NULL; + DWORD NewSectionFO = NULL; + bool ReturnValue = false; + ULONG_PTR tlsImageBase; + + tlsImageBase = (ULONG_PTR)GetPE32DataW(szFileName, NULL, UE_IMAGEBASE); + NewSectionVO = AddNewSectionW(szFileName, szSectionName, sizeof IMAGE_TLS_DIRECTORY64 * 2); + if(MapFileExW(szFileName, UE_ACCESS_ALL, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + NewSectionFO = (DWORD)ConvertVAtoFileOffset(FileMapVA, NewSectionVO + tlsImageBase, true); + ReturnValue = TLSBuildNewTable(FileMapVA, NewSectionFO, NewSectionVO, ArrayOfCallBacks, NumberOfCallBacks); + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + if(ReturnValue) + { + return(true); + } + else + { + return(false); + } + } + else + { + return(false); + } +} +// TitanEngine.TranslateName.functions: +__declspec(dllexport) void* __stdcall TranslateNativeName(char* szNativeName) +{ + + LPVOID TranslatedName = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE); + char szDeviceName[3] = "A:"; + char szDeviceCOMName[5] = "COM0"; + int CurrentDeviceLen; + + while(szDeviceName[0] <= 0x5A) + { + RtlZeroMemory(TranslatedName, 0x1000); + if(QueryDosDeviceA(szDeviceName, (LPSTR)TranslatedName, 0x1000) > NULL) + { + CurrentDeviceLen = lstrlenA((LPSTR)TranslatedName); + lstrcatA((LPSTR)TranslatedName, (LPCSTR)(szNativeName + CurrentDeviceLen)); + if(lstrcmpiA((LPCSTR)TranslatedName, szNativeName) == NULL) + { + RtlZeroMemory(TranslatedName, 0x1000); + lstrcatA((LPSTR)TranslatedName, szDeviceName); + lstrcatA((LPSTR)TranslatedName, (LPCSTR)(szNativeName + CurrentDeviceLen)); + return(TranslatedName); + } + } + szDeviceName[0]++; + } + while(szDeviceCOMName[3] <= 0x39) + { + RtlZeroMemory(TranslatedName, 0x1000); + if(QueryDosDeviceA(szDeviceCOMName, (LPSTR)TranslatedName, 0x1000) > NULL) + { + CurrentDeviceLen = lstrlenA((LPSTR)TranslatedName); + lstrcatA((LPSTR)TranslatedName, (LPCSTR)(szNativeName + CurrentDeviceLen)); + if(lstrcmpiA((LPCSTR)TranslatedName, szNativeName) == NULL) + { + RtlZeroMemory(TranslatedName, 0x1000); + lstrcatA((LPSTR)TranslatedName, szDeviceCOMName); + lstrcatA((LPSTR)TranslatedName, (LPCSTR)(szNativeName + CurrentDeviceLen)); + return(TranslatedName); + } + } + szDeviceCOMName[3]++; + } + VirtualFree(TranslatedName, NULL, MEM_RELEASE); + return(NULL); +} +__declspec(dllexport) void* __stdcall TranslateNativeNameW(wchar_t* szNativeName) +{ + + LPVOID TranslatedName = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE); + wchar_t szDeviceName[3] = L"A:"; + wchar_t szDeviceCOMName[5] = L"COM0"; + int CurrentDeviceLen; + + while(szDeviceName[0] <= 0x5A) + { + RtlZeroMemory(TranslatedName, 0x1000); + if(QueryDosDeviceW(szDeviceName, (LPWSTR)TranslatedName, MAX_PATH * 2) > NULL) + { + CurrentDeviceLen = lstrlenW((LPWSTR)TranslatedName); + lstrcatW((LPWSTR)TranslatedName, (LPCWSTR)(szNativeName + CurrentDeviceLen)); + if(lstrcmpiW((LPCWSTR)TranslatedName, szNativeName) == NULL) + { + RtlZeroMemory(TranslatedName, 0x1000); + lstrcatW((LPWSTR)TranslatedName, szDeviceName); + lstrcatW((LPWSTR)TranslatedName, (LPWSTR)(szNativeName + CurrentDeviceLen)); + return(TranslatedName); + } + } + szDeviceName[0]++; + } + while(szDeviceCOMName[3] <= 0x39) + { + RtlZeroMemory(TranslatedName, 0x1000); + if(QueryDosDeviceW(szDeviceCOMName, (LPWSTR)TranslatedName, MAX_PATH * 2) > NULL) + { + CurrentDeviceLen = lstrlenW((LPWSTR)TranslatedName); + lstrcatW((LPWSTR)TranslatedName, (LPCWSTR)(szNativeName + CurrentDeviceLen)); + if(lstrcmpiW((LPCWSTR)TranslatedName, szNativeName) == NULL) + { + RtlZeroMemory(TranslatedName, 0x1000); + lstrcatW((LPWSTR)TranslatedName, szDeviceCOMName); + lstrcatW((LPWSTR)TranslatedName, (LPWSTR)(szNativeName + CurrentDeviceLen)); + return(TranslatedName); + } + } + szDeviceCOMName[3]++; + } + VirtualFree(TranslatedName, NULL, MEM_RELEASE); + return(NULL); +} +// TitanEngine.Handler.functions: +__declspec(dllexport) long __stdcall HandlerGetActiveHandleCount(DWORD ProcessId) +{ + + int HandleCount = NULL; + LPVOID QuerySystemBuffer; + ULONG QuerySystemBufferSize = 0x2000; + ULONG RequiredSize = NULL; + ULONG TotalHandleCount = NULL; +#if !defined(_WIN64) + typedef NTSTATUS(__stdcall *fZwQuerySystemInformation)(DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); + typedef NTSTATUS(__stdcall *fZwQueryObject)(HANDLE hObject, DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); +#else + typedef NTSTATUS(__fastcall *fZwQuerySystemInformation)(DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); + typedef NTSTATUS(__fastcall *fZwQueryObject)(HANDLE hObject, DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); +#endif + LPVOID ZwQuerySystemInformation = (LPVOID)GetProcAddress(GetModuleHandleA("ntdll.dll"),"ZwQuerySystemInformation"); + LPVOID ZwQueryObject = (LPVOID)GetProcAddress(GetModuleHandleA("ntdll.dll"),"ZwQueryObject"); + fZwQuerySystemInformation cZwQuerySystemInformation = (fZwQuerySystemInformation)(ZwQuerySystemInformation); + fZwQueryObject cZwQueryObject = (fZwQueryObject)(ZwQueryObject); + PNTDLL_QUERY_HANDLE_INFO HandleInfo; + + if(ZwQuerySystemInformation != NULL && ZwQueryObject != NULL) + { + QuerySystemBuffer = VirtualAlloc(NULL, QuerySystemBufferSize, MEM_COMMIT, PAGE_READWRITE); + while(cZwQuerySystemInformation(NTDLL_SystemHandleInfo, QuerySystemBuffer, QuerySystemBufferSize, &RequiredSize) == (NTSTATUS)0xC0000004L) + { + QuerySystemBufferSize = RequiredSize; + VirtualFree(QuerySystemBuffer, NULL, MEM_RELEASE); + QuerySystemBuffer = VirtualAlloc(NULL, QuerySystemBufferSize, MEM_COMMIT, PAGE_READWRITE); + } + RtlMoveMemory(&TotalHandleCount, QuerySystemBuffer, sizeof ULONG); + QuerySystemBuffer = (LPVOID)((ULONG_PTR)QuerySystemBuffer + 4); + HandleInfo = (PNTDLL_QUERY_HANDLE_INFO)QuerySystemBuffer; + while(TotalHandleCount > NULL) + { + if(HandleInfo->ProcessId == ProcessId) + { + HandleCount++; + } + HandleInfo = (PNTDLL_QUERY_HANDLE_INFO)((ULONG_PTR)HandleInfo + sizeof NTDLL_QUERY_HANDLE_INFO); + TotalHandleCount--; + } + VirtualFree(QuerySystemBuffer, NULL, MEM_RELEASE); + return(HandleCount); + } + return(NULL); +} +__declspec(dllexport) bool __stdcall HandlerIsHandleOpen(DWORD ProcessId, HANDLE hHandle) +{ + + bool HandleActive = false; + LPVOID QuerySystemBuffer; + ULONG QuerySystemBufferSize = 0x2000; + ULONG RequiredSize = NULL; + ULONG TotalHandleCount = NULL; +#if !defined(_WIN64) + typedef NTSTATUS(__stdcall *fZwQuerySystemInformation)(DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); +#else + typedef NTSTATUS(__fastcall *fZwQuerySystemInformation)(DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); +#endif + LPVOID ZwQuerySystemInformation = (LPVOID)GetProcAddress(GetModuleHandleA("ntdll.dll"),"ZwQuerySystemInformation"); + fZwQuerySystemInformation cZwQuerySystemInformation = (fZwQuerySystemInformation)(ZwQuerySystemInformation); + PNTDLL_QUERY_HANDLE_INFO HandleInfo; + + if(ZwQuerySystemInformation != NULL) + { + QuerySystemBuffer = VirtualAlloc(NULL, QuerySystemBufferSize, MEM_COMMIT, PAGE_READWRITE); + while(cZwQuerySystemInformation(NTDLL_SystemHandleInfo, QuerySystemBuffer, QuerySystemBufferSize, &RequiredSize) == (NTSTATUS)0xC0000004L) + { + QuerySystemBufferSize = RequiredSize; + VirtualFree(QuerySystemBuffer, NULL, MEM_RELEASE); + QuerySystemBuffer = VirtualAlloc(NULL, QuerySystemBufferSize, MEM_COMMIT, PAGE_READWRITE); + } + RtlMoveMemory(&TotalHandleCount, QuerySystemBuffer, sizeof ULONG); + QuerySystemBuffer = (LPVOID)((ULONG_PTR)QuerySystemBuffer + 4); + HandleInfo = (PNTDLL_QUERY_HANDLE_INFO)QuerySystemBuffer; + while(TotalHandleCount > NULL) + { + if(HandleInfo->ProcessId == ProcessId && (HANDLE)HandleInfo->hHandle == hHandle) + { + HandleActive = true; + break; + } + HandleInfo = (PNTDLL_QUERY_HANDLE_INFO)((ULONG_PTR)HandleInfo + sizeof NTDLL_QUERY_HANDLE_INFO); + TotalHandleCount--; + } + VirtualFree(QuerySystemBuffer, NULL, MEM_RELEASE); + if(HandleActive) + { + return(true); + } + } + return(false); +} +__declspec(dllexport) void* __stdcall HandlerGetHandleName(HANDLE hProcess, DWORD ProcessId, HANDLE hHandle, bool TranslateName) +{ + + bool NameFound = false; + HANDLE myHandle = NULL; + LPVOID QuerySystemBuffer; + ULONG QuerySystemBufferSize = 0x2000; + ULONG RequiredSize = NULL; + ULONG TotalHandleCount = NULL; +#if !defined(_WIN64) + typedef NTSTATUS(__stdcall *fZwQuerySystemInformation)(DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); + typedef NTSTATUS(__stdcall *fZwQueryObject)(HANDLE hObject, DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); +#else + typedef NTSTATUS(__fastcall *fZwQuerySystemInformation)(DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); + typedef NTSTATUS(__fastcall *fZwQueryObject)(HANDLE hObject, DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); +#endif + LPVOID ZwQuerySystemInformation = (LPVOID)GetProcAddress(GetModuleHandleA("ntdll.dll"),"ZwQuerySystemInformation"); + LPVOID ZwQueryObject = (LPVOID)GetProcAddress(GetModuleHandleA("ntdll.dll"),"ZwQueryObject"); + fZwQuerySystemInformation cZwQuerySystemInformation = (fZwQuerySystemInformation)(ZwQuerySystemInformation); + fZwQueryObject cZwQueryObject = (fZwQueryObject)(ZwQueryObject); + PNTDLL_QUERY_HANDLE_INFO HandleInfo; + PUBLIC_OBJECT_BASIC_INFORMATION ObjectBasicInfo; + LPVOID ObjectNameInfo = VirtualAlloc(NULL, 0x2000, MEM_COMMIT, PAGE_READWRITE); + PPUBLIC_OBJECT_NAME_INFORMATION pObjectNameInfo = (PPUBLIC_OBJECT_NAME_INFORMATION)ObjectNameInfo; + LPVOID HandleFullName = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE); + LPVOID tmpHandleFullName = NULL; + + if(ZwQuerySystemInformation != NULL && ZwQueryObject != NULL) + { + QuerySystemBuffer = VirtualAlloc(NULL, QuerySystemBufferSize, MEM_COMMIT, PAGE_READWRITE); + while(cZwQuerySystemInformation(NTDLL_SystemHandleInfo, QuerySystemBuffer, QuerySystemBufferSize, &RequiredSize) == (NTSTATUS)0xC0000004L) + { + QuerySystemBufferSize = RequiredSize; + VirtualFree(QuerySystemBuffer, NULL, MEM_RELEASE); + QuerySystemBuffer = VirtualAlloc(NULL, QuerySystemBufferSize, MEM_COMMIT, PAGE_READWRITE); + } + RtlMoveMemory(&TotalHandleCount, QuerySystemBuffer, sizeof ULONG); + QuerySystemBuffer = (LPVOID)((ULONG_PTR)QuerySystemBuffer + 4); + HandleInfo = (PNTDLL_QUERY_HANDLE_INFO)QuerySystemBuffer; + while(TotalHandleCount > NULL) + { + if(HandleInfo->ProcessId == ProcessId && (HANDLE)HandleInfo->hHandle == hHandle) + { + //if(!(HandleInfo->GrantedAccess & SYNCHRONIZE) || ((HandleInfo->GrantedAccess & SYNCHRONIZE) && ((WORD)HandleInfo->GrantedAccess != 0x19F9))){// && (WORD)HandleInfo->GrantedAccess != 0x89))){ + if(HandleInfo->GrantedAccess != 0x0012019F) + { + if(DuplicateHandle(hProcess, hHandle, GetCurrentProcess(), &myHandle, NULL, false, DUPLICATE_SAME_ACCESS)) + { + RtlZeroMemory(&ObjectBasicInfo, sizeof PUBLIC_OBJECT_BASIC_INFORMATION); + cZwQueryObject(myHandle, ObjectBasicInformation, &ObjectBasicInfo, sizeof PUBLIC_OBJECT_BASIC_INFORMATION, &RequiredSize); + cZwQueryObject(myHandle, ObjectNameInformation, ObjectNameInfo, 8, &RequiredSize); + cZwQueryObject(myHandle, ObjectNameInformation, ObjectNameInfo, RequiredSize, &RequiredSize); + RtlZeroMemory(HandleFullName, 0x1000); + if(pObjectNameInfo->Name.Length != NULL) + { + WideCharToMultiByte(CP_ACP, NULL, (LPCWSTR)pObjectNameInfo->Name.Buffer, -1, (LPSTR)HandleFullName, 0x1000, NULL, NULL); + NameFound = true; + if(TranslateName) + { + tmpHandleFullName = TranslateNativeName((char*)HandleFullName); + if(tmpHandleFullName != NULL) + { + VirtualFree(HandleFullName, NULL, MEM_RELEASE); + HandleFullName = tmpHandleFullName; + } + } + } + EngineCloseHandle(myHandle); + break; + } + } + } + HandleInfo = (PNTDLL_QUERY_HANDLE_INFO)((ULONG_PTR)HandleInfo + sizeof NTDLL_QUERY_HANDLE_INFO); + TotalHandleCount--; + } + VirtualFree(ObjectNameInfo, NULL, MEM_RELEASE); + VirtualFree(QuerySystemBuffer, NULL, MEM_RELEASE); + if(!NameFound) + { + VirtualFree(HandleFullName, NULL, MEM_RELEASE); + return(NULL); + } + else + { + return(HandleFullName); + } + } + VirtualFree(HandleFullName, NULL, MEM_RELEASE); + VirtualFree(ObjectNameInfo, NULL, MEM_RELEASE); + return(NULL); +} +__declspec(dllexport) void* __stdcall HandlerGetHandleNameW(HANDLE hProcess, DWORD ProcessId, HANDLE hHandle, bool TranslateName) +{ + + bool NameFound = false; + HANDLE myHandle = NULL; + LPVOID QuerySystemBuffer; + ULONG QuerySystemBufferSize = 0x2000; + ULONG RequiredSize = NULL; + ULONG TotalHandleCount = NULL; +#if !defined(_WIN64) + typedef NTSTATUS(__stdcall *fZwQuerySystemInformation)(DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); + typedef NTSTATUS(__stdcall *fZwQueryObject)(HANDLE hObject, DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); +#else + typedef NTSTATUS(__fastcall *fZwQuerySystemInformation)(DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); + typedef NTSTATUS(__fastcall *fZwQueryObject)(HANDLE hObject, DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); +#endif + LPVOID ZwQuerySystemInformation = (LPVOID)GetProcAddress(GetModuleHandleA("ntdll.dll"),"ZwQuerySystemInformation"); + LPVOID ZwQueryObject = (LPVOID)GetProcAddress(GetModuleHandleA("ntdll.dll"),"ZwQueryObject"); + fZwQuerySystemInformation cZwQuerySystemInformation = (fZwQuerySystemInformation)(ZwQuerySystemInformation); + fZwQueryObject cZwQueryObject = (fZwQueryObject)(ZwQueryObject); + PNTDLL_QUERY_HANDLE_INFO HandleInfo; + PUBLIC_OBJECT_BASIC_INFORMATION ObjectBasicInfo; + LPVOID ObjectNameInfo = VirtualAlloc(NULL, 0x2000, MEM_COMMIT, PAGE_READWRITE); + PPUBLIC_OBJECT_NAME_INFORMATION pObjectNameInfo = (PPUBLIC_OBJECT_NAME_INFORMATION)ObjectNameInfo; + LPVOID HandleFullName = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE); + LPVOID tmpHandleFullName = NULL; + + if(ZwQuerySystemInformation != NULL && ZwQueryObject != NULL) + { + QuerySystemBuffer = VirtualAlloc(NULL, QuerySystemBufferSize, MEM_COMMIT, PAGE_READWRITE); + while(cZwQuerySystemInformation(NTDLL_SystemHandleInfo, QuerySystemBuffer, QuerySystemBufferSize, &RequiredSize) == (NTSTATUS)0xC0000004L) + { + QuerySystemBufferSize = RequiredSize; + VirtualFree(QuerySystemBuffer, NULL, MEM_RELEASE); + QuerySystemBuffer = VirtualAlloc(NULL, QuerySystemBufferSize, MEM_COMMIT, PAGE_READWRITE); + } + RtlMoveMemory(&TotalHandleCount, QuerySystemBuffer, sizeof ULONG); + QuerySystemBuffer = (LPVOID)((ULONG_PTR)QuerySystemBuffer + 4); + HandleInfo = (PNTDLL_QUERY_HANDLE_INFO)QuerySystemBuffer; + while(TotalHandleCount > NULL) + { + if(HandleInfo->ProcessId == ProcessId && (HANDLE)HandleInfo->hHandle == hHandle) + { + //if(!(HandleInfo->GrantedAccess & SYNCHRONIZE) || ((HandleInfo->GrantedAccess & SYNCHRONIZE) && ((WORD)HandleInfo->GrantedAccess != 0x19F9))){// && (WORD)HandleInfo->GrantedAccess != 0x89))){ + if(HandleInfo->GrantedAccess != 0x0012019F) + { + if(DuplicateHandle(hProcess, hHandle, GetCurrentProcess(), &myHandle, NULL, false, DUPLICATE_SAME_ACCESS)) + { + RtlZeroMemory(&ObjectBasicInfo, sizeof PUBLIC_OBJECT_BASIC_INFORMATION); + cZwQueryObject(myHandle, ObjectBasicInformation, &ObjectBasicInfo, sizeof PUBLIC_OBJECT_BASIC_INFORMATION, &RequiredSize); + cZwQueryObject(myHandle, ObjectNameInformation, ObjectNameInfo, 8, &RequiredSize); + cZwQueryObject(myHandle, ObjectNameInformation, ObjectNameInfo, RequiredSize, &RequiredSize); + RtlZeroMemory(HandleFullName, 0x1000); + if(pObjectNameInfo->Name.Length != NULL) + { + //WideCharToMultiByte(CP_ACP, NULL, (LPCWSTR)pObjectNameInfo->Name.Buffer, -1, (LPSTR)HandleFullName, 0x1000, NULL, NULL); + NameFound = true; + lstrcpyW((wchar_t*)HandleFullName, (wchar_t*)pObjectNameInfo->Name.Buffer); + if(TranslateName) + { + tmpHandleFullName = TranslateNativeNameW((wchar_t*)HandleFullName); + if(tmpHandleFullName != NULL) + { + VirtualFree(HandleFullName, NULL, MEM_RELEASE); + HandleFullName = tmpHandleFullName; + } + } + } + EngineCloseHandle(myHandle); + break; + } + } + } + HandleInfo = (PNTDLL_QUERY_HANDLE_INFO)((ULONG_PTR)HandleInfo + sizeof NTDLL_QUERY_HANDLE_INFO); + TotalHandleCount--; + } + VirtualFree(ObjectNameInfo, NULL, MEM_RELEASE); + VirtualFree(QuerySystemBuffer, NULL, MEM_RELEASE); + if(!NameFound) + { + VirtualFree(HandleFullName, NULL, MEM_RELEASE); + return(NULL); + } + else + { + return(HandleFullName); + } + } + VirtualFree(HandleFullName, NULL, MEM_RELEASE); + VirtualFree(ObjectNameInfo, NULL, MEM_RELEASE); + return(NULL); +} +__declspec(dllexport) long __stdcall HandlerEnumerateOpenHandles(DWORD ProcessId, LPVOID HandleBuffer, DWORD MaxHandleCount) +{ + + HANDLE myHandle = NULL; + LPVOID QuerySystemBuffer; + ULONG RequiredSize = NULL; + ULONG TotalHandleCount = NULL; + unsigned int HandleCount = NULL; + ULONG QuerySystemBufferSize = 0x2000; +#if !defined(_WIN64) + typedef NTSTATUS(__stdcall *fZwQuerySystemInformation)(DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); +#else + typedef NTSTATUS(__fastcall *fZwQuerySystemInformation)(DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); +#endif + LPVOID ZwQuerySystemInformation = (LPVOID)GetProcAddress(GetModuleHandleA("ntdll.dll"),"ZwQuerySystemInformation"); + fZwQuerySystemInformation cZwQuerySystemInformation = (fZwQuerySystemInformation)(ZwQuerySystemInformation); + PNTDLL_QUERY_HANDLE_INFO HandleInfo; + + if(ZwQuerySystemInformation != NULL) + { + QuerySystemBuffer = VirtualAlloc(NULL, QuerySystemBufferSize, MEM_COMMIT, PAGE_READWRITE); + while(cZwQuerySystemInformation(NTDLL_SystemHandleInfo, QuerySystemBuffer, QuerySystemBufferSize, &RequiredSize) == (NTSTATUS)0xC0000004L) + { + QuerySystemBufferSize = RequiredSize; + VirtualFree(QuerySystemBuffer, NULL, MEM_RELEASE); + QuerySystemBuffer = VirtualAlloc(NULL, QuerySystemBufferSize, MEM_COMMIT, PAGE_READWRITE); + } + RtlMoveMemory(&TotalHandleCount, QuerySystemBuffer, sizeof ULONG); + QuerySystemBuffer = (LPVOID)((ULONG_PTR)QuerySystemBuffer + 4); + HandleInfo = (PNTDLL_QUERY_HANDLE_INFO)QuerySystemBuffer; + while(TotalHandleCount > NULL) + { + if(HandleInfo->ProcessId == ProcessId && HandleCount < MaxHandleCount) + { + myHandle = (HANDLE)HandleInfo->hHandle; + RtlMoveMemory(HandleBuffer, &myHandle, sizeof HANDLE); + HandleBuffer = (LPVOID)((ULONG_PTR)HandleBuffer + sizeof HANDLE); + HandleCount++; + } + HandleInfo = (PNTDLL_QUERY_HANDLE_INFO)((ULONG_PTR)HandleInfo + sizeof NTDLL_QUERY_HANDLE_INFO); + TotalHandleCount--; + } + VirtualFree(QuerySystemBuffer, NULL, MEM_RELEASE); + return(HandleCount); + } + return(NULL); +} +__declspec(dllexport) long long __stdcall HandlerGetHandleDetails(HANDLE hProcess, DWORD ProcessId, HANDLE hHandle, DWORD InformationReturn) +{ + + HANDLE myHandle = NULL; + LPVOID QuerySystemBuffer; + ULONG QuerySystemBufferSize = 0x2000; + ULONG RequiredSize = NULL; + ULONG TotalHandleCount = NULL; +#if !defined(_WIN64) + typedef NTSTATUS(__stdcall *fZwQuerySystemInformation)(DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); + typedef NTSTATUS(__stdcall *fZwQueryObject)(HANDLE hObject, DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); +#else + typedef NTSTATUS(__fastcall *fZwQuerySystemInformation)(DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); + typedef NTSTATUS(__fastcall *fZwQueryObject)(HANDLE hObject, DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); +#endif + LPVOID ZwQuerySystemInformation = (LPVOID)GetProcAddress(GetModuleHandleA("ntdll.dll"),"ZwQuerySystemInformation"); + LPVOID ZwQueryObject = (LPVOID)GetProcAddress(GetModuleHandleA("ntdll.dll"),"ZwQueryObject"); + fZwQuerySystemInformation cZwQuerySystemInformation = (fZwQuerySystemInformation)(ZwQuerySystemInformation); + fZwQueryObject cZwQueryObject = (fZwQueryObject)(ZwQueryObject); + PNTDLL_QUERY_HANDLE_INFO HandleInfo; + PUBLIC_OBJECT_BASIC_INFORMATION ObjectBasicInfo; + LPVOID HandleFullData = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE); + LPVOID HandleNameData = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE); + PPUBLIC_OBJECT_TYPE_INFORMATION pObjectTypeInfo = (PPUBLIC_OBJECT_TYPE_INFORMATION)HandleFullData; + bool DontFreeStringMemory = false; + ULONG_PTR ReturnData = NULL; + + if(ZwQuerySystemInformation != NULL && ZwQueryObject != NULL) + { + QuerySystemBuffer = VirtualAlloc(NULL, QuerySystemBufferSize, MEM_COMMIT, PAGE_READWRITE); + while(cZwQuerySystemInformation(NTDLL_SystemHandleInfo, QuerySystemBuffer, QuerySystemBufferSize, &RequiredSize) == (NTSTATUS)0xC0000004L) + { + QuerySystemBufferSize = RequiredSize; + VirtualFree(QuerySystemBuffer, NULL, MEM_RELEASE); + QuerySystemBuffer = VirtualAlloc(NULL, QuerySystemBufferSize, MEM_COMMIT, PAGE_READWRITE); + } + RtlMoveMemory(&TotalHandleCount, QuerySystemBuffer, sizeof ULONG); + QuerySystemBuffer = (LPVOID)((ULONG_PTR)QuerySystemBuffer + 4); + HandleInfo = (PNTDLL_QUERY_HANDLE_INFO)QuerySystemBuffer; + while(TotalHandleCount > NULL) + { + if(HandleInfo->ProcessId == ProcessId && (HANDLE)HandleInfo->hHandle == hHandle) + { + if(DuplicateHandle(hProcess, hHandle, GetCurrentProcess(), &myHandle, NULL, false, DUPLICATE_SAME_ACCESS)) + { + RtlZeroMemory(&ObjectBasicInfo, sizeof PUBLIC_OBJECT_BASIC_INFORMATION); + cZwQueryObject(myHandle, ObjectBasicInformation, &ObjectBasicInfo, sizeof PUBLIC_OBJECT_BASIC_INFORMATION, &RequiredSize); + if(InformationReturn == UE_OPTION_HANDLER_RETURN_HANDLECOUNT) + { + ReturnData = (ULONG_PTR)ObjectBasicInfo.HandleCount; + } + else if(InformationReturn == UE_OPTION_HANDLER_RETURN_ACCESS) + { + ReturnData = (ULONG_PTR)HandleInfo->GrantedAccess; + } + else if(InformationReturn == UE_OPTION_HANDLER_RETURN_FLAGS) + { + ReturnData = (ULONG_PTR)HandleInfo->Flags; + } + else if(InformationReturn == UE_OPTION_HANDLER_RETURN_TYPENAME) + { + //if(!(HandleInfo->GrantedAccess & SYNCHRONIZE) || ((HandleInfo->GrantedAccess & SYNCHRONIZE) && ((WORD)HandleInfo->GrantedAccess != 0x19F9))){// && (WORD)HandleInfo->GrantedAccess != 0x89))){ + if(HandleInfo->GrantedAccess != 0x0012019F) + { + RtlZeroMemory(HandleFullData, 0x1000); + cZwQueryObject(myHandle, ObjectTypeInformation, HandleFullData, 8, &RequiredSize); + cZwQueryObject(myHandle, ObjectTypeInformation, HandleFullData, RequiredSize, &RequiredSize); + RtlZeroMemory(HandleNameData, 0x1000); + if(pObjectTypeInfo->Name.Length != NULL) + { + WideCharToMultiByte(CP_ACP, NULL, (LPCWSTR)pObjectTypeInfo->Name.Buffer, -1, (LPSTR)HandleNameData, 0x1000, NULL, NULL); + ReturnData = (ULONG_PTR)HandleNameData; + DontFreeStringMemory = true; + } + } + } + else if(InformationReturn == UE_OPTION_HANDLER_RETURN_TYPENAME_UNICODE) + { + //if(!(HandleInfo->GrantedAccess & SYNCHRONIZE) || ((HandleInfo->GrantedAccess & SYNCHRONIZE) && ((WORD)HandleInfo->GrantedAccess != 0x19F9))){// && (WORD)HandleInfo->GrantedAccess != 0x89))){ + if(HandleInfo->GrantedAccess != 0x0012019F) + { + RtlZeroMemory(HandleFullData, 0x1000); + cZwQueryObject(myHandle, ObjectTypeInformation, HandleFullData, 8, &RequiredSize); + cZwQueryObject(myHandle, ObjectTypeInformation, HandleFullData, RequiredSize, &RequiredSize); + RtlZeroMemory(HandleNameData, 0x1000); + if(pObjectTypeInfo->Name.Length != NULL) + { + //WideCharToMultiByte(CP_ACP, NULL, (LPCWSTR)pObjectTypeInfo->Name.Buffer, -1, (LPSTR)HandleNameData, 0x1000, NULL, NULL); + lstrcpyW((wchar_t*)HandleNameData, (wchar_t*)pObjectTypeInfo->Name.Buffer); + ReturnData = (ULONG_PTR)HandleNameData; + DontFreeStringMemory = true; + } + } + } + EngineCloseHandle(myHandle); + break; + } + } + HandleInfo = (PNTDLL_QUERY_HANDLE_INFO)((ULONG_PTR)HandleInfo + sizeof NTDLL_QUERY_HANDLE_INFO); + TotalHandleCount--; + } + if(!DontFreeStringMemory) + { + VirtualFree(HandleNameData, NULL, MEM_RELEASE); + } + VirtualFree(HandleFullData, NULL, MEM_RELEASE); + VirtualFree(QuerySystemBuffer, NULL, MEM_RELEASE); + return(ReturnData); + } + if(!DontFreeStringMemory) + { + VirtualFree(HandleNameData, NULL, MEM_RELEASE); + } + VirtualFree(HandleFullData, NULL, MEM_RELEASE); + return(NULL); +} +__declspec(dllexport) bool __stdcall HandlerCloseRemoteHandle(HANDLE hProcess, HANDLE hHandle) +{ + + HANDLE myHandle; + + if(hProcess != NULL) + { + DuplicateHandle(hProcess, hHandle, GetCurrentProcess(), &myHandle, NULL, false, DUPLICATE_CLOSE_SOURCE); + EngineCloseHandle(myHandle); + } + return(false); +} +__declspec(dllexport) long __stdcall HandlerEnumerateLockHandles(char* szFileOrFolderName, bool NameIsFolder, bool NameIsTranslated, LPVOID HandleDataBuffer, DWORD MaxHandleCount) +{ + + wchar_t uniFileOrFolderName[MAX_PATH] = {}; + + if(szFileOrFolderName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileOrFolderName, lstrlenA(szFileOrFolderName)+1, uniFileOrFolderName, sizeof(uniFileOrFolderName)/(sizeof(uniFileOrFolderName[0]))); + return(HandlerEnumerateLockHandlesW(uniFileOrFolderName, NameIsFolder, NameIsTranslated, HandleDataBuffer, MaxHandleCount)); + } + else + { + return(NULL); + } +} +__declspec(dllexport) long __stdcall HandlerEnumerateLockHandlesW(wchar_t* szFileOrFolderName, bool NameIsFolder, bool NameIsTranslated, LPVOID HandleDataBuffer, DWORD MaxHandleCount) +{ + + int FoundHandles = NULL; + HANDLE hProcess = NULL; + HANDLE myHandle = NULL; + HANDLE CopyHandle = NULL; + LPVOID QuerySystemBuffer; + ULONG QuerySystemBufferSize = 0x2000; + ULONG RequiredSize = NULL; + ULONG TotalHandleCount = NULL; + DWORD LastProcessId = NULL; +#if !defined(_WIN64) + typedef NTSTATUS(__stdcall *fZwQuerySystemInformation)(DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); + typedef NTSTATUS(__stdcall *fZwQueryObject)(HANDLE hObject, DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); +#else + typedef NTSTATUS(__fastcall *fZwQuerySystemInformation)(DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); + typedef NTSTATUS(__fastcall *fZwQueryObject)(HANDLE hObject, DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); +#endif + LPVOID ZwQuerySystemInformation = (LPVOID)GetProcAddress(GetModuleHandleA("ntdll.dll"),"ZwQuerySystemInformation"); + LPVOID ZwQueryObject = (LPVOID)GetProcAddress(GetModuleHandleA("ntdll.dll"),"ZwQueryObject"); + fZwQuerySystemInformation cZwQuerySystemInformation = (fZwQuerySystemInformation)(ZwQuerySystemInformation); + fZwQueryObject cZwQueryObject = (fZwQueryObject)(ZwQueryObject); + PNTDLL_QUERY_HANDLE_INFO HandleInfo; + PUBLIC_OBJECT_BASIC_INFORMATION ObjectBasicInfo; + LPVOID ObjectNameInfo = VirtualAlloc(NULL, 0x2000, MEM_COMMIT, PAGE_READWRITE); + PPUBLIC_OBJECT_NAME_INFORMATION pObjectNameInfo = (PPUBLIC_OBJECT_NAME_INFORMATION)ObjectNameInfo; + LPVOID HandleFullName = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE); + int LenFileOrFolderName = lstrlenW(szFileOrFolderName); + LPVOID tmpHandleFullName = NULL; + + if(ZwQuerySystemInformation != NULL && ZwQueryObject != NULL) + { + QuerySystemBuffer = VirtualAlloc(NULL, QuerySystemBufferSize, MEM_COMMIT, PAGE_READWRITE); + while(cZwQuerySystemInformation(NTDLL_SystemHandleInfo, QuerySystemBuffer, QuerySystemBufferSize, &RequiredSize) == (NTSTATUS)0xC0000004L) + { + QuerySystemBufferSize = RequiredSize; + VirtualFree(QuerySystemBuffer, NULL, MEM_RELEASE); + QuerySystemBuffer = VirtualAlloc(NULL, QuerySystemBufferSize, MEM_COMMIT, PAGE_READWRITE); + } + RtlMoveMemory(&TotalHandleCount, QuerySystemBuffer, sizeof ULONG); + QuerySystemBuffer = (LPVOID)((ULONG_PTR)QuerySystemBuffer + 4); + HandleInfo = (PNTDLL_QUERY_HANDLE_INFO)QuerySystemBuffer; + while(TotalHandleCount > NULL) + { + if(LastProcessId != HandleInfo->ProcessId) + { + if(hProcess != NULL) + { + EngineCloseHandle(hProcess); + } + hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_DUP_HANDLE, false, HandleInfo->ProcessId); + LastProcessId = HandleInfo->ProcessId; + } + if(hProcess != NULL) + { + //if(!(HandleInfo->GrantedAccess & SYNCHRONIZE) || ((HandleInfo->GrantedAccess & SYNCHRONIZE) && ((WORD)HandleInfo->GrantedAccess != 0x19F9))){// && (WORD)HandleInfo->GrantedAccess != 0x89))){ + if(HandleInfo->GrantedAccess != 0x0012019F) + { + if(DuplicateHandle(hProcess, (HANDLE)HandleInfo->hHandle, GetCurrentProcess(), &myHandle, NULL, false, DUPLICATE_SAME_ACCESS)) + { + RtlZeroMemory(&ObjectBasicInfo, sizeof PUBLIC_OBJECT_BASIC_INFORMATION); + cZwQueryObject(myHandle, ObjectBasicInformation, &ObjectBasicInfo, sizeof PUBLIC_OBJECT_BASIC_INFORMATION, &RequiredSize); + cZwQueryObject(myHandle, ObjectNameInformation, ObjectNameInfo, 8, &RequiredSize); + cZwQueryObject(myHandle, ObjectNameInformation, ObjectNameInfo, RequiredSize, &RequiredSize); + RtlZeroMemory(HandleFullName, 0x1000); + if(pObjectNameInfo->Name.Length != NULL) + { + //WideCharToMultiByte(CP_ACP, NULL, (LPCWSTR)pObjectNameInfo->Name.Buffer, -1, (LPSTR)HandleFullName, 0x1000, NULL, NULL); + lstrcpyW((wchar_t*)HandleFullName, (wchar_t*)pObjectNameInfo->Name.Buffer); + if(NameIsTranslated) + { + tmpHandleFullName = TranslateNativeNameW((wchar_t*)HandleFullName); + if(tmpHandleFullName != NULL) + { + VirtualFree(HandleFullName, NULL, MEM_RELEASE); + HandleFullName = tmpHandleFullName; + } + } + if(NameIsFolder) + { + if(lstrlenW((LPCWSTR)HandleFullName) > LenFileOrFolderName) + { + RtlZeroMemory((LPVOID)((ULONG_PTR)HandleFullName + LenFileOrFolderName * 2), 2); + } + } + if(lstrcmpiW((LPCWSTR)HandleFullName, szFileOrFolderName) == NULL && MaxHandleCount > NULL) + { + RtlMoveMemory(HandleDataBuffer, &HandleInfo->ProcessId, sizeof ULONG); + HandleDataBuffer = (LPVOID)((ULONG_PTR)HandleDataBuffer + sizeof ULONG); + CopyHandle = (HANDLE)HandleInfo->hHandle; + RtlMoveMemory(HandleDataBuffer, &CopyHandle, sizeof HANDLE); + HandleDataBuffer = (LPVOID)((ULONG_PTR)HandleDataBuffer + sizeof HANDLE); + FoundHandles++; + MaxHandleCount--; + } + } + EngineCloseHandle(myHandle); + } + } + } + HandleInfo = (PNTDLL_QUERY_HANDLE_INFO)((ULONG_PTR)HandleInfo + sizeof NTDLL_QUERY_HANDLE_INFO); + TotalHandleCount--; + } + VirtualFree(ObjectNameInfo, NULL, MEM_RELEASE); + VirtualFree(QuerySystemBuffer, NULL, MEM_RELEASE); + VirtualFree(HandleFullName, NULL, MEM_RELEASE); + return(FoundHandles); + } + VirtualFree(ObjectNameInfo, NULL, MEM_RELEASE); + VirtualFree(HandleFullName, NULL, MEM_RELEASE); + return(NULL); +} +__declspec(dllexport) bool __stdcall HandlerCloseAllLockHandles(char* szFileOrFolderName, bool NameIsFolder, bool NameIsTranslated) +{ + + wchar_t uniFileOrFolderName[MAX_PATH] = {}; + + if(szFileOrFolderName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileOrFolderName, lstrlenA(szFileOrFolderName)+1, uniFileOrFolderName, sizeof(uniFileOrFolderName)/(sizeof(uniFileOrFolderName[0]))); + return(HandlerCloseAllLockHandlesW(uniFileOrFolderName, NameIsFolder, NameIsTranslated)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall HandlerCloseAllLockHandlesW(wchar_t* szFileOrFolderName, bool NameIsFolder, bool NameIsTranslated) +{ + + bool AllHandled = true; + HANDLE hProcess = NULL; + HANDLE myHandle = NULL; + HANDLE CopyHandle = NULL; + LPVOID QuerySystemBuffer; + ULONG QuerySystemBufferSize = 0x2000; + ULONG RequiredSize = NULL; + ULONG TotalHandleCount = NULL; + DWORD LastProcessId = NULL; +#if !defined(_WIN64) + typedef NTSTATUS(__stdcall *fZwQuerySystemInformation)(DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); + typedef NTSTATUS(__stdcall *fZwQueryObject)(HANDLE hObject, DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); +#else + typedef NTSTATUS(__fastcall *fZwQuerySystemInformation)(DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); + typedef NTSTATUS(__fastcall *fZwQueryObject)(HANDLE hObject, DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); +#endif + LPVOID ZwQuerySystemInformation = (LPVOID)GetProcAddress(GetModuleHandleA("ntdll.dll"),"ZwQuerySystemInformation"); + LPVOID ZwQueryObject = (LPVOID)GetProcAddress(GetModuleHandleA("ntdll.dll"),"ZwQueryObject"); + fZwQuerySystemInformation cZwQuerySystemInformation = (fZwQuerySystemInformation)(ZwQuerySystemInformation); + fZwQueryObject cZwQueryObject = (fZwQueryObject)(ZwQueryObject); + PNTDLL_QUERY_HANDLE_INFO HandleInfo; + PUBLIC_OBJECT_BASIC_INFORMATION ObjectBasicInfo; + LPVOID ObjectNameInfo = VirtualAlloc(NULL, 0x2000, MEM_COMMIT, PAGE_READWRITE); + PPUBLIC_OBJECT_NAME_INFORMATION pObjectNameInfo = (PPUBLIC_OBJECT_NAME_INFORMATION)ObjectNameInfo; + LPVOID HandleFullName = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE); + int LenFileOrFolderName = lstrlenW(szFileOrFolderName); + LPVOID tmpHandleFullName = NULL; + + if(ZwQuerySystemInformation != NULL && ZwQueryObject != NULL) + { + QuerySystemBuffer = VirtualAlloc(NULL, QuerySystemBufferSize, MEM_COMMIT, PAGE_READWRITE); + while(cZwQuerySystemInformation(NTDLL_SystemHandleInfo, QuerySystemBuffer, QuerySystemBufferSize, &RequiredSize) == (NTSTATUS)0xC0000004L) + { + QuerySystemBufferSize = RequiredSize; + VirtualFree(QuerySystemBuffer, NULL, MEM_RELEASE); + QuerySystemBuffer = VirtualAlloc(NULL, QuerySystemBufferSize, MEM_COMMIT, PAGE_READWRITE); + } + RtlMoveMemory(&TotalHandleCount, QuerySystemBuffer, sizeof ULONG); + QuerySystemBuffer = (LPVOID)((ULONG_PTR)QuerySystemBuffer + 4); + HandleInfo = (PNTDLL_QUERY_HANDLE_INFO)QuerySystemBuffer; + while(TotalHandleCount > NULL) + { + if(LastProcessId != HandleInfo->ProcessId) + { + if(hProcess != NULL) + { + EngineCloseHandle(hProcess); + } + hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_DUP_HANDLE, false, HandleInfo->ProcessId); + LastProcessId = HandleInfo->ProcessId; + } + if(hProcess != NULL) + { + //if(!(HandleInfo->GrantedAccess & SYNCHRONIZE) || ((HandleInfo->GrantedAccess & SYNCHRONIZE) && ((WORD)HandleInfo->GrantedAccess != 0x19F9))){// && (WORD)HandleInfo->GrantedAccess != 0x89))){ + if(HandleInfo->GrantedAccess != 0x0012019F) + { + if(DuplicateHandle(hProcess, (HANDLE)HandleInfo->hHandle, GetCurrentProcess(), &myHandle, NULL, false, DUPLICATE_SAME_ACCESS)) + { + RtlZeroMemory(&ObjectBasicInfo, sizeof PUBLIC_OBJECT_BASIC_INFORMATION); + cZwQueryObject(myHandle, ObjectBasicInformation, &ObjectBasicInfo, sizeof PUBLIC_OBJECT_BASIC_INFORMATION, &RequiredSize); + cZwQueryObject(myHandle, ObjectNameInformation, ObjectNameInfo, 8, &RequiredSize); + cZwQueryObject(myHandle, ObjectNameInformation, ObjectNameInfo, RequiredSize, &RequiredSize); + RtlZeroMemory(HandleFullName, 0x1000); + if(pObjectNameInfo->Name.Length != NULL) + { + //WideCharToMultiByte(CP_ACP, NULL, (LPCWSTR)pObjectNameInfo->Name.Buffer, -1, (LPSTR)HandleFullName, 0x1000, NULL, NULL); + lstrcpyW((wchar_t*)HandleFullName, (wchar_t*)pObjectNameInfo->Name.Buffer); + if(NameIsTranslated) + { + tmpHandleFullName = TranslateNativeNameW((wchar_t*)HandleFullName); + if(tmpHandleFullName != NULL) + { + VirtualFree(HandleFullName, NULL, MEM_RELEASE); + HandleFullName = tmpHandleFullName; + } + } + if(NameIsFolder) + { + if(lstrlenW((LPCWSTR)HandleFullName) > LenFileOrFolderName) + { + RtlZeroMemory((LPVOID)((ULONG_PTR)HandleFullName + LenFileOrFolderName * 2), 2); + } + } + if(lstrcmpiW((LPCWSTR)HandleFullName, szFileOrFolderName) == NULL) + { + if(!HandlerCloseRemoteHandle(hProcess, (HANDLE)HandleInfo->hHandle)) + { + AllHandled = false; + } + } + } + EngineCloseHandle(myHandle); + } + } + } + HandleInfo = (PNTDLL_QUERY_HANDLE_INFO)((ULONG_PTR)HandleInfo + sizeof NTDLL_QUERY_HANDLE_INFO); + TotalHandleCount--; + } + VirtualFree(ObjectNameInfo, NULL, MEM_RELEASE); + VirtualFree(QuerySystemBuffer, NULL, MEM_RELEASE); + VirtualFree(HandleFullName, NULL, MEM_RELEASE); + if(AllHandled) + { + return(true); + } + else + { + return(false); + } + } + VirtualFree(ObjectNameInfo, NULL, MEM_RELEASE); + VirtualFree(HandleFullName, NULL, MEM_RELEASE); + return(false); +} +__declspec(dllexport) bool __stdcall HandlerIsFileLocked(char* szFileOrFolderName, bool NameIsFolder, bool NameIsTranslated) +{ + + wchar_t uniFileOrFolderName[MAX_PATH] = {}; + + if(szFileOrFolderName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileOrFolderName, lstrlenA(szFileOrFolderName)+1, uniFileOrFolderName, sizeof(uniFileOrFolderName)/(sizeof(uniFileOrFolderName[0]))); + return(HandlerIsFileLockedW(uniFileOrFolderName, NameIsFolder, NameIsTranslated)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall HandlerIsFileLockedW(wchar_t* szFileOrFolderName, bool NameIsFolder, bool NameIsTranslated) +{ + + HANDLE hProcess = NULL; + HANDLE myHandle = NULL; + HANDLE CopyHandle = NULL; + LPVOID QuerySystemBuffer; + ULONG QuerySystemBufferSize = 0x2000; + ULONG RequiredSize = NULL; + ULONG TotalHandleCount = NULL; + DWORD LastProcessId = NULL; +#if !defined(_WIN64) + typedef NTSTATUS(__stdcall *fZwQuerySystemInformation)(DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); + typedef NTSTATUS(__stdcall *fZwQueryObject)(HANDLE hObject, DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); +#else + typedef NTSTATUS(__fastcall *fZwQuerySystemInformation)(DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); + typedef NTSTATUS(__fastcall *fZwQueryObject)(HANDLE hObject, DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); +#endif + LPVOID ZwQuerySystemInformation = (LPVOID)GetProcAddress(GetModuleHandleA("ntdll.dll"),"ZwQuerySystemInformation"); + LPVOID ZwQueryObject = (LPVOID)GetProcAddress(GetModuleHandleA("ntdll.dll"),"ZwQueryObject"); + fZwQuerySystemInformation cZwQuerySystemInformation = (fZwQuerySystemInformation)(ZwQuerySystemInformation); + fZwQueryObject cZwQueryObject = (fZwQueryObject)(ZwQueryObject); + PNTDLL_QUERY_HANDLE_INFO HandleInfo; + PUBLIC_OBJECT_BASIC_INFORMATION ObjectBasicInfo; + LPVOID ObjectNameInfo = VirtualAlloc(NULL, 0x2000, MEM_COMMIT, PAGE_READWRITE); + PPUBLIC_OBJECT_NAME_INFORMATION pObjectNameInfo = (PPUBLIC_OBJECT_NAME_INFORMATION)ObjectNameInfo; + LPVOID HandleFullName = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE); + int LenFileOrFolderName = lstrlenW(szFileOrFolderName); + LPVOID tmpHandleFullName = NULL; + + if(ZwQuerySystemInformation != NULL && ZwQueryObject != NULL) + { + QuerySystemBuffer = VirtualAlloc(NULL, QuerySystemBufferSize, MEM_COMMIT, PAGE_READWRITE); + while(cZwQuerySystemInformation(NTDLL_SystemHandleInfo, QuerySystemBuffer, QuerySystemBufferSize, &RequiredSize) == (NTSTATUS)0xC0000004L) + { + QuerySystemBufferSize = RequiredSize; + VirtualFree(QuerySystemBuffer, NULL, MEM_RELEASE); + QuerySystemBuffer = VirtualAlloc(NULL, QuerySystemBufferSize, MEM_COMMIT, PAGE_READWRITE); + } + RtlMoveMemory(&TotalHandleCount, QuerySystemBuffer, sizeof ULONG); + QuerySystemBuffer = (LPVOID)((ULONG_PTR)QuerySystemBuffer + 4); + HandleInfo = (PNTDLL_QUERY_HANDLE_INFO)QuerySystemBuffer; + while(TotalHandleCount > NULL) + { + if(LastProcessId != HandleInfo->ProcessId) + { + if(hProcess != NULL) + { + EngineCloseHandle(hProcess); + } + hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_DUP_HANDLE, false, HandleInfo->ProcessId); + LastProcessId = HandleInfo->ProcessId; + } + if(hProcess != NULL) + { + //if(!(HandleInfo->GrantedAccess & SYNCHRONIZE) || ((HandleInfo->GrantedAccess & SYNCHRONIZE) && ((WORD)HandleInfo->GrantedAccess != 0x19F9))){// && (WORD)HandleInfo->GrantedAccess != 0x89))){ + if(HandleInfo->GrantedAccess != 0x0012019F) + { + if(DuplicateHandle(hProcess, (HANDLE)HandleInfo->hHandle, GetCurrentProcess(), &myHandle, NULL, false, DUPLICATE_SAME_ACCESS)) + { + RtlZeroMemory(&ObjectBasicInfo, sizeof PUBLIC_OBJECT_BASIC_INFORMATION); + cZwQueryObject(myHandle, ObjectBasicInformation, &ObjectBasicInfo, sizeof PUBLIC_OBJECT_BASIC_INFORMATION, &RequiredSize); + cZwQueryObject(myHandle, ObjectNameInformation, ObjectNameInfo, 8, &RequiredSize); + cZwQueryObject(myHandle, ObjectNameInformation, ObjectNameInfo, RequiredSize, &RequiredSize); + RtlZeroMemory(HandleFullName, 0x1000); + if(pObjectNameInfo->Name.Length != NULL) + { + //WideCharToMultiByte(CP_ACP, NULL, (LPCWSTR)pObjectNameInfo->Name.Buffer, -1, (LPSTR)HandleFullName, 0x1000, NULL, NULL); + lstrcpyW((wchar_t*)HandleFullName, (wchar_t*)pObjectNameInfo->Name.Buffer); + if(NameIsTranslated) + { + tmpHandleFullName = TranslateNativeNameW((wchar_t*)HandleFullName); + if(tmpHandleFullName != NULL) + { + VirtualFree(HandleFullName, NULL, MEM_RELEASE); + HandleFullName = tmpHandleFullName; + } + } + if(NameIsFolder) + { + if(lstrlenW((LPCWSTR)HandleFullName) > LenFileOrFolderName) + { + RtlZeroMemory((LPVOID)((ULONG_PTR)HandleFullName + LenFileOrFolderName * 2), 2); + } + } + if(lstrcmpiW((LPCWSTR)HandleFullName, szFileOrFolderName) == NULL) + { + VirtualFree(ObjectNameInfo, NULL, MEM_RELEASE); + VirtualFree(QuerySystemBuffer, NULL, MEM_RELEASE); + VirtualFree(HandleFullName, NULL, MEM_RELEASE); + EngineCloseHandle(myHandle); + return(true); + } + } + EngineCloseHandle(myHandle); + } + } + } + HandleInfo = (PNTDLL_QUERY_HANDLE_INFO)((ULONG_PTR)HandleInfo + sizeof NTDLL_QUERY_HANDLE_INFO); + TotalHandleCount--; + } + VirtualFree(ObjectNameInfo, NULL, MEM_RELEASE); + VirtualFree(QuerySystemBuffer, NULL, MEM_RELEASE); + VirtualFree(HandleFullName, NULL, MEM_RELEASE); + return(false); + } + VirtualFree(ObjectNameInfo, NULL, MEM_RELEASE); + VirtualFree(HandleFullName, NULL, MEM_RELEASE); + return(false); +} +// TitanEngine.Handler[Mutex].functions: +__declspec(dllexport) long __stdcall HandlerEnumerateOpenMutexes(HANDLE hProcess, DWORD ProcessId, LPVOID HandleBuffer, DWORD MaxHandleCount) +{ + + HANDLE myHandle = NULL; + HANDLE copyHandle = NULL; + LPVOID QuerySystemBuffer; + ULONG RequiredSize = NULL; + ULONG TotalHandleCount = NULL; + unsigned int HandleCount = NULL; + ULONG QuerySystemBufferSize = 0x2000; +#if !defined(_WIN64) + typedef NTSTATUS(__stdcall *fZwQuerySystemInformation)(DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); + typedef NTSTATUS(__stdcall *fZwQueryObject)(HANDLE hObject, DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); +#else + typedef NTSTATUS(__fastcall *fZwQuerySystemInformation)(DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); + typedef NTSTATUS(__fastcall *fZwQueryObject)(HANDLE hObject, DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); +#endif + LPVOID ZwQuerySystemInformation = (LPVOID)GetProcAddress(GetModuleHandleA("ntdll.dll"),"ZwQuerySystemInformation"); + LPVOID ZwQueryObject = (LPVOID)GetProcAddress(GetModuleHandleA("ntdll.dll"),"ZwQueryObject"); + fZwQuerySystemInformation cZwQuerySystemInformation = (fZwQuerySystemInformation)(ZwQuerySystemInformation); + fZwQueryObject cZwQueryObject = (fZwQueryObject)(ZwQueryObject); + PNTDLL_QUERY_HANDLE_INFO HandleInfo; + LPVOID HandleFullData = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE); + LPVOID HandleNameData = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE); + PPUBLIC_OBJECT_TYPE_INFORMATION pObjectTypeInfo = (PPUBLIC_OBJECT_TYPE_INFORMATION)HandleFullData; + + if(ZwQuerySystemInformation != NULL && ZwQueryObject != NULL) + { + QuerySystemBuffer = VirtualAlloc(NULL, QuerySystemBufferSize, MEM_COMMIT, PAGE_READWRITE); + while(cZwQuerySystemInformation(NTDLL_SystemHandleInfo, QuerySystemBuffer, QuerySystemBufferSize, &RequiredSize) == (NTSTATUS)0xC0000004L) + { + QuerySystemBufferSize = RequiredSize; + VirtualFree(QuerySystemBuffer, NULL, MEM_RELEASE); + QuerySystemBuffer = VirtualAlloc(NULL, QuerySystemBufferSize, MEM_COMMIT, PAGE_READWRITE); + } + RtlMoveMemory(&TotalHandleCount, QuerySystemBuffer, sizeof ULONG); + QuerySystemBuffer = (LPVOID)((ULONG_PTR)QuerySystemBuffer + 4); + HandleInfo = (PNTDLL_QUERY_HANDLE_INFO)QuerySystemBuffer; + while(TotalHandleCount > NULL) + { + if(HandleInfo->ProcessId == ProcessId && HandleCount < MaxHandleCount) + { + //if(!(HandleInfo->GrantedAccess & SYNCHRONIZE) || ((HandleInfo->GrantedAccess & SYNCHRONIZE) && ((WORD)HandleInfo->GrantedAccess != 0x19F9))){// && (WORD)HandleInfo->GrantedAccess != 0x89))){ + if(HandleInfo->GrantedAccess != 0x0012019F) + { + if(DuplicateHandle(hProcess, (HANDLE)HandleInfo->hHandle, GetCurrentProcess(), &myHandle, NULL, false, DUPLICATE_SAME_ACCESS)) + { + RtlZeroMemory(HandleFullData, 0x1000); + cZwQueryObject(myHandle, ObjectTypeInformation, HandleFullData, 8, &RequiredSize); + cZwQueryObject(myHandle, ObjectTypeInformation, HandleFullData, RequiredSize, &RequiredSize); + RtlZeroMemory(HandleNameData, 0x1000); + if(pObjectTypeInfo->Name.Length != NULL) + { + WideCharToMultiByte(CP_ACP, NULL, (LPCWSTR)pObjectTypeInfo->Name.Buffer, -1, (LPSTR)HandleNameData, 0x1000, NULL, NULL); + if(lstrcmpiA((LPCSTR)HandleNameData, "Mutant") == NULL) + { + copyHandle = (HANDLE)HandleInfo->hHandle; + RtlMoveMemory(HandleBuffer, ©Handle, sizeof HANDLE); + HandleBuffer = (LPVOID)((ULONG_PTR)HandleBuffer + sizeof HANDLE); + HandleCount++; + } + } + EngineCloseHandle(myHandle); + } + } + } + HandleInfo = (PNTDLL_QUERY_HANDLE_INFO)((ULONG_PTR)HandleInfo + sizeof NTDLL_QUERY_HANDLE_INFO); + TotalHandleCount--; + } + VirtualFree(HandleFullData, NULL, MEM_RELEASE); + VirtualFree(HandleNameData, NULL, MEM_RELEASE); + VirtualFree(QuerySystemBuffer, NULL, MEM_RELEASE); + return(HandleCount); + } + VirtualFree(HandleFullData, NULL, MEM_RELEASE); + VirtualFree(HandleNameData, NULL, MEM_RELEASE); + return(NULL); +} +__declspec(dllexport) long long __stdcall HandlerGetOpenMutexHandle(HANDLE hProcess, DWORD ProcessId, char* szMutexString) +{ + + wchar_t uniMutexString[MAX_PATH] = {}; + + if(szMutexString != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szMutexString, lstrlenA(szMutexString)+1, uniMutexString, sizeof(uniMutexString)/(sizeof(uniMutexString[0]))); + return((ULONG_PTR)HandlerGetOpenMutexHandleW(hProcess, ProcessId, uniMutexString)); + } + else + { + return(NULL); + } +} +__declspec(dllexport) long long __stdcall HandlerGetOpenMutexHandleW(HANDLE hProcess, DWORD ProcessId, wchar_t* szMutexString) +{ + + int i; + HANDLE myHandle; + LPVOID HandleBuffer = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE); + LPVOID cHandleBuffer = HandleBuffer; + int OpenHandleCount = HandlerEnumerateOpenMutexes(hProcess, ProcessId, HandleBuffer, 0x1000 / sizeof HANDLE); + wchar_t RealMutexName[512] = L"\\BaseNamedObjects\\"; + wchar_t* HandleName; + + if(OpenHandleCount > NULL) + { + lstrcatW(RealMutexName, szMutexString); + for(i = 0; i < OpenHandleCount; i++) + { + RtlMoveMemory(&myHandle, cHandleBuffer, sizeof HANDLE); + HandleName = (wchar_t*)HandlerGetHandleNameW(hProcess, ProcessId, myHandle, true); + if(HandleName != NULL) + { + if(lstrcmpiW(HandleName, RealMutexName) == NULL) + { + VirtualFree(HandleBuffer, NULL, MEM_RELEASE); + return((ULONG_PTR)myHandle); + } + } + cHandleBuffer = (LPVOID)((ULONG_PTR)cHandleBuffer + sizeof HANDLE); + } + } + VirtualFree(HandleBuffer, NULL, MEM_RELEASE); + return(NULL); +} +__declspec(dllexport) long __stdcall HandlerGetProcessIdWhichCreatedMutex(char* szMutexString) +{ + + wchar_t uniMutexString[MAX_PATH] = {}; + + if(szMutexString != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szMutexString, lstrlenA(szMutexString)+1, uniMutexString, sizeof(uniMutexString)/(sizeof(uniMutexString[0]))); + return(HandlerGetProcessIdWhichCreatedMutexW(uniMutexString)); + } + else + { + return(NULL); + } +} +__declspec(dllexport) long __stdcall HandlerGetProcessIdWhichCreatedMutexW(wchar_t* szMutexString) +{ + + HANDLE hProcess = NULL; + DWORD ReturnData = NULL; + HANDLE myHandle = NULL; + LPVOID QuerySystemBuffer; + ULONG RequiredSize = NULL; + DWORD LastProcessId = NULL; + ULONG TotalHandleCount = NULL; + ULONG QuerySystemBufferSize = 0x2000; +#if !defined(_WIN64) + typedef NTSTATUS(__stdcall *fZwQuerySystemInformation)(DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); + typedef NTSTATUS(__stdcall *fZwQueryObject)(HANDLE hObject, DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); +#else + typedef NTSTATUS(__fastcall *fZwQuerySystemInformation)(DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); + typedef NTSTATUS(__fastcall *fZwQueryObject)(HANDLE hObject, DWORD fInfoType, LPVOID fBuffer, ULONG fBufferSize, PULONG fRequiredSize); +#endif + LPVOID ZwQuerySystemInformation = (LPVOID)GetProcAddress(GetModuleHandleA("ntdll.dll"),"ZwQuerySystemInformation"); + LPVOID ZwQueryObject = (LPVOID)GetProcAddress(GetModuleHandleA("ntdll.dll"),"ZwQueryObject"); + fZwQuerySystemInformation cZwQuerySystemInformation = (fZwQuerySystemInformation)(ZwQuerySystemInformation); + fZwQueryObject cZwQueryObject = (fZwQueryObject)(ZwQueryObject); + PNTDLL_QUERY_HANDLE_INFO HandleInfo; + LPVOID HandleFullData = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE); + LPVOID HandleNameData = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE); + PPUBLIC_OBJECT_TYPE_INFORMATION pObjectTypeInfo = (PPUBLIC_OBJECT_TYPE_INFORMATION)HandleFullData; + LPVOID ObjectNameInfo = VirtualAlloc(NULL, 0x2000, MEM_COMMIT, PAGE_READWRITE); + PPUBLIC_OBJECT_NAME_INFORMATION pObjectNameInfo = (PPUBLIC_OBJECT_NAME_INFORMATION)ObjectNameInfo; + wchar_t RealMutexName[512] = L"\\BaseNamedObjects\\"; + + if(ZwQuerySystemInformation != NULL && ZwQueryObject != NULL) + { + lstrcatW(RealMutexName, szMutexString); + QuerySystemBuffer = VirtualAlloc(NULL, QuerySystemBufferSize, MEM_COMMIT, PAGE_READWRITE); + while(cZwQuerySystemInformation(NTDLL_SystemHandleInfo, QuerySystemBuffer, QuerySystemBufferSize, &RequiredSize) == (NTSTATUS)0xC0000004L) + { + QuerySystemBufferSize = RequiredSize; + VirtualFree(QuerySystemBuffer, NULL, MEM_RELEASE); + QuerySystemBuffer = VirtualAlloc(NULL, QuerySystemBufferSize, MEM_COMMIT, PAGE_READWRITE); + } + RtlMoveMemory(&TotalHandleCount, QuerySystemBuffer, sizeof ULONG); + QuerySystemBuffer = (LPVOID)((ULONG_PTR)QuerySystemBuffer + 4); + HandleInfo = (PNTDLL_QUERY_HANDLE_INFO)QuerySystemBuffer; + while(TotalHandleCount > NULL) + { + if(LastProcessId != HandleInfo->ProcessId) + { + if(hProcess != NULL) + { + EngineCloseHandle(hProcess); + } + hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_DUP_HANDLE, false, HandleInfo->ProcessId); + LastProcessId = HandleInfo->ProcessId; + } + if(hProcess != NULL) + { + //if(!(HandleInfo->GrantedAccess & SYNCHRONIZE) || ((HandleInfo->GrantedAccess & SYNCHRONIZE) && ((WORD)HandleInfo->GrantedAccess != 0x19F9))){// && (WORD)HandleInfo->GrantedAccess != 0x89))){ + if(HandleInfo->GrantedAccess != 0x0012019F) + { + if(DuplicateHandle(hProcess, (HANDLE)HandleInfo->hHandle, GetCurrentProcess(), &myHandle, NULL, false, DUPLICATE_SAME_ACCESS)) + { + RtlZeroMemory(HandleFullData, 0x1000); + cZwQueryObject(myHandle, ObjectTypeInformation, HandleFullData, 8, &RequiredSize); + cZwQueryObject(myHandle, ObjectTypeInformation, HandleFullData, RequiredSize, &RequiredSize); + RtlZeroMemory(HandleNameData, 0x1000); + if(pObjectTypeInfo->Name.Length != NULL) + { + //WideCharToMultiByte(CP_ACP, NULL, (LPCWSTR)pObjectTypeInfo->Name.Buffer, -1, (LPSTR)HandleNameData, 0x1000, NULL, NULL); + lstrcpyW((wchar_t*)HandleNameData, (wchar_t*)pObjectNameInfo->Name.Buffer); + if(lstrcmpiW((LPCWSTR)HandleNameData, L"Mutant") == NULL) + { + cZwQueryObject(myHandle, ObjectNameInformation, ObjectNameInfo, 8, &RequiredSize); + cZwQueryObject(myHandle, ObjectNameInformation, ObjectNameInfo, RequiredSize, &RequiredSize); + RtlZeroMemory(HandleNameData, 0x1000); + if(pObjectNameInfo->Name.Length != NULL) + { + RtlZeroMemory(HandleNameData, 0x1000); + //WideCharToMultiByte(CP_ACP, NULL, (LPCWSTR)pObjectNameInfo->Name.Buffer, -1, (LPSTR)HandleNameData, 0x1000, NULL, NULL); + lstrcpyW((wchar_t*)HandleNameData, (wchar_t*)pObjectNameInfo->Name.Buffer); + if(lstrcmpiW((LPCWSTR)HandleNameData, RealMutexName) == NULL) + { + ReturnData = HandleInfo->ProcessId; + break; + } + } + } + } + EngineCloseHandle(myHandle); + } + } + } + HandleInfo = (PNTDLL_QUERY_HANDLE_INFO)((ULONG_PTR)HandleInfo + sizeof NTDLL_QUERY_HANDLE_INFO); + TotalHandleCount--; + } + VirtualFree(HandleFullData, NULL, MEM_RELEASE); + VirtualFree(HandleNameData, NULL, MEM_RELEASE); + VirtualFree(ObjectNameInfo, NULL, MEM_RELEASE); + VirtualFree(QuerySystemBuffer, NULL, MEM_RELEASE); + return(ReturnData); + } + VirtualFree(HandleFullData, NULL, MEM_RELEASE); + VirtualFree(HandleNameData, NULL, MEM_RELEASE); + VirtualFree(ObjectNameInfo, NULL, MEM_RELEASE); + return(NULL); +} +// Global.Injector.functions: {DO NOT REORDER! USE ONLY IN RELEASE MODE!} +long __stdcall injectedImpRec(LPVOID Parameter) +{ + + HANDLE hFile; + HANDLE hFileMap; + PInjectImpRecCodeData APIData = (PInjectImpRecCodeData)Parameter; + LPVOID szFileName = (LPVOID)((ULONG_PTR)Parameter + sizeof InjectImpRecCodeData); + typedef ULONG_PTR(__cdecl *fTrace)(DWORD hFileMap, DWORD dwSizeMap, DWORD dwTimeOut, DWORD dwToTrace, DWORD dwExactCall); + typedef HANDLE(__stdcall *fCreateFileW)(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); + typedef HANDLE(__stdcall *fCreateFileMappingA)(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCSTR lpName); + typedef BOOL(__cdecl *fCloseHandle)(HANDLE hHandle); + fTrace cTrace = (fTrace)(APIData->fTrace); + fCreateFileW cCreateFileW = (fCreateFileW)(APIData->fCreateFileA); + fCloseHandle cCloseHandle = (fCloseHandle)(APIData->fCloseHandle); + fCreateFileMappingA cCreateFileMappingA = (fCreateFileMappingA)(APIData->fCreateFileMappingA); + + hFile = cCreateFileW((LPCWSTR)szFileName, GENERIC_READ+GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if(hFile != INVALID_HANDLE_VALUE) + { + hFileMap = cCreateFileMappingA(hFile, NULL, 4, NULL, 0x100, NULL); + cTrace((DWORD)hFileMap, 0x100, -1, (DWORD)APIData->AddressToTrace, NULL); + cCloseHandle(hFile); + return(1); + } + else + { + return(0); + } +} +long __stdcall injectedRemoteLoadLibrary(LPVOID Parameter) +{ + + PInjectCodeData APIData = (PInjectCodeData)Parameter; + Parameter = (LPVOID)((ULONG_PTR)Parameter + sizeof InjectCodeData); +#if !defined(_WIN64) + typedef ULONG_PTR(__stdcall *fLoadLibraryW)(LPCWSTR fLibraryName); + typedef ULONG_PTR(__stdcall *fVirtualFree)(LPVOID fMemBase, SIZE_T fMemSize, DWORD fFreeType); +#else + typedef ULONG_PTR(__fastcall *fLoadLibraryW)(LPCWSTR fLibraryName); + typedef ULONG_PTR(__fastcall *fVirtualFree)(LPVOID fMemBase, SIZE_T fMemSize, DWORD fFreeType); +#endif + fLoadLibraryW cLoadLibraryW = (fLoadLibraryW)(APIData->fLoadLibrary); + fVirtualFree cVirtualFree = (fVirtualFree)(APIData->fVirtualFree); + long retValue = NULL; + + if(cLoadLibraryW((LPCWSTR)Parameter) != NULL) + { + retValue++; + } + cVirtualFree(Parameter, NULL, MEM_RELEASE); + return(retValue); +} +long __stdcall injectedRemoteFreeLibrary(LPVOID Parameter) +{ + + PInjectCodeData APIData = (PInjectCodeData)Parameter; +#if !defined(_WIN64) + typedef ULONG_PTR(__stdcall *fFreeLibrary)(HMODULE fLibBase); + typedef ULONG_PTR(__stdcall *fVirtualFree)(LPVOID fMemBase, SIZE_T fMemSize, DWORD fFreeType); +#else + typedef ULONG_PTR(__fastcall *fFreeLibrary)(HMODULE fLibBase); + typedef ULONG_PTR(__fastcall *fVirtualFree)(LPVOID fMemBase, SIZE_T fMemSize, DWORD fFreeType); +#endif + fFreeLibrary cFreeLibrary = (fFreeLibrary)(APIData->fFreeLibrary); + fVirtualFree cVirtualFree = (fVirtualFree)(APIData->fVirtualFree); + long retValue = NULL; + + if(cFreeLibrary(APIData->fFreeLibraryHandle)) + { + retValue++; + } + cVirtualFree(Parameter, NULL, MEM_RELEASE); + return(retValue); +} +long __stdcall injectedRemoteFreeLibrarySimple(LPVOID Parameter) +{ + + PInjectCodeData APIData = (PInjectCodeData)Parameter; + LPVOID orgParameter = Parameter; + Parameter = (LPVOID)((ULONG_PTR)Parameter + sizeof InjectCodeData); +#if !defined(_WIN64) + typedef ULONG_PTR(__stdcall *fFreeLibrary)(HMODULE fLibBase); + typedef HMODULE(__stdcall *fGetModuleHandleW)(LPCWSTR fLibraryName); + typedef ULONG_PTR(__stdcall *fVirtualFree)(LPVOID fMemBase, SIZE_T fMemSize, DWORD fFreeType); +#else + typedef ULONG_PTR(__fastcall *fFreeLibrary)(HMODULE fLibBase); + typedef HMODULE(__fastcall *fGetModuleHandleW)(LPCWSTR fLibraryName); + typedef ULONG_PTR(__fastcall *fVirtualFree)(LPVOID fMemBase, SIZE_T fMemSize, DWORD fFreeType); +#endif + fGetModuleHandleW cGetModuleHandleW = (fGetModuleHandleW)(APIData->fGetModuleHandle); + fFreeLibrary cFreeLibrary = (fFreeLibrary)(APIData->fFreeLibrary); + fVirtualFree cVirtualFree = (fVirtualFree)(APIData->fVirtualFree); + long retValue = NULL; + HMODULE hModule; + + hModule = cGetModuleHandleW((LPCWSTR)Parameter); + if(hModule != NULL) + { + if(cFreeLibrary(hModule)) + { + retValue++; + } + } + else + { + retValue++; + } + cVirtualFree(orgParameter, NULL, MEM_RELEASE); + return(retValue); +} +long __stdcall injectedExitProcess(LPVOID Parameter) +{ + + PInjectCodeData APIData = (PInjectCodeData)Parameter; +#if !defined(_WIN64) + typedef ULONG_PTR(__stdcall *fExitProcess)(DWORD fExitCode); +#else + typedef ULONG_PTR(__fastcall *fExitProcess)(DWORD fExitCode); +#endif + fExitProcess cExitProcess = (fExitProcess)(APIData->fExitProcess); + long retValue = NULL; + + cExitProcess(APIData->fExitProcessCode); + return(NULL); +} +void __stdcall injectedTerminator() +{ + + int i; + + for(i = 0; i < UE_MAX_RESERVED_MEMORY_LEFT; i++) + { + if(engineReservedMemoryLeft[i] != NULL) + { + VirtualFreeEx(engineReservedMemoryProcess, (LPVOID)engineReservedMemoryLeft[i], NULL, MEM_RELEASE); + engineReservedMemoryLeft[i] = NULL; + } + } +} +// TitanEngine.Injector.functions: +__declspec(dllexport) bool __stdcall RemoteLoadLibrary(HANDLE hProcess, char* szLibraryFile, bool WaitForThreadExit) +{ + + wchar_t uniLibraryFile[MAX_PATH] = {}; + + if(szLibraryFile != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szLibraryFile, lstrlenA(szLibraryFile)+1, uniLibraryFile, sizeof(uniLibraryFile)/(sizeof(uniLibraryFile[0]))); + return(RemoteLoadLibraryW(hProcess, uniLibraryFile, WaitForThreadExit)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall RemoteLoadLibraryW(HANDLE hProcess, wchar_t* szLibraryFile, bool WaitForThreadExit) +{ + + int i; + InjectCodeData APIData; + LPVOID remStringData; + LPVOID remCodeData; + ULONG_PTR remInjectSize = (ULONG_PTR)((ULONG_PTR)&injectedRemoteFreeLibrary - (ULONG_PTR)&injectedRemoteLoadLibrary); +#if !defined(_WIN64) + typedef NTSTATUS(__stdcall *fZwSetInformationThread)(HANDLE fThreadHandle, DWORD fThreadInfoClass, LPVOID fBuffer, ULONG fBufferSize); +#else + typedef NTSTATUS(__fastcall *fZwSetInformationThread)(HANDLE fThreadHandle, DWORD fThreadInfoClass, LPVOID fBuffer, ULONG fBufferSize); +#endif + LPVOID ZwSetInformationThread = (LPVOID)GetProcAddress(GetModuleHandleA("ntdll.dll"),"ZwSetInformationThread"); + fZwSetInformationThread cZwSetInformationThread = (fZwSetInformationThread)(ZwSetInformationThread); + ULONG_PTR NumberOfBytesWritten; + DWORD ThreadId; + HANDLE hThread; + DWORD ExitCode; + + if(hProcess != NULL) + { + RtlZeroMemory(&APIData, sizeof InjectCodeData); + APIData.fLoadLibrary = (ULONG_PTR)ImporterGetRemoteAPIAddress(hProcess, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryW")); + APIData.fFreeLibrary = (ULONG_PTR)ImporterGetRemoteAPIAddress(hProcess, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"), "FreeLibrary")); + APIData.fGetModuleHandle = (ULONG_PTR)ImporterGetRemoteAPIAddress(hProcess, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetModuleHandleW")); + APIData.fGetProcAddress = (ULONG_PTR)ImporterGetRemoteAPIAddress(hProcess, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetProcAddress")); + APIData.fVirtualFree = (ULONG_PTR)ImporterGetRemoteAPIAddress(hProcess, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"), "VirtualFree")); + APIData.fExitProcess = (ULONG_PTR)ImporterGetRemoteAPIAddress(hProcess, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"), "ExitProcess")); + remCodeData = VirtualAllocEx(hProcess, NULL, remInjectSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + remStringData = VirtualAllocEx(hProcess, NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE); + if(WriteProcessMemory(hProcess, (LPVOID)((ULONG_PTR)remStringData + sizeof InjectCodeData), (LPCVOID)szLibraryFile, lstrlenW(szLibraryFile) * 2, &NumberOfBytesWritten)) + { + WriteProcessMemory(hProcess, remStringData, &APIData, sizeof InjectCodeData, &NumberOfBytesWritten); + WriteProcessMemory(hProcess, remCodeData, (LPCVOID)&injectedRemoteLoadLibrary, remInjectSize, &NumberOfBytesWritten); + if(WaitForThreadExit) + { + hThread = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)remCodeData, remStringData, CREATE_SUSPENDED, &ThreadId); + if(ZwSetInformationThread != NULL) + { + cZwSetInformationThread(hThread, 0x11, NULL, NULL); + } + ResumeThread(hThread); + WaitForSingleObject(hThread, INFINITE); + VirtualFreeEx(hProcess, remCodeData, NULL, MEM_RELEASE); + VirtualFreeEx(hProcess, remStringData, NULL, MEM_RELEASE); + if(GetExitCodeThread(hThread, &ExitCode)) + { + if(ExitCode == NULL) + { + return(false); + } + } + } + else + { + hThread = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)remCodeData, remStringData, NULL, &ThreadId); + for(i = 0; i < UE_MAX_RESERVED_MEMORY_LEFT; i++) + { + if(engineReservedMemoryLeft[i] == NULL) + { + break; + } + } + engineReservedMemoryLeft[i] = (ULONG_PTR)remCodeData; + engineReservedMemoryProcess = hProcess; + ThreaderSetCallBackForNextExitThreadEvent((LPVOID)&injectedTerminator); + } + return(true); + } + else + { + VirtualFreeEx(hProcess, remCodeData, NULL, MEM_RELEASE); + VirtualFreeEx(hProcess, remStringData, NULL, MEM_RELEASE); + } + } + return(false); +} +__declspec(dllexport) bool __stdcall RemoteFreeLibrary(HANDLE hProcess, HMODULE hModule, char* szLibraryFile, bool WaitForThreadExit) +{ + + wchar_t uniLibraryFile[MAX_PATH] = {}; + + if(szLibraryFile != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szLibraryFile, lstrlenA(szLibraryFile)+1, uniLibraryFile, sizeof(uniLibraryFile)/(sizeof(uniLibraryFile[0]))); + return(RemoteFreeLibraryW(hProcess, hModule, uniLibraryFile, WaitForThreadExit)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall RemoteFreeLibraryW(HANDLE hProcess, HMODULE hModule, wchar_t* szLibraryFile, bool WaitForThreadExit) +{ + + int i; + InjectCodeData APIData; + LPVOID remStringData; + LPVOID remCodeData; + ULONG_PTR remInjectSize1 = (ULONG_PTR)((ULONG_PTR)&injectedExitProcess - (ULONG_PTR)&injectedRemoteFreeLibrarySimple); + ULONG_PTR remInjectSize2 = (ULONG_PTR)((ULONG_PTR)&injectedRemoteFreeLibrarySimple - (ULONG_PTR)&injectedRemoteFreeLibrary); +#if !defined(_WIN64) + typedef NTSTATUS(__stdcall *fZwSetInformationThread)(HANDLE fThreadHandle, DWORD fThreadInfoClass, LPVOID fBuffer, ULONG fBufferSize); +#else + typedef NTSTATUS(__fastcall *fZwSetInformationThread)(HANDLE fThreadHandle, DWORD fThreadInfoClass, LPVOID fBuffer, ULONG fBufferSize); +#endif + LPVOID ZwSetInformationThread = (LPVOID)GetProcAddress(GetModuleHandleA("ntdll.dll"),"ZwSetInformationThread"); + fZwSetInformationThread cZwSetInformationThread = (fZwSetInformationThread)(ZwSetInformationThread); + ULONG_PTR NumberOfBytesWritten; + DWORD ThreadId; + HANDLE hThread; + DWORD ExitCode; + + if(hProcess != NULL) + { + RtlZeroMemory(&APIData, sizeof InjectCodeData); + APIData.fLoadLibrary = (ULONG_PTR)ImporterGetRemoteAPIAddress(hProcess, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryW")); + APIData.fFreeLibrary = (ULONG_PTR)ImporterGetRemoteAPIAddress(hProcess, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"), "FreeLibrary")); + APIData.fGetModuleHandle = (ULONG_PTR)ImporterGetRemoteAPIAddress(hProcess, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetModuleHandleW")); + APIData.fGetProcAddress = (ULONG_PTR)ImporterGetRemoteAPIAddress(hProcess, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetProcAddress")); + APIData.fVirtualFree = (ULONG_PTR)ImporterGetRemoteAPIAddress(hProcess, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"), "VirtualFree")); + APIData.fExitProcess = (ULONG_PTR)ImporterGetRemoteAPIAddress(hProcess, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"), "ExitProcess")); + APIData.fFreeLibraryHandle = hModule; + remCodeData = VirtualAllocEx(hProcess, NULL, remInjectSize1, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if(hModule == NULL) + { + remStringData = VirtualAllocEx(hProcess, NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE); + if(WriteProcessMemory(hProcess, (LPVOID)((ULONG_PTR)remStringData + sizeof InjectCodeData), (LPCVOID)szLibraryFile, lstrlenW(szLibraryFile) * 2, &NumberOfBytesWritten)) + { + WriteProcessMemory(hProcess, remStringData, &APIData, sizeof InjectCodeData, &NumberOfBytesWritten); + WriteProcessMemory(hProcess, remCodeData, (LPCVOID)&injectedRemoteFreeLibrarySimple, remInjectSize1, &NumberOfBytesWritten); + if(WaitForThreadExit) + { + hThread = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)remCodeData, remStringData, CREATE_SUSPENDED, &ThreadId); + if(ZwSetInformationThread != NULL) + { + cZwSetInformationThread(hThread, 0x11, NULL, NULL); + } + ResumeThread(hThread); + WaitForSingleObject(hThread, INFINITE); + VirtualFreeEx(hProcess, remCodeData, NULL, MEM_RELEASE); + VirtualFreeEx(hProcess, remStringData, NULL, MEM_RELEASE); + if(GetExitCodeThread(hThread, &ExitCode)) + { + if(ExitCode == NULL) + { + return(false); + } + } + } + else + { + hThread = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)remCodeData, remStringData, NULL, &ThreadId); + for(i = 0; i < UE_MAX_RESERVED_MEMORY_LEFT; i++) + { + if(engineReservedMemoryLeft[i] == NULL) + { + break; + } + } + engineReservedMemoryLeft[i] = (ULONG_PTR)remCodeData; + engineReservedMemoryProcess = hProcess; + ThreaderSetCallBackForNextExitThreadEvent((LPVOID)&injectedTerminator); + } + return(true); + } + else + { + VirtualFreeEx(hProcess, remCodeData, NULL, MEM_RELEASE); + VirtualFreeEx(hProcess, remStringData, NULL, MEM_RELEASE); + } + } + else + { + remStringData = VirtualAllocEx(hProcess, NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE); + if(WriteProcessMemory(hProcess, remStringData, &APIData, sizeof InjectCodeData, &NumberOfBytesWritten)) + { + WriteProcessMemory(hProcess, remCodeData, (LPCVOID)&injectedRemoteFreeLibrary, remInjectSize2, &NumberOfBytesWritten); + if(WaitForThreadExit) + { + hThread = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)remCodeData, remStringData, CREATE_SUSPENDED, &ThreadId); + if(ZwSetInformationThread != NULL) + { + cZwSetInformationThread(hThread, 0x11, NULL, NULL); + } + ResumeThread(hThread); + WaitForSingleObject(hThread, INFINITE); + VirtualFreeEx(hProcess, remCodeData, NULL, MEM_RELEASE); + if(GetExitCodeThread(hThread, &ExitCode)) + { + if(ExitCode == NULL) + { + return(false); + } + } + } + else + { + hThread = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)remCodeData, remStringData, NULL, &ThreadId); + for(i = 0; i < UE_MAX_RESERVED_MEMORY_LEFT; i++) + { + if(engineReservedMemoryLeft[i] == NULL) + { + break; + } + } + engineReservedMemoryLeft[i] = (ULONG_PTR)remCodeData; + engineReservedMemoryProcess = hProcess; + ThreaderSetCallBackForNextExitThreadEvent((LPVOID)&injectedTerminator); + } + return(true); + } + else + { + VirtualFreeEx(hProcess, remCodeData, NULL, MEM_RELEASE); + VirtualFreeEx(hProcess, remStringData, NULL, MEM_RELEASE); + } + } + } + return(false); +} +__declspec(dllexport) bool __stdcall RemoteExitProcess(HANDLE hProcess, DWORD ExitCode) +{ + + InjectCodeData APIData; + LPVOID remCodeData; + LPVOID remStringData; + ULONG_PTR remInjectSize = (ULONG_PTR)((ULONG_PTR)&injectedTerminator - (ULONG_PTR)&injectedExitProcess); + ULONG_PTR NumberOfBytesWritten; + DWORD ThreadId; + HANDLE hThread; + + if(hProcess != NULL) + { + RtlZeroMemory(&APIData, sizeof InjectCodeData); + APIData.fLoadLibrary = (ULONG_PTR)ImporterGetRemoteAPIAddress(hProcess, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA")); + APIData.fFreeLibrary = (ULONG_PTR)ImporterGetRemoteAPIAddress(hProcess, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"), "FreeLibrary")); + APIData.fGetModuleHandle = (ULONG_PTR)ImporterGetRemoteAPIAddress(hProcess, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetModuleHandleA")); + APIData.fGetProcAddress = (ULONG_PTR)ImporterGetRemoteAPIAddress(hProcess, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"), "GetProcAddress")); + APIData.fVirtualFree = (ULONG_PTR)ImporterGetRemoteAPIAddress(hProcess, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"), "VirtualFree")); + APIData.fExitProcess = (ULONG_PTR)ImporterGetRemoteAPIAddress(hProcess, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"), "ExitProcess")); + APIData.fExitProcessCode = ExitCode; + remStringData = VirtualAllocEx(hProcess, NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE); + remCodeData = VirtualAllocEx(hProcess, NULL, remInjectSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if(WriteProcessMemory(hProcess, remCodeData, (LPCVOID)&injectedExitProcess, remInjectSize, &NumberOfBytesWritten)) + { + WriteProcessMemory(hProcess, remStringData, &APIData, sizeof InjectCodeData, &NumberOfBytesWritten); + hThread = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)remCodeData, remStringData, NULL, &ThreadId); + VirtualFreeEx(hProcess, remCodeData, NULL, MEM_RELEASE); + return(true); + } + else + { + VirtualFreeEx(hProcess, remCodeData, NULL, MEM_RELEASE); + VirtualFreeEx(hProcess, remStringData, NULL, MEM_RELEASE); + } + } + return(false); +} +// TitanEngine.Tracer.functions: +__declspec(dllexport) long __stdcall TracerFixRedirectionViaImpRecPlugin(HANDLE hProcess, char* szPluginName, ULONG_PTR AddressToTrace) +{ + + int szLenght = NULL; + HMODULE hImpRecModule = NULL; + ULONG_PTR fImpRecTrace = NULL; + PMEMORY_CMP_HANDLER cmpModuleName; + ULONG_PTR remInjectSize = (ULONG_PTR)((ULONG_PTR)&injectedRemoteLoadLibrary - (ULONG_PTR)&injectedImpRec); +#if !defined(_WIN64) + typedef NTSTATUS(__stdcall *fZwSetInformationThread)(HANDLE fThreadHandle, DWORD fThreadInfoClass, LPVOID fBuffer, ULONG fBufferSize); +#else + typedef NTSTATUS(__fastcall *fZwSetInformationThread)(HANDLE fThreadHandle, DWORD fThreadInfoClass, LPVOID fBuffer, ULONG fBufferSize); +#endif + LPVOID ZwSetInformationThread = (LPVOID)GetProcAddress(GetModuleHandleA("ntdll.dll"),"ZwSetInformationThread"); + fZwSetInformationThread cZwSetInformationThread = (fZwSetInformationThread)(ZwSetInformationThread); + LPVOID szModuleName = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE); + LPVOID szGarbageFile = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE); + LPVOID cModuleName = szModuleName; + ULONG_PTR NumberOfBytesWritten; + InjectImpRecCodeData APIData; + DWORD TracedAddress = NULL; + DWORD TraceAddress = NULL; + LPVOID remStringData; + LPVOID remCodeData; + DWORD ThreadId; + HANDLE hThread; + DWORD ExitCode; + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + + if(GetModuleFileNameA(engineHandle, (LPCH)szModuleName, 0x1000) > NULL) + { + cModuleName = (LPVOID)((ULONG_PTR)cModuleName + lstrlenA((LPCSTR)szModuleName)); + cmpModuleName = (PMEMORY_CMP_HANDLER)(cModuleName); + while(cmpModuleName->DataByte[0] != 0x5C) + { + cmpModuleName = (PMEMORY_CMP_HANDLER)((ULONG_PTR)cmpModuleName - 1); + } + cmpModuleName = (PMEMORY_CMP_HANDLER)((ULONG_PTR)cmpModuleName + 1); + cmpModuleName->DataByte[0] = 0x00; + lstrcpyA((LPSTR)szGarbageFile, (LPCSTR)szModuleName); + lstrcatA((LPSTR)szGarbageFile, "garbage\\ImpRec.txt"); + lstrcatA((LPSTR)szModuleName, "imports\\ImpRec\\"); + lstrcatA((LPSTR)szModuleName, szPluginName); + if(ReadProcessMemory(hProcess, (LPVOID)AddressToTrace, &TraceAddress, 4, &NumberOfBytesWritten)) + { + if(RemoteLoadLibrary(hProcess, (char*)szModuleName, true)) + { + hImpRecModule = LoadLibraryA((char*)szModuleName); + if(hImpRecModule != NULL) + { + fImpRecTrace = (ULONG_PTR)GetProcAddress(hImpRecModule, "Trace"); + if(fImpRecTrace != NULL) + { + fImpRecTrace = fImpRecTrace - (ULONG_PTR)hImpRecModule; + remCodeData = VirtualAllocEx(hProcess, NULL, remInjectSize, MEM_COMMIT, PAGE_READWRITE); + remStringData = VirtualAllocEx(hProcess, NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE); + RtlZeroMemory(&APIData, sizeof InjectImpRecCodeData); + APIData.fTrace = fImpRecTrace + (ULONG_PTR)ImporterGetRemoteDLLBase(hProcess, hImpRecModule); + APIData.AddressToTrace = (ULONG_PTR)TraceAddress; + APIData.fCreateFileA = (ULONG_PTR)ImporterGetRemoteAPIAddress(hProcess, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"), "CreateFileA")); + APIData.fCreateFileMappingA = (ULONG_PTR)ImporterGetRemoteAPIAddress(hProcess, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"), "CreateFileMappingA")); + APIData.fCloseHandle = (ULONG_PTR)ImporterGetRemoteAPIAddress(hProcess, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"), "CloseHandle")); + if(WriteProcessMemory(hProcess, remCodeData, (LPCVOID)&injectedImpRec, remInjectSize, &NumberOfBytesWritten)) + { + WriteProcessMemory(hProcess, remStringData, &APIData, sizeof InjectImpRecCodeData, &NumberOfBytesWritten); + WriteProcessMemory(hProcess, (LPVOID)((ULONG_PTR)remStringData + sizeof InjectImpRecCodeData), (LPCVOID)szGarbageFile, lstrlenA((LPSTR)szGarbageFile), &NumberOfBytesWritten); + hThread = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)remCodeData, remStringData, CREATE_SUSPENDED, &ThreadId); + if(ZwSetInformationThread != NULL) + { + cZwSetInformationThread(hThread, 0x11, NULL, NULL); + } + ResumeThread(hThread); + WaitForSingleObject(hThread, INFINITE); + if(GetExitCodeThread(hThread, &ExitCode)) + { + if(ExitCode != NULL) + { + if(MapFileEx((char*)szGarbageFile, UE_ACCESS_READ, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + RtlMoveMemory(&TracedAddress, (LPVOID)FileMapVA, 4); + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + } + if(!DeleteFileA((LPCSTR)szGarbageFile)) + { + HandlerCloseAllLockHandles((char*)szGarbageFile, false, true); + DeleteFileA((LPCSTR)szGarbageFile); + } + } + } + } + RemoteFreeLibrary(hProcess, NULL, (char*)szModuleName, true); + VirtualFreeEx(hProcess, remCodeData, NULL, MEM_RELEASE); + VirtualFreeEx(hProcess, remStringData, NULL, MEM_RELEASE); + } + else + { + RemoteFreeLibrary(hProcess, NULL, (char*)szModuleName, true); + } + FreeLibrary(hImpRecModule); + } + } + } + } + VirtualFree(szModuleName, NULL, MEM_RELEASE); + VirtualFree(szGarbageFile, NULL, MEM_RELEASE); + return(TracedAddress); +} +// TitanEngine.StaticUnpacker.functions: +__declspec(dllexport) bool __stdcall StaticFileLoad(char* szFileName, DWORD DesiredAccess, bool SimulateLoad, LPHANDLE FileHandle, LPDWORD LoadedSize, LPHANDLE FileMap, PULONG_PTR FileMapVA) +{ + + if(!SimulateLoad) + { + if(MapFileEx(szFileName, DesiredAccess, FileHandle, LoadedSize, FileMap, FileMapVA, NULL)) + { + return(true); + } + } + else + { + *FileMapVA = (ULONG_PTR)ResourcerLoadFileForResourceUse(szFileName); + if(*FileMapVA != NULL) + { + *LoadedSize = (DWORD)GetPE32DataFromMappedFile(*FileMapVA, NULL, UE_SIZEOFIMAGE); + *FileHandle = NULL; + *FileMap = NULL; + return(true); + } + } + return(false); +} +__declspec(dllexport) bool __stdcall StaticFileLoadW(wchar_t* szFileName, DWORD DesiredAccess, bool SimulateLoad, LPHANDLE FileHandle, LPDWORD LoadedSize, LPHANDLE FileMap, PULONG_PTR FileMapVA) +{ + + if(!SimulateLoad) + { + if(MapFileExW(szFileName, DesiredAccess, FileHandle, LoadedSize, FileMap, FileMapVA, NULL)) + { + return(true); + } + } + else + { + *FileMapVA = (ULONG_PTR)ResourcerLoadFileForResourceUseW(szFileName); + if(*FileMapVA != NULL) + { + *LoadedSize = (DWORD)GetPE32DataFromMappedFile(*FileMapVA, NULL, UE_SIZEOFIMAGE); + *FileHandle = NULL; + *FileMap = NULL; + return(true); + } + } + return(false); +} +__declspec(dllexport) bool __stdcall StaticFileUnload(char* szFileName, bool CommitChanges, HANDLE FileHandle, DWORD LoadedSize, HANDLE FileMap, ULONG_PTR FileMapVA) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + + if(szFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + return(StaticFileUnloadW(uniFileName, CommitChanges, FileHandle, LoadedSize, FileMap, FileMapVA)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall StaticFileUnloadW(wchar_t* szFileName, bool CommitChanges, HANDLE FileHandle, DWORD LoadedSize, HANDLE FileMap, ULONG_PTR FileMapVA) +{ + + DWORD PeHeaderSize; + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + PIMAGE_SECTION_HEADER PESections; + DWORD SectionNumber = 0; + DWORD SectionRawOffset = 0; + DWORD SectionRawSize = 0; + BOOL FileIs64; + HANDLE myFileHandle; + DWORD myFileSize; + HANDLE myFileMap; + ULONG_PTR myFileMapVA; + + if(FileHandle != NULL && FileMap != NULL) + { + UnMapFileEx(FileHandle, LoadedSize, FileMap, FileMapVA); + return(true); + } + else + { + if(!CommitChanges) + { + return(ResourcerFreeLoadedFile((LPVOID)FileMapVA)); + } + else + { + if(MapFileExW(szFileName, UE_ACCESS_ALL, &myFileHandle, &myFileSize, &myFileMap, &myFileMapVA, NULL)) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(DOSHeader->e_lfanew < 0x1000 - 108) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + ResourcerFreeLoadedFile((LPVOID)FileMapVA); + UnMapFileEx(myFileHandle, myFileSize, myFileMap, myFileMapVA); + return(false); + } + if(!FileIs64) + { + PeHeaderSize = PEHeader32->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_SECTION_HEADER) * PEHeader32->FileHeader.NumberOfSections; + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader32 + PEHeader32->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + SectionNumber = PEHeader32->FileHeader.NumberOfSections; + RtlMoveMemory((LPVOID)myFileMapVA, (LPVOID)FileMapVA, PeHeaderSize); + while(SectionNumber > 0) + { + RtlMoveMemory((LPVOID)((ULONG_PTR)myFileMapVA + PESections->PointerToRawData), (LPVOID)(FileMapVA + PESections->VirtualAddress), PESections->SizeOfRawData); + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + IMAGE_SIZEOF_SECTION_HEADER); + SectionNumber--; + } + ResourcerFreeLoadedFile((LPVOID)FileMapVA); + UnMapFileEx(myFileHandle, myFileSize, myFileMap, myFileMapVA); + return(true); + } + else + { + PeHeaderSize = PEHeader64->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_SECTION_HEADER) * PEHeader64->FileHeader.NumberOfSections; + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PEHeader64 + PEHeader64->FileHeader.SizeOfOptionalHeader + sizeof(IMAGE_FILE_HEADER) + 4); + SectionNumber = PEHeader64->FileHeader.NumberOfSections; + RtlMoveMemory((LPVOID)myFileMapVA, (LPVOID)FileMapVA, PeHeaderSize); + while(SectionNumber > 0) + { + RtlMoveMemory((LPVOID)((ULONG_PTR)myFileMapVA + PESections->PointerToRawData), (LPVOID)(FileMapVA + PESections->VirtualAddress), PESections->SizeOfRawData); + PESections = (PIMAGE_SECTION_HEADER)((ULONG_PTR)PESections + IMAGE_SIZEOF_SECTION_HEADER); + SectionNumber--; + } + ResourcerFreeLoadedFile((LPVOID)FileMapVA); + UnMapFileEx(myFileHandle, myFileSize, myFileMap, myFileMapVA); + return(true); + } + } + else + { + ResourcerFreeLoadedFile((LPVOID)FileMapVA); + UnMapFileEx(myFileHandle, myFileSize, myFileMap, myFileMapVA); + return(false); + } + } + } + } + return(false); +} +__declspec(dllexport) bool __stdcall StaticFileOpen(char* szFileName, DWORD DesiredAccess, LPHANDLE FileHandle, LPDWORD FileSizeLow, LPDWORD FileSizeHigh) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + + if(szFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + return(StaticFileOpenW(uniFileName, DesiredAccess, FileHandle, FileSizeLow, FileSizeHigh)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall StaticFileOpenW(wchar_t* szFileName, DWORD DesiredAccess, LPHANDLE FileHandle, LPDWORD FileSizeLow, LPDWORD FileSizeHigh) +{ + + __try + { + *FileHandle = CreateFileW(szFileName, DesiredAccess, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if(FileHandle != INVALID_HANDLE_VALUE) + { + *FileSizeLow = GetFileSize(*FileHandle, FileSizeHigh); + return(true); + } + else + { + return(false); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return(false); + } +} +__declspec(dllexport) bool __stdcall StaticFileGetContent(HANDLE FileHandle, DWORD FilePositionLow, LPDWORD FilePositionHigh, void* Buffer, DWORD Size) +{ + + DWORD rfNumberOfBytesRead; + + if(SetFilePointer(FileHandle, FilePositionLow, (PLONG)FilePositionHigh, FILE_BEGIN) != INVALID_SET_FILE_POINTER) + { + if(ReadFile(FileHandle, Buffer, Size, &rfNumberOfBytesRead, NULL)) + { + if(rfNumberOfBytesRead == Size) + { + return(true); + } + else + { + RtlZeroMemory(Buffer, Size); + } + } + } + return(false); +} +__declspec(dllexport) void __stdcall StaticFileClose(HANDLE FileHandle) +{ + EngineCloseHandle(FileHandle); +} +__declspec(dllexport) void __stdcall StaticMemoryDecrypt(LPVOID MemoryStart, DWORD MemorySize, DWORD DecryptionType, DWORD DecryptionKeySize, ULONG_PTR DecryptionKey) +{ + + DWORD LoopCount = NULL; + BYTE DataByte = NULL; + WORD DataWord = NULL; + DWORD DataDword = NULL; + ULONG_PTR DataQword = NULL; + + if(MemoryStart != NULL && MemorySize > NULL) + { + LoopCount = MemorySize / DecryptionKeySize; + while(LoopCount > NULL) + { + if(DecryptionType == UE_STATIC_DECRYPTOR_XOR) + { + if(DecryptionKeySize == UE_STATIC_KEY_SIZE_1) + { + RtlMoveMemory(&DataByte, MemoryStart, UE_STATIC_KEY_SIZE_1); + DataByte = DataByte ^ (BYTE)DecryptionKey; + RtlMoveMemory(MemoryStart, &DataByte, UE_STATIC_KEY_SIZE_1); + } + else if(DecryptionKeySize == UE_STATIC_KEY_SIZE_2) + { + RtlMoveMemory(&DataWord, MemoryStart, UE_STATIC_KEY_SIZE_2); + DataWord = DataWord ^ (WORD)DecryptionKey; + RtlMoveMemory(MemoryStart, &DataWord, UE_STATIC_KEY_SIZE_2); + } + else if(DecryptionKeySize == UE_STATIC_KEY_SIZE_4) + { + RtlMoveMemory(&DataDword, MemoryStart, UE_STATIC_KEY_SIZE_4); + DataDword = DataDword ^ (DWORD)DecryptionKey; + RtlMoveMemory(MemoryStart, &DataDword, UE_STATIC_KEY_SIZE_4); + } + else if(DecryptionKeySize == UE_STATIC_KEY_SIZE_8) + { + RtlMoveMemory(&DataQword, MemoryStart, UE_STATIC_KEY_SIZE_8); + DataQword = DataQword ^ (ULONG_PTR)DecryptionKey; + RtlMoveMemory(MemoryStart, &DataQword, UE_STATIC_KEY_SIZE_8); + } + } + else if(DecryptionType == UE_STATIC_DECRYPTOR_SUB) + { + if(DecryptionKeySize == UE_STATIC_KEY_SIZE_1) + { + RtlMoveMemory(&DataByte, MemoryStart, UE_STATIC_KEY_SIZE_1); + DataByte = DataByte - (BYTE)DecryptionKey; + RtlMoveMemory(MemoryStart, &DataByte, UE_STATIC_KEY_SIZE_1); + } + else if(DecryptionKeySize == UE_STATIC_KEY_SIZE_2) + { + RtlMoveMemory(&DataWord, MemoryStart, UE_STATIC_KEY_SIZE_2); + DataWord = DataWord - (WORD)DecryptionKey; + RtlMoveMemory(MemoryStart, &DataWord, UE_STATIC_KEY_SIZE_2); + } + else if(DecryptionKeySize == UE_STATIC_KEY_SIZE_4) + { + RtlMoveMemory(&DataDword, MemoryStart, UE_STATIC_KEY_SIZE_4); + DataDword = DataDword - (DWORD)DecryptionKey; + RtlMoveMemory(MemoryStart, &DataDword, UE_STATIC_KEY_SIZE_4); + } + else if(DecryptionKeySize == UE_STATIC_KEY_SIZE_8) + { + RtlMoveMemory(&DataQword, MemoryStart, UE_STATIC_KEY_SIZE_8); + DataQword = DataQword - (ULONG_PTR)DecryptionKey; + RtlMoveMemory(MemoryStart, &DataQword, UE_STATIC_KEY_SIZE_8); + } + } + else if(DecryptionType == UE_STATIC_DECRYPTOR_ADD) + { + if(DecryptionKeySize == UE_STATIC_KEY_SIZE_1) + { + RtlMoveMemory(&DataByte, MemoryStart, UE_STATIC_KEY_SIZE_1); + DataByte = DataByte + (BYTE)DecryptionKey; + RtlMoveMemory(MemoryStart, &DataByte, UE_STATIC_KEY_SIZE_1); + } + else if(DecryptionKeySize == UE_STATIC_KEY_SIZE_2) + { + RtlMoveMemory(&DataWord, MemoryStart, UE_STATIC_KEY_SIZE_2); + DataWord = DataWord + (WORD)DecryptionKey; + RtlMoveMemory(MemoryStart, &DataWord, UE_STATIC_KEY_SIZE_2); + } + else if(DecryptionKeySize == UE_STATIC_KEY_SIZE_4) + { + RtlMoveMemory(&DataDword, MemoryStart, UE_STATIC_KEY_SIZE_4); + DataDword = DataDword + (DWORD)DecryptionKey; + RtlMoveMemory(MemoryStart, &DataDword, UE_STATIC_KEY_SIZE_4); + } + else if(DecryptionKeySize == UE_STATIC_KEY_SIZE_8) + { + RtlMoveMemory(&DataQword, MemoryStart, UE_STATIC_KEY_SIZE_8); + DataQword = DataQword + (ULONG_PTR)DecryptionKey; + RtlMoveMemory(MemoryStart, &DataQword, UE_STATIC_KEY_SIZE_8); + } + } + MemoryStart = (LPVOID)((ULONG_PTR)MemoryStart + DecryptionKeySize); + LoopCount--; + } + } +} +__declspec(dllexport) void __stdcall StaticMemoryDecryptEx(LPVOID MemoryStart, DWORD MemorySize, DWORD DecryptionKeySize, void* DecryptionCallBack) +{ + + DWORD LoopCount = NULL; + typedef bool(__stdcall *fStaticCallBack)(void* sMemoryStart, int sKeySize); + fStaticCallBack myStaticCallBack = (fStaticCallBack)DecryptionCallBack; + + if(MemoryStart != NULL && MemorySize > NULL) + { + LoopCount = MemorySize / DecryptionKeySize; + while(LoopCount > NULL) + { + __try + { + if(!myStaticCallBack(MemoryStart, (int)DecryptionKeySize)) + { + break; + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + break; + } + MemoryStart = (LPVOID)((ULONG_PTR)MemoryStart + DecryptionKeySize); + LoopCount--; + } + } +} +__declspec(dllexport) void __stdcall StaticMemoryDecryptSpecial(LPVOID MemoryStart, DWORD MemorySize, DWORD DecryptionKeySize, DWORD SpecDecryptionType, void* DecryptionCallBack) +{ + + DWORD LoopCount = NULL; + typedef bool(__stdcall *fStaticCallBack)(void* sMemoryStart, int sKeySize); + fStaticCallBack myStaticCallBack = (fStaticCallBack)DecryptionCallBack; + + if(MemoryStart != NULL && MemorySize > NULL) + { + if(SpecDecryptionType == UE_STATIC_DECRYPTOR_BACKWARD) + { + MemoryStart = (LPVOID)((ULONG_PTR)MemoryStart + MemorySize - DecryptionKeySize); + } + LoopCount = MemorySize / DecryptionKeySize; + while(LoopCount > NULL) + { + __try + { + if(!myStaticCallBack(MemoryStart, (int)DecryptionKeySize)) + { + break; + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + break; + } + if(SpecDecryptionType == UE_STATIC_DECRYPTOR_BACKWARD) + { + MemoryStart = (LPVOID)((ULONG_PTR)MemoryStart - DecryptionKeySize); + } + else + { + MemoryStart = (LPVOID)((ULONG_PTR)MemoryStart + DecryptionKeySize); + } + LoopCount--; + } + } +} +__declspec(dllexport) void __stdcall StaticSectionDecrypt(ULONG_PTR FileMapVA, DWORD SectionNumber, bool SimulateLoad, DWORD DecryptionType, DWORD DecryptionKeySize, ULONG_PTR DecryptionKey) +{ + + if(!SimulateLoad) + { + StaticMemoryDecrypt((LPVOID)((ULONG_PTR)GetPE32DataFromMappedFile(FileMapVA, SectionNumber, UE_SECTIONRAWOFFSET) + FileMapVA), (DWORD)GetPE32DataFromMappedFile(FileMapVA, SectionNumber, UE_SECTIONRAWSIZE), DecryptionType, DecryptionKeySize, DecryptionKey); + } + else + { + StaticMemoryDecrypt((LPVOID)((ULONG_PTR)GetPE32DataFromMappedFile(FileMapVA, SectionNumber, UE_SECTIONVIRTUALOFFSET) + FileMapVA), (DWORD)GetPE32DataFromMappedFile(FileMapVA, SectionNumber, UE_SECTIONRAWSIZE), DecryptionType, DecryptionKeySize, DecryptionKey); + } +} +__declspec(dllexport) bool __stdcall StaticMemoryDecompress(void* Source, DWORD SourceSize, void* Destination, DWORD DestinationSize, int Algorithm) +{ + + ELzmaStatus lzStatus; + CLzmaProps lzProps = {}; + ISzAlloc lzAlloc = {&LzmaAllocMem, &LzmaFreeMem}; + + if(Algorithm == UE_STATIC_APLIB) + { +#if !defined (_WIN64) + if(aP_depack_asm_safe(Source, SourceSize, Destination, DestinationSize) != APLIB_ERROR) + { + return(true); + } +#endif + } + else if(Algorithm == UE_STATIC_APLIB) + { +#if !defined (_WIN64) + if(aPsafe_depack(Source, SourceSize, Destination, DestinationSize) != APLIB_ERROR) + { + return(true); + } +#endif + } + else if(Algorithm == UE_STATIC_LZMA) + { + if(LzmaDecode((unsigned char*)Destination, (size_t*)DestinationSize, (unsigned char*)Source, (size_t*)SourceSize, (unsigned char*)&lzProps, LZMA_PROPS_SIZE, LZMA_FINISH_ANY, &lzStatus, &lzAlloc) == SZ_OK) + { + return(true); + } + } + return(false); +} +__declspec(dllexport) bool __stdcall StaticRawMemoryCopy(HANDLE hFile, ULONG_PTR FileMapVA, ULONG_PTR VitualAddressToCopy, DWORD Size, bool AddressIsRVA, char* szDumpFileName) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + + if(szDumpFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szDumpFileName, lstrlenA(szDumpFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + return(StaticRawMemoryCopyW(hFile, FileMapVA, VitualAddressToCopy, Size, AddressIsRVA, uniFileName)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall StaticRawMemoryCopyW(HANDLE hFile, ULONG_PTR FileMapVA, ULONG_PTR VitualAddressToCopy, DWORD Size, bool AddressIsRVA, wchar_t* szDumpFileName) +{ + + DWORD SizeToRead; + HANDLE hReadFile; + HANDLE hWriteFile; + LPVOID ueCopyBuffer; + ULONG_PTR AddressToCopy; + DWORD rfNumberOfBytesRead; + + if(FileMapVA != NULL) + { + if(DuplicateHandle(GetCurrentProcess(), hFile, GetCurrentProcess(), &hReadFile, NULL, false, DUPLICATE_SAME_ACCESS)) + { + if(AddressIsRVA) + { + VitualAddressToCopy = VitualAddressToCopy + (ULONG_PTR)GetPE32DataFromMappedFile(FileMapVA, NULL, UE_IMAGEBASE); + AddressToCopy = (ULONG_PTR)ConvertVAtoFileOffset(FileMapVA, VitualAddressToCopy, false); + } + else + { + AddressToCopy = (ULONG_PTR)ConvertVAtoFileOffset(FileMapVA, VitualAddressToCopy, false); + } + if(SetFilePointer(hReadFile, (long)AddressToCopy, NULL, FILE_BEGIN) != INVALID_SET_FILE_POINTER) + { + ueCopyBuffer = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE); + if(ueCopyBuffer != NULL) + { + if(EngineCreatePathForFileW(szDumpFileName)) + { + hWriteFile = CreateFileW(szDumpFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if(hWriteFile != INVALID_HANDLE_VALUE) + { + if(Size < 0x1000) + { + SizeToRead = Size; + } + else + { + SizeToRead = 0x1000; + } + while((int)Size > NULL) + { + if(ReadFile(hFile, ueCopyBuffer, SizeToRead, &rfNumberOfBytesRead, NULL) == TRUE && rfNumberOfBytesRead == SizeToRead) + { + WriteFile(hWriteFile, ueCopyBuffer, SizeToRead, &rfNumberOfBytesRead, NULL); + if(Size > 0x1000) + { + Size = Size - 0x1000; + } + else if(SizeToRead != Size) + { + if(ReadFile(hFile, ueCopyBuffer, Size, &rfNumberOfBytesRead, NULL) == TRUE && rfNumberOfBytesRead == SizeToRead) + { + WriteFile(hWriteFile, ueCopyBuffer, Size, &rfNumberOfBytesRead, NULL); + } + else + { + WriteFile(hWriteFile, ueCopyBuffer, rfNumberOfBytesRead, &rfNumberOfBytesRead, NULL); + } + SizeToRead = Size; + Size = NULL; + } + else + { + SizeToRead = Size; + Size = NULL; + } + } + else + { + WriteFile(hWriteFile, ueCopyBuffer, rfNumberOfBytesRead, &rfNumberOfBytesRead, NULL); + Size = NULL; + } + } + EngineCloseHandle(hReadFile); + EngineCloseHandle(hWriteFile); + VirtualFree(ueCopyBuffer, NULL, MEM_RELEASE); + return(true); + } + else + { + VirtualFree(ueCopyBuffer, NULL, MEM_RELEASE); + } + } + } + } + EngineCloseHandle(hReadFile); + } + } + return(false); +} +__declspec(dllexport) bool __stdcall StaticRawMemoryCopyEx(HANDLE hFile, DWORD RawAddressToCopy, DWORD Size, char* szDumpFileName) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + + if(szDumpFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szDumpFileName, lstrlenA(szDumpFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + return(StaticRawMemoryCopyExW(hFile, RawAddressToCopy, Size, uniFileName)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall StaticRawMemoryCopyExW(HANDLE hFile, DWORD RawAddressToCopy, DWORD Size, wchar_t* szDumpFileName) +{ + + DWORD SizeToRead; + HANDLE hReadFile; + HANDLE hWriteFile; + LPVOID ueCopyBuffer; + DWORD rfNumberOfBytesRead; + + if(DuplicateHandle(GetCurrentProcess(), hFile, GetCurrentProcess(), &hReadFile, NULL, false, DUPLICATE_SAME_ACCESS)) + { + if(SetFilePointer(hReadFile, (long)(RawAddressToCopy), NULL, FILE_BEGIN) != INVALID_SET_FILE_POINTER) + { + ueCopyBuffer = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE); + if(ueCopyBuffer != NULL) + { + if(EngineCreatePathForFileW(szDumpFileName)) + { + hWriteFile = CreateFileW(szDumpFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if(hWriteFile != INVALID_HANDLE_VALUE) + { + if(Size < 0x1000) + { + SizeToRead = Size; + } + else + { + SizeToRead = 0x1000; + } + while((int)Size > NULL) + { + if(ReadFile(hFile, ueCopyBuffer, SizeToRead, &rfNumberOfBytesRead, NULL) == TRUE && rfNumberOfBytesRead == SizeToRead) + { + WriteFile(hWriteFile, ueCopyBuffer, SizeToRead, &rfNumberOfBytesRead, NULL); + if(Size > 0x1000) + { + Size = Size - 0x1000; + } + else if(SizeToRead != Size) + { + if(ReadFile(hFile, ueCopyBuffer, Size, &rfNumberOfBytesRead, NULL) == TRUE && rfNumberOfBytesRead == SizeToRead) + { + WriteFile(hWriteFile, ueCopyBuffer, Size, &rfNumberOfBytesRead, NULL); + } + else + { + WriteFile(hWriteFile, ueCopyBuffer, rfNumberOfBytesRead, &rfNumberOfBytesRead, NULL); + } + SizeToRead = Size; + Size = NULL; + } + else + { + SizeToRead = Size; + Size = NULL; + } + } + else + { + WriteFile(hWriteFile, ueCopyBuffer, rfNumberOfBytesRead, &rfNumberOfBytesRead, NULL); + Size = NULL; + } + } + EngineCloseHandle(hReadFile); + EngineCloseHandle(hWriteFile); + VirtualFree(ueCopyBuffer, NULL, MEM_RELEASE); + return(true); + } + else + { + VirtualFree(ueCopyBuffer, NULL, MEM_RELEASE); + } + } + } + } + EngineCloseHandle(hReadFile); + } + return(false); +} +__declspec(dllexport) bool __stdcall StaticRawMemoryCopyEx64(HANDLE hFile, DWORD64 RawAddressToCopy, DWORD64 Size, char* szDumpFileName) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + + if(szDumpFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szDumpFileName, lstrlenA(szDumpFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + return(StaticRawMemoryCopyEx64W(hFile, RawAddressToCopy, Size, uniFileName)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall StaticRawMemoryCopyEx64W(HANDLE hFile, DWORD64 RawAddressToCopy, DWORD64 Size, wchar_t* szDumpFileName) +{ + + DWORD SizeToRead; + HANDLE hReadFile; + HANDLE hWriteFile; + LPVOID ueCopyBuffer; + DWORD rfNumberOfBytesRead; + long FilePosLow; + long FilePosHigh; + + if(DuplicateHandle(GetCurrentProcess(), hFile, GetCurrentProcess(), &hReadFile, NULL, false, DUPLICATE_SAME_ACCESS)) + { + FilePosLow = (DWORD)RawAddressToCopy; + RtlMoveMemory(&FilePosHigh, (void*)((ULONG_PTR)(&RawAddressToCopy) + 4), 4); + if(SetFilePointer(hReadFile, FilePosLow, &FilePosHigh, FILE_BEGIN) != INVALID_SET_FILE_POINTER) + { + ueCopyBuffer = VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE); + if(ueCopyBuffer != NULL) + { + if(EngineCreatePathForFileW(szDumpFileName)) + { + hWriteFile = CreateFileW(szDumpFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if(hWriteFile != INVALID_HANDLE_VALUE) + { + if(Size < 0x1000) + { + SizeToRead = (DWORD)Size; + } + else + { + SizeToRead = 0x1000; + } + while(Size != NULL) + { + if(ReadFile(hFile, ueCopyBuffer, SizeToRead, &rfNumberOfBytesRead, NULL) == TRUE && rfNumberOfBytesRead == SizeToRead) + { + WriteFile(hWriteFile, ueCopyBuffer, SizeToRead, &rfNumberOfBytesRead, NULL); + if(Size > 0x1000) + { + Size = Size - 0x1000; + } + else if((DWORD64)SizeToRead != Size) + { + if(ReadFile(hFile, ueCopyBuffer, (DWORD)Size, &rfNumberOfBytesRead, NULL) == TRUE && rfNumberOfBytesRead == SizeToRead) + { + WriteFile(hWriteFile, ueCopyBuffer, (DWORD)Size, &rfNumberOfBytesRead, NULL); + } + else + { + WriteFile(hWriteFile, ueCopyBuffer, rfNumberOfBytesRead, &rfNumberOfBytesRead, NULL); + } + SizeToRead = (DWORD)Size; + Size = NULL; + } + else + { + SizeToRead = (DWORD)Size; + Size = NULL; + } + } + else + { + WriteFile(hWriteFile, ueCopyBuffer, rfNumberOfBytesRead, &rfNumberOfBytesRead, NULL); + Size = NULL; + } + } + EngineCloseHandle(hReadFile); + EngineCloseHandle(hWriteFile); + VirtualFree(ueCopyBuffer, NULL, MEM_RELEASE); + return(true); + } + else + { + VirtualFree(ueCopyBuffer, NULL, MEM_RELEASE); + } + } + } + } + EngineCloseHandle(hReadFile); + } + return(false); +} +__declspec(dllexport) bool __stdcall StaticHashMemory(void* MemoryToHash, DWORD SizeOfMemory, void* HashDigest, bool OutputString, int Algorithm) +{ + +#define MD5LEN 16 +#define SHA1LEN 20 +#define HASH_MAX_LENGTH 20 + + HCRYPTPROV hProv = 0; + HCRYPTHASH hHash = 0; + HANDLE hFile = NULL; + DWORD rgbHash[HASH_MAX_LENGTH / 4]; + DWORD cbHash = 0; + DWORD crc32 = -1; + ALG_ID hashAlgo; + + if(Algorithm != UE_STATIC_HASH_CRC32) + { + if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, NULL)) //CRYPT_VERIFYCONTEXT + { + if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)) + { + return(false); + } + } + if(Algorithm == UE_STATIC_HASH_MD5) + { + hashAlgo = CALG_MD5; + } + else + { + hashAlgo = CALG_SHA; + } + if(!CryptCreateHash(hProv, hashAlgo, NULL, NULL, &hHash)) + { + CryptReleaseContext(hProv, NULL); + return(false); + } + else + { + if(!CryptHashData(hHash, (const BYTE*)MemoryToHash, SizeOfMemory, NULL)) + { + CryptReleaseContext(hProv, NULL); + CryptDestroyHash(hHash); + return(false); + } + } + if(Algorithm == UE_STATIC_HASH_MD5) + { + cbHash = MD5LEN; + if(!CryptGetHashParam(hHash, HP_HASHVAL, (BYTE*)&rgbHash[0], &cbHash, NULL)) + { + CryptDestroyHash(hHash); + CryptReleaseContext(hProv, NULL); + return(false); + } + else + { + rgbHash[0] = _byteswap_ulong(rgbHash[0]); + rgbHash[1] = _byteswap_ulong(rgbHash[1]); + rgbHash[2] = _byteswap_ulong(rgbHash[2]); + rgbHash[3] = _byteswap_ulong(rgbHash[3]); + __try + { + if(OutputString) + { + wsprintfA((char*)HashDigest, "%08X%08X%08X%08X", rgbHash[0], rgbHash[1], rgbHash[2], rgbHash[3]); + } + else + { + RtlMoveMemory(HashDigest, &rgbHash[0], MD5LEN / 4); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + CryptDestroyHash(hHash); + CryptReleaseContext(hProv, NULL); + return(false); + } + CryptDestroyHash(hHash); + CryptReleaseContext(hProv, NULL); + return(true); + } + } + else if(Algorithm == UE_STATIC_HASH_SHA1) + { + cbHash = SHA1LEN; + if(!CryptGetHashParam(hHash, HP_HASHVAL, (BYTE*)&rgbHash[0], &cbHash, NULL)) + { + CryptDestroyHash(hHash); + CryptReleaseContext(hProv, NULL); + return(false); + } + else + { + rgbHash[0] = _byteswap_ulong(rgbHash[0]); + rgbHash[1] = _byteswap_ulong(rgbHash[1]); + rgbHash[2] = _byteswap_ulong(rgbHash[2]); + rgbHash[3] = _byteswap_ulong(rgbHash[3]); + rgbHash[4] = _byteswap_ulong(rgbHash[4]); + __try + { + if(OutputString) + { + wsprintfA((char*)HashDigest, "%08X%08X%08X%08X%08X", rgbHash[0], rgbHash[1], rgbHash[2], rgbHash[3], rgbHash[4]); + } + else + { + RtlMoveMemory(HashDigest, &rgbHash[0], SHA1LEN / 4); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + CryptDestroyHash(hHash); + CryptReleaseContext(hProv, NULL); + return(false); + } + CryptDestroyHash(hHash); + CryptReleaseContext(hProv, NULL); + return(true); + } + } + } + else + { + EngineCrc32PartialCRC(&crc32, (unsigned char*)MemoryToHash, (unsigned long)SizeOfMemory); + crc32 = crc32 ^ 0xFFFFFFFF; + if(OutputString) + { + wsprintfA((char*)HashDigest, "%08X", crc32); + } + else + { + RtlMoveMemory(HashDigest, &crc32, sizeof crc32); + } + return(true); + } + return(false); +} +__declspec(dllexport) bool __stdcall StaticHashFile(char* szFileName, char* HashDigest, bool OutputString, int Algorithm) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + + if(szFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + return(StaticHashFileW(uniFileName, HashDigest, OutputString, Algorithm)); + } + else + { + return(false); + } +} +__declspec(dllexport) bool __stdcall StaticHashFileW(wchar_t* szFileName, char* HashDigest, bool OutputString, int Algorithm) +{ + +#define MD5LEN 16 +#define SHA1LEN 20 +#define HASH_MAX_LENGTH 20 + + bool bResult = true; + HCRYPTPROV hProv = 0; + HCRYPTHASH hHash = 0; + HANDLE hFile = NULL; + BYTE rgbFile[1024]; + DWORD cbRead = 0; + DWORD rgbHash[HASH_MAX_LENGTH / 4]; + DWORD cbHash = 0; + DWORD crc32 = -1; + ALG_ID hashAlgo; + + hFile = CreateFileW(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); + if(hFile == INVALID_HANDLE_VALUE || HashDigest == NULL) + { + return(false); + } + if(Algorithm != UE_STATIC_HASH_CRC32) + { + if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, NULL)) //CRYPT_VERIFYCONTEXT + { + if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)) + { + CloseHandle(hFile); + return(false); + } + } + if(Algorithm == UE_STATIC_HASH_MD5) + { + hashAlgo = CALG_MD5; + } + else + { + hashAlgo = CALG_SHA; + } + if(!CryptCreateHash(hProv, hashAlgo, NULL, NULL, &hHash)) + { + CloseHandle(hFile); + CryptReleaseContext(hProv, NULL); + return(false); + } + while(bResult) + { + if(!ReadFile(hFile, rgbFile, 1024, &cbRead, NULL)) + { + bResult = false; + } + else if(cbRead == NULL) + { + break; + } + if(!CryptHashData(hHash, rgbFile, cbRead, NULL)) + { + CryptReleaseContext(hProv, NULL); + CryptDestroyHash(hHash); + CloseHandle(hFile); + return(false); + } + } + if(!bResult) + { + CryptReleaseContext(hProv, NULL); + CryptDestroyHash(hHash); + CloseHandle(hFile); + return(false); + } + if(Algorithm == UE_STATIC_HASH_MD5) + { + cbHash = MD5LEN; + if(!CryptGetHashParam(hHash, HP_HASHVAL, (BYTE*)&rgbHash[0], &cbHash, NULL)) + { + CryptDestroyHash(hHash); + CryptReleaseContext(hProv, NULL); + CloseHandle(hFile); + return(false); + } + else + { + rgbHash[0] = _byteswap_ulong(rgbHash[0]); + rgbHash[1] = _byteswap_ulong(rgbHash[1]); + rgbHash[2] = _byteswap_ulong(rgbHash[2]); + rgbHash[3] = _byteswap_ulong(rgbHash[3]); + __try + { + if(OutputString) + { + wsprintfA(HashDigest, "%08X%08X%08X%08X", rgbHash[0], rgbHash[1], rgbHash[2], rgbHash[3]); + } + else + { + RtlMoveMemory(HashDigest, &rgbHash[0], MD5LEN / 4); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + CryptDestroyHash(hHash); + CryptReleaseContext(hProv, NULL); + CloseHandle(hFile); + return(false); + } + CryptDestroyHash(hHash); + CryptReleaseContext(hProv, NULL); + CloseHandle(hFile); + return(true); + } + } + else if(Algorithm == UE_STATIC_HASH_SHA1) + { + cbHash = SHA1LEN; + if(!CryptGetHashParam(hHash, HP_HASHVAL, (BYTE*)&rgbHash[0], &cbHash, NULL)) + { + CryptDestroyHash(hHash); + CryptReleaseContext(hProv, NULL); + CloseHandle(hFile); + return(false); + } + else + { + rgbHash[0] = _byteswap_ulong(rgbHash[0]); + rgbHash[1] = _byteswap_ulong(rgbHash[1]); + rgbHash[2] = _byteswap_ulong(rgbHash[2]); + rgbHash[3] = _byteswap_ulong(rgbHash[3]); + rgbHash[4] = _byteswap_ulong(rgbHash[4]); + __try + { + if(OutputString) + { + wsprintfA(HashDigest, "%08X%08X%08X%08X%08X", rgbHash[0], rgbHash[1], rgbHash[2], rgbHash[3], rgbHash[4]); + } + else + { + RtlMoveMemory(HashDigest, &rgbHash[0], SHA1LEN / 4); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + CryptDestroyHash(hHash); + CryptReleaseContext(hProv, NULL); + CloseHandle(hFile); + return(false); + } + CryptDestroyHash(hHash); + CryptReleaseContext(hProv, NULL); + CloseHandle(hFile); + return(true); + } + } + } + else + { + while(bResult) + { + if(!ReadFile(hFile, rgbFile, 1024, &cbRead, NULL)) + { + bResult = false; + } + else if(cbRead == NULL) + { + break; + } + EngineCrc32PartialCRC(&crc32, (unsigned char*)&rgbFile[0], cbRead); + } + crc32 = crc32 ^ 0xFFFFFFFF; + if(OutputString) + { + wsprintfA(HashDigest, "%08X", crc32); + } + else + { + RtlMoveMemory(HashDigest, &crc32, sizeof crc32); + } + CloseHandle(hFile); + return(true); + } + CloseHandle(hFile); + return(false); +} +// TitanEngine.Engine.functions: +__declspec(dllexport) void __stdcall SetEngineVariable(DWORD VariableId, bool VariableSet) +{ + + if(VariableId == UE_ENGINE_ALOW_MODULE_LOADING) + { + engineAlowModuleLoading = VariableSet; + } + else if(VariableId == UE_ENGINE_AUTOFIX_FORWARDERS) + { + engineCheckForwarders = VariableSet; + } + else if(VariableId == UE_ENGINE_PASS_ALL_EXCEPTIONS) + { + enginePassAllExceptions = VariableSet; + } + else if(VariableId == UE_ENGINE_NO_CONSOLE_WINDOW) + { + engineRemoveConsoleForDebugee = VariableSet; + } + else if(VariableId == UE_ENGINE_BACKUP_FOR_CRITICAL_FUNCTIONS) + { + engineBackupForCriticalFunctions = VariableSet; + } + else if(VariableId == UE_ENGINE_RESET_CUSTOM_HANDLER) + { + engineResetCustomHandler = VariableSet; + } + else if(VariableId == UE_ENGINE_CALL_PLUGIN_DEBUG_CALLBACK) + { + engineExecutePluginCallBack = VariableSet; + } +} +// Global.Engine.Hook.functions: +void EngineFakeLoadLibraryReturn() +{ + + ULONG_PTR ParameterData; + LPDEBUG_EVENT currentDBGEvent; + HANDLE currentProcess; + + currentDBGEvent = (LPDEBUG_EVENT)GetDebugData(); + currentProcess = dbgProcessInformation.hProcess; + if(currentProcess != NULL) + { +#if !defined(_WIN64) + ParameterData = (ULONG_PTR)GetFunctionParameter(currentProcess, UE_FUNCTION_STDCALL_RET, 1, UE_PARAMETER_DWORD); + if(ParameterData != NULL) + { + if(engineFakeDLLHandle != NULL) + { + SetContextData(UE_EAX, engineFakeDLLHandle); + } + else + { + SetContextData(UE_EAX, 0x10000000); + } + } +#else + ParameterData = (ULONG_PTR)GetFunctionParameter(currentProcess, UE_FUNCTION_FASTCALL, 1, UE_PARAMETER_QWORD); + if(ParameterData != NULL) + { + if(engineFakeDLLHandle != NULL) + { + SetContextData(UE_RAX, engineFakeDLLHandle); + } + else + { + SetContextData(UE_RAX, 0x10000000); + } + } +#endif + } +} +void EngineFakeGetProcAddressReturn() +{ + + ULONG_PTR ParameterData; + LPDEBUG_EVENT currentDBGEvent; + HANDLE currentProcess; + + currentDBGEvent = (LPDEBUG_EVENT)GetDebugData(); + currentProcess = dbgProcessInformation.hProcess; + if(currentProcess != NULL) + { +#if !defined(_WIN64) + ParameterData = (ULONG_PTR)GetFunctionParameter(currentProcess, UE_FUNCTION_STDCALL_RET, 1, UE_PARAMETER_DWORD); + if(ParameterData != NULL) + { + SetContextData(UE_EAX, (ULONG_PTR)ImporterGetRemoteAPIAddress(currentProcess, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"), "ExitProcess"))); + } +#else + ParameterData = (ULONG_PTR)GetFunctionParameter(currentProcess, UE_FUNCTION_FASTCALL, 1, UE_PARAMETER_QWORD); + if(ParameterData != NULL) + { + SetContextData(UE_RAX, (ULONG_PTR)ImporterGetRemoteAPIAddress(currentProcess, (ULONG_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"), "ExitProcess"))); + } +#endif + } +} +// Global.TitanEngine.Engine.functions: +bool __stdcall EngineGetFileDialog(char* GlobalBuffer) +{ + + OPENFILENAMEA sOpenFileName; + char szFilterString[] = "All Files \0*.*\0\0"; + char szDialogTitle[] = "TitanEngine2 from Reversing Labs"; + + RtlZeroMemory(&sOpenFileName, sizeof(OPENFILENAMEA)); + sOpenFileName.lStructSize = sizeof(OPENFILENAMEA); + sOpenFileName.lpstrFilter = &szFilterString[0]; + sOpenFileName.lpstrFile = &GlobalBuffer[0]; + sOpenFileName.nMaxFile = 1024; + sOpenFileName.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_LONGNAMES | OFN_EXPLORER | OFN_HIDEREADONLY; + sOpenFileName.lpstrTitle = &szDialogTitle[0]; + if(!GetOpenFileNameA(&sOpenFileName)) + { + RtlZeroMemory(&GlobalBuffer[0], 1024); + return(false); + } + else + { + return(true); + } +} +long __stdcall EngineWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + + char szAboutTitle[] = "[ About ]"; + char szAboutText[] = "%s \r\n\r\n ReversingLabs - http://www.reversinglabs.com \r\n\r\n Minimum engine version needed:\r\n- TitanEngine %i.%i.%i by RevLabs\r\n\r\nUnpacker coded by %s"; + typedef void(__stdcall *fStartUnpacking)(char* szInputFile, bool RealignFile, bool CopyOverlay); + fStartUnpacking myStartUnpacking = (fStartUnpacking)EngineStartUnpackingCallBack; + char GlobalBuffer[1024] = {}; + char AboutBuffer[1024] = {}; + bool bRealignFile = false; + bool bCopyOverlay = false; + + if(uMsg == WM_INITDIALOG) + { + SendMessageA(hwndDlg, WM_SETTEXT, NULL, (LPARAM)&szWindowUnpackerTitle); + SendMessageA(hwndDlg, WM_SETICON, NULL, (LPARAM)LoadIconA((HINSTANCE)engineHandle, MAKEINTRESOURCEA(IDI_ICON2))); + SetDlgItemTextA(hwndDlg, IDD_UNPACKERTITLE, szWindowUnpackerLongTitle); + SetDlgItemTextA(hwndDlg, IDC_FILENAME, "filename.exe"); + CheckDlgButton(hwndDlg, IDC_REALING, 1); + EngineWindowHandle = hwndDlg; + } + else if(uMsg == WM_DROPFILES) + { + DragQueryFileA((HDROP)wParam, NULL, GlobalBuffer, 1024); + SetDlgItemTextA(hwndDlg, IDC_FILENAME, GlobalBuffer); + } + else if(uMsg == WM_CLOSE) + { + EndDialog(hwndDlg, NULL); + } + else if(uMsg == WM_COMMAND) + { + if(wParam == IDC_UNPACK) + { + GetDlgItemTextA(hwndDlg, IDC_FILENAME, GlobalBuffer, 1024); + if(!IsFileBeingDebugged() && EngineFileExists(GlobalBuffer)) + { + EngineBoxHandle = GetDlgItem(hwndDlg, IDC_LISTBOX); + SendMessageA(EngineBoxHandle, LB_RESETCONTENT, NULL, NULL); + if(IsDlgButtonChecked(EngineWindowHandle, IDC_REALING)) + { + bRealignFile = true; + } + if(IsDlgButtonChecked(EngineWindowHandle, IDC_COPYOVERLAY)) + { + bCopyOverlay = true; + } + myStartUnpacking(GlobalBuffer, bRealignFile, bCopyOverlay); + } + } + else if(wParam == IDC_BROWSE) + { + if(EngineGetFileDialog(GlobalBuffer)) + { + SetDlgItemTextA(hwndDlg, IDC_FILENAME, GlobalBuffer); + } + } + else if(wParam == IDC_ABOUT) + { + wsprintfA(AboutBuffer, szAboutText, szWindowUnpackerName, TE_VER_MAJOR, TE_VER_MIDDLE, TE_VER_MINOR, szWindowUnpackerAuthor); + MessageBoxA(hwndDlg, AboutBuffer, szAboutTitle, MB_ICONASTERISK); + } + else if(wParam == IDC_EXIT) + { + EndDialog(hwndDlg, NULL); + } + } + return(NULL); +} +// Global.Engine.Simplification.functions: +void EngineSimplifyLoadLibraryCallBack() +{ + + ULONG_PTR iParameter1; + char szLogBufferData[MAX_PATH] = {}; + char szReadStringData[MAX_PATH] = {}; + ULONG_PTR CurrentBreakAddress = (ULONG_PTR)GetContextData(UE_CIP); + + if(!EngineUnpackerFileImporterInit) + { + EngineUnpackerFileImporterInit = true; + if(EngineUnpackerFileStatus.FileIsDLL) + { + ImporterInit(50 * 1024, (ULONG_PTR)GetDebuggedDLLBaseAddress()); + } + else + { + ImporterInit(50 * 1024, (ULONG_PTR)GetDebuggedFileBaseAddress()); + } + } + for(int i = 0; i < (int)EngineUnpackerBreakInfo.size(); i++) + { + if(EngineUnpackerBreakInfo[i].BreakPointAddress == CurrentBreakAddress) + { + iParameter1 = (ULONG_PTR)GetContextData((DWORD)EngineUnpackerBreakInfo[i].Parameter1); + if(EngineUnpackerBreakInfo[i].SingleBreak) + { + EngineUnpackerBreakInfo.erase(EngineUnpackerBreakInfo.begin() + i); + } + if(GetRemoteString(pEngineUnpackerProcessHandle->hProcess, (void*)iParameter1, &szReadStringData[0], MAX_PATH)) + { + ImporterAddNewDll(szReadStringData, (ULONG_PTR)GetContextData((DWORD)EngineUnpackerBreakInfo[i].Parameter2)); + if(EngineUnpackerOptionLogData) + { + wsprintfA(szLogBufferData,"[x] LoadLibrary BPX -> %s",szReadStringData); + EngineAddUnpackerWindowLogMessage(szLogBufferData); + } + } + break; + } + } +} +void EngineSimplifyGetProcAddressCallBack() +{ + + ULONG_PTR iParameter1; + char szLogBufferData[MAX_PATH] = {}; + char szReadStringData[MAX_PATH] = {}; + ULONG_PTR CurrentBreakAddress = (ULONG_PTR)GetContextData(UE_CIP); + + for(int i = 0; i < (int)EngineUnpackerBreakInfo.size(); i++) + { + if(EngineUnpackerBreakInfo[i].BreakPointAddress == CurrentBreakAddress) + { + iParameter1 = (ULONG_PTR)GetContextData((DWORD)EngineUnpackerBreakInfo[i].Parameter1); + if(EngineUnpackerBreakInfo[i].SingleBreak) + { + EngineUnpackerBreakInfo.erase(EngineUnpackerBreakInfo.begin() + i); + } + if(EngineUnpackerFileStatus.FileIsDLL) + { + if(iParameter1 > (ULONG_PTR)GetDebuggedDLLBaseAddress()) + { + if(GetRemoteString(pEngineUnpackerProcessHandle->hProcess, (void*)iParameter1, &szReadStringData[0], MAX_PATH)) + { + ImporterAddNewAPI(szReadStringData, (ULONG_PTR)GetContextData((DWORD)EngineUnpackerBreakInfo[i].Parameter2)); + if(EngineUnpackerOptionLogData) + { + wsprintfA(szLogBufferData,"[x] GetProcAddress BPX -> %s",szReadStringData); + EngineAddUnpackerWindowLogMessage(szLogBufferData); + } + } + } + else + { + ImporterAddNewOrdinalAPI(iParameter1, (ULONG_PTR)GetContextData((DWORD)EngineUnpackerBreakInfo[i].Parameter2)); + if(EngineUnpackerOptionLogData) + { + wsprintfA(szLogBufferData,"[x] GetProcAddress BPX -> %08X",iParameter1); + EngineAddUnpackerWindowLogMessage(szLogBufferData); + } + } + } + else + { + if(iParameter1 > (ULONG_PTR)GetDebuggedFileBaseAddress()) + { + if(GetRemoteString(pEngineUnpackerProcessHandle->hProcess, (void*)iParameter1, &szReadStringData[0], MAX_PATH)) + { + ImporterAddNewAPI(szReadStringData, (ULONG_PTR)GetContextData((DWORD)EngineUnpackerBreakInfo[i].Parameter2)); + if(EngineUnpackerOptionLogData) + { + wsprintfA(szLogBufferData,"[x] GetProcAddress BPX -> %s",szReadStringData); + EngineAddUnpackerWindowLogMessage(szLogBufferData); + } + } + } + else + { + ImporterAddNewOrdinalAPI(iParameter1, (ULONG_PTR)GetContextData((DWORD)EngineUnpackerBreakInfo[i].Parameter2)); + if(EngineUnpackerOptionLogData) + { + wsprintfA(szLogBufferData,"[x] GetProcAddress BPX -> %08X",iParameter1); + EngineAddUnpackerWindowLogMessage(szLogBufferData); + } + } + } + break; + } + } +} +void EngineSimplifyMakeSnapshotCallBack() +{ + + ULONG_PTR fdLoadedBase; + wchar_t szTempName[MAX_PATH] = {}; + wchar_t szTempFolder[MAX_PATH] = {}; + ULONG_PTR CurrentBreakAddress = (ULONG_PTR)GetContextData(UE_CIP); + + if(EngineUnpackerFileStatus.FileIsDLL) + { + fdLoadedBase = (ULONG_PTR)GetDebuggedDLLBaseAddress(); + } + else + { + fdLoadedBase = (ULONG_PTR)GetDebuggedFileBaseAddress(); + } + for(int i = 0; i < (int)EngineUnpackerBreakInfo.size(); i++) + { + if(EngineUnpackerBreakInfo[i].BreakPointAddress == CurrentBreakAddress) + { + if(EngineUnpackerBreakInfo[i].SnapShotNumber == 1) + { + if(GetTempPathW(MAX_PATH, szTempFolder) < MAX_PATH) + { + if(GetTempFileNameW(szTempFolder, L"OverlayTemp", GetTickCount() + 101, szTempName)) + { + lstrcpyW(szEngineUnpackerSnapShot1, szTempName); + RelocaterMakeSnapshotW(pEngineUnpackerProcessHandle->hProcess, szEngineUnpackerSnapShot1, (void*)(EngineUnpackerBreakInfo[i].Parameter1 + fdLoadedBase), EngineUnpackerBreakInfo[i].Parameter2); + } + } + } + else + { + if(GetTempPathW(MAX_PATH, szTempFolder) < MAX_PATH) + { + if(GetTempFileNameW(szTempFolder, L"OverlayTemp", GetTickCount() + 201, szTempName)) + { + lstrcpyW(szEngineUnpackerSnapShot2, szTempName); + RelocaterMakeSnapshotW(pEngineUnpackerProcessHandle->hProcess, szEngineUnpackerSnapShot2, (void*)(EngineUnpackerBreakInfo[i].Parameter1 + fdLoadedBase), EngineUnpackerBreakInfo[i].Parameter2); + } + } + } + return; + } + } +} +void EngineSimplifyEntryPointCallBack() +{ + + int i; + int j; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + HANDLE FileHandle; + long mImportTableOffset; + long mRelocTableOffset; + DWORD pOverlayStart; + DWORD pOverlaySize; + ULONG_PTR fdLoadedBase; + char szLogBufferData[MAX_PATH] = {}; + wchar_t szTempFolder[MAX_PATH] = {}; + wchar_t szTempName[MAX_PATH] = {}; + + __try + { + if(EngineUnpackerOptionUnpackedOEP == NULL) + { + EngineUnpackerOptionUnpackedOEP = (ULONG_PTR)GetContextData(UE_CIP); + } + if(EngineUnpackerOptionLogData) + { + wsprintfA(szLogBufferData,"[x] Entry Point at: %08X", EngineUnpackerOptionUnpackedOEP); + EngineAddUnpackerWindowLogMessage(szLogBufferData); + } + if(EngineUnpackerFileStatus.FileIsDLL) + { + fdLoadedBase = (ULONG_PTR)GetDebuggedDLLBaseAddress(); + RelocaterInit(100 * 1024, (ULONG_PTR)GetPE32DataW(szEngineUnpackerInputFile, NULL, UE_IMAGEBASE), fdLoadedBase); + for(i = 0; i < (int)EngineUnpackerBreakInfo.size(); i++) + { + if(EngineUnpackerBreakInfo[i].SnapShotNumber == 1) + { + j = i; + } + } + if(szEngineUnpackerSnapShot2[0] == 0x00) + { + if(GetTempPathW(MAX_PATH, szTempFolder) < MAX_PATH) + { + if(GetTempFileNameW(szTempFolder, L"OverlayTemp", GetTickCount() + 301, szTempName)) + { + lstrcpyW(szEngineUnpackerSnapShot2, szTempName); + RelocaterMakeSnapshotW(pEngineUnpackerProcessHandle->hProcess, szEngineUnpackerSnapShot2, (void*)(EngineUnpackerBreakInfo[j].Parameter1 + fdLoadedBase), EngineUnpackerBreakInfo[j].Parameter2); + } + } + } + RelocaterCompareTwoSnapshotsW(pEngineUnpackerProcessHandle->hProcess, fdLoadedBase, (ULONG_PTR)GetPE32DataW(szEngineUnpackerInputFile, NULL, UE_SIZEOFIMAGE), szEngineUnpackerSnapShot1, szEngineUnpackerSnapShot2, EngineUnpackerBreakInfo[j].Parameter1 + fdLoadedBase); + EngineUnpackerOptionRelocationFix = true; + } + else + { + fdLoadedBase = (ULONG_PTR)GetDebuggedFileBaseAddress(); + } + if(PastePEHeaderW(pEngineUnpackerProcessHandle->hProcess, (void*)fdLoadedBase, szEngineUnpackerInputFile)) + { + if(EngineUnpackerOptionLogData) + { + EngineAddUnpackerWindowLogMessage("[x] Paste PE header"); + } + } + DumpProcessW(pEngineUnpackerProcessHandle->hProcess, (void*)fdLoadedBase, szEngineUnpackerOutputFile, EngineUnpackerOptionUnpackedOEP); + if(EngineUnpackerOptionLogData) + { + EngineAddUnpackerWindowLogMessage("[x] Process dumped!"); + } + mImportTableOffset = AddNewSectionW(szEngineUnpackerOutputFile, ".TEv2", ImporterEstimatedSize() + 200) + (DWORD)fdLoadedBase; + if(EngineUnpackerOptionRelocationFix) + { + if(EngineUnpackerFileStatus.FileIsDLL) + { + mRelocTableOffset = AddNewSectionW(szEngineUnpackerOutputFile, ".TEv2", RelocaterEstimatedSize() + 200); + } + } + if(StaticFileLoadW(szEngineUnpackerOutputFile, UE_ACCESS_ALL, false, &FileHandle, &FileSize, &FileMap, &FileMapVA)) + { + if(ImporterExportIAT((ULONG_PTR)ConvertVAtoFileOffset(FileMapVA, mImportTableOffset, true), FileMapVA)) + { + if(EngineUnpackerOptionLogData) + { + EngineAddUnpackerWindowLogMessage("[x] IAT has been fixed!"); + } + } + if(EngineUnpackerOptionRelocationFix) + { + if(EngineUnpackerFileStatus.FileIsDLL) + { + RelocaterExportRelocation((ULONG_PTR)ConvertVAtoFileOffset(FileMapVA, mRelocTableOffset + fdLoadedBase, true), mRelocTableOffset, FileMapVA); + if(EngineUnpackerOptionLogData) + { + EngineAddUnpackerWindowLogMessage("[x] Exporting relocations!"); + } + } + } + if(EngineUnpackerOptionRealingFile) + { + FileSize = RealignPE(FileMapVA, FileSize, 2); + if(EngineUnpackerOptionLogData) + { + EngineAddUnpackerWindowLogMessage("[x] Realigning file!"); + } + } + StaticFileUnloadW(szEngineUnpackerOutputFile, false, FileHandle, FileSize, FileMap, FileMapVA); + MakeAllSectionsRWEW(szEngineUnpackerOutputFile); + if(EngineUnpackerFileStatus.FileIsDLL) + { + if(RelocaterChangeFileBaseW(szEngineUnpackerOutputFile, (ULONG_PTR)GetPE32DataW(szEngineUnpackerInputFile, NULL, UE_IMAGEBASE))) + { + if(EngineUnpackerOptionLogData) + { + EngineAddUnpackerWindowLogMessage("[x] Rebase file image!"); + } + } + } + if(EngineUnpackerOptionMoveOverlay && FindOverlayW(szEngineUnpackerInputFile, &pOverlayStart, &pOverlaySize)) + { + CopyOverlayW(szEngineUnpackerInputFile, szEngineUnpackerOutputFile); + if(EngineUnpackerOptionLogData) + { + EngineAddUnpackerWindowLogMessage("[x] Moving overlay to unpacked file!"); + } + } + StopDebug(); + if(EngineUnpackerOptionLogData) + { + EngineAddUnpackerWindowLogMessage("[Success] File has been unpacked!"); + } + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + ForceClose(); + ImporterCleanup(); + if(FileMapVA > NULL) + { + StaticFileUnloadW(szEngineUnpackerOutputFile, false, FileHandle, FileSize, FileMap, FileMapVA); + } + DeleteFileW(szEngineUnpackerOutputFile); + if(EngineUnpackerOptionLogData) + { + EngineAddUnpackerWindowLogMessage("[Fatal Unpacking Error] Please mail file you tried to unpack to ReversingLabs Corporation!"); + } + } + if(EngineUnpackerOptionLogData) + { + EngineAddUnpackerWindowLogMessage("-> Unpack ended..."); + } +} +// TitanEngine.Engine.Simplification.functions: +__declspec(dllexport) void __stdcall EngineUnpackerInitialize(char* szFileName, char* szUnpackedFileName, bool DoLogData, bool DoRealignFile, bool DoMoveOverlay, void* EntryCallBack) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + wchar_t uniUnpackedFileName[MAX_PATH] = {}; + + if(szFileName != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + if(szUnpackedFileName == NULL) + { + return(EngineUnpackerInitializeW(uniFileName, NULL, DoLogData, DoRealignFile, DoMoveOverlay, EntryCallBack)); + } + else + { + MultiByteToWideChar(CP_ACP, NULL, szUnpackedFileName, lstrlenA(szUnpackedFileName)+1, uniUnpackedFileName, sizeof(uniUnpackedFileName)/(sizeof(uniUnpackedFileName[0]))); + EngineUnpackerInitializeW(uniFileName, uniUnpackedFileName, DoLogData, DoRealignFile, DoMoveOverlay, EntryCallBack); + } + } +} +__declspec(dllexport) void __stdcall EngineUnpackerInitializeW(wchar_t* szFileName, wchar_t* szUnpackedFileName, bool DoLogData, bool DoRealignFile, bool DoMoveOverlay, void* EntryCallBack) +{ + + int i,j; + wchar_t TempBackBuffer[MAX_PATH] = {}; + + if(szFileName != NULL) + { + RtlZeroMemory(&szEngineUnpackerSnapShot1[0], MAX_PATH * 2); + RtlZeroMemory(&szEngineUnpackerSnapShot2[0], MAX_PATH * 2); + RtlZeroMemory(&EngineUnpackerFileStatus, sizeof FILE_STATUS_INFO); + if(IsPE32FileValidExW(szFileName, UE_DEPTH_DEEP, &EngineUnpackerFileStatus)) + { + if(!EngineUnpackerFileStatus.FileIsDLL) + { + pEngineUnpackerProcessHandle = (LPPROCESS_INFORMATION)InitDebugExW(szFileName, NULL, NULL, EntryCallBack); + } + else + { + pEngineUnpackerProcessHandle = (LPPROCESS_INFORMATION)InitDLLDebugW(szFileName, true, NULL, NULL, EntryCallBack); + } + if(pEngineUnpackerProcessHandle != NULL) + { + lstrcpyW(szEngineUnpackerInputFile, szFileName); + if(szUnpackedFileName != NULL) + { + lstrcpyW(szEngineUnpackerOutputFile, szUnpackedFileName); + } + else + { + lstrcpyW(TempBackBuffer, szFileName); + i = lstrlenW(TempBackBuffer); + while(TempBackBuffer[i] != 0x2E) + { + i--; + } + TempBackBuffer[i] = 0x00; + j = i + 1; + wsprintfW(szEngineUnpackerOutputFile, L"%s.unpacked.%s", &TempBackBuffer[0], &TempBackBuffer[j]); + } + EngineUnpackerOptionRealingFile = DoRealignFile; + EngineUnpackerOptionMoveOverlay = DoMoveOverlay; + EngineUnpackerOptionRelocationFix = false; + EngineUnpackerOptionLogData = DoLogData; + EngineUnpackerOptionUnpackedOEP = NULL; + EngineUnpackerFileImporterInit = false; + if(EngineUnpackerOptionLogData) + { + EngineAddUnpackerWindowLogMessage("-> Unpack started..."); + } + EngineUnpackerBreakInfo.clear(); + DebugLoop(); + } + } + } +} +__declspec(dllexport) bool __stdcall EngineUnpackerSetBreakCondition(void* SearchStart, DWORD SearchSize, void* SearchPattern, DWORD PatternSize, DWORD PatternDelta, ULONG_PTR BreakType, bool SingleBreak, DWORD Parameter1, DWORD Parameter2) +{ + + ULONG_PTR fPatternLocation; + DWORD fBreakPointType = UE_BREAKPOINT; + UnpackerInformation fUnpackerInformation = {}; + + if((int)SearchStart == UE_UNPACKER_CONDITION_SEARCH_FROM_EP) + { + if(EngineUnpackerFileStatus.FileIsDLL) + { + SearchStart = (void*)((ULONG_PTR)GetPE32DataW(szEngineUnpackerInputFile, NULL, UE_OEP) + (ULONG_PTR)GetDebuggedDLLBaseAddress()); + } + else + { + SearchStart = (void*)((ULONG_PTR)GetPE32DataW(szEngineUnpackerInputFile, NULL, UE_OEP) + (ULONG_PTR)GetDebuggedFileBaseAddress()); + } + } + if(SearchSize == NULL) + { + SearchSize = 0x1000; + } + fPatternLocation = (ULONG_PTR)FindEx(pEngineUnpackerProcessHandle->hProcess, SearchStart, SearchSize, SearchPattern, PatternSize, NULL); + if(fPatternLocation != NULL) + { + if(SingleBreak) + { + fBreakPointType = UE_SINGLESHOOT; + } + fPatternLocation = fPatternLocation + (int)PatternDelta; + fUnpackerInformation.Parameter1 = Parameter1; + fUnpackerInformation.Parameter2 = Parameter2; + fUnpackerInformation.SingleBreak = SingleBreak; + fUnpackerInformation.BreakPointAddress = fPatternLocation; + if(BreakType == UE_UNPACKER_CONDITION_LOADLIBRARY) + { + if(SetBPX(fPatternLocation, UE_BREAKPOINT, &EngineSimplifyLoadLibraryCallBack)) + { + EngineUnpackerBreakInfo.push_back(fUnpackerInformation); + return(true); + } + } + else if(BreakType == UE_UNPACKER_CONDITION_GETPROCADDRESS) + { + if(SetBPX(fPatternLocation, UE_BREAKPOINT, &EngineSimplifyGetProcAddressCallBack)) + { + EngineUnpackerBreakInfo.push_back(fUnpackerInformation); + return(true); + } + } + else if(BreakType == UE_UNPACKER_CONDITION_ENTRYPOINTBREAK) + { + if(SetBPX(fPatternLocation, UE_BREAKPOINT, &EngineSimplifyGetProcAddressCallBack)) + { + EngineUnpackerBreakInfo.push_back(fUnpackerInformation); + return(true); + } + } + else if(BreakType == UE_UNPACKER_CONDITION_RELOCSNAPSHOT1) + { + if(SetBPX(fPatternLocation, UE_BREAKPOINT, &EngineSimplifyMakeSnapshotCallBack)) + { + fUnpackerInformation.SnapShotNumber = 1; + EngineUnpackerBreakInfo.push_back(fUnpackerInformation); + return(true); + } + } + else if(BreakType == UE_UNPACKER_CONDITION_RELOCSNAPSHOT2) + { + if(SetBPX(fPatternLocation, UE_BREAKPOINT, &EngineSimplifyMakeSnapshotCallBack)) + { + fUnpackerInformation.SnapShotNumber = 2; + EngineUnpackerBreakInfo.push_back(fUnpackerInformation); + return(true); + } + } + else + { + if(SetBPX(fPatternLocation, fBreakPointType, (void*)BreakType)) + { + EngineUnpackerBreakInfo.push_back(fUnpackerInformation); + return(true); + } + } + } + return(false); +} +__declspec(dllexport) void __stdcall EngineUnpackerSetEntryPointAddress(ULONG_PTR UnpackedEntryPointAddress) +{ + EngineUnpackerOptionUnpackedOEP = UnpackedEntryPointAddress; +} +__declspec(dllexport) void __stdcall EngineUnpackerFinalizeUnpacking() +{ + + EngineSimplifyEntryPointCallBack(); + EmptyGarbage(); +} +// TitanEngine.Engine.functions: +__declspec(dllexport) bool __stdcall EngineCreateMissingDependencies(char* szFileName, char* szOutputFolder, bool LogCreatedFiles) +{ + + wchar_t uniFileName[MAX_PATH] = {}; + wchar_t uniOutputFolder[MAX_PATH] = {}; + + if(szFileName != NULL && szOutputFolder != NULL) + { + MultiByteToWideChar(CP_ACP, NULL, szFileName, lstrlenA(szFileName)+1, uniFileName, sizeof(uniFileName)/(sizeof(uniFileName[0]))); + MultiByteToWideChar(CP_ACP, NULL, szOutputFolder, lstrlenA(szOutputFolder)+1, uniOutputFolder, sizeof(uniOutputFolder)/(sizeof(uniOutputFolder[0]))); + return(EngineCreateMissingDependenciesW(uniFileName, uniOutputFolder, LogCreatedFiles)); + } + else + { + return(NULL); + } +} +__declspec(dllexport) bool __stdcall EngineCreateMissingDependenciesW(wchar_t* szFileName, wchar_t* szOutputFolder, bool LogCreatedFiles) +{ + + char* ImportDllName; + wchar_t ImportDllNameW[512]; + wchar_t BuildExportName[512]; + PIMAGE_THUNK_DATA32 ImportThunkX86; + PIMAGE_THUNK_DATA64 ImportThunkX64; + PIMAGE_IMPORT_DESCRIPTOR ImportPointer; + ULONG_PTR ImportTableAddress = NULL; + ULONG_PTR ImportThunkName = NULL; + DWORD ImportThunkAddress = NULL; + ULONG_PTR ImageBase = NULL; + PIMAGE_DOS_HEADER DOSHeader; + PIMAGE_NT_HEADERS32 PEHeader32; + PIMAGE_NT_HEADERS64 PEHeader64; + HANDLE FileHandle; + DWORD FileSize; + HANDLE FileMap; + ULONG_PTR FileMapVA; + BOOL FileIs64; + + if(MapFileExW(szFileName, UE_ACCESS_READ, &FileHandle, &FileSize, &FileMap, &FileMapVA, NULL)) + { + DOSHeader = (PIMAGE_DOS_HEADER)FileMapVA; + if(DOSHeader->e_lfanew < 0x1000 - 108) + { + PEHeader32 = (PIMAGE_NT_HEADERS32)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + PEHeader64 = (PIMAGE_NT_HEADERS64)((ULONG_PTR)DOSHeader + DOSHeader->e_lfanew); + if(PEHeader32->OptionalHeader.Magic == 0x10B) + { + FileIs64 = false; + } + else if(PEHeader32->OptionalHeader.Magic == 0x20B) + { + FileIs64 = true; + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + if(LogCreatedFiles) + { + if(engineDependencyFiles != NULL) + { + VirtualFree(engineDependencyFiles, NULL, MEM_RELEASE); + } + engineDependencyFiles = VirtualAlloc(NULL, 20 * 1024, MEM_COMMIT, PAGE_READWRITE); + engineDependencyFilesCWP = engineDependencyFiles; + } + if(!FileIs64) + { + ImageBase = (ULONG_PTR)PEHeader32->OptionalHeader.ImageBase; + ImportTableAddress = (ULONG_PTR)PEHeader32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; + ImportTableAddress = (ULONG_PTR)ConvertVAtoFileOffset(FileMapVA, ImportTableAddress + ImageBase, true); + ImportPointer = (PIMAGE_IMPORT_DESCRIPTOR)ImportTableAddress; + while(ImportPointer->FirstThunk != NULL) + { + ImportDllName = (PCHAR)((ULONG_PTR)ConvertVAtoFileOffset(FileMapVA, ImportPointer->Name + ImageBase, true)); + MultiByteToWideChar(CP_ACP, NULL, ImportDllName, lstrlenA(ImportDllName)+1, ImportDllNameW, sizeof(ImportDllNameW)/(sizeof(ImportDllNameW[0]))); + if(!EngineIsDependencyPresentW(ImportDllNameW, szFileName, szOutputFolder)) + { + RtlZeroMemory(&BuildExportName, 512); + lstrcatW(BuildExportName, szOutputFolder); + if(BuildExportName[lstrlenW(BuildExportName)-1] != 0x5C) + { + BuildExportName[lstrlenW(BuildExportName)] = 0x5C; + } + lstrcatW(BuildExportName, ImportDllNameW); + if(LogCreatedFiles) + { + RtlMoveMemory(engineDependencyFilesCWP, &BuildExportName, lstrlenW(BuildExportName) * 2); + engineDependencyFilesCWP = (LPVOID)((ULONG_PTR)engineDependencyFilesCWP + (lstrlenW(BuildExportName) * 2) + 2); + } + EngineExtractResource("MODULEx86", BuildExportName); + ExporterInit(20 * 1024, (ULONG_PTR)GetPE32DataW(BuildExportName, NULL, UE_IMAGEBASE), NULL, ImportDllName); + ImportThunkAddress = ImportPointer->FirstThunk; + if(ImportPointer->OriginalFirstThunk != NULL) + { + ImportThunkX86 = (PIMAGE_THUNK_DATA32)((ULONG_PTR)ConvertVAtoFileOffset(FileMapVA, ImportPointer->OriginalFirstThunk + ImageBase, true)); + } + else + { + ImportThunkX86 = (PIMAGE_THUNK_DATA32)((ULONG_PTR)ConvertVAtoFileOffset(FileMapVA, ImportPointer->FirstThunk + ImageBase, true)); + } + while(ImportThunkX86->u1.Function != NULL) + { + if(ImportThunkX86->u1.Ordinal & IMAGE_ORDINAL_FLAG32) + { + ExporterAddNewOrdinalExport(ImportThunkX86->u1.Ordinal ^ IMAGE_ORDINAL_FLAG32, 0x1000); + } + else + { + ImportThunkName = (ULONG_PTR)(ConvertVAtoFileOffset(FileMapVA, ImportThunkX86->u1.AddressOfData + ImageBase, true) + 2); + ExporterAddNewExport((PCHAR)ImportThunkName, 0x1000); + } + ImportThunkX86 = (PIMAGE_THUNK_DATA32)((ULONG_PTR)ImportThunkX86 + 4); + ImportThunkAddress = ImportThunkAddress + 4; + } + ExporterBuildExportTableExW(BuildExportName, ".export"); + } + ImportPointer = (PIMAGE_IMPORT_DESCRIPTOR)((ULONG_PTR)ImportPointer + sizeof IMAGE_IMPORT_DESCRIPTOR); + } + } + else + { + ImageBase = (ULONG_PTR)PEHeader64->OptionalHeader.ImageBase; + ImportTableAddress = (ULONG_PTR)PEHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; + ImportTableAddress = (ULONG_PTR)ConvertVAtoFileOffset(FileMapVA, ImportTableAddress + ImageBase, true); + ImportPointer = (PIMAGE_IMPORT_DESCRIPTOR)ImportTableAddress; + while(ImportPointer->FirstThunk != NULL) + { + ImportDllName = (PCHAR)((ULONG_PTR)ConvertVAtoFileOffset(FileMapVA, ImportPointer->Name + ImageBase, true)); + MultiByteToWideChar(CP_ACP, NULL, ImportDllName, lstrlenA(ImportDllName)+1, ImportDllNameW, sizeof(ImportDllNameW)/(sizeof(ImportDllNameW[0]))); + if(!EngineIsDependencyPresentW(ImportDllNameW, szFileName, szOutputFolder)) + { + RtlZeroMemory(&BuildExportName, 512); + lstrcatW(BuildExportName, szOutputFolder); + if(BuildExportName[lstrlenW(BuildExportName)-1] != 0x5C) + { + BuildExportName[lstrlenW(BuildExportName)] = 0x5C; + } + lstrcatW(BuildExportName, ImportDllNameW); + if(LogCreatedFiles) + { + RtlMoveMemory(engineDependencyFilesCWP, &BuildExportName, lstrlenW(BuildExportName) * 2); + engineDependencyFilesCWP = (LPVOID)((ULONG_PTR)engineDependencyFilesCWP + (lstrlenW(BuildExportName) * 2) + 2); + } + EngineExtractResource("MODULEx64", BuildExportName); + ExporterInit(20 * 1024, (ULONG_PTR)GetPE32DataW(BuildExportName, NULL, UE_IMAGEBASE), NULL, ImportDllName); + ImportThunkAddress = ImportPointer->FirstThunk; + if(ImportPointer->OriginalFirstThunk != NULL) + { + ImportThunkX64 = (PIMAGE_THUNK_DATA64)((ULONG_PTR)ConvertVAtoFileOffset(FileMapVA, ImportPointer->OriginalFirstThunk + ImageBase, true)); + } + else + { + ImportThunkX64 = (PIMAGE_THUNK_DATA64)((ULONG_PTR)ConvertVAtoFileOffset(FileMapVA, ImportPointer->FirstThunk + ImageBase, true)); + } + while(ImportThunkX64->u1.Function != NULL) + { + if(ImportThunkX64->u1.Ordinal & IMAGE_ORDINAL_FLAG64) + { + ExporterAddNewOrdinalExport((DWORD)(ImportThunkX64->u1.Ordinal ^ IMAGE_ORDINAL_FLAG64), 0x1000); + } + else + { + ImportThunkName = (ULONG_PTR)(ConvertVAtoFileOffset(FileMapVA, (ULONG_PTR)(ImportThunkX64->u1.AddressOfData + ImageBase), true) + 2); + ExporterAddNewExport((PCHAR)ImportThunkName, 0x1000); + } + ImportThunkX64 = (PIMAGE_THUNK_DATA64)((ULONG_PTR)ImportThunkX64 + 8); + ImportThunkAddress = ImportThunkAddress + 8; + } + ExporterBuildExportTableExW(BuildExportName, ".export"); + } + ImportPointer = (PIMAGE_IMPORT_DESCRIPTOR)((ULONG_PTR)ImportPointer + sizeof IMAGE_IMPORT_DESCRIPTOR); + } + } + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(true); + } + else + { + UnMapFileEx(FileHandle, FileSize, FileMap, FileMapVA); + return(false); + } + } + return(false); +} +__declspec(dllexport) bool __stdcall EngineFakeMissingDependencies(HANDLE hProcess) +{ + + if(hProcess != NULL) + { + SetAPIBreakPoint("ntdll.dll", "LdrLoadDll", UE_BREAKPOINT, UE_APIEND, (LPVOID)&EngineFakeLoadLibraryReturn); + SetAPIBreakPoint("ntdll.dll", "LdrGetProcedureAddress", UE_BREAKPOINT, UE_APIEND, (LPVOID)&EngineFakeGetProcAddressReturn); + } + return(false); +} +__declspec(dllexport) bool __stdcall EngineDeleteCreatedDependencies() +{ + + DWORD DummyCmp = NULL; + wchar_t szTempName[MAX_PATH]; + wchar_t szTempFolder[MAX_PATH]; + + if(engineDependencyFiles != NULL) + { + engineDependencyFilesCWP = engineDependencyFiles; + while(memcmp(engineDependencyFilesCWP, &DummyCmp, 1) != NULL) + { + RtlZeroMemory(&szTempName, sizeof szTempName); + RtlZeroMemory(&szTempFolder, sizeof szTempFolder); + if(GetTempPathW(MAX_PATH, szTempFolder) < MAX_PATH) + { + if(GetTempFileNameW(szTempFolder, L"DeleteTempGenFile", GetTickCount(), szTempName)) + { + DeleteFileW(szTempName); + if(!MoveFileW((LPCWSTR)engineDependencyFilesCWP, szTempName)) + { + DeleteFileW((LPCWSTR)engineDependencyFilesCWP); + } + else + { + DeleteFileW(szTempName); + } + } + } + engineDependencyFilesCWP = (LPVOID)((ULONG_PTR)engineDependencyFilesCWP + (lstrlenW((PWCHAR)engineDependencyFilesCWP) * 2) + 2); + } + VirtualFree(engineDependencyFiles, NULL, MEM_RELEASE); + engineDependencyFiles = NULL; + engineDependencyFilesCWP = NULL; + return(true); + } + return(false); +} + +__declspec(dllexport) bool __stdcall EngineCreateUnpackerWindow(char* WindowUnpackerTitle, char* WindowUnpackerLongTitle, char* WindowUnpackerName, char* WindowUnpackerAuthor, void* StartUnpackingCallBack) +{ + + EngineStartUnpackingCallBack = StartUnpackingCallBack; + lstrcpyA(szWindowUnpackerTitle, WindowUnpackerTitle); + lstrcpyA(szWindowUnpackerLongTitle, WindowUnpackerLongTitle); + lstrcpyA(szWindowUnpackerAuthor, WindowUnpackerAuthor); + lstrcpyA(szWindowUnpackerName, WindowUnpackerName); + if(DialogBoxParamA((HINSTANCE)engineHandle, MAKEINTRESOURCEA(IDD_MAINWINDOW), NULL, (DLGPROC)EngineWndProc, NULL) != -1) + { + return(true); + } + else + { + return(false); + } +} +__declspec(dllexport) void __stdcall EngineAddUnpackerWindowLogMessage(char* szLogMessage) +{ + + int cSelect; + + SendMessageA(EngineBoxHandle, LB_ADDSTRING, NULL, (LPARAM)szLogMessage); + cSelect = (int)SendMessageA(EngineBoxHandle, LB_GETCOUNT, NULL, NULL); + cSelect--; + SendMessageA(EngineBoxHandle, LB_SETCURSEL, (WPARAM)cSelect, NULL); +} +// Global.Engine.Extension.Functions: +__declspec(dllexport) bool __stdcall ExtensionManagerIsPluginLoaded(char* szPluginName) +{ + + for(unsigned int i = 0; i < Plugin.size(); i++) + { + if(lstrcmpiA(Plugin[i].PluginName, szPluginName) == NULL) + { + return(true); + } + } + return(false); +} +__declspec(dllexport) bool __stdcall ExtensionManagerIsPluginEnabled(char* szPluginName) +{ + + for(unsigned int i = 0; i < Plugin.size(); i++) + { + if(lstrcmpiA(Plugin[i].PluginName, szPluginName) == NULL) + { + if(!Plugin[i].PluginDisabled) + { + return(true); + } + else + { + return(false); + } + } + } + return(false); +} +__declspec(dllexport) bool __stdcall ExtensionManagerDisableAllPlugins() +{ + + for(unsigned int i = 0; i < Plugin.size(); i++) + { + Plugin[i].PluginDisabled = true; + } + return(true); +} +__declspec(dllexport) bool __stdcall ExtensionManagerDisablePlugin(char* szPluginName) +{ + + for(unsigned int i = 0; i < Plugin.size(); i++) + { + if(lstrcmpiA(Plugin[i].PluginName, szPluginName) == NULL) + { + Plugin[i].PluginDisabled = true; + return(true); + } + } + return(false); +} +__declspec(dllexport) bool __stdcall ExtensionManagerEnableAllPlugins() +{ + + for(unsigned int i = 0; i < Plugin.size(); i++) + { + Plugin[i].PluginDisabled = false; + } + return(true); +} +__declspec(dllexport) bool __stdcall ExtensionManagerEnablePlugin(char* szPluginName) +{ + + for(unsigned int i = 0; i < Plugin.size(); i++) + { + if(lstrcmpiA(Plugin[i].PluginName, szPluginName) == NULL) + { + Plugin[i].PluginDisabled = false; + return(true); + } + } + return(false); +} +__declspec(dllexport) bool __stdcall ExtensionManagerUnloadAllPlugins() +{ + + for(unsigned int i = 0; i < Plugin.size(); i++) + { + if(FreeLibrary(Plugin[i].PluginBaseAddress)) + { + Plugin.erase(Plugin.begin() + i); + } + } + return(true); +} +__declspec(dllexport) bool __stdcall ExtensionManagerUnloadPlugin(char* szPluginName) +{ + + typedef void(__stdcall *fPluginReleaseExec)(); + fPluginReleaseExec myPluginReleaseExec; + + for(unsigned int i = 0; i < Plugin.size(); i++) + { + if(lstrcmpiA(Plugin[i].PluginName, szPluginName) == NULL) + { + __try + { + if(Plugin[i].TitanReleasePlugin != NULL) + { + myPluginReleaseExec = (fPluginReleaseExec)Plugin[i].TitanReleasePlugin; + myPluginReleaseExec(); + if(FreeLibrary(Plugin[i].PluginBaseAddress)) + { + Plugin.erase(Plugin.begin() + i); + return(true); + } + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + if(FreeLibrary(Plugin[i].PluginBaseAddress)) + { + Plugin.erase(Plugin.begin() + i); + return(true); + } + } + } + } + return(false); +} +__declspec(dllexport) void* __stdcall ExtensionManagerGetPluginInfo(char* szPluginName) +{ + + for(unsigned int i = 0; i < Plugin.size(); i++) + { + if(lstrcmpiA(Plugin[i].PluginName, szPluginName) == NULL) + { + return(&Plugin[i]); + } + } + return(NULL); +} +// Global.Garbage.functions: +bool CreateGarbageItem(void* outGargabeItem, int MaxGargabeStringSize) +{ + + bool Created = false; + wchar_t szGarbageItem[512]; + wchar_t szGargabeItemBuff[128]; + + while(!Created) + { + RtlZeroMemory(&szGarbageItem, sizeof szGarbageItem); + RtlZeroMemory(&szGargabeItemBuff, sizeof szGargabeItemBuff); + srand((unsigned int)time(NULL)); + wsprintfW(szGargabeItemBuff, L"Junk-%08x\\", (rand() % 128 + 1) * (rand() % 128 + 1) + (rand() % 1024 + 1)); + lstrcpyW(szGarbageItem, engineSzEngineGarbageFolder); + lstrcatW(szGarbageItem, szGargabeItemBuff); + if(EngineCreatePathForFileW(szGarbageItem)) + { + Created = true; + } + } + if(lstrlenW(szGarbageItem) * 2 >= MaxGargabeStringSize) + { + RtlMoveMemory(outGargabeItem, &szGarbageItem, MaxGargabeStringSize); + return(false); + } + else + { + RtlMoveMemory(outGargabeItem, &szGarbageItem, lstrlenW(szGarbageItem) * 2); + return(true); + } +} +bool RemoveGarbageItem(wchar_t* szGarbageItem, bool RemoveFolder) +{ + + wchar_t szFindSearchString[MAX_PATH]; + wchar_t szFoundFile[MAX_PATH]; + WIN32_FIND_DATAW FindData; + bool QueryNextFile = true; + HANDLE CurrentFile; + + if(szGarbageItem != NULL) + { + lstrcpyW(szFindSearchString, szGarbageItem); + if(szFindSearchString[0] != NULL) + { + lstrcatW(szFindSearchString, L"\\*.*"); + CurrentFile = FindFirstFileW(szFindSearchString, &FindData); + while(QueryNextFile == true && CurrentFile != INVALID_HANDLE_VALUE) + { + RtlZeroMemory(&szFoundFile, sizeof szFoundFile); + lstrcpyW(szFoundFile, szGarbageItem); + lstrcatW(szFoundFile, FindData.cFileName); + if(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + if(FindData.cFileName[0] != 0x2E) + { + lstrcatW(szFoundFile, L"\\"); + RemoveGarbageItem(szFoundFile, true); + } + } + else + { + if(!DeleteFileW(szFoundFile)) + { + if(HandlerCloseAllLockHandlesW(szFoundFile, false, true)) + { + DeleteFileW(szFoundFile); + } + } + } + if(!FindNextFileW(CurrentFile, &FindData)) + { + QueryNextFile = false; + } + } + FindClose(CurrentFile); + if(RemoveFolder) + { + if(lstrlenW(engineSzEngineGarbageFolder) < lstrlenW(szGarbageItem)) + { + if(!RemoveDirectoryW(szGarbageItem)) + { + if(HandlerCloseAllLockHandlesW(szGarbageItem, true, true)) + { + RemoveDirectoryW(szGarbageItem); + } + } + } + } + return(true); + } + else + { + return(false); + } + } + else + { + return(false); + } +} +bool FillGarbageItem(wchar_t* szGarbageItem, wchar_t* szFileName, void* outGargabeItem, int MaxGargabeStringSize) +{ + + wchar_t szCopyFileName[512]; + wchar_t szGargabeItemBuff[128]; + + lstrcpyW(szCopyFileName, szGarbageItem); + if(szFileName != NULL) + { + lstrcatW(szCopyFileName, EngineExtractFileNameW(szFileName)); + } + else + { + srand((unsigned int)time(NULL)); + wsprintfW(szGargabeItemBuff, L"Junk-Data-%08x.bin", (rand() % 128 + 1) * (rand() % 128 + 1) + (rand() % 1024 + 1)); + lstrcatW(szCopyFileName, szGargabeItemBuff); + } + if(lstrlenW(szCopyFileName) >= MaxGargabeStringSize) + { + RtlMoveMemory(outGargabeItem, &szCopyFileName, MaxGargabeStringSize); + if(szFileName != NULL) + { + CopyFileW(szFileName, szCopyFileName, false); + } + } + else + { + RtlMoveMemory(outGargabeItem, &szCopyFileName, lstrlenW(szCopyFileName) * 2); + if(szFileName != NULL) + { + CopyFileW(szFileName, szCopyFileName, false); + } + } + return(true); +} +void EmptyGarbage() +{ + RemoveGarbageItem(engineSzEngineGarbageFolder, false); +} +// Global.Engine.Functions: +void EngineInitPlugins(wchar_t* szEngineFolder) +{ + + bool MoreFiles = true; + bool NameHasBeenRegistered = false; + PluginInformation myPluginInfo = {}; +#if defined (_WIN64) + wchar_t* szPluginFolder = L"plugins\\x64\\"; +#else + wchar_t* szPluginFolder = L"plugins\\x86\\"; +#endif + typedef bool(__stdcall *fPluginRegister)(char* szPluginName, LPDWORD titanPluginMajorVersion, LPDWORD titanPluginMinorVersion); + wchar_t szPluginSearchString[MAX_PATH] = {}; + wchar_t szPluginFullPath[MAX_PATH] = {}; + fPluginRegister myPluginRegister; + WIN32_FIND_DATAW FindData; + HANDLE CurrentFile; + + lstrcpyW(szPluginSearchString, szEngineFolder); + lstrcatW(szPluginSearchString, szPluginFolder); + lstrcatW(szPluginSearchString, L"*.dll"); + CurrentFile = FindFirstFileW(szPluginSearchString, &FindData); + while(MoreFiles) + { + lstrcpyW(szPluginFullPath, szEngineFolder); + lstrcatW(szPluginFullPath, szPluginFolder); + lstrcatW(szPluginFullPath, FindData.cFileName); + RtlZeroMemory(&myPluginInfo, sizeof PluginInformation); + myPluginInfo.PluginBaseAddress = LoadLibraryW(szPluginFullPath); + if(myPluginInfo.PluginBaseAddress != NULL) + { + myPluginInfo.TitanResetPlugin = (void*)GetProcAddress(myPluginInfo.PluginBaseAddress, "TitanResetPlugin"); + myPluginInfo.TitanReleasePlugin = (void*)GetProcAddress(myPluginInfo.PluginBaseAddress, "TitanReleasePlugin"); + myPluginInfo.TitanRegisterPlugin = (void*)GetProcAddress(myPluginInfo.PluginBaseAddress, "TitanRegisterPlugin"); + myPluginInfo.TitanDebuggingCallBack = (void*)GetProcAddress(myPluginInfo.PluginBaseAddress, "TitanDebuggingCallBack"); + myPluginRegister = (fPluginRegister)myPluginInfo.TitanRegisterPlugin; + if(myPluginRegister != NULL) + { + __try + { + if(myPluginRegister((char*)&myPluginInfo.PluginName[0], &myPluginInfo.PluginMajorVersion, &myPluginInfo.PluginMinorVersion)) + { + if(lstrlenA(myPluginInfo.PluginName) <= 64) + { + NameHasBeenRegistered = false; + for(unsigned int i = 0; i < Plugin.size(); i++) + { + if(lstrcmpiA(Plugin[i].PluginName, myPluginInfo.PluginName) == NULL) + { + NameHasBeenRegistered = true; + } + } + if(!NameHasBeenRegistered) + { + Plugin.push_back(myPluginInfo); + } + else + { + FreeLibrary(myPluginInfo.PluginBaseAddress); + } + } + else + { + FreeLibrary(myPluginInfo.PluginBaseAddress); + } + } + else + { + FreeLibrary(myPluginInfo.PluginBaseAddress); + } + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + FreeLibrary(myPluginInfo.PluginBaseAddress); + } + } + } + if(!FindNextFileW(CurrentFile, &FindData)) + { + MoreFiles = false; + } + } + FindClose(CurrentFile); +} +void EngineInit() +{ + + int i; + unsigned long ulPolynomial = 0x04C11DB7; //0x04C11DB7 is the official polynomial used by PKZip, WinZip and Ethernet. + + RtlZeroMemory(&engineSzEngineFile, sizeof engineSzEngineFile); + RtlZeroMemory(&engineSzEngineFolder, sizeof engineSzEngineFolder); + if(GetModuleFileNameW(engineHandle, engineSzEngineFile, MAX_PATH) > NULL) + { + lstrcpyW(engineSzEngineFolder, engineSzEngineFile); + i = lstrlenW(engineSzEngineFolder); + while(i > NULL && engineSzEngineFolder[i] != 0x5C) + { + engineSzEngineFolder[i] = 0x00; + i--; + } + if(i > NULL) + { + lstrcpyW(engineSzEngineGarbageFolder, engineSzEngineFolder); + lstrcatW(engineSzEngineGarbageFolder, L"garbage\\"); + } + EngineInitPlugins(engineSzEngineFolder); + } + // CRC32 table initialization + for(int iCodes = 0; iCodes <= 0xFF; iCodes++) + { + Crc32Table[iCodes] = EngineCrc32Reflect(iCodes, 8) << 24; + for(int iPos = 0; iPos < 8; iPos++) + { + Crc32Table[iCodes] = (Crc32Table[iCodes] << 1) ^ ((Crc32Table[iCodes] & (1 << 31)) ? ulPolynomial : 0); + } + Crc32Table[iCodes] = EngineCrc32Reflect(Crc32Table[iCodes], 32); + } +} +// Global.Engine.Entry: +bool APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) +{ + + int i; + + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + engineHandle = hModule; + if(sizeof HANDLE != 4) + { + engineCurrentPlatform = UE_PLATFORM_x64; + } + EngineInit(); + EmptyGarbage(); + for(i = 0; i < UE_MAX_RESERVED_MEMORY_LEFT; i++) + { + engineReservedMemoryLeft[i] = NULL; + } + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + if(lpReserved != NULL) + { + EngineExecutePluginReleaseCallBack(); + } + break; + } + return TRUE; +} diff --git a/TitanEngine/TitanEngine.def b/TitanEngine/TitanEngine.def new file mode 100644 index 0000000..4a648e1 --- /dev/null +++ b/TitanEngine/TitanEngine.def @@ -0,0 +1,407 @@ +LIBRARY "TitanEngine" +EXPORTS +DumpProcess +DumpProcessW +DumpProcessEx +DumpProcessExW +DumpMemory +DumpMemoryW +DumpMemoryEx +DumpMemoryExW +DumpRegions +DumpRegionsW +DumpRegionsEx +DumpRegionsExW +DumpModule +DumpModuleW +DumpModuleEx +DumpModuleExW +PastePEHeader +PastePEHeaderW +ExtractSection +ExtractSectionW +ResortFileSections +ResortFileSectionsW +FindOverlay +FindOverlayW +ExtractOverlay +ExtractOverlayW +AddOverlay +AddOverlayW +CopyOverlay +CopyOverlayW +RemoveOverlay +RemoveOverlayW +MakeAllSectionsRWE +MakeAllSectionsRWEW +AddNewSection +AddNewSectionW +AddNewSectionEx +AddNewSectionExW +ResizeLastSection +ResizeLastSectionW +SetSharedOverlay +SetSharedOverlayW +GetSharedOverlay +GetSharedOverlayW +DeleteLastSection +DeleteLastSectionW +DeleteLastSectionEx +DeleteLastSectionExW +GetPE32SectionNumberFromVA +ConvertVAtoFileOffset +ConvertVAtoFileOffsetEx +ConvertFileOffsetToVA +ConvertFileOffsetToVAEx +GetPE32Data +GetPE32DataW +GetPE32DataFromMappedFile +GetPE32DataEx +GetPE32DataExW +GetPE32DataFromMappedFileEx +SetPE32Data +SetPE32DataW +SetPE32DataForMappedFile +SetPE32DataEx +SetPE32DataExW +SetPE32DataForMappedFileEx +IsFileDLL +IsFileDLLW +WipeSection +WipeSectionW +RealignPE +RealignPEEx +RealignPEExW +IsPE32FileValidEx +IsPE32FileValidExW +FixBrokenPE32FileEx +FixBrokenPE32FileExW +FixHeaderCheckSum +FixHeaderCheckSumW +InitDebug +InitDebugW +InitDebugEx +InitDebugExW +InitDLLDebug +InitDLLDebugW +StopDebug +SetBPXOptions +IsBPXEnabled +SetBPX +SetBPXEx +DisableBPX +EnableBPX +DeleteBPX +SafeDeleteBPX +RemoveAllBreakPoints +SetMemoryBPX +SetMemoryBPXEx +RemoveMemoryBPX +SetAPIBreakPoint +DeleteAPIBreakPoint +SafeDeleteAPIBreakPoint +GetContextData +GetContextDataEx +GetContextFPUDataEx +SetContextData +SetContextDataEx +SetContextFPUDataEx +ClearExceptionNumber +CurrentExceptionNumber +StaticLengthDisassemble +LengthDisassemble +LengthDisassembleEx +StaticDisassemble +StaticDisassembleEx +DisassembleEx +Disassemble +MatchPatternEx +MatchPattern +FindEx +Find +FillEx +Fill +PatchEx +Patch +ReplaceEx +Replace +GetDebugData +GetTerminationData +GetExitCode +SetCustomHandler +ForceClose +SetNextDbgContinueStatus +DebugLoop +DebugLoopEx +StepInto +StepOver +SingleStep +SetHardwareBreakPoint +SetHardwareBreakPointEx +GetUnusedHardwareBreakPointRegister +DeleteHardwareBreakPoint +AttachDebugger +DetachDebugger +DetachDebuggerEx +GetDebuggedDLLBaseAddress +GetDebuggedFileBaseAddress +GetRemoteString +GetFunctionParameter +GetJumpDestination +GetJumpDestinationEx +IsJumpGoingToExecuteEx +IsJumpGoingToExecute +SetDebugLoopTimeOut +GetProcessInformation +GetStartupInformation +AutoDebugEx +AutoDebugExW +IsFileBeingDebugged +SetErrorModel +ImporterInit +ImporterAddNewDll +ImporterAddNewAPI +ImporterAddNewOrdinalAPI +ImporterExportIAT +ImporterExportIATEx +ImporterExportIATExW +ImporterEstimatedSize +ImporterSetImageBase +ImporterSetUnknownDelta +ImporterGetCurrentDelta +ImporterCleanup +ImporterGetAddedDllCount +ImporterGetAddedAPICount +ImporterGetLastAddedDLLName +ImporterMoveIAT +ImporterFindAPIWriteLocation +ImporterFindOrdinalAPIWriteLocation +ImporterFindAPIByWriteLocation +ImporterFindDLLByWriteLocation +ImporterGetDLLName +ImporterGetAPIName +ImporterGetAPINameEx +ImporterGetAPIOrdinalNumber +ImporterGetRemoteAPIAddress +ImporterGetRemoteAPIAddressEx +ImporterGetLocalAPIAddress +ImporterGetDLLNameFromDebugee +ImporterGetAPINameFromDebugee +ImporterGetAPIOrdinalNumberFromDebugee +ImporterGetDLLIndexEx +ImporterGetDLLIndex +ImporterGetRemoteDLLBase +ImporterGetRemoteDLLBaseEx +ImporterRelocateWriteLocation +ImporterIsForwardedAPI +ImporterAutoSearchIAT +ImporterAutoSearchIATW +ImporterAutoSearchIATEx +ImporterAutoFixIATEx +ImporterAutoFixIATExW +ImporterAutoFixIAT +ImporterAutoFixIATW +ImporterIsForwardedAPI +ImporterGetForwardedAPIName +ImporterGetForwardedDLLName +ImporterGetForwardedDLLIndex +ImporterGetForwardedAPIOrdinalNumber +ImporterGetNearestAPIAddress +ImporterGetNearestAPIName +ImporterCopyOriginalIAT +ImporterCopyOriginalIATW +ImporterLoadImportTable +ImporterLoadImportTableW +ImporterMoveOriginalIAT +ImporterMoveOriginalIATW +ImporterEnumAddedData +HooksSafeTransition +HooksSafeTransitionEx +HooksIsAddressRedirected +HooksGetTrampolineAddress +HooksGetHookEntryDetails +HooksInsertNewRedirection +HooksInsertNewIATRedirection +HooksInsertNewIATRedirectionEx +HooksRemoveRedirection +HooksRemoveRedirectionsForModule +HooksRemoveIATRedirection +HooksDisableRedirection +HooksDisableRedirectionsForModule +HooksDisableIATRedirection +HooksEnableRedirection +HooksEnableRedirectionsForModule +HooksEnableIATRedirection +HooksScanModuleMemory +HooksScanEntireProcessMemory +HooksScanEntireProcessMemoryEx +GetPEBLocation +HideDebugger +UnHideDebugger +RelocaterInit +RelocaterCleanup +RelocaterAddNewRelocation +RelocaterEstimatedSize +RelocaterExportRelocation +RelocaterExportRelocationEx +RelocaterExportRelocationExW +RelocaterGrabRelocationTable +RelocaterGrabRelocationTableEx +RelocaterMakeSnapshot +RelocaterMakeSnapshotW +RelocaterCompareTwoSnapshots +RelocaterCompareTwoSnapshotsW +RelocaterChangeFileBase +RelocaterChangeFileBaseW +RelocaterRelocateMemoryBlock +RelocaterWipeRelocationTable +RelocaterWipeRelocationTableW +ExporterInit +ExporterCleanup +ExporterSetImageBase +ExporterAddNewExport +ExporterAddNewOrdinalExport +ExporterGetAddedExportCount +ExporterEstimatedSize +ExporterBuildExportTable +ExporterBuildExportTableEx +ExporterBuildExportTableExW +ExporterLoadExportTable +ExporterLoadExportTableW +LibrarianSetBreakPoint +LibrarianRemoveBreakPoint +LibrarianGetLibraryInfo +LibrarianGetLibraryInfoW +LibrarianGetLibraryInfoEx +LibrarianGetLibraryInfoExW +LibrarianEnumLibraryInfo +LibrarianEnumLibraryInfoW +SetEngineVariable +TLSRemoveCallback +TLSRemoveCallbackW +TLSRemoveTable +TLSRemoveTableW +TLSBuildNewTable +TLSBuildNewTableEx +TLSBuildNewTableExW +TLSGrabCallBackData +TLSGrabCallBackDataW +TLSBackupData +TLSBackupDataW +TLSRestoreData +TLSBreakOnCallBack +TLSBreakOnCallBackEx +TLSBreakOnCallBackExW +ResourcerLoadFileForResourceUse +ResourcerLoadFileForResourceUseW +ResourcerFreeLoadedFile +ResourcerExtractResourceFromFileEx +ResourcerExtractResourceFromFile +ResourcerExtractResourceFromFileW +ResourcerEnumerateResource +ResourcerEnumerateResourceW +ResourcerEnumerateResourceEx +ResourcerFindResource +ResourcerFindResourceW +ResourcerFindResourceEx +TracerInit +TracerLevel1 +HashTracerLevel1 +TracerDetectRedirection +TracerFixKnownRedirection +TracerFixRedirectionViaImpRecPlugin +ThreaderImportRunningThreadData +ThreaderEnumThreadInfo +ThreaderGetThreadInfo +ThreaderPauseThread +ThreaderResumeThread +ThreaderTerminateThread +ThreaderPauseAllThreads +ThreaderResumeAllThreads +ThreaderPauseProcess +ThreaderResumeProcess +ThreaderCreateRemoteThread +ThreaderCreateRemoteThreadEx +ThreaderInjectAndExecuteCode +ThreaderInjectAndExecuteCodeEx +ThreaderSetCallBackForNextExitThreadEvent +ThreaderIsExceptionInMainThread +ThreaderIsThreadStillRunning +ThreaderIsThreadActive +ThreaderIsAnyThreadActive +ThreaderExecuteOnlyInjectedThreads +ThreaderGetOpenHandleForThread +ThreaderGetThreadData +StaticFileLoad +StaticFileLoadW +StaticFileUnload +StaticFileUnloadW +StaticFileOpen +StaticFileOpenW +StaticFileGetContent +StaticFileClose +StaticMemoryDecrypt +StaticMemoryDecryptEx +StaticMemoryDecryptSpecial +StaticSectionDecrypt +StaticMemoryDecompress +StaticRawMemoryCopyW +StaticRawMemoryCopy +StaticRawMemoryCopyEx +StaticRawMemoryCopyExW +StaticRawMemoryCopyEx64 +StaticRawMemoryCopyEx64W +StaticHashMemory +StaticHashFileW +StaticHashFile +TranslateNativeName +TranslateNativeNameW +HandlerGetActiveHandleCount +HandlerIsHandleOpen +HandlerGetHandleName +HandlerGetHandleNameW +HandlerEnumerateOpenHandles +HandlerGetHandleDetails +HandlerCloseRemoteHandle +HandlerCloseAllLockHandlesW +HandlerEnumerateLockHandles +HandlerEnumerateLockHandlesW +HandlerIsFileLocked +HandlerIsFileLockedW +HandlerCloseAllLockHandles +HandlerEnumerateOpenMutexes +HandlerGetOpenMutexHandle +HandlerGetOpenMutexHandleW +HandlerGetProcessIdWhichCreatedMutex +HandlerGetProcessIdWhichCreatedMutexW +RemoteLoadLibrary +RemoteLoadLibraryW +RemoteFreeLibrary +RemoteFreeLibraryW +RemoteExitProcess +FindOEPInit +FindOEPGenerically +FindOEPGenericallyW +GetActiveProcessId +GetActiveProcessIdW +EnumProcessesWithLibrary +EngineFakeMissingDependencies +EngineDeleteCreatedDependencies +EngineCreateMissingDependencies +EngineCreateMissingDependenciesW +EngineCreateUnpackerWindow +EngineAddUnpackerWindowLogMessage +ExtensionManagerIsPluginLoaded +ExtensionManagerIsPluginEnabled +ExtensionManagerDisablePlugin +ExtensionManagerDisableAllPlugins +ExtensionManagerEnablePlugin +ExtensionManagerEnableAllPlugins +ExtensionManagerUnloadPlugin +ExtensionManagerUnloadAllPlugins +ExtensionManagerGetPluginInfo +EngineUnpackerInitialize +EngineUnpackerInitializeW +EngineUnpackerSetEntryPointAddress +EngineUnpackerSetBreakCondition +EngineUnpackerFinalizeUnpacking \ No newline at end of file diff --git a/TitanEngine/TitanEngine.rc b/TitanEngine/TitanEngine.rc new file mode 100644 index 0000000..efd9eed --- /dev/null +++ b/TitanEngine/TitanEngine.rc @@ -0,0 +1,156 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// BINARY +// + +LOADERX86 BINARY "..\\TitanEngineLoaders\\LibraryLoader\\x32\\LibraryLoader.exe" +LOADERX64 BINARY "..\\TitanEngineLoaders\\LibraryLoader\\x64\\LibraryLoader.exe" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_MAINWINDOW DIALOGEX 0, 0, 255, 206 +STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_NOFAILCREATE | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_ACCEPTFILES +CAPTION "[ TitanEngine2 ]" +FONT 8, "Verdana", 0, 0, 0x1 +BEGIN + CONTROL 130,IDC_STATIC,"Static",SS_BITMAP,0,0,321,38 + CONTROL "Realign PE32 file [Recommended, but it can produce invalid files]",IDC_REALING, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,156,241,14 + EDITTEXT IDC_FILENAME,42,55,163,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP,WS_EX_STATICEDGE + CTEXT "- TitanEngine2 unpacker -",IDD_UNPACKERTITLE,2,39,250,10,SS_SUNKEN | NOT WS_GROUP,WS_EX_STATICEDGE + LTEXT "[Filename]",112,3,55,36,10 + GROUPBOX "Unpack execution messages",113,2,72,250,112 + LISTBOX IDC_LISTBOX,5,81,243,75,LBS_NOINTEGRALHEIGHT | NOT WS_BORDER | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP,WS_EX_STATICEDGE + PUSHBUTTON "UnPack",IDC_UNPACK,71,188,60,14,BS_CENTER | BS_VCENTER + PUSHBUTTON "Browse",IDC_BROWSE,210,53,40,14,BS_CENTER | BS_VCENTER + PUSHBUTTON "About",IDC_ABOUT,131,188,60,14 + PUSHBUTTON "Exit",IDC_EXIT,191,188,60,14 + CONTROL 131,IDC_STATIC,"Static",SS_BITMAP,5,191,46,9 + CONTROL "Copy file overlay [Recommended for all SFX files]",IDC_COPYOVERLAY, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,168,241,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_BITMAP1 BITMAP "HEADER.BMP" +IDB_BITMAP2 BITMAP "LOGO.bmp" + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 2,0,3,0 + PRODUCTVERSION 2,0,3,0 + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x0L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "ReversingLabs Corporation" + VALUE "FileDescription", "TitanEngine2" + VALUE "FileVersion", "2, 0, 3, 0" + VALUE "InternalName", "TitanEngine" + VALUE "LegalCopyright", "Copyright (C) 2009" + VALUE "OriginalFilename", "TitanEngine.dll" + VALUE "ProductName", "TitanEngine" + VALUE "ProductVersion", "2, 0, 3, 0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON2 ICON "MAINICON.ico" +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/TitanEngine/TitanEngine.vcproj b/TitanEngine/TitanEngine.vcproj new file mode 100644 index 0000000..e579a7e --- /dev/null +++ b/TitanEngine/TitanEngine.vcproj @@ -0,0 +1,521 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TitanEngine/TitanEngine.vcxproj b/TitanEngine/TitanEngine.vcxproj new file mode 100644 index 0000000..9f9f379 --- /dev/null +++ b/TitanEngine/TitanEngine.vcxproj @@ -0,0 +1,251 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {9C7B8246-FDDA-48C7-9634-044969701E40} + TitanEngine + Win32Proj + + + + DynamicLibrary + Unicode + true + + + DynamicLibrary + Unicode + + + DynamicLibrary + Unicode + true + + + DynamicLibrary + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + true + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + false + Speed + WIN32;_DEBUG;_WINDOWS;_USRDLL;UNPACKERENGINE_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreaded + 1Byte + true + Use + Level3 + EditAndContinue + Cdecl + CompileAsCpp + + + $(ProjectDir)distorm_x86.lib;Imagehlp.lib;psapi.lib;%(AdditionalDependencies) + $(OutDir)TitanEngine.dll + false + $(ProjectDir)TitanEngine.def + %(AddModuleNamesToAssembly) + true + false + false + Windows + + + false + false + MachineX86 + DefaultThreadingAttribute + + + + + X64 + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;UNPACKERENGINE_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + 1Byte + Use + Level3 + ProgramDatabase + StdCall + CompileAsCpp + + + $(ProjectDir)distorm_x64.lib;Imagehlp.lib;psapi.lib;%(AdditionalDependencies) + $(OutDir)TitanEngine.dll + false + $(ProjectDir)TitanEngine.def + true + false + false + Windows + false + false + MachineX64 + STAThreadingAttribute + + + + + Disabled + false + false + WIN32;NDEBUG;_WINDOWS;_USRDLL;UNPACKERENGINE_EXPORTS;%(PreprocessorDefinitions) + MultiThreaded + 1Byte + false + Use + Level3 + ProgramDatabase + Cdecl + CompileAsCpp + + + $(ProjectDir)distorm_x86.lib;Imagehlp.lib;psapi.lib;%(AdditionalDependencies) + $(ProjectDir)TitanEngine.def + false + + + + + + + X64 + + + MaxSpeed + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;UNPACKERENGINE_EXPORTS;%(PreprocessorDefinitions) + MultiThreaded + Default + true + Use + Level3 + ProgramDatabase + + + $(ProjectDir)distorm_x64.lib;Imagehlp.lib;psapi.lib;%(AdditionalDependencies) + $(OutDir)TitanEngine.dll + false + $(ProjectDir)TitanEngine.def + false + Windows + true + true + true + false + MachineX64 + + + + + + + false + + + false + + + false + + + false + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/TitanEngine/TitanEngine.vcxproj.filters b/TitanEngine/TitanEngine.vcxproj.filters new file mode 100644 index 0000000..52e46c9 --- /dev/null +++ b/TitanEngine/TitanEngine.vcxproj.filters @@ -0,0 +1,80 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {bf918bb7-d305-4123-9e17-3f28f4796516} + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + {0f4957c0-547f-4f5e-8133-a34644b29c2f} + + + {b4e0243e-1a54-40fe-be40-e7cc7a16c3e1} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files\ThirdParty + + + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + + + Resource Files\Binary + + + Resource Files\Binary + + + Resource Files\Binary + + + Resource Files\Binary + + + Resource Files\Images + + + Resource Files\Images + + + Resource Files\Images + + + + \ No newline at end of file diff --git a/TitanEngine/TitanEngine.vcxproj.user b/TitanEngine/TitanEngine.vcxproj.user new file mode 100644 index 0000000..695b5c7 --- /dev/null +++ b/TitanEngine/TitanEngine.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/TitanEngine/aplib.h b/TitanEngine/aplib.h new file mode 100644 index 0000000..97fee44 --- /dev/null +++ b/TitanEngine/aplib.h @@ -0,0 +1,66 @@ +/* + * aPLib compression library - the smaller the better :) + * + * MS COFF format header file + * + * Copyright (c) 1998-2005 by Joergen Ibsen / Jibz + * All Rights Reserved + * + * http://www.ibsensoftware.com/ + */ + +#ifndef APLIB_H_INCLUDED +#define APLIB_H_INCLUDED +#pragma comment(lib, "aplib.lib") + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef APLIB_ERROR +# define APLIB_ERROR (-1) +#endif + +unsigned int __cdecl aP_pack(const void *source, + void *destination, + unsigned int length, + void *workmem, + int (__cdecl *callback)(unsigned int, unsigned int, unsigned int, void *), + void *cbparam); + +unsigned int __cdecl aP_workmem_size(unsigned int inputsize); + +unsigned int __cdecl aP_max_packed_size(unsigned int inputsize); + +unsigned int __cdecl aP_depack_asm(const void *source, void *destination); + +unsigned int __cdecl aP_depack_asm_fast(const void *source, void *destination); + +unsigned int __cdecl aP_depack_asm_safe(const void *source, + unsigned int srclen, + void *destination, + unsigned int dstlen); + +unsigned int __cdecl aP_crc32(const void *source, unsigned int length); + +unsigned int __cdecl aPsafe_pack(const void *source, + void *destination, + unsigned int length, + void *workmem, + int (__cdecl *callback)(unsigned int, unsigned int, unsigned int, void *), + void *cbparam); + +unsigned int __cdecl aPsafe_check(const void *source); + +unsigned int __cdecl aPsafe_get_orig_size(const void *source); + +unsigned int __cdecl aPsafe_depack(const void *source, + unsigned int srclen, + void *destination, + unsigned int dstlen); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* APLIB_H_INCLUDED */ diff --git a/TitanEngine/aplib.lib b/TitanEngine/aplib.lib new file mode 100644 index 0000000000000000000000000000000000000000..ddbb11ae3c87fcc171b3ce9628edd55d33e91449 GIT binary patch literal 12250 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 tZLn@yzXnCht6&Bsz + #define OFFSET_INTEGER uint64_t + #endif +#else + /* 32 bit offsets are used. */ + #define OFFSET_INTEGER unsigned long +#endif + + +/* Support C++ compilers */ +#ifdef __cplusplus +extern "C" { +#endif + +/* Decodes modes of the disassembler, 16 bits or 32 bits or 64 bits for AMD64, x86-64. */ +typedef enum {Decode16Bits = 0, Decode32Bits = 1, Decode64Bits = 2} _DecodeType; + +typedef OFFSET_INTEGER _OffsetType; + +/* Static size of strings. Do not change this value. */ +#define MAX_TEXT_SIZE (60) +typedef struct { + unsigned int length; + unsigned char p[MAX_TEXT_SIZE]; /* p is a null terminated string. */ +} _WString; + +/* This structure holds all information the disassembler generates per instruction. */ +typedef struct { + _WString mnemonic; /* Mnemonic of decoded instruction, prefixed if required by REP, LOCK etc. */ + _WString operands; /* Operands of the decoded instruction, up to 3 operands, comma-seperated. */ + _WString instructionHex; /* Hex dump - little endian, including prefixes. */ + unsigned int size; /* Size of decoded instruction. */ + _OffsetType offset; /* Start offset of the decoded instruction. */ +} _DecodedInst; + +/* Return code of the decoding function. */ +typedef enum {DECRES_NONE, DECRES_SUCCESS, DECRES_MEMORYERR, DECRES_INPUTERR} _DecodeResult; + +/* distorm_decode + * Input: + * offset - Origin of the given code (virtual address that is), NOT an offset in code. + * code - Pointer to the code buffer to be disassembled. + * length - Amount of bytes that should be decoded from the code buffer. + * dt - Decoding mode, 16 bits (Decode16Bits), 32 bits (Decode32Bits) or AMD64 (Decode64Bits). + * result - Array of type _DecodeInst which will be used by this function in order to return the disassembled instructions. + * maxInstructions - The maximum number of entries in the result array that you pass to this function, so it won't exceed its bound. + * usedInstructionsCount - Number of the instruction that successfully were disassembled and written to the result array. + * Output: usedInstructionsCount will hold the number of entries used in the result array + * and the result array itself will be filled with the disassembled instructions. + * Return: DECRES_SUCCESS on success (no more to disassemble), DECRES_INPUTERR on input error (null code buffer, invalid decoding mode, etc...), + * DECRES_MEMORYERR when there are not enough entries to use in the result array, BUT YOU STILL have to check for usedInstructionsCount! + * Side-Effects: Even if the return code is DECRES_MEMORYERR, there might STILL be data in the + * array you passed, this function will try to use as much entries as possible! + * Notes: 1)The minimal size of maxInstructions is 15. + * 2)You will have to synchronize the offset,code and length by yourself if you pass code fragments and not a complete code block! + */ +#ifdef SUPPORT_64BIT_OFFSET + _DecodeResult distorm_decode64(_OffsetType codeOffset, const unsigned char* code, int codeLen, _DecodeType dt, _DecodedInst result[], unsigned int maxInstructions, unsigned int* usedInstructionsCount); + #define distorm_decode distorm_decode64 +#else + _DecodeResult distorm_decode32(_OffsetType codeOffset, const unsigned char* code, int codeLen, _DecodeType dt, _DecodedInst result[], unsigned int maxInstructions, unsigned int* usedInstructionsCount); + #define distorm_decode distorm_decode32 +#endif + +/* + * distorm_version + * Input: + * none + * + * Output: unsigned int - version of compiler library. + */ +unsigned int distorm_version(); + +#ifdef __cplusplus +} /* End Of Extern */ +#endif diff --git a/TitanEngine/distorm_x64.lib b/TitanEngine/distorm_x64.lib new file mode 100644 index 0000000000000000000000000000000000000000..b3581f4c829147322c1a85ba2564b45ae7fa8294 GIT binary patch literal 412064 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 O9_`g>j*9=T>7jFxU6vLGv;$~!Ss0p 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