11:16 PM

profile

BALATRO

Recently I found Balatro - a Poker (actually Big Two) based card game. I'm usually not good at all types of video games, and with curiosity, I decided to find out how this game was made.

Based on wikipedia and google, this game was made by Löve - a framework that helps users program games using Lua. You can learn more about it here.

The game directory only includes an executable file and some dll files, no folders. So my guess at the moment is that all the assets and logic of the game are packaged inside that exe file.

balatro1

Continue searching on google with the keywords "Love2D", "windows", "executable" and I found a link to love2d's wiki about creating exe file.

WindowsTo create your game executable under windows use the command line to runcopy /b love.exe+SuperGame.love SuperGame.exe

This information is really helpful. The command "copy /b ..." simply merges the binary of the two files together. In other words, if we have file A with the content "love" and file B with the content "2d", the command "copy /b A+B C" will create a file C with the content "love2d".

The official file "love.exe" when opened alone will look like this:

balatro2

With that in mind, let's try to unpack the game.

This link contains some information about file signatures - which will be extremely helpful in distinguishing between love.exe and the rest (the zip file).

Accordingly, the exe file will start with "\x4d\x5a" (MZ) and the zip file will usually be "\x50\x4b\x03\x04" (PK....)

First, we open the game's original exe file (Balatro.exe) in the hex editor to analyze.

balatro3

Actually, we don't need to care whether the file starts with "MZ" or not because that's obvious. The "copy" command also creates an exe file, and for that exe file to be considered valid, it must begin with "MZ", and "MZ" is the beginning of "love.exe" anyway. So the remaining thing we need to find is where the zip file begins.

Try searching "5b 40 03 04" and we get a lot of results:

balatro4

But after trying to find out if there is a case where there are multiple zip files packed or not, it seems that there is usually only 1 zip file like the command on the wiki. And almost all the results (because I haven't looked at them all) are between a lot of garbages while only the first result is after "\x00\x00\x00\x00..."

Considering that the first result will be the start of the zip file, I wrote a python script to extract it.

code1

The exe file we just extracted needs some dlls (located in the original game folder), so we need to copy them to the same folder. Now test the exe file and what is displayed is exactly the same as the official "love.exe" file.

balatro5

The next step is unzip the zip file. Our file was successfully recognized as a zip file and extracted without any error:

balatro6

After looking around the code for a while, I believe we can do a lot of things with it, like creating new logic or modifying one or more existing logic, creating a new card with completely new effects, Change text in game, etc.

As the two examples below, I will try to do the following two things: 1. Modifying the number of chips received to 1337; 2. Do the same thing, but for the money I would have received after each round.

The number of chips will basically be calculated based on our hand (not including jokers and tarot cards). The evaluate_poker_hand function seems to be what performs the function of analyzing the hand and then returning the result as to what type it is.

balatro7balatro8balatro9

The function evaluate_play calls 2 interesting functions: mod_mult and mod_chips.

balatro10balatro11

Change the return of mod_chips from _chips to 1337 and leave it there for now.

Next, we'll try to modify the money. The amount to be added to the existing amount is always displayed next to the text "Cash out".

balatro12balatro13balatro14balatro15balatro16

The way to win each blind is to have chips >= a certain number of chips in each blind (G.GAME.chips (our chips) >= G.GAME.blind.chips). Then it'll recalculate our money (dollar) by adding with G.GAME.blind.dollars. Let's change it to 1337 as well.

Now the next step is pack the game back again. I also wrote a script to do that.

packedaway

Now go to the directory that contains our patched game and run it.

The chips became 1337 as expected, but the money was 1340 instead of 1337 because I modified it at the wrong place. The money is also modified with the number of hands/discards left + some bonuses.

I test the game in the first round so there won't be any bonuses (from tarot or joker cards). So just modify the amount in case hand/discard left.

balatro18balatro19Conclusion? I guess

Well... Nothing much to say about this. Love2D is an open-source so anyone can learn about it more easily than ever. The way a complete game file is created is just simply by joining two files together, absolutely no obfuscation. Most of the time we spend is to understand the logic of the game from the extracted source. The bigger the game, the more time it takes to understand it. Finally, the main reason I want to share this with everyone is because I personally think it's quite interesting for those who want to learn about how software like video games are made.