Reversing Microsoft’s Windows95 Product Key Check Mechanism

Saket Upadhyay
InfoSec Write-ups
Published in
8 min readMay 14, 2021

--

A blast into the past to see what it took to be secure 25 years ago!

Disclaimer

Microsoft Windows95 is the registered property of Microsoft Corporation® and released for general use on August 24, 1995. This article is purely for educational purpose and does not intend to damage any software/product owned by any company/individual.

As Windows95 is discontinued (Mainstream support ended on December 31, 2000, and Extended support ended on December 31, 2001) and product-key check algorithms and strategies are far more advanced in subsequent versions, we can discuss this topic safely now.

Do you know that 111–1111111 is a valid Windows95 product key, so is 000–0000007? I didn’t. I was binging YouTube one day when I found it out via stacksmashing’s video [THIS] on the topic, where he discussed why this works and analyses some code too, this made me curious and I decided to do it myself and reverse the library file responsible for product key check.

I did just that, now I want to share the experience with you, as usual, I tried to make sure you can easily reproduce the results so I uploaded all the project files and source files for you to download :)

You can watch the video if you want to, but here we will discuss more.

Article Difficulty level:

To understand — Beginner

To Implement and Reproduce — Intermediate

Downloading Assets

Here are the things you would need to follow up with the article if you want to. [All files uploaded on Google Drive]

  1. Windows95 ISO
  2. setupx.dll
  3. Ghidra project files

Setting Up VM / Serial Key checkpoint.

I’ve used VMware Workstation 16 Pro for installing the Win95, the process is very easy and if you want you can follow the article given below, I am adding some screenshots just for some throwback to ’90s. For this article we will stop at the product key prompt.

The Good Stuff

My analysis stack

  1. Host OS : Windows 10 Pro. for Workstations
  2. Analysis OS : Kali Linux (Windows Subsystem for Linux [WSL] v2.0)
  3. 7z, cabextract, IDA , Ghidra

Extracting the ISO

If you downloaded the resources I’ve uploaded above, you should have a .7z file which you can extract using 7zip Archive Manager and you will get the ISO.

Now ISOs are similar to zip archives, they are lossless and store all the files in a container, that’s it. ISO do not generally compress the data, it just archives it.

So you can extract the ISO using any archive manager software, I used 7zip.

After that you will have a folder will all the contents of the ISO in it.

Go to this folder as we will continue next step here.

Here I opened PowerShell and activated my WSL distribution with bash

Finding the code/library responsible for “Product Identification”

Most of the files in windows’ setups are packed in .cab or cabinet files.

Cabinet is an archive-file format for Microsoft Windows that supports lossless data compression and embedded digital certificates used for maintaining archive integrity. ~ Wiki

To extract these files, I used cabextract utility in Linux. You can install it via your package manager —

After install, we extract all the CAB files in WIN95 folder

After this your WIN95 directory will be populated with loads of assets that windows95 uses for installation.

Then we will search for the string “Product Identification” using grep.

so we got suwin.exe as a potential target, but from experience I knew that these critical functions are not implemented in single executables, instead they are loaded via dynamic libraries or DLLs so we will try to list out the libraries used in this process.

So we open suwin.exe in Ghidra and look at the IMPORTS TABLE of the binary

Now in this we see 6 imported libraries

Among those we can discard GDI, KERNEL, KEYBOARD and USER as it is pretty obvious what they do.

Interesting ones are SETUPX and VERX imports, looking at imported functions of VERX, it looks like this is used to get file versions and other file information. So our only target remaining is SETUPX.

Searching this in the extracted folder we got reference to setupx.dll dynamic library file, which is used by suwin.exe

Let’s import this Library and analyze this in Ghidra.

Importing setupx.dll in Ghidra

After importing the file and taking some time to analyze the functions in the library, I was confused. There are so many functions in this that I cannot possibly check all of them to find key validation mechanism, so I looked at the function names and searched for keywords, also took some tips from stacksmashing’s video.

Looking for terms like “Product Key”, “Validation”, “Product ID”

We got something interesting “PIDVALIDATE”.

Now the PIDVALIDATE function takes two arguments and consists of lots of switch statements and cases.

Looking further into the assembly and de-compiled code, I seems like these switch conditions are used to check the type of Windows OS, eg. — “Home”, “Professional”, “Enterprise”, “OEM” etc.

The Juicy Stuff

Note : I’ve cleaned some code, renamed some variables, fixed some definitions and also created some clean GITHUB based gists to make it easy for you to understand it. You will not get exact same results when trying it yourself as you have to do all the above things yourself, but it’s fun and I suggest you to try it if you are interested.

Moving ahead… In PIDVALIDATE function we see two function calls that are interesting to us.

  1. PersonalProductKeyCheck(args); function is responsible for checking Home user keys.
  2. OEM_KeyCheck(args); function is responsible for OEM key check.

Product Key Check Function

This is where the actual product key for home users are checked. And I was surprised to see how SMALL this code is !!

After cleaning the code and fixing some assignments, we get this —

Clean-er Code for you:

Here we can see that we get 2 parameters param1 and param2 , param1 being the character sequence of product key char* .

In line 12, the first 3 digits of the key are copied to local_6 buffer, in line 14 char sequence is converted to integer via atoi library function, then it’s just a if condition that will reject any key starting with 333, 444 ,555, 666, 777, 888 or 999 that means if a key starts with anything from 000 — 998 except the above list it will pass on to next check.

Mod7 Check Function

In short, this is the function that checks if the sum of the next 7-digit number series is divisible by 7 or not. That’s it.

If the number is between 0–8 [Line 13] and if sum of all digits after the gives 0 (zero) as the remainder when divided by 7 [Line 19] then it is valid.

That means if your key meets the above conditions, it will PASS!

Example Case 1:

Key = 111-1111111 , This key works because 111 is not in exclusion list and 1+1+1+1+1+1+1=7 ; 7%7 = 0

Example Case 2:

Key = 420-0001677 also works as 420 is not in exclusion list and 0+0+0+1+6+7+7=21 ; 21%7 = 0

The OEM Key Check

The Windows95 was also distributed with OEM version, this key check is “somewhat” different than above check.

The OEM key is in the following format:

AAABB-OEM-XXXXXXX-CCCCC

Where,

  1. AAA is integer between 0–366 [Line 35]
  2. BB is between 04–93 [Line 41]
  3. OEM is fixed character [Line 17]
  4. XXXXXXX follows same mod7 rule as above [Line 48]
  5. CCCCC is random and is NOT checked at all!

Testing our analysis

1st case

Activation Code = 34505-OEM-0000007-13370 works, because:

  1. 0 < 345 < 366
  2. 3 < 05 < 94
  3. -OEM- is present
  4. 0+0+0+0+0+0+7=7 ; 7%7=0
  5. 13370 doesn’t matter.

2nd case

Activation Code = 35595-OEM-0000696-42069

Both of them work! and we can continue with the setup.

Conclusion

This small project was fun and this also shows us how far we’ve come in terms of security, from thinking “divisibility check by 7” is enough, to multifactor authentication, specifically optimized hash functions, Trusted Platform Modules etc.

I hope you enjoyed this blast to past experience 😃.

--

--