Advertisement
Shynd

Executor.cs

Mar 7th, 2011
540
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 14.98 KB | None | 0 0
  1. using System;
  2. using System.Text;
  3. using System.Threading;
  4. using System.Diagnostics;
  5. using System.Security.Cryptography;
  6. using System.Security.AccessControl;
  7. using System.Security.Principal;
  8.  
  9. using Magic;
  10.  
  11. namespace EndScene
  12. {
  13.     public sealed class Executor : IDisposable
  14.     {
  15.         #region Class Members
  16.  
  17.         public BlackMagic Memory { get; private set; }
  18.  
  19.         private object thisLock = new object();
  20.  
  21.         private Random m_Random;
  22.  
  23.         private bool m_ContinuousExecution = false;
  24.         private bool m_FirstExecution = false;
  25.  
  26.         private byte[] m_ClearBytes = new byte[0x1000];
  27.         private uint m_OrigEndScene;
  28.         private uint m_EndSceneDetour;
  29.         private uint m_InjectedCode;
  30.  
  31.         private uint m_DataPtr;
  32.         private uint m_ReturnedDataPtr;
  33.  
  34.         private uint m_InjectionWaitingHandlePtr;
  35.         private string m_InjectionWaitingEventName;
  36.         private EventWaitHandle m_InjectionWaitingEvent;
  37.  
  38.         private uint m_InjectionContinueHandlePtr;
  39.         private string m_InjectionContinueEventName;
  40.         private EventWaitHandle m_InjectionContinueEvent;
  41.  
  42.         private uint m_InjectionFinishedHandlePtr;
  43.         private string m_InjectionFinishedEventName;
  44.         private EventWaitHandle m_InjectionFinishedEvent;
  45.  
  46.         private UIntPtr WaitForSingleObject, CreateEventA, ResetEvent, SetEvent;
  47.  
  48.         #endregion
  49.  
  50.  
  51.         #region Class Properties
  52.  
  53.         public bool IsOpen { get { return (Memory != null && Memory.IsProcessOpen && Memory.IsThreadOpen); } }
  54.         public bool IsInitialized { get; private set; }
  55.  
  56.         public uint DataPointer { get { return m_DataPtr; } }
  57.         public uint ReturnPointer { get { return m_ReturnedDataPtr; } }
  58.         public uint InjectCodePointer { get { return m_InjectedCode; } }
  59.  
  60.         #endregion
  61.  
  62.  
  63.         #region Constructor
  64.  
  65.         public Executor(BlackMagic Memory, uint EndSceneProc)
  66.         {
  67.             if (Memory == null || Memory.IsProcessOpen == false)
  68.                 throw new ArgumentNullException("Memory object passed to Executor constructor was invalid.");
  69.  
  70.             if (EndSceneProc == 0 || Memory.ReadUInt(EndSceneProc) == 0)
  71.                 throw new ArgumentNullException("EndSceneProc passed to Executor constructor was invalid.");
  72.  
  73.             this.Memory = Memory;
  74.             this.Memory.Asm.SetMemorySize(0x10000);
  75.             m_OrigEndScene = EndSceneProc;
  76.  
  77.             if (this.Memory.IsThreadOpen == false)
  78.                 this.Memory.OpenThread();
  79.  
  80.             byte[] Seed = new byte[4];
  81.             RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
  82.             rng.GetNonZeroBytes(Seed);
  83.  
  84.             m_Random = new Random(BitConverter.ToInt32(Seed, 0));
  85.  
  86.             bool bCreated = false;
  87.             string CurrentUserName = Environment.UserDomainName + "\\" + Environment.UserName;
  88.  
  89.             EventWaitHandleSecurity EventSecurity = new EventWaitHandleSecurity();
  90.             EventWaitHandleAccessRule FullAccessRule = new EventWaitHandleAccessRule(
  91.                 CurrentUserName,
  92.                 EventWaitHandleRights.FullControl,
  93.                 AccessControlType.Allow
  94.             );
  95.             EventSecurity.AddAccessRule(FullAccessRule);
  96.  
  97.             m_InjectionWaitingEventName = @"Global\" + GetRandomString(16);
  98.             m_InjectionWaitingEvent = new EventWaitHandle(false, EventResetMode.ManualReset, m_InjectionWaitingEventName, out bCreated, EventSecurity);
  99.             if (!bCreated)
  100.                 throw new Exception("You should never see this message, but the event was opened instead of created!  That's bad!");
  101.  
  102.             m_InjectionContinueEventName = @"Global\" + GetRandomString(16);
  103.             m_InjectionContinueEvent = new EventWaitHandle(false, EventResetMode.AutoReset, m_InjectionContinueEventName, out bCreated, EventSecurity);
  104.             if (!bCreated)
  105.                 throw new Exception("You should never see this message, but the event was opened instead of created!  That's bad!");
  106.  
  107.             m_InjectionFinishedEventName = @"Global\" + GetRandomString(16);
  108.             m_InjectionFinishedEvent = new EventWaitHandle(false, EventResetMode.AutoReset, m_InjectionFinishedEventName, out bCreated, EventSecurity);
  109.             if (!bCreated)
  110.                 throw new Exception("You should never see this message, but the event was opened instead of created!  That's bad!");
  111.  
  112.             InitializeDetour();
  113.  
  114.             Clear();
  115.             IsInitialized = true;
  116.         }
  117.  
  118.         public Executor(int ProcessId, uint EndSceneProc) : this(new BlackMagic(ProcessId), EndSceneProc) { }
  119.  
  120.         #endregion
  121.  
  122.  
  123.         #region Public Methods
  124.  
  125.         public void BeginExecute()
  126.         {
  127.             if (m_ContinuousExecution == true)
  128.                 EndExecute();
  129.  
  130.             m_ContinuousExecution = true;
  131.             m_FirstExecution = true;
  132.         }
  133.  
  134.         public void EndExecute()
  135.         {
  136.             m_ContinuousExecution = false;
  137.             m_InjectionWaitingEvent.Reset();
  138.             m_InjectionContinueEvent.Set();
  139.  
  140.             Memory.WriteBytes(m_InjectedCode, m_ClearBytes);
  141.         }
  142.  
  143.         public void Execute()
  144.         {
  145.             if (!IsOpen || !IsInitialized)
  146.                 throw new Exception("Cannot execute code while process is not opened and/or Executor is not initialized.");
  147.  
  148.             lock (thisLock)
  149.             {
  150.                 Memory.Asm.Inject(m_InjectedCode);
  151.  
  152.                 m_InjectionWaitingEvent.Set();
  153.  
  154.                 if (m_ContinuousExecution == true)
  155.                     if (m_FirstExecution == false)
  156.                         m_InjectionContinueEvent.Set();
  157.                     else
  158.                         m_FirstExecution = false;
  159.  
  160.                 //wait for up to 10 seconds for execution to complete; helps detect foul-ups or infinite loops caused by incorrect injection
  161.                 if (m_InjectionFinishedEvent.WaitOne(10000, false) == false)
  162.                     throw new Exception("Process must have frozen or gotten out of sync; InjectionFinishedEvent was never fired.");
  163.  
  164.  
  165.                 //clean up if it's a one-time injection
  166.                 if (m_ContinuousExecution == false)
  167.                 {
  168.                     m_InjectionWaitingEvent.Reset();
  169.                     m_InjectionContinueEvent.Set();
  170.  
  171.                     Memory.WriteBytes(m_InjectedCode, m_ClearBytes);
  172.                 }
  173.             }
  174.         }
  175.  
  176.         public void Clear()
  177.         {
  178.             Memory.Asm.Clear();
  179.         }
  180.  
  181.         public void AddLine(string szLine)
  182.         {
  183.             Memory.Asm.AddLine(szLine);
  184.         }
  185.  
  186.         public void AddLine(string szFormatString, params object[] args)
  187.         {
  188.             Memory.Asm.AddLine(szFormatString, args);
  189.         }
  190.  
  191.         #endregion
  192.  
  193.  
  194.         #region Private Methods
  195.  
  196.         private string GetRandomString(int minLength, int maxLength)
  197.         {
  198.             char[] CHARPOOL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".ToCharArray();
  199.             StringBuilder l_sRet;
  200.  
  201.             if (minLength < maxLength)
  202.                 l_sRet = new StringBuilder(this.m_Random.Next(minLength, maxLength));
  203.             else
  204.                 l_sRet = new StringBuilder(minLength);
  205.  
  206.             for (int i = 0; i < l_sRet.Capacity; i++)
  207.                 l_sRet.Append(CHARPOOL[(int)(this.m_Random.NextDouble() * (CHARPOOL.Length - 1))]);
  208.  
  209.             return l_sRet.ToString();
  210.         }
  211.  
  212.         private string GetRandomString(int Length)
  213.         {
  214.             return GetRandomString(Length, Length);
  215.         }
  216.  
  217.         private string GetRandomString()
  218.         {
  219.             return GetRandomString(64, 64);
  220.         }
  221.  
  222.         private void InitializeDetour()
  223.         {
  224.             if (!IsOpen)
  225.                 throw new Exception("Process is not open for memory manipulation.");
  226.  
  227.             int l_PageSize = m_ClearBytes.Length;
  228.  
  229.             if (Memory.GetModule("d3d9.dll") == null)
  230.                 throw new Exception("Executor can only be used on processes that use DirectX9.");
  231.  
  232.  
  233.  
  234.             //find the addresses of exports we'll need to call
  235.             UIntPtr k32 = Imports.GetModuleHandle("kernel32.dll");
  236.             if (k32 == UIntPtr.Zero)
  237.                 throw new Exception("Could not get handle to kernel32.dll");
  238.  
  239.             WaitForSingleObject = Imports.GetProcAddress(k32, "WaitForSingleObject");
  240.             if (WaitForSingleObject == UIntPtr.Zero)
  241.                 throw new Exception("Could not get proc address of WaitForSingleObject.");
  242.  
  243.             CreateEventA = Imports.GetProcAddress(k32, "CreateEventA");
  244.             if (CreateEventA == UIntPtr.Zero)
  245.                 throw new Exception("Could not get proc address of CreateEventA.");
  246.  
  247.             ResetEvent = Imports.GetProcAddress(k32, "ResetEvent");
  248.             if (ResetEvent == UIntPtr.Zero)
  249.                 throw new Exception("Could not get proc address of ResetEvent.");
  250.  
  251.             SetEvent = Imports.GetProcAddress(k32, "SetEvent");
  252.             if (SetEvent == UIntPtr.Zero)
  253.                 throw new Exception("Could not get proc address of SetEvent.");
  254.  
  255.  
  256.  
  257.             //allocate all necessary memory
  258.             uint l_EventStub = Memory.AllocateMemory(l_PageSize, MemoryAllocType.MEM_COMMIT, MemoryProtectType.PAGE_EXECUTE);
  259.             if (l_EventStub == 0)
  260.                 throw new Exception("Could not allocate memory in target process for event stub.");
  261.  
  262.             uint l_InjectionWaitingEventNamePtr = Memory.AllocateMemory(l_PageSize, MemoryAllocType.MEM_COMMIT, MemoryProtectType.PAGE_READWRITE);
  263.             if (l_InjectionWaitingEventNamePtr == 0)
  264.                 throw new Exception("Could not allocate memory in target process for event names.");
  265.  
  266.  
  267.  
  268.             //write names to the same block of memory with a 4 byte buffer between the three
  269.             uint l_InjectionContinueEventNamePtr = (uint)(l_InjectionWaitingEventNamePtr + m_InjectionWaitingEventName.Length + 4);
  270.             uint l_InjectionFinishedEventNamePtr = (uint)(l_InjectionContinueEventNamePtr + m_InjectionContinueEventName.Length + 4);
  271.  
  272.             if (Memory.WriteASCIIString(l_InjectionWaitingEventNamePtr, m_InjectionWaitingEventName) == false ||
  273.                 Memory.WriteASCIIString(l_InjectionContinueEventNamePtr, m_InjectionContinueEventName) == false ||
  274.                 Memory.WriteASCIIString(l_InjectionFinishedEventNamePtr, m_InjectionFinishedEventName) == false)
  275.                 throw new Exception("Could not write event names to memory.");
  276.  
  277.  
  278.  
  279.             //allocate memory for the detour, the codecave, and a section of data for us to manipulate
  280.             m_EndSceneDetour = Memory.AllocateMemory(l_PageSize, MemoryAllocType.MEM_COMMIT, MemoryProtectType.PAGE_EXECUTE);
  281.             if (m_EndSceneDetour == 0)
  282.                 throw new Exception("Could not allocate memory in target process for detour.");
  283.  
  284.             m_InjectedCode = Memory.AllocateMemory(l_PageSize, MemoryAllocType.MEM_COMMIT, MemoryProtectType.PAGE_EXECUTE_READWRITE | MemoryProtectType.PAGE_NOCACHE);
  285.             if (m_InjectedCode == 0)
  286.                 throw new Exception("Could not allocate memory in target process for injected code.");
  287.  
  288.             m_DataPtr = Memory.AllocateMemory(l_PageSize, MemoryAllocType.MEM_COMMIT, MemoryProtectType.PAGE_READWRITE);
  289.             if (m_DataPtr == 0)
  290.                 throw new Exception("Could not allocate memory in target process for injected data.");
  291.  
  292.  
  293.  
  294.             //first few bytes of our data section are accounted for
  295.             m_InjectionWaitingHandlePtr = m_DataPtr;
  296.             m_InjectionContinueHandlePtr = m_DataPtr + 4;
  297.             m_InjectionFinishedHandlePtr = m_DataPtr + 8;
  298.             m_ReturnedDataPtr = m_DataPtr + 12;
  299.  
  300.  
  301.  
  302.             //inject and execute the codecave that registers the events inside WoW.exe
  303.             bool bEventInitSuccess = InjectEventStub(
  304.                 l_EventStub,
  305.                 l_InjectionWaitingEventNamePtr,
  306.                 l_InjectionContinueEventNamePtr,
  307.                 l_InjectionFinishedEventNamePtr
  308.             );
  309.  
  310.             if (bEventInitSuccess == false)
  311.                 throw new Exception("Could not successfully set up synchronization events.");
  312.  
  313.  
  314.  
  315.             //inject the endscene detour and codecave
  316.             InjectDetour();
  317.  
  318.             Memory.FreeMemory(l_EventStub);
  319.             Memory.FreeMemory(l_InjectionWaitingEventNamePtr);
  320.         }
  321.  
  322.         private void InjectDetour()
  323.         {
  324.             //basically, this codecave will check if code has been injected and is waiting to execute,
  325.             //then call the injected code if the event has been signaled.  it then checks if it's a
  326.             //one-time injection or if it's supposed to loop (which you control using BeginExecute and
  327.             //EndExecute).  It's useful to pause execution of the game and loop through injections if
  328.             //you're doing something like enumerating all objects and calling obj->GetName on each one,
  329.             //or something like that.  Goes much faster because you don't have to wait for the next
  330.             //frame in order to get the next name, etc.
  331.            
  332.             Memory.Asm.Clear();
  333.  
  334.             Memory.Asm.AddLine("pushad");
  335.             Memory.Asm.AddLine("@CheckInjection:");
  336.             Memory.Asm.AddLine("mov eax, [{0}]", m_InjectionWaitingHandlePtr);
  337.             Memory.Asm.AddLine("push 0");
  338.             Memory.Asm.AddLine("push eax");
  339.             Memory.Asm.AddLine("call {0}", WaitForSingleObject);
  340.             Memory.Asm.AddLine("test eax, eax");
  341.             Memory.Asm.AddLine("jnz @NoInjection");
  342.  
  343.  
  344.             Memory.Asm.AddLine("@Injection:");
  345.             Memory.Asm.AddLine("call {0}", m_InjectedCode);
  346.             Memory.Asm.AddLine("mov [{0}], eax", m_ReturnedDataPtr);
  347.  
  348.             Memory.Asm.AddLine("mov eax, [{0}]", m_InjectionFinishedHandlePtr);
  349.             Memory.Asm.AddLine("push eax");
  350.             Memory.Asm.AddLine("call {0}", SetEvent);
  351.  
  352.             Memory.Asm.AddLine("mov eax, [{0}]", m_InjectionContinueHandlePtr);
  353.             Memory.Asm.AddLine("push 1000"); //wait one second
  354.             Memory.Asm.AddLine("push eax");
  355.             Memory.Asm.AddLine("call {0}", WaitForSingleObject);
  356.             Memory.Asm.AddLine("test eax, eax");
  357.             Memory.Asm.AddLine("jz @CheckInjection");
  358.  
  359.             Memory.Asm.AddLine("mov eax, [{0}]", m_InjectionWaitingHandlePtr);
  360.             Memory.Asm.AddLine("push eax");
  361.             Memory.Asm.AddLine("call {0}", ResetEvent);
  362.  
  363.  
  364.             Memory.Asm.AddLine("@NoInjection:");
  365.             Memory.Asm.AddLine("popad");
  366.             Memory.Asm.AddLine("mov edi, edi");
  367.             Memory.Asm.AddLine("push ebp");
  368.             Memory.Asm.AddLine("mov ebp, esp");
  369.             Memory.Asm.AddLine("jmp {0}", m_OrigEndScene + 5);
  370.  
  371.             if (Memory.Asm.Inject(m_EndSceneDetour) == false)
  372.                 throw new Exception("Could not assemble and inject trampoline.");
  373.  
  374.  
  375.  
  376.  
  377.             //detour endscene
  378.             Memory.Asm.Clear();
  379.             Memory.Asm.AddLine("jmp {0}", m_EndSceneDetour);
  380.             if (Memory.Asm.Inject(m_OrigEndScene) == false)
  381.                 throw new Exception("Could not assemble and inject detour.");
  382.         }
  383.  
  384.         private bool InjectEventStub(uint EventStub, uint InjectionWaitingNamePtr, uint InjectionContinueNamePtr, uint InjectionFinishedNamePtr)
  385.         {
  386.             Memory.Asm.Clear();
  387.  
  388.             Memory.Asm.AddLine("push {0}", InjectionWaitingNamePtr);
  389.             Memory.Asm.AddLine("push 0");
  390.             Memory.Asm.AddLine("push 0");
  391.             Memory.Asm.AddLine("push 0");
  392.             Memory.Asm.AddLine("call {0}", CreateEventA);
  393.             Memory.Asm.AddLine("test eax, eax");
  394.             Memory.Asm.AddLine("jz @ReturnFalse");
  395.             Memory.Asm.AddLine("mov [{0}], eax", m_InjectionWaitingHandlePtr);
  396.  
  397.             Memory.Asm.AddLine("push {0}", InjectionContinueNamePtr);
  398.             Memory.Asm.AddLine("push 0");
  399.             Memory.Asm.AddLine("push 0");
  400.             Memory.Asm.AddLine("push 0");
  401.             Memory.Asm.AddLine("call {0}", CreateEventA);
  402.             Memory.Asm.AddLine("test eax, eax");
  403.             Memory.Asm.AddLine("jz @ReturnFalse");
  404.             Memory.Asm.AddLine("mov [{0}], eax", m_InjectionContinueHandlePtr);
  405.  
  406.             Memory.Asm.AddLine("push {0}", InjectionFinishedNamePtr);
  407.             Memory.Asm.AddLine("push 0");
  408.             Memory.Asm.AddLine("push 0");
  409.             Memory.Asm.AddLine("push 0");
  410.             Memory.Asm.AddLine("call {0}", CreateEventA);
  411.             Memory.Asm.AddLine("test eax, eax");
  412.             Memory.Asm.AddLine("jz @ReturnFalse");
  413.             Memory.Asm.AddLine("mov [{0}], eax", m_InjectionFinishedHandlePtr);
  414.  
  415.             Memory.Asm.AddLine("mov eax, 1");
  416.             Memory.Asm.AddLine("retn");
  417.  
  418.             Memory.Asm.AddLine("@ReturnFalse:");
  419.             Memory.Asm.AddLine("xor eax, eax");
  420.             Memory.Asm.AddLine("retn");
  421.  
  422.             return Memory.Asm.InjectAndExecute(EventStub) == 1 ? true : false;
  423.         }
  424.  
  425.         #endregion
  426.  
  427.  
  428.         #region IDisposable Members
  429.  
  430.         public void Dispose()
  431.         {
  432.             IsInitialized = false;
  433.  
  434.             if (Memory != null)
  435.             {
  436.                 Memory.Asm.Clear();
  437.                 Memory.Asm.AddLine("mov edi, edi");
  438.                 Memory.Asm.AddLine("push ebp");
  439.                 Memory.Asm.AddLine("mov ebp, esp");
  440.                 Memory.Asm.Inject(m_OrigEndScene);
  441.  
  442.                 Memory.FreeMemory(m_EndSceneDetour);
  443.                 Memory.FreeMemory(m_InjectedCode);
  444.                 Memory.FreeMemory(m_DataPtr);
  445.             }
  446.  
  447.             m_InjectionWaitingEvent.Close();
  448.             m_InjectionContinueEvent.Close();
  449.             m_InjectionFinishedEvent.Close();
  450.         }
  451.  
  452.         #endregion
  453.     }
  454. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement