Iniuria – An Analysis of the „Antileak“ System

Long time no see everyone, at least for those people that are used to #debuglog targeting payhacks (Yes, It’s that time again!). Today I’d like to talk a bit about something we did in the last couple of days. There are more and more cracks surfacing, which exploit the fact that common antileak systems in most cases suck balls; ranging from variants where the provided loader already includes the hack and has some credentials (mostly some form of a hardware id) hardcoded in the binary to hacks that are streamed form the server to the loader and then injected. The latter is used for the Iniuria antileak system as well – but at least with some degree of “protection”. So, let’s dive a bit into the server and client communication.

The Communication

iniuria_antileak

First of all, the antileak relevant communication is done with query.iniuria.us. That also means that we can route that address to localhost in the hosts file easily. Now, when you start the Iniuria client, it first requests the version.xml from the server (via http – important here because sloppy code ahead). The versions.xml contains the following:

<version>
 <number>129</number>
 <url>https://dl.dropboxusercontent.com/u/88120468/29_12_2014.exe</url>
</version>

As you can see it contains the current version number and a link to the binary of the client. For whatever reason this points to a file in a dropbox. You can try it yourself: http://query.iniuria.us/version.xml

Now, the client either updates itself and needs to be restarted or you are forwarded to the login screen. So, as the nice non paying person you are, you slam random characters into the fields and hit login. The next thing the client sends to the server is the following:

https://query.iniuria.us/login.php (yes, now we are using https)

payload:
Reason=Login&
Name=your_username&
PWD=your_password&
HWID=md5_of_hardwareid&
s=md5_of_request&
h=base64_encoded_hardware_info

Reason, Name and PWD are self-explanatory. HWID is the md5 checksum of the information that is used to identify your hardware (didn’t bother to look because it wasn’t necessary). The h field contains basic information about your hardware, probably used to identify account sharing and looks like this:

US (country code)
Windows 7 (your operating system)
Intel(R) Core(TM) i7-2600 CPU @ 3.40GHz (name of the CPU)
Z97P-D3 (name of the mainboard)

And at last the s field contains the md5 checksum of the request, so tampering with the fields of the request is a bit harder. Now, you, as a smart user that doesn’t pay for stuff like hacks, will see the following:

<?xml version="1.0" encoding="UTF-8"?>
<information>
 <status>WrongLogin</status>
</information>

or

<?xml version="1.0" encoding="UTF-8"?>
<information>
 <status>WrongHardware</status>
</information>

If you actually have paid for an iniuria account (and I really hope you didn’t), you would get something like this as a response:

<?xml version="1.0" encoding="UTF-8"?>
<information>
 <status>Confirmed</status>
 <hackinformation>
  <entry_1>
   <product>Iniuria CS:GO Full</product>
   <type>9</type>
   <game>Counter-Strike: Global Offensive</game>
   <productinfo>Framework</productinfo>
   <detection>undetected</detection>
   <exe>csgo.exe</exe>
   <window>Counter-Strike: Global Offensive</window>
   <expires>27.12.2015</expires>
   <changelog>base64_of_html_changelog</changelog>
   <isclass>0</isclass>
  </entry_1>
 </hackinformation>
</information>

This output varies with the kind of subscription you have. In this case it’s just Counter-Strike: Global Offensive. Most of the datails displayed in the loader. is used to tell the loader in which game the hack should be injected. So, this is pretty straight-forward. If you don’t have the driver already loaded, the client will download it in the next step:

https://query.iniuria.us/login.php

Reason=Cartoon&
Name=your_username&
PWD=your_password&
HWID=md5_of_hardwareid&
k=true&
s=md5_of_request

I worked on a 64 bit machine. I’m not really sure what the „k“ field is used for but it could be a switch to tell the server what driver should be provided: 32Bit or 64Bit. The Server responds with this:

<?xml version="1.0" encoding="UTF-8"?>
<information>
 <status>CartoonOk</status>
 <size>161736</size>
 <cartoon>base64_of_driver_image</cartoon>
</information>

It sends the driver to the client. Just decode the content of the field and you are ready to go.

After the driver download/startup and the response from the server with the product details, you decide what hack you want to use. Select it and press load. The client will send this if you decided to play with the cs:go hack:

http://query.iniuria.us/login.php (HTTP, NOT HTTPS)

Reason=Tom&
Name=your_username&
PWD=your_password&
HWID=md5_of_hardwareid&
Type=9&
s=md5_of_request

Yeah.. for whatever reason he uses HTTP here and not HTTPS. Pretty cool if you want to snoop iniuria credentials at your local university/school/dorm. „Type“ indicates the product that should be streamed to the client. If everything went fine the server will respond as follows:

<?xml version="1.0" encoding="UTF-8"?>
<information>
 <status>InformationOk</status>
 <size>825856</size>
 <type>9</type>
 <isclass>0</isclass>
</information>

We get the confirmation that we are able to use this hack and receive the size of the hack.
You may ask why you get the size in this response. Don’t worry, I’ll explain it after the next request/response. So, after the confirmation and opening the game the client requests the actual hack:

https://query.iniuria.us/login.php (hooray for HTTPS again)

Reason=Cherry&
Name=your_username&
PWD=your_password&
HWID=md5_of_hardwareid&
xml=base64_of_xml_with_api_export_data&
j=base_address_of_hack_in_game&
Type=9&
s=md5_of_request

This is the last request. the xml field contains the base64 encoded xml data of all the exported apis of the kernel32.dll, user32.dll and advapi32.dll and their addresses. The j field contains the address where the client already allocated memory in the game. Remember the field of the last response? Yes, that was necessary so the client could already allocate enough space for the hack in the cs:go memory space. Now we inform the server where the hack will be in the game process. This address with the export data of the dlls is enough for the server to provide a fully prepared hack for the client by mapping the sections, fixing the imports with the provided export list (xml field) and fix relocations for the new base of the hack (the j field). If everything was fine the server will respond with:

<?xml version="1.0" encoding="UTF-8"?>
<information>
 <status>CherryOk</status>
 <file>base64_of_prepared_hack_image</file>
 <entry>address_of_entrypoint</entry>
</information>

Here it is, the fully prepared hack that now gets written to the allocated address (j field of the request). The field contains the entrypoint of the hack library. So, CreateThread on this address and the hack is up and running.

Breaking the System

Now, the observant eye might see a problem or two with the whole concept. If you don’t, don’t worry. Here is something that really makes you think: The server seems to use a valid ssl certificate.. but the client doesn’t validate ANYTHING. Replay attacks are EASILY possible. Just take the requests of a valid customer and send them again.. though you might want to do this from the same internet connection or you might get banned. The fun stuff starts when we want to emulate the whole iniuria server.

The only thing that you have to do is replay every request the client does and save the result (all the xml responses). But there is one, quite annoying hurdle that you have to take: As stated above, the server does the „manual mapping“ stuff. You can’t use the reply with the hack since it only fits at a specific memory location with the kernel32.dll, user32.dll and advapi32.dll of a specific version loaded at specific addresses.

To fix that problem, we have to do several things:
1. we acquire two hack images with two different bases addresses and two lists with exported apis
2. Use the addresses of the exported apis list to search the the hack image and recognize all used apis and their offsets
3. diff both hack images to find differences so we can identify relocations
4. be able to patch one of the two „known“ hack images on a new request with a new export api list and new base

How to:
1.) No problem, just save two „Cherry“ requests with different bases and replay them.

2.) This is actually really easy. Just take the addresses from the fields and search through the hack images, save where you found the address and the name of the api. To make sure that everything went fine, do the same for the second hack image and check if both lists of [api_name, offset] are identical. If they are, the import fixing is not a problem anymore.

import_fix

3.) Finding the relocations is actually the hardest part in the server emulator. Since the hack images don’t contain a pe-header, we have to make educated guesses.. good educated guesses to make this work consistently. To make this work, we define a simple rule: for every ulong (4byte) we check, the lower half must be consistent with one of the
known images and the higher half can differ. Why you ask?

0x17FE 4337

When we talk about x86 memory allocation on windows, we know of the simple rule that all allocations will be a multiple of 0x10000. So, the only part that will vary is the higher part of the address (HIWORD). With this we can search for values that fit into this rule, substract the located address of the known module from the known base and save the offset and this delta like [offset, delta]. Now we can walk through the known library and write at those offsets the new_base + delta. With that we relocated the image to the requested address.

relocation_fix

4.) Just use the lists of the found imports and the relocations and write the data to a new instance of the known image. Encode it with base64, provide the entrypoint of the module ((known_entry – known_base) + new_base) and prepare the response.
done.

This is all it takes to emulate the iniuria server (and part of the client, actually).
Now, at this point we will not provide you with any binary, but since we want to educate people we provide a bit of code.

But first, here are the lessons learned from this from our point of view:
Even though the Pay to Cheat owners make way to much money out of blinded goons that seem to trust anyone as long they get a hack out of it, they don’t take anything serious. There are easy ways to make the job of people that want to break there systems waaaay harder, but that would require the coders to actually use their head and stop relying on the code of other people. I won’t give hints what to do here, obviously, but the amount of sloppy coding out there is depressing. The product quality of „commercial“ gamehacks can be compared with trojans, botnets and „hacking-tools“ you can from purchase in various scriptkiddy-forums.

Anyway, since the hardest part of the emulator is to fix the images, I’ll provide that code here. The communication part is easily done if you have basic skills in one scripting language.

https://openload.io/f/BmeUrf7IGQM/fix_image.py

Iniuria – An Analysis of the „Antileak“ System

Long time no see everyone, atleast for those people that are used to the Pay2Cheat targeting #debuglog. Today I’d like to talk a bit about something we did in the last couple of days. So, in the Pay to Cheat scene it seems that there are more and more cracks that utilizes the fact that the Antileak systems in most cases suck balls. Ranging from variants where the provided loader already includes the hack and has some credentials hardcoded in the binary to hacks that are streamed form the server to the loader and then injected. The latter is used for the Iniuria Antileak system as well, with a bit “protection”. So, let’s dive a bit into the server and client communication.

The Communication

iniuria_antileak

First of all, the antileak relevant communication is done with query.iniuria.us. That also means that we can route that address to localhost in the hosts file easily. Now, when you start the Iniuria Client,it first requests the version.xml from the server (via http – important here because slopping coding ahead). The versions.xml contains the following:

&lt;version&gt;
 &lt;number&gt;129&lt;/number&gt;
 &lt;url&gt;https://dl.dropboxusercontent.com/u/88120468/29_12_2014.exe&lt;/url&gt;
&lt;/version&gt;

As you can see it contains the current version number and a link to the binary of the client. For whatever reason this points to a file in a dropbox. You can try it yourself: http://query.iniuria.us/version.xml

Now, the client either updates itself and needs to be restarted or you are forwarded to the login screen. So, as the nice non paying person you are, you slam random characters into the fields and hit login. The next thing the client sends to the server is the following:

https://query.iniuria.us/login.php (yes, now we are using https)

payload:
Reason=Login&
Name=your_username&
PWD=your_password&
HWID=md5_of_hardwareid&
s=md5_of_request&
h=base64_encoded_hardware_info

Reason, Name and PWD are self-explanatory. HWID is the md5 checksumof the information that is used to identify your hardware (didn’t bother to look because it wasn’t necessary). The h field contains basic information about your hardware, probably used to identify account sharing and looks like this:

US (country code)
Windows 7 (your operating system)
Intel(R) Core(TM) i7-2600 CPU @ 3.40GHz (name of the CPU)
Z97P-D3 (name of the mainboard)

And at last the s field contains the md5 checksum of the request so tempering with the fields of the request is a bit harder. Now, you, as a smart user that doesn’t pay for stuff like hacks, will see the following:

&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;information&gt;
 &lt;status&gt;WrongLogin&lt;/status&gt;
&lt;/information&gt;

or

&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;information&gt;
 &lt;status&gt;WrongHardware&lt;/status&gt;
&lt;/information&gt;

If you actually have paid for an iniuria account (and I really hope you didn’t), you would get something this as a response:

&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;information&gt;
 &lt;status&gt;Confirmed&lt;/status&gt;
 &lt;hackinformation&gt;
  &lt;entry_1&gt;
   &lt;product&gt;Iniuria CS:GO Full&lt;/product&gt;
   &lt;type&gt;9&lt;/type&gt;
   &lt;game&gt;Counter-Strike: Global Offensive&lt;/game&gt;
   &lt;productinfo&gt;Framework&lt;/productinfo&gt;
   &lt;detection&gt;undetected&lt;/detection&gt;
   &lt;exe&gt;csgo.exe&lt;/exe&gt;
   &lt;window&gt;Counter-Strike: Global Offensive&lt;/window&gt;
   &lt;expires&gt;27.12.2015&lt;/expires&gt;
   &lt;changelog&gt;base64_of_html_changelog&lt;/changelog&gt;
   &lt;isclass&gt;0&lt;/isclass&gt;
  &lt;/entry_1&gt;
 &lt;/hackinformation&gt;
&lt;/information&gt;

This output varies with the kind of subscription you have. In this case it’s just Counter-Strike: Global Offensive. Most of the datais displayed in the loader. is used to tell the loader in which game the hack should be injected. So, this is pretty straight-forward. If you don’t have the driver already loaded, the client will download it in the next step:

https://query.iniuria.us/login.php

Reason=Cartoon&
Name=your_username&
PWD=your_password&
HWID=md5_of_hardwareid&
k=true&
s=md5_of_request

I worked on a 64 bit machine. I’m not really sure what the „k“ field is used for but it could be a switch to tell the server what driver should be provided: 32Bit or 64Bit. The Server responds with this:

&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;information&gt;
&lt;status&gt;CartoonOk&lt;/status&gt;
&lt;size&gt;161736&lt;/size&gt;
&lt;cartoon&gt;base64_of_driver_image&lt;/cartoon&gt;
&lt;/information&gt;

It sends the driver to the client. Just decode the content of the field and you are ready to go.

After the driver download/startup and the response from the server with the product details, you decide what hack you want to use. Select it and press load. The client will send this if you decided to play with the cs:go hack:

http://query.iniuria.us/login.php (HTTP, NOT HTTPS)

Reason=Tom&
Name=your_username&
PWD=your_password&
HWID=md5_of_hardwareid&
Type=9&
s=md5_of_request

Yeah.. for whatever reason he uses HTTP here and not HTTPS. Pretty cool if you want to snoop iniuria credentials at your local university/school/dorm. „Type“ indicates the product that should be streamed to the client. If everything went fine the server will respond as follows:

&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;information&gt;
&lt;status&gt;InformationOk&lt;/status&gt;
&lt;size&gt;825856&lt;/size&gt;
&lt;type&gt;9&lt;/type&gt;
&lt;isclass&gt;0&lt;/isclass&gt;
&lt;/information&gt;

We get the confirmation that we are able to use this hack and receive the size of the hack.
You may ask why you get the size in this response. Don’t worry, I’ll explain it after the next request/response. So, after the confirmation and you opened the game the client requests the actual hack:

https://query.iniuria.us/login.php (hooray for HTTPS again)

Reason=Cherry&
Name=your_username&
PWD=your_password&
HWID=md5_of_hardwareid&
xml=base64_of_xml_with_api_export_data&
j=base_address_of_hack_in_game&
Type=9&
s=md5_of_request

This is the last request. the xml field contains the base64 encoded xml data of all the exported apis of the kernel32.dll, user32.dll and advapi32.dll and their addresses. The j field contains the address where the client already allocated memory in the game. Remember the field of the last response? Yes, that was necessary so the client could already allocate enough space for the hack in the cs:go memory space. Now we inform the server where the hack will be in the game process. This address with the export data of the dlls is enough for the server to provide a fully prepared hack for the client by mapping the sections, fixing the imports with the provided export list (xml field) and fix relocations for the new base of the hack (the j field). If everything was fine the server will respond with:

&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;information&gt;
&lt;status&gt;CherryOk&lt;/status&gt;
&lt;file&gt;base64_of_prepared_hack_image&lt;/file&gt;
&lt;entry&gt;address_of_entrypoint&lt;/entry&gt;
&lt;/information&gt;

Here it is, the fully prepared hack that now gets written to the allocated address (j field of the request). The field contains the entrypoint of the hack library. So, CreateThread on this address and the hack is up and running.

Breaking the System

Now, the observant eye might see a problem or two with the whole concept. If you don’t, don’t worry. Here is something that really makes you think: The server seems to use a valid ssl certificate.. but the client doesn’t validate ANYTHING. Replay attacks are EASILY possible. Just take the requests of a valid customer and send them again.. though you might want to do this from the same internet connection or you might get banned. The fun stuff starts when we want to emulate the whole iniuria server.

The only thing that you have to do is replay every request the client does and save the result (all the xml responses). But there is one, quite annoying hurdle that you have to take: As stated above, the server does the „manual mapping“ stuff. You can’t use the reply with the hack since it only fits at a specific memory location with the kernel32.dll, user32.dll and advapi32.dll of a specific version loaded at specific addresses.

To fix that problem, we have to do several things:
1. we acquire two hack images with two different bases addresses and two lists with exported apis
2. Use the addresses of the exported apis list to search the the hack image and recognize all used apis and their offsets
3. diff both hack images to find differences so we can identify relocations
4. be able to patch one of the two „known“ hack images on a new request with a new export api list and new base

How to:
1.) No problem, just save two „Cherry“ requests with different bases and replay them.

2.) This is actually really easy. Just take the addresses from the fields and search through the hack images, save where you found the address and the name of the api. To make sure that everything went fine, do the same for the second hack image and check if both lists of [api_name, offset] are identical. If they are, the import fixing is not a problem anymore.

import_fix

3.) Finding the relocations is actually the hardest part in the server emulator. Since the hack images don’t contain a pe-header, we have to make educated guesses.. good educated guesses to make this work consistently. To make this work, we define a simple rule: for every ulong (4byte) we check, the lower half must be consistent with one of the
known images and the higher half can differ. Why you ask?

0x17FE 4337

When we talk about memory allocation, we know of the simple rule that all allocations will be at least a multiple of 0x10000. So, the only part that will vary are the higher part of the address. With this we can search for values that fit into this rule, substract the located address of the known module from the known base and save the offset and this delta like [offset, delta]. Now we can walk through the known library and write at those offsets the new_base + delta. With that we relocated the image to the requested address.

relocation_fix

4.) Just use the lists of the found imports and the relocations and write the data to a new instance of the known image. Encode it with base64, provide the entrypoint of the module ((known_entry – known_base) + new_base) and prepare the response.
done.

This is all it takes to emulate the iniuria server (and part of the client, actually).
Now, at this point we will not provide you with any binary, but since we want to educate people we provide a bit of code.

But first, here are the lessons learned from this from our point of view:
Even though the Pay to Cheat owners make way to much money out of blinded goons that seem to trust anyone as long they get a hack out of it, they don’t take anything serious. There are easy ways to make the job of people that want to break there systems waaaay harder, but that would require the coders to actually user their head and stop relying on the coder of other people. I won’t give hints what to do here, obviously, but the amount of sloppy coding and thinking with this example is depressing.

Anyway, since the hardest part of the emulator is to fix the images you need to prepare, I’ll provide that code here. The communication part is easily done if you have basic skills in one scripting language.

https://openload.io/f/BmeUrf7IGQM/fix_image.py