Today I decided to write about something special, which will introduce you to the mystical art of hacking. This is surely not for the faint hearted!
If you’re a lover of old video game consoles, you might remember the N64 hence the Project64 Emulator for Windows. It’s a great piece of software with just one annoyance: an occassional 30 seconds so called ‘nagware’ screen, which stops you from diving right into the action.
As a side-note: Project64 is open source and available on Github, so nothing is stopping you from modifying the source code accordingly and compile your own binary to overcome the issue! But that won’t be too much fun and as I’d say: simple problems need complex solutions! Let’s get rid of that annoying screen by hacking the binary!
Prerequisites:
- Intermediate understanding of x86 assembly language
- A PC running Windows 7 or above
- Project 64 3.0.1 which needs to be set up yet, meaning you must have finished the initial setup screen as it clashes with the steps in this tutorial otherwise
- OllyDbg 1.10
Let’s start by examining what actually is happening. If you open Project 64 you will notice that sometimes there ain’t a nagscreen at all and if there is, it won’t pop-up the same time the application window itself appears. Yes, there is a delay. Keep this in mind, it will be important later on. Now let’s have a look at the nagscreen again.
Yeah, this pretty much looks like a standard Windows dialog with standard buttons. So it’s more than likely they’ve used the Win 32 API for creatings those boxes. The Win 32 API is quite big and offers a lot of ways for creating dialog boxes but as this is a modal dialog we can reduce those to a handful, namely:
DialogBoxA, DialogBoxW, DialogBoxParamA, DialogBoxParamW, DialogBoxIndirectParamA, DialogBoxIndirectParamW, DialogBoxIndirectA and DialogBoxIndirectW.
Let the fun begin! Start OllyDbg with Administator rights and open-up Project 64’s executable Project64.exe inside. Now bring up the Executable modules view by pressing Alt+E, select Project64.exe, right-click it and choose View names.
The View names view displays a rather large list of all the imported/exported functions. As I mentioned earlier Project64 is utilizing the Win32 API for the Dialog boxes, there must be an import from Windows’ USER32.dll. If you browse this list you’ll sooner or later indeed discover an entry called USER32.DialogBoxParamW.
Great! Right-click that particular entry and select Find references to import. This will open another panel with all the addresses at which the program is creating a Dialog box. Right-click this list and select Set breakpoint on every command. This will make OllyDbg pause execution of the program each time a Dialog box is requested.
Time for action! Start Project64 – inside OllyDbg – by hitting F9. If Project64 opened normally without hitting a breakpoint, chances are it didn’t request the nagscreen, so you might have to restart it by Ctrl+F2 and some subsequent presses on F9 until it finally stops at one of those breakpoints.
No worries though, it will. If it does, your CPU – main thread view will look a little like this:
Okay, at virtual address 0x0045E2D9, Project64 is calling DialogBoxParamW. You might notice the square bracket next to the virtual addresses from 0x0045D8ED to 0x0045D930, which encloses the call. That’s OllyDbg’s way of representing a procedure. Plainly speaking the Dialog box is requested inside a function which starts at 0x0045D8ED. OllyDbg is a great debugger and lets us even find out the caller of that function! Click on address 0x0045D8ED and right below the CPU window you’ll see a list of Local calls. Right-click it and select Go to CALL from 0045E2D9.
As you might have guessed this will bring the CPU view to the address of the caller. Okay, this is not too meaningful yet. Scroll-up the CPU view, so the calling address – 0x0045E2D9 – is the bottom-most entry.
Yeah! Now we can see everything we need to know! Take your time and take a close look. Remember what you might have heard yet! Does anything ring a bell? Okay, I’ll stop torturing you. The right pane reads Timeout = 2500. ms. Initially I mentioned a delay upon the nagscreen appears and les voilá, here it is. By the way, the dot next to 2500. is OllyDbg’s way to distinct a decimal from a hexadecimal number.
So
requests the dialog,
requests the timer and something before those virtual addresses sometimes decides to display the nagscreen and sometimes it does not.
Let’s step back from 0x0045E2BD to a promising jump instruction:
The x86 JE instruction takes a jump if the Zero flag bit is set. If we think about it:
- If ZF=0 it won’t jump thus continue with the normal program flow and ultimately reach the SetTimer call at 0x0045E2BD
- If ZF=1 it will jump to address 0x0045E2DE, which is after the call to the procedure at 0x0045E2D9, invoking the call to DialogBoxParamW
But what decides if the Zero flag is 0 or 1? Let’s examine the two instructions prior the JE:
The Test instruction computes a logical AND between two operands and among other flags sets the Zero flag according to the result of the computation. As in this case the two operands are the same register – AL – the Zero flag will be set to 1 if the AL register is >0 and set to 0 if the register is 0.
This is commonly used as an optimized version of CMP AL, 0, which directly checks if the e.g. AL register is zero.
What does that mean? An instruction prior to TEST AL, AL must store a number in the AL register. From the above screenshot we can see that the instruction just before is a CALL to another virtual address. Without further examination we can assume that this is the subroutine which ramdomizes the appearance of the nagscreen. If it should display it, it will set the AL register to 1 – or any other number up to 255 – and if it should not to 0.
With that in mind, there are several ways to overcome that issue but I’ve decided for something simple:
Instead of making the jump dependent on the Zero flag let’s make it jump anyway, which will completely bypass the timer routine. In x86 terms this means transforming the JE into a JMP instruction. To do this select
in the CPU window, right-click it and choose Assemble.
In the following dialog just change JE to JMP and make sure Fill with NOP’s is deselected – though that does not matter in this particular case.
Now right-click anywhere in the CPU window, select Copy to executable and All modifications. In the next dialog choose Copy all.
This will open another window which you – again – have to right-click and finally select Save file.
That’s it!