edicted Blog Banner

edicted

QR Codes (A HackMUD Story)

https://img.inleo.io/DQmWdsy8gJTxGw4cucz8JpYTBBWDM3gRAjz5TruDtnZRYt1/image.png

image.png

The journey continues.

My HackMUD adventures have brought me to a new level of debasement. After writing scripts that would scrape corporate frontends for Tier 1 locations to hack... and then creating a cracker that would get me through the associated locks... well it was finally time to try and give tier 2 a whirl. But where to begin? <corporation.public> scrips were no longer going to hack it, so to speak.

So I went into the riskier security public scripts (from fullsec to highsec) and found <corporation.members>. After messing about in weyland.members{} for a while I found out how to retrieve QR codes that denote order numbers placed by consumers of the given corporation. The goal was to extract these order numbers and ask for a refund. This refund always gets declined but the corporation returns the location of the member themselves and allows the player to hack the customers of the corporation in T2. I unlocked my first T2 yesterday and was floored to receive over 10M GC, which is x200 times the reward of T1 locks (~50k GC). Talk about an incentive to progress in the game.

image.png

The QR codes

The codes themselves look like the one above. They contain corruption which can be repaired by running the script twice and comparing the two outputs against each other to repair the damaged zones. Luckily I had already written this function on my T1 scraper and I was able to reuse that function to repair these Quick Response Codes.

From here I was actually able to use my phone camera to read the QR code directly from the in-game command line. This gave me the 6-digit order code that allowed me to crack my first lock, but if I want to automate the process I'm going to need to create my own QR decoder, which is so so so much more complicated than I thought it would be.

This video on hand-solving QR codes was a lifesaver.

I have so much more respect for QR codes now. They are pretty complicated and have a lot of features compared to barcodes. They are essentially an upgrade to barcodes in pretty much every way. Extra space in the QR is reserved for error checking that can actually repair a broken code. If anything else the error checking ensures that corrupted data isn't fed into the scanning device.

QR as an airgap

QR codes are extremely important to crypto as well, so the overlap here between HackMUD and crypto is immense. QR codes can be used to airgap any type of data (including encrypted data) through the camera of the device taking the picture. This allows air-gapped hardware wallets to have immense security compared to something that connects to traditional operating systems through USB drives and such. This really is a magic technology within certain contexts, as it allows information to be transported via light waves in a relatively basic and low-tech way. Cameras are very cheap these days.

Source: wikipedia

image.png

Getting down to business: how to decode these things?

It turns out that a QR code is masked by one of 8 masking patterns. These masking patterns will flip the bits inside of the QR code based on an algorithm. These algorithms and their visual representations can be seen above. They look complicated but they are actually quite easy to calculate when the QR code exists within a 2D Array[i][j] consisting of i rows and j columns. All one has to do programmatically is loop through all the points of the array and flip them if the equation evaluates to true.

For example, if we are looping through a QR bitmap and the given position is Array[5][9] we would flip this bit if the masking pattern was 111 (aka on,on,on or true,true,true) which is the pattern in the top left j % 3 = 0. Because j is 9 and 9 % 3 = 0 this is true and we need to flip the bit. Conversely, a masking pattern of 100 would not be flipped because 5 % 2 does not equal zero.

At first the masking pattern seems like a completely unneeded and unnecessary complexity. However, it's extremely important as it prevents the QR code from looking like a blob and being very difficult to scan. It also helps it remain readable even if it should become damaged or corrupted. In fact my phone was able to read some of the purposefully corrupted codes in the game (before being repaired) because of the crazy error checking that these things do.

image.png

The above in-game QR code is encoded by 011; a nasty shape

It's a good thing I don't have to do this by hand lol. The algorithms will make it much easier.

image.png

A box inside a box inside a box (finder pattern)

Have you ever noticed that the corners of a QR code often look the same? This is called the "finder pattern" and it greatly helps the algorithm put the entire picture into alignment so it can decode the result.

The timing

What you may not of known is that this finder pattern is connected by the "timing". The timing is an on/off/on/off pattern that connects the finder pattern on the inside edges from the bottom-left to the top-left to the top-right. This allows the decoder to easily determine exactly how big each pixel is and the total size of the QR code and how much data could be stored within it. The timing from bottom to top and from left to right is identical, further allowing for more redundancy so that a decoder knows if any mistakes have been made.

image.png

Formatting data

Near the top-left and bottom-left finder-patterns is a bunch of critical information that we need to know. The two red pixels tell the decoder what level of error checking the QR code has. This video doesn't get into error checking at all, which is fine by me because the QRs that I want to decode aren't going to have any errors because they're not physical scans but rather data being scraped from HackMUD. However it's worth noting that more surplus space within the QR code is allocated to increase the error checking level, making it easier for the decoder to repair corrupted data.

The green block is the 3 bits of masking which we already went over. The yellow is "more formatting crap that you don't need to worry about". Sounds good to me. The blue is error correction format. So basically the main piece of information here is the masking code (which is only 3 bits). Once that is found we can use it to flip all the bits that need flipping so we can continue the decoding process.

image.png image.png

The bottom-right has critical data

The 4-bit square in the very bottom right tells us the encoding pattern. I'm being told 0100 (4) "byte" encoding is extremely common and I believe it will be the type I have to deal with in my game. A byte is 8-bits so I assume this means this type of format can store 1-byte UTF-8 (ASCII) characters which is similar to how Hive works at the base layer as well. 8-bits means there are potentially 2^8 possible characters that can be represented in these blocks which is 256 characters, but sometimes only 7 bits are used making it 128.

The one weird thing about all of this is that the 2x2 box is read top to bottom and left to right making it 0010 if we forget that binary itself is read right to left making it actually 0100 for 8-bit encoding. At the same time we can very clearly see that the "4" is highlighted and "4" in binary is 0100. Just worth noting that binary can get confusing.

box above the encoding message.

The 8 bits above the 2x2 encoding statement tell us how many characters we are actually looking for. In this case the QR code is the dude's Internet handle "Robomatics", so we would expect this section to tell us we need to find 10 characters because Robomatics is 10 characters long. 8 + 2 = 10 so it adds up correctly.

image.png

lol wut now?

From here we are looking for 10 characters and then a signal that we've reached the end.
The end is another 2x2 chunk after 10 blocks of data that should be empty. After that starts the error checking and repair which I'm not interested in, yet.

image.png image.png image.png image.png

Christ Almighty I just wanted to spell "Robomatics"

Once we know what kind of pattern we are dealing with we can start mapping the 8-bit codes to the correct ASCII characters. In the above situation we can see that 64 + 16 + 2 bits are on/true/1 and when we add up those numbers we get 82. So what does 82 map to in ASCII?

https://files.peakd.com/file/peakd-hive/edicted/23y9D9UaZmf4CLyjGM3L8FeWurz5S9iVQ3Hi8Wm9bXCP4mGznTj3AmWygWtavHqLgqPrs.png
https://files.peakd.com/file/peakd-hive/edicted/23yJborA48BxGZ1kMpxP5Hr9miUiwFRLQGR5cLW87swJ6escqUCXnYHj3pWBVA51bBEhZ.png

Did you guess capital "R"?

Good job! :D

image.png
image.png
image.png

And that spells "Robo"

The next 6 characters will spell "matics" after being decoded. And that is the gist of how QR codes work (minus the crazy error repair).

image.png

Hmmmm!

So now I have the knowledge to decode these QR codes programmatically. When will I get around to it? Who knows! Thus far just scanning the damn thing is more than worth it... although I may need to create a function that inverts the light and dark squares because most QR scanners work much better with the black bits representing "on"/"true"/"1" rather than the opposite.

Conclusion

The history of QR codes is interesting. Masahiro Hara, an employee of Japanese car company Denso Wave (subsidiary of Toyota) created them in 1994, patented them, but allowed the world to use them for free as long as the standard everyone used standardized formatting. Since then the patents have expired (2015).

The ability to transmit data using natural light or a scanning laser is a very underappreciated and underutilized piece of technology. Now that crypto uses these things for air-gaps and public key import that's starting to change, but still it's actually a bit crazy that we can do this type of stuff and nobody really seems to care... let alone figure out how it works. The more you know!


Return from QR Codes (A HackMUD Story) to edicted's Web3 Blog

QR Codes (A HackMUD Story) was published on and last updated on 10 May 2024.