<转>[C#][Tutorial] How to become an EndScene() hooker

简介: NOTICE: I am a C# noob and this tutorial is for other C# noobs. I have no doubt that I have broken countless C# coding conventions and good practices ...

NOTICE: I am a C# noob and this tutorial is for other C# noobs. I have no doubt that I have broken countless C# coding conventions and good practices and it is best to assume the way I did everything is one of the least efficient possible. Credits go to many people, some of which I will mention towards the end of the tutorial.

Things you will need:

    • Microsoft Visual Studio 2010 - You can easily write this with any other version of Visual Studio that supports C# and .Net 2.0 and higher but for the sake of this tutorial I will be using VS2010
    • SlimDX - This is the managed wrapper around DirectX which we will be using to handle DirectX as well as find the function address of EndScene. SlimDX can be downloaded here: SlimDX Homepage
    • EasyHook - This is a great library for injecting DLLs and hooking functions in C#. With this you can hook managed as well as unmanaged functions (more about that later). Download here: easyhook-continuing-detours - Project Hosting on Google Code
    • A quick explanation of the object model
      I'm not going to explain the object model in detail, I'm just going to explain where the info we want is and what we're going to do with it. Whenever an instance of an object is created in memory, memory is allocated for that object and all of its properties (variables). However, it would be insanely messy and inefficient to allocate memory for every function of that object and copy those functions there. Instead, a VMT is allocated, which points to all to the methods which are already in the memory of the DLL (in the case of Direct3D) and any and all instances of the object will point to the same function.

      This makes it very simple for us once we have injected a DLL: Create a Direct3D object and find EndScene in its VMT. Hook our object's EndScene and we will be hooking the same EndScene thatWoW uses. Simple... right?

      The Work Space
      This is where the inefficiency comes in. My workspace, especially the layout of the files is pretty awful, but deal with is.

      First off, you want to create a project and a solution. File->New->Project and call it whatever you want, something along of "host" or "injector" so that you know which is which and select Console application for its type. Then, in the solution browser, right click on the solution and select Add->New Project. Name this one something along the lines of "DLL" or "InjectedDll" or whatever and select "Class Library" for its type.

      Next, go to the Properties of the DLL and under Build change the build path to ../[Host name]/bin/Debug/ or click browse and point it to the bin/debug folder of the first project (the console application). This way, whenever you build solution both the DLL and the injector are built into the same folder and you don't have to do any of the copying from one folder to the other nonsense.

      References
      Now due to the way that interfaces are set up to communicate between the injected DLL and the host, the DLL must reference the executable in order to be able to create an instance of the interface class.

      First, in the host process (the console application), add a reference to EasyHook.dll and copy all of the EasyHook binaries to your /bin/Debug folder (I'll let you figure out which ones on your own, but for now just copy all of them). Also I would copy the SlimDX.dll from the SlimDX binaries folder just to save yourself some trouble. That's it. That's all you gotta do for the host. Now, the using code:
    • using System;
      using System.Collections.Generic;
      using System.Diagnostics;
      using System.Runtime.Remoting;
      using EasyHook;

      System.Diagnostics is needed for finding the PID of WoW and System.Runtime.Remoting is required in order to allow the DLL to communicate with the host process.

      Now do the same with the inject DLL project and add the EasyHook.dll as a reference. Then, add SlimDX (from the .Net tab) and from the Projects tab add a reference to the host project from the DLL.

    • using System;
      using System.Runtime.InteropServices;
      using System.Windows.Forms;
      using EasyHook;
      using SlimDX;
      using SlimDX.Direct3D9;

      Same thing as before but now you add SlimDX so that you can create a device and use the WoW D3D device. (Windows.Forms is for a MessageBox in EndScene to know whether its working)

      Setting up the communication interface
      Like I said, I am a noob. Seriously, a total noob, so all I know so far is how to do one way communication but for the purposes of this tutorial that's all you need. What happens is you define your communication interface in the host process and then the DLL can call functions from inside the memory space of the host.

      Here's the interface I'll use:

    •     public class WoWInterface : MarshalByRefObject
          {
              public void IsInstalled(Int32 InClientPID)
              {
                  return;
              }
      
              public void WriteConsole(String Write)
              {
                  Console.WriteLine(Write);
              }
      
          }

      Very simple, no? All you're doing is create a class that displays something on the console. Put this in the main namespace of your project.

      The actual injection!
      Once again, this part is very simple thanks to EasyHook. The first thing you want to do is declare a static string called "ChannelName" which will be the random name of our IPC communication channel. Then, in your main function you'll want to put something like this:

    •             int wowPid;
                  Config.Register("WowInjector App", "InjectedDll.dll", "DllInjector.exe");
      
                  Process[] procs = Process.GetProcessesByName("WoW");
      
                  wowPid = procs[0].Id;
      
                  RemoteHooking.IpcCreateServer<WoWInterface>(ref ChannelName, WellKnownObjectMode.SingleCall);
      
                  RemoteHooking.Inject(wowPid, InjectionOptions.Default, "InjectedDll.dll", "InjectedDll.dll", ChannelName);

      The first thing you'll want to do is add your executable and dll to the Global Assembly Cache. According to the internet god, "The Global Assembly Cache or GAC is a machine-wide .NET assemblies cache for Microsoft's CLR platform. The approach of having a specially controlled central repository addresses the shared library concept and helps to avoid pitfalls of other solutions that lead to drawbacks like DLL hell." (Wikipedia). Basically, it's supposed to make management of DLLs a bit easier (ala the theory of .NET: Let the coder have as little control as possible). The first argument is a quick note about what it is, doesn't matter what you put here. The rest of the function is a list of all the assemblies you want to add. Essentially, just add your executable and dll (EasyHook and all those are automatically added. Don't worry).

      The next 2 lines create an array of processes with the name "WoW.exe" (not case sensitive) and choses the first one and get its Process ID. Because it's an array you can always make some kind of dialog which asks for the instance to inject into on your own.

      Now on to the more complex line, creating the IPC server. The server basically serves the interface which other functions call. The object in the < > is the one that will be open for the clients to use while the "ref ChannelName" is essentially a pointer to the string where the name of our IPC server will be stored. This is totally irrelevant for this tutorial but "WellKnownObjectMode.SingleCall" means that a new instance of the WoWInterface object will be created for each client while "WellKnownObjectMode.Singleton" would set it so that a single instance is used for all clients.

      The injection line is also very simple. The first argument is the PID of the process we want to inject, the second is the options (Look it up for yourself), the third argument is the DLL to inject in the case of 32 bit while the 4th is the DLL for 64 bit which in our case would be the same for both. If you make your own bot I would recommend differentiating between the 2 DLLs because the SlimDX reference could come in both 32bit and 64bit varieties. And last but not least we the arguments we will pass to the DLL which in our case would be only the ChannelName for the IPC connection.

      The DLL!
      The first thing you want to do with the DLL is to make sure that the namespace for the DLL is the same as the namespace in your host project. Don't ask me why, it's just a quirk with EasyHook that I have run into. Make your life simple and just do it.

      The next step is specifying the entry point of your DLL which EasyHook wants. In this case it is always jsut " : EasyHook.IEntryPoint"

    •  public class Main : EasyHook.IEntryPoint
          {
              WoWInterface Interface;
              LocalHook EndSceneHooker;

      This declares our Main class and sets it as the entry point EasyHook is looking for. THIS IS ABSOLUTELY NECESSARY! Otherwise your DLL will never get injected.

      The variables we declare are an Instance of the IPC interface and the LocalHook object we will use to hook EndScene.


      The Main function

    •         public Main(RemoteHooking.IContext InContext, String InChannelName)
              {
                  Interface = RemoteHooking.IpcConnectClient<WoWInterface>(InChannelName);
                  Interface.WriteConsole("Dll successfully injected.");
              }

      This functions sole purpose is to create the communications interface and confirm that the DLL is injected.

      Once again, the IPC call has the object we will be using for the interface in < > and the only argument is the ChannelName (which was passed to our DLL by EasyHook). Then we call a function from that interface which we declared earlier called WriteConsole which is just Console.WriteLine.

      Code:
    • public void Run(RemoteHooking.IContext InContext, String InChannelName)
              {
                  Device dev;
                  dev = new Device(new Direct3D(), 0, DeviceType.Hardware, IntPtr.Zero, CreateFlags.HardwareVertexProcessing, new PresentParameters() { BackBufferWidth = 1, BackBufferHeight = 1 });
      
                  IntPtr addy = dev.ComPointer;
      
                  addy = (IntPtr)Marshal.ReadInt32(addy);
      
                  addy = (IntPtr)((int)addy + 0xA8);
                  addy = (IntPtr)Marshal.ReadInt32(addy);
      
                  EndSceneHooker = LocalHook.Create((IntPtr)addy, new DEndScene(EndSceneHook), this);
                  EndSceneHooker.ThreadACL.SetExclusiveACL(new Int32[] { 0 });
      
                  while (true)
                  {
                  }
              }

      This is the Run function which is the lifeblood of your DLL (at least until you inject). I BELIEVE (I do not know for sure) that if you return from this function your DLL might be unloaded by EasyHook so that's why every example I've seen had some sort of unending while loop.

      Then we create Direct3D device. This is a copy pasta from SlimDX except I changed the form pointer to IntPtr.Zero and the buffer to 1x1. Then by setting addy to the ComPointer (the real D3D device object) we get the pointer we need to get our VMT.

      We then read the Int32 at that address (and cast it to IntPtr) and this new address is the VMT. Then, since EndScene() is the 42 function we add 0xA8 (A8h = 168 = 42 * 4) to that to get the address of EndScene().

      Sidenote: You can always use Black/White magic or whatever their names are (White rain?) to read the values, just use "addy = (IntPtr) WhiteMagic.Read<Int32>(addy);" since it's basically the same thing.

      THAT IS ALL THIS IS!

      Boom we have the address of EndScene (protip: this is the address of EndScene() in any version ofWoW and in almost any game that uses DirectX9).

      These last two lines hook the function to our own. 

      Code:
    •   EndSceneHooker = LocalHook.Create(addy, new DEndScene(EndSceneHook), this);
                  EndSceneHooker.ThreadACL.SetExclusiveACL(new Int32[] { 0 });

      The first argument of LocalHook.Create() is the address of the function, the second is an unmanaged pointer (I'll explain it in a bit) and the last is a pointer to the Main object that makes up most of the DLL. (Look at EasyHook examples, I won't explain how all of that works.)

      OK I honestly have no idea what ThreadACL.SetExclusiveACL does or why you need it. That line is a copy pasta from the EasyHook examples so go read about it yourself. From what I can tell, I don't need to worry about it.

      The last code is here:

      Code:
    •         [UnmanagedFunctionPointer(CallingConvention.StdCall,
              CharSet = CharSet.Unicode,
              SetLastError = true)]
              delegate int DEndScene(
                  IntPtr Direct3dDevice);
      
              public int EndSceneHook(IntPtr Direct3dDevice)
              {
                  using (Device d3d = Device.FromPointer(Direct3dDevice))
                  {
                      MessageBox.Show("LOL");
                      return d3d.EndScene().Code;
                  }
              }

      The Unmanaged pointer declaration just makes it possible for us to pass the EndSceneHook function to the LocalHook.Create. In the function itself, we do using directive to set our device object (d3d) to the one passed to the function. Thus, our d3d object is actually the Direct3D object that WoW uses. Thus we can manipulate the graphics and do whatever the **** we want.

      The return line just calls the original EndScene and returns the error code (or success code or w.e)


      And... that's it. This code will continuously spam that MessageBox and WoW will never render because of the MessageBoxes blocking the thread.

      Sorry for my crappy explanations but now that you have the code in front of you it should be pretty easy to figure it out and this tutorial is more for WoW hacking noobs, not for people who don't even know the most basic features or syntax of the language. (I left out Strong name signing for a reason). I also made this pretty fragmented so that you had to know at least something to be able to use this tutorial and not be able to just copy paste.

      Also, I have no idea how to release the Device created in that code but since its a managed DLL its already heavy on the memory.

      If I missed something, message me or something and I will correct it. I made sure to create a project from scratch and copy pasted all this code and it worked perfectly (though since this is on a computer it might not work as exactly on yours. If it doesn't, please provide more information than just "it doesn't work"). Tested on a 64bit Windows 7.

      Big note: Any time you get an exception that says something along the lines of your binaries not being in the GAC it is probably because you are not running the executable with administrator privileges. Save yourself the trouble and just run Visual Studio as Administrator

      Now, WTB TUTORIAL ON HOW TO CALL WOW FUNCTIONS AND GET RETURN VALUES!

      Credits go to:
      http://www.rohitab.com/discuss/index...howtopic=34411
      http://spazzarama.wordpress.com/2010...t3d-api-hooks/
      and the EasyHook and SlimDX examples. COPY PASTE FTW!

相关文章
|
网络协议 C# Windows
C# Tutorial - Simple Threaded TCP Server
<p style="margin-top:0px; margin-bottom:18px; font-family:museo-sans,'Helvetica Neue',Helvetica,Arial,sans-serif; font-size:16px; line-height:24px; color:rgb(74,74,74)"> In this tutorial I'm goin
2281 0
|
2月前
|
开发框架 前端开发 .NET
C#编程与Web开发
【4月更文挑战第21天】本文探讨了C#在Web开发中的应用,包括使用ASP.NET框架、MVC模式、Web API和Entity Framework。C#作为.NET框架的主要语言,结合这些工具,能创建动态、高效的Web应用。实际案例涉及企业级应用、电子商务和社交媒体平台。尽管面临竞争和挑战,但C#在Web开发领域的前景将持续拓展。
|
2月前
|
SQL 开发框架 安全
C#编程与多线程处理
【4月更文挑战第21天】探索C#多线程处理,提升程序性能与响应性。了解C#中的Thread、Task类及Async/Await关键字,掌握线程同步与安全,实践并发计算、网络服务及UI优化。跟随未来发展趋势,利用C#打造高效应用。
|
29天前
|
存储 C# 开发者
C# 编程基础:注释、变量、常量、数据类型和自定义类型
C# 编程基础:注释、变量、常量、数据类型和自定义类型
22 1
|
2月前
|
开发框架 .NET Java
探索 C#编程的奥秘与魅力
【4月更文挑战第20天】C#是微软开发的现代、面向对象的编程语言,以其简洁语法、强大功能和跨平台支持脱颖而出。它支持自动垃圾回收、泛型、委托、LINQ,并广泛应用于桌面、Web、移动和游戏开发。C#拥有活跃的开发者社区和丰富的资源,是Unity游戏开发的首选语言。随着.NET Core,C#可在多个操作系统上运行,持续创新,未来发展潜力巨大。
|
2月前
|
存储 安全 网络安全
C#编程的安全性与加密技术
【4月更文挑战第21天】C#在.NET框架支持下,以其面向对象和高级特性成为安全软件开发的利器。本文探讨C#在安全加密领域的应用,包括使用System.Security.Cryptography库实现加密算法,利用SSL/TLS保障网络传输安全,进行身份验证,并强调编写安全代码的重要性。实际案例涵盖在线支付、企业应用和文件加密,展示了C#在应对安全挑战的同时,不断拓展其在该领域的潜力和未来前景。
|
2月前
|
人工智能 C# 云计算
C#编程的未来发展趋向
【4月更文挑战第21天】C#编程未来将深化跨平台支持,强化云计算与容器技术集成,如.NET Core、Docker。在AI和ML领域,C#将提供更丰富框架,与AI芯片集成。语言和工具将持续创新,优化异步编程,如Task、async和await,提升多核性能。开源生态的壮大将吸引更多开发者,共创更多机遇。
|
2月前
|
程序员 C#
C#编程中的面向对象编程思想
【4月更文挑战第21天】本文探讨了C#中的面向对象编程,包括类、对象、封装、继承和多态。类是对象的抽象,定义属性和行为;对象是类的实例。封装隐藏内部细节,只暴露必要接口。继承允许类复用和扩展属性与行为,而多态使不同类的对象能通过相同接口调用方法。C#通过访问修饰符实现封装,使用虚方法和抽象方法实现多态。理解并应用这些概念,能提升代码的清晰度和可扩展性,助你成为更好的C#程序员。
|
2月前
|
开发框架 安全 .NET
C#编程高手的成长之路
【4月更文挑战第21天】本文揭示了成为C#编程高手的路径:牢固掌握基础知识和面向对象编程,深入了解C#特性如泛型和委托,精通ASP.NET等框架工具,养成良好编程习惯,持续学习实践并参与开源项目,勇于挑战创新。通过这些步骤,不断提升编程技能,迈向C#编程的巅峰。
|
2月前
|
IDE 程序员 C#
C#编程入门:从零开始的旅程
【4月更文挑战第20天】本文引导初学者入门C#编程,从环境搭建开始,推荐使用Visual Studio Community版作为IDE。接着,通过编写&quot;Hello, World!&quot;程序,介绍基本语法,包括数据类型、运算符和表达式。文章还涉及控制结构、函数和方法,以及面向对象编程概念。通过学习,读者将对C#有初步了解,并激发进一步探索编程世界的兴趣。