Reversing Microsoft’s Windows95 Product Key Check Mechanism
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]
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.




Official VMWare Article : Windows 95 Installation Guidelines (vmware.com)
The Good Stuff

My analysis stack
- Host OS : Windows 10 Pro. for Workstations
- Analysis OS : Kali Linux (Windows Subsystem for Linux [WSL] v2.0)
- 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.
PersonalProductKeyCheck(args);
function is responsible for checking Home user keys.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,
- AAA is integer between 0–366 [Line 35]
- BB is between 04–93 [Line 41]
- OEM is fixed character [Line 17]
- XXXXXXX follows same mod7 rule as above [Line 48]
- CCCCC is random and is NOT checked at all!
Testing our analysis
1st case
Activation Code = 34505-OEM-0000007-13370
works, because:
- 0 < 345 < 366
- 3 < 05 < 94
- -OEM- is present
- 0+0+0+0+0+0+7=7 ; 7%7=0
- 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 😃.