+ Reply to Thread
Page 1 of 3 1 2 3 LastLast
Results 1 to 10 of 27

Thread: Halo Hash Verifier [Halo PC/Halo CE]

Hybrid View

  1. #1

    Halo Hash Verifier [Halo PC/Halo CE]

    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

    main.cpp
    Code:
    #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);
        }
    }
    Attached Files
    Last edited by urbanyoung; September 29th, 2012 at 12:52 AM.
    Reply With Quote

  2. #2

    Re: Halo Hash Verifier [Halo PC/Halo CE]

    Quote Originally Posted by urbanyoung View Post
    maybe someone somewhere will find it helpful.
    "Somewhere over the rainbow...."

    Thanks for sharing, just of curiosity how did you come up with the idea to look at the hash verification system?
    Reply With Quote

  3. #3

    Re: Halo Hash Verifier [Halo PC/Halo CE]

    Quote Originally Posted by Sean Aero View Post
    "Somewhere over the rainbow...."

    Thanks for sharing, just of curiosity how did you come up with the idea to look at the hash verification system?
    I always had an idea of "borrowing" someone's hash or making it seem as though they were in my server when they really weren't. I decided to finally look into it and confirm what I assumed; it isn't possible. Plus, the second packet sent from c->s is "mostly" just this gamespy stuff and because I want to make a clientless I should probably understand what it's doing. I want to make a clientless so I can fill my server easily without having to run 16 clients, which I need to do while testing reserved slots.
    Reply With Quote

  4. #4
    Kid in the Hall Kornman00's Avatar
    Join Date
    Sep 2006
    Location
    ◕‿◕, ┌( ಠ_ಠ)┘
    Posts
    3,135
    Blog Entries
    1
    Kornman00 has a reputation beyond repute Kornman00 has a reputation beyond repute Kornman00 has a reputation beyond repute Kornman00 has a reputation beyond repute Kornman00 has a reputation beyond repute Kornman00 has a reputation beyond repute Kornman00 has a reputation beyond repute Kornman00 has a reputation beyond repute Kornman00 has a reputation beyond repute Kornman00 has a reputation beyond repute Kornman00 has a reputation beyond repute

    Re: Halo Hash Verifier [Halo PC/Halo CE]


    Reply With Quote

  5. #5

    Re: Halo Hash Verifier [Halo PC/Halo CE]

    lol I've actually been looking at faking hashes at CE recently, found the function that gets the key from the registry and enctrypts it so I modified that (probably a little too nop-happy). well this explains why it didn't work

    however, it still seems possible to fake hashes if you could get the key the server sent, the rand number, and just generate an md5 in a codecave. since you have both md5 source strings? I know there's not a lot of room to jump to the codecave, but it seems possible.

    e: invalid or deleted file :|
    Last edited by Ryx; April 16th, 2012 at 01:31 AM.
    Reply With Quote

  6. #6

    Re: Halo Hash Verifier [Halo PC/Halo CE]

    There's no way to "fake" a hash, however there is a bug in Halo's processing that gives the same effect. The way the hash checks go is like this:

    1. The client generates a random number and creates an 8 digit hex string of it.
    2. Creates a string of %s%d%s, cd key, random number % 0xff, server key
    3. Get an MD5 hash of the cd key (this is used for banning)
    4. Gets an MD5 hash of the cd key with the server key appended to it.
    4. Builds the response which consists of cd key hash, client key string, hash of cd key + server key.

    The server sends the response off to gamespy which verifies it. The way it verifies it is (probably) by means of a database lookup and then rebuilding the two hashes. If the CD key hash is invalid, it returns an invalid cd key message. If it is valid the second hash is checked, if it's valid gamespy returns ok, otherwise it returns an authentication error. If any error is received the server gives you the "Invalid CD Key" error.

    You cannot fake the check unless you can generate a valid cd key (not cd key hash, the one it reads + encrypts from registry).

    If you want to look at the routine that generates the response, search for "CD key challenge too long", it's the only function with that reference.
    Last edited by urbanyoung; April 16th, 2012 at 10:20 PM.
    Reply With Quote

  7. #7

    Re: Halo Hash Verifier [Halo PC/Halo CE]

    Quote Originally Posted by urbanyoung View Post
    You cannot fake the check unless you can generate a valid cd key (not cd key hash, the one it reads + encrypts from registry).
    Let's not go down this road
    Reply With Quote

  8. #8

    Re: Halo Hash Verifier [Halo PC/Halo CE]

    Quote Originally Posted by Sean Aero View Post
    Let's not go down this road
    Well I don't really think there's a road to go down, not that I'm aware of anyway.
    Reply With Quote

  9. #9

    Re: Halo Hash Verifier [Halo PC/Halo CE]

    Quote Originally Posted by Sean Aero View Post
    Let's not go down this road
    By what, bruteforcing every cd combination? At that point you don't even need to fake hash.
    Reply With Quote

  10. #10

    Re: Halo Hash Verifier [Halo PC/Halo CE]

    What good will come of this discussion?
    Reply With Quote

+ Reply to Thread

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

     

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts