Valhalla Legends Forums Archive | Battle.net Bot Development | Confused about CD-Key hashing

AuthorMessageTime
Jailout2000
I've tried to understand how CD-Key hashing works, for SID_AUTH_CHECK and the old way using SID_CDKEY2/SID_CDKEY.

The part I'm not understanding is how it is done. What is the "public" key? What is the "product" value?

I assume the Key Length value is the length of the CD-Key, as seen before anything is done to it, for example: Length = 13 for 0123456789012.
I assume the Product value is what Product the key belongs to, for example D2DV or STAR.
I assume the Public value is a special key that is used when hashing the CD-Key.
And then I assume the hashed data is the actual hash of the CD-Key.

I fail to understand how this process works, and looking at many sources didn't help me much. I even looked at the source for BNCSutil and JBLS.

If someone can explain on this, that would be great. I am trying to make my bot independent of BNCSutil, that way I don't have to make sure it is present when someone uses my bot.

Not really on-topic, but I feel it is necessary... BNCSutil fails to version check my bot (and in turn failing the version check for Battle.net), and I don't know why. I can provide packet logs if needed.
October 21, 2009, 11:41 AM
HdxBmx27
Cdkeys that you see on your CD case are in an 'encoded' format. When you decode them they turn into 3 different values, Public, Private and Product. These three values are used in verifying that the cdkey is lagitimate.
If you take a look Here you will see that for the old 13 digit SC cdkeys, the digits are shuffled around a bit, and then after the shuffle you simply extract the 3 values using SubStr() (Mid() if you're using VB6)

Its actually not that difficult to understand, all of the decoding functions are basically the same, except for where exactly they take the valus from the result, and a few index changes.

As for the hashing issues, obviously if BNCSutil doesn't give you the proper values, you should not even be sending them to bnet.
I cant really help you with it as BNCSutil.dll is kinda old, (doesn't have lockdown) but if you use it correctly, it will work.
October 21, 2009, 1:21 PM
Camel
Iago's lockdown code is a sufficient suppliment to BNCSUtil. You'll need .bin files to pass lockdown, but you can find those anywhere you can illegitimately download hash files anyways.

This isn't the 'official' iago code, but I'm mirroring it for my own project here:
http://code.google.com/p/cbls/source/browse/#svn/trunk/CBLS/src/lockdown
October 21, 2009, 5:04 PM
Jailout2000
[quote author=Hdx link=topic=18096.msg183566#msg183566 date=1256131266]
Cdkeys that you see on your CD case are in an 'encoded' format. When you decode them they turn into 3 different values, Public, Private and Product. These three values are used in verifying that the cdkey is lagitimate.
If you take a look Here you will see that for the old 13 digit SC cdkeys, the digits are shuffled around a bit, and then after the shuffle you simply extract the 3 values using SubStr() (Mid() if you're using VB6)

Its actually not that difficult to understand, all of the decoding functions are basically the same, except for where exactly they take the valus from the result, and a few index changes.[/quote]This didn't make sense until someone else in a different topic said there was 3 DWORD's in a CD-Key. Now it makes sense. But now I'm confused on why the newer CD-Keys have 26 characters and not 12, and why the older CD-Keys have 13 characters instead of 12.

What CD-Keys use what part of the encoding, and how would I go about getting each value? I know that STAR/SEXP uses 13 characters and consists of purely numbers, I know that D2DV/D2XP/W2BN consists of 16 characters (4 DWORD's?) and what appears to be hexadecimal values, and then I know WAR3/W3XP consist of 26 characters that appear just like the D2DV/D2XP/W2BN CD-Keys, but longer.
October 22, 2009, 12:37 AM
HdxBmx27
If you would reason the source I linked you to you will see, that:
For 13-digit numeric cdkeys, the last digit is a 'checksum' digit. See Verify()
The CDKey is shuffled around, see getFinalValue()
After that you extract the values from the string:
Product: 1st 2 digits
Public: 3rd through 10th digits
Private: 11th through

For 16-char alpha-numeric cdkeys its pretty much the same, just different shuffle types.
Product: 1st 2 Digits (in hex)
Public: 3rd through 7th digits (in hex)
Private: 8th through 15th digit (in hex)

26-character alpha-numeric keys are a bit more complicated, but in essence once again they have a relativity simple decoding function applied to them, and the 3 values are extracted.


What language are you working in?, there are plenty of sources out there that will decode any of the cdkeys used by battle.net. It wouldn't be hard to find one int he language you need.
October 22, 2009, 1:05 AM
Jailout2000
Actually, it would be hard to find one in the language I need. I am using a language like VB.NET, but is a bit different. I am using REALbasic 2009 Release 2 Studio Edition. I've been able to convert [u]most[/u] documentation and examples for my bot, from many languages including VB6, Java, C++, and even PHP. Some things still don't make sense to me though.

Believe me, I'm not too relieved that I'm using RB, but for some reason, I can get it to be quicker than VB6 coding can be. I hooked my bot up (after building the parsing functions) to a personally written server, and made it spam the bot like hell. I then did the same thing for two bots made in VB6, FooLOps and StealthBot. My bot was done with 1,000 EID_INFO's in SID_CHATEVENT about the length of 4-10 characters when FO and SB caught up about 4-8 seconds later. So I don't have any plans to switch from a compiler everyone seems to dislike.

I do get what you mean in the code; I can understand lots of languages' code. I am looking at how the shuffling is done, and I'm not completely following how it is done though. Can you further explain the entire process? I want to get a good grasp on this before I implement it into my bot and risk getting a 2-week IP-ban (unless I go on a PvPGN server).
October 23, 2009, 12:10 AM
HdxBmx27
[quote author=Jailout2000 link=topic=18096.msg183590#msg183590 date=1256256618]Actually, it would be hard to find one in the language I need. I am using a language like VB.NET, but is a bit different. I am using REALbasic 2009 Release 2 Studio Edition. I've been able to convert [u]most[/u] documentation and examples for my bot, from many languages including VB6, Java, C++, and even PHP. Some things still don't make sense to me though.[/quote]Odd, didn't think anyone used REALBasic anymore. But if there are any particular aspects of things that you don't understand, ask specific questions, not general ones. Also posting your attempt at converting, and your results/test code would help.
[quote author=Jailout2000 link=topic=18096.msg183590#msg183590 date=1256256618]Believe me, I'm not too relieved that I'm using RB, but for some reason, I can get it to be quicker than VB6 coding can be. I hooked my bot up (after building the parsing functions) to a personally written server, and made it spam the bot like hell. I then did the same thing for two bots made in VB6, FooLOps and StealthBot. My bot was done with 1,000 EID_INFO's in SID_CHATEVENT about the length of 4-10 characters when FO and SB caught up about 4-8 seconds later. So I don't have any plans to switch from a compiler everyone seems to dislike.[/quote]That is actually not a valid test. You are not testing the speed of the languages, you are testing the speed of specific implementations. I am pretty sure that SB does about 10x more things then your bot does when it receives a chat event.
It add chats which triggers a change event which re-evaluates the entire RTB for color codes (rather dumb..) it fires off and waits for scripting events to finish, it queues up the raw packets for its logger, it ... you get my point. If you were to strip out all the extra stuff SB does, it'd probably be just as fast, if not the differences would be minute, as your code. But thats neither here not there so meh.

[quote author=Jailout2000 link=topic=18096.msg183590#msg183590 date=1256256618]I do get what you mean in the code; I can understand lots of languages' code. I am looking at how the shuffling is done, and I'm not completely following how it is done though. Can you further explain the entire process? I want to get a good grasp on this before I implement it into my bot and risk getting a 2-week IP-ban (unless I go on a PvPGN server).[/quote]
What aspect of the shuffle has you stumped?
I'll see if I can dig out my 'super clean' version of the cdkey decoding (I made it to make things easier to understand), but I forgot where i put it.
But what I would do is not even do the decoding while connected to battle.net
Get a program that you know decodes cdkeys properly, BNCSUtil.dll does a good job :P
And just start comparing outputs.
EA:
Write a VB6 app that uses BNCSUtill.dll, and does nothing put print out the public private and product values of a cdkey.
Then Output those values from your program, if they match up, it means you did it correctly and will not get IP banned from bnet.

99% of everything about battle.net can be tested OFFLINE with no risks of getting IPBanned.


October 23, 2009, 1:29 AM
Jailout2000
[quote author=Hdx link=topic=18096.msg183591#msg183591 date=1256261364]Odd, didn't think anyone used REALBasic anymore. But if there are any particular aspects of things that you don't understand, ask specific questions, not general ones. Also posting your attempt at converting, and your results/test code would help.[/quote]
Yeah, not many people do use REALbasic. As I said, many dislike it and for good reason; even I dislike it at times.

Specific questions... How does the code within the For...Next work, what is it doing besides some shuffle? I am having trouble reading lines like c ^= (byte) (hashkey & 7); and why it matters to even use exponents (c ^= (byte)). Now that I look at it, it is mostly the same code I've seen before.
[code]                for (short i = 11; i >= 0; i--) {
                        c = cdkey.charAt(seq);
                        if (c <= '7') {
                                c ^= (byte) (hashkey & 7);
                                hashkey >>>= 3;
                        } else c ^= (byte)(i & 1);
                        key[i] = (char)c;
                }
[/code]Here is my understanding of this code:
1. The loop is going backwards (11 to 0), which means it starts from the right of [i]seq
and goes to the left (assuming seq is the encoded CD-Key, as seen by humans).
2. It is getting a specific character at index i and length 1, like you are using c = Mid(seq, i, 1).
3. Checks if the value gotten from Mid(), c, is less than or equal to 7:
4-1. If true, it combines 7 using bitwise into the hashkey and then makes it into an exponent <-- confusing.
4-2. It makes hashkey bitwise right and equal 3? <-- confusing. I know it is doing Shift-right in Bitwise, but why equal 3?
5. If false, it does the same thing as 4 but uses i instead of hashkey and adds a bitwise 1 instead of 7.
6. It prepends (because the loop is going backward) to the decoded key value what c now equals.

My project code isn't really complete, right now it uses BNCSutil or BNLS (depending on circumstances and settings). I haven't completed the CD-Key decoding (I have it set everything to zero's) because my bot always fails the version check when using local hashing, BNCSutil, or even the BNLS.

[quote author=Hdx link=topic=18096.msg183591#msg183591 date=1256261364]That is actually not a valid test. You are not testing the speed of the languages, you are testing the speed of specific implementations. I am pretty sure that SB does about 10x more things then your bot does when it receives a chat event.
It add chats which triggers a change event which re-evaluates the entire RTB for color codes (rather dumb..) it fires off and waits for scripting events to finish, it queues up the raw packets for its logger, it ... you get my point. If you were to strip out all the extra stuff SB does, it'd probably be just as fast, if not the differences would be minute, as your code. But thats neither here not there so meh.[/quote]
This is how my socket receives its data, in a way that won't ever jumble up a packet and get packet read errors.
1. Data comes in from the server and gets put into an internal buffer ( Buffer = Buffer & NewData ).
2. It checks the length of the buffer if it equals at least 4 ( LenB(Buffer) >= 4 ).
3. If yes ( >= 4 ), it goes ahead and reads the first 4 bytes (the header) for 0xFF, the ID, and the length.
4. If the first byte is not 0xFF, then we disconnect assuming it is not Battle.net. Put the ID and length into a temporary variable and then read length like we did 2 ( LenB(Buffer) >= Length ).
4. If that check also went okay ( LenB(Buffer) >= Length ), then it gives that packet (the two temporary variables ID and length, and then the data it reads as a parameter) to another function which parses it.
5. It removes that entire packet, according to the length specified, from the buffer so it can read the next packet in-line. Then the entire process starts over from 2.
6. It continues reading until a check fails ( LenB(Buffer) < 4; LenB(Buffer) < Length; Connected = False; ).
7. It waits for more data from the server.
As you can see, it is a complicated process, and is probably just easier to show you the code; but even the code is long.
In the parse function, it has four parameters. Packet ID, Packet Length, Packet Data, and then the Full Packet (the packet as pulled from the buffer).
1. Initialization of buffers, variables, and some other junk for packets that may be read later.
2. Look at Packet ID, using a Select Case ( or switch{} ) statement, and see if we find the ID.
3. If yes, do the code associated. If no, cancel out of the parse, and in turn cancelling the read of the buffer or packet, or a disconnect (depends what we were waiting for).
4. The code associated varies a lot from packet to packet, but the concept is the same for most packets. If it has a lot of things associated with it like SID_AUTH_CHECK or SID_CHATEVENT, it gets its own child parse function, otherwise it gets parsed here.

That is how my bot does things from Battle.net. In each child parse function, there is easily double or triple the amount of stuff than there is in the original parse function. As for a chat event, my bot uses the same concept from the original parse function-it reads the event id instead of the packet id, same things happen if it doesn't find the event id.
For a talk/emote/whisper, it prints it out to the chat box then gives it off to yet another function for parsing of any bot commands. That function is very complicated and I'm still working out the kinks, but it works like StealthBot 2.699 Beta does (in the end-user's standpoint and not in code).
For most of the other events, it will do the usual. For an info/error, it will just print it regardless. For channel-specific things like restricted or full, it will display what any other bot does but actually includes the channel name (as seen from Text).

Now that I have that off my chest and hopefully have explained most of how my bot does things (I know I use functions a lot lol, I love using them I guess).

[quote author=Hdx link=topic=18096.msg183591#msg183591 date=1256261364]What aspect of the shuffle has you stumped?
I'll see if I can dig out my 'super clean' version of the cdkey decoding (I made it to make things easier to understand), but I forgot where i put it.
But what I would do is not even do the decoding while connected to battle.net
Get a program that you know decodes cdkeys properly, BNCSUtil.dll does a good job :P
And just start comparing outputs.
EA:
Write a VB6 app that uses BNCSUtill.dll, and does nothing put print out the public private and product values of a cdkey.
Then Output those values from your program, if they match up, it means you did it correctly and will not get IP banned from bnet.

99% of everything about battle.net can be tested OFFLINE with no risks of getting IPBanned.[/quote]
1. I explained that above.
2. I'd like that if you could, though it is probably like all the others unless you truly added massive comments or easier-to-read code.
3. You would decode after you save the CD-Key, or sometime before connecting? And/or save the decoded version in the settings? That may be an idea. lol
4. BNCSUtil.dll always says fail for me, but yet when I see an example, I don't see what I do wrong. I don't have the code to show you anymore =[
5. I haven't compared outputs yet because I still have yet to even get an output from my own code... or at least an output that makes sense lol.
6. I know lots of stuff can be tested offline, but there comes a time when PvPGN isn't always accurate or my findings contradict what I'm testing and I turn to testing it on actual servers to get a better idea of what happens. One of the quick-add features I made to my bot was the ability to use other bots to get past version check, cd-key, and login. After that, it doesn't need the other bot except for warden bypass. I plan to leave this feature in my bot as an Advanced feature, and I use it for testing some things anyway.
October 23, 2009, 3:12 AM
HdxBmx27
[quote author=Jailout2000 link=topic=18096.msg183592#msg183592 date=1256267567]Specific questions... How does the code within the For...Next work, what is it doing besides some shuffle? I am having trouble reading lines like c ^= (byte) (hashkey & 7); and why it matters to even use exponents (c ^= (byte)). Now that I look at it, it is mostly the same code I've seen before.[/quote]
Thats not exponent, thats the Bitwise XOR option.
[quote author=Jailout2000 link=topic=18096.msg183592#msg183592 date=1256267567]Here is my understanding of this code:
1. The loop is going backwards (11 to 0), which means it starts from the right of seq and goes to the left (assuming seq is the encoded CD-Key, as seen by humans).
2. It is getting a specific character at index i and length 1, like you are using c = Mid(seq, i, 1).
3. Checks if the value gotten from Mid(), c, is less than or equal to 7:
4-1. If true, it combines 7 using bitwise into the hashkey and then makes it into an exponent <-- confusing.
4-2. It makes hashkey bitwise right and equal 3? <-- confusing. I know it is doing Shift-right in Bitwise, but why equal 3?
5. If false, it does the same thing as 4 but uses i instead of hashkey and adds a bitwise 1 instead of 7.
6. It prepends (because the loop is going backward) to the decoded key value what c now equals.[/quote]
1) seq is not the CDKey, cdkey is. seq is an integer array that holds the [u] sequence[/u] we want to extract the values from the cdkey.
2) It's actually getting the character at index seq(i), So basically: c = Mid(cdkey, seq(i), 1)
3)  Actually less then or equal to '7' which is 0x37. We're dealing with ASCII here.
4-1) It grabs the last 3 bits of the hash key (7 in binary is 00000111)  and Bitwise XORs it with c, in VB6 the code would be: c = (c XOr (hash_key And 7))
4-2) it does a Bitwise shift right 3 bits. And then assigns the value to hash_key. hash_key = (hash_key >>> 3); does the same thing.
5) once again it just Bitwise XORs c[i] with either 1 or 0, depending on if [i]i is odd or even respectively.
6) Yup[quote author=Jailout2000 link=topic=18096.msg183592#msg183592 date=1256267567]My project code isn't really complete, right now it uses BNCSutil or BNLS (depending on circumstances and settings). I haven't completed the CD-Key decoding (I have it set everything to zero's) because my bot always fails the version check when using local hashing, BNCSutil, or even the BNLS.[/url] [/quote]Interesting, if you use BNLS/BNCSutill you shouldn't failed version check, maybe you're handeling the data improperly? I'd check your data buffer class.

[quote author=Jailout2000 link=topic=18096.msg183592#msg183592 date=1256267567]
This is how my socket receives its data, in a way that won't ever jumble up a packet and get packet read errors.
...
Now that I have that off my chest and hopefully have explained most of how my bot does things (I know I use functions a lot lol, I love using them I guess).[/quote] You just described how EVEY battle.net bot is setup. What I was talking about was the specific extras that the bots do AFTER the initial event split up, like printing to the screen, screwing where the database, firing off scripting events, etc.. but it's not important.

[quote author=Jailout2000 link=topic=18096.msg183592#msg183592 date=1256267567]1. I explained that above.
2. I'd like that if you could, though it is probably like all the others unless you truly added massive comments or easier-to-read code.
3. You would decode after you save the CD-Key, or sometime before connecting? And/or save the decoded version in the settings? That may be an idea. lol
4. BNCSUtil.dll always says fail for me, but yet when I see an example, I don't see what I do wrong. I don't have the code to show you anymore =[
5. I haven't compared outputs yet because I still have yet to even get an output from my own code... or at least an output that makes sense lol.
6. I know lots of stuff can be tested offline, but there comes a time when PvPGN isn't always accurate or my findings contradict what I'm testing and I turn to testing it on actual servers to get a better idea of what happens. One of the quick-add features I made to my bot was the ability to use other bots to get past version check, cd-key, and login. After that, it doesn't need the other bot except for warden bypass. I plan to leave this feature in my bot as an Advanced feature, and I use it for testing some things anyway.
[/quote]
2) Meh its really easy to read but i cant seem to find it
3) I would decode the cdkey in a debug version of my app so that i could tet to see if its working. If I wanted to add in validation to user inputted keys, i'd do it in w/e form controls the input information.
4) Are you using it properly? If you do it properly BNCSutil will work fine.
6) PvPGN isn't offline, by offline i mean not connecting to any servers at all.
October 23, 2009, 4:12 AM

Search