Initial commit: wowee native WoW 3.3.5a client

This commit is contained in:
Kelsi 2026-02-02 12:24:50 -08:00
commit ce6cb8f38e
147 changed files with 32347 additions and 0 deletions

View file

@ -0,0 +1,96 @@
#pragma once
#include "auth/srp.hpp"
#include "auth/auth_packets.hpp"
#include <memory>
#include <string>
#include <functional>
namespace wowee {
namespace network { class TCPSocket; class Packet; }
namespace auth {
struct Realm;
// Authentication state
enum class AuthState {
DISCONNECTED,
CONNECTED,
CHALLENGE_SENT,
CHALLENGE_RECEIVED,
PROOF_SENT,
AUTHENTICATED,
REALM_LIST_REQUESTED,
REALM_LIST_RECEIVED,
FAILED
};
// Authentication callbacks
using AuthSuccessCallback = std::function<void(const std::vector<uint8_t>& sessionKey)>;
using AuthFailureCallback = std::function<void(const std::string& reason)>;
using RealmListCallback = std::function<void(const std::vector<Realm>& realms)>;
class AuthHandler {
public:
AuthHandler();
~AuthHandler();
// Connection
bool connect(const std::string& host, uint16_t port = 3724);
void disconnect();
bool isConnected() const;
// Authentication
void authenticate(const std::string& username, const std::string& password);
// Realm list
void requestRealmList();
const std::vector<Realm>& getRealms() const { return realms; }
// State
AuthState getState() const { return state; }
const std::vector<uint8_t>& getSessionKey() const { return sessionKey; }
// Callbacks
void setOnSuccess(AuthSuccessCallback callback) { onSuccess = callback; }
void setOnFailure(AuthFailureCallback callback) { onFailure = callback; }
void setOnRealmList(RealmListCallback callback) { onRealmList = callback; }
// Update (call each frame)
void update(float deltaTime);
private:
void sendLogonChallenge();
void handleLogonChallengeResponse(network::Packet& packet);
void sendLogonProof();
void handleLogonProofResponse(network::Packet& packet);
void sendRealmListRequest();
void handleRealmListResponse(network::Packet& packet);
void handlePacket(network::Packet& packet);
void setState(AuthState newState);
void fail(const std::string& reason);
std::unique_ptr<network::TCPSocket> socket;
std::unique_ptr<SRP> srp;
AuthState state = AuthState::DISCONNECTED;
std::string username;
std::string password;
ClientInfo clientInfo;
std::vector<uint8_t> sessionKey;
std::vector<Realm> realms;
// Callbacks
AuthSuccessCallback onSuccess;
AuthFailureCallback onFailure;
RealmListCallback onRealmList;
// Receive buffer
std::vector<uint8_t> receiveBuffer;
};
} // namespace auth
} // namespace wowee

View file

@ -0,0 +1,43 @@
#pragma once
#include <cstdint>
namespace wowee {
namespace auth {
// Authentication server opcodes
enum class AuthOpcode : uint8_t {
LOGON_CHALLENGE = 0x00,
LOGON_PROOF = 0x01,
RECONNECT_CHALLENGE = 0x02,
RECONNECT_PROOF = 0x03,
REALM_LIST = 0x10,
};
// LOGON_CHALLENGE response status codes
enum class AuthResult : uint8_t {
SUCCESS = 0x00,
UNKNOWN0 = 0x01,
UNKNOWN1 = 0x02,
ACCOUNT_BANNED = 0x03,
ACCOUNT_INVALID = 0x04,
PASSWORD_INVALID = 0x05,
ALREADY_ONLINE = 0x06,
OUT_OF_CREDIT = 0x07,
BUSY = 0x08,
BUILD_INVALID = 0x09,
BUILD_UPDATE = 0x0A,
INVALID_SERVER = 0x0B,
ACCOUNT_SUSPENDED = 0x0C,
ACCESS_DENIED = 0x0D,
SURVEY = 0x0E,
PARENTAL_CONTROL = 0x0F,
LOCK_ENFORCED = 0x10,
TRIAL_EXPIRED = 0x11,
BATTLE_NET = 0x12,
};
const char* getAuthResultString(AuthResult result);
} // namespace auth
} // namespace wowee

View file

@ -0,0 +1,109 @@
#pragma once
#include "auth/auth_opcodes.hpp"
#include "network/packet.hpp"
#include <string>
#include <vector>
#include <cstdint>
namespace wowee {
namespace auth {
// Client build and version information
struct ClientInfo {
uint8_t majorVersion = 3;
uint8_t minorVersion = 3;
uint8_t patchVersion = 5;
uint16_t build = 12340; // 3.3.5a
std::string game = "WoW";
std::string platform = "x86";
std::string os = "Win";
std::string locale = "enUS";
uint32_t timezone = 0;
};
// LOGON_CHALLENGE packet builder
class LogonChallengePacket {
public:
static network::Packet build(const std::string& account, const ClientInfo& info = ClientInfo());
};
// LOGON_CHALLENGE response data
struct LogonChallengeResponse {
AuthResult result;
std::vector<uint8_t> B; // Server public ephemeral (32 bytes)
std::vector<uint8_t> g; // Generator (variable, usually 1 byte)
std::vector<uint8_t> N; // Prime modulus (variable, usually 256 bytes)
std::vector<uint8_t> salt; // Salt (32 bytes)
uint8_t securityFlags;
bool isSuccess() const { return result == AuthResult::SUCCESS; }
};
// LOGON_CHALLENGE response parser
class LogonChallengeResponseParser {
public:
static bool parse(network::Packet& packet, LogonChallengeResponse& response);
};
// LOGON_PROOF packet builder
class LogonProofPacket {
public:
static network::Packet build(const std::vector<uint8_t>& A,
const std::vector<uint8_t>& M1);
};
// LOGON_PROOF response data
struct LogonProofResponse {
uint8_t status;
std::vector<uint8_t> M2; // Server proof (20 bytes)
bool isSuccess() const { return status == 0; }
};
// LOGON_PROOF response parser
class LogonProofResponseParser {
public:
static bool parse(network::Packet& packet, LogonProofResponse& response);
};
// Realm data structure
struct Realm {
uint8_t icon;
uint8_t lock;
uint8_t flags;
std::string name;
std::string address;
float population;
uint8_t characters;
uint8_t timezone;
uint8_t id;
// Version info (conditional - only if flags & 0x04)
uint8_t majorVersion = 0;
uint8_t minorVersion = 0;
uint8_t patchVersion = 0;
uint16_t build = 0;
bool hasVersionInfo() const { return (flags & 0x04) != 0; }
};
// REALM_LIST packet builder
class RealmListPacket {
public:
static network::Packet build();
};
// REALM_LIST response data
struct RealmListResponse {
std::vector<Realm> realms;
};
// REALM_LIST response parser
class RealmListResponseParser {
public:
static bool parse(network::Packet& packet, RealmListResponse& response);
};
} // namespace auth
} // namespace wowee

55
include/auth/big_num.hpp Normal file
View file

@ -0,0 +1,55 @@
#pragma once
#include <vector>
#include <cstdint>
#include <string>
#include <openssl/bn.h>
namespace wowee {
namespace auth {
// Wrapper around OpenSSL BIGNUM for big integer arithmetic
class BigNum {
public:
BigNum();
explicit BigNum(uint32_t value);
explicit BigNum(const std::vector<uint8_t>& bytes, bool littleEndian = true);
~BigNum();
// Copy/move operations
BigNum(const BigNum& other);
BigNum& operator=(const BigNum& other);
BigNum(BigNum&& other) noexcept;
BigNum& operator=(BigNum&& other) noexcept;
// Factory methods
static BigNum fromRandom(int bytes);
static BigNum fromHex(const std::string& hex);
static BigNum fromDecimal(const std::string& dec);
// Arithmetic operations
BigNum add(const BigNum& other) const;
BigNum subtract(const BigNum& other) const;
BigNum multiply(const BigNum& other) const;
BigNum mod(const BigNum& modulus) const;
BigNum modPow(const BigNum& exponent, const BigNum& modulus) const;
// Comparison
bool equals(const BigNum& other) const;
bool isZero() const;
// Conversion
std::vector<uint8_t> toArray(bool littleEndian = true, int minSize = 0) const;
std::string toHex() const;
std::string toDecimal() const;
// Direct access (for advanced operations)
BIGNUM* getBN() { return bn; }
const BIGNUM* getBN() const { return bn; }
private:
BIGNUM* bn;
};
} // namespace auth
} // namespace wowee

27
include/auth/crypto.hpp Normal file
View file

@ -0,0 +1,27 @@
#pragma once
#include <vector>
#include <cstdint>
#include <string>
namespace wowee {
namespace auth {
class Crypto {
public:
static std::vector<uint8_t> sha1(const std::vector<uint8_t>& data);
static std::vector<uint8_t> sha1(const std::string& data);
/**
* HMAC-SHA1 message authentication code
*
* @param key Secret key
* @param data Data to authenticate
* @return 20-byte HMAC-SHA1 hash
*/
static std::vector<uint8_t> hmacSHA1(const std::vector<uint8_t>& key,
const std::vector<uint8_t>& data);
};
} // namespace auth
} // namespace wowee

53
include/auth/rc4.hpp Normal file
View file

@ -0,0 +1,53 @@
#pragma once
#include <cstdint>
#include <vector>
namespace wowee {
namespace auth {
/**
* RC4 Stream Cipher
*
* Used for encrypting/decrypting World of Warcraft packet headers.
* Only the packet headers are encrypted; packet bodies remain plaintext.
*
* Implementation based on standard RC4 algorithm with 256-byte state.
*/
class RC4 {
public:
RC4();
~RC4() = default;
/**
* Initialize the RC4 cipher with a key
*
* @param key Key bytes for initialization
*/
void init(const std::vector<uint8_t>& key);
/**
* Process bytes through the RC4 cipher
* Encrypts or decrypts data in-place (RC4 is symmetric)
*
* @param data Pointer to data to process
* @param length Number of bytes to process
*/
void process(uint8_t* data, size_t length);
/**
* Drop the first N bytes of keystream
* WoW protocol requires dropping first 1024 bytes
*
* @param count Number of bytes to drop
*/
void drop(size_t count);
private:
uint8_t state[256]; // RC4 state array
uint8_t x; // First index
uint8_t y; // Second index
};
} // namespace auth
} // namespace wowee

75
include/auth/srp.hpp Normal file
View file

@ -0,0 +1,75 @@
#pragma once
#include "auth/big_num.hpp"
#include <vector>
#include <cstdint>
#include <string>
namespace wowee {
namespace auth {
// SRP6a implementation for World of Warcraft authentication
// Based on the original wowee JavaScript implementation
class SRP {
public:
SRP();
~SRP() = default;
// Initialize with username and password
void initialize(const std::string& username, const std::string& password);
// Feed server challenge data (B, g, N, salt)
void feed(const std::vector<uint8_t>& B,
const std::vector<uint8_t>& g,
const std::vector<uint8_t>& N,
const std::vector<uint8_t>& salt);
// Get client public ephemeral (A) - send to server
std::vector<uint8_t> getA() const;
// Get client proof (M1) - send to server
std::vector<uint8_t> getM1() const;
// Verify server proof (M2)
bool verifyServerProof(const std::vector<uint8_t>& serverM2) const;
// Get session key (K) - used for encryption
std::vector<uint8_t> getSessionKey() const;
private:
// WoW-specific SRP multiplier (k = 3)
static constexpr uint32_t K_VALUE = 3;
// Helper methods
std::vector<uint8_t> computeAuthHash(const std::string& username,
const std::string& password) const;
void computeClientEphemeral();
void computeSessionKey();
void computeProofs(const std::string& username);
// SRP values
BigNum g; // Generator
BigNum N; // Prime modulus
BigNum k; // Multiplier (3 for WoW)
BigNum s; // Salt
BigNum a; // Client private ephemeral
BigNum A; // Client public ephemeral
BigNum B; // Server public ephemeral
BigNum x; // Salted password hash
BigNum u; // Scrambling parameter
BigNum S; // Shared session key (raw)
// Derived values
std::vector<uint8_t> K; // Interleaved session key (40 bytes)
std::vector<uint8_t> M1; // Client proof (20 bytes)
std::vector<uint8_t> M2; // Expected server proof (20 bytes)
// Stored credentials
std::string stored_username;
std::string stored_password;
bool initialized = false;
};
} // namespace auth
} // namespace wowee