#include #include #include #include // сокеты / io #include #include #include #include #include #include // Blowfish #include #define L2_BF_KEY "\x6B\x60\xCB\x5B\x82\xCE\x90\xB1\xCC\x2B\x6C\x55\x6C\x6C\x6C\x6C" // Параметры логин сервера //#define L2_LOGIN_SERVER "127.0.0.1" #define L2_LOGIN_SERVER "login.nanogame.org" //#define L2_LOGIN_SERVER "195.211.222.195" #define L2_LOGIN_PORT 2106 enum ERRORS { E_OK = 0, E_OPEN_SOCKET, E_RESOLVE, E_INVALID_ADDR_TYPE, E_CONNECT }; typedef struct l2_packet { unsigned short length; unsigned char *data; } _l2_packet; #pragma pack(push, 1) typedef struct L2LoginInitPacket { unsigned int session_id; // ID сессии unsigned int protocol_version; // ID сессии unsigned char rsa_key[128]; // RSA ключ unsigned int gameguard[4]; // Хуитка unsigned char blowfish_key[16]; // ключ } _L2LoginInitPacket; #pragma pack(pop) void dump(unsigned char *data, unsigned int len); // l2 packets void set_l2_blowfish_key(const unsigned char *key, unsigned int len, bool is_static); void init_packet(l2_packet *p); void free_packet(l2_packet *p); bool recv_l2_packet(int sock, l2_packet *p); bool send_l2_packet(int sock, unsigned char *data, unsigned short len); void create_packet(l2_packet *p, unsigned char *data, unsigned int len); unsigned int encode_xor(unsigned char *data, unsigned int size, unsigned int k); void print_bin(unsigned char *data, unsigned int len); bool is_static_bf_key = true; BF_KEY l2_blowfisdh_key; int main() { int sock; struct sockaddr_in addr; l2_packet p; init_packet(&p); try { addr.sin_family = AF_INET; addr.sin_port = htons(L2_LOGIN_PORT); addr.sin_addr.s_addr = inet_addr(L2_LOGIN_SERVER); // проверяем, IP ли это if (addr.sin_addr.s_addr == INADDR_NONE) { // нифига не IP // Резолвим домен struct hostent *h; if (!(h = gethostbyname(L2_LOGIN_SERVER))) { perror("gethostbyname error"); throw E_RESOLVE; } // Проверяем, AF_INET это или нет if (h->h_addrtype != AF_INET) { perror("Login server addr is not AF_INET o_O"); throw E_INVALID_ADDR_TYPE; } // Задём IP addr.sin_addr.s_addr = ((struct in_addr *) h->h_addr_list[0])->s_addr; } // Открываем сокет sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror("open socket error"); throw E_OPEN_SOCKET; } if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) != 0) { perror("connect socket error"); throw E_CONNECT; } printf("connected!\n"); /* // ID 00 // Session 27 40 56 09 // Revision 21 C6 00 00 // RSA D2 F8 2B A1 EB B4 01 D1 EE D9 98 0E 84 E4 58 65 1D D5 45 A1 99 35 E7 65 BD 2B C1 87 D8 C7 E4 01 E5 D3 F2 D8 E3 47 D5 36 0E D9 18 70 7F 99 B1 97 F7 EA 75 D8 74 6C 7A 5C 73 A1 37 92 F0 23 A5 22 3F DF 36 28 7C 41 01 CE 98 97 1F 3A 67 79 EB 59 31 F6 7F 76 70 BB 93 01 C3 1B 09 C2 D4 76 30 3B E5 64 0E FC 9B EE 6D C6 49 2D 20 43 50 15 A5 7E 15 95 E2 20 F5 9D D3 17 7F 5C 0F E0 E9 34 D0 49 // GG 4E 95 DD 29 FC 9C C3 77 20 B6 4D 97 F7 E0 45 07 // Key CC F6 29 04 DC D8 70 AD F9 35 0D 13 7E C9 A0 1F // NULL 00 // WTF FF 6B 17 48 B5 9E 5D 84 07 2E 00 00 00 00 Blowfish: CCF62904DCD870ADF9350D137EC9A01F */ /* connected! 153 00 EF 4A 0B 0D 21 C6 00 00 BE 07 55 6D 19 D5 21 9B 75 AE 9F 7C A2 5A AB 51 BC 0D F0 79 CF 4C DA A5 3A BA 47 6D E9 FC 76 31 48 FE 18 08 77 57 A7 4C A2 DA 63 E5 2D 41 A3 AF 61 38 84 BB 19 58 8E 35 3C 74 58 72 60 43 C8 2B AE 1B E7 B2 AE E8 C5 59 EA CA 30 F3 F2 9E 01 E8 3C 65 44 A6 AA 91 FA 38 C2 C1 4F 18 B4 FD A2 42 0E 0C 2D EE AE 9B CD 81 20 4A C6 A0 3D C9 F3 B2 B5 AC 70 58 66 36 46 B6 F7 71 A2 0B 42 45 28 50 4E 65 22 29 FC 60 FC 77 20 49 B2 97 37 1F B2 07 EE 8F 1F D7 99 AE 28 9F 8C 16 D7 2D C7 71 76 68 FF 5F D1 0D 1A 28 B2 98 73 EF 6E 00 00 00 00 Blowfish: EE8F1FD799AE289F8C16D72DC7717668 GG0: 2922654E GG1: 77FC60FC GG2: 97B24920 GG3: 07B21F37 session_id = 0D0B4AEF protocol_version = 0000C621 07 4A 0B 0D 21 92 90 4D 18 30 B5 7C 96 61 41 47 05 07 96 FB 00 22 00 D7 BF BC B9 60 CD 82 0B C7 19 25 C1 0B 81 FF 55 BC C5 B5 7C A9 8A 93 3B 58 BB BF 60 03 9E B1 AA */ //const unsigned char key[] = "\xEE\x8F\x1F\xD7\x99\xAE\x28\x9F\x8C\x16\xD7\x2D\xC7\x71\x76\x68"; const unsigned char key[] = "\x68\x76\x71\xC7\x2D\xD7\x16\x8C\x9F\x28\xAE\x99\xD7\x1F\x8F\xEE"; set_l2_blowfish_key((unsigned char *) key, 16, true); // for (unsigned int offset = 0; offset < p->length; offset += 8) // BF_decrypt((BF_LONG *)(p->data + offset), &l2_blowfisdh_key); // set_l2_blowfish_key((unsigned char *) L2_BF_KEY, sizeof(L2_BF_KEY) - 1, true); //0x2a, 0x00, unsigned char lal[] = { 0xe4, 0x50, 0x64, 0xe9, 0x7b, 0x4f, 0xa6, 0x43, 0xe3, 0x7b, 0x9b, 0xa1, 0x07, 0xa1, 0x93, 0x6a, 0xe3, 0x7b, 0x9b, 0xa1, 0x07, 0xa1, 0x93, 0x6a, 0x2e, 0x56, 0xa2, 0x2e, 0x22, 0x72, 0xa8, 0x6b, 0xe3, 0x7b, 0x9b, 0xa1, 0x07, 0xa1, 0x93, 0x6a }; std::cout << (float)sizeof(lal)/8 << "\n"; for (unsigned int offset = 0; offset < sizeof(lal); offset += 8) BF_decrypt((BF_LONG *)(lal + offset), &l2_blowfisdh_key); dump(lal, sizeof(lal)); // 90 B2 C4 36 3A DB F2 56 C9 A0 B1 90 0F F7 D5 28 // C9 A0 B1 90 0F F7 D5 28 1A E6 B2 A0 1B CA 8E CA // C9 A0 B1 90 0F F7 D5 28 exit(1); // Login Server // Задаём стандартный ключ логина set_l2_blowfish_key((unsigned char *) L2_BF_KEY, sizeof(L2_BF_KEY) - 1, true); while (true) { if (!recv_l2_packet(sock, &p) || !p.length) continue; switch (p.data[0]) { case 0x00: { // Расшифровуем и парсим пакет encode_xor(p.data + 1, p.length - 4, *(unsigned int *) (p.data + (p.length - 4))); dump(p.data, p.length); // Парсим пакет L2LoginInitPacket *l2_init = (L2LoginInitPacket *) (p.data + 1); printf("Blowfish: "); print_bin(l2_init->blowfish_key, 16); printf("\n"); printf("GG0: %08X\n", l2_init->gameguard[0]); printf("GG1: %08X\n", l2_init->gameguard[1]); printf("GG2: %08X\n", l2_init->gameguard[2]); printf("GG3: %08X\n", l2_init->gameguard[3]); printf("\n"); printf( "session_id = %08X\n" "protocol_version = %08X\n", l2_init->session_id, l2_init->protocol_version ); // Устанавливаем принятый ключ set_l2_blowfish_key((unsigned char *) l2_init->blowfish_key, 16, false); // Шлём RequestGGAuth // type | session_id | GG data0 | GG data1 | GG data2 | GG data3 unsigned char *packet = (unsigned char *) malloc(4 * 4 + 4 + 1 + 8); // packet[0] = 0x07; packet[1] = p.data[2]; packet[2] = p.data[3]; packet[3] = p.data[4]; packet[4] = p.data[5]; int off = 4; packet[1+off] = 0x92; packet[2+off] = 0x90; packet[3+off] = 0x4d; packet[4+off] = 0x18; packet[5+off] = 0x30; packet[6+off] = 0xb5; packet[7+off] = 0x7c; packet[8+off] = 0x96; packet[9+off] = 0x61; packet[10+off] = 0x41; packet[11+off] = 0x47; packet[12+off] = 0x05; packet[13+off] = 0x07; packet[14+off] = 0x96; packet[15+off] = 0xfb; packet[16+off] = 0x00; packet[17+off] = 0x00; packet[18+off] = 0x00; packet[19+off] = 0x00; packet[20+off] = 0x00; packet[21+off] = 0x00; packet[22+off] = 0x00; packet[23+off] = 0x00; packet[24+off] = 0x00; // *(unsigned int *) (packet + 1) = l2_init->session_id; // 21 // *(unsigned int *) (packet + 5) = l2_init->gameguard[0]; // *(unsigned int *) (packet + 9) = l2_init->gameguard[1]; // *(unsigned int *) (packet + 13) = l2_init->gameguard[2]; // *(unsigned int *) (packet + 17) = l2_init->gameguard[3]; send_l2_packet(sock, packet, 4 * 4 + 4 + 1 + 8); free(packet); } break; default: dump(p.data, p.length); break; } } //22 00 //BF 3F ED 84 94 5A 44 CB B4 E8 6A 23 75 C7 43 5B 5B 1C 95 F5 B0 07 ED A1 //01 51 F8 63 00 00 00 00 /* @Override protected void write() { writeC(0x00); // init packet id writeD(_sessionId); // session id writeD(0x0000c621); // protocol revision writeB(_publicKey); // RSA Public Key // unk GG related? writeD(0x29DD954E); writeD(0x77C39CFC); writeD(0x97ADB620); writeD(0x07BDE0F7); writeB(_blowfishKey); // BlowFish key writeC(0x00); // null termination ;) } */ } catch (int err_code) { } free_packet(&p); if (sock > -1) close(sock); return 0; } void set_l2_blowfish_key(const unsigned char *key, unsigned int len, bool is_static) { BF_set_key(&l2_blowfisdh_key, len, key); is_static_bf_key = is_static; } // Функции работы с пакетами L2 bool recv_l2_packet(int sock, l2_packet *p) { free_packet(p); if (recv(sock, &p->length, 2, 0) == 2) { p->length -= 2; // Отнимем длину длины if (p->length % 8 != 0) { fprintf(stderr, "Invalid packet length!!! (%d %% 8 == %d)\n", p->length, p->length % 8); return false; } p->data = (unsigned char *) malloc(p->length); if ((recv(sock, p->data, p->length, 0)) != p->length) { perror("recv"); free(p->data); p->data = NULL; return false; } /* free(p->data); unsigned char test_data[] = {0xba, 0x00, 0x2e, 0x28, 0x3a, 0x3a, 0xf6, 0xbc, 0xeb, 0x94, 0xb3, 0xc4, 0xe6, 0x23, 0x8b, 0xdb, 0x3c, 0xd3, 0xed, 0x42, 0x78, 0xf7, 0xf8, 0xce, 0x06, 0xd1, 0x91, 0x3d, 0xd8, 0x3e, 0xcf, 0x25, 0xba, 0x2b, 0x80, 0xd8, 0x4a, 0x71, 0xf6, 0x6e, 0x31, 0x18, 0xef, 0x78, 0x2f, 0x8d, 0xa3, 0xee, 0xed, 0xdc, 0x1b, 0xad, 0x60, 0xe9, 0x6f, 0x10, 0xf4, 0xab, 0x25, 0xb7, 0x51, 0x51, 0x18, 0xc6, 0xa5, 0x6a, 0x45, 0x90, 0x1a, 0xda, 0x84, 0xc3, 0xee, 0xd1, 0x79, 0x5a, 0x6e, 0x0a, 0x87, 0xdf, 0x4a, 0x18, 0x99, 0x29, 0xcb, 0xcb, 0x8c, 0x74, 0xb7, 0x3b, 0xb2, 0xa8, 0xed, 0x36, 0xd5, 0x51, 0x96, 0xac, 0xd8, 0x69, 0xec, 0x98, 0x5f, 0x3f, 0x10, 0x89, 0xa8, 0xd8, 0x8c, 0x7f, 0x3e, 0x10, 0xb3, 0x37, 0xcd, 0x94, 0xbf, 0x79, 0x33, 0x37, 0x0a, 0x7d, 0xff, 0x66, 0x13, 0x4e, 0xe7, 0xca, 0x29, 0xb1, 0x67, 0x87, 0xb8, 0x6e, 0xce, 0xaf, 0x7e, 0xbc, 0x5d, 0x32, 0x69, 0x42, 0x06, 0x4c, 0x7f, 0x56, 0xd2, 0xfb, 0xc0, 0x36, 0x19, 0x6d, 0x8c, 0x18, 0x7a, 0x51, 0x0a, 0x2d, 0x3a, 0xbb, 0xc0, 0x58, 0x4e, 0xee, 0x11, 0x11, 0xe7, 0xa7, 0x35, 0x46, 0x5d, 0xb6, 0xb6, 0xe7, 0x34, 0x85, 0x02, 0x96, 0xe2, 0x13, 0xbc, 0xb5, 0xbb, 0x52, 0xfb, 0x5a}; p->length = (test_data[0] | test_data[1] << 8) - 2; p->data = (unsigned char*)malloc(sizeof(test_data)-2); unsigned char *lal =(unsigned char *) test_data; lal++; lal++; memcpy(p->data, lal, sizeof(test_data)-2); // */ for (unsigned int offset = 0; offset < p->length; offset += 8) BF_decrypt((BF_LONG *)(p->data + offset), &l2_blowfisdh_key); } return true; } bool send_l2_packet(int sock, unsigned char *data, unsigned short len) { unsigned short packet_data_additional_len = 8 - (len % 8); unsigned int packet_data_len = 2 + len + packet_data_additional_len + 8; unsigned char *packet_data = (unsigned char *) malloc(packet_data_len); // size + data + checksum dump(data, len); packet_data[0] = packet_data_len & 0xFF; packet_data[1] = packet_data_len >> 8 & 0xFF; memcpy(packet_data + 2, data, len); if (packet_data_additional_len) memset(packet_data + 2 + len, 0, packet_data_additional_len); unsigned long chk = 0; unsigned int ecx = 0; unsigned long chk2 = 0; unsigned int ecx2 = 0; for (unsigned short i = 0; i < packet_data_len-8; i += 1) { //chk ^= packet_data[i]; ecx2 = *(unsigned int *) (packet_data + i); chk2 ^= ecx2; ecx = packet_data[i]; ecx |= packet_data[i + 1] << 8; ecx |= packet_data[i + 2] << 16; ecx |= packet_data[i + 3] << 24; chk ^= ecx; } // ........ // ................ /* packet_data[packet_data_len - 16] = chk & 0xFF; packet_data[packet_data_len - 15] = chk >> 8 & 0xFF; packet_data[packet_data_len - 14] = chk >> 16 & 0xFF; packet_data[packet_data_len - 13] = chk >> 24 & 0xFF; packet_data[packet_data_len - 12] = 0; packet_data[packet_data_len - 11] = 0; packet_data[packet_data_len - 10] = 0; packet_data[packet_data_len - 9] = 0; packet_data[packet_data_len - 8] = 0; packet_data[packet_data_len - 7] = 0; packet_data[packet_data_len - 6] = 0; packet_data[packet_data_len - 5] = 0; packet_data[packet_data_len - 4] = 0; packet_data[packet_data_len - 3] = 0; packet_data[packet_data_len - 2] = 0; packet_data[packet_data_len - 1] = 0; */ unsigned long c = encode_xor(packet_data + 2, len + packet_data_additional_len, 0); memcpy(packet_data + (packet_data_len - 8), &chk, sizeof(unsigned long)); printf("XOR: %16lX\n", chk); printf("XOR: %16lX\n", chk2); printf("XOR: %16lX\n", c); // packet_data[packet_data_len - 8] = 0; // packet_data[packet_data_len - 7] = 0; // packet_data[packet_data_len - 6] = 0; // packet_data[packet_data_len - 5] = 0; // packet_data[packet_data_len - 4] = chk & 0xFF; // packet_data[packet_data_len - 3] = chk >> 8 & 0xFF; // packet_data[packet_data_len - 2] = chk >> 16 & 0xFF; // packet_data[packet_data_len - 1] = chk >> 24 & 0xFF; /* packet_data[packet_data_len - 4] = 0; packet_data[packet_data_len - 3] = 0; packet_data[packet_data_len - 2] = 0; packet_data[packet_data_len - 1] = 0; packet_data[packet_data_len - 8] = chk >> 24 & 0xFF; packet_data[packet_data_len - 7] = chk >> 16 & 0xFF; packet_data[packet_data_len - 6] = chk >> 8 & 0xFF; packet_data[packet_data_len - 5] = chk >> 0 & 0xFF; */ // 42 //memcpy(packet_data + (packet_data_len - 8), &chk, 4); //memset(packet_data + (packet_data_len - 4), 0, 4); for (unsigned short offset = 2; offset < packet_data_len; offset += 8) BF_encrypt((BF_LONG *)(packet_data + offset), &l2_blowfisdh_key); // for (unsigned short offset = 2; offset < packet_data_len; offset += 8) // BF_decrypt((BF_LONG *)(packet_data + offset), &l2_blowfisdh_key); if (send(sock, packet_data, packet_data_len, 0) != packet_data_len) { perror("send"); free(packet_data); return false; } dump(packet_data, packet_data_len); free(packet_data); return true; } void create_packet(l2_packet *p, unsigned char *data, unsigned int len) { p->data = (unsigned char *) malloc(len); memcpy(p->data, data, len); p->length = len; } void init_packet(l2_packet *p) { memset(p, 0, sizeof(l2_packet)); } void free_packet(l2_packet *p) { p->length = 0; if (p->data) { free(p->data); p->data = NULL; } } /* // unk GG related? writeD(0x29DD954E); writeD(0x77C39CFC); writeD(0x97ADB620); writeD(0x07BDE0F7); writeB(_blowfishKey); // BlowFish key writeC(0x00); // null termination ;) 00 4D 9C E8 45 21 C6 00 00 D2 F8 2B A1 EB B4 01 D1 EE D9 98 0E 84 E4 58 65 1D D5 45 A1 99 35 E7 65 BD 2B C1 87 D8 C7 E4 01 E5 D3 F2 D8 E3 47 D5 36 0E D9 18 70 7F 99 B1 97 F7 EA 75 D8 74 6C 7A 5C 73 A1 37 92 F0 23 A5 22 3F DF 36 28 7C 41 01 CE 98 97 1F 3A 67 79 EB 59 31 F6 7F 76 70 BB 93 01 C3 1B 09 C2 D4 76 30 3B E5 64 0E FC 9B EE 6D C6 49 2D 20 43 50 15 65 7E 15 95 12 20 F5 9D 2F 17 7F 5C F1 E0 E9 B4 2F 49 4E 55 22 29 FC 60 FC 77 A0 51 B2 97 07 11 B2 07 BB 17 F3 7D 20 1B C0 E3 B7 4D 14 89 D0 BC 2A 85 E1 F9 4C B9 DD 2E 4D 76 59 86 59 00 00 00 00 Формат: 9B 00 // Длина 00 // Тип XX XX XX XX // ID сессии XX XX XX XX // Ревизия протокола [начало зашифрованного RSA-ключа] XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX [конец зашифрованного RSA-ключа] XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX // неизвестно для чего это (в яве тут нули) */ unsigned int encode_xor(unsigned char *data, unsigned int size, unsigned int k) { for (int *i = (int *) (data + size - 1); i >= (int *)data; --i) k -= (*(unsigned int *) i = *(unsigned int *) i ^ k); return k; } void dump(unsigned char *data, unsigned int len) { printf("\n", len); printf(" "); for (unsigned int i = 0; i < len; ++i) { printf("%02X ", data[i]); if ((i + 1) % 16 == 0) printf("\n "); } printf("\n\n"); } void print_bin(unsigned char *data, unsigned int len) { for (unsigned int i = 0; i < len; ++i) printf("%02X", data[i]); }