├── README.md ├── bin ├── PPLcontrol.exe └── pssuspend64.exe ├── drivers ├── RTCore │ ├── RTCore64.sys │ ├── install.cmd │ └── remove.cmd └── StartSuspended │ ├── StartSuspended.sys │ ├── install.cmd │ └── remove.cmd ├── keyderiv.py ├── patterns ├── README.md ├── tokenstore.pat ├── variablebag.pat ├── win7_physstore.pat └── winmodern_physstore.pat ├── splog.py ├── spp_prod.pem ├── spp_test.pem ├── sppdebug.reg ├── tokens_rebuild_v2.py ├── tsdecrypt.py └── tsencrypt.py /README.md: -------------------------------------------------------------------------------- 1 | # spp-stuff 2 | 3 | Collection of random stuff 4 | 5 | ## Debugging """Guide""" 6 | 7 | - Put machine into testsigning (`bcdedit /set testsigning on`) 8 | - Install drivers under `drivers/` by running `install.cmd` in each folder 9 | - Install `sppdebug.reg` to have SPPSvc auto-suspend on startup 10 | - Use PPLcontrol to set debugger to `PP Windows` protection level 11 | - Use [ScyllaHide](https://github.com/x64dbg/ScyllaHide/releases/tag/v1.4) with VMProtect profile for debugging 12 | - Take care to avoid having debugger attached at the end of a [heap execute](https://github.com/WitherOrNot/warbird-docs/blob/main/WarbirdModern.md#heap-executes), or sppsvc will crash with Fast Fail Exception 13 | 14 | ## Credits 15 | 16 | - asdcorp, abbodi, Lyssa - ImHex patterns 17 | - asdcorp - SPP debug setup, `tokens_rebuild_v2.py` 18 | -------------------------------------------------------------------------------- /bin/PPLcontrol.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/massgravel/spp-stuff/9de7d4195f2590df3f9f0eff27d2036ff95b7977/bin/PPLcontrol.exe -------------------------------------------------------------------------------- /bin/pssuspend64.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/massgravel/spp-stuff/9de7d4195f2590df3f9f0eff27d2036ff95b7977/bin/pssuspend64.exe -------------------------------------------------------------------------------- /drivers/RTCore/RTCore64.sys: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/massgravel/spp-stuff/9de7d4195f2590df3f9f0eff27d2036ff95b7977/drivers/RTCore/RTCore64.sys -------------------------------------------------------------------------------- /drivers/RTCore/install.cmd: -------------------------------------------------------------------------------- 1 | copy "%~dp0RTCore64.sys" %systemdrive%\RTCore64.sys 2 | sc.exe create RTCore64 type= kernel start= auto binPath= %systemdrive%\RTCore64.sys DisplayName= "Micro - Star MSI Afterburner" 3 | net.exe start RTCore64 4 | pause 5 | -------------------------------------------------------------------------------- /drivers/RTCore/remove.cmd: -------------------------------------------------------------------------------- 1 | net.exe stop RTCore64 2 | sc.exe delete RTCore64 3 | del %systemdrive%\RTCore64.sys 4 | pause 5 | -------------------------------------------------------------------------------- /drivers/StartSuspended/StartSuspended.sys: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/massgravel/spp-stuff/9de7d4195f2590df3f9f0eff27d2036ff95b7977/drivers/StartSuspended/StartSuspended.sys -------------------------------------------------------------------------------- /drivers/StartSuspended/install.cmd: -------------------------------------------------------------------------------- 1 | copy "%~dp0StartSuspended.sys" %systemdrive%\StartSuspended.sys 2 | sc.exe create StartSuspended type= kernel start= auto binPath= %systemdrive%\StartSuspended.sys 3 | reg.exe add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\StartSuspended /v Target /t REG_SZ /d sppsvc.exe /f 4 | net.exe start StartSuspended 5 | pause 6 | -------------------------------------------------------------------------------- /drivers/StartSuspended/remove.cmd: -------------------------------------------------------------------------------- 1 | net.exe stop RTCore64 2 | sc.exe delete RTCore64 3 | del %systemdrive%\RTCore64.sys 4 | pause 5 | -------------------------------------------------------------------------------- /keyderiv.py: -------------------------------------------------------------------------------- 1 | import re 2 | import json 3 | import sys 4 | 5 | """ 6 | Set all following breakpoints on sppsvc.exe in x64dbg with Break Condition 0, Command Condition 1, and the associated Command Text: 7 | 8 | For prod key, works on 19041.1266 -> 19044.3803 9 | 10 | `sppsvc+1957F4` - `log "MODULUS {mem;0x80@rdx}"` 11 | `sppsvc+195A80` - `log "MUL F1 {mem;0x80@rdx}"; log "MUL F2 {mem;0x80@r8}"` 12 | `sppsvc+1A36F1` - `log "MUL PROD {mem;0x80@rbx}"` 13 | `sppsvc+198CEC` - `log "MPMUL F1 {mem;0x80@[[arg.get(2)]-[[sppsvc+0x440198]]]}"; log "MPMUL F2 {mem;0x80@[[arg.get(3)]-[[sppsvc+0x440198]]]}"` 14 | `sppsvc+199E07` - `log "MPMUL PROD {mem;0x80@[rax-[[sppsvc+0x440198]]]}"` 15 | `sppsvc+19561C` - `log "LAST MPMODMUL"` 16 | 17 | For test key, works on 20221.1000 18 | 19 | `sppsvc+1DD940` - `log "MODULUS {mem;0x80@rdx}"` 20 | `sppsvc+1DDFF0` - `log "MUL F1 {mem;0x80@rdx}"; log "MUL F2 {mem;0x80@r8}"` 21 | `sppsvc+1DD8B1` - `log "MUL PROD {mem;0x80@rdi}"` 22 | `sppsvc+1D2050` - `log "MPMUL F1 {mem;0x80@[[arg.get(2)]-[[sppsvc+0x483178]]]}"; log "MPMUL F2 {mem;0x80@[[arg.get(3)]-[[sppsvc+0x483178]]]}"` 23 | `sppsvc+1D30F4` - `log "MPMUL PROD {mem;0x80@[[rbp-0x69]-[[sppsvc+0x483178]]]}"` 24 | `sppsvc+1CEDE2` - `log "LAST MPMODMUL"` 25 | 26 | Right-click in Log tab, select "Redirect Log File" and choose path before unsuspending, once LAST MPMODMUL is shown then save log file and use with this script. 27 | """ 28 | 29 | pows = {} 30 | 31 | mul_log = open(sys.argv[1], "r").read() 32 | 33 | muls = re.finditer(r"\s*(?:MPMUL|MUL) F1 (\w+)\s*(?:MPMUL|MUL) F2 (\w+)\s*(?:MPMUL|MUL) PROD (\w+)\s*", mul_log, re.DOTALL | re.MULTILINE) 34 | fs_mul = muls.__next__() 35 | 36 | assert fs_mul[1] == fs_mul[2] 37 | 38 | pows[fs_mul[1]] = 1 39 | pows[fs_mul[3]] = 2 40 | 41 | last_pow = 0 42 | 43 | for mul in muls: 44 | print(mul[1][:8], mul[2][:8], mul[3][:8]) 45 | pows[mul[3]] = pows[mul[1]] + pows[mul[2]] 46 | 47 | last_pow = pows[mul[3]] 48 | 49 | print("Derived private key: ", hex(last_pow)) -------------------------------------------------------------------------------- /patterns/README.md: -------------------------------------------------------------------------------- 1 | # ImHex Patterns 2 | 3 | You can use these pattern files with [ImHex](https://github.com/WerWolv/ImHex) to view contents of various SPP-related files. 4 | 5 | ## Pattern List 6 | 7 | - `variablebag` - For product key blobs in physical store/`cache.dat` 8 | - `tokenstore` - For `tokens.dat` 9 | - `win7_physstore`/`winmodern_physstore` - For decrypted Windows 7/Windows 8+ physical store 10 | 11 | Physical store can be decrypted with TSforge `/dump` option, ex. `tsforge /dump out.dat` on live system or `tsforge /dump out.dat in.dat` for physical store from offline system. 12 | -------------------------------------------------------------------------------- /patterns/tokenstore.pat: -------------------------------------------------------------------------------- 1 | struct EntryContent { 2 | u8 header[32]; 3 | u32 data_len; 4 | u8 sha256[32]; 5 | u8 data[data_len]; 6 | u8 footer[32]; 7 | }; 8 | 9 | struct Metadata { 10 | u32 entry_off; 11 | u32 populated; 12 | u32 content_off; 13 | u32 content_len; 14 | u32 alloc_len; 15 | char16 name[65]; 16 | char16 ext[4]; 17 | 18 | if (populated == 1) { 19 | EntryContent content @ content_off; 20 | } 21 | }; 22 | 23 | struct Block { 24 | u32 self_off; 25 | u32 next_off; 26 | Metadata metadata[103]; 27 | padding[16384 - sizeof(self_off) - sizeof(next_off) - sizeof(metadata)]; 28 | u8 sha256[32]; 29 | 30 | if (next_off != 0) { 31 | Block next @ next_off; 32 | } 33 | }; 34 | 35 | struct FileHeader { 36 | u32 version; 37 | u8 sha256[32]; 38 | Block block; 39 | }; 40 | 41 | FileHeader fileheader @ 0x00; -------------------------------------------------------------------------------- /patterns/variablebag.pat: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct varbag_entry { 4 | u32 crc32; 5 | u32 unk1; 6 | u32 len_name; 7 | u32 len_val; 8 | char16 name[len_name/2]; 9 | padding[-$&7]; 10 | u8 value[len_val]; 11 | padding[-$&7]; 12 | }; 13 | 14 | varbag_entry entries[while($ < std::mem::size())] @ 0x0; -------------------------------------------------------------------------------- /patterns/win7_physstore.pat: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct tsd_data { 4 | u32 val_type; // 0 None, 1 Named, 2 Attribute, 3 Timer 5 | u32 flags; 6 | u32 len_key; 7 | u32 len_val; 8 | u32 len_data; 9 | char16 key[len_key/2]; 10 | u8 value[len_val]; 11 | u8 data[len_data]; 12 | padding[-$&3]; 13 | }; 14 | 15 | tsd_data store[while($ < std::mem::size())] @ 0x8; -------------------------------------------------------------------------------- /patterns/winmodern_physstore.pat: -------------------------------------------------------------------------------- 1 | struct tsd_header { 2 | u32 len_name; 3 | char16 name[len_name/2]; 4 | u32 num_entries; 5 | padding[-$&3]; 6 | }; 7 | 8 | struct tsd_data { 9 | u32 unk1; 10 | u32 unk2; 11 | u32 len_name; 12 | u32 len_val; 13 | u32 unk3; 14 | char16 name[len_name/2]; 15 | u8 value[len_val]; 16 | padding[-$&3]; 17 | }; 18 | 19 | struct tsentry { 20 | tsd_header header; 21 | tsd_data data[header.num_entries]; 22 | }; 23 | 24 | struct data_store { 25 | u32 num_entries; 26 | tsentry entries[num_entries]; 27 | }; 28 | 29 | data_store store @ 0x8; -------------------------------------------------------------------------------- /splog.py: -------------------------------------------------------------------------------- 1 | # Decrypt C:\Windows\System32\spsys.log from Windows 7 2 | # Can be used to trace functions executed in spsys 3 | 4 | from Crypto.Cipher import AES 5 | from struct import unpack 6 | 7 | aeskey = bytes([0x5B, 0x68, 0x49, 0x25, 0x79, 0x7B, 0x81, 0xFE, 0x5C, 0x44, 0x1B, 0x08, 0x2B, 0xEA, 0xEC, 0x4E]) 8 | 9 | log_data = b"" 10 | 11 | with open("spsys.log", "rb") as f: 12 | aes = AES.new(aeskey, AES.MODE_ECB) 13 | log_data = aes.decrypt(f.read()[0x28:]) 14 | 15 | with open("spsys_log_d.bin", "wb") as f: 16 | f.write(log_data) -------------------------------------------------------------------------------- /spp_prod.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIICXQIBAAKBgQDXsWBAi5fZLtghWfw8h436oA2jj9NRtXwIflPNtfCZajhZUjie 3 | lWojg02FFWw/QgKAymqXWOACbvl1kME9PNFMKP42LQNci+TpaGWj8KUr9+llQ7c5 4 | FD1WYETdxd5BAB6GBWVRQjM6YbgR4/WL3U8IZ/k7sjhrJhLYV5BSP7qHKQIDAQAB 5 | AoGBAL84RIHUf9GOYxPmR+WNs4RuosjPuGOnBogtHrSvyNbpwX0GlKWbBxbm0DHd 6 | FTNbnQZ67Vax9x6RLd1ZcMeOhGljjawdN1J69svKdGEfLgk6ZjwY/IK1R+lhcNm6 7 | 6wq7lGZubHks+v4bfoIgNU6PSyrVguMUKyCIZI9UmNLXISbVAkEA2BvXsM7ByJx1 8 | 3UgjmQIIoYJLihaJxxR7VIXZG7k4Q5IE89tSUxNqgPr/KF5MlOBc4U1a3LfkV7E8 9 | zFC1YG4KKwJBAP+B4YPO+6233rd/Ua73QyXVAAp1rY/ZD/LYnfV/x5tew6HutDIK 10 | DeDwQ+FAnpbOH6e6MzBEaSn2SxinRy6nLfsCQAK15rCrBzcy7y+FVhz3L5CHB9eF 11 | jNjYYuueeiik3BXM4Q8F8zRji/RuMYEaHa/IWKHizH70N4L6EB8n6/53ot0CQFhQ 12 | EB564Eq/Dt/lxdnv5OmioYz7962MnRKXBKHiNJ/jNUM3OllBWGKzKQMmTqpZPF/A 13 | 4AiC3MaANpyi1NuvNRkCQQCr+LBFMuA05e901DwL24dMQsHsd3IDaXaf+ZBImg+M 14 | 60aHSrllG6RLV/Sk5lgKWCUvrIJ97Yza156wV/7U4VFj 15 | -----END RSA PRIVATE KEY----- -------------------------------------------------------------------------------- /spp_test.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIICXQIBAAKBgQD2nHchRdHpsxBrJhmBFbOxIa8tw+JXQb42rnz4cOYjaFEGeM7Q 3 | wydMfOOumFxQ/Jg9yl64N9mVduFpvcGzZdbz2/Td5ZDTnJ3PHo6178NgkmdyUzo3 4 | nv06m1+zgHrZ6Qi3thRXP+1RND1tqzUWDBYeP9ETxGYX1GfdNlTduHe+DwIDAQAB 5 | AoGBAPFt/LL2R6sjQs+jXRSiymh/MaD8RHpoQnAGIxKWdLf1SF2tp8t5Qt/+5Gfp 6 | gXdH00Oq+1AeXUWWPNfojdmzudrXYgAv750Vf5TdPMb9gPZZkc1d5ksw3n3h103V 7 | 0Wp0fX3sJavF5WiEN8GeByr+4c+naeQQm8+jacHQMmjTEWgBAkEA/CnRmlNCe7lF 8 | BiDMrFCHBHWa7bJRkZWoZhwOCYIEk2Sfrl1+WMWFMF7UkANtCU8ZECQH+4bbK7xh 9 | Mh2deLbd4QJBAPpdBVPcGDHCiPWAiSSEpVrXADEacJ8MuzE4ux48oXj6E8c4mmu/ 10 | S+mxoZLsa9PeEo5QLSGcVMsrhwVpdRZHue8CQDaHZIgW0R2oJsD4fsoUb94LAIG+ 11 | Od1dm5jZID/2Gb8110IBfbz8mZyoJRcvZnjI3gabhA5kTyjaB7qqpM7h3IECQQC+ 12 | ooHh/t71VLlQplTG17HI35knyogis2D988KXHXeeVF0m/vSmQn0dLsJmy1q3cosS 13 | jf4vb4gpQ7WF62zaUDdFAkBv/Lk1yuGX2Yx1f6a+BK4tC/EfJSTi2ojyvSH6IjgI 14 | 2eXEW4fB1vpiz0cf7maWHO2iPSFducHYF7OkuC//SJ+B 15 | -----END RSA PRIVATE KEY----- -------------------------------------------------------------------------------- /sppdebug.reg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/massgravel/spp-stuff/9de7d4195f2590df3f9f0eff27d2036ff95b7977/sppdebug.reg -------------------------------------------------------------------------------- /tokens_rebuild_v2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import struct 4 | import sys 5 | import os 6 | import hashlib 7 | 8 | TOKENS_VERSION = 3 9 | 10 | BLOCK_SIZE = 16384 11 | ENTRY_SIZE = 158 12 | MAX_ENTRIES = (BLOCK_SIZE - 8) // ENTRY_SIZE 13 | 14 | ENTRY_CONTENTS_HEADER = b'\x55' * 32 15 | ENTRY_CONTENTS_FOOTER = b'\xAA' * 32 16 | 17 | def parse_entry(f, offset): 18 | f.seek(offset) 19 | unpacked = struct.unpack(' MAX_ENTRIES: 149 | write_entries = MAX_ENTRIES 150 | write_next_block_offset = True 151 | 152 | for _ in range(write_entries): 153 | data, data_len, meta = build_entry(o_meta, o_data, entries.pop(0)) 154 | 155 | meta_block = meta + meta_block 156 | o_meta -= ENTRY_SIZE 157 | 158 | data_block += data 159 | o_data += data_len 160 | 161 | for _ in range(MAX_ENTRIES - write_entries): 162 | meta = build_entry_meta(o_meta, False, 0, 0xFFFFFFFF, ('', '')) 163 | 164 | meta_block = meta + meta_block 165 | o_meta -= ENTRY_SIZE 166 | 167 | if write_next_block_offset: 168 | next_block = o_data 169 | 170 | finished_block = struct.pack("