commit 840fb76d797319ca0542dccc92a08feb1e9a8264 Author: awuctl <61098069+awuctl@users.noreply.github.com> Date: Tue Aug 23 18:48:54 2022 +0200 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0d01231 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +* +!*.c +!*.py +!Makefile +!README.md +!LICENSE +!.gitignore \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..62ac64b --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +GCCOPT=-O0 -Wall -pedantic +GCC=gcc + +all: hwid_dec + +hwid_dec: hwid_dec.c + $(GCC) $(GCCOPT) $< -o $@ \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..52c914b --- /dev/null +++ b/README.md @@ -0,0 +1,35 @@ +# HWID Stuff + +Here are some basic example utilities for GenuineAuthorization tickets and HWID block blobs. + +If you'd like to learn more about the things those scripts work with, go to [massgravel/activation](https://github.com/massgravel/activation). + +# Info + +## `hwid_extract.py` + +This scripts extracts the HWID block blob from a GenuineAuthorization ticket into a file: + +```sh +# Writes to file +python hwid_extract.py GenuineTicket.xml hwid.bin + +# Writes to stdout +python hwid_extract.py GenuineTicket.xml +``` + +## `hwid_dec.c` + +This is a program that prints out all the individual fields in the HWID block blob. Build with `make`. + +```sh +hwid_dec hwid.bin +``` + +## `ticket_decode.py` + +This is a script that prints out meaningful individual fields in a ticket. + +```sh +python ticket_decode.py GenuineTicket.xml +``` \ No newline at end of file diff --git a/hwid_dec.c b/hwid_dec.c new file mode 100644 index 0000000..c426133 --- /dev/null +++ b/hwid_dec.c @@ -0,0 +1,108 @@ +#include +#include +#include + +struct __attribute__((packed)) HWID { + uint16_t size; + uint16_t version; + uint16_t instances[9]; + uint16_t dock_or_PCMCIA; + uint16_t hashRAM; + uint16_t hashBIOS; + uint16_t instanceHashes[]; +}; + +struct __attribute__((packed)) TIMEWEIGHT { + uint8_t num_weights; + struct __attribute__((packed)) Weight { + uint8_t type; + uint16_t weight; + } weight[]; +}; + +const char *CLASS_NAMES[] = { + "CDROM", + "Hard Disk Controllers", + "Hard Disk Drives", + "Displays", + "SCSI Adapters", + "PCMCIA", + "Audio Adapters", + "Dock", + "Network Interface Cards", + "CPUs", + "Memory", + "UNUSED", + "BIOS", + "UNUSED", + "Mobile Broadband", + "Bluetooth Interfaces" +}; + +const char *HWID_NAMES[] = { + "CDROM / Mobile Broadband", + "Hard Disk Controllers", + "Hard Disk Drives", + "Displays", + "SCSI Adapters / Bluetooth Controllers", + "Audio Adapters", + "Unused", + "Network Interface Cards", + "CPUs" +}; + +void print_block(uint8_t *hw_block) { + uint32_t size = *(uint32_t *)hw_block; + uint16_t unknown = *(uint16_t *)(hw_block + 4); + unsigned instance_count = 0; + + puts("Block Information:"); + printf("Size : [%08x]\n", size); + printf("Unknown : [%08x]\n", unknown); + puts(""); + + struct HWID *hwid = (struct HWID *)(hw_block + 6); + puts("HWID Information:"); + printf("Size : [%04x]\n", hwid->size); + printf("Version : [%04x]\n", hwid->version); + for(size_t i = 0; i < 9; i++) { + instance_count += hwid->instances[i]; + printf("Inst. (%02zx) : [%04x] -> %s\n", i, hwid->instances[i], HWID_NAMES[i]); + } + printf("Dock/PCMCIA : [%04x]\n", hwid->dock_or_PCMCIA); + printf("RAM hash : [%02x]\n", hwid->hashRAM); + printf("SMBIOS hash : [%04x]\n", hwid->hashBIOS); + for(size_t i = 0; i < instance_count; i++) { + printf("Hash (%02zx) : [%04x] %s\n", i, hwid->instanceHashes[i], (hwid->instanceHashes[i] & 1) == 1 ? "[[Non-Removable]]" : ""); + } + puts(""); + + struct TIMEWEIGHT *tw = (struct TIMEWEIGHT *) ((hw_block + 6) + hwid->size); + puts("Timeweight Information:"); + printf("Weights : [%02x]\n", tw->num_weights); + + for(size_t i = 0; i < tw->num_weights; i++) { + printf("Weight (%02x) : [%04x] -> %s\n", tw->weight[i].type, tw->weight[i].weight, CLASS_NAMES[tw->weight[i].type]); + } + +} + +int main(int argc, char *argv[]) { + + if(argc != 2) { + puts("Invalid parameters.\nUsages:\n\thwid file"); + exit(1); + } + + FILE *fd = fopen(argv[1], "r"); + fseek(fd, 0, SEEK_END); + long fsize = ftell(fd); + rewind(fd); + + uint8_t *hw_block = malloc(fsize); + fread(hw_block, 1, fsize, fd); + + print_block(hw_block); + + return 0; +} \ No newline at end of file diff --git a/hwid_extract.py b/hwid_extract.py new file mode 100755 index 0000000..f3f5433 --- /dev/null +++ b/hwid_extract.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python + +from functools import reduce +import xml.etree.ElementTree as ET + +from base64 import b64decode + +class Ticket: + @staticmethod + def get_properties(genAuth: ET.Element) -> str: + properties = genAuth.find('./{*}genuineProperties/{*}properties') + return properties.text + + @staticmethod + def split_keyval(x: str) -> dict: + parameters = {} + + for params in x.split(';'): + if not params or params == '\x00': + break + key_val = params.split('=') + parameters[key_val[0]] = key_val[1] + return parameters + + @staticmethod + def get_hwid(genAuth: ET.Element) -> str: + props = Ticket.split_keyval(Ticket.get_properties(genAuth)) + params = Ticket.split_keyval(b64decode(props['SessionId'] + '===').decode('utf-16')) + + return params['Hwid'] + +if __name__ == '__main__': + import argparse + + main_parser = argparse.ArgumentParser( + 'hwid_extract', + description='Extract the binary hardware id from ticket' + ) + main_parser.add_argument('input', type=argparse.FileType('rb')) + main_parser.add_argument('output', type=argparse.FileType('wb'), nargs='?') + args = main_parser.parse_args() + + ticket = ET.parse(args.input).getroot() + hwid = Ticket.get_hwid(ticket) + + hwid_block = b64decode(hwid + '===') + if args.output is None: + print(hwid_block) + else: + args.output.write(hwid_block) \ No newline at end of file diff --git a/ticket_decode.py b/ticket_decode.py new file mode 100755 index 0000000..a15fa14 --- /dev/null +++ b/ticket_decode.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python + +from functools import reduce +import xml.etree.ElementTree as ET + +from base64 import b64decode + +# Microsoft really hates padding base64 +# appending "===" is just so that b64decode +# doesn't complain about it. +# It's neither valid padding nor magic. + +class Ticket: + @staticmethod + def get_properties(genAuth: ET.Element) -> str: + properties = genAuth.find('./{*}genuineProperties/{*}properties') + return properties.text + + @staticmethod + def split_keyval(x: str) -> dict: + parameters = {} + + for params in x.split(';'): + if not params or params == '\x00': + break + key_val = params.split('=') + parameters[key_val[0]] = key_val[1] + return parameters + + def __init__(self, genuine_authorization: ET.Element): + self.gen_auth = genuine_authorization + self.gen_props = genuine_authorization.find('./{*}genuineProperties') + + props = self.gen_props.find('./{*}properties').text + self.props = self.split_keyval(props) + self.props['SessionId'] = self.split_keyval(b64decode(self.props['SessionId'] + '===').decode('utf-16')) + +if __name__ == '__main__': + import argparse + + main_parser = argparse.ArgumentParser( + 'ticket_decode', + description='Print out contents of a GenuineAuthorization ticket' + ) + main_parser.add_argument('input', type=argparse.FileType('r')) + args = main_parser.parse_args() + + ticket = Ticket(ET.parse(args.input).getroot()) + + # Print out stuff + + for prop in ticket.props: + if prop == 'SessionId': + for sess_prop in ticket.props['SessionId']: + print(sess_prop, ticket.props['SessionId'][sess_prop], sep=': ') + continue + print(prop, ticket.props[prop], sep=': ') \ No newline at end of file