People may dispute who made this, fisher or phail as they both claimed it as their work. Either way it's not used and can be released. This is not edited, the pure source of what I have.
YOU WILL NEED TO EDIT IT ACCORDINGLY FOR YOUR MATCHSERVER(probably)
That is easy though, I've done it for myself and got it working there is a spot for a command of !stats that will not work for you no matter what as you don't have a /stats command
main.cpp
Code:
#include <string>
#include <conio.h>
#include <windows.h>
#include "packet.h"
#include "struct.h"
#define BUFFER_SIZE 256
BYTE ran[] = {0x37, 0x04, 0x5D, 0x2E, 0x43, 0x3A, 0x49, 0x53, 0x50, 0x05, 0x13, 0xC9, 0x28, 0xA4, 0x4D, 0x05};
BYTE xor[] = {0x57, 0x02, 0x5B, 0x04, 0x34, 0x06, 0x01, 0x08, 0x37, 0x0A, 0x12, 0x69, 0x41, 0x38, 0x0F, 0x78};
#define VERSION 0x3a
#define FILELIST_CRC 0
#define ACCOUNT_NAME "testing22"
#define CHAR_NAME "testing22"
#define ACCOUNT_PASSWORD "notreallysecure"
#define HOME_CHANNEL MUID(0, 1)
MUID SVID;
MUID MYID;
MUID CHID;
BYTE KEY[32];
BYTE COUNTER;
SOCKET SOCK;
sockaddr_in SIN;
void WriteHex(void* A, char* B){
std::string patchstring = B;
char* token = strtok((char*)patchstring.c_str(), " ");
for(int i = 0; token != NULL; ++i){
BYTE b;
sscanf(token, "%X", &b);
((BYTE*)A)[i] = b;
token = strtok(NULL, " ");
}
}
void Talk(){
start:
SOCK = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
SIN.sin_family = AF_INET;
SIN.sin_addr.s_addr = inet_addr("89.46.35.33");
SIN.sin_port = htons(6000);
connect(SOCK, (sockaddr*)&SIN, sizeof(SIN));
PACKET_MANAGER in;
for(;;){
int rc;
rc = recv(SOCK, in.sbuffer, PACKET_MANAGER_BUFFER_SIZE, 0);
if(rc == 0 || rc == SOCKET_ERROR){
printf("DISCONNECTED\n");
goto start;
}
if(in.packet->version == 0xA){
printf("HANDSHAKE\n");
in.index = 6;
SVID = in.READ<MUID>();
MYID = in.READ<MUID>();
DWORD time = in.READ<DWORD>();
memcpy(KEY, in.buffer + 22, 4);
memcpy(KEY + 4, in.buffer + 10, 12);
memcpy(KEY + 16, ran, 16);
for(int i = 0; i < 16; ++i){
KEY[i] ^= xor[i];
}
PACKET_MANAGER out;
out.index = 8;
out.WRITE<WORD>(0x3e9);//login
out.WRITE<BYTE>(++COUNTER);//counter
out.WRITES(ACCOUNT_NAME);//name
out.WRITES(ACCOUNT_PASSWORD);//pass
out.WRITE<int>(VERSION);//version
out.WRITE<DWORD>(FILELIST_CRC);//crc
FILE* hashfile = fopen("hash.txt", "rb");
char hashstring[3 * 16];
fread(hashstring, 3, 16, hashfile);
fclose(hashfile);
BYTE hash[16];
WriteHex(hash, hashstring);
out.WRITEB(1, 16);//md5
out.WRITER((void*)hash, 16);
out.SET<WORD>(out.packet->size - 6, 6);
out.ENCRYPT(KEY);
send(SOCK, out.sbuffer, out.index, 0);
continue;
}
if(in.packet->version == 0x65){
in.DECRYPT(KEY);
}
WORD command = in.GET<WORD>(8);
switch(command){
case 0x142:{//ping
in.index = 11;
DWORD time = in.READ<DWORD>();
PACKET_MANAGER out;
out.index = 8;
out.WRITE<WORD>(0x143);//pong
out.WRITE<BYTE>(++COUNTER);//counter
out.WRITE<DWORD>(time);//time
out.SET<WORD>(out.packet->size - 6, 6);
out.ENCRYPT(KEY);
send(SOCK, out.sbuffer, out.index, 0);
break;
}
case 0x169:{//clock synch
break;
}
case 0x192:{//announce
in.index = 11;
int type = in.READ<int>();
char* msg = in.READS();
PACKET_MANAGER out;
out.index = 8;
out.WRITE<WORD>(0x4c9);//request channel chat
out.WRITE<BYTE>(++COUNTER);//counter
out.WRITE<MUID>(MYID);
out.WRITE<MUID>(CHID);
out.WRITES(msg);
out.SET<WORD>(out.packet->size - 6, 6);
out.ENCRYPT(KEY);
send(SOCK, out.sbuffer, out.index, 0);
break;
}
case 0x1f5:{//admin announce
in.index = 11;
MUID adminid = in.READ<MUID>();
char* message = in.READS();
printf("WALL: %s\n", message);
break;
}
case 0x3ea:{//response login
in.index = 11;
DWORD result = in.READ<DWORD>();
if(result != 0){
printf("LOGIN FAILED: %d\n", result);
goto start;
}
PACKET_MANAGER out;
out.index = 8;
out.WRITE<WORD>(0x6a5);//request char list
out.WRITE<BYTE>(++COUNTER);
out.WRITEB(1, 1);//dunno, but needed (message)
out.WRITE<BYTE>(0);
out.SET<WORD>(out.packet->size - 6, 6);
out.ENCRYPT(KEY);
send(SOCK, out.sbuffer, out.index, 0);
break;
}
case 0x4b7:{//response channel join
in.index = 11;
CHID = in.READ<MUID>();
DWORD type = in.READ<DWORD>();
char* name = in.READS();
printf("JOINED CHANNEL '%s'\n", name);
break;
}
case 0x4c6:{//channel player list
break;
}
case 0x4ca:{//channel chat
in.index = 11;
MUID id = in.READ<MUID>();
char* name = in.READS();
char* msg = in.READS();
int ugrade = in.READ<int>();
printf("%s: %s\n", name, msg);
if(id == MYID){
break;
}
char buffer[BUFFER_SIZE];
char* command = strtok(msg, " ");
if(command == NULL){
break;
}
if(_stricmp(command, "!stats") == 0){
sprintf_s(buffer, BUFFER_SIZE, "/stats %s", name);
char* target = strtok(NULL, "");
if(target != NULL){
sprintf_s(buffer, BUFFER_SIZE, "/stats %s", target);
}
PACKET_MANAGER out;
out.index = 8;
out.WRITE<WORD>(0x4c9);//request channel chat
out.WRITE<BYTE>(++COUNTER);//counter
out.WRITE<MUID>(MYID);//player id
out.WRITE<MUID>(MUID(0, -1));//channel id
out.WRITES(buffer);//message
out.SET<WORD>(out.packet->size - 6, 6);
out.ENCRYPT(KEY);
send(SOCK, out.sbuffer, out.index, 0);
break;
}
break;
}
case 0x4cf:{//channel rules
break;
}
case 0x522:{//stage list
break;
}
case 0x641:{
in.index = 11;
char* sender = in.READS();
char* receiver = in.READS();
char* msg = in.READS();
printf("from %s: %s\n", sender, msg);
PACKET_MANAGER out;
out.index = 8;
out.WRITE<WORD>(0x4c9);//request channel chat
out.WRITE<BYTE>(++COUNTER);//counter
out.WRITE<MUID>(MYID);
out.WRITE<MUID>(CHID);
char buffer[BUFFER_SIZE];
sprintf_s(buffer, BUFFER_SIZE, "%s says '%s'", sender, msg);
out.WRITES(buffer);
out.SET<WORD>(out.packet->size - 6, 6);
out.ENCRYPT(KEY);
send(SOCK, out.sbuffer, out.index, 0);
break;
}
case 0x6a6:{//response char list
in.index = 11;
in.READ<int>();//blob total size
in.READ<int>();//blob member size
int count = in.READ<int>();//blob member count
if(count > 0){
MTD_CharListInfo cli = in.READ<MTD_CharListInfo>();
PACKET_MANAGER out;
out.index = 8;
out.WRITE<WORD>(0x6a7);//request select char
out.WRITE<BYTE>(++COUNTER);
out.WRITE<MUID>(MYID);//player id
out.WRITE<int>(cli.nIndex);//index of char
out.SET<WORD>(out.packet->size - 6, 6);
out.ENCRYPT(KEY);
send(SOCK, out.sbuffer, out.index, 0);
break;
}
if(count == 0){
MTD_CharListInfo cli = in.READ<MTD_CharListInfo>();
PACKET_MANAGER out;
out.index = 8;
out.WRITE<WORD>(0x6af);//request create char
out.WRITE<BYTE>(++COUNTER);
out.WRITE<MUID>(MYID);//player id
out.WRITE<int>(0);//index
out.WRITES(CHAR_NAME);//name
out.WRITE<int>(0);//sex
out.WRITE<int>(0);//hair
out.WRITE<int>(0);//face
out.WRITE<int>(0);//class
out.SET<WORD>(out.packet->size - 6, 6);
out.ENCRYPT(KEY);
send(SOCK, out.sbuffer, out.index, 0);
break;
}
}
case 0x6a8:{//response select character
in.index = 11;
DWORD result = in.READ<DWORD>();
PACKET_MANAGER out;
out.index = 8;
out.WRITE<WORD>(0x4b5);//request channel join
out.WRITE<BYTE>(++COUNTER);
out.WRITE<MUID>(MYID);//player id
out.WRITE<MUID>(HOME_CHANNEL);//channel id
out.SET<WORD>(out.packet->size - 6, 6);
out.ENCRYPT(KEY);
send(SOCK, out.sbuffer, out.index, 0);
break;
}
case 0x6b0:{//response select character
in.index = 11;
DWORD result = in.READ<DWORD>();
if(result != 0){
printf("CHARACTER CREATION FAILED: %d\n", result);
goto start;
}
PACKET_MANAGER out;
out.index = 8;
out.WRITE<WORD>(0x6a5);//request char list
out.WRITE<BYTE>(++COUNTER);
out.WRITEB(1, 1);//dunno, but needed (message)
out.WRITE<BYTE>(0);
out.SET<WORD>(out.packet->size - 6, 6);
out.ENCRYPT(KEY);
send(SOCK, out.sbuffer, out.index, 0);
break;
}
default:{
print_packet((BYTE*)in.buffer, in.packet->size);
break;
}
}
}
}
int main(){
WSAData wsad;
WSAStartup(0x202, &wsad);
Talk();
return 0;
}
packet.h
Code:
#pragma once
typedef struct PACKET{
WORD version;
WORD size;
WORD checksum;
} PACKET;
#define PACKET_MANAGER_BUFFER_SIZE 0x400
typedef struct PACKET_MANAGER{
WORD index;
union{
PACKET* packet;
char* sbuffer;
BYTE* buffer;
};
void RESET(){
packet->version = 0x64;
packet->size = 0;
}
PACKET_MANAGER(){
sbuffer = (char*)malloc(PACKET_MANAGER_BUFFER_SIZE);
RESET();
}
PACKET_MANAGER(char* A){
sbuffer = A;
}
~PACKET_MANAGER(){
try{
free(buffer);
}
catch(...){
}
}
template <class T> void SET(T A, WORD B){
memcpy(buffer + B, &A, sizeof(T));
if((B + sizeof(T)) > packet->size){
packet->size = B + sizeof(T);
}
}
template <class T> T& GET(WORD B){
return *(T*)(buffer + B);
}
template <class T> void WRITE(T A){
memcpy(buffer + index, &A, sizeof(T));
index += sizeof(T);
if(index > packet->size){
packet->size = index;
}
}
template <class T> T& READ(){
T* ret = (T*)(buffer + index);
index += sizeof(T);
return *ret;
}
char* READS(){
WORD len = READ<WORD>();
char* ret = (char*)(buffer + index);
index += len;
if(index > packet->size){
return NULL;
}
return ret;
}
void WRITES(char* A){
WORD len = (WORD)strlen(A);
WRITE<WORD>(len + 2);
memcpy(buffer + index, A, len);
index += len;
WRITE<WORD>(0);
}
void WRITEB(DWORD A, DWORD B){
WRITE<DWORD>(A * B + 8);
WRITE<DWORD>(A);
WRITE<DWORD>(B);
}
void WRITER(void* A, WORD B){
memcpy(buffer + index, A, B);
index += B;
if(index > packet->size){
packet->size = index;
}
}
char* READR(WORD B){
char* ret = (char*)(buffer + index);
index += B;
return ret;
}
void ENCRYPT(BYTE* K){
index = packet->size;
for(int i = 0; i < packet->size; ++i){
WORD a = buffer[6 + i];
a ^= K[i % 32];
a <<= 5;
BYTE b = a >> 8;
b |= a & 0xff;
b ^= 0xf0;
buffer[6 + i] = b;
}
for(int i = 0; i < 2; ++i){
WORD a = buffer[2 + i];
a ^= K[i % 32];
a <<= 5;
BYTE b = a >> 8;
b |= a & 0xff;
b ^= 0xf0;
buffer[2 + i] = b;
}
packet->version = 0x65;
packet->checksum = 0;
for(int i = 6; i < index; ++i){
packet->checksum += buffer[i];
}
for(int i = 0; i < 4; ++i){
packet->checksum -= buffer[i];
}
#pragma warning(disable:4333)
packet->checksum += packet->checksum >> 0x10;
#pragma warning(default:4333)
}
void DECRYPT(BYTE* K){
for(int i = 0; i < 2; ++i){
BYTE a = buffer[2 + i];
a ^= 0xf0;
BYTE b = a & 0x1f;
a >>= 5;
b <<= 3;
b = a | b;
buffer[2 + i] = b ^ K[i % 32];
}
for(int i = 0; i < packet->size; ++i){
BYTE a = buffer[6 + i];
a ^= 0xf0;
BYTE b = a & 0x1f;
a >>= 5;
b <<= 3;
b = a | b;
buffer[6 + i] = b ^ K[i % 32];
}
packet->version = 0x64;
}
void CHECKSUM(){
index = packet->size;
packet->checksum = 0;
for(int i = 6; i < index; ++i){
packet->checksum += buffer[i];
}
for(int i = 0; i < 4; ++i){
packet->checksum -= buffer[i];
}
#pragma warning(disable:4333)
packet->checksum += packet->checksum >> 0x10;
#pragma warning(default:4333)
}
} PACKET_MANAGER;
void print_packet(BYTE* A, int B){
for(int i = 0; i < B; ++i){
printf("%.2x ", A[i]);
if(i % 16 == 0x0f && i != B){
printf("\n");
}
}
if(B % 16 != 0){
printf("\n");
}
}
struct.h
Code:
#pragma once
typedef struct MUID {
DWORD LowPart;
LONG HighPart;
MUID(){
LowPart = 0;
HighPart = 0;
}
MUID(DWORD A, LONG B){
LowPart = A;
HighPart = B;
}
operator bool(){
return this->HighPart != 0 || this->LowPart != 0;
}
} MUID;
bool operator==(const MUID& A, const MUID& B){
return A.HighPart == B.HighPart && A.LowPart == B.LowPart;
}
bool operator!=(const MUID& A, const MUID& B){
return (A == B) == false;
}
bool operator<(const MUID& A, const MUID& B){
return *(__int64*)&A < *(__int64*)&B;
}
bool operator>(const MUID& A, const MUID& B){
return *(__int64*)&A > *(__int64*)&B;
}
typedef struct LocatorData{
BYTE ip[4];
DWORD port;
BYTE index;
WORD playersmax;
WORD playerscurrent;
BYTE type;
BYTE active;
char name[64];
} LocatorData;
typedef struct MTD_CharListInfo{
char szName[32];
BYTE nIndex;
BYTE nLevel;
} MTD_CharListInfo;
typedef struct MTD_CharInfo{
char szName[32];
char szClanName[16];
DWORD nClanGrade;
WORD nClanContPoint;
char nCharNum;
WORD nLevel;
char nSex;
char nHair;
char nFace;
DWORD nXP;
int nBP;
float fBonusRate;
WORD nPrize;
WORD nHP;
WORD nAP;
WORD nMaxWeight;
WORD nSafeFalls;
WORD nFR;
WORD nCR;
WORD nER;
WORD nWR;
DWORD nEquipedItemDesc[12];
DWORD nUGradeID;
DWORD nClanCLID;
} MTD_CharInfo;
typedef struct MTD_ChannelPlayerListNode{
MUID uidPlayer;
char szName[32];
char szClanName[16];
char nLevel;
int nPlace;
BYTE nGrade;
BYTE nPlayerFlags;
DWORD nCLID;
DWORD nEmblemChecksum;
} MTD_ChannelPlayerListNode;
Have fun, and avoid fighting over who's it is.