0

I have a string that I found, that is probably hashed in base64. Decoding it returns error characters in every encoding I've tried. I also can't access the code that generated it and can't reverse engineer it.

This is the base64: AAECAR8GxwPJBLsFmQfZB/gIDI0B2AGoArUDhwSSBe0G6wfbCe0JgQr+DAA=

Now, its 60 byte long, and all the characters are valid for base64, if you have a better guess than base64 inform me!

I also have converted it into a byte array, but I don't really know how to convert the byte array to a string with different encoding. Maybe I could run a for each loop that prints the resulting string in different encodings, till I find one that is the actual text?

DimosthenisK
  • 61
  • 1
  • 6
  • On a side note, the original program that generated this code is a game that uses the unity engine. – DimosthenisK May 16 '17 at 18:01
  • It might be in a encoded in a charset you don't expect, also when you say you "found" the string, there's no reason it should be human-readable. It might just be any binary data! – TomTom101 May 16 '17 at 19:15

2 Answers2

5

This is the new deck encoding from Hearthstone. It indeed is valid base64, it just will never translate to plain text.

$ echo 'AAECAR8GxwPJBLsFmQfZB/gIDI0B2AGoArUDhwSSBe0G6wfbCe0JgQr+DAA=' | base64 -D | od -t u1
0000000     0   1   2   1  31   6 199   3 201   4 187   5 153   7 217   7
0000020   248   8  12 141   1 216   1 168   2 181   3 135   4 146   5 237
0000040     6 235   7 219   9 237   9 129  10 254  12   0
0000054

It is likely a custom struct serialization format specific to Hearthstone, with a field indicating the class, and the rest being a mapping of card id number (which I don't think are public yet) to amount of cards. You can clearly see some patterns if you re-arrange the formatting:

   0   1
   2   1
  31   6
 199   3
 201   4
 187   5
 153   7
 217   7
 248   8
  12
 141   1
 216   1
 168   2
 181   3
 135   4
 146   5
 237   6
 235   7
 219   9
 237   9
 129  10
 254  12
   0

Until the new update is released we can't really know more. When the update is out, it will be easy to experiment, exporting a one card only deck and comparing the result.

Tenchi2xh
  • 190
  • 1
  • 7
  • Thank you very much, It makes much sense now. I expected something like a json object. What did you use to convert that string from base64 to something readable, if I may ask?? – DimosthenisK May 17 '17 at 09:01
  • In this example I used bash commands: `base64` and `od`. `od` is like a hex viewer except you can choose the format a file is displayed in, like hexadecimal, decimal, C notation etc. – Tenchi2xh May 17 '17 at 12:50
  • In particular, piping a file through `od -t u1` like in the example will show every byte in unsigned decimal. By the way, if you are interested I made a really basic Python parser for deck codes inspired by @Tim's response – Tenchi2xh May 17 '17 at 12:52
4

To build on Tenchi2xh's answer, we can use the decklist that comes with the string to help figure out the meaning of the numbers.

  • 0 1 2 1 31 - some kind of header, probably indicating the class, format, and year
  • 6 - number of cards that appear 1x in the deck
  • Then there are 12 bytes, we can interpret these as 6 16-bit integers: 967 1225 1467 1945 2009 2296 - each of these is one card that appears 1x in the deck
  • 12 - number of cards that each appear 2x in the deck
  • 12 more 16-bit integers: 397 472 680 949 1159 1426 1773 2027 2523 2541 2689 3326 - each is a card that appears 2x
  • 0 - padding at the end

The last thing to figure out is which cards those 16-bit numbers are referring to. Luckily it's not too complicated, they are just slightly modified versions of the cards' "DBF IDs". I looked these up at HearthstoneJSON. The way to get the DBF ID from a number x is:

dbfId = (x >> 8) << 7 | (x % 128) (or in other words, keep the lowest 7 bits the same, and shift the rest right by 1)

For example: 967 decodes to DBF ID 455, which is Snake Trap. 3326 corresponds to DBF ID 1662, which is Eaglehorn Bow.

Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
Tim
  • 41
  • 2