Author | Message | Time |
---|---|---|
Trunning | Can I get a working download link for a Dll that contains the necessary functions for packet 0x51. Thanks. | April 30, 2010, 10:16 PM |
MyStiCaL | I believe this maybe what your looking for.. http://www.forbiddenlegacy.com/forum/index.php?topic=16.0 I use MBCSUtil.dll for .net though. | April 30, 2010, 10:33 PM |
Trunning | I just need the functions for packet 0x51, and I'm using C++. | May 1, 2010, 12:12 AM |
HdxBmx27 | For now, use BNLS, you need to learn how to handle network traffic. | May 1, 2010, 12:41 AM |
Trunning | Ok, where is the documentation for BNLS on http://bnetdocs.org. And which server do you recommend I use, and by that I mean, the safest. | May 1, 2010, 4:22 AM |
MyStiCaL | Well, If you use a Library to handle cdkey/password hashing, such as libbnet.dll which is in C++ then it wouldn't really matter what bnls server you use for checkrevision. as for bnls servers when i do use bnls, i use bnls.mattkv.net which uses JBLS by Hdx. | May 1, 2010, 6:22 AM |
Trunning | Ok thanks, still need a link to BNLS documentation. And what port for BNLS? | May 1, 2010, 6:25 AM |
HdxBmx27 | Seariously, it has a link on that page called BNLS Protocol Specs And it has a shitload of links for each BNLS packet... Its like one of the main points of BNetDocs.... I'm not trying to sound like a dick, but you really need to learn to actually read, and understand what you're reading. Anyways, BNLS works on a simple Request-Response concept. So basically look for a packet that gets you the data you need, look at the request (C->S with same packet name) and send it off. Just like BNCS, BNLS has a packet header, you can find information about that on BNetDocs under, you guessed it!, Protocol Headers! As for which server is the safest, I have not been keeping up on the latest servers, but bnls.mattkv.net is a reputable one, or phix.no-ip.biz which is hosted by PhiX from StealthBot.net. So you should be good with both of them. | May 1, 2010, 5:45 PM |
Trunning | I looked, even hit Ctrl + F to search for BNLS, found individual packets on the left, but that doesn't tell me the order I need to send them in. Is there any reference to what order I'm to send them in? And what the packets contain. | May 1, 2010, 6:12 PM |
HdxBmx27 | Read the rest of my post -.- | May 1, 2010, 6:15 PM |
Trunning | What port? And just to be sure, I just lookup 0x51, send that to BNLS server, it gives me the information I need for the 0x51 packet, correct? | May 1, 2010, 6:19 PM |
HdxBmx27 | No you need to look for a S->C BNLS packet that will give you the data you need for BNCS 0x51 C->S, heres a hint, you actually need 2 packets if you are also gunna hash the cdkeys. Once you find that packet, find it's C->S counter part [Like SID_AUTH_INFO has both a C->S and S->C, BNLS has things like BNLS_VERSIONBYTEREQUEST C->S and S->C] Once you've found the C->S counter part (heres another hint, it'll contain some of the info you got in SID_AUTH_INFO S->C) build it and send it to BNLS. BNLS will respond with the S->C version. Personally, I tell people who are learning Battle.net/network programming, to start with a simple client. Diablo 1. Diablo 1 doesn't need a cdkey, and uses the old password hashing method. So basically it's just 2 requests to BNLS. As opposed to 3+ Bnet Docs has the login sequance for Diablo 1 listed, so it's a piece of cake. | May 1, 2010, 6:28 PM |
Trunning | The only packet that jumps out at me is 0x0B, if you can give me links to the packets I will need, that would be great. Also what port for BNLS Servers?. | May 1, 2010, 6:35 PM |
HdxBmx27 | By default it uses 9367. And you're not understanding me I am specifically NOT giving you direct links because I want you to learn how to find them on your own. The 0x0B BNLS_HASHDATA you linked to is the packet you would send to hash your password when you are trying to login. (Works for everything but WC3) Heres a hint: CheckRevision() is the Version Check system for Battle.net | May 1, 2010, 6:50 PM |
Trunning | May 1, 2010, 6:59 PM | |
HdxBmx27 | Close, you actually don't need 0x18, as 0x1A replaced 0x18. So you only need 0x1A for check revision. If you'll notice, the packets are almost identical, except 0x18 has: (DWORD) Version DLL Digit And 0x1A Has: (FILETIME) Archive TimeStamp (String) Archive Name 0x1A was made to better support future version check systems as it has all the information the client has. Anyways, if you are using a product with a CDKey you still need the BNLS packet to hash CDKeys. But like I said, you should start with Diablo 1 as it doesn't have a CDKey | May 1, 2010, 7:08 PM |
Trunning | Guess I'll use Diablo 1 then, better go brush the dust off my Diablo 1 case. | May 1, 2010, 7:13 PM |
HdxBmx27 | Why? If you use BNLS you don't need anything from the game. But ya, D1 is fun dust it off to play it! Oh crap i forgot, by default BNLS doesnt support Diablo 1 FUUCCKK I think Phix Setup his server to support it. I'll do a little bit of looking around and make sure phix supports it. | May 1, 2010, 7:15 PM |
Trunning | Well I was going to capture a connection with WireShark, but I doubt I will now. All the reference I need is online. | May 1, 2010, 7:21 PM |
Trunning | 0x1A doesn't contain a product id for diablo 1, what do I use instead? And what an I'm suppose to use for the "Cookie"? | May 1, 2010, 7:32 PM |
dRAgoN | [quote author=Trunning link=topic=18219.msg184597#msg184597 date=1272687776] Ok, where is the documentation for BNLS on http://bnetdocs.org. And which server do you recommend I use, and by that I mean, the safest. [/quote] If you dont trust it dont use it, theres enough on these forms to deal with cdkeys and passwords so all you realy need is to use it for the checkrevision. | May 1, 2010, 7:33 PM |
HdxBmx27 | [code] public static final byte PRODUCT_STARCRAFT = 0x01; public static final byte PRODUCT_BROODWAR = 0x02; public static final byte PRODUCT_WAR2BNE = 0x03; public static final byte PRODUCT_DIABLO2 = 0x04; public static final byte PRODUCT_LORDOFDESTRUCTION = 0x05; public static final byte PRODUCT_JAPANSTARCRAFT = 0x06; public static final byte PRODUCT_WARCRAFT3 = 0x07; public static final byte PRODUCT_THEFROZENTHRONE = 0x08; public static final byte PRODUCT_DIABLO = 0x09; public static final byte PRODUCT_DIABLOSHAREWARE = 0x0A; public static final byte PRODUCT_STARCRAFTSHAREWARE= 0x0B;[/code] The support for Diablo, Diablo Shareware, and StarCraft Shareware is just an extension I made onto the BNLS protocol. It works exactly the same as other clients just with a different ID. and according to this Phix and Matt should support Diablo 1. [quote](12:56:04 PM) Ribose: yeah? (12:56:11 PM) Hdx: do you know of a JBLS server (12:56:15 PM) Hdx: which supports Diablo 1? (12:57:26 PM) Ribose: um (12:57:34 PM) Ribose: lemme see if my server is available to the world (1:00:17 PM) Ribose: ribose.no-ip.org should now be visible (1:00:29 PM) Hdx: and supports d1? (1:00:38 PM) Ribose: it should[/quote]There ya go, ribose's server supports D1. | May 1, 2010, 7:56 PM |
Trunning | Thanks, real quick question. Pkt goes out of scope after this function, so how am I suppose to keep the ArchiveName, etc. I tried returning Pkt with recv_SID_AUTH_INFO(), changed the return type to SMSG_SID_AUTH_INFO, but that didn't work. Ideas? [code]void recv_SID_AUTH_INFO(SOCKET sockBNCS, char *data, int length){ SMSG_SID_AUTH_INFO pkt; int raw_size = 20; //sizeof(pkt) - (sizeof(char *) * 2); memcpy(&pkt, data, raw_size); char *name_addr = data + raw_size; int name_len = strlen(name_addr); char *seed_addr = name_addr + name_len + 1; int seed_len = strlen(seed_addr); pkt.ArchiveName = (char*)malloc(name_len + 1); strcpy_s(pkt.ArchiveName, name_len + 1, name_addr); pkt.Seed = (char*)malloc(seed_len + 1); strcpy_s(pkt.Seed, seed_len + 1, seed_addr); printf("Received 0x50 %s, %s\n", pkt.ArchiveName, pkt.Seed); }[/code] | May 2, 2010, 4:48 AM |
HdxBmx27 | Mmkay i'm back i'll put a response before hitting the sack. You don't need to save the archive name beyond that function. You need to send the request from within that function. You can do it a few ways, either make a connection to BNLS before you connect to BNCS. Or, you can make two threads and keep each connection in there own thread. Personally this is my choice. Or you can create the connection in the recv_SID_AUTH_INFO function (or well, in a function it calls) Anyways, to answer your main question, it'd be something like: [code]void recv_SID_AUTH_INFO(...){ ...... Blah ... send_BNLS_VERSIONCHECKEX2(sockBNLS, pkt.ArchiveTime, pkt.ArchiveName, pkt.Seed); }[/code] | May 2, 2010, 8:06 AM |
Trunning | yeah I was thinking of that, creating the socket in that recv_SID_AUTH_INFO(), but it was messy and decided to get more ideas. But I'll do it that way,. | May 2, 2010, 8:40 AM |
Trunning | With the following code, I monitored with wireshark, and apparently the seed isn't being copied to the buffer I made. [code]#pragma comment (lib, "Ws2_32.lib") #include <winsock2.h> #include <windows.h> #include <string> #include <iostream> using namespace std; typedef unsigned long long FILET; struct BNCS_HEADER { BYTE Sanity; BYTE ID; WORD Length; }; struct BNLS_HEADER { WORD Length; BYTE ID; }; struct CMSG_SID_AUTH_INFO { DWORD ProtocolID; DWORD PlatformID; DWORD ProductID; DWORD VerByte; DWORD ProductLang; DWORD LocalIP; DWORD TimeZone; DWORD LocaleID; DWORD LangID; char *CountryAbbr; char *CountryName; }; struct SMSG_SID_AUTH_INFO { DWORD LogonType; DWORD ServerToken; DWORD UDPVal; FILET ArchiveTime; char *ArchiveName; char *Seed; }; struct CMSG_SID_PING{ DWORD PingValue; }; struct SMSG_SID_PING{ DWORD PingValue; }; struct CMSG_BNLS_VERCHECK { DWORD ProductID; DWORD Flags; DWORD Cookie; FILET ArchiveTime; char *ArchiveName; char *Seed; }; struct SMSG_BNLS_VERCHECK { DWORD Success; DWORD Version; DWORD Checksum; char *VerCheck; DWORD Cookie; DWORD LatestVer; }; void bnls_send(SOCKET sockBNLS, int ID, char *data, int length){ BNLS_HEADER header; header.ID = ID; header.Length = length + sizeof(BNLS_HEADER); send(sockBNLS, (const char*)&header, sizeof(BNLS_HEADER), NULL); send(sockBNLS, (const char*)data, length, NULL); } void bncs_send(SOCKET sockBNCS, int ID, char *data, int length){ BNCS_HEADER header; header.Sanity = 0xFF; header.ID = ID; header.Length = length + sizeof(BNCS_HEADER); send(sockBNCS, (const char*)&header, sizeof(BNCS_HEADER), NULL); send(sockBNCS, (const char*)data, length, NULL); } int socket_connect(SOCKET sockBNCS, const char *Server, WORD Port){ hostent *host = gethostbyname(Server); if (!host) return -1; SOCKADDR_IN info; info.sin_family = AF_INET; info.sin_addr = *((LPIN_ADDR)*host->h_addr_list); info.sin_port = htons(Port); if (connect(sockBNCS, (LPSOCKADDR)&info, sizeof(info)) == SOCKET_ERROR){ return -1; } return 0; } int send_SID_AUTH_INFO(SOCKET sockBNCS){ CMSG_SID_AUTH_INFO pkt; int sent = 0; memset(&pkt, 0, sizeof(CMSG_SID_AUTH_INFO)); TIME_ZONE_INFORMATION tz_Time; GetTimeZoneInformation(&tz_Time); pkt.ProtocolID = 0x00; pkt.PlatformID = 'IX86'; pkt.ProductID = 'DRTL'; pkt.VerByte = 0x2A; pkt.ProductLang = GetUserDefaultLangID(); pkt.LocalIP = inet_addr("192.168.1.100"); pkt.TimeZone = tz_Time.Bias; pkt.LocaleID = GetUserDefaultLCID(); pkt.LangID = GetUserDefaultLangID(); pkt.CountryAbbr = (char*)malloc(4); pkt.CountryName = (char*)malloc(14); strcpy_s(pkt.CountryAbbr, 4, "USA"); strcpy_s(pkt.CountryName, 14, "United States"); char *buffer; int pkt_size = sizeof(pkt) - (sizeof(char *) * 2); int full_size = pkt_size + strlen(pkt.CountryAbbr) + strlen(pkt.CountryName) + 2; buffer = (char*)malloc(full_size); memset(buffer, 0, full_size); memcpy(buffer, &pkt, pkt_size); strcpy_s(buffer + pkt_size, 4, pkt.CountryAbbr); strcpy_s(buffer + pkt_size + strlen(pkt.CountryAbbr) + 1, 14, pkt.CountryName); bncs_send(sockBNCS, 0x50, buffer, full_size); return 1; } void send_SID_PING(SOCKET sockBNCS, DWORD value){ printf("Pong 0x%08X\n", value); bncs_send(sockBNCS, 0x25, (char*)&value, 4); } void recv_SID_PING(SOCKET sockBNCS, char *data, int length){ SMSG_SID_PING pkt; memcpy(&pkt, data, sizeof(pkt)); printf("Ping 0x%08X\n", pkt.PingValue); send_SID_PING(sockBNCS, pkt.PingValue); } void recv_SID_AUTH_INFO(SOCKET sockBNCS, char *data, int length){ SMSG_SID_AUTH_INFO pkt; int raw_size = 20; //sizeof(pkt) - (sizeof(char *) * 2); memcpy(&pkt, data, raw_size); char *name_addr = data + raw_size; int name_len = strlen(name_addr); char *seed_addr = name_addr + name_len + 1; int seed_len = strlen(seed_addr); pkt.ArchiveName = (char*)malloc(name_len + 1); strcpy_s(pkt.ArchiveName, name_len + 1, name_addr); pkt.Seed = (char*)malloc(seed_len + 1); strcpy_s(pkt.Seed, seed_len + 1, seed_addr); printf("Archive: %s\nSeed: %s\n", pkt.ArchiveName, pkt.Seed); printf("\nCreating new socket for BNLS...\n"); SOCKET sockBNLS = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sockBNLS == SOCKET_ERROR){ printf("Failed to create socket!\n"); cin.get(); } printf("Connecting to BNLS Server...\n"); if (socket_connect(sockBNLS, "bnls.mattkv.net", 9367) == -1 ){ printf("Failed to connect to BNLS Server!\n"); cin.get(); } printf("Ready!\n\n"); CMSG_BNLS_VERCHECK packet = {0}; packet.ProductID = 0x09; packet.Flags = 0x00; packet.Cookie = 0x00; packet.ArchiveTime = pkt.ArchiveTime; packet.ArchiveName = pkt.ArchiveName; packet.Seed = pkt.Seed; int size = sizeof(packet) - (sizeof(char*) * 2); int full_size = strlen(packet.ArchiveName) + strlen(packet.Seed) + 2; char *buffer = (char*)malloc(full_size); memset(buffer, 0, full_size); memcpy(buffer, &packet, size); strcpy_s(buffer + size, strlen(packet.ArchiveName) + 1, packet.ArchiveName); strcpy_s(buffer + size + strlen(packet.ArchiveName) + 1, strlen(packet.Seed) + 1, packet.Seed); bnls_send(sockBNLS, 0x1A, buffer, full_size); closesocket(sockBNLS); } int main(){ WSADATA wsaData; WSAStartup(MAKEWORD(2, 0), &wsaData); SOCKET sockBNCS = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sockBNCS == INVALID_SOCKET){ printf("Failed to create socket!\n"); cin.get(); return -1; } if (socket_connect(sockBNCS, "useast.battle.net", 6112) == -1){ printf("Failed to connect!\n"); cin.get(); return -1; } printf("Sending protocol byte...\n"); int count; count = send(sockBNCS, "\x01", 1, NULL); if (count > 0) printf("Sent %d bytes\n", count); else printf("Failed to send protocol byte!\n"); if(send_SID_AUTH_INFO(sockBNCS)){ BNCS_HEADER header; char *data = (char*)malloc(0x200); int data_max = 0x200; bool sid_ping = false, sid_auth = false; while (true){ if (sid_ping = true && sid_auth == true) break; count = recv(sockBNCS, (char*)&header, sizeof(header), NULL); if (count != sizeof(header)){ printf("Didn't receive full header, %d of %d\n", count, sizeof(BNCS_HEADER)); closesocket(sockBNCS); WSACleanup(); cin.get(); return 0; } else { if (header.Length - 4 > data_max){ free(data); data = (char *)malloc(header.Length - 4); } count = recv(sockBNCS, data, header.Length - 4, NULL); if (count == SOCKET_ERROR){ count = WSAGetLastError(); printf("Receiving failed error #%d\n", count); return 0; }else if(count == 0 && header.Length != 4){ printf("Server closed connection\n"); return 0; }else if(count != header.Length - 4){ printf("Failed to receive full packet ID: 0x%02X, received %d of %d\n", header.ID, count, header.Length - 4); return 0; }else{ printf("\nReceived Packet ID: 0x%02X Length: 0x%04X (%d)\n", header.ID, header.Length, header.Length); switch(header.ID){ case 0x25: recv_SID_PING (sockBNCS, data, header.Length - 4); sid_ping = true; break; case 0x50: recv_SID_AUTH_INFO(sockBNCS, data, header.Length - 4); sid_auth = true; break; } } } } } printf("\nExiting Program!\n"); cin.get(); closesocket(sockBNCS); WSACleanup(); return 0; }[/code] | May 3, 2010, 2:09 AM |
HdxBmx27 | [code][code] int full_size = strlen(packet.ArchiveName) + strlen(packet.Seed) + 2;[/code] You're missing something.[/code] | May 3, 2010, 5:07 PM |
Trunning | [code][code]int full_size = size + strlen(packet.ArchiveName) + strlen(packet.Seed) + 2;[/code] I added size into the calculation now I'm sending: [code]0000 09 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0010 6f 5f c7 01 cc cc cc cc 6c 6f 63 6b 64 6f 77 6e o_......lockdown 0020 2d 49 58 38 36 2d 30 36 2e 6d 70 71 00 e8 e9 c6 -IX86-06.mpq.... 0030 bd d4 27 3f f9 63 2b 7c d1 5e eb dd 78 00 ..'?.c+|.^..x.[/code] And receving: [code]0000 0b 00 1a 00 00 00 00 00 00 00 00 ...........[/code][/code] | May 3, 2010, 6:24 PM |
HdxBmx27 | That means the server failed to calc the ver info. If you read the docs thats easy to see. For some reason you are sending a malformed packet, but a quick glace seems correct. But I dun wanna look hard. | May 3, 2010, 7:39 PM |
rabbit | [quote author=Hdx link=topic=18219.msg184637#msg184637 date=1272915574] That means the server failed to calc the ver info. If you read the docs thats easy to see. For some reason you are sending a malformed packet, but a quick glace seems correct. But I dun wanna look hard. [/quote] [quote author=Trunning link=topic=18219.msg184636#msg184636 date=1272911060] [code]0000 09 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 0010 6f 5f c7 01 cc cc cc cc 6c 6f 63 6b 64 6f 77 6e o_......lockdown 0020 2d 49 58 38 36 2d 30 36 2e 6d 70 71 00 e8 e9 c6 -IX86-06.mpq.... 0030 bd d4 27 3f f9 63 2b 7c d1 5e eb dd 78 00 ..'?.c+|.^..x.[/code] [/quote] I'm not even seeing a packet header in there. Going off of it being omitted (for some reason), there's an extra DWORD before the filetime and 0xCCCCCCCC makes no sense or the filetime has a hiword of 0 (which makes less sense) and 0xCCCCCC still makes no sense. | May 4, 2010, 1:57 AM |
Trunning | Changed the ProductID back to D2DV for experimentation, and I'm receiving something back from the BNLS Server now. And I'm unsure if the Cookie for packet 0x1A is suppose to be the current time, let alone if I'm giving it the right format. [code]#pragma comment (lib, "Ws2_32.lib") #include <winsock2.h> #include <windows.h> #include <string> #include <time.h> #include <iostream> using namespace std; typedef unsigned long long FILET; ///////////////////////////////////////// // // Structs // struct BNCS_HEADER { BYTE Sanity; BYTE ID; WORD Length; }; struct BNLS_HEADER { WORD Length; BYTE ID; }; struct CMSG_SID_AUTH_INFO { DWORD ProtocolID; DWORD PlatformID; DWORD ProductID; DWORD VerByte; DWORD ProductLang; DWORD LocalIP; DWORD TimeZone; DWORD LocaleID; DWORD LangID; char *CountryAbbr; char *CountryName; }; struct SMSG_SID_AUTH_INFO { DWORD LogonType; DWORD ServerToken; DWORD UDPVal; FILET ArchiveTime; char *ArchiveName; char *Seed; }; struct CMSG_SID_PING{ DWORD PingValue; }; struct SMSG_SID_PING{ DWORD PingValue; }; struct CMSG_BNLS_VERCHECK { DWORD ProductID; DWORD Flags; DWORD Cookie; FILET ArchiveTime; char *ArchiveName; char *Seed; }; struct SMSG_BNLS_VERCHECK { DWORD Success; DWORD Version; DWORD Checksum; char *VerCheck; DWORD Cookie; DWORD LatestVer; }; ///////////////////////////////////////// // // Functions // void bnls_send(SOCKET sockBNLS, int ID, char *data, int length){ BNLS_HEADER header; header.ID = ID; header.Length = length + sizeof(BNLS_HEADER); char *buffer = (char*)malloc(header.Length); memset(buffer, 0, header.Length); memcpy(buffer, &header, sizeof(BNLS_HEADER)); memcpy(buffer + sizeof(BNLS_HEADER), data, length); if (send(sockBNLS, buffer, header.Length, NULL) != header.Length){ printf("Failed to send complete packet!\n"); } } void bncs_send(SOCKET sockBNCS, int ID, char *data, int length){ BNCS_HEADER header; header.Sanity = 0xFF; header.ID = ID; header.Length = length + sizeof(BNCS_HEADER); send(sockBNCS, (const char*)&header, sizeof(BNCS_HEADER), NULL); send(sockBNCS, (const char*)data, length, NULL); } int socket_connect(SOCKET sockBNCS, const char *Server, WORD Port){ hostent *host = gethostbyname(Server); if (!host) return -1; SOCKADDR_IN info; info.sin_family = AF_INET; info.sin_addr = *((LPIN_ADDR)*host->h_addr_list); info.sin_port = htons(Port); if (connect(sockBNCS, (LPSOCKADDR)&info, sizeof(info)) == SOCKET_ERROR){ return -1; } return 0; } int send_SID_AUTH_INFO(SOCKET sockBNCS){ CMSG_SID_AUTH_INFO pkt; int sent = 0; memset(&pkt, 0, sizeof(CMSG_SID_AUTH_INFO)); TIME_ZONE_INFORMATION tz_Time; GetTimeZoneInformation(&tz_Time); pkt.ProtocolID = 0x00; pkt.PlatformID = 'IX86'; pkt.ProductID = 'D2DV'; pkt.VerByte = 0x0C; pkt.ProductLang = GetUserDefaultLangID(); pkt.LocalIP = inet_addr("192.168.1.100"); pkt.TimeZone = tz_Time.Bias; pkt.LocaleID = GetUserDefaultLCID(); pkt.LangID = GetUserDefaultLangID(); pkt.CountryAbbr = (char*)malloc(4); pkt.CountryName = (char*)malloc(14); strcpy_s(pkt.CountryAbbr, 4, "USA"); strcpy_s(pkt.CountryName, 14, "United States"); char *buffer; int pkt_size = sizeof(pkt) - (sizeof(char *) * 2); int full_size = pkt_size + strlen(pkt.CountryAbbr) + strlen(pkt.CountryName) + 2; buffer = (char*)malloc(full_size); memset(buffer, 0, full_size); memcpy(buffer, &pkt, pkt_size); strcpy_s(buffer + pkt_size, 4, pkt.CountryAbbr); strcpy_s(buffer + pkt_size + strlen(pkt.CountryAbbr) + 1, 14, pkt.CountryName); bncs_send(sockBNCS, 0x50, buffer, full_size); return 1; } void send_SID_PING(SOCKET sockBNCS, DWORD value){ printf("Pong 0x%08X\n", value); bncs_send(sockBNCS, 0x25, (char*)&value, 4); } void recv_SID_PING(SOCKET sockBNCS, char *data, int length){ SMSG_SID_PING pkt; memcpy(&pkt, data, sizeof(pkt)); printf("Ping 0x%08X\n", pkt.PingValue); send_SID_PING(sockBNCS, pkt.PingValue); } void recv_SID_AUTH_INFO(SOCKET sockBNCS, char *data, int length){ SMSG_SID_AUTH_INFO pkt; int raw_size = 20; //sizeof(pkt) - (sizeof(char *) * 2); memcpy(&pkt, data, raw_size); char *name_addr = data + raw_size; int name_len = strlen(name_addr); char *seed_addr = name_addr + name_len + 1; int seed_len = strlen(seed_addr); pkt.ArchiveName = (char*)malloc(name_len + 1); strcpy_s(pkt.ArchiveName, name_len + 1, name_addr); pkt.Seed = (char*)malloc(seed_len + 1); strcpy_s(pkt.Seed, seed_len + 1, seed_addr); printf("Archive: %s\nSeed: %s\n\n", pkt.ArchiveName, pkt.Seed); SOCKET sockBNLS = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sockBNLS == SOCKET_ERROR){ printf("Failed to create socket!\n"); cin.get(); } printf("Connecting to BNLS Server...\n"); if (socket_connect(sockBNLS, "bnls.mattkv.net", 9367) == -1 ){ printf("Failed to connect to BNLS Server!\n"); cin.get(); } printf("Connected!\n\n"); time_t tTime; tTime = time(NULL); CMSG_BNLS_VERCHECK packet; packet.ProductID = 0x04; packet.Flags = 0x00; packet.Cookie = (DWORD)tTime; packet.ArchiveTime = pkt.ArchiveTime; packet.ArchiveName = pkt.ArchiveName; packet.Seed = pkt.Seed; int size = sizeof(packet) - (sizeof(char*) * 2); int full_size = size + strlen(packet.ArchiveName) + strlen(packet.Seed) + 2; char *buffer = (char*)malloc(full_size); memset(buffer, 0, full_size); memcpy(buffer, &packet, size); strcpy_s(buffer + size, strlen(packet.ArchiveName) + 1, packet.ArchiveName); strcpy_s(buffer + size + strlen(packet.ArchiveName) + 1, strlen(packet.Seed) + 1, packet.Seed); printf("Sending 0x1A < Size %d >\n", full_size); bnls_send(sockBNLS, 0x1A, buffer, full_size); char *r_data = (char*)malloc(100); memset(r_data, 0, 100); recv(sockBNLS, r_data, 100, NULL); printf("\nData ->\n\n%s\n\n", r_data); closesocket(sockBNLS); } ///////////////////////////////////////// // // Main Entry Point // int main(){ WSADATA wsaData; WSAStartup(MAKEWORD(2, 0), &wsaData); SOCKET sockBNCS = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sockBNCS == INVALID_SOCKET){ printf("Failed to create socket!\n"); cin.get(); return -1; } printf("Connecting...\n"); if (socket_connect(sockBNCS, "useast.battle.net", 6112) == -1){ printf("Failed to connect!\n"); cin.get(); return -1; } printf("Connected!\n\n"); printf("Initializing connection ( 0x01 )\n"); int count; count = send(sockBNCS, "\x01", 1, NULL); if (count > 0) printf("Sent Protocol byte < %d >\n\n", count); else printf("Failed to initialize connection!\n"); if(send_SID_AUTH_INFO(sockBNCS)){ BNCS_HEADER header; char *data = (char*)malloc(0x200); int data_max = 0x200; bool sid_ping = false, sid_auth = false; while (true){ if (sid_ping = true && sid_auth == true) break; count = recv(sockBNCS, (char*)&header, sizeof(header), NULL); if (count != sizeof(header)){ printf("Didn't receive full header, %d of %d\n", count, sizeof(BNCS_HEADER)); closesocket(sockBNCS); WSACleanup(); cin.get(); return 0; } else { if (header.Length - 4 > data_max){ free(data); data = (char *)malloc(header.Length - 4); } count = recv(sockBNCS, data, header.Length - 4, NULL); if (count == SOCKET_ERROR){ count = WSAGetLastError(); printf("Receiving failed error #%d\n", count); return 0; }else if(count == 0 && header.Length != 4){ printf("Server closed connection\n"); return 0; }else if(count != header.Length - 4){ printf("Failed to receive full packet ID: 0x%02X, received %d of %d\n", header.ID, count, header.Length - 4); return 0; }else{ printf("\nReceived Packet ID: 0x%02X Length: 0x%04X (%d)\n", header.ID, header.Length, header.Length); switch(header.ID){ case 0x25: recv_SID_PING (sockBNCS, data, header.Length - 4); sid_ping = true; break; case 0x50: recv_SID_AUTH_INFO(sockBNCS, data, header.Length - 4); sid_auth = true; break; } } } } } printf("\nExiting Program!\n"); cin.get(); closesocket(sockBNCS); WSACleanup(); return 0; }[/code] Sent [code]0000 6b 00 1a cc 04 00 00 00 00 00 00 00 fe 07 e1 4b k..............K 0010 cc cc cc cc 70 5f c7 01 cc cc cc cc 76 65 72 2d ....p_......ver- 0020 49 58 38 36 2d 31 2e 6d 70 71 00 43 3d 37 33 32 IX86-1.mpq.C=732 0030 39 31 38 33 33 33 20 42 3d 34 32 30 39 36 38 39 918333 B=4209689 0040 37 30 32 20 41 3d 31 31 37 37 33 34 38 31 33 31 702 A=1177348131 0050 20 34 20 41 3d 41 2b 53 20 42 3d 42 2d 43 20 43 4 A=A+S B=B-C C 0060 3d 43 5e 41 20 41 3d 41 2d 42 00 =C^A A=A-B.[/code] Received [code]0000 0b 00 1a 00 00 00 00 00 fe 07 e1 ...........[/code] | May 5, 2010, 5:57 AM |
HdxBmx27 | You're not receiving anything new back. You're receiving the cookie you are sending back. Just like you were before. Look at the packet log, compare it to the Packet structure, you can obviously see that you are sending a malformed packet. Figure out why. If you see 'cc' in your packet logs, 99% of the time, it's because you fucked something up. (CC is usually representative of uninitialized memory) I think this is a case of compiler optimization, you may need to explicitly define the layout, See: #pragma pack() | May 5, 2010, 6:10 AM |
Trunning | I just put a breakpoint an it appears everything is being set, but there is still a few 'cc's in the packet log. | May 5, 2010, 6:34 AM |
HdxBmx27 | Yup, liberal application of pack fixes it. | May 5, 2010, 7:03 AM |
Trunning | Huh? | May 5, 2010, 7:50 AM |
HdxBmx27 | Put #pragma pack(1) before your 1st struct and #pragma paack(pop) after your last. | May 5, 2010, 8:11 AM |
Trunning | Ah working now. I'm using this code to receive the packet, but its not working. And this appears to be the same as yours. [code]BNLS_HEADER head; memset((void*)&head, 0, sizeof(BNLS_HEADER)); recv(sockBNLS, (char*)&head, sizeof(BNLS_HEADER), NULL); char *rdata = (char*)malloc(head.Length); memset((void*)rdata, 0, head.Length); recv(sockBNLS, rdata, head.Length, NULL); printf("\n\n%s\n", rdata);[/code] | May 5, 2010, 9:13 AM |
rabbit | The cookie is just a tracking value so you can keep multiple BNLS connections separated; it has no impact on any result or action taken by BNLS. | May 5, 2010, 2:59 PM |
HdxBmx27 | You need to minus the size of the header from the 2nd recv. As the Length in the header includes the header. | May 5, 2010, 5:21 PM |
Trunning | Didn't think of that, still didn't work. [code]int head_size = sizeof(BNLS_HEADER); char *rdata = (char*)malloc(head.Length - head_size); memset((void*)rdata, 0, head.Length - head_size); recv(sockBNLS, rdata, head.Length - head_size, NULL);[/code] [quote author=rabbit link=topic=18219.msg184652#msg184652 date=1273071554] The cookie is just a tracking value so you can keep multiple BNLS connections separated; it has no impact on any result or action taken by BNLS. [/quote] And the best way to keep it random is use the time. | May 6, 2010, 3:54 AM |
HdxBmx27 | You never want to have a cookie be completely random.... In general it can be used as a 'Request ID', Say you have 4 bots connecting, and you want them all to use the same BNLS connection. You'd send a cookie of 1 for the first bot, 2 for the second, etc.. so you know which response goes to which bot. BUT the theory behind things like this is way beyond you, so just set it to 0x0BADC0DE. :P Anyways, set a break point, what happens? Nothing? Define nothing. Also, [code]int body_size = head.Length - sizeof(BNLS_HEADER); char *rdata if(body_size > 0) { rdata = (char*)malloc(body_size); memset((void*)rdata, 0, body_size); printf("Recv: %d\n", recv(sockBNLS, rdata, body_size, NULL)); } [/code] Try that. (Note how I changed your head_size to body_size, simple change means a lot easier to read code) | May 6, 2010, 4:27 AM |
Trunning | Oh wow, it's the address of rdata. I'm trying to copy it to a packet but it doesn't copy the data there. [code] int body_size = head.Length - sizeof(BNLS_HEADER); char *rdata; if(body_size > 0) { rdata = (char*)malloc(body_size); memset((void*)rdata, 0, body_size); printf("\nRecv: %d\n", recv(sockBNLS, rdata, body_size, NULL)); SMSG_BNLS_VERCHECK ya; memcpy(&ya, rdata, sizeof(SMSG_BNLS_VERCHECK)); }[/code] | May 6, 2010, 5:00 AM |
HdxBmx27 | In theroy it should work. I'd like to see your full code. BTW instead of posting code here, post to pastebin. Stops table breaking, and i can view it all in 1 glance. Anyways, is the data being set in rdata? What does the printf say? Does it equal body_size? You really need to be more specific when you post. | May 6, 2010, 5:31 AM |
Trunning | http://pastebin.com/PH2ixcDa I'm receiving 53 bytes, and body_size is 53. | May 6, 2010, 5:54 AM |
HdxBmx27 | The problem you have here, is simply, the scope of the struct you are copying to is leaving as right after you do memcpy, so move the declaration of your variable out of the If. And ugh! Your code hurts my eyes, I should re-write it a bit cleaner/more organized... | May 6, 2010, 8:22 PM |
Trunning | Yeah don't worry, I plan to always clean code up, put it in functions, pass variables as parameters, etc. I'll be waiting for you improved version of my code ::) | May 6, 2010, 8:33 PM |
HdxBmx27 | You're using C++, think Objects! If you notice pretty much everything for the network communication is exactly the same for BNLS/BNCS. Just different in the structure of the header. If you make a object doing all the generic stuff, then inherite it to more protocol specific objects.. anyways. I said I *should* not that I would. | May 6, 2010, 8:41 PM |
Trunning | Wow never mind, aren't I stupid. | May 6, 2010, 8:44 PM |
HdxBmx27 | ..... I don't even think I should answer why that doesn't work. It's so obvious... Hint: How many variables are you passing? | May 6, 2010, 8:48 PM |
Trunning | Nevermind, I was setting ya to 0, with memset after memcpy, stupid order Eh? | May 6, 2010, 8:51 PM |
Trunning | Printing out the Version Check Stat String, prints out some unknown characters apparently. http://pastebin.com/tELnwtCz Also what data do I use from 0x1A, for 0x51. 0x1A - 0x51 (DWORD) Version - (DWORD) EXE Version (DWORD) Checksum - (DWORD) EXE Hash Do they match up? | May 6, 2010, 9:03 PM |
HdxBmx27 | [quote author=Trunning link=topic=18219.msg184670#msg184670 date=1273179830]Printing out the Version Check Stat String, prints out some unknown characters apparently.[/quote]Well no shit, thats because a char * is supposto point to a char array, which is not whas going on. As you see in the other code, we malloc some space, then do strcpy. So you have to do some memory shuffling to get the struct filled out properly. [quote author=Trunning link=topic=18219.msg184670#msg184670 date=1273179830]Also what data do I use from 0x1A, for 0x51. 0x1A - 0x51 (DWORD) Version - (DWORD) EXE Version (DWORD) Checksum - (DWORD) EXE Hash Do they match up? [/quote]Yes. | May 6, 2010, 9:11 PM |
Trunning | I see you've done that here: [code]SMSG_SID_AUTH_INFO pkt; int raw_size = 20; //sizeof(pkt) - (sizeof(char *) * 2); memcpy(&pkt, data, raw_size); char *name_addr = data + raw_size; int name_len = strlen(name_addr); char *seed_addr = name_addr + name_len + 1; int seed_len = strlen(seed_addr); pkt.ArchiveName = (char*)malloc(name_len + 1); strcpy_s(pkt.ArchiveName, name_len + 1, name_addr); pkt.Seed = (char*)malloc(seed_len + 1); strcpy_s(pkt.Seed, seed_len + 1, seed_addr);[/code] Can you explain how this works, and give an example with the packet 0x1A? Hmm I think I could pull this off, if the 1 char* in SMSG_BNLS_VERCHECK was at the end, but it's in the middle. | May 6, 2010, 9:13 PM |
HdxBmx27 | No, i've already given you enough code for you to be able to do it yourself, BUT I will explain whats going on. Basically in memory you have this laid out exactly as bellow (Instead of the hex it's the char representative.) [code]0000 6b 00 1a cc 04 00 00 00 00 00 00 00 fe 07 e1 4b k..............K 0010 cc cc cc cc 70 5f c7 01 cc cc cc cc 76 65 72 2d ....p_......ver- 0020 49 58 38 36 2d 31 2e 6d 70 71 00 43 3d 37 33 32 IX86-1.mpq.C=732 0030 39 31 38 33 33 33 20 42 3d 34 32 30 39 36 38 39 918333 B=4209689 0040 37 30 32 20 41 3d 31 31 37 37 33 34 38 31 33 31 702 A=1177348131 0050 20 34 20 41 3d 41 2b 53 20 42 3d 42 2d 43 20 43 4 A=A+S B=B-C C 0060 3d 43 5e 41 20 41 3d 41 2d 42 00 =C^A A=A-B.[/code] [code]k\x00\x1A\xCC\x04\x00\x00\x00\x00\x00\x00\x00\xFE\x07\xE1K \xCC\xCC\xCC\xCCp_\xC7\x01\xCC\xCC\xCC\xCCver-IX86-1.mpq\x00 C=732918333 B=4209689702 A=1177348131 4 A=A+S B=B-C C=C^A A=A-B\x00[/code] When we do our memcpy, we copy the data and fit it into the struct. Which works great for normal numeric values, but not for strings, becuse a pointer is actually a 32-bit value which points to another address in memory. Which has our string. So a basic example is: [code]00000000: 04 00 00 00 00000004: Our String\x0[/code] As you can see, our char * is actually holding the value of 0x00000004, which is the address of our string. Make sense? So when you copy the giant chunk, you are actually making the computer think that our string is at address 'ver-' which is obviously a invalid address. (Well it could be valid, just not where we want it. So what we do is we use malloc to allocate another section in memory to hold the string value we want. We use memcpy to move the string from where it was, to where we just allocated. Then we update our struct's value to the new pointer. So here is some examples: [code]struct TEST{ DWORD Value1; char *StringVal; };[/code][code]01 02 03 04 41 42 43 44 00 . . . . A B C D .[/code] So we do a memcpy:[code]TEST t; memcpy(&t, data, sizeof(TEST)[/code] Our struct now has the following values: [code]Value1: 0x04030201 StringVal: 0x44434241 -> UNKNOWN MEMORY[/code] As you can see, it has our string as the pointer, this is a no no! So what we do is move the string: [code]int string_len = strlen(data + 4); //Data is a pointer to the first 0x01, our string is 4 bytes in, hence the +4 char *str = (char *)malloc(string_len + 1); //strlen() does not include the trailing null 0x00 but we need it. memcpy(str, data + 4, string_len + 1); //lets copy out string, including the null to the new memory space t.StringVal = str; //And assign the new pointer to our struct. printf("String: %s\n", t.StringVal); //Will now print out "String: ABCD"![/code] I am bad at explaining things but you need to learn and get used to how memory is laid out. It's a simple concept. Seine it's in the middle, you are going to have to move the rest of the data into the struct, you can do that with another memcpy() with the proper address (hint: you'll need to use the length of the string) | May 6, 2010, 9:38 PM |
Trunning | I understand DMA, memory, pointers, etc. And I was thinking, get the size of the 3 dwords, (sizeof(DWORD) * 3). Then we are at where the char* should be, then we get the string length with strlen(), it stops at the null terminator. Then there will be 2 more dwords after that, 8 bytes. Simple questions: After I find out whats where, how then do I copy, 3 dwords, a char*, and 2 more dwords to pkt. In the destination do I just use + offset in bytes? The data that should be hashed for 'Hashed Key Data' is: 1. Client Token 2. Server Token 3. Key Product (from decoded CD key) 4. Key Public (from decoded CD key) 5. (DWORD) 0 6. Key Private (from decoded CD key) Should the key product contain "D2DV", etc? Should the key public contain "AAAABBBBCCCCDDDD"? That's an example of a CDKey. And what does key private contain? | May 6, 2010, 9:47 PM |
HdxBmx27 | The public, private, and product values are all contained within the human readable cdkey. Blizzard has a proprietary function to decode the cdkeys into these 3 values. If you use BNLS_CDKEY you don't have to worry about it, you just have to send your raw cdkey, server/client tokens, and it'll return all the proper data. BUT like I said, if you use D1 for now, you wont need to worry about any cdkeys. [In 0x51 just set the number of cdkeys to 0 and do not include any of the data thats per cdkey.] | May 6, 2010, 9:52 PM |
Trunning | Ok then, but is this theory right? And can I use X-Sha-1 logon sequence for diablo 1, or do I have to use it's specific logon sequence. [code]SMSG_BNLS_VERCHECK pkt; int raw_gap = (sizeof(DWORD) * 3); char *ss = data + raw_gap; int ss_len = strlen(ss); memcpy(&pkt, data, raw_gap); memcpy(&pkt + raw_gap, ss, ss_len); memcpy(&pkt + raw_gap + ss_len, data + raw_gap + ss_len, 8); // makes sense to me[/code] | May 6, 2010, 9:54 PM |
HdxBmx27 | [quote author=Trunning link=topic=18219.msg184676#msg184676 date=1273182881]And can I use X-Sha-1 logon sequence for diablo 1, or do I have to use it's specific logon sequence.[/quote]Ya, Blizzard is ually happy with D1 using the SID_AUTH login. Its ok for a temporary thing until you work out how to properly support all the protocols. [quote author=Trunning link=topic=18219.msg184676#msg184676 date=1273182881]Ok then, but is this theory right? [code]SMSG_BNLS_VERCHECK pkt; int raw_gap = (sizeof(DWORD) * 3); char *ss = data + raw_gap; int ss_len = strlen(ss); memcpy(&pkt, data, raw_gap); memcpy(&pkt + raw_gap, ss, ss_len); memcpy(&pkt + raw_gap + ss_len, data + raw_gap + ss_len, 8); // makes sense to me[/code][/quote] Nope, wheres your malloc? BTW your 'gap' is actually strlen+1. | May 6, 2010, 9:59 PM |
Trunning | Huge breakthrough, I just confirmed the world will end on the 21st of December, 2012. Ah well I feel good now, this works. I understand it too. [code] SMSG_BNLS_VERCHECK pkt; int raw_gap = (sizeof(DWORD) * 3); char *ss = data + raw_gap; int ss_len = strlen(ss) + 1; memcpy(&pkt, data, raw_gap); pkt.VerCheck = (char*)malloc(ss_len); memcpy(pkt.VerCheck, ss, ss_len); memcpy(&pkt + raw_gap + ss_len, data + raw_gap + ss_len, 8); // makes sense to me printf("Stat String: %s\n", pkt.VerCheck);[/code] | May 6, 2010, 10:05 PM |
HdxBmx27 | Only thing I have to say is FINAL-FUCKING-LY! eek, nvm, | May 6, 2010, 10:11 PM |
Trunning | Hmm? [code]int ss_len = strlen(ss) + 1;[/code] | May 6, 2010, 10:12 PM |
HdxBmx27 | ya i skimmed over it. it wasnt in your original anyways with what you have learned, you should be online within 1/2 hr tops. Get a crackin. | May 6, 2010, 10:27 PM |
Trunning | Sadly I don't agree. Also I'm assuming a checksum can be a negative value. Here is my output: [code] Recv: 53 Success: 1 Version: 16780544 Checksum: -1485220444 Ver SS: game.exe 02/08/10 23:11:00 57344 Cookie: 0 Latest Version: 0 [/code] And the code: [code]void recv_BNLS_VERCHECK(SOCKET sockBNLS, char *data, int length) { SMSG_BNLS_VERCHECK pkt; memset((void*)&pkt, 0, sizeof(pkt)); int raw_gap = (sizeof(DWORD) * 3); char *ss = data + raw_gap; int ss_len = strlen(ss) + 1; pkt.VerCheck = (char*)malloc(ss_len); memcpy(&pkt, data, raw_gap); memcpy(pkt.VerCheck, ss, ss_len); memcpy(&pkt + raw_gap + ss_len, data + raw_gap + ss_len, (sizeof(DWORD) * 2)); printf("Success: %d\n", pkt.Success); printf("Version: %d\n", pkt.Version); printf("Checksum: %d\n", pkt.Checksum); printf("Ver SS: %s\n", pkt.VerCheck); printf("Cookie: %d\n", pkt.Cookie); printf("Latest Version: %d\n", pkt.LatestVer); }[/code] | May 6, 2010, 10:36 PM |
HdxBmx27 | You're not supposto use ss_len in the last memcpy. [code] memcpy(&pkt + raw_gap + 4, data + raw_gap + ss_len, (sizeof(DWORD) * 2));[/code] And as with most things on Battle.net the checksum is actually a 32-but unsigned variable. Negatives are fine, but arnt really negs. | May 6, 2010, 11:32 PM |
Trunning | Still both zero, took out + ss_len, and put in + 4, didn't work. I tried several other things, but all failed. | May 6, 2010, 11:38 PM |
HdxBmx27 | Define several other things, seriously, be more descriptive. Anyways your code *should* work. Do you have packet logs? | May 6, 2010, 11:49 PM |
Trunning | 3 Other Things: + 1 + sizeof(char) + 4 // yours And this is 0x1A, S -> C. [code]0000 00 26 18 7f 24 a2 00 04 ed 6f a5 60 08 00 45 00 .&..$....o.`..E. 0010 00 60 5f b4 40 00 70 06 42 58 cc 98 d9 e5 c0 a8 .`_.@.p.BX...... 0020 01 65 24 97 06 5f d8 7c 70 8e 02 b6 d5 d4 50 18 .e$.._.|p.....P. 0030 ff 98 f4 99 00 00 38 00 1a 01 00 00 00 00 0d 00 ......8......... 0040 01 02 e0 ec 37 67 61 6d 65 2e 65 78 65 20 30 32 ....7game.exe 02 0050 2f 30 38 2f 31 30 20 32 33 3a 31 31 3a 30 30 20 /08/10 23:11:00 0060 35 37 33 34 34 00 b8 56 e3 4b 0d 00 00 00 57344..V.K....[/code] | May 6, 2010, 11:55 PM |
HdxBmx27 | Well, the code posted 2 posts ago should work fine. dunno what you're doing wrong. | May 7, 2010, 12:13 AM |
Trunning | Ok well here is my entire code. http://pastebin.com/fEGpHbVc | May 7, 2010, 12:16 AM |
Trunning | Ok well I've tried everything I can think of, I rewrote the memcpy() twice, I'm getting pretty desperate. | May 7, 2010, 5:59 AM |
Trunning | Wow the solution was so simple, type casting pkt to a character pointer. | May 7, 2010, 10:55 AM |
Trunning | Yeah I know you told me to use diablo 1, but if I change the ProductID and VerByte, server gives me a weird seed, plus I feel fine sending a couple extra packets. When my code gets to the following function, the array in SMSG_BNLS_CDKEY is being set, but I get a runtime error "Run-Time Check Failure #2 - Stack around the variable 'pkt' was corrupted.". [code]void recv_BNLS_CDKEY(SOCKET sockBNLS, char *data, int length) { SMSG_BNLS_CDKEY pkt; memset((void*)&pkt, 0, sizeof(pkt)); memcpy(&pkt, data, length); printf("Sucess: %d\n", pkt.Result); }[/code] Struct [code]struct SMSG_BNLS_CDKEY { BYTE Result; DWORD ClientToken; DWORD Data[9]; };[/code] | May 7, 2010, 12:40 PM |
dRAgoN | your using DRTL there is no cdkey used for it, so you shouldent be asking BNLS for that data. edit: nm apparently your using d2 again, either way not seeing your send for that in the code posted so dont know why you would be recieveing that | May 7, 2010, 1:05 PM |
Trunning | Here it is, the struct, and the code to send, and receive. [code]struct CMSG_BNLS_CDKEY { DWORD ServerToken; char* CDKey; };[/code] [code]CMSG_BNLS_CDKEY packet; packet.ServerToken = g_ServerToken; // Copying the actual value here packet.CDKey = g_CDKey; // g_CDKey is a char*, so I'm just copying the address int pack_size = ((sizeof(packet) - 4) + strlen(g_CDKey) + 1); char* buffer = (char*)malloc(pack_size); memcpy(buffer, (void*)&packet, sizeof(DWORD)); memcpy(buffer + sizeof(DWORD), g_CDKey, strlen(g_CDKey) + 1); bnls_send(sockBNLS, 0x01, buffer, pack_size); printf("Well ...\n"); free(buffer); // Recv the response BNLS_HEADER san; recv(sockBNLS, (char*)&san, sizeof(BNLS_HEADER), NULL); int body = san.Length - sizeof(BNLS_HEADER); char* adata; if (body > 0){ adata = (char*)malloc(body); int count = recv(sockBNLS, adata, body, NULL); printf("Got 0x01 from BNLS, Size: %d\n", count); recv_BNLS_CDKEY(sockBNLS, adata, count); free(adata); }[/code] | May 7, 2010, 1:19 PM |
Trunning | [code]BYTE - Success[/code] Was actually a DWORD, but BnetDocs didn't actually specifically say this. | May 7, 2010, 3:09 PM |
HdxBmx27 | http://www.bnetdocs.org/?op=packet&pid=123 yes it does... humm anyways booleans are usually a dword on bnet. | May 8, 2010, 5:03 AM |
Trunning | http://www.bnetdocs.org/?op=doc&did=19 [code]BOOL - A byte that equals 1 or 0. Can also be a DWORD, depending on the packet.[/code] ? | May 8, 2010, 5:05 AM |
dRAgoN | 0 = False 1 = True edit: most of the packet documents tell you if the BOOL is a BYTE WORD DWORD and so on. | May 8, 2010, 5:13 AM |