Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
831504110d | ||
|
|
1738a31bde | ||
|
|
bb1a1e7f3f | ||
|
|
3dfd6eb9aa | ||
|
|
32353cc35f | ||
|
|
ee066856af | ||
|
|
ab8d15c6e3 | ||
|
|
696162e916 | ||
|
|
01d6d8fc1a | ||
|
|
dda722bde2 | ||
|
|
1e7907647e | ||
|
|
3d8c868c6a | ||
|
|
6d86853af5 | ||
|
|
a9aff45f65 | ||
|
|
2aae952475 | ||
|
|
494287b00d |
No files matched your search
@@ -52,9 +52,16 @@ jobs:
|
||||
|
||||
- name: Build xpmgr
|
||||
run: |
|
||||
$env:PATH = 'C:\TDM-GCC-64\bin;' + $env:PATH
|
||||
cmake -S . -B build -G "MinGW Makefiles" -DCMAKE_CXX_COMPILER=C:/TDM-GCC-64/bin/g++.exe
|
||||
cmake --build build --config Debug
|
||||
|
||||
- name: Strip binaries
|
||||
run: |
|
||||
$env:PATH = 'C:\TDM-GCC-64\bin;' + $env:PATH
|
||||
strip .\build\xpmgr_x86.exe
|
||||
strip .\build\xpmgr_x64.exe
|
||||
|
||||
- name: Upload build artifact (x86)
|
||||
uses: actions/[email protected]
|
||||
with:
|
||||
|
||||
@@ -5,11 +5,48 @@ set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
set(SOURCES xpmgr.cpp)
|
||||
set(LIB_SOURCES xpmgr_lib.cpp)
|
||||
|
||||
# x86 is freestanding Pentium code. TDM-GCC's libgcc/libstdc++/CRT are built
|
||||
# for a newer CPU and import XP SP2 APIs, so the x86 link does not use them.
|
||||
set(X86_ARCH_FLAGS
|
||||
-m32
|
||||
-march=pentium
|
||||
-mtune=pentium
|
||||
-mfpmath=387
|
||||
-mno-mmx
|
||||
-mno-sse
|
||||
-mno-sse2
|
||||
-mno-3dnow
|
||||
-fno-tree-vectorize
|
||||
-fno-tree-loop-distribute-patterns
|
||||
-fno-exceptions
|
||||
-fno-rtti
|
||||
-fno-threadsafe-statics
|
||||
-fno-use-cxa-atexit
|
||||
-fno-stack-protector
|
||||
-fno-asynchronous-unwind-tables
|
||||
-fno-unwind-tables
|
||||
-ffreestanding
|
||||
)
|
||||
# Office XP's earliest hosts are Windows 98 and NT 4 SP6a. Keep the headers
|
||||
# at that floor so Windows 2000 and XP APIs cannot become static imports.
|
||||
set(X86_ARCH_DEFS
|
||||
WINVER=0x0400
|
||||
_WIN32_WINNT=0x0400
|
||||
NTDDI_VERSION=0x04000000
|
||||
ENVIRONMENT32
|
||||
)
|
||||
|
||||
# ==== x86 build ====
|
||||
|
||||
add_library(xpmgr_static_x86 STATIC ${LIB_SOURCES})
|
||||
target_compile_options(xpmgr_static_x86 PRIVATE ${X86_ARCH_FLAGS})
|
||||
target_compile_definitions(xpmgr_static_x86 PRIVATE ${X86_ARCH_DEFS})
|
||||
target_link_libraries(xpmgr_static_x86 PRIVATE ole32 oleaut32)
|
||||
|
||||
set(RES_X86 ${CMAKE_BINARY_DIR}/icon_x86.res)
|
||||
|
||||
# Create a custom target for the x86 resource compilation
|
||||
add_custom_command(
|
||||
OUTPUT ${RES_X86}
|
||||
COMMAND windres -F pe-i386 -O coff ${CMAKE_SOURCE_DIR}/icon.rc -o ${RES_X86}
|
||||
@@ -19,21 +56,48 @@ add_custom_command(
|
||||
|
||||
add_custom_target(xpmgr_x86_res ALL DEPENDS ${RES_X86})
|
||||
|
||||
# Now define the executable and link dependencies
|
||||
add_executable(xpmgr_x86 ${SOURCES})
|
||||
add_executable(xpmgr_x86 ${SOURCES} crt_win32.cpp)
|
||||
add_dependencies(xpmgr_x86 xpmgr_x86_res)
|
||||
|
||||
target_compile_options(xpmgr_x86 PRIVATE -m32)
|
||||
target_link_options(xpmgr_x86 PRIVATE -m32)
|
||||
target_compile_options(xpmgr_x86 PRIVATE ${X86_ARCH_FLAGS})
|
||||
target_compile_definitions(xpmgr_x86 PRIVATE ${X86_ARCH_DEFS})
|
||||
target_link_options(xpmgr_x86 PRIVATE
|
||||
-m32
|
||||
-nostdlib
|
||||
-nostartfiles
|
||||
-nodefaultlibs
|
||||
-Wl,--subsystem,console:4.0
|
||||
-Wl,--major-os-version,4
|
||||
-Wl,--minor-os-version,0
|
||||
-Wl,--major-subsystem-version,4
|
||||
-Wl,--minor-subsystem-version,0
|
||||
"SHELL:-Xlinker --stack -Xlinker 1048576,4096"
|
||||
-Wl,--disable-auto-import
|
||||
-Wl,-e,_mainCRTStartup
|
||||
${RES_X86}
|
||||
)
|
||||
target_link_libraries(xpmgr_x86 PRIVATE xpmgr_static_x86 ole32 oleaut32 kernel32)
|
||||
|
||||
# Link .res file as a resource
|
||||
target_link_libraries(xpmgr_x86 PRIVATE ole32 oleaut32 uuid)
|
||||
target_link_options(xpmgr_x86 PRIVATE -Wl,--subsystem,console ${RES_X86})
|
||||
get_filename_component(XPMGR_GCC_BIN "${CMAKE_CXX_COMPILER}" DIRECTORY)
|
||||
find_program(XPMGR_OBJDUMP NAMES objdump HINTS "${XPMGR_GCC_BIN}")
|
||||
if(NOT XPMGR_OBJDUMP)
|
||||
message(FATAL_ERROR "objdump is required to verify the Pentium / Office XP host floor")
|
||||
endif()
|
||||
|
||||
add_custom_command(TARGET xpmgr_x86 POST_BUILD
|
||||
COMMAND powershell.exe -NoProfile -ExecutionPolicy Bypass -File "${CMAKE_SOURCE_DIR}/tools/check-x86-baseline.ps1" -Exe "$<TARGET_FILE:xpmgr_x86>" -Objdump "${XPMGR_OBJDUMP}"
|
||||
COMMENT "Checking xpmgr_x86 for a Pentium and the Office XP host floor"
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
# ==== x64 build ====
|
||||
|
||||
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)
|
||||
|
||||
# Create a custom target for the x64 resource compilation
|
||||
add_custom_command(
|
||||
OUTPUT ${RES_X64}
|
||||
COMMAND windres -O coff ${CMAKE_SOURCE_DIR}/icon.rc -o ${RES_X64}
|
||||
@@ -43,13 +107,18 @@ add_custom_command(
|
||||
|
||||
add_custom_target(xpmgr_x64_res ALL DEPENDS ${RES_X64})
|
||||
|
||||
# Now define the executable and link dependencies
|
||||
add_executable(xpmgr_x64 ${SOURCES})
|
||||
add_dependencies(xpmgr_x64 xpmgr_x64_res)
|
||||
|
||||
target_compile_options(xpmgr_x64 PRIVATE -m64)
|
||||
target_link_options(xpmgr_x64 PRIVATE -m64)
|
||||
|
||||
# Link .res file as a resource
|
||||
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})
|
||||
|
||||
# Install targets
|
||||
install(TARGETS xpmgr_static_x86 xpmgr_static_x64
|
||||
ARCHIVE DESTINATION lib
|
||||
LIBRARY DESTINATION lib)
|
||||
|
||||
install(FILES xpmgr.h DESTINATION include)
|
||||
@@ -1,24 +1,21 @@
|
||||
# xpmgr
|
||||

|
||||
|
||||
Command line interface for Windows XP license management, inspired by Microsoft's "slmgr".
|
||||
Command line interface for managing licenses of older versions of Windows/Office (starting with Windows and office XP), inspired by Microsoft's slmgr.
|
||||
|
||||
## Usage
|
||||
**You need to download the right version for your edition of Windows XP/2003!**
|
||||
|
||||
In most cases, you'll need `xpmgr_x86.exe`.
|
||||
|
||||
If you have Windows XP Professional x64 Edition or a x64 version of Windows Server 2003, you need `xpmgr_x64.exe`.
|
||||
|
||||
If you have an Itanium version of Windows XP or Server 2003, Windows Product Activation is not on those editions, so there is no need for this tool.
|
||||
If you are trying to manage Windows XP Professional x64 Edition or an x64 version of Windows Server 2003, you need `xpmgr_x64.exe`.
|
||||
|
||||
`/dli`: Gets the product ID (ex: `76477-755-3803223-21229`).
|
||||
|
||||
`/ipk`: Sets the product key (tested to work with dashes). If already activated, this should give an error instead.
|
||||
|
||||
`/dti`: Gets an Installation ID with **no dashes** (ex: `253286028742154311079061239762245184619981623171292574`). If already activated, this should give an error instead.
|
||||
`/dti`: Gets an Installation ID (ex: `253286028742154311079061239762245184619981623171292574`). If already activated, this should give an error instead.
|
||||
|
||||
`/atp`: Sets a Confirmation ID (tested to work with dashes). If already activated, this should give an error instead. If successful, this also removes the "Activate Windows" shortcuts and kills the WPA notifier process (`wpabaln.exe`) if it's running.
|
||||
`/atp`: Sets a Confirmation ID. If already activated, this should give an error instead. If successful, this also removes the "Activate Windows" shortcuts and kills the WPA notifier process (`wpabaln.exe`) if it's running.
|
||||
|
||||
`/xpr`: Gets the number of days before activation is required, in days. If already activated, this should give an error instead.
|
||||
|
||||
@@ -26,11 +23,15 @@ If you have an Itanium version of Windows XP or Server 2003, Windows Product Act
|
||||
|
||||
`/?`: Outputs all the commands you can use.
|
||||
|
||||
`/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
|
||||
https://github.com/UMSKT/xpmgr/releases
|
||||
|
||||
## Credits
|
||||
Icon made by %fillin%, released under Creative Commons CC-BY-SA 4.0. Modified by [TheTank20](https://github.com/thepwrtank18) to differenciate from UMSKT.
|
||||
Icon made by [TehAweseomestKitteh](https://kittehcreations.com/), released under Creative Commons CC-BY-SA 4.0. Modified by [TheTank20](https://github.com/thepwrtank18) (poorly) to differenciate from UMSKT.
|
||||
|
||||
## License
|
||||
This code is licensed under the LGPLv3 license.
|
||||
@@ -38,7 +39,7 @@ This code is licensed under the LGPLv3 license.
|
||||
> Versions from May 7th, 2025 and earlier are licensed under the EPL license.
|
||||
|
||||
## Building
|
||||
Make sure Visual Studio 2017 or later is installed (recommended, might not be needed). Then, install [TDM-GCC](https://jmeubank.github.io/tdm-gcc/about/). Then, use CMake to build:
|
||||
Install [TDM-GCC](https://jmeubank.github.io/tdm-gcc/about/). Then, use CMake to build:
|
||||
```
|
||||
cmake -S . -B build -G "MinGW Makefiles" -DCMAKE_CXX_COMPILER=C:/TDM-GCC-64/bin/g++.exe
|
||||
cmake --build build --config Debug
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
/* Freestanding startup for the Pentium / Office XP host-floor x86 build.
|
||||
Linked with -nostdlib so libgcc, libstdc++, and the MinGW CRT stay out. */
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
extern int main(int argc, char** argv);
|
||||
|
||||
typedef void (*xpmgr_ctor)(void);
|
||||
|
||||
extern "C" xpmgr_ctor __init_array_start[] __attribute__((weak));
|
||||
extern "C" xpmgr_ctor __init_array_end[] __attribute__((weak));
|
||||
|
||||
extern "C" void* memset(void* dst, int value, size_t count) {
|
||||
unsigned char* bytes = (unsigned char*)dst;
|
||||
unsigned char fill = (unsigned char)value;
|
||||
while (count--) {
|
||||
*bytes++ = fill;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
extern "C" void* memcpy(void* dst, const void* src, size_t count) {
|
||||
unsigned char* out = (unsigned char*)dst;
|
||||
const unsigned char* in = (const unsigned char*)src;
|
||||
while (count--) {
|
||||
*out++ = *in++;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
extern "C" void* memmove(void* dst, const void* src, size_t count) {
|
||||
unsigned char* out = (unsigned char*)dst;
|
||||
const unsigned char* in = (const unsigned char*)src;
|
||||
size_t index;
|
||||
if (out == in || count == 0) {
|
||||
return dst;
|
||||
}
|
||||
if (out < in) {
|
||||
for (index = 0; index < count; index++) {
|
||||
out[index] = in[index];
|
||||
}
|
||||
} else {
|
||||
index = count;
|
||||
while (index > 0) {
|
||||
index--;
|
||||
out[index] = in[index];
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
extern "C" int memcmp(const void* left, const void* right, size_t count) {
|
||||
const unsigned char* a = (const unsigned char*)left;
|
||||
const unsigned char* b = (const unsigned char*)right;
|
||||
while (count--) {
|
||||
if (*a != *b) {
|
||||
return *a - *b;
|
||||
}
|
||||
a++;
|
||||
b++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* GCC calls this when a frame is at least one page. EAX is the frame size
|
||||
and must be preserved; the caller subtracts it from ESP afterwards. */
|
||||
extern "C" __attribute__((naked)) void __chkstk_ms(void) {
|
||||
__asm__ __volatile__(
|
||||
"pushl %ecx\n\t"
|
||||
"pushl %eax\n\t"
|
||||
"cmpl $0x1000, %eax\n\t"
|
||||
"leal 12(%esp), %ecx\n\t"
|
||||
"jb 1f\n\t"
|
||||
"2:\n\t"
|
||||
"subl $0x1000, %ecx\n\t"
|
||||
"testl %eax, (%ecx)\n\t"
|
||||
"subl $0x1000, %eax\n\t"
|
||||
"cmpl $0x1000, %eax\n\t"
|
||||
"ja 2b\n\t"
|
||||
"1:\n\t"
|
||||
"subl %eax, %ecx\n\t"
|
||||
"testl %eax, (%ecx)\n\t"
|
||||
"popl %eax\n\t"
|
||||
"popl %ecx\n\t"
|
||||
"ret\n\t"
|
||||
);
|
||||
}
|
||||
|
||||
extern "C" void __cxa_pure_virtual(void) {
|
||||
ExitProcess(1);
|
||||
}
|
||||
|
||||
extern "C" void __main(void) {
|
||||
xpmgr_ctor* ctor;
|
||||
if (!__init_array_start || !__init_array_end) {
|
||||
return;
|
||||
}
|
||||
for (ctor = __init_array_start; ctor < __init_array_end; ctor++) {
|
||||
if (*ctor) {
|
||||
(*ctor)();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int is_space(char ch) {
|
||||
return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n';
|
||||
}
|
||||
|
||||
extern "C" void mainCRTStartup(void) {
|
||||
char* command = GetCommandLineA();
|
||||
char* buffer;
|
||||
char** argv;
|
||||
int length = 0;
|
||||
int argc = 0;
|
||||
char* cursor;
|
||||
HANDLE heap = GetProcessHeap();
|
||||
|
||||
if (!command) {
|
||||
command = (char*)"";
|
||||
}
|
||||
while (command[length]) {
|
||||
length++;
|
||||
}
|
||||
|
||||
buffer = (char*)HeapAlloc(heap, 0, (SIZE_T)length + 1);
|
||||
argv = (char**)HeapAlloc(heap, HEAP_ZERO_MEMORY, (SIZE_T)(length + 2) * sizeof(char*));
|
||||
if (!buffer || !argv) {
|
||||
ExitProcess(1);
|
||||
}
|
||||
for (int index = 0; index <= length; index++) {
|
||||
buffer[index] = command[index];
|
||||
}
|
||||
|
||||
cursor = buffer;
|
||||
while (*cursor) {
|
||||
char* out;
|
||||
int quoted = 0;
|
||||
int more;
|
||||
while (is_space(*cursor)) {
|
||||
cursor++;
|
||||
}
|
||||
if (!*cursor) {
|
||||
break;
|
||||
}
|
||||
argv[argc++] = cursor;
|
||||
out = cursor;
|
||||
while (*cursor) {
|
||||
if (*cursor == '"') {
|
||||
quoted = !quoted;
|
||||
cursor++;
|
||||
continue;
|
||||
}
|
||||
if (!quoted && is_space(*cursor)) {
|
||||
break;
|
||||
}
|
||||
*out++ = *cursor++;
|
||||
}
|
||||
more = *cursor != 0;
|
||||
*out = 0;
|
||||
if (more) {
|
||||
cursor++;
|
||||
}
|
||||
}
|
||||
argv[argc] = NULL;
|
||||
|
||||
ExitProcess((UINT)main(argc, argv));
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
The icons in this folder follow the same CC-BY-SA 4.0 license as the final version, seen in the root folder.
|
||||
Modifications were made to the smaller VGA icons for clarity.
|
||||
|
After Width: | Height: | Size: 85 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 445 B |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 535 B |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 637 B |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 746 B |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 964 B |
|
After Width: | Height: | Size: 2.5 KiB |
@@ -0,0 +1,160 @@
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][string]$Exe,
|
||||
[Parameter(Mandatory = $true)][string]$Objdump
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
function Fail([string]$Message) {
|
||||
Write-Host "x86 baseline check failed: $Message"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if (-not (Test-Path -LiteralPath $Exe)) {
|
||||
Fail "missing binary: $Exe"
|
||||
}
|
||||
if (-not (Test-Path -LiteralPath $Objdump)) {
|
||||
Fail "missing objdump: $Objdump"
|
||||
}
|
||||
|
||||
$format = & $Objdump -f -- $Exe 2>&1 | Out-String
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Fail "objdump -f failed: $format"
|
||||
}
|
||||
if ($format -notmatch "pei-i386") {
|
||||
Fail "expected a PE32 i386 binary"
|
||||
}
|
||||
|
||||
$pe = & $Objdump -p -- $Exe 2>&1 | Out-String
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Fail "objdump -p failed: $pe"
|
||||
}
|
||||
|
||||
function PeField([string]$Text, [string]$Name) {
|
||||
if ($Text -match ("(?m)^\s*" + [regex]::Escape($Name) + "\s+(\d+)")) {
|
||||
return [int]$Matches[1]
|
||||
}
|
||||
return $null
|
||||
}
|
||||
|
||||
$osMajor = PeField $pe "MajorOSystemVersion"
|
||||
$osMinor = PeField $pe "MinorOSystemVersion"
|
||||
$subMajor = PeField $pe "MajorSubsystemVersion"
|
||||
$subMinor = PeField $pe "MinorSubsystemVersion"
|
||||
if ($osMajor -ne 4 -or $osMinor -ne 0 -or $subMajor -ne 4 -or $subMinor -ne 0) {
|
||||
Fail "expected Office XP host subsystem 4.0, got OS $osMajor.$osMinor subsystem $subMajor.$subMinor"
|
||||
}
|
||||
|
||||
$badDlls = "(?i)(libstdc\+\+|libgcc|libatomic|libssp|msvcp\d*|vcruntime\d*|ucrtbase|api-ms-win|msvcr\d+|msvcrt)"
|
||||
$allowedDlls = @{
|
||||
"kernel32.dll" = $true
|
||||
"ole32.dll" = $true
|
||||
"oleaut32.dll" = $true
|
||||
}
|
||||
$badImports = @{
|
||||
"encodepointer" = $true
|
||||
"decodepointer" = $true
|
||||
"encodesystempointer" = $true
|
||||
"decodesystempointer" = $true
|
||||
"gettickcount64" = $true
|
||||
"initializecriticalsectionex" = $true
|
||||
"flsalloc" = $true
|
||||
"flsfree" = $true
|
||||
"flsgetvalue" = $true
|
||||
"flssetvalue" = $true
|
||||
"comparestringex" = $true
|
||||
"lcmapstringex" = $true
|
||||
"getlocaleinfoex" = $true
|
||||
"lcidtolocalename" = $true
|
||||
"localenametolcid" = $true
|
||||
"initializeconditionvariable" = $true
|
||||
"sleepconditionvariablecs" = $true
|
||||
"sleepconditionvariablesrw" = $true
|
||||
"wakeconditionvariable" = $true
|
||||
"wakeallconditionvariable" = $true
|
||||
"initializesrwlock" = $true
|
||||
"acquiresrwlockexclusive" = $true
|
||||
"releasesrwlockexclusive" = $true
|
||||
"tryacquiresrwlockexclusive" = $true
|
||||
"getfileinformationbyhandleex" = $true
|
||||
"setfileinformationbyhandle" = $true
|
||||
"getfinalpathnamebyhandlea" = $true
|
||||
"getfinalpathnamebyhandlew" = $true
|
||||
"createsymboliclinka" = $true
|
||||
"createsymboliclinkw" = $true
|
||||
"getmodulehandleexa" = $true
|
||||
"getmodulehandleexw" = $true
|
||||
"iswow64process" = $true
|
||||
"interlockedcompareexchange64" = $true
|
||||
"heapsetinformation" = $true
|
||||
"__getmainargs" = $true
|
||||
"__wgetmainargs" = $true
|
||||
"__set_app_type" = $true
|
||||
"_amsg_exit" = $true
|
||||
"__p__fmode" = $true
|
||||
"__p__commode" = $true
|
||||
"__p__environ" = $true
|
||||
"getnativesysteminfo" = $true
|
||||
"createtoolhelp32snapshot" = $true
|
||||
"process32first" = $true
|
||||
"process32firsta" = $true
|
||||
"process32firstw" = $true
|
||||
"process32next" = $true
|
||||
"process32nexta" = $true
|
||||
"process32nextw" = $true
|
||||
"loadlibraryw" = $true
|
||||
}
|
||||
|
||||
$importHits = New-Object System.Collections.Generic.List[string]
|
||||
foreach ($line in ($pe -split "`r?`n")) {
|
||||
if ($line -match "DLL Name:\s*(\S+)") {
|
||||
$dll = $Matches[1]
|
||||
if (-not $allowedDlls.ContainsKey($dll.ToLowerInvariant()) -or $dll -match $badDlls) {
|
||||
$importHits.Add("DLL $dll")
|
||||
}
|
||||
}
|
||||
if ($line -match "^\s+[0-9A-Fa-f]+\s+[0-9A-Fa-f]+\s+(\S+)") {
|
||||
$name = $Matches[1]
|
||||
if ($name -match "^(.*)@\d+$") {
|
||||
$name = $Matches[1]
|
||||
}
|
||||
if ($badImports.ContainsKey($name.ToLowerInvariant())) {
|
||||
$importHits.Add($name)
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($importHits.Count -gt 0) {
|
||||
$shown = ($importHits | Select-Object -First 20) -join ", "
|
||||
Fail "post-RTM or CRT imports: $shown"
|
||||
}
|
||||
|
||||
$badMnemonic = "(?i)^(cmov[a-z]*|fcmov[a-z]*|emms|nopl|nopw|fcomi|fcomip|fucomi|fucomip|movaps|movups|movapd|movupd|movdqa|movdqu|movss|movhps|movlps|movlhps|movhlps|xorps|xorpd|andps|andpd|orps|orpd|addps|addpd|addss|addsd|subps|subpd|subss|subsd|mulps|mulpd|mulss|mulsd|divps|divpd|divss|divsd|cvtsi2ss|cvtsi2sd|cvttss2si|cvttsd2si|cvtss2si|cvtsd2si|pshufd|pshuflw|pshufhw|pshufw|punpck[a-z]+|packss[a-z]+|packus[a-z]+|pcmp[a-z]+|padd[bwdq]|psub[bwdq]|pmullw|pmulhw|pmulhuw|pmaddwd|pavgb|pavgw|pextrw|pinsrw|pmovmskb|prefetch[a-z]*|sfence|mfence|lfence|maskmovq|movntq|movntps|lddqu|pause)\b"
|
||||
$badRegister = "(?i)%(mm|xmm|ymm|zmm)[0-9]"
|
||||
$insnHits = New-Object System.Collections.Generic.List[string]
|
||||
$disasm = & $Objdump -d -M att -- $Exe 2>&1
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Fail "objdump -d failed"
|
||||
}
|
||||
foreach ($line in $disasm) {
|
||||
$text = [string]$line
|
||||
$insn = $null
|
||||
if ($text.Contains("`t")) {
|
||||
$parts = $text.Split("`t")
|
||||
$insn = $parts[$parts.Length - 1].Trim()
|
||||
}
|
||||
if (-not $insn) {
|
||||
continue
|
||||
}
|
||||
if ($insn -match $badMnemonic -or $insn -match $badRegister) {
|
||||
$insnHits.Add($text.Trim())
|
||||
if ($insnHits.Count -ge 20) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($insnHits.Count -gt 0) {
|
||||
Fail ("forbidden instructions:`n" + ($insnHits -join "`n"))
|
||||
}
|
||||
|
||||
Write-Host "x86 baseline check passed (Pentium, Office XP host floor): $Exe"
|
||||
exit 0
|
||||
@@ -2,624 +2,240 @@
|
||||
typedef struct IUnknown IUnknown;
|
||||
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include <comdef.h>
|
||||
#include <regex>
|
||||
#include <TlHelp32.h>
|
||||
#include "xpmgr.h"
|
||||
#include "xpmgr_util.h"
|
||||
|
||||
// Check windows
|
||||
#if _WIN32 || _WIN64
|
||||
#if _WIN64
|
||||
#define ENVIRONMENT64
|
||||
#else
|
||||
#define ENVIRONMENT32
|
||||
#endif
|
||||
#endif
|
||||
|
||||
const char* specifiedProduct = nullptr;
|
||||
|
||||
// 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 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 } };
|
||||
|
||||
#undef XP_INTERFACE
|
||||
#define XP_INTERFACE ICOMLicenseAgent
|
||||
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 BOOL XP_ComInitialized = FALSE;
|
||||
static ICOMLicenseAgent* XP_LicenseAgent = nullptr;
|
||||
|
||||
static BOOL XP_LoadLicenseManager()
|
||||
{
|
||||
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;
|
||||
static int option_exists(int argc, char** argv, const char* option) {
|
||||
for (int index = 1; index < argc; index++) {
|
||||
if (xpmgr_streq(argv[index], option)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#pragma region Internals
|
||||
|
||||
wchar_t* convertCharArrayToLPCWSTR(const char* charArray)
|
||||
{
|
||||
auto* wString = new wchar_t[4096];
|
||||
MultiByteToWideChar(CP_ACP, 0, charArray, -1, wString, 4096);
|
||||
return wString;
|
||||
}
|
||||
|
||||
char* getCmdOption(char** begin, char** end, const std::string& option)
|
||||
{
|
||||
char** itr = std::find(begin, end, option);
|
||||
if (itr != end && ++itr != end)
|
||||
{
|
||||
return *itr;
|
||||
static const char* option_value(int argc, char** argv, const char* option) {
|
||||
for (int index = 1; index < argc - 1; index++) {
|
||||
if (xpmgr_streq(argv[index], option)) {
|
||||
return argv[index + 1];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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';
|
||||
static char* read_stdin_line(void) {
|
||||
HANDLE input = GetStdHandle(STD_INPUT_HANDLE);
|
||||
char* buffer;
|
||||
int count = 0;
|
||||
const int cap = 4096;
|
||||
if (input == NULL || input == INVALID_HANDLE_VALUE) {
|
||||
return NULL;
|
||||
}
|
||||
buffer = (char*)HeapAlloc(GetProcessHeap(), 0, cap);
|
||||
if (!buffer) {
|
||||
return NULL;
|
||||
}
|
||||
while (count < cap - 1) {
|
||||
char ch;
|
||||
DWORD got = 0;
|
||||
if (!ReadFile(input, &ch, 1, &got, NULL) || got == 0) {
|
||||
break;
|
||||
}
|
||||
if (ch == '\n') {
|
||||
break;
|
||||
}
|
||||
buffer[count++] = ch;
|
||||
}
|
||||
while (count > 0) {
|
||||
char ch = buffer[count - 1];
|
||||
if (ch != ' ' && ch != '\t' && ch != '\r') {
|
||||
break;
|
||||
}
|
||||
count--;
|
||||
}
|
||||
buffer[count] = 0;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
ULONG ConvertToULONG(const char* str)
|
||||
{
|
||||
char* end;
|
||||
const ULONG value = std::strtoul(str, &end, 10);
|
||||
return value;
|
||||
static int finish(int code) {
|
||||
XPMGR_Cleanup();
|
||||
return code;
|
||||
}
|
||||
|
||||
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;
|
||||
static int windows_command_selected(int argc, char** argv) {
|
||||
return option_exists(argc, argv, "/dti")
|
||||
|| option_exists(argc, argv, "/atp")
|
||||
|| option_exists(argc, argv, "/xpr")
|
||||
|| option_exists(argc, argv, "/xpr-eval")
|
||||
|| option_exists(argc, argv, "/ipk")
|
||||
|| option_exists(argc, argv, "/dli");
|
||||
}
|
||||
|
||||
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;
|
||||
/* Windows product activation is XP/2003 only. Office hosts must still reach command dispatch. */
|
||||
static int windows_host_error(const OSVERSIONINFOA* info) {
|
||||
if (info->dwPlatformId == VER_PLATFORM_WIN32_NT
|
||||
&& info->dwMajorVersion == 5
|
||||
&& (info->dwMinorVersion == 1 || info->dwMinorVersion == 2)) {
|
||||
return 0;
|
||||
}
|
||||
xpmgr_write("An error occurred: Windows management only works on Windows NT 5.1 and 5.2.");
|
||||
if (info->dwPlatformId == VER_PLATFORM_WIN32_NT && info->dwMajorVersion > 5) {
|
||||
xpmgr_write(" Use slmgr instead: https://learn.microsoft.com/en-us/windows-server/get-started/activation-slmgr-vbs-options");
|
||||
return 3;
|
||||
}
|
||||
if (info->dwPlatformId == VER_PLATFORM_WIN32_NT && info->dwMajorVersion == 5 && info->dwMinorVersion == 0) {
|
||||
xpmgr_write(" You should be fine anyways, since Windows 2000 doesn't use Product Activation.");
|
||||
return 4;
|
||||
}
|
||||
if (info->dwPlatformId == VER_PLATFORM_WIN32_NT && info->dwMajorVersion == 5) {
|
||||
return 5;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// ReSharper disable once CppLocalVariableMayBeConst
|
||||
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
if (snapshot == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
std::cout << "An error occurred at IsProcessRunning: Failed to create process snapshot." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
PROCESSENTRY32W processEntry{};
|
||||
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 =
|
||||
int main(int argc, char* argv[]) {
|
||||
const char* USAGE_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)\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\n"
|
||||
"/ipk [pkey]: Sets/changes product key (can also read from stdin)\n"
|
||||
"/dli: Gets the product ID of Windows\n"
|
||||
"/?: Displays this message";
|
||||
const wchar_t* result = NULL;
|
||||
wchar_t* wide = NULL;
|
||||
|
||||
if (cmdOptionExists(argv, argv + argc, "--GetUsage")) {
|
||||
std::cout << text;
|
||||
if (option_exists(argc, argv, "/?")) {
|
||||
xpmgr_write(USAGE_TEXT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
specifiedProduct = "WindowsNT5x";
|
||||
OSVERSIONINFOA info = {};
|
||||
int hostError;
|
||||
info.dwOSVersionInfoSize = sizeof(info);
|
||||
if (!GetVersionExA(&info)) {
|
||||
xpmgr_write("An error occurred: Could not read the operating system version.\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && info.dwMinorVersion == 0) {
|
||||
xpmgr_write("An error occurred: This program requires Windows 98 or later.\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (!windows_command_selected(argc, argv)) {
|
||||
xpmgr_write("An error occurred: No arguments listed\n\n");
|
||||
xpmgr_write(USAGE_TEXT);
|
||||
return 7;
|
||||
}
|
||||
|
||||
hostError = windows_host_error(&info);
|
||||
if (hostError) {
|
||||
return hostError;
|
||||
}
|
||||
|
||||
if (std::strcmp(specifiedProduct, "WindowsNT5x") == 0) {
|
||||
SYSTEM_INFO systemInfo;
|
||||
GetNativeSystemInfo(&systemInfo);
|
||||
#ifdef ENVIRONMENT32
|
||||
if (systemInfo.wProcessorArchitecture != PROCESSOR_ARCHITECTURE_INTEL) { // running under WOW64
|
||||
if (systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) { // is AMD64
|
||||
std::cout << "An error occurred at systemInfo: Incorrect version of xpmgr. You need to download the x64 version.";
|
||||
/* XP x64 WPA lives in the 64-bit process. Office is 32-bit, so this stays on the Windows path. */
|
||||
SYSTEM_INFO systemInfo;
|
||||
typedef void (WINAPI *GetNativeSystemInfoFn)(LPSYSTEM_INFO);
|
||||
HMODULE kernel = GetModuleHandleA("kernel32.dll");
|
||||
GetNativeSystemInfoFn nativeInfo = NULL;
|
||||
if (kernel) {
|
||||
nativeInfo = (GetNativeSystemInfoFn)GetProcAddress(kernel, "GetNativeSystemInfo");
|
||||
}
|
||||
else if (systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64) { // is IA64
|
||||
std::cout << "An error occurred at systemInfo: Windows Product Activation does not exist on this platform.";
|
||||
if (nativeInfo) {
|
||||
nativeInfo(&systemInfo);
|
||||
} else {
|
||||
GetSystemInfo(&systemInfo);
|
||||
}
|
||||
else { // is PPC, megafart 386, whatever else
|
||||
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!";
|
||||
if (systemInfo.wProcessorArchitecture != PROCESSOR_ARCHITECTURE_INTEL) {
|
||||
if (systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) {
|
||||
xpmgr_write("An error occurred: Incorrect version of xpmgr. You need to download the x64 version.");
|
||||
return 1;
|
||||
}
|
||||
if (systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64) {
|
||||
xpmgr_write("An error occurred: Windows Product Activation does not exist on this platform.");
|
||||
return 1;
|
||||
}
|
||||
xpmgr_write("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
|
||||
OSVERSIONINFOEX info = {};
|
||||
info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
|
||||
GetVersionEx(reinterpret_cast<LPOSVERSIONINFO>(&info));
|
||||
|
||||
if (info.dwMajorVersion != 5) {
|
||||
std::cout << "An error occurred at OSVERSIONINFOEX: Windows management only works on Windows NT 5.1 and 5.2.";
|
||||
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;
|
||||
XPMGR_Initialize();
|
||||
|
||||
if (option_exists(argc, argv, "/dti")) {
|
||||
result = XPMGR_GetInstallationID();
|
||||
}
|
||||
return 2;
|
||||
else if (option_exists(argc, argv, "/atp")) {
|
||||
const char* confirmationId = option_value(argc, argv, "/atp");
|
||||
char* piped = NULL;
|
||||
if (!confirmationId) {
|
||||
piped = read_stdin_line();
|
||||
if (!piped || !piped[0]) {
|
||||
xpmgr_write("An error occurred: No confirmation ID provided via argument or pipe\n\n");
|
||||
xpmgr_write(USAGE_TEXT);
|
||||
xpmgr_free(piped);
|
||||
return finish(7);
|
||||
}
|
||||
wide = xpmgr_widen(piped);
|
||||
xpmgr_free(piped);
|
||||
} else {
|
||||
wide = xpmgr_widen(confirmationId);
|
||||
}
|
||||
if (!wide) {
|
||||
xpmgr_write("An error occurred: Out of memory\n");
|
||||
return finish(7);
|
||||
}
|
||||
result = XPMGR_SetConfirmationID(wide);
|
||||
}
|
||||
else if (option_exists(argc, argv, "/xpr")) {
|
||||
result = XPMGR_GetWPALeft();
|
||||
}
|
||||
else if (option_exists(argc, argv, "/xpr-eval")) {
|
||||
result = XPMGR_GetEvalLeft();
|
||||
}
|
||||
else if (option_exists(argc, argv, "/ipk")) {
|
||||
const char* productKey = option_value(argc, argv, "/ipk");
|
||||
char* piped = NULL;
|
||||
if (!productKey) {
|
||||
piped = read_stdin_line();
|
||||
if (!piped || !piped[0]) {
|
||||
xpmgr_write("An error occurred: No product key provided via argument or pipe\n\n");
|
||||
xpmgr_write(USAGE_TEXT);
|
||||
xpmgr_free(piped);
|
||||
return finish(7);
|
||||
}
|
||||
wide = xpmgr_widen(piped);
|
||||
xpmgr_free(piped);
|
||||
} else {
|
||||
wide = xpmgr_widen(productKey);
|
||||
}
|
||||
if (!wide) {
|
||||
xpmgr_write("An error occurred: Out of memory\n");
|
||||
return finish(7);
|
||||
}
|
||||
result = XPMGR_SetProductKey(wide);
|
||||
}
|
||||
else if (option_exists(argc, argv, "/dli")) {
|
||||
result = XPMGR_GetProductID();
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
xpmgr_write("An error occurred: No arguments listed\n\n");
|
||||
xpmgr_write(USAGE_TEXT);
|
||||
return finish(7);
|
||||
}
|
||||
|
||||
if (cmdOptionExists(argv, argv + argc, "/dti")) {
|
||||
std::cout << ConvertToStdString(XP_GetInstallationID());
|
||||
return 0;
|
||||
}
|
||||
else if (cmdOptionExists(argv, argv + argc, "/atp")) {
|
||||
std::cout << ConvertToStdString(XP_SetConfirmationID(ConvertCharToBSTR(getCmdOption(argv, argv + argc, "--SetConfirmationID"))));
|
||||
return 0;
|
||||
}
|
||||
else if (cmdOptionExists(argv, argv + argc, "/xpr")) {
|
||||
std::cout << ConvertToStdString(XP_GetWPALeft());
|
||||
return 0;
|
||||
}
|
||||
else if (cmdOptionExists(argv, argv + argc, "/xpr-eval")) {
|
||||
std::cout << ConvertToStdString(XP_GetEvalLeft());
|
||||
return 0;
|
||||
if (result) {
|
||||
char* output = xpmgr_narrow(result);
|
||||
xpmgr_write(output);
|
||||
xpmgr_free(output);
|
||||
}
|
||||
xpmgr_free(wide);
|
||||
|
||||
else if (cmdOptionExists(argv, argv + argc, "/ipk")) {
|
||||
std::cout << ConvertToStdString(XP_SetProductKey(convertCharArrayToLPCWSTR(getCmdOption(argv, argv + argc, "--SetProductKey"))));
|
||||
XPMGR_Cleanup();
|
||||
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
|
||||
@@ -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
|
||||
@@ -0,0 +1,515 @@
|
||||
#include "xpmgr.h"
|
||||
#include <windows.h>
|
||||
#include <objbase.h>
|
||||
#include <oleauto.h>
|
||||
#include <TlHelp32.h>
|
||||
#include "xpmgr_util.h"
|
||||
|
||||
// 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) {
|
||||
lstrcpynW(LastErrorMessage, message, 1024);
|
||||
}
|
||||
|
||||
static unsigned wide_length(const wchar_t* text) {
|
||||
unsigned length = 0;
|
||||
if (!text) {
|
||||
return 0;
|
||||
}
|
||||
while (text[length]) {
|
||||
length++;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
static void write_ulong_wide(unsigned long value, wchar_t* out) {
|
||||
wchar_t digits[16];
|
||||
int count = 0;
|
||||
int index = 0;
|
||||
if (value == 0) {
|
||||
out[0] = L'0';
|
||||
out[1] = 0;
|
||||
return;
|
||||
}
|
||||
while (value && count < 16) {
|
||||
digits[count++] = (wchar_t)(L'0' + (value % 10));
|
||||
value /= 10;
|
||||
}
|
||||
while (count > 0) {
|
||||
out[index++] = digits[--count];
|
||||
}
|
||||
out[index] = 0;
|
||||
}
|
||||
|
||||
static int product_key_char(wchar_t ch) {
|
||||
const wchar_t* alphabet = L"2346789BCDFGHJKMPQRTVWXY";
|
||||
for (int index = 0; alphabet[index]; index++) {
|
||||
if (alphabet[index] == ch) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int product_key_ok(const wchar_t* key) {
|
||||
if (!key) {
|
||||
return 0;
|
||||
}
|
||||
for (int group = 0; group < 5; group++) {
|
||||
if (group) {
|
||||
if (*key != L'-') {
|
||||
return 0;
|
||||
}
|
||||
key++;
|
||||
}
|
||||
for (int index = 0; index < 5; index++) {
|
||||
if (!product_key_char(*key)) {
|
||||
return 0;
|
||||
}
|
||||
key++;
|
||||
}
|
||||
}
|
||||
return *key == 0;
|
||||
}
|
||||
|
||||
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 && handle != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(handle);
|
||||
}
|
||||
}
|
||||
operator HANDLE() const { return handle; }
|
||||
};
|
||||
|
||||
typedef HANDLE (WINAPI *CreateToolhelp32SnapshotFn)(DWORD flags, DWORD processId);
|
||||
typedef BOOL (WINAPI *Process32Fn)(HANDLE snapshot, LPPROCESSENTRY32 entry);
|
||||
|
||||
struct Toolhelp {
|
||||
HANDLE snapshot;
|
||||
Process32Fn first;
|
||||
Process32Fn next;
|
||||
};
|
||||
|
||||
/* NT 4 has no ToolHelp in kernel32. Windows 98 has the ANSI exports.
|
||||
Resolve them here so neither host gets a static import. Missing exports skip cleanup. */
|
||||
static int open_process_snapshot(Toolhelp* toolhelp) {
|
||||
HMODULE kernel = GetModuleHandleA("kernel32.dll");
|
||||
CreateToolhelp32SnapshotFn createSnapshot;
|
||||
if (!kernel) {
|
||||
return 0;
|
||||
}
|
||||
createSnapshot = (CreateToolhelp32SnapshotFn)GetProcAddress(kernel, "CreateToolhelp32Snapshot");
|
||||
toolhelp->first = (Process32Fn)GetProcAddress(kernel, "Process32First");
|
||||
toolhelp->next = (Process32Fn)GetProcAddress(kernel, "Process32Next");
|
||||
if (!createSnapshot || !toolhelp->first || !toolhelp->next) {
|
||||
return 0;
|
||||
}
|
||||
toolhelp->snapshot = createSnapshot(TH32CS_SNAPPROCESS, 0);
|
||||
if (toolhelp->snapshot == INVALID_HANDLE_VALUE) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool IsProcessRunning(const char* processName) {
|
||||
Toolhelp toolhelp;
|
||||
int opened = open_process_snapshot(&toolhelp);
|
||||
if (opened == 0) {
|
||||
return false;
|
||||
}
|
||||
if (opened < 0) {
|
||||
xpmgr_write("Failed to create process snapshot: ");
|
||||
xpmgr_write_uint(GetLastError());
|
||||
xpmgr_write("\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
ProcessHandle snapshot(toolhelp.snapshot);
|
||||
PROCESSENTRY32 processEntry{};
|
||||
processEntry.dwSize = sizeof(PROCESSENTRY32);
|
||||
|
||||
if (!toolhelp.first(snapshot, &processEntry)) {
|
||||
xpmgr_write("Failed to retrieve process information: ");
|
||||
xpmgr_write_uint(GetLastError());
|
||||
xpmgr_write("\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
do {
|
||||
if (lstrcmpiA(processEntry.szExeFile, processName) == 0) {
|
||||
return true;
|
||||
}
|
||||
} while (toolhelp.next(snapshot, &processEntry));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool TerminateProcessByName(const char* processName) {
|
||||
Toolhelp toolhelp;
|
||||
int opened = open_process_snapshot(&toolhelp);
|
||||
if (opened == 0) {
|
||||
return false;
|
||||
}
|
||||
if (opened < 0) {
|
||||
xpmgr_write("Failed to create process snapshot: ");
|
||||
xpmgr_write_uint(GetLastError());
|
||||
xpmgr_write("\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
ProcessHandle snapshot(toolhelp.snapshot);
|
||||
PROCESSENTRY32 processEntry{};
|
||||
processEntry.dwSize = sizeof(PROCESSENTRY32);
|
||||
|
||||
if (!toolhelp.first(snapshot, &processEntry)) {
|
||||
xpmgr_write("Failed to retrieve process information: ");
|
||||
xpmgr_write_uint(GetLastError());
|
||||
xpmgr_write("\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
do {
|
||||
if (lstrcmpiA(processEntry.szExeFile, processName) == 0) {
|
||||
ProcessHandle processHandle(OpenProcess(PROCESS_TERMINATE, FALSE, processEntry.th32ProcessID));
|
||||
if (processHandle == nullptr) {
|
||||
xpmgr_write("Failed to open process: ");
|
||||
xpmgr_write_uint(GetLastError());
|
||||
xpmgr_write("\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!TerminateProcess(processHandle, 0)) {
|
||||
xpmgr_write("Failed to terminate process: ");
|
||||
xpmgr_write_uint(GetLastError());
|
||||
xpmgr_write("\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} while (toolhelp.next(snapshot, &processEntry));
|
||||
|
||||
xpmgr_write("Process not found: ");
|
||||
xpmgr_write(processName);
|
||||
xpmgr_write("\n");
|
||||
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];
|
||||
lstrcpynW(result, installationID, 256);
|
||||
SysFreeString(installationID);
|
||||
return result;
|
||||
}
|
||||
|
||||
const wchar_t* XPMGR_SetConfirmationID(const wchar_t* confirmationId) {
|
||||
if (!XP_LoadLicenseManager()) {
|
||||
return XPMGR_GetLastError();
|
||||
}
|
||||
|
||||
if (!confirmationId) {
|
||||
SetLastErrorMessage(L"Invalid confirmation ID - verification failed");
|
||||
return XPMGR_GetLastError();
|
||||
}
|
||||
|
||||
// Create a working copy and remove dashes
|
||||
wchar_t cleanCid[256];
|
||||
const wchar_t* src = confirmationId;
|
||||
wchar_t* dst = cleanCid;
|
||||
while (*src && (dst - cleanCid) < 255) {
|
||||
if (*src != L'-') {
|
||||
*dst++ = *src;
|
||||
}
|
||||
src++;
|
||||
}
|
||||
*dst = 0;
|
||||
|
||||
// Verify each 6-character chunk
|
||||
unsigned len = wide_length(cleanCid);
|
||||
for (unsigned i = 0; i < len; i += 6) {
|
||||
wchar_t chunk[7];
|
||||
unsigned count = 0;
|
||||
while (count < 6 && cleanCid[i + count]) {
|
||||
chunk[count] = cleanCid[i + count];
|
||||
count++;
|
||||
}
|
||||
chunk[count] = 0;
|
||||
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("wpabaln.exe")) {
|
||||
if (!TerminateProcessByName("wpabaln.exe")) {
|
||||
xpmgr_write("Warning: Failed to terminate WPA notifier process.\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up activation files
|
||||
HMODULE hMod = LoadLibraryA("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
|
||||
xpmgr_write("Warning: Failed to remove activation reminders. Error: ");
|
||||
xpmgr_write_uint(error);
|
||||
xpmgr_write("\n");
|
||||
xpmgr_write("You can try to run the following command yourself: \n");
|
||||
xpmgr_write("rundll32 setupapi,InstallHinfSection DEL_OOBE_ACTIVATE 132 syssetup.inf\n");
|
||||
}
|
||||
}
|
||||
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];
|
||||
write_ulong_wide(dwWPALeft, result);
|
||||
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];
|
||||
write_ulong_wide(dwEvalLeft, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
const wchar_t* XPMGR_SetProductKey(const wchar_t* productKey) {
|
||||
if (!XP_LoadLicenseManager()) {
|
||||
return XPMGR_GetLastError();
|
||||
}
|
||||
|
||||
if (!product_key_ok(productKey)) {
|
||||
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];
|
||||
lstrcpynW(result, productID, 256);
|
||||
SysFreeString(productID);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
/* Tiny helpers so both binaries can avoid libstdc++. */
|
||||
|
||||
static int xpmgr_streq(const char* a, const char* b) {
|
||||
if (!a || !b) {
|
||||
return 0;
|
||||
}
|
||||
while (*a && *a == *b) {
|
||||
a++;
|
||||
b++;
|
||||
}
|
||||
return *a == *b;
|
||||
}
|
||||
|
||||
static void xpmgr_write(const char* text) {
|
||||
DWORD length = 0;
|
||||
DWORD wrote = 0;
|
||||
HANDLE out;
|
||||
if (!text) {
|
||||
return;
|
||||
}
|
||||
while (text[length]) {
|
||||
length++;
|
||||
}
|
||||
out = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (out == NULL || out == INVALID_HANDLE_VALUE) {
|
||||
return;
|
||||
}
|
||||
WriteFile(out, text, length, &wrote, NULL);
|
||||
}
|
||||
|
||||
static void xpmgr_write_uint(unsigned long value) {
|
||||
char digits[16];
|
||||
char text[16];
|
||||
int count = 0;
|
||||
int index = 0;
|
||||
if (value == 0) {
|
||||
xpmgr_write("0");
|
||||
return;
|
||||
}
|
||||
while (value && count < 16) {
|
||||
digits[count++] = (char)('0' + (value % 10));
|
||||
value /= 10;
|
||||
}
|
||||
while (count > 0) {
|
||||
text[index++] = digits[--count];
|
||||
}
|
||||
text[index] = 0;
|
||||
xpmgr_write(text);
|
||||
}
|
||||
|
||||
static void xpmgr_write_wide(const wchar_t* text) {
|
||||
char bytes[260];
|
||||
int index = 0;
|
||||
if (!text) {
|
||||
return;
|
||||
}
|
||||
while (text[index] && index < 259) {
|
||||
wchar_t ch = text[index];
|
||||
bytes[index] = (ch >= 32 && ch < 127) ? (char)ch : '?';
|
||||
index++;
|
||||
}
|
||||
bytes[index] = 0;
|
||||
xpmgr_write(bytes);
|
||||
}
|
||||
|
||||
static void xpmgr_free(void* block) {
|
||||
if (block) {
|
||||
HeapFree(GetProcessHeap(), 0, block);
|
||||
}
|
||||
}
|
||||
|
||||
static wchar_t* xpmgr_widen(const char* text) {
|
||||
int chars;
|
||||
wchar_t* wide;
|
||||
if (!text) {
|
||||
return NULL;
|
||||
}
|
||||
chars = MultiByteToWideChar(CP_ACP, 0, text, -1, NULL, 0);
|
||||
if (chars <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
wide = (wchar_t*)HeapAlloc(GetProcessHeap(), 0, (SIZE_T)chars * sizeof(wchar_t));
|
||||
if (!wide) {
|
||||
return NULL;
|
||||
}
|
||||
if (MultiByteToWideChar(CP_ACP, 0, text, -1, wide, chars) <= 0) {
|
||||
HeapFree(GetProcessHeap(), 0, wide);
|
||||
return NULL;
|
||||
}
|
||||
return wide;
|
||||
}
|
||||
|
||||
static char* xpmgr_narrow(const wchar_t* text) {
|
||||
int bytes;
|
||||
char* narrow;
|
||||
UINT codepage = CP_UTF8;
|
||||
if (!text) {
|
||||
return NULL;
|
||||
}
|
||||
/* Windows 98, Me, and NT 4 reject CP_UTF8. These strings are ASCII. */
|
||||
bytes = WideCharToMultiByte(codepage, 0, text, -1, NULL, 0, NULL, NULL);
|
||||
if (bytes <= 0) {
|
||||
codepage = CP_ACP;
|
||||
bytes = WideCharToMultiByte(codepage, 0, text, -1, NULL, 0, NULL, NULL);
|
||||
if (bytes <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
narrow = (char*)HeapAlloc(GetProcessHeap(), 0, (SIZE_T)bytes);
|
||||
if (!narrow) {
|
||||
return NULL;
|
||||
}
|
||||
if (WideCharToMultiByte(codepage, 0, text, -1, narrow, bytes, NULL, NULL) <= 0) {
|
||||
HeapFree(GetProcessHeap(), 0, narrow);
|
||||
return NULL;
|
||||
}
|
||||
return narrow;
|
||||
}
|
||||