Compare commits

...

7 Commits

Author SHA1 Message Date
TheTank20
1738a31bde
Update windows.yml 2025-07-23 11:48:18 -05:00
TheTank20
bb1a1e7f3f
Update windows.yml 2025-07-23 11:43:13 -05:00
TheTank20
3dfd6eb9aa
Update windows.yml 2025-07-23 11:42:42 -05:00
TheTank20
32353cc35f
Merge pull request #13 from UMSKT/rewrite
rewrite
2025-07-23 02:40:04 -05:00
TheTank20
ee066856af Update README.md 2025-07-23 02:38:54 -05:00
TheTank20
ab8d15c6e3 library 2025-07-23 02:37:07 -05:00
TheTank20
696162e916 rewrite 2025-07-23 02:18:27 -05:00
6 changed files with 677 additions and 643 deletions

View File

@ -66,3 +66,92 @@ jobs:
with: with:
name: xpmgr (x64) name: xpmgr (x64)
path: .\build\xpmgr_x64.exe path: .\build\xpmgr_x64.exe
compress:
needs: build
if: success()
runs-on: windows-latest
steps:
- name: Cache TDM-GCC
id: cache-gcc
uses: actions/cache/restore@v4
with:
path: |
C:\TDM-GCC-64
key: TDM-GCC-10.3.0
- name: Setup TDM-GCC
if: steps.cache-gcc.outputs.cache-hit != 'true'
run: |
Write-Host Downloading TDM-GCC v10.3.0...
Invoke-WebRequest -Uri 'https://github.com/jmeubank/tdm-gcc/releases/download/v10.3.0-tdm64-2/tdm64-gcc-10.3.0-2.exe' -OutFile 'C:\Windows\temp\TDM-GCC-64.exe'
Write-Host Creating directory...
New-Item -ItemType Directory -Path 'C:\TDM-GCC-64'
Write-Host Copying files [Set 1/3]...
Start-Process '7z' -ArgumentList 'e C:\Windows\temp\TDM-GCC-64.exe -oC:\TDM-GCC-64 -y' -Wait
Write-Host Copying files [Set 2/3]...
Start-Process '7z' -ArgumentList 'e C:\TDM-GCC-64\*.tar.xz -oC:\TDM-GCC-64 -y' -Wait
Write-Host Copying files [Set 3/3]...
Start-Process '7z' -ArgumentList 'x C:\TDM-GCC-64\*.tar -oC:\TDM-GCC-64 -y' -Wait
- name: Save TDM-GCC
uses: actions/cache/save@v4
if: steps.cache-gcc.outputs.cache-hit != 'true'
with:
path: |
C:\TDM-GCC-64
key: TDM-GCC-10.3.0
- name: Setup UPX
run: |
Invoke-WebRequest -Uri 'https://github.com/upx/upx/releases/download/v5.0.2/upx-5.0.2-win64.zip' -OutFile 'C:\Windows\temp\upx.zip'
Write-Host Creating directory...
New-Item -ItemType Directory -Path 'C:\UPX'
Write-Host Copying files...
Expand-Archive -Path 'C:\Windows\temp\upx.zip' -DestinationPath 'C:\UPX'
Write-Host Adding environment variables...
$env:PATH = 'C:\UPX\upx-5.0.2-win64;' + $env:PATH
[Environment]::SetEnvironmentVariable('PATH', $env:PATH, [EnvironmentVariableTarget]::Machine)
- name: Download x86 artifact
uses: actions/download-artifact@v4
with:
name: xpmgr (x86)
path: .\build\x86
- name: Download x64 artifact
uses: actions/download-artifact@v4
with:
name: xpmgr (x64)
path: .\build\x64
- name: Compress binaries
shell: pwsh
run: |
# Strip symbols
strip .\build\x86\xpmgr_x86.exe
strip .\build\x64\xpmgr_x64.exe
# Remove resources
New-Item -ItemType Directory -Force -Path .\actions_upload
llvm-objcopy --remove-section .rsrc .\build\x86\xpmgr_x86.exe .\actions_upload\xpmgr_x86_comp.exe
llvm-objcopy --remove-section .rsrc .\build\x64\xpmgr_x64.exe .\actions_upload\xpmgr_x64_comp.exe
# Compress with UPX
& "C:\UPX\upx-5.0.2-win64\upx.exe" --best --ultra-brute .\actions_upload\xpmgr_x86_comp.exe
& "C:\UPX\upx-5.0.2-win64\upx.exe" --best --ultra-brute .\actions_upload\xpmgr_x64_comp.exe
Rename-Item -Path .\actions_upload\xpmgr_x86_comp.exe -NewName xpmgr_x86.exe
Rename-Item -Path .\actions_upload\xpmgr_x64_comp.exe -NewName xpmgr_x64.exe
- name: Upload build artifact (x86)
uses: actions/upload-artifact@v4.6.2
with:
name: xpmgr (x86, compressed)
path: .\actions_upload\xpmgr_x86.exe
- name: Upload build artifact (x64)
uses: actions/upload-artifact@v4.6.2
with:
name: xpmgr (x64, compressed)
path: .\actions_upload\xpmgr_x64.exe

View File

@ -5,8 +5,15 @@ set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(SOURCES xpmgr.cpp) set(SOURCES xpmgr.cpp)
set(LIB_SOURCES xpmgr_lib.cpp)
# ==== x86 build ==== # ==== x86 build ====
# Static library for x86
add_library(xpmgr_static_x86 STATIC ${LIB_SOURCES})
target_compile_options(xpmgr_static_x86 PRIVATE -m32)
target_link_libraries(xpmgr_static_x86 PRIVATE ole32 oleaut32 uuid)
set(RES_X86 ${CMAKE_BINARY_DIR}/icon_x86.res) set(RES_X86 ${CMAKE_BINARY_DIR}/icon_x86.res)
# Create a custom target for the x86 resource compilation # Create a custom target for the x86 resource compilation
@ -26,11 +33,17 @@ add_dependencies(xpmgr_x86 xpmgr_x86_res)
target_compile_options(xpmgr_x86 PRIVATE -m32) target_compile_options(xpmgr_x86 PRIVATE -m32)
target_link_options(xpmgr_x86 PRIVATE -m32) target_link_options(xpmgr_x86 PRIVATE -m32)
# Link .res file as a resource # Link .res file and static library
target_link_libraries(xpmgr_x86 PRIVATE ole32 oleaut32 uuid) target_link_libraries(xpmgr_x86 PRIVATE ole32 oleaut32 uuid xpmgr_static_x86)
target_link_options(xpmgr_x86 PRIVATE -Wl,--subsystem,console ${RES_X86}) target_link_options(xpmgr_x86 PRIVATE -Wl,--subsystem,console ${RES_X86})
# ==== x64 build ==== # ==== x64 build ====
# Static library for x64
add_library(xpmgr_static_x64 STATIC ${LIB_SOURCES})
target_compile_options(xpmgr_static_x64 PRIVATE -m64)
target_link_libraries(xpmgr_static_x64 PRIVATE ole32 oleaut32 uuid)
set(RES_X64 ${CMAKE_BINARY_DIR}/icon_x64.res) set(RES_X64 ${CMAKE_BINARY_DIR}/icon_x64.res)
# Create a custom target for the x64 resource compilation # Create a custom target for the x64 resource compilation
@ -50,6 +63,13 @@ add_dependencies(xpmgr_x64 xpmgr_x64_res)
target_compile_options(xpmgr_x64 PRIVATE -m64) target_compile_options(xpmgr_x64 PRIVATE -m64)
target_link_options(xpmgr_x64 PRIVATE -m64) target_link_options(xpmgr_x64 PRIVATE -m64)
# Link .res file as a resource # Link .res file and static library
target_link_libraries(xpmgr_x64 PRIVATE ole32 oleaut32 uuid) target_link_libraries(xpmgr_x64 PRIVATE ole32 oleaut32 uuid xpmgr_static_x64)
target_link_options(xpmgr_x64 PRIVATE -Wl,--subsystem,console ${RES_X64}) target_link_options(xpmgr_x64 PRIVATE -Wl,--subsystem,console ${RES_X64})
# Install targets
install(TARGETS xpmgr_static_x86 xpmgr_static_x64
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib)
install(FILES xpmgr.h DESTINATION include)

View File

@ -28,6 +28,8 @@ If you have an Itanium version of Windows XP or Server 2003, Windows Product Act
`/ipk` and `/dti` also support reading from stdin via a pipe. So, you could do something like `echo FCKGW-RHQQ2-YXRKT-8TG6W-2B7Q8 | xpmgr_x86 /ipk` or `echo 253286028742154311079061239762245184619981623171292574 | xpmgr_x86 /atp` (replace echo with your own program). `/ipk` and `/dti` also support reading from stdin via a pipe. So, you could do something like `echo FCKGW-RHQQ2-YXRKT-8TG6W-2B7Q8 | xpmgr_x86 /ipk` or `echo 253286028742154311079061239762245184619981623171292574 | xpmgr_x86 /atp` (replace echo with your own program).
This can also be used as a library; see the xpmgr.h file for details.
## Releases ## Releases
https://github.com/UMSKT/xpmgr/releases https://github.com/UMSKT/xpmgr/releases

788
xpmgr.cpp
View File

@ -3,662 +3,172 @@ typedef struct IUnknown IUnknown;
#include <windows.h> #include <windows.h>
#include <iostream> #include <iostream>
#include <comdef.h> #include <string>
#include <regex> #include <algorithm>
#include <TlHelp32.h> #include "xpmgr.h"
// Check windows // Command line handling
#if _WIN32 || _WIN64 struct CommandLineArgs {
#if _WIN64 static const char* getCmdOption(char** begin, char** end, const std::string& option) {
#define ENVIRONMENT64 const char* opt = option.c_str();
#else char** itr = std::find_if(begin, end, [opt](const char* arg) { return strcmp(arg, opt) == 0; });
#define ENVIRONMENT32 if (itr != end && ++itr != end) {
#endif return *itr;
#endif }
return nullptr;
}
const char* specifiedProduct = nullptr; static bool cmdOptionExists(char** begin, char** end, const std::string& option) {
const char* opt = option.c_str();
return std::find_if(begin, end, [opt](const char* arg) { return strcmp(arg, opt) == 0; }) != end;
}
// This is a really weird way of making a GUID. In short, this becomes ACADF079-CBCD-4032-83F2-FA47C4DB096F. Ignore the 0x and it makes sense. static std::string readFromStdin() {
static CLSID XP_CLSID = { 0xACADF079, 0xCBCD, 0x4032, {0x83, 0xF2, 0xFA, 0x47, 0xC4, 0xDB, 0x09, 0x6F} }; std::string input;
static IID XP_IID = { 0xB8CBAD79, 0x3F1F, 0x481A, { 0xBB, 0x0C, 0xE7, 0xBB, 0xD7, 0x7B, 0xDD, 0xD1 } }; if (!std::cin.eof() && std::getline(std::cin, input)) {
// Remove any trailing whitespace, newlines or carriage returns
#undef XP_INTERFACE input.erase(std::find_if(input.rbegin(), input.rend(), [](unsigned char ch) {
#define XP_INTERFACE ICOMLicenseAgent return !std::isspace(ch);
DECLARE_INTERFACE_(ICOMLicenseAgent, IDispatch) }).base(), input.end());
{ return input;
protected: }
~ICOMLicenseAgent() = default; return "";
}
public:
/*** IUnknown methods ***/
STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID * ppvObj) PURE;
STDMETHOD_(ULONG, AddRef)() PURE;
STDMETHOD_(ULONG, Release)() PURE;
/*** IDispatch methods ***/
STDMETHOD(GetTypeInfoCount)(THIS_ UINT FAR * pctinfo) PURE;
STDMETHOD(GetTypeInfo)(THIS_ UINT itinfo, LCID lcid, ITypeInfo FAR * FAR * pptinfo) PURE;
STDMETHOD(GetIDsOfNames)(THIS_ REFIID riid, OLECHAR FAR * FAR * rgszNames, UINT cNames, LCID lcid, DISPID FAR * rgdispid) PURE;
STDMETHOD(Invoke)(THIS_ DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR * pdispparams, VARIANT FAR * pvarResult, EXCEPINFO FAR * pexcepinfo, UINT FAR * puArgErr) PURE;
/*** ICOMLicenseAgent methods ***/
STDMETHOD(Initialize)(THIS_ ULONG dwBPC, ULONG dwMode, BSTR bstrLicSource, ULONG * pdwRetCode) PURE;
STDMETHOD(GetFirstName)(THIS_ BSTR * pbstrVal) PURE;
STDMETHOD(SetFirstName)(THIS_ BSTR bstrNewVal) PURE;
STDMETHOD(GetLastName)(THIS_ BSTR * pbstrVal) PURE;
STDMETHOD(SetLastName)(THIS_ BSTR bstrNewVal) PURE;
STDMETHOD(GetOrgName)(THIS_ BSTR * pbstrVal) PURE;
STDMETHOD(SetOrgName)(THIS_ BSTR bstrNewVal) PURE;
STDMETHOD(GetEmail)(THIS_ BSTR * pbstrVal) PURE;
STDMETHOD(SetEmail)(THIS_ BSTR bstrNewVal) PURE;
STDMETHOD(GetPhone)(THIS_ BSTR * pbstrVal) PURE;
STDMETHOD(SetPhone)(THIS_ BSTR bstrNewVal) PURE;
STDMETHOD(GetAddress1)(THIS_ BSTR * pbstrVal) PURE;
STDMETHOD(SetAddress1)(THIS_ BSTR bstrNewVal) PURE;
STDMETHOD(GetCity)(THIS_ BSTR * pbstrVal) PURE;
STDMETHOD(SetCity)(THIS_ BSTR bstrNewVal) PURE;
STDMETHOD(GetState)(THIS_ BSTR * pbstrVal) PURE;
STDMETHOD(SetState)(THIS_ BSTR bstrNewVal) PURE;
STDMETHOD(GetCountryCode)(THIS_ BSTR * pbstrVal) PURE;
STDMETHOD(SetCountryCode)(THIS_ BSTR bstrNewVal) PURE;
STDMETHOD(GetCountryDesc)(THIS_ BSTR * pbstrVal) PURE;
STDMETHOD(SetCountryDesc)(THIS_ BSTR bstrNewVal) PURE;
STDMETHOD(GetZip)(THIS_ BSTR * pbstrVal) PURE;
STDMETHOD(SetZip)(THIS_ BSTR bstrNewVal) PURE;
STDMETHOD(GetIsoLanguage)(THIS_ ULONG * pdwVal) PURE;
STDMETHOD(SetIsoLanguage)(THIS_ ULONG dwNewVal) PURE;
STDMETHOD(GetMSUpdate)(THIS_ BSTR * pbstrVal) PURE;
STDMETHOD(SetMSUpdate)(THIS_ BSTR bstrNewVal) PURE;
STDMETHOD(GetMSOffer)(THIS_ BSTR * pbstrVal) PURE;
STDMETHOD(SetMSOffer)(THIS_ BSTR bstrNewVal) PURE;
STDMETHOD(GetOtherOffer)(THIS_ BSTR * pbstrVal) PURE;
STDMETHOD(SetOtherOffer)(THIS_ BSTR bstrNewVal) PURE;
STDMETHOD(GetAddress2)(THIS_ BSTR * pbstrVal) PURE;
STDMETHOD(SetAddress2)(THIS_ BSTR bstrNewVal) PURE;
STDMETHOD(AsyncProcessHandshakeRequest)(THIS_ LONG bReviseCustInfo) PURE;
STDMETHOD(AsyncProcessNewLicenseRequest)() PURE;
STDMETHOD(AsyncProcessReissueLicenseRequest)() PURE;
STDMETHOD(AsyncProcessReviseCustInfoRequest)() PURE;
STDMETHOD(GetAsyncProcessReturnCode)(THIS_ ULONG * pdwRetCode) PURE;
STDMETHOD(AsyncProcessDroppedLicenseRequest)() PURE;
STDMETHOD(GenerateInstallationId)(THIS_ BSTR * pbstrVal) PURE;
STDMETHOD(DepositConfirmationId)(THIS_ BSTR bstrVal, ULONG * pdwRetCode) PURE;
STDMETHOD(GetExpirationInfo)(THIS_ ULONG * pdwWPALeft, ULONG * pdwEvalLeft) PURE;
STDMETHOD(AsyncProcessRegistrationRequest)() PURE;
STDMETHOD(ProcessHandshakeRequest)(THIS_ LONG bReviseCustInfo) PURE;
STDMETHOD(ProcessNewLicenseRequest)() PURE;
STDMETHOD(ProcessDroppedLicenseRequest)() PURE;
STDMETHOD(ProcessReissueLicenseRequest)() PURE;
STDMETHOD(ProcessReviseCustInfoRequest)() PURE;
STDMETHOD(EnsureInternetConnection)() PURE;
STDMETHOD(SetProductKey)(THIS_ LPWSTR pszNewProductKey) PURE;
STDMETHOD(GetProductID)(THIS_ BSTR * pbstrVal) PURE;
STDMETHOD(VerifyCheckDigits)(THIS_ BSTR bstrCIDIID, LONG * pbValue) PURE;
}; };
static BOOL XP_ComInitialized = FALSE; // Helper function to convert char* to wchar_t*
static ICOMLicenseAgent* XP_LicenseAgent = nullptr; wchar_t* convertCharArrayToLPCWSTR(const char* charArray) {
auto* wString = new wchar_t[4096];
static BOOL XP_LoadLicenseManager() MultiByteToWideChar(CP_ACP, 0, charArray, -1, wString, 4096);
{ return wString;
if (!XP_ComInitialized) {
const HRESULT status = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
if (FAILED(status)) {
const char* errorString = "An error occurred at CoInitializeEx:";
const int bufferSize = snprintf(nullptr, 0, "%s 0x%08X\n", errorString, static_cast<unsigned int>(status));
char* result = new char[bufferSize + 1];
snprintf(result, bufferSize + 1, "%s 0x%08X\n", errorString, static_cast<unsigned int>(status));
std::cout << result;
return FALSE;
}
XP_ComInitialized = TRUE;
}
if (!XP_LicenseAgent) {
HRESULT status = CoCreateInstance(XP_CLSID, nullptr, CLSCTX_INPROC_SERVER, XP_IID, reinterpret_cast<void **>(&XP_LicenseAgent));
int good = 0;
if (SUCCEEDED(status)) {
ULONG dwRetCode;
status = XP_LicenseAgent->Initialize(0xC475 /* This needs to be changed, I believe it's causing the crashing.*/ , 3, nullptr, &dwRetCode);
if (SUCCEEDED(status) && dwRetCode == 0) {
good = 1;
}
else {
XP_LicenseAgent->Release();
XP_LicenseAgent = nullptr;
}
}
if (!good) {
const char* errorString = "An error occurred at CoCreateInstance:";
const int bufferSize = snprintf(nullptr, 0, "%s 0x%08X\n", errorString, static_cast<unsigned int>(status));
char* result = new char[bufferSize + 1];
snprintf(result, bufferSize + 1, "%s 0x%08X\n", errorString, static_cast<unsigned int>(status));
std::cout << result;
return FALSE;
}
}
return TRUE;
} }
#pragma region Internals // Helper function to convert wchar_t* to char*
char* convertWCharToChar(const wchar_t* wcharArray) {
const int size = WideCharToMultiByte(CP_UTF8, 0, wcharArray, -1, nullptr, 0, nullptr, nullptr);
auto* charStr = new char[size];
WideCharToMultiByte(CP_UTF8, 0, wcharArray, -1, charStr, size, nullptr, nullptr);
return charStr;
}
// Add function to read from stdin int main(int argc, char* argv[]) {
std::string readFromStdin() { const char* USAGE_TEXT =
std::string input; "xpmgr - Windows XP License Manager (compiled on " __DATE__ " " __TIME__ ")\n"
if (!std::cin.eof() && std::getline(std::cin, input)) { "\n"
// Remove any trailing whitespace, newlines or carriage returns "Usage: \n"
input.erase(std::find_if(input.rbegin(), input.rend(), [](unsigned char ch) { "/dti: Gets the Installation ID\n"
return !std::isspace(ch); "/atp [cid]: Sets Confirmation ID (If successful, activates Windows/Office) (can also read from stdin)\n"
}).base(), input.end()); "/xpr: Gets the days before activation is required (Grace period)\n"
return input; "/xpr-eval: Gets the days before the evaluation period expires (Eval. copies only)\n"
"/ipk [pkey]: Sets/changes product key (can also read from stdin)\n"
"/dli: Gets the product ID of Windows\n"
"/?: Displays this message";
if (CommandLineArgs::cmdOptionExists(argv, argv + argc, "--GetUsage")) {
std::cout << USAGE_TEXT;
return 0;
} }
return "";
}
wchar_t* convertCharArrayToLPCWSTR(const char* charArray) // Check Windows version
{ OSVERSIONINFOEX info = {};
auto* wString = new wchar_t[4096]; info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
MultiByteToWideChar(CP_ACP, 0, charArray, -1, wString, 4096); GetVersionEx(reinterpret_cast<LPOSVERSIONINFO>(&info));
return wString;
}
char* getCmdOption(char** begin, char** end, const std::string& option) if (info.dwMajorVersion != 5) {
{ std::cout << "An error occurred: Windows management only works on Windows NT 5.1 and 5.2.";
char** itr = std::find(begin, end, option); if (info.dwMajorVersion > 5) {
if (itr != end && ++itr != end) std::cout << " Use slmgr instead: https://learn.microsoft.com/en-us/windows-server/get-started/activation-slmgr-vbs-options";
{ return 3;
return *itr; }
} return 2;
return nullptr;
}
bool cmdOptionExists(char** begin, char** end, const std::string& option)
{
return std::find(begin, end, option) != end;
}
char* BstrToChar(BSTR bstr)
{
const int len = static_cast<int>(::SysStringLen(bstr));
const int bufSize = ::WideCharToMultiByte(CP_UTF8, 0, bstr, len, nullptr, 0, nullptr, nullptr);
const auto buffer = new char[bufSize + 1];
::WideCharToMultiByte(CP_UTF8, 0, bstr, len, buffer, bufSize, nullptr, nullptr);
buffer[bufSize] = '\0';
return buffer;
}
ULONG ConvertToULONG(const char* str)
{
char* end;
const ULONG value = std::strtoul(str, &end, 10);
return value;
}
OLECHAR SizeToOLECHAR(size_t value)
{
// Convert size_t to wstring
const std::wstring wideString = std::to_wstring(value);
// Retrieve the first character from the wide string
const OLECHAR oChar = wideString[0];
return oChar;
}
BSTR ConvertToBSTR(const std::string& str) {
const int size = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, nullptr, 0);
// ReSharper disable once CppLocalVariableMayBeConst
BSTR bstr = SysAllocStringLen(nullptr, size - 1);
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, bstr, size);
return bstr;
}
std::string ConvertToStdString(BSTR bstr) {
const int size = WideCharToMultiByte(CP_UTF8, 0, bstr, -1, nullptr, 0, nullptr, nullptr);
const auto buffer = new char[size];
WideCharToMultiByte(CP_UTF8, 0, bstr, -1, buffer, size, nullptr, nullptr);
std::string result(buffer);
delete[] buffer;
return result;
}
BSTR ConvertCharToBSTR(const char* charString) {
const int size = MultiByteToWideChar(CP_UTF8, 0, charString, -1, nullptr, 0);
// ReSharper disable once CppLocalVariableMayBeConst
BSTR bstr = SysAllocStringLen(nullptr, size - 1);
MultiByteToWideChar(CP_UTF8, 0, charString, -1, bstr, size);
return bstr;
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
void safeStrncat(char* destination, const char* source, size_t size) {
const size_t destLen = strlen(destination);
const size_t srcLen = strlen(source);
if (destLen + srcLen < size) {
// fuck off Microsoft
strncat(destination, source, size - destLen - 1); // -1 for the null terminator
} else {
// Handle buffer overflow error
std::cout << "An error occurred at safeStrncat: Buffer overflow during strncat operation." << std::endl;
} }
}
#pragma clang diagnostic pop
bool IsProcessRunning(const wchar_t* processName) if (info.dwMinorVersion != 1 && info.dwMinorVersion != 2) {
{ std::cout << "An error occurred: Windows management only works on Windows NT 5.1 and 5.2.";
// ReSharper disable once CppLocalVariableMayBeConst if (info.dwMinorVersion == 0) {
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); std::cout << " You should be fine anyways, since Windows 2000 doesn't use Product Activation.";
if (snapshot == INVALID_HANDLE_VALUE) return 4;
{ }
std::cout << "An error occurred at IsProcessRunning: Failed to create process snapshot." << std::endl; return 5;
return false; }
}
PROCESSENTRY32W processEntry{}; // Check architecture
processEntry.dwSize = sizeof(PROCESSENTRY32W);
if (!Process32FirstW(snapshot, &processEntry))
{
CloseHandle(snapshot);
std::cout << "An error occurred at IsProcessRunning: Failed to retrieve process information." << std::endl;
return false;
}
while (Process32NextW(snapshot, &processEntry))
{
if (wcscmp(processEntry.szExeFile, processName) == 0)
{
CloseHandle(snapshot);
return true; // Process found
}
}
CloseHandle(snapshot);
return false; // Process not found
}
bool TerminateProcessByName(const wchar_t* processName)
{
// ReSharper disable once CppLocalVariableMayBeConst
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (snapshot == INVALID_HANDLE_VALUE)
{
return false;
}
PROCESSENTRY32W processEntry{};
processEntry.dwSize = sizeof(PROCESSENTRY32W);
if (!Process32FirstW(snapshot, &processEntry))
{
CloseHandle(snapshot);
return false;
}
while (Process32NextW(snapshot, &processEntry))
{
if (wcscmp(processEntry.szExeFile, processName) == 0)
{
// ReSharper disable once CppLocalVariableMayBeConst
HANDLE processHandle = OpenProcess(PROCESS_TERMINATE, FALSE, processEntry.th32ProcessID);
if (processHandle != nullptr)
{
if (TerminateProcess(processHandle, 0))
{
CloseHandle(processHandle);
CloseHandle(snapshot);
return true; // Process terminated successfully
}
else
{
CloseHandle(processHandle);
CloseHandle(snapshot);
return false; // Failed to terminate the process
}
}
else
{
CloseHandle(snapshot);
return false; // Failed to open process handle
}
}
}
CloseHandle(snapshot);
return false; // Process not found
}
#pragma endregion
#pragma region Windows XP
static BSTR XP_GetWPALeft() {
if (!XP_LoadLicenseManager()) {
return SysAllocString(L"An error occurred at XP_LoadLicenseManager: Failed to load");
}
ULONG dwWPALeft = 0, dwEvalLeft = 0;
const HRESULT status = XP_LicenseAgent->GetExpirationInfo(&dwWPALeft, &dwEvalLeft);
if (FAILED(status)) {
XP_LicenseAgent->Release();
XP_LicenseAgent = nullptr;
const char* errorString = "An error occurred at CoInitializeEx:";
const int bufferSize = snprintf(nullptr, 0, "%s 0x%08X", errorString, static_cast<unsigned int>(status));
char* result = new char[bufferSize + 1];
snprintf(result, bufferSize + 1, "%s 0x%08X", errorString, static_cast<unsigned int>(status));
const int wideCharSize = MultiByteToWideChar(CP_UTF8, 0, result, -1, nullptr, 0);
auto* wideResult = new OLECHAR[wideCharSize];
MultiByteToWideChar(CP_UTF8, 0, result, -1, wideResult, wideCharSize);
return SysAllocString(wideResult);
}
if (dwWPALeft == 0x7FFFFFFF) {
return SysAllocString(L"An error occurred at GetWPALeft: Windows is activated");
}
wchar_t buffer[16];
swprintf(buffer, L"%lu", dwWPALeft);
return SysAllocString(buffer);
}
static BSTR XP_GetEvalLeft() {
if (!XP_LoadLicenseManager()) {
return SysAllocString(L"An error occurred at XP_LoadLicenseManager: Failed to load");
}
ULONG dwWPALeft = 0, dwEvalLeft = 0;
const HRESULT status = XP_LicenseAgent->GetExpirationInfo(&dwWPALeft, &dwEvalLeft);
if (FAILED(status)) {
XP_LicenseAgent->Release();
XP_LicenseAgent = nullptr;
const char* errorString = "An error occurred at GetExpirationInfo:";
const int bufferSize = snprintf(nullptr, 0, "%s 0x%08X", errorString, static_cast<unsigned int>(status));
char* result = new char[bufferSize + 1];
snprintf(result, bufferSize + 1, "%s 0x%08X", errorString, static_cast<unsigned int>(status));
const int wideCharSize = MultiByteToWideChar(CP_UTF8, 0, result, -1, nullptr, 0);
auto* wideResult = new OLECHAR[wideCharSize];
MultiByteToWideChar(CP_UTF8, 0, result, -1, wideResult, wideCharSize);
return SysAllocString(wideResult);
}
if (dwEvalLeft == 0x7FFFFFFF) {
return SysAllocString(L"An error occurred at GetEvalLeft: Not an evaluation copy");
}
wchar_t buffer[16];
swprintf(buffer, L"%lu", dwWPALeft);
return SysAllocString(buffer);
}
static BSTR XP_VerifyCheckDigits(BSTR cidChunk) {
if (!XP_LoadLicenseManager()) {
return SysAllocString(L"An error occurred at XP_LoadLicenseManager: Failed to load");
}
if (0 == wcscmp(XP_GetWPALeft(), L"An error occurred at GetWPALeft: Windows is activated")) {
return SysAllocString(L"An error occurred at GetWPALeft: Windows is activated");
}
LONG pbValue;
const HRESULT status = XP_LicenseAgent->VerifyCheckDigits(cidChunk, &pbValue);
if (FAILED(status) || !pbValue) {
char errorMessage[70] = "An error occurred at XP_VerifyCheckDigits:";
char pbValueChar[20];
snprintf(errorMessage, sizeof(errorMessage), "%ld", pbValue);
safeStrncat(errorMessage, pbValueChar, sizeof(errorMessage));
const int len = MultiByteToWideChar(CP_UTF8, 0, errorMessage, -1, nullptr, 0);
auto* oleCharString = new OLECHAR[len];
MultiByteToWideChar(CP_UTF8, 0, errorMessage, -1, oleCharString, len);
return SysAllocString(oleCharString);
}
return SysAllocString(L"Successfully verified CID chunk");
}
static BSTR XP_SetConfirmationID(BSTR confirmationID) {
if (!XP_LoadLicenseManager()) {
return SysAllocString(L"An error occurred at XP_LoadLicenseManager: Failed to load");
}
if (0 == wcscmp(XP_GetWPALeft(), L"An error occurred at GetWPALeft: Windows is activated")) {
return SysAllocString(L"An error occurred at GetWPALeft: Windows is activated");
}
const int length = static_cast<int>(SysStringLen(confirmationID));
char* str = new char[length + 1];
WideCharToMultiByte(CP_UTF8, 0, confirmationID, length, str, length, nullptr, nullptr);
str[length] = '\0';
std::string inputString(str);
inputString.erase(std::remove(inputString.begin(), inputString.end(), '-'), inputString.end()); // remove -'s
for (size_t i = 0; i < inputString.length(); i += 6) {
std::string substring = inputString.substr(i, 6);
const char* cstr = substring.c_str();
if (0 != wcscmp(XP_VerifyCheckDigits(ConvertCharToBSTR(cstr)), L"Successfully verified CID chunk")) {
return SysAllocString(L"An error occurred at XP_VerifyCheckDigits: Check for misspelling");
}
}
ULONG dwRetCode;
const HRESULT status = XP_LicenseAgent->DepositConfirmationId(confirmationID, &dwRetCode);
if (FAILED(status) || dwRetCode) {
const char* errorString = "An error occurred at DepositConfirmationId:";
const int bufferSize = snprintf(nullptr, 0, "%s 0x%08X %lu", errorString, static_cast<unsigned int>(status), dwRetCode);
char* result = new char[bufferSize + 1];
snprintf(result, bufferSize + 1, "%s 0x%08X %lu", errorString, static_cast<unsigned int>(status), dwRetCode);
const int wideCharSize = MultiByteToWideChar(CP_UTF8, 0, result, -1, nullptr, 0);
auto* wideResult = new OLECHAR[wideCharSize];
MultiByteToWideChar(CP_UTF8, 0, result, -1, wideResult, wideCharSize);
return SysAllocString(wideResult);
}
system("rundll32 setupapi,InstallHinfSection DEL_OOBE_ACTIVATE 132 syssetup.inf"); // remove activation shortcuts
if (IsProcessRunning(L"wpabaln.exe")) { // end WPA notifier process if there
TerminateProcessByName(L"wpabaln.exe");
}
return SysAllocString(L"Successfully set confirmation ID");
}
static BSTR XP_GetInstallationID() {
if (!XP_LoadLicenseManager()) {
return SysAllocString(L"An error occurred at XP_LoadLicenseManager: Failed to load");
}
if (0 == wcscmp(XP_GetWPALeft(), L"An error occurred at GetWPALeft: Windows is activated")) {
return SysAllocString(L"An error occurred at GetWPALeft: Windows is activated");
}
BSTR installationID = nullptr;
const HRESULT status = XP_LicenseAgent->GenerateInstallationId(&installationID);
if (FAILED(status) || !installationID) {
const char* errorString = "An error occurred at GenerateInstallationId:";
const int bufferSize = snprintf(nullptr, 0, "%s 0x%08X", errorString, static_cast<unsigned int>(status));
char* result = new char[bufferSize + 1];
snprintf(result, bufferSize + 1, "%s 0x%08X", errorString, static_cast<unsigned int>(status));
const int wideCharSize = MultiByteToWideChar(CP_UTF8, 0, result, -1, nullptr, 0);
auto* wideResult = new OLECHAR[wideCharSize];
MultiByteToWideChar(CP_UTF8, 0, result, -1, wideResult, wideCharSize);
return SysAllocString(wideResult);
}
else {
return installationID;
}
}
static BSTR XP_SetProductKey(LPWSTR productKey) {
if (!XP_LoadLicenseManager()) {
return SysAllocString(L"An error occurred at XP_LoadLicenseManager: Failed to load");
}
std::wstring ws(productKey);
const std::string productKeyToRegex = std::string(ws.begin(), ws.end());
const std::regex pattern("[2346789BCDFGHJKMPQRTVWXY]{5}-[2346789BCDFGHJKMPQRTVWXY]{5}-[2346789BCDFGHJKMPQRTVWXY]{5}-[2346789BCDFGHJKMPQRTVWXY]{5}-[2346789BCDFGHJKMPQRTVWXY]{5}");
if (!std::regex_match(productKeyToRegex, pattern)) {
return SysAllocString(L"An error occurred at regex_match: Product key is invalid");
}
if (0 == wcscmp(XP_GetWPALeft(), L"An error occurred at GetWPALeft: Windows is activated")) {
return SysAllocString(L"An error occurred at GetWPALeft: Windows is activated");
}
const HRESULT status = XP_LicenseAgent->SetProductKey(productKey);
if (FAILED(status)) {
const char* errorString = "An error occurred at SetProductKey:";
const int bufferSize = snprintf(nullptr, 0, "%s 0x%08X", errorString, static_cast<unsigned int>(status));
char* result = new char[bufferSize + 1];
snprintf(result, bufferSize + 1, "%s 0x%08X", errorString, static_cast<unsigned int>(status));
const int wideCharSize = MultiByteToWideChar(CP_UTF8, 0, result, -1, nullptr, 0);
auto* wideResult = new OLECHAR[wideCharSize];
MultiByteToWideChar(CP_UTF8, 0, result, -1, wideResult, wideCharSize);
return SysAllocString(wideResult);
}
else {
return SysAllocString(L"Successfully set product key");
}
}
static BSTR XP_GetProductID() {
if (!XP_LoadLicenseManager()) {
return SysAllocString(L"An error occurred at XP_LoadLicenseManager: Failed to load");
}
BSTR productID = nullptr;
const HRESULT status = XP_LicenseAgent->GetProductID(&productID);
if (FAILED(status)) {
const char* errorString = "An error occurred at GetProductID:";
const int bufferSize = snprintf(nullptr, 0, "%s 0x%08X", errorString, static_cast<unsigned int>(status));
char* result = new char[bufferSize + 1];
snprintf(result, bufferSize + 1, "%s 0x%08X", errorString, static_cast<unsigned int>(status));
const int wideCharSize = MultiByteToWideChar(CP_UTF8, 0, result, -1, nullptr, 0);
auto* wideResult = new OLECHAR[wideCharSize];
MultiByteToWideChar(CP_UTF8, 0, result, -1, wideResult, wideCharSize);
return SysAllocString(wideResult);
}
else {
return productID;
}
}
#pragma endregion
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
int main(int argc, char* argv[])
{
const char* text =
"xpmgr - Windows XP License Manager (compiled on " __DATE__ " " __TIME__ ")\n"
"\n"
"Usage: \n"
"/dti: Gets the Installation ID\n"
"/atp [cid]: Sets Confirmation ID (If successful, activates Windows/Office) (can also read from stdin)\n"
"/xpr: Gets the days before activation is required (Grace period)\n"
"/xpr-eval: Gets the days before the evaluation period expires (Eval. copies only)\n"
"/ipk [pkey]: Sets/changes product key (can also read from stdin)\n"
"/dli: Gets the product ID of Windows\n"
"/?: Displays this message";
if (cmdOptionExists(argv, argv + argc, "--GetUsage")) {
std::cout << text;
return 0;
}
specifiedProduct = "WindowsNT5x";
if (std::strcmp(specifiedProduct, "WindowsNT5x") == 0) {
SYSTEM_INFO systemInfo;
GetNativeSystemInfo(&systemInfo);
#ifdef ENVIRONMENT32 #ifdef ENVIRONMENT32
if (systemInfo.wProcessorArchitecture != PROCESSOR_ARCHITECTURE_INTEL) { // running under WOW64 SYSTEM_INFO systemInfo;
if (systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) { // is AMD64 GetNativeSystemInfo(&systemInfo);
std::cout << "An error occurred at systemInfo: Incorrect version of xpmgr. You need to download the x64 version."; if (systemInfo.wProcessorArchitecture != PROCESSOR_ARCHITECTURE_INTEL) {
} if (systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) {
else if (systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64) { // is IA64 std::cout << "An error occurred: Incorrect version of xpmgr. You need to download the x64 version.";
std::cout << "An error occurred at systemInfo: Windows Product Activation does not exist on this platform."; return 1;
} }
else { // is PPC, megafart 386, whatever else if (systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64) {
std::cout << "An error occurred at systemInfo: Incorrect version of xpmgr. Send an issue at https://github.com/UMSKT/xpmgr/issues if you want to help us make a version for your platform!"; std::cout << "An error occurred: Windows Product Activation does not exist on this platform.";
} return 1;
return 1; }
} std::cout << "An error occurred: Incorrect version of xpmgr. Send an issue at https://github.com/UMSKT/xpmgr/issues if you want to help us make a version for your platform!";
return 1;
}
#endif #endif
OSVERSIONINFOEX info = {};
info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
GetVersionEx(reinterpret_cast<LPOSVERSIONINFO>(&info));
if (info.dwMajorVersion != 5) { // Initialize the library
std::cout << "An error occurred at OSVERSIONINFOEX: Windows management only works on Windows NT 5.1 and 5.2."; XPMGR_Initialize();
if (info.dwMajorVersion > 5) {
std::cout << " Use slmgr instead: https://learn.microsoft.com/en-us/windows-server/get-started/activation-slmgr-vbs-options";
return 3;
}
return 2;
}
else {
if (info.dwMinorVersion != 1 && info.dwMinorVersion != 2) {
std::cout << "An error occurred at OSVERSIONINFOEX: Windows management only works on Windows NT 5.1 and 5.2.";
if (info.dwMinorVersion == 0) {
std::cout << " You should be fine anyways, since Windows 2000 doesn't use Product Activation.";
return 4;
}
return 5;
}
}
}
if (cmdOptionExists(argv, argv + argc, "/dti")) { // Handle commands
std::cout << ConvertToStdString(XP_GetInstallationID()); const wchar_t* result = nullptr;
return 0; if (CommandLineArgs::cmdOptionExists(argv, argv + argc, "/dti")) {
} result = XPMGR_GetInstallationID();
else if (cmdOptionExists(argv, argv + argc, "/atp")) { }
const char* confirmationId = getCmdOption(argv, argv + argc, "/atp"); else if (CommandLineArgs::cmdOptionExists(argv, argv + argc, "/atp")) {
if (!confirmationId) { const char* confirmationId = CommandLineArgs::getCmdOption(argv, argv + argc, "/atp");
// No argument provided, try reading from stdin if (!confirmationId) {
std::string pipedInput = readFromStdin(); std::string pipedInput = CommandLineArgs::readFromStdin();
if (!pipedInput.empty()) { if (!pipedInput.empty()) {
std::cout << ConvertToStdString(XP_SetConfirmationID(ConvertCharToBSTR(pipedInput.c_str()))); result = XPMGR_SetConfirmationID(convertCharArrayToLPCWSTR(pipedInput.c_str()));
} else { } else {
std::cout << "An error occurred at main: No confirmation ID provided via argument or pipe\n\n"; std::cout << "An error occurred: No confirmation ID provided via argument or pipe\n\n" << USAGE_TEXT;
std::cout << text; XPMGR_Cleanup();
return 7; return 7;
} }
} else { } else {
std::cout << ConvertToStdString(XP_SetConfirmationID(ConvertCharToBSTR(confirmationId))); result = XPMGR_SetConfirmationID(convertCharArrayToLPCWSTR(confirmationId));
} }
return 0; }
} else if (CommandLineArgs::cmdOptionExists(argv, argv + argc, "/xpr")) {
else if (cmdOptionExists(argv, argv + argc, "/xpr")) { result = XPMGR_GetWPALeft();
std::cout << ConvertToStdString(XP_GetWPALeft()); }
return 0; else if (CommandLineArgs::cmdOptionExists(argv, argv + argc, "/xpr-eval")) {
} result = XPMGR_GetEvalLeft();
else if (cmdOptionExists(argv, argv + argc, "/xpr-eval")) { }
std::cout << ConvertToStdString(XP_GetEvalLeft()); else if (CommandLineArgs::cmdOptionExists(argv, argv + argc, "/ipk")) {
return 0; const char* productKey = CommandLineArgs::getCmdOption(argv, argv + argc, "/ipk");
} if (!productKey) {
std::string pipedInput = CommandLineArgs::readFromStdin();
if (!pipedInput.empty()) {
result = XPMGR_SetProductKey(convertCharArrayToLPCWSTR(pipedInput.c_str()));
} else {
std::cout << "An error occurred: No product key provided via argument or pipe\n\n" << USAGE_TEXT;
XPMGR_Cleanup();
return 7;
}
} else {
result = XPMGR_SetProductKey(convertCharArrayToLPCWSTR(productKey));
}
}
else if (CommandLineArgs::cmdOptionExists(argv, argv + argc, "/dli")) {
result = XPMGR_GetProductID();
}
else {
std::cout << "An error occurred: No arguments listed\n\n" << USAGE_TEXT;
XPMGR_Cleanup();
return 7;
}
else if (cmdOptionExists(argv, argv + argc, "/ipk")) { if (result) {
const char* productKey = getCmdOption(argv, argv + argc, "/ipk"); char* output = convertWCharToChar(result);
if (!productKey) { std::cout << output;
// No argument provided, try reading from stdin delete[] output;
std::string pipedInput = readFromStdin(); }
if (!pipedInput.empty()) {
std::cout << ConvertToStdString(XP_SetProductKey(convertCharArrayToLPCWSTR(pipedInput.c_str()))); XPMGR_Cleanup();
} else { return 0;
std::cout << "An error occurred at main: No product key provided via argument or pipe\n\n";
std::cout << text;
return 7;
}
} else {
std::cout << ConvertToStdString(XP_SetProductKey(convertCharArrayToLPCWSTR(productKey)));
}
return 0;
}
else if (cmdOptionExists(argv, argv + argc, "/dli")) {
std::cout << ConvertToStdString(XP_GetProductID());
return 0;
}
else {
std::cout << "An error occurred at main: No arguments listed\n\n";
std::cout << text;
return 7;
}
} }
#pragma clang diagnostic pop

24
xpmgr.h Normal file
View File

@ -0,0 +1,24 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <windows.h>
// Core functions that match command line options
const wchar_t* XPMGR_GetInstallationID(); // /dti
const wchar_t* XPMGR_SetConfirmationID(const wchar_t* confirmationId); // /atp
const wchar_t* XPMGR_GetWPALeft(); // /xpr
const wchar_t* XPMGR_GetEvalLeft(); // /xpr-eval
const wchar_t* XPMGR_SetProductKey(const wchar_t* productKey); // /ipk
const wchar_t* XPMGR_GetProductID(); // /dli
// Additional utility functions
const wchar_t* XPMGR_GetLastError();
void XPMGR_Initialize();
void XPMGR_Cleanup();
#ifdef __cplusplus
}
#endif

389
xpmgr_lib.cpp Normal file
View File

@ -0,0 +1,389 @@
#include "xpmgr.h"
#include <windows.h>
#include <objbase.h>
#include <oleauto.h>
#include <regex>
#include <string>
#include <algorithm>
#include <TlHelp32.h>
#include <iostream>
// CLSID and IID definitions
static CLSID XP_CLSID = { 0xACADF079, 0xCBCD, 0x4032, {0x83, 0xF2, 0xFA, 0x47, 0xC4, 0xDB, 0x09, 0x6F} };
static IID XP_IID = { 0xB8CBAD79, 0x3F1F, 0x481A, { 0xBB, 0x0C, 0xE7, 0xBB, 0xD7, 0x7B, 0xDD, 0xD1 } };
// Interface definition
DECLARE_INTERFACE_(ICOMLicenseAgent, IDispatch)
{
protected:
~ICOMLicenseAgent() = default;
public:
/*** IUnknown methods ***/
STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID* ppvObj) PURE;
STDMETHOD_(ULONG, AddRef)() PURE;
STDMETHOD_(ULONG, Release)() PURE;
/*** IDispatch methods ***/
STDMETHOD(GetTypeInfoCount)(THIS_ UINT FAR* pctinfo) PURE;
STDMETHOD(GetTypeInfo)(THIS_ UINT itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo) PURE;
STDMETHOD(GetIDsOfNames)(THIS_ REFIID riid, OLECHAR FAR* FAR* rgszNames, UINT cNames, LCID lcid, DISPID FAR* rgdispid) PURE;
STDMETHOD(Invoke)(THIS_ DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR* pdispparams, VARIANT FAR* pvarResult, EXCEPINFO FAR* pexcepinfo, UINT FAR* puArgErr) PURE;
/*** ICOMLicenseAgent methods ***/
STDMETHOD(Initialize)(THIS_ ULONG dwBPC, ULONG dwMode, BSTR bstrLicSource, ULONG* pdwRetCode) PURE;
STDMETHOD(GetFirstName)(THIS_ BSTR* pbstrVal) PURE;
STDMETHOD(SetFirstName)(THIS_ BSTR bstrNewVal) PURE;
STDMETHOD(GetLastName)(THIS_ BSTR* pbstrVal) PURE;
STDMETHOD(SetLastName)(THIS_ BSTR bstrNewVal) PURE;
STDMETHOD(GetOrgName)(THIS_ BSTR* pbstrVal) PURE;
STDMETHOD(SetOrgName)(THIS_ BSTR bstrNewVal) PURE;
STDMETHOD(GetEmail)(THIS_ BSTR* pbstrVal) PURE;
STDMETHOD(SetEmail)(THIS_ BSTR bstrNewVal) PURE;
STDMETHOD(GetPhone)(THIS_ BSTR* pbstrVal) PURE;
STDMETHOD(SetPhone)(THIS_ BSTR bstrNewVal) PURE;
STDMETHOD(GetAddress1)(THIS_ BSTR* pbstrVal) PURE;
STDMETHOD(SetAddress1)(THIS_ BSTR bstrNewVal) PURE;
STDMETHOD(GetCity)(THIS_ BSTR* pbstrVal) PURE;
STDMETHOD(SetCity)(THIS_ BSTR bstrNewVal) PURE;
STDMETHOD(GetState)(THIS_ BSTR* pbstrVal) PURE;
STDMETHOD(SetState)(THIS_ BSTR bstrNewVal) PURE;
STDMETHOD(GetCountryCode)(THIS_ BSTR* pbstrVal) PURE;
STDMETHOD(SetCountryCode)(THIS_ BSTR bstrNewVal) PURE;
STDMETHOD(GetCountryDesc)(THIS_ BSTR* pbstrVal) PURE;
STDMETHOD(SetCountryDesc)(THIS_ BSTR bstrNewVal) PURE;
STDMETHOD(GetZip)(THIS_ BSTR* pbstrVal) PURE;
STDMETHOD(SetZip)(THIS_ BSTR bstrNewVal) PURE;
STDMETHOD(GetIsoLanguage)(THIS_ ULONG* pdwVal) PURE;
STDMETHOD(SetIsoLanguage)(THIS_ ULONG dwNewVal) PURE;
STDMETHOD(GetMSUpdate)(THIS_ BSTR* pbstrVal) PURE;
STDMETHOD(SetMSUpdate)(THIS_ BSTR bstrNewVal) PURE;
STDMETHOD(GetMSOffer)(THIS_ BSTR* pbstrVal) PURE;
STDMETHOD(SetMSOffer)(THIS_ BSTR bstrNewVal) PURE;
STDMETHOD(GetOtherOffer)(THIS_ BSTR* pbstrVal) PURE;
STDMETHOD(SetOtherOffer)(THIS_ BSTR bstrNewVal) PURE;
STDMETHOD(GetAddress2)(THIS_ BSTR* pbstrVal) PURE;
STDMETHOD(SetAddress2)(THIS_ BSTR bstrNewVal) PURE;
STDMETHOD(AsyncProcessHandshakeRequest)(THIS_ LONG bReviseCustInfo) PURE;
STDMETHOD(AsyncProcessNewLicenseRequest)() PURE;
STDMETHOD(AsyncProcessReissueLicenseRequest)() PURE;
STDMETHOD(AsyncProcessReviseCustInfoRequest)() PURE;
STDMETHOD(GetAsyncProcessReturnCode)(THIS_ ULONG* pdwRetCode) PURE;
STDMETHOD(AsyncProcessDroppedLicenseRequest)() PURE;
STDMETHOD(GenerateInstallationId)(THIS_ BSTR* pbstrVal) PURE;
STDMETHOD(DepositConfirmationId)(THIS_ BSTR bstrVal, ULONG* pdwRetCode) PURE;
STDMETHOD(GetExpirationInfo)(THIS_ ULONG* pdwWPALeft, ULONG* pdwEvalLeft) PURE;
STDMETHOD(AsyncProcessRegistrationRequest)() PURE;
STDMETHOD(ProcessHandshakeRequest)(THIS_ LONG bReviseCustInfo) PURE;
STDMETHOD(ProcessNewLicenseRequest)() PURE;
STDMETHOD(ProcessDroppedLicenseRequest)() PURE;
STDMETHOD(ProcessReissueLicenseRequest)() PURE;
STDMETHOD(ProcessReviseCustInfoRequest)() PURE;
STDMETHOD(EnsureInternetConnection)() PURE;
STDMETHOD(SetProductKey)(THIS_ LPWSTR pszNewProductKey) PURE;
STDMETHOD(GetProductID)(THIS_ BSTR* pbstrVal) PURE;
STDMETHOD(VerifyCheckDigits)(THIS_ BSTR bstrCIDIID, LONG* pbValue) PURE;
};
// Static variables
static BOOL XP_ComInitialized = FALSE;
static ICOMLicenseAgent* XP_LicenseAgent = nullptr;
static wchar_t LastErrorMessage[1024] = L"";
// Helper functions
static void SetLastErrorMessage(const wchar_t* message) {
wcscpy(LastErrorMessage, message);
}
static BOOL XP_LoadLicenseManager() {
if (!XP_ComInitialized) {
const HRESULT status = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
if (FAILED(status)) {
SetLastErrorMessage(L"Failed to initialize COM");
return FALSE;
}
XP_ComInitialized = TRUE;
}
if (!XP_LicenseAgent) {
HRESULT status = CoCreateInstance(XP_CLSID, nullptr, CLSCTX_INPROC_SERVER, XP_IID, reinterpret_cast<void**>(&XP_LicenseAgent));
if (SUCCEEDED(status)) {
ULONG dwRetCode;
status = XP_LicenseAgent->Initialize(0xC475, 3, nullptr, &dwRetCode);
if (SUCCEEDED(status) && dwRetCode == 0) {
return TRUE;
}
XP_LicenseAgent->Release();
XP_LicenseAgent = nullptr;
}
SetLastErrorMessage(L"Failed to create license manager instance");
return FALSE;
}
return TRUE;
}
// Helper function to verify a confirmation ID chunk
static bool VerifyConfirmationIDChunk(ICOMLicenseAgent* agent, const wchar_t* chunk) {
LONG pbValue = 0;
BSTR bstrChunk = SysAllocString(chunk);
HRESULT status = agent->VerifyCheckDigits(bstrChunk, &pbValue);
SysFreeString(bstrChunk);
return SUCCEEDED(status) && pbValue != 0;
}
struct ProcessHandle {
HANDLE handle;
explicit ProcessHandle(HANDLE h) : handle(h) {}
~ProcessHandle() { if (handle != INVALID_HANDLE_VALUE) CloseHandle(handle); }
operator HANDLE() const { return handle; }
};
bool IsProcessRunning(const wchar_t* processName) {
ProcessHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
if (snapshot == INVALID_HANDLE_VALUE) {
std::cout << "Failed to create process snapshot: " << GetLastError() << std::endl;
return false;
}
PROCESSENTRY32W processEntry{};
processEntry.dwSize = sizeof(PROCESSENTRY32W);
if (!Process32FirstW(snapshot, &processEntry)) {
std::cout << "Failed to retrieve process information: " << GetLastError() << std::endl;
return false;
}
do {
if (wcscmp(processEntry.szExeFile, processName) == 0) {
return true;
}
} while (Process32NextW(snapshot, &processEntry));
return false;
}
bool TerminateProcessByName(const wchar_t* processName) {
ProcessHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
if (snapshot == INVALID_HANDLE_VALUE) {
std::cout << "Failed to create process snapshot: " << GetLastError() << std::endl;
return false;
}
PROCESSENTRY32W processEntry{};
processEntry.dwSize = sizeof(PROCESSENTRY32W);
if (!Process32FirstW(snapshot, &processEntry)) {
std::cout << "Failed to retrieve process information: " << GetLastError() << std::endl;
return false;
}
do {
if (wcscmp(processEntry.szExeFile, processName) == 0) {
ProcessHandle processHandle(OpenProcess(PROCESS_TERMINATE, FALSE, processEntry.th32ProcessID));
if (processHandle == nullptr) {
std::cout << "Failed to open process: " << GetLastError() << std::endl;
return false;
}
if (!TerminateProcess(processHandle, 0)) {
std::cout << "Failed to terminate process: " << GetLastError() << std::endl;
return false;
}
return true;
}
} while (Process32NextW(snapshot, &processEntry));
std::cout << "Process not found: " << processName << std::endl;
return false;
}
// Exported functions implementation
extern "C" {
void XPMGR_Initialize() {
XP_LoadLicenseManager();
}
void XPMGR_Cleanup() {
if (XP_LicenseAgent) {
XP_LicenseAgent->Release();
XP_LicenseAgent = nullptr;
}
if (XP_ComInitialized) {
CoUninitialize();
XP_ComInitialized = FALSE;
}
}
const wchar_t* XPMGR_GetLastError() {
return LastErrorMessage;
}
const wchar_t* XPMGR_GetInstallationID() {
if (!XP_LoadLicenseManager()) {
return XPMGR_GetLastError();
}
BSTR installationID = nullptr;
const HRESULT status = XP_LicenseAgent->GenerateInstallationId(&installationID);
if (FAILED(status) || !installationID) {
SetLastErrorMessage(L"Failed to generate installation ID");
return XPMGR_GetLastError();
}
static wchar_t result[256];
wcscpy(result, installationID);
SysFreeString(installationID);
return result;
}
const wchar_t* XPMGR_SetConfirmationID(const wchar_t* confirmationId) {
if (!XP_LoadLicenseManager()) {
return XPMGR_GetLastError();
}
// Create a working copy and remove dashes
wchar_t cleanCid[256] = {0};
const wchar_t* src = confirmationId;
wchar_t* dst = cleanCid;
while (*src) {
if (*src != L'-') {
*dst++ = *src;
}
src++;
}
*dst = 0;
// Verify each 6-character chunk
size_t len = wcslen(cleanCid);
for (size_t i = 0; i < len; i += 6) {
wchar_t chunk[7] = {0};
wcsncpy(chunk, cleanCid + i, 6);
if (!VerifyConfirmationIDChunk(XP_LicenseAgent, chunk)) {
SetLastErrorMessage(L"Invalid confirmation ID - verification failed");
return XPMGR_GetLastError();
}
}
// Pass the original confirmation ID (with dashes if present) to the API
BSTR bstrConfirmationId = SysAllocString(confirmationId);
ULONG dwRetCode;
const HRESULT status = XP_LicenseAgent->DepositConfirmationId(bstrConfirmationId, &dwRetCode);
SysFreeString(bstrConfirmationId);
if (FAILED(status) || dwRetCode) {
SetLastErrorMessage(L"Failed to deposit confirmation ID");
return XPMGR_GetLastError();
}
// Handle WPA notifier process
if (IsProcessRunning(L"wpabaln.exe")) {
if (!TerminateProcessByName(L"wpabaln.exe")) {
std::cout << "Warning: Failed to terminate WPA notifier process." << std::endl;
}
}
// Clean up activation files
HMODULE hMod = LoadLibraryW(L"setupapi.dll");
if (hMod) {
using InstallHinfSectionFunc = BOOL (WINAPI*)(HWND, HINSTANCE, PCWSTR, INT);
if (auto installHinfSection = reinterpret_cast<InstallHinfSectionFunc>(GetProcAddress(hMod, "InstallHinfSectionW"))) {
SetLastError(0);
const BOOL result = installHinfSection(nullptr, nullptr, L"DEL_OOBE_ACTIVATE 132 syssetup.inf", 132);
const DWORD error = GetLastError();
if (!result && error != 0 && error != 6) { // Ignore error 6 (ERROR_INVALID_HANDLE) as it indicates success
std::cout << "Warning: Failed to remove activation reminders. Error: " << error << std::endl;
std::cout << "You can try to run the following command yourself: " << std::endl;
std::cout << "rundll32 setupapi,InstallHinfSection DEL_OOBE_ACTIVATE 132 syssetup.inf" << std::endl;
}
}
FreeLibrary(hMod);
}
return L"Successfully set confirmation ID";
}
const wchar_t* XPMGR_GetWPALeft() {
if (!XP_LoadLicenseManager()) {
return XPMGR_GetLastError();
}
ULONG dwWPALeft = 0, dwEvalLeft = 0;
const HRESULT status = XP_LicenseAgent->GetExpirationInfo(&dwWPALeft, &dwEvalLeft);
if (FAILED(status)) {
SetLastErrorMessage(L"Failed to get expiration info");
return XPMGR_GetLastError();
}
if (dwWPALeft == 0x7FFFFFFF) {
return L"Windows is activated";
}
static wchar_t result[16];
_ultow(dwWPALeft, result, 10);
return result;
}
const wchar_t* XPMGR_GetEvalLeft() {
if (!XP_LoadLicenseManager()) {
return XPMGR_GetLastError();
}
ULONG dwWPALeft = 0, dwEvalLeft = 0;
const HRESULT status = XP_LicenseAgent->GetExpirationInfo(&dwWPALeft, &dwEvalLeft);
if (FAILED(status)) {
SetLastErrorMessage(L"Failed to get expiration info");
return XPMGR_GetLastError();
}
if (dwEvalLeft == 0x7FFFFFFF) {
return L"Not an evaluation copy";
}
static wchar_t result[16];
_ultow(dwEvalLeft, result, 10);
return result;
}
const wchar_t* XPMGR_SetProductKey(const wchar_t* productKey) {
if (!XP_LoadLicenseManager()) {
return XPMGR_GetLastError();
}
// Validate product key format
std::wregex pattern(L"[2346789BCDFGHJKMPQRTVWXY]{5}-[2346789BCDFGHJKMPQRTVWXY]{5}-[2346789BCDFGHJKMPQRTVWXY]{5}-[2346789BCDFGHJKMPQRTVWXY]{5}-[2346789BCDFGHJKMPQRTVWXY]{5}");
if (!std::regex_match(productKey, pattern)) {
SetLastErrorMessage(L"Invalid product key format");
return XPMGR_GetLastError();
}
const HRESULT status = XP_LicenseAgent->SetProductKey(const_cast<LPWSTR>(productKey));
if (FAILED(status)) {
SetLastErrorMessage(L"Failed to set product key");
return XPMGR_GetLastError();
}
return L"Successfully set product key";
}
const wchar_t* XPMGR_GetProductID() {
if (!XP_LoadLicenseManager()) {
return XPMGR_GetLastError();
}
BSTR productID = nullptr;
const HRESULT status = XP_LicenseAgent->GetProductID(&productID);
if (FAILED(status) || !productID) {
SetLastErrorMessage(L"Failed to get product ID");
return XPMGR_GetLastError();
}
static wchar_t result[256];
wcscpy(result, productID);
SysFreeString(productID);
return result;
}
}