From f8e1416ef19b65cf194a76f86dff7c071552e50c Mon Sep 17 00:00:00 2001 From: num0005 Date: Sun, 15 Jul 2018 00:54:56 +0100 Subject: [PATCH] Code cleanup. Move files to subdirectories. Rename patching functions and move all functions to header. Renamed a few files to make more sense. --- .gitignore | 3 - H2Codez/{ => Common}/BasicTagTypes.h | 0 H2Codez/{ => Common}/BlamBaseTypes.h | 0 H2Codez/{ => Common}/DiscordInterface.cpp | 2 +- H2Codez/{ => Common}/DiscordInterface.h | 0 H2Codez/{ => Common}/FiloInterface.cpp | 0 H2Codez/{ => Common}/FiloInterface.h | 2 +- .../H2EKCommon.cpp} | 15 +- .../{H2ToolsCommon.h => Common/H2EKCommon.h} | 2 +- H2Codez/{ => Common}/discord-rpc.h | 0 H2Codez/H2Codez.aps | Bin 17968 -> 0 bytes H2Codez/H2Codez.vcxproj | 87 +- H2Codez/H2Codez.vcxproj.filters | 179 +- H2Codez/{ => H2Guerilla}/H2Guerilla.cpp | 10 +- H2Codez/{ => H2Guerilla}/H2Guerilla.h | 0 H2Codez/{ => H2Sapien}/H2Sapien.cpp | 18 +- H2Codez/{ => H2Sapien}/H2Sapien.h | 0 H2Codez/H2SapienTextRasterizer.h | 13 - H2Codez/H2Tool/H2Tool_Commands.cpp | 679 ++- H2Codez/H2Tool_Commands.cpp | 737 --- H2Codez/HaloScript.cpp | 32 - H2Codez/HaloScript.h | 16 - H2Codez/{ => HaloScript}/hs_ai_behaviour.cpp | 2 +- H2Codez/{ => HaloScript}/hs_ai_behaviour.h | 0 H2Codez/{ => HaloScript}/hs_command.h | 2 +- H2Codez/{ => HaloScript}/hs_global_ids.h | 0 H2Codez/{ => HaloScript}/hs_global_variable.h | 0 .../hs_interface.cpp} | 5 +- .../hs_interface.h} | 2 +- H2Codez/{ => HaloScript}/hs_opcodes.h | 0 H2Codez/{ => HaloScript}/hs_types.h | 0 H2Codez/Patches.h | 69 - .../{ => Precompiled}/discord-rpc-debug.lib | Bin H2Codez/{ => Precompiled}/discord-rpc.lib | Bin H2Codez/{ => Resources}/H2Guerilla.rc | Bin H2Codez/{ => Resources}/H2Sapien.rc | Bin H2Codez/{ => Resources}/resource.h | 68 +- H2Codez/SigScanning.h | 48 - H2Codez/{ => Tags}/ScenarioTag.h | 0 H2Codez/dllmain.cpp | 7 +- H2Codez/h2codez.cpp | 8 +- H2Codez/patches.cpp | 37 - H2Codez/stdafx.h | 10 +- H2Codez/{ => util}/Debug.cpp | 4 +- H2Codez/{ => util}/Debug.h | 0 H2Codez/{ => util}/Detours/detours.cpp | 4736 ++++++++--------- H2Codez/{ => util}/Detours/detours.h | 2118 ++++---- H2Codez/{ => util}/Detours/detver.h | 0 H2Codez/{ => util}/Detours/disasm.cpp | 0 H2Codez/{ => util}/Detours/disolx86.cpp | 0 H2Codez/{ => util}/Detours/image.cpp | 0 H2Codez/{ => util}/Detours/modules.cpp | 0 H2Codez/{ => util}/Logs.cpp | 118 +- H2Codez/{ => util}/Logs.h | 94 +- H2Codez/util/Patches.h | 146 + H2Codez/{ => util}/RingBuffer.h | 0 H2Codez/{ => util}/Settings.cpp | 0 H2Codez/{ => util}/Settings.h | 0 58 files changed, 4519 insertions(+), 4750 deletions(-) rename H2Codez/{ => Common}/BasicTagTypes.h (100%) rename H2Codez/{ => Common}/BlamBaseTypes.h (100%) rename H2Codez/{ => Common}/DiscordInterface.cpp (99%) rename H2Codez/{ => Common}/DiscordInterface.h (100%) rename H2Codez/{ => Common}/FiloInterface.cpp (100%) rename H2Codez/{ => Common}/FiloInterface.h (99%) rename H2Codez/{H2ToolsCommon.cpp => Common/H2EKCommon.cpp} (97%) rename H2Codez/{H2ToolsCommon.h => Common/H2EKCommon.h} (94%) rename H2Codez/{ => Common}/discord-rpc.h (100%) delete mode 100644 H2Codez/H2Codez.aps rename H2Codez/{ => H2Guerilla}/H2Guerilla.cpp (98%) rename H2Codez/{ => H2Guerilla}/H2Guerilla.h (100%) rename H2Codez/{ => H2Sapien}/H2Sapien.cpp (98%) rename H2Codez/{ => H2Sapien}/H2Sapien.h (100%) delete mode 100644 H2Codez/H2SapienTextRasterizer.h delete mode 100644 H2Codez/H2Tool_Commands.cpp delete mode 100644 H2Codez/HaloScript.cpp delete mode 100644 H2Codez/HaloScript.h rename H2Codez/{ => HaloScript}/hs_ai_behaviour.cpp (95%) rename H2Codez/{ => HaloScript}/hs_ai_behaviour.h (100%) rename H2Codez/{ => HaloScript}/hs_command.h (98%) rename H2Codez/{ => HaloScript}/hs_global_ids.h (100%) rename H2Codez/{ => HaloScript}/hs_global_variable.h (100%) rename H2Codez/{HaloScriptInterface.cpp => HaloScript/hs_interface.cpp} (97%) rename H2Codez/{HaloScriptInterface.h => HaloScript/hs_interface.h} (98%) rename H2Codez/{ => HaloScript}/hs_opcodes.h (100%) rename H2Codez/{ => HaloScript}/hs_types.h (100%) delete mode 100644 H2Codez/Patches.h rename H2Codez/{ => Precompiled}/discord-rpc-debug.lib (100%) rename H2Codez/{ => Precompiled}/discord-rpc.lib (100%) rename H2Codez/{ => Resources}/H2Guerilla.rc (100%) rename H2Codez/{ => Resources}/H2Sapien.rc (100%) rename H2Codez/{ => Resources}/resource.h (97%) delete mode 100644 H2Codez/SigScanning.h rename H2Codez/{ => Tags}/ScenarioTag.h (100%) delete mode 100644 H2Codez/patches.cpp rename H2Codez/{ => util}/Debug.cpp (98%) rename H2Codez/{ => util}/Debug.h (100%) rename H2Codez/{ => util}/Detours/detours.cpp (97%) rename H2Codez/{ => util}/Detours/detours.h (97%) rename H2Codez/{ => util}/Detours/detver.h (100%) rename H2Codez/{ => util}/Detours/disasm.cpp (100%) rename H2Codez/{ => util}/Detours/disolx86.cpp (100%) rename H2Codez/{ => util}/Detours/image.cpp (100%) rename H2Codez/{ => util}/Detours/modules.cpp (100%) rename H2Codez/{ => util}/Logs.cpp (90%) rename H2Codez/{ => util}/Logs.h (94%) create mode 100644 H2Codez/util/Patches.h rename H2Codez/{ => util}/RingBuffer.h (100%) rename H2Codez/{ => util}/Settings.cpp (100%) rename H2Codez/{ => util}/Settings.h (100%) diff --git a/.gitignore b/.gitignore index 67db9c1..c68e8f0 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,6 @@ # Compiled Dynamic libraries *.so *.dylib -*.dll # Fortran module files *.mod @@ -26,7 +25,6 @@ *.a # Executables -*.exe *.out *.app @@ -36,7 +34,6 @@ H2Codez/build/* *.VC.db *.VC.VC.opendb *.ipch -*.pdb *.exp *.ipdb *.iobj diff --git a/H2Codez/BasicTagTypes.h b/H2Codez/Common/BasicTagTypes.h similarity index 100% rename from H2Codez/BasicTagTypes.h rename to H2Codez/Common/BasicTagTypes.h diff --git a/H2Codez/BlamBaseTypes.h b/H2Codez/Common/BlamBaseTypes.h similarity index 100% rename from H2Codez/BlamBaseTypes.h rename to H2Codez/Common/BlamBaseTypes.h diff --git a/H2Codez/DiscordInterface.cpp b/H2Codez/Common/DiscordInterface.cpp similarity index 99% rename from H2Codez/DiscordInterface.cpp rename to H2Codez/Common/DiscordInterface.cpp index 397a6cd..16b33c6 100644 --- a/H2Codez/DiscordInterface.cpp +++ b/H2Codez/Common/DiscordInterface.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "../stdafx.h" #include "DiscordInterface.h" #include diff --git a/H2Codez/DiscordInterface.h b/H2Codez/Common/DiscordInterface.h similarity index 100% rename from H2Codez/DiscordInterface.h rename to H2Codez/Common/DiscordInterface.h diff --git a/H2Codez/FiloInterface.cpp b/H2Codez/Common/FiloInterface.cpp similarity index 100% rename from H2Codez/FiloInterface.cpp rename to H2Codez/Common/FiloInterface.cpp diff --git a/H2Codez/FiloInterface.h b/H2Codez/Common/FiloInterface.h similarity index 99% rename from H2Codez/FiloInterface.h rename to H2Codez/Common/FiloInterface.h index b2e0251..df7995a 100644 --- a/H2Codez/FiloInterface.h +++ b/H2Codez/Common/FiloInterface.h @@ -1,5 +1,5 @@ #pragma once -#include "stdafx.h" +#include "../stdafx.h" struct filo { diff --git a/H2Codez/H2ToolsCommon.cpp b/H2Codez/Common/H2EKCommon.cpp similarity index 97% rename from H2Codez/H2ToolsCommon.cpp rename to H2Codez/Common/H2EKCommon.cpp index e5d445f..11cbd95 100644 --- a/H2Codez/H2ToolsCommon.cpp +++ b/H2Codez/Common/H2EKCommon.cpp @@ -1,17 +1,18 @@ -#include -#include "stdafx.h" -#include "Patches.h" -#include "H2ToolsCommon.h" +#include "H2EKCommon.h" +#include "../stdafx.h" +#include "../util/Patches.h" #include "Psapi.h" #include "DiscordInterface.h" -#include "Debug.h" +#include "../util/Debug.h" +#include "../HaloScript/hs_interface.h" +#include #include #include #include #include #include -using namespace HaloScriptCommon; +using namespace H2CommonPatches; typedef int (WINAPI *LoadStringW_Typedef)(HINSTANCE hInstance, UINT uID, LPWSTR lpBuffer, int cchBufferMax); LoadStringW_Typedef LoadStringW_Orginal; @@ -215,7 +216,7 @@ wchar_t* __stdcall get_wide_halo_2_documents_path() // This fixes that by making sure the code gets the string type it was expecting void fix_documents_path_string_type() { - WriteJmpTo(SwitchAddessByMode(0x00589D10, 0x004BA7C0, 0x0048A050), get_narrow_halo_2_documents_path); + WriteJmp(SwitchAddessByMode(0x00589D10, 0x004BA7C0, 0x0048A050), get_narrow_halo_2_documents_path); // The only two functions that weren't broken before PatchCall(SwitchAddessByMode(0x006708E6, 0x005061A5, 0x005AEFF6), get_wide_halo_2_documents_path); // wrl export diff --git a/H2Codez/H2ToolsCommon.h b/H2Codez/Common/H2EKCommon.h similarity index 94% rename from H2Codez/H2ToolsCommon.h rename to H2Codez/Common/H2EKCommon.h index fa0f1ff..d22c734 100644 --- a/H2Codez/H2ToolsCommon.h +++ b/H2Codez/Common/H2EKCommon.h @@ -1,5 +1,5 @@ #pragma once -#include "HaloScriptInterface.h" +#include "..\HaloScript\hs_interface.h" struct hs_convert_data_store { diff --git a/H2Codez/discord-rpc.h b/H2Codez/Common/discord-rpc.h similarity index 100% rename from H2Codez/discord-rpc.h rename to H2Codez/Common/discord-rpc.h diff --git a/H2Codez/H2Codez.aps b/H2Codez/H2Codez.aps deleted file mode 100644 index 82715f984008e7c245124f325ede05a643ec13af..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17968 zcmd5^XS5_ob-pW!AP``JNhYjB(h}t9o}NVRQ2kzOd%8#6J@4(?v(U)9Pq0GTwRg1^ z2w?=+J|+j7aEy&H298a%$vI<7B7@0EQ>dQ zTet4586u*c_&I)D{oucyKLvifD}L5#lLGvE{P>OrKmD}kKXgq*6yA5={OIG_aD1>`_Lsv_iY?JdhGm*c9xeMJ8)d|>-B``>ep z>_@{l#*c@eiUjS!-w9YeCJS#l;BvSWg4 ze^%C+*i+SoDD!y{ih9FO=YpJ`L#LZ~m`|sE7B#Tf>w$o-bpv6ZRYjgI>I28zYP{T< zincnpeukE*odw!KJIGjT{+tZFPD9YMTleMf)MO;zuQ9ybr-M<4>`3#6F zkq2~;B3WDKT0HQS9@xQxysGjkz_A1$)B*i$3rH-H2RBHN7m+AhL7=N>GU#GTk{(1! zp^i%YrdlgX53;1t(hj(gr3YbBXmAHr!t@|bN^t{Kd7f6utb~+UQvmA?5T{!K%ie<& zDfWeGDNb|0s;6_*k(dYU+-@)ZNFrk(yBlOZi3C<~minQPU~imalc^@lWUr{BEi4*V zl>6&>DNRi&0!xEa{K29s)Sj!27UD$Xu?NK=7T%;Ya-prN-@@X&^@^v}f0m2$jnYjJ#Raw)7B zy;hgzGm)uchhC?P!!$3Y1P+$y^}4+DH=5!;y`fuN`*OJ*EY2G>GQ)(`rKsj?vC;W} z-eiD9f<11aLwd7?s#+s@i&b7n36@+cpVJ%DTWxq&h>fHj@r2%{@%b$Bt7Z^ByO^Z1WyP{OGIz4)ijitho z!vyx;Wz1EWL+@M0`U-RD{mYoAus(fY85=0fqkmtr|m_8vP5hYa}roxv-%W-@3DXScwj?yOAp-&qabWqNT>(Xb8;<-{Gw@;td zr7?`LB75{XT|9$0O3B>;ecmds(!>*6-0b%yPdd{7e~U zr|-}=O)T`w(2vwq^j-RviB)VDrHjED*zeP~mr&_RNYtb6m}ogm6Ezk60ex2@Y*DmhewQ&TaH17eBAO07y1{~gh68PiT^ODl?r0AGx;ZbfUz>xk54mr;1jBLR z6OB9XL-?C56B>`G58;1r3FTf?-9FuX1&ZTP!5-aW3ErFM(?pKDk7M+fEAdA8`Z)S; zCCAN&V9j@jK$)R2hIJc_@cnFF)(g;~+iI{7i*k={r_23$l^a`b3~6q!(Q*o_)~?VP zlY9q_rGBv{H0ID94J=UxbnLivCtVzg3TLid&9T#`J8J}LB$Qh*c0Agtfq?HQa*f8$ zfX-Y@l$;ApVKRmL31yYPYjMxAi2j}qv1#=#vLE;!xEyL_nqXS*VIu8uFoBkwZ34W} zc#S7ekXc#|0eNP6uw`aGNuB^+DuVUN?ZisY06PV`8Ka0`r{W|~;dr`}!2XsIl z>H_T315J(NCrG`H4H3yU}BYD?oJzhh_ULS z2B)}stS6~F^I|6^p`l2WyZtbPm!22$0F5J`)-=w(F1x}Q2VeB*Tn(}Bry+-SYY5s5 zq>|Tb87TKXxut%AOZF__21Ijf%&sc|9!&-TVG}AC&)McxV zL+7={vpUObQ53kB`5V|Ye$do~>ru5N#F29N-1FHiFDi5(_Jm?qA#x*|gCjE6%tf%t zBDu7oNmDV!bldIpX;V|?I1p@tM|(6O$q>%Mj)Zxzc>~(gycu5@@{C27;^K_mr_nsa zy-phExQBE0AsVSRbB(z4P>skI8BxmPf(;GxMzr5Tag|=IkT<3S7F^{EE%7F_tx?<;+4-7ca7iWj${i!#LdrAKN!REKfnOQPjIU8GSyBvhjwU95`{oSaMF68r%j z(m-6~d*xLWz>p4W0Q*nw0zLwOjp&axCa-KfJcW(vh{n`CPYzz86FRC$@eB#-D)O_<_X<5hzX#jcc+P|%|_BTC?`7+_47 zX)s8tsXsIENsk_*ap_{IK(W!r#G%VIM+PD~O}O+}4a*w@w-h!A$62XL%`ATC$Az&-CB@b zdWt6DT;pb#!J;@gGoGqZ-A`EHqJ?N{+mlC6Gia_X5Z@qGxIzESxAZANvpu&*hm7%9x&|DQ(`N!#F5*T1zfEDc|dV+UvN3v3V->-I7VhD(2EGq}1*>C@lal(ND(w^lb^ z9-8s!g*K<~qa?3`IdU3m7;ts}!6pS;G6;YchV&vEoG%7BqJOkOb6+{mm|koX%)QCM zn}4ziYjYWfMBhHW#0J|f>o@_u)CQaQ9BPL2G7UBgwAil;+sL7ne>ov<=2z=-x!~Kp ze2En$*pcyE#$jRy0hd=SQIt!G%$qO$JO}ZYSDuKpS-{|{-aLBM5(_J){4?FyfL?uK zn$g^lUZZ&kk|(oDwIzE)MC7$gFvf<#V_SFJH;$0J&fv-nU9DUN*%my6H)_0@br>yN zx-%7Wjh(SWZ_*sNci2!+#!{MUXYA6OHQMYq=|VVg65i56$`yr;GduU_tu2o8ZDGjZ zv?g)W`hecHilS_o8p4p?t|^VtT?Bq1{)pb8aovka8PhvgQDB~MF;TYxXFQ>Its=4W z1BEe}KD~PtQ^z|XRY332oHcgF0fyZ&BrnK8qa$txR#i6S-rRhjAN<`BY#igqa3LkA*YyJHm zeaOP#sEb18A7jUN=))Gw6Bg%)E6TQgmp)<4_^4a*q*sl2^f8On zScFJqiOhFGlmUI*BDE9J`sR*5q)%9!0(U1)I!Hf9ojCr8K54O#>d+?2AJczYIFG3m zf+M<+WI~^^@O7+vok(xo@qPNV1((28R1viU`iuqRoZh{FL;9=*vjJV$Pguy$S-8k! zC6}PjYsfEPmKN(A^yrHgX0CJK(3dQj?Ps2)${++Tec8gHU3t8i`JhiJ~h@ z#v))++vsfU1Oxi&G9DtxBYk@(7}D34@iJT&Q%*giff0SZC6sj@BDNFyshDR;Rn{}4 z&1HlucETQgQ}deWToY!EU0C_=X|#C}0DV`^iVMU3eGQ}S5GhFmcIgKi<~W#v_34K# zHml3?($?Bb6U;+!Ve)^{rKlhn+aP%Io2+E*gt|BZe%d9A>8#p9tLc1-w;d|BgGT%G zvo0@AL<)75Q&&$Dgy(RADFHmXw#!Y@RII_9;?%364Cv=wihKbvgHb8+O=NiE7$=z8 zvo5Zgzvz+?K54chj5i1PRHKNIFY#71H>O{8X?lK4b#-xQ{JKlz`9|MWUMbJg9sBf~ zE+vnG(DrRz92mdt()fAC%0s~&hxEHHx6F{CUx&e5I%V8(M8~^iw){A&_A z&<(mI9#kw^eVz>IhFv_#pmflhs^;-X<(rJ?^e(BHl?aJ7+z{27s;FbSQJ300)?uYa zNOaXWCUoO&6}A03$Eb_@@)=!LkmtLnezDsMCMq!ky2;7dxMU+P*-TMLH*L9Pt%lSf z5#78+W>6P6&e<9Q{1rv)MqJoVsPLVrx88{=j7y0CkO=RHFox2QW@8(%29_!*b+1c{SdcCUj zyOY?B9J-qYvTbN$i*Dr7-7T2Ue^z`U6DVk*Pxr7Wa7fp?nR|#8zd3D8aZvz zfOc7gu3AJxx~D~GE&}q7qZ%2}y(|tll1yQe5w~l%N;IZ>YZ`2SD8v6jzNhB61b&sR z@jHnV&tgcT1u!RczY{Z?ohf{}e@nu_gYz1Tf#;?@3UslG z0Lw?Hp)L*hY{UhLpAJR3SO%duq9ucDocdj}K}q3A6XJQC{as%oU@takpOPiC3FEsx zkIp@X)6vMtr+7`3^UEh>WF4By;>~1l;7grCVV|fkqK7D26Ul;HJNn=hV)1c$UtxV=!4M_U8GUY5Xfk<9LAU~))4#GYOy6Y zp+g#zu>dp%m-VnNRdO3SdSt5CEH(4nWS0@pVr z>e5qJp{m_JJ#7`pvxbH}diqLKf&+TSN>DXCq-U-|gm73y(^5_K`?;Ng^ zfn3QUy|5(|i9a%9oNz<>H;ur7gXbLJb=z)2HlRnZx3SH24*3Fe=nXc;HxVE%z0pS23IRV0 zSfAcxV}bl+2S22Jvkh$tgRpUMseDF<^i~@Uw~+n%TKsMsmYwqn!-C@($a`!8_pV2c zG|78cF`AJhLGnHeR{F@m& zDqY?jkSOlc)w)={3q`3%A8bnznMCXS)_~(Ac%9yN-NA@Hz5gyCVrU++p$VU^u^CBbaRU0P z%~1^9QAl62DQz>F6w%jhQqzF8SyMow(-&uhpJdC%uQVMLr@2+4hMvM*ky%qR6Y>3>-s*wSG z-zFi5EQ12Nr6K*mCRxpl=!Yj{=yt~RUz&xC%p5s$CB}sQTO&a(UzA}Uefl3=oFE{l zk_`fh${%Tf`6d|Bk2R=H6D>nTKhYp3qvm7?l<^s8k; z`|3qe2K4J?O7l7tV;ItJG_0)BY{s7=12(4LuE1*Jp_ITo^xtU?PjtPg?$hyQs9PH! zZasDJ$)IKibp!aU-%7OGMntD9vDA6ce#|JwGh#Yblhl@%K2Ob`ivW%%(yMV9pAfh{ zT~FiiCWD%Ds&pRtm`4=rRb zV~=jK#NZ1oKlW9O0o`&)UYtllkPy6;iATvs!tX$Wt-Yd<2{M74;P0ChIFfm+cB?+@e2;Fu zf`qfq;0)+CCI?YEzA&@%kQaDu7^obwKw9v&CQp*`Y7rb4$OzufBs2}RNe_XH;O$ME z8}L(}-mS$dA}ja@CMQCeArwizh|~!r2Jc`pj8^c_t*q1;g8bkeO%`NPSq=BapAj| zEbI&9n^+xmVpkw6d{>jigFysS&aM;&QQ^Cp1Wqo?xswl(_530>e0Q6NhV(KcD0~l- z(BzNN9zVWP8mM|4(%CDBxVqk_); zt)QAmeAuUfNoiuITH!(ju1x}4bq;c~3Lw*nP?{1QQEQV{;`3_ZIy*02;SsVnY4|7@ zf8vW{_;|*T+lu^rH?pe;Sf9$D^T!8*@b}m8H4^gAwfGi;?)OGqCCmBy7TWJVINtm@ z{j`woOZ)IK>!Y+yNAUMPe3*QjF2%nQ9j5(sj4sCShv*WCZQz5#M^Sb@T|_(aQSeLf z{{tvHjNcHN$F~vSnK;eR(qVjVcpLRqy>*}=$_}9HGBE7lkD&Z0@MEaCAOAlGA6DjX znoxgQDOI}<2j_f9wG$uMKL|Ov=1w}B9z|ms;;Rq#;gj+Q(F)7JZC(HwcGAftXQ|JT zl5arDeQ5m>w0kjX?#FKjG5Y=ZokzMY(F@R*lKB6#oR><;O*siOX6we)OS-`diS%eX zN2cGA=v}cAW~sZfw7)22KGD5**nR2m{b==&zvBd7VRF*%IN|Rj`4E2oFW*PP-$8N) z`af|UEeojf4}X)$o|D#D{;m=Jo{=k1M}J3){+(X-m7m=j>ga7~l diff --git a/H2Codez/H2Codez.vcxproj b/H2Codez/H2Codez.vcxproj index 4ecc1a8..75decdc 100644 --- a/H2Codez/H2Codez.vcxproj +++ b/H2Codez/H2Codez.vcxproj @@ -72,7 +72,7 @@ Windows true - version.lib;Comdlg32.lib;Shlwapi.lib;Dbghelp.lib;discord-rpc-debug.lib;%(AdditionalDependencies) + version.lib;Comdlg32.lib;Shlwapi.lib;Dbghelp.lib;Precompiled\discord-rpc-debug.lib;%(AdditionalDependencies) @@ -96,7 +96,7 @@ true true true - version.lib;Comdlg32.lib;Shlwapi.lib;Dbghelp.lib;discord-rpc.lib;%(AdditionalDependencies) + version.lib;Comdlg32.lib;Shlwapi.lib;Dbghelp.lib;Precompiled\discord-rpc.lib;%(AdditionalDependencies) true UseLinkTimeCodeGeneration @@ -110,44 +110,44 @@ - - - - - - - - + + + + + + + + - - - + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - + + + + + + + false @@ -156,25 +156,24 @@ - + - - - + + + - - - - - - + + + + + Create - - + + diff --git a/H2Codez/H2Codez.vcxproj.filters b/H2Codez/H2Codez.vcxproj.filters index 4d9895d..d559073 100644 --- a/H2Codez/H2Codez.vcxproj.filters +++ b/H2Codez/H2Codez.vcxproj.filters @@ -31,24 +31,24 @@ {58180921-4d86-4ddd-9f94-6f967c0598d4} - - {bf0d6f38-d03a-43e4-b8b2-31f929a0cd61} - {0ba390b2-f03c-404c-988f-facf6ae1964d} {fa4a8928-3838-40b7-8b15-0f517eb11655} - - {5a7dab93-c43b-4f54-b6ef-7efaaeaadf19} - {57453ed4-21c3-4fe6-b127-81ade21db8a0} {50187530-4577-4dd1-bd6b-4bca9d0c64da} + + {bf0d6f38-d03a-43e4-b8b2-31f929a0cd61} + + + {5a7dab93-c43b-4f54-b6ef-7efaaeaadf19} + @@ -77,158 +77,155 @@ Header Files - - Header Files - Source Files\Patches\H2Tool Source Files - - Source Files\Patches\H2Guerilla - - - Source Files\Utils - - - Source Files\Patches\H2Sapien - - - Source Files\Common Interfaces - Source Files\Common Interfaces - - Source Files\Common Interfaces - Source Files\Patches\H2Tool - - Source Files\Common Interfaces + + Resource Files - - Source Files\Utils + + Source Files\util\detours - - Source Files\Utils + + Source Files\util\detours - - Source Files\Utils\ms_detours + + Source Files\util - - Source Files\Utils\ms_detours + + Source Files\util - - Source Files\Common Interfaces\Tags + + Source Files\util - - Source Files\Common Interfaces\Tags + + Source Files\util - + Source Files\Common Interfaces\HaloScript - + Source Files\Common Interfaces\HaloScript - + Source Files\Common Interfaces\HaloScript - + Source Files\Common Interfaces\HaloScript - + Source Files\Common Interfaces\HaloScript - + Source Files\Common Interfaces\HaloScript - + Source Files\Common Interfaces\HaloScript - - Source Files\Utils + + Source Files\util - + Source Files\Common Interfaces - - Source Files\Utils + + Source Files\Common Interfaces + + + Source Files\Common Interfaces + + + Source Files\Common Interfaces + + + Source Files\Common Interfaces\Tags + + + Source Files\Patches\H2Sapien + + + Source Files\Common Interfaces\Tags + + + Source Files\Patches\H2Guerilla Source Files - - Source Files\Patches\H2Tool - Source Files - - Source Files\Patches\H2Guerilla + + Source Files\Patches\H2Tool - - Source Files\Utils + + Header Files - - Source Files\Patches\H2Sapien + + Source Files\util\detours - - Source Files\Common Interfaces + + Source Files\util\detours - - Source Files\Common Interfaces + + Source Files\util\detours - - Source Files\Patches\H2Tool + + Source Files\util\detours - - Source Files\Common Interfaces + + Source Files\util\detours - - Source Files\Utils + + Source Files\util - - Source Files\Utils + + Source Files\util - - Source Files\Utils\ms_detours + + Source Files\Common Interfaces\HaloScript - - Source Files\Utils\ms_detours + + Source Files\Common Interfaces\HaloScript - - Source Files\Utils\ms_detours + + Source Files\util - - Source Files\Utils\ms_detours + + Source Files\Common Interfaces - - Source Files\Utils\ms_detours + + Source Files\Common Interfaces - - Source Files\Common Interfaces\HaloScript + + Source Files\Common Interfaces - - Source Files\Common Interfaces\HaloScript + + Source Files\Patches\H2Sapien - - Source Files\Utils + + Source Files\Patches\H2Tool - - Header Files + + Source Files\Patches\H2Guerilla - + Resource Files - + Resource Files diff --git a/H2Codez/H2Guerilla.cpp b/H2Codez/H2Guerilla/H2Guerilla.cpp similarity index 98% rename from H2Codez/H2Guerilla.cpp rename to H2Codez/H2Guerilla/H2Guerilla.cpp index fc19b8a..f62044f 100644 --- a/H2Codez/H2Guerilla.cpp +++ b/H2Codez/H2Guerilla/H2Guerilla.cpp @@ -1,9 +1,9 @@ -#include "stdafx.h" +#include "..\stdafx.h" #include "H2Guerilla.h" -#include "Patches.h" -#include "resource.h" -#include "H2ToolsCommon.h" -#include "FiloInterface.h" +#include "..\util\Patches.h" +#include "..\Resources\resource.h" +#include "..\Common\H2EKCommon.h" +#include "..\Common\FiloInterface.h" typedef int(__fastcall *toggle_expert_mode)(int thisptr, int __unused); toggle_expert_mode toggle_expert_mode_orginal; diff --git a/H2Codez/H2Guerilla.h b/H2Codez/H2Guerilla/H2Guerilla.h similarity index 100% rename from H2Codez/H2Guerilla.h rename to H2Codez/H2Guerilla/H2Guerilla.h diff --git a/H2Codez/H2Sapien.cpp b/H2Codez/H2Sapien/H2Sapien.cpp similarity index 98% rename from H2Codez/H2Sapien.cpp rename to H2Codez/H2Sapien/H2Sapien.cpp index 1e81497..55658bf 100644 --- a/H2Codez/H2Sapien.cpp +++ b/H2Codez/H2Sapien/H2Sapien.cpp @@ -1,15 +1,15 @@ -#include "stdafx.h" +#include "../stdafx.h" #include "H2Sapien.h" -#include "H2ToolsCommon.h" -#include "HaloScriptInterface.h" -#include "BlamBaseTypes.h" -#include "Patches.h" -#include "resource.h" +#include "..\Common\H2EKCommon.h" +#include "..\HaloScript\hs_interface.h" +#include "..\Common\BlamBaseTypes.h" +#include "..\util\Patches.h" +#include "..\Resources\resource.h" #include #include #include #include -#include "RingBuffer.h" +#include "..\util\RingBuffer.h" using namespace HaloScriptCommon; @@ -528,7 +528,7 @@ void H2SapienPatches::Init() WritePointer(0x477D40, L"%ws\n"); PatchCall(0x5783B0, print_help_to_doc); - WriteJmpTo(0x4ECC2E, &console_input_jump_hook); + WriteJmp(0x4ECC2E, &console_input_jump_hook); // replace a call to memcpy PatchCall(0x58F6AA, &console_write_hook); @@ -580,7 +580,7 @@ void H2SapienPatches::Init() WriteValue(0x008EFDB4, hs_global_table_size); // fix "game_tick_rate" - WriteJmpTo(0x006F7D60, get_tick_rate); + WriteJmp(0x006F7D60, get_tick_rate); WriteValue(0x00A5D104, sapien_defaults); diff --git a/H2Codez/H2Sapien.h b/H2Codez/H2Sapien/H2Sapien.h similarity index 100% rename from H2Codez/H2Sapien.h rename to H2Codez/H2Sapien/H2Sapien.h diff --git a/H2Codez/H2SapienTextRasterizer.h b/H2Codez/H2SapienTextRasterizer.h deleted file mode 100644 index cbdef1b..0000000 --- a/H2Codez/H2SapienTextRasterizer.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once -#include - -namespace TextRasterizer { - - struct text_rasterizer_screen_bounds - { - uint16_t y0; - uint16_t x0; - uint16_t y1; - uint16_t x1; - }; -} \ No newline at end of file diff --git a/H2Codez/H2Tool/H2Tool_Commands.cpp b/H2Codez/H2Tool/H2Tool_Commands.cpp index 10ce31b..54b3566 100644 --- a/H2Codez/H2Tool/H2Tool_Commands.cpp +++ b/H2Codez/H2Tool/H2Tool_Commands.cpp @@ -1,10 +1,17 @@ #include "stdafx.h" -#include "ToolCommandDefinitions.inl" -#include "H2Tool_extra_commands.inl" -#include "Patches.h" +#include "H2Tool\ToolCommandDefinitions.inl" +#include "H2Tool\H2Tool_extra_commands.inl" +#include "H2ToolsCommon.h" +#include "util/Patches.h" +#include "Version.h" +#include "ScenarioTag.h" +#include -//I should better leave the H2tool version i am using +using namespace HaloScriptCommon; + +//I should better mention the H2tool version i am using //tool debug pc 11081.07.04.30.0934.main Apr 30 2007 09:37:08 +//Credits to Kornmann https://bitbucket.org/KornnerStudios/opensauce-release/wiki/Home static const s_tool_command* h2tool_extra_commands[] = { @@ -18,6 +25,7 @@ static const s_tool_command* h2tool_extra_commands[] = { &import_sound, &tool_build_structure_from_jms, &h2dev_extra_commands_defination, + &list_extra_commands, }; @@ -56,43 +64,639 @@ void _H2ToolDetachHooks() // DetourDetach(&(PVOID&)psquadsettings,h_SquadSettings); return; } +#pragma region structure_import Tweeks +void H2ToolPatches::Increase_structure_import_size_Check() +{ + //if ( FileSize.LowPart > 0x1400000 && !FileSize.HighPart ) + ///1400000h = 20971520 BYTES ~ 20 MB + +/* +.text:0041F836 C90 cmp dword ptr [esp+0C90h+FileSize], 1400000h ; Compare Two Operands <-Change This Size +.text:0041F83E C90 jbe loc_41F8D9 ; Jump if Below or Equal (CF=1 | ZF=1) +.text:0041F83E +.text:0041F844 C90 cmp dword ptr [esp+0C90h+FileSize+4], ebx ; Compare Two Operands +.text:0041F848 C90 jnz loc_41F8D9 +*/ + + + //increasing the 20 MB File Import Check + DWORD new_size = 0x1400000 * TOOL_INCREASE_FACTOR; ///671.08864 MB + WriteValue(0x41F836 + 4, new_size); + + // push + // TODO: check this + // WriteValue(0x589183 + 1, new_size); +} +void H2ToolPatches::structure_bsp_geometry_collision_check_increase() +{ +//return collision_surfaces_count <= 0x7FFF && edges_count <= 0xFFFF && collision_vertices_count <= 0xFFFF; + ///0x7FFF = 32767 + ///0xFFFF = 65535 +/* +.text:005A2D50 000 cmp [esp+collision_surfaces_count], 7FFFh ; Compare Two Operands +.text:005A2D58 000 jg short loc_5A2D6E ; Jump if Greater (ZF=0 & SF=OF) +.text:005A2D58 +.text:005A2D5A 000 mov eax, 0FFFFh +.text:005A2D5F 000 cmp [esp+a2], eax +*/ + //increasing the collision_surfaces_count + DWORD collision_surfaces_count = 0x7FFF * TOOL_INCREASE_FACTOR; /// 0xFFFE0 + WriteValue(0x5A2D50 + 4, collision_surfaces_count); + + + //increasing the edges_vertices_count + DWORD edges_vertices_count = 0xFFFF * TOOL_INCREASE_FACTOR; /// 0x1FFFE0 + WriteValue(0x5A2D5A + 1, edges_vertices_count); + + ///Also Patching in the error_proc method incase we ever hit this Limit :) +/* +.text:00464C50 118 push 0FFFFh +.text:00464C55 11C push eax +.text:00464C56 120 push 0FFFFh +.text:00464C5B 124 push ecx +.text:00464C5C 128 push 7FFFh +*/ + WriteValue(0x464C50 + 1, edges_vertices_count); + WriteValue(0x464C56 + 1, edges_vertices_count); + WriteValue(0x464C5C + 1, collision_surfaces_count); -void H2Tool_Extras::Increase_structure_size_Check() + +} +void H2ToolPatches::structure_bsp_geometry_3D_check_increase() { + // return nodes_count < &unk_800000 && planes_count < 0x8000 && leaves_count < &unk_800000; + /// planes_count =0x8000 = 32768 +/* +.text:005A2CFB 000 cmp [esp+planes_count], 32768 ; Compare Two Operands +.text:005A2D03 000 jge short loc_5A2D0E ; Jump if Greater or Equal (SF=OF) +.text:005A2D03 +*/ + ////increasing the planes_count Check + DWORD new_planes_count = 0x8000 *TOOL_INCREASE_FACTOR; /// 0x100000 + WriteValue(0x5A2CFB + 4, new_planes_count); - BYTE Size_Patch[4] = { 0xF2,0xF2,0xF2,0x0F }; +} +void H2ToolPatches::structure_bsp_geometry_2D_check_increase() +{ +/* +.text:00464BA5 118 push 0 <- b_DONT_CHECK variable is set to false by default .Need to make it true +.text:00464BA7 11C push ecx +.text:00464BA8 120 push edx +.text:00464BA9 124 call collision_bsp_2d_vertex_check ; Call Procedure +*/ + WriteBytes(0x464BA5 + 1, new BYTE{1}, 1); + + //No Need to modify the Proc error here cuz it will never hit :) +} - WriteBytesASM(0x41F83A, Size_Patch, 4); +static const int BSP_MAX_DEPTH = 512; +static const int function_epilog = 0x00465797; +static void __declspec(naked) bsp_depth_check() +{ + __asm { + add eax, 1 + cmp eax, BSP_MAX_DEPTH + jle continue_compile + jmp abort_with_error + + continue_compile: + // remove return address + pop eax + // push function epilog for ret + push function_epilog + ret + + + abort_with_error: + ret + } } -void H2Tool_Extras::Enable_sp_map_compiling() +void structure_bsp_depth_check_increase() { + // remove old check + NopFill(0x00465726, 0xA); + // write call to our check + WriteCall(0x00465726, bsp_depth_check); } -void H2Tool_Extras::Initialize() +void H2ToolPatches::Increase_structure_bsp_geometry_check() { - H2PCTool.WriteLog("Dll Successfully Injected to H2Tool"); + H2PCTool.WriteLog("Increasing structure_bsp_geometry checks"); + structure_bsp_geometry_2D_check_increase(); + structure_bsp_geometry_3D_check_increase(); + structure_bsp_geometry_collision_check_increase(); + structure_bsp_depth_check_increase(); +} + +#pragma endregion + +#pragma region Shared_tag_removal_scheme +//A reference to H2EK_OS tools SansSharing.inl +/* +* shared tag scheme removal changes + +.text:005887DF push 1 ; CHANGE THIS TO FALSE +.text:005887E1 mov esi, eax +.text:005887E3 call _postprocess_animation_data + +.text:00588C21 push 1 ; CHANGE THIS TO FALSE +.text:00588C23 push edx +.text:00588C24 mov esi, eax +.text:00588C26 call _build_cache_file_prepare_sound_gestalt + +.text:00588D52 push 1 ; CHANGE THIS TO FALSE +.text:00588D54 push 0 +.text:00588D56 push 0 +.text:00588D58 push 0 +.text:00588D5A lea edx, [esp+1F94h+multiplayer_shared_dependency_graph] +.text:00588D61 mov esi, eax +.text:00588D63 push edx +.text:00588D64 lea eax, [esp+1F98h+cache_header] +.text:00588D6B push eax +.text:00588D6C lea edx, [esp+1F9Ch+scenario_name_wide] +.text:00588D70 call _build_cache_file_add_tags ; ecx = s_shared_tag_index + +.text:00588DCD push 1 ; CHANGE THIS TO FALSE +.text:00588DCF mov ecx, edi +.text:00588DD1 mov esi, eax +.text:00588DD3 call _build_cache_file_add_sound_samples + +.text:00588E37 push 1 ; CHANGE THIS TO FALSE +.text:00588E39 push ecx +.text:00588E3A mov esi, eax +.text:00588E3C call _build_cache_file_sound_gestalt + +.text:00588E99 push 1 ; CHANGE THIS TO FALSE +.text:00588E9B lea edx, [esp+1F88h+cache_header] +.text:00588EA2 push edx +.text:00588EA3 push edi +.text:00588EA4 mov esi, eax +.text:00588EA6 call _build_cache_file_add_geometry_blocks + +.text:0058908E push 1 ; CHANGE THIS TO FALSE +.text:00589090 mov esi, eax +.text:00589092 call _language_packing + +.text:005890A7 push 1 ; CHANGE THIS TO FALSE +.text:005890A9 push ecx +.text:005890AA call _build_cache_file_add_language_packs + +.text:00589105 push 1 ; CHANGE THIS TO FALSE +.text:00589107 push edi +.text:00589108 mov esi, eax +.text:0058910A call _build_cache_file_add_bitmap_pixels + +.text:00589181 push 1 ; CHANGE THIS TO FALSE +.text:00589183 push 1400000h ; base address +.text:00589188 push edx +.text:00589189 mov esi, eax +.text:0058918B push edi +.text:0058918C lea eax, [esp+1F94h+multiplayer_shared_dependency_graph] +.text:00589193 push eax +.text:00589194 lea ecx, [esp+1F98h+cache_header] +.text:0058919B push ecx +.text:0058919C mov ecx, [esp+1F9Ch+multiplayer_shared_tag_index_sorted] +.text:005891A0 lea edx, [esp+1F9Ch+scenario_name_wide] +.text:005891A4 call _build_cache_file_add_tags ; ecx = s_shared_tag_index + +*/ + +#pragma endregion + +void H2ToolPatches::apply_shared_tag_removal_scheme() +{ + BYTE* patching_offsets_list[] = { + CAST_PTR(BYTE*, 0x5887DF),//_postprocess_animation_data + CAST_PTR(BYTE*, 0x588C21),//_build_cache_file_prepare_sound_gestalt + CAST_PTR(BYTE*, 0x588D52),//_build_cache_file_add_tags + CAST_PTR(BYTE*, 0x588DCD),//_build_cache_file_add_sound_samples + CAST_PTR(BYTE*, 0x588E37),//_build_cache_file_sound_gestalt + CAST_PTR(BYTE *,0x588E99),//_build_cache_file_add_geometry_blocks + CAST_PTR(BYTE *,0x58908E),//_language_packing + CAST_PTR(BYTE *,0x5890A7),//_build_cache_file_add_language_packs + CAST_PTR(BYTE *,0x589105),//_build_cache_file_add_bitmap_pixels + CAST_PTR(BYTE *,0x589181),//_build_cache_file_add_tags + }; + + BYTE patch[1] = { 0x0 }; + for (int x = 0; x < NUMBEROF(patching_offsets_list); x++) WriteBytes((DWORD)(patching_offsets_list[x] + 1), patch, 1);//patching push 1 -> push 0 +} + +void H2ToolPatches::unlock_other_scenario_types_compiling() +{ + //Refer to H2EK_OpenSauce Campaign_sharing + static void* BUILD_CACHE_FILE_FOR_SCENARIO__CHECK_SCENARIO_TYPE = CAST_PTR(void*,0x588320); + BYTE patch[1] = {0xEB}; + WriteBytes((DWORD)BUILD_CACHE_FILE_FOR_SCENARIO__CHECK_SCENARIO_TYPE, patch, 1);//change jz to jmp + +} + +static signed long _scenario_type; + +static void __declspec(naked) _build_cache_file_for_scenario__intercept_get_scenario_type() +{ + //Refer to H2EK_OpenSauce Campaign_sharing + //Basically this function helps us to store the scenario_type which can be used in later areas + static const unsigned __int32 INTERCEPTOR_EXIT = 0x588313; + + __asm { + movsx edx, word ptr[eax + 0x1C] + push esi + mov[esp + 0x58], edx // mov [esp+1F90h+scenario_type], edx + mov _scenario_type, edx + jmp INTERCEPTOR_EXIT + } +} + +const static wchar_t *campaign_shared_path = L"maps\\single_player_shared.map"; +const static char *load_sharing_log_messages[] = +{ + "tag sharing: loading tag names from single_player_shared.map", + "tag sharing: failed to open singleplayer shared map file", + "singleplayer shared cache file doesn't have its string table!! AAAAaaaaggghh!!!", + "singleplayer shared cache file string count is suspect (> 0x6000)", + "singleplayer shared cache file doesn't have its tag dependency graph!! AAAAaaaaggghh!!!", + "singleplayer shared cache file tag dependency graph size is suspect (> 0x100000)", + "tag sharing: ruh roh, single_player_shared.map has no shared tags" + +}; + +const static int load_sharing_log_offsets[] = +{ + 0x005813E7, + 0x00581499, + 0x005814B7, + 0x005818FF, + 0x00581587, + 0x005818EB, + 0x005817CD +}; + +static char __cdecl h_BUILD_CACHE_FILE_FOR_SCENARIO__TAG_SHARING_LOAD_SHARED(void *a1, void* a2) +{ + //Refer to H2EK_OpenSauce Campaign_sharing + + // If scenario_type is single_player,modify the strings + if (_scenario_type == 0) + { + // Replace file name strings + WritePointer(0x581455, campaign_shared_path); + WritePointer(0x581480, campaign_shared_path); + + // fix log strings to match + for (int i = 0; i < ARRAYSIZE(load_sharing_log_offsets); i++) + WritePointer(load_sharing_log_offsets[i] + 1, load_sharing_log_messages[i]); + } + H2PCTool.WriteLog("loading....tag_sharing method"); + + + DWORD TAG_SHARING_LOAD_MULTIPLAYER_SHARED = 0x5813C0; + return ((char(__cdecl *)(void*, void*))TAG_SHARING_LOAD_MULTIPLAYER_SHARED)(a1,a2);// call Function via address + +} +void H2ToolPatches::render_model_import_unlock() +{ + //Patches the h2tool to use the custom render_model_generation methods + + ///Patch Details::#1 patching the orignal render_model_generate function to call mine + /* + .text:0041C7A0 000 mov eax, [esp+arguments] + .text:0041C7A4 000 mov ecx, [eax] + .text:0041C7A6 000 jmp loc_41C4A0 ; Jump + */ + PatchCall(0x41C7A6, h2pc_import_render_model_proc); +} + +void H2ToolPatches::enable_campaign_tags_sharing() +{ + //Refer to H2EK_OpenSauce Campaign_sharing + + void* BUILD_CACHE_FILE_FOR_SCENARIO__GET_SCENARIO_TYPE = CAST_PTR(void*, 0x58830A); + int BUILD_CACHE_FILE_FOR_SCENARIO__TAG_SHARING_LOAD_SHARED = 0x5883DE; + + /* + //get_scenario_ Intercept codes + BYTE patch[1] = { 0xE8}; + + //Writing a call in memory to jmp to our function + WriteBytesASM((DWORD)BUILD_CACHE_FILE_FOR_SCENARIO__GET_SCENARIO_TYPE, patch, 1); + PatchCall((DWORD)BUILD_CACHE_FILE_FOR_SCENARIO__GET_SCENARIO_TYPE, (DWORD)_build_cache_file_for_scenario__intercept_get_scenario_type);//Writing the address to be jumped + */ + WriteJmp(BUILD_CACHE_FILE_FOR_SCENARIO__GET_SCENARIO_TYPE, _build_cache_file_for_scenario__intercept_get_scenario_type); + + + //single_player_shared sharing + + //.text:005883DE call BUILD_CACHE_FILE_FOR_SCENARIO__TAG_SHARING_LOAD_SHARED ; STR: "tag sharing: loading tag names from shared.map", "tag sharing: + PatchCall(BUILD_CACHE_FILE_FOR_SCENARIO__TAG_SHARING_LOAD_SHARED, h_BUILD_CACHE_FILE_FOR_SCENARIO__TAG_SHARING_LOAD_SHARED);//modifying the call to go to my h_function rather orignal + + H2PCTool.WriteLog("Single Player tag_sharing enabled"); +} + +void H2ToolPatches::remove_bsp_version_check() +{ + // allow tool to work with BSPs compliled by newer versions of tool. + // downgrades the error you would get to a non-fatal one. + BYTE bsp_version_check_return[] = { 0xB0, 0x01 }; + WriteBytes(0x00545D0F, bsp_version_check_return, sizeof(bsp_version_check_return)); +} + +void H2ToolPatches::disable_secure_file_locking() +{ + // allow other processes to read files open with fopen_s + WriteValue(0x0074DDD6 + 1, _SH_DENYWR); +} + +hs_convert_data_store *hs_get_converter_data_store(unsigned __int16 handle) +{ + typedef void* (__cdecl *get_args)(int a1, unsigned __int16 a2); + get_args get_args_impl = reinterpret_cast(0x00557E60); + return static_cast(get_args_impl(*reinterpret_cast(0xBCBF4C), handle)); +} + +const char *hs_get_string_data(hs_convert_data_store *data_store) +{ + const char *hs_string_data = *reinterpret_cast(0x00CDB198); + return &hs_string_data[data_store->string_value_offset]; +} + +char hs_error[0x1024]; + +void hs_converter_error(hs_convert_data_store *data_store, const std::string &error) +{ + const char **hs_error_string_ptr = reinterpret_cast(0x00CDB1AC); + DWORD *hs_error_offset_ptr = reinterpret_cast(0x00CDB1B0); + + strncpy(hs_error, error.c_str(), sizeof(hs_error)); + + *hs_error_string_ptr = hs_error; + *hs_error_offset_ptr = data_store->string_value_offset; + data_store->output = NONE; +} + +scnr_tag *get_global_scenario() +{ + return *reinterpret_cast(0x00AA00E4); +} + +void hs_convert_string_id_to_tagblock_offset(tag_block_ref *tag_block, int element_size, int block_offset, int hs_converter_id) +{ + auto data_store = hs_get_converter_data_store(hs_converter_id); + const char *value_string = hs_get_string_data(data_store); + + data_store->output = FIND_TAG_BLOCK_STRING_ID(tag_block, element_size, block_offset, GET_STRING_ID(value_string)); + + if (data_store->output == NONE) { + std::string error = "this is not a valid '" + hs_type_string[static_cast(data_store->target_hs_type)] + "' name, check tags"; + hs_converter_error(data_store, error); + } +} + +void hs_convert_string_to_tagblock_offset(tag_block_ref *tag_block, int element_size, int block_offset, int hs_converter_id) +{ + auto data_store = hs_get_converter_data_store(hs_converter_id); + const char *value_string = hs_get_string_data(data_store); + + data_store->output = FIND_TAG_BLOCK_STRING(tag_block, element_size, block_offset, value_string); + + if (data_store->output == NONE) { + std::string error = "this is not a valid '" + hs_type_string[static_cast(data_store->target_hs_type)] + "' name, check tags"; + hs_converter_error(data_store, error); + } +} + +char __cdecl hs_convert_conversation(unsigned __int16 a1) +{ + scnr_tag *scenario = get_global_scenario(); + hs_convert_string_to_tagblock_offset(&scenario->aIConversations, 128, 0, a1); + return 1; +} + +char __cdecl hs_convert_internal_id_passthrough(unsigned __int16 a1) +{ + hs_convert_data_store *data_store = hs_get_converter_data_store(a1); + const char *input_string = hs_get_string_data(data_store); + if (!_stricmp(input_string, "NONE")) { + data_store->output = NONE; + return 1; + } + try { + data_store->output = std::stoi(input_string, nullptr, 0); + return 1; + } + catch (invalid_argument) { + hs_converter_error(data_store, "invalid " + get_hs_type_string(data_store->target_hs_type) + " ID"); + return 0; + } + catch (out_of_range) + { + hs_converter_error(data_store, get_hs_type_string(data_store->target_hs_type) + " ID out of range"); + return 0; + } +} + +char __cdecl hs_convert_ai_behaviour(unsigned __int16 a1) +{ + hs_convert_data_store *data_store = hs_get_converter_data_store(a1); + const std::string input = hs_get_string_data(data_store); + ai_behaviour out = string_to_ai_behaviour(input); + if (out != ai_behaviour::invalid) { + data_store->output = static_cast(out); + return 1; + } else { + hs_converter_error(data_store, "Invalid AI behaviour"); + return 0; + } +} + +char __cdecl hs_convert_ai_orders(unsigned __int16 a1) +{ + scnr_tag *scenario = get_global_scenario(); + hs_convert_string_to_tagblock_offset(&scenario->orders, 144, 0, a1); + return 1; +} + +enum ai_id_type +{ + squad, + squad_group, + unknown, + starting_location, + + none = NONE +}; + +char __cdecl hs_convert_ai(unsigned __int16 a1) +{ + scnr_tag *scenario = get_global_scenario(); + hs_convert_data_store *data_store = hs_get_converter_data_store(a1); + std::string input_string = hs_get_string_data(data_store); + + ai_id_type ai_type = ai_id_type::none; + + DWORD main_index = NONE; + DWORD secondary_index = 0; + + if (input_string.find('/') != string::npos) { + ai_type = ai_id_type::starting_location; + std::string squad_name = input_string.substr(0, input_string.find('/')); + std::string squad_pos = input_string.substr(input_string.find('/') + 1); + + secondary_index = FIND_TAG_BLOCK_STRING(&scenario->squads, 120, 0, squad_name); + if (secondary_index != NONE) + { + // can't get the sqaud block struct working so this is a workaround for now + main_index = strtol(squad_pos.c_str(), nullptr, 0); + } else { + hs_converter_error(data_store, "No such squad."); + return 0; + } + } else { + + ai_type = ai_id_type::squad; + // attempt to find a squad with that name first + main_index = FIND_TAG_BLOCK_STRING(&scenario->squads, 120, 0, input_string); + if (main_index == NONE) { + // if no sqaud with that name exists try the sqaud groups + ai_type = ai_id_type::squad_group; + main_index = FIND_TAG_BLOCK_STRING(&scenario->squadGroups, 36, 0, input_string); + } + } + if (main_index != NONE) { + DWORD id = (ai_type << 30) | (secondary_index << 16) | main_index; + data_store->output = id; + return 1; + } else { + // fallback to passthrough for backwards compatibility and AI squad starting locations + return hs_convert_internal_id_passthrough(a1); + } +} + +#define set_hs_converter(type, func) \ + hs_convert_lookup_table[static_cast(type)] = func; + +void fix_hs_converters() +{ + void **hs_convert_lookup_table = reinterpret_cast(0x009F0C88); + set_hs_converter(hs_type::ai_behavior, hs_convert_ai_behaviour); + set_hs_converter(hs_type::conversation, hs_convert_conversation); + set_hs_converter(hs_type::ai_orders, hs_convert_ai_orders); + set_hs_converter(hs_type::ai, hs_convert_ai); + + // hacky workaround, lets the user directly input the ID it's meant to generate. + hs_type passthrough_types[] = { + hs_type::style, hs_type::hud_message, + hs_type::navpoint, hs_type::point_reference, + hs_type::ai_command_list + }; + + for (auto i : passthrough_types) + set_hs_converter(i, hs_convert_internal_id_passthrough); +} + +#undef set_hs_converter - this->Increase_structure_size_Check(); - this->AddExtraCommands(); +void HaloScriptExtend() +{ + + hs_command **command_table = reinterpret_cast(0x009ECFE0); + hs_global_variable **global_table = reinterpret_cast(0x009EFF78); + g_halo_script_interface->init_custom(command_table, global_table); + + // Replace pointers to the commmand table + static DWORD cmd_offsets[] = + { + 0x005C5365 + 3, 0x005C5530 + 3, 0x005C5554 + 3, + 0x005C5821 + 3, 0x005C5C44 + 3, 0x005C5E64 + 3, + 0x005C5E9A + 3, 0x005C5F48 + 3 + }; + + hs_command **cmds = g_halo_script_interface->get_command_table(); + + for (DWORD addr : cmd_offsets) + WritePointer(addr, cmds); + + // patch command table size + const static int hs_cmd_table_size = g_halo_script_interface->get_command_table_size(); + WriteValue(0x008CD59C, hs_cmd_table_size); + + // Replace pointers to the globals table + static DWORD var_offsets[] = + { + 0x005C53D5, 0x005C53F0, 0x005C5430, + 0x005C5474, 0x005C58D1, 0x006884A1, + 0x006884BD, 0x0068850D, 0x0068858B, + 0x006885A2 + }; + + hs_global_variable **vars = g_halo_script_interface->get_global_table(); + + for (DWORD addr : var_offsets) + WritePointer(addr + 3, vars); + + // patch globals table size + const static int hs_global_table_size = g_halo_script_interface->get_global_table_size(); + WriteValue(0x008D2238, hs_global_table_size); +} + +LPWSTR __crtGetCommandLineW_hook() +{ + typedef LPWSTR (*__crtGetCommandLineW_t)(); + __crtGetCommandLineW_t __crtGetCommandLineW_impl = reinterpret_cast<__crtGetCommandLineW_t>(0x00764EB3); + + wchar_t *real_cmd = __crtGetCommandLineW_impl(); + std::wstring fake_cmd = std::regex_replace(real_cmd, std::wregex(L"( pause_after_run| shared_tag_removal)"), L""); + wcscpy(real_cmd, fake_cmd.c_str()); + return real_cmd; +} + +void H2ToolPatches::fix_command_line() +{ + PatchCall(0x00751F83, __crtGetCommandLineW_hook); +} + +void H2ToolPatches::Initialize() +{ + H2PCTool.WriteLog("Dll Successfully Injected to H2Tool"); + wcout << "H2Toolz version: " << version << std::endl + << "Built on " __DATE__ " at " __TIME__ << std::endl; + + Increase_structure_import_size_Check(); + Increase_structure_bsp_geometry_check(); + AddExtraCommands(); + unlock_other_scenario_types_compiling(); + render_model_import_unlock(); + remove_bsp_version_check(); + disable_secure_file_locking(); + fix_hs_converters(); + HaloScriptExtend(); + fix_command_line(); + //enable_campaign_tags_sharing(); // Still crashes might need tag changes. + + std::string cmd = GetCommandLineA(); + if (cmd.find("shared_tag_removal") != string::npos) + apply_shared_tag_removal_scheme(); + } -void H2Tool_Extras::AddExtraCommands() + +void H2ToolPatches::AddExtraCommands() { H2PCTool.WriteLog("Adding Extra Commands to H2Tool"); #pragma region New Function Defination Creation - BYTE k_number_of_tool_commands = 0xC; - BYTE k_number_of_tool_commands_new = 0xC + NUMBEROF(h2tool_extra_commands); + static const BYTE k_number_of_tool_commands = 0xC; + static const BYTE k_number_of_tool_commands_new = k_number_of_tool_commands + NUMBEROF(h2tool_extra_commands); // Tool's original tool commands static const s_tool_command* const* tool_import_classes = CAST_PTR(s_tool_command**, 0x97B6EC); // The new tool commands list which is made up of tool's // and [yelo_extra_tool_commands] - static s_tool_command* tool_commands[0xC + NUMBEROF(h2tool_extra_commands)]; + static s_tool_command* tool_commands[k_number_of_tool_commands_new]; // copy official tool commands memcpy_s(tool_commands, sizeof(tool_commands), @@ -106,30 +710,19 @@ void H2Tool_Extras::AddExtraCommands() #pragma endregion #pragma region UpdateTool_function References - static s_tool_command*** tool_commands_references[] = { - CAST_PTR(s_tool_command***, 0x410596), - CAST_PTR(s_tool_command***, 0x41060E), - CAST_PTR(s_tool_command***, 0x412D86), + DWORD tool_commands_references[] = { + 0x410596, + 0x41060E, + 0x412D86, }; - static BYTE* tool_commands_count[] = { - CAST_PTR(BYTE*, 0x4105E5), - CAST_PTR(BYTE*, 0x412D99), + DWORD tool_commands_count[] = { + 0x4105E5, + 0x412D99, }; // update references to the tool command definitions - - DWORD new_tool_defination_Table_address = (DWORD)&tool_commands[0]; - - H2PCTool.WriteLog("New Tool_Definations Addy : %0X", new_tool_defination_Table_address); - - DWORD c = new_tool_defination_Table_address; - BYTE *f = (BYTE*)(&c); - BYTE Reference_Patch[4] = { f[0],f[1],f[2],f[3] };//move to ecx - - - H2PCTool.WriteLog("Reversed : %0X %0X %0X %0X", f[0], f[1], f[2], f[3]); - - for (int x = 0; x < NUMBEROF(tool_commands_references); x++) WriteBytesASM((DWORD)tool_commands_references[x], Reference_Patch, 4); + for (int x = 0; x < NUMBEROF(tool_commands_references); x++) + WriteValue(tool_commands_references[x], tool_commands); @@ -137,16 +730,8 @@ void H2Tool_Extras::AddExtraCommands() #pragma region UpdateTool_functionCount References // update code which contain the tool command definitions count - - - BYTE Count_Patch[1] = { k_number_of_tool_commands_new }; // cmp si, 0Ch - - - for (int x = 0; x < NUMBEROF(tool_commands_count); x++) WriteBytesASM((DWORD)tool_commands_count[x], Count_Patch, 1); - - - - + for (int x = 0; x < NUMBEROF(tool_commands_count); x++) + WriteValue(tool_commands_count[x], k_number_of_tool_commands_new); #pragma endregion -} \ No newline at end of file +} diff --git a/H2Codez/H2Tool_Commands.cpp b/H2Codez/H2Tool_Commands.cpp deleted file mode 100644 index 46f2c41..0000000 --- a/H2Codez/H2Tool_Commands.cpp +++ /dev/null @@ -1,737 +0,0 @@ -#include "stdafx.h" -#include "H2Tool\ToolCommandDefinitions.inl" -#include "H2Tool\H2Tool_extra_commands.inl" -#include "H2ToolsCommon.h" -#include "Patches.h" -#include "Version.h" -#include "ScenarioTag.h" -#include - -using namespace HaloScriptCommon; - -//I should better mention the H2tool version i am using -//tool debug pc 11081.07.04.30.0934.main Apr 30 2007 09:37:08 -//Credits to Kornmann https://bitbucket.org/KornnerStudios/opensauce-release/wiki/Home - - -static const s_tool_command* h2tool_extra_commands[] = { - &import_model_render, - &import_model_collision, - &import_model_physics, - &import_model, - &import_model_animations, - import_class_monitor_structures, - import_class_monitor_bitmaps, - &import_sound, - &tool_build_structure_from_jms, - &h2dev_extra_commands_defination, - &list_extra_commands, - -}; - -int __cdecl s_tool_command_compare(void *, const void* lhs, const void* rhs) -{ - const s_tool_command* _lhs = *CAST_PTR(const s_tool_command* const*, lhs); - const s_tool_command* _rhs = *CAST_PTR(const s_tool_command* const*, rhs); - - const wchar_t* l = _lhs->name; - const wchar_t* r = _rhs->name; - if (l[0] == L'~') l++; - if (r[0] == L'~') r++; - - return _wcsicmp(l, r); -} - -void _H2ToolAttachHooks() -{ - DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); - - - // DetourAttach(&(PVOID&)pPlayerSpeed,OnPlayerSpeed); - - // DetourAttach(&(PVOID&)pcreatechar,h_CreateCharacter); - //DetourAttach(&(PVOID&)pXYZ, h_XYZUpdate); - - - DetourTransactionCommit(); - return; -} -void _H2ToolDetachHooks() -{ - //DetourDetach(&(PVOID&)pgameoptions,h_GetGameOptions); - // DetourDetach(&(PVOID&)pMapSelect,h_MPMapSelect); - // DetourDetach(&(PVOID&)psquadsettings,h_SquadSettings); - return; -} -#pragma region structure_import Tweeks -void H2ToolPatches::Increase_structure_import_size_Check() -{ - //if ( FileSize.LowPart > 0x1400000 && !FileSize.HighPart ) - ///1400000h = 20971520 BYTES ~ 20 MB - -/* -.text:0041F836 C90 cmp dword ptr [esp+0C90h+FileSize], 1400000h ; Compare Two Operands <-Change This Size -.text:0041F83E C90 jbe loc_41F8D9 ; Jump if Below or Equal (CF=1 | ZF=1) -.text:0041F83E -.text:0041F844 C90 cmp dword ptr [esp+0C90h+FileSize+4], ebx ; Compare Two Operands -.text:0041F848 C90 jnz loc_41F8D9 -*/ - - - //increasing the 20 MB File Import Check - DWORD new_size = 0x1400000 * TOOL_INCREASE_FACTOR; ///671.08864 MB - WriteValue(0x41F836 + 4, new_size); - - // push - // TODO: check this - // WriteValue(0x589183 + 1, new_size); -} -void H2ToolPatches::structure_bsp_geometry_collision_check_increase() -{ -//return collision_surfaces_count <= 0x7FFF && edges_count <= 0xFFFF && collision_vertices_count <= 0xFFFF; - ///0x7FFF = 32767 - ///0xFFFF = 65535 -/* -.text:005A2D50 000 cmp [esp+collision_surfaces_count], 7FFFh ; Compare Two Operands -.text:005A2D58 000 jg short loc_5A2D6E ; Jump if Greater (ZF=0 & SF=OF) -.text:005A2D58 -.text:005A2D5A 000 mov eax, 0FFFFh -.text:005A2D5F 000 cmp [esp+a2], eax -*/ - //increasing the collision_surfaces_count - DWORD collision_surfaces_count = 0x7FFF * TOOL_INCREASE_FACTOR; /// 0xFFFE0 - WriteValue(0x5A2D50 + 4, collision_surfaces_count); - - - //increasing the edges_vertices_count - DWORD edges_vertices_count = 0xFFFF * TOOL_INCREASE_FACTOR; /// 0x1FFFE0 - WriteValue(0x5A2D5A + 1, edges_vertices_count); - - ///Also Patching in the error_proc method incase we ever hit this Limit :) -/* -.text:00464C50 118 push 0FFFFh -.text:00464C55 11C push eax -.text:00464C56 120 push 0FFFFh -.text:00464C5B 124 push ecx -.text:00464C5C 128 push 7FFFh -*/ - WriteValue(0x464C50 + 1, edges_vertices_count); - WriteValue(0x464C56 + 1, edges_vertices_count); - WriteValue(0x464C5C + 1, collision_surfaces_count); - - -} -void H2ToolPatches::structure_bsp_geometry_3D_check_increase() -{ - // return nodes_count < &unk_800000 && planes_count < 0x8000 && leaves_count < &unk_800000; - /// planes_count =0x8000 = 32768 -/* -.text:005A2CFB 000 cmp [esp+planes_count], 32768 ; Compare Two Operands -.text:005A2D03 000 jge short loc_5A2D0E ; Jump if Greater or Equal (SF=OF) -.text:005A2D03 -*/ - ////increasing the planes_count Check - DWORD new_planes_count = 0x8000 *TOOL_INCREASE_FACTOR; /// 0x100000 - WriteValue(0x5A2CFB + 4, new_planes_count); - -} -void H2ToolPatches::structure_bsp_geometry_2D_check_increase() -{ -/* -.text:00464BA5 118 push 0 <- b_DONT_CHECK variable is set to false by default .Need to make it true -.text:00464BA7 11C push ecx -.text:00464BA8 120 push edx -.text:00464BA9 124 call collision_bsp_2d_vertex_check ; Call Procedure -*/ - WriteBytes(0x464BA5 + 1, new BYTE{1}, 1); - - //No Need to modify the Proc error here cuz it will never hit :) -} - -static const int BSP_MAX_DEPTH = 512; - -static const int function_epilog = 0x00465797; -static void __declspec(naked) bsp_depth_check() -{ - __asm { - add eax, 1 - cmp eax, BSP_MAX_DEPTH - jle continue_compile - jmp abort_with_error - - continue_compile: - // remove return address - pop eax - // push function epilog for ret - push function_epilog - ret - - - abort_with_error: - ret - } -} - -void structure_bsp_depth_check_increase() -{ - // remove old check - NopFill(0x00465726, 0xA); - - // write call to our check - WriteCallTo(0x00465726, bsp_depth_check); -} - -void H2ToolPatches::Increase_structure_bsp_geometry_check() -{ - H2PCTool.WriteLog("Increasing structure_bsp_geometry checks"); - structure_bsp_geometry_2D_check_increase(); - structure_bsp_geometry_3D_check_increase(); - structure_bsp_geometry_collision_check_increase(); - structure_bsp_depth_check_increase(); -} - -#pragma endregion - -#pragma region Shared_tag_removal_scheme -//A reference to H2EK_OS tools SansSharing.inl -/* -* shared tag scheme removal changes - -.text:005887DF push 1 ; CHANGE THIS TO FALSE -.text:005887E1 mov esi, eax -.text:005887E3 call _postprocess_animation_data - -.text:00588C21 push 1 ; CHANGE THIS TO FALSE -.text:00588C23 push edx -.text:00588C24 mov esi, eax -.text:00588C26 call _build_cache_file_prepare_sound_gestalt - -.text:00588D52 push 1 ; CHANGE THIS TO FALSE -.text:00588D54 push 0 -.text:00588D56 push 0 -.text:00588D58 push 0 -.text:00588D5A lea edx, [esp+1F94h+multiplayer_shared_dependency_graph] -.text:00588D61 mov esi, eax -.text:00588D63 push edx -.text:00588D64 lea eax, [esp+1F98h+cache_header] -.text:00588D6B push eax -.text:00588D6C lea edx, [esp+1F9Ch+scenario_name_wide] -.text:00588D70 call _build_cache_file_add_tags ; ecx = s_shared_tag_index - -.text:00588DCD push 1 ; CHANGE THIS TO FALSE -.text:00588DCF mov ecx, edi -.text:00588DD1 mov esi, eax -.text:00588DD3 call _build_cache_file_add_sound_samples - -.text:00588E37 push 1 ; CHANGE THIS TO FALSE -.text:00588E39 push ecx -.text:00588E3A mov esi, eax -.text:00588E3C call _build_cache_file_sound_gestalt - -.text:00588E99 push 1 ; CHANGE THIS TO FALSE -.text:00588E9B lea edx, [esp+1F88h+cache_header] -.text:00588EA2 push edx -.text:00588EA3 push edi -.text:00588EA4 mov esi, eax -.text:00588EA6 call _build_cache_file_add_geometry_blocks - -.text:0058908E push 1 ; CHANGE THIS TO FALSE -.text:00589090 mov esi, eax -.text:00589092 call _language_packing - -.text:005890A7 push 1 ; CHANGE THIS TO FALSE -.text:005890A9 push ecx -.text:005890AA call _build_cache_file_add_language_packs - -.text:00589105 push 1 ; CHANGE THIS TO FALSE -.text:00589107 push edi -.text:00589108 mov esi, eax -.text:0058910A call _build_cache_file_add_bitmap_pixels - -.text:00589181 push 1 ; CHANGE THIS TO FALSE -.text:00589183 push 1400000h ; base address -.text:00589188 push edx -.text:00589189 mov esi, eax -.text:0058918B push edi -.text:0058918C lea eax, [esp+1F94h+multiplayer_shared_dependency_graph] -.text:00589193 push eax -.text:00589194 lea ecx, [esp+1F98h+cache_header] -.text:0058919B push ecx -.text:0058919C mov ecx, [esp+1F9Ch+multiplayer_shared_tag_index_sorted] -.text:005891A0 lea edx, [esp+1F9Ch+scenario_name_wide] -.text:005891A4 call _build_cache_file_add_tags ; ecx = s_shared_tag_index - -*/ - -#pragma endregion - -void H2ToolPatches::apply_shared_tag_removal_scheme() -{ - BYTE* patching_offsets_list[] = { - CAST_PTR(BYTE*, 0x5887DF),//_postprocess_animation_data - CAST_PTR(BYTE*, 0x588C21),//_build_cache_file_prepare_sound_gestalt - CAST_PTR(BYTE*, 0x588D52),//_build_cache_file_add_tags - CAST_PTR(BYTE*, 0x588DCD),//_build_cache_file_add_sound_samples - CAST_PTR(BYTE*, 0x588E37),//_build_cache_file_sound_gestalt - CAST_PTR(BYTE *,0x588E99),//_build_cache_file_add_geometry_blocks - CAST_PTR(BYTE *,0x58908E),//_language_packing - CAST_PTR(BYTE *,0x5890A7),//_build_cache_file_add_language_packs - CAST_PTR(BYTE *,0x589105),//_build_cache_file_add_bitmap_pixels - CAST_PTR(BYTE *,0x589181),//_build_cache_file_add_tags - }; - - BYTE patch[1] = { 0x0 }; - for (int x = 0; x < NUMBEROF(patching_offsets_list); x++) WriteBytes((DWORD)(patching_offsets_list[x] + 1), patch, 1);//patching push 1 -> push 0 -} - -void H2ToolPatches::unlock_other_scenario_types_compiling() -{ - //Refer to H2EK_OpenSauce Campaign_sharing - static void* BUILD_CACHE_FILE_FOR_SCENARIO__CHECK_SCENARIO_TYPE = CAST_PTR(void*,0x588320); - BYTE patch[1] = {0xEB}; - WriteBytes((DWORD)BUILD_CACHE_FILE_FOR_SCENARIO__CHECK_SCENARIO_TYPE, patch, 1);//change jz to jmp - -} - -static signed long _scenario_type; - -static void __declspec(naked) _build_cache_file_for_scenario__intercept_get_scenario_type() -{ - //Refer to H2EK_OpenSauce Campaign_sharing - //Basically this function helps us to store the scenario_type which can be used in later areas - static const unsigned __int32 INTERCEPTOR_EXIT = 0x588313; - - __asm { - movsx edx, word ptr[eax + 0x1C] - push esi - mov[esp + 0x58], edx // mov [esp+1F90h+scenario_type], edx - mov _scenario_type, edx - jmp INTERCEPTOR_EXIT - } -} - -const static wchar_t *campaign_shared_path = L"maps\\single_player_shared.map"; -const static char *load_sharing_log_messages[] = -{ - "tag sharing: loading tag names from single_player_shared.map", - "tag sharing: failed to open singleplayer shared map file", - "singleplayer shared cache file doesn't have its string table!! AAAAaaaaggghh!!!", - "singleplayer shared cache file string count is suspect (> 0x6000)", - "singleplayer shared cache file doesn't have its tag dependency graph!! AAAAaaaaggghh!!!", - "singleplayer shared cache file tag dependency graph size is suspect (> 0x100000)", - "tag sharing: ruh roh, single_player_shared.map has no shared tags" - -}; - -const static int load_sharing_log_offsets[] = -{ - 0x005813E7, - 0x00581499, - 0x005814B7, - 0x005818FF, - 0x00581587, - 0x005818EB, - 0x005817CD -}; - -static char __cdecl h_BUILD_CACHE_FILE_FOR_SCENARIO__TAG_SHARING_LOAD_SHARED(void *a1, void* a2) -{ - //Refer to H2EK_OpenSauce Campaign_sharing - - // If scenario_type is single_player,modify the strings - if (_scenario_type == 0) - { - // Replace file name strings - WritePointer(0x581455, campaign_shared_path); - WritePointer(0x581480, campaign_shared_path); - - // fix log strings to match - for (int i = 0; i < ARRAYSIZE(load_sharing_log_offsets); i++) - WritePointer(load_sharing_log_offsets[i] + 1, load_sharing_log_messages[i]); - } - H2PCTool.WriteLog("loading....tag_sharing method"); - - - DWORD TAG_SHARING_LOAD_MULTIPLAYER_SHARED = 0x5813C0; - return ((char(__cdecl *)(void*, void*))TAG_SHARING_LOAD_MULTIPLAYER_SHARED)(a1,a2);// call Function via address - -} -void H2ToolPatches::render_model_import_unlock() -{ - //Patches the h2tool to use the custom render_model_generation methods - - ///Patch Details::#1 patching the orignal render_model_generate function to call mine - /* - .text:0041C7A0 000 mov eax, [esp+arguments] - .text:0041C7A4 000 mov ecx, [eax] - .text:0041C7A6 000 jmp loc_41C4A0 ; Jump - */ - PatchCall(0x41C7A6, h2pc_import_render_model_proc); -} - -void H2ToolPatches::enable_campaign_tags_sharing() -{ - //Refer to H2EK_OpenSauce Campaign_sharing - - void* BUILD_CACHE_FILE_FOR_SCENARIO__GET_SCENARIO_TYPE = CAST_PTR(void*, 0x58830A); - int BUILD_CACHE_FILE_FOR_SCENARIO__TAG_SHARING_LOAD_SHARED = 0x5883DE; - - /* - //get_scenario_ Intercept codes - BYTE patch[1] = { 0xE8}; - - //Writing a call in memory to jmp to our function - WriteBytesASM((DWORD)BUILD_CACHE_FILE_FOR_SCENARIO__GET_SCENARIO_TYPE, patch, 1); - PatchCall((DWORD)BUILD_CACHE_FILE_FOR_SCENARIO__GET_SCENARIO_TYPE, (DWORD)_build_cache_file_for_scenario__intercept_get_scenario_type);//Writing the address to be jumped - */ - WriteJmpTo(BUILD_CACHE_FILE_FOR_SCENARIO__GET_SCENARIO_TYPE, _build_cache_file_for_scenario__intercept_get_scenario_type); - - - //single_player_shared sharing - - //.text:005883DE call BUILD_CACHE_FILE_FOR_SCENARIO__TAG_SHARING_LOAD_SHARED ; STR: "tag sharing: loading tag names from shared.map", "tag sharing: - PatchCall(BUILD_CACHE_FILE_FOR_SCENARIO__TAG_SHARING_LOAD_SHARED, h_BUILD_CACHE_FILE_FOR_SCENARIO__TAG_SHARING_LOAD_SHARED);//modifying the call to go to my h_function rather orignal - - H2PCTool.WriteLog("Single Player tag_sharing enabled"); -} - -void H2ToolPatches::remove_bsp_version_check() -{ - // allow tool to work with BSPs compliled by newer versions of tool. - // downgrades the error you would get to a non-fatal one. - BYTE bsp_version_check_return[] = { 0xB0, 0x01 }; - WriteBytes(0x00545D0F, bsp_version_check_return, sizeof(bsp_version_check_return)); -} - -void H2ToolPatches::disable_secure_file_locking() -{ - // allow other processes to read files open with fopen_s - WriteValue(0x0074DDD6 + 1, _SH_DENYWR); -} - -hs_convert_data_store *hs_get_converter_data_store(unsigned __int16 handle) -{ - typedef void* (__cdecl *get_args)(int a1, unsigned __int16 a2); - get_args get_args_impl = reinterpret_cast(0x00557E60); - return static_cast(get_args_impl(*reinterpret_cast(0xBCBF4C), handle)); -} - -const char *hs_get_string_data(hs_convert_data_store *data_store) -{ - const char *hs_string_data = *reinterpret_cast(0x00CDB198); - return &hs_string_data[data_store->string_value_offset]; -} - -char hs_error[0x1024]; - -void hs_converter_error(hs_convert_data_store *data_store, const std::string &error) -{ - const char **hs_error_string_ptr = reinterpret_cast(0x00CDB1AC); - DWORD *hs_error_offset_ptr = reinterpret_cast(0x00CDB1B0); - - strncpy(hs_error, error.c_str(), sizeof(hs_error)); - - *hs_error_string_ptr = hs_error; - *hs_error_offset_ptr = data_store->string_value_offset; - data_store->output = NONE; -} - -scnr_tag *get_global_scenario() -{ - return *reinterpret_cast(0x00AA00E4); -} - -void hs_convert_string_id_to_tagblock_offset(tag_block_ref *tag_block, int element_size, int block_offset, int hs_converter_id) -{ - auto data_store = hs_get_converter_data_store(hs_converter_id); - const char *value_string = hs_get_string_data(data_store); - - data_store->output = FIND_TAG_BLOCK_STRING_ID(tag_block, element_size, block_offset, GET_STRING_ID(value_string)); - - if (data_store->output == NONE) { - std::string error = "this is not a valid '" + hs_type_string[static_cast(data_store->target_hs_type)] + "' name, check tags"; - hs_converter_error(data_store, error); - } -} - -void hs_convert_string_to_tagblock_offset(tag_block_ref *tag_block, int element_size, int block_offset, int hs_converter_id) -{ - auto data_store = hs_get_converter_data_store(hs_converter_id); - const char *value_string = hs_get_string_data(data_store); - - data_store->output = FIND_TAG_BLOCK_STRING(tag_block, element_size, block_offset, value_string); - - if (data_store->output == NONE) { - std::string error = "this is not a valid '" + hs_type_string[static_cast(data_store->target_hs_type)] + "' name, check tags"; - hs_converter_error(data_store, error); - } -} - -char __cdecl hs_convert_conversation(unsigned __int16 a1) -{ - scnr_tag *scenario = get_global_scenario(); - hs_convert_string_to_tagblock_offset(&scenario->aIConversations, 128, 0, a1); - return 1; -} - -char __cdecl hs_convert_internal_id_passthrough(unsigned __int16 a1) -{ - hs_convert_data_store *data_store = hs_get_converter_data_store(a1); - const char *input_string = hs_get_string_data(data_store); - if (!_stricmp(input_string, "NONE")) { - data_store->output = NONE; - return 1; - } - try { - data_store->output = std::stoi(input_string, nullptr, 0); - return 1; - } - catch (invalid_argument) { - hs_converter_error(data_store, "invalid " + get_hs_type_string(data_store->target_hs_type) + " ID"); - return 0; - } - catch (out_of_range) - { - hs_converter_error(data_store, get_hs_type_string(data_store->target_hs_type) + " ID out of range"); - return 0; - } -} - -char __cdecl hs_convert_ai_behaviour(unsigned __int16 a1) -{ - hs_convert_data_store *data_store = hs_get_converter_data_store(a1); - const std::string input = hs_get_string_data(data_store); - ai_behaviour out = string_to_ai_behaviour(input); - if (out != ai_behaviour::invalid) { - data_store->output = static_cast(out); - return 1; - } else { - hs_converter_error(data_store, "Invalid AI behaviour"); - return 0; - } -} - -char __cdecl hs_convert_ai_orders(unsigned __int16 a1) -{ - scnr_tag *scenario = get_global_scenario(); - hs_convert_string_to_tagblock_offset(&scenario->orders, 144, 0, a1); - return 1; -} - -enum ai_id_type -{ - squad, - squad_group, - unknown, - starting_location, - - none = NONE -}; - -char __cdecl hs_convert_ai(unsigned __int16 a1) -{ - scnr_tag *scenario = get_global_scenario(); - hs_convert_data_store *data_store = hs_get_converter_data_store(a1); - std::string input_string = hs_get_string_data(data_store); - - ai_id_type ai_type = ai_id_type::none; - - DWORD main_index = NONE; - DWORD secondary_index = 0; - - if (input_string.find('/') != string::npos) { - ai_type = ai_id_type::starting_location; - std::string squad_name = input_string.substr(0, input_string.find('/')); - std::string squad_pos = input_string.substr(input_string.find('/') + 1); - - secondary_index = FIND_TAG_BLOCK_STRING(&scenario->squads, 120, 0, squad_name); - if (secondary_index != NONE) - { - // can't get the sqaud block struct working so this is a workaround for now - main_index = strtol(squad_pos.c_str(), nullptr, 0); - } else { - hs_converter_error(data_store, "No such squad."); - return 0; - } - } else { - - ai_type = ai_id_type::squad; - // attempt to find a squad with that name first - main_index = FIND_TAG_BLOCK_STRING(&scenario->squads, 120, 0, input_string); - if (main_index == NONE) { - // if no sqaud with that name exists try the sqaud groups - ai_type = ai_id_type::squad_group; - main_index = FIND_TAG_BLOCK_STRING(&scenario->squadGroups, 36, 0, input_string); - } - } - if (main_index != NONE) { - DWORD id = (ai_type << 30) | (secondary_index << 16) | main_index; - data_store->output = id; - return 1; - } else { - // fallback to passthrough for backwards compatibility and AI squad starting locations - return hs_convert_internal_id_passthrough(a1); - } -} - -#define set_hs_converter(type, func) \ - hs_convert_lookup_table[static_cast(type)] = func; - -void fix_hs_converters() -{ - void **hs_convert_lookup_table = reinterpret_cast(0x009F0C88); - set_hs_converter(hs_type::ai_behavior, hs_convert_ai_behaviour); - set_hs_converter(hs_type::conversation, hs_convert_conversation); - set_hs_converter(hs_type::ai_orders, hs_convert_ai_orders); - set_hs_converter(hs_type::ai, hs_convert_ai); - - // hacky workaround, lets the user directly input the ID it's meant to generate. - hs_type passthrough_types[] = { - hs_type::style, hs_type::hud_message, - hs_type::navpoint, hs_type::point_reference, - hs_type::ai_command_list - }; - - for (auto i : passthrough_types) - set_hs_converter(i, hs_convert_internal_id_passthrough); -} - -#undef set_hs_converter - -void HaloScriptExtend() -{ - - hs_command **command_table = reinterpret_cast(0x009ECFE0); - hs_global_variable **global_table = reinterpret_cast(0x009EFF78); - g_halo_script_interface->init_custom(command_table, global_table); - - // Replace pointers to the commmand table - static DWORD cmd_offsets[] = - { - 0x005C5365 + 3, 0x005C5530 + 3, 0x005C5554 + 3, - 0x005C5821 + 3, 0x005C5C44 + 3, 0x005C5E64 + 3, - 0x005C5E9A + 3, 0x005C5F48 + 3 - }; - - hs_command **cmds = g_halo_script_interface->get_command_table(); - - for (DWORD addr : cmd_offsets) - WritePointer(addr, cmds); - - // patch command table size - const static int hs_cmd_table_size = g_halo_script_interface->get_command_table_size(); - WriteValue(0x008CD59C, hs_cmd_table_size); - - // Replace pointers to the globals table - static DWORD var_offsets[] = - { - 0x005C53D5, 0x005C53F0, 0x005C5430, - 0x005C5474, 0x005C58D1, 0x006884A1, - 0x006884BD, 0x0068850D, 0x0068858B, - 0x006885A2 - }; - - hs_global_variable **vars = g_halo_script_interface->get_global_table(); - - for (DWORD addr : var_offsets) - WritePointer(addr + 3, vars); - - // patch globals table size - const static int hs_global_table_size = g_halo_script_interface->get_global_table_size(); - WriteValue(0x008D2238, hs_global_table_size); -} - -LPWSTR __crtGetCommandLineW_hook() -{ - typedef LPWSTR (*__crtGetCommandLineW_t)(); - __crtGetCommandLineW_t __crtGetCommandLineW_impl = reinterpret_cast<__crtGetCommandLineW_t>(0x00764EB3); - - wchar_t *real_cmd = __crtGetCommandLineW_impl(); - std::wstring fake_cmd = std::regex_replace(real_cmd, std::wregex(L"( pause_after_run| shared_tag_removal)"), L""); - wcscpy(real_cmd, fake_cmd.c_str()); - return real_cmd; -} - -void H2ToolPatches::fix_command_line() -{ - PatchCall(0x00751F83, __crtGetCommandLineW_hook); -} - -void H2ToolPatches::Initialize() -{ - H2PCTool.WriteLog("Dll Successfully Injected to H2Tool"); - wcout << "H2Toolz version: " << version << std::endl - << "Built on " __DATE__ " at " __TIME__ << std::endl; - - Increase_structure_import_size_Check(); - Increase_structure_bsp_geometry_check(); - AddExtraCommands(); - unlock_other_scenario_types_compiling(); - render_model_import_unlock(); - remove_bsp_version_check(); - disable_secure_file_locking(); - fix_hs_converters(); - HaloScriptExtend(); - fix_command_line(); - //enable_campaign_tags_sharing(); // Still crashes might need tag changes. - - std::string cmd = GetCommandLineA(); - if (cmd.find("shared_tag_removal") != string::npos) - apply_shared_tag_removal_scheme(); - - -} - - -void H2ToolPatches::AddExtraCommands() -{ - H2PCTool.WriteLog("Adding Extra Commands to H2Tool"); -#pragma region New Function Defination Creation - - static const BYTE k_number_of_tool_commands = 0xC; - static const BYTE k_number_of_tool_commands_new = k_number_of_tool_commands + NUMBEROF(h2tool_extra_commands); - - // Tool's original tool commands - static const s_tool_command* const* tool_import_classes = CAST_PTR(s_tool_command**, 0x97B6EC); - // The new tool commands list which is made up of tool's - // and [yelo_extra_tool_commands] - static s_tool_command* tool_commands[k_number_of_tool_commands_new]; - - // copy official tool commands - memcpy_s(tool_commands, sizeof(tool_commands), - tool_import_classes, sizeof(s_tool_command*) * k_number_of_tool_commands); - // copy yelo tool commands - memcpy_s(&tool_commands[k_number_of_tool_commands], sizeof(h2tool_extra_commands), - h2tool_extra_commands, sizeof(h2tool_extra_commands)); - - // Now I know my ABCs - qsort_s(tool_commands, NUMBEROF(tool_commands), sizeof(s_tool_command*), s_tool_command_compare, NULL); -#pragma endregion -#pragma region UpdateTool_function References - - DWORD tool_commands_references[] = { - 0x410596, - 0x41060E, - 0x412D86, - }; - DWORD tool_commands_count[] = { - 0x4105E5, - 0x412D99, - }; - - // update references to the tool command definitions - for (int x = 0; x < NUMBEROF(tool_commands_references); x++) - WriteValue(tool_commands_references[x], tool_commands); - - - -#pragma endregion -#pragma region UpdateTool_functionCount References - // update code which contain the tool command definitions count - - for (int x = 0; x < NUMBEROF(tool_commands_count); x++) - WriteValue(tool_commands_count[x], k_number_of_tool_commands_new); - -#pragma endregion -} diff --git a/H2Codez/HaloScript.cpp b/H2Codez/HaloScript.cpp deleted file mode 100644 index e7615dd..0000000 --- a/H2Codez/HaloScript.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "stdafx.h" -#include "HaloScript.h" - -using namespace HaloScriptCommon; - -// this is a massive hack but whatever -bool false_hack = false; -std::string HaloScript::get_value_as_string(void *var_ptr, hs_type type) -{ - std::string value_as_string; - if (!var_ptr) - var_ptr = &false_hack; - - switch (type) { - case hs_type::boolean: - value_as_string = (*static_cast(var_ptr)) ? "True" : "False"; - return value_as_string; - case hs_type::hs_long: - value_as_string = std::to_string(*static_cast(var_ptr)); - return value_as_string; - case hs_type::nothing: - return "void";; - case hs_type::real: - value_as_string = std::to_string(*static_cast(var_ptr)); - return value_as_string; - case hs_type::hs_short: - value_as_string = std::to_string(*static_cast(var_ptr)); - return value_as_string; - default: - throw std::runtime_error("Converting HS data of type '" + hs_type_string[type] + "' to string is not implemented.\n"); - } -} diff --git a/H2Codez/HaloScript.h b/H2Codez/HaloScript.h deleted file mode 100644 index f0b699f..0000000 --- a/H2Codez/HaloScript.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -#include "H2ToolsCommon.h" - -class HaloScript -{ -public: - /* Used to return data to the scripting engine, marks the end of a script command*/ - static void **epilog(void *a1, int return_data); - - /* returns the arguments passed to the command */ - static void **prolog(__int16 command_id, int a2, char a3); - - /* Not finnished, didn't even add all the function types*/ - static std::string get_value_as_string(void *var_ptr, HaloScriptCommon::hs_type type); -}; - diff --git a/H2Codez/hs_ai_behaviour.cpp b/H2Codez/HaloScript/hs_ai_behaviour.cpp similarity index 95% rename from H2Codez/hs_ai_behaviour.cpp rename to H2Codez/HaloScript/hs_ai_behaviour.cpp index 239f997..f67659b 100644 --- a/H2Codez/hs_ai_behaviour.cpp +++ b/H2Codez/HaloScript/hs_ai_behaviour.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "../stdafx.h" #include "hs_ai_behaviour.h" std::string search_for; diff --git a/H2Codez/hs_ai_behaviour.h b/H2Codez/HaloScript/hs_ai_behaviour.h similarity index 100% rename from H2Codez/hs_ai_behaviour.h rename to H2Codez/HaloScript/hs_ai_behaviour.h diff --git a/H2Codez/hs_command.h b/H2Codez/HaloScript/hs_command.h similarity index 98% rename from H2Codez/hs_command.h rename to H2Codez/HaloScript/hs_command.h index 5630356..977c88f 100644 --- a/H2Codez/hs_command.h +++ b/H2Codez/HaloScript/hs_command.h @@ -1,6 +1,6 @@ #pragma once #include "hs_types.h" -#include "stdafx.h" +#include "../stdafx.h" namespace HaloScriptCommon { diff --git a/H2Codez/hs_global_ids.h b/H2Codez/HaloScript/hs_global_ids.h similarity index 100% rename from H2Codez/hs_global_ids.h rename to H2Codez/HaloScript/hs_global_ids.h diff --git a/H2Codez/hs_global_variable.h b/H2Codez/HaloScript/hs_global_variable.h similarity index 100% rename from H2Codez/hs_global_variable.h rename to H2Codez/HaloScript/hs_global_variable.h diff --git a/H2Codez/HaloScriptInterface.cpp b/H2Codez/HaloScript/hs_interface.cpp similarity index 97% rename from H2Codez/HaloScriptInterface.cpp rename to H2Codez/HaloScript/hs_interface.cpp index 58b08ab..d78bb36 100644 --- a/H2Codez/HaloScriptInterface.cpp +++ b/H2Codez/HaloScript/hs_interface.cpp @@ -1,6 +1,5 @@ -#include "HaloScriptInterface.h" -#include "h2codez.h" -#include "HaloScript.h" +#include "hs_interface.h" +#include "../h2codez.h" HaloScriptInterface *g_halo_script_interface = new HaloScriptInterface; diff --git a/H2Codez/HaloScriptInterface.h b/H2Codez/HaloScript/hs_interface.h similarity index 98% rename from H2Codez/HaloScriptInterface.h rename to H2Codez/HaloScript/hs_interface.h index d3d43df..1f100d8 100644 --- a/H2Codez/HaloScriptInterface.h +++ b/H2Codez/HaloScript/hs_interface.h @@ -1,5 +1,5 @@ #pragma once -#include "stdafx.h" +#include "../stdafx.h" #include "hs_ai_behaviour.h" #include "hs_types.h" diff --git a/H2Codez/hs_opcodes.h b/H2Codez/HaloScript/hs_opcodes.h similarity index 100% rename from H2Codez/hs_opcodes.h rename to H2Codez/HaloScript/hs_opcodes.h diff --git a/H2Codez/hs_types.h b/H2Codez/HaloScript/hs_types.h similarity index 100% rename from H2Codez/hs_types.h rename to H2Codez/HaloScript/hs_types.h diff --git a/H2Codez/Patches.h b/H2Codez/Patches.h deleted file mode 100644 index c2ea8b8..0000000 --- a/H2Codez/Patches.h +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once - -void WriteBytes(DWORD destAddress, LPVOID patch, DWORD numBytes); -void PatchCall(DWORD call_addr, DWORD new_function_ptr); -void WritePointer(DWORD offset, void *ptr); -void PatchWinAPICall(DWORD call_addr, DWORD new_function_ptr); - -inline void PatchCall(DWORD call_addr, void *new_function_ptr) -{ - PatchCall(call_addr, reinterpret_cast(new_function_ptr)); -} - -inline void WritePointer(DWORD offset, const void *ptr) { - WritePointer(offset, const_cast(ptr)); -} - -template -inline void WriteValue(DWORD offset, value_type data) -{ - WriteBytes(offset, &data, sizeof(data)); -} - -inline void NopFill(const DWORD address, int len) -{ - BYTE *nop_fill = new BYTE[len]; - memset(nop_fill, 0x90, len); - WriteBytes(address, nop_fill, len); - - delete[] nop_fill; -} - -inline void NopFill(const void *address, int len) -{ - NopFill(reinterpret_cast(address), len); -} - -inline void WriteJmpTo(DWORD call_addr, DWORD new_function_ptr) -{ - BYTE call_patch[1] = { 0xE9 }; - WriteBytes(call_addr, call_patch, 1); - PatchCall(call_addr, new_function_ptr); -} - -inline void WriteJmpTo(DWORD call_addr, void *new_function_ptr) -{ - WriteJmpTo(call_addr, reinterpret_cast(new_function_ptr)); -} - -inline void WriteJmpTo(void *call_addr, void *new_function_ptr) -{ - WriteJmpTo(reinterpret_cast(call_addr), reinterpret_cast(new_function_ptr)); -} - -inline void WriteCallTo(DWORD call_addr, DWORD new_function_ptr) -{ - BYTE call_patch[1] = { 0xE8 }; - WriteBytes(call_addr, call_patch, 1); - PatchCall(call_addr, new_function_ptr); -} - -inline void WriteCallTo(DWORD call_addr, void *new_function_ptr) -{ - WriteCallTo(call_addr, reinterpret_cast(new_function_ptr)); -} - -inline void PatchWinAPICall(DWORD call_addr, void * new_function_ptr) -{ - PatchWinAPICall(call_addr, reinterpret_cast(new_function_ptr)); -} diff --git a/H2Codez/discord-rpc-debug.lib b/H2Codez/Precompiled/discord-rpc-debug.lib similarity index 100% rename from H2Codez/discord-rpc-debug.lib rename to H2Codez/Precompiled/discord-rpc-debug.lib diff --git a/H2Codez/discord-rpc.lib b/H2Codez/Precompiled/discord-rpc.lib similarity index 100% rename from H2Codez/discord-rpc.lib rename to H2Codez/Precompiled/discord-rpc.lib diff --git a/H2Codez/H2Guerilla.rc b/H2Codez/Resources/H2Guerilla.rc similarity index 100% rename from H2Codez/H2Guerilla.rc rename to H2Codez/Resources/H2Guerilla.rc diff --git a/H2Codez/H2Sapien.rc b/H2Codez/Resources/H2Sapien.rc similarity index 100% rename from H2Codez/H2Sapien.rc rename to H2Codez/Resources/H2Sapien.rc diff --git a/H2Codez/resource.h b/H2Codez/Resources/resource.h similarity index 97% rename from H2Codez/resource.h rename to H2Codez/Resources/resource.h index 9c204ac..aa9e7f5 100644 --- a/H2Codez/resource.h +++ b/H2Codez/Resources/resource.h @@ -1,34 +1,34 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by H2Sapien.rc -// -#define SAPIEN_COMMAND 0 -#define VS_VERSION_INFO 1 -#define SAPIEN_COMMAND_DIALOG 101 -#define IDD_DIALOG1 102 -#define IDD_SELECT_CUSTOM_SPEED 102 -#define SAPIEN_MENU 241 -#define GUERILLA_MENU 1000 -#define IDC_LIST1 1001 -#define IDC_CUSTOM_SPEED 1001 -#define ID_EDIT_ADVANCEDSHADERVIEW 40001 -#define ID_FILE_NEWINSTANCE 40002 -#define SAPIEN_FILE_NEWINSTANCE 40005 -#define SAPIEN_RUN_COMMAND 40007 -#define SAPIEN_OPEN_RUN_COMMAND_DIALOG 40008 -#define SAPIEN_SCRIPT_DOC 40010 -#define SCRIPT_DOC 40011 -#define SAPIEN_IN_GAME_LOD 40014 -#define SHOW_HIDDEN_FIELDS 40015 -#define ID_VIEW_CUSTOMDIRECTORSPEED 40016 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 105 -#define _APS_NEXT_COMMAND_VALUE 40017 -#define _APS_NEXT_CONTROL_VALUE 1003 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by H2Sapien.rc +// +#define SAPIEN_COMMAND 0 +#define VS_VERSION_INFO 1 +#define SAPIEN_COMMAND_DIALOG 101 +#define IDD_DIALOG1 102 +#define IDD_SELECT_CUSTOM_SPEED 102 +#define SAPIEN_MENU 241 +#define GUERILLA_MENU 1000 +#define IDC_LIST1 1001 +#define IDC_CUSTOM_SPEED 1001 +#define ID_EDIT_ADVANCEDSHADERVIEW 40001 +#define ID_FILE_NEWINSTANCE 40002 +#define SAPIEN_FILE_NEWINSTANCE 40005 +#define SAPIEN_RUN_COMMAND 40007 +#define SAPIEN_OPEN_RUN_COMMAND_DIALOG 40008 +#define SAPIEN_SCRIPT_DOC 40010 +#define SCRIPT_DOC 40011 +#define SAPIEN_IN_GAME_LOD 40014 +#define SHOW_HIDDEN_FIELDS 40015 +#define ID_VIEW_CUSTOMDIRECTORSPEED 40016 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 105 +#define _APS_NEXT_COMMAND_VALUE 40017 +#define _APS_NEXT_CONTROL_VALUE 1003 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/H2Codez/SigScanning.h b/H2Codez/SigScanning.h deleted file mode 100644 index 8c251bb..0000000 --- a/H2Codez/SigScanning.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once -#include "stdafx.h" -#include - -//Whats this file for? -//I use Signature Scanning here to find similar opcodes b/w Halo 2 and The Editing Kit package -//Can also be used to compare signatures of other processes - -MODULEINFO GetModeuleInfo(char* szModule) -{ - MODULEINFO p = { 0 }; - HMODULE q = GetModuleHandleA(szModule); - if (q == 0) - { - pLog.WriteLog("Process Not Found "); - return p; - } - GetModuleInformation(GetCurrentProcess(), q, &p, sizeof(MODULEINFO)); - return p; -} - -DWORD FindPattern(char *szPattern, char *szMask) -{ - char* ProcName = "halo2.exe"; - //char* ProcName = "H2Sapien.exe"; - //char* ProcName = "H2Sapien.exe"; - // Get the current process information - MODULEINFO mInfo = GetModeuleInfo(ProcName); - // Find the base address - DWORD dwBase = (DWORD)mInfo.lpBaseOfDll; - DWORD dwSize = (DWORD)mInfo.SizeOfImage; - // Get the pattern length - DWORD dwPatternLength = (DWORD)strlen(szMask); - // Loop through all the process - for (DWORD i = 0; i < dwSize - dwPatternLength; i++) - { - bool bFound = true; - // Loop through the pattern caracters - for (DWORD j = 0; j < dwPatternLength; j++) - bFound &= szMask[j] == '?' || szPattern[j] == *(char*)(dwBase + i + j); - - // If found return the current address - if (bFound) - return dwBase + i; - } - // Return null - return NULL; -} \ No newline at end of file diff --git a/H2Codez/ScenarioTag.h b/H2Codez/Tags/ScenarioTag.h similarity index 100% rename from H2Codez/ScenarioTag.h rename to H2Codez/Tags/ScenarioTag.h diff --git a/H2Codez/dllmain.cpp b/H2Codez/dllmain.cpp index d79311b..fb038fe 100644 --- a/H2Codez/dllmain.cpp +++ b/H2Codez/dllmain.cpp @@ -1,10 +1,9 @@ // dllmain.cpp : Defines the entry point for the DLL application. #include "stdafx.h" -#include "DiscordInterface.h" -#include "SigScanning.h" -#include "Debug.h" -#include "H2ToolsCommon.h" +#include "Common\DiscordInterface.h" +#include "Util\Debug.h" +#include "Common\H2EKCommon.h" #pragma region declarations diff --git a/H2Codez/h2codez.cpp b/H2Codez/h2codez.cpp index 6b72e9b..3f36f92 100644 --- a/H2Codez/h2codez.cpp +++ b/H2Codez/h2codez.cpp @@ -1,8 +1,8 @@ #include "stdafx.h" -#include "H2Guerilla.h" -#include "H2Sapien.h" -#include "H2ToolsCommon.h" -#include "DiscordInterface.h" +#include "H2Guerilla\H2Guerilla.h" +#include "H2Sapien\H2Sapien.h" +#include "Common\H2EKCommon.h" +#include "Common\DiscordInterface.h" char app_directory[256]; std::wstring_convert> wstring_to_string; diff --git a/H2Codez/patches.cpp b/H2Codez/patches.cpp deleted file mode 100644 index f76572c..0000000 --- a/H2Codez/patches.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "stdafx.h" -#include "Patches.h" - -void WriteBytes(DWORD destAddress, LPVOID patch, DWORD numBytes) -{ - DWORD OldProtection; - void *target_addr = reinterpret_cast(destAddress); - - VirtualProtect(target_addr, numBytes, PAGE_EXECUTE_READWRITE, &OldProtection); - memcpy(target_addr, patch, numBytes); - VirtualProtect(target_addr, numBytes, OldProtection, NULL); - - FlushInstructionCache(GetCurrentProcess(), target_addr, numBytes); -} - -void PatchCall(DWORD call_addr, DWORD new_function_ptr) { - DWORD callRelative = new_function_ptr - (call_addr + 5); - WritePointer(call_addr + 1, reinterpret_cast(callRelative)); -} - -void WritePointer(DWORD offset, void *ptr) { - BYTE* pbyte = (BYTE*)&ptr; - BYTE assmNewFuncRel[0x4] = { pbyte[0], pbyte[1], pbyte[2], pbyte[3] }; - WriteBytes(offset, assmNewFuncRel, 0x4); -} - -void PatchWinAPICall(DWORD call_addr, DWORD new_function_ptr) -{ - BYTE call = 0xE8; - WriteValue(call_addr, call); - - PatchCall(call_addr, new_function_ptr); - - // pad the extra unused byte - BYTE padding = 0x90; - WriteValue(call_addr + 5, padding); -} diff --git a/H2Codez/stdafx.h b/H2Codez/stdafx.h index ab7401b..2e8752d 100644 --- a/H2Codez/stdafx.h +++ b/H2Codez/stdafx.h @@ -28,12 +28,12 @@ #pragma endregion #include "h2codez.h" -#include "Detours\detours.h" -#include "Logs.h" +#include "util\Detours\detours.h" +#include "util\Logs.h" #include "H2Tool\H2Tool_Commands.h" -#include "discord-rpc.h" -#include "Patches.h" -#include "Settings.h" +#include "Common\discord-rpc.h" +#include "util\Patches.h" +#include "util\Settings.h" extern Settings conf; extern BOOL EnableDbgConsole; diff --git a/H2Codez/Debug.cpp b/H2Codez/util/Debug.cpp similarity index 98% rename from H2Codez/Debug.cpp rename to H2Codez/util/Debug.cpp index f905001..a70fb27 100644 --- a/H2Codez/Debug.cpp +++ b/H2Codez/util/Debug.cpp @@ -1,9 +1,9 @@ -#include "stdafx.h" +#include "../stdafx.h" #include #include #include #include "Debug.h" -#include "Version.h" +#include "../Version.h" #define crash_reports_path "reports//crash_reports//" diff --git a/H2Codez/Debug.h b/H2Codez/util/Debug.h similarity index 100% rename from H2Codez/Debug.h rename to H2Codez/util/Debug.h diff --git a/H2Codez/Detours/detours.cpp b/H2Codez/util/Detours/detours.cpp similarity index 97% rename from H2Codez/Detours/detours.cpp rename to H2Codez/util/Detours/detours.cpp index 0869f27..dfe9ff8 100644 --- a/H2Codez/Detours/detours.cpp +++ b/H2Codez/util/Detours/detours.cpp @@ -1,2368 +1,2368 @@ -////////////////////////////////////////////////////////////////////////////// -// -// Core Detours Functionality (detours.cpp of detours.lib) -// -// Microsoft Research Detours Package, Version 3.0 Build_343. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// - -#pragma warning(disable:4068) // unknown pragma (suppress) - -#if _MSC_VER >= 1900 -#pragma warning(push) -#pragma warning(disable:4091) // empty typedef -#endif - -#define _ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE 1 -#include - -#if (_MSC_VER < 1299) -#pragma warning(disable: 4710) -#endif - -//#define DETOUR_DEBUG 1 -#define DETOURS_INTERNAL - -#include "detours.h" - -#if DETOURS_VERSION != 30001 -#error detours.h version mismatch -#endif - -#if _MSC_VER >= 1900 -#pragma warning(pop) -#endif - -#define NOTHROW - -////////////////////////////////////////////////////////////////////////////// -// -struct _DETOUR_ALIGN -{ - BYTE obTarget : 3; - BYTE obTrampoline : 5; -}; - -C_ASSERT(sizeof(_DETOUR_ALIGN) == 1); - -////////////////////////////////////////////////////////////////////////////// -// -// Region reserved for system DLLs, which cannot be used for trampolines. -// -static PVOID s_pSystemRegionLowerBound = (PVOID)(ULONG_PTR)0x70000000; -static PVOID s_pSystemRegionUpperBound = (PVOID)(ULONG_PTR)0x80000000; - -////////////////////////////////////////////////////////////////////////////// -// -static bool detour_is_imported(PBYTE pbCode, PBYTE pbAddress) -{ - MEMORY_BASIC_INFORMATION mbi; - VirtualQuery((PVOID)pbCode, &mbi, sizeof(mbi)); - __try { - PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mbi.AllocationBase; - if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) { - return false; - } - - PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader + - pDosHeader->e_lfanew); - if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) { - return false; - } - - if (pbAddress >= ((PBYTE)pDosHeader + - pNtHeader->OptionalHeader - .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress) && - pbAddress < ((PBYTE)pDosHeader + - pNtHeader->OptionalHeader - .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress + - pNtHeader->OptionalHeader - .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size)) { - return true; - } - } -#pragma prefast(suppress:28940, "A bad pointer means this probably isn't a PE header.") - __except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? - EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { - return false; - } - return false; -} - -inline ULONG_PTR detour_2gb_below(ULONG_PTR address) -{ - return (address > (ULONG_PTR)0x7ff80000) ? address - 0x7ff80000 : 0x80000; -} - -inline ULONG_PTR detour_2gb_above(ULONG_PTR address) -{ -#if defined(DETOURS_64BIT) - return (address < (ULONG_PTR)0xffffffff80000000) ? address + 0x7ff80000 : (ULONG_PTR)0xfffffffffff80000; -#else - return (address < (ULONG_PTR)0x80000000) ? address + 0x7ff80000 : (ULONG_PTR)0xfff80000; -#endif -} - -///////////////////////////////////////////////////////////////////////// X86. -// -#ifdef DETOURS_X86 - -struct _DETOUR_TRAMPOLINE -{ - BYTE rbCode[30]; // target code + jmp to pbRemain - BYTE cbCode; // size of moved target code. - BYTE cbCodeBreak; // padding to make debugging easier. - BYTE rbRestore[22]; // original target code. - BYTE cbRestore; // size of original target code. - BYTE cbRestoreBreak; // padding to make debugging easier. - _DETOUR_ALIGN rAlign[8]; // instruction alignment array. - PBYTE pbRemain; // first instruction after moved code. [free list] - PBYTE pbDetour; // first instruction of detour function. -}; - -C_ASSERT(sizeof(_DETOUR_TRAMPOLINE) == 72); - -enum { - SIZE_OF_JMP = 5 -}; - -inline PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE pbJmpVal) -{ - PBYTE pbJmpSrc = pbCode + 5; - *pbCode++ = 0xE9; // jmp +imm32 - *((INT32*&)pbCode)++ = (INT32)(pbJmpVal - pbJmpSrc); - return pbCode; -} - -inline PBYTE detour_gen_jmp_indirect(PBYTE pbCode, PBYTE *ppbJmpVal) -{ - *pbCode++ = 0xff; // jmp [+imm32] - *pbCode++ = 0x25; - *((INT32*&)pbCode)++ = (INT32)((PBYTE)ppbJmpVal); - return pbCode; -} - -inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit) -{ - while (pbCode < pbLimit) { - *pbCode++ = 0xcc; // brk; - } - return pbCode; -} - -inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals) -{ - if (pbCode == NULL) { - return NULL; - } - if (ppGlobals != NULL) { - *ppGlobals = NULL; - } - - // First, skip over the import vector if there is one. - if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [imm32] - // Looks like an import alias jump, then get the code it points to. - PBYTE pbTarget = *(UNALIGNED PBYTE *)&pbCode[2]; - if (detour_is_imported(pbCode, pbTarget)) { - PBYTE pbNew = *(UNALIGNED PBYTE *)pbTarget; - DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew)); - pbCode = pbNew; - } - } - - // Then, skip over a patch jump - if (pbCode[0] == 0xeb) { // jmp +imm8 - PBYTE pbNew = pbCode + 2 + *(CHAR *)&pbCode[1]; - DETOUR_TRACE(("%p->%p: skipped over short jump.\n", pbCode, pbNew)); - pbCode = pbNew; - - // First, skip over the import vector if there is one. - if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [imm32] - // Looks like an import alias jump, then get the code it points to. - PBYTE pbTarget = *(UNALIGNED PBYTE *)&pbCode[2]; - if (detour_is_imported(pbCode, pbTarget)) { - pbNew = *(UNALIGNED PBYTE *)pbTarget; - DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew)); - pbCode = pbNew; - } - } - // Finally, skip over a long jump if it is the target of the patch jump. - else if (pbCode[0] == 0xe9) { // jmp +imm32 - pbNew = pbCode + 5 + *(UNALIGNED INT32 *)&pbCode[1]; - DETOUR_TRACE(("%p->%p: skipped over long jump.\n", pbCode, pbNew)); - pbCode = pbNew; - } - } - return pbCode; -} - -inline void detour_find_jmp_bounds(PBYTE pbCode, - PDETOUR_TRAMPOLINE *ppLower, - PDETOUR_TRAMPOLINE *ppUpper) -{ - // We have to place trampolines within +/- 2GB of code. - ULONG_PTR lo = detour_2gb_below((ULONG_PTR)pbCode); - ULONG_PTR hi = detour_2gb_above((ULONG_PTR)pbCode); - DETOUR_TRACE(("[%p..%p..%p]\n", lo, pbCode, hi)); - - // And, within +/- 2GB of relative jmp targets. - if (pbCode[0] == 0xe9) { // jmp +imm32 - PBYTE pbNew = pbCode + 5 + *(UNALIGNED INT32 *)&pbCode[1]; - - if (pbNew < pbCode) { - hi = detour_2gb_above((ULONG_PTR)pbNew); - } - else { - lo = detour_2gb_below((ULONG_PTR)pbNew); - } - DETOUR_TRACE(("[%p..%p..%p] +imm32\n", lo, pbCode, hi)); - } - - *ppLower = (PDETOUR_TRAMPOLINE)lo; - *ppUpper = (PDETOUR_TRAMPOLINE)hi; -} - -inline BOOL detour_does_code_end_function(PBYTE pbCode) -{ - if (pbCode[0] == 0xeb || // jmp +imm8 - pbCode[0] == 0xe9 || // jmp +imm32 - pbCode[0] == 0xe0 || // jmp eax - pbCode[0] == 0xc2 || // ret +imm8 - pbCode[0] == 0xc3 || // ret - pbCode[0] == 0xcc) { // brk - return TRUE; - } - else if (pbCode[0] == 0xf3 && pbCode[1] == 0xc3) { // rep ret - return TRUE; - } - else if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32] - return TRUE; - } - else if ((pbCode[0] == 0x26 || // jmp es: - pbCode[0] == 0x2e || // jmp cs: - pbCode[0] == 0x36 || // jmp ss: - pbCode[0] == 0x3e || // jmp ds: - pbCode[0] == 0x64 || // jmp fs: - pbCode[0] == 0x65) && // jmp gs: - pbCode[1] == 0xff && // jmp [+imm32] - pbCode[2] == 0x25) { - return TRUE; - } - return FALSE; -} - -inline ULONG detour_is_code_filler(PBYTE pbCode) -{ - // 1-byte through 11-byte NOPs. - if (pbCode[0] == 0x90) { - return 1; - } - if (pbCode[0] == 0x66 && pbCode[1] == 0x90) { - return 2; - } - if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x00) { - return 3; - } - if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x40 && - pbCode[3] == 0x00) { - return 4; - } - if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x44 && - pbCode[3] == 0x00 && pbCode[4] == 0x00) { - return 5; - } - if (pbCode[0] == 0x66 && pbCode[1] == 0x0F && pbCode[2] == 0x1F && - pbCode[3] == 0x44 && pbCode[4] == 0x00 && pbCode[5] == 0x00) { - return 6; - } - if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x80 && - pbCode[3] == 0x00 && pbCode[4] == 0x00 && pbCode[5] == 0x00 && - pbCode[6] == 0x00) { - return 7; - } - if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x84 && - pbCode[3] == 0x00 && pbCode[4] == 0x00 && pbCode[5] == 0x00 && - pbCode[6] == 0x00 && pbCode[7] == 0x00) { - return 8; - } - if (pbCode[0] == 0x66 && pbCode[1] == 0x0F && pbCode[2] == 0x1F && - pbCode[3] == 0x84 && pbCode[4] == 0x00 && pbCode[5] == 0x00 && - pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00) { - return 9; - } - if (pbCode[0] == 0x66 && pbCode[1] == 0x66 && pbCode[2] == 0x0F && - pbCode[3] == 0x1F && pbCode[4] == 0x84 && pbCode[5] == 0x00 && - pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00 && - pbCode[9] == 0x00) { - return 10; - } - if (pbCode[0] == 0x66 && pbCode[1] == 0x66 && pbCode[2] == 0x66 && - pbCode[3] == 0x0F && pbCode[4] == 0x1F && pbCode[5] == 0x84 && - pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00 && - pbCode[9] == 0x00 && pbCode[10] == 0x00) { - return 11; - } - - // int 3. - if (pbCode[0] == 0xcc) { - return 1; - } - return 0; -} - -#endif // DETOURS_X86 - -///////////////////////////////////////////////////////////////////////// X64. -// -#ifdef DETOURS_X64 - -struct _DETOUR_TRAMPOLINE -{ - // An X64 instuction can be 15 bytes long. - // In practice 11 seems to be the limit. - BYTE rbCode[30]; // target code + jmp to pbRemain. - BYTE cbCode; // size of moved target code. - BYTE cbCodeBreak; // padding to make debugging easier. - BYTE rbRestore[30]; // original target code. - BYTE cbRestore; // size of original target code. - BYTE cbRestoreBreak; // padding to make debugging easier. - _DETOUR_ALIGN rAlign[8]; // instruction alignment array. - PBYTE pbRemain; // first instruction after moved code. [free list] - PBYTE pbDetour; // first instruction of detour function. - BYTE rbCodeIn[8]; // jmp [pbDetour] -}; - -C_ASSERT(sizeof(_DETOUR_TRAMPOLINE) == 96); - -enum { - SIZE_OF_JMP = 5 -}; - -inline PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE pbJmpVal) -{ - PBYTE pbJmpSrc = pbCode + 5; - *pbCode++ = 0xE9; // jmp +imm32 - *((INT32*&)pbCode)++ = (INT32)(pbJmpVal - pbJmpSrc); - return pbCode; -} - -inline PBYTE detour_gen_jmp_indirect(PBYTE pbCode, PBYTE *ppbJmpVal) -{ - PBYTE pbJmpSrc = pbCode + 6; - *pbCode++ = 0xff; // jmp [+imm32] - *pbCode++ = 0x25; - *((INT32*&)pbCode)++ = (INT32)((PBYTE)ppbJmpVal - pbJmpSrc); - return pbCode; -} - -inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit) -{ - while (pbCode < pbLimit) { - *pbCode++ = 0xcc; // brk; - } - return pbCode; -} - -inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals) -{ - if (pbCode == NULL) { - return NULL; - } - if (ppGlobals != NULL) { - *ppGlobals = NULL; - } - - // First, skip over the import vector if there is one. - if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32] - // Looks like an import alias jump, then get the code it points to. - PBYTE pbTarget = pbCode + 6 + *(UNALIGNED INT32 *)&pbCode[2]; - if (detour_is_imported(pbCode, pbTarget)) { - PBYTE pbNew = *(UNALIGNED PBYTE *)pbTarget; - DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew)); - pbCode = pbNew; - } - } - - // Then, skip over a patch jump - if (pbCode[0] == 0xeb) { // jmp +imm8 - PBYTE pbNew = pbCode + 2 + *(CHAR *)&pbCode[1]; - DETOUR_TRACE(("%p->%p: skipped over short jump.\n", pbCode, pbNew)); - pbCode = pbNew; - - // First, skip over the import vector if there is one. - if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32] - // Looks like an import alias jump, then get the code it points to. - PBYTE pbTarget = pbCode + 6 + *(UNALIGNED INT32 *)&pbCode[2]; - if (detour_is_imported(pbCode, pbTarget)) { - pbNew = *(UNALIGNED PBYTE *)pbTarget; - DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew)); - pbCode = pbNew; - } - } - // Finally, skip over a long jump if it is the target of the patch jump. - else if (pbCode[0] == 0xe9) { // jmp +imm32 - pbNew = pbCode + 5 + *(UNALIGNED INT32 *)&pbCode[1]; - DETOUR_TRACE(("%p->%p: skipped over long jump.\n", pbCode, pbNew)); - pbCode = pbNew; - } - } - return pbCode; -} - -inline void detour_find_jmp_bounds(PBYTE pbCode, - PDETOUR_TRAMPOLINE *ppLower, - PDETOUR_TRAMPOLINE *ppUpper) -{ - // We have to place trampolines within +/- 2GB of code. - ULONG_PTR lo = detour_2gb_below((ULONG_PTR)pbCode); - ULONG_PTR hi = detour_2gb_above((ULONG_PTR)pbCode); - DETOUR_TRACE(("[%p..%p..%p]\n", lo, pbCode, hi)); - - // And, within +/- 2GB of relative jmp vectors. - if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32] - PBYTE pbNew = pbCode + 6 + *(UNALIGNED INT32 *)&pbCode[2]; - - if (pbNew < pbCode) { - hi = detour_2gb_above((ULONG_PTR)pbNew); - } - else { - lo = detour_2gb_below((ULONG_PTR)pbNew); - } - DETOUR_TRACE(("[%p..%p..%p] [+imm32]\n", lo, pbCode, hi)); - } - // And, within +/- 2GB of relative jmp targets. - else if (pbCode[0] == 0xe9) { // jmp +imm32 - PBYTE pbNew = pbCode + 5 + *(UNALIGNED INT32 *)&pbCode[1]; - - if (pbNew < pbCode) { - hi = detour_2gb_above((ULONG_PTR)pbNew); - } - else { - lo = detour_2gb_below((ULONG_PTR)pbNew); - } - DETOUR_TRACE(("[%p..%p..%p] +imm32\n", lo, pbCode, hi)); - } - - *ppLower = (PDETOUR_TRAMPOLINE)lo; - *ppUpper = (PDETOUR_TRAMPOLINE)hi; -} - -inline BOOL detour_does_code_end_function(PBYTE pbCode) -{ - if (pbCode[0] == 0xeb || // jmp +imm8 - pbCode[0] == 0xe9 || // jmp +imm32 - pbCode[0] == 0xe0 || // jmp eax - pbCode[0] == 0xc2 || // ret +imm8 - pbCode[0] == 0xc3 || // ret - pbCode[0] == 0xcc) { // brk - return TRUE; - } - else if (pbCode[0] == 0xf3 && pbCode[1] == 0xc3) { // rep ret - return TRUE; - } - else if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32] - return TRUE; - } - else if ((pbCode[0] == 0x26 || // jmp es: - pbCode[0] == 0x2e || // jmp cs: - pbCode[0] == 0x36 || // jmp ss: - pbCode[0] == 0x3e || // jmp ds: - pbCode[0] == 0x64 || // jmp fs: - pbCode[0] == 0x65) && // jmp gs: - pbCode[1] == 0xff && // jmp [+imm32] - pbCode[2] == 0x25) { - return TRUE; - } - return FALSE; -} - -inline ULONG detour_is_code_filler(PBYTE pbCode) -{ - // 1-byte through 11-byte NOPs. - if (pbCode[0] == 0x90) { - return 1; - } - if (pbCode[0] == 0x66 && pbCode[1] == 0x90) { - return 2; - } - if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x00) { - return 3; - } - if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x40 && - pbCode[3] == 0x00) { - return 4; - } - if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x44 && - pbCode[3] == 0x00 && pbCode[4] == 0x00) { - return 5; - } - if (pbCode[0] == 0x66 && pbCode[1] == 0x0F && pbCode[2] == 0x1F && - pbCode[3] == 0x44 && pbCode[4] == 0x00 && pbCode[5] == 0x00) { - return 6; - } - if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x80 && - pbCode[3] == 0x00 && pbCode[4] == 0x00 && pbCode[5] == 0x00 && - pbCode[6] == 0x00) { - return 7; - } - if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x84 && - pbCode[3] == 0x00 && pbCode[4] == 0x00 && pbCode[5] == 0x00 && - pbCode[6] == 0x00 && pbCode[7] == 0x00) { - return 8; - } - if (pbCode[0] == 0x66 && pbCode[1] == 0x0F && pbCode[2] == 0x1F && - pbCode[3] == 0x84 && pbCode[4] == 0x00 && pbCode[5] == 0x00 && - pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00) { - return 9; - } - if (pbCode[0] == 0x66 && pbCode[1] == 0x66 && pbCode[2] == 0x0F && - pbCode[3] == 0x1F && pbCode[4] == 0x84 && pbCode[5] == 0x00 && - pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00 && - pbCode[9] == 0x00) { - return 10; - } - if (pbCode[0] == 0x66 && pbCode[1] == 0x66 && pbCode[2] == 0x66 && - pbCode[3] == 0x0F && pbCode[4] == 0x1F && pbCode[5] == 0x84 && - pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00 && - pbCode[9] == 0x00 && pbCode[10] == 0x00) { - return 11; - } - - // int 3. - if (pbCode[0] == 0xcc) { - return 1; - } - return 0; -} - -#endif // DETOURS_X64 - -//////////////////////////////////////////////////////////////////////// IA64. -// -#ifdef DETOURS_IA64 - -struct _DETOUR_TRAMPOLINE -{ - // On the IA64, a trampoline is used for both incoming and outgoing calls. - // - // The trampoline contains the following bundles for the outgoing call: - // movl gp=target_gp; - // - // brl target_code; - // - // The trampoline contains the following bundles for the incoming call: - // alloc r41=ar.pfs, b, 0, 8, 0 - // mov r40=rp - // - // adds r50=0, r39 - // adds r49=0, r38 - // adds r48=0, r37 ;; - // - // adds r47=0, r36 - // adds r46=0, r35 - // adds r45=0, r34 - // - // adds r44=0, r33 - // adds r43=0, r32 - // adds r42=0, gp ;; - // - // movl gp=ffffffff`ffffffff ;; - // - // brl.call.sptk.few rp=disas!TestCodes+20e0 (00000000`00404ea0) ;; - // - // adds gp=0, r42 - // mov rp=r40, +0 ;; - // mov.i ar.pfs=r41 - // - // br.ret.sptk.many rp ;; - // - // This way, we only have to relocate a single bundle. - // - // The complicated incoming trampoline is required because we have to - // create an additional stack frame so that we save and restore the gp. - // We must do this because gp is a caller-saved register, but not saved - // if the caller thinks the target is in the same DLL, which changes - // when we insert a detour. - // - DETOUR_IA64_BUNDLE bMovlTargetGp; // Bundle which sets target GP - BYTE rbCode[sizeof(DETOUR_IA64_BUNDLE)]; // moved bundle. - DETOUR_IA64_BUNDLE bBrlRemainEip; // Brl to pbRemain - // This must be adjacent to bBranchIslands. - - // Each instruction in the moved bundle could be a IP-relative chk or branch or call. - // Any such instructions are changed to point to a brl in bBranchIslands. - // This must be adjacent to bBrlRemainEip -- see "pbPool". - DETOUR_IA64_BUNDLE bBranchIslands[DETOUR_IA64_INSTRUCTIONS_PER_BUNDLE]; - - // Target of brl inserted in target function - DETOUR_IA64_BUNDLE bAllocFrame; // alloc frame - DETOUR_IA64_BUNDLE bSave37to39; // save r37, r38, r39. - DETOUR_IA64_BUNDLE bSave34to36; // save r34, r35, r36. - DETOUR_IA64_BUNDLE bSaveGPto33; // save gp, r32, r33. - DETOUR_IA64_BUNDLE bMovlDetourGp; // set detour GP. - DETOUR_IA64_BUNDLE bCallDetour; // call detour. - DETOUR_IA64_BUNDLE bPopFrameGp; // pop frame and restore gp. - DETOUR_IA64_BUNDLE bReturn; // return to caller. - - PLABEL_DESCRIPTOR pldTrampoline; - - BYTE rbRestore[sizeof(DETOUR_IA64_BUNDLE)]; // original target bundle. - BYTE cbRestore; // size of original target code. - BYTE cbCode; // size of moved target code. - _DETOUR_ALIGN rAlign[14]; // instruction alignment array. - PBYTE pbRemain; // first instruction after moved code. [free list] - PBYTE pbDetour; // first instruction of detour function. - PPLABEL_DESCRIPTOR ppldDetour; // [pbDetour,gpDetour] - PPLABEL_DESCRIPTOR ppldTarget; // [pbTarget,gpDetour] -}; - -C_ASSERT(sizeof(DETOUR_IA64_BUNDLE) == 16); -C_ASSERT(sizeof(_DETOUR_TRAMPOLINE) == 256 + DETOUR_IA64_INSTRUCTIONS_PER_BUNDLE * 16); - -enum { - SIZE_OF_JMP = sizeof(DETOUR_IA64_BUNDLE) -}; - -inline PBYTE detour_skip_jmp(PBYTE pPointer, PVOID *ppGlobals) -{ - PBYTE pGlobals = NULL; - PBYTE pbCode = NULL; - - if (pPointer != NULL) { - PPLABEL_DESCRIPTOR ppld = (PPLABEL_DESCRIPTOR)pPointer; - pbCode = (PBYTE)ppld->EntryPoint; - pGlobals = (PBYTE)ppld->GlobalPointer; - } - if (ppGlobals != NULL) { - *ppGlobals = pGlobals; - } - if (pbCode == NULL) { - return NULL; - } - - DETOUR_IA64_BUNDLE *pb = (DETOUR_IA64_BUNDLE *)pbCode; - - // IA64 Local Import Jumps look like: - // addl r2=ffffffff`ffe021c0, gp ;; - // ld8 r2=[r2] - // nop.i 0 ;; - // - // ld8 r3=[r2], 8 ;; - // ld8 gp=[r2] - // mov b6=r3, +0 - // - // nop.m 0 - // nop.i 0 - // br.cond.sptk.few b6 - // - - // 002024000200100b - if ((pb[0].wide[0] & 0xfffffc000603ffff) == 0x002024000200100b && - pb[0].wide[1] == 0x0004000000203008 && - pb[1].wide[0] == 0x001014180420180a && - pb[1].wide[1] == 0x07000830c0203008 && - pb[2].wide[0] == 0x0000000100000010 && - pb[2].wide[1] == 0x0080006000000200) { - - ULONG64 offset = - ((pb[0].wide[0] & 0x0000000001fc0000) >> 18) | // imm7b - ((pb[0].wide[0] & 0x000001ff00000000) >> 25) | // imm9d - ((pb[0].wide[0] & 0x00000000f8000000) >> 11); // imm5c - if (pb[0].wide[0] & 0x0000020000000000) { // sign - offset |= 0xffffffffffe00000; - } - PBYTE pbTarget = pGlobals + offset; - DETOUR_TRACE(("%p: potential import jump, target=%p\n", pb, pbTarget)); - - if (detour_is_imported(pbCode, pbTarget) && *(PBYTE*)pbTarget != NULL) { - DETOUR_TRACE(("%p: is import jump, label=%p\n", pb, *(PBYTE *)pbTarget)); - - PPLABEL_DESCRIPTOR ppld = (PPLABEL_DESCRIPTOR)*(PBYTE *)pbTarget; - pbCode = (PBYTE)ppld->EntryPoint; - pGlobals = (PBYTE)ppld->GlobalPointer; - if (ppGlobals != NULL) { - *ppGlobals = pGlobals; - } - } - } - return pbCode; -} - - -inline void detour_find_jmp_bounds(PBYTE pbCode, - PDETOUR_TRAMPOLINE *ppLower, - PDETOUR_TRAMPOLINE *ppUpper) -{ - (void)pbCode; - *ppLower = (PDETOUR_TRAMPOLINE)(ULONG_PTR)0x0000000000080000; - *ppUpper = (PDETOUR_TRAMPOLINE)(ULONG_PTR)0xfffffffffff80000; -} - -inline BOOL detour_does_code_end_function(PBYTE pbCode) -{ - // Routine not needed on IA64. - (void)pbCode; - return FALSE; -} - -inline ULONG detour_is_code_filler(PBYTE pbCode) -{ - // Routine not needed on IA64. - (void)pbCode; - return 0; -} - -#endif // DETOURS_IA64 - -#ifdef DETOURS_ARM - -struct _DETOUR_TRAMPOLINE -{ - // A Thumb-2 instruction can be 2 or 4 bytes long. - BYTE rbCode[62]; // target code + jmp to pbRemain - BYTE cbCode; // size of moved target code. - BYTE cbCodeBreak; // padding to make debugging easier. - BYTE rbRestore[22]; // original target code. - BYTE cbRestore; // size of original target code. - BYTE cbRestoreBreak; // padding to make debugging easier. - _DETOUR_ALIGN rAlign[8]; // instruction alignment array. - PBYTE pbRemain; // first instruction after moved code. [free list] - PBYTE pbDetour; // first instruction of detour function. -}; - -C_ASSERT(sizeof(_DETOUR_TRAMPOLINE) == 104); - -enum { - SIZE_OF_JMP = 8 -}; - -inline PBYTE align4(PBYTE pValue) -{ - return (PBYTE)(((ULONG)pValue) & ~(ULONG)3u); -} - -inline ULONG fetch_thumb_opcode(PBYTE pbCode) -{ - ULONG Opcode = *(UINT16 *)&pbCode[0]; - if (Opcode >= 0xe800) { - Opcode = (Opcode << 16) | *(UINT16 *)&pbCode[2]; - } - return Opcode; -} - -inline void write_thumb_opcode(PBYTE &pbCode, ULONG Opcode) -{ - if (Opcode >= 0x10000) { - *((UINT16*&)pbCode)++ = Opcode >> 16; - } - *((UINT16*&)pbCode)++ = (UINT16)Opcode; -} - -PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE *ppPool, PBYTE pbJmpVal) -{ - PBYTE pbLiteral; - if (ppPool != NULL) { - *ppPool = *ppPool - 4; - pbLiteral = *ppPool; - } - else { - pbLiteral = align4(pbCode + 6); - } - - *((PBYTE*&)pbLiteral) = DETOURS_PBYTE_TO_PFUNC(pbJmpVal); - LONG delta = pbLiteral - align4(pbCode + 4); - - write_thumb_opcode(pbCode, 0xf8dff000 | delta); // LDR PC,[PC+n] - - if (ppPool == NULL) { - if (((ULONG)pbCode & 2) != 0) { - write_thumb_opcode(pbCode, 0xdefe); // BREAK - } - pbCode += 4; - } - return pbCode; -} - -inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit) -{ - while (pbCode < pbLimit) { - write_thumb_opcode(pbCode, 0xdefe); - } - return pbCode; -} - -inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals) -{ - if (pbCode == NULL) { - return NULL; - } - if (ppGlobals != NULL) { - *ppGlobals = NULL; - } - - // Skip over the import jump if there is one. - pbCode = (PBYTE)DETOURS_PFUNC_TO_PBYTE(pbCode); - ULONG Opcode = fetch_thumb_opcode(pbCode); - - if ((Opcode & 0xfbf08f00) == 0xf2400c00) { // movw r12,#xxxx - ULONG Opcode2 = fetch_thumb_opcode(pbCode+4); - - if ((Opcode2 & 0xfbf08f00) == 0xf2c00c00) { // movt r12,#xxxx - ULONG Opcode3 = fetch_thumb_opcode(pbCode+8); - if (Opcode3 == 0xf8dcf000) { // ldr pc,[r12] - PBYTE pbTarget = (PBYTE)(((Opcode2 << 12) & 0xf7000000) | - ((Opcode2 << 1) & 0x08000000) | - ((Opcode2 << 16) & 0x00ff0000) | - ((Opcode >> 4) & 0x0000f700) | - ((Opcode >> 15) & 0x00000800) | - ((Opcode >> 0) & 0x000000ff)); - if (detour_is_imported(pbCode, pbTarget)) { - PBYTE pbNew = *(PBYTE *)pbTarget; - pbNew = DETOURS_PFUNC_TO_PBYTE(pbNew); - DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew)); - return pbNew; - } - } - } - } - return pbCode; -} - -inline void detour_find_jmp_bounds(PBYTE pbCode, - PDETOUR_TRAMPOLINE *ppLower, - PDETOUR_TRAMPOLINE *ppUpper) -{ - (void)pbCode; - *ppLower = (PDETOUR_TRAMPOLINE)(ULONG_PTR)0x00080000; - *ppUpper = (PDETOUR_TRAMPOLINE)(ULONG_PTR)0xfff80000; -} - -inline BOOL detour_does_code_end_function(PBYTE pbCode) -{ - ULONG Opcode = fetch_thumb_opcode(pbCode); - if ((Opcode & 0xffffff87) == 0x4700 || // bx - (Opcode & 0xf800d000) == 0xf0009000) { // b - return TRUE; - } - if ((Opcode & 0xffff8000) == 0xe8bd8000) { // pop {...,pc} - __debugbreak(); - return TRUE; - } - if ((Opcode & 0xffffff00) == 0x0000bd00) { // pop {...,pc} - __debugbreak(); - return TRUE; - } - return FALSE; -} - -inline ULONG detour_is_code_filler(PBYTE pbCode) -{ - if (pbCode[0] == 0x00 && pbCode[1] == 0xbf) { // nop. - return 2; - } - if (pbCode[0] == 0x00 && pbCode[1] == 0x00) { // zero-filled padding. - return 2; - } - return 0; -} - -#endif // DETOURS_ARM - -#ifdef DETOURS_ARM64 - -struct _DETOUR_TRAMPOLINE -{ - // An ARM64 instruction is 4 bytes long. - BYTE rbCode[64]; // target code + jmp to pbRemain - BYTE cbCode; // size of moved target code. - BYTE cbCodeBreak[3]; // padding to make debugging easier. - BYTE rbRestore[24]; // original target code. - BYTE cbRestore; // size of original target code. - BYTE cbRestoreBreak[3]; // padding to make debugging easier. - _DETOUR_ALIGN rAlign[8]; // instruction alignment array. - PBYTE pbRemain; // first instruction after moved code. [free list] - PBYTE pbDetour; // first instruction of detour function. -}; - -C_ASSERT(sizeof(_DETOUR_TRAMPOLINE) == 120); - -enum { - SIZE_OF_JMP = 16 -}; - -inline ULONG fetch_opcode(PBYTE pbCode) -{ - return *(ULONG *)pbCode; -} - -inline void write_opcode(PBYTE &pbCode, ULONG Opcode) -{ - *(ULONG *)pbCode = Opcode; - pbCode += 4; -} - -PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE *ppPool, PBYTE pbJmpVal) -{ - PBYTE pbLiteral; - if (ppPool != NULL) { - *ppPool = *ppPool - 8; - pbLiteral = *ppPool; - } - else { - pbLiteral = pbCode + 8; - } - - *((PBYTE*&)pbLiteral) = pbJmpVal; - LONG delta = (LONG)(pbLiteral - pbCode); - - write_opcode(pbCode, 0x58000011 | ((delta / 4) << 5)); // LDR X17,[PC+n] - write_opcode(pbCode, 0xd61f0000 | (17 << 5)); // BR X17 - - if (ppPool == NULL) { - pbCode += 8; - } - return pbCode; -} - -inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit) -{ - while (pbCode < pbLimit) { - write_opcode(pbCode, 0xd4100000 | (0xf000 << 5)); - } - return pbCode; -} - -inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals) -{ - if (pbCode == NULL) { - return NULL; - } - if (ppGlobals != NULL) { - *ppGlobals = NULL; - } - - // Skip over the import jump if there is one. - pbCode = (PBYTE)pbCode; - ULONG Opcode = fetch_opcode(pbCode); - if ((Opcode & 0x9f00001f) == 0x90000010) { // adrp x16, IAT - ULONG Opcode2 = fetch_opcode(pbCode+4); - - if ((Opcode2 & 0xffe003ff) == 0xf9400210) { // ldr x16, [x16, IAT] - ULONG Opcode3 = fetch_opcode(pbCode+8); - - if (Opcode3 == 0xd61f0200) { // br x16 - - ULONG PageOffset = ((Opcode & 0x60000000) >> 29) | ((Opcode & 0x00ffffe0) >> 3); - PageOffset = (LONG)(Opcode << 11) >> 11; - - PBYTE pbTarget = (PBYTE)(((ULONG64)pbCode & 0xfffffffffffff000ULL) + PageOffset + - ((Opcode2 >> 10) & 0xfff)); - if (detour_is_imported(pbCode, pbTarget)) { - PBYTE pbNew = *(PBYTE *)pbTarget; - DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew)); - return pbNew; - } - } - } - } - return pbCode; -} - -inline void detour_find_jmp_bounds(PBYTE pbCode, - PDETOUR_TRAMPOLINE *ppLower, - PDETOUR_TRAMPOLINE *ppUpper) -{ - (void)pbCode; - *ppLower = (PDETOUR_TRAMPOLINE)(ULONG_PTR)0x0000000000080000; - *ppUpper = (PDETOUR_TRAMPOLINE)(ULONG_PTR)0xfffffffffff80000; -} - -inline BOOL detour_does_code_end_function(PBYTE pbCode) -{ - ULONG Opcode = fetch_opcode(pbCode); - if ((Opcode & 0xfffffc1f) == 0xd65f0000 || // br - (Opcode & 0xfc000000) == 0x14000000) { // b - return TRUE; - } - return FALSE; -} - -inline ULONG detour_is_code_filler(PBYTE pbCode) -{ - if (*(ULONG *)pbCode == 0xd503201f) { // nop. - return 4; - } - if (*(ULONG *)pbCode == 0x00000000) { // zero-filled padding. - return 4; - } - return 0; -} - -#endif // DETOURS_ARM64 - -//////////////////////////////////////////////// Trampoline Memory Management. -// -struct DETOUR_REGION -{ - ULONG dwSignature; - DETOUR_REGION * pNext; // Next region in list of regions. - DETOUR_TRAMPOLINE * pFree; // List of free trampolines in this region. -}; -typedef DETOUR_REGION * PDETOUR_REGION; - -const ULONG DETOUR_REGION_SIGNATURE = 'Rrtd'; -const ULONG DETOUR_REGION_SIZE = 0x10000; -const ULONG DETOUR_TRAMPOLINES_PER_REGION = (DETOUR_REGION_SIZE - / sizeof(DETOUR_TRAMPOLINE)) - 1; -static PDETOUR_REGION s_pRegions = NULL; // List of all regions. -static PDETOUR_REGION s_pRegion = NULL; // Default region. - -static DWORD detour_writable_trampoline_regions() -{ - // Mark all of the regions as writable. - for (PDETOUR_REGION pRegion = s_pRegions; pRegion != NULL; pRegion = pRegion->pNext) { - DWORD dwOld; - if (!VirtualProtect(pRegion, DETOUR_REGION_SIZE, PAGE_EXECUTE_READWRITE, &dwOld)) { - return GetLastError(); - } - } - return NO_ERROR; -} - -static void detour_runnable_trampoline_regions() -{ - HANDLE hProcess = GetCurrentProcess(); - - // Mark all of the regions as executable. - for (PDETOUR_REGION pRegion = s_pRegions; pRegion != NULL; pRegion = pRegion->pNext) { - DWORD dwOld; - VirtualProtect(pRegion, DETOUR_REGION_SIZE, PAGE_EXECUTE_READ, &dwOld); - FlushInstructionCache(hProcess, pRegion, DETOUR_REGION_SIZE); - } -} - -static PBYTE detour_alloc_round_down_to_region(PBYTE pbTry) -{ - // WinXP64 returns free areas that aren't REGION aligned to 32-bit applications. - ULONG_PTR extra = ((ULONG_PTR)pbTry) & (DETOUR_REGION_SIZE - 1); - if (extra != 0) { - pbTry -= extra; - } - return pbTry; -} - -static PBYTE detour_alloc_round_up_to_region(PBYTE pbTry) -{ - // WinXP64 returns free areas that aren't REGION aligned to 32-bit applications. - ULONG_PTR extra = ((ULONG_PTR)pbTry) & (DETOUR_REGION_SIZE - 1); - if (extra != 0) { - ULONG_PTR adjust = DETOUR_REGION_SIZE - extra; - pbTry += adjust; - } - return pbTry; -} - -// Starting at pbLo, try to allocate a memory region, continue until pbHi. - -static PVOID detour_alloc_region_from_lo(PBYTE pbLo, PBYTE pbHi) -{ - PBYTE pbTry = detour_alloc_round_up_to_region(pbLo); - - DETOUR_TRACE((" Looking for free region in %p..%p from %p:\n", pbLo, pbHi, pbTry)); - - for (; pbTry < pbHi;) { - MEMORY_BASIC_INFORMATION mbi; - - if (pbTry >= s_pSystemRegionLowerBound && pbTry <= s_pSystemRegionUpperBound) { - // Skip region reserved for system DLLs, but preserve address space entropy. - pbTry += 0x08000000; - continue; - } - - ZeroMemory(&mbi, sizeof(mbi)); - if (!VirtualQuery(pbTry, &mbi, sizeof(mbi))) { - break; - } - - DETOUR_TRACE((" Try %p => %p..%p %6x\n", - pbTry, - mbi.BaseAddress, - (PBYTE)mbi.BaseAddress + mbi.RegionSize - 1, - mbi.State)); - - if (mbi.State == MEM_FREE && mbi.RegionSize >= DETOUR_REGION_SIZE) { - - PVOID pv = VirtualAlloc(pbTry, - DETOUR_REGION_SIZE, - MEM_COMMIT|MEM_RESERVE, - PAGE_EXECUTE_READWRITE); - if (pv != NULL) { - return pv; - } - pbTry += DETOUR_REGION_SIZE; - } - else { - pbTry = detour_alloc_round_up_to_region((PBYTE)mbi.BaseAddress + mbi.RegionSize); - } - } - return NULL; -} - -// Starting at pbHi, try to allocate a memory region, continue until pbLo. - -static PVOID detour_alloc_region_from_hi(PBYTE pbLo, PBYTE pbHi) -{ - PBYTE pbTry = detour_alloc_round_down_to_region(pbHi - DETOUR_REGION_SIZE); - - DETOUR_TRACE((" Looking for free region in %p..%p from %p:\n", pbLo, pbHi, pbTry)); - - for (; pbTry > pbLo;) { - MEMORY_BASIC_INFORMATION mbi; - - DETOUR_TRACE((" Try %p\n", pbTry)); - if (pbTry >= s_pSystemRegionLowerBound && pbTry <= s_pSystemRegionUpperBound) { - // Skip region reserved for system DLLs, but preserve address space entropy. - pbTry -= 0x08000000; - continue; - } - - ZeroMemory(&mbi, sizeof(mbi)); - if (!VirtualQuery(pbTry, &mbi, sizeof(mbi))) { - break; - } - - DETOUR_TRACE((" Try %p => %p..%p %6x\n", - pbTry, - mbi.BaseAddress, - (PBYTE)mbi.BaseAddress + mbi.RegionSize - 1, - mbi.State)); - - if (mbi.State == MEM_FREE && mbi.RegionSize >= DETOUR_REGION_SIZE) { - - PVOID pv = VirtualAlloc(pbTry, - DETOUR_REGION_SIZE, - MEM_COMMIT|MEM_RESERVE, - PAGE_EXECUTE_READWRITE); - if (pv != NULL) { - return pv; - } - pbTry -= DETOUR_REGION_SIZE; - } - else { - pbTry = detour_alloc_round_down_to_region((PBYTE)mbi.AllocationBase - - DETOUR_REGION_SIZE); - } - } - return NULL; -} - -static PDETOUR_TRAMPOLINE detour_alloc_trampoline(PBYTE pbTarget) -{ - // We have to place trampolines within +/- 2GB of target. - - PDETOUR_TRAMPOLINE pLo; - PDETOUR_TRAMPOLINE pHi; - - detour_find_jmp_bounds(pbTarget, &pLo, &pHi); - - PDETOUR_TRAMPOLINE pTrampoline = NULL; - - // Insure that there is a default region. - if (s_pRegion == NULL && s_pRegions != NULL) { - s_pRegion = s_pRegions; - } - - // First check the default region for an valid free block. - if (s_pRegion != NULL && s_pRegion->pFree != NULL && - s_pRegion->pFree >= pLo && s_pRegion->pFree <= pHi) { - - found_region: - pTrampoline = s_pRegion->pFree; - // do a last sanity check on region. - if (pTrampoline < pLo || pTrampoline > pHi) { - return NULL; - } - s_pRegion->pFree = (PDETOUR_TRAMPOLINE)pTrampoline->pbRemain; - memset(pTrampoline, 0xcc, sizeof(*pTrampoline)); - return pTrampoline; - } - - // Then check the existing regions for a valid free block. - for (s_pRegion = s_pRegions; s_pRegion != NULL; s_pRegion = s_pRegion->pNext) { - if (s_pRegion != NULL && s_pRegion->pFree != NULL && - s_pRegion->pFree >= pLo && s_pRegion->pFree <= pHi) { - goto found_region; - } - } - - // We need to allocate a new region. - - // Round pbTarget down to 64KB block. - pbTarget = pbTarget - (PtrToUlong(pbTarget) & 0xffff); - - PVOID pbTry = NULL; - - // NB: We must always also start the search at an offset from pbTarget - // in order to maintain ASLR entropy. - -#if defined(DETOURS_64BIT) - // Try looking 1GB below or lower. - if (pbTry == NULL && pbTarget > (PBYTE)0x40000000) { - pbTry = detour_alloc_region_from_hi((PBYTE)pLo, pbTarget - 0x40000000); - } - // Try looking 1GB above or higher. - if (pbTry == NULL && pbTarget < (PBYTE)0xffffffff40000000) { - pbTry = detour_alloc_region_from_lo(pbTarget + 0x40000000, (PBYTE)pHi); - } - // Try looking 1GB below or higher. - if (pbTry == NULL && pbTarget > (PBYTE)0x40000000) { - pbTry = detour_alloc_region_from_lo(pbTarget - 0x40000000, pbTarget); - } - // Try looking 1GB above or lower. - if (pbTry == NULL && pbTarget < (PBYTE)0xffffffff40000000) { - pbTry = detour_alloc_region_from_hi(pbTarget, pbTarget + 0x40000000); - } -#endif - - // Try anything below. - if (pbTry == NULL) { - pbTry = detour_alloc_region_from_hi((PBYTE)pLo, pbTarget); - } - // try anything above. - if (pbTry == NULL) { - pbTry = detour_alloc_region_from_lo(pbTarget, (PBYTE)pHi); - } - - if (pbTry != NULL) { - s_pRegion = (DETOUR_REGION*)pbTry; - s_pRegion->dwSignature = DETOUR_REGION_SIGNATURE; - s_pRegion->pFree = NULL; - s_pRegion->pNext = s_pRegions; - s_pRegions = s_pRegion; - DETOUR_TRACE((" Allocated region %p..%p\n\n", - s_pRegion, ((PBYTE)s_pRegion) + DETOUR_REGION_SIZE - 1)); - - // Put everything but the first trampoline on the free list. - PBYTE pFree = NULL; - pTrampoline = ((PDETOUR_TRAMPOLINE)s_pRegion) + 1; - for (int i = DETOUR_TRAMPOLINES_PER_REGION - 1; i > 1; i--) { - pTrampoline[i].pbRemain = pFree; - pFree = (PBYTE)&pTrampoline[i]; - } - s_pRegion->pFree = (PDETOUR_TRAMPOLINE)pFree; - goto found_region; - } - - DETOUR_TRACE(("Couldn't find available memory region!\n")); - return NULL; -} - -static void detour_free_trampoline(PDETOUR_TRAMPOLINE pTrampoline) -{ - PDETOUR_REGION pRegion = (PDETOUR_REGION) - ((ULONG_PTR)pTrampoline & ~(ULONG_PTR)0xffff); - - memset(pTrampoline, 0, sizeof(*pTrampoline)); - pTrampoline->pbRemain = (PBYTE)pRegion->pFree; - pRegion->pFree = pTrampoline; -} - -static BOOL detour_is_region_empty(PDETOUR_REGION pRegion) -{ - // Stop if the region isn't a region (this would be bad). - if (pRegion->dwSignature != DETOUR_REGION_SIGNATURE) { - return FALSE; - } - - PBYTE pbRegionBeg = (PBYTE)pRegion; - PBYTE pbRegionLim = pbRegionBeg + DETOUR_REGION_SIZE; - - // Stop if any of the trampolines aren't free. - PDETOUR_TRAMPOLINE pTrampoline = ((PDETOUR_TRAMPOLINE)pRegion) + 1; - for (int i = 0; i < DETOUR_TRAMPOLINES_PER_REGION; i++) { - if (pTrampoline[i].pbRemain != NULL && - (pTrampoline[i].pbRemain < pbRegionBeg || - pTrampoline[i].pbRemain >= pbRegionLim)) { - return FALSE; - } - } - - // OK, the region is empty. - return TRUE; -} - -static void detour_free_unused_trampoline_regions() -{ - PDETOUR_REGION *ppRegionBase = &s_pRegions; - PDETOUR_REGION pRegion = s_pRegions; - - while (pRegion != NULL) { - if (detour_is_region_empty(pRegion)) { - *ppRegionBase = pRegion->pNext; - - VirtualFree(pRegion, 0, MEM_RELEASE); - s_pRegion = NULL; - } - else { - ppRegionBase = &pRegion->pNext; - } - pRegion = *ppRegionBase; - } -} - -///////////////////////////////////////////////////////// Transaction Structs. -// -struct DetourThread -{ - DetourThread * pNext; - HANDLE hThread; -}; - -struct DetourOperation -{ - DetourOperation * pNext; - BOOL fIsRemove; - PBYTE * ppbPointer; - PBYTE pbTarget; - PDETOUR_TRAMPOLINE pTrampoline; - ULONG dwPerm; -}; - -static BOOL s_fIgnoreTooSmall = FALSE; -static BOOL s_fRetainRegions = FALSE; - -static LONG s_nPendingThreadId = 0; // Thread owning pending transaction. -static LONG s_nPendingError = NO_ERROR; -static PVOID * s_ppPendingError = NULL; -static DetourThread * s_pPendingThreads = NULL; -static DetourOperation * s_pPendingOperations = NULL; - -////////////////////////////////////////////////////////////////////////////// -// -PVOID WINAPI DetourCodeFromPointer(_In_ PVOID pPointer, - _Out_opt_ PVOID *ppGlobals) -{ - return detour_skip_jmp((PBYTE)pPointer, ppGlobals); -} - -//////////////////////////////////////////////////////////// Transaction APIs. -// -BOOL WINAPI DetourSetIgnoreTooSmall(_In_ BOOL fIgnore) -{ - BOOL fPrevious = s_fIgnoreTooSmall; - s_fIgnoreTooSmall = fIgnore; - return fPrevious; -} - -BOOL WINAPI DetourSetRetainRegions(_In_ BOOL fRetain) -{ - BOOL fPrevious = s_fRetainRegions; - s_fRetainRegions = fRetain; - return fPrevious; -} - -PVOID WINAPI DetourSetSystemRegionLowerBound(_In_ PVOID pSystemRegionLowerBound) -{ - PVOID pPrevious = s_pSystemRegionLowerBound; - s_pSystemRegionLowerBound = pSystemRegionLowerBound; - return pPrevious; -} - -PVOID WINAPI DetourSetSystemRegionUpperBound(_In_ PVOID pSystemRegionUpperBound) -{ - PVOID pPrevious = s_pSystemRegionUpperBound; - s_pSystemRegionUpperBound = pSystemRegionUpperBound; - return pPrevious; -} - -LONG WINAPI DetourTransactionBegin() -{ - // Only one transaction is allowed at a time. -_Benign_race_begin_ - if (s_nPendingThreadId != 0) { - return ERROR_INVALID_OPERATION; - } -_Benign_race_end_ - - // Make sure only one thread can start a transaction. - if (InterlockedCompareExchange(&s_nPendingThreadId, (LONG)GetCurrentThreadId(), 0) != 0) { - return ERROR_INVALID_OPERATION; - } - - s_pPendingOperations = NULL; - s_pPendingThreads = NULL; - s_ppPendingError = NULL; - - // Make sure the trampoline pages are writable. - s_nPendingError = detour_writable_trampoline_regions(); - - return s_nPendingError; -} - -LONG WINAPI DetourTransactionAbort() -{ - if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) { - return ERROR_INVALID_OPERATION; - } - - // Restore all of the page permissions. - for (DetourOperation *o = s_pPendingOperations; o != NULL;) { - // We don't care if this fails, because the code is still accessible. - DWORD dwOld; - VirtualProtect(o->pbTarget, o->pTrampoline->cbRestore, - o->dwPerm, &dwOld); - - if (!o->fIsRemove) { - if (o->pTrampoline) { - detour_free_trampoline(o->pTrampoline); - o->pTrampoline = NULL; - } - } - - DetourOperation *n = o->pNext; - delete o; - o = n; - } - s_pPendingOperations = NULL; - - // Make sure the trampoline pages are no longer writable. - detour_runnable_trampoline_regions(); - - // Resume any suspended threads. - for (DetourThread *t = s_pPendingThreads; t != NULL;) { - // There is nothing we can do if this fails. - ResumeThread(t->hThread); - - DetourThread *n = t->pNext; - delete t; - t = n; - } - s_pPendingThreads = NULL; - s_nPendingThreadId = 0; - - return NO_ERROR; -} - -LONG WINAPI DetourTransactionCommit() -{ - return DetourTransactionCommitEx(NULL); -} - -static BYTE detour_align_from_trampoline(PDETOUR_TRAMPOLINE pTrampoline, BYTE obTrampoline) -{ - for (LONG n = 0; n < ARRAYSIZE(pTrampoline->rAlign); n++) { - if (pTrampoline->rAlign[n].obTrampoline == obTrampoline) { - return pTrampoline->rAlign[n].obTarget; - } - } - return 0; -} - -static LONG detour_align_from_target(PDETOUR_TRAMPOLINE pTrampoline, LONG obTarget) -{ - for (LONG n = 0; n < ARRAYSIZE(pTrampoline->rAlign); n++) { - if (pTrampoline->rAlign[n].obTarget == obTarget) { - return pTrampoline->rAlign[n].obTrampoline; - } - } - return 0; -} - -LONG WINAPI DetourTransactionCommitEx(_Out_opt_ PVOID **pppFailedPointer) -{ - if (pppFailedPointer != NULL) { - // Used to get the last error. - *pppFailedPointer = s_ppPendingError; - } - if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) { - return ERROR_INVALID_OPERATION; - } - - // If any of the pending operations failed, then we abort the whole transaction. - if (s_nPendingError != NO_ERROR) { - DETOUR_BREAK(); - DetourTransactionAbort(); - return s_nPendingError; - } - - // Common variables. - DetourOperation *o; - DetourThread *t; - BOOL freed = FALSE; - - // Insert or remove each of the detours. - for (o = s_pPendingOperations; o != NULL; o = o->pNext) { - if (o->fIsRemove) { - CopyMemory(o->pbTarget, - o->pTrampoline->rbRestore, - o->pTrampoline->cbRestore); -#ifdef DETOURS_IA64 - *o->ppbPointer = (PBYTE)o->pTrampoline->ppldTarget; -#endif // DETOURS_IA64 - -#ifdef DETOURS_X86 - *o->ppbPointer = o->pbTarget; -#endif // DETOURS_X86 - -#ifdef DETOURS_X64 - *o->ppbPointer = o->pbTarget; -#endif // DETOURS_X64 - -#ifdef DETOURS_ARM - *o->ppbPointer = DETOURS_PBYTE_TO_PFUNC(o->pbTarget); -#endif // DETOURS_ARM - -#ifdef DETOURS_ARM64 - *o->ppbPointer = o->pbTarget; -#endif // DETOURS_ARM - } - else { - DETOUR_TRACE(("detours: pbTramp =%p, pbRemain=%p, pbDetour=%p, cbRestore=%d\n", - o->pTrampoline, - o->pTrampoline->pbRemain, - o->pTrampoline->pbDetour, - o->pTrampoline->cbRestore)); - - DETOUR_TRACE(("detours: pbTarget=%p: " - "%02x %02x %02x %02x " - "%02x %02x %02x %02x " - "%02x %02x %02x %02x [before]\n", - o->pbTarget, - o->pbTarget[0], o->pbTarget[1], o->pbTarget[2], o->pbTarget[3], - o->pbTarget[4], o->pbTarget[5], o->pbTarget[6], o->pbTarget[7], - o->pbTarget[8], o->pbTarget[9], o->pbTarget[10], o->pbTarget[11])); - -#ifdef DETOURS_IA64 - ((DETOUR_IA64_BUNDLE*)o->pbTarget) - ->SetBrl((UINT64)&o->pTrampoline->bAllocFrame); - *o->ppbPointer = (PBYTE)&o->pTrampoline->pldTrampoline; -#endif // DETOURS_IA64 - -#ifdef DETOURS_X64 - detour_gen_jmp_indirect(o->pTrampoline->rbCodeIn, &o->pTrampoline->pbDetour); - PBYTE pbCode = detour_gen_jmp_immediate(o->pbTarget, o->pTrampoline->rbCodeIn); - pbCode = detour_gen_brk(pbCode, o->pTrampoline->pbRemain); - *o->ppbPointer = o->pTrampoline->rbCode; - UNREFERENCED_PARAMETER(pbCode); -#endif // DETOURS_X64 - -#ifdef DETOURS_X86 - PBYTE pbCode = detour_gen_jmp_immediate(o->pbTarget, o->pTrampoline->pbDetour); - pbCode = detour_gen_brk(pbCode, o->pTrampoline->pbRemain); - *o->ppbPointer = o->pTrampoline->rbCode; - UNREFERENCED_PARAMETER(pbCode); -#endif // DETOURS_X86 - -#ifdef DETOURS_ARM - PBYTE pbCode = detour_gen_jmp_immediate(o->pbTarget, NULL, o->pTrampoline->pbDetour); - pbCode = detour_gen_brk(pbCode, o->pTrampoline->pbRemain); - *o->ppbPointer = DETOURS_PBYTE_TO_PFUNC(o->pTrampoline->rbCode); - UNREFERENCED_PARAMETER(pbCode); -#endif // DETOURS_ARM - -#ifdef DETOURS_ARM64 - PBYTE pbCode = detour_gen_jmp_immediate(o->pbTarget, NULL, o->pTrampoline->pbDetour); - pbCode = detour_gen_brk(pbCode, o->pTrampoline->pbRemain); - *o->ppbPointer = o->pTrampoline->rbCode; - UNREFERENCED_PARAMETER(pbCode); -#endif // DETOURS_ARM64 - - DETOUR_TRACE(("detours: pbTarget=%p: " - "%02x %02x %02x %02x " - "%02x %02x %02x %02x " - "%02x %02x %02x %02x [after]\n", - o->pbTarget, - o->pbTarget[0], o->pbTarget[1], o->pbTarget[2], o->pbTarget[3], - o->pbTarget[4], o->pbTarget[5], o->pbTarget[6], o->pbTarget[7], - o->pbTarget[8], o->pbTarget[9], o->pbTarget[10], o->pbTarget[11])); - - DETOUR_TRACE(("detours: pbTramp =%p: " - "%02x %02x %02x %02x " - "%02x %02x %02x %02x " - "%02x %02x %02x %02x\n", - o->pTrampoline, - o->pTrampoline->rbCode[0], o->pTrampoline->rbCode[1], - o->pTrampoline->rbCode[2], o->pTrampoline->rbCode[3], - o->pTrampoline->rbCode[4], o->pTrampoline->rbCode[5], - o->pTrampoline->rbCode[6], o->pTrampoline->rbCode[7], - o->pTrampoline->rbCode[8], o->pTrampoline->rbCode[9], - o->pTrampoline->rbCode[10], o->pTrampoline->rbCode[11])); - -#ifdef DETOURS_IA64 - DETOUR_TRACE(("\n")); - DETOUR_TRACE(("detours: &pldTrampoline =%p\n", - &o->pTrampoline->pldTrampoline)); - DETOUR_TRACE(("detours: &bMovlTargetGp =%p [%p]\n", - &o->pTrampoline->bMovlTargetGp, - o->pTrampoline->bMovlTargetGp.GetMovlGp())); - DETOUR_TRACE(("detours: &rbCode =%p [%p]\n", - &o->pTrampoline->rbCode, - ((DETOUR_IA64_BUNDLE&)o->pTrampoline->rbCode).GetBrlTarget())); - DETOUR_TRACE(("detours: &bBrlRemainEip =%p [%p]\n", - &o->pTrampoline->bBrlRemainEip, - o->pTrampoline->bBrlRemainEip.GetBrlTarget())); - DETOUR_TRACE(("detours: &bMovlDetourGp =%p [%p]\n", - &o->pTrampoline->bMovlDetourGp, - o->pTrampoline->bMovlDetourGp.GetMovlGp())); - DETOUR_TRACE(("detours: &bBrlDetourEip =%p [%p]\n", - &o->pTrampoline->bCallDetour, - o->pTrampoline->bCallDetour.GetBrlTarget())); - DETOUR_TRACE(("detours: pldDetour =%p [%p]\n", - o->pTrampoline->ppldDetour->EntryPoint, - o->pTrampoline->ppldDetour->GlobalPointer)); - DETOUR_TRACE(("detours: pldTarget =%p [%p]\n", - o->pTrampoline->ppldTarget->EntryPoint, - o->pTrampoline->ppldTarget->GlobalPointer)); - DETOUR_TRACE(("detours: pbRemain =%p\n", - o->pTrampoline->pbRemain)); - DETOUR_TRACE(("detours: pbDetour =%p\n", - o->pTrampoline->pbDetour)); - DETOUR_TRACE(("\n")); -#endif // DETOURS_IA64 - } - } - - // Update any suspended threads. - for (t = s_pPendingThreads; t != NULL; t = t->pNext) { - CONTEXT cxt; - cxt.ContextFlags = CONTEXT_CONTROL; - -#undef DETOURS_EIP - -#ifdef DETOURS_X86 -#define DETOURS_EIP Eip -#endif // DETOURS_X86 - -#ifdef DETOURS_X64 -#define DETOURS_EIP Rip -#endif // DETOURS_X64 - -#ifdef DETOURS_IA64 -#define DETOURS_EIP StIIP -#endif // DETOURS_IA64 - -#ifdef DETOURS_ARM -#define DETOURS_EIP Pc -#endif // DETOURS_ARM - -#ifdef DETOURS_ARM64 -#define DETOURS_EIP Pc -#endif // DETOURS_ARM64 - -typedef ULONG_PTR DETOURS_EIP_TYPE; - - if (GetThreadContext(t->hThread, &cxt)) { - for (o = s_pPendingOperations; o != NULL; o = o->pNext) { - if (o->fIsRemove) { - if (cxt.DETOURS_EIP >= (DETOURS_EIP_TYPE)(ULONG_PTR)o->pTrampoline && - cxt.DETOURS_EIP < (DETOURS_EIP_TYPE)((ULONG_PTR)o->pTrampoline - + sizeof(o->pTrampoline)) - ) { - - cxt.DETOURS_EIP = (DETOURS_EIP_TYPE) - ((ULONG_PTR)o->pbTarget - + detour_align_from_trampoline(o->pTrampoline, - (BYTE)(cxt.DETOURS_EIP - - (DETOURS_EIP_TYPE)(ULONG_PTR) - o->pTrampoline))); - - SetThreadContext(t->hThread, &cxt); - } - } - else { - if (cxt.DETOURS_EIP >= (DETOURS_EIP_TYPE)(ULONG_PTR)o->pbTarget && - cxt.DETOURS_EIP < (DETOURS_EIP_TYPE)((ULONG_PTR)o->pbTarget - + o->pTrampoline->cbRestore) - ) { - - cxt.DETOURS_EIP = (DETOURS_EIP_TYPE) - ((ULONG_PTR)o->pTrampoline - + detour_align_from_target(o->pTrampoline, - (BYTE)(cxt.DETOURS_EIP - - (DETOURS_EIP_TYPE)(ULONG_PTR) - o->pbTarget))); - - SetThreadContext(t->hThread, &cxt); - } - } - } - } -#undef DETOURS_EIP - } - - // Restore all of the page permissions and flush the icache. - HANDLE hProcess = GetCurrentProcess(); - for (o = s_pPendingOperations; o != NULL;) { - // We don't care if this fails, because the code is still accessible. - DWORD dwOld; - VirtualProtect(o->pbTarget, o->pTrampoline->cbRestore, o->dwPerm, &dwOld); - FlushInstructionCache(hProcess, o->pbTarget, o->pTrampoline->cbRestore); - - if (o->fIsRemove && o->pTrampoline) { - detour_free_trampoline(o->pTrampoline); - o->pTrampoline = NULL; - freed = true; - } - - DetourOperation *n = o->pNext; - delete o; - o = n; - } - s_pPendingOperations = NULL; - - // Free any trampoline regions that are now unused. - if (freed && !s_fRetainRegions) { - detour_free_unused_trampoline_regions(); - } - - // Make sure the trampoline pages are no longer writable. - detour_runnable_trampoline_regions(); - - // Resume any suspended threads. - for (t = s_pPendingThreads; t != NULL;) { - // There is nothing we can do if this fails. - ResumeThread(t->hThread); - - DetourThread *n = t->pNext; - delete t; - t = n; - } - s_pPendingThreads = NULL; - s_nPendingThreadId = 0; - - if (pppFailedPointer != NULL) { - *pppFailedPointer = s_ppPendingError; - } - - return s_nPendingError; -} - -LONG WINAPI DetourUpdateThread(_In_ HANDLE hThread) -{ - LONG error; - - // If any of the pending operations failed, then we don't need to do this. - if (s_nPendingError != NO_ERROR) { - return s_nPendingError; - } - - // Silently (and safely) drop any attempt to suspend our own thread. - if (hThread == GetCurrentThread()) { - return NO_ERROR; - } - - DetourThread *t = new NOTHROW DetourThread; - if (t == NULL) { - error = ERROR_NOT_ENOUGH_MEMORY; - fail: - if (t != NULL) { - delete t; - t = NULL; - } - s_nPendingError = error; - s_ppPendingError = NULL; - DETOUR_BREAK(); - return error; - } - - if (SuspendThread(hThread) == (DWORD)-1) { - error = GetLastError(); - DETOUR_BREAK(); - goto fail; - } - - t->hThread = hThread; - t->pNext = s_pPendingThreads; - s_pPendingThreads = t; - - return NO_ERROR; -} - -///////////////////////////////////////////////////////////// Transacted APIs. -// -LONG WINAPI DetourAttach(_Inout_ PVOID *ppPointer, - _In_ PVOID pDetour) -{ - return DetourAttachEx(ppPointer, pDetour, NULL, NULL, NULL); -} - -LONG WINAPI DetourAttachEx(_Inout_ PVOID *ppPointer, - _In_ PVOID pDetour, - _Out_opt_ PDETOUR_TRAMPOLINE *ppRealTrampoline, - _Out_opt_ PVOID *ppRealTarget, - _Out_opt_ PVOID *ppRealDetour) -{ - LONG error = NO_ERROR; - - if (ppRealTrampoline != NULL) { - *ppRealTrampoline = NULL; - } - if (ppRealTarget != NULL) { - *ppRealTarget = NULL; - } - if (ppRealDetour != NULL) { - *ppRealDetour = NULL; - } - if (pDetour == NULL) { - DETOUR_TRACE(("empty detour\n")); - return ERROR_INVALID_PARAMETER; - } - - if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) { - DETOUR_TRACE(("transaction conflict with thread id=%d\n", s_nPendingThreadId)); - return ERROR_INVALID_OPERATION; - } - - // If any of the pending operations failed, then we don't need to do this. - if (s_nPendingError != NO_ERROR) { - DETOUR_TRACE(("pending transaction error=%d\n", s_nPendingError)); - return s_nPendingError; - } - - if (ppPointer == NULL) { - DETOUR_TRACE(("ppPointer is null\n")); - return ERROR_INVALID_HANDLE; - } - if (*ppPointer == NULL) { - error = ERROR_INVALID_HANDLE; - s_nPendingError = error; - s_ppPendingError = ppPointer; - DETOUR_TRACE(("*ppPointer is null (ppPointer=%p)\n", ppPointer)); - DETOUR_BREAK(); - return error; - } - - PBYTE pbTarget = (PBYTE)*ppPointer; - PDETOUR_TRAMPOLINE pTrampoline = NULL; - DetourOperation *o = NULL; - -#ifdef DETOURS_IA64 - PPLABEL_DESCRIPTOR ppldDetour = (PPLABEL_DESCRIPTOR)pDetour; - PPLABEL_DESCRIPTOR ppldTarget = (PPLABEL_DESCRIPTOR)pbTarget; - PVOID pDetourGlobals = NULL; - PVOID pTargetGlobals = NULL; - - pDetour = (PBYTE)DetourCodeFromPointer(ppldDetour, &pDetourGlobals); - pbTarget = (PBYTE)DetourCodeFromPointer(ppldTarget, &pTargetGlobals); - DETOUR_TRACE((" ppldDetour=%p, code=%p [gp=%p]\n", - ppldDetour, pDetour, pDetourGlobals)); - DETOUR_TRACE((" ppldTarget=%p, code=%p [gp=%p]\n", - ppldTarget, pbTarget, pTargetGlobals)); -#else // DETOURS_IA64 - pbTarget = (PBYTE)DetourCodeFromPointer(pbTarget, NULL); - pDetour = DetourCodeFromPointer(pDetour, NULL); -#endif // !DETOURS_IA64 - - // Don't follow a jump if its destination is the target function. - // This happens when the detour does nothing other than call the target. - if (pDetour == (PVOID)pbTarget) { - if (s_fIgnoreTooSmall) { - goto stop; - } - else { - DETOUR_BREAK(); - goto fail; - } - } - - if (ppRealTarget != NULL) { - *ppRealTarget = pbTarget; - } - if (ppRealDetour != NULL) { - *ppRealDetour = pDetour; - } - - o = new NOTHROW DetourOperation; - if (o == NULL) { - error = ERROR_NOT_ENOUGH_MEMORY; - fail: - s_nPendingError = error; - DETOUR_BREAK(); - stop: - if (pTrampoline != NULL) { - detour_free_trampoline(pTrampoline); - pTrampoline = NULL; - if (ppRealTrampoline != NULL) { - *ppRealTrampoline = NULL; - } - } - if (o != NULL) { - delete o; - o = NULL; - } - s_ppPendingError = ppPointer; - return error; - } - - pTrampoline = detour_alloc_trampoline(pbTarget); - if (pTrampoline == NULL) { - error = ERROR_NOT_ENOUGH_MEMORY; - DETOUR_BREAK(); - goto fail; - } - - if (ppRealTrampoline != NULL) { - *ppRealTrampoline = pTrampoline; - } - - DETOUR_TRACE(("detours: pbTramp=%p, pDetour=%p\n", pTrampoline, pDetour)); - - memset(pTrampoline->rAlign, 0, sizeof(pTrampoline->rAlign)); - - // Determine the number of movable target instructions. - PBYTE pbSrc = pbTarget; - PBYTE pbTrampoline = pTrampoline->rbCode; -#ifdef DETOURS_IA64 - PBYTE pbPool = (PBYTE)(&pTrampoline->bBranchIslands + 1); -#else - PBYTE pbPool = pbTrampoline + sizeof(pTrampoline->rbCode); -#endif - ULONG cbTarget = 0; - ULONG cbJump = SIZE_OF_JMP; - ULONG nAlign = 0; - -#ifdef DETOURS_ARM - // On ARM, we need an extra instruction when the function isn't 32-bit aligned. - // Check if the existing code is another detour (or at least a similar - // "ldr pc, [PC+0]" jump. - if ((ULONG)pbTarget & 2) { - cbJump += 2; - - ULONG op = fetch_thumb_opcode(pbSrc); - if (op == 0xbf00) { - op = fetch_thumb_opcode(pbSrc + 2); - if (op == 0xf8dff000) { // LDR PC,[PC] - *((PUSHORT&)pbTrampoline)++ = *((PUSHORT&)pbSrc)++; - *((PULONG&)pbTrampoline)++ = *((PULONG&)pbSrc)++; - *((PULONG&)pbTrampoline)++ = *((PULONG&)pbSrc)++; - cbTarget = (LONG)(pbSrc - pbTarget); - // We will fall through the "while" because cbTarget is now >= cbJump. - } - } - } - else { - ULONG op = fetch_thumb_opcode(pbSrc); - if (op == 0xf8dff000) { // LDR PC,[PC] - *((PULONG&)pbTrampoline)++ = *((PULONG&)pbSrc)++; - *((PULONG&)pbTrampoline)++ = *((PULONG&)pbSrc)++; - cbTarget = (LONG)(pbSrc - pbTarget); - // We will fall through the "while" because cbTarget is now >= cbJump. - } - } -#endif - - while (cbTarget < cbJump) { - PBYTE pbOp = pbSrc; - LONG lExtra = 0; - - DETOUR_TRACE((" DetourCopyInstruction(%p,%p)\n", - pbTrampoline, pbSrc)); - pbSrc = (PBYTE) - DetourCopyInstruction(pbTrampoline, (PVOID*)&pbPool, pbSrc, NULL, &lExtra); - DETOUR_TRACE((" DetourCopyInstruction() = %p (%d bytes)\n", - pbSrc, (int)(pbSrc - pbOp))); - pbTrampoline += (pbSrc - pbOp) + lExtra; - cbTarget = (LONG)(pbSrc - pbTarget); - pTrampoline->rAlign[nAlign].obTarget = cbTarget; - pTrampoline->rAlign[nAlign].obTrampoline = pbTrampoline - pTrampoline->rbCode; - nAlign++; - - if (nAlign >= ARRAYSIZE(pTrampoline->rAlign)) { - break; - } - - if (detour_does_code_end_function(pbOp)) { - break; - } - } - - // Consume, but don't duplicate padding if it is needed and available. - while (cbTarget < cbJump) { - LONG cFiller = detour_is_code_filler(pbSrc); - if (cFiller == 0) { - break; - } - - pbSrc += cFiller; - cbTarget = (LONG)(pbSrc - pbTarget); - } - -#if DETOUR_DEBUG - { - DETOUR_TRACE((" detours: rAlign [")); - LONG n = 0; - for (n = 0; n < ARRAYSIZE(pTrampoline->rAlign); n++) { - if (pTrampoline->rAlign[n].obTarget == 0 && - pTrampoline->rAlign[n].obTrampoline == 0) { - break; - } - DETOUR_TRACE((" %d/%d", - pTrampoline->rAlign[n].obTarget, - pTrampoline->rAlign[n].obTrampoline - )); - - } - DETOUR_TRACE((" ]\n")); - } -#endif - - if (cbTarget < cbJump || nAlign > ARRAYSIZE(pTrampoline->rAlign)) { - // Too few instructions. - - error = ERROR_INVALID_BLOCK; - if (s_fIgnoreTooSmall) { - goto stop; - } - else { - DETOUR_BREAK(); - goto fail; - } - } - - if (pbTrampoline > pbPool) { - __debugbreak(); - } - - pTrampoline->cbCode = (BYTE)(pbTrampoline - pTrampoline->rbCode); - pTrampoline->cbRestore = (BYTE)cbTarget; - CopyMemory(pTrampoline->rbRestore, pbTarget, cbTarget); - -#if !defined(DETOURS_IA64) - if (cbTarget > sizeof(pTrampoline->rbCode) - cbJump) { - // Too many instructions. - error = ERROR_INVALID_HANDLE; - DETOUR_BREAK(); - goto fail; - } -#endif // !DETOURS_IA64 - - pTrampoline->pbRemain = pbTarget + cbTarget; - pTrampoline->pbDetour = (PBYTE)pDetour; - -#ifdef DETOURS_IA64 - pTrampoline->ppldDetour = ppldDetour; - pTrampoline->ppldTarget = ppldTarget; - pTrampoline->pldTrampoline.EntryPoint = (UINT64)&pTrampoline->bMovlTargetGp; - pTrampoline->pldTrampoline.GlobalPointer = (UINT64)pDetourGlobals; - - ((DETOUR_IA64_BUNDLE *)pTrampoline->rbCode)->SetStop(); - - pTrampoline->bMovlTargetGp.SetMovlGp((UINT64)pTargetGlobals); - pTrampoline->bBrlRemainEip.SetBrl((UINT64)pTrampoline->pbRemain); - - // Alloc frame: alloc r41=ar.pfs,11,0,8,0; mov r40=rp - pTrampoline->bAllocFrame.wide[0] = 0x00000580164d480c; - pTrampoline->bAllocFrame.wide[1] = 0x00c4000500000200; - // save r36, r37, r38. - pTrampoline->bSave37to39.wide[0] = 0x031021004e019001; - pTrampoline->bSave37to39.wide[1] = 0x8401280600420098; - // save r34,r35,r36: adds r47=0,r36; adds r46=0,r35; adds r45=0,r34 - pTrampoline->bSave34to36.wide[0] = 0x02e0210048017800; - pTrampoline->bSave34to36.wide[1] = 0x84011005a042008c; - // save gp,r32,r33" adds r44=0,r33; adds r43=0,r32; adds r42=0,gp ;; - pTrampoline->bSaveGPto33.wide[0] = 0x02b0210042016001; - pTrampoline->bSaveGPto33.wide[1] = 0x8400080540420080; - // set detour GP. - pTrampoline->bMovlDetourGp.SetMovlGp((UINT64)pDetourGlobals); - // call detour: brl.call.sptk.few rp=detour ;; - pTrampoline->bCallDetour.wide[0] = 0x0000000100000005; - pTrampoline->bCallDetour.wide[1] = 0xd000001000000000; - pTrampoline->bCallDetour.SetBrlTarget((UINT64)pDetour); - // pop frame & gp: adds gp=0,r42; mov rp=r40,+0;; mov.i ar.pfs=r41 - pTrampoline->bPopFrameGp.wide[0] = 0x4000210054000802; - pTrampoline->bPopFrameGp.wide[1] = 0x00aa029000038005; - // return to caller: br.ret.sptk.many rp ;; - pTrampoline->bReturn.wide[0] = 0x0000000100000019; - pTrampoline->bReturn.wide[1] = 0x0084000880000200; - - DETOUR_TRACE(("detours: &bMovlTargetGp=%p\n", &pTrampoline->bMovlTargetGp)); - DETOUR_TRACE(("detours: &bMovlDetourGp=%p\n", &pTrampoline->bMovlDetourGp)); -#endif // DETOURS_IA64 - - pbTrampoline = pTrampoline->rbCode + pTrampoline->cbCode; -#ifdef DETOURS_X64 - pbTrampoline = detour_gen_jmp_indirect(pbTrampoline, &pTrampoline->pbRemain); - pbTrampoline = detour_gen_brk(pbTrampoline, pbPool); -#endif // DETOURS_X64 - -#ifdef DETOURS_X86 - pbTrampoline = detour_gen_jmp_immediate(pbTrampoline, pTrampoline->pbRemain); - pbTrampoline = detour_gen_brk(pbTrampoline, pbPool); -#endif // DETOURS_X86 - -#ifdef DETOURS_ARM - pbTrampoline = detour_gen_jmp_immediate(pbTrampoline, &pbPool, pTrampoline->pbRemain); - pbTrampoline = detour_gen_brk(pbTrampoline, pbPool); -#endif // DETOURS_ARM - -#ifdef DETOURS_ARM64 - pbTrampoline = detour_gen_jmp_immediate(pbTrampoline, &pbPool, pTrampoline->pbRemain); - pbTrampoline = detour_gen_brk(pbTrampoline, pbPool); -#endif // DETOURS_ARM64 - - (void)pbTrampoline; - - DWORD dwOld = 0; - if (!VirtualProtect(pbTarget, cbTarget, PAGE_EXECUTE_READWRITE, &dwOld)) { - error = GetLastError(); - DETOUR_BREAK(); - goto fail; - } - - DETOUR_TRACE(("detours: pbTarget=%p: " - "%02x %02x %02x %02x " - "%02x %02x %02x %02x " - "%02x %02x %02x %02x\n", - pbTarget, - pbTarget[0], pbTarget[1], pbTarget[2], pbTarget[3], - pbTarget[4], pbTarget[5], pbTarget[6], pbTarget[7], - pbTarget[8], pbTarget[9], pbTarget[10], pbTarget[11])); - DETOUR_TRACE(("detours: pbTramp =%p: " - "%02x %02x %02x %02x " - "%02x %02x %02x %02x " - "%02x %02x %02x %02x\n", - pTrampoline, - pTrampoline->rbCode[0], pTrampoline->rbCode[1], - pTrampoline->rbCode[2], pTrampoline->rbCode[3], - pTrampoline->rbCode[4], pTrampoline->rbCode[5], - pTrampoline->rbCode[6], pTrampoline->rbCode[7], - pTrampoline->rbCode[8], pTrampoline->rbCode[9], - pTrampoline->rbCode[10], pTrampoline->rbCode[11])); - - o->fIsRemove = FALSE; - o->ppbPointer = (PBYTE*)ppPointer; - o->pTrampoline = pTrampoline; - o->pbTarget = pbTarget; - o->dwPerm = dwOld; - o->pNext = s_pPendingOperations; - s_pPendingOperations = o; - - return NO_ERROR; -} - -LONG WINAPI DetourDetach(_Inout_ PVOID *ppPointer, - _In_ PVOID pDetour) -{ - LONG error = NO_ERROR; - - if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) { - return ERROR_INVALID_OPERATION; - } - - // If any of the pending operations failed, then we don't need to do this. - if (s_nPendingError != NO_ERROR) { - return s_nPendingError; - } - - if (pDetour == NULL) { - return ERROR_INVALID_PARAMETER; - } - if (ppPointer == NULL) { - return ERROR_INVALID_HANDLE; - } - if (*ppPointer == NULL) { - error = ERROR_INVALID_HANDLE; - s_nPendingError = error; - s_ppPendingError = ppPointer; - DETOUR_BREAK(); - return error; - } - - DetourOperation *o = new NOTHROW DetourOperation; - if (o == NULL) { - error = ERROR_NOT_ENOUGH_MEMORY; - fail: - s_nPendingError = error; - DETOUR_BREAK(); - stop: - if (o != NULL) { - delete o; - o = NULL; - } - s_ppPendingError = ppPointer; - return error; - } - - -#ifdef DETOURS_IA64 - PPLABEL_DESCRIPTOR ppldTrampo = (PPLABEL_DESCRIPTOR)*ppPointer; - PPLABEL_DESCRIPTOR ppldDetour = (PPLABEL_DESCRIPTOR)pDetour; - PVOID pDetourGlobals = NULL; - PVOID pTrampoGlobals = NULL; - - pDetour = (PBYTE)DetourCodeFromPointer(ppldDetour, &pDetourGlobals); - PDETOUR_TRAMPOLINE pTrampoline = (PDETOUR_TRAMPOLINE) - DetourCodeFromPointer(ppldTrampo, &pTrampoGlobals); - DETOUR_TRACE((" ppldDetour=%p, code=%p [gp=%p]\n", - ppldDetour, pDetour, pDetourGlobals)); - DETOUR_TRACE((" ppldTrampo=%p, code=%p [gp=%p]\n", - ppldTrampo, pTrampoline, pTrampoGlobals)); - - - DETOUR_TRACE(("\n")); - DETOUR_TRACE(("detours: &pldTrampoline =%p\n", - &pTrampoline->pldTrampoline)); - DETOUR_TRACE(("detours: &bMovlTargetGp =%p [%p]\n", - &pTrampoline->bMovlTargetGp, - pTrampoline->bMovlTargetGp.GetMovlGp())); - DETOUR_TRACE(("detours: &rbCode =%p [%p]\n", - &pTrampoline->rbCode, - ((DETOUR_IA64_BUNDLE&)pTrampoline->rbCode).GetBrlTarget())); - DETOUR_TRACE(("detours: &bBrlRemainEip =%p [%p]\n", - &pTrampoline->bBrlRemainEip, - pTrampoline->bBrlRemainEip.GetBrlTarget())); - DETOUR_TRACE(("detours: &bMovlDetourGp =%p [%p]\n", - &pTrampoline->bMovlDetourGp, - pTrampoline->bMovlDetourGp.GetMovlGp())); - DETOUR_TRACE(("detours: &bBrlDetourEip =%p [%p]\n", - &pTrampoline->bCallDetour, - pTrampoline->bCallDetour.GetBrlTarget())); - DETOUR_TRACE(("detours: pldDetour =%p [%p]\n", - pTrampoline->ppldDetour->EntryPoint, - pTrampoline->ppldDetour->GlobalPointer)); - DETOUR_TRACE(("detours: pldTarget =%p [%p]\n", - pTrampoline->ppldTarget->EntryPoint, - pTrampoline->ppldTarget->GlobalPointer)); - DETOUR_TRACE(("detours: pbRemain =%p\n", - pTrampoline->pbRemain)); - DETOUR_TRACE(("detours: pbDetour =%p\n", - pTrampoline->pbDetour)); - DETOUR_TRACE(("\n")); -#else // !DETOURS_IA64 - PDETOUR_TRAMPOLINE pTrampoline = - (PDETOUR_TRAMPOLINE)DetourCodeFromPointer(*ppPointer, NULL); - pDetour = DetourCodeFromPointer(pDetour, NULL); -#endif // !DETOURS_IA64 - - ////////////////////////////////////// Verify that Trampoline is in place. - // - LONG cbTarget = pTrampoline->cbRestore; - PBYTE pbTarget = pTrampoline->pbRemain - cbTarget; - if (cbTarget == 0 || cbTarget > sizeof(pTrampoline->rbCode)) { - error = ERROR_INVALID_BLOCK; - if (s_fIgnoreTooSmall) { - goto stop; - } - else { - DETOUR_BREAK(); - goto fail; - } - } - - if (pTrampoline->pbDetour != pDetour) { - error = ERROR_INVALID_BLOCK; - if (s_fIgnoreTooSmall) { - goto stop; - } - else { - DETOUR_BREAK(); - goto fail; - } - } - - DWORD dwOld = 0; - if (!VirtualProtect(pbTarget, cbTarget, - PAGE_EXECUTE_READWRITE, &dwOld)) { - error = GetLastError(); - DETOUR_BREAK(); - goto fail; - } - - o->fIsRemove = TRUE; - o->ppbPointer = (PBYTE*)ppPointer; - o->pTrampoline = pTrampoline; - o->pbTarget = pbTarget; - o->dwPerm = dwOld; - o->pNext = s_pPendingOperations; - s_pPendingOperations = o; - - return NO_ERROR; -} - -////////////////////////////////////////////////////////////////////////////// -// -// Helpers for manipulating page protection. -// - -// For reference: -// PAGE_NOACCESS 0x01 -// PAGE_READONLY 0x02 -// PAGE_READWRITE 0x04 -// PAGE_WRITECOPY 0x08 -// PAGE_EXECUTE 0x10 -// PAGE_EXECUTE_READ 0x20 -// PAGE_EXECUTE_READWRITE 0x40 -// PAGE_EXECUTE_WRITECOPY 0x80 -// PAGE_GUARD ... -// PAGE_NOCACHE ... -// PAGE_WRITECOMBINE ... - -#define DETOUR_PAGE_EXECUTE_ALL (PAGE_EXECUTE | \ - PAGE_EXECUTE_READ | \ - PAGE_EXECUTE_READWRITE | \ - PAGE_EXECUTE_WRITECOPY) - -#define DETOUR_PAGE_NO_EXECUTE_ALL (PAGE_NOACCESS | \ - PAGE_READONLY | \ - PAGE_READWRITE | \ - PAGE_WRITECOPY) - -#define DETOUR_PAGE_ATTRIBUTES (~(DETOUR_PAGE_EXECUTE_ALL | DETOUR_PAGE_NO_EXECUTE_ALL)) - -C_ASSERT((DETOUR_PAGE_NO_EXECUTE_ALL << 4) == DETOUR_PAGE_EXECUTE_ALL); - -static DWORD DetourPageProtectAdjustExecute(_In_ DWORD dwOldProtect, - _In_ DWORD dwNewProtect) -// Copy EXECUTE from dwOldProtect to dwNewProtect. -{ - bool const fOldExecute = ((dwOldProtect & DETOUR_PAGE_EXECUTE_ALL) != 0); - bool const fNewExecute = ((dwNewProtect & DETOUR_PAGE_EXECUTE_ALL) != 0); - - if (fOldExecute && !fNewExecute) { - dwNewProtect = ((dwNewProtect & DETOUR_PAGE_NO_EXECUTE_ALL) << 4) - | (dwNewProtect & DETOUR_PAGE_ATTRIBUTES); - } - else if (!fOldExecute && fNewExecute) { - dwNewProtect = ((dwNewProtect & DETOUR_PAGE_EXECUTE_ALL) >> 4) - | (dwNewProtect & DETOUR_PAGE_ATTRIBUTES); - } - return dwNewProtect; -} - -_Success_(return != FALSE) -BOOL WINAPI DetourVirtualProtectSameExecuteEx(_In_ HANDLE hProcess, - _In_ PVOID pAddress, - _In_ SIZE_T nSize, - _In_ DWORD dwNewProtect, - _Out_ PDWORD pdwOldProtect) -// Some systems do not allow executability of a page to change. This function applies -// dwNewProtect to [pAddress, nSize), but preserving the previous executability. -// This function is meant to be a drop-in replacement for some uses of VirtualProtectEx. -// When "restoring" page protection, there is no need to use this function. -{ - MEMORY_BASIC_INFORMATION mbi; - - // Query to get existing execute access. - - ZeroMemory(&mbi, sizeof(mbi)); - - if (VirtualQueryEx(hProcess, pAddress, &mbi, sizeof(mbi)) == 0) { - return FALSE; - } - return VirtualProtectEx(hProcess, pAddress, nSize, - DetourPageProtectAdjustExecute(mbi.Protect, dwNewProtect), - pdwOldProtect); -} - -_Success_(return != FALSE) -BOOL WINAPI DetourVirtualProtectSameExecute(_In_ PVOID pAddress, - _In_ SIZE_T nSize, - _In_ DWORD dwNewProtect, - _Out_ PDWORD pdwOldProtect) -{ - return DetourVirtualProtectSameExecuteEx(GetCurrentProcess(), - pAddress, nSize, dwNewProtect, pdwOldProtect); -} - -// End of File +////////////////////////////////////////////////////////////////////////////// +// +// Core Detours Functionality (detours.cpp of detours.lib) +// +// Microsoft Research Detours Package, Version 3.0 Build_343. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// + +#pragma warning(disable:4068) // unknown pragma (suppress) + +#if _MSC_VER >= 1900 +#pragma warning(push) +#pragma warning(disable:4091) // empty typedef +#endif + +#define _ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE 1 +#include + +#if (_MSC_VER < 1299) +#pragma warning(disable: 4710) +#endif + +//#define DETOUR_DEBUG 1 +#define DETOURS_INTERNAL + +#include "detours.h" + +#if DETOURS_VERSION != 30001 +#error detours.h version mismatch +#endif + +#if _MSC_VER >= 1900 +#pragma warning(pop) +#endif + +#define NOTHROW + +////////////////////////////////////////////////////////////////////////////// +// +struct _DETOUR_ALIGN +{ + BYTE obTarget : 3; + BYTE obTrampoline : 5; +}; + +C_ASSERT(sizeof(_DETOUR_ALIGN) == 1); + +////////////////////////////////////////////////////////////////////////////// +// +// Region reserved for system DLLs, which cannot be used for trampolines. +// +static PVOID s_pSystemRegionLowerBound = (PVOID)(ULONG_PTR)0x70000000; +static PVOID s_pSystemRegionUpperBound = (PVOID)(ULONG_PTR)0x80000000; + +////////////////////////////////////////////////////////////////////////////// +// +static bool detour_is_imported(PBYTE pbCode, PBYTE pbAddress) +{ + MEMORY_BASIC_INFORMATION mbi; + VirtualQuery((PVOID)pbCode, &mbi, sizeof(mbi)); + __try { + PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mbi.AllocationBase; + if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) { + return false; + } + + PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader + + pDosHeader->e_lfanew); + if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) { + return false; + } + + if (pbAddress >= ((PBYTE)pDosHeader + + pNtHeader->OptionalHeader + .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress) && + pbAddress < ((PBYTE)pDosHeader + + pNtHeader->OptionalHeader + .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress + + pNtHeader->OptionalHeader + .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size)) { + return true; + } + } +#pragma prefast(suppress:28940, "A bad pointer means this probably isn't a PE header.") + __except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? + EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { + return false; + } + return false; +} + +inline ULONG_PTR detour_2gb_below(ULONG_PTR address) +{ + return (address > (ULONG_PTR)0x7ff80000) ? address - 0x7ff80000 : 0x80000; +} + +inline ULONG_PTR detour_2gb_above(ULONG_PTR address) +{ +#if defined(DETOURS_64BIT) + return (address < (ULONG_PTR)0xffffffff80000000) ? address + 0x7ff80000 : (ULONG_PTR)0xfffffffffff80000; +#else + return (address < (ULONG_PTR)0x80000000) ? address + 0x7ff80000 : (ULONG_PTR)0xfff80000; +#endif +} + +///////////////////////////////////////////////////////////////////////// X86. +// +#ifdef DETOURS_X86 + +struct _DETOUR_TRAMPOLINE +{ + BYTE rbCode[30]; // target code + jmp to pbRemain + BYTE cbCode; // size of moved target code. + BYTE cbCodeBreak; // padding to make debugging easier. + BYTE rbRestore[22]; // original target code. + BYTE cbRestore; // size of original target code. + BYTE cbRestoreBreak; // padding to make debugging easier. + _DETOUR_ALIGN rAlign[8]; // instruction alignment array. + PBYTE pbRemain; // first instruction after moved code. [free list] + PBYTE pbDetour; // first instruction of detour function. +}; + +C_ASSERT(sizeof(_DETOUR_TRAMPOLINE) == 72); + +enum { + SIZE_OF_JMP = 5 +}; + +inline PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE pbJmpVal) +{ + PBYTE pbJmpSrc = pbCode + 5; + *pbCode++ = 0xE9; // jmp +imm32 + *((INT32*&)pbCode)++ = (INT32)(pbJmpVal - pbJmpSrc); + return pbCode; +} + +inline PBYTE detour_gen_jmp_indirect(PBYTE pbCode, PBYTE *ppbJmpVal) +{ + *pbCode++ = 0xff; // jmp [+imm32] + *pbCode++ = 0x25; + *((INT32*&)pbCode)++ = (INT32)((PBYTE)ppbJmpVal); + return pbCode; +} + +inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit) +{ + while (pbCode < pbLimit) { + *pbCode++ = 0xcc; // brk; + } + return pbCode; +} + +inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals) +{ + if (pbCode == NULL) { + return NULL; + } + if (ppGlobals != NULL) { + *ppGlobals = NULL; + } + + // First, skip over the import vector if there is one. + if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [imm32] + // Looks like an import alias jump, then get the code it points to. + PBYTE pbTarget = *(UNALIGNED PBYTE *)&pbCode[2]; + if (detour_is_imported(pbCode, pbTarget)) { + PBYTE pbNew = *(UNALIGNED PBYTE *)pbTarget; + DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew)); + pbCode = pbNew; + } + } + + // Then, skip over a patch jump + if (pbCode[0] == 0xeb) { // jmp +imm8 + PBYTE pbNew = pbCode + 2 + *(CHAR *)&pbCode[1]; + DETOUR_TRACE(("%p->%p: skipped over short jump.\n", pbCode, pbNew)); + pbCode = pbNew; + + // First, skip over the import vector if there is one. + if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [imm32] + // Looks like an import alias jump, then get the code it points to. + PBYTE pbTarget = *(UNALIGNED PBYTE *)&pbCode[2]; + if (detour_is_imported(pbCode, pbTarget)) { + pbNew = *(UNALIGNED PBYTE *)pbTarget; + DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew)); + pbCode = pbNew; + } + } + // Finally, skip over a long jump if it is the target of the patch jump. + else if (pbCode[0] == 0xe9) { // jmp +imm32 + pbNew = pbCode + 5 + *(UNALIGNED INT32 *)&pbCode[1]; + DETOUR_TRACE(("%p->%p: skipped over long jump.\n", pbCode, pbNew)); + pbCode = pbNew; + } + } + return pbCode; +} + +inline void detour_find_jmp_bounds(PBYTE pbCode, + PDETOUR_TRAMPOLINE *ppLower, + PDETOUR_TRAMPOLINE *ppUpper) +{ + // We have to place trampolines within +/- 2GB of code. + ULONG_PTR lo = detour_2gb_below((ULONG_PTR)pbCode); + ULONG_PTR hi = detour_2gb_above((ULONG_PTR)pbCode); + DETOUR_TRACE(("[%p..%p..%p]\n", lo, pbCode, hi)); + + // And, within +/- 2GB of relative jmp targets. + if (pbCode[0] == 0xe9) { // jmp +imm32 + PBYTE pbNew = pbCode + 5 + *(UNALIGNED INT32 *)&pbCode[1]; + + if (pbNew < pbCode) { + hi = detour_2gb_above((ULONG_PTR)pbNew); + } + else { + lo = detour_2gb_below((ULONG_PTR)pbNew); + } + DETOUR_TRACE(("[%p..%p..%p] +imm32\n", lo, pbCode, hi)); + } + + *ppLower = (PDETOUR_TRAMPOLINE)lo; + *ppUpper = (PDETOUR_TRAMPOLINE)hi; +} + +inline BOOL detour_does_code_end_function(PBYTE pbCode) +{ + if (pbCode[0] == 0xeb || // jmp +imm8 + pbCode[0] == 0xe9 || // jmp +imm32 + pbCode[0] == 0xe0 || // jmp eax + pbCode[0] == 0xc2 || // ret +imm8 + pbCode[0] == 0xc3 || // ret + pbCode[0] == 0xcc) { // brk + return TRUE; + } + else if (pbCode[0] == 0xf3 && pbCode[1] == 0xc3) { // rep ret + return TRUE; + } + else if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32] + return TRUE; + } + else if ((pbCode[0] == 0x26 || // jmp es: + pbCode[0] == 0x2e || // jmp cs: + pbCode[0] == 0x36 || // jmp ss: + pbCode[0] == 0x3e || // jmp ds: + pbCode[0] == 0x64 || // jmp fs: + pbCode[0] == 0x65) && // jmp gs: + pbCode[1] == 0xff && // jmp [+imm32] + pbCode[2] == 0x25) { + return TRUE; + } + return FALSE; +} + +inline ULONG detour_is_code_filler(PBYTE pbCode) +{ + // 1-byte through 11-byte NOPs. + if (pbCode[0] == 0x90) { + return 1; + } + if (pbCode[0] == 0x66 && pbCode[1] == 0x90) { + return 2; + } + if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x00) { + return 3; + } + if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x40 && + pbCode[3] == 0x00) { + return 4; + } + if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x44 && + pbCode[3] == 0x00 && pbCode[4] == 0x00) { + return 5; + } + if (pbCode[0] == 0x66 && pbCode[1] == 0x0F && pbCode[2] == 0x1F && + pbCode[3] == 0x44 && pbCode[4] == 0x00 && pbCode[5] == 0x00) { + return 6; + } + if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x80 && + pbCode[3] == 0x00 && pbCode[4] == 0x00 && pbCode[5] == 0x00 && + pbCode[6] == 0x00) { + return 7; + } + if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x84 && + pbCode[3] == 0x00 && pbCode[4] == 0x00 && pbCode[5] == 0x00 && + pbCode[6] == 0x00 && pbCode[7] == 0x00) { + return 8; + } + if (pbCode[0] == 0x66 && pbCode[1] == 0x0F && pbCode[2] == 0x1F && + pbCode[3] == 0x84 && pbCode[4] == 0x00 && pbCode[5] == 0x00 && + pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00) { + return 9; + } + if (pbCode[0] == 0x66 && pbCode[1] == 0x66 && pbCode[2] == 0x0F && + pbCode[3] == 0x1F && pbCode[4] == 0x84 && pbCode[5] == 0x00 && + pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00 && + pbCode[9] == 0x00) { + return 10; + } + if (pbCode[0] == 0x66 && pbCode[1] == 0x66 && pbCode[2] == 0x66 && + pbCode[3] == 0x0F && pbCode[4] == 0x1F && pbCode[5] == 0x84 && + pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00 && + pbCode[9] == 0x00 && pbCode[10] == 0x00) { + return 11; + } + + // int 3. + if (pbCode[0] == 0xcc) { + return 1; + } + return 0; +} + +#endif // DETOURS_X86 + +///////////////////////////////////////////////////////////////////////// X64. +// +#ifdef DETOURS_X64 + +struct _DETOUR_TRAMPOLINE +{ + // An X64 instuction can be 15 bytes long. + // In practice 11 seems to be the limit. + BYTE rbCode[30]; // target code + jmp to pbRemain. + BYTE cbCode; // size of moved target code. + BYTE cbCodeBreak; // padding to make debugging easier. + BYTE rbRestore[30]; // original target code. + BYTE cbRestore; // size of original target code. + BYTE cbRestoreBreak; // padding to make debugging easier. + _DETOUR_ALIGN rAlign[8]; // instruction alignment array. + PBYTE pbRemain; // first instruction after moved code. [free list] + PBYTE pbDetour; // first instruction of detour function. + BYTE rbCodeIn[8]; // jmp [pbDetour] +}; + +C_ASSERT(sizeof(_DETOUR_TRAMPOLINE) == 96); + +enum { + SIZE_OF_JMP = 5 +}; + +inline PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE pbJmpVal) +{ + PBYTE pbJmpSrc = pbCode + 5; + *pbCode++ = 0xE9; // jmp +imm32 + *((INT32*&)pbCode)++ = (INT32)(pbJmpVal - pbJmpSrc); + return pbCode; +} + +inline PBYTE detour_gen_jmp_indirect(PBYTE pbCode, PBYTE *ppbJmpVal) +{ + PBYTE pbJmpSrc = pbCode + 6; + *pbCode++ = 0xff; // jmp [+imm32] + *pbCode++ = 0x25; + *((INT32*&)pbCode)++ = (INT32)((PBYTE)ppbJmpVal - pbJmpSrc); + return pbCode; +} + +inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit) +{ + while (pbCode < pbLimit) { + *pbCode++ = 0xcc; // brk; + } + return pbCode; +} + +inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals) +{ + if (pbCode == NULL) { + return NULL; + } + if (ppGlobals != NULL) { + *ppGlobals = NULL; + } + + // First, skip over the import vector if there is one. + if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32] + // Looks like an import alias jump, then get the code it points to. + PBYTE pbTarget = pbCode + 6 + *(UNALIGNED INT32 *)&pbCode[2]; + if (detour_is_imported(pbCode, pbTarget)) { + PBYTE pbNew = *(UNALIGNED PBYTE *)pbTarget; + DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew)); + pbCode = pbNew; + } + } + + // Then, skip over a patch jump + if (pbCode[0] == 0xeb) { // jmp +imm8 + PBYTE pbNew = pbCode + 2 + *(CHAR *)&pbCode[1]; + DETOUR_TRACE(("%p->%p: skipped over short jump.\n", pbCode, pbNew)); + pbCode = pbNew; + + // First, skip over the import vector if there is one. + if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32] + // Looks like an import alias jump, then get the code it points to. + PBYTE pbTarget = pbCode + 6 + *(UNALIGNED INT32 *)&pbCode[2]; + if (detour_is_imported(pbCode, pbTarget)) { + pbNew = *(UNALIGNED PBYTE *)pbTarget; + DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew)); + pbCode = pbNew; + } + } + // Finally, skip over a long jump if it is the target of the patch jump. + else if (pbCode[0] == 0xe9) { // jmp +imm32 + pbNew = pbCode + 5 + *(UNALIGNED INT32 *)&pbCode[1]; + DETOUR_TRACE(("%p->%p: skipped over long jump.\n", pbCode, pbNew)); + pbCode = pbNew; + } + } + return pbCode; +} + +inline void detour_find_jmp_bounds(PBYTE pbCode, + PDETOUR_TRAMPOLINE *ppLower, + PDETOUR_TRAMPOLINE *ppUpper) +{ + // We have to place trampolines within +/- 2GB of code. + ULONG_PTR lo = detour_2gb_below((ULONG_PTR)pbCode); + ULONG_PTR hi = detour_2gb_above((ULONG_PTR)pbCode); + DETOUR_TRACE(("[%p..%p..%p]\n", lo, pbCode, hi)); + + // And, within +/- 2GB of relative jmp vectors. + if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32] + PBYTE pbNew = pbCode + 6 + *(UNALIGNED INT32 *)&pbCode[2]; + + if (pbNew < pbCode) { + hi = detour_2gb_above((ULONG_PTR)pbNew); + } + else { + lo = detour_2gb_below((ULONG_PTR)pbNew); + } + DETOUR_TRACE(("[%p..%p..%p] [+imm32]\n", lo, pbCode, hi)); + } + // And, within +/- 2GB of relative jmp targets. + else if (pbCode[0] == 0xe9) { // jmp +imm32 + PBYTE pbNew = pbCode + 5 + *(UNALIGNED INT32 *)&pbCode[1]; + + if (pbNew < pbCode) { + hi = detour_2gb_above((ULONG_PTR)pbNew); + } + else { + lo = detour_2gb_below((ULONG_PTR)pbNew); + } + DETOUR_TRACE(("[%p..%p..%p] +imm32\n", lo, pbCode, hi)); + } + + *ppLower = (PDETOUR_TRAMPOLINE)lo; + *ppUpper = (PDETOUR_TRAMPOLINE)hi; +} + +inline BOOL detour_does_code_end_function(PBYTE pbCode) +{ + if (pbCode[0] == 0xeb || // jmp +imm8 + pbCode[0] == 0xe9 || // jmp +imm32 + pbCode[0] == 0xe0 || // jmp eax + pbCode[0] == 0xc2 || // ret +imm8 + pbCode[0] == 0xc3 || // ret + pbCode[0] == 0xcc) { // brk + return TRUE; + } + else if (pbCode[0] == 0xf3 && pbCode[1] == 0xc3) { // rep ret + return TRUE; + } + else if (pbCode[0] == 0xff && pbCode[1] == 0x25) { // jmp [+imm32] + return TRUE; + } + else if ((pbCode[0] == 0x26 || // jmp es: + pbCode[0] == 0x2e || // jmp cs: + pbCode[0] == 0x36 || // jmp ss: + pbCode[0] == 0x3e || // jmp ds: + pbCode[0] == 0x64 || // jmp fs: + pbCode[0] == 0x65) && // jmp gs: + pbCode[1] == 0xff && // jmp [+imm32] + pbCode[2] == 0x25) { + return TRUE; + } + return FALSE; +} + +inline ULONG detour_is_code_filler(PBYTE pbCode) +{ + // 1-byte through 11-byte NOPs. + if (pbCode[0] == 0x90) { + return 1; + } + if (pbCode[0] == 0x66 && pbCode[1] == 0x90) { + return 2; + } + if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x00) { + return 3; + } + if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x40 && + pbCode[3] == 0x00) { + return 4; + } + if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x44 && + pbCode[3] == 0x00 && pbCode[4] == 0x00) { + return 5; + } + if (pbCode[0] == 0x66 && pbCode[1] == 0x0F && pbCode[2] == 0x1F && + pbCode[3] == 0x44 && pbCode[4] == 0x00 && pbCode[5] == 0x00) { + return 6; + } + if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x80 && + pbCode[3] == 0x00 && pbCode[4] == 0x00 && pbCode[5] == 0x00 && + pbCode[6] == 0x00) { + return 7; + } + if (pbCode[0] == 0x0F && pbCode[1] == 0x1F && pbCode[2] == 0x84 && + pbCode[3] == 0x00 && pbCode[4] == 0x00 && pbCode[5] == 0x00 && + pbCode[6] == 0x00 && pbCode[7] == 0x00) { + return 8; + } + if (pbCode[0] == 0x66 && pbCode[1] == 0x0F && pbCode[2] == 0x1F && + pbCode[3] == 0x84 && pbCode[4] == 0x00 && pbCode[5] == 0x00 && + pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00) { + return 9; + } + if (pbCode[0] == 0x66 && pbCode[1] == 0x66 && pbCode[2] == 0x0F && + pbCode[3] == 0x1F && pbCode[4] == 0x84 && pbCode[5] == 0x00 && + pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00 && + pbCode[9] == 0x00) { + return 10; + } + if (pbCode[0] == 0x66 && pbCode[1] == 0x66 && pbCode[2] == 0x66 && + pbCode[3] == 0x0F && pbCode[4] == 0x1F && pbCode[5] == 0x84 && + pbCode[6] == 0x00 && pbCode[7] == 0x00 && pbCode[8] == 0x00 && + pbCode[9] == 0x00 && pbCode[10] == 0x00) { + return 11; + } + + // int 3. + if (pbCode[0] == 0xcc) { + return 1; + } + return 0; +} + +#endif // DETOURS_X64 + +//////////////////////////////////////////////////////////////////////// IA64. +// +#ifdef DETOURS_IA64 + +struct _DETOUR_TRAMPOLINE +{ + // On the IA64, a trampoline is used for both incoming and outgoing calls. + // + // The trampoline contains the following bundles for the outgoing call: + // movl gp=target_gp; + // + // brl target_code; + // + // The trampoline contains the following bundles for the incoming call: + // alloc r41=ar.pfs, b, 0, 8, 0 + // mov r40=rp + // + // adds r50=0, r39 + // adds r49=0, r38 + // adds r48=0, r37 ;; + // + // adds r47=0, r36 + // adds r46=0, r35 + // adds r45=0, r34 + // + // adds r44=0, r33 + // adds r43=0, r32 + // adds r42=0, gp ;; + // + // movl gp=ffffffff`ffffffff ;; + // + // brl.call.sptk.few rp=disas!TestCodes+20e0 (00000000`00404ea0) ;; + // + // adds gp=0, r42 + // mov rp=r40, +0 ;; + // mov.i ar.pfs=r41 + // + // br.ret.sptk.many rp ;; + // + // This way, we only have to relocate a single bundle. + // + // The complicated incoming trampoline is required because we have to + // create an additional stack frame so that we save and restore the gp. + // We must do this because gp is a caller-saved register, but not saved + // if the caller thinks the target is in the same DLL, which changes + // when we insert a detour. + // + DETOUR_IA64_BUNDLE bMovlTargetGp; // Bundle which sets target GP + BYTE rbCode[sizeof(DETOUR_IA64_BUNDLE)]; // moved bundle. + DETOUR_IA64_BUNDLE bBrlRemainEip; // Brl to pbRemain + // This must be adjacent to bBranchIslands. + + // Each instruction in the moved bundle could be a IP-relative chk or branch or call. + // Any such instructions are changed to point to a brl in bBranchIslands. + // This must be adjacent to bBrlRemainEip -- see "pbPool". + DETOUR_IA64_BUNDLE bBranchIslands[DETOUR_IA64_INSTRUCTIONS_PER_BUNDLE]; + + // Target of brl inserted in target function + DETOUR_IA64_BUNDLE bAllocFrame; // alloc frame + DETOUR_IA64_BUNDLE bSave37to39; // save r37, r38, r39. + DETOUR_IA64_BUNDLE bSave34to36; // save r34, r35, r36. + DETOUR_IA64_BUNDLE bSaveGPto33; // save gp, r32, r33. + DETOUR_IA64_BUNDLE bMovlDetourGp; // set detour GP. + DETOUR_IA64_BUNDLE bCallDetour; // call detour. + DETOUR_IA64_BUNDLE bPopFrameGp; // pop frame and restore gp. + DETOUR_IA64_BUNDLE bReturn; // return to caller. + + PLABEL_DESCRIPTOR pldTrampoline; + + BYTE rbRestore[sizeof(DETOUR_IA64_BUNDLE)]; // original target bundle. + BYTE cbRestore; // size of original target code. + BYTE cbCode; // size of moved target code. + _DETOUR_ALIGN rAlign[14]; // instruction alignment array. + PBYTE pbRemain; // first instruction after moved code. [free list] + PBYTE pbDetour; // first instruction of detour function. + PPLABEL_DESCRIPTOR ppldDetour; // [pbDetour,gpDetour] + PPLABEL_DESCRIPTOR ppldTarget; // [pbTarget,gpDetour] +}; + +C_ASSERT(sizeof(DETOUR_IA64_BUNDLE) == 16); +C_ASSERT(sizeof(_DETOUR_TRAMPOLINE) == 256 + DETOUR_IA64_INSTRUCTIONS_PER_BUNDLE * 16); + +enum { + SIZE_OF_JMP = sizeof(DETOUR_IA64_BUNDLE) +}; + +inline PBYTE detour_skip_jmp(PBYTE pPointer, PVOID *ppGlobals) +{ + PBYTE pGlobals = NULL; + PBYTE pbCode = NULL; + + if (pPointer != NULL) { + PPLABEL_DESCRIPTOR ppld = (PPLABEL_DESCRIPTOR)pPointer; + pbCode = (PBYTE)ppld->EntryPoint; + pGlobals = (PBYTE)ppld->GlobalPointer; + } + if (ppGlobals != NULL) { + *ppGlobals = pGlobals; + } + if (pbCode == NULL) { + return NULL; + } + + DETOUR_IA64_BUNDLE *pb = (DETOUR_IA64_BUNDLE *)pbCode; + + // IA64 Local Import Jumps look like: + // addl r2=ffffffff`ffe021c0, gp ;; + // ld8 r2=[r2] + // nop.i 0 ;; + // + // ld8 r3=[r2], 8 ;; + // ld8 gp=[r2] + // mov b6=r3, +0 + // + // nop.m 0 + // nop.i 0 + // br.cond.sptk.few b6 + // + + // 002024000200100b + if ((pb[0].wide[0] & 0xfffffc000603ffff) == 0x002024000200100b && + pb[0].wide[1] == 0x0004000000203008 && + pb[1].wide[0] == 0x001014180420180a && + pb[1].wide[1] == 0x07000830c0203008 && + pb[2].wide[0] == 0x0000000100000010 && + pb[2].wide[1] == 0x0080006000000200) { + + ULONG64 offset = + ((pb[0].wide[0] & 0x0000000001fc0000) >> 18) | // imm7b + ((pb[0].wide[0] & 0x000001ff00000000) >> 25) | // imm9d + ((pb[0].wide[0] & 0x00000000f8000000) >> 11); // imm5c + if (pb[0].wide[0] & 0x0000020000000000) { // sign + offset |= 0xffffffffffe00000; + } + PBYTE pbTarget = pGlobals + offset; + DETOUR_TRACE(("%p: potential import jump, target=%p\n", pb, pbTarget)); + + if (detour_is_imported(pbCode, pbTarget) && *(PBYTE*)pbTarget != NULL) { + DETOUR_TRACE(("%p: is import jump, label=%p\n", pb, *(PBYTE *)pbTarget)); + + PPLABEL_DESCRIPTOR ppld = (PPLABEL_DESCRIPTOR)*(PBYTE *)pbTarget; + pbCode = (PBYTE)ppld->EntryPoint; + pGlobals = (PBYTE)ppld->GlobalPointer; + if (ppGlobals != NULL) { + *ppGlobals = pGlobals; + } + } + } + return pbCode; +} + + +inline void detour_find_jmp_bounds(PBYTE pbCode, + PDETOUR_TRAMPOLINE *ppLower, + PDETOUR_TRAMPOLINE *ppUpper) +{ + (void)pbCode; + *ppLower = (PDETOUR_TRAMPOLINE)(ULONG_PTR)0x0000000000080000; + *ppUpper = (PDETOUR_TRAMPOLINE)(ULONG_PTR)0xfffffffffff80000; +} + +inline BOOL detour_does_code_end_function(PBYTE pbCode) +{ + // Routine not needed on IA64. + (void)pbCode; + return FALSE; +} + +inline ULONG detour_is_code_filler(PBYTE pbCode) +{ + // Routine not needed on IA64. + (void)pbCode; + return 0; +} + +#endif // DETOURS_IA64 + +#ifdef DETOURS_ARM + +struct _DETOUR_TRAMPOLINE +{ + // A Thumb-2 instruction can be 2 or 4 bytes long. + BYTE rbCode[62]; // target code + jmp to pbRemain + BYTE cbCode; // size of moved target code. + BYTE cbCodeBreak; // padding to make debugging easier. + BYTE rbRestore[22]; // original target code. + BYTE cbRestore; // size of original target code. + BYTE cbRestoreBreak; // padding to make debugging easier. + _DETOUR_ALIGN rAlign[8]; // instruction alignment array. + PBYTE pbRemain; // first instruction after moved code. [free list] + PBYTE pbDetour; // first instruction of detour function. +}; + +C_ASSERT(sizeof(_DETOUR_TRAMPOLINE) == 104); + +enum { + SIZE_OF_JMP = 8 +}; + +inline PBYTE align4(PBYTE pValue) +{ + return (PBYTE)(((ULONG)pValue) & ~(ULONG)3u); +} + +inline ULONG fetch_thumb_opcode(PBYTE pbCode) +{ + ULONG Opcode = *(UINT16 *)&pbCode[0]; + if (Opcode >= 0xe800) { + Opcode = (Opcode << 16) | *(UINT16 *)&pbCode[2]; + } + return Opcode; +} + +inline void write_thumb_opcode(PBYTE &pbCode, ULONG Opcode) +{ + if (Opcode >= 0x10000) { + *((UINT16*&)pbCode)++ = Opcode >> 16; + } + *((UINT16*&)pbCode)++ = (UINT16)Opcode; +} + +PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE *ppPool, PBYTE pbJmpVal) +{ + PBYTE pbLiteral; + if (ppPool != NULL) { + *ppPool = *ppPool - 4; + pbLiteral = *ppPool; + } + else { + pbLiteral = align4(pbCode + 6); + } + + *((PBYTE*&)pbLiteral) = DETOURS_PBYTE_TO_PFUNC(pbJmpVal); + LONG delta = pbLiteral - align4(pbCode + 4); + + write_thumb_opcode(pbCode, 0xf8dff000 | delta); // LDR PC,[PC+n] + + if (ppPool == NULL) { + if (((ULONG)pbCode & 2) != 0) { + write_thumb_opcode(pbCode, 0xdefe); // BREAK + } + pbCode += 4; + } + return pbCode; +} + +inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit) +{ + while (pbCode < pbLimit) { + write_thumb_opcode(pbCode, 0xdefe); + } + return pbCode; +} + +inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals) +{ + if (pbCode == NULL) { + return NULL; + } + if (ppGlobals != NULL) { + *ppGlobals = NULL; + } + + // Skip over the import jump if there is one. + pbCode = (PBYTE)DETOURS_PFUNC_TO_PBYTE(pbCode); + ULONG Opcode = fetch_thumb_opcode(pbCode); + + if ((Opcode & 0xfbf08f00) == 0xf2400c00) { // movw r12,#xxxx + ULONG Opcode2 = fetch_thumb_opcode(pbCode+4); + + if ((Opcode2 & 0xfbf08f00) == 0xf2c00c00) { // movt r12,#xxxx + ULONG Opcode3 = fetch_thumb_opcode(pbCode+8); + if (Opcode3 == 0xf8dcf000) { // ldr pc,[r12] + PBYTE pbTarget = (PBYTE)(((Opcode2 << 12) & 0xf7000000) | + ((Opcode2 << 1) & 0x08000000) | + ((Opcode2 << 16) & 0x00ff0000) | + ((Opcode >> 4) & 0x0000f700) | + ((Opcode >> 15) & 0x00000800) | + ((Opcode >> 0) & 0x000000ff)); + if (detour_is_imported(pbCode, pbTarget)) { + PBYTE pbNew = *(PBYTE *)pbTarget; + pbNew = DETOURS_PFUNC_TO_PBYTE(pbNew); + DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew)); + return pbNew; + } + } + } + } + return pbCode; +} + +inline void detour_find_jmp_bounds(PBYTE pbCode, + PDETOUR_TRAMPOLINE *ppLower, + PDETOUR_TRAMPOLINE *ppUpper) +{ + (void)pbCode; + *ppLower = (PDETOUR_TRAMPOLINE)(ULONG_PTR)0x00080000; + *ppUpper = (PDETOUR_TRAMPOLINE)(ULONG_PTR)0xfff80000; +} + +inline BOOL detour_does_code_end_function(PBYTE pbCode) +{ + ULONG Opcode = fetch_thumb_opcode(pbCode); + if ((Opcode & 0xffffff87) == 0x4700 || // bx + (Opcode & 0xf800d000) == 0xf0009000) { // b + return TRUE; + } + if ((Opcode & 0xffff8000) == 0xe8bd8000) { // pop {...,pc} + __debugbreak(); + return TRUE; + } + if ((Opcode & 0xffffff00) == 0x0000bd00) { // pop {...,pc} + __debugbreak(); + return TRUE; + } + return FALSE; +} + +inline ULONG detour_is_code_filler(PBYTE pbCode) +{ + if (pbCode[0] == 0x00 && pbCode[1] == 0xbf) { // nop. + return 2; + } + if (pbCode[0] == 0x00 && pbCode[1] == 0x00) { // zero-filled padding. + return 2; + } + return 0; +} + +#endif // DETOURS_ARM + +#ifdef DETOURS_ARM64 + +struct _DETOUR_TRAMPOLINE +{ + // An ARM64 instruction is 4 bytes long. + BYTE rbCode[64]; // target code + jmp to pbRemain + BYTE cbCode; // size of moved target code. + BYTE cbCodeBreak[3]; // padding to make debugging easier. + BYTE rbRestore[24]; // original target code. + BYTE cbRestore; // size of original target code. + BYTE cbRestoreBreak[3]; // padding to make debugging easier. + _DETOUR_ALIGN rAlign[8]; // instruction alignment array. + PBYTE pbRemain; // first instruction after moved code. [free list] + PBYTE pbDetour; // first instruction of detour function. +}; + +C_ASSERT(sizeof(_DETOUR_TRAMPOLINE) == 120); + +enum { + SIZE_OF_JMP = 16 +}; + +inline ULONG fetch_opcode(PBYTE pbCode) +{ + return *(ULONG *)pbCode; +} + +inline void write_opcode(PBYTE &pbCode, ULONG Opcode) +{ + *(ULONG *)pbCode = Opcode; + pbCode += 4; +} + +PBYTE detour_gen_jmp_immediate(PBYTE pbCode, PBYTE *ppPool, PBYTE pbJmpVal) +{ + PBYTE pbLiteral; + if (ppPool != NULL) { + *ppPool = *ppPool - 8; + pbLiteral = *ppPool; + } + else { + pbLiteral = pbCode + 8; + } + + *((PBYTE*&)pbLiteral) = pbJmpVal; + LONG delta = (LONG)(pbLiteral - pbCode); + + write_opcode(pbCode, 0x58000011 | ((delta / 4) << 5)); // LDR X17,[PC+n] + write_opcode(pbCode, 0xd61f0000 | (17 << 5)); // BR X17 + + if (ppPool == NULL) { + pbCode += 8; + } + return pbCode; +} + +inline PBYTE detour_gen_brk(PBYTE pbCode, PBYTE pbLimit) +{ + while (pbCode < pbLimit) { + write_opcode(pbCode, 0xd4100000 | (0xf000 << 5)); + } + return pbCode; +} + +inline PBYTE detour_skip_jmp(PBYTE pbCode, PVOID *ppGlobals) +{ + if (pbCode == NULL) { + return NULL; + } + if (ppGlobals != NULL) { + *ppGlobals = NULL; + } + + // Skip over the import jump if there is one. + pbCode = (PBYTE)pbCode; + ULONG Opcode = fetch_opcode(pbCode); + if ((Opcode & 0x9f00001f) == 0x90000010) { // adrp x16, IAT + ULONG Opcode2 = fetch_opcode(pbCode+4); + + if ((Opcode2 & 0xffe003ff) == 0xf9400210) { // ldr x16, [x16, IAT] + ULONG Opcode3 = fetch_opcode(pbCode+8); + + if (Opcode3 == 0xd61f0200) { // br x16 + + ULONG PageOffset = ((Opcode & 0x60000000) >> 29) | ((Opcode & 0x00ffffe0) >> 3); + PageOffset = (LONG)(Opcode << 11) >> 11; + + PBYTE pbTarget = (PBYTE)(((ULONG64)pbCode & 0xfffffffffffff000ULL) + PageOffset + + ((Opcode2 >> 10) & 0xfff)); + if (detour_is_imported(pbCode, pbTarget)) { + PBYTE pbNew = *(PBYTE *)pbTarget; + DETOUR_TRACE(("%p->%p: skipped over import table.\n", pbCode, pbNew)); + return pbNew; + } + } + } + } + return pbCode; +} + +inline void detour_find_jmp_bounds(PBYTE pbCode, + PDETOUR_TRAMPOLINE *ppLower, + PDETOUR_TRAMPOLINE *ppUpper) +{ + (void)pbCode; + *ppLower = (PDETOUR_TRAMPOLINE)(ULONG_PTR)0x0000000000080000; + *ppUpper = (PDETOUR_TRAMPOLINE)(ULONG_PTR)0xfffffffffff80000; +} + +inline BOOL detour_does_code_end_function(PBYTE pbCode) +{ + ULONG Opcode = fetch_opcode(pbCode); + if ((Opcode & 0xfffffc1f) == 0xd65f0000 || // br + (Opcode & 0xfc000000) == 0x14000000) { // b + return TRUE; + } + return FALSE; +} + +inline ULONG detour_is_code_filler(PBYTE pbCode) +{ + if (*(ULONG *)pbCode == 0xd503201f) { // nop. + return 4; + } + if (*(ULONG *)pbCode == 0x00000000) { // zero-filled padding. + return 4; + } + return 0; +} + +#endif // DETOURS_ARM64 + +//////////////////////////////////////////////// Trampoline Memory Management. +// +struct DETOUR_REGION +{ + ULONG dwSignature; + DETOUR_REGION * pNext; // Next region in list of regions. + DETOUR_TRAMPOLINE * pFree; // List of free trampolines in this region. +}; +typedef DETOUR_REGION * PDETOUR_REGION; + +const ULONG DETOUR_REGION_SIGNATURE = 'Rrtd'; +const ULONG DETOUR_REGION_SIZE = 0x10000; +const ULONG DETOUR_TRAMPOLINES_PER_REGION = (DETOUR_REGION_SIZE + / sizeof(DETOUR_TRAMPOLINE)) - 1; +static PDETOUR_REGION s_pRegions = NULL; // List of all regions. +static PDETOUR_REGION s_pRegion = NULL; // Default region. + +static DWORD detour_writable_trampoline_regions() +{ + // Mark all of the regions as writable. + for (PDETOUR_REGION pRegion = s_pRegions; pRegion != NULL; pRegion = pRegion->pNext) { + DWORD dwOld; + if (!VirtualProtect(pRegion, DETOUR_REGION_SIZE, PAGE_EXECUTE_READWRITE, &dwOld)) { + return GetLastError(); + } + } + return NO_ERROR; +} + +static void detour_runnable_trampoline_regions() +{ + HANDLE hProcess = GetCurrentProcess(); + + // Mark all of the regions as executable. + for (PDETOUR_REGION pRegion = s_pRegions; pRegion != NULL; pRegion = pRegion->pNext) { + DWORD dwOld; + VirtualProtect(pRegion, DETOUR_REGION_SIZE, PAGE_EXECUTE_READ, &dwOld); + FlushInstructionCache(hProcess, pRegion, DETOUR_REGION_SIZE); + } +} + +static PBYTE detour_alloc_round_down_to_region(PBYTE pbTry) +{ + // WinXP64 returns free areas that aren't REGION aligned to 32-bit applications. + ULONG_PTR extra = ((ULONG_PTR)pbTry) & (DETOUR_REGION_SIZE - 1); + if (extra != 0) { + pbTry -= extra; + } + return pbTry; +} + +static PBYTE detour_alloc_round_up_to_region(PBYTE pbTry) +{ + // WinXP64 returns free areas that aren't REGION aligned to 32-bit applications. + ULONG_PTR extra = ((ULONG_PTR)pbTry) & (DETOUR_REGION_SIZE - 1); + if (extra != 0) { + ULONG_PTR adjust = DETOUR_REGION_SIZE - extra; + pbTry += adjust; + } + return pbTry; +} + +// Starting at pbLo, try to allocate a memory region, continue until pbHi. + +static PVOID detour_alloc_region_from_lo(PBYTE pbLo, PBYTE pbHi) +{ + PBYTE pbTry = detour_alloc_round_up_to_region(pbLo); + + DETOUR_TRACE((" Looking for free region in %p..%p from %p:\n", pbLo, pbHi, pbTry)); + + for (; pbTry < pbHi;) { + MEMORY_BASIC_INFORMATION mbi; + + if (pbTry >= s_pSystemRegionLowerBound && pbTry <= s_pSystemRegionUpperBound) { + // Skip region reserved for system DLLs, but preserve address space entropy. + pbTry += 0x08000000; + continue; + } + + ZeroMemory(&mbi, sizeof(mbi)); + if (!VirtualQuery(pbTry, &mbi, sizeof(mbi))) { + break; + } + + DETOUR_TRACE((" Try %p => %p..%p %6x\n", + pbTry, + mbi.BaseAddress, + (PBYTE)mbi.BaseAddress + mbi.RegionSize - 1, + mbi.State)); + + if (mbi.State == MEM_FREE && mbi.RegionSize >= DETOUR_REGION_SIZE) { + + PVOID pv = VirtualAlloc(pbTry, + DETOUR_REGION_SIZE, + MEM_COMMIT|MEM_RESERVE, + PAGE_EXECUTE_READWRITE); + if (pv != NULL) { + return pv; + } + pbTry += DETOUR_REGION_SIZE; + } + else { + pbTry = detour_alloc_round_up_to_region((PBYTE)mbi.BaseAddress + mbi.RegionSize); + } + } + return NULL; +} + +// Starting at pbHi, try to allocate a memory region, continue until pbLo. + +static PVOID detour_alloc_region_from_hi(PBYTE pbLo, PBYTE pbHi) +{ + PBYTE pbTry = detour_alloc_round_down_to_region(pbHi - DETOUR_REGION_SIZE); + + DETOUR_TRACE((" Looking for free region in %p..%p from %p:\n", pbLo, pbHi, pbTry)); + + for (; pbTry > pbLo;) { + MEMORY_BASIC_INFORMATION mbi; + + DETOUR_TRACE((" Try %p\n", pbTry)); + if (pbTry >= s_pSystemRegionLowerBound && pbTry <= s_pSystemRegionUpperBound) { + // Skip region reserved for system DLLs, but preserve address space entropy. + pbTry -= 0x08000000; + continue; + } + + ZeroMemory(&mbi, sizeof(mbi)); + if (!VirtualQuery(pbTry, &mbi, sizeof(mbi))) { + break; + } + + DETOUR_TRACE((" Try %p => %p..%p %6x\n", + pbTry, + mbi.BaseAddress, + (PBYTE)mbi.BaseAddress + mbi.RegionSize - 1, + mbi.State)); + + if (mbi.State == MEM_FREE && mbi.RegionSize >= DETOUR_REGION_SIZE) { + + PVOID pv = VirtualAlloc(pbTry, + DETOUR_REGION_SIZE, + MEM_COMMIT|MEM_RESERVE, + PAGE_EXECUTE_READWRITE); + if (pv != NULL) { + return pv; + } + pbTry -= DETOUR_REGION_SIZE; + } + else { + pbTry = detour_alloc_round_down_to_region((PBYTE)mbi.AllocationBase + - DETOUR_REGION_SIZE); + } + } + return NULL; +} + +static PDETOUR_TRAMPOLINE detour_alloc_trampoline(PBYTE pbTarget) +{ + // We have to place trampolines within +/- 2GB of target. + + PDETOUR_TRAMPOLINE pLo; + PDETOUR_TRAMPOLINE pHi; + + detour_find_jmp_bounds(pbTarget, &pLo, &pHi); + + PDETOUR_TRAMPOLINE pTrampoline = NULL; + + // Insure that there is a default region. + if (s_pRegion == NULL && s_pRegions != NULL) { + s_pRegion = s_pRegions; + } + + // First check the default region for an valid free block. + if (s_pRegion != NULL && s_pRegion->pFree != NULL && + s_pRegion->pFree >= pLo && s_pRegion->pFree <= pHi) { + + found_region: + pTrampoline = s_pRegion->pFree; + // do a last sanity check on region. + if (pTrampoline < pLo || pTrampoline > pHi) { + return NULL; + } + s_pRegion->pFree = (PDETOUR_TRAMPOLINE)pTrampoline->pbRemain; + memset(pTrampoline, 0xcc, sizeof(*pTrampoline)); + return pTrampoline; + } + + // Then check the existing regions for a valid free block. + for (s_pRegion = s_pRegions; s_pRegion != NULL; s_pRegion = s_pRegion->pNext) { + if (s_pRegion != NULL && s_pRegion->pFree != NULL && + s_pRegion->pFree >= pLo && s_pRegion->pFree <= pHi) { + goto found_region; + } + } + + // We need to allocate a new region. + + // Round pbTarget down to 64KB block. + pbTarget = pbTarget - (PtrToUlong(pbTarget) & 0xffff); + + PVOID pbTry = NULL; + + // NB: We must always also start the search at an offset from pbTarget + // in order to maintain ASLR entropy. + +#if defined(DETOURS_64BIT) + // Try looking 1GB below or lower. + if (pbTry == NULL && pbTarget > (PBYTE)0x40000000) { + pbTry = detour_alloc_region_from_hi((PBYTE)pLo, pbTarget - 0x40000000); + } + // Try looking 1GB above or higher. + if (pbTry == NULL && pbTarget < (PBYTE)0xffffffff40000000) { + pbTry = detour_alloc_region_from_lo(pbTarget + 0x40000000, (PBYTE)pHi); + } + // Try looking 1GB below or higher. + if (pbTry == NULL && pbTarget > (PBYTE)0x40000000) { + pbTry = detour_alloc_region_from_lo(pbTarget - 0x40000000, pbTarget); + } + // Try looking 1GB above or lower. + if (pbTry == NULL && pbTarget < (PBYTE)0xffffffff40000000) { + pbTry = detour_alloc_region_from_hi(pbTarget, pbTarget + 0x40000000); + } +#endif + + // Try anything below. + if (pbTry == NULL) { + pbTry = detour_alloc_region_from_hi((PBYTE)pLo, pbTarget); + } + // try anything above. + if (pbTry == NULL) { + pbTry = detour_alloc_region_from_lo(pbTarget, (PBYTE)pHi); + } + + if (pbTry != NULL) { + s_pRegion = (DETOUR_REGION*)pbTry; + s_pRegion->dwSignature = DETOUR_REGION_SIGNATURE; + s_pRegion->pFree = NULL; + s_pRegion->pNext = s_pRegions; + s_pRegions = s_pRegion; + DETOUR_TRACE((" Allocated region %p..%p\n\n", + s_pRegion, ((PBYTE)s_pRegion) + DETOUR_REGION_SIZE - 1)); + + // Put everything but the first trampoline on the free list. + PBYTE pFree = NULL; + pTrampoline = ((PDETOUR_TRAMPOLINE)s_pRegion) + 1; + for (int i = DETOUR_TRAMPOLINES_PER_REGION - 1; i > 1; i--) { + pTrampoline[i].pbRemain = pFree; + pFree = (PBYTE)&pTrampoline[i]; + } + s_pRegion->pFree = (PDETOUR_TRAMPOLINE)pFree; + goto found_region; + } + + DETOUR_TRACE(("Couldn't find available memory region!\n")); + return NULL; +} + +static void detour_free_trampoline(PDETOUR_TRAMPOLINE pTrampoline) +{ + PDETOUR_REGION pRegion = (PDETOUR_REGION) + ((ULONG_PTR)pTrampoline & ~(ULONG_PTR)0xffff); + + memset(pTrampoline, 0, sizeof(*pTrampoline)); + pTrampoline->pbRemain = (PBYTE)pRegion->pFree; + pRegion->pFree = pTrampoline; +} + +static BOOL detour_is_region_empty(PDETOUR_REGION pRegion) +{ + // Stop if the region isn't a region (this would be bad). + if (pRegion->dwSignature != DETOUR_REGION_SIGNATURE) { + return FALSE; + } + + PBYTE pbRegionBeg = (PBYTE)pRegion; + PBYTE pbRegionLim = pbRegionBeg + DETOUR_REGION_SIZE; + + // Stop if any of the trampolines aren't free. + PDETOUR_TRAMPOLINE pTrampoline = ((PDETOUR_TRAMPOLINE)pRegion) + 1; + for (int i = 0; i < DETOUR_TRAMPOLINES_PER_REGION; i++) { + if (pTrampoline[i].pbRemain != NULL && + (pTrampoline[i].pbRemain < pbRegionBeg || + pTrampoline[i].pbRemain >= pbRegionLim)) { + return FALSE; + } + } + + // OK, the region is empty. + return TRUE; +} + +static void detour_free_unused_trampoline_regions() +{ + PDETOUR_REGION *ppRegionBase = &s_pRegions; + PDETOUR_REGION pRegion = s_pRegions; + + while (pRegion != NULL) { + if (detour_is_region_empty(pRegion)) { + *ppRegionBase = pRegion->pNext; + + VirtualFree(pRegion, 0, MEM_RELEASE); + s_pRegion = NULL; + } + else { + ppRegionBase = &pRegion->pNext; + } + pRegion = *ppRegionBase; + } +} + +///////////////////////////////////////////////////////// Transaction Structs. +// +struct DetourThread +{ + DetourThread * pNext; + HANDLE hThread; +}; + +struct DetourOperation +{ + DetourOperation * pNext; + BOOL fIsRemove; + PBYTE * ppbPointer; + PBYTE pbTarget; + PDETOUR_TRAMPOLINE pTrampoline; + ULONG dwPerm; +}; + +static BOOL s_fIgnoreTooSmall = FALSE; +static BOOL s_fRetainRegions = FALSE; + +static LONG s_nPendingThreadId = 0; // Thread owning pending transaction. +static LONG s_nPendingError = NO_ERROR; +static PVOID * s_ppPendingError = NULL; +static DetourThread * s_pPendingThreads = NULL; +static DetourOperation * s_pPendingOperations = NULL; + +////////////////////////////////////////////////////////////////////////////// +// +PVOID WINAPI DetourCodeFromPointer(_In_ PVOID pPointer, + _Out_opt_ PVOID *ppGlobals) +{ + return detour_skip_jmp((PBYTE)pPointer, ppGlobals); +} + +//////////////////////////////////////////////////////////// Transaction APIs. +// +BOOL WINAPI DetourSetIgnoreTooSmall(_In_ BOOL fIgnore) +{ + BOOL fPrevious = s_fIgnoreTooSmall; + s_fIgnoreTooSmall = fIgnore; + return fPrevious; +} + +BOOL WINAPI DetourSetRetainRegions(_In_ BOOL fRetain) +{ + BOOL fPrevious = s_fRetainRegions; + s_fRetainRegions = fRetain; + return fPrevious; +} + +PVOID WINAPI DetourSetSystemRegionLowerBound(_In_ PVOID pSystemRegionLowerBound) +{ + PVOID pPrevious = s_pSystemRegionLowerBound; + s_pSystemRegionLowerBound = pSystemRegionLowerBound; + return pPrevious; +} + +PVOID WINAPI DetourSetSystemRegionUpperBound(_In_ PVOID pSystemRegionUpperBound) +{ + PVOID pPrevious = s_pSystemRegionUpperBound; + s_pSystemRegionUpperBound = pSystemRegionUpperBound; + return pPrevious; +} + +LONG WINAPI DetourTransactionBegin() +{ + // Only one transaction is allowed at a time. +_Benign_race_begin_ + if (s_nPendingThreadId != 0) { + return ERROR_INVALID_OPERATION; + } +_Benign_race_end_ + + // Make sure only one thread can start a transaction. + if (InterlockedCompareExchange(&s_nPendingThreadId, (LONG)GetCurrentThreadId(), 0) != 0) { + return ERROR_INVALID_OPERATION; + } + + s_pPendingOperations = NULL; + s_pPendingThreads = NULL; + s_ppPendingError = NULL; + + // Make sure the trampoline pages are writable. + s_nPendingError = detour_writable_trampoline_regions(); + + return s_nPendingError; +} + +LONG WINAPI DetourTransactionAbort() +{ + if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) { + return ERROR_INVALID_OPERATION; + } + + // Restore all of the page permissions. + for (DetourOperation *o = s_pPendingOperations; o != NULL;) { + // We don't care if this fails, because the code is still accessible. + DWORD dwOld; + VirtualProtect(o->pbTarget, o->pTrampoline->cbRestore, + o->dwPerm, &dwOld); + + if (!o->fIsRemove) { + if (o->pTrampoline) { + detour_free_trampoline(o->pTrampoline); + o->pTrampoline = NULL; + } + } + + DetourOperation *n = o->pNext; + delete o; + o = n; + } + s_pPendingOperations = NULL; + + // Make sure the trampoline pages are no longer writable. + detour_runnable_trampoline_regions(); + + // Resume any suspended threads. + for (DetourThread *t = s_pPendingThreads; t != NULL;) { + // There is nothing we can do if this fails. + ResumeThread(t->hThread); + + DetourThread *n = t->pNext; + delete t; + t = n; + } + s_pPendingThreads = NULL; + s_nPendingThreadId = 0; + + return NO_ERROR; +} + +LONG WINAPI DetourTransactionCommit() +{ + return DetourTransactionCommitEx(NULL); +} + +static BYTE detour_align_from_trampoline(PDETOUR_TRAMPOLINE pTrampoline, BYTE obTrampoline) +{ + for (LONG n = 0; n < ARRAYSIZE(pTrampoline->rAlign); n++) { + if (pTrampoline->rAlign[n].obTrampoline == obTrampoline) { + return pTrampoline->rAlign[n].obTarget; + } + } + return 0; +} + +static LONG detour_align_from_target(PDETOUR_TRAMPOLINE pTrampoline, LONG obTarget) +{ + for (LONG n = 0; n < ARRAYSIZE(pTrampoline->rAlign); n++) { + if (pTrampoline->rAlign[n].obTarget == obTarget) { + return pTrampoline->rAlign[n].obTrampoline; + } + } + return 0; +} + +LONG WINAPI DetourTransactionCommitEx(_Out_opt_ PVOID **pppFailedPointer) +{ + if (pppFailedPointer != NULL) { + // Used to get the last error. + *pppFailedPointer = s_ppPendingError; + } + if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) { + return ERROR_INVALID_OPERATION; + } + + // If any of the pending operations failed, then we abort the whole transaction. + if (s_nPendingError != NO_ERROR) { + DETOUR_BREAK(); + DetourTransactionAbort(); + return s_nPendingError; + } + + // Common variables. + DetourOperation *o; + DetourThread *t; + BOOL freed = FALSE; + + // Insert or remove each of the detours. + for (o = s_pPendingOperations; o != NULL; o = o->pNext) { + if (o->fIsRemove) { + CopyMemory(o->pbTarget, + o->pTrampoline->rbRestore, + o->pTrampoline->cbRestore); +#ifdef DETOURS_IA64 + *o->ppbPointer = (PBYTE)o->pTrampoline->ppldTarget; +#endif // DETOURS_IA64 + +#ifdef DETOURS_X86 + *o->ppbPointer = o->pbTarget; +#endif // DETOURS_X86 + +#ifdef DETOURS_X64 + *o->ppbPointer = o->pbTarget; +#endif // DETOURS_X64 + +#ifdef DETOURS_ARM + *o->ppbPointer = DETOURS_PBYTE_TO_PFUNC(o->pbTarget); +#endif // DETOURS_ARM + +#ifdef DETOURS_ARM64 + *o->ppbPointer = o->pbTarget; +#endif // DETOURS_ARM + } + else { + DETOUR_TRACE(("detours: pbTramp =%p, pbRemain=%p, pbDetour=%p, cbRestore=%d\n", + o->pTrampoline, + o->pTrampoline->pbRemain, + o->pTrampoline->pbDetour, + o->pTrampoline->cbRestore)); + + DETOUR_TRACE(("detours: pbTarget=%p: " + "%02x %02x %02x %02x " + "%02x %02x %02x %02x " + "%02x %02x %02x %02x [before]\n", + o->pbTarget, + o->pbTarget[0], o->pbTarget[1], o->pbTarget[2], o->pbTarget[3], + o->pbTarget[4], o->pbTarget[5], o->pbTarget[6], o->pbTarget[7], + o->pbTarget[8], o->pbTarget[9], o->pbTarget[10], o->pbTarget[11])); + +#ifdef DETOURS_IA64 + ((DETOUR_IA64_BUNDLE*)o->pbTarget) + ->SetBrl((UINT64)&o->pTrampoline->bAllocFrame); + *o->ppbPointer = (PBYTE)&o->pTrampoline->pldTrampoline; +#endif // DETOURS_IA64 + +#ifdef DETOURS_X64 + detour_gen_jmp_indirect(o->pTrampoline->rbCodeIn, &o->pTrampoline->pbDetour); + PBYTE pbCode = detour_gen_jmp_immediate(o->pbTarget, o->pTrampoline->rbCodeIn); + pbCode = detour_gen_brk(pbCode, o->pTrampoline->pbRemain); + *o->ppbPointer = o->pTrampoline->rbCode; + UNREFERENCED_PARAMETER(pbCode); +#endif // DETOURS_X64 + +#ifdef DETOURS_X86 + PBYTE pbCode = detour_gen_jmp_immediate(o->pbTarget, o->pTrampoline->pbDetour); + pbCode = detour_gen_brk(pbCode, o->pTrampoline->pbRemain); + *o->ppbPointer = o->pTrampoline->rbCode; + UNREFERENCED_PARAMETER(pbCode); +#endif // DETOURS_X86 + +#ifdef DETOURS_ARM + PBYTE pbCode = detour_gen_jmp_immediate(o->pbTarget, NULL, o->pTrampoline->pbDetour); + pbCode = detour_gen_brk(pbCode, o->pTrampoline->pbRemain); + *o->ppbPointer = DETOURS_PBYTE_TO_PFUNC(o->pTrampoline->rbCode); + UNREFERENCED_PARAMETER(pbCode); +#endif // DETOURS_ARM + +#ifdef DETOURS_ARM64 + PBYTE pbCode = detour_gen_jmp_immediate(o->pbTarget, NULL, o->pTrampoline->pbDetour); + pbCode = detour_gen_brk(pbCode, o->pTrampoline->pbRemain); + *o->ppbPointer = o->pTrampoline->rbCode; + UNREFERENCED_PARAMETER(pbCode); +#endif // DETOURS_ARM64 + + DETOUR_TRACE(("detours: pbTarget=%p: " + "%02x %02x %02x %02x " + "%02x %02x %02x %02x " + "%02x %02x %02x %02x [after]\n", + o->pbTarget, + o->pbTarget[0], o->pbTarget[1], o->pbTarget[2], o->pbTarget[3], + o->pbTarget[4], o->pbTarget[5], o->pbTarget[6], o->pbTarget[7], + o->pbTarget[8], o->pbTarget[9], o->pbTarget[10], o->pbTarget[11])); + + DETOUR_TRACE(("detours: pbTramp =%p: " + "%02x %02x %02x %02x " + "%02x %02x %02x %02x " + "%02x %02x %02x %02x\n", + o->pTrampoline, + o->pTrampoline->rbCode[0], o->pTrampoline->rbCode[1], + o->pTrampoline->rbCode[2], o->pTrampoline->rbCode[3], + o->pTrampoline->rbCode[4], o->pTrampoline->rbCode[5], + o->pTrampoline->rbCode[6], o->pTrampoline->rbCode[7], + o->pTrampoline->rbCode[8], o->pTrampoline->rbCode[9], + o->pTrampoline->rbCode[10], o->pTrampoline->rbCode[11])); + +#ifdef DETOURS_IA64 + DETOUR_TRACE(("\n")); + DETOUR_TRACE(("detours: &pldTrampoline =%p\n", + &o->pTrampoline->pldTrampoline)); + DETOUR_TRACE(("detours: &bMovlTargetGp =%p [%p]\n", + &o->pTrampoline->bMovlTargetGp, + o->pTrampoline->bMovlTargetGp.GetMovlGp())); + DETOUR_TRACE(("detours: &rbCode =%p [%p]\n", + &o->pTrampoline->rbCode, + ((DETOUR_IA64_BUNDLE&)o->pTrampoline->rbCode).GetBrlTarget())); + DETOUR_TRACE(("detours: &bBrlRemainEip =%p [%p]\n", + &o->pTrampoline->bBrlRemainEip, + o->pTrampoline->bBrlRemainEip.GetBrlTarget())); + DETOUR_TRACE(("detours: &bMovlDetourGp =%p [%p]\n", + &o->pTrampoline->bMovlDetourGp, + o->pTrampoline->bMovlDetourGp.GetMovlGp())); + DETOUR_TRACE(("detours: &bBrlDetourEip =%p [%p]\n", + &o->pTrampoline->bCallDetour, + o->pTrampoline->bCallDetour.GetBrlTarget())); + DETOUR_TRACE(("detours: pldDetour =%p [%p]\n", + o->pTrampoline->ppldDetour->EntryPoint, + o->pTrampoline->ppldDetour->GlobalPointer)); + DETOUR_TRACE(("detours: pldTarget =%p [%p]\n", + o->pTrampoline->ppldTarget->EntryPoint, + o->pTrampoline->ppldTarget->GlobalPointer)); + DETOUR_TRACE(("detours: pbRemain =%p\n", + o->pTrampoline->pbRemain)); + DETOUR_TRACE(("detours: pbDetour =%p\n", + o->pTrampoline->pbDetour)); + DETOUR_TRACE(("\n")); +#endif // DETOURS_IA64 + } + } + + // Update any suspended threads. + for (t = s_pPendingThreads; t != NULL; t = t->pNext) { + CONTEXT cxt; + cxt.ContextFlags = CONTEXT_CONTROL; + +#undef DETOURS_EIP + +#ifdef DETOURS_X86 +#define DETOURS_EIP Eip +#endif // DETOURS_X86 + +#ifdef DETOURS_X64 +#define DETOURS_EIP Rip +#endif // DETOURS_X64 + +#ifdef DETOURS_IA64 +#define DETOURS_EIP StIIP +#endif // DETOURS_IA64 + +#ifdef DETOURS_ARM +#define DETOURS_EIP Pc +#endif // DETOURS_ARM + +#ifdef DETOURS_ARM64 +#define DETOURS_EIP Pc +#endif // DETOURS_ARM64 + +typedef ULONG_PTR DETOURS_EIP_TYPE; + + if (GetThreadContext(t->hThread, &cxt)) { + for (o = s_pPendingOperations; o != NULL; o = o->pNext) { + if (o->fIsRemove) { + if (cxt.DETOURS_EIP >= (DETOURS_EIP_TYPE)(ULONG_PTR)o->pTrampoline && + cxt.DETOURS_EIP < (DETOURS_EIP_TYPE)((ULONG_PTR)o->pTrampoline + + sizeof(o->pTrampoline)) + ) { + + cxt.DETOURS_EIP = (DETOURS_EIP_TYPE) + ((ULONG_PTR)o->pbTarget + + detour_align_from_trampoline(o->pTrampoline, + (BYTE)(cxt.DETOURS_EIP + - (DETOURS_EIP_TYPE)(ULONG_PTR) + o->pTrampoline))); + + SetThreadContext(t->hThread, &cxt); + } + } + else { + if (cxt.DETOURS_EIP >= (DETOURS_EIP_TYPE)(ULONG_PTR)o->pbTarget && + cxt.DETOURS_EIP < (DETOURS_EIP_TYPE)((ULONG_PTR)o->pbTarget + + o->pTrampoline->cbRestore) + ) { + + cxt.DETOURS_EIP = (DETOURS_EIP_TYPE) + ((ULONG_PTR)o->pTrampoline + + detour_align_from_target(o->pTrampoline, + (BYTE)(cxt.DETOURS_EIP + - (DETOURS_EIP_TYPE)(ULONG_PTR) + o->pbTarget))); + + SetThreadContext(t->hThread, &cxt); + } + } + } + } +#undef DETOURS_EIP + } + + // Restore all of the page permissions and flush the icache. + HANDLE hProcess = GetCurrentProcess(); + for (o = s_pPendingOperations; o != NULL;) { + // We don't care if this fails, because the code is still accessible. + DWORD dwOld; + VirtualProtect(o->pbTarget, o->pTrampoline->cbRestore, o->dwPerm, &dwOld); + FlushInstructionCache(hProcess, o->pbTarget, o->pTrampoline->cbRestore); + + if (o->fIsRemove && o->pTrampoline) { + detour_free_trampoline(o->pTrampoline); + o->pTrampoline = NULL; + freed = true; + } + + DetourOperation *n = o->pNext; + delete o; + o = n; + } + s_pPendingOperations = NULL; + + // Free any trampoline regions that are now unused. + if (freed && !s_fRetainRegions) { + detour_free_unused_trampoline_regions(); + } + + // Make sure the trampoline pages are no longer writable. + detour_runnable_trampoline_regions(); + + // Resume any suspended threads. + for (t = s_pPendingThreads; t != NULL;) { + // There is nothing we can do if this fails. + ResumeThread(t->hThread); + + DetourThread *n = t->pNext; + delete t; + t = n; + } + s_pPendingThreads = NULL; + s_nPendingThreadId = 0; + + if (pppFailedPointer != NULL) { + *pppFailedPointer = s_ppPendingError; + } + + return s_nPendingError; +} + +LONG WINAPI DetourUpdateThread(_In_ HANDLE hThread) +{ + LONG error; + + // If any of the pending operations failed, then we don't need to do this. + if (s_nPendingError != NO_ERROR) { + return s_nPendingError; + } + + // Silently (and safely) drop any attempt to suspend our own thread. + if (hThread == GetCurrentThread()) { + return NO_ERROR; + } + + DetourThread *t = new NOTHROW DetourThread; + if (t == NULL) { + error = ERROR_NOT_ENOUGH_MEMORY; + fail: + if (t != NULL) { + delete t; + t = NULL; + } + s_nPendingError = error; + s_ppPendingError = NULL; + DETOUR_BREAK(); + return error; + } + + if (SuspendThread(hThread) == (DWORD)-1) { + error = GetLastError(); + DETOUR_BREAK(); + goto fail; + } + + t->hThread = hThread; + t->pNext = s_pPendingThreads; + s_pPendingThreads = t; + + return NO_ERROR; +} + +///////////////////////////////////////////////////////////// Transacted APIs. +// +LONG WINAPI DetourAttach(_Inout_ PVOID *ppPointer, + _In_ PVOID pDetour) +{ + return DetourAttachEx(ppPointer, pDetour, NULL, NULL, NULL); +} + +LONG WINAPI DetourAttachEx(_Inout_ PVOID *ppPointer, + _In_ PVOID pDetour, + _Out_opt_ PDETOUR_TRAMPOLINE *ppRealTrampoline, + _Out_opt_ PVOID *ppRealTarget, + _Out_opt_ PVOID *ppRealDetour) +{ + LONG error = NO_ERROR; + + if (ppRealTrampoline != NULL) { + *ppRealTrampoline = NULL; + } + if (ppRealTarget != NULL) { + *ppRealTarget = NULL; + } + if (ppRealDetour != NULL) { + *ppRealDetour = NULL; + } + if (pDetour == NULL) { + DETOUR_TRACE(("empty detour\n")); + return ERROR_INVALID_PARAMETER; + } + + if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) { + DETOUR_TRACE(("transaction conflict with thread id=%d\n", s_nPendingThreadId)); + return ERROR_INVALID_OPERATION; + } + + // If any of the pending operations failed, then we don't need to do this. + if (s_nPendingError != NO_ERROR) { + DETOUR_TRACE(("pending transaction error=%d\n", s_nPendingError)); + return s_nPendingError; + } + + if (ppPointer == NULL) { + DETOUR_TRACE(("ppPointer is null\n")); + return ERROR_INVALID_HANDLE; + } + if (*ppPointer == NULL) { + error = ERROR_INVALID_HANDLE; + s_nPendingError = error; + s_ppPendingError = ppPointer; + DETOUR_TRACE(("*ppPointer is null (ppPointer=%p)\n", ppPointer)); + DETOUR_BREAK(); + return error; + } + + PBYTE pbTarget = (PBYTE)*ppPointer; + PDETOUR_TRAMPOLINE pTrampoline = NULL; + DetourOperation *o = NULL; + +#ifdef DETOURS_IA64 + PPLABEL_DESCRIPTOR ppldDetour = (PPLABEL_DESCRIPTOR)pDetour; + PPLABEL_DESCRIPTOR ppldTarget = (PPLABEL_DESCRIPTOR)pbTarget; + PVOID pDetourGlobals = NULL; + PVOID pTargetGlobals = NULL; + + pDetour = (PBYTE)DetourCodeFromPointer(ppldDetour, &pDetourGlobals); + pbTarget = (PBYTE)DetourCodeFromPointer(ppldTarget, &pTargetGlobals); + DETOUR_TRACE((" ppldDetour=%p, code=%p [gp=%p]\n", + ppldDetour, pDetour, pDetourGlobals)); + DETOUR_TRACE((" ppldTarget=%p, code=%p [gp=%p]\n", + ppldTarget, pbTarget, pTargetGlobals)); +#else // DETOURS_IA64 + pbTarget = (PBYTE)DetourCodeFromPointer(pbTarget, NULL); + pDetour = DetourCodeFromPointer(pDetour, NULL); +#endif // !DETOURS_IA64 + + // Don't follow a jump if its destination is the target function. + // This happens when the detour does nothing other than call the target. + if (pDetour == (PVOID)pbTarget) { + if (s_fIgnoreTooSmall) { + goto stop; + } + else { + DETOUR_BREAK(); + goto fail; + } + } + + if (ppRealTarget != NULL) { + *ppRealTarget = pbTarget; + } + if (ppRealDetour != NULL) { + *ppRealDetour = pDetour; + } + + o = new NOTHROW DetourOperation; + if (o == NULL) { + error = ERROR_NOT_ENOUGH_MEMORY; + fail: + s_nPendingError = error; + DETOUR_BREAK(); + stop: + if (pTrampoline != NULL) { + detour_free_trampoline(pTrampoline); + pTrampoline = NULL; + if (ppRealTrampoline != NULL) { + *ppRealTrampoline = NULL; + } + } + if (o != NULL) { + delete o; + o = NULL; + } + s_ppPendingError = ppPointer; + return error; + } + + pTrampoline = detour_alloc_trampoline(pbTarget); + if (pTrampoline == NULL) { + error = ERROR_NOT_ENOUGH_MEMORY; + DETOUR_BREAK(); + goto fail; + } + + if (ppRealTrampoline != NULL) { + *ppRealTrampoline = pTrampoline; + } + + DETOUR_TRACE(("detours: pbTramp=%p, pDetour=%p\n", pTrampoline, pDetour)); + + memset(pTrampoline->rAlign, 0, sizeof(pTrampoline->rAlign)); + + // Determine the number of movable target instructions. + PBYTE pbSrc = pbTarget; + PBYTE pbTrampoline = pTrampoline->rbCode; +#ifdef DETOURS_IA64 + PBYTE pbPool = (PBYTE)(&pTrampoline->bBranchIslands + 1); +#else + PBYTE pbPool = pbTrampoline + sizeof(pTrampoline->rbCode); +#endif + ULONG cbTarget = 0; + ULONG cbJump = SIZE_OF_JMP; + ULONG nAlign = 0; + +#ifdef DETOURS_ARM + // On ARM, we need an extra instruction when the function isn't 32-bit aligned. + // Check if the existing code is another detour (or at least a similar + // "ldr pc, [PC+0]" jump. + if ((ULONG)pbTarget & 2) { + cbJump += 2; + + ULONG op = fetch_thumb_opcode(pbSrc); + if (op == 0xbf00) { + op = fetch_thumb_opcode(pbSrc + 2); + if (op == 0xf8dff000) { // LDR PC,[PC] + *((PUSHORT&)pbTrampoline)++ = *((PUSHORT&)pbSrc)++; + *((PULONG&)pbTrampoline)++ = *((PULONG&)pbSrc)++; + *((PULONG&)pbTrampoline)++ = *((PULONG&)pbSrc)++; + cbTarget = (LONG)(pbSrc - pbTarget); + // We will fall through the "while" because cbTarget is now >= cbJump. + } + } + } + else { + ULONG op = fetch_thumb_opcode(pbSrc); + if (op == 0xf8dff000) { // LDR PC,[PC] + *((PULONG&)pbTrampoline)++ = *((PULONG&)pbSrc)++; + *((PULONG&)pbTrampoline)++ = *((PULONG&)pbSrc)++; + cbTarget = (LONG)(pbSrc - pbTarget); + // We will fall through the "while" because cbTarget is now >= cbJump. + } + } +#endif + + while (cbTarget < cbJump) { + PBYTE pbOp = pbSrc; + LONG lExtra = 0; + + DETOUR_TRACE((" DetourCopyInstruction(%p,%p)\n", + pbTrampoline, pbSrc)); + pbSrc = (PBYTE) + DetourCopyInstruction(pbTrampoline, (PVOID*)&pbPool, pbSrc, NULL, &lExtra); + DETOUR_TRACE((" DetourCopyInstruction() = %p (%d bytes)\n", + pbSrc, (int)(pbSrc - pbOp))); + pbTrampoline += (pbSrc - pbOp) + lExtra; + cbTarget = (LONG)(pbSrc - pbTarget); + pTrampoline->rAlign[nAlign].obTarget = cbTarget; + pTrampoline->rAlign[nAlign].obTrampoline = pbTrampoline - pTrampoline->rbCode; + nAlign++; + + if (nAlign >= ARRAYSIZE(pTrampoline->rAlign)) { + break; + } + + if (detour_does_code_end_function(pbOp)) { + break; + } + } + + // Consume, but don't duplicate padding if it is needed and available. + while (cbTarget < cbJump) { + LONG cFiller = detour_is_code_filler(pbSrc); + if (cFiller == 0) { + break; + } + + pbSrc += cFiller; + cbTarget = (LONG)(pbSrc - pbTarget); + } + +#if DETOUR_DEBUG + { + DETOUR_TRACE((" detours: rAlign [")); + LONG n = 0; + for (n = 0; n < ARRAYSIZE(pTrampoline->rAlign); n++) { + if (pTrampoline->rAlign[n].obTarget == 0 && + pTrampoline->rAlign[n].obTrampoline == 0) { + break; + } + DETOUR_TRACE((" %d/%d", + pTrampoline->rAlign[n].obTarget, + pTrampoline->rAlign[n].obTrampoline + )); + + } + DETOUR_TRACE((" ]\n")); + } +#endif + + if (cbTarget < cbJump || nAlign > ARRAYSIZE(pTrampoline->rAlign)) { + // Too few instructions. + + error = ERROR_INVALID_BLOCK; + if (s_fIgnoreTooSmall) { + goto stop; + } + else { + DETOUR_BREAK(); + goto fail; + } + } + + if (pbTrampoline > pbPool) { + __debugbreak(); + } + + pTrampoline->cbCode = (BYTE)(pbTrampoline - pTrampoline->rbCode); + pTrampoline->cbRestore = (BYTE)cbTarget; + CopyMemory(pTrampoline->rbRestore, pbTarget, cbTarget); + +#if !defined(DETOURS_IA64) + if (cbTarget > sizeof(pTrampoline->rbCode) - cbJump) { + // Too many instructions. + error = ERROR_INVALID_HANDLE; + DETOUR_BREAK(); + goto fail; + } +#endif // !DETOURS_IA64 + + pTrampoline->pbRemain = pbTarget + cbTarget; + pTrampoline->pbDetour = (PBYTE)pDetour; + +#ifdef DETOURS_IA64 + pTrampoline->ppldDetour = ppldDetour; + pTrampoline->ppldTarget = ppldTarget; + pTrampoline->pldTrampoline.EntryPoint = (UINT64)&pTrampoline->bMovlTargetGp; + pTrampoline->pldTrampoline.GlobalPointer = (UINT64)pDetourGlobals; + + ((DETOUR_IA64_BUNDLE *)pTrampoline->rbCode)->SetStop(); + + pTrampoline->bMovlTargetGp.SetMovlGp((UINT64)pTargetGlobals); + pTrampoline->bBrlRemainEip.SetBrl((UINT64)pTrampoline->pbRemain); + + // Alloc frame: alloc r41=ar.pfs,11,0,8,0; mov r40=rp + pTrampoline->bAllocFrame.wide[0] = 0x00000580164d480c; + pTrampoline->bAllocFrame.wide[1] = 0x00c4000500000200; + // save r36, r37, r38. + pTrampoline->bSave37to39.wide[0] = 0x031021004e019001; + pTrampoline->bSave37to39.wide[1] = 0x8401280600420098; + // save r34,r35,r36: adds r47=0,r36; adds r46=0,r35; adds r45=0,r34 + pTrampoline->bSave34to36.wide[0] = 0x02e0210048017800; + pTrampoline->bSave34to36.wide[1] = 0x84011005a042008c; + // save gp,r32,r33" adds r44=0,r33; adds r43=0,r32; adds r42=0,gp ;; + pTrampoline->bSaveGPto33.wide[0] = 0x02b0210042016001; + pTrampoline->bSaveGPto33.wide[1] = 0x8400080540420080; + // set detour GP. + pTrampoline->bMovlDetourGp.SetMovlGp((UINT64)pDetourGlobals); + // call detour: brl.call.sptk.few rp=detour ;; + pTrampoline->bCallDetour.wide[0] = 0x0000000100000005; + pTrampoline->bCallDetour.wide[1] = 0xd000001000000000; + pTrampoline->bCallDetour.SetBrlTarget((UINT64)pDetour); + // pop frame & gp: adds gp=0,r42; mov rp=r40,+0;; mov.i ar.pfs=r41 + pTrampoline->bPopFrameGp.wide[0] = 0x4000210054000802; + pTrampoline->bPopFrameGp.wide[1] = 0x00aa029000038005; + // return to caller: br.ret.sptk.many rp ;; + pTrampoline->bReturn.wide[0] = 0x0000000100000019; + pTrampoline->bReturn.wide[1] = 0x0084000880000200; + + DETOUR_TRACE(("detours: &bMovlTargetGp=%p\n", &pTrampoline->bMovlTargetGp)); + DETOUR_TRACE(("detours: &bMovlDetourGp=%p\n", &pTrampoline->bMovlDetourGp)); +#endif // DETOURS_IA64 + + pbTrampoline = pTrampoline->rbCode + pTrampoline->cbCode; +#ifdef DETOURS_X64 + pbTrampoline = detour_gen_jmp_indirect(pbTrampoline, &pTrampoline->pbRemain); + pbTrampoline = detour_gen_brk(pbTrampoline, pbPool); +#endif // DETOURS_X64 + +#ifdef DETOURS_X86 + pbTrampoline = detour_gen_jmp_immediate(pbTrampoline, pTrampoline->pbRemain); + pbTrampoline = detour_gen_brk(pbTrampoline, pbPool); +#endif // DETOURS_X86 + +#ifdef DETOURS_ARM + pbTrampoline = detour_gen_jmp_immediate(pbTrampoline, &pbPool, pTrampoline->pbRemain); + pbTrampoline = detour_gen_brk(pbTrampoline, pbPool); +#endif // DETOURS_ARM + +#ifdef DETOURS_ARM64 + pbTrampoline = detour_gen_jmp_immediate(pbTrampoline, &pbPool, pTrampoline->pbRemain); + pbTrampoline = detour_gen_brk(pbTrampoline, pbPool); +#endif // DETOURS_ARM64 + + (void)pbTrampoline; + + DWORD dwOld = 0; + if (!VirtualProtect(pbTarget, cbTarget, PAGE_EXECUTE_READWRITE, &dwOld)) { + error = GetLastError(); + DETOUR_BREAK(); + goto fail; + } + + DETOUR_TRACE(("detours: pbTarget=%p: " + "%02x %02x %02x %02x " + "%02x %02x %02x %02x " + "%02x %02x %02x %02x\n", + pbTarget, + pbTarget[0], pbTarget[1], pbTarget[2], pbTarget[3], + pbTarget[4], pbTarget[5], pbTarget[6], pbTarget[7], + pbTarget[8], pbTarget[9], pbTarget[10], pbTarget[11])); + DETOUR_TRACE(("detours: pbTramp =%p: " + "%02x %02x %02x %02x " + "%02x %02x %02x %02x " + "%02x %02x %02x %02x\n", + pTrampoline, + pTrampoline->rbCode[0], pTrampoline->rbCode[1], + pTrampoline->rbCode[2], pTrampoline->rbCode[3], + pTrampoline->rbCode[4], pTrampoline->rbCode[5], + pTrampoline->rbCode[6], pTrampoline->rbCode[7], + pTrampoline->rbCode[8], pTrampoline->rbCode[9], + pTrampoline->rbCode[10], pTrampoline->rbCode[11])); + + o->fIsRemove = FALSE; + o->ppbPointer = (PBYTE*)ppPointer; + o->pTrampoline = pTrampoline; + o->pbTarget = pbTarget; + o->dwPerm = dwOld; + o->pNext = s_pPendingOperations; + s_pPendingOperations = o; + + return NO_ERROR; +} + +LONG WINAPI DetourDetach(_Inout_ PVOID *ppPointer, + _In_ PVOID pDetour) +{ + LONG error = NO_ERROR; + + if (s_nPendingThreadId != (LONG)GetCurrentThreadId()) { + return ERROR_INVALID_OPERATION; + } + + // If any of the pending operations failed, then we don't need to do this. + if (s_nPendingError != NO_ERROR) { + return s_nPendingError; + } + + if (pDetour == NULL) { + return ERROR_INVALID_PARAMETER; + } + if (ppPointer == NULL) { + return ERROR_INVALID_HANDLE; + } + if (*ppPointer == NULL) { + error = ERROR_INVALID_HANDLE; + s_nPendingError = error; + s_ppPendingError = ppPointer; + DETOUR_BREAK(); + return error; + } + + DetourOperation *o = new NOTHROW DetourOperation; + if (o == NULL) { + error = ERROR_NOT_ENOUGH_MEMORY; + fail: + s_nPendingError = error; + DETOUR_BREAK(); + stop: + if (o != NULL) { + delete o; + o = NULL; + } + s_ppPendingError = ppPointer; + return error; + } + + +#ifdef DETOURS_IA64 + PPLABEL_DESCRIPTOR ppldTrampo = (PPLABEL_DESCRIPTOR)*ppPointer; + PPLABEL_DESCRIPTOR ppldDetour = (PPLABEL_DESCRIPTOR)pDetour; + PVOID pDetourGlobals = NULL; + PVOID pTrampoGlobals = NULL; + + pDetour = (PBYTE)DetourCodeFromPointer(ppldDetour, &pDetourGlobals); + PDETOUR_TRAMPOLINE pTrampoline = (PDETOUR_TRAMPOLINE) + DetourCodeFromPointer(ppldTrampo, &pTrampoGlobals); + DETOUR_TRACE((" ppldDetour=%p, code=%p [gp=%p]\n", + ppldDetour, pDetour, pDetourGlobals)); + DETOUR_TRACE((" ppldTrampo=%p, code=%p [gp=%p]\n", + ppldTrampo, pTrampoline, pTrampoGlobals)); + + + DETOUR_TRACE(("\n")); + DETOUR_TRACE(("detours: &pldTrampoline =%p\n", + &pTrampoline->pldTrampoline)); + DETOUR_TRACE(("detours: &bMovlTargetGp =%p [%p]\n", + &pTrampoline->bMovlTargetGp, + pTrampoline->bMovlTargetGp.GetMovlGp())); + DETOUR_TRACE(("detours: &rbCode =%p [%p]\n", + &pTrampoline->rbCode, + ((DETOUR_IA64_BUNDLE&)pTrampoline->rbCode).GetBrlTarget())); + DETOUR_TRACE(("detours: &bBrlRemainEip =%p [%p]\n", + &pTrampoline->bBrlRemainEip, + pTrampoline->bBrlRemainEip.GetBrlTarget())); + DETOUR_TRACE(("detours: &bMovlDetourGp =%p [%p]\n", + &pTrampoline->bMovlDetourGp, + pTrampoline->bMovlDetourGp.GetMovlGp())); + DETOUR_TRACE(("detours: &bBrlDetourEip =%p [%p]\n", + &pTrampoline->bCallDetour, + pTrampoline->bCallDetour.GetBrlTarget())); + DETOUR_TRACE(("detours: pldDetour =%p [%p]\n", + pTrampoline->ppldDetour->EntryPoint, + pTrampoline->ppldDetour->GlobalPointer)); + DETOUR_TRACE(("detours: pldTarget =%p [%p]\n", + pTrampoline->ppldTarget->EntryPoint, + pTrampoline->ppldTarget->GlobalPointer)); + DETOUR_TRACE(("detours: pbRemain =%p\n", + pTrampoline->pbRemain)); + DETOUR_TRACE(("detours: pbDetour =%p\n", + pTrampoline->pbDetour)); + DETOUR_TRACE(("\n")); +#else // !DETOURS_IA64 + PDETOUR_TRAMPOLINE pTrampoline = + (PDETOUR_TRAMPOLINE)DetourCodeFromPointer(*ppPointer, NULL); + pDetour = DetourCodeFromPointer(pDetour, NULL); +#endif // !DETOURS_IA64 + + ////////////////////////////////////// Verify that Trampoline is in place. + // + LONG cbTarget = pTrampoline->cbRestore; + PBYTE pbTarget = pTrampoline->pbRemain - cbTarget; + if (cbTarget == 0 || cbTarget > sizeof(pTrampoline->rbCode)) { + error = ERROR_INVALID_BLOCK; + if (s_fIgnoreTooSmall) { + goto stop; + } + else { + DETOUR_BREAK(); + goto fail; + } + } + + if (pTrampoline->pbDetour != pDetour) { + error = ERROR_INVALID_BLOCK; + if (s_fIgnoreTooSmall) { + goto stop; + } + else { + DETOUR_BREAK(); + goto fail; + } + } + + DWORD dwOld = 0; + if (!VirtualProtect(pbTarget, cbTarget, + PAGE_EXECUTE_READWRITE, &dwOld)) { + error = GetLastError(); + DETOUR_BREAK(); + goto fail; + } + + o->fIsRemove = TRUE; + o->ppbPointer = (PBYTE*)ppPointer; + o->pTrampoline = pTrampoline; + o->pbTarget = pbTarget; + o->dwPerm = dwOld; + o->pNext = s_pPendingOperations; + s_pPendingOperations = o; + + return NO_ERROR; +} + +////////////////////////////////////////////////////////////////////////////// +// +// Helpers for manipulating page protection. +// + +// For reference: +// PAGE_NOACCESS 0x01 +// PAGE_READONLY 0x02 +// PAGE_READWRITE 0x04 +// PAGE_WRITECOPY 0x08 +// PAGE_EXECUTE 0x10 +// PAGE_EXECUTE_READ 0x20 +// PAGE_EXECUTE_READWRITE 0x40 +// PAGE_EXECUTE_WRITECOPY 0x80 +// PAGE_GUARD ... +// PAGE_NOCACHE ... +// PAGE_WRITECOMBINE ... + +#define DETOUR_PAGE_EXECUTE_ALL (PAGE_EXECUTE | \ + PAGE_EXECUTE_READ | \ + PAGE_EXECUTE_READWRITE | \ + PAGE_EXECUTE_WRITECOPY) + +#define DETOUR_PAGE_NO_EXECUTE_ALL (PAGE_NOACCESS | \ + PAGE_READONLY | \ + PAGE_READWRITE | \ + PAGE_WRITECOPY) + +#define DETOUR_PAGE_ATTRIBUTES (~(DETOUR_PAGE_EXECUTE_ALL | DETOUR_PAGE_NO_EXECUTE_ALL)) + +C_ASSERT((DETOUR_PAGE_NO_EXECUTE_ALL << 4) == DETOUR_PAGE_EXECUTE_ALL); + +static DWORD DetourPageProtectAdjustExecute(_In_ DWORD dwOldProtect, + _In_ DWORD dwNewProtect) +// Copy EXECUTE from dwOldProtect to dwNewProtect. +{ + bool const fOldExecute = ((dwOldProtect & DETOUR_PAGE_EXECUTE_ALL) != 0); + bool const fNewExecute = ((dwNewProtect & DETOUR_PAGE_EXECUTE_ALL) != 0); + + if (fOldExecute && !fNewExecute) { + dwNewProtect = ((dwNewProtect & DETOUR_PAGE_NO_EXECUTE_ALL) << 4) + | (dwNewProtect & DETOUR_PAGE_ATTRIBUTES); + } + else if (!fOldExecute && fNewExecute) { + dwNewProtect = ((dwNewProtect & DETOUR_PAGE_EXECUTE_ALL) >> 4) + | (dwNewProtect & DETOUR_PAGE_ATTRIBUTES); + } + return dwNewProtect; +} + +_Success_(return != FALSE) +BOOL WINAPI DetourVirtualProtectSameExecuteEx(_In_ HANDLE hProcess, + _In_ PVOID pAddress, + _In_ SIZE_T nSize, + _In_ DWORD dwNewProtect, + _Out_ PDWORD pdwOldProtect) +// Some systems do not allow executability of a page to change. This function applies +// dwNewProtect to [pAddress, nSize), but preserving the previous executability. +// This function is meant to be a drop-in replacement for some uses of VirtualProtectEx. +// When "restoring" page protection, there is no need to use this function. +{ + MEMORY_BASIC_INFORMATION mbi; + + // Query to get existing execute access. + + ZeroMemory(&mbi, sizeof(mbi)); + + if (VirtualQueryEx(hProcess, pAddress, &mbi, sizeof(mbi)) == 0) { + return FALSE; + } + return VirtualProtectEx(hProcess, pAddress, nSize, + DetourPageProtectAdjustExecute(mbi.Protect, dwNewProtect), + pdwOldProtect); +} + +_Success_(return != FALSE) +BOOL WINAPI DetourVirtualProtectSameExecute(_In_ PVOID pAddress, + _In_ SIZE_T nSize, + _In_ DWORD dwNewProtect, + _Out_ PDWORD pdwOldProtect) +{ + return DetourVirtualProtectSameExecuteEx(GetCurrentProcess(), + pAddress, nSize, dwNewProtect, pdwOldProtect); +} + +// End of File diff --git a/H2Codez/Detours/detours.h b/H2Codez/util/Detours/detours.h similarity index 97% rename from H2Codez/Detours/detours.h rename to H2Codez/util/Detours/detours.h index 44d6b77..2ccdca1 100644 --- a/H2Codez/Detours/detours.h +++ b/H2Codez/util/Detours/detours.h @@ -1,1059 +1,1059 @@ -///////////////////////////////////////////////////////////////////////////// -// -// Core Detours Functionality (detours.h of detours.lib) -// -// Microsoft Research Detours Package, Version 3.0 Build_343. -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// - -#pragma once -#ifndef _DETOURS_H_ -#define _DETOURS_H_ - -#define DETOURS_VERSION 30001 // 3.00.01 - -////////////////////////////////////////////////////////////////////////////// -// - -#undef DETOURS_X64 -#undef DETOURS_X86 -#undef DETOURS_IA64 -#undef DETOURS_ARM -#undef DETOURS_ARM64 -#undef DETOURS_BITS -#undef DETOURS_32BIT -#undef DETOURS_64BIT - -#if defined(_X86_) -#define DETOURS_X86 -#define DETOURS_OPTION_BITS 64 - -#elif defined(_AMD64_) -#define DETOURS_X64 -#define DETOURS_OPTION_BITS 32 - -#elif defined(_IA64_) -#define DETOURS_IA64 -#define DETOURS_OPTION_BITS 32 - -#elif defined(_ARM_) -#define DETOURS_ARM - -#elif defined(_ARM64_) -#define DETOURS_ARM64 - -#else -#error Unknown architecture (x86, amd64, ia64, arm, arm64) -#endif - -#ifdef _WIN64 -#undef DETOURS_32BIT -#define DETOURS_64BIT 1 -#define DETOURS_BITS 64 -// If all 64bit kernels can run one and only one 32bit architecture. -//#define DETOURS_OPTION_BITS 32 -#else -#define DETOURS_32BIT 1 -#undef DETOURS_64BIT -#define DETOURS_BITS 32 -// If all 64bit kernels can run one and only one 32bit architecture. -//#define DETOURS_OPTION_BITS 32 -#endif - -#define VER_DETOURS_BITS DETOUR_STRINGIFY(DETOURS_BITS) - -////////////////////////////////////////////////////////////////////////////// -// - -#if (_MSC_VER < 1299) -typedef LONG LONG_PTR; -typedef ULONG ULONG_PTR; -#endif - -///////////////////////////////////////////////// SAL 2.0 Annotations w/o SAL. -// -// These definitions are include so that Detours will build even if the -// compiler doesn't have full SAL 2.0 support. -// -#ifndef DETOURS_DONT_REMOVE_SAL_20 - -#ifdef DETOURS_TEST_REMOVE_SAL_20 -#undef _Analysis_assume_ -#undef _Benign_race_begin_ -#undef _Benign_race_end_ -#undef _Field_range_ -#undef _Field_size_ -#undef _In_ -#undef _In_bytecount_ -#undef _In_count_ -#undef _In_opt_ -#undef _In_opt_bytecount_ -#undef _In_opt_count_ -#undef _In_opt_z_ -#undef _In_range_ -#undef _In_reads_ -#undef _In_reads_bytes_ -#undef _In_reads_opt_ -#undef _In_reads_opt_bytes_ -#undef _In_reads_or_z_ -#undef _In_z_ -#undef _Inout_ -#undef _Inout_opt_ -#undef _Inout_z_count_ -#undef _Out_ -#undef _Out_opt_ -#undef _Out_writes_ -#undef _Outptr_result_maybenull_ -#undef _Readable_bytes_ -#undef _Success_ -#undef _Writable_bytes_ -#undef _Pre_notnull_ -#endif - -#if defined(_Deref_out_opt_z_) && !defined(_Outptr_result_maybenull_) -#define _Outptr_result_maybenull_ _Deref_out_opt_z_ -#endif - -#if defined(_In_count_) && !defined(_In_reads_) -#define _In_reads_(x) _In_count_(x) -#endif - -#if defined(_In_opt_count_) && !defined(_In_reads_opt_) -#define _In_reads_opt_(x) _In_opt_count_(x) -#endif - -#if defined(_In_opt_bytecount_) && !defined(_In_reads_opt_bytes_) -#define _In_reads_opt_bytes_(x) _In_opt_bytecount_(x) -#endif - -#if defined(_In_bytecount_) && !defined(_In_reads_bytes_) -#define _In_reads_bytes_(x) _In_bytecount_(x) -#endif - -#ifndef _In_ -#define _In_ -#endif - -#ifndef _In_bytecount_ -#define _In_bytecount_(x) -#endif - -#ifndef _In_count_ -#define _In_count_(x) -#endif - -#ifndef _In_opt_ -#define _In_opt_ -#endif - -#ifndef _In_opt_bytecount_ -#define _In_opt_bytecount_(x) -#endif - -#ifndef _In_opt_count_ -#define _In_opt_count_(x) -#endif - -#ifndef _In_opt_z_ -#define _In_opt_z_ -#endif - -#ifndef _In_range_ -#define _In_range_(x,y) -#endif - -#ifndef _In_reads_ -#define _In_reads_(x) -#endif - -#ifndef _In_reads_bytes_ -#define _In_reads_bytes_(x) -#endif - -#ifndef _In_reads_opt_ -#define _In_reads_opt_(x) -#endif - -#ifndef _In_reads_opt_bytes_ -#define _In_reads_opt_bytes_(x) -#endif - -#ifndef _In_reads_or_z_ -#define _In_reads_or_z_ -#endif - -#ifndef _In_z_ -#define _In_z_ -#endif - -#ifndef _Inout_ -#define _Inout_ -#endif - -#ifndef _Inout_opt_ -#define _Inout_opt_ -#endif - -#ifndef _Inout_z_count_ -#define _Inout_z_count_(x) -#endif - -#ifndef _Out_ -#define _Out_ -#endif - -#ifndef _Out_opt_ -#define _Out_opt_ -#endif - -#ifndef _Out_writes_ -#define _Out_writes_(x) -#endif - -#ifndef _Outptr_result_maybenull_ -#define _Outptr_result_maybenull_ -#endif - -#ifndef _Writable_bytes_ -#define _Writable_bytes_(x) -#endif - -#ifndef _Readable_bytes_ -#define _Readable_bytes_(x) -#endif - -#ifndef _Success_ -#define _Success_(x) -#endif - -#ifndef _Pre_notnull_ -#define _Pre_notnull_ -#endif - -#ifdef DETOURS_INTERNAL - -#pragma warning(disable:4615) // unknown warning type (suppress with older compilers) - -#ifndef _Benign_race_begin_ -#define _Benign_race_begin_ -#endif - -#ifndef _Benign_race_end_ -#define _Benign_race_end_ -#endif - -#ifndef _Field_size_ -#define _Field_size_(x) -#endif - -#ifndef _Field_range_ -#define _Field_range_(x,y) -#endif - -#ifndef _Analysis_assume_ -#define _Analysis_assume_(x) -#endif - -#endif // DETOURS_INTERNAL -#endif // DETOURS_DONT_REMOVE_SAL_20 - -////////////////////////////////////////////////////////////////////////////// -// -#ifndef GUID_DEFINED -#define GUID_DEFINED -typedef struct _GUID -{ - DWORD Data1; - WORD Data2; - WORD Data3; - BYTE Data4[ 8 ]; -} GUID; - -#ifdef INITGUID -#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ - const GUID name \ - = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } -#else -#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ - const GUID name -#endif // INITGUID -#endif // !GUID_DEFINED - -#if defined(__cplusplus) -#ifndef _REFGUID_DEFINED -#define _REFGUID_DEFINED -#define REFGUID const GUID & -#endif // !_REFGUID_DEFINED -#else // !__cplusplus -#ifndef _REFGUID_DEFINED -#define _REFGUID_DEFINED -#define REFGUID const GUID * const -#endif // !_REFGUID_DEFINED -#endif // !__cplusplus - -#ifndef ARRAYSIZE -#define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0])) -#endif - -// -////////////////////////////////////////////////////////////////////////////// - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -/////////////////////////////////////////////////// Instruction Target Macros. -// -#define DETOUR_INSTRUCTION_TARGET_NONE ((PVOID)0) -#define DETOUR_INSTRUCTION_TARGET_DYNAMIC ((PVOID)(LONG_PTR)-1) -#define DETOUR_SECTION_HEADER_SIGNATURE 0x00727444 // "Dtr\0" - -extern const GUID DETOUR_EXE_RESTORE_GUID; -extern const GUID DETOUR_EXE_HELPER_GUID; - -#define DETOUR_TRAMPOLINE_SIGNATURE 0x21727444 // Dtr! -typedef struct _DETOUR_TRAMPOLINE DETOUR_TRAMPOLINE, *PDETOUR_TRAMPOLINE; - -/////////////////////////////////////////////////////////// Binary Structures. -// -#pragma pack(push, 8) -typedef struct _DETOUR_SECTION_HEADER -{ - DWORD cbHeaderSize; - DWORD nSignature; - DWORD nDataOffset; - DWORD cbDataSize; - - DWORD nOriginalImportVirtualAddress; - DWORD nOriginalImportSize; - DWORD nOriginalBoundImportVirtualAddress; - DWORD nOriginalBoundImportSize; - - DWORD nOriginalIatVirtualAddress; - DWORD nOriginalIatSize; - DWORD nOriginalSizeOfImage; - DWORD cbPrePE; - - DWORD nOriginalClrFlags; - DWORD reserved1; - DWORD reserved2; - DWORD reserved3; - - // Followed by cbPrePE bytes of data. -} DETOUR_SECTION_HEADER, *PDETOUR_SECTION_HEADER; - -typedef struct _DETOUR_SECTION_RECORD -{ - DWORD cbBytes; - DWORD nReserved; - GUID guid; -} DETOUR_SECTION_RECORD, *PDETOUR_SECTION_RECORD; - -typedef struct _DETOUR_CLR_HEADER -{ - // Header versioning - ULONG cb; - USHORT MajorRuntimeVersion; - USHORT MinorRuntimeVersion; - - // Symbol table and startup information - IMAGE_DATA_DIRECTORY MetaData; - ULONG Flags; - - // Followed by the rest of the IMAGE_COR20_HEADER -} DETOUR_CLR_HEADER, *PDETOUR_CLR_HEADER; - -typedef struct _DETOUR_EXE_RESTORE -{ - DWORD cb; - DWORD cbidh; - DWORD cbinh; - DWORD cbclr; - - PBYTE pidh; - PBYTE pinh; - PBYTE pclr; - - IMAGE_DOS_HEADER idh; - union { - IMAGE_NT_HEADERS inh; - IMAGE_NT_HEADERS32 inh32; - IMAGE_NT_HEADERS64 inh64; - BYTE raw[sizeof(IMAGE_NT_HEADERS64) + - sizeof(IMAGE_SECTION_HEADER) * 32]; - }; - DETOUR_CLR_HEADER clr; - -} DETOUR_EXE_RESTORE, *PDETOUR_EXE_RESTORE; - -typedef struct _DETOUR_EXE_HELPER -{ - DWORD cb; - DWORD pid; - DWORD nDlls; - CHAR rDlls[4]; -} DETOUR_EXE_HELPER, *PDETOUR_EXE_HELPER; - -#pragma pack(pop) - -#define DETOUR_SECTION_HEADER_DECLARE(cbSectionSize) \ -{ \ - sizeof(DETOUR_SECTION_HEADER),\ - DETOUR_SECTION_HEADER_SIGNATURE,\ - sizeof(DETOUR_SECTION_HEADER),\ - (cbSectionSize),\ - \ - 0,\ - 0,\ - 0,\ - 0,\ - \ - 0,\ - 0,\ - 0,\ - 0,\ -} - -/////////////////////////////////////////////////////////////// Helper Macros. -// -#define DETOURS_STRINGIFY(x) DETOURS_STRINGIFY_(x) -#define DETOURS_STRINGIFY_(x) #x - -///////////////////////////////////////////////////////////// Binary Typedefs. -// -typedef BOOL (CALLBACK *PF_DETOUR_BINARY_BYWAY_CALLBACK)( - _In_opt_ PVOID pContext, - _In_opt_ LPCSTR pszFile, - _Outptr_result_maybenull_ LPCSTR *ppszOutFile); - -typedef BOOL (CALLBACK *PF_DETOUR_BINARY_FILE_CALLBACK)( - _In_opt_ PVOID pContext, - _In_ LPCSTR pszOrigFile, - _In_ LPCSTR pszFile, - _Outptr_result_maybenull_ LPCSTR *ppszOutFile); - -typedef BOOL (CALLBACK *PF_DETOUR_BINARY_SYMBOL_CALLBACK)( - _In_opt_ PVOID pContext, - _In_ ULONG nOrigOrdinal, - _In_ ULONG nOrdinal, - _Out_ ULONG *pnOutOrdinal, - _In_opt_ LPCSTR pszOrigSymbol, - _In_opt_ LPCSTR pszSymbol, - _Outptr_result_maybenull_ LPCSTR *ppszOutSymbol); - -typedef BOOL (CALLBACK *PF_DETOUR_BINARY_COMMIT_CALLBACK)( - _In_opt_ PVOID pContext); - -typedef BOOL (CALLBACK *PF_DETOUR_ENUMERATE_EXPORT_CALLBACK)(_In_opt_ PVOID pContext, - _In_ ULONG nOrdinal, - _In_opt_ LPCSTR pszName, - _In_opt_ PVOID pCode); - -typedef BOOL (CALLBACK *PF_DETOUR_IMPORT_FILE_CALLBACK)(_In_opt_ PVOID pContext, - _In_opt_ HMODULE hModule, - _In_opt_ LPCSTR pszFile); - -typedef BOOL (CALLBACK *PF_DETOUR_IMPORT_FUNC_CALLBACK)(_In_opt_ PVOID pContext, - _In_ DWORD nOrdinal, - _In_opt_ LPCSTR pszFunc, - _In_opt_ PVOID pvFunc); - -// Same as PF_DETOUR_IMPORT_FUNC_CALLBACK but extra indirection on last parameter. -typedef BOOL (CALLBACK *PF_DETOUR_IMPORT_FUNC_CALLBACK_EX)(_In_opt_ PVOID pContext, - _In_ DWORD nOrdinal, - _In_opt_ LPCSTR pszFunc, - _In_opt_ PVOID* ppvFunc); - -typedef VOID * PDETOUR_BINARY; -typedef VOID * PDETOUR_LOADED_BINARY; - -//////////////////////////////////////////////////////////// Transaction APIs. -// -LONG WINAPI DetourTransactionBegin(VOID); -LONG WINAPI DetourTransactionAbort(VOID); -LONG WINAPI DetourTransactionCommit(VOID); -LONG WINAPI DetourTransactionCommitEx(_Out_opt_ PVOID **pppFailedPointer); - -LONG WINAPI DetourUpdateThread(_In_ HANDLE hThread); - -LONG WINAPI DetourAttach(_Inout_ PVOID *ppPointer, - _In_ PVOID pDetour); - -LONG WINAPI DetourAttachEx(_Inout_ PVOID *ppPointer, - _In_ PVOID pDetour, - _Out_opt_ PDETOUR_TRAMPOLINE *ppRealTrampoline, - _Out_opt_ PVOID *ppRealTarget, - _Out_opt_ PVOID *ppRealDetour); - -LONG WINAPI DetourDetach(_Inout_ PVOID *ppPointer, - _In_ PVOID pDetour); - -BOOL WINAPI DetourSetIgnoreTooSmall(_In_ BOOL fIgnore); -BOOL WINAPI DetourSetRetainRegions(_In_ BOOL fRetain); -PVOID WINAPI DetourSetSystemRegionLowerBound(_In_ PVOID pSystemRegionLowerBound); -PVOID WINAPI DetourSetSystemRegionUpperBound(_In_ PVOID pSystemRegionUpperBound); - -////////////////////////////////////////////////////////////// Code Functions. -// -PVOID WINAPI DetourFindFunction(_In_ LPCSTR pszModule, - _In_ LPCSTR pszFunction); -PVOID WINAPI DetourCodeFromPointer(_In_ PVOID pPointer, - _Out_opt_ PVOID *ppGlobals); -PVOID WINAPI DetourCopyInstruction(_In_opt_ PVOID pDst, - _Inout_opt_ PVOID *ppDstPool, - _In_ PVOID pSrc, - _Out_opt_ PVOID *ppTarget, - _Out_opt_ LONG *plExtra); -BOOL WINAPI DetourSetCodeModule(_In_ HMODULE hModule, - _In_ BOOL fLimitReferencesToModule); - -///////////////////////////////////////////////////// Loaded Binary Functions. -// -HMODULE WINAPI DetourGetContainingModule(_In_ PVOID pvAddr); -HMODULE WINAPI DetourEnumerateModules(_In_opt_ HMODULE hModuleLast); -PVOID WINAPI DetourGetEntryPoint(_In_opt_ HMODULE hModule); -ULONG WINAPI DetourGetModuleSize(_In_opt_ HMODULE hModule); -BOOL WINAPI DetourEnumerateExports(_In_ HMODULE hModule, - _In_opt_ PVOID pContext, - _In_ PF_DETOUR_ENUMERATE_EXPORT_CALLBACK pfExport); -BOOL WINAPI DetourEnumerateImports(_In_opt_ HMODULE hModule, - _In_opt_ PVOID pContext, - _In_opt_ PF_DETOUR_IMPORT_FILE_CALLBACK pfImportFile, - _In_opt_ PF_DETOUR_IMPORT_FUNC_CALLBACK pfImportFunc); - -BOOL WINAPI DetourEnumerateImportsEx(_In_opt_ HMODULE hModule, - _In_opt_ PVOID pContext, - _In_opt_ PF_DETOUR_IMPORT_FILE_CALLBACK pfImportFile, - _In_opt_ PF_DETOUR_IMPORT_FUNC_CALLBACK_EX pfImportFuncEx); - -_Writable_bytes_(*pcbData) -_Readable_bytes_(*pcbData) -_Success_(return != NULL) -PVOID WINAPI DetourFindPayload(_In_opt_ HMODULE hModule, - _In_ REFGUID rguid, - _Out_ DWORD *pcbData); - -_Writable_bytes_(*pcbData) -_Readable_bytes_(*pcbData) -_Success_(return != NULL) -PVOID WINAPI DetourFindPayloadEx(_In_ REFGUID rguid, - _Out_ DWORD * pcbData); - -DWORD WINAPI DetourGetSizeOfPayloads(_In_opt_ HMODULE hModule); - -///////////////////////////////////////////////// Persistent Binary Functions. -// - -PDETOUR_BINARY WINAPI DetourBinaryOpen(_In_ HANDLE hFile); - -_Writable_bytes_(*pcbData) -_Readable_bytes_(*pcbData) -_Success_(return != NULL) -PVOID WINAPI DetourBinaryEnumeratePayloads(_In_ PDETOUR_BINARY pBinary, - _Out_opt_ GUID *pGuid, - _Out_ DWORD *pcbData, - _Inout_ DWORD *pnIterator); - -_Writable_bytes_(*pcbData) -_Readable_bytes_(*pcbData) -_Success_(return != NULL) -PVOID WINAPI DetourBinaryFindPayload(_In_ PDETOUR_BINARY pBinary, - _In_ REFGUID rguid, - _Out_ DWORD *pcbData); - -PVOID WINAPI DetourBinarySetPayload(_In_ PDETOUR_BINARY pBinary, - _In_ REFGUID rguid, - _In_reads_opt_(cbData) PVOID pData, - _In_ DWORD cbData); -BOOL WINAPI DetourBinaryDeletePayload(_In_ PDETOUR_BINARY pBinary, _In_ REFGUID rguid); -BOOL WINAPI DetourBinaryPurgePayloads(_In_ PDETOUR_BINARY pBinary); -BOOL WINAPI DetourBinaryResetImports(_In_ PDETOUR_BINARY pBinary); -BOOL WINAPI DetourBinaryEditImports(_In_ PDETOUR_BINARY pBinary, - _In_opt_ PVOID pContext, - _In_opt_ PF_DETOUR_BINARY_BYWAY_CALLBACK pfByway, - _In_opt_ PF_DETOUR_BINARY_FILE_CALLBACK pfFile, - _In_opt_ PF_DETOUR_BINARY_SYMBOL_CALLBACK pfSymbol, - _In_opt_ PF_DETOUR_BINARY_COMMIT_CALLBACK pfCommit); -BOOL WINAPI DetourBinaryWrite(_In_ PDETOUR_BINARY pBinary, _In_ HANDLE hFile); -BOOL WINAPI DetourBinaryClose(_In_ PDETOUR_BINARY pBinary); - -/////////////////////////////////////////////////// Create Process & Load Dll. -// -typedef BOOL (WINAPI *PDETOUR_CREATE_PROCESS_ROUTINEA)( - _In_opt_ LPCSTR lpApplicationName, - _Inout_opt_ LPSTR lpCommandLine, - _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, - _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, - _In_ BOOL bInheritHandles, - _In_ DWORD dwCreationFlags, - _In_opt_ LPVOID lpEnvironment, - _In_opt_ LPCSTR lpCurrentDirectory, - _In_ LPSTARTUPINFOA lpStartupInfo, - _Out_ LPPROCESS_INFORMATION lpProcessInformation); - -typedef BOOL (WINAPI *PDETOUR_CREATE_PROCESS_ROUTINEW)( - _In_opt_ LPCWSTR lpApplicationName, - _Inout_opt_ LPWSTR lpCommandLine, - _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, - _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, - _In_ BOOL bInheritHandles, - _In_ DWORD dwCreationFlags, - _In_opt_ LPVOID lpEnvironment, - _In_opt_ LPCWSTR lpCurrentDirectory, - _In_ LPSTARTUPINFOW lpStartupInfo, - _Out_ LPPROCESS_INFORMATION lpProcessInformation); - -BOOL WINAPI DetourCreateProcessWithDllA(_In_opt_ LPCSTR lpApplicationName, - _Inout_opt_ LPSTR lpCommandLine, - _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, - _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, - _In_ BOOL bInheritHandles, - _In_ DWORD dwCreationFlags, - _In_opt_ LPVOID lpEnvironment, - _In_opt_ LPCSTR lpCurrentDirectory, - _In_ LPSTARTUPINFOA lpStartupInfo, - _Out_ LPPROCESS_INFORMATION lpProcessInformation, - _In_ LPCSTR lpDllName, - _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); - -BOOL WINAPI DetourCreateProcessWithDllW(_In_opt_ LPCWSTR lpApplicationName, - _Inout_opt_ LPWSTR lpCommandLine, - _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, - _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, - _In_ BOOL bInheritHandles, - _In_ DWORD dwCreationFlags, - _In_opt_ LPVOID lpEnvironment, - _In_opt_ LPCWSTR lpCurrentDirectory, - _In_ LPSTARTUPINFOW lpStartupInfo, - _Out_ LPPROCESS_INFORMATION lpProcessInformation, - _In_ LPCSTR lpDllName, - _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); - -#ifdef UNICODE -#define DetourCreateProcessWithDll DetourCreateProcessWithDllW -#define PDETOUR_CREATE_PROCESS_ROUTINE PDETOUR_CREATE_PROCESS_ROUTINEW -#else -#define DetourCreateProcessWithDll DetourCreateProcessWithDllA -#define PDETOUR_CREATE_PROCESS_ROUTINE PDETOUR_CREATE_PROCESS_ROUTINEA -#endif // !UNICODE - -BOOL WINAPI DetourCreateProcessWithDllExA(_In_opt_ LPCSTR lpApplicationName, - _Inout_opt_ LPSTR lpCommandLine, - _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, - _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, - _In_ BOOL bInheritHandles, - _In_ DWORD dwCreationFlags, - _In_opt_ LPVOID lpEnvironment, - _In_opt_ LPCSTR lpCurrentDirectory, - _In_ LPSTARTUPINFOA lpStartupInfo, - _Out_ LPPROCESS_INFORMATION lpProcessInformation, - _In_ LPCSTR lpDllName, - _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); - -BOOL WINAPI DetourCreateProcessWithDllExW(_In_opt_ LPCWSTR lpApplicationName, - _Inout_opt_ LPWSTR lpCommandLine, - _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, - _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, - _In_ BOOL bInheritHandles, - _In_ DWORD dwCreationFlags, - _In_opt_ LPVOID lpEnvironment, - _In_opt_ LPCWSTR lpCurrentDirectory, - _In_ LPSTARTUPINFOW lpStartupInfo, - _Out_ LPPROCESS_INFORMATION lpProcessInformation, - _In_ LPCSTR lpDllName, - _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); - -#ifdef UNICODE -#define DetourCreateProcessWithDllEx DetourCreateProcessWithDllExW -#else -#define DetourCreateProcessWithDllEx DetourCreateProcessWithDllExA -#endif // !UNICODE - -BOOL WINAPI DetourCreateProcessWithDllsA(_In_opt_ LPCSTR lpApplicationName, - _Inout_opt_ LPSTR lpCommandLine, - _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, - _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, - _In_ BOOL bInheritHandles, - _In_ DWORD dwCreationFlags, - _In_opt_ LPVOID lpEnvironment, - _In_opt_ LPCSTR lpCurrentDirectory, - _In_ LPSTARTUPINFOA lpStartupInfo, - _Out_ LPPROCESS_INFORMATION lpProcessInformation, - _In_ DWORD nDlls, - _In_reads_(nDlls) LPCSTR *rlpDlls, - _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); - -BOOL WINAPI DetourCreateProcessWithDllsW(_In_opt_ LPCWSTR lpApplicationName, - _Inout_opt_ LPWSTR lpCommandLine, - _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, - _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, - _In_ BOOL bInheritHandles, - _In_ DWORD dwCreationFlags, - _In_opt_ LPVOID lpEnvironment, - _In_opt_ LPCWSTR lpCurrentDirectory, - _In_ LPSTARTUPINFOW lpStartupInfo, - _Out_ LPPROCESS_INFORMATION lpProcessInformation, - _In_ DWORD nDlls, - _In_reads_(nDlls) LPCSTR *rlpDlls, - _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); - -#ifdef UNICODE -#define DetourCreateProcessWithDlls DetourCreateProcessWithDllsW -#else -#define DetourCreateProcessWithDlls DetourCreateProcessWithDllsA -#endif // !UNICODE - -BOOL WINAPI DetourProcessViaHelperA(_In_ DWORD dwTargetPid, - _In_ LPCSTR lpDllName, - _In_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); - -BOOL WINAPI DetourProcessViaHelperW(_In_ DWORD dwTargetPid, - _In_ LPCSTR lpDllName, - _In_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); - -#ifdef UNICODE -#define DetourProcessViaHelper DetourProcessViaHelperW -#else -#define DetourProcessViaHelper DetourProcessViaHelperA -#endif // !UNICODE - -BOOL WINAPI DetourProcessViaHelperDllsA(_In_ DWORD dwTargetPid, - _In_ DWORD nDlls, - _In_reads_(nDlls) LPCSTR *rlpDlls, - _In_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); - -BOOL WINAPI DetourProcessViaHelperDllsW(_In_ DWORD dwTargetPid, - _In_ DWORD nDlls, - _In_reads_(nDlls) LPCSTR *rlpDlls, - _In_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); - -#ifdef UNICODE -#define DetourProcessViaHelperDlls DetourProcessViaHelperDllsW -#else -#define DetourProcessViaHelperDlls DetourProcessViaHelperDllsA -#endif // !UNICODE - -BOOL WINAPI DetourUpdateProcessWithDll(_In_ HANDLE hProcess, - _In_reads_(nDlls) LPCSTR *rlpDlls, - _In_ DWORD nDlls); - -BOOL WINAPI DetourUpdateProcessWithDllEx(_In_ HANDLE hProcess, - _In_ HMODULE hImage, - _In_ BOOL bIs32Bit, - _In_reads_(nDlls) LPCSTR *rlpDlls, - _In_ DWORD nDlls); - -BOOL WINAPI DetourCopyPayloadToProcess(_In_ HANDLE hProcess, - _In_ REFGUID rguid, - _In_reads_bytes_(cbData) PVOID pvData, - _In_ DWORD cbData); -BOOL WINAPI DetourRestoreAfterWith(VOID); -BOOL WINAPI DetourRestoreAfterWithEx(_In_reads_bytes_(cbData) PVOID pvData, - _In_ DWORD cbData); -BOOL WINAPI DetourIsHelperProcess(VOID); -VOID CALLBACK DetourFinishHelperProcess(_In_ HWND, - _In_ HINSTANCE, - _In_ LPSTR, - _In_ INT); - -// -////////////////////////////////////////////////////////////////////////////// -#ifdef __cplusplus -} -#endif // __cplusplus - -//////////////////////////////////////////////// Detours Internal Definitions. -// -#ifdef __cplusplus -#ifdef DETOURS_INTERNAL - -#define NOTHROW -// #define NOTHROW (nothrow) - -////////////////////////////////////////////////////////////////////////////// -// -#if (_MSC_VER < 1299) -#include -typedef IMAGEHLP_MODULE IMAGEHLP_MODULE64; -typedef PIMAGEHLP_MODULE PIMAGEHLP_MODULE64; -typedef IMAGEHLP_SYMBOL SYMBOL_INFO; -typedef PIMAGEHLP_SYMBOL PSYMBOL_INFO; - -static inline -LONG InterlockedCompareExchange(_Inout_ LONG *ptr, _In_ LONG nval, _In_ LONG oval) -{ - return (LONG)::InterlockedCompareExchange((PVOID*)ptr, (PVOID)nval, (PVOID)oval); -} -#else -#pragma warning(push) -#pragma warning(disable:4091) // empty typedef -#include -#pragma warning(pop) -#endif - -#ifdef IMAGEAPI // defined by DBGHELP.H -typedef LPAPI_VERSION (NTAPI *PF_ImagehlpApiVersionEx)(_In_ LPAPI_VERSION AppVersion); - -typedef BOOL (NTAPI *PF_SymInitialize)(_In_ HANDLE hProcess, - _In_opt_ LPCSTR UserSearchPath, - _In_ BOOL fInvadeProcess); -typedef DWORD (NTAPI *PF_SymSetOptions)(_In_ DWORD SymOptions); -typedef DWORD (NTAPI *PF_SymGetOptions)(VOID); -typedef DWORD64 (NTAPI *PF_SymLoadModule64)(_In_ HANDLE hProcess, - _In_opt_ HANDLE hFile, - _In_ LPSTR ImageName, - _In_opt_ LPSTR ModuleName, - _In_ DWORD64 BaseOfDll, - _In_opt_ DWORD SizeOfDll); -typedef BOOL (NTAPI *PF_SymGetModuleInfo64)(_In_ HANDLE hProcess, - _In_ DWORD64 qwAddr, - _Out_ PIMAGEHLP_MODULE64 ModuleInfo); -typedef BOOL (NTAPI *PF_SymFromName)(_In_ HANDLE hProcess, - _In_ LPSTR Name, - _Out_ PSYMBOL_INFO Symbol); - -typedef struct _DETOUR_SYM_INFO -{ - HANDLE hProcess; - HMODULE hDbgHelp; - PF_ImagehlpApiVersionEx pfImagehlpApiVersionEx; - PF_SymInitialize pfSymInitialize; - PF_SymSetOptions pfSymSetOptions; - PF_SymGetOptions pfSymGetOptions; - PF_SymLoadModule64 pfSymLoadModule64; - PF_SymGetModuleInfo64 pfSymGetModuleInfo64; - PF_SymFromName pfSymFromName; -} DETOUR_SYM_INFO, *PDETOUR_SYM_INFO; - -PDETOUR_SYM_INFO DetourLoadImageHlp(VOID); - -#endif // IMAGEAPI - -#if defined(_INC_STDIO) && !defined(_CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS) -#error detours.h must be included before stdio.h (or at least define _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS earlier) -#endif -#define _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS 1 - -#ifndef DETOUR_TRACE -#if DETOUR_DEBUG -#define DETOUR_TRACE(x) printf x -#define DETOUR_BREAK() __debugbreak() -#include -#include -#else -#define DETOUR_TRACE(x) -#define DETOUR_BREAK() -#endif -#endif - -#if 1 || defined(DETOURS_IA64) - -// -// IA64 instructions are 41 bits, 3 per bundle, plus 5 bit bundle template => 128 bits per bundle. -// - -#define DETOUR_IA64_INSTRUCTIONS_PER_BUNDLE (3) - -#define DETOUR_IA64_TEMPLATE_OFFSET (0) -#define DETOUR_IA64_TEMPLATE_SIZE (5) - -#define DETOUR_IA64_INSTRUCTION_SIZE (41) -#define DETOUR_IA64_INSTRUCTION0_OFFSET (DETOUR_IA64_TEMPLATE_SIZE) -#define DETOUR_IA64_INSTRUCTION1_OFFSET (DETOUR_IA64_TEMPLATE_SIZE + DETOUR_IA64_INSTRUCTION_SIZE) -#define DETOUR_IA64_INSTRUCTION2_OFFSET (DETOUR_IA64_TEMPLATE_SIZE + DETOUR_IA64_INSTRUCTION_SIZE + DETOUR_IA64_INSTRUCTION_SIZE) - -C_ASSERT(DETOUR_IA64_TEMPLATE_SIZE + DETOUR_IA64_INSTRUCTIONS_PER_BUNDLE * DETOUR_IA64_INSTRUCTION_SIZE == 128); - -__declspec(align(16)) struct DETOUR_IA64_BUNDLE -{ - public: - union - { - BYTE data[16]; - UINT64 wide[2]; - }; - - enum { - A_UNIT = 1u, - I_UNIT = 2u, - M_UNIT = 3u, - B_UNIT = 4u, - F_UNIT = 5u, - L_UNIT = 6u, - X_UNIT = 7u, - }; - struct DETOUR_IA64_METADATA - { - ULONG nTemplate : 8; // Instruction template. - ULONG nUnit0 : 4; // Unit for slot 0 - ULONG nUnit1 : 4; // Unit for slot 1 - ULONG nUnit2 : 4; // Unit for slot 2 - }; - - protected: - static const DETOUR_IA64_METADATA s_rceCopyTable[33]; - - UINT RelocateBundle(_Inout_ DETOUR_IA64_BUNDLE* pDst, _Inout_opt_ DETOUR_IA64_BUNDLE* pBundleExtra) const; - - bool RelocateInstruction(_Inout_ DETOUR_IA64_BUNDLE* pDst, - _In_ BYTE slot, - _Inout_opt_ DETOUR_IA64_BUNDLE* pBundleExtra) const; - - // 120 112 104 96 88 80 72 64 56 48 40 32 24 16 8 0 - // f. e. d. c. b. a. 9. 8. 7. 6. 5. 4. 3. 2. 1. 0. - - // 00 - // f.e. d.c. b.a. 9.8. 7.6. 5.4. 3.2. 1.0. - // 0000 0000 0000 0000 0000 0000 0000 001f : Template [4..0] - // 0000 0000 0000 0000 0000 03ff ffff ffe0 : Zero [ 41.. 5] - // 0000 0000 0000 0000 0000 3c00 0000 0000 : Zero [ 45.. 42] - // 0000 0000 0007 ffff ffff c000 0000 0000 : One [ 82.. 46] - // 0000 0000 0078 0000 0000 0000 0000 0000 : One [ 86.. 83] - // 0fff ffff ff80 0000 0000 0000 0000 0000 : Two [123.. 87] - // f000 0000 0000 0000 0000 0000 0000 0000 : Two [127..124] - BYTE GetTemplate() const; - // Get 4 bit opcodes. - BYTE GetInst0() const; - BYTE GetInst1() const; - BYTE GetInst2() const; - BYTE GetUnit(BYTE slot) const; - BYTE GetUnit0() const; - BYTE GetUnit1() const; - BYTE GetUnit2() const; - // Get 37 bit data. - UINT64 GetData0() const; - UINT64 GetData1() const; - UINT64 GetData2() const; - - // Get/set the full 41 bit instructions. - UINT64 GetInstruction(BYTE slot) const; - UINT64 GetInstruction0() const; - UINT64 GetInstruction1() const; - UINT64 GetInstruction2() const; - void SetInstruction(BYTE slot, UINT64 instruction); - void SetInstruction0(UINT64 instruction); - void SetInstruction1(UINT64 instruction); - void SetInstruction2(UINT64 instruction); - - // Get/set bitfields. - static UINT64 GetBits(UINT64 Value, UINT64 Offset, UINT64 Count); - static UINT64 SetBits(UINT64 Value, UINT64 Offset, UINT64 Count, UINT64 Field); - - // Get specific read-only fields. - static UINT64 GetOpcode(UINT64 instruction); // 4bit opcode - static UINT64 GetX(UINT64 instruction); // 1bit opcode extension - static UINT64 GetX3(UINT64 instruction); // 3bit opcode extension - static UINT64 GetX6(UINT64 instruction); // 6bit opcode extension - - // Get/set specific fields. - static UINT64 GetImm7a(UINT64 instruction); - static UINT64 SetImm7a(UINT64 instruction, UINT64 imm7a); - static UINT64 GetImm13c(UINT64 instruction); - static UINT64 SetImm13c(UINT64 instruction, UINT64 imm13c); - static UINT64 GetSignBit(UINT64 instruction); - static UINT64 SetSignBit(UINT64 instruction, UINT64 signBit); - static UINT64 GetImm20a(UINT64 instruction); - static UINT64 SetImm20a(UINT64 instruction, UINT64 imm20a); - static UINT64 GetImm20b(UINT64 instruction); - static UINT64 SetImm20b(UINT64 instruction, UINT64 imm20b); - - static UINT64 SignExtend(UINT64 Value, UINT64 Offset); - - BOOL IsMovlGp() const; - - VOID SetInst(BYTE Slot, BYTE nInst); - VOID SetInst0(BYTE nInst); - VOID SetInst1(BYTE nInst); - VOID SetInst2(BYTE nInst); - VOID SetData(BYTE Slot, UINT64 nData); - VOID SetData0(UINT64 nData); - VOID SetData1(UINT64 nData); - VOID SetData2(UINT64 nData); - BOOL SetNop(BYTE Slot); - BOOL SetNop0(); - BOOL SetNop1(); - BOOL SetNop2(); - - public: - BOOL IsBrl() const; - VOID SetBrl(); - VOID SetBrl(UINT64 target); - UINT64 GetBrlTarget() const; - VOID SetBrlTarget(UINT64 target); - VOID SetBrlImm(UINT64 imm); - UINT64 GetBrlImm() const; - - UINT64 GetMovlGp() const; - VOID SetMovlGp(UINT64 gp); - - VOID SetStop(); - - UINT Copy(_Out_ DETOUR_IA64_BUNDLE *pDst, _Inout_opt_ DETOUR_IA64_BUNDLE* pBundleExtra = NULL) const; -}; -#endif // DETOURS_IA64 - -#ifdef DETOURS_ARM - -#define DETOURS_PFUNC_TO_PBYTE(p) ((PBYTE)(((ULONG_PTR)(p)) & ~(ULONG_PTR)1)) -#define DETOURS_PBYTE_TO_PFUNC(p) ((PBYTE)(((ULONG_PTR)(p)) | (ULONG_PTR)1)) - -#endif // DETOURS_ARM - -////////////////////////////////////////////////////////////////////////////// - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -#define DETOUR_OFFLINE_LIBRARY(x) \ -PVOID WINAPI DetourCopyInstruction##x(_In_opt_ PVOID pDst, \ - _Inout_opt_ PVOID *ppDstPool, \ - _In_ PVOID pSrc, \ - _Out_opt_ PVOID *ppTarget, \ - _Out_opt_ LONG *plExtra); \ - \ -BOOL WINAPI DetourSetCodeModule##x(_In_ HMODULE hModule, \ - _In_ BOOL fLimitReferencesToModule); \ - -DETOUR_OFFLINE_LIBRARY(X86) -DETOUR_OFFLINE_LIBRARY(X64) -DETOUR_OFFLINE_LIBRARY(ARM) -DETOUR_OFFLINE_LIBRARY(ARM64) -DETOUR_OFFLINE_LIBRARY(IA64) - -#undef DETOUR_OFFLINE_LIBRARY - -////////////////////////////////////////////////////////////////////////////// -// -// Helpers for manipulating page protection. -// - -_Success_(return != FALSE) -BOOL WINAPI DetourVirtualProtectSameExecuteEx(_In_ HANDLE hProcess, - _In_ PVOID pAddress, - _In_ SIZE_T nSize, - _In_ DWORD dwNewProtect, - _Out_ PDWORD pdwOldProtect); - -_Success_(return != FALSE) -BOOL WINAPI DetourVirtualProtectSameExecute(_In_ PVOID pAddress, - _In_ SIZE_T nSize, - _In_ DWORD dwNewProtect, - _Out_ PDWORD pdwOldProtect); -#ifdef __cplusplus -} -#endif // __cplusplus - -////////////////////////////////////////////////////////////////////////////// - -#define MM_ALLOCATION_GRANULARITY 0x10000 - -////////////////////////////////////////////////////////////////////////////// - -#endif // DETOURS_INTERNAL -#endif // __cplusplus - -#endif // _DETOURS_H_ -// -//////////////////////////////////////////////////////////////// End of File. +///////////////////////////////////////////////////////////////////////////// +// +// Core Detours Functionality (detours.h of detours.lib) +// +// Microsoft Research Detours Package, Version 3.0 Build_343. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// + +#pragma once +#ifndef _DETOURS_H_ +#define _DETOURS_H_ + +#define DETOURS_VERSION 30001 // 3.00.01 + +////////////////////////////////////////////////////////////////////////////// +// + +#undef DETOURS_X64 +#undef DETOURS_X86 +#undef DETOURS_IA64 +#undef DETOURS_ARM +#undef DETOURS_ARM64 +#undef DETOURS_BITS +#undef DETOURS_32BIT +#undef DETOURS_64BIT + +#if defined(_X86_) +#define DETOURS_X86 +#define DETOURS_OPTION_BITS 64 + +#elif defined(_AMD64_) +#define DETOURS_X64 +#define DETOURS_OPTION_BITS 32 + +#elif defined(_IA64_) +#define DETOURS_IA64 +#define DETOURS_OPTION_BITS 32 + +#elif defined(_ARM_) +#define DETOURS_ARM + +#elif defined(_ARM64_) +#define DETOURS_ARM64 + +#else +#error Unknown architecture (x86, amd64, ia64, arm, arm64) +#endif + +#ifdef _WIN64 +#undef DETOURS_32BIT +#define DETOURS_64BIT 1 +#define DETOURS_BITS 64 +// If all 64bit kernels can run one and only one 32bit architecture. +//#define DETOURS_OPTION_BITS 32 +#else +#define DETOURS_32BIT 1 +#undef DETOURS_64BIT +#define DETOURS_BITS 32 +// If all 64bit kernels can run one and only one 32bit architecture. +//#define DETOURS_OPTION_BITS 32 +#endif + +#define VER_DETOURS_BITS DETOUR_STRINGIFY(DETOURS_BITS) + +////////////////////////////////////////////////////////////////////////////// +// + +#if (_MSC_VER < 1299) +typedef LONG LONG_PTR; +typedef ULONG ULONG_PTR; +#endif + +///////////////////////////////////////////////// SAL 2.0 Annotations w/o SAL. +// +// These definitions are include so that Detours will build even if the +// compiler doesn't have full SAL 2.0 support. +// +#ifndef DETOURS_DONT_REMOVE_SAL_20 + +#ifdef DETOURS_TEST_REMOVE_SAL_20 +#undef _Analysis_assume_ +#undef _Benign_race_begin_ +#undef _Benign_race_end_ +#undef _Field_range_ +#undef _Field_size_ +#undef _In_ +#undef _In_bytecount_ +#undef _In_count_ +#undef _In_opt_ +#undef _In_opt_bytecount_ +#undef _In_opt_count_ +#undef _In_opt_z_ +#undef _In_range_ +#undef _In_reads_ +#undef _In_reads_bytes_ +#undef _In_reads_opt_ +#undef _In_reads_opt_bytes_ +#undef _In_reads_or_z_ +#undef _In_z_ +#undef _Inout_ +#undef _Inout_opt_ +#undef _Inout_z_count_ +#undef _Out_ +#undef _Out_opt_ +#undef _Out_writes_ +#undef _Outptr_result_maybenull_ +#undef _Readable_bytes_ +#undef _Success_ +#undef _Writable_bytes_ +#undef _Pre_notnull_ +#endif + +#if defined(_Deref_out_opt_z_) && !defined(_Outptr_result_maybenull_) +#define _Outptr_result_maybenull_ _Deref_out_opt_z_ +#endif + +#if defined(_In_count_) && !defined(_In_reads_) +#define _In_reads_(x) _In_count_(x) +#endif + +#if defined(_In_opt_count_) && !defined(_In_reads_opt_) +#define _In_reads_opt_(x) _In_opt_count_(x) +#endif + +#if defined(_In_opt_bytecount_) && !defined(_In_reads_opt_bytes_) +#define _In_reads_opt_bytes_(x) _In_opt_bytecount_(x) +#endif + +#if defined(_In_bytecount_) && !defined(_In_reads_bytes_) +#define _In_reads_bytes_(x) _In_bytecount_(x) +#endif + +#ifndef _In_ +#define _In_ +#endif + +#ifndef _In_bytecount_ +#define _In_bytecount_(x) +#endif + +#ifndef _In_count_ +#define _In_count_(x) +#endif + +#ifndef _In_opt_ +#define _In_opt_ +#endif + +#ifndef _In_opt_bytecount_ +#define _In_opt_bytecount_(x) +#endif + +#ifndef _In_opt_count_ +#define _In_opt_count_(x) +#endif + +#ifndef _In_opt_z_ +#define _In_opt_z_ +#endif + +#ifndef _In_range_ +#define _In_range_(x,y) +#endif + +#ifndef _In_reads_ +#define _In_reads_(x) +#endif + +#ifndef _In_reads_bytes_ +#define _In_reads_bytes_(x) +#endif + +#ifndef _In_reads_opt_ +#define _In_reads_opt_(x) +#endif + +#ifndef _In_reads_opt_bytes_ +#define _In_reads_opt_bytes_(x) +#endif + +#ifndef _In_reads_or_z_ +#define _In_reads_or_z_ +#endif + +#ifndef _In_z_ +#define _In_z_ +#endif + +#ifndef _Inout_ +#define _Inout_ +#endif + +#ifndef _Inout_opt_ +#define _Inout_opt_ +#endif + +#ifndef _Inout_z_count_ +#define _Inout_z_count_(x) +#endif + +#ifndef _Out_ +#define _Out_ +#endif + +#ifndef _Out_opt_ +#define _Out_opt_ +#endif + +#ifndef _Out_writes_ +#define _Out_writes_(x) +#endif + +#ifndef _Outptr_result_maybenull_ +#define _Outptr_result_maybenull_ +#endif + +#ifndef _Writable_bytes_ +#define _Writable_bytes_(x) +#endif + +#ifndef _Readable_bytes_ +#define _Readable_bytes_(x) +#endif + +#ifndef _Success_ +#define _Success_(x) +#endif + +#ifndef _Pre_notnull_ +#define _Pre_notnull_ +#endif + +#ifdef DETOURS_INTERNAL + +#pragma warning(disable:4615) // unknown warning type (suppress with older compilers) + +#ifndef _Benign_race_begin_ +#define _Benign_race_begin_ +#endif + +#ifndef _Benign_race_end_ +#define _Benign_race_end_ +#endif + +#ifndef _Field_size_ +#define _Field_size_(x) +#endif + +#ifndef _Field_range_ +#define _Field_range_(x,y) +#endif + +#ifndef _Analysis_assume_ +#define _Analysis_assume_(x) +#endif + +#endif // DETOURS_INTERNAL +#endif // DETOURS_DONT_REMOVE_SAL_20 + +////////////////////////////////////////////////////////////////////////////// +// +#ifndef GUID_DEFINED +#define GUID_DEFINED +typedef struct _GUID +{ + DWORD Data1; + WORD Data2; + WORD Data3; + BYTE Data4[ 8 ]; +} GUID; + +#ifdef INITGUID +#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + const GUID name \ + = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } +#else +#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + const GUID name +#endif // INITGUID +#endif // !GUID_DEFINED + +#if defined(__cplusplus) +#ifndef _REFGUID_DEFINED +#define _REFGUID_DEFINED +#define REFGUID const GUID & +#endif // !_REFGUID_DEFINED +#else // !__cplusplus +#ifndef _REFGUID_DEFINED +#define _REFGUID_DEFINED +#define REFGUID const GUID * const +#endif // !_REFGUID_DEFINED +#endif // !__cplusplus + +#ifndef ARRAYSIZE +#define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0])) +#endif + +// +////////////////////////////////////////////////////////////////////////////// + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/////////////////////////////////////////////////// Instruction Target Macros. +// +#define DETOUR_INSTRUCTION_TARGET_NONE ((PVOID)0) +#define DETOUR_INSTRUCTION_TARGET_DYNAMIC ((PVOID)(LONG_PTR)-1) +#define DETOUR_SECTION_HEADER_SIGNATURE 0x00727444 // "Dtr\0" + +extern const GUID DETOUR_EXE_RESTORE_GUID; +extern const GUID DETOUR_EXE_HELPER_GUID; + +#define DETOUR_TRAMPOLINE_SIGNATURE 0x21727444 // Dtr! +typedef struct _DETOUR_TRAMPOLINE DETOUR_TRAMPOLINE, *PDETOUR_TRAMPOLINE; + +/////////////////////////////////////////////////////////// Binary Structures. +// +#pragma pack(push, 8) +typedef struct _DETOUR_SECTION_HEADER +{ + DWORD cbHeaderSize; + DWORD nSignature; + DWORD nDataOffset; + DWORD cbDataSize; + + DWORD nOriginalImportVirtualAddress; + DWORD nOriginalImportSize; + DWORD nOriginalBoundImportVirtualAddress; + DWORD nOriginalBoundImportSize; + + DWORD nOriginalIatVirtualAddress; + DWORD nOriginalIatSize; + DWORD nOriginalSizeOfImage; + DWORD cbPrePE; + + DWORD nOriginalClrFlags; + DWORD reserved1; + DWORD reserved2; + DWORD reserved3; + + // Followed by cbPrePE bytes of data. +} DETOUR_SECTION_HEADER, *PDETOUR_SECTION_HEADER; + +typedef struct _DETOUR_SECTION_RECORD +{ + DWORD cbBytes; + DWORD nReserved; + GUID guid; +} DETOUR_SECTION_RECORD, *PDETOUR_SECTION_RECORD; + +typedef struct _DETOUR_CLR_HEADER +{ + // Header versioning + ULONG cb; + USHORT MajorRuntimeVersion; + USHORT MinorRuntimeVersion; + + // Symbol table and startup information + IMAGE_DATA_DIRECTORY MetaData; + ULONG Flags; + + // Followed by the rest of the IMAGE_COR20_HEADER +} DETOUR_CLR_HEADER, *PDETOUR_CLR_HEADER; + +typedef struct _DETOUR_EXE_RESTORE +{ + DWORD cb; + DWORD cbidh; + DWORD cbinh; + DWORD cbclr; + + PBYTE pidh; + PBYTE pinh; + PBYTE pclr; + + IMAGE_DOS_HEADER idh; + union { + IMAGE_NT_HEADERS inh; + IMAGE_NT_HEADERS32 inh32; + IMAGE_NT_HEADERS64 inh64; + BYTE raw[sizeof(IMAGE_NT_HEADERS64) + + sizeof(IMAGE_SECTION_HEADER) * 32]; + }; + DETOUR_CLR_HEADER clr; + +} DETOUR_EXE_RESTORE, *PDETOUR_EXE_RESTORE; + +typedef struct _DETOUR_EXE_HELPER +{ + DWORD cb; + DWORD pid; + DWORD nDlls; + CHAR rDlls[4]; +} DETOUR_EXE_HELPER, *PDETOUR_EXE_HELPER; + +#pragma pack(pop) + +#define DETOUR_SECTION_HEADER_DECLARE(cbSectionSize) \ +{ \ + sizeof(DETOUR_SECTION_HEADER),\ + DETOUR_SECTION_HEADER_SIGNATURE,\ + sizeof(DETOUR_SECTION_HEADER),\ + (cbSectionSize),\ + \ + 0,\ + 0,\ + 0,\ + 0,\ + \ + 0,\ + 0,\ + 0,\ + 0,\ +} + +/////////////////////////////////////////////////////////////// Helper Macros. +// +#define DETOURS_STRINGIFY(x) DETOURS_STRINGIFY_(x) +#define DETOURS_STRINGIFY_(x) #x + +///////////////////////////////////////////////////////////// Binary Typedefs. +// +typedef BOOL (CALLBACK *PF_DETOUR_BINARY_BYWAY_CALLBACK)( + _In_opt_ PVOID pContext, + _In_opt_ LPCSTR pszFile, + _Outptr_result_maybenull_ LPCSTR *ppszOutFile); + +typedef BOOL (CALLBACK *PF_DETOUR_BINARY_FILE_CALLBACK)( + _In_opt_ PVOID pContext, + _In_ LPCSTR pszOrigFile, + _In_ LPCSTR pszFile, + _Outptr_result_maybenull_ LPCSTR *ppszOutFile); + +typedef BOOL (CALLBACK *PF_DETOUR_BINARY_SYMBOL_CALLBACK)( + _In_opt_ PVOID pContext, + _In_ ULONG nOrigOrdinal, + _In_ ULONG nOrdinal, + _Out_ ULONG *pnOutOrdinal, + _In_opt_ LPCSTR pszOrigSymbol, + _In_opt_ LPCSTR pszSymbol, + _Outptr_result_maybenull_ LPCSTR *ppszOutSymbol); + +typedef BOOL (CALLBACK *PF_DETOUR_BINARY_COMMIT_CALLBACK)( + _In_opt_ PVOID pContext); + +typedef BOOL (CALLBACK *PF_DETOUR_ENUMERATE_EXPORT_CALLBACK)(_In_opt_ PVOID pContext, + _In_ ULONG nOrdinal, + _In_opt_ LPCSTR pszName, + _In_opt_ PVOID pCode); + +typedef BOOL (CALLBACK *PF_DETOUR_IMPORT_FILE_CALLBACK)(_In_opt_ PVOID pContext, + _In_opt_ HMODULE hModule, + _In_opt_ LPCSTR pszFile); + +typedef BOOL (CALLBACK *PF_DETOUR_IMPORT_FUNC_CALLBACK)(_In_opt_ PVOID pContext, + _In_ DWORD nOrdinal, + _In_opt_ LPCSTR pszFunc, + _In_opt_ PVOID pvFunc); + +// Same as PF_DETOUR_IMPORT_FUNC_CALLBACK but extra indirection on last parameter. +typedef BOOL (CALLBACK *PF_DETOUR_IMPORT_FUNC_CALLBACK_EX)(_In_opt_ PVOID pContext, + _In_ DWORD nOrdinal, + _In_opt_ LPCSTR pszFunc, + _In_opt_ PVOID* ppvFunc); + +typedef VOID * PDETOUR_BINARY; +typedef VOID * PDETOUR_LOADED_BINARY; + +//////////////////////////////////////////////////////////// Transaction APIs. +// +LONG WINAPI DetourTransactionBegin(VOID); +LONG WINAPI DetourTransactionAbort(VOID); +LONG WINAPI DetourTransactionCommit(VOID); +LONG WINAPI DetourTransactionCommitEx(_Out_opt_ PVOID **pppFailedPointer); + +LONG WINAPI DetourUpdateThread(_In_ HANDLE hThread); + +LONG WINAPI DetourAttach(_Inout_ PVOID *ppPointer, + _In_ PVOID pDetour); + +LONG WINAPI DetourAttachEx(_Inout_ PVOID *ppPointer, + _In_ PVOID pDetour, + _Out_opt_ PDETOUR_TRAMPOLINE *ppRealTrampoline, + _Out_opt_ PVOID *ppRealTarget, + _Out_opt_ PVOID *ppRealDetour); + +LONG WINAPI DetourDetach(_Inout_ PVOID *ppPointer, + _In_ PVOID pDetour); + +BOOL WINAPI DetourSetIgnoreTooSmall(_In_ BOOL fIgnore); +BOOL WINAPI DetourSetRetainRegions(_In_ BOOL fRetain); +PVOID WINAPI DetourSetSystemRegionLowerBound(_In_ PVOID pSystemRegionLowerBound); +PVOID WINAPI DetourSetSystemRegionUpperBound(_In_ PVOID pSystemRegionUpperBound); + +////////////////////////////////////////////////////////////// Code Functions. +// +PVOID WINAPI DetourFindFunction(_In_ LPCSTR pszModule, + _In_ LPCSTR pszFunction); +PVOID WINAPI DetourCodeFromPointer(_In_ PVOID pPointer, + _Out_opt_ PVOID *ppGlobals); +PVOID WINAPI DetourCopyInstruction(_In_opt_ PVOID pDst, + _Inout_opt_ PVOID *ppDstPool, + _In_ PVOID pSrc, + _Out_opt_ PVOID *ppTarget, + _Out_opt_ LONG *plExtra); +BOOL WINAPI DetourSetCodeModule(_In_ HMODULE hModule, + _In_ BOOL fLimitReferencesToModule); + +///////////////////////////////////////////////////// Loaded Binary Functions. +// +HMODULE WINAPI DetourGetContainingModule(_In_ PVOID pvAddr); +HMODULE WINAPI DetourEnumerateModules(_In_opt_ HMODULE hModuleLast); +PVOID WINAPI DetourGetEntryPoint(_In_opt_ HMODULE hModule); +ULONG WINAPI DetourGetModuleSize(_In_opt_ HMODULE hModule); +BOOL WINAPI DetourEnumerateExports(_In_ HMODULE hModule, + _In_opt_ PVOID pContext, + _In_ PF_DETOUR_ENUMERATE_EXPORT_CALLBACK pfExport); +BOOL WINAPI DetourEnumerateImports(_In_opt_ HMODULE hModule, + _In_opt_ PVOID pContext, + _In_opt_ PF_DETOUR_IMPORT_FILE_CALLBACK pfImportFile, + _In_opt_ PF_DETOUR_IMPORT_FUNC_CALLBACK pfImportFunc); + +BOOL WINAPI DetourEnumerateImportsEx(_In_opt_ HMODULE hModule, + _In_opt_ PVOID pContext, + _In_opt_ PF_DETOUR_IMPORT_FILE_CALLBACK pfImportFile, + _In_opt_ PF_DETOUR_IMPORT_FUNC_CALLBACK_EX pfImportFuncEx); + +_Writable_bytes_(*pcbData) +_Readable_bytes_(*pcbData) +_Success_(return != NULL) +PVOID WINAPI DetourFindPayload(_In_opt_ HMODULE hModule, + _In_ REFGUID rguid, + _Out_ DWORD *pcbData); + +_Writable_bytes_(*pcbData) +_Readable_bytes_(*pcbData) +_Success_(return != NULL) +PVOID WINAPI DetourFindPayloadEx(_In_ REFGUID rguid, + _Out_ DWORD * pcbData); + +DWORD WINAPI DetourGetSizeOfPayloads(_In_opt_ HMODULE hModule); + +///////////////////////////////////////////////// Persistent Binary Functions. +// + +PDETOUR_BINARY WINAPI DetourBinaryOpen(_In_ HANDLE hFile); + +_Writable_bytes_(*pcbData) +_Readable_bytes_(*pcbData) +_Success_(return != NULL) +PVOID WINAPI DetourBinaryEnumeratePayloads(_In_ PDETOUR_BINARY pBinary, + _Out_opt_ GUID *pGuid, + _Out_ DWORD *pcbData, + _Inout_ DWORD *pnIterator); + +_Writable_bytes_(*pcbData) +_Readable_bytes_(*pcbData) +_Success_(return != NULL) +PVOID WINAPI DetourBinaryFindPayload(_In_ PDETOUR_BINARY pBinary, + _In_ REFGUID rguid, + _Out_ DWORD *pcbData); + +PVOID WINAPI DetourBinarySetPayload(_In_ PDETOUR_BINARY pBinary, + _In_ REFGUID rguid, + _In_reads_opt_(cbData) PVOID pData, + _In_ DWORD cbData); +BOOL WINAPI DetourBinaryDeletePayload(_In_ PDETOUR_BINARY pBinary, _In_ REFGUID rguid); +BOOL WINAPI DetourBinaryPurgePayloads(_In_ PDETOUR_BINARY pBinary); +BOOL WINAPI DetourBinaryResetImports(_In_ PDETOUR_BINARY pBinary); +BOOL WINAPI DetourBinaryEditImports(_In_ PDETOUR_BINARY pBinary, + _In_opt_ PVOID pContext, + _In_opt_ PF_DETOUR_BINARY_BYWAY_CALLBACK pfByway, + _In_opt_ PF_DETOUR_BINARY_FILE_CALLBACK pfFile, + _In_opt_ PF_DETOUR_BINARY_SYMBOL_CALLBACK pfSymbol, + _In_opt_ PF_DETOUR_BINARY_COMMIT_CALLBACK pfCommit); +BOOL WINAPI DetourBinaryWrite(_In_ PDETOUR_BINARY pBinary, _In_ HANDLE hFile); +BOOL WINAPI DetourBinaryClose(_In_ PDETOUR_BINARY pBinary); + +/////////////////////////////////////////////////// Create Process & Load Dll. +// +typedef BOOL (WINAPI *PDETOUR_CREATE_PROCESS_ROUTINEA)( + _In_opt_ LPCSTR lpApplicationName, + _Inout_opt_ LPSTR lpCommandLine, + _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, + _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, + _In_ BOOL bInheritHandles, + _In_ DWORD dwCreationFlags, + _In_opt_ LPVOID lpEnvironment, + _In_opt_ LPCSTR lpCurrentDirectory, + _In_ LPSTARTUPINFOA lpStartupInfo, + _Out_ LPPROCESS_INFORMATION lpProcessInformation); + +typedef BOOL (WINAPI *PDETOUR_CREATE_PROCESS_ROUTINEW)( + _In_opt_ LPCWSTR lpApplicationName, + _Inout_opt_ LPWSTR lpCommandLine, + _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, + _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, + _In_ BOOL bInheritHandles, + _In_ DWORD dwCreationFlags, + _In_opt_ LPVOID lpEnvironment, + _In_opt_ LPCWSTR lpCurrentDirectory, + _In_ LPSTARTUPINFOW lpStartupInfo, + _Out_ LPPROCESS_INFORMATION lpProcessInformation); + +BOOL WINAPI DetourCreateProcessWithDllA(_In_opt_ LPCSTR lpApplicationName, + _Inout_opt_ LPSTR lpCommandLine, + _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, + _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, + _In_ BOOL bInheritHandles, + _In_ DWORD dwCreationFlags, + _In_opt_ LPVOID lpEnvironment, + _In_opt_ LPCSTR lpCurrentDirectory, + _In_ LPSTARTUPINFOA lpStartupInfo, + _Out_ LPPROCESS_INFORMATION lpProcessInformation, + _In_ LPCSTR lpDllName, + _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); + +BOOL WINAPI DetourCreateProcessWithDllW(_In_opt_ LPCWSTR lpApplicationName, + _Inout_opt_ LPWSTR lpCommandLine, + _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, + _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, + _In_ BOOL bInheritHandles, + _In_ DWORD dwCreationFlags, + _In_opt_ LPVOID lpEnvironment, + _In_opt_ LPCWSTR lpCurrentDirectory, + _In_ LPSTARTUPINFOW lpStartupInfo, + _Out_ LPPROCESS_INFORMATION lpProcessInformation, + _In_ LPCSTR lpDllName, + _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); + +#ifdef UNICODE +#define DetourCreateProcessWithDll DetourCreateProcessWithDllW +#define PDETOUR_CREATE_PROCESS_ROUTINE PDETOUR_CREATE_PROCESS_ROUTINEW +#else +#define DetourCreateProcessWithDll DetourCreateProcessWithDllA +#define PDETOUR_CREATE_PROCESS_ROUTINE PDETOUR_CREATE_PROCESS_ROUTINEA +#endif // !UNICODE + +BOOL WINAPI DetourCreateProcessWithDllExA(_In_opt_ LPCSTR lpApplicationName, + _Inout_opt_ LPSTR lpCommandLine, + _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, + _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, + _In_ BOOL bInheritHandles, + _In_ DWORD dwCreationFlags, + _In_opt_ LPVOID lpEnvironment, + _In_opt_ LPCSTR lpCurrentDirectory, + _In_ LPSTARTUPINFOA lpStartupInfo, + _Out_ LPPROCESS_INFORMATION lpProcessInformation, + _In_ LPCSTR lpDllName, + _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); + +BOOL WINAPI DetourCreateProcessWithDllExW(_In_opt_ LPCWSTR lpApplicationName, + _Inout_opt_ LPWSTR lpCommandLine, + _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, + _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, + _In_ BOOL bInheritHandles, + _In_ DWORD dwCreationFlags, + _In_opt_ LPVOID lpEnvironment, + _In_opt_ LPCWSTR lpCurrentDirectory, + _In_ LPSTARTUPINFOW lpStartupInfo, + _Out_ LPPROCESS_INFORMATION lpProcessInformation, + _In_ LPCSTR lpDllName, + _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); + +#ifdef UNICODE +#define DetourCreateProcessWithDllEx DetourCreateProcessWithDllExW +#else +#define DetourCreateProcessWithDllEx DetourCreateProcessWithDllExA +#endif // !UNICODE + +BOOL WINAPI DetourCreateProcessWithDllsA(_In_opt_ LPCSTR lpApplicationName, + _Inout_opt_ LPSTR lpCommandLine, + _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, + _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, + _In_ BOOL bInheritHandles, + _In_ DWORD dwCreationFlags, + _In_opt_ LPVOID lpEnvironment, + _In_opt_ LPCSTR lpCurrentDirectory, + _In_ LPSTARTUPINFOA lpStartupInfo, + _Out_ LPPROCESS_INFORMATION lpProcessInformation, + _In_ DWORD nDlls, + _In_reads_(nDlls) LPCSTR *rlpDlls, + _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); + +BOOL WINAPI DetourCreateProcessWithDllsW(_In_opt_ LPCWSTR lpApplicationName, + _Inout_opt_ LPWSTR lpCommandLine, + _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, + _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, + _In_ BOOL bInheritHandles, + _In_ DWORD dwCreationFlags, + _In_opt_ LPVOID lpEnvironment, + _In_opt_ LPCWSTR lpCurrentDirectory, + _In_ LPSTARTUPINFOW lpStartupInfo, + _Out_ LPPROCESS_INFORMATION lpProcessInformation, + _In_ DWORD nDlls, + _In_reads_(nDlls) LPCSTR *rlpDlls, + _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); + +#ifdef UNICODE +#define DetourCreateProcessWithDlls DetourCreateProcessWithDllsW +#else +#define DetourCreateProcessWithDlls DetourCreateProcessWithDllsA +#endif // !UNICODE + +BOOL WINAPI DetourProcessViaHelperA(_In_ DWORD dwTargetPid, + _In_ LPCSTR lpDllName, + _In_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); + +BOOL WINAPI DetourProcessViaHelperW(_In_ DWORD dwTargetPid, + _In_ LPCSTR lpDllName, + _In_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); + +#ifdef UNICODE +#define DetourProcessViaHelper DetourProcessViaHelperW +#else +#define DetourProcessViaHelper DetourProcessViaHelperA +#endif // !UNICODE + +BOOL WINAPI DetourProcessViaHelperDllsA(_In_ DWORD dwTargetPid, + _In_ DWORD nDlls, + _In_reads_(nDlls) LPCSTR *rlpDlls, + _In_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); + +BOOL WINAPI DetourProcessViaHelperDllsW(_In_ DWORD dwTargetPid, + _In_ DWORD nDlls, + _In_reads_(nDlls) LPCSTR *rlpDlls, + _In_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); + +#ifdef UNICODE +#define DetourProcessViaHelperDlls DetourProcessViaHelperDllsW +#else +#define DetourProcessViaHelperDlls DetourProcessViaHelperDllsA +#endif // !UNICODE + +BOOL WINAPI DetourUpdateProcessWithDll(_In_ HANDLE hProcess, + _In_reads_(nDlls) LPCSTR *rlpDlls, + _In_ DWORD nDlls); + +BOOL WINAPI DetourUpdateProcessWithDllEx(_In_ HANDLE hProcess, + _In_ HMODULE hImage, + _In_ BOOL bIs32Bit, + _In_reads_(nDlls) LPCSTR *rlpDlls, + _In_ DWORD nDlls); + +BOOL WINAPI DetourCopyPayloadToProcess(_In_ HANDLE hProcess, + _In_ REFGUID rguid, + _In_reads_bytes_(cbData) PVOID pvData, + _In_ DWORD cbData); +BOOL WINAPI DetourRestoreAfterWith(VOID); +BOOL WINAPI DetourRestoreAfterWithEx(_In_reads_bytes_(cbData) PVOID pvData, + _In_ DWORD cbData); +BOOL WINAPI DetourIsHelperProcess(VOID); +VOID CALLBACK DetourFinishHelperProcess(_In_ HWND, + _In_ HINSTANCE, + _In_ LPSTR, + _In_ INT); + +// +////////////////////////////////////////////////////////////////////////////// +#ifdef __cplusplus +} +#endif // __cplusplus + +//////////////////////////////////////////////// Detours Internal Definitions. +// +#ifdef __cplusplus +#ifdef DETOURS_INTERNAL + +#define NOTHROW +// #define NOTHROW (nothrow) + +////////////////////////////////////////////////////////////////////////////// +// +#if (_MSC_VER < 1299) +#include +typedef IMAGEHLP_MODULE IMAGEHLP_MODULE64; +typedef PIMAGEHLP_MODULE PIMAGEHLP_MODULE64; +typedef IMAGEHLP_SYMBOL SYMBOL_INFO; +typedef PIMAGEHLP_SYMBOL PSYMBOL_INFO; + +static inline +LONG InterlockedCompareExchange(_Inout_ LONG *ptr, _In_ LONG nval, _In_ LONG oval) +{ + return (LONG)::InterlockedCompareExchange((PVOID*)ptr, (PVOID)nval, (PVOID)oval); +} +#else +#pragma warning(push) +#pragma warning(disable:4091) // empty typedef +#include +#pragma warning(pop) +#endif + +#ifdef IMAGEAPI // defined by DBGHELP.H +typedef LPAPI_VERSION (NTAPI *PF_ImagehlpApiVersionEx)(_In_ LPAPI_VERSION AppVersion); + +typedef BOOL (NTAPI *PF_SymInitialize)(_In_ HANDLE hProcess, + _In_opt_ LPCSTR UserSearchPath, + _In_ BOOL fInvadeProcess); +typedef DWORD (NTAPI *PF_SymSetOptions)(_In_ DWORD SymOptions); +typedef DWORD (NTAPI *PF_SymGetOptions)(VOID); +typedef DWORD64 (NTAPI *PF_SymLoadModule64)(_In_ HANDLE hProcess, + _In_opt_ HANDLE hFile, + _In_ LPSTR ImageName, + _In_opt_ LPSTR ModuleName, + _In_ DWORD64 BaseOfDll, + _In_opt_ DWORD SizeOfDll); +typedef BOOL (NTAPI *PF_SymGetModuleInfo64)(_In_ HANDLE hProcess, + _In_ DWORD64 qwAddr, + _Out_ PIMAGEHLP_MODULE64 ModuleInfo); +typedef BOOL (NTAPI *PF_SymFromName)(_In_ HANDLE hProcess, + _In_ LPSTR Name, + _Out_ PSYMBOL_INFO Symbol); + +typedef struct _DETOUR_SYM_INFO +{ + HANDLE hProcess; + HMODULE hDbgHelp; + PF_ImagehlpApiVersionEx pfImagehlpApiVersionEx; + PF_SymInitialize pfSymInitialize; + PF_SymSetOptions pfSymSetOptions; + PF_SymGetOptions pfSymGetOptions; + PF_SymLoadModule64 pfSymLoadModule64; + PF_SymGetModuleInfo64 pfSymGetModuleInfo64; + PF_SymFromName pfSymFromName; +} DETOUR_SYM_INFO, *PDETOUR_SYM_INFO; + +PDETOUR_SYM_INFO DetourLoadImageHlp(VOID); + +#endif // IMAGEAPI + +#if defined(_INC_STDIO) && !defined(_CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS) +#error detours.h must be included before stdio.h (or at least define _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS earlier) +#endif +#define _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS 1 + +#ifndef DETOUR_TRACE +#if DETOUR_DEBUG +#define DETOUR_TRACE(x) printf x +#define DETOUR_BREAK() __debugbreak() +#include +#include +#else +#define DETOUR_TRACE(x) +#define DETOUR_BREAK() +#endif +#endif + +#if 1 || defined(DETOURS_IA64) + +// +// IA64 instructions are 41 bits, 3 per bundle, plus 5 bit bundle template => 128 bits per bundle. +// + +#define DETOUR_IA64_INSTRUCTIONS_PER_BUNDLE (3) + +#define DETOUR_IA64_TEMPLATE_OFFSET (0) +#define DETOUR_IA64_TEMPLATE_SIZE (5) + +#define DETOUR_IA64_INSTRUCTION_SIZE (41) +#define DETOUR_IA64_INSTRUCTION0_OFFSET (DETOUR_IA64_TEMPLATE_SIZE) +#define DETOUR_IA64_INSTRUCTION1_OFFSET (DETOUR_IA64_TEMPLATE_SIZE + DETOUR_IA64_INSTRUCTION_SIZE) +#define DETOUR_IA64_INSTRUCTION2_OFFSET (DETOUR_IA64_TEMPLATE_SIZE + DETOUR_IA64_INSTRUCTION_SIZE + DETOUR_IA64_INSTRUCTION_SIZE) + +C_ASSERT(DETOUR_IA64_TEMPLATE_SIZE + DETOUR_IA64_INSTRUCTIONS_PER_BUNDLE * DETOUR_IA64_INSTRUCTION_SIZE == 128); + +__declspec(align(16)) struct DETOUR_IA64_BUNDLE +{ + public: + union + { + BYTE data[16]; + UINT64 wide[2]; + }; + + enum { + A_UNIT = 1u, + I_UNIT = 2u, + M_UNIT = 3u, + B_UNIT = 4u, + F_UNIT = 5u, + L_UNIT = 6u, + X_UNIT = 7u, + }; + struct DETOUR_IA64_METADATA + { + ULONG nTemplate : 8; // Instruction template. + ULONG nUnit0 : 4; // Unit for slot 0 + ULONG nUnit1 : 4; // Unit for slot 1 + ULONG nUnit2 : 4; // Unit for slot 2 + }; + + protected: + static const DETOUR_IA64_METADATA s_rceCopyTable[33]; + + UINT RelocateBundle(_Inout_ DETOUR_IA64_BUNDLE* pDst, _Inout_opt_ DETOUR_IA64_BUNDLE* pBundleExtra) const; + + bool RelocateInstruction(_Inout_ DETOUR_IA64_BUNDLE* pDst, + _In_ BYTE slot, + _Inout_opt_ DETOUR_IA64_BUNDLE* pBundleExtra) const; + + // 120 112 104 96 88 80 72 64 56 48 40 32 24 16 8 0 + // f. e. d. c. b. a. 9. 8. 7. 6. 5. 4. 3. 2. 1. 0. + + // 00 + // f.e. d.c. b.a. 9.8. 7.6. 5.4. 3.2. 1.0. + // 0000 0000 0000 0000 0000 0000 0000 001f : Template [4..0] + // 0000 0000 0000 0000 0000 03ff ffff ffe0 : Zero [ 41.. 5] + // 0000 0000 0000 0000 0000 3c00 0000 0000 : Zero [ 45.. 42] + // 0000 0000 0007 ffff ffff c000 0000 0000 : One [ 82.. 46] + // 0000 0000 0078 0000 0000 0000 0000 0000 : One [ 86.. 83] + // 0fff ffff ff80 0000 0000 0000 0000 0000 : Two [123.. 87] + // f000 0000 0000 0000 0000 0000 0000 0000 : Two [127..124] + BYTE GetTemplate() const; + // Get 4 bit opcodes. + BYTE GetInst0() const; + BYTE GetInst1() const; + BYTE GetInst2() const; + BYTE GetUnit(BYTE slot) const; + BYTE GetUnit0() const; + BYTE GetUnit1() const; + BYTE GetUnit2() const; + // Get 37 bit data. + UINT64 GetData0() const; + UINT64 GetData1() const; + UINT64 GetData2() const; + + // Get/set the full 41 bit instructions. + UINT64 GetInstruction(BYTE slot) const; + UINT64 GetInstruction0() const; + UINT64 GetInstruction1() const; + UINT64 GetInstruction2() const; + void SetInstruction(BYTE slot, UINT64 instruction); + void SetInstruction0(UINT64 instruction); + void SetInstruction1(UINT64 instruction); + void SetInstruction2(UINT64 instruction); + + // Get/set bitfields. + static UINT64 GetBits(UINT64 Value, UINT64 Offset, UINT64 Count); + static UINT64 SetBits(UINT64 Value, UINT64 Offset, UINT64 Count, UINT64 Field); + + // Get specific read-only fields. + static UINT64 GetOpcode(UINT64 instruction); // 4bit opcode + static UINT64 GetX(UINT64 instruction); // 1bit opcode extension + static UINT64 GetX3(UINT64 instruction); // 3bit opcode extension + static UINT64 GetX6(UINT64 instruction); // 6bit opcode extension + + // Get/set specific fields. + static UINT64 GetImm7a(UINT64 instruction); + static UINT64 SetImm7a(UINT64 instruction, UINT64 imm7a); + static UINT64 GetImm13c(UINT64 instruction); + static UINT64 SetImm13c(UINT64 instruction, UINT64 imm13c); + static UINT64 GetSignBit(UINT64 instruction); + static UINT64 SetSignBit(UINT64 instruction, UINT64 signBit); + static UINT64 GetImm20a(UINT64 instruction); + static UINT64 SetImm20a(UINT64 instruction, UINT64 imm20a); + static UINT64 GetImm20b(UINT64 instruction); + static UINT64 SetImm20b(UINT64 instruction, UINT64 imm20b); + + static UINT64 SignExtend(UINT64 Value, UINT64 Offset); + + BOOL IsMovlGp() const; + + VOID SetInst(BYTE Slot, BYTE nInst); + VOID SetInst0(BYTE nInst); + VOID SetInst1(BYTE nInst); + VOID SetInst2(BYTE nInst); + VOID SetData(BYTE Slot, UINT64 nData); + VOID SetData0(UINT64 nData); + VOID SetData1(UINT64 nData); + VOID SetData2(UINT64 nData); + BOOL SetNop(BYTE Slot); + BOOL SetNop0(); + BOOL SetNop1(); + BOOL SetNop2(); + + public: + BOOL IsBrl() const; + VOID SetBrl(); + VOID SetBrl(UINT64 target); + UINT64 GetBrlTarget() const; + VOID SetBrlTarget(UINT64 target); + VOID SetBrlImm(UINT64 imm); + UINT64 GetBrlImm() const; + + UINT64 GetMovlGp() const; + VOID SetMovlGp(UINT64 gp); + + VOID SetStop(); + + UINT Copy(_Out_ DETOUR_IA64_BUNDLE *pDst, _Inout_opt_ DETOUR_IA64_BUNDLE* pBundleExtra = NULL) const; +}; +#endif // DETOURS_IA64 + +#ifdef DETOURS_ARM + +#define DETOURS_PFUNC_TO_PBYTE(p) ((PBYTE)(((ULONG_PTR)(p)) & ~(ULONG_PTR)1)) +#define DETOURS_PBYTE_TO_PFUNC(p) ((PBYTE)(((ULONG_PTR)(p)) | (ULONG_PTR)1)) + +#endif // DETOURS_ARM + +////////////////////////////////////////////////////////////////////////////// + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#define DETOUR_OFFLINE_LIBRARY(x) \ +PVOID WINAPI DetourCopyInstruction##x(_In_opt_ PVOID pDst, \ + _Inout_opt_ PVOID *ppDstPool, \ + _In_ PVOID pSrc, \ + _Out_opt_ PVOID *ppTarget, \ + _Out_opt_ LONG *plExtra); \ + \ +BOOL WINAPI DetourSetCodeModule##x(_In_ HMODULE hModule, \ + _In_ BOOL fLimitReferencesToModule); \ + +DETOUR_OFFLINE_LIBRARY(X86) +DETOUR_OFFLINE_LIBRARY(X64) +DETOUR_OFFLINE_LIBRARY(ARM) +DETOUR_OFFLINE_LIBRARY(ARM64) +DETOUR_OFFLINE_LIBRARY(IA64) + +#undef DETOUR_OFFLINE_LIBRARY + +////////////////////////////////////////////////////////////////////////////// +// +// Helpers for manipulating page protection. +// + +_Success_(return != FALSE) +BOOL WINAPI DetourVirtualProtectSameExecuteEx(_In_ HANDLE hProcess, + _In_ PVOID pAddress, + _In_ SIZE_T nSize, + _In_ DWORD dwNewProtect, + _Out_ PDWORD pdwOldProtect); + +_Success_(return != FALSE) +BOOL WINAPI DetourVirtualProtectSameExecute(_In_ PVOID pAddress, + _In_ SIZE_T nSize, + _In_ DWORD dwNewProtect, + _Out_ PDWORD pdwOldProtect); +#ifdef __cplusplus +} +#endif // __cplusplus + +////////////////////////////////////////////////////////////////////////////// + +#define MM_ALLOCATION_GRANULARITY 0x10000 + +////////////////////////////////////////////////////////////////////////////// + +#endif // DETOURS_INTERNAL +#endif // __cplusplus + +#endif // _DETOURS_H_ +// +//////////////////////////////////////////////////////////////// End of File. diff --git a/H2Codez/Detours/detver.h b/H2Codez/util/Detours/detver.h similarity index 100% rename from H2Codez/Detours/detver.h rename to H2Codez/util/Detours/detver.h diff --git a/H2Codez/Detours/disasm.cpp b/H2Codez/util/Detours/disasm.cpp similarity index 100% rename from H2Codez/Detours/disasm.cpp rename to H2Codez/util/Detours/disasm.cpp diff --git a/H2Codez/Detours/disolx86.cpp b/H2Codez/util/Detours/disolx86.cpp similarity index 100% rename from H2Codez/Detours/disolx86.cpp rename to H2Codez/util/Detours/disolx86.cpp diff --git a/H2Codez/Detours/image.cpp b/H2Codez/util/Detours/image.cpp similarity index 100% rename from H2Codez/Detours/image.cpp rename to H2Codez/util/Detours/image.cpp diff --git a/H2Codez/Detours/modules.cpp b/H2Codez/util/Detours/modules.cpp similarity index 100% rename from H2Codez/Detours/modules.cpp rename to H2Codez/util/Detours/modules.cpp diff --git a/H2Codez/Logs.cpp b/H2Codez/util/Logs.cpp similarity index 90% rename from H2Codez/Logs.cpp rename to H2Codez/util/Logs.cpp index 9cd349b..155074f 100644 --- a/H2Codez/Logs.cpp +++ b/H2Codez/util/Logs.cpp @@ -1,60 +1,58 @@ -#include "stdafx.h" - - - -Logs::Logs(char* filename) -{ - - file.open(filename); //open file -} - - -void Logs::WriteLog(const char* line, ...) -{ - - SYSTEMTIME tt; -GetLocalTime(&tt); - - char buf[2048]; - va_list myarg; - - //Creating the buffer - va_start(myarg,line); - vsnprintf(buf,2048,line,myarg); - va_end(myarg); -#if _DEBUG - // print to console - printf("Logs: %s\n", buf); -#endif - - //Lets now Write the buffer to our opened File - - file< -inline T verify_output(T output, const char *expression, const char *func_name, const char* file, const int line) -{ - if (!output) { - pLog.WriteLog("'%s' failed in '%s' at '%s:%d'!", func_name, expression, file, line); - DWORD last_error = GetLastError(); - if (last_error) - { - LPWSTR messageBuffer = NULL; - size_t size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, last_error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, NULL); - if (size) { - pLog.WriteLog("Last error: '%ws'", messageBuffer); - LocalFree(messageBuffer); - } else { - pLog.WriteLog("Converting error %d to string failed!", last_error); - } - SetLastError(0); - } - } - return output; -} -#define LOG_CHECK(expression) \ +#pragma once +#include "..\stdafx.h" +using namespace std; + +class Logs +{ +public: + Logs(char* filename); //Constructor that creates and sets the Log name + void Exit(); //close file + void WriteLog(const char* line, ...); //Write to Log File + +private: + ofstream file; + +}; + +namespace Debug +{ + void Start_Console();///AllocConsole +}; +extern Logs pLog; +extern Logs H2PCTool; + + +template +inline T verify_output(T output, const char *expression, const char *func_name, const char* file, const int line) +{ + if (!output) { + pLog.WriteLog("'%s' failed in '%s' at '%s:%d'!", func_name, expression, file, line); + DWORD last_error = GetLastError(); + if (last_error) + { + LPWSTR messageBuffer = NULL; + size_t size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, last_error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, NULL); + if (size) { + pLog.WriteLog("Last error: '%ws'", messageBuffer); + LocalFree(messageBuffer); + } else { + pLog.WriteLog("Converting error %d to string failed!", last_error); + } + SetLastError(0); + } + } + return output; +} +#define LOG_CHECK(expression) \ verify_output(expression, #expression, __FUNCTION__, __FILE__, __LINE__) \ No newline at end of file diff --git a/H2Codez/util/Patches.h b/H2Codez/util/Patches.h new file mode 100644 index 0000000..9d06ea2 --- /dev/null +++ b/H2Codez/util/Patches.h @@ -0,0 +1,146 @@ +#pragma once + +/* + Writes `numBytes` bytes from `patch` to `destAddress` +*/ +inline void WriteBytes(void* destAddress, void *patch, DWORD numBytes) +{ + DWORD OldProtection; + + VirtualProtect(destAddress, numBytes, PAGE_EXECUTE_READWRITE, &OldProtection); + memcpy(destAddress, patch, numBytes); + VirtualProtect(destAddress, numBytes, OldProtection, NULL); + + FlushInstructionCache(GetCurrentProcess(), destAddress, numBytes); +} + +/* + Writes `numBytes` bytes from `patch` to `destAddress` +*/ +inline void WriteBytes(DWORD destAddress, void *patch, DWORD numBytes) +{ + WriteBytes(reinterpret_cast(destAddress), patch, numBytes); +} + +/* + Writes data to memory at address +*/ +template +inline void WriteValue(DWORD address, value_type data) +{ + WriteBytes(address, &data, sizeof(data)); +} + + + + +/* + Writes pointer to memory address +*/ +inline void WritePointer(DWORD offset, void *ptr) { + WriteValue(offset, ptr); +} + +/* + Writes pointer to memory address +*/ +inline void WritePointer(DWORD offset, const void *ptr) { + WriteValue(offset, ptr); +} + + + + +/* + Write a block of `len` of nops at `address` +*/ +inline void NopFill(const DWORD address, int len) +{ + BYTE *nop_fill = new BYTE[len]; + memset(nop_fill, 0x90, len); + WriteBytes(address, nop_fill, len); + + delete[] nop_fill; +} + +/* + Write a block of `len` of nops at `address` +*/ +inline void NopFill(const void *address, int len) +{ + NopFill(reinterpret_cast(address), len); +} + + + +/* + Patches an existing function call +*/ +inline void PatchCall(DWORD call_addr, DWORD new_function_ptr) { + DWORD callRelative = new_function_ptr - (call_addr + 5); + WriteValue(call_addr + 1, reinterpret_cast(callRelative)); +} + +/* + Patches an existing function call +*/ +inline void PatchCall(DWORD call_addr, void *new_function_ptr) +{ + PatchCall(call_addr, reinterpret_cast(new_function_ptr)); +} + + + +/* + Write relative jump at `address` to `target_addr` +*/ +inline void WriteJmp(DWORD call_addr, DWORD target_addr) +{ + BYTE call_patch[1] = { 0xE9 }; + WriteBytes(call_addr, call_patch, 1); + PatchCall(call_addr, target_addr); +} + +/* + Write relative jump at `address` to `target_addr` +*/ +inline void WriteJmp(DWORD address, void *target_addr) +{ + WriteJmp(address, reinterpret_cast(target_addr)); +} + +/* + Write relative jump at `address` to `target_addr` +*/ +inline void WriteJmp(void *address, void *target_addr) +{ + WriteJmp(reinterpret_cast(address), reinterpret_cast(target_addr)); +} + + + +/* + Write call to `function_ptr` at `address` +*/ +inline void WriteCall(DWORD address, DWORD function_ptr) +{ + BYTE call_patch[1] = { 0xE8 }; + WriteBytes(address, call_patch, 1); + PatchCall(address, function_ptr); +} + +/* + Write call to `function_ptr` at `address` +*/ +inline void WriteCall(DWORD address, void *function_ptr) +{ + WriteCall(address, reinterpret_cast(function_ptr)); +} + +/* + Write call to `function_ptr` at `address` +*/ +inline void WriteCall(void *address, void *function_ptr) +{ + WriteCall(reinterpret_cast(address), reinterpret_cast(function_ptr)); +} diff --git a/H2Codez/RingBuffer.h b/H2Codez/util/RingBuffer.h similarity index 100% rename from H2Codez/RingBuffer.h rename to H2Codez/util/RingBuffer.h diff --git a/H2Codez/Settings.cpp b/H2Codez/util/Settings.cpp similarity index 100% rename from H2Codez/Settings.cpp rename to H2Codez/util/Settings.cpp diff --git a/H2Codez/Settings.h b/H2Codez/util/Settings.h similarity index 100% rename from H2Codez/Settings.h rename to H2Codez/util/Settings.h