supporting changes for proxy server rewrite
This commit is contained in:
+1
-1
@@ -35,12 +35,12 @@ add_executable(newserv
|
|||||||
src/FileContentsCache.cc
|
src/FileContentsCache.cc
|
||||||
src/Menu.cc
|
src/Menu.cc
|
||||||
src/PSOProtocol.cc
|
src/PSOProtocol.cc
|
||||||
|
src/PSOEncryption.cc
|
||||||
src/Client.cc
|
src/Client.cc
|
||||||
src/Lobby.cc
|
src/Lobby.cc
|
||||||
src/ServerState.cc
|
src/ServerState.cc
|
||||||
src/Server.cc
|
src/Server.cc
|
||||||
src/License.cc
|
src/License.cc
|
||||||
src/PSOEncryption.cc
|
|
||||||
src/Player.cc
|
src/Player.cc
|
||||||
src/SendCommands.cc
|
src/SendCommands.cc
|
||||||
src/ChatCommands.cc
|
src/ChatCommands.cc
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ struct Client {
|
|||||||
ServerBehavior server_behavior;
|
ServerBehavior server_behavior;
|
||||||
bool is_virtual_connection;
|
bool is_virtual_connection;
|
||||||
bool should_disconnect;
|
bool should_disconnect;
|
||||||
std::string recv_buffer;
|
|
||||||
|
|
||||||
// timing & menus
|
// timing & menus
|
||||||
uint64_t play_time_begin; // time of connection (used for incrementing play time on BB)
|
uint64_t play_time_begin; // time of connection (used for incrementing play time on BB)
|
||||||
|
|||||||
+227
-176
@@ -16,9 +16,9 @@ using namespace std;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// most ciphers used by pso are symmetric; alias decrypt to encrypt by default
|
// Most ciphers used by PSO are symmetric; alias decrypt to encrypt by default
|
||||||
void PSOEncryption::decrypt(void* data, size_t size) {
|
void PSOEncryption::decrypt(void* data, size_t size, bool advance) {
|
||||||
this->encrypt(data, size);
|
this->encrypt(data, size, advance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -71,26 +71,50 @@ PSOPCEncryption::PSOPCEncryption(uint32_t seed) : offset(1) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t PSOPCEncryption::next() {
|
uint32_t PSOPCEncryption::next(bool advance) {
|
||||||
if (this->offset == PC_STREAM_LENGTH) {
|
if (this->offset == PC_STREAM_LENGTH) {
|
||||||
this->update_stream();
|
this->update_stream();
|
||||||
this->offset = 1;
|
this->offset = 1;
|
||||||
}
|
}
|
||||||
return this->stream[this->offset++];
|
uint32_t ret = this->stream[this->offset];
|
||||||
|
if (advance) {
|
||||||
|
this->offset++;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PSOPCEncryption::encrypt(void* vdata, size_t size) {
|
void PSOPCEncryption::encrypt(void* vdata, size_t size, bool advance) {
|
||||||
if (size & 3) {
|
if (size & 3) {
|
||||||
throw invalid_argument("size must be a multiple of 4");
|
throw invalid_argument("size must be a multiple of 4");
|
||||||
}
|
}
|
||||||
|
if (!advance && (size != 4)) {
|
||||||
|
throw logic_error("cannot peek-encrypt/decrypt with size > 4");
|
||||||
|
}
|
||||||
size >>= 2;
|
size >>= 2;
|
||||||
|
|
||||||
uint32_t* data = reinterpret_cast<uint32_t*>(vdata);
|
uint32_t* data = reinterpret_cast<uint32_t*>(vdata);
|
||||||
for (size_t x = 0; x < size; x++) {
|
for (size_t x = 0; x < size; x++) {
|
||||||
data[x] ^= this->next();
|
data[x] ^= this->next(advance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PSOPCEncryption::skip(size_t size) {
|
||||||
|
if (size & 3) {
|
||||||
|
throw invalid_argument("size must be a multiple of 4");
|
||||||
|
}
|
||||||
|
size >>= 2;
|
||||||
|
|
||||||
|
// TODO: Do something smarter than just calling next() in a loop here
|
||||||
|
size_t new_offset = this->offset + size;
|
||||||
|
while (new_offset > PC_STREAM_LENGTH) {
|
||||||
|
this->update_stream();
|
||||||
|
// The PC encryption apparently always skips the first key in the stream
|
||||||
|
new_offset -= (PC_STREAM_LENGTH - 1);
|
||||||
|
}
|
||||||
|
this->offset = new_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void PSOGCEncryption::update_stream() {
|
void PSOGCEncryption::update_stream() {
|
||||||
@@ -110,12 +134,15 @@ void PSOGCEncryption::update_stream() {
|
|||||||
this->offset = 0;
|
this->offset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t PSOGCEncryption::next() {
|
uint32_t PSOGCEncryption::next(bool advance) {
|
||||||
this->offset++;
|
|
||||||
if (this->offset == GC_STREAM_LENGTH) {
|
if (this->offset == GC_STREAM_LENGTH) {
|
||||||
this->update_stream();
|
this->update_stream();
|
||||||
}
|
}
|
||||||
return this->stream[this->offset];
|
uint32_t ret = this->stream[this->offset];
|
||||||
|
if (advance) {
|
||||||
|
this->offset++;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
PSOGCEncryption::PSOGCEncryption(uint32_t seed) : offset(0) {
|
PSOGCEncryption::PSOGCEncryption(uint32_t seed) : offset(0) {
|
||||||
@@ -145,27 +172,43 @@ PSOGCEncryption::PSOGCEncryption(uint32_t seed) : offset(0) {
|
|||||||
this->stream[this->offset++] = (this->stream[source3++] ^ (((this->stream[source1++] << 23) & 0xFF800000) ^ ((this->stream[source2++] >> 9) & 0x007FFFFF)));
|
this->stream[this->offset++] = (this->stream[source3++] ^ (((this->stream[source1++] << 23) & 0xFF800000) ^ ((this->stream[source2++] >> 9) & 0x007FFFFF)));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t x = 0; x < 3; x++) {
|
for (size_t x = 0; x < 4; x++) {
|
||||||
this->update_stream();
|
this->update_stream();
|
||||||
}
|
}
|
||||||
this->offset = GC_STREAM_LENGTH - 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PSOGCEncryption::encrypt(void* vdata, size_t size) {
|
void PSOGCEncryption::encrypt(void* vdata, size_t size, bool advance) {
|
||||||
if (size & 3) {
|
if (size & 3) {
|
||||||
throw invalid_argument("size must be a multiple of 4");
|
throw invalid_argument("size must be a multiple of 4");
|
||||||
}
|
}
|
||||||
|
if (!advance && (size != 4)) {
|
||||||
|
throw logic_error("cannot peek-encrypt/decrypt with size > 4");
|
||||||
|
}
|
||||||
size >>= 2;
|
size >>= 2;
|
||||||
|
|
||||||
uint32_t* data = reinterpret_cast<uint32_t*>(vdata);
|
uint32_t* data = reinterpret_cast<uint32_t*>(vdata);
|
||||||
for (size_t x = 0; x < size; x++) {
|
for (size_t x = 0; x < size; x++) {
|
||||||
data[x] ^= this->next();
|
data[x] ^= this->next(advance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PSOGCEncryption::skip(size_t size) {
|
||||||
|
if (size & 3) {
|
||||||
|
throw invalid_argument("size must be a multiple of 4");
|
||||||
|
}
|
||||||
|
size >>= 2;
|
||||||
|
|
||||||
|
size_t new_offset = this->offset + size;
|
||||||
|
while (new_offset > GC_STREAM_LENGTH) {
|
||||||
|
this->update_stream();
|
||||||
|
new_offset -= GC_STREAM_LENGTH;
|
||||||
|
}
|
||||||
|
this->offset = new_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void PSOBBEncryption::decrypt(void* vdata, size_t size) {
|
void PSOBBEncryption::decrypt(void* vdata, size_t size, bool) {
|
||||||
if (size & 7) {
|
if (size & 7) {
|
||||||
throw invalid_argument("size must be a multiple of 8");
|
throw invalid_argument("size must be a multiple of 8");
|
||||||
}
|
}
|
||||||
@@ -178,19 +221,19 @@ void PSOBBEncryption::decrypt(void* vdata, size_t size) {
|
|||||||
while (edx < size) {
|
while (edx < size) {
|
||||||
ebx = data[edx];
|
ebx = data[edx];
|
||||||
ebx = ebx ^ this->stream[5];
|
ebx = ebx ^ this->stream[5];
|
||||||
ebp = ((this->stream[(ebx >> 0x18) + 0x12]+this->stream[((ebx >> 0x10)& 0xff) + 0x112])
|
ebp = ((this->stream[(ebx >> 0x18) + 0x12] + this->stream[((ebx >> 0x10) & 0xFF) + 0x112])
|
||||||
^ this->stream[((ebx >> 0x8)& 0xff) + 0x212]) + this->stream[(ebx & 0xff) + 0x312];
|
^ this->stream[((ebx >> 0x8) & 0xFF) + 0x212]) + this->stream[(ebx & 0xFF) + 0x312];
|
||||||
ebp = ebp ^ this->stream[4];
|
ebp = ebp ^ this->stream[4];
|
||||||
ebp ^= data[edx + 1];
|
ebp ^= data[edx + 1];
|
||||||
edi = ((this->stream[(ebp >> 0x18) + 0x12]+this->stream[((ebp >> 0x10)& 0xff) + 0x112])
|
edi = ((this->stream[(ebp >> 0x18) + 0x12] + this->stream[((ebp >> 0x10) & 0xFF) + 0x112])
|
||||||
^ this->stream[((ebp >> 0x8)& 0xff) + 0x212]) + this->stream[(ebp & 0xff) + 0x312];
|
^ this->stream[((ebp >> 0x8) & 0xFF) + 0x212]) + this->stream[(ebp & 0xFF) + 0x312];
|
||||||
edi = edi ^ this->stream[3];
|
edi = edi ^ this->stream[3];
|
||||||
ebx = ebx ^ edi;
|
ebx = ebx ^ edi;
|
||||||
esi = ((this->stream[(ebx >> 0x18) + 0x12]+this->stream[((ebx >> 0x10)& 0xff) + 0x112])
|
esi = ((this->stream[(ebx >> 0x18) + 0x12] + this->stream[((ebx >> 0x10) & 0xFF) + 0x112])
|
||||||
^ this->stream[((ebx >> 0x8)& 0xff) + 0x212]) + this->stream[(ebx & 0xff) + 0x312];
|
^ this->stream[((ebx >> 0x8) & 0xFF) + 0x212]) + this->stream[(ebx & 0xFF) + 0x312];
|
||||||
ebp = ebp ^ esi ^ this->stream[2];
|
ebp = ebp ^ esi ^ this->stream[2];
|
||||||
edi = ((this->stream[(ebp >> 0x18) + 0x12]+this->stream[((ebp >> 0x10)& 0xff) + 0x112])
|
edi = ((this->stream[(ebp >> 0x18) + 0x12] + this->stream[((ebp >> 0x10) & 0xFF) + 0x112])
|
||||||
^ this->stream[((ebp >> 0x8)& 0xff) + 0x212]) + this->stream[(ebp & 0xff) + 0x312];
|
^ this->stream[((ebp >> 0x8) & 0xFF) + 0x212]) + this->stream[(ebp & 0xFF) + 0x312];
|
||||||
edi = edi ^ this->stream[1];
|
edi = edi ^ this->stream[1];
|
||||||
ebp = ebp ^ this->stream[0];
|
ebp = ebp ^ this->stream[0];
|
||||||
ebx = ebx ^ edi;
|
ebx = ebx ^ edi;
|
||||||
@@ -200,7 +243,7 @@ void PSOBBEncryption::decrypt(void* vdata, size_t size) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PSOBBEncryption::encrypt(void* vdata, size_t size) {
|
void PSOBBEncryption::encrypt(void* vdata, size_t size, bool) {
|
||||||
if (size & 7) {
|
if (size & 7) {
|
||||||
throw invalid_argument("size must be a multiple of 8");
|
throw invalid_argument("size must be a multiple of 8");
|
||||||
}
|
}
|
||||||
@@ -213,19 +256,19 @@ void PSOBBEncryption::encrypt(void* vdata, size_t size) {
|
|||||||
while (edx < size) {
|
while (edx < size) {
|
||||||
ebx = data[edx];
|
ebx = data[edx];
|
||||||
ebx = ebx ^ this->stream[0];
|
ebx = ebx ^ this->stream[0];
|
||||||
ebp = ((this->stream[(ebx >> 0x18) + 0x12]+this->stream[((ebx >> 0x10)& 0xff) + 0x112])
|
ebp = ((this->stream[(ebx >> 0x18) + 0x12] + this->stream[((ebx >> 0x10) & 0xFF) + 0x112])
|
||||||
^ this->stream[((ebx >> 0x8)& 0xff) + 0x212]) + this->stream[(ebx & 0xff) + 0x312];
|
^ this->stream[((ebx >> 0x8) & 0xFF) + 0x212]) + this->stream[(ebx & 0xFF) + 0x312];
|
||||||
ebp = ebp ^ this->stream[1];
|
ebp = ebp ^ this->stream[1];
|
||||||
ebp ^= data[edx + 1];
|
ebp ^= data[edx + 1];
|
||||||
edi = ((this->stream[(ebp >> 0x18) + 0x12]+this->stream[((ebp >> 0x10)& 0xff) + 0x112])
|
edi = ((this->stream[(ebp >> 0x18) + 0x12] + this->stream[((ebp >> 0x10) & 0xFF) + 0x112])
|
||||||
^ this->stream[((ebp >> 0x8)& 0xff) + 0x212]) + this->stream[(ebp & 0xff) + 0x312];
|
^ this->stream[((ebp >> 0x8) & 0xFF) + 0x212]) + this->stream[(ebp & 0xFF) + 0x312];
|
||||||
edi = edi ^ this->stream[2];
|
edi = edi ^ this->stream[2];
|
||||||
ebx = ebx ^ edi;
|
ebx = ebx ^ edi;
|
||||||
esi = ((this->stream[(ebx >> 0x18) + 0x12]+this->stream[((ebx >> 0x10)& 0xff) + 0x112])
|
esi = ((this->stream[(ebx >> 0x18) + 0x12] + this->stream[((ebx >> 0x10) & 0xFF) + 0x112])
|
||||||
^ this->stream[((ebx >> 0x8)& 0xff) + 0x212]) + this->stream[(ebx & 0xff) + 0x312];
|
^ this->stream[((ebx >> 0x8) & 0xFF) + 0x212]) + this->stream[(ebx & 0xFF) + 0x312];
|
||||||
ebp = ebp ^ esi ^ this->stream[3];
|
ebp = ebp ^ esi ^ this->stream[3];
|
||||||
edi = ((this->stream[(ebp >> 0x18) + 0x12]+this->stream[((ebp >> 0x10)& 0xff) + 0x112])
|
edi = ((this->stream[(ebp >> 0x18) + 0x12] + this->stream[((ebp >> 0x10) & 0xFF) + 0x112])
|
||||||
^ this->stream[((ebp >> 0x8)& 0xff) + 0x212]) + this->stream[(ebp & 0xff) + 0x312];
|
^ this->stream[((ebp >> 0x8) & 0xFF) + 0x212]) + this->stream[(ebp & 0xFF) + 0x312];
|
||||||
edi = edi ^ this->stream[4];
|
edi = edi ^ this->stream[4];
|
||||||
ebp = ebp ^ this->stream[5];
|
ebp = ebp ^ this->stream[5];
|
||||||
ebx = ebx ^ edi;
|
ebx = ebx ^ edi;
|
||||||
@@ -235,8 +278,12 @@ void PSOBBEncryption::encrypt(void* vdata, size_t size) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PSOBBEncryption::PSOBBEncryption(const KeyFile& key, const void* original_seed,
|
PSOBBEncryption::PSOBBEncryption(
|
||||||
size_t seed_size) : offset(0) {
|
const KeyFile& key, const void* original_seed, size_t seed_size)
|
||||||
|
: stream(this->generate_stream(key, original_seed, seed_size)) { }
|
||||||
|
|
||||||
|
vector<uint32_t> PSOBBEncryption::generate_stream(
|
||||||
|
const KeyFile& key, const void* original_seed, size_t seed_size) {
|
||||||
if (seed_size % 3) {
|
if (seed_size % 3) {
|
||||||
throw invalid_argument("seed size must be divisible by 3");
|
throw invalid_argument("seed size must be divisible by 3");
|
||||||
}
|
}
|
||||||
@@ -250,194 +297,198 @@ PSOBBEncryption::PSOBBEncryption(const KeyFile& key, const void* original_seed,
|
|||||||
seed.push_back(original_seed_data[x + 2] ^ 0x18);
|
seed.push_back(original_seed_data[x + 2] ^ 0x18);
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(this->stream, &key, sizeof(key));
|
vector<uint32_t> stream(BB_STREAM_LENGTH, 0);
|
||||||
|
memcpy(stream.data(), &key, sizeof(key));
|
||||||
|
|
||||||
this->postprocess_initial_stream(seed);
|
// This block was formerly postprocess_initial_stream
|
||||||
}
|
{
|
||||||
|
uint32_t eax, ecx, edx, ebx, ebp, esi, edi, ou, x;
|
||||||
|
|
||||||
void PSOBBEncryption::postprocess_initial_stream(const string& seed) {
|
ecx = 0;
|
||||||
uint32_t eax, ecx, edx, ebx, ebp, esi, edi, ou, x;
|
ebx = 0;
|
||||||
|
|
||||||
ecx = 0;
|
while (ebx < (seed.size() / 4)) {
|
||||||
ebx = 0;
|
ebp = static_cast<uint32_t>(seed[ecx]) << 0x18;
|
||||||
|
eax = ecx + 1;
|
||||||
while (ebx < (seed.size() / 4)) {
|
edx = eax % seed.size();
|
||||||
ebp = static_cast<uint32_t>(seed[ecx]) << 0x18;
|
eax = (static_cast<uint32_t>(seed[edx]) << 0x10) & 0xFF0000;
|
||||||
eax = ecx + 1;
|
ebp = (ebp | eax) & 0xFFFF00FF;
|
||||||
edx = eax % seed.size();
|
eax = ecx + 2;
|
||||||
eax = (static_cast<uint32_t>(seed[edx]) << 0x10) & 0xFF0000;
|
edx = eax % seed.size();
|
||||||
ebp = (ebp | eax) & 0xffff00ff;
|
eax = (static_cast<uint32_t>(seed[edx]) << 0x08) & 0xFF00;
|
||||||
eax = ecx + 2;
|
ebp = (ebp | eax) & 0xFFFFFF00;
|
||||||
edx = eax % seed.size();
|
eax = ecx + 3;
|
||||||
eax = (static_cast<uint32_t>(seed[edx]) << 0x08) & 0xFF00;
|
ecx = ecx + 4;
|
||||||
ebp = (ebp | eax) & 0xffffff00;
|
edx = eax % seed.size();
|
||||||
eax = ecx + 3;
|
eax = static_cast<uint32_t>(seed[edx]);
|
||||||
ecx = ecx + 4;
|
ebp = ebp | eax;
|
||||||
edx = eax % seed.size();
|
eax = ecx;
|
||||||
eax = static_cast<uint32_t>(seed[edx]);
|
edx = eax % seed.size();
|
||||||
ebp = ebp | eax;
|
stream[ebx] ^= ebp;
|
||||||
eax = ecx;
|
ecx = edx;
|
||||||
edx = eax % seed.size();
|
ebx++;
|
||||||
this->stream[ebx] ^= ebp;
|
|
||||||
ecx = edx;
|
|
||||||
ebx++;
|
|
||||||
}
|
|
||||||
|
|
||||||
ebp = 0;
|
|
||||||
esi = 0;
|
|
||||||
ecx = 0;
|
|
||||||
edi = 0;
|
|
||||||
ebx = 0;
|
|
||||||
edx = 0x48;
|
|
||||||
|
|
||||||
while (edi < edx) {
|
|
||||||
esi = esi ^ this->stream[0];
|
|
||||||
eax = esi >> 0x18;
|
|
||||||
ebx = (esi >> 0x10) & 0xff;
|
|
||||||
eax = this->stream[eax + 0x12] + this->stream[ebx + 0x112];
|
|
||||||
ebx = (esi >> 8) & 0xFF;
|
|
||||||
eax = eax ^ this->stream[ebx + 0x212];
|
|
||||||
ebx = esi & 0xFF;
|
|
||||||
eax = eax + this->stream[ebx + 0x312];
|
|
||||||
|
|
||||||
eax = eax ^ this->stream[1];
|
|
||||||
ecx = ecx ^ eax;
|
|
||||||
ebx = ecx >> 0x18;
|
|
||||||
eax = (ecx >> 0x10) & 0xFF;
|
|
||||||
ebx = this->stream[ebx + 0x12] + this->stream[eax + 0x112];
|
|
||||||
eax = (ecx >> 8) & 0xFF;
|
|
||||||
ebx = ebx ^ this->stream[eax + 0x212];
|
|
||||||
eax = ecx & 0xFF;
|
|
||||||
ebx = ebx + this->stream[eax + 0x312];
|
|
||||||
|
|
||||||
for (x = 0; x <= 5; x++) {
|
|
||||||
ebx = ebx ^ this->stream[(x * 2) + 2];
|
|
||||||
esi = esi ^ ebx;
|
|
||||||
ebx = esi >> 0x18;
|
|
||||||
eax = (esi >> 0x10) & 0xFF;
|
|
||||||
ebx = this->stream[ebx + 0x12] + this->stream[eax + 0x112];
|
|
||||||
eax = (esi >> 8) & 0xFF;
|
|
||||||
ebx = ebx ^ this->stream[eax + 0x212];
|
|
||||||
eax = esi & 0xFF;
|
|
||||||
ebx = ebx + this->stream[eax + 0x312];
|
|
||||||
|
|
||||||
ebx = ebx ^ this->stream[(x * 2) + 3];
|
|
||||||
ecx = ecx ^ ebx;
|
|
||||||
ebx = ecx >> 0x18;
|
|
||||||
eax = (ecx >> 0x10) & 0xFF;
|
|
||||||
ebx = this->stream[ebx + 0x12] + this->stream[eax + 0x112];
|
|
||||||
eax = (ecx >> 8) & 0xFF;
|
|
||||||
ebx = ebx ^ this->stream[eax + 0x212];
|
|
||||||
eax = ecx & 0xff;
|
|
||||||
ebx = ebx + this->stream[eax + 0x312];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ebx = ebx ^ this->stream[14];
|
ebp = 0;
|
||||||
esi = esi ^ ebx;
|
esi = 0;
|
||||||
eax = esi >> 0x18;
|
ecx = 0;
|
||||||
ebx = (esi >> 0x10) & 0xFF;
|
edi = 0;
|
||||||
eax = this->stream[eax + 0x12] + this->stream[ebx + 0x112];
|
ebx = 0;
|
||||||
ebx = (esi >> 8) & 0xff;
|
edx = 0x48;
|
||||||
eax = eax ^ this->stream[ebx + 0x212];
|
|
||||||
ebx = esi & 0xff;
|
|
||||||
eax = eax + this->stream[ebx + 0x312];
|
|
||||||
|
|
||||||
eax = eax ^ this->stream[15];
|
|
||||||
eax = ecx ^ eax;
|
|
||||||
ecx = eax >> 0x18;
|
|
||||||
ebx = (eax >> 0x10) & 0xFF;
|
|
||||||
ecx = this->stream[ecx + 0x12] + this->stream[ebx + 0x112];
|
|
||||||
ebx = (eax >> 8) & 0xFF;
|
|
||||||
ecx = ecx ^ this->stream[ebx + 0x212];
|
|
||||||
ebx = eax & 0xFF;
|
|
||||||
ecx = ecx + this->stream[ebx + 0x312];
|
|
||||||
|
|
||||||
ecx = ecx ^ this->stream[16];
|
|
||||||
ecx = ecx ^ esi;
|
|
||||||
esi = this->stream[17];
|
|
||||||
esi = esi ^ eax;
|
|
||||||
this->stream[(edi / 4)] = esi;
|
|
||||||
this->stream[(edi / 4)+1] = ecx;
|
|
||||||
edi = edi + 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
eax = 0;
|
|
||||||
edx = 0;
|
|
||||||
ou = 0;
|
|
||||||
while (ou < 0x1000) {
|
|
||||||
edi = 0x48;
|
|
||||||
edx = 0x448;
|
|
||||||
|
|
||||||
while (edi < edx) {
|
while (edi < edx) {
|
||||||
esi = esi ^ this->stream[0];
|
esi = esi ^ stream[0];
|
||||||
eax = esi >> 0x18;
|
eax = esi >> 0x18;
|
||||||
ebx = (esi >> 0x10) & 0xff;
|
ebx = (esi >> 0x10) & 0xFF;
|
||||||
eax = this->stream[eax + 0x12] + this->stream[ebx + 0x112];
|
eax = stream[eax + 0x12] + stream[ebx + 0x112];
|
||||||
ebx = (esi >> 8) & 0xFF;
|
ebx = (esi >> 8) & 0xFF;
|
||||||
eax = eax ^ this->stream[ebx + 0x212];
|
eax = eax ^ stream[ebx + 0x212];
|
||||||
ebx = esi & 0xFF;
|
ebx = esi & 0xFF;
|
||||||
eax = eax + this->stream[ebx + 0x312];
|
eax = eax + stream[ebx + 0x312];
|
||||||
|
|
||||||
eax = eax ^ this->stream[1];
|
eax = eax ^ stream[1];
|
||||||
ecx = ecx ^ eax;
|
ecx = ecx ^ eax;
|
||||||
ebx = ecx >> 0x18;
|
ebx = ecx >> 0x18;
|
||||||
eax = (ecx >> 0x10) & 0xFF;
|
eax = (ecx >> 0x10) & 0xFF;
|
||||||
ebx = this->stream[ebx + 0x12] + this->stream[eax + 0x112];
|
ebx = stream[ebx + 0x12] + stream[eax + 0x112];
|
||||||
eax = (ecx >> 8) & 0xFF;
|
eax = (ecx >> 8) & 0xFF;
|
||||||
ebx = ebx ^ this->stream[eax + 0x212];
|
ebx = ebx ^ stream[eax + 0x212];
|
||||||
eax = ecx & 0xFF;
|
eax = ecx & 0xFF;
|
||||||
ebx = ebx + this->stream[eax + 0x312];
|
ebx = ebx + stream[eax + 0x312];
|
||||||
|
|
||||||
for (x = 0; x <= 5; x++) {
|
for (x = 0; x <= 5; x++) {
|
||||||
ebx = ebx ^ this->stream[(x * 2) + 2];
|
ebx = ebx ^ stream[(x * 2) + 2];
|
||||||
esi = esi ^ ebx;
|
esi = esi ^ ebx;
|
||||||
ebx = esi >> 0x18;
|
ebx = esi >> 0x18;
|
||||||
eax = (esi >> 0x10) & 0xFF;
|
eax = (esi >> 0x10) & 0xFF;
|
||||||
ebx = this->stream[ebx + 0x12] + this->stream[eax + 0x112];
|
ebx = stream[ebx + 0x12] + stream[eax + 0x112];
|
||||||
eax = (esi >> 8) & 0xFF;
|
eax = (esi >> 8) & 0xFF;
|
||||||
ebx = ebx ^ this->stream[eax + 0x212];
|
ebx = ebx ^ stream[eax + 0x212];
|
||||||
eax = esi & 0xFF;
|
eax = esi & 0xFF;
|
||||||
ebx = ebx + this->stream[eax + 0x312];
|
ebx = ebx + stream[eax + 0x312];
|
||||||
|
|
||||||
ebx = ebx ^ this->stream[(x * 2) + 3];
|
ebx = ebx ^ stream[(x * 2) + 3];
|
||||||
ecx = ecx ^ ebx;
|
ecx = ecx ^ ebx;
|
||||||
ebx = ecx >> 0x18;
|
ebx = ecx >> 0x18;
|
||||||
eax = (ecx >> 0x10) & 0xFF;
|
eax = (ecx >> 0x10) & 0xFF;
|
||||||
ebx = this->stream[ebx + 0x12] + this->stream[eax + 0x112];
|
ebx = stream[ebx + 0x12] + stream[eax + 0x112];
|
||||||
eax = (ecx >> 8) & 0xFF;
|
eax = (ecx >> 8) & 0xFF;
|
||||||
ebx = ebx ^ this->stream[eax + 0x212];
|
ebx = ebx ^ stream[eax + 0x212];
|
||||||
eax = ecx & 0xFF;
|
eax = ecx & 0xFF;
|
||||||
ebx = ebx + this->stream[eax + 0x312];
|
ebx = ebx + stream[eax + 0x312];
|
||||||
}
|
}
|
||||||
|
|
||||||
ebx = ebx ^ this->stream[14];
|
ebx = ebx ^ stream[14];
|
||||||
esi = esi ^ ebx;
|
esi = esi ^ ebx;
|
||||||
eax = esi >> 0x18;
|
eax = esi >> 0x18;
|
||||||
ebx = (esi >> 0x10) & 0xFF;
|
ebx = (esi >> 0x10) & 0xFF;
|
||||||
eax = this->stream[eax + 0x12] + this->stream[ebx + 0x112];
|
eax = stream[eax + 0x12] + stream[ebx + 0x112];
|
||||||
ebx = (esi >> 8) & 0xFF;
|
ebx = (esi >> 8) & 0xFF;
|
||||||
eax = eax ^ this->stream[ebx + 0x212];
|
eax = eax ^ stream[ebx + 0x212];
|
||||||
ebx = esi & 0xFF;
|
ebx = esi & 0xFF;
|
||||||
eax = eax + this->stream[ebx + 0x312];
|
eax = eax + stream[ebx + 0x312];
|
||||||
|
|
||||||
eax = eax ^ this->stream[15];
|
eax = eax ^ stream[15];
|
||||||
eax = ecx ^ eax;
|
eax = ecx ^ eax;
|
||||||
ecx = eax >> 0x18;
|
ecx = eax >> 0x18;
|
||||||
ebx = (eax >> 0x10) & 0xFF;
|
ebx = (eax >> 0x10) & 0xFF;
|
||||||
ecx = this->stream[ecx + 0x12] + this->stream[ebx + 0x112];
|
ecx = stream[ecx + 0x12] + stream[ebx + 0x112];
|
||||||
ebx = (eax >> 8) & 0xFF;
|
ebx = (eax >> 8) & 0xFF;
|
||||||
ecx = ecx ^ this->stream[ebx + 0x212];
|
ecx = ecx ^ stream[ebx + 0x212];
|
||||||
ebx = eax & 0xFF;
|
ebx = eax & 0xFF;
|
||||||
ecx = ecx + this->stream[ebx + 0x312];
|
ecx = ecx + stream[ebx + 0x312];
|
||||||
|
|
||||||
ecx = ecx ^ this->stream[16];
|
ecx = ecx ^ stream[16];
|
||||||
ecx = ecx ^ esi;
|
ecx = ecx ^ esi;
|
||||||
esi = this->stream[17];
|
esi = stream[17];
|
||||||
esi = esi ^ eax;
|
esi = esi ^ eax;
|
||||||
this->stream[(ou / 4) + (edi / 4)] = esi;
|
stream[(edi / 4)] = esi;
|
||||||
this->stream[(ou / 4) + (edi / 4) + 1] = ecx;
|
stream[(edi / 4)+1] = ecx;
|
||||||
edi = edi + 8;
|
edi = edi + 8;
|
||||||
}
|
}
|
||||||
ou = ou + 0x400;
|
|
||||||
|
eax = 0;
|
||||||
|
edx = 0;
|
||||||
|
ou = 0;
|
||||||
|
while (ou < 0x1000) {
|
||||||
|
edi = 0x48;
|
||||||
|
edx = 0x448;
|
||||||
|
|
||||||
|
while (edi < edx) {
|
||||||
|
esi = esi ^ stream[0];
|
||||||
|
eax = esi >> 0x18;
|
||||||
|
ebx = (esi >> 0x10) & 0xFF;
|
||||||
|
eax = stream[eax + 0x12] + stream[ebx + 0x112];
|
||||||
|
ebx = (esi >> 8) & 0xFF;
|
||||||
|
eax = eax ^ stream[ebx + 0x212];
|
||||||
|
ebx = esi & 0xFF;
|
||||||
|
eax = eax + stream[ebx + 0x312];
|
||||||
|
|
||||||
|
eax = eax ^ stream[1];
|
||||||
|
ecx = ecx ^ eax;
|
||||||
|
ebx = ecx >> 0x18;
|
||||||
|
eax = (ecx >> 0x10) & 0xFF;
|
||||||
|
ebx = stream[ebx + 0x12] + stream[eax + 0x112];
|
||||||
|
eax = (ecx >> 8) & 0xFF;
|
||||||
|
ebx = ebx ^ stream[eax + 0x212];
|
||||||
|
eax = ecx & 0xFF;
|
||||||
|
ebx = ebx + stream[eax + 0x312];
|
||||||
|
|
||||||
|
for (x = 0; x <= 5; x++) {
|
||||||
|
ebx = ebx ^ stream[(x * 2) + 2];
|
||||||
|
esi = esi ^ ebx;
|
||||||
|
ebx = esi >> 0x18;
|
||||||
|
eax = (esi >> 0x10) & 0xFF;
|
||||||
|
ebx = stream[ebx + 0x12] + stream[eax + 0x112];
|
||||||
|
eax = (esi >> 8) & 0xFF;
|
||||||
|
ebx = ebx ^ stream[eax + 0x212];
|
||||||
|
eax = esi & 0xFF;
|
||||||
|
ebx = ebx + stream[eax + 0x312];
|
||||||
|
|
||||||
|
ebx = ebx ^ stream[(x * 2) + 3];
|
||||||
|
ecx = ecx ^ ebx;
|
||||||
|
ebx = ecx >> 0x18;
|
||||||
|
eax = (ecx >> 0x10) & 0xFF;
|
||||||
|
ebx = stream[ebx + 0x12] + stream[eax + 0x112];
|
||||||
|
eax = (ecx >> 8) & 0xFF;
|
||||||
|
ebx = ebx ^ stream[eax + 0x212];
|
||||||
|
eax = ecx & 0xFF;
|
||||||
|
ebx = ebx + stream[eax + 0x312];
|
||||||
|
}
|
||||||
|
|
||||||
|
ebx = ebx ^ stream[14];
|
||||||
|
esi = esi ^ ebx;
|
||||||
|
eax = esi >> 0x18;
|
||||||
|
ebx = (esi >> 0x10) & 0xFF;
|
||||||
|
eax = stream[eax + 0x12] + stream[ebx + 0x112];
|
||||||
|
ebx = (esi >> 8) & 0xFF;
|
||||||
|
eax = eax ^ stream[ebx + 0x212];
|
||||||
|
ebx = esi & 0xFF;
|
||||||
|
eax = eax + stream[ebx + 0x312];
|
||||||
|
|
||||||
|
eax = eax ^ stream[15];
|
||||||
|
eax = ecx ^ eax;
|
||||||
|
ecx = eax >> 0x18;
|
||||||
|
ebx = (eax >> 0x10) & 0xFF;
|
||||||
|
ecx = stream[ecx + 0x12] + stream[ebx + 0x112];
|
||||||
|
ebx = (eax >> 8) & 0xFF;
|
||||||
|
ecx = ecx ^ stream[ebx + 0x212];
|
||||||
|
ebx = eax & 0xFF;
|
||||||
|
ecx = ecx + stream[ebx + 0x312];
|
||||||
|
|
||||||
|
ecx = ecx ^ stream[16];
|
||||||
|
ecx = ecx ^ esi;
|
||||||
|
esi = stream[17];
|
||||||
|
esi = esi ^ eax;
|
||||||
|
stream[(ou / 4) + (edi / 4)] = esi;
|
||||||
|
stream[(ou / 4) + (edi / 4) + 1] = ecx;
|
||||||
|
edi = edi + 8;
|
||||||
|
}
|
||||||
|
ou = ou + 0x400;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PSOBBEncryption::skip(size_t) { }
|
||||||
|
|||||||
+16
-15
@@ -4,6 +4,7 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -15,8 +16,9 @@ class PSOEncryption {
|
|||||||
public:
|
public:
|
||||||
virtual ~PSOEncryption() = default;
|
virtual ~PSOEncryption() = default;
|
||||||
|
|
||||||
virtual void encrypt(void* data, size_t size) = 0;
|
virtual void encrypt(void* data, size_t size, bool advance = true) = 0;
|
||||||
virtual void decrypt(void* data, size_t size);
|
virtual void decrypt(void* data, size_t size, bool advance = true);
|
||||||
|
virtual void skip(size_t size) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
PSOEncryption() = default;
|
PSOEncryption() = default;
|
||||||
@@ -26,11 +28,12 @@ class PSOPCEncryption : public PSOEncryption {
|
|||||||
public:
|
public:
|
||||||
explicit PSOPCEncryption(uint32_t seed);
|
explicit PSOPCEncryption(uint32_t seed);
|
||||||
|
|
||||||
virtual void encrypt(void* data, size_t size);
|
virtual void encrypt(void* data, size_t size, bool advance = true);
|
||||||
|
virtual void skip(size_t size);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void update_stream();
|
void update_stream();
|
||||||
uint32_t next();
|
uint32_t next(bool advance = true);
|
||||||
|
|
||||||
uint32_t stream[PC_STREAM_LENGTH];
|
uint32_t stream[PC_STREAM_LENGTH];
|
||||||
uint16_t offset;
|
uint16_t offset;
|
||||||
@@ -40,11 +43,12 @@ class PSOGCEncryption : public PSOEncryption {
|
|||||||
public:
|
public:
|
||||||
explicit PSOGCEncryption(uint32_t key);
|
explicit PSOGCEncryption(uint32_t key);
|
||||||
|
|
||||||
virtual void encrypt(void* data, size_t size);
|
virtual void encrypt(void* data, size_t size, bool advance = true);
|
||||||
|
virtual void skip(size_t size);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void update_stream();
|
void update_stream();
|
||||||
uint32_t next();
|
uint32_t next(bool advance = true);
|
||||||
|
|
||||||
uint32_t stream[GC_STREAM_LENGTH];
|
uint32_t stream[GC_STREAM_LENGTH];
|
||||||
uint16_t offset;
|
uint16_t offset;
|
||||||
@@ -59,16 +63,13 @@ public:
|
|||||||
|
|
||||||
PSOBBEncryption(const KeyFile& key, const void* seed, size_t seed_size);
|
PSOBBEncryption(const KeyFile& key, const void* seed, size_t seed_size);
|
||||||
|
|
||||||
virtual void encrypt(void* data, size_t size);
|
virtual void encrypt(void* data, size_t size, bool advance = true);
|
||||||
virtual void decrypt(void* data, size_t size);
|
virtual void decrypt(void* data, size_t size, bool advance = true);
|
||||||
|
virtual void skip(size_t size);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
PSOBBEncryption() = default;
|
static std::vector<uint32_t> generate_stream(
|
||||||
|
const KeyFile& key, const void* seed, size_t seed_size);
|
||||||
|
|
||||||
void postprocess_initial_stream(const std::string& seed);
|
const std::vector<uint32_t> stream;
|
||||||
|
|
||||||
void update_stream();
|
|
||||||
|
|
||||||
uint32_t stream[BB_STREAM_LENGTH];
|
|
||||||
uint16_t offset;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,11 +1,19 @@
|
|||||||
#include "PSOProtocol.hh"
|
#include "PSOProtocol.hh"
|
||||||
|
|
||||||
|
#include <event2/buffer.h>
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
PSOCommandHeader::PSOCommandHeader() {
|
||||||
|
this->bb.size = 0;
|
||||||
|
this->bb.command = 0;
|
||||||
|
this->bb.flag = 0;
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t PSOCommandHeader::command(GameVersion version) const {
|
uint16_t PSOCommandHeader::command(GameVersion version) const {
|
||||||
switch (version) {
|
switch (version) {
|
||||||
case GameVersion::DC:
|
case GameVersion::DC:
|
||||||
@@ -48,3 +56,56 @@ uint32_t PSOCommandHeader::flag(GameVersion version) const {
|
|||||||
throw logic_error("unknown game version");
|
throw logic_error("unknown game version");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void for_each_received_command(
|
||||||
|
struct bufferevent* bev,
|
||||||
|
GameVersion version,
|
||||||
|
PSOEncryption* crypt,
|
||||||
|
function<void(uint16_t, uint16_t, const string&)> fn) {
|
||||||
|
struct evbuffer* buf = bufferevent_get_input(bev);
|
||||||
|
|
||||||
|
size_t header_size = version == GameVersion::BB ? 8 : 4;
|
||||||
|
for (;;) {
|
||||||
|
PSOCommandHeader header;
|
||||||
|
if (evbuffer_copyout(buf, &header, header_size)
|
||||||
|
< static_cast<ssize_t>(header_size)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crypt) {
|
||||||
|
crypt->decrypt(&header, header_size, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t command_logical_size = header.size(version);
|
||||||
|
|
||||||
|
// BB pads commands to 8-byte boundaries, and this is not reflected in the
|
||||||
|
// size field
|
||||||
|
size_t command_physical_size = (version == GameVersion::BB)
|
||||||
|
? (command_logical_size + header_size - 1) & ~(header_size - 1)
|
||||||
|
: command_logical_size;
|
||||||
|
if (evbuffer_get_length(buf) < command_physical_size) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we get here, then there is a full command in the buffer
|
||||||
|
|
||||||
|
evbuffer_drain(buf, header_size);
|
||||||
|
|
||||||
|
string command_data(command_logical_size - header_size, '\0');
|
||||||
|
if (evbuffer_remove(buf, command_data.data(), command_data.size())
|
||||||
|
< static_cast<ssize_t>(command_data.size())) {
|
||||||
|
throw logic_error("enough bytes available, but could not remove them");
|
||||||
|
}
|
||||||
|
if (command_logical_size != command_physical_size) {
|
||||||
|
evbuffer_drain(buf, command_physical_size - command_logical_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crypt) {
|
||||||
|
crypt->skip(header_size);
|
||||||
|
crypt->decrypt(command_data.data(), command_data.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn(header.command(version), header.flag(version), command_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
+17
-5
@@ -1,26 +1,30 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
#include <event2/bufferevent.h>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
#include "Version.hh"
|
#include "Version.hh"
|
||||||
|
#include "PSOEncryption.hh"
|
||||||
|
|
||||||
struct PSOCommandHeaderPC {
|
struct PSOCommandHeaderPC {
|
||||||
uint16_t size;
|
uint16_t size;
|
||||||
uint8_t command;
|
uint8_t command;
|
||||||
uint8_t flag;
|
uint8_t flag;
|
||||||
};
|
} __attribute__((packed));
|
||||||
|
|
||||||
struct PSOCommandHeaderDCGC {
|
struct PSOCommandHeaderDCGC {
|
||||||
uint8_t command;
|
uint8_t command;
|
||||||
uint8_t flag;
|
uint8_t flag;
|
||||||
uint16_t size;
|
uint16_t size;
|
||||||
};
|
} __attribute__((packed));
|
||||||
|
|
||||||
struct PSOCommandHeaderBB {
|
struct PSOCommandHeaderBB {
|
||||||
uint16_t size;
|
uint16_t size;
|
||||||
uint16_t command;
|
uint16_t command;
|
||||||
uint32_t flag;
|
uint32_t flag;
|
||||||
};
|
} __attribute__((packed));
|
||||||
|
|
||||||
union PSOCommandHeader {
|
union PSOCommandHeader {
|
||||||
PSOCommandHeaderDCGC dc;
|
PSOCommandHeaderDCGC dc;
|
||||||
@@ -31,10 +35,18 @@ union PSOCommandHeader {
|
|||||||
uint16_t command(GameVersion version) const;
|
uint16_t command(GameVersion version) const;
|
||||||
uint16_t size(GameVersion version) const;
|
uint16_t size(GameVersion version) const;
|
||||||
uint32_t flag(GameVersion version) const;
|
uint32_t flag(GameVersion version) const;
|
||||||
};
|
|
||||||
|
PSOCommandHeader();
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
union PSOSubcommand {
|
union PSOSubcommand {
|
||||||
uint8_t byte[4];
|
uint8_t byte[4];
|
||||||
uint16_t word[2];
|
uint16_t word[2];
|
||||||
uint32_t dword;
|
uint32_t dword;
|
||||||
};
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
void for_each_received_command(
|
||||||
|
struct bufferevent* bev,
|
||||||
|
GameVersion version,
|
||||||
|
PSOEncryption* crypt,
|
||||||
|
std::function<void(uint16_t, uint16_t, const std::string&)> fn);
|
||||||
|
|||||||
+26
-21
@@ -128,24 +128,34 @@ static const char* dc_lobby_server_copyright = "DreamCast Lobby Server. Copyrigh
|
|||||||
static const char* bb_game_server_copyright = "Phantasy Star Online Blue Burst Game Server. Copyright 1999-2004 SONICTEAM.";
|
static const char* bb_game_server_copyright = "Phantasy Star Online Blue Burst Game Server. Copyright 1999-2004 SONICTEAM.";
|
||||||
static const char* patch_server_copyright = "Patch Server. Copyright SonicTeam, LTD. 2001";
|
static const char* patch_server_copyright = "Patch Server. Copyright SonicTeam, LTD. 2001";
|
||||||
|
|
||||||
static void send_server_init_dc_pc_gc(shared_ptr<Client> c, const char* copyright_text,
|
string prepare_server_init_contents_dc_pc_gc(
|
||||||
uint8_t command) {
|
bool initial_connection,
|
||||||
struct {
|
uint32_t server_key,
|
||||||
|
uint32_t client_key) {
|
||||||
|
struct Command {
|
||||||
char copyright[0x40];
|
char copyright[0x40];
|
||||||
uint32_t server_key;
|
uint32_t server_key;
|
||||||
uint32_t client_key;
|
uint32_t client_key;
|
||||||
char after_message[200];
|
char after_message[200];
|
||||||
} cmd;
|
};
|
||||||
|
string ret(sizeof(Command), '\0');
|
||||||
|
auto* cmd = reinterpret_cast<Command*>(ret.data());
|
||||||
|
|
||||||
|
strcpy(cmd->copyright, initial_connection ? dc_port_map_copyright : dc_lobby_server_copyright);
|
||||||
|
cmd->server_key = server_key;
|
||||||
|
cmd->client_key = client_key;
|
||||||
|
strcpy(cmd->after_message, anti_copyright);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void send_server_init_dc_pc_gc(shared_ptr<Client> c,
|
||||||
|
bool initial_connection, uint8_t command) {
|
||||||
uint32_t server_key = random_object<uint32_t>();
|
uint32_t server_key = random_object<uint32_t>();
|
||||||
uint32_t client_key = random_object<uint32_t>();
|
uint32_t client_key = random_object<uint32_t>();
|
||||||
|
|
||||||
memset(&cmd, 0, sizeof(cmd));
|
string data = prepare_server_init_contents_dc_pc_gc(
|
||||||
strcpy(cmd.copyright, copyright_text);
|
initial_connection, server_key, client_key);
|
||||||
cmd.server_key = server_key;
|
send_command(c, command, 0x00, data);
|
||||||
cmd.client_key = client_key;
|
|
||||||
strcpy(cmd.after_message, anti_copyright);
|
|
||||||
send_command(c, command, 0x00, cmd);
|
|
||||||
|
|
||||||
switch (c->version) {
|
switch (c->version) {
|
||||||
case GameVersion::DC:
|
case GameVersion::DC:
|
||||||
@@ -163,19 +173,14 @@ static void send_server_init_dc_pc_gc(shared_ptr<Client> c, const char* copyrigh
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void send_server_init_pc(shared_ptr<Client> c, bool initial_connection) {
|
static void send_server_init_pc(shared_ptr<Client> c, bool initial_connection) {
|
||||||
send_server_init_dc_pc_gc(c,
|
send_server_init_dc_pc_gc(c, initial_connection, 0x17);
|
||||||
initial_connection ? dc_port_map_copyright : dc_lobby_server_copyright,
|
|
||||||
0x17);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void send_server_init_gc(shared_ptr<Client> c, bool initial_connection) {
|
static void send_server_init_gc(shared_ptr<Client> c, bool initial_connection) {
|
||||||
send_server_init_dc_pc_gc(c,
|
send_server_init_dc_pc_gc(c, initial_connection, initial_connection ? 0x17 : 0x02);
|
||||||
initial_connection ? dc_port_map_copyright : dc_lobby_server_copyright,
|
|
||||||
initial_connection ? 0x17 : 0x02);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void send_server_init_bb(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
static void send_server_init_bb(shared_ptr<ServerState> s, shared_ptr<Client> c) {
|
||||||
bool) {
|
|
||||||
struct {
|
struct {
|
||||||
char copyright[0x60];
|
char copyright[0x60];
|
||||||
uint8_t server_key[0x30];
|
uint8_t server_key[0x30];
|
||||||
@@ -196,7 +201,7 @@ static void send_server_init_bb(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
|||||||
sizeof(cmd.client_key)));
|
sizeof(cmd.client_key)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void send_server_init_patch(shared_ptr<Client> c, bool) {
|
static void send_server_init_patch(shared_ptr<Client> c) {
|
||||||
struct {
|
struct {
|
||||||
char copyright[0x40];
|
char copyright[0x40];
|
||||||
uint32_t server_key;
|
uint32_t server_key;
|
||||||
@@ -223,11 +228,11 @@ void send_server_init(shared_ptr<ServerState> s, shared_ptr<Client> c,
|
|||||||
if (c->version == GameVersion::PC) {
|
if (c->version == GameVersion::PC) {
|
||||||
send_server_init_pc(c, initial_connection);
|
send_server_init_pc(c, initial_connection);
|
||||||
} else if (c->version == GameVersion::PATCH) {
|
} else if (c->version == GameVersion::PATCH) {
|
||||||
send_server_init_patch(c, initial_connection);
|
send_server_init_patch(c);
|
||||||
} else if (c->version == GameVersion::GC) {
|
} else if (c->version == GameVersion::GC) {
|
||||||
send_server_init_gc(c, initial_connection);
|
send_server_init_gc(c, initial_connection);
|
||||||
} else if (c->version == GameVersion::BB) {
|
} else if (c->version == GameVersion::BB) {
|
||||||
send_server_init_bb(s, c, initial_connection);
|
send_server_init_bb(s, c);
|
||||||
} else {
|
} else {
|
||||||
throw logic_error("unimplemented versioned command");
|
throw logic_error("unimplemented versioned command");
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -74,7 +74,8 @@ void send_command(std::shared_ptr<TARGET> c, uint16_t command, uint32_t flag,
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
std::string prepare_server_init_contents_dc_pc_gc(
|
||||||
|
bool initial_connection, uint32_t server_key, uint32_t client_key);
|
||||||
void send_server_init(std::shared_ptr<ServerState> s, std::shared_ptr<Client> c,
|
void send_server_init(std::shared_ptr<ServerState> s, std::shared_ptr<Client> c,
|
||||||
bool initial_connection);
|
bool initial_connection);
|
||||||
void send_update_client_config(std::shared_ptr<Client> c);
|
void send_update_client_config(std::shared_ptr<Client> c);
|
||||||
|
|||||||
+10
-49
@@ -208,55 +208,16 @@ void Server::on_disconnecting_client_error(struct bufferevent* bev,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Server::receive_and_process_commands(shared_ptr<Client> c) {
|
void Server::receive_and_process_commands(shared_ptr<Client> c) {
|
||||||
struct evbuffer* buf = bufferevent_get_input(c->bev);
|
for_each_received_command(c->bev, c->version, c->crypt_in.get(),
|
||||||
size_t header_size = (c->version == GameVersion::BB) ? 8 : 4;
|
[this, c](uint16_t command, uint16_t flag, const std::string& data) {
|
||||||
|
try {
|
||||||
// read as much data into recv_buffer as we can and decrypt it
|
process_command(this->state, c, command, flag, data.size(), data.data());
|
||||||
size_t existing_bytes = c->recv_buffer.size();
|
} catch (const exception& e) {
|
||||||
size_t new_bytes = evbuffer_get_length(buf);
|
log(INFO, "[Server] Error in client stream: %s", e.what());
|
||||||
new_bytes &= ~(header_size - 1); // only read in multiples of header_size
|
c->should_disconnect = true;
|
||||||
c->recv_buffer.resize(existing_bytes + new_bytes);
|
return;
|
||||||
void* recv_ptr = c->recv_buffer.data() + existing_bytes;
|
}
|
||||||
if (evbuffer_remove(buf, recv_ptr, new_bytes) != static_cast<ssize_t>(new_bytes)) {
|
});
|
||||||
throw runtime_error("some bytes could not be read from the receive buffer");
|
|
||||||
}
|
|
||||||
|
|
||||||
// decrypt the received data if encryption is enabled
|
|
||||||
if (c->crypt_in.get()) {
|
|
||||||
c->crypt_in->decrypt(recv_ptr, new_bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
// process as many commands as possible
|
|
||||||
size_t offset = 0;
|
|
||||||
while (offset < c->recv_buffer.size()) {
|
|
||||||
const PSOCommandHeader* header = reinterpret_cast<const PSOCommandHeader*>(
|
|
||||||
c->recv_buffer.data() + offset);
|
|
||||||
size_t size = header->size(c->version);
|
|
||||||
if (offset + size > c->recv_buffer.size()) {
|
|
||||||
break; // don't have a complete command; we're done for now
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we get here, then we have a complete, decrypted command waiting to be
|
|
||||||
// processed. we copy it out and append zeroes on the end so that it's safe
|
|
||||||
// to call string functions on the buffer in command handlers
|
|
||||||
string data = c->recv_buffer.substr(offset + header_size, size - header_size);
|
|
||||||
data.append(4, '\0');
|
|
||||||
try {
|
|
||||||
process_command(this->state, c, header->command(c->version),
|
|
||||||
header->flag(c->version), size - header_size, data.data());
|
|
||||||
} catch (const exception& e) {
|
|
||||||
log(INFO, "[Server] Error in client stream: %s", e.what());
|
|
||||||
c->should_disconnect = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// BB pads commands to 8-byte boundaries, so if we see a shorter command,
|
|
||||||
// skip over the padding
|
|
||||||
offset += (size + header_size - 1) & ~(header_size - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove the processed commands from the receive buffer
|
|
||||||
c->recv_buffer = c->recv_buffer.substr(offset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Server::Server(shared_ptr<struct event_base> base,
|
Server::Server(shared_ptr<struct event_base> base,
|
||||||
|
|||||||
Reference in New Issue
Block a user