Monday 10 September 2007

Trial Game Unlocking

The other day, I downloaded a trial version of a game from a website.
The game was a fairly simple one where you have a series of balls rolling along a track, and you have to shoot coloured balls at them to cause them to pop.

I was enjoying the game a lot - it was great fun - but then after 60 minutes the game turned itself off and displayed a message stating that my trial was over and that I would have to purchase the game to continue playing.
A lot of software these days is based on trial use systems, whereby the user is entitled to a certain amount of use of the program, and then after a this time has been used the program locks itself so that it can no longer function, or functions with severely reduced functionality.

The problem with this method of software protection though, is that the actual program is still on the user's PC - after the trial period the software "locks" but is actually still fully available.

With this in mind, I decided to have some fun seeing how easy it would be to simply bypass the trial protection and to continue playing the game.
Before I continue, I would like to say that I do believe people should pay a fair price for software, as I myself am aware of how much effort goes into producing applications and games, and that I did actually purchased the software in question.

To start, I installed the software on a new PC, thereby unlocking it for full use.
I then ran the software.
The first thing that happened was that a nag screen appeared which informed me that I had only 60 minutes of free gameplay left. I clicked on the Play button on this screen to start the game. The nag screen then disappeared and a couple of seconds later the game appeared on screen.

I closed the program, and then opened OllyDBG. I opened the program in OllyDBG and selected Run. The nag screen appeared.
At this point I Paused OllyDBG and noticed I was in kernel32. I selected "Execute till user code".
I now noticed I was in a large proc that seemed to control the trial window that had been displayed.
As the trial window had been kind enough to inform me how much time was left in my trial period, I knew that this value had to have been supplied from somewhre, so I decided to have a look through the proc.
I saw something that interested me at +5FAD, which was the following:
  PUSH   00533940   UNICODE "gTimeLeft"
Now time left could of course be for a number of different things, but it was a good place to start looking for what I was after. I set a breakpoint on this line and then let the program continue to run.
However, my breakpoint did not hit. So I tried a different method, I restarted the program, and then checked to ensure the breakpoint was still set on that line.
I then seleced Run.
A short while later, the breakpoint was hit - this was obviously used as part of the initialisation of the trial screen rather than during it's general running.

The first thing I did now that the breakpoint had hit was to have a look at the new few lines of code:
+5FAD  PUSH   00533940                    UNICODE "gTimeLeft"
+5FB2  LEA    ECX, DWORD PTR SS:[EBP-2C]
+5FB5  CALL   +87D3
+5FBA  MOV    DWORD PTR SS:[EBP-4], 1D
+5FC1  PUSH   DWORD PTR DS:[5BA530]

I made the initial assumption that at +5FB5, there was a call to a proc that retrieved this value "gTimeLeft". I quickly stepped through the proc and resulting sub-proc calls to see whether I could find anything obvious, but couldn't.
I decided to get back to the main proc and step through this to see whether there was anything else helpful.
I stepped through until I got to +5FC1, where the value at 5BA530 was pushed onto the stack.
The value at this location turned out to be 0x3C (60), which was identical to the 60 minutes displayed on the trail screen. However, this could be pure coincidence and I wanted to be sure.
I set a new breakpoint on this line and then let the program run. I played it for a couple of minutes and then closed it.
After OllyDBG had informed me that the process had terminated, I restarted and ran the program, and shortly afterwards my breakpoint was hit again. This time the value was 0x3A (58). I let the program run so that the trial screen would appear, and lo and behold the message displayed the fact that I had 58 minutes remaining in my trial.

Armed with an apparent location for the amount of time left in the game, I restarted the program, and then decided to perform an analysis on any code which accessed this memory location (5BA530).
In OllyDBG, I examined the location in memory and then used "Find References" to enumerate all the places where this memory location was referenced.
It turned out that there were 4 locations:
+37B4  MOV    DWORD PTR DS:[5BA530], EAX
+5FC1  PUSH   DWORD PTR DS:[5BA530]
+6391  CMP    DWORD PTR DS:[5BA530], EBC
+68DC  PUSH   DWORD PTR DS:[5BA530]

The most sensible way to proceed was to set a breakpoint on each of them, which I then did, and I then restarted and ran the program again.

The first breakpoint that was hit was at +37B4, which seemed to load the number of remaining minutes into the memory location. At this stage, I thought that a simple modification of this line would allow one to play indefinitely, but I wanted a slightly cleaner solution, so I continued execution.
The next breakpoint hit was at +5FC1, which is where the value seemed to be loaded for display on the trial screen. I again continued execution. The trial screen was displayed, so I clicked on the Play button to load the game itself.
The next breakpoint to be hit was at +68DC. This was used to generate a debug message output using OutputDebugStringA in Kernel32. I removed this breakpoint (as it was hit every second) and again continued execution.
However, the final breakpoint was not hit, and so I decided to exit the game and see whether that may trigger anything, but it did not. The process terminated.

So now I had a single point at which I could manipulate the game, +37B4, where the initial remaining time had been set. I restarted the program and ran it until this breakpoint was hit again.
I could easily of changed the remaining time value at this point, or simply modify the code so that instead of loading the remaining time into the address, it always loaded a high fixed value, but this didn't seem like a particularly elegant solution, so I wanted to actually find out where the trial screen was displayed so I could see whether there was a better way of influencing the program.
I stepped through the code until the proc returned (at +37C6). I stepped through the code here, and noticed that at +61FD, there was a call to +61BD, and that if I stepped over this, the trial screen was displayed and the game seemed to load. This is where I put my next breakpoint.
I restarted and ran the program, and then stepped into the proc that was called. I saw that the called proc only had a single call, so I stepped into this too.
Now I ended up in the large proc that contained the "gTimeLeft" line I found earlier, and a reference to the remaining time in 5BA530 (at +5FC1).

I don't want to go through this large proc. A quick glance at it tells me that this is where the trial registration screen is displayed, and I want to intercept the execution before it gets here.
With this in mind, I go back to the original call into the large proc, and back to the original call into the calling proc, which is at +61FD.
There is a small proc here, which includes the line at +61E8:
+61E8 PUSH 00533970 ASCII "TrialScreen"
Now this is starting to look more interesting. This proc seems to be concerned with launching the trial screen. I would like to see where it is called from, so I examine the start of this proc, at +61D7 and see that there is a single call from +7FE3, which I go to.
I put a breakpoint on +7FE3, and then restart and run the program. The breakpoint hits straight away, so I decide to step over the line - I am not interested in how the trial screen is displayed at the moment - and see what happens.
As expected, the trial screen is displayed. I click the Play button and see that the trial screen closes, and immediately I am back into my code, at +7FE8. The line I just stepped over is just responsible for displaying the trial screen.
The line I am now on (at +7FE8) contains the a JMP to +81A6.
If I run the program now the game will load.
So, what will happen if I replace the CALL in +7FE8 with NOP instructions? Will the game load without a trial screen?
I decide to try it, and as I hoped, the trial screen is not displayed - the game just loads. I have managed to find where the trial screen is displayed from.

I decide to have a look around to see what is going on with the code - I am particularly interested in the events leading up to the display of the trial screen.
I notice that there is a CMP at +7FD8 and a JNZ at +8FE1 just above the call to the trial screen. I set a breakpoint on these to see what is happening in them.
After restarting the program, I notice that the CMP is checking to see whether a value is 0 or not. If the value is 0, a JMP is made to the next line at +7FED, essentially this skips the trial screen.
I decide to force this jump by altering the Z flag. I then allow the program to run to see what has happened.
I actually end up being presented with a screen that tells me my trial period is over, and I can no longer play the game. I assume, from this, that this must be what gets called when there are no minutes left to use up and you cannot trial the game any more.
This isn't what I'm looking for though, so I have a look further up the proc to see what I can find. I notice that there is another CMP just above, at +7FC9. I put a breakpoint on this line, and notice that it has jumps from +7E9B and +7EB7.
I want to know whether either of these jumps are what leads to this instruction or whether the execution simply continues from the previous instruction (+7FC7) so I set a breakpoint on +7FC7.
I restart and run the code and see that the instruction +7FC9 is jumped to, because the breakpoint at +7FC7 is never triggered.
There is a JBE just after the CMP. This is always taken. If I force it not to be taken, I am presented with a screen asking for my order number for registration purposes. Again, not really what I am looking for.
So I decide to go back a bit further, to examine the jumps that led us to +7FC9, so I set breakpoints at +7E9B and +8EB7. Both jumps are actually JE instructions.

I restart and run the program, and the breakpoint on +7E9B is triggered, but I notice the JE instruction at this address is not followed. I continue execution.
The breakpoint on +7EB7 is then triggered, and this time the JE is taken, so this is where the program execution branches to the whole registration screen\trial screen\end of trial screen area.

Moving back down to look at the registration, trial and end of trial screen section in the proc, between +7FC7 and +7FF2, I notice that after each screen has been displayed (via a CALL), a JMP is made to +81A6.
Now this seems to be when the program is actually executed, so I go and examine the code located there.
Interestingly, the first things I notice are a ASCII reference to the program file, and a UNICODE reference containing the wors "Unable to extract game executable.".
This must be where the game is actually loaded from!
Now if the game is registered, then the entire section about registration screens and trial screens should be skipped, so I have a look and see if +81A6 is jumped to from anywhere else.
I can see the three jumps from the registration, trial and end of trial screens at +7FD6, +7FE8 and +7FF2, but there are also two additional jumps from +802D and +8049.
Both of these are located in some code that is just below the whole registration screen area, which starts at +7FF7.
I see that there are two jumps to +7FF7, one from +7E4F and one from +7E5B.
I go and have a look at these. They are both conditional JNZ based on CMP statements.
I set breakpoints, restart and run the code.

The breakpoint at +7E4F is triggered (as expected; it is first). I quickly notice that neither this or the second JNZ are taken, and then the execution quickly proceeds to the registration screen.
I thought it may be prudent to force one of the JNZ, so I pick the first one at +7E4F and restart the program.
When the breakpoint is triggered, I simply change the Z register so the jump is taken, and run the program. None of the screens are displayed, and the game loads and plays successfully.

I have found where I can bypass the registration and trial screens.
Simply changing the JNZ to a JMP (and filling the leftover byte with a NOP) will cause the program to execute every time, regardless of minutes remaining (0 or more). The software protection is, effectively, disabled.

Just to see for myself, I wanted to modify the actual EXE file to see whether this change could easily be made permanent.
I open the EXE using UltraEdit and quickly see that the code is not encrypted. I modify the few bytes so that the JNZ is a JMP, and then save the file.
I can now run it every time without any prompting what-so-ever. I have even tried patching it after the trial period ran out (after 60 minutes was up) and it still works.

This kind of technique of software protection is poor. It actually took me longer to write this article than it did for me to break the protection in this game.
The method used for this game relies on the fact that a wrapper has been produced around the game itself, and this wrapper provides all the registration and trial functionality. The actual game has no concept of this what-so-ever.
Also, the wrapper itself is poorly produced. The fact that I can bypass all the protection with a change to a single line of code is staggering. It would be better to have put a check into several places in the code, and also embedded further, regular checks into the game itself.
However, a lot of developers do not understand how vulnerable their code can be, particularly when they write their code in a language such as C++ and then compile it to assembler.
The actual assembler output from their C++ code may be very different from what they originally wrote, and could be susceptable to easy attack using methods like the ones I have used today.

I am not going to produce a patch for this particular bit of software, because I am reluctant to give away the ability to bypass the software protection on what is actually a very good game. Like I said at the start of my article, I have actually purchased this game because I like it so much, and the only reason I have produced this article is because of my academic interest in the protection methods used in the real world.

If you have any queries about this article, please do not hesitate to get in touch.

Until next time...

Thursday 6 September 2007

Good Password Generation?

Following on from my previous articles about password generation and the potential flaws in using password generation tools, I thought it might be useful to produce a tool that generates robust passwords based upon a generation code (such as an asset number).

I had the following objectives for the tool:
- Generate passwords that were random every time
- Generate a repeatable password based on a numeric seed using an algorithm that was not easy to break
I also wished for the generation to be configurable:
- Allow passwords between 1 and 15 characters
- Allow a character set to be specified
- For random passwords, allow a quantity of passwords to be specified
- For repeatable passwords, allow an asset number to be entered

RANDOM PASSWORD GENERATION
I started off by looking at producing passwords that were random every time. These would not be based on asset codes, but instead should generate passwords that appear truly random when compared to each other.

I decided to implement two types of random password generator, both based on Microsoft .Net random number generators.
The first was to be based on the simple subtractive random number generator which is implemented by the .Net class Random.
The second would be based on the cyptographic random number generator, RNGCryptServiceProvider (in System.Security.Cryptography).

To produce the passwords, the random number generator would be used to supply a byte array containing a sequence of character positions from the character set used to seed the passwords.

For simplicity, say I was using the character set 'ABCDE' and I wanted a 8 character password.
I request a sequence of 8 bytes from the random number generator, each with a value between 0 and 4, and receive the byte array '0, 3, 2, 4, 4, 2, 0, 1'.
I then use these positions to retrieve characters from the character set, as so:
0 = A, 3 = D, 2 = C, 4 = E, 4 = E, 2 = C, 0 = A, 1 = B
Which gives a password 'ADCEECAB'.

Passwords based on random number generators can be good because there should be no discernable pattern present in the generated sequence.

However, passwords generated in this way do result in some security problems:
- The passwords are not repeatable because they are not based on an asset number. This means they have to be stored somewhere for later retrieval, which may potentially represent a huge security risk.
- The passwords may not be truly random. Random number generators work from a predefined formula for which gives the appearance of randomness, however, they are not truly random (see below for more on this).

Before I move on, I would like to discusss the randomness of the passwords that can be generated using a random number generator.
A simple random number generator, such as the Random class in Microsoft.Net, is a pseudo-random number generator, that is, the numbers that are generated are not random at all, they are derived mathematically using a formula, and the numbers appear to be random.
The Random class (in .Net) uses a "seed" to generate a sequence of numbers. In .Net, by default this is based on the number of ticks so far in the day. However, a seed can also be supplied directly to the class Constructor.
This highlights an important limitation of simple random number generators - if the same seed is used again, the sequence of numbers generated will be the same.

Create a simple program that instantiates a Random class with a seed of 1, and then gets the first 10 integers (Random.Next()).
Execute the program a few times. Each time the numbers generated will be the same, in the same order.
It is very important to accept that if the seed used to create the Random class can be ascertained, the entire sequence of numbers used to generate a password can be recreated, and this may prove the undoing of any password generator based on pseudo-random number generation.

REPEATABLE PASSWORD GENERATION
For a repeatable password to be generated, an asset code will be required. To simplify matters, the asset code will be limited to numerics only.

I decided to implement two repeatable password generators:
- Simple. This will be based on the principals outlined above with regards to using a fixed seed for random number generation. The seed will be the asset code.
- Complex. This will be based on a method that uses a predefined formula to generate the asset code. I will not reveal the formula because I would like to see whether anyone can figure it out for themselves.

To generate the actual passwords, the repeatable password generation will work in the same way as the random number generator, that is a sequence of valid numbers will be generated that will indicate the positions of the character to be used in the password from a character set.

Repeatable password generators offer advantages over randomly generated passwords, because they do not need to be written down anywhere; They can be generated at any later time simply by supplying the asset code.

However, they do have limitations:
- The password that is generated is, ultimately, based on a formula of some sort and so can be broken given a large enough set to work with
- The tool must be properly protected from unauthorised access. Access to the tool is, essentially, access to the entire system.

THE IMPLEMENTATION
I decided to implement each of the different generation methods (both random and repeatable) in classes that support a common interface, IRNG. This way my generation program does not care which actual implementation is being used to generate the passwords.

I wrote a manager class called PwManager, which will be responsible for generating the passwords using the desired generator.

I then placed the manager class, the interface and the generator classes in an assembly, and referenced this from my Windows Forms project.

In my Windows Forms project, I added a form to allow the user to configure the generation method, password length and character set and also, depending upon the chosen generation method, the number of passwords to be generated or the asset code.
I then added a second form which would be used to display the results of the generation.

When a button is pushed on the first form, the PwManager is instantiated and configured with the appropriate parameters, and the generation of the password(s) takes place. The resulting configuration information and password list is displayed on the second form.

DEMO PROGRAM
If you would like to download and use the password generator program, it can be downloaded here.

There are two assemblies in the download, a library and an executable. The executable is simply a UI which presents the functionality from the library.
Feel free to reference the library from your own code and make use of the generation methods.

A final note: Please do not use the program to generate passwords for your organisation - it is freely available on the web (from my blog) and others could easily obtain it. Instead, the source code is (as always) available upon request - ask me for it and modify it to make it unique to your organisation.

CONCLUSION
I have demonstrated several techniques for generating passwords during this article.
I would be interested to hear if anyone can break the repeatable password generators, you are welcome to try!

Monday 3 September 2007

Bulk Password Generation Part 2

In my previous article I managed to demonstrate that a password generation technique implemented by a tool in an organisation could be easily broken with as few as 300 passwords.
In the article I broke the password generator for the BIOS passwords generated by the aforementioned tool.
In this article, I will discuss breaking the local administrator passwords generated by the tool, and then go on to discuss the tool required to reproduce the passwords.

It should be noted, before I continue, that I do not have the tool used to generate the passwords. Instead, I have been given a list of sequential passwords generated from the tool.
The tool itself generates passwords based on the asset tag of the PC they are for. The asset tags are a number.
The passwords I have been given are for the 500 assets numbered 0 - 499.

Referring to my previous article, the local administrator passwords are 8 characters long, and were structured like this:
UlUlUnns
Where U is Uppercase letter, l is lowercase letter, n is number and s was a symbol.

In the same way as before, I started by looking at the first few passwords:
0 JcVvI32(
1 KdWwJ43)
2 LeXxK54*
3 MfYyL65+
4 NgZzM06-
5 OhAaN17!

At this stage I began to get the same sinking feeling that I got when I worked on the BIOS passwords. The passwords are, again, sequential.
I briefly hoped that the producer of the password generator tool had the aptitude to at least use a different technique for the two different password types...
But fairly soon it became obvious that these passwords were as simple to break as the other ones.
In fact, using the same technique as demonstrated in my previous article, I broke the entire set of formulae for each letter in less than 20 minutes!
Although characters 2 and 4 of this password are lowercase, they are not mixed, so they are still as limited as the uppercase characters, i.e. 26 possibilities in the sequence.
The final formulae for each character turn out to be:
1) l = (n + 113) mod 137 mod 26
2) l = (n + 54) mod 153 mod 26
3) l = (n + 21) mod 113 mod 26
4) l = (n + 99) mod 117 mod 26
5) l = (n + 86) mod 193 mod 26
6) l = (n + 123) mod 127 mod 10
7) l = (n + 202) mod 239 mod 10
8) l = (n + 105) mod 129 mod 10

Where l is the final number of the character in the sequence, and n is the asset number.
The character sequence for positions 1, 3 and 5 is A - Z (0 - 25).
The character sequence for positions 2 and 4 is a - z (0 - 25).
The character sequence for positions 6 and 7 is 0 - 9 (0 - 9).
The character sequence for position 8 is '!#$%&()*+-' ('0123456789').

The only minor benefit that was present with these passwords is that a much larger sequence was needed in order to be sure of the generation techniques.
In fact, I needed the full 500 for character 7 and just under 400 for 3 of the others.

That said though, the generation technique is still extremely poor, for the same reasons that the BIOS password generator was poor, and also:

AS EASY TO BRUTE FORCE (Following on from previous article section)
The BIOS passwords could be relatively easily brute forced.
These passwords are as easy, despite the inclusion of the lowercase characters.
This is because, like the BIOS passwords, the entire sequence is strict in it's structure.
The lowercase characters are always at positions 2 and 4.
If, like with the BIOS passwords, the full character sequence could be used in each position (A-Z, a-z, 0-9, symbols) then there would be 72 possibilities at each position:
72^8 = 722,204,136,308,736
A whopping 722 trillion, over 60,784 times more than for the standard password, and still 36 times more than the strongest possible BIOS password (with 46 possibilities per position).


I had been asked if I could produce a tool that would reproduce the passwords, given the asset number.
I was now armed with the knowledge to do this, so I proceeded to produce a tool to do the work outlined in this and my previous article.

I decided to write the tool in C# (Microsoft.Net 2.0).
A screenshot of the tool is shown below:


To use the tool, enter the asset code into the 'Asset Code' textbox, and click the Go button.
The Administrator password will appear in the "Admin Password" box and the BIOS password will appear in the "BIOS Password" box.
The tool itself simply implements the formulae described in this and my previous article to generate the passwords.
If you would like the source code for the tool, please e-mail me and I will send it to you.

The tool can be downloaded here.


To conclude:
Using password generation tools is a good idea. Company administrators find such tools invaluable in producing random passwords for hundreds, or thousands, of computers at an organisation.
Generation tools can produce passwords that appear to be significantly more random than those that could be thought up by a human.
However, if poorly implemented, password generation tools can pose a significant security risk.
Consider some important facts:
- My friend was able to obtain a list of 500 passwords generated for sequential asset numbers without having any administrative access to his domain
- The password algorithm used was easy to break, being based on a sequential generation system
- The password implementation was extremely poor, using a fixed format and poor combinations of character sequences

The organisation in question would have had a significantly more secure system if:
- The tool was protected so that only administrators could access it
- The algorithms used were truly random
- The passwords were never sequential
- The password format was not predefined

I may explore a password generator program in my next article, to see how it could be done in a more secure way.

If you have any queries about this article then don't hesitate to contact me.

Have fun!