#include "http.h" #include #include #include #include #include #include #include #include "ws.h" DWORD WINAPI WSThreadProc(LPVOID ssl); int OpenWebSocket(const char *hostname, const char *path, SSL **out_ssl) { SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock == INVALID_SOCKET) { MessageBoxA(NULL, "socket failed", "WebSocket Error", 0); return 1; } struct sockaddr_in server; RtlZeroMemory(&server, sizeof(server)); server.sin_family = AF_INET; server.sin_port = htons(443); server.sin_addr = **(struct in_addr **)gethostbyname(hostname)->h_addr_list; if (connect(sock, (struct sockaddr *)&server, sizeof(server)) == SOCKET_ERROR) { MessageBoxA(NULL, "connect failed", "WebSocket Error", 0); closesocket(sock); return 1; } SSL_library_init(); SSL_load_error_strings(); OpenSSL_add_all_algorithms(); SSL_CTX *ctx = SSL_CTX_new(TLS_client_method()); if (!ctx) { MessageBoxA(NULL, "SSL_CTX_new failed", "WebSocket Error", 0); closesocket(sock); return 1; } SSL *ssl = SSL_new(ctx); if (!ssl) { MessageBoxA(NULL, "SSL_new failed", "WebSocket Error", 0); SSL_CTX_free(ctx); closesocket(sock); return 1; } SSL_set_fd(ssl, (int)sock); SSL_set_tlsext_host_name(ssl, hostname); if (SSL_connect(ssl) <= 0) { MessageBoxA(NULL, "SSL_connect failed", "WebSocket Error", 0); SSL_free(ssl); SSL_CTX_free(ctx); closesocket(sock); return 1; } // anything but a Base64 lib const char *ws_key = "tLGs4Zw47vMKJ8bT5AXjLw=="; // send WebSocket upgrade request char request[2048]; wsprintfA(request, "GET %s HTTP/1.1\r\n" "Host: %s\r\n" "Upgrade: websocket\r\n" "Connection: Upgrade\r\n" "Sec-WebSocket-Key: %s\r\n" "Sec-WebSocket-Version: 13\r\n" "\r\n", path, hostname, ws_key); SSL_write(ssl, request, (int)strlen(request)); // read response into epic stack arr char buffer[4096]; int bytes = SSL_read(ssl, &buffer, sizeof(buffer) - 1); if (bytes > 0) { buffer[bytes] = '\0'; // check for 101 Switching Protocols otherwise it means smth fucked up if (strstr(buffer, "101") == NULL) { MessageBoxA(NULL, buffer, "websocket isnt websocketing", 0); SSL_shutdown(ssl); SSL_free(ssl); SSL_CTX_free(ctx); closesocket(sock); return 1; } } CreateThread(0, 8192, WSThreadProc, ssl, 0, 0); // connection upgraded to WebSocket yay *out_ssl = ssl; return 0; } DWORD WINAPI WSThreadProc(LPVOID ssl) { char *buffer; size_t length; while (1) { int result = ReadWebSocket(ssl, &buffer, &length); if (length != 0 && result != 0) { WebSocketOnDataArrival(ssl, buffer, length); // printf("%s\n",buffer); // LE IMPORTANT: free the buffer after processing... memleak goez // brr otherewise free(buffer); } else { break; } } return 0; }; int SendWebSocket(SSL *ssl, const char *data, size_t length, unsigned char flags) { unsigned char frame[14]; size_t frame_size = 0; // Flags are to our goofy ahh param frame[0] = flags; frame_size++; // Mask bit set (client must mask the ahh) (stolen code) if (length < 126) { frame[1] = 0x80 | (unsigned char)length; frame_size++; } else if (length < 65536) { frame[1] = 0x80 | 126; frame[2] = (length >> 8) & 0xFF; frame[3] = length & 0xFF; frame_size += 3; } else { frame[1] = 0x80 | 127; frame[2] = (length >> 56) & 0xFF; frame[3] = (length >> 48) & 0xFF; frame[4] = (length >> 40) & 0xFF; frame[5] = (length >> 32) & 0xFF; frame[6] = (length >> 24) & 0xFF; frame[7] = (length >> 16) & 0xFF; frame[8] = (length >> 8) & 0xFF; frame[9] = length & 0xFF; frame_size += 9; } // whats even the purpose of ts, just fake the masks unsigned char mask[4]; for (unsigned char i = 0; i < 4; i++) { mask[i] = (unsigned char)(i & 0xFF); } RtlCopyMemory(&frame[frame_size], mask, 4); // me when i rtlcopymemory to look cool frame_size += 4; // Send frame header if (SSL_write(ssl, frame, (int)frame_size) <= 0) { return 1; } // Mask and send payload unsigned char *masked_data = (unsigned char *)malloc(length); if (!masked_data) { return 1; } for (size_t i = 0; i < length; i++) { masked_data[i] = data[i] ^ mask[i % 4]; } int result = SSL_write(ssl, masked_data, (int)length); free(masked_data); return (result <= 0) ? 1 : 0; } int ReadWebSocket(SSL *ssl, char **out_buffer, size_t *out_length) { *out_buffer = malloc(10); // tmp buffer unsigned char opcode; BOOL hasSetFirstOpcode = FALSE; unsigned long long payloadLen = 0; while (1) { unsigned long long curPayloadLen = 0; unsigned char fin; unsigned char coreHeaders; if (SSL_read(ssl, &coreHeaders, 1) != 1) { return 0; } fin = coreHeaders >> 7; if (hasSetFirstOpcode != TRUE) { opcode = (coreHeaders << 4) >> 4; hasSetFirstOpcode = TRUE; } unsigned char plHeaders; SSL_read(ssl, &plHeaders, 1); unsigned char tlen = (plHeaders << 1) >> 1; if (tlen == 127) { SSL_read(ssl, &curPayloadLen, 8); curPayloadLen = ntohll(curPayloadLen); payloadLen += curPayloadLen; } else if (tlen == 126) { unsigned short templen; SSL_read(ssl, &templen, 2); curPayloadLen = ntohs(templen); payloadLen += curPayloadLen; } else { curPayloadLen = tlen; payloadLen += curPayloadLen; } if (opcode == 0x01) { *out_buffer = realloc(*out_buffer, payloadLen + 1); *out_length = payloadLen + 1; } else { *out_buffer = realloc(*out_buffer, payloadLen); *out_length = payloadLen; } unsigned long long totalRead = 0; while (totalRead < curPayloadLen) { int bytesRead = SSL_read( ssl, *out_buffer + (payloadLen - curPayloadLen) + totalRead, curPayloadLen - totalRead); if (bytesRead <= 0) { free(*out_buffer); return 0; } totalRead += bytesRead; } if (fin == 1) { break; } } if (opcode == 0x01) { (*out_buffer)[payloadLen] = '\0'; } return 1; }