 |
|
 |
Code posted above doesn't work!!!
Work version:
wstring GetWindowsKey()
{
wstring wsResult; HKEY hRegistryKey; BYTE *DigitalProductID = 0; DWORD DataLength; BYTE ProductKeyExtract[15]; char sCDKey[30]; int ByteCounter; int k; int nCur; bool bOk = false;
const char *KeyChars[] = {
"B","C","D","F","G","H","J","K","M",
"P","Q","R","T","V","W","X","Y",
"2","3","4","6","7","8","9",NULL
};
const TCHAR NT_CURRENT[] = _T("SOFTWARE\\MICROSOFT\\Windows NT\\CurrentVersion");
if( RegOpenKeyEx(HKEY_LOCAL_MACHINE, NT_CURRENT,
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
&hRegistryKey) == ERROR_SUCCESS )
{
DataLength = 164;
DigitalProductID = new byte[DataLength];
memset(DigitalProductID, 0, DataLength);
if( RegQueryValueEx(hRegistryKey, _T("DigitalProductId"),
NULL, NULL, DigitalProductID, &DataLength) == ERROR_SUCCESS )
{
memcpy(ProductKeyExtract, DigitalProductID+52, 15);
bOk = true;
}
if(DigitalProductID) delete []DigitalProductID;
RegCloseKey(hRegistryKey);
}
if( !bOk )
return wsResult;
memset(sCDKey, 0, sizeof(sCDKey));
for(ByteCounter=24; ByteCounter >= 0; --ByteCounter)
{
nCur = 0;
for(k=14; k >= 0; --k)
{
nCur = (nCur * 256) ^ ProductKeyExtract[k];
ProductKeyExtract[k] = nCur / 24;
nCur %= 24;
}
strcat(sCDKey, KeyChars[nCur]);
if( !(ByteCounter % 5) && ByteCounter )
strcat(sCDKey, "-");
}
_strrev(sCDKey);
USES_CONVERSION;
wsResult = A2W(sCDKey);
return wsResult;
}
modified on Friday, January 30, 2009 1:09 PM
|
|
|
|
 |
|
 |
On Windows XP 32bits Works
But on Windows Vista Home Basic x64 doesn't work, in the registry is this value "DigitalProductId4" I change but still doesnt work
I havent tested on Vista 32bits
Best Regards!!!
|
|
|
|
 |
|
 |
On 64 bit operating systems, this code is required to either be compiled into a 64 bit executable or detect that host Operating System is 64 and open the registry key with the KEY_WOW64_64KEY flag.
Hope this helps.
Edit: Wow, this is older than I thought it was.
|
|
|
|
 |
|
 |
Thanks danielsage
yeah it's old but I didn't know that!!
|
|
|
|
 |
|
 |
Here's the C# version:
http://www.gotdotnet.com/Community/UserSamples/Details.aspx?SampleGuid=26B414CD-87F2-472E-9EBE-A54EA7EF2095
Here's the VB.NET version:
http://www.gotdotnet.com/Community/UserSamples/Details.aspx?SampleGuid=3C3270B5-3ABA-4D34-A288D17FB93073E5
|
|
|
|
 |
|
 |
Nice piece of code.
Just wondering why you would bother to introduce the MFC CString and then return a BSTR? Why not just return the CString strResult and be done with it (assuming MFC users will want to convert the BSTR back to CString or equivelant anyway), or load the result into a BSTR var in the first place, and omit the MFC var altogether.
Just curious... It's still a good piece of work. Thanks!
In business, if two people always agree, one of them is unnecessary.
|
|
|
|
 |
|
 |
Hello,
thanks for posting this small piece of code.
One small bug noticed:
//Last Indexer
ProductKeyExtract[sizeof(ProductKeyExtract)] = NULL;
This will corrupt the stack, because [sizeof(ProductKeyExtract)] is outside of the ProductKeyExtract array. The 2 lines can be imho simply removed, since you do not treat this buffer as a C-styled string.
|
|
|
|
 |
|
 |
Yea, I found that bug right away as well (though didn't visit this article until just this morning).
NT_CURRENT isn't a standard define - it should be REGSTR_PATH_NT_CURRENTVERSION (from regstr.h). Perhaps the NT_CURRENT definition is part of some other devtool the author is using.
The method employed to insert hyphens is absolutely painful, repeatedly reversing the string to insert a hyphen (or even, just to add the next decoded character), and reversing it back. Since the characters are emitted last first, just skip the whole strrev business until the very end:
strcat(sCDKey, KeyChars[nCur]);
if(!(ByteCounter % 5) && (ByteCounter))
{
//Insert "-" between every five character sequence
strcat(sCDKey, "-");
}
}
//reverse the ENTIRE sequence ONCE.
_strrev(sCDKey);
OR add the following above the ByteCounter loop:
// 5 sequences of 5 chars + 4 intermediate hyphens
int MasterIndex= 5*5 + 4;
and replace the strcat/strrev stuff:
// Simply construct the code in reverse order. no strcat/strrev.
sCDKey[--MasterIndex] = *KeyChars[nCur];
if( ByteCounter && !(ByteCounter % 5) )
{
sCDKey[--MasterIndex] = '-';
}
This would insert the characters of the decoded key in the appropriate locations right from the start, no _strrev or strcat necessary.
Look Ma, no compiler warnings...
I found it curious that with all the variables crammed on the stack, the storage for the DigitalProductID registry value was actually _allocated_. There isn't a problem with allocating, but it could just as easily have been a stack variable -- sCDKey for instance doesn't need 256 bytes - it's a 30 character string (including null termination). DigitalProductID of course should be freed within the RegKeyOpenEx() conditional, right after the necessary bytes have been copied out of it. Likewise, the RegCloseKey() should be within the same conditional - and for that matter, all the decoding should be dependant upon a successful key retrieval.
I fixed issues I had with the code, and modified the function to take a passed BYTE array which may have been retrieved manually (say, from the registry on a non-booting HD, which puts the key elsewhere). In all, useful information to have.
I'm a bit more interested in what the conversion is between the CD key and the numeric product code.
-S. Straw
|
|
|
|
 |
|
 |
Any idea why it doesn't work in Windows Vista x64?
|
|
|
|
 |
|
 |
Maybe windows product key installed another session in vista!
...
|
|
|
|
 |
|
 |
I OR KEY_WOW64_64KEY In the fourth parameter of RegOpenKeyEx function, and can read the value of DigitalProductId with RegQueryValue. I don't know why it works, but it just worked. :P
|
|
|
|
 |
|
 |
tzukuei wrote: OR KEY_WOW64_64KEY In the fourth parameter of RegOpenKeyEx function, and can read the value of DigitalProductId with RegQueryValue. I don't know why it works, but it just worked.
Did you bother to check that on Vista x64?
There is no HKLM\\SOFTWARE\\MICROSOFT\\Windows NT\\CurrentVersion\\DigitalProductId there.
Windows XP x64 and Windows 2003 x64 have that key, but Vista x64 doesn't.
|
|
|
|
 |
|
 |
I have HKLM\\SOFTWARE\\MICROSOFT\\Windows NT\\CurrentVersion\\DigitalProductId on my Vista x64 RC2(build number 5744). Don't you have it? I can read the value using the parameter I described on my Vista x64 RC2. B.T.W., there is another key DigitalProductId4 at HKLM\\SOFTWARE\\MICROSOFT\\Windows NT\\CurrentVersion, but I don't know the differences between that.
|
|
|
|
 |
|
 |
I don't have that value. Please see the image here. I have Vindows Vista x64 RC2 build 5744, fresh install, no other operating system on the machine.
I have both DigitalProductId and DigitalProductId4 on my Vista 32 machine (it is RC1); see an image here.
|
|
|
|
 |
|
 |
I don't know what's going wrong with this, see my picture here[^].
|
|
|
|
 |
|
 |
Instead of KEY_ALL_ACCESS use
KEY_QUERY_VALUE | KEY_WOW64_64KEY
BTW, nice job.
awjapp
|
|
|
|
 |
|
|
 |
|
 |
Very simple access registry !! Good!!
...
|
|
|
|
 |
|
 |
RegistryKey key = Registry.LocalMachine;
key = key.OpenSubKey(@"SOFTWARE\MICROSOFT\Windows NT\CurrentVersion", false);
byte []digital_id = (byte[]) key.GetValue("DigitalProductId");
key.Close();
byte []product_key = new byte[15];
StringBuilder cdkey = new StringBuilder();
for(int i = 52;i <= 66;i++)
product_key[i - 52] = digital_id[i];
for(int i = 24;i >= 0;i--)
{
int nCur = 0;
for(int j = 14;j >= 0;j--)
{
nCur = (nCur*256) ^ product_key[j];
product_key[j] = (byte) (nCur/24);
nCur %= 24;
}
cdkey.Insert(0, key_chars[nCur]);
if ((0 == i % 5) && (0 != i))
cdkey.Insert(0,'-');
}
Console.WriteLine("CDKey: " + cdkey);
|
|
|
|
 |
|
 |
Not Work in C#!
using System;
using System.Text;
using Microsoft.Win32;
Error: The name 'key_chars' does not exist in the current context
|
|
|
|
 |