Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Text;
- using System.Threading;
- using System.Diagnostics;
- using System.Security.Cryptography;
- using System.Security.AccessControl;
- using System.Security.Principal;
- using Magic;
- namespace EndScene
- {
- public sealed class Executor : IDisposable
- {
- #region Class Members
- public BlackMagic Memory { get; private set; }
- private object thisLock = new object();
- private Random m_Random;
- private bool m_ContinuousExecution = false;
- private bool m_FirstExecution = false;
- private byte[] m_ClearBytes = new byte[0x1000];
- private uint m_OrigEndScene;
- private uint m_EndSceneDetour;
- private uint m_InjectedCode;
- private uint m_DataPtr;
- private uint m_ReturnedDataPtr;
- private uint m_InjectionWaitingHandlePtr;
- private string m_InjectionWaitingEventName;
- private EventWaitHandle m_InjectionWaitingEvent;
- private uint m_InjectionContinueHandlePtr;
- private string m_InjectionContinueEventName;
- private EventWaitHandle m_InjectionContinueEvent;
- private uint m_InjectionFinishedHandlePtr;
- private string m_InjectionFinishedEventName;
- private EventWaitHandle m_InjectionFinishedEvent;
- private UIntPtr WaitForSingleObject, CreateEventA, ResetEvent, SetEvent;
- #endregion
- #region Class Properties
- public bool IsOpen { get { return (Memory != null && Memory.IsProcessOpen && Memory.IsThreadOpen); } }
- public bool IsInitialized { get; private set; }
- public uint DataPointer { get { return m_DataPtr; } }
- public uint ReturnPointer { get { return m_ReturnedDataPtr; } }
- public uint InjectCodePointer { get { return m_InjectedCode; } }
- #endregion
- #region Constructor
- public Executor(BlackMagic Memory, uint EndSceneProc)
- {
- if (Memory == null || Memory.IsProcessOpen == false)
- throw new ArgumentNullException("Memory object passed to Executor constructor was invalid.");
- if (EndSceneProc == 0 || Memory.ReadUInt(EndSceneProc) == 0)
- throw new ArgumentNullException("EndSceneProc passed to Executor constructor was invalid.");
- this.Memory = Memory;
- this.Memory.Asm.SetMemorySize(0x10000);
- m_OrigEndScene = EndSceneProc;
- if (this.Memory.IsThreadOpen == false)
- this.Memory.OpenThread();
- byte[] Seed = new byte[4];
- RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
- rng.GetNonZeroBytes(Seed);
- m_Random = new Random(BitConverter.ToInt32(Seed, 0));
- bool bCreated = false;
- string CurrentUserName = Environment.UserDomainName + "\\" + Environment.UserName;
- EventWaitHandleSecurity EventSecurity = new EventWaitHandleSecurity();
- EventWaitHandleAccessRule FullAccessRule = new EventWaitHandleAccessRule(
- CurrentUserName,
- EventWaitHandleRights.FullControl,
- AccessControlType.Allow
- );
- EventSecurity.AddAccessRule(FullAccessRule);
- m_InjectionWaitingEventName = @"Global\" + GetRandomString(16);
- m_InjectionWaitingEvent = new EventWaitHandle(false, EventResetMode.ManualReset, m_InjectionWaitingEventName, out bCreated, EventSecurity);
- if (!bCreated)
- throw new Exception("You should never see this message, but the event was opened instead of created! That's bad!");
- m_InjectionContinueEventName = @"Global\" + GetRandomString(16);
- m_InjectionContinueEvent = new EventWaitHandle(false, EventResetMode.AutoReset, m_InjectionContinueEventName, out bCreated, EventSecurity);
- if (!bCreated)
- throw new Exception("You should never see this message, but the event was opened instead of created! That's bad!");
- m_InjectionFinishedEventName = @"Global\" + GetRandomString(16);
- m_InjectionFinishedEvent = new EventWaitHandle(false, EventResetMode.AutoReset, m_InjectionFinishedEventName, out bCreated, EventSecurity);
- if (!bCreated)
- throw new Exception("You should never see this message, but the event was opened instead of created! That's bad!");
- InitializeDetour();
- Clear();
- IsInitialized = true;
- }
- public Executor(int ProcessId, uint EndSceneProc) : this(new BlackMagic(ProcessId), EndSceneProc) { }
- #endregion
- #region Public Methods
- public void BeginExecute()
- {
- if (m_ContinuousExecution == true)
- EndExecute();
- m_ContinuousExecution = true;
- m_FirstExecution = true;
- }
- public void EndExecute()
- {
- m_ContinuousExecution = false;
- m_InjectionWaitingEvent.Reset();
- m_InjectionContinueEvent.Set();
- Memory.WriteBytes(m_InjectedCode, m_ClearBytes);
- }
- public void Execute()
- {
- if (!IsOpen || !IsInitialized)
- throw new Exception("Cannot execute code while process is not opened and/or Executor is not initialized.");
- lock (thisLock)
- {
- Memory.Asm.Inject(m_InjectedCode);
- m_InjectionWaitingEvent.Set();
- if (m_ContinuousExecution == true)
- if (m_FirstExecution == false)
- m_InjectionContinueEvent.Set();
- else
- m_FirstExecution = false;
- //wait for up to 10 seconds for execution to complete; helps detect foul-ups or infinite loops caused by incorrect injection
- if (m_InjectionFinishedEvent.WaitOne(10000, false) == false)
- throw new Exception("Process must have frozen or gotten out of sync; InjectionFinishedEvent was never fired.");
- //clean up if it's a one-time injection
- if (m_ContinuousExecution == false)
- {
- m_InjectionWaitingEvent.Reset();
- m_InjectionContinueEvent.Set();
- Memory.WriteBytes(m_InjectedCode, m_ClearBytes);
- }
- }
- }
- public void Clear()
- {
- Memory.Asm.Clear();
- }
- public void AddLine(string szLine)
- {
- Memory.Asm.AddLine(szLine);
- }
- public void AddLine(string szFormatString, params object[] args)
- {
- Memory.Asm.AddLine(szFormatString, args);
- }
- #endregion
- #region Private Methods
- private string GetRandomString(int minLength, int maxLength)
- {
- char[] CHARPOOL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".ToCharArray();
- StringBuilder l_sRet;
- if (minLength < maxLength)
- l_sRet = new StringBuilder(this.m_Random.Next(minLength, maxLength));
- else
- l_sRet = new StringBuilder(minLength);
- for (int i = 0; i < l_sRet.Capacity; i++)
- l_sRet.Append(CHARPOOL[(int)(this.m_Random.NextDouble() * (CHARPOOL.Length - 1))]);
- return l_sRet.ToString();
- }
- private string GetRandomString(int Length)
- {
- return GetRandomString(Length, Length);
- }
- private string GetRandomString()
- {
- return GetRandomString(64, 64);
- }
- private void InitializeDetour()
- {
- if (!IsOpen)
- throw new Exception("Process is not open for memory manipulation.");
- int l_PageSize = m_ClearBytes.Length;
- if (Memory.GetModule("d3d9.dll") == null)
- throw new Exception("Executor can only be used on processes that use DirectX9.");
- //find the addresses of exports we'll need to call
- UIntPtr k32 = Imports.GetModuleHandle("kernel32.dll");
- if (k32 == UIntPtr.Zero)
- throw new Exception("Could not get handle to kernel32.dll");
- WaitForSingleObject = Imports.GetProcAddress(k32, "WaitForSingleObject");
- if (WaitForSingleObject == UIntPtr.Zero)
- throw new Exception("Could not get proc address of WaitForSingleObject.");
- CreateEventA = Imports.GetProcAddress(k32, "CreateEventA");
- if (CreateEventA == UIntPtr.Zero)
- throw new Exception("Could not get proc address of CreateEventA.");
- ResetEvent = Imports.GetProcAddress(k32, "ResetEvent");
- if (ResetEvent == UIntPtr.Zero)
- throw new Exception("Could not get proc address of ResetEvent.");
- SetEvent = Imports.GetProcAddress(k32, "SetEvent");
- if (SetEvent == UIntPtr.Zero)
- throw new Exception("Could not get proc address of SetEvent.");
- //allocate all necessary memory
- uint l_EventStub = Memory.AllocateMemory(l_PageSize, MemoryAllocType.MEM_COMMIT, MemoryProtectType.PAGE_EXECUTE);
- if (l_EventStub == 0)
- throw new Exception("Could not allocate memory in target process for event stub.");
- uint l_InjectionWaitingEventNamePtr = Memory.AllocateMemory(l_PageSize, MemoryAllocType.MEM_COMMIT, MemoryProtectType.PAGE_READWRITE);
- if (l_InjectionWaitingEventNamePtr == 0)
- throw new Exception("Could not allocate memory in target process for event names.");
- //write names to the same block of memory with a 4 byte buffer between the three
- uint l_InjectionContinueEventNamePtr = (uint)(l_InjectionWaitingEventNamePtr + m_InjectionWaitingEventName.Length + 4);
- uint l_InjectionFinishedEventNamePtr = (uint)(l_InjectionContinueEventNamePtr + m_InjectionContinueEventName.Length + 4);
- if (Memory.WriteASCIIString(l_InjectionWaitingEventNamePtr, m_InjectionWaitingEventName) == false ||
- Memory.WriteASCIIString(l_InjectionContinueEventNamePtr, m_InjectionContinueEventName) == false ||
- Memory.WriteASCIIString(l_InjectionFinishedEventNamePtr, m_InjectionFinishedEventName) == false)
- throw new Exception("Could not write event names to memory.");
- //allocate memory for the detour, the codecave, and a section of data for us to manipulate
- m_EndSceneDetour = Memory.AllocateMemory(l_PageSize, MemoryAllocType.MEM_COMMIT, MemoryProtectType.PAGE_EXECUTE);
- if (m_EndSceneDetour == 0)
- throw new Exception("Could not allocate memory in target process for detour.");
- m_InjectedCode = Memory.AllocateMemory(l_PageSize, MemoryAllocType.MEM_COMMIT, MemoryProtectType.PAGE_EXECUTE_READWRITE | MemoryProtectType.PAGE_NOCACHE);
- if (m_InjectedCode == 0)
- throw new Exception("Could not allocate memory in target process for injected code.");
- m_DataPtr = Memory.AllocateMemory(l_PageSize, MemoryAllocType.MEM_COMMIT, MemoryProtectType.PAGE_READWRITE);
- if (m_DataPtr == 0)
- throw new Exception("Could not allocate memory in target process for injected data.");
- //first few bytes of our data section are accounted for
- m_InjectionWaitingHandlePtr = m_DataPtr;
- m_InjectionContinueHandlePtr = m_DataPtr + 4;
- m_InjectionFinishedHandlePtr = m_DataPtr + 8;
- m_ReturnedDataPtr = m_DataPtr + 12;
- //inject and execute the codecave that registers the events inside WoW.exe
- bool bEventInitSuccess = InjectEventStub(
- l_EventStub,
- l_InjectionWaitingEventNamePtr,
- l_InjectionContinueEventNamePtr,
- l_InjectionFinishedEventNamePtr
- );
- if (bEventInitSuccess == false)
- throw new Exception("Could not successfully set up synchronization events.");
- //inject the endscene detour and codecave
- InjectDetour();
- Memory.FreeMemory(l_EventStub);
- Memory.FreeMemory(l_InjectionWaitingEventNamePtr);
- }
- private void InjectDetour()
- {
- //basically, this codecave will check if code has been injected and is waiting to execute,
- //then call the injected code if the event has been signaled. it then checks if it's a
- //one-time injection or if it's supposed to loop (which you control using BeginExecute and
- //EndExecute). It's useful to pause execution of the game and loop through injections if
- //you're doing something like enumerating all objects and calling obj->GetName on each one,
- //or something like that. Goes much faster because you don't have to wait for the next
- //frame in order to get the next name, etc.
- Memory.Asm.Clear();
- Memory.Asm.AddLine("pushad");
- Memory.Asm.AddLine("@CheckInjection:");
- Memory.Asm.AddLine("mov eax, [{0}]", m_InjectionWaitingHandlePtr);
- Memory.Asm.AddLine("push 0");
- Memory.Asm.AddLine("push eax");
- Memory.Asm.AddLine("call {0}", WaitForSingleObject);
- Memory.Asm.AddLine("test eax, eax");
- Memory.Asm.AddLine("jnz @NoInjection");
- Memory.Asm.AddLine("@Injection:");
- Memory.Asm.AddLine("call {0}", m_InjectedCode);
- Memory.Asm.AddLine("mov [{0}], eax", m_ReturnedDataPtr);
- Memory.Asm.AddLine("mov eax, [{0}]", m_InjectionFinishedHandlePtr);
- Memory.Asm.AddLine("push eax");
- Memory.Asm.AddLine("call {0}", SetEvent);
- Memory.Asm.AddLine("mov eax, [{0}]", m_InjectionContinueHandlePtr);
- Memory.Asm.AddLine("push 1000"); //wait one second
- Memory.Asm.AddLine("push eax");
- Memory.Asm.AddLine("call {0}", WaitForSingleObject);
- Memory.Asm.AddLine("test eax, eax");
- Memory.Asm.AddLine("jz @CheckInjection");
- Memory.Asm.AddLine("mov eax, [{0}]", m_InjectionWaitingHandlePtr);
- Memory.Asm.AddLine("push eax");
- Memory.Asm.AddLine("call {0}", ResetEvent);
- Memory.Asm.AddLine("@NoInjection:");
- Memory.Asm.AddLine("popad");
- Memory.Asm.AddLine("mov edi, edi");
- Memory.Asm.AddLine("push ebp");
- Memory.Asm.AddLine("mov ebp, esp");
- Memory.Asm.AddLine("jmp {0}", m_OrigEndScene + 5);
- if (Memory.Asm.Inject(m_EndSceneDetour) == false)
- throw new Exception("Could not assemble and inject trampoline.");
- //detour endscene
- Memory.Asm.Clear();
- Memory.Asm.AddLine("jmp {0}", m_EndSceneDetour);
- if (Memory.Asm.Inject(m_OrigEndScene) == false)
- throw new Exception("Could not assemble and inject detour.");
- }
- private bool InjectEventStub(uint EventStub, uint InjectionWaitingNamePtr, uint InjectionContinueNamePtr, uint InjectionFinishedNamePtr)
- {
- Memory.Asm.Clear();
- Memory.Asm.AddLine("push {0}", InjectionWaitingNamePtr);
- Memory.Asm.AddLine("push 0");
- Memory.Asm.AddLine("push 0");
- Memory.Asm.AddLine("push 0");
- Memory.Asm.AddLine("call {0}", CreateEventA);
- Memory.Asm.AddLine("test eax, eax");
- Memory.Asm.AddLine("jz @ReturnFalse");
- Memory.Asm.AddLine("mov [{0}], eax", m_InjectionWaitingHandlePtr);
- Memory.Asm.AddLine("push {0}", InjectionContinueNamePtr);
- Memory.Asm.AddLine("push 0");
- Memory.Asm.AddLine("push 0");
- Memory.Asm.AddLine("push 0");
- Memory.Asm.AddLine("call {0}", CreateEventA);
- Memory.Asm.AddLine("test eax, eax");
- Memory.Asm.AddLine("jz @ReturnFalse");
- Memory.Asm.AddLine("mov [{0}], eax", m_InjectionContinueHandlePtr);
- Memory.Asm.AddLine("push {0}", InjectionFinishedNamePtr);
- Memory.Asm.AddLine("push 0");
- Memory.Asm.AddLine("push 0");
- Memory.Asm.AddLine("push 0");
- Memory.Asm.AddLine("call {0}", CreateEventA);
- Memory.Asm.AddLine("test eax, eax");
- Memory.Asm.AddLine("jz @ReturnFalse");
- Memory.Asm.AddLine("mov [{0}], eax", m_InjectionFinishedHandlePtr);
- Memory.Asm.AddLine("mov eax, 1");
- Memory.Asm.AddLine("retn");
- Memory.Asm.AddLine("@ReturnFalse:");
- Memory.Asm.AddLine("xor eax, eax");
- Memory.Asm.AddLine("retn");
- return Memory.Asm.InjectAndExecute(EventStub) == 1 ? true : false;
- }
- #endregion
- #region IDisposable Members
- public void Dispose()
- {
- IsInitialized = false;
- if (Memory != null)
- {
- Memory.Asm.Clear();
- Memory.Asm.AddLine("mov edi, edi");
- Memory.Asm.AddLine("push ebp");
- Memory.Asm.AddLine("mov ebp, esp");
- Memory.Asm.Inject(m_OrigEndScene);
- Memory.FreeMemory(m_EndSceneDetour);
- Memory.FreeMemory(m_InjectedCode);
- Memory.FreeMemory(m_DataPtr);
- }
- m_InjectionWaitingEvent.Close();
- m_InjectionContinueEvent.Close();
- m_InjectionFinishedEvent.Close();
- }
- #endregion
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement