They are all made for Ragnarok 2 or sumthin but can be appliede to mabinogi
Its for a different game but still very usefull. Think of RagII.exe as client.exe
- EhSvc.dll
the main Hackshield file, contains the HackShield class used by Engine.dll,
does the basic functions like loading/unloading its kernel mode driver, file integrity scanning,
memory integrity scanning. the checksum generated by the integrity scans are used to authenticate with the game-server
- v3warpns.v3d and v3warpds.v3d
contain each a kernel mode driver (.sys file) in encrypted from, one v3d contains a win9x driver the other a winNT driver.
once the driver has been loaded it will protect the ro process from being accessed (read/write) by every non-kernel mode programm
(example: taskmanager)
- v3pro32s.dll
i didn't look at it yet, but i suspect it to be the loader for the .sys driver files (.v3d files)
maybe not written by Hackshield creators
- EGRNAP.dll and EGRNAPX2.dll
ahhnlab "anti-virus" scanning libs, probably used to scann for programms like packet sniffers, memory editors etc
- Hshield.log
produced by EhSvc.dll, its encrypted with an evolving XOR key, i've reversed that algo, its included in my hackshield emu source & there's a ready to use decryption tool in SagaTools, however it doesn't contain much useful info (basically logs detections/checksum errors for gravity/hackshield to investigate)
- psapi.dll
a proccess helper library by Microsoft, nothing special
Defeating Hackshield
Disabling Hackshield is pretty easy and means basically hooking/patching the functions "StartServiceW" of the Hackshield class which is an export of EhSvc.dll.
Either its wrapper inside of Engine.dll, or directly in EhSvc.dll. Just do nothing and return - that's all.
However, after doing that MakeGUIDAckMsg() and MakeAckMsg(), both exports of EhSvc.dll will stop working and therefore we can't authenticate with the gameserver anymore.
To solve that issue one way would be to patch all "has hackshield been started" checks in side of those Make..Msg() functions,it will work fine, however it has one big downside. To understand it , we have to look at how these functions "generate" the authentication answers.
1.) MakeGUIDAckMsg()
In short this functions reads the GUID of EhSvc.dll (16 bytes) directly from that file on your harddisk, encrypts it and sends it to the server.
Okay, that shouldn't be a big deal, we just have to make sure that these 16 bytes remain intact and we are safe.
2.)MakeAckMsg()
This function is a bit more complicated, it does:
-generate a file checksum of RagII.exe
-generate a file checksum of EhSvc.dll and EGRNAP.dll
-generate a file checksum of v3warpns.v3d and v3warpds.v3d
-generate a proccess memory checksum of up to 32 function addresses in proccess-memory
It's important to know that the RagII.exe checksum is calculated "dynamicly" as i name it, that means:
the gameserver sends hackshield a start-offset and a size for a part of RagII.exe.
These values will be random, so the checksum will always be different.
The other checksums are static, so they will always be the same.
The memory checksum is the most annoying part of that authentication, that's because the function addresses are given by the server (they can be random), making it very powerfull.
As we don't know which memory locations might be requested, we can't be sure our modifications will be detected or not.
Back to topic : that's the downside i've talked of earlier: just forcing the auth-answers to be enabled will enable the game-server to detect any modifications to the checked files and any memory locations.
Of course we can redirect the file checks to backuped files in another location pretty easily, but the memory scans are very hard to fool (as RagII.exe,Engine.dll,etc are packed with TheMida file-data will NOT match memory-data on run-time)
To come by that issue, i've re-written both MakeGUIDAckMsg() and MakeAckMsg() , put them inside my hack and redirected all calls to the originals functions to my Make..Msg() functions.
At proccess startup, i take a snapshot of the important memory locations (RagII.exe, Engine.dll, etc). Now if the server requests MakeAckMsg() data, i use the snapshots instead of the current memory data. >> Hackshield is fully bypassed!
Remarks
- currently only the OEP of RagII.exe is checked by the memory check, this is pretty weak (its always the same check - same checksum returned)
- in future grav could use these memory checks to fights bots somehow,
HOWEVER:
-> bots that work together with the original client can be easily implemented without detailed knowlegde of hackshield
-> these challenges are only used once at connect, never during gameplay > weak
-> stand-alone bots are affected by this memory checks, however the only challenge is knowlede of the unpacked .exe/.dll data (and only if they'll start to make memory checks being random, which is not the case atm)
the main Hackshield file, contains the HackShield class used by Engine.dll,
does the basic functions like loading/unloading its kernel mode driver, file integrity scanning,
memory integrity scanning. the checksum generated by the integrity scans are used to authenticate with the game-server
- v3warpns.v3d and v3warpds.v3d
contain each a kernel mode driver (.sys file) in encrypted from, one v3d contains a win9x driver the other a winNT driver.
once the driver has been loaded it will protect the ro process from being accessed (read/write) by every non-kernel mode programm
(example: taskmanager)
- v3pro32s.dll
i didn't look at it yet, but i suspect it to be the loader for the .sys driver files (.v3d files)
maybe not written by Hackshield creators
- EGRNAP.dll and EGRNAPX2.dll
ahhnlab "anti-virus" scanning libs, probably used to scann for programms like packet sniffers, memory editors etc
- Hshield.log
produced by EhSvc.dll, its encrypted with an evolving XOR key, i've reversed that algo, its included in my hackshield emu source & there's a ready to use decryption tool in SagaTools, however it doesn't contain much useful info (basically logs detections/checksum errors for gravity/hackshield to investigate)
- psapi.dll
a proccess helper library by Microsoft, nothing special
Defeating Hackshield
Disabling Hackshield is pretty easy and means basically hooking/patching the functions "StartServiceW" of the Hackshield class which is an export of EhSvc.dll.
Either its wrapper inside of Engine.dll, or directly in EhSvc.dll. Just do nothing and return - that's all.
However, after doing that MakeGUIDAckMsg() and MakeAckMsg(), both exports of EhSvc.dll will stop working and therefore we can't authenticate with the gameserver anymore.
To solve that issue one way would be to patch all "has hackshield been started" checks in side of those Make..Msg() functions,it will work fine, however it has one big downside. To understand it , we have to look at how these functions "generate" the authentication answers.
1.) MakeGUIDAckMsg()
In short this functions reads the GUID of EhSvc.dll (16 bytes) directly from that file on your harddisk, encrypts it and sends it to the server.
Okay, that shouldn't be a big deal, we just have to make sure that these 16 bytes remain intact and we are safe.
2.)MakeAckMsg()
This function is a bit more complicated, it does:
-generate a file checksum of RagII.exe
-generate a file checksum of EhSvc.dll and EGRNAP.dll
-generate a file checksum of v3warpns.v3d and v3warpds.v3d
-generate a proccess memory checksum of up to 32 function addresses in proccess-memory
It's important to know that the RagII.exe checksum is calculated "dynamicly" as i name it, that means:
the gameserver sends hackshield a start-offset and a size for a part of RagII.exe.
These values will be random, so the checksum will always be different.
The other checksums are static, so they will always be the same.
The memory checksum is the most annoying part of that authentication, that's because the function addresses are given by the server (they can be random), making it very powerfull.
As we don't know which memory locations might be requested, we can't be sure our modifications will be detected or not.
Back to topic : that's the downside i've talked of earlier: just forcing the auth-answers to be enabled will enable the game-server to detect any modifications to the checked files and any memory locations.
Of course we can redirect the file checks to backuped files in another location pretty easily, but the memory scans are very hard to fool (as RagII.exe,Engine.dll,etc are packed with TheMida file-data will NOT match memory-data on run-time)
To come by that issue, i've re-written both MakeGUIDAckMsg() and MakeAckMsg() , put them inside my hack and redirected all calls to the originals functions to my Make..Msg() functions.
At proccess startup, i take a snapshot of the important memory locations (RagII.exe, Engine.dll, etc). Now if the server requests MakeAckMsg() data, i use the snapshots instead of the current memory data. >> Hackshield is fully bypassed!
Remarks
- currently only the OEP of RagII.exe is checked by the memory check, this is pretty weak (its always the same check - same checksum returned)
- in future grav could use these memory checks to fights bots somehow,
HOWEVER:
-> bots that work together with the original client can be easily implemented without detailed knowlegde of hackshield
-> these challenges are only used once at connect, never during gameplay > weak
-> stand-alone bots are affected by this memory checks, however the only challenge is knowlede of the unpacked .exe/.dll data (and only if they'll start to make memory checks being random, which is not the case atm)
Some more stuff I found about emulating HS
HShieldEmu.h
PHP Code:
#ifndef __HACKSHIELDEMU_H
#define __HACKSHIELDEMU_H
#include "global.h"
struct hshield_packet_ack_server {
DWORD IntegrityCheck1_offset_ragII_exe;
DWORD IntegrityCheck1_size_ragII_exe;
DWORD VerfiyCheck_data;
DWORD enabled_checks;
DWORD MemoryCheck_function_adresses[32];
};
struct hshield_packet_ack_client {
DWORD VerifyCheck_checksum[2];
BYTE IntegrityCheck1_checksum[16];
BYTE MemoryCheck_checksum[16];
BYTE IntegrityCheck2_checksum[16];
BYTE IntegrityCheck3_checksum[16];
};
static class HackShieldEmu {
enum doHShieldCheckFlags {
doMemoryCheck = 1, // calculate checksums of function addresses given by the server
doIntegrityCheck1 = 2, // calculate checksum of RagII.exe
doIntegrityCheck2 = 4, // calculate checksum of Ehsvc.dll and EGRNAP.dll
doIntegrityCheck3 = 8, // calculate checksum of v3warpds.v3d and v3warpns.v3d
};
// hshield MakeGUIDAckMsg() and MakeGUIDAck() functions
//
// calculates the GUIDAck answer for given challenge input (20 bytes)
// output is 20 bytes
// reuturns 0 if successful
int MakeGUIDAckMsg(unsigned char *input, unsigned char *ack_answer);
// input: 160 bytes from server->client ack packet
// ack_answer: 72 bytes for the client->server packet
// returns 0 if succesful
int MakeAckMSG(unsigned char *input, unsigned char *ack_answer);
// input: the first 16 bytes from hshield server packet
// output: 16 bytes aes key
void calculate_hshield_aeskey(unsigned char* input, unsigned char* output)
// internal functions, not documented here
int GetCustumMD5OfFile(char *filename,DWORD offset, DWORD size, BYTE *output);
int GetMemoryCheckData(hshield_packet_ack_server *ackData,hshield_packet_ack_client *ackAnswer);
int GetIntegrityCheck1Data(hshield_packet_ack_server *ackData,hshield_packet_ack_client *ackAnswer);
int GetIntegrityCheck2Data(hshield_packet_ack_server *ackData,hshield_packet_ack_client *ackAnswer);
int GetIntegrityCheck3Data(hshield_packet_ack_server *ackData,hshield_packet_ack_client *ackAnswer);
// hshield.log de-/encryption functions
//
// format of a hshield.log file:
//
// struct hshield_log_file {
// hshield_log_entry entries[x];
// };
//
// struct hshield_log_entry {
// int log_size;
// unsigned char log_data[log_size];
// };
//
// output: pointer to the output buffer (must have same size as input buffer)
// input: pointer to the input buffer
// sizeInput: size of the input buffer (in bytes)
// key: key used for de-/encryption (RO2 default key is 1252)
int encrypt_logfile_data(unsigned char *output, unsigned char *input, int sizeInput,DWORD key = 1252);
int decrypt_logfile_data(unsigned char *output, unsigned char *input, int sizeInput,DWORD key = 1252);
};
#endif
#define __HACKSHIELDEMU_H
#include "global.h"
struct hshield_packet_ack_server {
DWORD IntegrityCheck1_offset_ragII_exe;
DWORD IntegrityCheck1_size_ragII_exe;
DWORD VerfiyCheck_data;
DWORD enabled_checks;
DWORD MemoryCheck_function_adresses[32];
};
struct hshield_packet_ack_client {
DWORD VerifyCheck_checksum[2];
BYTE IntegrityCheck1_checksum[16];
BYTE MemoryCheck_checksum[16];
BYTE IntegrityCheck2_checksum[16];
BYTE IntegrityCheck3_checksum[16];
};
static class HackShieldEmu {
enum doHShieldCheckFlags {
doMemoryCheck = 1, // calculate checksums of function addresses given by the server
doIntegrityCheck1 = 2, // calculate checksum of RagII.exe
doIntegrityCheck2 = 4, // calculate checksum of Ehsvc.dll and EGRNAP.dll
doIntegrityCheck3 = 8, // calculate checksum of v3warpds.v3d and v3warpns.v3d
};
// hshield MakeGUIDAckMsg() and MakeGUIDAck() functions
//
// calculates the GUIDAck answer for given challenge input (20 bytes)
// output is 20 bytes
// reuturns 0 if successful
int MakeGUIDAckMsg(unsigned char *input, unsigned char *ack_answer);
// input: 160 bytes from server->client ack packet
// ack_answer: 72 bytes for the client->server packet
// returns 0 if succesful
int MakeAckMSG(unsigned char *input, unsigned char *ack_answer);
// input: the first 16 bytes from hshield server packet
// output: 16 bytes aes key
void calculate_hshield_aeskey(unsigned char* input, unsigned char* output)
// internal functions, not documented here
int GetCustumMD5OfFile(char *filename,DWORD offset, DWORD size, BYTE *output);
int GetMemoryCheckData(hshield_packet_ack_server *ackData,hshield_packet_ack_client *ackAnswer);
int GetIntegrityCheck1Data(hshield_packet_ack_server *ackData,hshield_packet_ack_client *ackAnswer);
int GetIntegrityCheck2Data(hshield_packet_ack_server *ackData,hshield_packet_ack_client *ackAnswer);
int GetIntegrityCheck3Data(hshield_packet_ack_server *ackData,hshield_packet_ack_client *ackAnswer);
// hshield.log de-/encryption functions
//
// format of a hshield.log file:
//
// struct hshield_log_file {
// hshield_log_entry entries[x];
// };
//
// struct hshield_log_entry {
// int log_size;
// unsigned char log_data[log_size];
// };
//
// output: pointer to the output buffer (must have same size as input buffer)
// input: pointer to the input buffer
// sizeInput: size of the input buffer (in bytes)
// key: key used for de-/encryption (RO2 default key is 1252)
int encrypt_logfile_data(unsigned char *output, unsigned char *input, int sizeInput,DWORD key = 1252);
int decrypt_logfile_data(unsigned char *output, unsigned char *input, int sizeInput,DWORD key = 1252);
};
#endif
HShieldEmu.cpp
PHP Code:
#include "HackShieldEmu.h"
int HackShieldEmu::MakeGUIDAckMsg(unsigned char *input, unsigned char *ack_answer)
{
unsigned char *encryption_key = new unsigned char[16];
calculate_hshield_aeskey(&input[0],encryption_key);
unsigned char guid_of_EhSvc_dll[]= { 0xF6 , 0x33 , 0x08 , 0x58 , 0x90 , 0x28 , 0x80 , 0x44 , 0x81 , 0xDF , 0xA5 , 0xC9 , 0x19 , 0x6D , 0x46 , 0xF7 };
memcpy(&guid_answer[4],guid_of_EhSvc_dll,16);
unsigned char *decrypted_input = new unsigned char[4];
Decrypt(&input[16],4, decrypted_input, encryption_key);
DWORD *a1 = (DWORD*)&decrypted_input[0];
DWORD *a2 = (DWORD*)&guid_answer[0];
*a2 = -1658038656 & (((*a1 >> 11) ^ *a1) << 7) ^ (*a1 >> 11) ^ *a1;
Encrypt(ack_answer,20,guid_answer,encryption_key);
delete[] encryption_key;
delete[] decrypted_input;
return 0;
}
int HackShieldEmu::MakeAckMSG(unsigned char *input, unsigned char *ack_answer)
{
hshield_packet_ack_client *ackAnswer = (hshield_packet_ack_client*)ack_answer;
memset(ackAnswer,0,72);
unsigned char *encryption_key = new unsigned char[16];
calculate_hshield_aeskey(&input[0],encryption_key);
hshield_packet_ack_server *ackData = new hshield_packet_ack_server();
Decrypt(&input[16],144, (BYTE*)ackData, encryption_key);
// always do VerifyCheck
ackAnswer->VerifyCheck_checksum[0] = -1658038656 & (((ackData->VerfiyCheck_data >> 11) ^ ackData->VerfiyCheck_data) << 7) ^ (ackData->VerfiyCheck_data >> 11) ^ ackData->VerfiyCheck_data;
ackAnswer->VerifyCheck_checksum[1] = ackData->VerfiyCheck_data ^ (ackData->VerfiyCheck_data << 15);
// do MemoryCheck if requested
if(ackData->enabled_checks & doMemoryCheck) {
if(GetMemoryCheckData(ackData,ackAnswer)) return 1;
}
// do IntegrityCheck1 if requested
if(ackData->enabled_checks & doIntegrityCheck1) {
if(GetIntegrityCheck1Data(ackData,ackAnswer)) return 2;
}
// do IntegrityCheck2 if requested
if(ackData->enabled_checks & doIntegrityCheck2) {
if(GetIntegrityCheck2Data(ackData,ackAnswer)) return 3;
}
// do IntegrityCheck3 if requested
if(ackData->enabled_checks & doIntegrityCheck3) {
if(GetIntegrityCheck3Data(ackData,ackAnswer)) return 4;
}
Encrypt((BYTE*)ackAnswer,72,(BYTE*)ackAnswer,encry ption_key);
delete[] encryption_key;
delete ackData;
return 0;
}
int HackShieldEmu::GetCustumMD5OfFile(char *filename,DWORD offset, DWORD size, BYTE *output)
{
ifstream file (filename, ios::in|ios::binary|ios::ate);
if (file.is_open())
{
ifstream::pos_type fsize = file.tellg();
DWORD ifsize = (DWORD)fsize;
BYTE *filebuf = new unsigned char [fsize];
file.seekg (0, ios::beg);
file.read((char*)filebuf, fsize);
file.close();
md5_state_t state;
md5_init(&state);
if(offset || size) {
md5_append_hshield(&state, &filebuf[offset], size);
md5_append_hshield(&state, &filebuf[0], ifsize);
}
else {
md5_append_hshield(&state, &filebuf[0], 40);
md5_append_hshield(&state, &filebuf[60], ifsize-60);
}
md5_finish_hshield(&state, output);
delete[] filebuf;
return 0;
}
return 1;
}
int HackShieldEmu::GetMemoryCheckData(hshield_packet_a ck_server *ackData,hshield_packet_ack_client *ackAnswer)
{
md5_state_t state;
md5_init(&state);
for(int i=0; i<32; i++) {
if(ackData->MemoryCheck_function_adresses[i] == 0) break;
DWORD pointer = ackData->MemoryCheck_function_adresses[i];
DWORD len = 0;
while(true) {
t_disasm da;
pointer += Disasm((char*)pointer,MAXCMDSIZE,0x400000,&da,DISA SM_SIZE);
if(*(BYTE*)pointer == 0xC2 ) break; // ret value
else if(*(BYTE*)pointer == 0xC3 ) break; // ret
else if(*(BYTE*)pointer == 0xCA ) break; // retf value
else if(*(BYTE*)pointer == 0xCB ) break; // retf
}
DWORD length = pointer - ackData->MemoryCheck_function_adresses[i];
if(length > 0) {
unsigned char md5_buffer[16];
md5_get_hshield(&md5_buffer[0], (BYTE*)ackData->MemoryCheck_function_adresses[i], length);
md5_append_hshield(&state, &md5_buffer[0], 16);
}
}
md5_finish_hshield(&state, &ackAnswer->MemoryCheck_checksum[0]);
return 0;
}
int HackShieldEmu::GetIntegrityCheck1Data(hshield_pack et_ack_server *ackData,hshield_packet_ack_client *ackAnswer)
{
return GetCustumMD5OfFile("..\\checksum_files\\RagII.exe" , ackData->IntegrityCheck1_offset_ragII_exe, ackData->IntegrityCheck1_size_ragII_exe, &ackAnswer->IntegrityCheck1_checksum[0]);
}
int HackShieldEmu::GetIntegrityCheck2Data(hshield_pack et_ack_server *ackData,hshield_packet_ack_client *ackAnswer)
{
md5_state_t state;
md5_init(&state);
unsigned char temp_md5[16];
if(GetCustumMD5OfFile("..\\checksum_files\\Ehsvc.d ll", 0, 0, &temp_md5[0])) return 1;
md5_append_hshield(&state, &temp_md5[0], 16);
if(GetCustumMD5OfFile("..\\checksum_files\\EGRNAP. dll", 0, 0, &temp_md5[0])) return 2;
md5_append_hshield(&state, &temp_md5[0], 16);
md5_finish_hshield(&state, &ackAnswer->IntegrityCheck2_checksum[0]);
return 0;
}
int HackShieldEmu::GetIntegrityCheck3Data(hshield_pack et_ack_server *ackData,hshield_packet_ack_client *ackAnswer)
{
md5_state_t state;
md5_init(&state);
unsigned char temp_md5[16];
if(GetCustumMD5OfFile("..\\checksum_files\\v3warpd s.v3d", 0, 0, &temp_md5[0])) return 1;
md5_append_hshield(&state, &temp_md5[0], 16);
if(GetCustumMD5OfFile("..\\checksum_files\\v3warpn s.v3d", 0, 0, &temp_md5[0])) return 2;
md5_append_hshield(&state, &temp_md5[0], 16);
md5_finish_hshield(&state, &ackAnswer->IntegrityCheck3_checksum[0]);
return 0;
}
void HackShieldEmu::calculate_hshield_aeskey(unsigned char* input, unsigned char* output)
{
unsigned char *temp = new unsigned char[20];
memcpy(temp, input, 16);
for(int i=0;i<5;i++)
{
md5_state_t state;
md5_init(&state);
md5_append_hshield(&state, temp, 16);
md5_finish_hshield(&state, temp);
for(int i=0; i<8;i++) temp[i] = temp[i] ^ temp[i+8];
}
unsigned char *temp2 = new unsigned char[20];
for(int i=0;i<4;i++)
{
DWORD *dtemp1 = (DWORD*)&temp[i*4];
DWORD *dtemp2 = (DWORD*)&temp2[i*4];
*dtemp2 = *dtemp1 & 0xFFFF0000;
*dtemp1 = (*dtemp1 * 69069 ) + 1;
*dtemp2 |= ( *dtemp1 & 0xFFFF0000 ) >> 16;
}
memcpy(output, temp2, 16);
delete[] temp;
delete[] temp2;
for(int i=0; i < 16; i++)
{
if(output[i] & 1) output[i] ^= 0xDF ^ (output[i] >> 1);
else output[i] ^= output[i] >> 1;
}
}
int HackShieldEmu::encrypt_logfile_data(unsigned char *output, unsigned char *input, int sizeInput,DWORD key)
{
if ( output && input && sizeOutput > 0 && sizeInput > 0 )
{
memset(output, 0, sizeInput);
if ( sizeInput > 0 )
{
unsigned char *v8 = new unsigned char[4];
DWORD *dword_v8 = (DWORD*)v8;
*v8 = 0x00000000;
unsigned char *temp_key = new unsigned char[4];
DWORD *dword_temp_key = (DWORD*)temp_key;
*dword_temp_key = key;
for(int i = 0; i < sizeInput; i++)
{
v8[1] = temp_key[1] ^ input[i]; // encrypt the input byte
output[i] = v8[1]; // write the encrypted input byte to the output
*dword_v8 = 12691 * (*dword_temp_key + v8[1]); // update v8
*dword_temp_key = 22719 - *dword_v8; // update tempkey
}
delete[] v8;
delete[] temp_key;
}
return 0;
}
return -1;
}
int HackShieldEmu::decrypt_logfile_data(unsigned char *output, unsigned char *input, int sizeInput,DWORD key = 1252)
{
if ( output && input && sizeOutput > 0 && sizeInput > 0 )
{
memset(output, 0, sizeInput);
if ( sizeInput > 0 )
{
unsigned char *v8 = new unsigned char[4];
DWORD *dword_v8 = (DWORD*)v8;
*v8 = 0x00000000;
unsigned char *temp_key = new unsigned char[4];
DWORD *dword_temp_key = (DWORD*)temp_key;
*dword_temp_key = key;
for(int i = 0; i < sizeInput; i++)
{
v8[1] = temp_key[1] ^ input[i]; // encrypt the input byte
output[i] = v8[1]; // write the encrypted input byte to the output
*dword_v8 = 12691 * (*dword_temp_key + input[i]); // update v8
*dword_temp_key = 22719 - *dword_v8; // update tempkey
}
delete[] v8;
delete[] temp_key;
}
return 0;
}
return -1;
}
int HackShieldEmu::MakeGUIDAckMsg(unsigned char *input, unsigned char *ack_answer)
{
unsigned char *encryption_key = new unsigned char[16];
calculate_hshield_aeskey(&input[0],encryption_key);
unsigned char guid_of_EhSvc_dll[]= { 0xF6 , 0x33 , 0x08 , 0x58 , 0x90 , 0x28 , 0x80 , 0x44 , 0x81 , 0xDF , 0xA5 , 0xC9 , 0x19 , 0x6D , 0x46 , 0xF7 };
memcpy(&guid_answer[4],guid_of_EhSvc_dll,16);
unsigned char *decrypted_input = new unsigned char[4];
Decrypt(&input[16],4, decrypted_input, encryption_key);
DWORD *a1 = (DWORD*)&decrypted_input[0];
DWORD *a2 = (DWORD*)&guid_answer[0];
*a2 = -1658038656 & (((*a1 >> 11) ^ *a1) << 7) ^ (*a1 >> 11) ^ *a1;
Encrypt(ack_answer,20,guid_answer,encryption_key);
delete[] encryption_key;
delete[] decrypted_input;
return 0;
}
int HackShieldEmu::MakeAckMSG(unsigned char *input, unsigned char *ack_answer)
{
hshield_packet_ack_client *ackAnswer = (hshield_packet_ack_client*)ack_answer;
memset(ackAnswer,0,72);
unsigned char *encryption_key = new unsigned char[16];
calculate_hshield_aeskey(&input[0],encryption_key);
hshield_packet_ack_server *ackData = new hshield_packet_ack_server();
Decrypt(&input[16],144, (BYTE*)ackData, encryption_key);
// always do VerifyCheck
ackAnswer->VerifyCheck_checksum[0] = -1658038656 & (((ackData->VerfiyCheck_data >> 11) ^ ackData->VerfiyCheck_data) << 7) ^ (ackData->VerfiyCheck_data >> 11) ^ ackData->VerfiyCheck_data;
ackAnswer->VerifyCheck_checksum[1] = ackData->VerfiyCheck_data ^ (ackData->VerfiyCheck_data << 15);
// do MemoryCheck if requested
if(ackData->enabled_checks & doMemoryCheck) {
if(GetMemoryCheckData(ackData,ackAnswer)) return 1;
}
// do IntegrityCheck1 if requested
if(ackData->enabled_checks & doIntegrityCheck1) {
if(GetIntegrityCheck1Data(ackData,ackAnswer)) return 2;
}
// do IntegrityCheck2 if requested
if(ackData->enabled_checks & doIntegrityCheck2) {
if(GetIntegrityCheck2Data(ackData,ackAnswer)) return 3;
}
// do IntegrityCheck3 if requested
if(ackData->enabled_checks & doIntegrityCheck3) {
if(GetIntegrityCheck3Data(ackData,ackAnswer)) return 4;
}
Encrypt((BYTE*)ackAnswer,72,(BYTE*)ackAnswer,encry ption_key);
delete[] encryption_key;
delete ackData;
return 0;
}
int HackShieldEmu::GetCustumMD5OfFile(char *filename,DWORD offset, DWORD size, BYTE *output)
{
ifstream file (filename, ios::in|ios::binary|ios::ate);
if (file.is_open())
{
ifstream::pos_type fsize = file.tellg();
DWORD ifsize = (DWORD)fsize;
BYTE *filebuf = new unsigned char [fsize];
file.seekg (0, ios::beg);
file.read((char*)filebuf, fsize);
file.close();
md5_state_t state;
md5_init(&state);
if(offset || size) {
md5_append_hshield(&state, &filebuf[offset], size);
md5_append_hshield(&state, &filebuf[0], ifsize);
}
else {
md5_append_hshield(&state, &filebuf[0], 40);
md5_append_hshield(&state, &filebuf[60], ifsize-60);
}
md5_finish_hshield(&state, output);
delete[] filebuf;
return 0;
}
return 1;
}
int HackShieldEmu::GetMemoryCheckData(hshield_packet_a ck_server *ackData,hshield_packet_ack_client *ackAnswer)
{
md5_state_t state;
md5_init(&state);
for(int i=0; i<32; i++) {
if(ackData->MemoryCheck_function_adresses[i] == 0) break;
DWORD pointer = ackData->MemoryCheck_function_adresses[i];
DWORD len = 0;
while(true) {
t_disasm da;
pointer += Disasm((char*)pointer,MAXCMDSIZE,0x400000,&da,DISA SM_SIZE);
if(*(BYTE*)pointer == 0xC2 ) break; // ret value
else if(*(BYTE*)pointer == 0xC3 ) break; // ret
else if(*(BYTE*)pointer == 0xCA ) break; // retf value
else if(*(BYTE*)pointer == 0xCB ) break; // retf
}
DWORD length = pointer - ackData->MemoryCheck_function_adresses[i];
if(length > 0) {
unsigned char md5_buffer[16];
md5_get_hshield(&md5_buffer[0], (BYTE*)ackData->MemoryCheck_function_adresses[i], length);
md5_append_hshield(&state, &md5_buffer[0], 16);
}
}
md5_finish_hshield(&state, &ackAnswer->MemoryCheck_checksum[0]);
return 0;
}
int HackShieldEmu::GetIntegrityCheck1Data(hshield_pack et_ack_server *ackData,hshield_packet_ack_client *ackAnswer)
{
return GetCustumMD5OfFile("..\\checksum_files\\RagII.exe" , ackData->IntegrityCheck1_offset_ragII_exe, ackData->IntegrityCheck1_size_ragII_exe, &ackAnswer->IntegrityCheck1_checksum[0]);
}
int HackShieldEmu::GetIntegrityCheck2Data(hshield_pack et_ack_server *ackData,hshield_packet_ack_client *ackAnswer)
{
md5_state_t state;
md5_init(&state);
unsigned char temp_md5[16];
if(GetCustumMD5OfFile("..\\checksum_files\\Ehsvc.d ll", 0, 0, &temp_md5[0])) return 1;
md5_append_hshield(&state, &temp_md5[0], 16);
if(GetCustumMD5OfFile("..\\checksum_files\\EGRNAP. dll", 0, 0, &temp_md5[0])) return 2;
md5_append_hshield(&state, &temp_md5[0], 16);
md5_finish_hshield(&state, &ackAnswer->IntegrityCheck2_checksum[0]);
return 0;
}
int HackShieldEmu::GetIntegrityCheck3Data(hshield_pack et_ack_server *ackData,hshield_packet_ack_client *ackAnswer)
{
md5_state_t state;
md5_init(&state);
unsigned char temp_md5[16];
if(GetCustumMD5OfFile("..\\checksum_files\\v3warpd s.v3d", 0, 0, &temp_md5[0])) return 1;
md5_append_hshield(&state, &temp_md5[0], 16);
if(GetCustumMD5OfFile("..\\checksum_files\\v3warpn s.v3d", 0, 0, &temp_md5[0])) return 2;
md5_append_hshield(&state, &temp_md5[0], 16);
md5_finish_hshield(&state, &ackAnswer->IntegrityCheck3_checksum[0]);
return 0;
}
void HackShieldEmu::calculate_hshield_aeskey(unsigned char* input, unsigned char* output)
{
unsigned char *temp = new unsigned char[20];
memcpy(temp, input, 16);
for(int i=0;i<5;i++)
{
md5_state_t state;
md5_init(&state);
md5_append_hshield(&state, temp, 16);
md5_finish_hshield(&state, temp);
for(int i=0; i<8;i++) temp[i] = temp[i] ^ temp[i+8];
}
unsigned char *temp2 = new unsigned char[20];
for(int i=0;i<4;i++)
{
DWORD *dtemp1 = (DWORD*)&temp[i*4];
DWORD *dtemp2 = (DWORD*)&temp2[i*4];
*dtemp2 = *dtemp1 & 0xFFFF0000;
*dtemp1 = (*dtemp1 * 69069 ) + 1;
*dtemp2 |= ( *dtemp1 & 0xFFFF0000 ) >> 16;
}
memcpy(output, temp2, 16);
delete[] temp;
delete[] temp2;
for(int i=0; i < 16; i++)
{
if(output[i] & 1) output[i] ^= 0xDF ^ (output[i] >> 1);
else output[i] ^= output[i] >> 1;
}
}
int HackShieldEmu::encrypt_logfile_data(unsigned char *output, unsigned char *input, int sizeInput,DWORD key)
{
if ( output && input && sizeOutput > 0 && sizeInput > 0 )
{
memset(output, 0, sizeInput);
if ( sizeInput > 0 )
{
unsigned char *v8 = new unsigned char[4];
DWORD *dword_v8 = (DWORD*)v8;
*v8 = 0x00000000;
unsigned char *temp_key = new unsigned char[4];
DWORD *dword_temp_key = (DWORD*)temp_key;
*dword_temp_key = key;
for(int i = 0; i < sizeInput; i++)
{
v8[1] = temp_key[1] ^ input[i]; // encrypt the input byte
output[i] = v8[1]; // write the encrypted input byte to the output
*dword_v8 = 12691 * (*dword_temp_key + v8[1]); // update v8
*dword_temp_key = 22719 - *dword_v8; // update tempkey
}
delete[] v8;
delete[] temp_key;
}
return 0;
}
return -1;
}
int HackShieldEmu::decrypt_logfile_data(unsigned char *output, unsigned char *input, int sizeInput,DWORD key = 1252)
{
if ( output && input && sizeOutput > 0 && sizeInput > 0 )
{
memset(output, 0, sizeInput);
if ( sizeInput > 0 )
{
unsigned char *v8 = new unsigned char[4];
DWORD *dword_v8 = (DWORD*)v8;
*v8 = 0x00000000;
unsigned char *temp_key = new unsigned char[4];
DWORD *dword_temp_key = (DWORD*)temp_key;
*dword_temp_key = key;
for(int i = 0; i < sizeInput; i++)
{
v8[1] = temp_key[1] ^ input[i]; // encrypt the input byte
output[i] = v8[1]; // write the encrypted input byte to the output
*dword_v8 = 12691 * (*dword_temp_key + input[i]); // update v8
*dword_temp_key = 22719 - *dword_v8; // update tempkey
}
delete[] v8;
delete[] temp_key;
}
return 0;
}
return -1;
}
More info just found
Getting rid of HackShield is trivial, assuming the server does not validate any packets... such as is the case with Rappelez and ShotOnline , you can see this on my website ->
I have a simple walkthru I wrote for someone here (for ShotOnline) ->
This is more-or-less the following steps:
1. Unpack the game client .exe from whatever packer they are using.
2. Delete any HackShield related files from the game client folder, this includes: HShield.exe, Ehsvc.dll, the HShield sub directory, and any other .dll that if you mouse over it you see the words "AHNLabs".. you want to generate errors regarding the protection, the error messages are a really good clue as to where the routines you'll be patching are located.
3. Load the game client into OllyDbg, and run it - you will probably receive some kind of MessageBox error about HS... press F12, then alt F9 and click okay to the MessageBox -- now scroll up... you're looking for (usually) some kind of conditional jxx instruction that you'll patch to JMP... (set a bp and restart the game client from olly to test it.. ) some clients have a few and related error messages, or some have one big init routine that can be patched and the whole thing is skipped ; ) (i.e. Mabinogi)...
The best (and most simple) way of killing GG and HS to to never run them to start with. So this involves breaking on basic winapi (yes winapi - not the native api, or some kernel mode api, like some morons think =) functions like CreateProcessA (GameGuard) or LoadLibraryA (Ehsvc.dll for HS) and seeing that their processes or threads never get created.
I have a simple walkthru I wrote for someone here (for ShotOnline) ->
This is more-or-less the following steps:
1. Unpack the game client .exe from whatever packer they are using.
2. Delete any HackShield related files from the game client folder, this includes: HShield.exe, Ehsvc.dll, the HShield sub directory, and any other .dll that if you mouse over it you see the words "AHNLabs".. you want to generate errors regarding the protection, the error messages are a really good clue as to where the routines you'll be patching are located.
3. Load the game client into OllyDbg, and run it - you will probably receive some kind of MessageBox error about HS... press F12, then alt F9 and click okay to the MessageBox -- now scroll up... you're looking for (usually) some kind of conditional jxx instruction that you'll patch to JMP... (set a bp and restart the game client from olly to test it.. ) some clients have a few and related error messages, or some have one big init routine that can be patched and the whole thing is skipped ; ) (i.e. Mabinogi)...
The best (and most simple) way of killing GG and HS to to never run them to start with. So this involves breaking on basic winapi (yes winapi - not the native api, or some kernel mode api, like some morons think =) functions like CreateProcessA (GameGuard) or LoadLibraryA (Ehsvc.dll for HS) and seeing that their processes or threads never get created.