Amlegit Reverse Engineered
Amlegit is an Apex legends cheat bundled with a HWID spoofer, their user base is a little over three thousand users. The cheat iself offers a 2d box esp, silent aim, and a few other features. As you will see in this extensive writeup this cheat is nothing more than a paste of publicly released exploits and source code. The communication method as shown below is a basic IOCTL hook of a system driver.
The launcher I will be talking about is actually their “second stage” launcher. The first stage of the launcher downloads and puts all the QT files/executables inside of a random temp folder and then starts the second launcher. Inside of this temp folder there are three files that stick out, buffer.dll, inject.dll, and mmap.dll. All of these files are VMP’ed but their export tables are still parseable. Opening them each in Ida presented me with at least two exports each (start and another function defined by the programmers of amlegit) Although the export tables are parseable, the functions themselves are not, even viewing the functions data at runtime resembled nothing understandable. In order for me to call these export functions myself I would need to know both the calling convention (most likely fastcall), parameters, and return type. This can be achieved by looking at what calls these exported functions. Lucky for me the second stage launcher had xref’s to all of these functions besides GetDriver (which was referenced inside of inject.dll dump).
Export connect takes zero parameters and returns a bool. This function sets up communication between the user mode process and the kernel driver.
Export inject takes two parameters, the first is the name of the dll on disk to inject into the process specified by the second parameter. The second parameter takes the classname of a window. This function is used to inject the dll into the game.
Export load takes no parameters and returns a bool. This function loads the intel lan driver. (part of kdmapper).
Export map takes one parameter which is a char pointer and returns a bool. This function is used to map an unsigned driver into the kernel.
As shown above mmap.dll exports two functions (three total including dllmain). Although these functions are exported from mmap.dll you will not be able to parse what they do since they are heavily virtualized and obfuscated. This being said if we are able to parse a function call to anyone of these functions we will most likely be able to make out parameters and return types.
So why are we looking inside of the module if we cant parse what these functions are doing? Well simply put mmap.dll actually loads buffer.dll and calls GetDriver. This will allow us to see the parameters and return type for GetDriver.
Let's break this assembly down. The first thing that we see is a call to GetModuleHandle. You can see that GetModuleHandle takes a char pointer since we move the address of a string in this case “buffer.dll” into rcx (which if you don't already know is the first register used in the fastcall calling convention to pass an integer value). Next we see a test rax, rax. In short this instruction tests to see if rax is zero, it then stores the result in the EFLAGS register. There is a lot more that is going on behind the scenes with the test instruction but i'll leave that up to you and google. This test instruction also gives us very important information about the return value (and size) for the function. In fastcall rax is the register that contains the return value for values that are 64 bits or less in size (byte, word, dword, qword). By reading the assembly we can tell that the entire 64 bits of data is being used (which means it returns a long long). This matches our expectations for GetModuleHandle which takes a long pointer to a c style string and returns a value that matches 64 bits in size. Keep in mind HMODULE can be 32 bit but this module is 64 bit.
After we call GetModuleHandle we are going to make a call to GetProcAddress_1 which is a wrapper function around the real GetProcAddress. First we move the address of “GetDriver” into rbx which is the register used for the second parameter (for integer values). Then we move the result from GetModuleHandle into rcx which as you probably know by now is the register for the first integer value parameter. The result is going to be 64 bits in length, this is inferred by the test and branch operation right. It also lines up with MSDN definitions of GetProcAddress.
Now that we have the address of GetDriver inside of rax we are going to call it. If you were to glance over this assembly you would assume we are putting 1 into rcx but we are actually loading the effect address of 1 (lea). So this tells use that GetDriver takes a pointer as its one and only parameter. The return value is also inferred by the subsequent operations with rax.
Since we know the parameters and return type of GetDriver we can actually call this function with our own code. Just to be clear the function prototype looks like this
Now that we have the driver lets take a look at how it communicates with the cheats usermode counterpart. This cheat IOCTL hooks by changing the major function pointer of a legitimate windows driver to point to their ioctl function. They also change the unload function to point to theirs so if/when that driver gets unloaded they can remove the IOCTL hook.
Considering that we know how the driver communicates with the user mode process let's look at the IOCTL hook function itself. The IOCTL supports reading from a process given its PID, write to a process given its PID, allocate memory in a process given its PID, and spoofing hwid’s. The two options that stick out to me are the hwid spoofer and the allocation of memory because keep in mind this cheat is internal so they must hide their memory right? Wrong, as you will see they just call ZwAllocateVirtualMemory after calling ZwOpenProcess. They do not hide their memory at all.
Before I dive into the spoofer I would just like to make it clear that the developers of amlegit did not discover a new method of spoofing hwid’s. In other words they just pasted together public code and started selling it. If you don't feel like reading about github repositories then you can skip this section and move onto the next.
The spoofer in this driver is public code that can be found here. It is anything but undetected and using it will result in a ban. Let's first look at the IOCTL option to spoof hwid’s. The debug print statements tell us what each subsequent function correlates to. This makes it actually really easy to cross reference the public github repository to ensure what we are looking for is truly someone else's work.
Let's look at spoof_disk first. This function is 1:1 with public source as you will see. Since the function is quite large I'm going to put it on another page for you to cross reference it with the github repo.
Here is a copy of the youtube video demonstrating the launcher just incase it goes private or deleted. As you will see in the video the console that opens contains the same information that is printed when you run btbd's spoofer, blatant paste.... (1:50)
Here is a video of the cheat in action. The account that was demonstrating this cheat is already banned since the cheat is detected. As you can see its nothing special.