• Welcome to Valhalla Legends Archive.
 

Need help. Logging BNet... [NOT solved]

Started by z-stars, July 22, 2004, 01:47 PM

Previous topic - Next topic
|

z-stars

#105
I don't understand, now that I send a *right* exe hash, battle.net answers with a "0x51 Invalid CD Key" packet, and bans me for 30 to 60 minutes, but when I send a *wrong* exe hash, bnet just answers with a 0x51 Invalid Version packet and doesn't ban me. And now, I don't know what could be wrong to get that "Invalid CD-Key" response. Everything "static" is the same than the real client sends, also, I have tested the CheckRevision() function with fixed values and it outputs the same ExeHash than the real lod client does. Also, I have solved the CdKey2 Value 1 error I had yesterday, I assigned dwPrivate2 to it instead assigning dwPublic2...
So, does anyone know what could be wrong plz? (And btw, why does bnet ban me for so long when I send it the right exe hash?)
The only 0x51 values that aren't static that I haven't been able to test are the client token, some RunCDKeyDecode()  values (like dwPrivates) and the Hashed CD-Keys datas, so maybe the error is something related to those.
ATM In my code I get the client token using GetTickCount(), and I write the CD-Key hashed data (dwOutputBuffer) as it is, without converting it to Little Endian or without changing the order.
For example, if dwOutputBuffer[0] was 01 02 03 04, and dwOutputBuffer[1] was 05 06 07 08, the packet sent to battle net would be "... 01 02 03 04 05 06 07 08..."

I hope with that info someone is able to help me, BTW if you want me to post the any part of the code or any packet log just tell me.
Thx for your help in advance.


EDIT: I'll post again the actual code of the function that makes packet 0x51, I've made some changes to it to solve some errors.


// S SID_AUTH_CHECK
// This function is supossed to build and send the fifth packet (0x51)
// At the start of this function, csFifthPacket.packet (the packet 0x51 that
// this function sends to battle.net at the end) is EMPTY.
int LTBNFifthPacket()
{
   /* Globals... */
   BEFORE_SEND;
   int n = 0;
   char * CDKeyOwner = "Luis";
   /* End of Globals */

   /* First, load Battle.snp to do the hashing for us */
   HMODULE battlesnp;
   battlesnp = LoadLibrary("Battle.snp");
   if(!battlesnp) cout << "Couldn't load battle.snp" << endl;
   /* Battlesnp Loaded */


   /* CHECK REVISION */
   /* Call CheckRevision() to get the some of the values to send */
   /* The values we get are: ExeHash and Version (dwExeHash, and dwVersion) */
   /* Also, we get an ExeInfo string. (To CRExeInfo). */
   DWORD dwCRVersion = 0;
   DWORD dwCRChecksum = 0;
   char CRExeInfo[5000];
   memset(CRExeInfo, 0, 5000);
   BOOL bCheckRevision = 0;
   bCheckRevision =
      CheckRevision("C:\\Archivos de programa\\Diablo II\\Game.exe",
         "C:\\Archivos de programa\\Diablo II\\Bnclient.dll",
         "C:\\Archivos de programa\\Diablo II\\D2client.dll",
         r_SID_AUTH_INFO.ValueString,
         &dwCRVersion, &dwCRChecksum,
         CRExeInfo,
         r_SID_AUTH_INFO.IX86ver_filename);
   if(bCheckRevision == FALSE)
   {
      cout << "ERROR: Check Revision() Failed" << endl;
      system("pause");
   }
   else cout << "CheckRevision() Success" << endl;
   strcpy(CRExeInfo, "Game.exe 10/13/03 08:35:30 1198857");
   /*printf("dwVersion: %x  || dwChecksum: %x || ExeInfo: %s",
      dwVersion, dwChecksum, CRExeInfo);*/
   /* END OF CHECK REVISION */

         

   /* VARIABLES TO PUT IN THE PACKET DECLARATIONS */
   int x = 0;
   BYTE FirstByte = 0xFF; // It's always 0xFF
   BYTE PacketID = 0x51; // PacketId's 0x51
   WORD PacketLen = 132 + strlen(CDKeyOwner); // Packet Length is 132 + ownerlen
   DWORD ClientToken = GetTickCount(); // I use GetTickCount() to get that
   DWORD ExeVersion = dwCRVersion; // From CheckRevision()
   DWORD ExeHash = dwCRChecksum; // From CheckRevision()
   DWORD CDKeyNumber = 2; // 1 D2 cd key, 1 Lod cd key.
   DWORD UsingOfKeys = 0; // 0

   DWORD Key1Len = 0x10; // Length of D2 CdKey: 16 (0x10)
   DWORD Key1Num1 = x; // This is supossed to be the First Number of the first cd key.
                  // I'm not sure how to get it.
   DWORD Key1Unknown = 0; // Unknown(0)

   DWORD Key2Len = 0x10; // Same...
   
   DWORD Key2Num1 = x;      // Same...
   DWORD Key2Unknown = 0; // Unknown (0)
   /* END OF VARIABLES TO PUT IN THE PACKET DECLARATIONS */


   /* DO THE SAME FOR CDKEY2 */
   DWORD dwKey2Product = 0;
   DWORD dwKey2Private = 0;
   DWORD dwKey2Public = 0;
   RunCDkeyDecode(&dwKey2Product, &dwKey2Public, &dwKey2Private, szLODCdKey);

   DWORD dwKey2HashBuffer[6];
   DWORD dwKey2OutBuffer[5];
   dwKey2HashBuffer[0] = GetTickCount();
   dwKey2HashBuffer[1] = r_SID_AUTH_INFO.Server_Token;
   dwKey2HashBuffer[2] = dwKey2Product;
   dwKey2HashBuffer[3] = dwKey2Public;
   dwKey2HashBuffer[4] = 0;
   dwKey2HashBuffer[5] = dwKey2Private;
   HashData(24, dwKey2OutBuffer, dwKey2HashBuffer);
   /* ~~ */



   /* CALL RUNCDKEYDECODE */
   DWORD dwKey1Product = 0;
   DWORD dwKey1Private = 0;
   DWORD dwKey1Public = 0;
   RunCDkeyDecode(&dwKey1Product, &dwKey1Public, &dwKey1Private, szD2CdKey);
   ////
   //cout << endl << "RUNCDKEYDECODE" << endl;
   //cout << "dwProduct: " << hex << dwProduct << endl;
   //cout << "dwPublic: " << hex << dwPublic << endl;
   //cout << "dwPrivate: " << hex << dwPrivate << endl;
   //cout << endl << endl;
   /* END OF CALL RUNCDKEYDECODE */

   /* CALL HASHDATA FOR CDKEY1*/
   DWORD dwKey1HashBuffer[6];
   DWORD dwKey1OutBuffer[5]; // This is supossed to be the CDKey1 Data.
   dwKey1HashBuffer[0] = ClientToken; // We got this with GetTickCount()
   dwKey1HashBuffer[1] = r_SID_AUTH_INFO.Server_Token; // Bnet sent this in the last packet
   dwKey1HashBuffer[2] = dwKey1Product; // We got this with RunCDKeyDecode
   dwKey1HashBuffer[3] = dwKey1Public; // We got this with RunCDKeyDecode too
   dwKey1HashBuffer[4] = 0; // 0...
   dwKey1HashBuffer[5] = dwKey1Private; // Also, we got this with RunCDKeyDecode
   HashData(24, dwKey1OutBuffer, dwKey1HashBuffer);
   /* END OF CALL HASHDATA */


   /* WRITE EVERYTHING IN THE PACKET */

   // Info about csFifthPacket class:
   // The packet itself is csFifthPacket.packet and it is a
   // dynamically allocated BYTE array.
   // The position the next function will write to is stored at
   // nByte2Write and is increased automatically with each WriteX function
   // call.
   // WriteByte writes a byte to packet. (csFifthPacket.packet).
   // WriteWord and WriteDWord take 2 arguments. The first one tells
   // if it has to convert the Word or DWord given to Little Endian before
   // putting it in packet or not. If the first argument is 0, it will
   // convert the DWORD given to Little Endian, and then put it in the
   // packet. If it is 1, it will put it in the packet directly without
   // converting it.
   // WriteString() just writes a string and a null terminator to packet.

   csFifthPacket.WriteByte(0xFF);  // header R
   csFifthPacket.WriteByte(0x51);

   csFifthPacket.WriteWord(0, 132 + strlen(CDKeyOwner));
   
   csFifthPacket.WriteDWord(0, ClientToken); // client token R?
   csFifthPacket.WriteDWord(0, ExeVersion); // Exe Version R
   csFifthPacket.WriteDWord(0, dwCRChecksum); // Exe Hash R
   csFifthPacket.WriteDWord(0, CDKeyNumber); // Number of CD keys R
   csFifthPacket.WriteDWord(0, UsingOfKeys); // Zero R

   cout << "dwKey1Public: " << hex << dwKey1Public << endl;
   cout << "dwKey1Private: " << hex << dwKey1Private << endl;
   cout << "dwKey2Public: " << hex << dwKey2Public << endl;
   cout << "dwKey2Private: " << hex << dwKey2Private << endl;

   csFifthPacket.WriteDWord(0, Key1Len); // Key1 Length R
   cout << "dwKey1Product: " << hex << dwKey1Product << endl;
   cout << "dwKey2Product: " << hex << dwKey2Product << endl;

   csFifthPacket.WriteDWord(0, dwKey1Product); // Key1 Product R
   csFifthPacket.WriteDWord(0, dwKey1Public); // Key1 Number1 R
   csFifthPacket.WriteDWord(0, Key1Unknown); // Key1 Unknown R
#if OUTPUT_TO_LE == FALSE
   csFifthPacket.WriteDWord(1,dwKey1OutBuffer[0]); // KEY 1
   csFifthPacket.WriteDWord(1,dwKey1OutBuffer[1]); // HASHED DATA
   csFifthPacket.WriteDWord(1,dwKey1OutBuffer[2]);   
   csFifthPacket.WriteDWord(1,dwKey1OutBuffer[3]);
   csFifthPacket.WriteDWord(1,dwKey1OutBuffer[4]);
#else
   csFifthPacket.WriteDWord(0,dwKey1OutBuffer[4]);
   csFifthPacket.WriteDWord(0,dwKey1OutBuffer[3]);
   csFifthPacket.WriteDWord(0,dwKey1OutBuffer[2]);
   csFifthPacket.WriteDWord(0,dwKey1OutBuffer[1]);
   csFifthPacket.WriteDWord(0,dwKey1OutBuffer[0]);
#endif
   
   csFifthPacket.WriteDWord(0, Key2Len);   // key2 length R
   csFifthPacket.WriteDWord(0, dwKey2Product); // Key2 Product R
   csFifthPacket.WriteDWord(0, dwKey2Public); // Key 2 Number 1 R?
   csFifthPacket.WriteDWord(0, Key2Unknown); // Key 2 Unknown
#if OUTPUT_TO_LE == FALSE
   csFifthPacket.WriteDWord(1,dwKey2OutBuffer[0]); // KEY 2
   csFifthPacket.WriteDWord(1,dwKey2OutBuffer[1]); // HASHED DATA
   csFifthPacket.WriteDWord(1,dwKey2OutBuffer[2]);
   csFifthPacket.WriteDWord(1,dwKey2OutBuffer[3]);
   csFifthPacket.WriteDWord(1,dwKey2OutBuffer[4]);
#else
   csFifthPacket.WriteDWord(0,dwKey2OutBuffer[4]);
   csFifthPacket.WriteDWord(0,dwKey2OutBuffer[3]);
   csFifthPacket.WriteDWord(0,dwKey2OutBuffer[2]);
   csFifthPacket.WriteDWord(0,dwKey2OutBuffer[1]);
   csFifthPacket.WriteDWord(0,dwKey2OutBuffer[0]);
#endif

   csFifthPacket.WriteString(CRExeInfo); // From CheckRevision()
   csFifthPacket.WriteString(CDKeyOwner);

   // These two sentences set the packet size word of packet to the packet
   // len. (Previously it was 136 instead 134).
   
   /* END OF WRITE EVERYTHING AT THE PACKET */

   
   /* SEND csFifthPacket.packet TO BATTLE.NET */
   n = SendPacket(csFifthPacket.packet, csFifthPacket.GetPacketLen());
   if(n == -1) error(10, "SendPacket");
   else cout << "Packet 0x51 Sent " << "Bytes: " << n << endl;
   /* END OF SEND PACKET TO BATTLE.NET */

   return n;
}


void HashData(DWORD length, LPVOID outbuf, LPVOID tohash)
{
  DWORD len = length;
  __asm
  {
     push ecx
     push edx
     mov ecx, outbuf
     mov edx, tohash
     push len
     call HashFunction
     pop edx
     pop ecx
  }
}


void RunCDkeyDecode(DWORD *Product, DWORD *CDKeyVal1, DWORD *CDKeyVal2, const char *CDKey)
{

  __asm
  {
     push ecx
     push edx
     mov ecx, CDKey
     mov edx, Product
     push CDKeyVal2
     push CDKeyVal1
     call DecodeCDKeyFunction
     pop edx
     pop ecx
  }
}


The CheckRevision() function is in the first page of the topic, but as I wrote, I tested it yesterday so I think it works well. I think I posted my WriteDWord() function in the sixth or seventh page of the topic.
I haven't posted the full source of the class because it's kinda long but if anyone wanna see it I have no inconvenience in posting it.

Also, I posted the packet logs 2 or 3 posts back.

Kp

This is easy.  The server checks if you got the right version.  If you didn't, it sends invalid version and quits processing your message.  If your version is right, then it checks your CD key.  So, your cdkey has apparently been wrong all this time, but the server was ignoring it until recently, since you couldn't even get the version information right.
[19:20:23] (BotNet) <[vL]Kp> Any idiot can make a bot with CSB, and many do!

z-stars

Quote from: Kp on July 27, 2004, 06:24 PM
This is easy.  The server checks if you got the right version.  If you didn't, it sends invalid version and quits processing your message.  If your version is right, then it checks your CD key.  So, your cdkey has apparently been wrong all this time, but the server was ignoring it until recently, since you couldn't even get the version information right.

Yeah but why does bnet get so "angry" about invalid cd keys, and it doesn't care about invalid versions? and more important, what do I do for the CD Key thing to work well?

MyndFyre

Quote from: z-stars on July 27, 2004, 06:30 PM
Yeah but why does bnet get so "angry" about invalid cd keys, and it doesn't care about invalid versions? and more important, what do I do for the CD Key thing to work well?

I'm not sure what you mean by "angry", but Battle.net (once upon a time) took an aggressive stance about bots.  Any violations of the protocol result in immediate disconnect.

I imagine that having an invalid CD key is more cause for IP banning because it appears you stole their client, rather than invalid version because it appears that their client simply needs to be upgraded.
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

z-stars

#109
Quote from: Myndfyre on July 27, 2004, 06:43 PM
Quote from: z-stars on July 27, 2004, 06:30 PM
Yeah but why does bnet get so "angry" about invalid cd keys, and it doesn't care about invalid versions? and more important, what do I do for the CD Key thing to work well?

I'm not sure what you mean by "angry", but Battle.net (once upon a time) took an aggressive stance about bots.  Any violations of the protocol result in immediate disconnect.

I imagine that having an invalid CD key is more cause for IP banning because it appears you stole their client, rather than invalid version because it appears that their client simply needs to be upgraded.

I see, but about my prog, nobody knows why could it be failing? :(

OnlyMeat

Here this is what i do when im testing out new packets:-

(1) Packet log the real client.
(2) Isolate the 0x50 packet bnet sends the real client (serialize as binary file )

(3) Load the serialized 0x50 packet into your program as if you were processing the real 0x50. Also you need to record the cookies the real client used when sending 0x51, this should'nt be a problem cuz they are sent with the packet in raw form at a fixed offset, then hardcode those cookies in your 0x51 construct for the testing duration.

(4) Now Serialize the 0x51 packet your program produces in response to 0x50

(5) Now the important part compare the the real clients 0x51 with yours in a hex editor (visual studio will do)

(6) the 2 packets should be exactly the same!, if not then you will see immediatly where the problem is.

This procedure works very well for me, just improvise these kind of testing procedures and it makes it easier to get this stuff right first time without getting ip banned!!

z-stars

#111
Quote from: OnlyMeat on July 27, 2004, 07:28 PM
Here this is what i do when im testing out new packets:-

(1) Packet log the real client.
(2) Isolate the 0x50 packet bnet sends the real client (serialize as binary file )

(3) Load the serialized 0x50 packet into your program as if you were processing the real 0x50. Also you need to record the cookies the real client used when sending 0x51, this should'nt be a problem cuz they are sent with the packet in raw form at a fixed offset, then hardcode those cookies in your 0x51 construct for the testing duration.

(4) Now Serialize the 0x51 packet your program produces in response to 0x50

(5) Now the important part compare the the real clients 0x51 with yours in a hex editor (visual studio will do)

(6) the 2 packets should be exactly the same!, if not then you will see immediatly where the problem is.

This procedure works very well for me, just improvise these kind of testing procedures and it makes it easier to get this stuff right first time without getting ip banned!!


I think I did something like this with CheckRevision(), but how do I get the Client Token  that d2 uses? I get my prog's with GetTickCount()

MyndFyre

Quote from: z-stars on July 27, 2004, 06:56 PM
Quote from: Myndfyre on July 27, 2004, 06:43 PM
Quote from: z-stars on July 27, 2004, 06:30 PM
Yeah but why does bnet get so "angry" about invalid cd keys, and it doesn't care about invalid versions? and more important, what do I do for the CD Key thing to work well?

I'm not sure what you mean by "angry", but Battle.net (once upon a time) took an aggressive stance about bots.  Any violations of the protocol result in immediate disconnect.

I imagine that having an invalid CD key is more cause for IP banning because it appears you stole their client, rather than invalid version because it appears that their client simply needs to be upgraded.

I see, but about my prog, nobody knows why could it be failing? :(

It's not written correctly?  Improper debugging techniques?  Random bad luck?

The 0x51 Client Session Key / Client Token is a randomly-generated value.  GetTickCount() would work; there are really no restrictions on it, except that it's used for hashing the CD key.
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

z-stars

#113
But how can I find what's the Client Token the real d2 client uses in a certain time? If I knew this I could try the hash cd key function with fixed values to see if they are the same than the real d2 client generates...

BTW, does anyone have some working code that hashes a cd key and puts it into a rdy to send packet so I can compare with my code?

OnlyMeat

Quote from: z-stars on July 28, 2004, 07:02 AM
But how can I find what's the Client Token the real d2 client uses in a certain time? If I knew this I could try the hash cd key function with fixed values to see if they are the same than the real d2 client generates...

BTW, does anyone have some working code that hashes a cd key and puts it into a rdy to send packet so I can compare with my code?

Well if i remember correctly the seed is the first dword in the 0x51 packet the client sends, take the code i posted in the first page of this topic ( you really should have read it ) it contains the first packet entries:-


   ///////////////////////////////////////////////////////////////////////////////////
   // Fill-in default version info
   Packet   << nSeed             // Seed
         << nVersion             // Client Version
         << nChecksum            // Checksum from files
         << pAuthInfo->nCDKeys   // No. cd-keys
         << (UINT)0x00;          // Spawn (BOOL)


So it just should be a matter of hard coding the first DWORD in the 0x51 packet the client sends into your 0x51 generation routine and loading the serialized 0x50 packet from the original packet log.

Hope this helps.

MyndFyre

Quote from: z-stars on July 28, 2004, 07:02 AM
But how can I find what's the Client Token the real d2 client uses in a certain time? If I knew this I could try the hash cd key function with fixed values to see if they are the same than the real d2 client generates...

BTW, does anyone have some working code that hashes a cd key and puts it into a rdy to send packet so I can compare with my code?

I really don't think it matters what the number is, but if you're really that concerned about it, why don't you extract the 0x51 client key value from the 0x51 C->S packet from your packet log of the actual client?

This was your packet log:


0000  FF 51 86 00 58 01 3F 01 00 0A 00 01 5C D5 B3 27    .Q..X.?.....\..'
0010  02 00 00 00 00 00 00 00 10 00 00 00 06 00 00 00    ................
0020  D9 15 0D 00 00 00 00 00 xx xx xx xx xx xx xx xx    ................
0030  xx xx xx xx xx xx xx xx xx xx xx xx 10 00 00 00    ..7...H.........
0040  0A 00 00 00 FB F9 12 00 00 00 00 00 xx xx xx xx    ............MUjt
0050  xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx    lc.D........'NJQ
0060  47 61 6D 65 2E 65 78 65 20 31 30 2F 31 33 2F 30    Game.exe 10/13/0
0070  33 20 30 38 3A 33 35 3A 33 30 20 31 31 39 38 38    3 08:35:30 11988
0080  35 37 00 4D 65 00                                                    57.Me.


The client key occurs at offset 0x04 to 0x07.  With reversed byte order, it's 0x013f0158.
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

|