Valhalla Legends Forums Archive | Battle.net Bot Development | C++ Basic Connection

AuthorMessageTime
Trunning
Basically I'm stuck at receiving, I'm not sure if I have to put the pingval in a struct with the header, msgid and length. Or if I'm even receiving correctly, but if I'm doing anything wrong help is appreciated.

So if you can steer me in the right direction, I'd appreciated that.

[code]#pragma comment(lib, "Ws2_32.lib")
#include <windows.h>
#include <winsock.h>
#include <string>
#include <iostream>
using namespace std;

int main(){
  WSADATA wsaData;

  WSAStartup(MAKEWORD(2,0), &wsaData);

  LPHOSTENT host;

  host = gethostbyname("asia.battle.net");

  if (!host)
  {
     MessageBox(NULL, "Host error", "", MB_OK);
     WSACleanup();
     return 0;
  }

  SOCKET theSocket;
  SOCKET theBnet;

  theSocket = socket(AF_INET,
                 SOCK_STREAM,
                 IPPROTO_TCP);

  theBnet = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

  if (theSocket == INVALID_SOCKET)
  {
     MessageBox(NULL, "theSocket bad...", "", MB_OK);
     WSACleanup();
     return 0;
  }

  if (theBnet == INVALID_SOCKET)
  {
  MessageBox(NULL, "Bnet socket bad...", "", MB_OK);
  WSACleanup();
  return 0;
  }

  SOCKADDR_IN info;

  info.sin_family = AF_INET;
  info.sin_addr = *((LPIN_ADDR)*host->h_addr_list);
  info.sin_port = htons(6112);

  int con;
  con = connect(theSocket, (LPSOCKADDR)&info, sizeof(info));

  if (con == SOCKET_ERROR)
  {
     MessageBox(NULL, (LPCSTR)WSAGetLastError(), "", MB_OK);
     WSACleanup();
     return 0;
  }

  struct SID_AUTH_INFO {
     BYTE   Header;
     BYTE   MsgID;
     WORD   wLen;
     DWORD   ProtocolID;
     DWORD   PlatformID;
     DWORD   ProductID;
     DWORD   VerByte;
     DWORD   ProductLang;
     DWORD   LocalIP;
     DWORD   TimeZone;
     DWORD   LocaleID;
     DWORD   LangID;
     char   CountryAbr[4];
     char   Country[10];
  } Packet;
 
  Packet.Header      = 0xFF;
  Packet.MsgID      = 0x50;
  Packet.wLen         = sizeof(SID_AUTH_INFO);
  Packet.ProtocolID   = 0x0;
  Packet.PlatformID   = '68XI';
  Packet.ProductID   = 'DV2D';
  Packet.VerByte      = 0x0D;
  Packet.ProductLang   = 0;
  Packet.LocalIP      = inet_addr("192.168.1.100");
  Packet.TimeZone      = 600;
  Packet.LocaleID      = 0;
  Packet.LangID      = (DWORD)GetUserDefaultLangID();
  strcpy(Packet.CountryAbr, "Aus");
  strcpy(Packet.Country, "Australia");

  DWORD PingVal;

  bind(theBnet, (LPSOCKADDR)&info, sizeof(info));

  cout << "Sending 0x50... " << send(theSocket, (const char*)&Packet, sizeof(SID_AUTH_INFO), NULL) << " bytes sent\n\n";

  recv(theBnet, (char *)&PingVal, sizeof(PingVal), NULL);

  cout << PingVal;

  // for testing purposes
  char n;
  cin >> n;
  closesocket(theBnet);
  closesocket(theSocket);
  return 0;
}[/code]
March 27, 2010, 8:25 AM
BreW
[quote author=Trunning link=topic=18199.msg184384#msg184384 date=1269678327]
Basically I'm stuck at receiving, I'm not sure if I have to put the pingval in a struct with the header, msgid and length. Or if I'm even receiving correctly, but if I'm doing anything wrong help is appreciated.

So if you can steer me in the right direction, I'd appreciated that.

[code]#pragma comment(lib, "Ws2_32.lib")
#include <windows.h>
#include <winsock.h>
#include <string>
#include <iostream>
using namespace std;

int main(){
  WSADATA wsaData;

  WSAStartup(MAKEWORD(2,0), &wsaData);

  LPHOSTENT host;

  host = gethostbyname("asia.battle.net");

  if (!host)
  {
     MessageBox(NULL, "Host error", "", MB_OK);
     WSACleanup();
     return 0;
  }

  SOCKET theSocket;
  SOCKET theBnet;

  theSocket = socket(AF_INET,
                 SOCK_STREAM,
                 IPPROTO_TCP);

  theBnet = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

  if (theSocket == INVALID_SOCKET)
  {
     MessageBox(NULL, "theSocket bad...", "", MB_OK);
     WSACleanup();
     return 0;
  }

  if (theBnet == INVALID_SOCKET)
  {
  MessageBox(NULL, "Bnet socket bad...", "", MB_OK);
  WSACleanup();
  return 0;
  }

  SOCKADDR_IN info;

  info.sin_family = AF_INET;
  info.sin_addr = *((LPIN_ADDR)*host->h_addr_list);
  info.sin_port = htons(6112);

  int con;
  con = connect(theSocket, (LPSOCKADDR)&info, sizeof(info));

  if (con == SOCKET_ERROR)
  {
     MessageBox(NULL, (LPCSTR)WSAGetLastError(), "", MB_OK);
     WSACleanup();
     return 0;
  }

  struct SID_AUTH_INFO {
     BYTE   Header;
     BYTE   MsgID;
     WORD   wLen;
     DWORD   ProtocolID;
     DWORD   PlatformID;
     DWORD   ProductID;
     DWORD   VerByte;
     DWORD   ProductLang;
     DWORD   LocalIP;
     DWORD   TimeZone;
     DWORD   LocaleID;
     DWORD   LangID;
     char   CountryAbr[4];
     char   Country[10];
  } Packet;
 
  Packet.Header      = 0xFF;
  Packet.MsgID      = 0x50;
  Packet.wLen         = sizeof(SID_AUTH_INFO);
  Packet.ProtocolID   = 0x0;
  Packet.PlatformID   = '68XI';
  Packet.ProductID   = 'DV2D';
  Packet.VerByte      = 0x0D;
  Packet.ProductLang   = 0;
  Packet.LocalIP      = inet_addr("192.168.1.100");
  Packet.TimeZone      = 600;
  Packet.LocaleID      = 0;
  Packet.LangID      = (DWORD)GetUserDefaultLangID();
  strcpy(Packet.CountryAbr, "Aus");
  strcpy(Packet.Country, "Australia");

  DWORD PingVal;

  bind(theBnet, (LPSOCKADDR)&info, sizeof(info));

  cout << "Sending 0x50... " << send(theSocket, (const char*)&Packet, sizeof(SID_AUTH_INFO), NULL) << " bytes sent\n\n";

  recv(theBnet, (char *)&PingVal, sizeof(PingVal), NULL);

  cout << PingVal;

  // for testing purposes
  char n;
  cin >> n;
  closesocket(theBnet);
  closesocket(theSocket);
  return 0;
}[/code]
[/quote]

Lots of problems here.
The first thing that jumped out at me was the fact that your packet IDs are backwards... why? 'VD2D', '68XI', etc. The ill-gotten advice to write IDs backwards originated from the fact that nearly all bot 'developers' used VB6, and inserted that data as a binary string. You obviously don't do this since it's stored in that struct little-endian (I assume you're using a little-endian platform).
The next problem - you don't ever send the data! Before doing that, however, note that a single identification byte of 0x01 with no header of any sort must be sent after connection and before all other battle.net traffic.
Also, your size parameter is wrong. It includes the length of the header (4), and the length of the strings are not usually constant. You're just getting away with it for this packet because there's no variation from logon to logon.
Why are you recving on a different socket? theBnet is not in the connected state.



You might want to look into a basic socket tutorial.
March 27, 2010, 1:40 PM
Trunning
Based on everything you said I changed as much as I could. I'm still not getting any data back.

[code]#pragma comment(lib, "Ws2_32.lib")
#include <windows.h>
#include <winsock.h>
#include <string>
#include <iostream>
using namespace std;

int main(){
struct SID_AUTH_INFO {
BYTE   Header;
BYTE   MsgID;
WORD   wLen;
DWORD   ProtocolID;
DWORD   PlatformID;
DWORD   ProductID;
DWORD   VerByte;
DWORD   ProductLang;
DWORD   LocalIP;
DWORD   TimeZone;
DWORD   LocaleID;
DWORD   LangID;
char   CountryAbr[4];
char   Country[10];
} Packet;
   
Packet.Header      = 0xFF;
Packet.MsgID      = 0x50;
Packet.ProtocolID   = 0x0;
Packet.PlatformID   = 'IX86';
Packet.ProductID   = 'D2DV';
Packet.VerByte      = 0x0D;
Packet.ProductLang   = 0;
Packet.LocalIP      = inet_addr("192.168.1.100");
Packet.TimeZone      = 600;
Packet.LocaleID      = 0;
Packet.LangID      = (DWORD)GetUserDefaultLangID();
Packet.wLen         = sizeof(SID_AUTH_INFO);
strcpy(Packet.CountryAbr, "Aus");
strcpy(Packet.Country, "Australia");
int size = sizeof((Packet.MsgID) & (Packet.ProtocolID) & (Packet.PlatformID) & (Packet.ProductID) & (Packet.VerByte) & (Packet.ProductLang) & (Packet.LocalIP) & (Packet.TimeZone) & (Packet.LocaleID) & (Packet.LangID) );
DWORD Pre = 0x01;

DWORD PingVal;

int con;
WSADATA wsaData;

WSAStartup(MAKEWORD(2,0), &wsaData);

LPHOSTENT host;

host = gethostbyname("useast.battle.net");

if (!host)
{
  MessageBox(NULL, "Host error", "", MB_OK);
  WSACleanup();
  return 0;
}

SOCKET theSocket;

theSocket = socket(AF_INET,
  SOCK_STREAM,
  IPPROTO_TCP);

if (theSocket == INVALID_SOCKET)
{
  MessageBox(NULL, "theSocket bad...", "", MB_OK);
  WSACleanup();
  return 0;
}

SOCKADDR_IN info;

info.sin_family = AF_INET;
info.sin_addr = *((LPIN_ADDR)*host->h_addr_list);
info.sin_port = htons(6112);

con = connect(theSocket, (LPSOCKADDR)&info, sizeof(info));

if (con == SOCKET_ERROR)
{
  MessageBox(NULL, (LPCSTR)WSAGetLastError(), "", MB_OK);
  WSACleanup();
  return 0;
}

cout << "Sending 0x01...\n";
con = send(theSocket, (const char*)&Pre, sizeof(Pre), NULL);
if (con > 0){
cout << con << " bytes sent\n";
} else {
cout << "Nothing sent!\n";
}

cout << "Sending 0x50...\n";
con = send(theSocket, (const char*)&Packet, size, NULL);
if ( con > 0 ){
   cout << con << " bytes sent\n";
} else {
   cout << "Nothing sent!\n";
}

/*
con = bind(theSocket, (LPSOCKADDR)&info, sizeof(info));
if (con == SOCKET_ERROR){
cout << WSAGetLastError();

int n;
cin >>n;
WSACleanup();
return 0;
}*/

listen(theSocket, 2);
con = recv(theSocket, (char*)&PingVal, sizeof(PingVal), NULL);
if (con > 0){
cout << "Ping cookie: " << PingVal;
} else {
cout << "Nothing received!\n";
}

// for testing purposes
char n;
cin >> n;
closesocket(theSocket);
return 0;
}[/code]
March 28, 2010, 2:08 AM
BreW
[quote author=Trunning link=topic=18199.msg184393#msg184393 date=1269742117]
Based on everything you said I changed as much as I could. I'm still not getting any data back.

[code]...
DWORD Pre = 0x01;
...
[/code]
[/quote]


[quote author=brew link=topic=18199.msg184385#msg184385 date=1269697229]
note that a single identification byte of 0x01
[/quote]

Also, keep in mind that the response is an 0x25 packet with the standard BNCS header, that just happens to contain a single dword of the ping value.

I strongly suggest you generalize your code more.
March 28, 2010, 3:15 AM
Trunning
I changed Pre to a byte, still not receiving anything. And I'll organize it more when I've got working code.
March 28, 2010, 4:39 AM
Yegg
Maybe I'm not adding anything here that directly solves your issue, but this can be very helpful. I have not taken a look at your code (just briefly), but have you monitored network data being sent to and from the Bnet server while running your code?
Since it seems you're new to this area of programming (or, computers, really), you'll need a packet logger (maybe you already know this).

Install Wireshark: http://www.wireshark.org/download.html

There's nothing you need to set up in the program. Simply select your network interface you wish to monitor (it will list the network devices that are connected to your pc -- such as Ethernet). You'll want to add a filter so that it reports packets of data that are to or from the server you are connecting to ("useast.battle.net" for instance). If you dont filter it this way, you will hundreds of other packets being listed on the Wireshark window immediately and you wont be able to find your Battle.net ones.

Again, while this isn't directly solving your issue, you can't possibly know exactly what is happening on the network when your code is executed, by just looking at the console or GUI to your program. At least if you saw what a packet logger sees, it may help you out in a few areas. For all you know, certain data has been sent but your program failed to display it on the screen for one reason or another (of course, this is just a stab in the dark). In any event.. it's extremely useful to know how to effectively use a packet logger when getting into any kind of network related programming.

Try out Wireshark, do as I mentioned, and see what you may or may not be able to figure out with it.

If you need help, you can of course ask me or someone else here (I'm also sure most programmers here can or do use Wireshark).
March 28, 2010, 6:32 AM
Trunning
I'm not new to computers or C++, just combining C++ and Battle.net.

And I've got Wireshark already. I checked what the client Diablo 2 sent, and then my program, the start is different. I was hoping someone would tell me what I'm doing wrong.
March 28, 2010, 6:41 AM
BreW
[quote author=Trunning link=topic=18199.msg184397#msg184397 date=1269758465]
I'm not new to computers or C++, just combining C++ and Battle.net.

And I've got Wireshark already. I checked what the client Diablo 2 sent, and then my program, the start is different. I was hoping someone would tell me what I'm doing wrong.
[/quote]

Well, in your latest rendition of your code, you seemed to have omitted the size field of the header entirely. The length is a 16 little-endian int which is equal to the length of the data you're sending, minus the size of the standard BNCS header, which is 4. In other words

[code]
Packet.wLen         = sizeof(SID_AUTH_INFO);
[/code]

is wrong.

Why are you still doing that, you said you fixed it in your earlier post? You don't get any data because it's expecting 4 more bytes than you're sending it.


P.S.
You really don't that call to bind(). That socket is already 'bound' to that connection.
March 28, 2010, 12:52 PM
Trunning
Ok this isn't working, how about you just fix my code, then I can learn from that.

[code]#pragma comment(lib, "Ws2_32.lib")
#include <windows.h>
#include <winsock.h>
#include <string>
#include <iostream>
using namespace std;

int main(){
struct SID_AUTH_INFO {
BYTE  Header;
BYTE  MsgID;
WORD  wLen;
DWORD  ProtocolID;
DWORD  PlatformID;
DWORD  ProductID;
DWORD  VerByte;
DWORD  ProductLang;
DWORD  LocalIP;
DWORD  TimeZone;
DWORD  LocaleID;
DWORD  LangID;
char  CountryAbr[4];
char  Country[10];
} Packet;
 
Packet.Header      = 0xFF;
Packet.MsgID      = 0x50;
Packet.ProtocolID  = 0x0;
Packet.PlatformID  = 'IX86';
Packet.ProductID  = 'D2DV';
Packet.VerByte      = 0x0D;
Packet.ProductLang  = 0;
Packet.LocalIP      = inet_addr("192.168.1.100");
Packet.TimeZone      = 600;
Packet.LocaleID      = 0;
Packet.LangID      = (DWORD)GetUserDefaultLangID();
Packet.wLen        = sizeof(SID_AUTH_INFO);
strcpy(Packet.CountryAbr, "Aus");
strcpy(Packet.Country, "Australia");
int size = sizeof((Packet.MsgID) & (Packet.ProtocolID) & (Packet.PlatformID) & (Packet.ProductID) & (Packet.VerByte) & (Packet.ProductLang) & (Packet.LocalIP) & (Packet.TimeZone) & (Packet.LocaleID) & (Packet.LangID) );
DWORD Pre = 0x01;

BYTE PingVal;

int con;
WSADATA wsaData;

WSAStartup(MAKEWORD(2,0), &wsaData);

LPHOSTENT host;

host = gethostbyname("useast.battle.net");

if (!host)
{
  MessageBox(NULL, "Host error", "", MB_OK);
  WSACleanup();
  return 0;
}

SOCKET theSocket;

theSocket = socket(AF_INET,
  SOCK_STREAM,
  IPPROTO_TCP);

if (theSocket == INVALID_SOCKET)
{
  MessageBox(NULL, "theSocket bad...", "", MB_OK);
  WSACleanup();
  return 0;
}

SOCKADDR_IN info;

info.sin_family = AF_INET;
info.sin_addr = *((LPIN_ADDR)*host->h_addr_list);
info.sin_port = htons(6112);

con = connect(theSocket, (LPSOCKADDR)&info, sizeof(info));

if (con == SOCKET_ERROR)
{
  MessageBox(NULL, (LPCSTR)WSAGetLastError(), "", MB_OK);
  WSACleanup();
  return 0;
}

cout << "Sending 0x01...\n";
con = send(theSocket, (const char*)&Pre, sizeof(Pre), NULL);
if (con > 0){
cout << con << " bytes sent\n";
} else {
cout << "Nothing sent!\n";
}

cout << "Sending 0x50...\n";
con = send(theSocket, (const char*)&Packet, size, NULL);
if ( con > 0 ){
  cout << con << " bytes sent\n";
} else {
  cout << "Nothing sent!\n";
}

con = recv(theSocket, (char*)&PingVal, sizeof(PingVal), NULL);
if (con > 0){
cout << "Ping cookie: " << PingVal;
break;
}

// for testing purposes
char n;
cin >> n;
closesocket(theSocket);
return 0;
}[/code]
March 28, 2010, 4:09 PM
rabbit
I suggest you look into using a packet buffer class ("DM's packet buffer" seems to be popular).  It will allow you to construct packets in a generalized fashion and you won't have to create a struct for each packet.

Anyway, with your code, you declare and set variable size, but nowhere do I see "Packet.wLen = size", so your packet header says the packet's length is 0.
March 28, 2010, 5:37 PM
BreW
[code]#pragma comment(lib, "Ws2_32.lib")
#include <windows.h>
#include <winsock.h>
#include <string>
#include <iostream>
using namespace std;

int main(){
struct SID_AUTH_INFO {
BYTE   Header;
BYTE   MsgID;
WORD   wLen;
DWORD   ProtocolID;
DWORD   PlatformID;
DWORD   ProductID;
DWORD   VerByte;
DWORD   ProductLang;
DWORD   LocalIP;
DWORD   TimeZone;
DWORD   LocaleID;
DWORD   LangID;
char   CountryAbr[4];
char   Country[10];
} Packet;
 
Packet.Header      = 0xFF;
Packet.MsgID      = 0x50;
Packet.ProtocolID   = 0x0;
Packet.PlatformID   = 'IX86';
Packet.ProductID   = 'D2DV';
Packet.VerByte      = 0x0D;
Packet.ProductLang   = 0;
Packet.LocalIP      = inet_addr("192.168.1.100");
Packet.TimeZone      = 600;
Packet.LocaleID      = 0;
Packet.LangID      = (DWORD)GetUserDefaultLangID();
Packet.wLen         = sizeof(SID_AUTH_INFO) - 4;
strcpy(Packet.CountryAbr, "Aus");
strcpy(Packet.Country, "Australia");
/*int size = sizeof((Packet.MsgID) & (Packet.ProtocolID) & (Packet.PlatformID) & (Packet.ProductID) & (Packet.VerByte) & (Packet.ProductLang) & (Packet.LocalIP) & (Packet.TimeZone) & (Packet.LocaleID) & (Packet.LangID) );
DWORD Pre = 0x01;*/

BYTE PingPacket[8];

int con;
WSADATA wsaData;

WSAStartup(MAKEWORD(2,0), &wsaData);

LPHOSTENT host;

host = gethostbyname("useast.battle.net");

if (!host)
{
 MessageBox(NULL, "Host error", "", MB_OK);
 WSACleanup();
 return 0;
}

SOCKET theSocket;

theSocket = socket(AF_INET,
 SOCK_STREAM,
 IPPROTO_TCP);

if (theSocket == INVALID_SOCKET)
{
 MessageBox(NULL, "theSocket bad...", "", MB_OK);
 WSACleanup();
 return 0;
}

SOCKADDR_IN info;

info.sin_family = AF_INET;
info.sin_addr = *((LPIN_ADDR)*host->h_addr_list);
info.sin_port = htons(6112);

con = connect(theSocket, (LPSOCKADDR)&info, sizeof(info));

if (con == SOCKET_ERROR)
{
 MessageBox(NULL, (LPCSTR)WSAGetLastError(), "", MB_OK);
 WSACleanup();
 return 0;
}

cout << "Sending 0x01...\n";
con = send(theSocket, "\x01", 1, NULL); //look at this, you're sending _1_ byte. nothing more.
if (con > 0){
cout << con << " bytes sent\n";
} else {
cout << "Nothing sent!\n";
}

cout << "Sending 0x50...\n";
con = send(theSocket, (const char*)&Packet, sizeof(SID_AUTH_INFO) - 4, NULL);
if ( con > 0 ){
  cout << con << " bytes sent\n";
} else {
  cout << "Nothing sent!\n";
}

con = recv(theSocket, PingPacket, sizeof(PingPacket), NULL);
if (con > 0){
cout << "Ping cookie: " << *(unsigned __int32 *)(PingPacket + 4);
break; //what does break; do here, in an if statement?
}

// for testing purposes
char n;
cin >> n;
closesocket(theSocket);
return 0;
}[/code]

I feel that I have made myself more than perfectly clear in the previous posts. Even after observing the logon sequence for yourself via a packet capture device, it seems you've failed to grasp the concept of what is supposed to be sent and what is supposed to be received.
Are you entirely certain that you have a solid grasp on coding with C/++?

@rabbit: I don't see what's wrong with his method of packet construction. If he didn't include the header with the actual packet's struct, it would work out nicely. In fact, this is the way Blizzard coded the packet construction in their batle.snp (not with a packet buffer, *gasp*)
March 28, 2010, 8:46 PM
rabbit
And?  I'm saying it'd be easier to get help if he used a packet buffer because more people do it that way, so more people know the pitfalls and benefits.
March 28, 2010, 9:01 PM
HdxBmx27
Alright, well when it comes to Bnet packets, Blizzard does indeed use structs themselves, but Rabbit is correct. Most people here are used to using Buffer classes. And with computer processing power so cheap it's usefull to make a Buffer class. BUT! If you're working in a language that allows you such a low level access to memory as C, then you can do a hybrid if you are fancy enough.

As for your current problem. Structure should not be an after thaught, if you do things correctly. You may never have to touch a peice of code again. And it will make your life easier to work in chunks.

The basic 'connection' function for me looks like this:
[code]Create Socket
If (SocketConnect()){
  Send Protocol Byte
  Send First Packets
  while(SocketConnected){
    Read Header
    Read Body
    Call Packet Handeling Function
  }
}[/code]As you can see the psudo-function is rather small, and easy to maintain. Right now seince it looks like you are realy new to sockets. I'd go this route. So for your code:
[code]
struct BNCS_HEADER{
  BYTE Sanity;
  BYTE ID;
  WORD Length;
};

struct SID_AUTH_INFO {
  BNCS_HEADER Header;
  DWORD  ProtocolID;
  DWORD  PlatformID;
  DWORD  ProductID;
  DWORD  VerByte;
  DWORD  ProductLang;
  DWORD  LocalIP;
  DWORD  TimeZone;
  DWORD  LocaleID;
  DWORD  LangID;
  char  CountryInfo[0x100]; //Allocate enough for any country info.
};


int main(){
WSADATA wsaData;                                              \
WSAStartup(MAKEWORD(2,0), &wsaData);                          |
                                                                |
  SOCKET sockBNCS = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);  |
  if(sockBNCS == INVALID_SOCKET){                                | Create the socket
    printf("Could not create BNCS Socket\n");                    |
    WSACleanup();                                                |
    return -1;                                                  |
  }                                                            /
 
  if(socket_connect(sockBNCS, "useast.battle.net", 6112) == 0){ //Connect Socket
    int sent;
   
    printf("Sending Protocol Byte 0x01\n"); \
    sent = send(sockBNCS, '\x01', 1, NULL);  |
    if(sent > 0){                            |
      printf("Sent %d byte(s)\n", sent);    | Send Protocol Byte
    }else{                                  |
      printf("Sending Failed!\n");          |
    }                                      /
   
    send_SID_AUTH_INFO(sockBNCS); //Send First Packet

    BNCS_HEADER header; //This is the data to hold incoming packet information
    void *data = malloc(0x200); //This will hold the actual data of a packet, this is whats sent to the handler.
    int data_max = 0x200;
   
    while(true){ //While Socket Connected
      sent = recv(sockBNCS, &header, sizeof(header), NULL); \
      if(sent != sizeof(header)){                            |
        printf("Did not receive full header!\n");            |
        WSACleanup();                                        | Read the Header
        return -1;                                          |
      }                                                    /
     
      if(header.Length - 4 > data_max){  \
        free(data);                      | Reallocated space for the packet body, if necessary
        data = malloc(header.Length - 4); |
      }                                  /
     
      sent = recv(sockBNCS, &data, header.Length - 4); \
      if(sent != header.Length - 4){                    |
        printf("Could not read packet data!\n");        | Receive Body
        WSACleanup();                                  |
        return -1;                                      |
      }                                                /
     
      switch(header.ID){                                          \
        case 0x25: process_SID_PING(data, header.Length - 4);      |
        case 0x50: process_SID_AUTH_INFO(data, header.Length - 4); | Call Packet Handler Function
        ....                                                      |
      }                                                          /
    }
   
  }
  WSACleanup();
  return 0;
}

int socket_connect(SOCKET sockBNCS, const char *Server, WORD Port){
LPHOSTENT host = gethostbyname(Server);

if (!host){
    printf("Could not resolve host for %s\n", Server);
  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){
    printf("Could not connect to %s:%d Error: %d\n", Server, Port, WSAGetLastError());
  return -1;
}
  return 0;
}

int send_SID_AUTH_INFO(SOCKET sockBNCS){
  SID_AUTH_INFO pkt;
  int AbbrLen, NameLen, sent;
  memset(&pkt, 0, sizeof(SID_AUTH_INFO)); //If you don't do this, the pkt could have random info.
 
  pkt.ProtocolID  = 0x00;
  pkt.PlatformID  = 'IX86';
  pkt.ProductID  = 'D2DV';
  pkt.VerByte    = 0x0D;
  pkt.ProductLang = 0x00;
  pkt.LocalIP    = inet_addr("192.168.1.100");
  pkt.TimeZone    = 600;
  pkt.LocaleID    = 0x00;
  pkt.LangID      = (DWORD)GetUserDefaultLangID();
  AbbrLen = strcpy(&pkt.CountryInfo[0], "AUS"); //I *think* strcpy() returns the number of bytes copied, can't remember
  NameLen = strcpy(&pkt.CountryInfo[AbbrLen + 1], "Australia");
 
  pkt.Header.Sanity = 0xFF;
  pkt.Header.ID    = 0x50;
  pkt.Header.Length =  4      //Header Length
                    + (4 * 9) //Number of DWORDs in the packet
                    + AbbrLen //Abbreviation Length
                    + 1      //Null Terminator
                    + NameLen //Country Name Length
                    + 1;      //Null Terminator
  printf("Sending %d bytes for 0x50 SID_AUTH_INFO\n", pkt.Header.Length);
  sent = send(sockBNCS, &pkt, pkt.Header.Length, NULL);
  if(sent > 0){
    printf("Sent %d bytes\n", sent);
  }else{
    printf("Sending failed!\n");
  }
  return 0;
}[/code]Anyways  this code does no work obviously, but if you tweak it you can get it working
March 28, 2010, 10:29 PM
rabbit
Shouldn't it be SOCKET &sockBNCS in those functions?
March 28, 2010, 11:01 PM
HdxBmx27
maybe, but a SOCKET is simply a ID number of the socket (AE a HANDLE) so meh. As I said the code doesnt work. It simply shows a concept of the design/layout.
March 28, 2010, 11:04 PM
Trunning
@Brew
Removed the break, that was there from earlier experimentation, the if statement was in a while loop. And I'm still not receving anything with your code.
March 29, 2010, 4:02 AM
BreW
[quote author=Trunning link=topic=18199.msg184418#msg184418 date=1269835374]
@Brew
Removed the break, that was there from earlier experimentation, the if statement was in a while loop. And I'm still not receving anything with your code.
[/quote]

Ooops, my mistake!
Remove the -4 from the third parameter of the second send(). That should do it.
March 29, 2010, 4:58 AM
Trunning
Done that, still nothing.

[code]#pragma comment(lib, "Ws2_32.lib")
#include <windows.h>
#include <winsock.h>
#include <string>
#include <iostream>
using namespace std;

int main(){
struct SID_AUTH_INFO {
BYTE  Header;
BYTE  MsgID;
WORD  wLen;
DWORD  ProtocolID;
DWORD  PlatformID;
DWORD  ProductID;
DWORD  VerByte;
DWORD  ProductLang;
DWORD  LocalIP;
DWORD  TimeZone;
DWORD  LocaleID;
DWORD  LangID;
char  CountryAbr[4];
char  Country[10];
} Packet;
 
Packet.Header      = 0xFF;
Packet.MsgID      = 0x50;
Packet.ProtocolID  = 0x0;
Packet.PlatformID  = 'IX86';
Packet.ProductID  = 'D2DV';
Packet.VerByte      = 0x0D;
Packet.ProductLang  = 0;
Packet.LocalIP      = inet_addr("192.168.1.100");
Packet.TimeZone      = 600;
Packet.LocaleID      = 0;
Packet.LangID      = (DWORD)GetUserDefaultLangID();
Packet.wLen        = sizeof(SID_AUTH_INFO) - 4;
strcpy(Packet.CountryAbr, "Aus");
strcpy(Packet.Country, "Australia");
/*int size = sizeof((Packet.MsgID) & (Packet.ProtocolID) & (Packet.PlatformID) & (Packet.ProductID) & (Packet.VerByte) & (Packet.ProductLang) & (Packet.LocalIP) & (Packet.TimeZone) & (Packet.LocaleID) & (Packet.LangID) );
DWORD Pre = 0x01;*/

BYTE PingPacket[8];

int con;
WSADATA wsaData;

WSAStartup(MAKEWORD(2,0), &wsaData);

LPHOSTENT host;

host = gethostbyname("useast.battle.net");

if (!host)
{
  MessageBox(NULL, "Host error", "", MB_OK);
  WSACleanup();
  return 0;
}

SOCKET theSocket;

theSocket = socket(AF_INET,
  SOCK_STREAM,
  IPPROTO_TCP);

if (theSocket == INVALID_SOCKET)
{
  MessageBox(NULL, "theSocket bad...", "", MB_OK);
  WSACleanup();
  return 0;
}

SOCKADDR_IN info;

info.sin_family = AF_INET;
info.sin_addr = *((LPIN_ADDR)*host->h_addr_list);
info.sin_port = htons(6112);

con = connect(theSocket, (LPSOCKADDR)&info, sizeof(info));

if (con == SOCKET_ERROR)
{
  MessageBox(NULL, (LPCSTR)WSAGetLastError(), "", MB_OK);
  WSACleanup();
  return 0;
}

cout << "Sending 0x01...\n";
con = send(theSocket, "\x01", 1, NULL); //look at this, you're sending _1_ byte. nothing more.
if (con > 0){
cout << con << " bytes sent\n";
} else {
cout << "Nothing sent!\n";
}

cout << "Sending 0x50...\n";
con = send(theSocket, (const char*)&Packet, sizeof(SID_AUTH_INFO), NULL);
if ( con > 0 ){
  cout << con << " bytes sent\n";
} else {
  cout << "Nothing sent!\n";
}

con = recv(theSocket, (char*)&PingPacket, sizeof(PingPacket), NULL);
if (con > 0){
cout << "Ping cookie: " << *(unsigned __int32 *)(PingPacket + 4);
}

// for testing purposes
char n;
cin >> n;
closesocket(theSocket);
return 0;
}[/code]
March 29, 2010, 6:14 AM
rabbit
Check your packet log.  Are you sure the typecast of your packet struct is working properly?
March 29, 2010, 8:12 AM
HdxBmx27
btw, I was waiting for brew to correct himself, but the Length in the packet Header INCLUDES the fucking header!
Anyways, as a side note, you are not guaranteed to get SID_PING before you get SID_AUTH_INFO back (you usually do but still)

Clean your code, test each section, use wireshark to see whats actually being sent. And it should be easy to get it working. Did you just gloss over my post because it wasn't copy/paste code?
And your table breakage is annoying!
March 29, 2010, 8:22 AM
Trunning
I looked at your code, but I really wanted to fix mine.
March 29, 2010, 8:39 AM
BreW
[quote author=Hdx link=topic=18199.msg184424#msg184424 date=1269850938]
btw, I was waiting for brew to correct himself, but the Length in the packet Header INCLUDES the fucking header!
[/quote]

Yes. Wow... I screwed up twice in the same post. I've forgotten a bunch about the BNCS protocol over the years. It makes me feel pretty bad that I'm giving this guy bad advice, thanks for pointing that out though, Hdx.

Oh well, who cares? Bnet2 is where it's at! :P
This guy is just probably trying to make a D2-run "clientless" bot in order to sell items, like the thousands of others....
March 29, 2010, 4:22 PM
Trunning
Are you serious? My final goal was just logging into the chat room.
March 30, 2010, 1:01 AM
HdxBmx27
Just read my code. Understand what i'm saying, and you would have working code days ago. As for wanting to get 'your code working' most of what I posted was your code, just reorganized.
Well, you could write a connection in a single function, but it would just be a huge headache and be annoying.
March 30, 2010, 7:14 PM
Trunning
Ok I ran through your code best I could, and came up with this. And strcpy doesn't return the bytes copied, it returns the destination string, according to MSDN. Anyway, with the following code, I'm still not receiving anything.

[code]#pragma comment(lib, "Ws2_32.lib")
#include <stdio.h>
#include <winsock.h>
#include <windows.h>

int socket_connect(SOCKET sockBNCS, const char *Server, WORD Port);
int send_SID_AUTH_INFO(SOCKET sockBNCS);

struct BNCS_HEADER {
BYTE Sanity;
BYTE ID;
WORD Length;
};

struct SID_AUTH_INFO {
BNCS_HEADER Header;
DWORD  ProtocolID;
DWORD  PlatformID;
DWORD  ProductID;
DWORD  VerByte;
DWORD  ProductLang;
DWORD  LocalIP;
DWORD  TimeZone;
DWORD  LocaleID;
DWORD  LangID;
char  CountryInfo[0x100];
};

int main(){
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 0), &wsaData);

SOCKET sockBNCS = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockBNCS == INVALID_SOCKET){
MessageBox(NULL, "Error -> Invalid Socket!", "", MB_OK);
closesocket(sockBNCS);
WSACleanup();
return 0;
}

int sent;
if (socket_connect(sockBNCS, "useast.battle.net", 6112) == 0){

printf("Sending Protocol Byte 0x01\n");
sent = send(sockBNCS, (const char*)'\x01', 1, NULL);
if (sent > 0){
printf("Sent %d bytes\n", sent);
} else if (sent == 0) {
printf("Failed to send protocol byte!");
}
}

send_SID_AUTH_INFO(sockBNCS);

BNCS_HEADER header; // hold incoming data
void *data = malloc(0x200);
int data_max = 0x200;

while(true){
sent = recv(sockBNCS, (char*)&header, sizeof(header), NULL);
if (sent != sizeof(header)){
printf("Didn't receive full header!\n");
}
}

if (header.Length - 4 > data_max){
free(data);
data = malloc(header.Length - 4);
}

sent = recv(sockBNCS, (char*)&data, header.Length -4, NULL);
if (sent != header.Length - 4){
printf("Could not read packet data!");
}

switch (header.ID){
case 0x25:
printf("We got 0x25!\n");
case 0x50:
printf("We got 0x50!\n");
}

WSACleanup();
closesocket(sockBNCS);
system("pause");
return 0;
}

int socket_connect(SOCKET sockBNCS, const char *Server, WORD Port){
LPHOSTENT host = gethostbyname(Server);

if (!host){
MessageBox(NULL, "Error -> Host", "", MB_OK);
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){
MessageBox(NULL, (LPCSTR)WSAGetLastError(), "", MB_OK);
return -1;
}
return 0;
}

int send_SID_AUTH_INFO(SOCKET sockBNCS){
  SID_AUTH_INFO pkt;
  int AbbrLen, NameLen, sent;
  memset(&pkt, 0, sizeof(SID_AUTH_INFO)); //If you don't do this, the pkt could have random info.
 
  pkt.ProtocolID  = 0x00;
  pkt.PlatformID  = 'IX86';
  pkt.ProductID  = 'D2DV';
  pkt.VerByte    = 0x0D;
  pkt.ProductLang = 0x00;
  pkt.LocalIP    = inet_addr("192.168.1.100");
  pkt.TimeZone    = 600;
  pkt.LocaleID    = 0x00;
  pkt.LangID      = (DWORD)GetUserDefaultLangID();
  strcpy(&pkt.CountryInfo[0], "AUS"); //I *think* strcpy() returns the number of bytes copied, can't remember
  AbbrLen = sizeof(pkt.CountryInfo[0]);
  strcpy(&pkt.CountryInfo[AbbrLen + 1], "Australia");
  NameLen = sizeof(pkt.CountryInfo[AbbrLen + 1]);
 
  pkt.Header.Sanity = 0xFF;
  pkt.Header.ID    = 0x50;
  pkt.Header.Length =  4      //Header Length
                    + (4 * 9) //Number of DWORDs in the packet
                    + AbbrLen //Abbreviation Length
                    + 1      //Null Terminator
                    + NameLen //Country Name Length
                    + 1;      //Null Terminator
  printf("Sending %d bytes for 0x50 SID_AUTH_INFO\n", pkt.Header.Length);
  sent = send(sockBNCS, (const char*)&pkt, pkt.Header.Length, NULL);
  if(sent > 0){
    printf("Sent %d bytes\n", sent);
  }else{
    printf("Sending failed!\n");
  }
  return 0;
}[/code]
March 30, 2010, 9:05 PM
dRAgoN
Just a thought, have you set any break points to see if its even getting to the packet send?
yeah ive neglected to read the entire thread sue me, if you are connected you will still recieve SID_NULL, side note if you havent sent nothing you also wont recieve nothing besides SID_NULL unless ofcorse you are ipbanned.
March 31, 2010, 5:45 AM
HdxBmx27
you fucked up the while(true) loop, it should include everything up to the WSACleanup() at the end.
Also, everything except for the stuff after WSACleanup at th end should be inside the if(socket_connect) condition. Howed you mess up the structure of the code i posted so much?
Think of it logically, why would you want to send shit if you arnt connected?
March 31, 2010, 6:35 PM
Trunning
Ah, it also looks like 01 isn't being sent, on the left is the code below, and the right is actual diablo 2 client.

[img]http://img7.imageshack.us/img7/1828/15170869.png[/img]
I put the crap into the while loop, up until the WSACleanup. And put the while loop in the if(socket_connet), and still no go. Maybe you can clean it up.

[code]#pragma comment(lib, "Ws2_32.lib")
#include <stdio.h>
#include <winsock.h>
#include <windows.h>

int socket_connect(SOCKET sockBNCS, const char *Server, WORD Port);
int send_SID_AUTH_INFO(SOCKET sockBNCS);

struct BNCS_HEADER {
BYTE Sanity;
BYTE ID;
WORD Length;
};

struct SID_AUTH_INFO {
BNCS_HEADER Header;
DWORD   ProtocolID;
DWORD   PlatformID;
DWORD   ProductID;
DWORD   VerByte;
DWORD   ProductLang;
DWORD   LocalIP;
DWORD   TimeZone;
DWORD   LocaleID;
DWORD   LangID;
char   CountryInfo[0x100];
};

int main(){
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 0), &wsaData);

SOCKET sockBNCS = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockBNCS == INVALID_SOCKET){
MessageBox(NULL, "Error -> Invalid Socket!", "", MB_OK);
closesocket(sockBNCS);
WSACleanup();
return 0;
}

int sent;
if (socket_connect(sockBNCS, "useast.battle.net", 6112) == 0){

printf("Sending Protocol Byte 0x01\n");
sent = send(sockBNCS, (const char*)'\x01', 1, NULL);
if (sent > 0){
printf("Sent %d bytes\n", sent);
} else if (sent == 0) {
printf("Failed to send protocol byte!");
}
send_SID_AUTH_INFO(sockBNCS);

BNCS_HEADER header; // hold incoming data
void *data = malloc(0x200);
int data_max = 0x200;

while(true){
sent = recv(sockBNCS, (char*)&header, sizeof(header), NULL);
if (sent != sizeof(header)){
printf("We didn't get the full header!\n");
}
if (header.Length - 4 > data_max){
free(data);
data = malloc(header.Length - 4);
}

sent = recv(sockBNCS, (char*)&data, header.Length -4, NULL);
if (sent != header.Length - 4){
printf("Could not read packet data!\n");
}

switch (header.ID){
case 0x25:
printf("We got 0x25!\n");
break;
case 0x50:
printf("We got 0x50!\n");
break;
}
}
}

WSACleanup();
closesocket(sockBNCS);
system("pause");
return 0;
}

int socket_connect(SOCKET sockBNCS, const char *Server, WORD Port){
LPHOSTENT host = gethostbyname(Server);

if (!host){
MessageBox(NULL, "Error -> Host", "", MB_OK);
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){
MessageBox(NULL, (LPCSTR)WSAGetLastError(), "", MB_OK);
return -1;
}
return 0;
}

int send_SID_AUTH_INFO(SOCKET sockBNCS){
 SID_AUTH_INFO pkt;
 int AbbrLen, NameLen, sent;
 memset(&pkt, 0, sizeof(SID_AUTH_INFO)); //If you don't do this, the pkt could have random info.
 
 pkt.ProtocolID  = 0x00;
 pkt.PlatformID  = 'IX86';
 pkt.ProductID   = 'D2DV';
 pkt.VerByte     = 0x0D;
 pkt.ProductLang = 0x00;
 pkt.LocalIP     = inet_addr("192.168.1.100");
 pkt.TimeZone    = 600;
 pkt.LocaleID    = 0x00;
 pkt.LangID      = (DWORD)GetUserDefaultLangID();
 strcpy(&pkt.CountryInfo[0], "AUS"); //I *think* strcpy() returns the number of bytes copied, can't remember
 AbbrLen = sizeof(pkt.CountryInfo[0]);
 strcpy(&pkt.CountryInfo[AbbrLen + 1], "Australia");
 NameLen = sizeof(pkt.CountryInfo[AbbrLen + 1]);
 
 pkt.Header.Sanity = 0xFF;
 pkt.Header.ID     = 0x50;
 pkt.Header.Length =  4       //Header Length
                    + (4 * 9) //Number of DWORDs in the packet
                    + AbbrLen //Abbreviation Length
                    + 1       //Null Terminator
                    + NameLen //Country Name Length
                    + 1;      //Null Terminator
 printf("Sending %d bytes for 0x50 SID_AUTH_INFO\n", pkt.Header.Length);
 sent = send(sockBNCS, (const char*)&pkt, pkt.Header.Length, NULL);
 if(sent > 0){
   printf("Sent %d bytes\n", sent);
 }else{
   printf("Sending failed!\n");
 }
 return 0;
}[/code]
April 1, 2010, 6:15 AM
rabbit
You should probably try to send 0x01 a few times and then abort the entire condition if you can't send it for some reason, since you can't do anything without it.
April 1, 2010, 7:15 AM
HdxBmx27
True, but heres the kicker, what does the console say?
If it failed to send you should see an error, and if it did send ou should see confirmation.
ALSO Don't fucking use sizeof() to get the length of a string.
strlen() is what you want. As you can see in the screen shot, you're not sending the full strings. I bet you're IP banned.
Also, use "\x1" not (const char *)'\x1', it's a faster way, and should solve your issue. (Instead of placing the value it places a pointer to your binaries data segment which is exactly what you want)

But, look at your console, see what it says.

Another question, why are you sending Australia if you are in the US?
Also, FOR THE LOVE OF GOD stop breaking tables!
April 1, 2010, 6:03 PM
Trunning
I don't play on useast.
Compiler won't let use '\x01', I have to type cast it.
I found out the error, and fixed it.
The client can't figure out where I live.
Can't help it.
April 2, 2010, 2:09 AM
rabbit
Hdx said "\x1" which is different from '\x01'.
April 2, 2010, 2:50 AM
Trunning
Ah, read that wrong. Either way, compiler still complains.
April 2, 2010, 4:33 AM
Zoo
Use quotes not apostrophes, works a lot better.
April 2, 2010, 7:36 AM
JoeTheOdd
They're called double-quotes and single-quotes in the professional environment.
April 2, 2010, 9:27 AM
Yegg
Omg. I almost shit myself when you went as far as to take a screenshot of your using Wireshark. Maybe if you told us packet log results from the start your issue would be solved by now? Because here is what you need to do:

First, change the below line:
[code]sent = send(sockBNCS, (const char*)'\x01', 1, NULL);[/code]
to
[code]sent = send(sockBNCS, "\x01", 1, NULL);[/code]

When setting pkt.LangID to the value returned by GetUserDefaultLangID(), the type cast to DWORD is not necesssary. GetUserDefaultLangID() returns a WORD (which is listed as a LANGID type in this case).

I made a change to your SID_AUTH_INFO struct.

[code]struct SID_AUTH_INFO {
BNCS_HEADER Header;
DWORD   ProtocolID;
DWORD   PlatformID;
DWORD   ProductID;
DWORD   VerByte;
DWORD   ProductLang;
DWORD   LocalIP;
DWORD   TimeZone;
DWORD   LocaleID;
DWORD   LangID;
char *CountryAbbr;
char *CountryName;
};[/code]

Is the new version of it. I got rid of your char CountryInfo[0x100] and the reasoning will be explained below.


Many major changes took place with the below code of yours:
[code]  strcpy(&pkt.CountryInfo[0], "AUS"); //I *think* strcpy() returns the number of bytes copied, can't remember
 AbbrLen = sizeof(pkt.CountryInfo[0]);
 strcpy(&pkt.CountryInfo[AbbrLen + 1], "Australia");
 NameLen = sizeof(pkt.CountryInfo[AbbrLen + 1]);
 
 pkt.Header.Sanity = 0xFF;
 pkt.Header.ID     = 0x50;
 pkt.Header.Length =  4       //Header Length
                    + (4 * 9) //Number of DWORDs in the packet
                    + AbbrLen //Abbreviation Length
                    + 1       //Null Terminator
                    + NameLen //Country Name Length
                    + 1;      //Null Terminator
 printf("Sending %d bytes for 0x50 SID_AUTH_INFO\n", pkt.Header.Length);
 sent = send(sockBNCS, (const char*)&pkt, pkt.Header.Length, NULL);[/code]

I changed it to the code below (which I'll explain):
[code]  pkt.CountryAbbr = (char *) malloc (4);
 pkt.CountryName = (char *) malloc (10);
 strcpy (pkt.CountryAbbr, "AUS");
 strcpy (pkt.CountryName, "Australia");

 int pkt_size = sizeof(pkt) - 8;
 
 pkt.Header.Sanity = 0xFF;
 pkt.Header.ID     = 0x50;
 pkt.Header.Length = pkt_size + 14; // 14 being strlen of CountryAbbr + CountryName inc. nulls.
 char *buffer;
 
 buffer = (char *) malloc (pkt.Header.Length);
 memcpy (buffer, &pkt, pkt_size);
 memcpy (buffer+pkt_size, pkt.CountryAbbr, 4);
 memcpy (buffer+pkt_size+4, pkt.CountryName, 10);

 printf("Sending %d bytes for 0x50 SID_AUTH_INFO\n", pkt.Header.Length);
 sent = send(sockBNCS, (const char*)buffer, pkt.Header.Length, NULL);[/code]

I'm not sure why you wanted to separate the country abbreviation and name into a single char array, but its better to store them in their own area in memory. It also looks neater.

The reason I instead have 2 char pointers is so that we can define the size of each variable depending on how much space we need. Sure, in your case you hardcoded your country info in. But if you were making an actual application you planned to release (or even for just yourself, for the sake of better design), you would probably want to make a call to GetLocaleInfo to retrieve the country abbreviation and name. GetLocaleInfo() is pretty simple (and is found on MSDN):
[code] len = GetLocaleInfo (LOCALE_USER_DEFAULT, LOCALE_SENGCOUNTRY, NULL, 0);
SID_AUTH_INFO.CountryName = (char*) malloc (len);
GetLocaleInfo (LOCALE_USER_DEFAULT,LOCALE_SENGCOUNTRY, (LPSTR)SID_AUTH_INFO.CountryName, len);[/code]
On the first call to GetLocaleInfo, it returns the length of the string that represents the info you are seeking. On the second call, it stores that string in a buffer variable. And as you can see, in that example code, I allocate the proper amount of memory to CountryName, and I use it with GetLocaleInfo.

In your code, I tried keeping it as close to the code you already had, without changing else (because let's face it.. there is a tremendous amount of room for improvement). In case you didn't figure it out, I allocated 4 bytes to pkt.CountryAbbr (even though "AUS" is 3 letters) because the 4th byte is how the null terminator gets accounted for (same applies for pkt.CountryName of course).

The meaning behind sizeof(pkt) - 8 is because when we obtain the size of the entire struct, the 2 char pointers (remember: pointer gets treated as unsigned long -- so 4 bytes) dont have a defined size in the way we know them to be. the struct is just aware that those 2 members are pointers (thus, 4 bytes each). So this is why we subtract 8 when doing sizeof(pkt).

When you calculated your value for pkt.Header.Length, you had quite a mess there. As you can see,
[code]pkt.Header.Length = pkt_size + 14[/code]
looks much nicer.
Since I think it'd be nice if you incorporated GetLocaleInfo into your code, I didnt worry about doing a strlen() on either CountryAbbr or CountryName and just hardcoded the total length in. This way.. if you decide to use GetLocaleInfo (do it), you'll be able to replace that 14 accordingly.

I always find it nicer to just use some kind of buffer variable to store your data in prior to writing it to a file or sending over a socket (or whatever other technology you choose). So I did just that. I just tossed this together
[code]  memcpy (buffer+pkt_size, pkt.CountryAbbr, 4);
 memcpy (buffer+pkt_size+4, pkt.CountryName, 10);[/code]
So in reality, since we may not always know the length of CountryAbbr or CountryName, we wouldn't be able to just hardcode it in like that. I have it this way for examples sake and to show you what needs to be done to make your code work nicely.

And don't forget the last line...
[code]sent = send(sockBNCS, (const char*)buffer, pkt.Header.Length, NULL);[/code]
only change here is that &pkt is replaced with buffer.

Again, this was tossed together so that it would work correctly, and for examples sake. Of course you'll want to free up any unused memory before you're done (CountryAbbr, CountryName, and buffer need to be freed (ie. use free() function in case you're unaware)).

If you need any more help.. just ask.
April 2, 2010, 2:30 PM
Zoo
[quote author=Joe[x86] link=topic=18199.msg184457#msg184457 date=1270200478]
They're called double-quotes and single-quotes in the professional environment.
[/quote]

Noted, but I have a feeling he understands the difference better when the explanation sets them as far from each other as possible :)
April 2, 2010, 4:39 PM
HdxBmx27
Yegg, I made it a char[] instead of pointers for a reason, he's not smart enough to copy structs.
I chose 0x100 at random just because I have never seen any country name + abbr come any where near that length, so it's fairly easy.
Though, you can do it either way. Because IIRC, NO packet in the bnet protocol has a string followed by anything else but a string.

Anyways, the code as it stands is pretty much complete crap anyways, and unless he is willing to take advice and actually learn, all of this is moot.
April 2, 2010, 6:49 PM
Yegg
[quote author=Hdx link=topic=18199.msg184462#msg184462 date=1270234197]
Yegg, I made it a char[] instead of pointers for a reason, he's not smart enough to copy structs.
I chose 0x100 at random just because I have never seen any country name + abbr come any where near that length, so it's fairly easy.
Though, you can do it either way. Because IIRC, NO packet in the bnet protocol has a string followed by anything else but a string.

Anyways, the code as it stands is pretty much complete crap anyways, and unless he is willing to take advice and actually learn, all of this is moot.
[/quote]

Ah, I thought that was something he came up with in regards to the char[]. Either way, I figured I'd try to explain thoroughly and give examples, so hopefully he'll at least learn something.

And yes, I agree, the code is pretty bad. Aside from it being fine for merely testing a connection to battle.net, if he plans to use this code in an actual app, it could definitely use a huge makeover.
April 2, 2010, 9:04 PM
Trunning
Ok I completely just re-made this based on HDX's code, and then implemented Yegg's. I also decided just to use usa instead.

In my packet dump in WS it doesn't appear to be including D2DV. Here is my current code.

I'm pretty sure unless I send the right information, Battle.net won't send back either 0x25 or 0x50.
[code]#pragma comment (lib, "Ws2_32.lib")
#include <windows.h>
#include <winsock.h>
#include <string>
#include <iostream>
using namespace std;

struct BNCS_HEADER {
BYTE bHead;
BYTE bID;
WORD wLen;
};

struct SID_AUTH_INFO {
BNCS_HEADER Header;
DWORD   ProtocolID;
DWORD   PlatformID;
DWORD   ProductID;
DWORD   VerByte;
DWORD   ProductLang;
DWORD   LocalIP;
DWORD   TimeZone;
DWORD   LocaleID;
DWORD   LangID;
char *CountryAbbr;
char *CountryName;
};

int socket_connect(SOCKET sockBNCS, const char *Server, WORD Port){
LPHOSTENT 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){
SID_AUTH_INFO pkt;
int sent;
memset(&pkt, 0, sizeof(SID_AUTH_INFO));

pkt.ProtocolID = 0x00;
pkt.PlatformID = 'IX86';
pkt.ProductID = 'D2DV';
pkt.VerByte = 0x00;
pkt.ProductID = 0x00;
pkt.LocalIP = inet_addr("192.168.1.100");
pkt.TimeZone = 600;
pkt.LocaleID = 0x00;
pkt.LangID = GetUserDefaultLangID();

pkt.CountryAbbr = (char*)malloc(4);
pkt.CountryName = (char*)malloc(14);
strcpy(pkt.CountryAbbr, "USA");
strcpy(pkt.CountryName, "United States");

int pkt_size = sizeof(pkt) - 8;

pkt.Header.bHead = 0xFF;
pkt.Header.bID = 0x50;
pkt.Header.wLen = pkt_size + 18;

char *buffer;

buffer = (char*)malloc(pkt.Header.wLen);
memcpy(buffer, &pkt, pkt_size);
memcpy(buffer + pkt_size, pkt.CountryAbbr, 4);
memcpy(buffer + pkt_size + 4, pkt.CountryName, 14);

sent = send(sockBNCS, (const char*)buffer, pkt.Header.wLen, NULL);
return sent;
}

int main(){
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 0), &wsaData);


SOCKET sockBNCS = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockBNCS == INVALID_SOCKET){
cout << "Failed to create socket!";
cin.ignore();
cin.get();
return -1;
}

if (socket_connect(sockBNCS, "asia.battle.net", 6112) == -1){
cout << "Failed to connect!";
cin.ignore();
cin.get();
return -1;
}

cout << "Sending protocol byte...\n";
int sent;
sent = send(sockBNCS, "\x01", 1, NULL);

if (sent > 0)
cout << "Sent < " << sent << " bytes >\n";
else
cout << "Failed to send protocol byte!\n";

cout << "Sending 0x50...\n";
sent = send_SID_AUTH_INFO(sockBNCS);
cout << "Sent < " << sent << " bytes >\n";

BNCS_HEADER header;
void *data = malloc(0x200);
int data_max = 0x200;

while (true){
sent = recv(sockBNCS, (char*)&header, sizeof(header), NULL);
if (sent != sizeof(header)){
cout << "Didn't receive full header\n";
cin.ignore();
cin.get();
WSACleanup();
return -1;
} else
break;
}

if (header.wLen - 4 > data_max){
free(data);
data = malloc(header.wLen - 4);
}

sent = recv(sockBNCS, (char*)&data, header.wLen - 4, NULL);
if (sent != header.wLen - 4){
cout << "Could not read packet data\n";
cin.ignore();
cin.get();
WSACleanup();
return -1;
}

cout << "Header Id : " << header.bID;

cin.ignore();
cin.get();
closesocket(sockBNCS);
WSACleanup();
return 0;
}[/code]

And here my dump.
[code]0000  00 04 ed 6f a5 60 00 26  18 7f 24 a2 08 00 45 00   ...o.`.& ..$...E.
0010  00 62 63 1a 40 00 80 06  01 54 c0 a8 01 65 d3 e9   .bc.@... .T...e..
0020  00 31 09 dd 17 e0 b1 7c  e6 c5 9c 3a 1c 50 50 18   .1.....| ...:.PP.
0030  ff ff 96 7c 00 00 ff 50  3a 00 00 00 00 00 36 38   ...|...P :.....68
0040  58 49 00 00 00 00 00 00  00 00 00 00 00 00 c0 a8   XI...... ........
0050  01 64 58 02 00 00 00 00  00 00 09 04 00 00 55 53   .dX..... ......US
0060  41 00 55 6e 69 74 65 64  20 53 74 61 74 65 73 00   A.United  States.[/code]
April 27, 2010, 5:56 AM
dRAgoN
pkt.LocaleID = GetUserDefaultLCID();
April 27, 2010, 6:18 AM
Trunning
Thanks I'll add that, still don't know why D2DV isn't being sent.
April 27, 2010, 10:14 AM
dRAgoN
set break points through out the function, and put a watch on "pkt" step through and watch the dta in "pkt" for changes it should give you an idea where your problem is at.
April 27, 2010, 1:05 PM
Trunning
It appears the data is being set, and I don't how to set a watch.
April 27, 2010, 2:25 PM
dRAgoN
[quote author=Trunning link=topic=18199.msg184524#msg184524 date=1272378341]
It appears the data is being set, and I don't how to set a watch.
[/quote]
Don't have it infront of me but should be in view, to set the watch highlight and drag onto the watch window, you can watch 'most' variables in that window. (asuming your using MS version btw)
April 27, 2010, 5:15 PM
Trunning
Stepping through lines, hitting the ProductID initialization, sets it to "1144144982".
April 27, 2010, 6:28 PM
dRAgoN
[quote author=Trunning link=topic=18199.msg184527#msg184527 date=1272392902]
Stepping through lines, hitting the ProductID initialization, sets it to "1144144982".
[/quote]
keep stepping untill that reads 0 1144144982 = d2dv
edit: 1144144982= 0x44324456 = 'D2DV'
April 27, 2010, 7:34 PM
rabbit
Shouldn't it be inserted as VD2D?
April 27, 2010, 10:21 PM
Yegg
[quote author=rabbit link=topic=18199.msg184530#msg184530 date=1272406867]
Shouldn't it be inserted as VD2D?
[/quote]

It is. Putting those single quotes around it will take care of the byte order.
If you look at the hex dump of the packet he showed u, where "VD2D" should appear, it is instead filled with nulls.

Trunning: I just noticed you're doing the following in your code
[code]void *data = malloc(0x200);[/code]

You're using data as the variable for storing data from the server. First off, even if you never think the response is going to be larger than 0x200 for a given packet, it makes more sense to use a design where you can dynamically allocate the correct amount of memory.
Second, why not declare data as a char* and cast the malloc() response as a char*?
April 28, 2010, 12:03 AM
rabbit
[quote author=Yegg link=topic=18199.msg184532#msg184532 date=1272412980]
[quote author=rabbit link=topic=18199.msg184530#msg184530 date=1272406867]
Shouldn't it be inserted as VD2D?
[/quote]

It is. Putting those single quotes around it will take care of the byte order.
If you look at the hex dump of the packet he showed u, where "VD2D" should appear, it is instead filled with nulls.

Trunning: I just noticed you're doing the following in your code
[code]void *data = malloc(0x200);[/code]

You're using data as the variable for storing data from the server. First off, even if you never think the response is going to be larger than 0x200 for a given packet, it makes more sense to use a design where you can dynamically allocate the correct amount of memory.
Second, why not declare data as a char* and cast the malloc() response as a char*?
[/quote]Why wouldn't I do something as silly as pay attention to what he wrote?  Pffffffff.
April 28, 2010, 12:22 AM
Trunning
[quote author=Yegg link=topic=18199.msg184532#msg184532 date=1272412980]
[quote author=rabbit link=topic=18199.msg184530#msg184530 date=1272406867]
Shouldn't it be inserted as VD2D?
[/quote]

It is. Putting those single quotes around it will take care of the byte order.
If you look at the hex dump of the packet he showed u, where "VD2D" should appear, it is instead filled with nulls.

Trunning: I just noticed you're doing the following in your code
[code]void *data = malloc(0x200);[/code]

You're using data as the variable for storing data from the server. First off, even if you never think the response is going to be larger than 0x200 for a given packet, it makes more sense to use a design where you can dynamically allocate the correct amount of memory.
Second, why not declare data as a char* and cast the malloc() response as a char*?
[/quote]

That was Hdx's code, I'll change to what you suggested.

Still nothing on why D2DV isn't being sent?
April 28, 2010, 4:17 AM
HdxBmx27
The void* doesn't really matter, as the data will be typecasted to a struct. So a pointer is a pointer is a pointer. Only time casting it to a specific type like char* is useful is when you are accessing it like an array.

Anyways, the code for reading data isn't the issue.
Its the code for building the auth packet.

Debugging, what is ProductID at when you reach:
memcpy(buffer, &pkt, pkt_size);
?
April 28, 2010, 6:24 AM
Trunning
It's 0 there.
April 28, 2010, 7:27 AM
Yegg
[quote author=Trunning link=topic=18199.msg184539#msg184539 date=1272439679]
It's 0 there.
[/quote]

See what happens if you remove the line with memset.
April 28, 2010, 3:38 PM
HdxBmx27
if you do that, your struct will have random data in it.
Anyways, quit pointing him at places where you know the problem isn't.
[code]
pkt.ProductID = 'D2DV'; <~~It gets properly set here
pkt.VerByte = 0x00;
pkt.ProductID = 0x00;
pkt.LocalIP = inet_addr("192.168.1.100");
pkt.TimeZone = 600;
pkt.LocaleID = 0x00;
pkt.LangID = GetUserDefaultLangID();

pkt.CountryAbbr = (char*)malloc(4);
pkt.CountryName = (char*)malloc(14);
strcpy(pkt.CountryAbbr, "USA");
strcpy(pkt.CountryName, "United States");

int pkt_size = sizeof(pkt) - 8;

pkt.Header.bHead = 0xFF;
pkt.Header.bID = 0x50;
pkt.Header.wLen = pkt_size + 18;

char *buffer;

buffer = (char*)malloc(pkt.Header.wLen);
memcpy(buffer, &pkt, pkt_size); <~~~~Its 0 Here[/code]
Now step through the code, and look for a line where the debugger says the it looses its value.
It's a fairly obvious bug, but hey! You can't learn if you don't try!
April 28, 2010, 4:30 PM
Yegg
Probably has something to do with this:
[code]pkt.ProductID = 'D2DV';
pkt.VerByte = 0x00;
pkt.ProductID = 0x00;[/code]

ProductID is set twice.
April 28, 2010, 8:45 PM
HdxBmx27
[quote author=Yegg link=topic=18199.msg184545#msg184545 date=1272487553]
Probably has something to do with this:
[code]pkt.ProductID = 'D2DV';
pkt.VerByte = 0x00;
pkt.ProductID = 0x00;[/code]

ProductID is set twice.
[/quote]Thats what I was getting at yes...
April 28, 2010, 11:01 PM
Trunning
Oh wow, can't believe it was that simple. Anyway, now at least I'm receiving 0x25 then 0x50 back.

With the code, I'm receiving 0x25, but I've tried a couple of methods based on it to receive 0x50, but failed. Can I get an example of 0x50, then I should be fine. Thanks.
April 29, 2010, 1:02 AM
HdxBmx27
Just send valid information in your c->s 0x50 Read: Version Byte
Also, if you can parse out 0x25, then you should be able to parse out 0x50. As the code should be generic.
April 29, 2010, 3:29 AM
Trunning
As I said in my last post, I attempted and failed. Also if I were to manage to receive 0x50 properly, I don't know how to access certain parts of data. It's not like the send me a struct that contains.
[code](DWORD) Logon Type
(DWORD) Server Token
(DWORD) UDPValue *
(FILETIME) MPQ filetime
(STRING) IX86ver filename
(STRING) ValueString[/code]
April 29, 2010, 3:43 AM
HdxBmx27
[quote author=Trunning link=topic=18199.msg184549#msg184549 date=1272512629]
As I said in my last post, I attempted and failed.
[/quote]
Post your current code, DO NOT BREAK THE FUCKING TABLES, and we can see where you're fucking up.

[quote author=Trunning link=topic=18199.msg184549#msg184549 date=1272512629]It's not like the send me a struct that contains.
[code](DWORD) Logon Type
(DWORD) Server Token
(DWORD) UDPValue *
(FILETIME) MPQ filetime
(STRING) IX86ver filename
(STRING) ValueString[/code][/quote]As a matter of a fact, it does ;) (Well, you have to extract the strings, but ya)
April 29, 2010, 3:49 AM
Trunning
I'm getting an error at runtime which is "Run-Time Check Failure #2 - Stack around the variable 'auth' was corrupted.".

[code]#pragma comment (lib, "Ws2_32.lib")
#include <windows.h>
#include <winsock.h>
#include <string>
#include <iostream>
using namespace std;

struct BNCS_HEADER {
BYTE bHead;
BYTE bID;
WORD wLen;
};

struct SID_AUTH_INFO {
BNCS_HEADER Header;
DWORD  ProtocolID;
DWORD  PlatformID;
DWORD  ProductID;
DWORD  VerByte;
DWORD  ProductLang;
DWORD  LocalIP;
DWORD  TimeZone;
DWORD  LocaleID;
DWORD  LangID;
char *CountryAbbr;
char *CountryName;
};

int socket_connect(SOCKET sockBNCS, const char *Server, WORD Port){
LPHOSTENT 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){
SID_AUTH_INFO pkt;
int sent = 0;
memset(&pkt, 0, sizeof(SID_AUTH_INFO));

pkt.ProtocolID = 0x00;
pkt.PlatformID = 'IX86';
pkt.ProductID = 'D2DV';
pkt.VerByte = 0x0C;
pkt.LocalIP = inet_addr("192.168.1.100");
pkt.TimeZone = 0x00;
pkt.LocaleID = GetUserDefaultLCID();
pkt.LangID = GetUserDefaultLangID();

pkt.CountryAbbr = (char*)malloc(4);
pkt.CountryName = (char*)malloc(14);
strcpy(pkt.CountryAbbr, "USA");
strcpy(pkt.CountryName, "United States");

int pkt_size = sizeof(pkt) - 8;

pkt.Header.bHead = 0xFF;
pkt.Header.bID = 0x50;
pkt.Header.wLen = pkt_size + 18;

char *buffer;

buffer = (char*)malloc(pkt.Header.wLen);
memcpy(buffer, &pkt, pkt_size);
memcpy(buffer + pkt_size, pkt.CountryAbbr, 4);
memcpy(buffer + pkt_size + 4, pkt.CountryName, 14);

sent = send(sockBNCS, (const char*)buffer, pkt.Header.wLen, NULL);
return sent;
}

int recv_SID_PING(SOCKET sockBNCS){
BNCS_HEADER header;
void *data = malloc(0x200);
int data_max = 0x200, sent;

while (true){
sent = recv(sockBNCS, (char*)&header, sizeof(header), NULL);
if (sent != sizeof(header)){
cout << "Didn't receive full header\n";
return -1;
} else if ( sent == sizeof(header))
break;
}

if (header.wLen - 4 > data_max){
free(data);
data = malloc(header.wLen - 4);
}

sent = recv(sockBNCS, (char*)&data, header.wLen - 4, NULL);
if (sent != header.wLen - 4){
cout << "\nCould not read packet data";
return -1;
}

if (header.bID == '%'){
cout << "\n\nReceived packet < 0x20 < " << header.wLen - 4 << " bytes > >";
cout << "\nServer cookie : " << data;
}

return header.wLen;
}

int recv_SID_AUTH_INFO(SOCKET sockBNCS){
BNCS_HEADER header;
void *auth = malloc(0x250);
memset(auth, 0, 0x250);
int data_max = 0x250, sent;

while (true){
sent = recv(sockBNCS, (char*)&header, sizeof(header), NULL);
if (sent != sizeof(header)){
cout << "Didn't receive full header\n";
return -1;
} else if ( sent == sizeof(header))
break;
}

if (header.wLen - 4 > data_max){
free(auth);
auth = malloc(header.wLen - 4);
}

sent = recv(sockBNCS, (char*)&auth, header.wLen - 4, NULL);
if (sent != header.wLen - 4){
cout << "\nCould not read packet data";
return -1;
}

return header.wLen;
}

int main(){
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 0), &wsaData);


SOCKET sockBNCS = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockBNCS == INVALID_SOCKET){
cout << "Failed to create socket!";
cin.ignore();
cin.get();
return -1;
}

if (socket_connect(sockBNCS, "useast.battle.net", 6112) == -1){
cout << "Failed to connect!";
cin.ignore();
cin.get();
return -1;
}

cout << "Sending protocol byte...\n";
int sent;
sent = send(sockBNCS, "\x01", 1, NULL);

if (sent > 0)
cout << "Sent < " << sent << " bytes >\n";
else
cout << "Failed to send protocol byte!\n";

cout << "Sending 0x50...\n";
sent = send_SID_AUTH_INFO(sockBNCS);
cout << "Sent < " << sent << " bytes >\n";

if (recv_SID_PING(sockBNCS) == -1){
cin.ignore();
cin.get();
closesocket(sockBNCS);
WSACleanup();
}

if (recv_SID_AUTH_INFO(sockBNCS) == -1){
cin.ignore();
cin.get();
closesocket(sockBNCS);
WSACleanup();
}

cin.ignore();
cin.get();
closesocket(sockBNCS);
WSACleanup();
return 0;
}[/code]
April 29, 2010, 4:22 AM
HdxBmx27
Why the hell are you duplicating code?
The whole, Receive the header, then receive the data should be in your main() function, NOT in your recv_ functions.
April 29, 2010, 5:11 AM
dRAgoN
[code]
TIME_ZONE_INFORMATION tz_Time;
GetTimeZoneInformation(&tz_Time);

pkt.TimeZone = tz_Time.Bias;[/code]
April 29, 2010, 5:14 AM
Trunning
Made another attempt, I'm unsure if my struct is right ( Don't know what data type to use for MPQTime ), let alone if I'm suppose to use one.

[code]#pragma comment (lib, "Ws2_32.lib")
#include <windows.h>
#include <winsock.h>
#include <string>
#include <iostream>
using namespace std;

struct BNCS_HEADER {
BYTE bHead;
BYTE bID;
WORD wLen;
};

struct SID_AUTH_INFO {
BNCS_HEADER Header;
DWORD   ProtocolID;
DWORD   PlatformID;
DWORD   ProductID;
DWORD   VerByte;
DWORD   ProductLang;
DWORD   LocalIP;
DWORD   TimeZone;
DWORD   LocaleID;
DWORD   LangID;
char *CountryAbbr;
char *CountryName;
};

struct SERVER_SAI {
BNCS_HEADER Header;
DWORD LogonType;
DWORD ServerToken;
DWORD UDPVal;
DWORD MPQTime;
string Ver;
string Val;
};

int socket_connect(SOCKET sockBNCS, const char *Server, WORD Port){
LPHOSTENT 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){
SID_AUTH_INFO pkt;
int sent = 0;
memset(&pkt, 0, sizeof(SID_AUTH_INFO));

pkt.ProtocolID = 0x00;
pkt.PlatformID = 'IX86';
pkt.ProductID = 'D2DV';
pkt.VerByte = 0x0C;
pkt.LocalIP = inet_addr("192.168.1.100");
pkt.TimeZone = 0x00;
pkt.LocaleID = GetUserDefaultLCID();
pkt.LangID = GetUserDefaultLangID();

pkt.CountryAbbr = (char*)malloc(4);
pkt.CountryName = (char*)malloc(14);
strcpy(pkt.CountryAbbr, "USA");
strcpy(pkt.CountryName, "United States");

int pkt_size = sizeof(pkt) - 8;

pkt.Header.bHead = 0xFF;
pkt.Header.bID = 0x50;
pkt.Header.wLen = pkt_size + 18;

char *buffer;

buffer = (char*)malloc(pkt.Header.wLen);
memcpy(buffer, &pkt, pkt_size);
memcpy(buffer + pkt_size, pkt.CountryAbbr, 4);
memcpy(buffer + pkt_size + 4, pkt.CountryName, 14);

sent = send(sockBNCS, (const char*)buffer, pkt.Header.wLen, NULL);
return sent;
}

int main(){
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 0), &wsaData);


SOCKET sockBNCS = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockBNCS == INVALID_SOCKET){
cout << "Failed to create socket!";
cin.ignore();
cin.get();
return -1;
}

if (socket_connect(sockBNCS, "useast.battle.net", 6112) == -1){
cout << "Failed to connect!";
cin.ignore();
cin.get();
return -1;
}

cout << "Sending protocol byte...\n";
int sent;
sent = send(sockBNCS, "\x01", 1, NULL);

if (sent > 0)
cout << "Sent < " << sent << " bytes >\n";
else
cout << "Failed to send protocol byte!\n";

cout << "Sending 0x50...\n";
sent = send_SID_AUTH_INFO(sockBNCS);
cout << "Sent < " << sent << " bytes >\n";

BNCS_HEADER header;
void *data = malloc(0x200);
int data_max = 0x200;

while (true){
sent = recv(sockBNCS, (char*)&header, sizeof(header), NULL);
if (sent != sizeof(header)){
cout << "Didn't receive full header\n";
cin.ignore();
cin.get();
closesocket(sockBNCS);
WSACleanup();
} else if ( sent == sizeof(header))
break;
}

if (header.wLen - 4 > data_max){
free(data);
data = malloc(header.wLen - 4);
}

sent = recv(sockBNCS, (char*)&data, header.wLen - 4, NULL);
if (sent != header.wLen - 4){
cout << "\nCould not read packet data";
cin.ignore();
cin.get();
closesocket(sockBNCS);
WSACleanup();
}

if (header.bID == '%'){
cout << "\n\nReceived packet < 0x20 < " << header.wLen - 4 << " bytes > >";
cout << "\nServer cookie : " << data;
}

SERVER_SAI auth;
while (true){
sent = recv(sockBNCS, (char*)&auth, sizeof(auth), NULL);
if (auth.Header.wLen - 4 != sizeof(auth)){
cout << "\n\nDidn't receive full header\n";
cin.ignore();
cin.get();
closesocket(sockBNCS);
WSACleanup();
return -1;
} else if (auth.Header.wLen - 4 == sizeof(auth))
break;
}

cout << "\n\nReceived packet < 0x50 < " << auth.Header.wLen - 4 << " bytes > >";

cin.ignore();
cin.get();
closesocket(sockBNCS);
WSACleanup();
return 0;
}[/code]
April 29, 2010, 5:24 AM
HdxBmx27
Tired, so meh.
This is where a lot of the benifits of data buffers come in.
Anyways, the output of the following code is:
[quote]Sending protocol byte...
Sent 1 bytes
Received Packet ID: 0x25 Length: 0x0008 (8)
Ping 0x69321268
Pong 0x69321268
Received Packet ID: 0x50 Length: 0x0067 (103)
Received 0x50 ver-IX86-5.mpq, B=2407285681 A=2737422848 C=383046708 4 A=A^S B=B^C C=C+A A=A-B[/quote]
[code]#include "stdafx.h"
#pragma comment (lib, "Ws2_32.lib")
#include <winsock2.h>
#include <windows.h>
#include <string>
#include <iostream>
using namespace std;

struct BNCS_HEADER {
BYTE Sanity;
BYTE ID;
WORD Length;
};

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;
unsigned long long ArchiveTime;
char  *ArchiveName;
char  *Seed;
};

struct CMSG_SID_PING{
DWORD PingValue;
};

struct SMSG_SID_PING{
DWORD PingValue;
};

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("Received 0x50 %s, %s\n", pkt.ArchiveName, pkt.Seed);
}

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, "uswest.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;

while (true){
count = recv(sockBNCS, (char*)&header, sizeof(header), MSG_WAITALL);
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, MSG_WAITALL);
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("Received 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); break;
case 0x50: recv_SID_AUTH_INFO(sockBNCS, data, header.Length - 4); break;
}
}
}
}
}

printf("Exiting Program!\n");
cin.get();
closesocket(sockBNCS);
WSACleanup();
return 0;
}
[/code]
You are using C++, make use of some of the better aspects of C++, (mainly move away from cin/cout, and start using objects!)
April 29, 2010, 7:20 AM
Trunning
Here is my output from your code:

[code]Sending protocol byte...
Sent 1 bytes
Didn't receive full header, -1 of 4[/code]

But in wireshark I'm clearly getting all the data.
April 29, 2010, 7:30 AM
HdxBmx27
That *should* only popup if you're ipbanned -1 is SOCKET_ERROR. Switch servers.
April 29, 2010, 7:32 AM
Trunning
Well settings the send()'s flags to NULL fixed it for me.

And do I have to create a new socket, for BNFTP to download the archive? Or can I skip that?

Also couple questions:

How do I obtain these values:
[code](DWORD) Client Token
(DWORD) EXE Version
(DWORD) EXE Hash[/code]

What are these suppose to contain:
[code](DWORD) CD-key's product value
(DWORD) CD-key's public value[/code]

Can you give me an exmaple of the structure SID_AUTH_INFO.

Thanks...
April 29, 2010, 7:38 AM
dRAgoN
[quote author=Trunning link=topic=18199.msg184558#msg184558 date=1272526720]
Well settings the send()'s flags to NULL fixed it for me.

And do I have to create a new socket, for BNFTP to download the archive? Or can I skip that?

Also couple questions:

How do I obtain these values:
[code](DWORD) Client Token
(DWORD) EXE Version
(DWORD) EXE Hash[/code]

What are these suppose to contain:
[code](DWORD) CD-key's product value
(DWORD) CD-key's public value[/code]

Can you give me an exmaple of the structure SID_AUTH_INFO.

Thanks...

[/quote]
You can skip the BN_FTP but yes you would need another socket for it lol.
Edit: as for the cd values, you should be able to find them on the forum here somewhere, along with other various functions youll need for them.
April 29, 2010, 1:54 PM
Trunning
I'll try finding them, and I meant SID_AUTH_CHECK in my last post.
April 30, 2010, 1:45 AM
dRAgoN
[quote author=Trunning link=topic=18199.msg184571#msg184571 date=1272591943]
I'll try finding them, and I meant SID_AUTH_CHECK in my last post.
[/quote]
thats on the forum here somewhere to.
April 30, 2010, 2:46 AM
Trunning
I searched and found very little, but it appears I need a CheckRevision() function, that's in one of several Dll's. Or I can use BNLS (Battle.net Login Server) to do it.

I can't find any working links to download one of the Dll's.
April 30, 2010, 5:48 AM
dRAgoN
[quote author=Trunning link=topic=18199.msg184577#msg184577 date=1272606506]
I searched and found very little, but it appears I need a CheckRevision() function, that's in one of several Dll's. Or I can use BNLS (Battle.net Login Server) to do it.

I can't find any working links to download one of the Dll's.
[/quote]
Your not looking hard enough, https://davnit.net/bnet/vL/index.php?topic=16314.0
Edit: As for DLLs think the only ones to ever have been posted here was warden.dll and some other one both links are broken to so you need to ask around here maybe, that or use JBLS.
edit2: or write your own heh.
April 30, 2010, 1:17 PM
Trunning
I'll make a new topic asking for one, I'm not using BNLS.
April 30, 2010, 10:13 PM

Search