/* winegcc lotro-behaviour.c -Isource/wine/include/ -lws2_32 -o lotro-behaviour && ./lotro-behaviour.exe */ #include#include #include /* Copy from rsaenh.c */ #define RSAENH_MAGIC_RSA2 0x32415352 #define RSAENH_MAGIC_RSA1 0x31415352 /* This method is used to dump a region of memory */ static void byte_dump(CONST BYTE * pbData, DWORD dwDataLen) { DWORD i; if (pbData && dwDataLen > 0) { for (i = 0; i < dwDataLen; i++) { printf("0x%02x (%d)\n", pbData[i], pbData[i]); } } } /* Load the clients private key into the given pointer */ static void load_private_key(CONST BYTE * pbData) { BLOBHEADER * pHeader = (BLOBHEADER *) pbData; pHeader->bType = PRIVATEKEYBLOB; pHeader->bVersion = 0x2; pHeader->reserved = 0; pHeader->aiKeyAlg = CALG_RSA_KEYX; RSAPUBKEY * pRsaPubKey = (RSAPUBKEY *) (pbData + sizeof(BLOBHEADER)); pRsaPubKey->magic = RSAENH_MAGIC_RSA2; pRsaPubKey->bitlen = 512; pRsaPubKey->pubexp = 1; BYTE pbSrc[288] = { 0xab, 0xef, 0xfa, 0xc6, 0x7d, 0xe8, 0xde, 0xfb, 0x68, 0x38, 0x09, 0x92, 0xd9, 0x42, 0x7e, 0x6b, 0x89, 0x9e, 0x21, 0xd7, 0x52, 0x1c, 0x99, 0x3c, 0x17, 0x48, 0x4e, 0x3a, 0x44, 0x02, 0xf2, 0xfa, 0x74, 0x57, 0xda, 0xe4, 0xd3, 0xc0, 0x35, 0x67, 0xfa, 0x6e, 0xdf, 0x78, 0x4c, 0x75, 0x35, 0x1c, 0xa0, 0x74, 0x49, 0xe3, 0x20, 0x13, 0x71, 0x35, 0x65, 0xdf, 0x12, 0x20, 0xf5, 0xf5, 0xf5, 0xc1, 0xed, 0x5c, 0x91, 0x36, 0x75, 0xb0, 0xa9, 0x9c, 0x04, 0xdb, 0x0c, 0x8c, 0xbf, 0x99, 0x75, 0x13, 0x7e, 0x87, 0x80, 0x4b, 0x71, 0x94, 0xb8, 0x00, 0xa0, 0x7d, 0xb7, 0x53, 0xdd, 0x20, 0x63, 0xee, 0xf7, 0x83, 0x41, 0xfe, 0x16, 0xa7, 0x6e, 0xdf, 0x21, 0x7d, 0x76, 0xc0, 0x85, 0xd5, 0x65, 0x7f, 0x00, 0x23, 0x57, 0x45, 0x52, 0x02, 0x9d, 0xea, 0x69, 0xac, 0x1f, 0xfd, 0x3f, 0x8c, 0x4a, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0xd5, 0xaa, 0xb1, 0xa6, 0x03, 0x18, 0x92, 0x03, 0xaa, 0x31, 0x2e, 0x48, 0x4b, 0x65, 0x20, 0x99, 0xcd, 0xc6, 0x0c, 0x15, 0x0c, 0xbf, 0x3e, 0xff, 0x78, 0x95, 0x67, 0xb1, 0x74, 0x5b, 0x60, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; memcpy((void *)pbData + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY), &pbSrc, 288); } /* Load the servers public key into the given pointer */ static void load_public_key(CONST BYTE * pbData) { BLOBHEADER * pHeader = (BLOBHEADER *) pbData; pHeader->bType = PUBLICKEYBLOB; pHeader->bVersion = 0x2; pHeader->reserved = 0; pHeader->aiKeyAlg = CALG_RSA_KEYX; RSAPUBKEY * pRsaPubKey = (RSAPUBKEY *) (pbData + sizeof(BLOBHEADER)); pRsaPubKey->magic = RSAENH_MAGIC_RSA1; pRsaPubKey->bitlen = 1024; pRsaPubKey->pubexp = 0x010001; BYTE pbSrc[128] = { 0x4d, 0x03, 0x8d, 0xd7, 0xd8, 0xa8, 0x85, 0x97, 0x2d, 0x04, 0xde, 0x57, 0xe2, 0x77, 0xc4, 0xbf, 0xc6, 0x13, 0x15, 0x0e, 0x26, 0x72, 0x99, 0x11, 0xa1, 0xcd, 0xf3, 0x8f, 0xd5, 0x5d, 0x63, 0x4c, 0xf3, 0x75, 0xb7, 0x62, 0x9d, 0xee, 0xe8, 0xd5, 0xc5, 0xa7, 0x0e, 0x3c, 0x9c, 0x51, 0xd4, 0x3f, 0x00, 0x45, 0xb2, 0xed, 0x19, 0xb1, 0xca, 0xda, 0x84, 0x1c, 0x6b, 0x35, 0x41, 0x17, 0x46, 0xd0, 0x56, 0xb9, 0x4c, 0x06, 0xcd, 0x8d, 0xc5, 0x50, 0x39, 0x36, 0x4e, 0xe3, 0x9b, 0x5e, 0x3c, 0x44, 0xe8, 0x04, 0x0e, 0x90, 0xc4, 0x89, 0xfc, 0x24, 0xe9, 0xc4, 0xff, 0xc6, 0x97, 0xfd, 0xd6, 0x5d, 0x2b, 0x67, 0x5c, 0xa2, 0x7f, 0x8d, 0x2a, 0xb9, 0x5a, 0x52, 0x3c, 0xec, 0x0d, 0xc1, 0x55, 0xc8, 0xc1, 0xb0, 0x07, 0x3a, 0xdc, 0x03, 0x9c, 0x38, 0x34, 0x08, 0x0e, 0x19, 0x27, 0xcd, 0x7b, 0xd0 }; memcpy((void *)pbData + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY), &pbSrc, 128); } void main() { int retval; char* localIP; BOOLEAN first = TRUE; BYTE bDataPrivKey[sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + 288]; BYTE bDataPubKey[sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + 128]; WSADATA wsaData; retval = WSAStartup(2, &wsaData); if (retval != 0) { printf("WSAStartup returned %d\n", retval); return; } SOCKET socket = WSASocket(AF_INET, SOCK_DGRAM, 0, (LPWSAPROTOCOL_INFO) NULL, 0, 0x1 /* What is this for */); BYTE name[256]; gethostname(&name, 256); struct hostent* localHost = gethostbyname((const CHAR *) &name); localIP = inet_ntoa (*(struct in_addr *)*localHost->h_addr_list); struct sockaddr_in addr; addr.sin_family = AF_INET; /* addr.sin_addr.s_addr = inet_addr(localIP); */ addr.sin_addr.s_addr = inet_addr("0.0.0.0"); addr.sin_port = htons(10691); retval = bind(socket, (const struct sockaddr *) &addr, sizeof(addr)); if (retval != 0) { printf("bind returned %d\n", retval); closesocket(socket); WSACleanup(); return; } CHAR optval[4]; int optlen = 4; retval = getsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char *)&optval, &optlen); if (retval != 0) { printf("bind returned %d\n", retval); closesocket(socket); WSACleanup(); return; } //byte_dump((CONST BYTE *) &optval, 4); retval = getsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char *)&optval, &optlen); //byte_dump((CONST BYTE *) &optval, 4); HCRYPTPROV hProv; CryptAcquireContext(&hProv, "", MS_ENHANCED_PROV, 1, CRYPT_VERIFYCONTEXT | CRYPT_NEWKEYSET); /* Loads the private key */ BYTE bDataPriv[512]; DWORD dwDataPrivLen = 512; first = TRUE; do { if (!CryptGetProvParam(hProv, PP_ENUMALGS_EX, (BYTE *)&bDataPriv, &dwDataPrivLen, first ? CRYPT_FIRST : CRYPT_NEXT)) { printf("No more CryptProvParam to fullfill CALG_RSA_KEYX for Priv\n"); break; } first = FALSE; } while (((PROV_ENUMALGS_EX *) &bDataPriv)->aiAlgid != CALG_RSA_KEYX); load_private_key((CONST BYTE * ) &bDataPrivKey); HCRYPTKEY hPrivKey; CryptImportKey(hProv, (BYTE *)&bDataPrivKey, sizeof(bDataPrivKey), 0, CRYPT_EXPORTABLE, &hPrivKey); /* Loads the public key */ BYTE bDataPub1[512]; DWORD dwDataPubLen1 = 512; first = TRUE; do { if (!CryptGetProvParam(hProv, PP_ENUMALGS_EX, (BYTE *)&bDataPub1, &dwDataPubLen1, first ? CRYPT_FIRST : CRYPT_NEXT)) { printf("No more CryptProvParam to fullfill CALG_RSA_KEYX for Pub\n"); break; } first = FALSE; } while (((PROV_ENUMALGS_EX *) &bDataPub1)->aiAlgid != CALG_RSA_KEYX); BYTE bDataPub2[512]; DWORD dwDataPubLen2 = 512; first = TRUE; do { if (!CryptGetProvParam(hProv, PP_ENUMALGS_EX, (BYTE *)&bDataPub2, &dwDataPubLen2, first ? CRYPT_FIRST : CRYPT_NEXT)) { printf("No more CryptProvParam to fullfill CALG_RC4 for Pub\n"); break; } first = FALSE; } while (((PROV_ENUMALGS_EX *) &bDataPub2)->aiAlgid != CALG_RC4); load_public_key((CONST BYTE * ) &bDataPubKey); HCRYPTKEY hPubKey; CryptImportKey(hProv, (BYTE *)&bDataPubKey, sizeof(bDataPubKey), 0, CRYPT_EXPORTABLE, &hPubKey); /* CryptGenKey */ HCRYPTKEY hRcKey; CryptGenKey (hProv, CALG_RC4, CRYPT_EXPORTABLE, &hRcKey); /* CryptExportKey */ DWORD dwDataLen; CryptExportKey(hRcKey, hPubKey, SIMPLEBLOB, 0, 0, &dwDataLen); BYTE * pbData = malloc(dwDataLen); CryptExportKey(hRcKey, hPubKey, SIMPLEBLOB, 0, pbData, &dwDataLen); BYTE encryptData1[] = { 0x01, 0x32, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x31 }; DWORD encryptData1Len = 9; CryptEncrypt(hRcKey, 0, TRUE, 0, 0, &encryptData1Len, 9); CryptEncrypt(hRcKey, 0, TRUE, 0, (BYTE *) &encryptData1, &encryptData1Len, 9); char buffer0[] = { 0x54, 0xa7 }; char buffer1[] = { 0xb0, 0x02, 0x0f, 0x08, 0xed, 0x00, 0x00, 0x00, 0x48, 0xfe, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; char buffer2[] = { 0x48, 0xfe, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; WSABUF wsabufs[3]; wsabufs[0].len = sizeof(buffer0); wsabufs[0].buf = malloc(sizeof(buffer0)); memcpy(wsabufs[0].buf, &buffer0, sizeof(buffer0)); wsabufs[1].len = sizeof(buffer1); wsabufs[1].buf = malloc(sizeof(buffer1)); memcpy(wsabufs[1].buf, &buffer1, sizeof(buffer1)); wsabufs[2].len = sizeof(buffer2); wsabufs[2].buf = malloc(sizeof(buffer2)); memcpy(wsabufs[2].buf, &buffer2, sizeof(buffer2)); struct sockaddr_in to; to.sin_family = AF_INET; to.sin_port = htons(9000); to.sin_addr.s_addr = inet_addr("192.168.1.140"); DWORD bytesSent; WSASendTo(socket, (LPWSABUF)&wsabufs, 3, &bytesSent, 0, (const struct sockaddr *) &to, 16, 0, 0); free(pbData); CryptReleaseContext(hProv, 0); closesocket(socket); WSACleanup(); }
Based on what I learned I tried to look at what the server needs to do as initial setup. I came up with the following dummy:
/* Run with: winegcc lotro-server.c -Isource/wine/include/ -lws2_32 -o lotro-server && ./lotro-server.exe */ #include#include #include #include /* This method is used to dump a region of memory */ static void byte_dump(CONST BYTE * pbData, DWORD dwDataLen) { DWORD i; if (pbData && dwDataLen > 0) { for (i = 0; i < dwDataLen; i++) { printf("0x%02x (%d)\n", pbData[i], pbData[i]); } } } int main() { WORD wVersionRequested; WSADATA wsaData; int err = 0, remoteAddrLen = sizeof(SOCKADDR_IN); SOCKET s = INVALID_SOCKET; struct addrinfo hints, *result = NULL, *remoteAddr; char buf[256]; /* Initialize winsock with version 2.2 */ wVersionRequested = MAKEWORD(2, 2); err = WSAStartup(wVersionRequested, &wsaData); if (err != NO_ERROR) { printf("WSAStartup failed: %d\n", err); return -1; } /* Verify the system is winsock 2.2 capable */ if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) { printf("WSAStartup returned wrong version\n"); WSACleanup(); return -2; } /* Determine our local address */ hints.ai_family = AF_INET; hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = 0; hints.ai_flags = AI_PASSIVE; err = getaddrinfo(NULL, "9000", &hints, &result); if (err != 0) { printf("getaddrinfo failed: %d\n", err); WSACleanup(); return -3; } s = socket(result->ai_family, result->ai_socktype, result->ai_protocol); if (s == INVALID_SOCKET) { printf("Creating the socket failed: %d\n", WSAGetLastError()); freeaddrinfo(result); WSACleanup(); return -4; } err = bind(s, result->ai_addr, (int)result->ai_addrlen); if (err == SOCKET_ERROR) { printf("Binding failed: %d\n", WSAGetLastError()); closesocket(s); freeaddrinfo(result); WSACleanup(); return -5; } printf("Waiting for client\n"); while(1) { err = recvfrom(s, buf, 256, 0, (SOCKADDR *) &remoteAddr, &remoteAddrLen); if (err == SOCKET_ERROR) { printf("Recieve failed: %d\n", WSAGetLastError()); closesocket(s); freeaddrinfo(result); WSACleanup(); return -6; } printf("Read %d bytes\n", err); byte_dump((CONST BYTE *) &buf, err); err = sendto(s ,buf, err, 0, (SOCKADDR*)&remoteAddr, remoteAddrLen); if (err == SOCKET_ERROR) { printf("Send failed: %d\n", WSAGetLastError()); closesocket(s); freeaddrinfo(result); WSACleanup(); return -7; } printf("Sent %d bytes\n", err); } closesocket(s); freeaddrinfo(result); WSACleanup(); return 0; }