PDA

View Full Version : HCE Hash Verify in PHP (or CLI C++)



taterSALAD
November 17th, 2013, 09:47 PM
I saw urbanyoung's post in this thread here: http://www.modacity.net/forums/showthread.php?24469-Halo-Hash-Verifier-Halo-PC-Halo-CE

I (http://www.modacity.net/forums/showthread.php?24469-Halo-Hash-Verifier-Halo-PC-Halo-CE) was wondering if this could be made in either a CLI form or even in PHP.
Sorry if this is the wrong place.

RadWolfie
November 17th, 2013, 10:28 PM
Yes, this can be done in PHP. I'm not sure about CLI since I never used it before. It's just matter of time to translate the C++ code to PHP code.

taterSALAD
November 17th, 2013, 10:49 PM
I've tried to convert this into workable PHP code without much success. I just don't know enough about how sockets work and the way this data is parsed and handled to do it.
I'm basically asking for a little help here. Haha

Thanks to anyone who can help. :)

RadWolfie
November 17th, 2013, 11:35 PM
Try practice with official example as shown here (http://www.php.net/manual/en/sockets.examples.php). I haven't started on socket interfaces for PHP yet. I have done little work with sockets, only slightly familiar, and always kept getting the data overlapping.

Basically you will need to create (http://www.php.net/manual/en/function.socket-create.php) a socket and bind (http://www.php.net/manual/en/function.socket-bind.php) it to the operating system to open the door, if the firewall permit it, to the external network access. Once done, you can start connect (http://www.php.net/manual/en/function.socket-connect.php), as a client, to the other side of the listener. Finally, you can either send (http://www.php.net/manual/en/function.socket-send.php) or recieve (http://www.php.net/manual/en/function.socket-recv.php) data between the two. (Just follow the example and you can achieve this easily.) Although it may be slightly different from C++ and still part of the standard.

Also you can use the options (http://www.php.net/manual/en/function.socket-get-option.php) provided which must be done after create valid socket and before binding (I think).

Keep in mind: TCP required socket_listen and socket_accept to act as a server whilst UDP doesn't.

taterSALAD
November 18th, 2013, 12:01 AM
This is the code I'm doing right now but it's not working as expected. It just hangs. D:
I'm so clueless... Sorry


$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_bind($socket, 0, 0);
$host="halor.master.gamespy.com";
$port=29910;
socket_connect($socket, $host, $port);
$hash = "a29682363c72fdbe6197f62c5040032c";
buf = "";
$string = '\\auth\\\\pid\\793\\ch\\nxdqevx\\resp\\'.$hash.'1 2345678'.$hash.'\\ip\\0\\skey\\12345';
echo $string;
socket_sendto($socket, $string, strlen($string), 0, $host, $port);
socket_recvfrom($socket, $buf, 1, 0, $host, $port);
echo $buf;

RadWolfie
November 18th, 2013, 12:48 AM
The port may should be 2301, base on research from Internet. I'm not sure the server's opening port yet for gamespy. And I'm not sure about the host name either. And I know there are some here that knows how to use the gamespy query. So, I'll let them answer.

P.S. Haven't research on gamespy protocol aka haven't hook into gamespy sender/receiver and its parameters. But I have done is either allow validate the gamespy cd hash or not along with response back from gamespy on server-side.

taterSALAD
November 18th, 2013, 01:13 AM
I just used the information I pulled from the source in the topic I linked above.

urbanyoung1
November 20th, 2013, 02:09 AM
I cannot for the life of me remember my username/password, or the email I used to register. So screw it, I made a new account.

Anyway, it looks like you're attempting to use connection-based sockets instead of connection-less ones, ie TCP vs UDP. I'm not familiar with PHP's sockets, but it I'm pretty sure you don't want to use both socket_connect and socket_sendto/recvfrom. connect is for connection-based sockets (hence its name) and sendto/recvfrom are for connection-less sockets. In this particular case, you're wanting to use connection-less sockets.

You said a CLI C++ version will do, so try this and just system call it from PHP. It returns 0 on success, which means it received a valid response - it does not mean the hash is valid. To check if the hash is valid you'll need to check stdout, either 'valid' or 'invalid' will be printed. If it returns 1 then something went wrong.


#ifdef _WIN32#include <windows.h>
#else
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>


typedef int SOCKET;
static const int SOCKET_ERROR = -1;
#endif


#include <stdio.h>
#include <vector>
#include <iostream>
#include <sstream>
#include <cstring>


#ifdef _WIN32
#pragma comment(lib, "ws2_32.lib")
#endif


using std::cout;
using std::endl;
using std::cerr;


std::vector<char> transform_data(const char* input, size_t length)
{
std::vector<char> output;
output.reserve(length);


static const std::string mask = "gamespy";


for (size_t i = 0, j = 0; i < length; i++)
{
if (j == mask.size()) j = 0;
output.push_back(input[i] ^ mask[j++]);
}
return output;
}


// http://www.gamedev.net/community/forums/topic.asp?topic_id=381544#TokenizeString
std::vector<std::string> TokenizeString(const std::string& str, const std::string& delim)
{
using namespace std;
vector<string> tokens;
size_t p0 = 0, p1 = string::npos;
while (p0 != string::npos)
{
p1 = str.find_first_of(delim, p0);
if (p1 != p0)
{
string token = str.substr(p0, p1 - p0);
tokens.push_back(token);
}
p0 = str.find_first_not_of(delim, p1);
}
return tokens;
}


hostent* get_host(const char * host)
{
if (inet_addr(host) == INADDR_NONE) {
return gethostbyname(host);
}
else {
unsigned long addr = 0;
addr = inet_addr(host);
return gethostbyaddr((char*)&addr, sizeof(addr), AF_INET);
}
}


#ifdef _WIN32
struct wsa
{
wsa() {
auto result = WSAStartup(MAKEWORD(2, 2), &data);
if (result != ERROR_SUCCESS)
throw std::runtime_error("cannot initialize winsock.");
}


~wsa() {
WSACleanup();
}


WSADATA data;
};
#endif
int main(int argc, char** argv)
{
try {
if (argc != 2) {
cerr << "usage: " << argv[0] << " <hash>" << endl;
return 1;
}


const char* hash = argv[1];
if (strlen(hash) != 32) {
cout << "invalid" << endl;
return 0;
}
#ifdef _WIN32
wsa w;
#endif
sockaddr_in svr, local;


hostent* host = get_host("halor.master.gamespy.com");


if (!host) {
cerr << "cannot resolve halor.master.gamespy.com." << endl;
return 1;
}


svr.sin_addr.s_addr = *((unsigned long*)host->h_addr);
svr.sin_family = AF_INET;
svr.sin_port = htons(29910);


local.sin_family = AF_INET;
local.sin_addr.s_addr = 0;
local.sin_port = 0; // choose any


SOCKET s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
// bind to the local address
int r = bind(s, (sockaddr *)&local, sizeof(local));


if (r == SOCKET_ERROR) {
cerr << "cannot bind the local socket." << endl;
return 1;
}


std::ostringstream ss;
ss << "\\auth\\\\pid\\793\\"
<< "ch\\nxdqevx\\resp\\" // server key
<< hash
<< "12345678" // client key
<< hash // auth token, but we can't generate a valid one
<< "\\ip\\0" // ip address, 0 = local
<< "\\skey\\12345"; // server key for iding resonse


std::string input = ss.str();
std::vector<char> data = transform_data(input.c_str(), input.size());


// send the pkt
int ret = sendto(s, (const char*)&data[0], data.size(), 0, (sockaddr *)&svr, sizeof(svr));


char buff[1024];
sockaddr_in from;
#ifdef _WIN32
int len;
#else
socklen_t len;
#endif

len = sizeof(from);


int bytesReceived = recvfrom(s, (char*)&buff, sizeof(buff), 0, (sockaddr *)&from, &len);
std::vector<char> result = transform_data(buff, bytesReceived);


std::string result_str((const char*)&result[0], bytesReceived);
std::vector<std::string> tokens = TokenizeString(result_str, "\\");


if (tokens.size())
{
if (tokens[tokens.size() - 1] == "Invalid CD Key")
cout << "invalid" << endl;
else if (tokens[tokens.size() - 1] == "Invalid authentication")
cout << "valid" << endl;
else {
cerr << "error: " << endl << result_str << endl;
return 1;
}


return 0;
}
} catch (std::exception& e) {
cerr << e.what() << endl;
}
return 1;
}

edit: updated code so it builds on linux

taterSALAD
November 20th, 2013, 11:11 AM
Thank's so much Oxide! This is funny though, because we're actually using this in a Phasor script since OnGamespyCheck hasn't been implemented yet. XD

EDIT:
We have a list of known shared hashes. I thought these were caught and GameSpy had them blocked from authenticating. They're still showing up as valid on this. Is there a reason why or am I wrong in my belief that they were flagged by GameSpy?

urbanyoung1
November 20th, 2013, 10:10 PM
IIRC they will only be blocked if somebody is currently in a server using that hash.

taterSALAD
November 21st, 2013, 08:59 AM
These shared hashes are very, very common. I would honestly be surprised if they weren't in use at any given time.
EDIT: Servers that allow these hashes though, don't authenticate them though, do they? Meaning they never get reported as being "used" at that moment in time.

How come they get rejected from servers with validation though?

RadWolfie
November 22nd, 2013, 05:08 PM
We have a list of known shared hashes. I thought these were caught and GameSpy had them blocked from authenticating. They're still showing up as valid on this. Is there a reason why or am I wrong in my belief that they were flagged by GameSpy?
GameSpy only block the known key generator, fake key, and key that's in used on another server.


These shared hashes are very, very common. I would honestly be surprised if they weren't in use at any given time.
This would be likely a family computer which is using the same Halo game or the same player changing names.


EDIT: Servers that allow these hashes though, don't authenticate them though, do they? Meaning they never get reported as being "used" at that moment in time.

How come they get rejected from servers with validation though?
Only the private server that doesn't do the authenticate and therefore never will get "reported" as in used. The only time they (valid cd key users) get rejected from the public server is due to key in used or banned key and possible IP address if you're using third-party modification which controls the ban system.

P.S. I think Phasor always output the GameSpy response to the console base on last time reviewing the Phasor's CE version.

YetiSnak
November 22nd, 2013, 05:39 PM
Servers that allow these hashes though, don't authenticate them though, do they? Meaning they never get reported as being "used" at that moment in time.

How come they get rejected from servers with validation though?

The reason those hashes show up as valid through oxide's code is because they are valid, they show up as unvalid in gamespy when other people are in the server with that hash.

I'm guessing the servers that allow those hashes dont check the cd key similar to what this patcher does http://brandinimp.com/?p=170

the reason those hashes get rejected fro servers with validation is probably to prevent shared cd keys.
Idk if you can query the server for hashes in use to see if that hash is being used.



(http://brandinimp.com/?p=170)

Btcc22
November 22nd, 2013, 05:43 PM
GameSpy only block the known key generator, fake key, and key that's in used on another server.

Plus keys that are shared about on various websites. A huge list of them was blacklisted quite recently.

taterSALAD
November 22nd, 2013, 11:28 PM
The list of shared hashes we have are known to be wildly shared with many different copies of Halo, not family hashes. Simple google results show many names banned by these and private research showed them being used by IP addresses from many different locations.

Thanks for all of the responses guys! Very helpful. :)

Sean Aero
November 29th, 2013, 05:38 AM
just out of curiosity for what purpose would you like to use it?

chrisk123999
December 3rd, 2013, 08:36 AM
We're using it in conjunction with Phasor to make make a stat tracker that you don't need to sign up for to use. It's more or less quite functional, but we want to weed out any invalid hashes from displaying on the website. We're also using it for our own internal admin system (auto ban or IP ban depending on valid hash).

Still a work in progress, but this (http://chris.2g1m.net/)is what it adds up to so far.

Patrickssj6
December 3rd, 2013, 09:33 AM
If you need some more inspiration. (http://www.modacity.net/forums/showthread.php?23088-Shame...) You should also focus on SQL safety.