Valhalla Legends Forums Archive | Battle.net Bot Development | Dll contains CheckRevision()

AuthorMessageTime
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
It looks like these should be all I need.

0x18
0x1A
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

Search