Jump to content
 Share

Ash

Reverse Engineering: A Fun Case Study and Overview

Recommended Posts

Posted  Edited by AshAkiri

Ash Presents...

---

Reverse Engineering:

A Fun Case Study and Overview

---

I. Introduction

 

Reverse Engineering: A phrase commonly associated with both the InfoSec world (e.g. Malware Research) and in the game hacking world (e.g. cracking a game for various reasons). A quick definition that I pulled from Wikipedia is as follows: In 1990, the Institute of Electrical and Electronics Engineers (IEEE) defined reverse engineering as "the process of analyzing a subject system to identify the system's components and their interrelationships, and to create representations of the system in another form or at a higher level of abstraction", where the "subject system" is the end product of software development. Reverse engineering is a process of examination only: the software system under consideration is not modified (which would make it re-engineering or restructuring). Reverse engineering can be performed from any stage of the product cycle, not necessarily from the functional end product [1]

 

This is a fancy way of saying: Reverse engineering is a set of procedures that are used in order to analyze something that we don't know about, so that we can figure out how it works. This can be done for a variety of reasons. Personally, I work on a project that involves re-creating network services for a popular series of Japanese music-based arcade games so that they can be played outside of their intended country. This involves needing to Reverse Engineer (RE) the game binary so that I can know what the game is expecting to receive from the server. I've also previously worked on a project that involved re-creating scripted World of Warcraft events for a private server. That kind of RE relied heavily on performing research through non-technical means (e.g. finding youtube videos and online resources to explain how the events worked once upon a time). In this way, we refer to RE as the process of analyzing something we wish to know more about.

 

The purpose of this tutorial is more strictly just for fun and to serve as motivation to do additional research. We will not be getting into terribly much detail, because that would take hours to write up, and is best left to the student to poke around. Practice and an inquisitive mind are your best friends when trying to learn RE. (Well, that, and a healthy understanding of the target file types e.g. the Windows PE format. If you are more technically inclined, now is a good time to brush up on it but it's not necessary for this tutorial). Practically, you will want to get a good understanding of debuggers as well, but again - that's outside the scope of this tutorial.

 

For the scope of this tutorial, I will make a few assumptions. Primarily, we're going to work on the assumption that code does not look scary to you, and that you have already written some kind of code at some point in time that you have compiled.

 

Ready? Let's go.

 

II.  Background Information

For our purposes, we will only touch briefly on the process of actually compiling written code into an executable program

 

Consider this basic C program:

 

#include <stdio.h>

int main()
{
    // Print Hello World
    printf("Hello World");
    return 0;
}

If we compile this and execute it, we will get the following:

 

spacer.png

 

Fairly straightforward! But what we care about here is the process that turned it into something that the system was able to understand. The very basic explanation of this process is two-fold. First, the compiler is going to take these nice, pretty lines of C and turn it to the respective x86_64 instruction set assembly code that it relates to. This will look something like this.

spacer.png

 

Woah. Suddenly our program isn't so clean anymore. That said, the compiler does some magic at this stage which can sometimes be a bit of a PITA, but hey - that's beyond the scope of this :^). Finally, when this is done, the Assembler is going to do its job of turning these instructions into object code - This is what the processor is going to use to actually execute these instructions. We can more or less stop here for this process and ignore say, the linker. The big takeaway here is C code (compiler) > Assembly Code (assembler) > Executable Program

 

In our case, we are wanting to somehow take this process, and go backwards - Given some executable we have, can we somehow follow the reverse of this process and get back to the original source code? Well, the answer is a soft kind of. See that really ugly blob of assembly and how it doesn't look nice and clean like the true source code? That's because of our best friend Mr. Compiler. He looooooves trying to do things in order to make his life and the life of his best friend Mrs. Processor easier, without any consideration to those of us trying to poke our nose into things we weren't intended to. How rude.

 

Luckily for us, we do have a means of getting back to this source code. Enter our friend            spacer.png

 

Ghidra is a free tool developed by the NSA which will perform both the process of Disassembly (turning the .exe back into assembly) and Decompilation (turning that assembly back into as much C as it can). Typically, Disassemblers were very easy to find, however, up until earlier this year, IDA was generally the only go-to for a good decompiler, and - anyone who has ever looked into how expensive IDA is can tell you - is prohibitively expensive. Now, we have a nice free (and open source!) solution to solve this problem. Let's look at what Ghidra is able to do.

 

spacer.png

 

As you can see, the Disassembler generates something that looks ugly as sin, even compared to the original assembly code that was generated. This is all due to how the compilation process ends up working. The Disassembler (and by association, the Decompiler) have to make some educated guesses on what was originally done. As you can see, the Decompiler was able to generate something for us that, while isn't completely identical, is generally fairly serviceable so that we can go about our business. One thing that isn't in this program were variables - unfortunately, these variable names are nearly always missing from the decompiled view and are left with dummy names.

 

So now that we are fresh with our understanding of how source code becomes a program, and how that program turns back into some semblance of its original code, let's see how to go about doing it!

 

III. Prep

 

Step one is installing Ghidra and its Java requirement. Come back when you're done.

 

 

With that handy, if you'd like to follow along with this tutorial, grab a copy of this really old shareware game I used to play like 23 years ago. https://archive.org/download/ARCADE95/ARCADE95.zip

If you're feeling squirrely, go find some other shareware game and see if you can "crack" another game!

 

IV. Initial Research

 

So now that we've got everything downloaded, let's take a look at the file structure of this.

 

spacer.png

 

Looks like we've got some resources, some help documentation, some random files used for that help documentation, and an executable. Let's open it up.

 

spacer.png

 

We've got the typical "Hey, if you like this, give us money!" window (which, by the by, as far as I can tell, the company no longer exists, which is why we're using this for our tutorial)

 

spacer.png

 

We've got a few options that seem to be locked so that we can't access this during the "trial"

 

spacer.png

 

And some more locked options. Cool. Let's get under the hood and see what is going on.

 

V. Ghidra

The first time you load up Ghidra, you'll get the usual set-up steps of agreeing to a lot of things you didn't read. Once this is all done, you'll see the Project Selection screen. This will look something like this:

 

spacer.png

 

Step One is creating a new project! To do this, select File > New Project, or use Ctrl+N. It will ask you if you would like to create a Non-Shared Project or a Shared Project. In this case, we want to create a Non-Shared Project. The next screen will ask you to give it a directory and a Name. Once this is done, click "Finish". Your project will now list as an Active Project, albeit an empty one. Simply drag over your .EXE file into this window, to import it!

 

spacer.png

 

When you attempt to import your project, you will see this window. While a more proper RE course would go into details about what all of this means, simply just press OK here. The Import Summary will pop up next. For that, just hit 'OK'. Finally, Double Click the .EXE file that is now listed under your Active Project. The CodeBrowser tool will open it, and you will see the following:

 

fYFEMCxA.png

 

This analysis is what will allow the various code functions to be decompiled. We will click Yes here, and in the menu that appears after, click Analyze - there are many other Analysis options which can be selected, but for the sake of having this not become huge, just go with the defaults. It shouldn't take too long for this Analysis to complete - say, a minute or so. When it is all done, an error might come up - Just ignore it

 

nDkCG9a9.png

 

And click 'OK'. With that, we will have our workspace all set-up and ready to go! Compare what you've got to this link to make sure you're all set up: https://ash.s-ul.eu/FftnKCSc.png

 

VI. Analysis

 

So we've got Ghidra all ready with our Disassembly view, but where do we go now? Unfortunately, this process is not an exact science. When I will start a new arcade game, generally, I'll start with looking at the strings. Ghidra will go through the entire program and try to identify strings, or string-like things. We'll get a lot of nonsense here (since the tool will just guess that the null terminated AksfVn looking things that really aren't strings are, but we'll ignore them). To look at all of the strings Ghidra has identified, Select Search > For Strings from the top menu. A window with options will come up - Just keep all of those settings default, and select 'Search'.

 

XjD8MJb3.png

 

Give this an overview. Some things will be very obviously non-strings, while others, like the listing of languages about 1/4th of the way down, may seem strange! A lot of this comes from the various libraries (e.g. DLLs) that the program uses. These can also generally be ignored. What we're interested in are the game strings. Can you think of where to start? Well, think back - when we were doing our initial overview, we noticed that there were some options that were not accessible, to include

  • Buy Five Tickets
  • Buy Ten Tickets
  • <And all of those options>

 

Let's take a look at what's going on around that 'Buy Five Tickets' line. In the 'Filter', type 'Buy'.

TiwWiXI8.png

 

We can look at that first string by simply clicking it - the Assembly view will jump to that specific instruction! Now let's close out of that and take a look.

 

10nyfrQF.png

 

At address 0x449224, we've got that string - What's important here is that XREF on the right. These XREFs are anything which refers to this particular 'thing'. Let's dissect what it means

 

FUN_ : This means that we are looking at some 'function' - since we don't know what it was originally called, Ghidra just gives it the prefix FUN_

004021c3: This is the starting address of the function itself

0040225e: This is the address of the line that references our 'Buy Five Tickets' string

 

For now, click anywhere in that name to jump to that function. Not only will you see that function in the assembly view, but the Decompiled view should now have what Ghidra believes is a representation of the original code that made up that function!

 

YLq93Jtd.png

 

The Reverse Engineer in me is elated by this. Why? Well, look at the first line of this picture! We've got some 'If' statement - If it is true, then we never do anything with Buy Five Tickets or Buy Ten Tickets! This seems like it would be a good lead to me, no?

 

So that line says if some variable is equal to zero, don't use Buy Five Tickets/Buy Ten Tickets. This sounds like it could be something like ' if (isActivated == 0)' to me, so what I'll do is change that variable name to 'isActivated' instead of the ugly '_DAT_004...'. To do this, simply click on that ugly variable name, and press 'L', or right click and select 'Rename Global'. Here, you can change the name. I changed it to 'isActivated'. Now, it looks like:

FOEAVG3s.png

 

So that's pretty cool! Did you catch where it said that the value was a 'Global'? Well, that means this variable is used elsewhere! Let's have a look. In order to see all of the places something is referenced, just double click the variable name. In our Assembly view, we now see:

5IaZlszq.png

 

So as we know, there are 6 places that reference this variable - three of which are where the variable is 'read' to, and three of which are where something is written to that variable, denoted by the (R) and (W) respectively. Remember how that code wanted to see if isActivated is 0, well, what we would like to see now is if there are any situations where that variable is written with a non-zero value. Let's ignore all of the (R)s for now, and take a look at the (W)s

Selecting the first one brings us back to the function we came from:

 

jIr6JJks.png

 

Whoops - let's double click isActivated again, and choose the second one:

qUAG4Zov.png

 

Hey now. We're getting somewhere! We actually see both the second AND third writes here - the third is just within the body of that if statement. Speaking of which, what's going on with that if statement? Well, we've got something about CommandLineInfo, then a Function Call, then we set isActivated to 1. We then have another function call which looks like it compares two values with the == operator, and checks to see if they're equal. If they aren't, we set isActivated to 0! Let's see what that DAT_004492b0 is. Double click that to navigate to where that variable sits in memory.

7uhaFWjd.png

 

Oho. That's the ASCII string "2011". It wasn't processed as a string by Ghidra for some reason. Honestly, that's not too uncommon. There are ways to fix this, but it's outside our scope for now. So let's go back - click that FUN_004059f7 in the XREFs list to go back, or hit the back arrow up top by the menu under 'Edit'

 

Looking at the code again, we are comparing some value, local_24, to 2011. If local_24 == 2011, then isActivated remains at 1. How do we get local_24 to be 2011 then?

 

Well, unfortunately, we don't really see anything for local_24. If you mouse-wheel click on local_24, you will highlight every instance of that variable in this function. A quick glance shows that it's declared on line 15 as a CString of size 16, and is only used on line 46 and 51. Let's look around a bit. Remember that CComandLineInfo function on line 42? Well, let's see what that is about. Notice how it is actually named something reasonable instead of FUN_<address>? Well, that's because it's an imported function. Taking a look at the Assembly view, you will see the function call as:

0cQwKWRo.png

 

Do a quick google search and you'll find https://docs.microsoft.com/en-us/cpp/mfc/reference/ccommandlineinfo-class?view=vs-2019

 

hgs77ahf.png

 

Hmm...So immediately before we check that some value is equal to 2011, we're creating an object that parses command line info....Surely it isn't as easy as just running that exe file with 2011 as a parameter...is it?

 

Oeu9Sr1z.png

 

kcdL5vOv.png

 

Whelp...

 

No splash screen either :^) - We've just managed to "activate" the game. Apparently, the game checks to see if it was launched with 2011 as its first parameter. If it does, it treats itself as being activated. If you'd want to do this without having to run it in a command prompt, you can also create a shortcut with 2011 as a part of the target.

 

DVb6wLx2.png

 

Congrats! You've just RE'd a Shareware game from 24 years ago to get the full version, since it can't be purchased legitimately anymore! 

 

VII. Takeaways

 

As you can see, this was a fairly straightforward example, but we did make a few assumptions - We never actually saw where local_24 was getting populated by 2011, we just assumed that to be the case from the documentation on google -- well, a lot of REing is making those sorts of educated guesses. There are often times where we just have to slam our heads against these problems and hope for the best.

 

Not everything with this process is methodical - Often times, it just comes down to how you as the reverse engineer goes about it. Personally, my first starting point is always going to strings, but maybe you prefer to do something else. This is fine.

 

The best way to go about it, honestly, is to just poke around. Find something that seems interesting to you, and open it up and see what you can find! I always like to introduce people to RE with an exercise like this  because it's always interesting to be able to see how these old games used to work and certain assumptions that were made before the days of crazy DRM schemes and encryption. Sure, having a random parameter being checked for equivalence seems ridiculously insecure, but this was the mid 90s and all of these fancy tools weren't in heavy use, so they could get away with it! Naturally, things aren't that easy these days, and there is a lot of work that takes place to try to trip up less advanced hackers.

 

I hope this tutorial has given you enough of an interest in this subject matter to warrant further research! There are a ton of excellent videos on the subject on YouTube on more advanced usage of Ghidra, and what more modern programs may look like. The last bit of parting advice I'll give is to always stay curious, and to keep learning as much as possible!

 

VIII. Sources

[1] https://en.wikipedia.org/wiki/Reverse_engineering#Reverse_engineering_of_software

 

IX. Homework

 

RE the activation code of https://archive.org/download/BOTZW95/BOTZ_W95.zip

PM me your answer and proof that it works, and you might get a prize!

 

 

 

 

 

 

Edited by AshAkiri

Share this post


Link to post
Share on other sites


Posted  Edited by Joshy

This was a very interesting read.

 

Is it considered fully legal or are there some gray areas to it?  I wont be participating in it myself as of now because I know I have to meet standards that may seem excessive to others, but it is what it is; it has certainly answered a few curious questions I've had and may I eventually poke around to it more thoroughly when it's absolutely clear I'm allowed to- for academic purposes of course.

Edited by Joshy

PoorWDm.png?width=360&height=152

Share this post


Link to post
Share on other sites


Posted  Edited by AshAkiri - Edit Reason: clarity
20 minutes ago, Joshy said:

This was a very interesting read.

 

Is it considered fully legal or are there some gray areas to it?  I wont be participating in it myself as now because I know I have to meet standards that may seem excessive to others, but it is what it is; it has certainly answered a few curious questions I've had and may eventually poke around to it when it's absolutely clear I'm allowed to- for academic purposes of course.

 

It's definitely a YMMV kind of thing. Would I advocate REing non-abandonware for the purposes of abusing someone's copyright? Absolutely not. There's a reason I selected a game available on the internet archive from a quarter century ago. That said, what you do with the software that is on your computer is your business. When you start releasing things (e.g. cracked games on TPB), well, that's a whole different story.

 

Which is to say, REing itself is not a gray area at all. It's what you do with it that could be.

Edited by AshAkiri
clarity

Share this post


Link to post
Share on other sites


Posted  Edited by Joshy

Thanks.

 

I was just curious about the YMMV thing.  As for anything regarding security clearance I mentioned nothing, but I'm sure anyone with that need to know and considering it would leave it to their investigator to determine.

 

Still a very cool guide.  Great job.

Edited by Joshy

PoorWDm.png?width=360&height=152

Share this post


Link to post
Share on other sites


  • 2 weeks later...

So, i need help 😄
Thanks for the tutorial ofc, very well written!
I got to the point where i found the "Rsrc_Dialog_e2_409" (img attached) ... thats the dialog that is shown when you dont have the full version.
I think that must be the correct entry point, but im not sure how to get further.

There is no function attached, neither did it help to search for references or call tree of that address.
I cant find another entry point, maybe i would have to play through the game to get to the point where i cant continue anymore, but im too lazy for that. (And i cant play a game at work without anyone noticing :D)

So could you point me in the right direction how i get to a function i can RE, or at least anything how i can progress...
Thank you :)

image.thumb.png.e0b5bfda99ac9febc67ce46b04505767.pngd the "

Share this post


Link to post
Share on other sites


On 2/4/2020 at 4:10 AM, Flex Surf said:

So, i need help 😄
Thanks for the tutorial ofc, very well written!
I got to the point where i found the "Rsrc_Dialog_e2_409" (img attached) ... thats the dialog that is shown when you dont have the full version.
I think that must be the correct entry point, but im not sure how to get further.

There is no function attached, neither did it help to search for references or call tree of that address.
I cant find another entry point, maybe i would have to play through the game to get to the point where i cant continue anymore, but im too lazy for that. (And i cant play a game at work without anyone noticing :D)

So could you point me in the right direction how i get to a function i can RE, or at least anything how i can progress...
Thank you :)

image.thumb.png.e0b5bfda99ac9febc67ce46b04505767.pngd the "

 

Hey there!

 

First off, I'm so glad you decided to start poking around this! It's always a fun journey to start getting into RE -

 

As far as advice goes, let's talk about that.

 

Good job on finding the pop-up window that shows when the trial is there. As you said, there's no reference to this dialog box resource (hence, Rsrc_dialog). Welcome to the annoyances that come with disassembly/decompile. Sometimes things get eaten. Especially when you get all sorts of fun virtual functions causing these things to not have 'direct' references.

 

A viable next step would be to take patterns that you already know to be true to see if they carry over into this new program! No need to re-invent the wheel! We talked about a specific function that parses command line arguments - Try filtering the list of functions to see if this function is also being used in this example.

 



qUAG4Zov.png

 

Remember this? Look to see if you can find it again!

 

Sometimes, you'll find that say, after an update, the game (or whatever) starts to scramble their imported function names, for example. In this case, one strategy that can be used is to find an older version where the function names aren't scrambled, then go match their behavior in the new version! Always use the tools at your disposal to help find the solution!

 

Let me know if you need any more help!

Share this post


Link to post
Share on other sites


Thanks, i got the Solution now :)
Even tho its was more just because i already saw your solution to the other one, but couldnt really wrap my head around how this one functions and i come out with another 4 digit code that looked similar in the code as yours for the example tool..
maybe this is still too complicated for me 😄

Share this post


Link to post
Share on other sites


6 hours ago, Flex Surf said:

maybe this is still too complicated for me 😄

 

Don't let it be! The purpose of this exercise is to just get familiar with the tool and to learn a few concepts of RE! If the concept that you learned is to look for existing patterns and try to find similar ones, that's a fantastic skill to have in your skill set!

Share this post


Link to post
Share on other sites




×
×
  • Create New...