urbanyoung
April 12th, 2012, 01:59 AM
So, I couldn't be fucked doing math today and so I took a look at the gamespy hash authentication system. Basically, the server sends the client a key which it uses (along with a random key it generates) to produce two md5 strings which are sent to the server. One string is the cd key hash (used for banning) and the other is used by gamespy to authenticate the first one, so you can't steal someone else's hash.
Anyway, I made a little program that checks if a hash is valid. It's not all that useful but maybe someone somewhere will find it helpful. I've included both the .exe and the source code. I got a warning from Chrome when I downloaded it, check the source if you want.
Download: attached
(http://www.mediafire.com/?qww48gwwgqn9w4g)main.cpp
#include <windows.h>#include <stdio.h>
#include <vector>
#include "Stream.h"
#include "resource.h"
#pragma comment(lib, "ws2_32.lib")
hostent * GetHost(const char * host);
INT_PTR CALLBACK Main_DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
std::vector<std::string> TokenizeString(const std::string& str, const std::string& delim);
hostent* host = 0;
sockaddr_in svr, local;
SOCKET s = 0;
int WINAPI WinMain( __in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in_opt LPSTR lpCmdLine, __in int nShowCmd )
{
HWND hWnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, Main_DlgProc);
MSG Msg = {0};
while(GetMessage(&Msg, 0, 0, 0) > 0)
{
// Process GUI messages
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return 0;
}
void transformData(LPBYTE stream, int len)
{
const char* secString = "gamespy";
int secLen = strlen(secString);
for (int i = 0, j = 0; i < len; i++)
{
if (!secString[j]) j = 0;
stream[i] ^= secString[j++];
}
}
INT_PTR CALLBACK Main_DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
// Handle the message
switch(uMsg)
{
// Dialog initialize
case WM_INITDIALOG:
{
WSADATA wsaData = {0};
// Try to start the winsock library
DWORD dwError = WSAStartup(MAKEWORD(2, 2), &wsaData);
if(dwError != ERROR_SUCCESS)
{
MessageBox(0, "Cannot startup WINSOCK", "ERROR", MB_ICONERROR);
return 0;
}
host = GetHost("halor.master.gamespy.com");
if (!host)
{
MessageBox(0, "Cannot resolve halor.master.gamespy.com.", "ERROR", MB_ICONERROR);
return 0;
}
// Setup the connection properties
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
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)
{
MessageBox(0, "Cannot bind the local socket.", "ERROR", MB_ICONERROR);
return 0;
}
}break;
// Commands
case WM_COMMAND:
{
int button = LOWORD(wParam);
// This gets called when a button is pressed, the case is the button id.
switch (button)
{
case IDC_CHECK:
{
if (GetWindowTextLength(GetDlgItem(hWnd, IDC_HASH)) == 32)
{
char hash_to_check[33] = {0};
GetWindowText(GetDlgItem(hWnd, IDC_HASH), hash_to_check, sizeof(hash_to_check));
streamBuilder b;
b.AppendString("\\auth\\\\pid\\793"); // game info
b.AppendString("\\ch\\nxdqevx"); // server key (any random 7 letter str)
b.AppendString("\\resp\\");
b.AppendString(hash_to_check); // hash to verify
b.AppendString("12345678"); // client key
b.AppendString(hash_to_check); // should be the auth token but we can't possibly generate a valid one
b.AppendString("\\ip\\0"); // ip address as 32bit number, 0 works fine too
b.AppendString("\\skey\\12345"); // used to id response
LPBYTE stream = b.getStream();
transformData(stream, b.getStreamSize());
// send the pkt
int ret = sendto( s, (char*)stream, b.getStreamSize(), 0, (sockaddr *)&svr, sizeof(svr));
char buff[1024] = {0};
sockaddr_in from;
int len = sizeof(from);
int bytesReceived = recvfrom(s, (char*)&buff, sizeof(buff), 0, (sockaddr *)&from, &len);
transformData((LPBYTE)buff, bytesReceived);
std::vector<std::string> tokens = TokenizeString(buff, "\\");
if (tokens.size())
{
if (tokens[tokens.size()-1] == "Invalid CD Key")
MessageBox(hWnd, "The CD Key is invalid.", "Response Received", MB_ICONEXCLAMATION);
else if (tokens[tokens.size()-1] == "Invalid authentication")
MessageBox(hWnd, "The CD Key is valid!", "Valid CD Key", MB_ICONINFORMATION);
else
MessageBox(hWnd, "An unknown error occurred :(", "Response Received", MB_ICONERROR);
}
else
MessageBox(hWnd, "An unknown error occurred :(", "Response Received", MB_ICONERROR);
SetWindowText(GetDlgItem(hWnd, IDC_HASH), "");
}
else
MessageBox(hWnd, "The hash must be 32 characters long.", "Error", MB_ICONERROR);
} break;
case IDCANCEL:
{
PostQuitMessage(0);
} break;
}
} break;
//-------------------------------------------------------------------------
default:
{
return FALSE;
}
}
// Message handled
return TRUE;
}
// 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 * GetHost(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);
}
}
Anyway, I made a little program that checks if a hash is valid. It's not all that useful but maybe someone somewhere will find it helpful. I've included both the .exe and the source code. I got a warning from Chrome when I downloaded it, check the source if you want.
Download: attached
(http://www.mediafire.com/?qww48gwwgqn9w4g)main.cpp
#include <windows.h>#include <stdio.h>
#include <vector>
#include "Stream.h"
#include "resource.h"
#pragma comment(lib, "ws2_32.lib")
hostent * GetHost(const char * host);
INT_PTR CALLBACK Main_DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
std::vector<std::string> TokenizeString(const std::string& str, const std::string& delim);
hostent* host = 0;
sockaddr_in svr, local;
SOCKET s = 0;
int WINAPI WinMain( __in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in_opt LPSTR lpCmdLine, __in int nShowCmd )
{
HWND hWnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, Main_DlgProc);
MSG Msg = {0};
while(GetMessage(&Msg, 0, 0, 0) > 0)
{
// Process GUI messages
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return 0;
}
void transformData(LPBYTE stream, int len)
{
const char* secString = "gamespy";
int secLen = strlen(secString);
for (int i = 0, j = 0; i < len; i++)
{
if (!secString[j]) j = 0;
stream[i] ^= secString[j++];
}
}
INT_PTR CALLBACK Main_DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
// Handle the message
switch(uMsg)
{
// Dialog initialize
case WM_INITDIALOG:
{
WSADATA wsaData = {0};
// Try to start the winsock library
DWORD dwError = WSAStartup(MAKEWORD(2, 2), &wsaData);
if(dwError != ERROR_SUCCESS)
{
MessageBox(0, "Cannot startup WINSOCK", "ERROR", MB_ICONERROR);
return 0;
}
host = GetHost("halor.master.gamespy.com");
if (!host)
{
MessageBox(0, "Cannot resolve halor.master.gamespy.com.", "ERROR", MB_ICONERROR);
return 0;
}
// Setup the connection properties
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
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)
{
MessageBox(0, "Cannot bind the local socket.", "ERROR", MB_ICONERROR);
return 0;
}
}break;
// Commands
case WM_COMMAND:
{
int button = LOWORD(wParam);
// This gets called when a button is pressed, the case is the button id.
switch (button)
{
case IDC_CHECK:
{
if (GetWindowTextLength(GetDlgItem(hWnd, IDC_HASH)) == 32)
{
char hash_to_check[33] = {0};
GetWindowText(GetDlgItem(hWnd, IDC_HASH), hash_to_check, sizeof(hash_to_check));
streamBuilder b;
b.AppendString("\\auth\\\\pid\\793"); // game info
b.AppendString("\\ch\\nxdqevx"); // server key (any random 7 letter str)
b.AppendString("\\resp\\");
b.AppendString(hash_to_check); // hash to verify
b.AppendString("12345678"); // client key
b.AppendString(hash_to_check); // should be the auth token but we can't possibly generate a valid one
b.AppendString("\\ip\\0"); // ip address as 32bit number, 0 works fine too
b.AppendString("\\skey\\12345"); // used to id response
LPBYTE stream = b.getStream();
transformData(stream, b.getStreamSize());
// send the pkt
int ret = sendto( s, (char*)stream, b.getStreamSize(), 0, (sockaddr *)&svr, sizeof(svr));
char buff[1024] = {0};
sockaddr_in from;
int len = sizeof(from);
int bytesReceived = recvfrom(s, (char*)&buff, sizeof(buff), 0, (sockaddr *)&from, &len);
transformData((LPBYTE)buff, bytesReceived);
std::vector<std::string> tokens = TokenizeString(buff, "\\");
if (tokens.size())
{
if (tokens[tokens.size()-1] == "Invalid CD Key")
MessageBox(hWnd, "The CD Key is invalid.", "Response Received", MB_ICONEXCLAMATION);
else if (tokens[tokens.size()-1] == "Invalid authentication")
MessageBox(hWnd, "The CD Key is valid!", "Valid CD Key", MB_ICONINFORMATION);
else
MessageBox(hWnd, "An unknown error occurred :(", "Response Received", MB_ICONERROR);
}
else
MessageBox(hWnd, "An unknown error occurred :(", "Response Received", MB_ICONERROR);
SetWindowText(GetDlgItem(hWnd, IDC_HASH), "");
}
else
MessageBox(hWnd, "The hash must be 32 characters long.", "Error", MB_ICONERROR);
} break;
case IDCANCEL:
{
PostQuitMessage(0);
} break;
}
} break;
//-------------------------------------------------------------------------
default:
{
return FALSE;
}
}
// Message handled
return TRUE;
}
// 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 * GetHost(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);
}
}