Advertisement
Guest User

Untitled

a guest
Oct 27th, 2013
99
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
D 9.04 KB | None | 0 0
  1. module ScriptHooks;
  2.  
  3. private import ScriptClasses;
  4. private import IndentedStreamWriter;
  5. private import std.c.stdlib;
  6. private import std.c.string;
  7.  
  8. alias HookType function(void* obj, void* result, ubyte* args) HookFunction;
  9. alias extern(Windows) void function(ScriptStackFrame* stack, void* result, ScriptFunction func) CleanupStack;
  10. // These are __thiscall, but, as D doesn't support __thiscall, they are declared
  11. // as __cdecl, and an assembly stub is used to pass the this argument in ECX,
  12. // and push the arguments in right to left order.
  13. alias extern(C++) void function(ScriptStackFrame* stack, void* result) NativeFunction;
  14. alias extern(C++) void function(ScriptStackFrame* stack, void* result, ScriptFunction func) CallFunction;
  15.  
  16. public struct ScriptStackFrame
  17. {
  18. private:
  19.     byte __padding__[0x10];
  20.  
  21.     ScriptStruct* mNode;
  22.     ScriptObject* mObject;
  23.     ubyte* mCode;
  24.     ubyte* mLocals;
  25.  
  26.     ScriptStackFrame* mPreviousFrame;
  27.  
  28. public:
  29.     @property
  30.     {
  31.         auto ref ScriptStruct* Node() { return mNode; }
  32.         auto ref ScriptObject* ParentObject() { return mObject; }
  33.         auto ref ubyte* Code() { return mCode; }
  34.         auto ref ubyte* Locals() { return mLocals; }
  35.         auto ref ScriptStackFrame* PreviousFrame() { return mPreviousFrame; }
  36.     }
  37. }
  38.  
  39. public enum HookType
  40. {
  41.     Continue,
  42.     Block,
  43. }
  44.  
  45. public struct HookInfo
  46. {
  47. private:
  48.     HookFunction mFunctionHook;
  49.     ScriptFunction mHookTarget;
  50.     NativeFunction mOriginalFunction;
  51.     int[] mArgumentSizes;
  52.     int mStackSize;
  53.  
  54. public:
  55.     @property
  56.     {
  57.         auto ref HookFunction FunctionHook() { return mFunctionHook; }
  58.         auto ref ScriptFunction HookTarget() { return mHookTarget; }
  59.         auto ref NativeFunction OriginalFunction() { return mOriginalFunction; }
  60.         auto ref int[] ArgumentSizes() { return mArgumentSizes; }
  61.         auto ref int StackSize() { return mStackSize; }
  62.     }
  63. }
  64. version(D_InlineAsm_X86)
  65. {
  66. private:
  67.     static __gshared HookInfo[] mHookArray;
  68.  
  69.     static __gshared NativeFunction* mNativeArray;
  70.     static __gshared NativeFunction mOriginalVirtualFunction;
  71.     static __gshared CleanupStack mCleanupStack;
  72.     static __gshared CallFunction mCallFunction;
  73.  
  74. public:
  75.     @property
  76.     {
  77.         final static auto ref NativeFunction* NativeArray() { return mNativeArray; }
  78.         final static auto ref CleanupStack CleanupStackPtr() { return mCleanupStack; }
  79.         final static auto ref CallFunction CallFunctionPtr() { return mCallFunction; }
  80.     }
  81.  
  82.     static extern(C) HookType CallHook(HookFunction func, ScriptObject* obj, int paramSize, void* result, byte* funcArgs)
  83.     {
  84.         asm
  85.         {
  86.             naked;
  87.  
  88.             push EBP;
  89.             mov EBP, ESP;
  90.             push EDX;
  91.             push ECX;
  92.  
  93.             mov ECX, funcArgs;
  94.             add ECX, paramSize;
  95.  
  96.             mov EDX, funcArgs;
  97.  
  98.             cmp EDX, ECX;
  99.             je endLoop;
  100.  
  101.     pushLoop:
  102.             push dword ptr [EDX];
  103.             add EDX, 4;
  104.  
  105.             cmp EDX, ECX;
  106.             jl pushLoop;
  107.  
  108.     endLoop:
  109.             push result;
  110.             push obj;
  111.  
  112.             call func;
  113.             add ESP, 8;
  114.             add ESP, paramSize;
  115.  
  116.             pop ECX;
  117.             pop EDX;
  118.             pop EBP;
  119.  
  120.             ret;
  121.         }
  122.     }
  123.  
  124.     static size_t** GetEBP()
  125.     {
  126.         asm
  127.         {
  128.             naked;
  129.             mov EAX, EBP;
  130.             ret;
  131.         }
  132.     }
  133.  
  134.     static void HookThunk()
  135.     {
  136.         asm
  137.         {
  138.             naked;
  139.  
  140.             push EBP;
  141.             mov EBP, ESP;
  142.  
  143.             push dword ptr [EBP+0xC];
  144.             push dword ptr [EBP+0x8];
  145.             push dword ptr [EBP+0x4];
  146.             push ECX;
  147.             call HookHandler;
  148.             add ESP, 0x10;
  149.  
  150.             pop EBP;
  151.            
  152.             ret 0x8;
  153.         }
  154.     }
  155.  
  156.     export extern(C) static void HookHandler(ScriptObject thisPtr, size_t retAddr, ScriptStackFrame* stack, void* result)
  157.     {
  158.         size_t func;
  159.         //size_t funcPtr = cast(size_t)mCallFunction.funcptr;
  160.         //size_t mPtr = cast(size_t)mCallFunction.ptr;
  161.         size_t mmcallfunc = cast(size_t)mCallFunction;
  162.         if (retAddr >= cast(size_t)mCallFunction && retAddr <= cast(size_t)mCallFunction + 0x100)
  163.         {
  164.             //lea ebp, [esp-404] in CallFunction
  165.             func = *cast(size_t*)(**GetEBP() + 0x404 + 0x10); //3rd arg of CallFunction
  166.         }
  167.         else //ProcessEvent
  168.         {
  169.             //OutputLog( "ProcessEvent: 0x%X\n", ret_addr );
  170.             func = *cast(size_t*)(**GetEBP() + 0x8); //1st arg of ProcessEvent
  171.         }
  172.  
  173.         ubyte* origCode = stack.Code;
  174.         for (uint i = 0; i < mHookArray.length; i++)
  175.         {
  176.             if (func == cast(size_t)cast(void*)mHookArray[i].HookTarget)
  177.             {
  178.                 int argOffset = mHookArray[i].StackSize;
  179.                 byte* funcArgs = cast(byte*)malloc(argOffset);
  180.  
  181.                 if (retAddr >= cast(size_t)mCallFunction && retAddr <= cast(size_t)mCallFunction + 0x100)
  182.                 {
  183.                     for (uint paramNum = 0; *stack.Code != 0x16 && paramNum < mHookArray[i].ArgumentSizes.length; paramNum++) //copy args to buffer, respecting LIFO
  184.                     {
  185.                         argOffset -= mHookArray[i].ArgumentSizes[paramNum];
  186.                        
  187.                         ScriptObject *po = stack.ParentObject;
  188.                         NativeFunction nFunc = mNativeArray[*stack.Code++];
  189.                         byte* retLocation = funcArgs + argOffset;
  190.                         asm
  191.                         {
  192.                             mov ECX, po;
  193.                             push retLocation;
  194.                             push stack;
  195.                             call nFunc;
  196.                         }
  197.                         //mNativeArray[*stack.Code++](stack.ParentObject, stack, funcArgs + argOffset);
  198.                     }
  199.  
  200.                     //OutputLog( "Function: %s\n", hook_array[ i ].hook_target->GetName() );
  201.                     if(CallHook(mHookArray[i].FunctionHook, stack.ParentObject, mHookArray[i].StackSize, result, funcArgs) == HookType.Block)
  202.                     {
  203.                         mCleanupStack(stack, result, mHookArray[i].HookTarget);
  204.                         free(funcArgs);
  205.                         return;
  206.                     }
  207.                    
  208.                     free(funcArgs);
  209.                     stack.Code = origCode;
  210.                    
  211.                     if(mHookArray[i].OriginalFunction)
  212.                     {
  213.                         mHookArray[i].HookTarget.Function = mHookArray[i].OriginalFunction;
  214.  
  215.                         ScriptFunction ht = mHookArray[i].HookTarget;
  216.                         asm
  217.                         {
  218.                             mov ECX, thisPtr;
  219.                             push ht;
  220.                             push result;
  221.                             push stack;
  222.                             call mCallFunction;
  223.                         }
  224.                         //mCallFunction(thisPtr, stack, result, mHookArray[i].HookTarget);
  225.                         mHookArray[i].HookTarget.Function = &HookThunk;
  226.                     }
  227.                     else
  228.                     {
  229.                         mHookArray[i].HookTarget.FunctionFlags.UnsetFlag(ScriptFunctionFlags.Native);
  230.                        
  231.                         ScriptFunction ht = mHookArray[i].HookTarget;
  232.                         asm
  233.                         {
  234.                             mov ECX, thisPtr;
  235.                             push ht;
  236.                             push result;
  237.                             push stack;
  238.                             call mCallFunction;
  239.                         }
  240.                         //mCallFunction(thisPtr, stack, result, mHookArray[i].HookTarget);
  241.                         mHookArray[i].HookTarget.FunctionFlags.SetFlag(ScriptFunctionFlags.Native);
  242.                     }
  243.                 }
  244.                 else
  245.                 {
  246.                     ubyte* params = *cast(ubyte**)(**GetEBP() + 0xC);
  247.                     int paramsOffset = 0;
  248.  
  249.                     for (uint paramNum = 0; paramNum < mHookArray[i].ArgumentSizes.length; paramNum++) //copy args to buffer, respecting LIFO
  250.                     {
  251.                         argOffset -= mHookArray[i].ArgumentSizes[paramNum];
  252.  
  253.                         memcpy(funcArgs + argOffset, params + paramsOffset, mHookArray[i].ArgumentSizes[paramNum]);
  254.  
  255.                         paramsOffset += mHookArray[i].ArgumentSizes[paramNum];
  256.                     }
  257.  
  258.                     if(CallHook(mHookArray[i].FunctionHook, stack.ParentObject, mHookArray[i].StackSize, result, funcArgs) == HookType.Block)
  259.                     {
  260.                         free(funcArgs);
  261.                         return;
  262.                     }
  263.                    
  264.                     free(funcArgs);
  265.                    
  266.                     if(mHookArray[i].OriginalFunction)
  267.                     {
  268.                         mHookArray[i].HookTarget.Function = mHookArray[i].OriginalFunction;
  269.                         thisPtr.ProcessEvent(mHookArray[i].HookTarget, params, result);
  270.                         mHookArray[i].HookTarget.Function = &HookThunk;
  271.                     }
  272.                     else
  273.                     {
  274.                         mHookArray[i].HookTarget.FunctionFlags.UnsetFlag(ScriptFunctionFlags.Native);
  275.                         thisPtr.ProcessEvent(mHookArray[i].HookTarget, params, result);
  276.                         mHookArray[i].HookTarget.FunctionFlags.SetFlag(ScriptFunctionFlags.Native);
  277.                     }
  278.                 }
  279.                
  280.                 return;
  281.             }
  282.  
  283.         }
  284.     }
  285.  
  286.     static void AddHook(immutable string functionName, void* hook)
  287.     {
  288.         ScriptFunction scriptFunction = ScriptObject.Find!(ScriptFunction)(functionName);
  289.         IndentedStreamWriter wtr = new IndentedStreamWriter("TribesAscendSDK-Error.txt");
  290.  
  291.         if(scriptFunction)
  292.             AddHook(scriptFunction, hook);
  293.         else
  294.             wtr.WriteLine( "Failed to find function %s.", functionName );
  295.     }
  296.  
  297.     static void AddHook(ScriptFunction scriptFunction, void* hook)
  298.     {
  299.         HookInfo newHook;
  300.        
  301.         newHook.FunctionHook = cast(HookFunction)hook;
  302.         newHook.HookTarget = scriptFunction;
  303.        
  304.         newHook.StackSize = 0;
  305.        
  306.         if(scriptFunction.FunctionFlags.HasFlag(ScriptFunctionFlags.Native))
  307.         {
  308.             newHook.OriginalFunction = cast(NativeFunction)scriptFunction.Function;
  309.         }
  310.         else
  311.         {
  312.             newHook.OriginalFunction = null;
  313.         }
  314.  
  315.        
  316.         for(ScriptProperty scriptProperty = cast(ScriptProperty)scriptFunction.Children; scriptProperty; scriptProperty = cast(ScriptProperty)scriptProperty.Next)
  317.         {
  318.             if(scriptProperty.PropertyFlags.HasFlag(ScriptPropertyFlags.Param))
  319.             {
  320.                 //OutputLog( "Arg %s size %i\n", script_property->GetName(), script_property->element_size );
  321.                 newHook.ArgumentSizes ~= scriptProperty.ElementSize;
  322.                 newHook.StackSize += scriptProperty.ElementSize;
  323.             }
  324.         }
  325.        
  326.         newHook.StackSize = ((newHook.StackSize >> 2) + ((newHook.StackSize & 0x03) != 0)) << 2;
  327.        
  328.         mHookArray ~= newHook;
  329.        
  330.         scriptFunction.Function = &HookThunk;
  331.         scriptFunction.FunctionFlags.SetFlag(ScriptFunctionFlags.Native);
  332.  
  333.         //OutputLog( "Hooked function %s (0x%X) (args %i)\n\n", function_name, script_function, new_hook.stack_size );
  334.     }
  335. }
  336. else
  337. {
  338.     static assert(0, "Only x86 is supported!");
  339. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement