• Welcome to Valhalla Legends Archive.
 

Dll contains CheckRevision()

Started by Trunning, April 30, 2010, 05:16 PM

Previous topic - Next topic

Hdx

#15
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

Proud host of the JBLS server www.JBLS.org.
JBLS.org Status:
JBLS/BNLS Server Status

Trunning

Guess I'll use Diablo 1 then, better go brush the dust off my Diablo 1 case.

Hdx

#17
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.

Proud host of the JBLS server www.JBLS.org.
JBLS.org Status:
JBLS/BNLS Server Status

Trunning

Well I was going to capture a connection with WireShark, but I doubt I will now. All the reference I need is online.

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"?

l)ragon

Quote from: Trunning on April 30, 2010, 11:22 PM
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.
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.
*^~·.,¸¸,.·´¯`·.,¸¸,.-·~^*ˆ¨¯¯¨ˆ*^~·.,l)ragon,.-·~^*ˆ¨¯¯¨ˆ*^~·.,¸¸,.·´¯`·.,¸¸,.-·~^*

Hdx

#21

    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;

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
There ya go, ribose's server supports D1.

Proud host of the JBLS server www.JBLS.org.
JBLS.org Status:
JBLS/BNLS Server Status

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?
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);
}

Hdx

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:
void recv_SID_AUTH_INFO(...){
    ...... Blah ...
    send_BNLS_VERSIONCHECKEX2(sockBNLS, pkt.ArchiveTime, pkt.ArchiveName, pkt.Seed);
}

Proud host of the JBLS server www.JBLS.org.
JBLS.org Status:
JBLS/BNLS Server Status

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,.

Trunning

With the following code, I monitored with wireshark, and apparently the seed isn't being copied to the buffer I made.

#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;
}

Hdx

[code]
int full_size = strlen(packet.ArchiveName) + strlen(packet.Seed) + 2;

You're missing something.[/code]

Proud host of the JBLS server www.JBLS.org.
JBLS.org Status:
JBLS/BNLS Server Status

Trunning

[code]int full_size = size + strlen(packet.ArchiveName) + strlen(packet.Seed) + 2;

I added size into the calculation now I'm sending:

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.


And receving:

0000   0b 00 1a 00 00 00 00 00 00 00 00                 ...........[/code]

Hdx

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.

Proud host of the JBLS server www.JBLS.org.
JBLS.org Status:
JBLS/BNLS Server Status

rabbit

#29
Quote from: Hdx on May 03, 2010, 02:39 PM
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 from: Trunning on May 03, 2010, 01:24 PM
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.


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.
Grif: Yeah, and the people in the red states are mad because the people in the blue states are mean to them and want them to pay money for roads and schools instead of cool things like NASCAR and shotguns.  Also, there's something about ketchup in there.

|