mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-22 23:30:14 +00:00
Initial commit: wowee native WoW 3.3.5a client
This commit is contained in:
commit
ce6cb8f38e
147 changed files with 32347 additions and 0 deletions
96
include/auth/auth_handler.hpp
Normal file
96
include/auth/auth_handler.hpp
Normal 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
|
||||
43
include/auth/auth_opcodes.hpp
Normal file
43
include/auth/auth_opcodes.hpp
Normal 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
|
||||
109
include/auth/auth_packets.hpp
Normal file
109
include/auth/auth_packets.hpp
Normal 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
55
include/auth/big_num.hpp
Normal 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
27
include/auth/crypto.hpp
Normal 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
53
include/auth/rc4.hpp
Normal 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
75
include/auth/srp.hpp
Normal 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue