mirror of
https://github.com/SystemRage/py-kms.git
synced 2024-11-25 17:55:37 +01:00
A Great Update: py-kms_2019-05-15
This commit is contained in:
parent
698353f800
commit
660d86d42b
File diff suppressed because it is too large
Load Diff
739
py-kms/pykms_Aes.py
Normal file
739
py-kms/pykms_Aes.py
Normal file
@ -0,0 +1,739 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# aes.py: implements AES - Advanced Encryption Standard
|
||||
# from the SlowAES project, http://code.google.com/p/slowaes/
|
||||
#
|
||||
# Copyright (c) 2008 Josh Davis ( http://www.josh-davis.org )
|
||||
# Alex Martelli ( http://www.aleax.it )
|
||||
#
|
||||
# Modified for py-kms, Python 2 / 3 compatible
|
||||
# Copyright (c) 2019 Matteo Fan ( SystemRage@protonmail.com )
|
||||
#
|
||||
# Ported from C code written by Laurent Haan ( http://www.progressive-coding.com )
|
||||
|
||||
# Licensed under the Apache License, Version 2.0
|
||||
# http://www.apache.org/licenses/
|
||||
#
|
||||
|
||||
from __future__ import print_function, unicode_literals
|
||||
import os
|
||||
import math
|
||||
|
||||
def append_PKCS7_padding(val):
|
||||
""" Function to pad the given data to a multiple of 16-bytes by PKCS7 padding. """
|
||||
numpads = 16 - (len(val) % 16)
|
||||
return val + numpads * bytearray(chr(numpads).encode('utf-8'))
|
||||
|
||||
def strip_PKCS7_padding(val):
|
||||
""" Function to strip off PKCS7 padding. """
|
||||
|
||||
if len(val) % 16 or not val:
|
||||
raise ValueError("String of len %d can't be PCKS7-padded" % len(val))
|
||||
numpads = val[-1]
|
||||
if numpads > 16:
|
||||
raise ValueError("String ending with %r can't be PCKS7-padded" % val[-1])
|
||||
return val[:-numpads]
|
||||
|
||||
|
||||
class AES( object ):
|
||||
""" Class implementing the Advanced Encryption Standard algorithm. """
|
||||
|
||||
#*py-kms*
|
||||
v6 = False
|
||||
|
||||
# Valid key sizes
|
||||
KeySize = {
|
||||
"SIZE_128": 16,
|
||||
"SIZE_192": 24,
|
||||
"SIZE_256": 32
|
||||
}
|
||||
|
||||
# Rijndael S-box
|
||||
sbox = [ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67,
|
||||
0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59,
|
||||
0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7,
|
||||
0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1,
|
||||
0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05,
|
||||
0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83,
|
||||
0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29,
|
||||
0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
|
||||
0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa,
|
||||
0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c,
|
||||
0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc,
|
||||
0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec,
|
||||
0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19,
|
||||
0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee,
|
||||
0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49,
|
||||
0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
|
||||
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4,
|
||||
0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6,
|
||||
0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70,
|
||||
0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9,
|
||||
0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e,
|
||||
0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1,
|
||||
0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0,
|
||||
0x54, 0xbb, 0x16 ]
|
||||
|
||||
# Rijndael Inverted S-box
|
||||
rsbox = [ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3,
|
||||
0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f,
|
||||
0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54,
|
||||
0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b,
|
||||
0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24,
|
||||
0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8,
|
||||
0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d,
|
||||
0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda,
|
||||
0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab,
|
||||
0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3,
|
||||
0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1,
|
||||
0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41,
|
||||
0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6,
|
||||
0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9,
|
||||
0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d,
|
||||
0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
|
||||
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0,
|
||||
0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07,
|
||||
0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60,
|
||||
0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f,
|
||||
0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5,
|
||||
0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b,
|
||||
0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55,
|
||||
0x21, 0x0c, 0x7d ]
|
||||
|
||||
# Rijndael Rcon
|
||||
Rcon = [ 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36,
|
||||
0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97,
|
||||
0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72,
|
||||
0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66,
|
||||
0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04,
|
||||
0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d,
|
||||
0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3,
|
||||
0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61,
|
||||
0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
|
||||
0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40,
|
||||
0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc,
|
||||
0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5,
|
||||
0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a,
|
||||
0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d,
|
||||
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c,
|
||||
0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35,
|
||||
0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4,
|
||||
0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,
|
||||
0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08,
|
||||
0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
|
||||
0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d,
|
||||
0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2,
|
||||
0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74,
|
||||
0xe8, 0xcb ]
|
||||
|
||||
def getSBoxValue(self,num):
|
||||
""" Method to retrieve a given S-Box value. """
|
||||
return self.sbox[num]
|
||||
|
||||
def getSBoxInvert(self,num):
|
||||
""" Method to retrieve a given Inverted S-Box value."""
|
||||
return self.rsbox[num]
|
||||
|
||||
def rotate(self, word):
|
||||
""" Method performing Rijndael's key schedule rotate operation.
|
||||
Rotate a word eight bits to the left: eg, rotate(1d2c3a4f) == 2c3a4f1d
|
||||
@param word: char list of size 4 (32 bits overall).
|
||||
"""
|
||||
return word[1:] + word[:1]
|
||||
|
||||
def getRconValue(self, num):
|
||||
""" Method to retrieve a given Rcon value. """
|
||||
return self.Rcon[num]
|
||||
|
||||
def core(self, word, iteration):
|
||||
""" Method performing the key schedule core operation. """
|
||||
# Rotate the 32-bit word 8 bits to the left.
|
||||
word = self.rotate(word)
|
||||
# Apply S-Box substitution on all 4 parts of the 32-bit word.
|
||||
for i in range(4):
|
||||
word[i] = self.getSBoxValue(word[i])
|
||||
# XOR the output of the rcon operation with i to the first part (leftmost) only.
|
||||
word[0] = word[0] ^ self.getRconValue(iteration)
|
||||
return word
|
||||
|
||||
def expandKey(self, key, size, expandedKeySize):
|
||||
""" Method performing Rijndael's key expansion.
|
||||
Expands an 128, 192, 256 key into an 176, 208, 240 bytes key.
|
||||
"""
|
||||
# Current expanded keySize, in bytes.
|
||||
currentSize = 0
|
||||
rconIteration = 1
|
||||
expandedKey = [0] * expandedKeySize
|
||||
|
||||
# Set the 16, 24, 32 bytes of the expanded key to the input key.
|
||||
for j in range(size):
|
||||
expandedKey[j] = key[j]
|
||||
currentSize += size
|
||||
|
||||
while currentSize < expandedKeySize:
|
||||
# Assign the previous 4 bytes to the temporary value t.
|
||||
t = expandedKey[currentSize - 4:currentSize]
|
||||
|
||||
# Every 16,24,32 bytes we apply the core schedule to t
|
||||
# and increment rconIteration afterwards.
|
||||
if currentSize % size == 0:
|
||||
t = self.core(t, rconIteration)
|
||||
rconIteration += 1
|
||||
# For 256-bit keys, we add an extra sbox to the calculation.
|
||||
if size == self.KeySize["SIZE_256"] and ((currentSize % size) == 16):
|
||||
for l in range(4):
|
||||
t[l] = self.getSBoxValue(t[l])
|
||||
|
||||
# We XOR t with the four-byte block 16,24,32 bytes before the new
|
||||
# expanded key. This becomes the next four bytes in the expanded key.
|
||||
for m in range(4):
|
||||
expandedKey[currentSize] = expandedKey[currentSize - size] ^ t[m]
|
||||
currentSize += 1
|
||||
return expandedKey
|
||||
|
||||
def addRoundKey(self, state, roundKey):
|
||||
""" Method to add (XORs) the round key to the state. """
|
||||
for i in range(16):
|
||||
state[i] ^= roundKey[i]
|
||||
return state
|
||||
|
||||
def createRoundKey(self, expandedKey, roundKeyPointer):
|
||||
""" Creates a round key from the given expanded key and the
|
||||
position within the expanded key.
|
||||
"""
|
||||
roundKey = [0] * 16
|
||||
for i in range(4):
|
||||
for j in range(4):
|
||||
roundKey[j * 4 + i] = expandedKey[roundKeyPointer + i * 4 + j]
|
||||
return roundKey
|
||||
|
||||
def galois_multiplication(self, a, b):
|
||||
""" Method to perform a Galois multiplication of 8 bit characters
|
||||
a and b.
|
||||
"""
|
||||
p = 0
|
||||
for counter in range(8):
|
||||
if b & 1:
|
||||
p ^= a
|
||||
hi_bit_set = a & 0x80
|
||||
a <<= 1
|
||||
# keep a 8 bit
|
||||
a &= 0xFF
|
||||
if hi_bit_set:
|
||||
a ^= 0x1b
|
||||
b >>= 1
|
||||
return p
|
||||
|
||||
def subBytes(self, state, isInv):
|
||||
""" Method to substitute all the values from the state with the
|
||||
value in the SBox using the state value as index for the SBox.
|
||||
"""
|
||||
if isInv:
|
||||
getter = self.getSBoxInvert
|
||||
else:
|
||||
getter = self.getSBoxValue
|
||||
for i in range(16):
|
||||
state[i] = getter(state[i])
|
||||
return state
|
||||
|
||||
def shiftRows(self, state, isInv):
|
||||
""" Method to iterate over the 4 rows and call shiftRow(...) with that row. """
|
||||
for i in range(4):
|
||||
state = self.shiftRow(state, i * 4, i, isInv)
|
||||
return state
|
||||
|
||||
def shiftRow(self, state, statePointer, nbr, isInv):
|
||||
""" Method to shift the row to the left. """
|
||||
for i in range(nbr):
|
||||
if isInv:
|
||||
state[statePointer:statePointer + 4] = state[statePointer + 3:statePointer + 4] + \
|
||||
state[statePointer:statePointer + 3]
|
||||
else:
|
||||
state[statePointer:statePointer + 4] = state[statePointer + 1:statePointer + 4] + \
|
||||
state[statePointer:statePointer + 1]
|
||||
return state
|
||||
|
||||
|
||||
def mixColumns(self, state, isInv):
|
||||
""" Method to perform a galois multiplication of the 4x4 matrix. """
|
||||
# Iterate over the 4 columns.
|
||||
for i in range(4):
|
||||
# Construct one column by slicing over the 4 rows.
|
||||
column = state[i:i + 16:4]
|
||||
# Apply the mixColumn on one column.
|
||||
column = self.mixColumn(column, isInv)
|
||||
# Put the values back into the state.
|
||||
state[i:i + 16:4] = column
|
||||
return state
|
||||
|
||||
def mixColumn(self, column, isInv):
|
||||
""" Method to perform a galois multiplication of 1 column the 4x4 matrix. """
|
||||
if isInv:
|
||||
mult = [14, 9, 13, 11]
|
||||
else:
|
||||
mult = [2, 1, 1, 3]
|
||||
cpy = list(column)
|
||||
g = self.galois_multiplication
|
||||
|
||||
column[0] = g(cpy[0], mult[0]) ^ g(cpy[3], mult[1]) ^ \
|
||||
g(cpy[2], mult[2]) ^ g(cpy[1], mult[3])
|
||||
column[1] = g(cpy[1], mult[0]) ^ g(cpy[0], mult[1]) ^ \
|
||||
g(cpy[3], mult[2]) ^ g(cpy[2], mult[3])
|
||||
column[2] = g(cpy[2], mult[0]) ^ g(cpy[1], mult[1]) ^ \
|
||||
g(cpy[0], mult[2]) ^ g(cpy[3], mult[3])
|
||||
column[3] = g(cpy[3], mult[0]) ^ g(cpy[2], mult[1]) ^ \
|
||||
g(cpy[1], mult[2]) ^ g(cpy[0], mult[3])
|
||||
return column
|
||||
|
||||
|
||||
def aes_round(self, state, roundKey, roundKms):
|
||||
""" Method to apply the 4 operations of the forward round in sequence. """
|
||||
state = self.subBytes(state, False)
|
||||
state = self.shiftRows(state, False)
|
||||
state = self.mixColumns(state, False)
|
||||
|
||||
#*py-kms*
|
||||
if self.v6:
|
||||
if roundKms == 4:
|
||||
state[0] ^= 0x73
|
||||
if roundKms == 6:
|
||||
state[0] ^= 0x09
|
||||
if roundKms == 8:
|
||||
state[0] ^= 0xE4
|
||||
|
||||
state = self.addRoundKey(state, roundKey)
|
||||
return state
|
||||
|
||||
def aes_invRound(self, state, roundKey, roundKms):
|
||||
""" Method to apply the 4 operations of the inverse round in sequence. """
|
||||
state = self.shiftRows(state, True)
|
||||
state = self.subBytes(state, True)
|
||||
state = self.addRoundKey(state, roundKey)
|
||||
|
||||
#*py-kms*
|
||||
if self.v6:
|
||||
if roundKms == 4:
|
||||
state[0] ^= 0x73
|
||||
if roundKms == 6:
|
||||
state[0] ^= 0x09
|
||||
if roundKms == 8:
|
||||
state[0] ^= 0xE4
|
||||
|
||||
state = self.mixColumns(state, True)
|
||||
return state
|
||||
|
||||
|
||||
def aes_main(self, state, expandedKey, nbrRounds):
|
||||
""" Method to do the AES encryption for one round.
|
||||
|
||||
Perform the initial operations, the standard round and the
|
||||
final operations of the forward AES, creating a round key for each round.
|
||||
"""
|
||||
state = self.addRoundKey(state, self.createRoundKey(expandedKey, 0))
|
||||
i = 1
|
||||
while i < nbrRounds:
|
||||
state = self.aes_round(state, self.createRoundKey(expandedKey, 16 * i), i)
|
||||
i += 1
|
||||
state = self.subBytes(state, False)
|
||||
state = self.shiftRows(state, False)
|
||||
state = self.addRoundKey(state, self.createRoundKey(expandedKey, 16 * nbrRounds))
|
||||
return state
|
||||
|
||||
|
||||
def aes_invMain(self, state, expandedKey, nbrRounds):
|
||||
""" Method to do the inverse AES encryption for one round.
|
||||
|
||||
Perform the initial operations, the standard round, and the
|
||||
final operations of the inverse AES, creating a round key for each round.
|
||||
"""
|
||||
state = self.addRoundKey(state, self.createRoundKey(expandedKey, 16 * nbrRounds))
|
||||
i = nbrRounds - 1
|
||||
while i > 0:
|
||||
state = self.aes_invRound(state, self.createRoundKey(expandedKey, 16 * i), i)
|
||||
i -= 1
|
||||
state = self.shiftRows(state, True)
|
||||
state = self.subBytes(state, True)
|
||||
state = self.addRoundKey(state, self.createRoundKey(expandedKey, 0))
|
||||
return state
|
||||
|
||||
def encrypt(self, iput, key, size):
|
||||
""" Method to encrypt a 128 bit input block against the given key
|
||||
of size specified.
|
||||
"""
|
||||
output = [0] * 16
|
||||
# The number of rounds.
|
||||
nbrRounds = 0
|
||||
# The 128 bit block to encode.
|
||||
block = [0] * 16
|
||||
# Set the number of rounds.
|
||||
if size == self.KeySize["SIZE_128"]:
|
||||
nbrRounds = 10
|
||||
elif size == self.KeySize["SIZE_192"]:
|
||||
nbrRounds = 12
|
||||
elif size == self.KeySize["SIZE_256"]:
|
||||
nbrRounds = 14
|
||||
# *py-kms* The KMS v4 parameters.
|
||||
elif size == 20:
|
||||
nbrRounds = 11
|
||||
else:
|
||||
raise ValueError("Wrong key size given ({}).".format(size))
|
||||
|
||||
# The expanded keySize.
|
||||
expandedKeySize = 16 * (nbrRounds + 1)
|
||||
|
||||
# Set the block values, for the block:
|
||||
# a[0,0] a[0,1] a[0,2] a[0,3]
|
||||
# a[1,0] a[1,1] a[1,2] a[1,3]
|
||||
# a[2,0] a[2,1] a[2,2] a[2,3]
|
||||
# a[3,0] a[3,1] a[3,2] a[3,3]
|
||||
# the mapping order is a[0,0] a[1,0] a[2,0] a[3,0] a[0,1] a[1,1] ... a[2,3] a[3,3]
|
||||
|
||||
# Iterate over the columns and over the rows.
|
||||
for i in range(4):
|
||||
for j in range(4):
|
||||
block[i + j * 4] = iput[i * 4 +j]
|
||||
|
||||
# Expand the key into an 176, 208, 240 bytes key
|
||||
expandedKey = self.expandKey(key, size, expandedKeySize)
|
||||
|
||||
# Encrypt the block using the expandedKey.
|
||||
block = self.aes_main(block, expandedKey, nbrRounds)
|
||||
|
||||
# Unmap the block again into the output.
|
||||
for k in range(4):
|
||||
for l in range(4):
|
||||
output[k * 4 + l] = block[k + l * 4]
|
||||
return output
|
||||
|
||||
|
||||
def decrypt(self, iput, key, size):
|
||||
""" Method to decrypt a 128 bit input block against the given key
|
||||
of size specified.
|
||||
"""
|
||||
output = [0] * 16
|
||||
# The number of rounds.
|
||||
nbrRounds = 0
|
||||
# The 128 bit block to decode.
|
||||
block = [0] * 16
|
||||
# Set the number of rounds.
|
||||
if size == self.KeySize["SIZE_128"]:
|
||||
nbrRounds = 10
|
||||
elif size == self.KeySize["SIZE_192"]:
|
||||
nbrRounds = 12
|
||||
elif size == self.KeySize["SIZE_256"]:
|
||||
nbrRounds = 14
|
||||
#*py-kms* The KMS v4 parameters.
|
||||
elif size == 20:
|
||||
nbrRounds = 11
|
||||
else:
|
||||
raise ValueError("Wrong key size given ({}).".format(size))
|
||||
|
||||
# The expanded keySize.
|
||||
expandedKeySize = 16 * (nbrRounds + 1)
|
||||
|
||||
# Set the block values, for the block:
|
||||
# a[0,0] a[0,1] a[0,2] a[0,3]
|
||||
# a[1,0] a[1,1] a[1,2] a[1,3]
|
||||
# a[2,0] a[2,1] a[2,2] a[2,3]
|
||||
# a[3,0] a[3,1] a[3,2] a[3,3]
|
||||
# the mapping order is a[0,0] a[1,0] a[2,0] a[3,0] a[0,1] a[1,1] ... a[2,3] a[3,3]
|
||||
|
||||
# Iterate over the columns and the rows.
|
||||
for i in range(4):
|
||||
for j in range(4):
|
||||
block[i + j * 4] = iput[i * 4 + j]
|
||||
|
||||
# Expand the key into an 176, 208, 240 bytes key.
|
||||
expandedKey = self.expandKey(key, size, expandedKeySize)
|
||||
# Decrypt the block using the expandedKey.
|
||||
block = self.aes_invMain(block, expandedKey, nbrRounds)
|
||||
# Unmap the block again into the output.
|
||||
for k in range(4):
|
||||
for l in range(4):
|
||||
output[k * 4 +l] = block[k + l * 4]
|
||||
return output
|
||||
|
||||
|
||||
class AESModeOfOperation( object ):
|
||||
""" Class implementing the different AES mode of operations. """
|
||||
|
||||
aes = AES()
|
||||
|
||||
# Supported modes of operation.
|
||||
ModeOfOperation = {
|
||||
"OFB": 0,
|
||||
"CFB": 1,
|
||||
"CBC": 2
|
||||
}
|
||||
|
||||
def convertString(self, string, start, end, mode):
|
||||
""" Method to convert a 16 character string into a number array. """
|
||||
if end - start > 16:
|
||||
end = start + 16
|
||||
if mode == self.ModeOfOperation["CBC"]:
|
||||
ar = [0] * 16
|
||||
else:
|
||||
ar = []
|
||||
|
||||
i = start
|
||||
j = 0
|
||||
while len(ar) < end - start:
|
||||
ar.append(0)
|
||||
while i < end:
|
||||
ar[j] = string[i]
|
||||
j += 1
|
||||
i += 1
|
||||
return ar
|
||||
|
||||
|
||||
def encrypt(self, stringIn, mode, key, size, IV):
|
||||
""" Method to perform the encryption operation.
|
||||
|
||||
@param stringIn: input string to be encrypted
|
||||
@param mode: mode of operation (0, 1 or 2)
|
||||
@param key: a hex key of the bit length size
|
||||
@param size: the bit length of the key (16, 24 or 32)
|
||||
@param IV: the 128 bit hex initilization vector
|
||||
@return tuple with mode of operation, length of the input and the encrypted data
|
||||
"""
|
||||
if len(key) % size:
|
||||
raise ValueError("Illegal size ({}) for key '{}'.".format(size, key))
|
||||
if len(IV) % 16:
|
||||
raise ValueError("IV is not a multiple of 16.")
|
||||
# The AES input/output.
|
||||
plaintext = []
|
||||
iput = [0] * 16
|
||||
output = []
|
||||
ciphertext = [0] * 16
|
||||
# The output cipher string.
|
||||
cipherOut = []
|
||||
|
||||
firstRound = True
|
||||
if stringIn != None:
|
||||
for j in range(int(math.ceil(float(len(stringIn))/16))):
|
||||
start = j * 16
|
||||
end = j * 16 + 16
|
||||
if end > len(stringIn):
|
||||
end = len(stringIn)
|
||||
plaintext = self.convertString(stringIn, start, end, mode)
|
||||
|
||||
if mode == self.ModeOfOperation["CFB"]:
|
||||
if firstRound:
|
||||
output = self.aes.encrypt(IV, key, size)
|
||||
firstRound = False
|
||||
else:
|
||||
output = self.aes.encrypt(iput, key, size)
|
||||
for i in range(16):
|
||||
if len(plaintext) - 1 < i:
|
||||
ciphertext[i] = 0 ^ output[i]
|
||||
elif len(output) - 1 < i:
|
||||
ciphertext[i] = plaintext[i] ^ 0
|
||||
elif len(plaintext) - 1 < i and len(output) < i:
|
||||
ciphertext[i] = 0 ^ 0
|
||||
else:
|
||||
ciphertext[i] = plaintext[i] ^ output[i]
|
||||
for k in range(end - start):
|
||||
cipherOut.append(ciphertext[k])
|
||||
iput = ciphertext
|
||||
|
||||
elif mode == self.ModeOfOperation["OFB"]:
|
||||
if firstRound:
|
||||
output = self.aes.encrypt(IV, key, size)
|
||||
firstRound = False
|
||||
else:
|
||||
output = self.aes.encrypt(iput, key, size)
|
||||
for i in range(16):
|
||||
if len(plaintext) - 1 < i:
|
||||
ciphertext[i] = 0 ^ output[i]
|
||||
elif len(output) - 1 < i:
|
||||
ciphertext[i] = plaintext[i] ^ 0
|
||||
elif len(plaintext) - 1 < i and len(output) < i:
|
||||
ciphertext[i] = 0 ^ 0
|
||||
else:
|
||||
ciphertext[i] = plaintext[i] ^ output[i]
|
||||
for k in range(end - start):
|
||||
cipherOut.append(ciphertext[k])
|
||||
iput = output
|
||||
|
||||
elif mode == self.ModeOfOperation["CBC"]:
|
||||
for i in range(16):
|
||||
if firstRound:
|
||||
iput[i] = plaintext[i] ^ IV[i]
|
||||
else:
|
||||
iput[i] = plaintext[i] ^ ciphertext[i]
|
||||
firstRound = False
|
||||
ciphertext = self.aes.encrypt(iput, key, size)
|
||||
# Always 16 bytes because of the padding for CBC.
|
||||
for k in range(16):
|
||||
cipherOut.append(ciphertext[k])
|
||||
return mode, len(stringIn), cipherOut
|
||||
|
||||
|
||||
def decrypt(self, cipherIn, originalsize, mode, key, size, IV):
|
||||
""" Method to perform the decryption operation.
|
||||
|
||||
@param cipherIn: encrypted string to be decrypted
|
||||
@param originalsize: unencrypted string length (required for CBC)
|
||||
@param mode: mode of operation (0, 1 or 2)
|
||||
@param key: a number array of the bit length size
|
||||
@param size: the bit length of the key (16, 24 or 32)
|
||||
@param IV: the 128 bit number array initilization vector
|
||||
@return decrypted data
|
||||
"""
|
||||
if len(key) % size:
|
||||
raise ValueError("Illegal size ({}) for key '{}'.".format(size, key))
|
||||
if len(IV) % 16:
|
||||
raise ValueError("IV is not a multiple of 16.")
|
||||
# The AES input/output.
|
||||
ciphertext = []
|
||||
iput = []
|
||||
output = []
|
||||
plaintext = [0] * 16
|
||||
# The output plain text character list.
|
||||
chrOut = []
|
||||
|
||||
firstRound = True
|
||||
if cipherIn != None:
|
||||
for j in range(int(math.ceil(float(len(cipherIn))/16))):
|
||||
start = j * 16
|
||||
end = j * 16 + 16
|
||||
if end > len(cipherIn):
|
||||
end = len(cipherIn)
|
||||
ciphertext = cipherIn[start:end]
|
||||
|
||||
if mode == self.ModeOfOperation["CFB"]:
|
||||
if firstRound:
|
||||
output = self.aes.encrypt(IV, key, size)
|
||||
firstRound = False
|
||||
else:
|
||||
output = self.aes.encrypt(iput, key, size)
|
||||
for i in range(16):
|
||||
if len(output) - 1 < i:
|
||||
plaintext[i] = 0 ^ ciphertext[i]
|
||||
elif len(ciphertext) - 1 < i:
|
||||
plaintext[i] = output[i] ^ 0
|
||||
elif len(output) - 1 < i and len(ciphertext) < i:
|
||||
plaintext[i] = 0 ^ 0
|
||||
else:
|
||||
plaintext[i] = output[i] ^ ciphertext[i]
|
||||
for k in range(end - start):
|
||||
chrOut.append(plaintext[k])
|
||||
iput = ciphertext
|
||||
|
||||
elif mode == self.ModeOfOperation["OFB"]:
|
||||
if firstRound:
|
||||
output = self.aes.encrypt(IV, key, size)
|
||||
firstRound = False
|
||||
else:
|
||||
output = self.aes.encrypt(iput, key, size)
|
||||
for i in range(16):
|
||||
if len(output) - 1 < i:
|
||||
plaintext[i] = 0 ^ ciphertext[i]
|
||||
elif len(ciphertext) - 1 < i:
|
||||
plaintext[i] = output[i] ^ 0
|
||||
elif len(output) - 1 < i and len(ciphertext) < i:
|
||||
plaintext[i] = 0 ^ 0
|
||||
else:
|
||||
plaintext[i] = output[i] ^ ciphertext[i]
|
||||
for k in range(end - start):
|
||||
chrOut.append(plaintext[k])
|
||||
iput = output
|
||||
|
||||
elif mode == self.ModeOfOperation["CBC"]:
|
||||
output = self.aes.decrypt(ciphertext, key, size)
|
||||
for i in range(16):
|
||||
if firstRound:
|
||||
plaintext[i] = IV[i] ^ output[i]
|
||||
else:
|
||||
plaintext[i] = iput[i] ^ output[i]
|
||||
firstRound = False
|
||||
if originalsize is not None and originalsize < end:
|
||||
for k in range(originalsize - start):
|
||||
chrOut.append(plaintext[k])
|
||||
else:
|
||||
for k in range(end - start):
|
||||
chrOut.append(plaintext[k])
|
||||
iput = ciphertext
|
||||
return chrOut
|
||||
|
||||
|
||||
def encryptData(key, data, mode=AESModeOfOperation.ModeOfOperation["CBC"]):
|
||||
""" Module function to encrypt the given data with the given key.
|
||||
|
||||
@param key: key to be used for encryption
|
||||
@param data: data to be encrypted
|
||||
@param mode: mode of operations (0, 1 or 2)
|
||||
@return encrypted data prepended with the initialization vector
|
||||
"""
|
||||
if mode == AESModeOfOperation.ModeOfOperation["CBC"]:
|
||||
data = append_PKCS7_padding(data)
|
||||
|
||||
keysize = len(key)
|
||||
assert keysize in AES.KeySize.values(), 'invalid key size: {}'.format(keysize)
|
||||
# Create a new iv using random data.
|
||||
iv = bytearray(os.urandom(16))
|
||||
moo = AESModeOfOperation()
|
||||
(mode, length, ciph) = moo.encrypt(data, mode, key, keysize, iv)
|
||||
# With padding, the original length does not need to be known.
|
||||
# It's a bad idea to store the original message length prepend the iv.
|
||||
return iv + bytearray(ciph)
|
||||
|
||||
def decryptData(key, data, mode=AESModeOfOperation.ModeOfOperation["CBC"]):
|
||||
""" Module function to decrypt the given data with the given key.
|
||||
|
||||
@param key: key to be used for decryption
|
||||
@param data: data to be decrypted with initialization vector prepended
|
||||
@param mode: mode of operations (0, 1 or 2)
|
||||
@return decrypted data
|
||||
"""
|
||||
keysize = len(key)
|
||||
assert keysize in AES.KeySize.values(), 'invalid key size: {}'.format(keysize)
|
||||
# iv is first 16 bytes.
|
||||
iv = data[:16]
|
||||
data = data[16:]
|
||||
moo = AESModeOfOperation()
|
||||
decr = moo.decrypt(data, None, mode, key, keysize, iv)
|
||||
if mode == AESModeOfOperation.ModeOfOperation["CBC"]:
|
||||
decr = strip_PKCS7_padding(decr)
|
||||
return decr
|
||||
|
||||
|
||||
class Test(object):
|
||||
def generateRandomKey(self, keysize):
|
||||
""" Generates a key from random data of length `keysize`.
|
||||
The returned key is a string of bytes.
|
||||
"""
|
||||
if keysize not in (16, 24, 32):
|
||||
raise ValueError('Invalid keysize, %s. Should be one of (16, 24, 32).' % keysize)
|
||||
return bytearray(os.urandom(keysize))
|
||||
|
||||
def testString(self, cleartext, keysize = 16, modeName = "CBC"):
|
||||
""" Test with random key, choice of mode. """
|
||||
print('Random key test with Mode:', modeName)
|
||||
print('ClearText:', bytes(cleartext))
|
||||
key = self.generateRandomKey(keysize)
|
||||
print('Key:', bytes([x for x in key]))
|
||||
mode = AESModeOfOperation.ModeOfOperation[modeName]
|
||||
cipher = encryptData(key, cleartext, mode)
|
||||
print('Cipher:', bytes([x for x in cipher]))
|
||||
decr = decryptData(key, cipher, mode)
|
||||
print('Decrypted:', bytes(decr))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
moo = AESModeOfOperation()
|
||||
cleartext = "This is a test with several blocks ! Some utf-8 characters åäö and test continues"
|
||||
print('ClearText: %s\n' % cleartext)
|
||||
cleartext = bytearray(cleartext.encode("utf-8"))
|
||||
|
||||
cipherkey = [143, 194, 34, 208, 145, 203, 230, 143, 177, 246, 97, 206, 145, 92, 255, 84]
|
||||
iv = [103, 35, 148, 239, 76, 213, 47, 118, 255, 222, 123, 176, 106, 134, 98, 92]
|
||||
mode, orig_len, ciph = moo.encrypt(cleartext, moo.ModeOfOperation["CBC"],
|
||||
cipherkey, moo.aes.KeySize["SIZE_128"], iv)
|
||||
|
||||
print('Encrypt result: mode = %s, length = %s (%s), encrypted = %s\n' % (mode, orig_len, len(cleartext), bytes(ciph)))
|
||||
|
||||
decr = moo.decrypt(ciph, orig_len, mode, cipherkey, moo.aes.KeySize["SIZE_128"], iv)
|
||||
print('Decrypt result: %s\n' % bytes(decr))
|
||||
Test().testString(cleartext, 16, "CBC")
|
255
py-kms/pykms_Base.py
Normal file
255
py-kms/pykms_Base.py
Normal file
@ -0,0 +1,255 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import binascii
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import uuid
|
||||
import socket
|
||||
|
||||
from pykms_Structure import Structure
|
||||
from pykms_DB2Dict import kmsDB2Dict
|
||||
from pykms_PidGenerator import epidGenerator
|
||||
from pykms_Filetimes import filetime_to_dt
|
||||
from pykms_Sql import sql_initialize, sql_update, sql_update_epid
|
||||
from pykms_Format import justify, byterize, enco, deco, ShellMessage
|
||||
|
||||
#--------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
loggersrv = logging.getLogger('logsrv')
|
||||
|
||||
class UUID(Structure):
|
||||
commonHdr = ()
|
||||
structure = (
|
||||
('raw', '16s'),
|
||||
)
|
||||
|
||||
def get(self):
|
||||
return uuid.UUID(bytes_le = enco(str(self), 'latin-1'))
|
||||
|
||||
class kmsBase:
|
||||
def __init__(self, data, srv_config):
|
||||
self.data = data
|
||||
self.srv_config = srv_config
|
||||
|
||||
class kmsRequestStruct(Structure):
|
||||
commonHdr = ()
|
||||
structure = (
|
||||
('versionMinor', '<H'),
|
||||
('versionMajor', '<H'),
|
||||
('isClientVm', '<I'),
|
||||
('licenseStatus', '<I'),
|
||||
('graceTime', '<I'),
|
||||
('applicationId', ':', UUID),
|
||||
('skuId', ':', UUID),
|
||||
('kmsCountedId' , ':', UUID),
|
||||
('clientMachineId', ':', UUID),
|
||||
('requiredClientCount', '<I'),
|
||||
('requestTime', '<Q'),
|
||||
('previousClientMachineId', ':', UUID),
|
||||
('machineName', 'u'),
|
||||
('_mnPad', '_-mnPad', '126-len(machineName)'),
|
||||
('mnPad', ':'),
|
||||
)
|
||||
|
||||
def getMachineName(self):
|
||||
return self['machineName'].decode('utf-16le')
|
||||
|
||||
def getLicenseStatus(self):
|
||||
return kmsBase.licenseStates[self['licenseStatus']] or "Unknown"
|
||||
|
||||
class kmsResponseStruct(Structure):
|
||||
commonHdr = ()
|
||||
structure = (
|
||||
('versionMinor', '<H'),
|
||||
('versionMajor', '<H'),
|
||||
('epidLen', '<I=len(kmsEpid)+2'),
|
||||
('kmsEpid', 'u'),
|
||||
('clientMachineId', ':', UUID),
|
||||
('responseTime', '<Q'),
|
||||
('currentClientCount', '<I'),
|
||||
('vLActivationInterval', '<I'),
|
||||
('vLRenewalInterval', '<I'),
|
||||
)
|
||||
|
||||
class GenericRequestHeader(Structure):
|
||||
commonHdr = ()
|
||||
structure = (
|
||||
('bodyLength1', '<I'),
|
||||
('bodyLength2', '<I'),
|
||||
('versionMinor', '<H'),
|
||||
('versionMajor', '<H'),
|
||||
('remainder', '_'),
|
||||
)
|
||||
|
||||
licenseStates = {
|
||||
0 : "Unlicensed",
|
||||
1 : "Activated",
|
||||
2 : "Grace Period",
|
||||
3 : "Out-of-Tolerance Grace Period",
|
||||
4 : "Non-Genuine Grace Period",
|
||||
5 : "Notifications Mode",
|
||||
6 : "Extended Grace Period",
|
||||
}
|
||||
|
||||
licenseStatesEnum = {
|
||||
'unlicensed' : 0,
|
||||
'licensed' : 1,
|
||||
'oobGrace' : 2,
|
||||
'ootGrace' : 3,
|
||||
'nonGenuineGrace' : 4,
|
||||
'notification' : 5,
|
||||
'extendedGrace' : 6
|
||||
}
|
||||
|
||||
|
||||
def getPadding(self, bodyLength):
|
||||
## https://forums.mydigitallife.info/threads/71213-Source-C-KMS-Server-from-Microsoft-Toolkit?p=1277542&viewfull=1#post1277542
|
||||
return 4 + (((~bodyLength & 3) + 1) & 3)
|
||||
|
||||
def serverLogic(self, kmsRequest):
|
||||
if self.srv_config['sqlite'] and self.srv_config['dbSupport']:
|
||||
self.dbName = sql_initialize()
|
||||
|
||||
ShellMessage.Process(15).run()
|
||||
kmsRequest = byterize(kmsRequest)
|
||||
loggersrv.debug("KMS Request Bytes: \n%s\n" % justify(deco(binascii.b2a_hex(enco(str(kmsRequest), 'latin-1')), 'latin-1')))
|
||||
loggersrv.debug("KMS Request: \n%s\n" % justify(kmsRequest.dump(print_to_stdout = False)))
|
||||
|
||||
clientMachineId = kmsRequest['clientMachineId'].get()
|
||||
applicationId = kmsRequest['applicationId'].get()
|
||||
skuId = kmsRequest['skuId'].get()
|
||||
requestDatetime = filetime_to_dt(kmsRequest['requestTime'])
|
||||
|
||||
# Localize the request time, if module "tzlocal" is available.
|
||||
try:
|
||||
from tzlocal import get_localzone
|
||||
from pytz.exceptions import UnknownTimeZoneError
|
||||
try:
|
||||
tz = get_localzone()
|
||||
local_dt = tz.localize(requestDatetime)
|
||||
except UnknownTimeZoneError:
|
||||
loggersrv.warning('Unknown time zone ! Request time not localized.')
|
||||
local_dt = requestDatetime
|
||||
except ImportError:
|
||||
loggersrv.warning('Module "tzlocal" not available ! Request time not localized.')
|
||||
local_dt = requestDatetime
|
||||
|
||||
# Activation threshold.
|
||||
# https://docs.microsoft.com/en-us/windows/deployment/volume-activation/activate-windows-10-clients-vamt
|
||||
MinClients = kmsRequest['requiredClientCount']
|
||||
RequiredClients = MinClients * 2
|
||||
if self.srv_config["CurrentClientCount"] != None:
|
||||
if 0 < self.srv_config["CurrentClientCount"] < MinClients:
|
||||
# fixed to 6 (product server) or 26 (product desktop)
|
||||
currentClientCount = MinClients + 1
|
||||
loggersrv.warning("Not enough clients ! Fixed with %s, but activated client could be detected as not genuine !" %currentClientCount)
|
||||
elif MinClients <= self.srv_config["CurrentClientCount"] < RequiredClients:
|
||||
currentClientCount = self.srv_config["CurrentClientCount"]
|
||||
loggersrv.warning("With count = %s, activated client could be detected as not genuine !" %currentClientCount)
|
||||
elif self.srv_config["CurrentClientCount"] >= RequiredClients:
|
||||
# fixed to 10 (product server) or 50 (product desktop)
|
||||
currentClientCount = RequiredClients
|
||||
if self.srv_config["CurrentClientCount"] > RequiredClients:
|
||||
loggersrv.warning("Too many clients ! Fixed with %s" %currentClientCount)
|
||||
else:
|
||||
# fixed to 10 (product server) or 50 (product desktop)
|
||||
currentClientCount = RequiredClients
|
||||
|
||||
|
||||
# Get a name for SkuId, AppId.
|
||||
kmsdb = kmsDB2Dict()
|
||||
|
||||
appitems = kmsdb[2]
|
||||
for appitem in appitems:
|
||||
kmsitems = appitem['KmsItems']
|
||||
for kmsitem in kmsitems:
|
||||
skuitems = kmsitem['SkuItems']
|
||||
for skuitem in skuitems:
|
||||
try:
|
||||
if uuid.UUID(skuitem['Id']) == skuId:
|
||||
skuName = skuitem['DisplayName']
|
||||
break
|
||||
except:
|
||||
skuName = skuId
|
||||
loggersrv.warning("Can't find a name for this product !!")
|
||||
|
||||
try:
|
||||
if uuid.UUID(appitem['Id']) == applicationId:
|
||||
appName = appitem['DisplayName']
|
||||
except:
|
||||
appName = applicationId
|
||||
loggersrv.warning("Can't find a name for this application group !!")
|
||||
|
||||
infoDict = {
|
||||
"machineName" : kmsRequest.getMachineName(),
|
||||
"clientMachineId" : str(clientMachineId),
|
||||
"appId" : appName,
|
||||
"skuId" : skuName,
|
||||
"licenseStatus" : kmsRequest.getLicenseStatus(),
|
||||
"requestTime" : int(time.time()),
|
||||
"kmsEpid" : None
|
||||
}
|
||||
|
||||
loggersrv.info("Machine Name: %s" % infoDict["machineName"])
|
||||
loggersrv.info("Client Machine ID: %s" % infoDict["clientMachineId"])
|
||||
loggersrv.info("Application ID: %s" % infoDict["appId"])
|
||||
loggersrv.info("SKU ID: %s" % infoDict["skuId"])
|
||||
loggersrv.info("License Status: %s" % infoDict["licenseStatus"])
|
||||
loggersrv.info("Request Time: %s" % local_dt.strftime('%Y-%m-%d %H:%M:%S %Z (UTC%z)'))
|
||||
loggersrv.mini("", extra = {'host': socket.gethostname() + " [" + self.srv_config["ip"] + "]",
|
||||
'status' : infoDict["licenseStatus"],
|
||||
'product' : infoDict["skuId"]})
|
||||
|
||||
if self.srv_config['sqlite'] and self.srv_config['dbSupport']:
|
||||
sql_update(self.dbName, infoDict)
|
||||
|
||||
return self.createKmsResponse(kmsRequest, currentClientCount)
|
||||
|
||||
def createKmsResponse(self, kmsRequest, currentClientCount):
|
||||
response = self.kmsResponseStruct()
|
||||
response['versionMinor'] = kmsRequest['versionMinor']
|
||||
response['versionMajor'] = kmsRequest['versionMajor']
|
||||
|
||||
if not self.srv_config["epid"]:
|
||||
response["kmsEpid"] = epidGenerator(kmsRequest['kmsCountedId'].get(), kmsRequest['versionMajor'],
|
||||
self.srv_config["lcid"]).encode('utf-16le')
|
||||
else:
|
||||
response["kmsEpid"] = self.srv_config["epid"].encode('utf-16le')
|
||||
|
||||
response['clientMachineId'] = kmsRequest['clientMachineId']
|
||||
# rule: timeserver - 4h <= timeclient <= timeserver + 4h, check if is satisfied.
|
||||
response['responseTime'] = kmsRequest['requestTime']
|
||||
response['currentClientCount'] = currentClientCount
|
||||
response['vLActivationInterval'] = self.srv_config["VLActivationInterval"]
|
||||
response['vLRenewalInterval'] = self.srv_config["VLRenewalInterval"]
|
||||
|
||||
if self.srv_config['sqlite'] and self.srv_config['dbSupport']:
|
||||
response = sql_update_epid(self.dbName, kmsRequest, response)
|
||||
|
||||
loggersrv.info("Server ePID: %s" % response["kmsEpid"].decode('utf-16le'))
|
||||
|
||||
return response
|
||||
|
||||
|
||||
import pykms_RequestV4, pykms_RequestV5, pykms_RequestV6, pykms_RequestUnknown
|
||||
|
||||
def generateKmsResponseData(data, srv_config):
|
||||
version = kmsBase.GenericRequestHeader(data)['versionMajor']
|
||||
currentDate = time.strftime("%a %b %d %H:%M:%S %Y")
|
||||
|
||||
if version == 4:
|
||||
loggersrv.info("Received V%d request on %s." % (version, currentDate))
|
||||
messagehandler = pykms_RequestV4.kmsRequestV4(data, srv_config)
|
||||
elif version == 5:
|
||||
loggersrv.info("Received V%d request on %s." % (version, currentDate))
|
||||
messagehandler = pykms_RequestV5.kmsRequestV5(data, srv_config)
|
||||
elif version == 6:
|
||||
loggersrv.info("Received V%d request on %s." % (version, currentDate))
|
||||
messagehandler = pykms_RequestV6.kmsRequestV6(data, srv_config)
|
||||
else:
|
||||
loggersrv.info("Unhandled KMS version V%d." % version)
|
||||
messagehandler = pykms_RequestUnknown.kmsRequestUnknown(data, srv_config)
|
||||
|
||||
return messagehandler.executeRequestLogic()
|
266
py-kms/pykms_Client.py
Normal file
266
py-kms/pykms_Client.py
Normal file
@ -0,0 +1,266 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import re
|
||||
import argparse
|
||||
import binascii
|
||||
import datetime
|
||||
import random
|
||||
import socket
|
||||
import string
|
||||
import sys
|
||||
import uuid
|
||||
import logging
|
||||
import os
|
||||
import errno
|
||||
|
||||
import pykms_RpcBind, pykms_RpcRequest
|
||||
from pykms_Filetimes import dt_to_filetime
|
||||
from pykms_Dcerpc import MSRPCHeader, MSRPCBindNak, MSRPCRequestHeader, MSRPCRespHeader
|
||||
from pykms_Base import kmsBase, UUID
|
||||
from pykms_RequestV4 import kmsRequestV4
|
||||
from pykms_RequestV5 import kmsRequestV5
|
||||
from pykms_RequestV6 import kmsRequestV6
|
||||
from pykms_RpcBase import rpcBase
|
||||
from pykms_DB2Dict import kmsDB2Dict
|
||||
from pykms_Misc import logger_create
|
||||
from pykms_Format import justify, byterize, enco, deco, ShellMessage
|
||||
|
||||
clt_description = 'KMS Client Emulator written in Python'
|
||||
clt_version = 'py-kms_2019-05-15'
|
||||
clt_config = {}
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
loggerclt = logging.getLogger('logclt')
|
||||
|
||||
# 'help' string - 'default' value - 'dest' string.
|
||||
clt_options = {
|
||||
'ip' : {'help' : 'The IP address or hostname of the KMS server.', 'def' : "0.0.0.0", 'des' : "ip"},
|
||||
'port' : {'help' : 'The port the KMS service is listening on. The default is \"1688\".', 'def' : 1688, 'des' : "port"},
|
||||
'mode' : {'help' : 'Use this flag to manually specify a Microsoft product for testing the server. The default is \"Windows81\"',
|
||||
'def' : "Windows8.1", 'des' : "mode",
|
||||
'choi' : ["WindowsVista","Windows7","Windows8","Windows8.1","Windows10","Office2010","Office2013","Office2016","Office2019"]},
|
||||
'cmid' : {'help' : 'Use this flag to manually specify a CMID to use. If no CMID is specified, a random CMID will be generated.',
|
||||
'def' : None, 'des' : "cmid"},
|
||||
'name' : {'help' : 'Use this flag to manually specify an ASCII machineName to use. If no machineName is specified a random machineName \
|
||||
will be generated.', 'def' : None, 'des' : "machineName"},
|
||||
'llevel' : {'help' : 'Use this option to set a log level. The default is \"ERROR\".', 'def' : "ERROR", 'des' : "loglevel",
|
||||
'choi' : ["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG", "MINI"]},
|
||||
'lfile' : {'help' : 'Use this option to set an output log file. The default is \"pykms_logclient.log\" or type \"STDOUT\" to view log info on stdout.',
|
||||
'def' : os.path.dirname(os.path.abspath( __file__ )) + "/pykms_logclient.log", 'des' : "logfile"},
|
||||
'lsize' : {'help' : 'Use this flag to set a maximum size (in MB) to the output log file. Desactivated by default.', 'def' : 0, 'des': "logsize"},
|
||||
}
|
||||
|
||||
def client_options():
|
||||
parser = argparse.ArgumentParser(description = clt_description, epilog = 'version: ' + clt_version)
|
||||
parser.add_argument("ip", nargs = "?", action = "store", default = clt_options['ip']['def'], help = clt_options['ip']['help'], type = str)
|
||||
parser.add_argument("port", nargs = "?", action = "store", default = clt_options['port']['def'], help = clt_options['port']['help'], type = int)
|
||||
parser.add_argument("-m", "--mode", dest = clt_options['mode']['des'], default = clt_options['mode']['def'], choices = clt_options['mode']['choi'],
|
||||
help = clt_options['mode']['help'], type = str)
|
||||
parser.add_argument("-c", "--cmid", dest = clt_options['cmid']['des'], default = clt_options['cmid']['def'], help = clt_options['cmid']['help'], type = str)
|
||||
parser.add_argument("-n", "--name", dest = clt_options['name']['des'] , default = clt_options['name']['def'], help = clt_options['name']['help'], type = str)
|
||||
parser.add_argument("-V", "--loglevel", dest = clt_options['llevel']['des'], action = "store", choices = clt_options['llevel']['choi'],
|
||||
default = clt_options['llevel']['def'], help = clt_options['llevel']['help'], type = str)
|
||||
parser.add_argument("-F", "--logfile", dest = clt_options['lfile']['des'], action = "store", default = clt_options['lfile']['def'],
|
||||
help = clt_options['lfile']['help'], type = str)
|
||||
parser.add_argument("-S", "--logsize", dest = clt_options['lsize']['des'], action = "store", default = clt_options['lsize']['def'],
|
||||
help = clt_options['lsize']['help'], type = float)
|
||||
|
||||
clt_config.update(vars(parser.parse_args()))
|
||||
|
||||
|
||||
def client_check():
|
||||
# Setup hidden or not messages.
|
||||
ShellMessage.view = ( False if clt_config['logfile'] == 'STDOUT' else True )
|
||||
# Create log.
|
||||
logger_create(loggerclt, clt_config, mode = 'a')
|
||||
|
||||
# Check cmid.
|
||||
if clt_config['cmid'] is not None:
|
||||
try:
|
||||
uuid.UUID(clt_config['cmid'])
|
||||
except ValueError:
|
||||
loggerclt.error("Bad CMID. Exiting...")
|
||||
sys.exit()
|
||||
|
||||
# Check machineName.
|
||||
if clt_config['machineName'] is not None:
|
||||
if len(clt_config['machineName']) < 2 or len(clt_config['machineName']) > 63:
|
||||
loggerclt.error("machineName must be between 2 and 63 characters in length.")
|
||||
sys.exit()
|
||||
|
||||
clt_config['call_id'] = 1
|
||||
|
||||
|
||||
def client_update():
|
||||
kmsdb = kmsDB2Dict()
|
||||
|
||||
appitems = kmsdb[2]
|
||||
for appitem in appitems:
|
||||
kmsitems = appitem['KmsItems']
|
||||
for kmsitem in kmsitems:
|
||||
name = re.sub('\(.*\)', '', kmsitem['DisplayName']).replace('2015', '').replace(' ', '')
|
||||
if name == clt_config['mode']:
|
||||
skuitems = kmsitem['SkuItems']
|
||||
# Select 'Enterprise' for Windows or 'Professional Plus' for Office.
|
||||
for skuitem in skuitems:
|
||||
if skuitem['DisplayName'].replace(' ','') == name + 'Enterprise' or \
|
||||
skuitem['DisplayName'].replace(' ','') == name[:6] + 'ProfessionalPlus' + name[6:]:
|
||||
|
||||
clt_config['KMSClientSkuID'] = skuitem['Id']
|
||||
clt_config['RequiredClientCount'] = int(kmsitem['NCountPolicy'])
|
||||
clt_config['KMSProtocolMajorVersion'] = int(float(kmsitem['DefaultKmsProtocol']))
|
||||
clt_config['KMSProtocolMinorVersion'] = 0
|
||||
clt_config['KMSClientLicenseStatus'] = 2
|
||||
clt_config['KMSClientAppID'] = appitem['Id']
|
||||
clt_config['KMSClientKMSCountedID'] = kmsitem['Id']
|
||||
break
|
||||
|
||||
def client_create():
|
||||
loggerclt.info("\n\nConnecting to %s on port %d..." % (clt_config['ip'], clt_config['port']))
|
||||
s = socket.create_connection((clt_config['ip'], clt_config['port']))
|
||||
loggerclt.info("Connection successful !")
|
||||
binder = pykms_RpcBind.handler(None, clt_config)
|
||||
RPC_Bind = enco(str(binder.generateRequest()), 'latin-1')
|
||||
loggerclt.info("Sending RPC bind request...")
|
||||
ShellMessage.Process([-1, 1]).run()
|
||||
s.send(RPC_Bind)
|
||||
try:
|
||||
ShellMessage.Process([-4, 7]).run()
|
||||
bindResponse = s.recv(1024)
|
||||
except socket.error as e:
|
||||
if e.errno == errno.ECONNRESET:
|
||||
loggerclt.error("Connection reset by peer. Exiting...")
|
||||
sys.exit()
|
||||
else:
|
||||
raise
|
||||
if bindResponse == '' or not bindResponse:
|
||||
loggerclt.error("No data received ! Exiting...")
|
||||
sys.exit()
|
||||
packetType = MSRPCHeader(bindResponse)['type']
|
||||
if packetType == rpcBase.packetType['bindAck']:
|
||||
loggerclt.info("RPC bind acknowledged.")
|
||||
ShellMessage.Process(8).run()
|
||||
kmsRequest = createKmsRequest()
|
||||
requester = pykms_RpcRequest.handler(kmsRequest, clt_config)
|
||||
s.send(enco(str(requester.generateRequest()), 'latin-1'))
|
||||
ShellMessage.Process([-1, 12]).run()
|
||||
response = s.recv(1024)
|
||||
loggerclt.debug("Response: \n%s\n" % justify(deco(binascii.b2a_hex(response), 'latin-1')))
|
||||
ShellMessage.Process([-4, 20]).run()
|
||||
parsed = MSRPCRespHeader(response)
|
||||
kmsData = readKmsResponse(parsed['pduData'], kmsRequest, clt_config)
|
||||
kmsResp = kmsData['response']
|
||||
|
||||
try:
|
||||
hwid = kmsData['hwid']
|
||||
loggerclt.info("KMS Host HWID: %s" % deco(binascii.b2a_hex(enco(hwid, 'latin-1')).upper(), 'utf-8'))
|
||||
except KeyError:
|
||||
pass
|
||||
loggerclt.info("KMS Host ePID: %s" % kmsResp['kmsEpid'].encode('utf-8').decode('utf-16le'))
|
||||
loggerclt.info("KMS Host Current Client Count: %s" % kmsResp['currentClientCount'])
|
||||
loggerclt.info("KMS VL Activation Interval: %s" % kmsResp['vLActivationInterval'])
|
||||
loggerclt.info("KMS VL Renewal Interval: %s" % kmsResp['vLRenewalInterval'])
|
||||
loggerclt.mini("", extra = {'host': socket.gethostname() + " [" + clt_config["ip"] + "]",
|
||||
'status' : "Activated",
|
||||
'product' : clt_config["mode"]})
|
||||
|
||||
ShellMessage.Process(21).run()
|
||||
|
||||
elif packetType == rpcBase.packetType['bindNak']:
|
||||
loggerclt.info(justify(MSRPCBindNak(bindResponse).dump(print_to_stdout = False)))
|
||||
sys.exit()
|
||||
else:
|
||||
loggerclt.critical("Something went wrong.")
|
||||
sys.exit()
|
||||
|
||||
|
||||
def clt_main(with_gui = False):
|
||||
if not with_gui:
|
||||
# Parse options.
|
||||
client_options()
|
||||
|
||||
# Check options.
|
||||
client_check()
|
||||
# Update Config.
|
||||
client_update()
|
||||
# Create and run client.
|
||||
client_create()
|
||||
|
||||
def createKmsRequestBase():
|
||||
requestDict = kmsBase.kmsRequestStruct()
|
||||
requestDict['versionMinor'] = clt_config['KMSProtocolMinorVersion']
|
||||
requestDict['versionMajor'] = clt_config['KMSProtocolMajorVersion']
|
||||
requestDict['isClientVm'] = 0
|
||||
requestDict['licenseStatus'] = clt_config['KMSClientLicenseStatus']
|
||||
requestDict['graceTime'] = 43200
|
||||
requestDict['applicationId'] = UUID(uuid.UUID(clt_config['KMSClientAppID']).bytes_le)
|
||||
requestDict['skuId'] = UUID(uuid.UUID(clt_config['KMSClientSkuID']).bytes_le)
|
||||
requestDict['kmsCountedId'] = UUID(uuid.UUID(clt_config['KMSClientKMSCountedID']).bytes_le)
|
||||
requestDict['clientMachineId'] = UUID(uuid.UUID(clt_config['cmid']).bytes_le if (clt_config['cmid'] is not None) else uuid.uuid4().bytes_le)
|
||||
requestDict['previousClientMachineId'] = '\0' * 16 # I'm pretty sure this is supposed to be a null UUID.
|
||||
requestDict['requiredClientCount'] = clt_config['RequiredClientCount']
|
||||
requestDict['requestTime'] = dt_to_filetime(datetime.datetime.utcnow())
|
||||
requestDict['machineName'] = (clt_config['machineName'] if (clt_config['machineName'] is not None) else
|
||||
''.join(random.choice(string.ascii_letters + string.digits) for i in range(random.randint(2,63)))).encode('utf-16le')
|
||||
requestDict['mnPad'] = '\0'.encode('utf-16le') * (63 - len(requestDict['machineName'].decode('utf-16le')))
|
||||
|
||||
# Debug Stuff
|
||||
ShellMessage.Process(9).run()
|
||||
requestDict = byterize(requestDict)
|
||||
loggerclt.debug("Request Base Dictionary: \n%s\n" % justify(requestDict.dump(print_to_stdout = False)))
|
||||
|
||||
return requestDict
|
||||
|
||||
def createKmsRequest():
|
||||
# Update the call ID
|
||||
clt_config['call_id'] += 1
|
||||
|
||||
# KMS Protocol Major Version
|
||||
if clt_config['KMSProtocolMajorVersion'] == 4:
|
||||
handler = kmsRequestV4(None, clt_config)
|
||||
elif clt_config['KMSProtocolMajorVersion'] == 5:
|
||||
handler = kmsRequestV5(None, clt_config)
|
||||
elif clt_config['KMSProtocolMajorVersion'] == 6:
|
||||
handler = kmsRequestV6(None, clt_config)
|
||||
else:
|
||||
return None
|
||||
|
||||
requestBase = createKmsRequestBase()
|
||||
return handler.generateRequest(requestBase)
|
||||
|
||||
def readKmsResponse(data, request, clt_config):
|
||||
if clt_config['KMSProtocolMajorVersion'] == 4:
|
||||
loggerclt.info("Received V4 response")
|
||||
response = readKmsResponseV4(data, request)
|
||||
elif clt_config['KMSProtocolMajorVersion'] == 5:
|
||||
loggerclt.info("Received V5 response")
|
||||
response = readKmsResponseV5(data)
|
||||
elif clt_config['KMSProtocolMajorVersion'] == 6:
|
||||
loggerclt.info("Received V6 response")
|
||||
response = readKmsResponseV6(data)
|
||||
else:
|
||||
loggerclt.info("Unhandled response version: %d.%d" % (clt_config['KMSProtocolMajorVersion'], clt_config['KMSProtocolMinorVersion']))
|
||||
loggerclt.info("I'm not even sure how this happened...")
|
||||
return response
|
||||
|
||||
def readKmsResponseV4(data, request):
|
||||
response = kmsRequestV4.ResponseV4(data)
|
||||
hashed = kmsRequestV4(data, clt_config).generateHash(bytearray(enco(str(response['response']) , 'latin-1')))
|
||||
if deco(hashed, 'latin-1') == response['hash']:
|
||||
loggerclt.info("Response Hash has expected value !")
|
||||
return response
|
||||
|
||||
def readKmsResponseV5(data):
|
||||
response = kmsRequestV5.ResponseV5(data)
|
||||
decrypted = kmsRequestV5(data, clt_config).decryptResponse(response)
|
||||
return decrypted
|
||||
|
||||
def readKmsResponseV6(data):
|
||||
response = kmsRequestV6.ResponseV5(data)
|
||||
decrypted = kmsRequestV6(data, clt_config).decryptResponse(response)
|
||||
message = decrypted['message']
|
||||
return message
|
||||
|
||||
if __name__ == "__main__":
|
||||
clt_main(with_gui = False)
|
47
py-kms/pykms_DB2Dict.py
Normal file
47
py-kms/pykms_DB2Dict.py
Normal file
@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def kmsDB2Dict():
|
||||
path = os.path.join(os.path.dirname(__file__), 'KmsDataBase.xml')
|
||||
root = ET.parse(path).getroot()
|
||||
|
||||
kmsdb, child1, child2, child3 = [ [] for _ in range(4) ]
|
||||
|
||||
## Get winbuilds.
|
||||
for winbuild in root.iter('WinBuild'):
|
||||
child1.append(winbuild.attrib)
|
||||
|
||||
kmsdb.append(child1)
|
||||
|
||||
## Get csvlkitem data.
|
||||
child1 = []
|
||||
for csvlk in root.iter('CsvlkItem'):
|
||||
for activ in csvlk.iter('Activate'):
|
||||
child2.append(activ.attrib['KmsItem'])
|
||||
csvlk.attrib.update({'Activate' : child2})
|
||||
child1.append(csvlk.attrib)
|
||||
child2 = []
|
||||
|
||||
kmsdb.append(child1)
|
||||
|
||||
## Get appitem data.
|
||||
child1 = []
|
||||
for app in root.iter('AppItem'):
|
||||
for kms in app.iter('KmsItem'):
|
||||
for sku in kms.iter('SkuItem'):
|
||||
child3.append(sku.attrib)
|
||||
kms.attrib.update({'SkuItems' : child3})
|
||||
child2.append(kms.attrib)
|
||||
child3 = []
|
||||
|
||||
app.attrib.update({'KmsItems' : child2})
|
||||
child1.append(app.attrib)
|
||||
child2 = []
|
||||
|
||||
kmsdb.append(child1)
|
||||
|
||||
return kmsdb
|
731
py-kms/pykms_Dcerpc.py
Normal file
731
py-kms/pykms_Dcerpc.py
Normal file
@ -0,0 +1,731 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved.
|
||||
#
|
||||
# This software is provided under under a slightly modified version
|
||||
# of the Apache Software License. See the accompanying LICENSE file
|
||||
# for more information.
|
||||
#
|
||||
# Description:
|
||||
# Partial C706.pdf + [MS-RPCE] implementation
|
||||
#
|
||||
# Best way to learn how to use these calls is to grab the protocol standard
|
||||
# so you understand what the call does, and then read the test case located
|
||||
# at https://github.com/SecureAuthCorp/impacket/tree/master/tests/SMB_RPC
|
||||
#
|
||||
# ToDo:
|
||||
# [ ] Take out all the security provider stuff out of here (e.g. RPC_C_AUTHN_WINNT)
|
||||
# and put it elsewhere. This will make the coder cleaner and easier to add
|
||||
# more SSP (e.g. NETLOGON)
|
||||
#
|
||||
"""
|
||||
Stripped down version of:
|
||||
https://github.com/SecureAuthCorp/impacket/blob/master/impacket/dcerpc/v5/rpcrt.py
|
||||
"""
|
||||
|
||||
from pykms_Structure import Structure
|
||||
|
||||
# MS/RPC Constants
|
||||
MSRPC_REQUEST = 0x00
|
||||
MSRPC_PING = 0x01
|
||||
MSRPC_RESPONSE = 0x02
|
||||
MSRPC_FAULT = 0x03
|
||||
MSRPC_WORKING = 0x04
|
||||
MSRPC_NOCALL = 0x05
|
||||
MSRPC_REJECT = 0x06
|
||||
MSRPC_ACK = 0x07
|
||||
MSRPC_CL_CANCEL = 0x08
|
||||
MSRPC_FACK = 0x09
|
||||
MSRPC_CANCELACK = 0x0A
|
||||
MSRPC_BIND = 0x0B
|
||||
MSRPC_BINDACK = 0x0C
|
||||
MSRPC_BINDNAK = 0x0D
|
||||
MSRPC_ALTERCTX = 0x0E
|
||||
MSRPC_ALTERCTX_R= 0x0F
|
||||
MSRPC_AUTH3 = 0x10
|
||||
MSRPC_SHUTDOWN = 0x11
|
||||
MSRPC_CO_CANCEL = 0x12
|
||||
MSRPC_ORPHANED = 0x13
|
||||
|
||||
# MS/RPC Packet Flags
|
||||
PFC_FIRST_FRAG = 0x01
|
||||
PFC_LAST_FRAG = 0x02
|
||||
|
||||
# For PDU types bind, bind_ack, alter_context, and
|
||||
# alter_context_resp, this flag MUST be interpreted as PFC_SUPPORT_HEADER_SIGN
|
||||
MSRPC_SUPPORT_SIGN = 0x04
|
||||
|
||||
#For the
|
||||
#remaining PDU types, this flag MUST be interpreted as PFC_PENDING_CANCEL.
|
||||
MSRPC_PENDING_CANCEL= 0x04
|
||||
|
||||
PFC_RESERVED_1 = 0x08
|
||||
PFC_CONC_MPX = 0x10
|
||||
PFC_DID_NOT_EXECUTE = 0x20
|
||||
PFC_MAYBE = 0x40
|
||||
PFC_OBJECT_UUID = 0x80
|
||||
|
||||
# Auth Types - Security Providers
|
||||
RPC_C_AUTHN_NONE = 0x00
|
||||
RPC_C_AUTHN_GSS_NEGOTIATE = 0x09
|
||||
RPC_C_AUTHN_WINNT = 0x0A
|
||||
RPC_C_AUTHN_GSS_SCHANNEL = 0x0E
|
||||
RPC_C_AUTHN_GSS_KERBEROS = 0x10
|
||||
RPC_C_AUTHN_NETLOGON = 0x44
|
||||
RPC_C_AUTHN_DEFAULT = 0xFF
|
||||
|
||||
# Auth Levels
|
||||
RPC_C_AUTHN_LEVEL_NONE = 1
|
||||
RPC_C_AUTHN_LEVEL_CONNECT = 2
|
||||
RPC_C_AUTHN_LEVEL_CALL = 3
|
||||
RPC_C_AUTHN_LEVEL_PKT = 4
|
||||
RPC_C_AUTHN_LEVEL_PKT_INTEGRITY = 5
|
||||
RPC_C_AUTHN_LEVEL_PKT_PRIVACY = 6
|
||||
|
||||
#Reasons for rejection of a context element, included in bind_ack result reason
|
||||
rpc_provider_reason = {
|
||||
0 : 'reason_not_specified',
|
||||
1 : 'abstract_syntax_not_supported',
|
||||
2 : 'proposed_transfer_syntaxes_not_supported',
|
||||
3 : 'local_limit_exceeded',
|
||||
4 : 'protocol_version_not_specified',
|
||||
8 : 'authentication_type_not_recognized',
|
||||
9 : 'invalid_checksum'
|
||||
}
|
||||
|
||||
MSRPC_CONT_RESULT_ACCEPT = 0
|
||||
MSRPC_CONT_RESULT_USER_REJECT = 1
|
||||
MSRPC_CONT_RESULT_PROV_REJECT = 2
|
||||
|
||||
#Results of a presentation context negotiation
|
||||
rpc_cont_def_result = {
|
||||
0 : 'acceptance',
|
||||
1 : 'user_rejection',
|
||||
2 : 'provider_rejection'
|
||||
}
|
||||
|
||||
#status codes, references:
|
||||
#https://docs.microsoft.com/windows/desktop/Rpc/rpc-return-values
|
||||
#https://msdn.microsoft.com/library/default.asp?url=/library/en-us/randz/protocol/common_return_values.asp
|
||||
#winerror.h
|
||||
#https://www.opengroup.org/onlinepubs/9629399/apdxn.htm
|
||||
|
||||
rpc_status_codes = {
|
||||
0x00000005 : 'rpc_s_access_denied',
|
||||
0x00000008 : 'Authentication type not recognized',
|
||||
0x000006D8 : 'rpc_fault_cant_perform',
|
||||
0x000006C6 : 'rpc_x_invalid_bound', # the arrays bound are invalid
|
||||
0x000006E4 : 'rpc_s_cannot_support: The requested operation is not supported.', # some operation is not supported
|
||||
0x000006F7 : 'rpc_x_bad_stub_data', # the stub data is invalid, doesn't match with the IDL definition
|
||||
0x1C010001 : 'nca_s_comm_failure', # unable to get response from server:
|
||||
0x1C010002 : 'nca_s_op_rng_error', # bad operation number in call
|
||||
0x1C010003 : 'nca_s_unk_if', # unknown interface
|
||||
0x1C010006 : 'nca_s_wrong_boot_time', # client passed server wrong server boot time
|
||||
0x1C010009 : 'nca_s_you_crashed', # a restarted server called back a client
|
||||
0x1C01000B : 'nca_s_proto_error', # someone messed up the protocol
|
||||
0x1C010013 : 'nca_s_out_args_too_big ', # output args too big
|
||||
0x1C010014 : 'nca_s_server_too_busy', # server is too busy to handle call
|
||||
0x1C010015 : 'nca_s_fault_string_too_long', # string argument longer than declared max len
|
||||
0x1C010017 : 'nca_s_unsupported_type ', # no implementation of generic operation for object
|
||||
0x1C000001 : 'nca_s_fault_int_div_by_zero',
|
||||
0x1C000002 : 'nca_s_fault_addr_error ',
|
||||
0x1C000003 : 'nca_s_fault_fp_div_zero',
|
||||
0x1C000004 : 'nca_s_fault_fp_underflow',
|
||||
0x1C000005 : 'nca_s_fault_fp_overflow',
|
||||
0x1C000006 : 'nca_s_fault_invalid_tag',
|
||||
0x1C000007 : 'nca_s_fault_invalid_bound ',
|
||||
0x1C000008 : 'nca_s_rpc_version_mismatch',
|
||||
0x1C000009 : 'nca_s_unspec_reject ',
|
||||
0x1C00000A : 'nca_s_bad_actid',
|
||||
0x1C00000B : 'nca_s_who_are_you_failed',
|
||||
0x1C00000C : 'nca_s_manager_not_entered ',
|
||||
0x1C00000D : 'nca_s_fault_cancel',
|
||||
0x1C00000E : 'nca_s_fault_ill_inst',
|
||||
0x1C00000F : 'nca_s_fault_fp_error',
|
||||
0x1C000010 : 'nca_s_fault_int_overflow',
|
||||
0x1C000012 : 'nca_s_fault_unspec',
|
||||
0x1C000013 : 'nca_s_fault_remote_comm_failure ',
|
||||
0x1C000014 : 'nca_s_fault_pipe_empty ',
|
||||
0x1C000015 : 'nca_s_fault_pipe_closed',
|
||||
0x1C000016 : 'nca_s_fault_pipe_order ',
|
||||
0x1C000017 : 'nca_s_fault_pipe_discipline',
|
||||
0x1C000018 : 'nca_s_fault_pipe_comm_error',
|
||||
0x1C000019 : 'nca_s_fault_pipe_memory',
|
||||
0x1C00001A : 'nca_s_fault_context_mismatch ',
|
||||
0x1C00001B : 'nca_s_fault_remote_no_memory ',
|
||||
0x1C00001C : 'nca_s_invalid_pres_context_id',
|
||||
0x1C00001D : 'nca_s_unsupported_authn_level',
|
||||
0x1C00001F : 'nca_s_invalid_checksum ',
|
||||
0x1C000020 : 'nca_s_invalid_crc',
|
||||
0x1C000021 : 'nca_s_fault_user_defined',
|
||||
0x1C000022 : 'nca_s_fault_tx_open_failed',
|
||||
0x1C000023 : 'nca_s_fault_codeset_conv_error',
|
||||
0x1C000024 : 'nca_s_fault_object_not_found ',
|
||||
0x1C000025 : 'nca_s_fault_no_client_stub',
|
||||
0x16c9a000 : "rpc_s_mod",
|
||||
0x16c9a001 : "rpc_s_op_rng_error",
|
||||
0x16c9a002 : "rpc_s_cant_create_socket",
|
||||
0x16c9a003 : "rpc_s_cant_bind_socket",
|
||||
0x16c9a004 : "rpc_s_not_in_call",
|
||||
0x16c9a005 : "rpc_s_no_port",
|
||||
0x16c9a006 : "rpc_s_wrong_boot_time",
|
||||
0x16c9a007 : "rpc_s_too_many_sockets",
|
||||
0x16c9a008 : "rpc_s_illegal_register",
|
||||
0x16c9a009 : "rpc_s_cant_recv",
|
||||
0x16c9a00a : "rpc_s_bad_pkt",
|
||||
0x16c9a00b : "rpc_s_unbound_handle",
|
||||
0x16c9a00c : "rpc_s_addr_in_use",
|
||||
0x16c9a00d : "rpc_s_in_args_too_big",
|
||||
0x16c9a00e : "rpc_s_string_too_long",
|
||||
0x16c9a00f : "rpc_s_too_many_objects",
|
||||
0x16c9a010 : "rpc_s_binding_has_no_auth",
|
||||
0x16c9a011 : "rpc_s_unknown_authn_service",
|
||||
0x16c9a012 : "rpc_s_no_memory",
|
||||
0x16c9a013 : "rpc_s_cant_nmalloc",
|
||||
0x16c9a014 : "rpc_s_call_faulted",
|
||||
0x16c9a015 : "rpc_s_call_failed",
|
||||
0x16c9a016 : "rpc_s_comm_failure",
|
||||
0x16c9a017 : "rpc_s_rpcd_comm_failure",
|
||||
0x16c9a018 : "rpc_s_illegal_family_rebind",
|
||||
0x16c9a019 : "rpc_s_invalid_handle",
|
||||
0x16c9a01a : "rpc_s_coding_error",
|
||||
0x16c9a01b : "rpc_s_object_not_found",
|
||||
0x16c9a01c : "rpc_s_cthread_not_found",
|
||||
0x16c9a01d : "rpc_s_invalid_binding",
|
||||
0x16c9a01e : "rpc_s_already_registered",
|
||||
0x16c9a01f : "rpc_s_endpoint_not_found",
|
||||
0x16c9a020 : "rpc_s_invalid_rpc_protseq",
|
||||
0x16c9a021 : "rpc_s_desc_not_registered",
|
||||
0x16c9a022 : "rpc_s_already_listening",
|
||||
0x16c9a023 : "rpc_s_no_protseqs",
|
||||
0x16c9a024 : "rpc_s_no_protseqs_registered",
|
||||
0x16c9a025 : "rpc_s_no_bindings",
|
||||
0x16c9a026 : "rpc_s_max_descs_exceeded",
|
||||
0x16c9a027 : "rpc_s_no_interfaces",
|
||||
0x16c9a028 : "rpc_s_invalid_timeout",
|
||||
0x16c9a029 : "rpc_s_cant_inq_socket",
|
||||
0x16c9a02a : "rpc_s_invalid_naf_id",
|
||||
0x16c9a02b : "rpc_s_inval_net_addr",
|
||||
0x16c9a02c : "rpc_s_unknown_if",
|
||||
0x16c9a02d : "rpc_s_unsupported_type",
|
||||
0x16c9a02e : "rpc_s_invalid_call_opt",
|
||||
0x16c9a02f : "rpc_s_no_fault",
|
||||
0x16c9a030 : "rpc_s_cancel_timeout",
|
||||
0x16c9a031 : "rpc_s_call_cancelled",
|
||||
0x16c9a032 : "rpc_s_invalid_call_handle",
|
||||
0x16c9a033 : "rpc_s_cannot_alloc_assoc",
|
||||
0x16c9a034 : "rpc_s_cannot_connect",
|
||||
0x16c9a035 : "rpc_s_connection_aborted",
|
||||
0x16c9a036 : "rpc_s_connection_closed",
|
||||
0x16c9a037 : "rpc_s_cannot_accept",
|
||||
0x16c9a038 : "rpc_s_assoc_grp_not_found",
|
||||
0x16c9a039 : "rpc_s_stub_interface_error",
|
||||
0x16c9a03a : "rpc_s_invalid_object",
|
||||
0x16c9a03b : "rpc_s_invalid_type",
|
||||
0x16c9a03c : "rpc_s_invalid_if_opnum",
|
||||
0x16c9a03d : "rpc_s_different_server_instance",
|
||||
0x16c9a03e : "rpc_s_protocol_error",
|
||||
0x16c9a03f : "rpc_s_cant_recvmsg",
|
||||
0x16c9a040 : "rpc_s_invalid_string_binding",
|
||||
0x16c9a041 : "rpc_s_connect_timed_out",
|
||||
0x16c9a042 : "rpc_s_connect_rejected",
|
||||
0x16c9a043 : "rpc_s_network_unreachable",
|
||||
0x16c9a044 : "rpc_s_connect_no_resources",
|
||||
0x16c9a045 : "rpc_s_rem_network_shutdown",
|
||||
0x16c9a046 : "rpc_s_too_many_rem_connects",
|
||||
0x16c9a047 : "rpc_s_no_rem_endpoint",
|
||||
0x16c9a048 : "rpc_s_rem_host_down",
|
||||
0x16c9a049 : "rpc_s_host_unreachable",
|
||||
0x16c9a04a : "rpc_s_access_control_info_inv",
|
||||
0x16c9a04b : "rpc_s_loc_connect_aborted",
|
||||
0x16c9a04c : "rpc_s_connect_closed_by_rem",
|
||||
0x16c9a04d : "rpc_s_rem_host_crashed",
|
||||
0x16c9a04e : "rpc_s_invalid_endpoint_format",
|
||||
0x16c9a04f : "rpc_s_unknown_status_code",
|
||||
0x16c9a050 : "rpc_s_unknown_mgr_type",
|
||||
0x16c9a051 : "rpc_s_assoc_creation_failed",
|
||||
0x16c9a052 : "rpc_s_assoc_grp_max_exceeded",
|
||||
0x16c9a053 : "rpc_s_assoc_grp_alloc_failed",
|
||||
0x16c9a054 : "rpc_s_sm_invalid_state",
|
||||
0x16c9a055 : "rpc_s_assoc_req_rejected",
|
||||
0x16c9a056 : "rpc_s_assoc_shutdown",
|
||||
0x16c9a057 : "rpc_s_tsyntaxes_unsupported",
|
||||
0x16c9a058 : "rpc_s_context_id_not_found",
|
||||
0x16c9a059 : "rpc_s_cant_listen_socket",
|
||||
0x16c9a05a : "rpc_s_no_addrs",
|
||||
0x16c9a05b : "rpc_s_cant_getpeername",
|
||||
0x16c9a05c : "rpc_s_cant_get_if_id",
|
||||
0x16c9a05d : "rpc_s_protseq_not_supported",
|
||||
0x16c9a05e : "rpc_s_call_orphaned",
|
||||
0x16c9a05f : "rpc_s_who_are_you_failed",
|
||||
0x16c9a060 : "rpc_s_unknown_reject",
|
||||
0x16c9a061 : "rpc_s_type_already_registered",
|
||||
0x16c9a062 : "rpc_s_stop_listening_disabled",
|
||||
0x16c9a063 : "rpc_s_invalid_arg",
|
||||
0x16c9a064 : "rpc_s_not_supported",
|
||||
0x16c9a065 : "rpc_s_wrong_kind_of_binding",
|
||||
0x16c9a066 : "rpc_s_authn_authz_mismatch",
|
||||
0x16c9a067 : "rpc_s_call_queued",
|
||||
0x16c9a068 : "rpc_s_cannot_set_nodelay",
|
||||
0x16c9a069 : "rpc_s_not_rpc_tower",
|
||||
0x16c9a06a : "rpc_s_invalid_rpc_protid",
|
||||
0x16c9a06b : "rpc_s_invalid_rpc_floor",
|
||||
0x16c9a06c : "rpc_s_call_timeout",
|
||||
0x16c9a06d : "rpc_s_mgmt_op_disallowed",
|
||||
0x16c9a06e : "rpc_s_manager_not_entered",
|
||||
0x16c9a06f : "rpc_s_calls_too_large_for_wk_ep",
|
||||
0x16c9a070 : "rpc_s_server_too_busy",
|
||||
0x16c9a071 : "rpc_s_prot_version_mismatch",
|
||||
0x16c9a072 : "rpc_s_rpc_prot_version_mismatch",
|
||||
0x16c9a073 : "rpc_s_ss_no_import_cursor",
|
||||
0x16c9a074 : "rpc_s_fault_addr_error",
|
||||
0x16c9a075 : "rpc_s_fault_context_mismatch",
|
||||
0x16c9a076 : "rpc_s_fault_fp_div_by_zero",
|
||||
0x16c9a077 : "rpc_s_fault_fp_error",
|
||||
0x16c9a078 : "rpc_s_fault_fp_overflow",
|
||||
0x16c9a079 : "rpc_s_fault_fp_underflow",
|
||||
0x16c9a07a : "rpc_s_fault_ill_inst",
|
||||
0x16c9a07b : "rpc_s_fault_int_div_by_zero",
|
||||
0x16c9a07c : "rpc_s_fault_int_overflow",
|
||||
0x16c9a07d : "rpc_s_fault_invalid_bound",
|
||||
0x16c9a07e : "rpc_s_fault_invalid_tag",
|
||||
0x16c9a07f : "rpc_s_fault_pipe_closed",
|
||||
0x16c9a080 : "rpc_s_fault_pipe_comm_error",
|
||||
0x16c9a081 : "rpc_s_fault_pipe_discipline",
|
||||
0x16c9a082 : "rpc_s_fault_pipe_empty",
|
||||
0x16c9a083 : "rpc_s_fault_pipe_memory",
|
||||
0x16c9a084 : "rpc_s_fault_pipe_order",
|
||||
0x16c9a085 : "rpc_s_fault_remote_comm_failure",
|
||||
0x16c9a086 : "rpc_s_fault_remote_no_memory",
|
||||
0x16c9a087 : "rpc_s_fault_unspec",
|
||||
0x16c9a088 : "uuid_s_bad_version",
|
||||
0x16c9a089 : "uuid_s_socket_failure",
|
||||
0x16c9a08a : "uuid_s_getconf_failure",
|
||||
0x16c9a08b : "uuid_s_no_address",
|
||||
0x16c9a08c : "uuid_s_overrun",
|
||||
0x16c9a08d : "uuid_s_internal_error",
|
||||
0x16c9a08e : "uuid_s_coding_error",
|
||||
0x16c9a08f : "uuid_s_invalid_string_uuid",
|
||||
0x16c9a090 : "uuid_s_no_memory",
|
||||
0x16c9a091 : "rpc_s_no_more_entries",
|
||||
0x16c9a092 : "rpc_s_unknown_ns_error",
|
||||
0x16c9a093 : "rpc_s_name_service_unavailable",
|
||||
0x16c9a094 : "rpc_s_incomplete_name",
|
||||
0x16c9a095 : "rpc_s_group_not_found",
|
||||
0x16c9a096 : "rpc_s_invalid_name_syntax",
|
||||
0x16c9a097 : "rpc_s_no_more_members",
|
||||
0x16c9a098 : "rpc_s_no_more_interfaces",
|
||||
0x16c9a099 : "rpc_s_invalid_name_service",
|
||||
0x16c9a09a : "rpc_s_no_name_mapping",
|
||||
0x16c9a09b : "rpc_s_profile_not_found",
|
||||
0x16c9a09c : "rpc_s_not_found",
|
||||
0x16c9a09d : "rpc_s_no_updates",
|
||||
0x16c9a09e : "rpc_s_update_failed",
|
||||
0x16c9a09f : "rpc_s_no_match_exported",
|
||||
0x16c9a0a0 : "rpc_s_entry_not_found",
|
||||
0x16c9a0a1 : "rpc_s_invalid_inquiry_context",
|
||||
0x16c9a0a2 : "rpc_s_interface_not_found",
|
||||
0x16c9a0a3 : "rpc_s_group_member_not_found",
|
||||
0x16c9a0a4 : "rpc_s_entry_already_exists",
|
||||
0x16c9a0a5 : "rpc_s_nsinit_failure",
|
||||
0x16c9a0a6 : "rpc_s_unsupported_name_syntax",
|
||||
0x16c9a0a7 : "rpc_s_no_more_elements",
|
||||
0x16c9a0a8 : "rpc_s_no_ns_permission",
|
||||
0x16c9a0a9 : "rpc_s_invalid_inquiry_type",
|
||||
0x16c9a0aa : "rpc_s_profile_element_not_found",
|
||||
0x16c9a0ab : "rpc_s_profile_element_replaced",
|
||||
0x16c9a0ac : "rpc_s_import_already_done",
|
||||
0x16c9a0ad : "rpc_s_database_busy",
|
||||
0x16c9a0ae : "rpc_s_invalid_import_context",
|
||||
0x16c9a0af : "rpc_s_uuid_set_not_found",
|
||||
0x16c9a0b0 : "rpc_s_uuid_member_not_found",
|
||||
0x16c9a0b1 : "rpc_s_no_interfaces_exported",
|
||||
0x16c9a0b2 : "rpc_s_tower_set_not_found",
|
||||
0x16c9a0b3 : "rpc_s_tower_member_not_found",
|
||||
0x16c9a0b4 : "rpc_s_obj_uuid_not_found",
|
||||
0x16c9a0b5 : "rpc_s_no_more_bindings",
|
||||
0x16c9a0b6 : "rpc_s_invalid_priority",
|
||||
0x16c9a0b7 : "rpc_s_not_rpc_entry",
|
||||
0x16c9a0b8 : "rpc_s_invalid_lookup_context",
|
||||
0x16c9a0b9 : "rpc_s_binding_vector_full",
|
||||
0x16c9a0ba : "rpc_s_cycle_detected",
|
||||
0x16c9a0bb : "rpc_s_nothing_to_export",
|
||||
0x16c9a0bc : "rpc_s_nothing_to_unexport",
|
||||
0x16c9a0bd : "rpc_s_invalid_vers_option",
|
||||
0x16c9a0be : "rpc_s_no_rpc_data",
|
||||
0x16c9a0bf : "rpc_s_mbr_picked",
|
||||
0x16c9a0c0 : "rpc_s_not_all_objs_unexported",
|
||||
0x16c9a0c1 : "rpc_s_no_entry_name",
|
||||
0x16c9a0c2 : "rpc_s_priority_group_done",
|
||||
0x16c9a0c3 : "rpc_s_partial_results",
|
||||
0x16c9a0c4 : "rpc_s_no_env_setup",
|
||||
0x16c9a0c5 : "twr_s_unknown_sa",
|
||||
0x16c9a0c6 : "twr_s_unknown_tower",
|
||||
0x16c9a0c7 : "twr_s_not_implemented",
|
||||
0x16c9a0c8 : "rpc_s_max_calls_too_small",
|
||||
0x16c9a0c9 : "rpc_s_cthread_create_failed",
|
||||
0x16c9a0ca : "rpc_s_cthread_pool_exists",
|
||||
0x16c9a0cb : "rpc_s_cthread_no_such_pool",
|
||||
0x16c9a0cc : "rpc_s_cthread_invoke_disabled",
|
||||
0x16c9a0cd : "ept_s_cant_perform_op",
|
||||
0x16c9a0ce : "ept_s_no_memory",
|
||||
0x16c9a0cf : "ept_s_database_invalid",
|
||||
0x16c9a0d0 : "ept_s_cant_create",
|
||||
0x16c9a0d1 : "ept_s_cant_access",
|
||||
0x16c9a0d2 : "ept_s_database_already_open",
|
||||
0x16c9a0d3 : "ept_s_invalid_entry",
|
||||
0x16c9a0d4 : "ept_s_update_failed",
|
||||
0x16c9a0d5 : "ept_s_invalid_context",
|
||||
0x16c9a0d6 : "ept_s_not_registered",
|
||||
0x16c9a0d7 : "ept_s_server_unavailable",
|
||||
0x16c9a0d8 : "rpc_s_underspecified_name",
|
||||
0x16c9a0d9 : "rpc_s_invalid_ns_handle",
|
||||
0x16c9a0da : "rpc_s_unknown_error",
|
||||
0x16c9a0db : "rpc_s_ss_char_trans_open_fail",
|
||||
0x16c9a0dc : "rpc_s_ss_char_trans_short_file",
|
||||
0x16c9a0dd : "rpc_s_ss_context_damaged",
|
||||
0x16c9a0de : "rpc_s_ss_in_null_context",
|
||||
0x16c9a0df : "rpc_s_socket_failure",
|
||||
0x16c9a0e0 : "rpc_s_unsupported_protect_level",
|
||||
0x16c9a0e1 : "rpc_s_invalid_checksum",
|
||||
0x16c9a0e2 : "rpc_s_invalid_credentials",
|
||||
0x16c9a0e3 : "rpc_s_credentials_too_large",
|
||||
0x16c9a0e4 : "rpc_s_call_id_not_found",
|
||||
0x16c9a0e5 : "rpc_s_key_id_not_found",
|
||||
0x16c9a0e6 : "rpc_s_auth_bad_integrity",
|
||||
0x16c9a0e7 : "rpc_s_auth_tkt_expired",
|
||||
0x16c9a0e8 : "rpc_s_auth_tkt_nyv",
|
||||
0x16c9a0e9 : "rpc_s_auth_repeat",
|
||||
0x16c9a0ea : "rpc_s_auth_not_us",
|
||||
0x16c9a0eb : "rpc_s_auth_badmatch",
|
||||
0x16c9a0ec : "rpc_s_auth_skew",
|
||||
0x16c9a0ed : "rpc_s_auth_badaddr",
|
||||
0x16c9a0ee : "rpc_s_auth_badversion",
|
||||
0x16c9a0ef : "rpc_s_auth_msg_type",
|
||||
0x16c9a0f0 : "rpc_s_auth_modified",
|
||||
0x16c9a0f1 : "rpc_s_auth_badorder",
|
||||
0x16c9a0f2 : "rpc_s_auth_badkeyver",
|
||||
0x16c9a0f3 : "rpc_s_auth_nokey",
|
||||
0x16c9a0f4 : "rpc_s_auth_mut_fail",
|
||||
0x16c9a0f5 : "rpc_s_auth_baddirection",
|
||||
0x16c9a0f6 : "rpc_s_auth_method",
|
||||
0x16c9a0f7 : "rpc_s_auth_badseq",
|
||||
0x16c9a0f8 : "rpc_s_auth_inapp_cksum",
|
||||
0x16c9a0f9 : "rpc_s_auth_field_toolong",
|
||||
0x16c9a0fa : "rpc_s_invalid_crc",
|
||||
0x16c9a0fb : "rpc_s_binding_incomplete",
|
||||
0x16c9a0fc : "rpc_s_key_func_not_allowed",
|
||||
0x16c9a0fd : "rpc_s_unknown_stub_rtl_if_vers",
|
||||
0x16c9a0fe : "rpc_s_unknown_ifspec_vers",
|
||||
0x16c9a0ff : "rpc_s_proto_unsupp_by_auth",
|
||||
0x16c9a100 : "rpc_s_authn_challenge_malformed",
|
||||
0x16c9a101 : "rpc_s_protect_level_mismatch",
|
||||
0x16c9a102 : "rpc_s_no_mepv",
|
||||
0x16c9a103 : "rpc_s_stub_protocol_error",
|
||||
0x16c9a104 : "rpc_s_class_version_mismatch",
|
||||
0x16c9a105 : "rpc_s_helper_not_running",
|
||||
0x16c9a106 : "rpc_s_helper_short_read",
|
||||
0x16c9a107 : "rpc_s_helper_catatonic",
|
||||
0x16c9a108 : "rpc_s_helper_aborted",
|
||||
0x16c9a109 : "rpc_s_not_in_kernel",
|
||||
0x16c9a10a : "rpc_s_helper_wrong_user",
|
||||
0x16c9a10b : "rpc_s_helper_overflow",
|
||||
0x16c9a10c : "rpc_s_dg_need_way_auth",
|
||||
0x16c9a10d : "rpc_s_unsupported_auth_subtype",
|
||||
0x16c9a10e : "rpc_s_wrong_pickle_type",
|
||||
0x16c9a10f : "rpc_s_not_listening",
|
||||
0x16c9a110 : "rpc_s_ss_bad_buffer",
|
||||
0x16c9a111 : "rpc_s_ss_bad_es_action",
|
||||
0x16c9a112 : "rpc_s_ss_wrong_es_version",
|
||||
0x16c9a113 : "rpc_s_fault_user_defined",
|
||||
0x16c9a114 : "rpc_s_ss_incompatible_codesets",
|
||||
0x16c9a115 : "rpc_s_tx_not_in_transaction",
|
||||
0x16c9a116 : "rpc_s_tx_open_failed",
|
||||
0x16c9a117 : "rpc_s_partial_credentials",
|
||||
0x16c9a118 : "rpc_s_ss_invalid_codeset_tag",
|
||||
0x16c9a119 : "rpc_s_mgmt_bad_type",
|
||||
0x16c9a11a : "rpc_s_ss_invalid_char_input",
|
||||
0x16c9a11b : "rpc_s_ss_short_conv_buffer",
|
||||
0x16c9a11c : "rpc_s_ss_iconv_error",
|
||||
0x16c9a11d : "rpc_s_ss_no_compat_codeset",
|
||||
0x16c9a11e : "rpc_s_ss_no_compat_charsets",
|
||||
0x16c9a11f : "dce_cs_c_ok",
|
||||
0x16c9a120 : "dce_cs_c_unknown",
|
||||
0x16c9a121 : "dce_cs_c_notfound",
|
||||
0x16c9a122 : "dce_cs_c_cannot_open_file",
|
||||
0x16c9a123 : "dce_cs_c_cannot_read_file",
|
||||
0x16c9a124 : "dce_cs_c_cannot_allocate_memory",
|
||||
0x16c9a125 : "rpc_s_ss_cleanup_failed",
|
||||
0x16c9a126 : "rpc_svc_desc_general",
|
||||
0x16c9a127 : "rpc_svc_desc_mutex",
|
||||
0x16c9a128 : "rpc_svc_desc_xmit",
|
||||
0x16c9a129 : "rpc_svc_desc_recv",
|
||||
0x16c9a12a : "rpc_svc_desc_dg_state",
|
||||
0x16c9a12b : "rpc_svc_desc_cancel",
|
||||
0x16c9a12c : "rpc_svc_desc_orphan",
|
||||
0x16c9a12d : "rpc_svc_desc_cn_state",
|
||||
0x16c9a12e : "rpc_svc_desc_cn_pkt",
|
||||
0x16c9a12f : "rpc_svc_desc_pkt_quotas",
|
||||
0x16c9a130 : "rpc_svc_desc_auth",
|
||||
0x16c9a131 : "rpc_svc_desc_source",
|
||||
0x16c9a132 : "rpc_svc_desc_stats",
|
||||
0x16c9a133 : "rpc_svc_desc_mem",
|
||||
0x16c9a134 : "rpc_svc_desc_mem_type",
|
||||
0x16c9a135 : "rpc_svc_desc_dg_pktlog",
|
||||
0x16c9a136 : "rpc_svc_desc_thread_id",
|
||||
0x16c9a137 : "rpc_svc_desc_timestamp",
|
||||
0x16c9a138 : "rpc_svc_desc_cn_errors",
|
||||
0x16c9a139 : "rpc_svc_desc_conv_thread",
|
||||
0x16c9a13a : "rpc_svc_desc_pid",
|
||||
0x16c9a13b : "rpc_svc_desc_atfork",
|
||||
0x16c9a13c : "rpc_svc_desc_cma_thread",
|
||||
0x16c9a13d : "rpc_svc_desc_inherit",
|
||||
0x16c9a13e : "rpc_svc_desc_dg_sockets",
|
||||
0x16c9a13f : "rpc_svc_desc_timer",
|
||||
0x16c9a140 : "rpc_svc_desc_threads",
|
||||
0x16c9a141 : "rpc_svc_desc_server_call",
|
||||
0x16c9a142 : "rpc_svc_desc_nsi",
|
||||
0x16c9a143 : "rpc_svc_desc_dg_pkt",
|
||||
0x16c9a144 : "rpc_m_cn_ill_state_trans_sa",
|
||||
0x16c9a145 : "rpc_m_cn_ill_state_trans_ca",
|
||||
0x16c9a146 : "rpc_m_cn_ill_state_trans_sg",
|
||||
0x16c9a147 : "rpc_m_cn_ill_state_trans_cg",
|
||||
0x16c9a148 : "rpc_m_cn_ill_state_trans_sr",
|
||||
0x16c9a149 : "rpc_m_cn_ill_state_trans_cr",
|
||||
0x16c9a14a : "rpc_m_bad_pkt_type",
|
||||
0x16c9a14b : "rpc_m_prot_mismatch",
|
||||
0x16c9a14c : "rpc_m_frag_toobig",
|
||||
0x16c9a14d : "rpc_m_unsupp_stub_rtl_if",
|
||||
0x16c9a14e : "rpc_m_unhandled_callstate",
|
||||
0x16c9a14f : "rpc_m_call_failed",
|
||||
0x16c9a150 : "rpc_m_call_failed_no_status",
|
||||
0x16c9a151 : "rpc_m_call_failed_errno",
|
||||
0x16c9a152 : "rpc_m_call_failed_s",
|
||||
0x16c9a153 : "rpc_m_call_failed_c",
|
||||
0x16c9a154 : "rpc_m_errmsg_toobig",
|
||||
0x16c9a155 : "rpc_m_invalid_srchattr",
|
||||
0x16c9a156 : "rpc_m_nts_not_found",
|
||||
0x16c9a157 : "rpc_m_invalid_accbytcnt",
|
||||
0x16c9a158 : "rpc_m_pre_v2_ifspec",
|
||||
0x16c9a159 : "rpc_m_unk_ifspec",
|
||||
0x16c9a15a : "rpc_m_recvbuf_toosmall",
|
||||
0x16c9a15b : "rpc_m_unalign_authtrl",
|
||||
0x16c9a15c : "rpc_m_unexpected_exc",
|
||||
0x16c9a15d : "rpc_m_no_stub_data",
|
||||
0x16c9a15e : "rpc_m_eventlist_full",
|
||||
0x16c9a15f : "rpc_m_unk_sock_type",
|
||||
0x16c9a160 : "rpc_m_unimp_call",
|
||||
0x16c9a161 : "rpc_m_invalid_seqnum",
|
||||
0x16c9a162 : "rpc_m_cant_create_uuid",
|
||||
0x16c9a163 : "rpc_m_pre_v2_ss",
|
||||
0x16c9a164 : "rpc_m_dgpkt_pool_corrupt",
|
||||
0x16c9a165 : "rpc_m_dgpkt_bad_free",
|
||||
0x16c9a166 : "rpc_m_lookaside_corrupt",
|
||||
0x16c9a167 : "rpc_m_alloc_fail",
|
||||
0x16c9a168 : "rpc_m_realloc_fail",
|
||||
0x16c9a169 : "rpc_m_cant_open_file",
|
||||
0x16c9a16a : "rpc_m_cant_read_addr",
|
||||
0x16c9a16b : "rpc_svc_desc_libidl",
|
||||
0x16c9a16c : "rpc_m_ctxrundown_nomem",
|
||||
0x16c9a16d : "rpc_m_ctxrundown_exc",
|
||||
0x16c9a16e : "rpc_s_fault_codeset_conv_error",
|
||||
0x16c9a16f : "rpc_s_no_call_active",
|
||||
0x16c9a170 : "rpc_s_cannot_support",
|
||||
0x16c9a171 : "rpc_s_no_context_available",
|
||||
}
|
||||
|
||||
# Context Item
|
||||
class CtxItem(Structure):
|
||||
structure = (
|
||||
('ContextID','<H=0'),
|
||||
('TransItems','B=0'),
|
||||
('Pad','B=0'),
|
||||
('AbstractSyntax','20s=""'),
|
||||
('TransferSyntax','20s=""'),
|
||||
)
|
||||
|
||||
class CtxItemResult(Structure):
|
||||
structure = (
|
||||
('Result','<H=0'),
|
||||
('Reason','<H=0'),
|
||||
('TransferSyntax','20s=""'),
|
||||
)
|
||||
|
||||
class SEC_TRAILER(Structure):
|
||||
commonHdr = (
|
||||
('auth_type', 'B=10'),
|
||||
('auth_level','B=0'),
|
||||
('auth_pad_len','B=0'),
|
||||
('auth_rsvrd','B=0'),
|
||||
('auth_ctx_id','<L=747920'),
|
||||
)
|
||||
|
||||
class MSRPCHeader(Structure):
|
||||
_SIZE = 16
|
||||
commonHdr = (
|
||||
('ver_major','B=5'), # 0
|
||||
('ver_minor','B=0'), # 1
|
||||
('type','B=0'), # 2
|
||||
('flags','B=0'), # 3
|
||||
('representation','<L=0x10'), # 4
|
||||
('frag_len','<H=self._SIZE+len(auth_data)+(16 if (self["flags"] & 0x80) > 0 else 0)+len(pduData)+len(pad)+len(sec_trailer)'), # 8
|
||||
('auth_len','<H=len(auth_data)'), # 10
|
||||
('call_id','<L=1'), # 12 <-- Common up to here (including this)
|
||||
)
|
||||
|
||||
structure = (
|
||||
('dataLen','_-pduData','self["frag_len"]-self["auth_len"]-self._SIZE-(8 if self["auth_len"] > 0 else 0)'),
|
||||
('pduData',':'),
|
||||
('_pad', '_-pad','(4 - ((self._SIZE + (16 if (self["flags"] & 0x80) > 0 else 0) + len(self["pduData"])) & 3) & 3)'),
|
||||
('pad', ':'),
|
||||
('_sec_trailer', '_-sec_trailer', '8 if self["auth_len"] > 0 else 0'),
|
||||
('sec_trailer',':'),
|
||||
('auth_dataLen','_-auth_data','self["auth_len"]'),
|
||||
('auth_data',':'),
|
||||
)
|
||||
|
||||
def __init__(self, data = None, alignment = 0):
|
||||
Structure.__init__(self,data, alignment)
|
||||
if data is None:
|
||||
self['ver_major'] = 5
|
||||
self['ver_minor'] = 0
|
||||
self['flags'] = PFC_FIRST_FRAG | PFC_LAST_FRAG
|
||||
self['type'] = MSRPC_REQUEST
|
||||
self.__frag_len_set = 0
|
||||
self['auth_len'] = 0
|
||||
self['pduData'] = b''
|
||||
self['auth_data'] = b''
|
||||
self['sec_trailer'] = b''
|
||||
self['pad'] = b''
|
||||
|
||||
def get_header_size(self):
|
||||
return self._SIZE + (16 if (self["flags"] & PFC_OBJECT_UUID) > 0 else 0)
|
||||
|
||||
def get_packet(self):
|
||||
if self['auth_data'] != b'':
|
||||
self['auth_len'] = len(self['auth_data'])
|
||||
# The sec_trailer structure MUST be 4-byte aligned with respect to
|
||||
# the beginning of the PDU. Padding octets MUST be used to align the
|
||||
# sec_trailer structure if its natural beginning is not already 4-byte aligned
|
||||
##self['pad'] = '\xAA' * (4 - ((self._SIZE + len(self['pduData'])) & 3) & 3)
|
||||
|
||||
return self.getData()
|
||||
|
||||
class MSRPCRequestHeader(MSRPCHeader):
|
||||
_SIZE = 24
|
||||
commonHdr = MSRPCHeader.commonHdr + (
|
||||
('alloc_hint','<L=0'), # 16
|
||||
('ctx_id','<H=0'), # 20
|
||||
('op_num','<H=0'), # 22
|
||||
('_uuid','_-uuid','16 if self["flags"] & 0x80 > 0 else 0' ), # 22
|
||||
('uuid',':'), # 22
|
||||
)
|
||||
|
||||
def __init__(self, data = None, alignment = 0):
|
||||
MSRPCHeader.__init__(self, data, alignment)
|
||||
if data is None:
|
||||
self['type'] = MSRPC_REQUEST
|
||||
self['ctx_id'] = 0
|
||||
self['uuid'] = b''
|
||||
|
||||
class MSRPCRespHeader(MSRPCHeader):
|
||||
_SIZE = 24
|
||||
commonHdr = MSRPCHeader.commonHdr + (
|
||||
('alloc_hint','<L=0'), # 16
|
||||
('ctx_id','<H=0'), # 20
|
||||
('cancel_count','<B=0'), # 22
|
||||
('padding','<B=0'), # 23
|
||||
)
|
||||
|
||||
def __init__(self, aBuffer = None, alignment = 0):
|
||||
MSRPCHeader.__init__(self, aBuffer, alignment)
|
||||
if aBuffer is None:
|
||||
self['type'] = MSRPC_RESPONSE
|
||||
self['ctx_id'] = 0
|
||||
|
||||
class MSRPCBind(Structure):
|
||||
_CTX_ITEM_LEN = len(CtxItem())
|
||||
structure = (
|
||||
('max_tfrag','<H=4280'),
|
||||
('max_rfrag','<H=4280'),
|
||||
('assoc_group','<L=0'),
|
||||
('ctx_num','B=0'),
|
||||
('Reserved','B=0'),
|
||||
('Reserved2','<H=0'),
|
||||
('_ctx_items', '_-ctx_items', 'self["ctx_num"]*self._CTX_ITEM_LEN'),
|
||||
('ctx_items',':'),
|
||||
)
|
||||
|
||||
def __init__(self, data = None, alignment = 0):
|
||||
Structure.__init__(self, data, alignment)
|
||||
if data is None:
|
||||
self['max_tfrag'] = 4280
|
||||
self['max_rfrag'] = 4280
|
||||
self['assoc_group'] = 0
|
||||
self['ctx_num'] = 1
|
||||
self['ctx_items'] = b''
|
||||
self.__ctx_items = []
|
||||
|
||||
def addCtxItem(self, item):
|
||||
self.__ctx_items.append(item)
|
||||
|
||||
def getData(self):
|
||||
self['ctx_num'] = len(self.__ctx_items)
|
||||
for i in self.__ctx_items:
|
||||
self['ctx_items'] += i.getData()
|
||||
return Structure.getData(self)
|
||||
|
||||
class MSRPCBindAck(MSRPCHeader):
|
||||
_SIZE = 26 # Up to SecondaryAddr
|
||||
_CTX_ITEM_LEN = len(CtxItemResult())
|
||||
structure = (
|
||||
('max_tfrag','<H=0'),
|
||||
('max_rfrag','<H=0'),
|
||||
('assoc_group','<L=0'),
|
||||
('SecondaryAddrLen','<H&SecondaryAddr'),
|
||||
('SecondaryAddr','z'), # Optional if SecondaryAddrLen == 0
|
||||
('PadLen','_-Pad','(4-((self["SecondaryAddrLen"]+self._SIZE) % 4))%4'),
|
||||
('Pad',':'),
|
||||
('ctx_num','B=0'),
|
||||
('Reserved','B=0'),
|
||||
('Reserved2','<H=0'),
|
||||
('_ctx_items','_-ctx_items','self["ctx_num"]*self._CTX_ITEM_LEN'),
|
||||
('ctx_items',':'),
|
||||
('_sec_trailer', '_-sec_trailer', '8 if self["auth_len"] > 0 else 0'),
|
||||
('sec_trailer',':'),
|
||||
('auth_dataLen','_-auth_data','self["auth_len"]'),
|
||||
('auth_data',':'),
|
||||
)
|
||||
def __init__(self, data = None, alignment = 0):
|
||||
self.__ctx_items = []
|
||||
MSRPCHeader.__init__(self,data,alignment)
|
||||
if data is None:
|
||||
self['Pad'] = b''
|
||||
self['ctx_items'] = b''
|
||||
self['sec_trailer'] = b''
|
||||
self['auth_data'] = b''
|
||||
|
||||
def getCtxItems(self):
|
||||
return self.__ctx_items
|
||||
|
||||
def getCtxItem(self,index):
|
||||
return self.__ctx_items[index-1]
|
||||
|
||||
def fromString(self, data):
|
||||
Structure.fromString(self,data)
|
||||
# Parse the ctx_items
|
||||
data = self['ctx_items']
|
||||
for i in range(self['ctx_num']):
|
||||
item = CtxItemResult(data)
|
||||
self.__ctx_items.append(item)
|
||||
data = data[len(item):]
|
||||
|
||||
class MSRPCBindNak(Structure):
|
||||
structure = (
|
||||
('RejectedReason','<H=0'),
|
||||
('SupportedVersions',':'),
|
||||
)
|
||||
def __init__(self, data = None, alignment = 0):
|
||||
Structure.__init__(self,data,alignment)
|
||||
if data is None:
|
||||
self['SupportedVersions'] = b''
|
105
py-kms/pykms_Filetimes.py
Normal file
105
py-kms/pykms_Filetimes.py
Normal file
@ -0,0 +1,105 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (c) 2009, David Buxton <david@gasmark6.com>
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
"""Tools to convert between Python datetime instances and Microsoft times.
|
||||
"""
|
||||
from datetime import datetime, timedelta, tzinfo
|
||||
from calendar import timegm
|
||||
|
||||
|
||||
# http://support.microsoft.com/kb/167296
|
||||
# How To Convert a UNIX time_t to a Win32 FILETIME or SYSTEMTIME
|
||||
EPOCH_AS_FILETIME = 116444736000000000 # January 1, 1970 as MS file time
|
||||
HUNDREDS_OF_NANOSECONDS = 10000000
|
||||
|
||||
|
||||
ZERO = timedelta(0)
|
||||
HOUR = timedelta(hours=1)
|
||||
|
||||
|
||||
class UTC(tzinfo):
|
||||
"""UTC"""
|
||||
def utcoffset(self, dt):
|
||||
return ZERO
|
||||
|
||||
def tzname(self, dt):
|
||||
return "UTC"
|
||||
|
||||
def dst(self, dt):
|
||||
return ZERO
|
||||
|
||||
|
||||
utc = UTC()
|
||||
|
||||
|
||||
def dt_to_filetime(dt):
|
||||
"""Converts a datetime to Microsoft filetime format. If the object is
|
||||
time zone-naive, it is forced to UTC before conversion.
|
||||
|
||||
>>> "%.0f" % dt_to_filetime(datetime(2009, 7, 25, 23, 0))
|
||||
'128930364000000000'
|
||||
|
||||
>>> "%.0f" % dt_to_filetime(datetime(1970, 1, 1, 0, 0, tzinfo=utc))
|
||||
'116444736000000000'
|
||||
|
||||
>>> "%.0f" % dt_to_filetime(datetime(1970, 1, 1, 0, 0))
|
||||
'116444736000000000'
|
||||
|
||||
>>> dt_to_filetime(datetime(2009, 7, 25, 23, 0, 0, 100))
|
||||
128930364000001000
|
||||
"""
|
||||
if (dt.tzinfo is None) or (dt.tzinfo.utcoffset(dt) is None):
|
||||
dt = dt.replace(tzinfo=utc)
|
||||
ft = EPOCH_AS_FILETIME + (timegm(dt.timetuple()) * HUNDREDS_OF_NANOSECONDS)
|
||||
return ft + (dt.microsecond * 10)
|
||||
|
||||
|
||||
def filetime_to_dt(ft):
|
||||
"""Converts a Microsoft filetime number to a Python datetime. The new
|
||||
datetime object is time zone-naive but is equivalent to tzinfo=utc.
|
||||
|
||||
>>> filetime_to_dt(116444736000000000)
|
||||
datetime.datetime(1970, 1, 1, 0, 0)
|
||||
|
||||
>>> filetime_to_dt(128930364000000000)
|
||||
datetime.datetime(2009, 7, 25, 23, 0)
|
||||
|
||||
>>> filetime_to_dt(128930364000001000)
|
||||
datetime.datetime(2009, 7, 25, 23, 0, 0, 100)
|
||||
"""
|
||||
# Get seconds and remainder in terms of Unix epoch
|
||||
(s, ns100) = divmod(ft - EPOCH_AS_FILETIME, HUNDREDS_OF_NANOSECONDS)
|
||||
# Convert to datetime object
|
||||
dt = datetime.utcfromtimestamp(s)
|
||||
# Add remainder in as microseconds. Python 3.2 requires an integer
|
||||
dt = dt.replace(microsecond=(ns100 // 10))
|
||||
return dt
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import doctest
|
||||
|
||||
doctest.testmod()
|
248
py-kms/pykms_Format.py
Normal file
248
py-kms/pykms_Format.py
Normal file
@ -0,0 +1,248 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from __future__ import print_function, unicode_literals
|
||||
import re
|
||||
import sys
|
||||
import threading
|
||||
|
||||
try:
|
||||
# Python 2.x imports
|
||||
from StringIO import StringIO
|
||||
import Queue as Queue
|
||||
except ImportError:
|
||||
# Python 3.x imports
|
||||
from io import StringIO
|
||||
import queue as Queue
|
||||
|
||||
pyver = sys.version_info[:2]
|
||||
#----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def enco(strg, typ = 'latin-1'):
|
||||
if pyver >= (3, 0):
|
||||
if isinstance(strg, str):
|
||||
strgenc = strg.encode(typ)
|
||||
return strgenc
|
||||
else:
|
||||
return strg
|
||||
|
||||
def deco(strg, typ = 'latin-1'):
|
||||
if pyver >= (3, 0):
|
||||
if isinstance(strg, bytes):
|
||||
strgdec = strg.decode(typ)
|
||||
return strgdec
|
||||
else:
|
||||
return strg
|
||||
|
||||
|
||||
def byterize(obj):
|
||||
|
||||
def do_encode(dictio, key):
|
||||
if isinstance(dictio[key], str) and len(dictio[key]) > 0 and key not in ['SecondaryAddr']:
|
||||
dictio[key] = dictio[key].encode('latin-1')
|
||||
elif hasattr(dictio[key], '__dict__'):
|
||||
subdictio = dictio[key].__dict__['fields']
|
||||
for subkey in subdictio:
|
||||
do_encode(subdictio, subkey)
|
||||
|
||||
if pyver >= (3, 0):
|
||||
objdict = obj.__dict__['fields']
|
||||
for field in objdict:
|
||||
do_encode(objdict, field)
|
||||
|
||||
return obj
|
||||
|
||||
|
||||
def justify(astring, indent = 35, break_every = 100):
|
||||
str_indent = ('\n' + ' ' * indent)
|
||||
splitted = astring.split('\n')
|
||||
longests = [(n, s) for n, s in enumerate(splitted) if len(s) >= break_every]
|
||||
|
||||
for longest in longests:
|
||||
lines = []
|
||||
for i in range(0, len(longest[1]), break_every):
|
||||
lines.append(longest[1][i : i + break_every])
|
||||
splitted[longest[0]] = str_indent.join(lines)
|
||||
|
||||
if len(splitted) > 1:
|
||||
justy = str_indent.join(splitted)
|
||||
else:
|
||||
justy = str_indent + str_indent.join(splitted)
|
||||
|
||||
return justy
|
||||
|
||||
##----------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
ColorMap = {'red' : '\x1b[91m',
|
||||
'green' : '\x1b[92m',
|
||||
'yellow' : '\x1b[93m',
|
||||
'blue' : '\x1b[94m',
|
||||
'magenta' : '\x1b[95m',
|
||||
'cyan' : '\x1b[96m',
|
||||
'white' : '\x1b[97m'
|
||||
}
|
||||
|
||||
ExtraMap = {'end' : '\x1b[0m',
|
||||
'bold' : '\x1b[1m',
|
||||
'dim' : '\x1b[2m',
|
||||
'italic' : '\x1b[3m',
|
||||
'underlined' : '\x1b[4m',
|
||||
'blink1' : '\x1b[5m',
|
||||
'blink2' : '\x1b[6m',
|
||||
'reverse' : '\x1b[7m',
|
||||
'hidden' : '\x1b[8m',
|
||||
'strike' : '\x1b[9m'
|
||||
}
|
||||
|
||||
ColorExtraMap = dict(ColorMap, **ExtraMap)
|
||||
|
||||
MsgMap = {0 : {'text' : "{yellow}\n\t\t\tClient generating RPC Bind Request...{end}", 'where' : "clt"},
|
||||
1 : {'text' : "{white}<==============={end}{yellow}\tClient sending RPC Bind Request...{end}", 'where' : "clt"},
|
||||
2 : {'text' : "{yellow}Server received RPC Bind Request !!!\t\t\t\t{end}{white}<==============={end}", 'where' : "srv"},
|
||||
3 : {'text' : "{yellow}Server parsing RPC Bind Request...{end}", 'where' : "srv"},
|
||||
4 : {'text' : "{yellow}Server generating RPC Bind Response...{end}", 'where' : "srv"},
|
||||
5 : {'text' : "{yellow}Server sending RPC Bind Response...\t\t\t\t{end}{white}===============>{end}", 'where' : "srv"},
|
||||
6 : {'text' : "{green}{bold}RPC Bind acknowledged !!!\n\n{end}", 'where' : "srv"},
|
||||
7 : {'text' : "{white}===============>{end}{yellow}\tClient received RPC Bind Response !!!{end}", 'where' : "clt"},
|
||||
8 : {'text' : "{green}{bold}\t\t\tRPC Bind acknowledged !!!\n{end}", 'where' : "clt"},
|
||||
9 : {'text' : "{blue}\t\t\tClient generating Activation Request dictionary...{end}", 'where' : "clt"},
|
||||
10 : {'text' : "{blue}\t\t\tClient generating Activation Request data...{end}", 'where' : "clt"},
|
||||
11 : {'text' : "{blue}\t\t\tClient generating RPC Activation Request...{end}", 'where' : "clt"},
|
||||
12 : {'text' : "{white}<==============={end}{blue}\tClient sending RPC Activation Request...\n\n{end}", 'where' : "clt"},
|
||||
13 : {'text' : "{blue}Server received RPC Activation Request !!!\t\t\t{end}{white}<==============={end}", 'where' : "srv"},
|
||||
14 : {'text' : "{blue}Server parsing RPC Activation Request...{end}", 'where' : "srv"},
|
||||
15 : {'text' : "{blue}Server processing KMS Activation Request...{end}", 'where' : "srv"},
|
||||
16 : {'text' : "{blue}Server processing KMS Activation Response...{end}", 'where' : "srv"},
|
||||
17 : {'text' : "{blue}Server generating RPC Activation Response...{end}", 'where' : "srv"},
|
||||
18 : {'text' : "{blue}Server sending RPC Activation Response...\t\t\t{end}{white}===============>{end}", 'where' : "srv"},
|
||||
19 : {'text' : "{green}{bold}Server responded, now in Stand by...\n{end}", 'where' : "srv"},
|
||||
20 : {'text' : "{white}===============>{end}{blue}\tClient received Response !!!{end}", 'where' : "clt"},
|
||||
21 : {'text' : "{green}{bold}\t\t\tActivation Done !!!{end}", 'where' : "clt"},
|
||||
-1 : {'text' : "{white}Server receiving{end}", 'where' : "clt"},
|
||||
-2 : {'text' : "{white}\n\n\t\t\t\t\t\t\t\tClient sending{end}", 'where' : "srv"},
|
||||
-3 : {'text' : "{white}\t\t\t\t\t\t\t\tClient receiving{end}", 'where' : "srv"},
|
||||
-4 : {'text' : "{white}\n\nServer sending{end}", 'where' : "clt"}
|
||||
}
|
||||
|
||||
|
||||
def pick_MsgMap(messagelist):
|
||||
pattern = r"(?<!\{)\{([^}]+)\}(?!\})"
|
||||
picktxt, pickarrw = [ [] for _ in range(2) ]
|
||||
|
||||
for messageitem in messagelist:
|
||||
picklist = re.sub(pattern, '*', messageitem['text'])
|
||||
picklist = list(filter(None, picklist.split('*')))
|
||||
picktxt.append(picklist[0])
|
||||
try:
|
||||
pickarrw.append(picklist[1])
|
||||
except IndexError:
|
||||
pass
|
||||
return picktxt, pickarrw
|
||||
|
||||
def unshell_MsgMap(arrows):
|
||||
unMsgMap = {}
|
||||
for key, values in MsgMap.items():
|
||||
txt = pick_MsgMap([values])
|
||||
|
||||
if txt[0][0] in arrows:
|
||||
unMsgMap.update({txt[1][0] : values['where']})
|
||||
else:
|
||||
unMsgMap.update({txt[0][0] : values['where']})
|
||||
return unMsgMap
|
||||
|
||||
#-------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
# https://stackoverflow.com/questions/230751/how-to-flush-output-of-print-function
|
||||
if pyver < (3, 3):
|
||||
old_print = print
|
||||
|
||||
def print(*args, **kwargs):
|
||||
flush = kwargs.pop('flush', False)
|
||||
old_print(*args, **kwargs)
|
||||
if flush:
|
||||
file = kwargs.get('file', sys.stdout)
|
||||
file.flush() if file is not None else sys.stdout.flush()
|
||||
|
||||
# https://ryanjoneil.github.io/posts/2014-02-14-capturing-stdout-in-a-python-child-process.html
|
||||
class ShellMessage(object):
|
||||
view = None
|
||||
|
||||
class Collect(StringIO):
|
||||
# Capture string sent to stdout.
|
||||
def write(self, s):
|
||||
StringIO.write(self, s)
|
||||
|
||||
class Process(object):
|
||||
def __init__(self, nshell):
|
||||
self.nshell = nshell
|
||||
self.print_queue = Queue.Queue()
|
||||
|
||||
def run(self):
|
||||
if not ShellMessage.view:
|
||||
return
|
||||
# Start thread process.
|
||||
print_thread = threading.Thread(target = self.spawn(), args=(self.print_queue,))
|
||||
print_thread.setDaemon(True)
|
||||
print_thread.start()
|
||||
# Do something with output.
|
||||
toprint = self.read(0.1) # 0.1 s to let the shell output the result
|
||||
# Redirect output.
|
||||
from pykms_GuiBase import gui_redirect # Import after variables creation !
|
||||
gui_redirect(toprint)
|
||||
|
||||
def spawn(self):
|
||||
# Save everything that would otherwise go to stdout.
|
||||
outstream = ShellMessage.Collect()
|
||||
sys.stdout = outstream
|
||||
|
||||
try:
|
||||
# Print something.
|
||||
if isinstance(self.nshell, list):
|
||||
for n in self.nshell:
|
||||
print(MsgMap[n]['text'].format(**ColorExtraMap), flush = True)
|
||||
else:
|
||||
print(MsgMap[self.nshell]['text'].format(**ColorExtraMap), flush = True)
|
||||
finally:
|
||||
# Restore stdout and send content.
|
||||
sys.stdout = sys.__stdout__
|
||||
try:
|
||||
self.print_queue.put(outstream.getvalue())
|
||||
except Queue.Full:
|
||||
pass
|
||||
|
||||
def read(self, timeout = None):
|
||||
try:
|
||||
toprint = self.print_queue.get(block = timeout is not None, timeout = timeout)
|
||||
self.print_queue.task_done()
|
||||
return toprint
|
||||
except Queue.Empty:
|
||||
return None
|
||||
|
||||
|
||||
def unshell_message(ansi_string, m):
|
||||
ansi_find = re.compile(r'\x1B\[[0-?]*[ -/]*[@-~]')
|
||||
ansi_list = re.findall(ansi_find, ansi_string)
|
||||
ansi_indx_start = [ n for n in range(len(ansi_string)) for ansi in list(set(ansi_list)) if ansi_string.find(ansi, n) == n ]
|
||||
ansi_indx_stop = [ n + len(value) for n, value in zip(ansi_indx_start, ansi_list)]
|
||||
ansi_indx = sorted(list(set(ansi_indx_start + ansi_indx_stop)))
|
||||
|
||||
msgcolored = {}
|
||||
ColorMapReversed = dict(zip(ColorMap.values(), ColorMap.keys()))
|
||||
ExtraMapReversed = dict(zip(ExtraMap.values(), ExtraMap.keys()))
|
||||
|
||||
for k in range(len(ansi_indx) - 1):
|
||||
ansi_value = ansi_string[ansi_indx[k] : ansi_indx[k + 1]]
|
||||
if ansi_value != '\x1b[0m':
|
||||
tagname = "tag" + str(m).zfill(2)
|
||||
if tagname not in msgcolored:
|
||||
msgcolored[tagname] = {'color' : '', 'extra' : [], 'text' : ''}
|
||||
|
||||
if ansi_value in ColorMapReversed.keys():
|
||||
msgcolored[tagname]['color'] = ColorMapReversed[ansi_value]
|
||||
elif ansi_value in ExtraMapReversed.keys():
|
||||
msgcolored[tagname]['extra'].append(ExtraMapReversed[ansi_value])
|
||||
else:
|
||||
msgcolored[tagname]['text'] = ansi_value
|
||||
else:
|
||||
m += 1
|
||||
# Ordering.
|
||||
msgcolored = dict(sorted(msgcolored.items()))
|
||||
|
||||
return msgcolored, m
|
464
py-kms/pykms_GuiBase.py
Normal file
464
py-kms/pykms_GuiBase.py
Normal file
@ -0,0 +1,464 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
|
||||
try:
|
||||
# Python 2.x imports
|
||||
import Tkinter as tk
|
||||
import ttk
|
||||
import tkMessageBox as messagebox
|
||||
import tkFileDialog as filedialog
|
||||
import tkFont
|
||||
except ImportError:
|
||||
# Python 3.x imports
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
from tkinter import messagebox
|
||||
from tkinter import filedialog
|
||||
import tkinter.font as tkFont
|
||||
|
||||
from pykms_Server import srv_options, srv_version, srv_config, serverqueue, serverthread
|
||||
from pykms_GuiMisc import ToolTip, TextDoubleScroll, TextRedirect, custom_background, make_clear
|
||||
from pykms_Client import clt_options, clt_version, clt_config, clt_main
|
||||
|
||||
gui_description = 'py-kms GUI'
|
||||
gui_version = 'v1.0'
|
||||
|
||||
##---------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
def get_ip_address():
|
||||
if os.name == 'posix':
|
||||
try:
|
||||
# Python 2.x import
|
||||
import commands
|
||||
except ImportError:
|
||||
#Python 3.x import
|
||||
import subprocess as commands
|
||||
ip = commands.getoutput("hostname -I")
|
||||
elif os.name == 'nt':
|
||||
import socket
|
||||
ip = socket.gethostbyname(socket.gethostname())
|
||||
else:
|
||||
ip = ''
|
||||
print('Error: Couldn\'t get local ip')
|
||||
return ip
|
||||
|
||||
def switch_dir(path):
|
||||
if os.path.isdir(path):
|
||||
os.chdir(path)
|
||||
return True
|
||||
|
||||
if path == '':
|
||||
os.chdir(os.getcwd())
|
||||
return True
|
||||
else:
|
||||
return
|
||||
|
||||
def gui_redirect(str_to_print):
|
||||
global txsrv, txclt, txcol, rclt
|
||||
|
||||
try:
|
||||
TextRedirect.StdoutRedirect(txsrv, txclt, txcol, rclt, str_to_print)
|
||||
except:
|
||||
print(str_to_print)
|
||||
|
||||
##---------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
class KmsGui(tk.Tk):
|
||||
def browse(self, entrywidget, options):
|
||||
path = filedialog.askdirectory()
|
||||
if os.path.isdir(path):
|
||||
entrywidget.delete('0', 'end')
|
||||
entrywidget.insert('end', path + os.sep + os.path.basename(options['lfile']['def']))
|
||||
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
tk.Tk.__init__(self, *args, **kwargs)
|
||||
self.wraplength = 200
|
||||
|
||||
## Define fonts and colors.
|
||||
self.btnwinfont = tkFont.Font(family = 'Times', size = 12, weight = 'bold')
|
||||
self.othfont = tkFont.Font(family = 'Times', size = 9, weight = 'bold')
|
||||
self.optfont = tkFont.Font(family = 'Helvetica', size = 11, weight = 'bold')
|
||||
self.msgfont = tkFont.Font(family = 'Helvetica', size = 7)
|
||||
|
||||
self.customcolors = { 'black' : '#000000',
|
||||
'white' : '#FFFFFF',
|
||||
'green' : '#90EE90',
|
||||
'yellow' : '#FFFF00',
|
||||
'magenta' : '#DA70D6',
|
||||
'orange' : '#FFA500',
|
||||
'red' : '#FF4500',
|
||||
'blue' : '#1E90FF',
|
||||
'cyan' : '#AFEEEE',
|
||||
'lavender': '#E6E6FA',
|
||||
}
|
||||
self.gui_create()
|
||||
|
||||
def gui_create(self):
|
||||
## Create server gui
|
||||
self.gui_srv()
|
||||
## Create client gui + other operations.
|
||||
self.gui_complete()
|
||||
## Create globals for printing process (redirect stdout).
|
||||
global txsrv, txclt, txcol, rclt
|
||||
txsrv = self.textboxsrv.get()
|
||||
txclt = self.textboxclt.get()
|
||||
txcol = self.customcolors
|
||||
rclt = self.runbtnclt
|
||||
## Redirect stderr.
|
||||
sys.stderr = TextRedirect.StderrRedirect(txsrv, txclt, txcol)
|
||||
|
||||
def gui_srv(self):
|
||||
## Create main containers. -------------------------------------------------------------------------------------------------------------
|
||||
self.masterwin = tk.Canvas(self, borderwidth = 3, relief = tk.RIDGE)
|
||||
self.btnsrvwin = tk.Canvas(self.masterwin, background = self.customcolors['white'], borderwidth = 3, relief = 'ridge')
|
||||
self.optsrvwin = tk.Canvas(self.masterwin, background = self.customcolors['white'], borderwidth = 3, relief = 'ridge')
|
||||
# self.optaddsrvwin = tk.Canvas(self.masterwin, background = self.customcolors['white'], borderwidth = 3, relief = 'ridge')
|
||||
self.msgsrvwin = tk.Frame(self.masterwin, background = self.customcolors['black'], relief = 'ridge', width = 300, height = 200)
|
||||
|
||||
## Layout main containers.
|
||||
self.masterwin.grid(row = 0, column = 0, sticky = 'nsew')
|
||||
self.btnsrvwin.grid(row = 0, column = 1, padx = 2, pady = 2, sticky = 'nw')
|
||||
self.optsrvwin.grid(row = 0, column = 2, padx = 2, pady = 2, sticky = 'nw')
|
||||
# self.optaddsrvwin.grid(row = 0, column = 3, padx = 2, pady = 2, sticky = 'nw')
|
||||
self.msgsrvwin.grid(row = 1, column = 2, padx = 1, pady = 1, sticky = 'nsew')
|
||||
self.msgsrvwin.grid_propagate(False)
|
||||
self.msgsrvwin.grid_columnconfigure(0, weight = 1)
|
||||
self.msgsrvwin.grid_rowconfigure(0, weight = 1)
|
||||
|
||||
## Create widgets (btnsrvwin) -----------------------------------------------------------------------------------------------------------
|
||||
self.statesrv = tk.Label(self.btnsrvwin, text = 'Server\nState:\nStopped', font = self.othfont, foreground = self.customcolors['red'])
|
||||
self.runbtnsrv = tk.Button(self.btnsrvwin, text = 'START\nSERVER', background = self.customcolors['green'],
|
||||
foreground = self.customcolors['white'], relief = 'flat', font = self.btnwinfont, command = self.srv_clickedmain)
|
||||
self.shbtnclt = tk.Button(self.btnsrvwin, text = 'SHOW\nCLIENT', background = self.customcolors['magenta'],
|
||||
foreground = self.customcolors['white'], relief = 'flat', font = self.btnwinfont, command = self.clt_showhide)
|
||||
self.clearbtnsrv = tk.Button(self.btnsrvwin, text = 'CLEAR', background = self.customcolors['orange'],
|
||||
foreground = self.customcolors['white'], relief = 'flat', font = self.btnwinfont,
|
||||
command = lambda: make_clear([txsrv, txclt]))
|
||||
self.exitbtnsrv = tk.Button(self.btnsrvwin, text = 'EXIT', background = self.customcolors['black'],
|
||||
foreground = self.customcolors['white'], relief = 'flat', font = self.btnwinfont, command = self.destroy)
|
||||
|
||||
## Layout widgets (btnsrvwin)
|
||||
self.statesrv.grid(row = 0, column = 0, padx = 2, pady = 2, sticky = 'ew')
|
||||
self.runbtnsrv.grid(row = 1, column = 0, padx = 2, pady = 2, sticky = 'ew')
|
||||
self.shbtnclt.grid(row = 2, column = 0, padx = 2, pady = 2, sticky = 'ew')
|
||||
self.clearbtnsrv.grid(row = 3, column = 0, padx = 2, pady = 2, sticky = 'ew')
|
||||
self.exitbtnsrv.grid(row = 4, column = 0, padx = 2, pady = 2, sticky = 'ew')
|
||||
|
||||
## Create widgets (optsrvwin) ------------------------------------------------------------------------------------------------------
|
||||
# Version.
|
||||
ver = tk.Label(self.optsrvwin, text = 'You are running server version: ' + srv_version, foreground = self.customcolors['red'],
|
||||
font = self.othfont)
|
||||
# Ip Address.
|
||||
ipaddlbl = tk.Label(self.optsrvwin, text = 'IP Address: ', font = self.optfont)
|
||||
self.ipadd = tk.Entry(self.optsrvwin, width = 10, font = self.optfont)
|
||||
self.ipadd.insert('end', srv_options['ip']['def'])
|
||||
ToolTip(self.ipadd, text = srv_options['ip']['help'], wraplength = self.wraplength)
|
||||
myipadd = tk.Label(self.optsrvwin, text = 'Your IP address is: {}'.format(get_ip_address()), foreground = self.customcolors['red'],
|
||||
font = self.othfont)
|
||||
# Port.
|
||||
portlbl = tk.Label(self.optsrvwin, text = 'Port: ', font = self.optfont)
|
||||
self.port = tk.Entry(self.optsrvwin, width = 10, font = self.optfont)
|
||||
self.port.insert('end', str(srv_options['port']['def']))
|
||||
ToolTip(self.port, text = srv_options['port']['help'], wraplength = self.wraplength)
|
||||
# EPID.
|
||||
epidlbl = tk.Label(self.optsrvwin, text = 'EPID: ', font = self.optfont)
|
||||
self.epid = tk.Entry(self.optsrvwin, width = 10, font = self.optfont)
|
||||
self.epid.insert('end', str(srv_options['epid']['def']))
|
||||
ToolTip(self.epid, text = srv_options['epid']['help'], wraplength = self.wraplength)
|
||||
# LCID.
|
||||
lcidlbl = tk.Label(self.optsrvwin, text = 'LCID: ', font = self.optfont)
|
||||
self.lcid = tk.Entry(self.optsrvwin, width = 10, font = self.optfont)
|
||||
self.lcid.insert('end', str(srv_options['lcid']['def']))
|
||||
ToolTip(self.lcid, text = srv_options['lcid']['help'], wraplength = self.wraplength)
|
||||
# HWID.
|
||||
hwidlbl = tk.Label(self.optsrvwin, text = 'HWID: ', font = self.optfont)
|
||||
self.hwid = tk.Entry(self.optsrvwin, width = 10, font = self.optfont)
|
||||
self.hwid.insert('end', srv_options['hwid']['def'])
|
||||
ToolTip(self.hwid, text = srv_options['hwid']['help'], wraplength = self.wraplength)
|
||||
# Client Count
|
||||
countlbl = tk.Label(self.optsrvwin, text = 'Client Count: ', font = self.optfont)
|
||||
self.count = tk.Entry(self.optsrvwin, width = 10, font = self.optfont)
|
||||
self.count.insert('end', str(srv_options['count']['def']))
|
||||
ToolTip(self.count, text = srv_options['count']['help'], wraplength = self.wraplength)
|
||||
# Activation Interval.
|
||||
activlbl = tk.Label(self.optsrvwin, text = 'Activation Interval: ', font = self.optfont)
|
||||
self.activ = tk.Entry(self.optsrvwin, width = 10, font = self.optfont)
|
||||
self.activ.insert('end', str(srv_options['activation']['def']))
|
||||
ToolTip(self.activ, text = srv_options['activation']['help'], wraplength = self.wraplength)
|
||||
# Renewal Interval.
|
||||
renewlbl = tk.Label(self.optsrvwin, text = 'Activation Interval: ', font = self.optfont)
|
||||
self.renew = tk.Entry(self.optsrvwin, width = 10, font = self.optfont)
|
||||
self.renew.insert('end', str(srv_options['renewal']['def']))
|
||||
ToolTip(self.renew, text = srv_options['renewal']['help'], wraplength = self.wraplength)
|
||||
# Logfile.
|
||||
filelbl = tk.Label(self.optsrvwin, text = 'Logfile Path / Name: ', font = self.optfont)
|
||||
self.file = tk.Entry(self.optsrvwin, width = 10, font = self.optfont)
|
||||
self.file.insert('end', srv_options['lfile']['def'])
|
||||
ToolTip(self.file, text = srv_options['lfile']['help'], wraplength = self.wraplength)
|
||||
filebtnwin = tk.Button(self.optsrvwin, text = 'Browse', command = lambda: self.browse(self.file, srv_options))
|
||||
# Loglevel.
|
||||
levellbl = tk.Label(self.optsrvwin, text = 'Loglevel: ', font = self.optfont)
|
||||
self.level = ttk.Combobox(self.optsrvwin, values = tuple(srv_options['llevel']['choi']), width = 10)
|
||||
self.level.set(srv_options['llevel']['def'])
|
||||
ToolTip(self.level, text = srv_options['llevel']['help'], wraplength = self.wraplength)
|
||||
# Sqlite database.
|
||||
self.chkval = tk.BooleanVar()
|
||||
self.chkval.set(srv_options['sql']['def'])
|
||||
chksql = tk.Checkbutton(self.optsrvwin, text = 'Create Sqlite\nDatabase', font = self.optfont, var = self.chkval)
|
||||
ToolTip(chksql, text = srv_options['sql']['help'], wraplength = self.wraplength)
|
||||
|
||||
## Layout widgets (optsrvwin)
|
||||
ver.grid(row = 0, column = 0, columnspan = 3, padx = 5, pady = 5, sticky = 'ew')
|
||||
ipaddlbl.grid(row = 1, column = 0, padx = 5, pady = 5, sticky = 'e')
|
||||
self.ipadd.grid(row = 1, column = 1, padx = 5, pady = 5, sticky = 'ew')
|
||||
myipadd.grid(row = 2, column = 1, columnspan = 2, padx = 5, pady = 5, sticky = 'ew')
|
||||
portlbl.grid(row = 3, column = 0, padx = 5, pady = 5, sticky = 'e')
|
||||
self.port.grid(row = 3, column = 1, padx = 5, pady = 5, sticky = 'ew')
|
||||
epidlbl.grid(row = 4, column = 0, padx = 5, pady = 5, sticky = 'e')
|
||||
self.epid.grid(row = 4, column = 1, padx = 5, pady = 5, sticky = 'ew')
|
||||
lcidlbl.grid(row = 5, column = 0, padx = 5, pady = 5, sticky = 'e')
|
||||
self.lcid.grid(row = 5, column = 1, padx = 5, pady = 5, sticky = 'ew')
|
||||
hwidlbl.grid(row = 6, column = 0, padx = 5, pady = 5, sticky = 'e')
|
||||
self.hwid.grid(row = 6, column = 1, padx = 5, pady = 5, sticky = 'ew')
|
||||
countlbl.grid(row = 7, column = 0, padx = 5, pady = 5, sticky = 'e')
|
||||
self.count.grid(row = 7, column = 1, padx = 5, pady = 5, sticky = 'ew')
|
||||
activlbl.grid(row = 8, column = 0, padx = 5, pady = 5, sticky = 'e')
|
||||
self.activ.grid(row = 8, column = 1, padx = 5, pady = 5, sticky = 'ew')
|
||||
renewlbl.grid(row = 9, column = 0, padx = 5, pady = 5, sticky = 'e')
|
||||
self.renew.grid(row = 9, column = 1, padx = 5, pady = 5, sticky = 'ew')
|
||||
filelbl.grid(row = 10, column = 0, padx = 5, pady = 5, sticky = 'e')
|
||||
self.file.grid(row = 10, column = 1, padx = 5, pady = 5, sticky = 'ew')
|
||||
filebtnwin.grid(row = 10, column = 2, padx = 5, pady = 5, sticky = 'ew')
|
||||
levellbl.grid(row = 11, column = 0, padx = 5, pady = 5, sticky = 'e')
|
||||
self.level.grid(row = 11, column = 1, padx = 5, pady = 5, sticky = 'ew')
|
||||
chksql.grid(row = 12, column = 1, padx = 5, pady = 5, sticky = 'ew')
|
||||
|
||||
## Create widgets and layout (msgsrvwin) -----------------------------------------------------------------------------------------------
|
||||
self.textboxsrv = TextDoubleScroll(self.msgsrvwin, background = self.customcolors['black'], wrap = 'word', state = 'disabled',
|
||||
relief = 'ridge', font = self.msgfont)
|
||||
self.textboxsrv.put()
|
||||
|
||||
## Create widgets (optaddsrvwin) -----------------------------------------------------------------------------------------------------
|
||||
# self.timeout = tk.Entry(self.optaddsrvwin, width = 10)
|
||||
# self.timeout.insert('end', '555')
|
||||
## Layout widgets (optaddsrvwin)
|
||||
# self.timeout.grid(row = 0, column = 0, padx = 5, pady = 5, sticky = 'e')
|
||||
|
||||
def gui_complete(self):
|
||||
## Create client widgets (optcltwin, msgcltwin, btncltwin)
|
||||
self.update_idletasks() # update Gui to get btnsrvwin values --> btncltwin.
|
||||
self.iconify()
|
||||
self.gui_clt()
|
||||
minw, minh = self.winfo_width(), self.winfo_height()
|
||||
# Main window custom background.
|
||||
self.update_idletasks() # update Gui for custom background
|
||||
self.iconify()
|
||||
custom_background(self)
|
||||
# Main window other modifications.
|
||||
self.wm_attributes("-topmost", True)
|
||||
self.protocol("WM_DELETE_WINDOW", lambda:0)
|
||||
self.minsize(minw, minh)
|
||||
self.resizable(True, False)
|
||||
|
||||
def get_position(self, genericwidget):
|
||||
x, y = (genericwidget.winfo_x(), genericwidget.winfo_y())
|
||||
w, h = (genericwidget.winfo_width(), genericwidget.winfo_height())
|
||||
return x, y, w, h
|
||||
|
||||
def gui_clt(self):
|
||||
self.optcltwin = tk.Canvas(self.masterwin, background = self.customcolors['white'], borderwidth = 3, relief = 'ridge')
|
||||
self.msgcltwin = tk.Frame(self.masterwin, background = self.customcolors['black'], relief = 'ridge', width = 300, height = 200)
|
||||
self.btncltwin = tk.Canvas(self.masterwin, background = self.customcolors['white'], borderwidth = 3, relief = 'ridge')
|
||||
|
||||
xb, yb, wb, hb = self.get_position(self.btnsrvwin)
|
||||
self.btncltwin_X = xb + 2
|
||||
self.btncltwin_Y = yb + hb + 10
|
||||
self.btncltwin.place(x = self.btncltwin_X, y = self.btncltwin_Y, bordermode = 'inside', anchor = 'nw')
|
||||
self.optcltwin.grid(row = 0, column = 4, padx = 2, pady = 2, sticky = 'nw')
|
||||
self.msgcltwin.grid(row = 1, column = 4, padx = 1, pady = 1, sticky = 'nsew')
|
||||
self.msgcltwin.grid_propagate(False)
|
||||
self.msgcltwin.grid_columnconfigure(0, weight = 1)
|
||||
self.msgcltwin.grid_rowconfigure(0, weight = 1)
|
||||
|
||||
# Create widgets (btncltwin) ------------------------------------------------------------------------------------------------------------
|
||||
self.runbtnclt = tk.Button(self.btncltwin, text = 'START\nCLIENT', background = self.customcolors['blue'],
|
||||
foreground = self.customcolors['white'], relief = 'flat', font = self.btnwinfont,
|
||||
state = 'disabled', command = self.clt_clickedstart)
|
||||
|
||||
#self.othbutt = tk.Button(self.btncltwin, text = 'Botton\n2', background = self.customcolors['green'],
|
||||
# foreground = self.customcolors['white'], relief = 'flat', font = self.btnwinfont)
|
||||
|
||||
# Layout widgets (btncltwin)
|
||||
self.runbtnclt.grid(row = 0, column = 0, padx = 2, pady = 2, sticky = 'ew')
|
||||
#self.othbutt.grid(row = 1, column = 0, padx = 2, pady = 2, sticky = 'ew')
|
||||
|
||||
# Create widgets (optcltwin) ------------------------------------------------------------------------------------------------------------
|
||||
# Version.
|
||||
cltver = tk.Label(self.optcltwin, text = 'You are running client version: ' + clt_version, foreground = self.customcolors['red'],
|
||||
font = self.othfont)
|
||||
# Ip Address.
|
||||
cltipaddlbl = tk.Label(self.optcltwin, text = 'IP Address: ', font = self.optfont)
|
||||
self.cltipadd = tk.Entry(self.optcltwin, width = 10, font = self.optfont)
|
||||
self.cltipadd.insert('end', clt_options['ip']['def'])
|
||||
ToolTip(self.cltipadd, text = clt_options['ip']['help'], wraplength = self.wraplength)
|
||||
# Port.
|
||||
cltportlbl = tk.Label(self.optcltwin, text = 'Port: ', font = self.optfont)
|
||||
self.cltport = tk.Entry(self.optcltwin, width = 10, font = self.optfont)
|
||||
self.cltport.insert('end', str(clt_options['port']['def']))
|
||||
ToolTip(self.cltport, text = clt_options['port']['help'], wraplength = self.wraplength)
|
||||
# Mode.
|
||||
cltmodelbl = tk.Label(self.optcltwin, text = 'Mode: ', font = self.optfont)
|
||||
self.cltmode = ttk.Combobox(self.optcltwin, values = tuple(clt_options['mode']['choi']), width = 10)
|
||||
self.cltmode.set(clt_options['mode']['def'])
|
||||
ToolTip(self.cltmode, text = clt_options['mode']['help'], wraplength = self.wraplength)
|
||||
# CMID.
|
||||
cltcmidlbl = tk.Label(self.optcltwin, text = 'CMID: ', font = self.optfont)
|
||||
self.cltcmid = tk.Entry(self.optcltwin, width = 10, font = self.optfont)
|
||||
self.cltcmid.insert('end', str(clt_options['cmid']['def']))
|
||||
ToolTip(self.cltcmid, text = clt_options['cmid']['help'], wraplength = self.wraplength)
|
||||
# Machine Name.
|
||||
cltnamelbl = tk.Label(self.optcltwin, text = 'Machine Name: ', font = self.optfont)
|
||||
self.cltname = tk.Entry(self.optcltwin, width = 10, font = self.optfont)
|
||||
self.cltname.insert('end', str(clt_options['name']['def']))
|
||||
ToolTip(self.cltname, text = clt_options['name']['help'], wraplength = self.wraplength)
|
||||
# Logfile.
|
||||
cltfilelbl = tk.Label(self.optcltwin, text = 'Logfile Path / Name: ', font = self.optfont)
|
||||
self.cltfile = tk.Entry(self.optcltwin, width = 10, font = self.optfont)
|
||||
self.cltfile.insert('end', clt_options['lfile']['def'])
|
||||
ToolTip(self.cltfile, text = clt_options['lfile']['help'], wraplength = self.wraplength)
|
||||
cltfilebtnwin = tk.Button(self.optcltwin, text = 'Browse', command = lambda: self.browse(self.cltfile, clt_options))
|
||||
# Loglevel.
|
||||
cltlevellbl = tk.Label(self.optcltwin, text = 'Loglevel: ', font = self.optfont)
|
||||
self.cltlevel = ttk.Combobox(self.optcltwin, values = tuple(clt_options['llevel']['choi']), width = 10)
|
||||
self.cltlevel.set(clt_options['llevel']['def'])
|
||||
ToolTip(self.cltlevel, text = clt_options['llevel']['help'], wraplength = self.wraplength)
|
||||
|
||||
# Layout widgets (optcltwin)
|
||||
cltver.grid(row = 0, column = 0, columnspan = 3, padx = 5, pady = 5, sticky = 'ew')
|
||||
cltipaddlbl.grid(row = 1, column = 0, padx = 5, pady = 5, sticky = 'e')
|
||||
self.cltipadd.grid(row = 1, column = 1, padx = 5, pady = 5, sticky = 'ew')
|
||||
cltportlbl.grid(row = 2, column = 0, padx = 5, pady = 5, sticky = 'e')
|
||||
self.cltport.grid(row = 2, column = 1, padx = 5, pady = 5, sticky = 'ew')
|
||||
cltmodelbl.grid(row = 3, column = 0, padx = 5, pady = 5, sticky = 'e')
|
||||
self.cltmode.grid(row = 3, column = 1, padx = 5, pady = 5, sticky = 'ew')
|
||||
cltcmidlbl.grid(row = 4, column = 0, padx = 5, pady = 5, sticky = 'e')
|
||||
self.cltcmid.grid(row = 4, column = 1, padx = 5, pady = 5, sticky = 'ew')
|
||||
cltnamelbl.grid(row = 5, column = 0, padx = 5, pady = 5, sticky = 'e')
|
||||
self.cltname.grid(row = 5, column = 1, padx = 5, pady = 5, sticky = 'ew')
|
||||
cltfilelbl.grid(row = 6, column = 0, padx = 5, pady = 5, sticky = 'ew')
|
||||
self.cltfile.grid(row = 6, column = 1, padx = 5, pady = 5, sticky = 'e')
|
||||
cltfilebtnwin.grid(row = 6, column = 2, padx = 5, pady = 5, sticky = 'ew')
|
||||
cltlevellbl.grid(row = 7, column = 0, padx = 5, pady = 5, sticky = 'e')
|
||||
self.cltlevel.grid(row = 7, column = 1, padx = 5, pady = 5, sticky = 'ew')
|
||||
|
||||
# Create widgets and layout (msgcltwin) ----------------------------------------------------------------------------------------------------------
|
||||
self.textboxclt = TextDoubleScroll(self.msgcltwin, background = self.customcolors['black'], wrap = 'word', state = 'disabled',
|
||||
relief = 'ridge', font = self.msgfont)
|
||||
self.textboxclt.put()
|
||||
|
||||
def proper_none(self, value):
|
||||
value = None if value == 'None' else value
|
||||
try:
|
||||
return int(value)
|
||||
except TypeError:
|
||||
return value
|
||||
|
||||
def clt_showhide(self, force = False):
|
||||
if self.optcltwin.winfo_ismapped() or force:
|
||||
self.shbtnclt['text'] = 'SHOW\nCLIENT'
|
||||
self.optcltwin.grid_remove()
|
||||
self.msgcltwin.grid_remove()
|
||||
self.btncltwin.place_forget()
|
||||
else:
|
||||
self.shbtnclt['text'] = 'HIDE\nCLIENT'
|
||||
self.optcltwin.grid()
|
||||
self.msgcltwin.grid()
|
||||
self.btncltwin.place(x = self.btncltwin_X, y = self.btncltwin_Y, bordermode = 'inside', anchor = 'nw')
|
||||
|
||||
def srv_clickedmain(self):
|
||||
if self.runbtnsrv['text'] == 'START\nSERVER':
|
||||
if self.srv_clickedstart():
|
||||
self.runbtnsrv.configure(text = 'STOP\nSERVER', background = self.customcolors['red'],
|
||||
foreground = self.customcolors['white'])
|
||||
self.runbtnclt.configure(state = 'normal')
|
||||
elif self.runbtnsrv['text'] == 'STOP\nSERVER':
|
||||
self.srv_clickedstop()
|
||||
self.runbtnsrv.configure(text = 'START\nSERVER', background = self.customcolors['green'],
|
||||
foreground = self.customcolors['white'])
|
||||
self.runbtnclt.configure(state = 'disabled')
|
||||
|
||||
def srv_clickedstart(self):
|
||||
ok = False
|
||||
if switch_dir(os.path.dirname(self.file.get())):
|
||||
if self.file.get().lower().endswith('.log'):
|
||||
# Load dict.
|
||||
srv_config[srv_options['ip']['des']] = self.ipadd.get()
|
||||
srv_config[srv_options['port']['des']] = int(self.port.get())
|
||||
srv_config[srv_options['epid']['des']] = self.proper_none(self.epid.get())
|
||||
srv_config[srv_options['lcid']['des']] = int(self.lcid.get())
|
||||
srv_config[srv_options['hwid']['des']] = self.hwid.get()
|
||||
srv_config[srv_options['count']['des']] = self.proper_none(self.count.get())
|
||||
srv_config[srv_options['activation']['des']] = int(self.activ.get())
|
||||
srv_config[srv_options['renewal']['des']] = int(self.renew.get())
|
||||
srv_config[srv_options['lfile']['des']] = self.file.get()
|
||||
srv_config[srv_options['llevel']['des']] = self.level.get()
|
||||
srv_config[srv_options['sql']['des']] = self.chkval.get()
|
||||
## TODO.
|
||||
srv_config[srv_options['lsize']['des']] = 0
|
||||
srv_config[srv_options['time']['des']] = 30
|
||||
|
||||
serverqueue.put('start')
|
||||
# wait for switch.
|
||||
while not serverthread.is_running:
|
||||
pass
|
||||
self.srv_togglestate()
|
||||
ok = True
|
||||
else:
|
||||
messagebox.showerror('Invalid extension', 'Not a .log file !')
|
||||
else:
|
||||
messagebox.showerror('Invalid path', 'Path you have provided not found !')
|
||||
return ok
|
||||
|
||||
|
||||
def srv_clickedstop(self):
|
||||
if serverthread.is_running:
|
||||
serverqueue.put('stop')
|
||||
serverthread.server.shutdown()
|
||||
# wait for switch.
|
||||
while serverthread.is_running:
|
||||
pass
|
||||
self.srv_togglestate()
|
||||
|
||||
def srv_togglestate(self):
|
||||
if serverthread.is_running:
|
||||
txt, color = ('Server\nState:\nServing', self.customcolors['green'])
|
||||
else:
|
||||
txt, color = ('Server\nState:\nStopped', self.customcolors['red'])
|
||||
|
||||
self.statesrv.configure(text = txt, foreground = color)
|
||||
|
||||
def clt_clickedstart(self):
|
||||
if switch_dir(os.path.dirname(self.cltfile.get())):
|
||||
if self.cltfile.get().lower().endswith('.log'):
|
||||
# Load dict.
|
||||
clt_config[clt_options['ip']['des']] = self.cltipadd.get()
|
||||
clt_config[clt_options['port']['des']] = int(self.cltport.get())
|
||||
clt_config[clt_options['mode']['des']] = self.cltmode.get()
|
||||
clt_config[clt_options['cmid']['des']] = self.proper_none(self.cltcmid.get())
|
||||
clt_config[clt_options['name']['des']] = self.proper_none(self.cltname.get())
|
||||
clt_config[clt_options['lfile']['des']] = self.cltfile.get()
|
||||
clt_config[clt_options['llevel']['des']] = self.cltlevel.get()
|
||||
## TODO
|
||||
clt_config[clt_options['lsize']['des']] = 0
|
||||
|
||||
|
||||
clientthread = threading.Thread(target = clt_main, args=(True,))
|
||||
clientthread.setDaemon(True)
|
||||
clientthread.start()
|
||||
else:
|
||||
messagebox.showerror('Invalid extension', 'Not a .log file !')
|
||||
else:
|
||||
messagebox.showerror('Invalid path', 'Path you have provided not found !')
|
334
py-kms/pykms_GuiMisc.py
Normal file
334
py-kms/pykms_GuiMisc.py
Normal file
@ -0,0 +1,334 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from collections import Counter
|
||||
|
||||
try:
|
||||
# Python 2.x imports
|
||||
import Tkinter as tk
|
||||
import ttk
|
||||
import tkFont
|
||||
except ImportError:
|
||||
# Python 3.x imports
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
import tkinter.font as tkFont
|
||||
|
||||
from pykms_Format import unshell_message, MsgMap, pick_MsgMap, unshell_MsgMap
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
# https://stackoverflow.com/questions/3221956/how-do-i-display-tooltips-in-tkinter
|
||||
class ToolTip(object):
|
||||
""" Create a tooltip for a given widget """
|
||||
def __init__(self, widget, bg = '#FFFFEA', pad = (5, 3, 5, 3), text = 'widget info', waittime = 400, wraplength = 250):
|
||||
self.waittime = waittime # ms
|
||||
self.wraplength = wraplength # pixels
|
||||
self.widget = widget
|
||||
self.text = text
|
||||
self.widget.bind("<Enter>", self.onEnter)
|
||||
self.widget.bind("<Leave>", self.onLeave)
|
||||
self.widget.bind("<ButtonPress>", self.onLeave)
|
||||
self.bg = bg
|
||||
self.pad = pad
|
||||
self.id = None
|
||||
self.tw = None
|
||||
|
||||
def onEnter(self, event = None):
|
||||
self.schedule()
|
||||
|
||||
def onLeave(self, event = None):
|
||||
self.unschedule()
|
||||
self.hide()
|
||||
|
||||
def schedule(self):
|
||||
self.unschedule()
|
||||
self.id = self.widget.after(self.waittime, self.show)
|
||||
|
||||
def unschedule(self):
|
||||
id_ = self.id
|
||||
self.id = None
|
||||
if id_:
|
||||
self.widget.after_cancel(id_)
|
||||
|
||||
def show(self):
|
||||
def tip_pos_calculator(widget, label, tip_delta = (10, 5), pad = (5, 3, 5, 3)):
|
||||
w = widget
|
||||
s_width, s_height = w.winfo_screenwidth(), w.winfo_screenheight()
|
||||
width, height = (pad[0] + label.winfo_reqwidth() + pad[2],
|
||||
pad[1] + label.winfo_reqheight() + pad[3])
|
||||
mouse_x, mouse_y = w.winfo_pointerxy()
|
||||
x1, y1 = mouse_x + tip_delta[0], mouse_y + tip_delta[1]
|
||||
x2, y2 = x1 + width, y1 + height
|
||||
|
||||
x_delta = x2 - s_width
|
||||
if x_delta < 0:
|
||||
x_delta = 0
|
||||
y_delta = y2 - s_height
|
||||
if y_delta < 0:
|
||||
y_delta = 0
|
||||
|
||||
offscreen = (x_delta, y_delta) != (0, 0)
|
||||
|
||||
if offscreen:
|
||||
if x_delta:
|
||||
x1 = mouse_x - tip_delta[0] - width
|
||||
if y_delta:
|
||||
y1 = mouse_y - tip_delta[1] - height
|
||||
|
||||
offscreen_again = y1 < 0 # out on the top
|
||||
|
||||
if offscreen_again:
|
||||
# No further checks will be done.
|
||||
|
||||
# TIP:
|
||||
# A further mod might automagically augment the
|
||||
# wraplength when the tooltip is too high to be
|
||||
# kept inside the screen.
|
||||
y1 = 0
|
||||
|
||||
return x1, y1
|
||||
|
||||
bg = self.bg
|
||||
pad = self.pad
|
||||
widget = self.widget
|
||||
|
||||
# creates a toplevel window
|
||||
self.tw = tk.Toplevel(widget)
|
||||
|
||||
# leaves only the label and removes the app window
|
||||
self.tw.wm_overrideredirect(True)
|
||||
|
||||
win = tk.Frame(self.tw, background = bg, borderwidth = 0)
|
||||
label = ttk.Label(win, text = self.text, justify = tk.LEFT, background = bg, relief = tk.SOLID, borderwidth = 0,
|
||||
wraplength = self.wraplength)
|
||||
label.grid(padx = (pad[0], pad[2]), pady = (pad[1], pad[3]), sticky=tk.NSEW)
|
||||
win.grid()
|
||||
|
||||
x, y = tip_pos_calculator(widget, label)
|
||||
|
||||
self.tw.wm_geometry("+%d+%d" % (x, y))
|
||||
|
||||
def hide(self):
|
||||
tw = self.tw
|
||||
if tw:
|
||||
tw.destroy()
|
||||
self.tw = None
|
||||
|
||||
##--------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
# https://stackoverflow.com/questions/2914603/segmentation-fault-while-redirecting-sys-stdout-to-tkinter-text-widget
|
||||
# https://stackoverflow.com/questions/7217715/threadsafe-printing-across-multiple-processes-python-2-x
|
||||
# https://stackoverflow.com/questions/3029816/how-do-i-get-a-thread-safe-print-in-python-2-6
|
||||
# https://stackoverflow.com/questions/20303291/issue-with-redirecting-stdout-to-tkinter-text-widget-with-threads
|
||||
|
||||
def make_clear(widgetlist):
|
||||
for widget in widgetlist:
|
||||
widget.configure(state = 'normal')
|
||||
widget.delete('1.0', 'end')
|
||||
widget.configure(state = 'disabled')
|
||||
|
||||
class TextRedirect(object):
|
||||
class StdoutRedirect(object):
|
||||
tag_num = 0
|
||||
listwhere = []
|
||||
arrows, clt_msg_nonewline = pick_MsgMap([MsgMap[1], MsgMap[7], MsgMap[12], MsgMap[20]])
|
||||
srv_msg_nonewline, _ = pick_MsgMap([MsgMap[2], MsgMap[5], MsgMap[13], MsgMap[18]])
|
||||
arrows = list(set(arrows))
|
||||
lenarrow = len(arrows[0])
|
||||
unMsgMap = unshell_MsgMap(arrows)
|
||||
|
||||
def __init__(self, srv_text_space, clt_text_space, customcolors, runclt, str_to_print):
|
||||
self.srv_text_space = srv_text_space
|
||||
self.clt_text_space = clt_text_space
|
||||
self.customcolors = customcolors
|
||||
self.runclt = runclt
|
||||
self.runclt.configure(state = 'disabled')
|
||||
self.str_to_print = str_to_print
|
||||
self.textbox_do()
|
||||
|
||||
def textbox_finish(self, message):
|
||||
if all(x == "srv" for x in TextRedirect.StdoutRedirect.listwhere):
|
||||
terminator = pick_MsgMap([MsgMap[19]])[0]
|
||||
else:
|
||||
terminator = pick_MsgMap([MsgMap[21]])[0]
|
||||
|
||||
if message in terminator:
|
||||
TextRedirect.StdoutRedirect.tag_num = 0
|
||||
self.runclt.configure(state = 'normal')
|
||||
|
||||
def textbox_clear(self):
|
||||
if TextRedirect.StdoutRedirect.tag_num == 0:
|
||||
# Clear "srv" and "clt" textboxs.
|
||||
make_clear([self.srv_text_space, self.clt_text_space])
|
||||
|
||||
def textbox_write(self, tag, message, color, extras):
|
||||
widget = self.textbox_choose(message)
|
||||
TextRedirect.StdoutRedirect.listwhere.append(self.where)
|
||||
self.maxchar = widget['width']
|
||||
self.textbox_color(tag, widget, color, self.customcolors['black'], extras)
|
||||
widget.configure(state = 'normal')
|
||||
widget.insert('end', self.textbox_format(message), tag)
|
||||
widget.see('end')
|
||||
widget.configure(state = 'disabled')
|
||||
self.textbox_finish(message)
|
||||
|
||||
def textbox_choose(self, message):
|
||||
if message not in self.arrows:
|
||||
self.remind = message
|
||||
self.where = self.unMsgMap[message]
|
||||
if self.where == "srv":
|
||||
return self.srv_text_space
|
||||
elif self.where == "clt":
|
||||
return self.clt_text_space
|
||||
else:
|
||||
if self.remind in self.srv_msg_nonewline:
|
||||
self.where = "srv"
|
||||
return self.srv_text_space
|
||||
else:
|
||||
self.where = "clt"
|
||||
return self.clt_text_space
|
||||
|
||||
def textbox_color(self, tag, widget, forecolor = 'white', backcolor = 'black', extras = []):
|
||||
xfont = tkFont.Font(font = widget['font'])
|
||||
|
||||
for extra in extras:
|
||||
if extra == 'bold':
|
||||
xfont.configure(weight = "bold")
|
||||
elif extra == 'italic':
|
||||
xfont.configure(slant = "italic")
|
||||
elif extra == 'underlined':
|
||||
xfont.text_font.configure(underline = True)
|
||||
elif extra == 'strike':
|
||||
xfont.configure(overstrike = True)
|
||||
|
||||
widget.tag_configure(tag, foreground = forecolor, background = backcolor, font = xfont)
|
||||
|
||||
def textbox_format(self, message):
|
||||
lenfixed = self.maxchar - len(message.replace('\t', ''))
|
||||
|
||||
if self.where == "srv":
|
||||
if message in self.srv_msg_nonewline:
|
||||
lung = lenfixed - self.lenarrow + 4
|
||||
else:
|
||||
lung = lenfixed + self.lenarrow + 10
|
||||
if not message.endswith('\n'):
|
||||
message += '\n'
|
||||
elif self.where == "clt":
|
||||
if message in self.clt_msg_nonewline:
|
||||
lung = lenfixed - self.lenarrow
|
||||
if not message.endswith('\n'):
|
||||
message += '\n'
|
||||
else:
|
||||
lung = lenfixed + 10
|
||||
if not message.endswith('\n') and message not in self.arrows:
|
||||
message += '\n'
|
||||
|
||||
count = Counter(message)
|
||||
countab = (count['\t'] if count['\t'] != 0 else 1)
|
||||
message = message.replace('\t' * countab, ' ' * lung)
|
||||
return message
|
||||
|
||||
def textbox_do(self):
|
||||
self.textbox_clear()
|
||||
msgs, TextRedirect.StdoutRedirect.tag_num = unshell_message(self.str_to_print, TextRedirect.StdoutRedirect.tag_num)
|
||||
for tag in msgs:
|
||||
self.textbox_write(tag, msgs[tag]['text'], self.customcolors[msgs[tag]['color']], msgs[tag]['extra'])
|
||||
|
||||
class StderrRedirect(StdoutRedirect):
|
||||
def __init__(self, srv_text_space, clt_text_space, customcolors):
|
||||
self.srv_text_space = srv_text_space
|
||||
self.clt_text_space = clt_text_space
|
||||
self.customcolors = customcolors
|
||||
self.tag_err = 'STDERR'
|
||||
|
||||
def write(self, string):
|
||||
self.textbox_clear()
|
||||
self.textbox_color(self.tag_err, self.srv_text_space, self.customcolors['red'], self.customcolors['black'])
|
||||
self.srv_text_space.configure(state = 'normal')
|
||||
self.srv_text_space.insert('end', string, self.tag_err)
|
||||
self.srv_text_space.see('end')
|
||||
self.srv_text_space.configure(state = 'disabled')
|
||||
|
||||
##-------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
class TextDoubleScroll(tk.Frame):
|
||||
def __init__(self, master, **kwargs):
|
||||
""" Initialize.
|
||||
- horizontal scrollbar
|
||||
- vertical scrollbar
|
||||
- text widget
|
||||
"""
|
||||
self.master = master
|
||||
tk.Frame.__init__(self, master)
|
||||
|
||||
self.textbox = tk.Text(self.master, **kwargs)
|
||||
self.sizegrip = ttk.Sizegrip(self.master)
|
||||
self.hs = ttk.Scrollbar(self.master, orient = "horizontal", command = self.on_scrollbar_x)
|
||||
self.vs = ttk.Scrollbar(self.master, orient = "vertical", command = self.on_scrollbar_y)
|
||||
self.textbox.configure(yscrollcommand = self.on_textscroll, xscrollcommand = self.hs.set)
|
||||
|
||||
def on_scrollbar_x(self, *args):
|
||||
""" Horizontally scrolls text widget. """
|
||||
self.textbox.xview(*args)
|
||||
|
||||
def on_scrollbar_y(self, *args):
|
||||
""" Vertically scrolls text widget. """
|
||||
self.textbox.yview(*args)
|
||||
|
||||
def on_textscroll(self, *args):
|
||||
""" Moves the scrollbar and scrolls text widget when the mousewheel is moved on a text widget. """
|
||||
self.vs.set(*args)
|
||||
self.on_scrollbar_y('moveto', args[0])
|
||||
|
||||
def put(self, **kwargs):
|
||||
""" Grid the scrollbars and textbox correctly. """
|
||||
self.textbox.grid(row = 0, column = 0, padx = 3, pady = 3, sticky = "nsew")
|
||||
self.vs.grid(row = 0, column = 1, sticky = "ns")
|
||||
self.hs.grid(row = 1, column = 0, sticky = "we")
|
||||
self.sizegrip.grid(row = 1, column = 1, sticky = "news")
|
||||
|
||||
def get(self):
|
||||
""" Return the "frame" useful to place inner controls. """
|
||||
return self.textbox
|
||||
|
||||
##--------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
def custom_background(window):
|
||||
allwidgets = window.grid_slaves(0,0)[0].grid_slaves() + window.grid_slaves(0,0)[0].place_slaves()
|
||||
widgets = [ widget for widget in allwidgets if widget.winfo_class() == 'Canvas']
|
||||
|
||||
try:
|
||||
from PIL import Image, ImageTk
|
||||
|
||||
# Open Image.
|
||||
img = Image.open(os.path.dirname(os.path.abspath( __file__ )) + "/pykms_Keys.gif")
|
||||
# Resize image.
|
||||
img.resize((window.winfo_width(), window.winfo_height()), Image.ANTIALIAS)
|
||||
# Put semi-transparent background chunks.
|
||||
window.backcrops = []
|
||||
|
||||
for widget in widgets:
|
||||
x, y, w, h = window.get_position(widget)
|
||||
cropped = img.crop((x, y, x + w, y + h))
|
||||
cropped.putalpha(24)
|
||||
window.backcrops.append(ImageTk.PhotoImage(cropped))
|
||||
|
||||
# Not in same loop to prevent reference garbage.
|
||||
for crop, widget in zip(window.backcrops, widgets):
|
||||
widget.create_image(1, 1, image = crop, anchor = 'nw')
|
||||
|
||||
# Put semi-transparent background overall.
|
||||
img.putalpha(96)
|
||||
window.backimg = ImageTk.PhotoImage(img)
|
||||
window.masterwin.create_image(1, 1, image = window.backimg, anchor = 'nw')
|
||||
|
||||
except ImportError:
|
||||
for widget in widgets:
|
||||
widget.configure(background = window.customcolors['lavender'])
|
||||
|
||||
# Hide client.
|
||||
window.clt_showhide(force = True)
|
||||
# Show Gui.
|
||||
window.deiconify()
|
||||
|
||||
##---------------------------------------------------------------------------------------------------------------------------------------------------------
|
BIN
py-kms/pykms_Keys.gif
Normal file
BIN
py-kms/pykms_Keys.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 524 KiB |
473
py-kms/pykms_Misc.py
Normal file
473
py-kms/pykms_Misc.py
Normal file
@ -0,0 +1,473 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import logging
|
||||
from logging.handlers import RotatingFileHandler
|
||||
|
||||
#-----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
# https://stackoverflow.com/questions/2183233/how-to-add-a-custom-loglevel-to-pythons-logging-facility
|
||||
# https://stackoverflow.com/questions/17558552/how-do-i-add-custom-field-to-python-log-format-string
|
||||
# https://stackoverflow.com/questions/1343227/can-pythons-logging-format-be-modified-depending-on-the-message-log-level
|
||||
# https://stackoverflow.com/questions/14844970/modifying-logging-message-format-based-on-message-logging-level-in-python3
|
||||
|
||||
def add_logging_level(levelName, levelNum, methodName = None):
|
||||
""" Adds a new logging level to the `logging` module and the currently configured logging class.
|
||||
`levelName` becomes an attribute of the `logging` module with the value `levelNum`.
|
||||
`methodName` becomes a convenience method for both `logging` itself and the class returned by `logging.getLoggerClass()`
|
||||
(usually just `logging.Logger`). If `methodName` is not specified, `levelName.lower()` is used.
|
||||
|
||||
To avoid accidental clobberings of existing attributes, this method will raise an `AttributeError` if the level name
|
||||
is already an attribute of the `logging` module or if the method name is already present .
|
||||
|
||||
Example
|
||||
-------
|
||||
>>> add_logging_level('TRACE', logging.DEBUG - 5)
|
||||
>>> logging.getLogger(__name__).setLevel("TRACE")
|
||||
>>> logging.getLogger(__name__).trace('that worked')
|
||||
>>> logging.trace('so did this')
|
||||
>>> logging.TRACE
|
||||
5
|
||||
"""
|
||||
|
||||
if not methodName:
|
||||
methodName = levelName.lower()
|
||||
|
||||
if hasattr(logging, levelName) or hasattr(logging, methodName) or hasattr(logging.getLoggerClass(), methodName):
|
||||
return
|
||||
|
||||
def logForLevel(self, message, *args, **kwargs):
|
||||
if self.isEnabledFor(levelNum):
|
||||
self._log(levelNum, message, args, **kwargs)
|
||||
def logToRoot(message, *args, **kwargs):
|
||||
logging.log(levelNum, message, *args, **kwargs)
|
||||
|
||||
logging.addLevelName(levelNum, levelName)
|
||||
setattr(logging, levelName, levelNum)
|
||||
setattr(logging.getLoggerClass(), methodName, logForLevel)
|
||||
setattr(logging, methodName, logToRoot)
|
||||
|
||||
|
||||
class LevelFormatter(logging.Formatter):
|
||||
dfmt = '%a, %d %b %Y %H:%M:%S'
|
||||
default_fmt = logging.Formatter('[%(asctime)s] [%(levelname)8s] %(message)s', datefmt = dfmt)
|
||||
|
||||
def __init__(self, formats):
|
||||
""" `formats` is a dict { loglevel : logformat } """
|
||||
self.formatters = {}
|
||||
for loglevel in formats:
|
||||
self.formatters[loglevel] = logging.Formatter(formats[loglevel], datefmt = self.dfmt)
|
||||
|
||||
def format(self, record):
|
||||
formatter = self.formatters.get(record.levelno, self.default_fmt)
|
||||
return formatter.format(record)
|
||||
|
||||
|
||||
def logger_create(log_obj, config, mode = 'a'):
|
||||
# Create new level.
|
||||
add_logging_level('MINI', logging.CRITICAL + 10)
|
||||
|
||||
# Configure visualization.
|
||||
if config['logfile'] == 'STDOUT':
|
||||
# Only STDOUT.
|
||||
log_handler = logging.StreamHandler(sys.stdout)
|
||||
elif config['logfile'] == 'FILE&STDOUT':
|
||||
# logfile and STDOUT.
|
||||
# Not implemented yet. (maybe useless ?)
|
||||
pass
|
||||
else:
|
||||
# Only logfile.
|
||||
log_handler = RotatingFileHandler(filename = config['logfile'], mode = mode, maxBytes = int(config['logsize'] * 1024 * 512),
|
||||
backupCount = 1, encoding = None, delay = 0)
|
||||
|
||||
log_handler.setLevel(config['loglevel'])
|
||||
# Configure formattation.
|
||||
formatter = LevelFormatter({logging.MINI : '[%(asctime)s] [%(levelname)8s] %(host)s %(status)s %(product)s %(message)s'})
|
||||
log_handler.setFormatter(formatter)
|
||||
# Attach.
|
||||
log_obj.setLevel(config['loglevel'])
|
||||
log_obj.addHandler(log_handler)
|
||||
|
||||
|
||||
# Valid language identifiers to be used in the EPID (see "kms.c" in vlmcsd)
|
||||
ValidLcid = [1025, 1026, 1027, 1028, 1029,
|
||||
1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039,
|
||||
1040, 1041, 1042, 1043, 1044, 1045, 1046, 1048, 1049,
|
||||
1050, 1051, 1052, 1053, 1054, 1056, 1057, 1058, 1059,
|
||||
1060, 1061, 1062, 1063, 1065, 1066, 1067, 1068, 1069,
|
||||
1071, 1074, 1076, 1077, 1078, 1079,
|
||||
1080, 1081, 1082, 1083, 1086, 1087, 1088, 1089,
|
||||
1091, 1092, 1093, 1094, 1095, 1097, 1098, 1099,
|
||||
1100, 1102, 1103, 1104, 1106, 1110, 1111, 1114, 1125, 1131, 1153,
|
||||
2049, 2052, 2055, 2057, 2058, 2060, 2064, 2067, 2068, 2070, 2074, 2077, 2092, 2107, 2110, 2115, 2155,
|
||||
3073, 3076, 3079, 3081, 3082, 3084, 3098, 3131, 3179,
|
||||
4097, 4100, 4103, 4105, 4106, 4108, 4122, 4155,
|
||||
5121, 5124, 5127, 5129, 5130, 5132, 5146, 5179,
|
||||
6145, 6153, 6154, 6156, 6170, 6203,
|
||||
7169, 7177, 7178, 7194, 7227,
|
||||
8193, 8201, 8202, 8251,
|
||||
9217, 9225, 9226, 9275,
|
||||
10241, 10249, 10250, 11265, 11273, 11274, 12289, 12297, 12298,
|
||||
13313, 13321, 13322, 14337, 14346, 15361, 15370, 16385, 16394, 17418, 18442, 19466, 20490]
|
||||
|
||||
# http://joshpoley.blogspot.com/2011/09/hresults-user-0x004.html (slerror.h)
|
||||
ErrorCodes = {
|
||||
'SL_E_SRV_INVALID_PUBLISH_LICENSE' : (0xC004B001, 'The activation server determined that the license is invalid.'),
|
||||
'SL_E_SRV_INVALID_PRODUCT_KEY_LICENSE' : (0xC004B002, 'The activation server determined that the license is invalid.'),
|
||||
'SL_E_SRV_INVALID_RIGHTS_ACCOUNT_LICENSE' : (0xC004B003, 'The activation server determined that the license is invalid.'),
|
||||
'SL_E_SRV_INVALID_LICENSE_STRUCTURE' : (0xC004B004, 'The activation server determined that the license is invalid.'),
|
||||
'SL_E_SRV_AUTHORIZATION_FAILED' : (0xC004B005, 'The activation server determined that the license is invalid.'),
|
||||
'SL_E_SRV_INVALID_BINDING' : (0xC004B006, 'The activation server determined that the license is invalid.'),
|
||||
'SL_E_SRV_SERVER_PONG' : (0xC004B007, 'The activation server reported that the computer could not connect to the activation server.'),
|
||||
'SL_E_SRV_INVALID_PAYLOAD' : (0xC004B008, 'The activation server determined that the product could not be activated.'),
|
||||
'SL_E_SRV_INVALID_SECURITY_PROCESSOR_LICENSE' : (0xC004B009, 'The activation server determined that the license is invalid.'),
|
||||
'SL_E_SRV_BUSINESS_TOKEN_ENTRY_NOT_FOUND' : (0xC004B010, 'The activation server determined that required business token entry cannot be found.'),
|
||||
'SL_E_SRV_CLIENT_CLOCK_OUT_OF_SYNC' : (0xC004B011, 'The activation server determined that your computer clock time is not correct. You must correct your clock before you can activate.'),
|
||||
'SL_E_SRV_GENERAL_ERROR' : (0xC004B100, 'The activation server determined that the product could not be activated.'),
|
||||
'SL_E_CHPA_PRODUCT_KEY_OUT_OF_RANGE' : (0xC004C001, 'The activation server determined the specified product key is invalid.'),
|
||||
'SL_E_CHPA_INVALID_BINDING' : (0xC004C002, 'The activation server determined there is a problem with the specified product key.'),
|
||||
'SL_E_CHPA_PRODUCT_KEY_BLOCKED' : (0xC004C003, 'The activation server determined the specified product key has been blocked.'),
|
||||
'SL_E_CHPA_INVALID_PRODUCT_KEY' : (0xC004C004, 'The activation server determined the specified product key is invalid.'),
|
||||
'SL_E_CHPA_BINDING_NOT_FOUND' : (0xC004C005, 'The activation server determined the license is invalid.'),
|
||||
'SL_E_CHPA_BINDING_MAPPING_NOT_FOUND' : (0xC004C006, 'The activation server determined the license is invalid.'),
|
||||
'SL_E_CHPA_UNSUPPORTED_PRODUCT_KEY' : (0xC004C007, 'The activation server determined the specified product key is invalid.'),
|
||||
'SL_E_CHPA_MAXIMUM_UNLOCK_EXCEEDED' : (0xC004C008, 'The activation server reported that the product key has exceeded its unlock limit.'),
|
||||
'SL_E_CHPA_ACTCONFIG_ID_NOT_FOUND' : (0xC004C009, 'The activation server determined the license is invalid.'),
|
||||
'SL_E_CHPA_INVALID_PRODUCT_DATA_ID' : (0xC004C00A, 'The activation server determined the license is invalid.'),
|
||||
'SL_E_CHPA_INVALID_PRODUCT_DATA' : (0xC004C00B, 'The activation server determined the license is invalid.'),
|
||||
'SL_E_CHPA_SYSTEM_ERROR' : (0xC004C00C, 'The activation server experienced an error.'),
|
||||
'SL_E_CHPA_INVALID_ACTCONFIG_ID' : (0xC004C00D, 'The activation server determined the product key is not valid.'),
|
||||
'SL_E_CHPA_INVALID_PRODUCT_KEY_LENGTH' : (0xC004C00E, 'The activation server determined the specified product key is invalid.'),
|
||||
'SL_E_CHPA_INVALID_PRODUCT_KEY_FORMAT' : (0xC004C00F, 'The activation server determined the specified product key is invalid.'),
|
||||
'SL_E_CHPA_INVALID_PRODUCT_KEY_CHAR' : (0xC004C010, 'The activation server determined the specified product key is invalid.'),
|
||||
'SL_E_CHPA_INVALID_BINDING_URI' : (0xC004C011, 'The activation server determined the license is invalid.'),
|
||||
'SL_E_CHPA_NETWORK_ERROR' : (0xC004C012, 'The activation server experienced a network error.'),
|
||||
'SL_E_CHPA_DATABASE_ERROR' : (0xC004C013, 'The activation server experienced an error.'),
|
||||
'SL_E_CHPA_INVALID_ARGUMENT' : (0xC004C014, 'The activation server experienced an error.'),
|
||||
'SL_E_CHPA_RESPONSE_NOT_AVAILABLE' : (0xC004C015, 'The activation server experienced an error.'),
|
||||
'SL_E_CHPA_OEM_SLP_COA0' : (0xC004C016, 'The activation server reported that the specified product key cannot be used for online activation.'),
|
||||
'SL_E_CHPA_PRODUCT_KEY_BLOCKED_IPLOCATION' : (0xC004C017, 'The activation server determined the specified product key has been blocked for this geographic location.'),
|
||||
'SL_E_CHPA_DMAK_LIMIT_EXCEEDED' : (0xC004C020, 'The activation server reported that the Multiple Activation Key has exceeded its limit.'),
|
||||
'SL_E_CHPA_DMAK_EXTENSION_LIMIT_EXCEEDED' : (0xC004C021, 'The activation server reported that the Multiple Activation Key extension limit has been exceeded.'),
|
||||
'SL_E_CHPA_REISSUANCE_LIMIT_NOT_FOUND' : (0xC004C022, 'The activation server reported that the re-issuance limit was not found.'),
|
||||
'SL_E_CHPA_OVERRIDE_REQUEST_NOT_FOUND' : (0xC004C023, 'The activation server reported that the override request was not found.'),
|
||||
'SL_E_CHPA_TIMEBASED_ACTIVATION_BEFORE_START_DATE' : (0xC004C030, 'The activation server reported that time based activation attempted before start date.'),
|
||||
'SL_E_CHPA_TIMEBASED_ACTIVATION_AFTER_END_DATE' : (0xC004C031, 'The activation server reported that time based activation attempted after end date.'),
|
||||
'SL_E_CHPA_TIMEBASED_ACTIVATION_NOT_AVAILABLE' : (0xC004C032, 'The activation server reported that new time based activation is not available.'),
|
||||
'SL_E_CHPA_TIMEBASED_PRODUCT_KEY_NOT_CONFIGURED' : (0xC004C033, 'The activation server reported that the time based product key is not configured for activation.'),
|
||||
'SL_E_CHPA_NO_RULES_TO_ACTIVATE' : (0xC004C04F, 'The activation server reported that no business rules available to activate specified product key.'),
|
||||
'SL_E_CHPA_GENERAL_ERROR' : (0xC004C050, 'The activation server experienced a general error.'),
|
||||
'SL_E_CHPA_DIGITALMARKER_INVALID_BINDING' : (0xC004C051, 'The activation server determined the license is invalid.'),
|
||||
'SL_E_CHPA_DIGITALMARKER_BINDING_NOT_CONFIGURED' : (0xC004C052, 'The activation server determined there is a problem with the specified product key.'),
|
||||
'SL_E_CHPA_DYNAMICALLY_BLOCKED_PRODUCT_KEY' : (0xC004C060, 'The activation server determined the specified product key has been blocked.'),
|
||||
'SL_E_INVALID_LICENSE_STATE_BREACH_GRACE' : (0xC004C291, 'Genuine Validation determined the license state is invalid.'),
|
||||
'SL_E_INVALID_LICENSE_STATE_BREACH_GRACE_EXPIRED' : (0xC004C292, 'Genuine Validation determined the license state is invalid.'),
|
||||
'SL_E_INVALID_TEMPLATE_ID' : (0xC004C2F6, 'Genuine Validation determined the validation input template identifier is invalid.'),
|
||||
'SL_E_INVALID_XML_BLOB' : (0xC004C2FA, 'Genuine Validation determined the validation input data blob is invalid.'),
|
||||
'SL_E_VALIDATION_BLOB_PARAM_NOT_FOUND' : (0xC004C327, 'Genuine Validation determined the validation input data blob parameter is invalid.'),
|
||||
'SL_E_INVALID_CLIENT_TOKEN' : (0xC004C328, 'Genuine Validation determined the client token data is invalid.'),
|
||||
'SL_E_INVALID_OFFLINE_BLOB' : (0xC004C329, 'Genuine Validation determined the offline data blob is invalid.'),
|
||||
'SL_E_OFFLINE_VALIDATION_BLOB_PARAM_NOT_FOUND' : (0xC004C32A, 'Genuine Validation determined the offline data blob parameter is invalid.'),
|
||||
'SL_E_INVALID_OSVERSION_TEMPLATEID' : (0xC004C32B, 'Genuine Validation determined the validation template identifier is invalid for this version of the Windows operating system.'),
|
||||
'SL_E_OFFLINE_GENUINE_BLOB_REVOKED' : (0xC004C32C, 'Genuine Validation determined the offline genuine blob is revoked.'),
|
||||
'SL_E_OFFLINE_GENUINE_BLOB_NOT_FOUND' : (0xC004C32D, 'Genuine Validation determined the offline genuine blob is not found.'),
|
||||
'SL_E_CHPA_MSCH_RESPONSE_NOT_AVAILABLE_VGA' : (0xC004C3FF, 'The activation server determined the VGA service response is not available in the expected format.'),
|
||||
'SL_E_INVALID_OS_FOR_PRODUCT_KEY' : (0xC004C401, 'Genuine Validation determined the product key is invalid for this version of the Windows operating system.'),
|
||||
'SL_E_INVALID_FILE_HASH' : (0xC004C4A1, 'Genuine Validation determined the file hash is invalid.'),
|
||||
'SL_E_VALIDATION_BLOCKED_PRODUCT_KEY' : (0xC004C4A2, 'Genuine Validation determined the product key has been blocked.'),
|
||||
'SL_E_MISMATCHED_KEY_TYPES' : (0xC004C4A4, 'Genuine Validation determined the product key type is invalid.'),
|
||||
'SL_E_VALIDATION_INVALID_PRODUCT_KEY' : (0xC004C4A5, 'Genuine Validation determined the product key is invalid.'),
|
||||
'SL_E_INVALID_OEM_OR_VOLUME_BINDING_DATA' : (0xC004C4A7, 'Genuine Validation determined the OEM or Volume binding data is invalid.'),
|
||||
'SL_E_INVALID_LICENSE_STATE' : (0xC004C4A8, 'Genuine Validation determined the license state is invalid.'),
|
||||
'SL_E_IP_LOCATION_FALIED' : (0xC004C4A9, 'Genuine Validation determined the specified product key has been blocked for this geographic location.'),
|
||||
'SL_E_SOFTMOD_EXPLOIT_DETECTED' : (0xC004C4AB, 'Genuine Validation detected Windows licensing exploits.'),
|
||||
'SL_E_INVALID_TOKEN_DATA' : (0xC004C4AC, 'Genuine Validation determined the token activation data is invalid.'),
|
||||
'SL_E_HEALTH_CHECK_FAILED_NEUTRAL_FILES' : (0xC004C4AD, 'Genuine Validation detected tampered Windows binaries.'),
|
||||
'SL_E_HEALTH_CHECK_FAILED_MUI_FILES' : (0xC004C4AE, 'Genuine Validation detected tampered Windows binaries.'),
|
||||
'SL_E_INVALID_AD_DATA' : (0xC004C4AF, 'Genuine Validation determined the active directory activation data is invalid.'),
|
||||
'SL_E_INVALID_RSDP_COUNT' : (0xC004C4B0, 'Genuine Validation detected Windows licensing exploits.'),
|
||||
'SL_E_ENGINE_DETECTED_EXPLOIT' : (0xC004C4B1, 'Genuine Validation detected Windows licensing exploits.'),
|
||||
'SL_E_NOTIFICATION_BREACH_DETECTED' : (0xC004C531, 'Genuine Validation detected Windows licensing exploits.'),
|
||||
'SL_E_NOTIFICATION_GRACE_EXPIRED' : (0xC004C532, 'Genuine Validation determined the license state is in notification due to expired grace.'),
|
||||
'SL_E_NOTIFICATION_OTHER_REASONS' : (0xC004C533, 'Genuine Validation determined the license state is in notification.'),
|
||||
'SL_E_NON_GENUINE_STATUS_LAST' : (0xC004C600, 'Genuine Validation determined your copy of Windows is not genuine.'),
|
||||
'SL_E_CHPA_BUSINESS_RULE_INPUT_NOT_FOUND' : (0xC004C700, 'The activation server reported that business rule cound not find required input.'),
|
||||
'SL_E_CHPA_NULL_VALUE_FOR_PROPERTY_NAME_OR_ID' : (0xC004C750, 'The activation server reported that NULL value specified for business property name and Id.'),
|
||||
'SL_E_CHPA_UNKNOWN_PROPERTY_NAME' : (0xC004C751, 'The activation server reported that property name specifies unknown property.'),
|
||||
'SL_E_CHPA_UNKNOWN_PROPERTY_ID' : (0xC004C752, 'The activation server reported that property Id specifies unknown property.'),
|
||||
'SL_E_CHPA_FAILED_TO_UPDATE_PRODUCTKEY_BINDING' : (0xC004C755, 'The activation server reported that it failed to update product key binding.'),
|
||||
'SL_E_CHPA_FAILED_TO_INSERT_PRODUCTKEY_BINDING' : (0xC004C756, 'The activation server reported that it failed to insert product key binding.'),
|
||||
'SL_E_CHPA_FAILED_TO_DELETE_PRODUCTKEY_BINDING' : (0xC004C757, 'The activation server reported that it failed to delete product key binding.'),
|
||||
'SL_E_CHPA_FAILED_TO_PROCESS_PRODUCT_KEY_BINDINGS_XML' : (0xC004C758, 'The activation server reported that it failed to process input XML for product key bindings.'),
|
||||
'SL_E_CHPA_FAILED_TO_INSERT_PRODUCT_KEY_PROPERTY' : (0xC004C75A, 'The activation server reported that it failed to insert product key property.'),
|
||||
'SL_E_CHPA_FAILED_TO_UPDATE_PRODUCT_KEY_PROPERTY' : (0xC004C75B, 'The activation server reported that it failed to update product key property.'),
|
||||
'SL_E_CHPA_FAILED_TO_DELETE_PRODUCT_KEY_PROPERTY' : (0xC004C75C, 'The activation server reported that it failed to delete product key property.'),
|
||||
'SL_E_CHPA_UNKNOWN_PRODUCT_KEY_TYPE' : (0xC004C764, 'The activation server reported that the product key type is unknown.'),
|
||||
'SL_E_CHPA_PRODUCT_KEY_BEING_USED' : (0xC004C770, 'The activation server reported that the product key type is being used by another user.'),
|
||||
'SL_E_CHPA_FAILED_TO_INSERT_PRODUCT_KEY_RECORD' : (0xC004C780, 'The activation server reported that it failed to insert product key record.'),
|
||||
'SL_E_CHPA_FAILED_TO_UPDATE_PRODUCT_KEY_RECORD' : (0xC004C781, 'The activation server reported that it failed to update product key record.'),
|
||||
'SL_REMAPPING_SP_PUB_API_INVALID_LICENSE' : (0xC004D000, ''),
|
||||
'SL_REMAPPING_SP_PUB_API_INVALID_ALGORITHM_TYPE' : (0xC004D009, ''),
|
||||
'SL_REMAPPING_SP_PUB_API_TOO_MANY_LOADED_ENVIRONMENTS' : (0xC004D00C, ''),
|
||||
'SL_REMAPPING_SP_PUB_API_BAD_GET_INFO_QUERY' : (0xC004D012, ''),
|
||||
'SL_REMAPPING_SP_PUB_API_INVALID_KEY_LENGTH' : (0xC004D055, ''),
|
||||
'SL_REMAPPING_SP_PUB_API_NO_AES_PROVIDER' : (0xC004D073, ''),
|
||||
'SL_REMAPPING_SP_PUB_API_HANDLE_NOT_COMMITED' : (0xC004D081, 'The handle was used before calling SPCommit with it.'),
|
||||
'SL_REMAPPING_SP_PUB_GENERAL_NOT_INITIALIZED' : (0xC004D101, 'The security processor reported an initialization error.'),
|
||||
'SL_REMAPPING_SP_STATUS_SYSTEM_TIME_SKEWED' : (0x8004D102, 'The security processor reported that the machine time is inconsistent with the trusted time.'),
|
||||
'SL_REMAPPING_SP_STATUS_GENERIC_FAILURE' : (0xC004D103, 'The security processor reported that an error has occurred.'),
|
||||
'SL_REMAPPING_SP_STATUS_INVALIDARG' : (0xC004D104, 'The security processor reported that invalid data was used.'),
|
||||
'SL_REMAPPING_SP_STATUS_ALREADY_EXISTS' : (0xC004D105, 'The security processor reported that the value already exists.'),
|
||||
'SL_REMAPPING_SP_STATUS_INSUFFICIENT_BUFFER' : (0xC004D107, 'The security processor reported that an insufficient buffer was used.'),
|
||||
'SL_REMAPPING_SP_STATUS_INVALIDDATA' : (0xC004D108, 'The security processor reported that invalid data was used.'),
|
||||
'SL_REMAPPING_SP_STATUS_INVALID_SPAPI_CALL' : (0xC004D109, 'The security processor reported that an invalid call was made.'),
|
||||
'SL_REMAPPING_SP_STATUS_INVALID_SPAPI_VERSION' : (0xC004D10A, 'The security processor reported a version mismatch error.'),
|
||||
'SL_REMAPPING_SP_STATUS_DEBUGGER_DETECTED' : (0x8004D10B, 'The security processor cannot operate while a debugger is attached.'),
|
||||
'SL_REMAPPING_SP_STATUS_NO_MORE_DATA' : (0xC004D10C, 'No more data is available.'),
|
||||
'SL_REMAPPING_SP_PUB_CRYPTO_INVALID_KEYLENGTH' : (0xC004D201, 'The length of the cryptopgraphic key material/blob is invalid.'),
|
||||
'SL_REMAPPING_SP_PUB_CRYPTO_INVALID_BLOCKLENGTH' : (0xC004D202, 'The block length is not correct for this algorithm.'),
|
||||
'SL_REMAPPING_SP_PUB_CRYPTO_INVALID_CIPHER' : (0xC004D203, 'The Cryptopgrahic cipher/algorithm type is invalid.'),
|
||||
'SL_REMAPPING_SP_PUB_CRYPTO_INVALID_CIPHERMODE' : (0xC004D204, 'The specified cipher mode is invalid. For example both encrypt and decrypt cannot be specified for symmetric keys.'),
|
||||
'SL_REMAPPING_SP_PUB_CRYPTO_UNKNOWN_PROVIDERID' : (0xC004D205, 'The SPAPIID for the specified Cryptographic Provider is unknown.'),
|
||||
'SL_REMAPPING_SP_PUB_CRYPTO_UNKNOWN_KEYID' : (0xC004D206, 'The SPAPIID for the specified Cryptographic Key (type) is unknown.'),
|
||||
'SL_REMAPPING_SP_PUB_CRYPTO_UNKNOWN_HASHID' : (0xC004D207, 'The SPAPIID for the specified Cryptographic Hash is unknown.'),
|
||||
'SL_REMAPPING_SP_PUB_CRYPTO_UNKNOWN_ATTRIBUTEID' : (0xC004D208, 'The SPAPIID for the specified Cryptographic Attribute is unknown.'),
|
||||
'SL_REMAPPING_SP_PUB_CRYPTO_HASH_FINALIZED' : (0xC004D209, 'The hash object has been finalized and can no longer be updated.'),
|
||||
'SL_REMAPPING_SP_PUB_CRYPTO_KEY_NOT_AVAILABLE' : (0xC004D20A, 'The key is not available within the current state.'),
|
||||
'SL_REMAPPING_SP_PUB_CRYPTO_KEY_NOT_FOUND' : (0xC004D20B, 'The key does not exist. It may not have have been created yet.'),
|
||||
'SL_REMAPPING_SP_PUB_CRYPTO_NOT_BLOCK_ALIGNED' : (0xC004D20C, "The data length is not a multiple of the algorithm's block length."),
|
||||
'SL_REMAPPING_SP_PUB_CRYPTO_INVALID_SIGNATURELENGTH' : (0xC004D20D, 'The length of the signature is not valid.'),
|
||||
'SL_REMAPPING_SP_PUB_CRYPTO_INVALID_SIGNATURE' : (0xC004D20E, 'The signature does not correlate with the comparison hash.'),
|
||||
'SL_REMAPPING_SP_PUB_CRYPTO_INVALID_BLOCK' : (0xC004D20F, 'The RSA block is not valid.'),
|
||||
'SL_REMAPPING_SP_PUB_CRYPTO_INVALID_FORMAT' : (0xC004D210, 'The format of the RSA block is not valid.'),
|
||||
'SL_REMAPPING_SP_PUB_CRYPTO_INVALID_PADDING' : (0xC004D211, 'The CBC padding is not valid.'),
|
||||
'SL_REMAPPING_SP_PUB_TS_TAMPERED' : (0xC004D301, 'The security processor reported that the trusted data store was tampered.'),
|
||||
'SL_REMAPPING_SP_PUB_TS_REARMED' : (0xC004D302, 'The security processor reported that the trusted data store was rearmed.'),
|
||||
'SL_REMAPPING_SP_PUB_TS_RECREATED' : (0xC004D303, 'The security processor reported that the trusted store has been recreated.'),
|
||||
'SL_REMAPPING_SP_PUB_TS_ENTRY_KEY_NOT_FOUND' : (0xC004D304, 'The security processor reported that entry key was not found in the trusted data store.'),
|
||||
'SL_REMAPPING_SP_PUB_TS_ENTRY_KEY_ALREADY_EXISTS' : (0xC004D305, 'The security processor reported that the entry key already exists in the trusted data store.'),
|
||||
'SL_REMAPPING_SP_PUB_TS_ENTRY_KEY_SIZE_TOO_BIG' : (0xC004D306, 'The security processor reported that the entry key is too big to fit in the trusted data store.'),
|
||||
'SL_REMAPPING_SP_PUB_TS_MAX_REARM_REACHED' : (0xC004D307, 'The security processor reported that the maximum allowed number of re-arms has been exceeded. You must re-install the OS before trying to re-arm again.'),
|
||||
'SL_REMAPPING_SP_PUB_TS_DATA_SIZE_TOO_BIG' : (0xC004D308, 'The security processor has reported that entry data size is too big to fit in the trusted data store.'),
|
||||
'SL_REMAPPING_SP_PUB_TS_INVALID_HW_BINDING' : (0xC004D309, 'The security processor has reported that the machine has gone out of hardware tolerance.'),
|
||||
'SL_REMAPPING_SP_PUB_TIMER_ALREADY_EXISTS' : (0xC004D30A, 'The security processor has reported that the secure timer already exists.'),
|
||||
'SL_REMAPPING_SP_PUB_TIMER_NOT_FOUND' : (0xC004D30B, 'The security processor has reported that the secure timer was not found.'),
|
||||
'SL_REMAPPING_SP_PUB_TIMER_EXPIRED' : (0xC004D30C, 'The security processor has reported that the secure timer has expired.'),
|
||||
'SL_REMAPPING_SP_PUB_TIMER_NAME_SIZE_TOO_BIG' : (0xC004D30D, 'The security processor has reported that the secure timer name is too long.'),
|
||||
'SL_REMAPPING_SP_PUB_TS_FULL' : (0xC004D30E, 'The security processor reported that the trusted data store is full.'),
|
||||
'SL_REMAPPING_SP_PUB_TRUSTED_TIME_OK' : (0x4004D30F, 'Trusted time is already up-to-date.'),
|
||||
'SL_REMAPPING_SP_PUB_TS_ENTRY_READ_ONLY' : (0xC004D310, 'Read-only entry cannot be modified.'),
|
||||
'SL_REMAPPING_SP_PUB_TIMER_READ_ONLY' : (0xC004D311, 'Read-only timer cannot be modified.'),
|
||||
'SL_REMAPPING_SP_PUB_TS_ATTRIBUTE_READ_ONLY' : (0xC004D312, 'Read-only attribute cannot be modified.'),
|
||||
'SL_REMAPPING_SP_PUB_TS_ATTRIBUTE_NOT_FOUND' : (0xC004D313, 'Attribute not found.'),
|
||||
'SL_REMAPPING_SP_PUB_TS_ACCESS_DENIED' : (0xC004D314, 'Trusted Store access denied.'),
|
||||
'SL_REMAPPING_SP_PUB_TS_NAMESPACE_NOT_FOUND' : (0xC004D315, 'Namespace not found.'),
|
||||
'SL_REMAPPING_SP_PUB_TS_NAMESPACE_IN_USE' : (0xC004D316, 'Namespace in use.'),
|
||||
'SL_REMAPPING_SP_PUB_TS_TAMPERED_BREADCRUMB_LOAD_INVALID' : (0xC004D317, 'Trusted store tampered.'),
|
||||
'SL_REMAPPING_SP_PUB_TS_TAMPERED_BREADCRUMB_GENERATION' : (0xC004D318, 'Trusted store tampered.'),
|
||||
'SL_REMAPPING_SP_PUB_TS_TAMPERED_INVALID_DATA' : (0xC004D319, 'Trusted store tampered.'),
|
||||
'SL_REMAPPING_SP_PUB_TS_TAMPERED_NO_DATA' : (0xC004D31A, 'Trusted store tampered.'),
|
||||
'SL_REMAPPING_SP_PUB_TS_TAMPERED_DATA_BREADCRUMB_MISMATCH' : (0xC004D31B, 'Trusted store tampered'),
|
||||
'SL_REMAPPING_SP_PUB_TS_TAMPERED_DATA_VERSION_MISMATCH' : (0xC004D31C, 'Trusted store tampered.'),
|
||||
'SL_REMAPPING_SP_PUB_TAMPER_MODULE_AUTHENTICATION' : (0xC004D401, 'The security processor reported a system file mismatch error.'),
|
||||
'SL_REMAPPING_SP_PUB_TAMPER_SECURITY_PROCESSOR_PATCHED' : (0xC004D402, 'The security processor reported a system file mismatch error.'),
|
||||
'SL_REMAPPING_SP_PUB_KM_CACHE_TAMPER' : (0xC004D501, 'The security processor reported an error with the kernel data.'),
|
||||
'SL_REMAPPING_SP_PUB_KM_CACHE_TAMPER_RESTORE_FAILED' : (0xC004D502, 'Kernel Mode Cache is tampered and the restore attempt failed.'),
|
||||
'SL_REMAPPING_SP_PUB_KM_CACHE_IDENTICAL' : (0x4004D601, 'Kernel Mode Cache was not changed.'),
|
||||
'SL_REMAPPING_SP_PUB_KM_CACHE_POLICY_CHANGED' : (0x4004D602, 'Reboot-requiring policies have changed.'),
|
||||
'SL_REMAPPING_SP_STATUS_PUSHKEY_CONFLICT' : (0xC004D701, 'External decryption key was already set for specified feature.'),
|
||||
'SL_REMAPPING_SP_PUB_PROXY_SOFT_TAMPER' : (0xC004D702, 'Error occured during proxy execution'),
|
||||
'SL_E_INVALID_CONTEXT' : (0xC004E001, 'The Software Licensing Service determined that the specified context is invalid.'),
|
||||
'SL_E_TOKEN_STORE_INVALID_STATE' : (0xC004E002, 'The Software Licensing Service reported that the license store contains inconsistent data.'),
|
||||
'SL_E_EVALUATION_FAILED' : (0xC004E003, 'The Software Licensing Service reported that license evaluation failed.'),
|
||||
'SL_E_NOT_EVALUATED' : (0xC004E004, 'The Software Licensing Service reported that the license has not been evaluated.'),
|
||||
'SL_E_NOT_ACTIVATED' : (0xC004E005, 'The Software Licensing Service reported that the license is not activated.'),
|
||||
'SL_E_INVALID_GUID' : (0xC004E006, 'The Software Licensing Service reported that the license contains invalid data.'),
|
||||
'SL_E_TOKSTO_TOKEN_NOT_FOUND' : (0xC004E007, 'The Software Licensing Service reported that the license store does not contain the requested license.'),
|
||||
'SL_E_TOKSTO_NO_PROPERTIES' : (0xC004E008, 'The Software Licensing Service reported that the license property is invalid.'),
|
||||
'SL_E_TOKSTO_NOT_INITIALIZED' : (0xC004E009, 'The Software Licensing Service reported that the license store is not initialized.'),
|
||||
'SL_E_TOKSTO_ALREADY_INITIALIZED' : (0xC004E00A, 'The Software Licensing Service reported that the license store is already initialized.'),
|
||||
'SL_E_TOKSTO_NO_ID_SET' : (0xC004E00B, 'The Software Licensing Service reported that the license property is invalid.'),
|
||||
'SL_E_TOKSTO_CANT_CREATE_FILE' : (0xC004E00C, 'The Software Licensing Service reported that the license could not be opened or created.'),
|
||||
'SL_E_TOKSTO_CANT_WRITE_TO_FILE' : (0xC004E00D, 'The Software Licensing Service reported that the license could not be written.'),
|
||||
'SL_E_TOKSTO_CANT_READ_FILE' : (0xC004E00E, 'The Software Licensing Service reported that the license store could not read the license file.'),
|
||||
'SL_E_TOKSTO_CANT_PARSE_PROPERTIES' : (0xC004E00F, 'The Software Licensing Service reported that the license property is corrupted.'),
|
||||
'SL_E_TOKSTO_PROPERTY_NOT_FOUND' : (0xC004E010, 'The Software Licensing Service reported that the license property is missing.'),
|
||||
'SL_E_TOKSTO_INVALID_FILE' : (0xC004E011, 'The Software Licensing Service reported that the license store contains an invalid license file.'),
|
||||
'SL_E_TOKSTO_CANT_CREATE_MUTEX' : (0xC004E012, 'The Software Licensing Service reported that the license store failed to start synchronization properly.'),
|
||||
'SL_E_TOKSTO_CANT_ACQUIRE_MUTEX' : (0xC004E013, 'The Software Licensing Service reported that the license store failed to synchronize properly.'),
|
||||
'SL_E_TOKSTO_NO_TOKEN_DATA' : (0xC004E014, 'The Software Licensing Service reported that the license property is invalid.'),
|
||||
'SL_E_EUL_CONSUMPTION_FAILED' : (0xC004E015, 'The Software Licensing Service reported that license consumption failed.'),
|
||||
'SL_E_PKEY_INVALID_CONFIG' : (0xC004E016, 'The Software Licensing Service reported that the product key is invalid.'),
|
||||
'SL_E_PKEY_INVALID_UNIQUEID' : (0xC004E017, 'The Software Licensing Service reported that the product key is invalid.'),
|
||||
'SL_E_PKEY_INVALID_ALGORITHM' : (0xC004E018, 'The Software Licensing Service reported that the product key is invalid.'),
|
||||
'SL_E_PKEY_INTERNAL_ERROR' : (0xC004E019, 'The Software Licensing Service determined that validation of the specified product key failed.'),
|
||||
'SL_E_LICENSE_INVALID_ADDON_INFO' : (0xC004E01A, 'The Software Licensing Service reported that invalid add-on information was found.'),
|
||||
'SL_E_HWID_ERROR' : (0xC004E01B, 'The Software Licensing Service reported that not all hardware information could be collected.'),
|
||||
'SL_E_PKEY_INVALID_KEYCHANGE1' : (0xC004E01C, 'This evaluation product key is no longer valid.'),
|
||||
'SL_E_PKEY_INVALID_KEYCHANGE2' : (0xC004E01D, 'The new product key cannot be used on this installation of Windows. Type a different product key. (CD-AB)'),
|
||||
'SL_E_PKEY_INVALID_KEYCHANGE3' : (0xC004E01E, 'The new product key cannot be used on this installation of Windows. Type a different product key. (AB-AB)'),
|
||||
'SL_E_POLICY_OTHERINFO_MISMATCH' : (0xC004E020, 'The Software Licensing Service reported that there is a mismatched between a policy value and information stored in the OtherInfo section.'),
|
||||
'SL_E_PRODUCT_UNIQUENESS_GROUP_ID_INVALID' : (0xC004E021, 'The Software Licensing Service reported that the Genuine information contained in the license is not consistent.'),
|
||||
'SL_E_SECURE_STORE_ID_MISMATCH' : (0xC004E022, 'The Software Licensing Service reported that the secure store id value in license does not match with the current value.'),
|
||||
'SL_E_INVALID_RULESET_RULE' : (0xC004E023, 'The Software Licensing Service reported that the notification rules appear to be invalid.'),
|
||||
'SL_E_INVALID_CONTEXT_DATA' : (0xC004E024, 'The Software Licensing Service reported that the reported machine data appears to be invalid.'),
|
||||
'SL_E_INVALID_HASH' : (0xC004E025, 'The Software Licensing Service reported that the data hash does not correspond to the data.'),
|
||||
'SL_E_INVALID_USE_OF_ADD_ON_PKEY' : (0x8004E026, 'The Software Licensing Service reported that a valid product key for an add-on sku was entered where a Windows product key was expected.'),
|
||||
'SL_E_WINDOWS_VERSION_MISMATCH' : (0xC004E027, 'The Software Licensing Service reported that the version of SPPSvc does not match the policy.'),
|
||||
'SL_E_ACTIVATION_IN_PROGRESS' : (0xC004E028, 'The Software Licensing Service reported that there is another activation attempt in progress for this sku. Please wait for that attempt to complete before trying again.'),
|
||||
'SL_E_STORE_UPGRADE_TOKEN_REQUIRED' : (0xC004E029, 'The Software Licensing Service reported that the activated license requires a corresponding Store upgrade license in order to work. Please visit the Store to purchase a new license or re-download an existing one.'),
|
||||
'SL_E_STORE_UPGRADE_TOKEN_WRONG_EDITION' : (0xC004E02A, 'The Software Licensing Service reported that the Store upgrade license is not enabled for the current OS edition. Please visit the Store to purchase the appropriate license.'),
|
||||
'SL_E_STORE_UPGRADE_TOKEN_WRONG_PID' : (0xC004E02B, 'The Software Licensing Service reported that the Store upgrade license does not match the current active product key. Please visit the Store to purchase a new license or re-download an existing one.'),
|
||||
'SL_E_STORE_UPGRADE_TOKEN_NOT_PRS_SIGNED' : (0xC004E02C, 'The Software Licensing Service reported that the Store upgrade license does not match the current signing level for the installed Operating System. Please visit the Store to purchase a new license or re-download an existing one.'),
|
||||
'SL_E_STORE_UPGRADE_TOKEN_WRONG_VERSION' : (0xC004E02D, 'The Software Licensing Service reported that the Store upgrade license does not enable the current version of the installed Operating System. Please visit the Store to purchase a new license or re-download an existing one.'),
|
||||
'SL_E_STORE_UPGRADE_TOKEN_NOT_AUTHORIZED' : (0xC004E02E, 'The Software Licensing Service reported that the Store upgrade license could not be authorized. Please visit the Store to purchase a new license or re-download an existing one.'),
|
||||
'SL_E_SFS_INVALID_FS_VERSION' : (0x8004E101, 'The Software Licensing Service reported that the Token Store file version is invalid.'),
|
||||
'SL_E_SFS_INVALID_FD_TABLE' : (0x8004E102, 'The Software Licensing Service reported that the Token Store contains an invalid descriptor table.'),
|
||||
'SL_E_SFS_INVALID_SYNC' : (0x8004E103, 'The Software Licensing Service reported that the Token Store contains a token with an invalid header/footer.'),
|
||||
'SL_E_SFS_BAD_TOKEN_NAME' : (0x8004E104, 'The Software Licensing Service reported that a Token Store token has an invalid name.'),
|
||||
'SL_E_SFS_BAD_TOKEN_EXT' : (0x8004E105, 'The Software Licensing Service reported that a Token Store token has an invalid extension.'),
|
||||
'SL_E_SFS_DUPLICATE_TOKEN_NAME' : (0x8004E106, 'The Software Licensing Service reported that the Token Store contains a duplicate token.'),
|
||||
'SL_E_SFS_TOKEN_SIZE_MISMATCH' : (0x8004E107, 'The Software Licensing Service reported that a token in the Token Store has a size mismatch.'),
|
||||
'SL_E_SFS_INVALID_TOKEN_DATA_HASH' : (0x8004E108, 'The Software Licensing Service reported that a token in the Token Store contains an invalid hash.'),
|
||||
'SL_E_SFS_FILE_READ_ERROR' : (0x8004E109, 'The Software Licensing Service reported that the Token Store was unable to read a token.'),
|
||||
'SL_E_SFS_FILE_WRITE_ERROR' : (0x8004E10A, 'The Software Licensing Service reported that the Token Store was unable to write a token.'),
|
||||
'SL_E_SFS_INVALID_FILE_POSITION' : (0x8004E10B, 'The Software Licensing Service reported that the Token Store attempted an invalid file operation.'),
|
||||
'SL_E_SFS_NO_ACTIVE_TRANSACTION' : (0x8004E10C, 'The Software Licensing Service reported that there is no active transaction.'),
|
||||
'SL_E_SFS_INVALID_FS_HEADER' : (0x8004E10D, 'The Software Licensing Service reported that the Token Store file header is invalid.'),
|
||||
'SL_E_SFS_INVALID_TOKEN_DESCRIPTOR' : (0x8004E10E, 'The Software Licensing Service reported that a Token Store token descriptor is invalid.'),
|
||||
'SL_E_INTERNAL_ERROR' : (0xC004F001, 'The Software Licensing Service reported an internal error.'),
|
||||
'SL_E_RIGHT_NOT_CONSUMED' : (0xC004F002, 'The Software Licensing Service reported that rights consumption failed.'),
|
||||
'SL_E_USE_LICENSE_NOT_INSTALLED' : (0xC004F003, 'The Software Licensing Service reported that the required license could not be found.'),
|
||||
'SL_E_MISMATCHED_PKEY_RANGE' : (0xC004F004, 'The Software Licensing Service reported that the product key does not match the range defined in the license.'),
|
||||
'SL_E_MISMATCHED_PID' : (0xC004F005, 'The Software Licensing Service reported that the product key does not match the product key for the license.'),
|
||||
'SL_E_EXTERNAL_SIGNATURE_NOT_FOUND' : (0xC004F006, 'The Software Licensing Service reported that the signature file for the license is not available.'),
|
||||
'SL_E_RAC_NOT_AVAILABLE' : (0xC004F007, 'The Software Licensing Service reported that the license could not be found.'),
|
||||
'SL_E_SPC_NOT_AVAILABLE' : (0xC004F008, 'The Software Licensing Service reported that the license could not be found.'),
|
||||
'SL_E_GRACE_TIME_EXPIRED' : (0xC004F009, 'The Software Licensing Service reported that the grace period expired.'),
|
||||
'SL_E_MISMATCHED_APPID' : (0xC004F00A, 'The Software Licensing Service reported that the application ID does not match the application ID for the license.'),
|
||||
'SL_E_NO_PID_CONFIG_DATA' : (0xC004F00B, 'The Software Licensing Service reported that the product identification data is not available.'),
|
||||
'SL_I_OOB_GRACE_PERIOD' : (0x4004F00C, 'The Software Licensing Service reported that the application is running within the valid grace period.'),
|
||||
'SL_I_OOT_GRACE_PERIOD' : (0x4004F00D, 'The Software Licensing Service reported that the application is running within the valid out of tolerance grace period.'),
|
||||
'SL_E_MISMATCHED_SECURITY_PROCESSOR' : (0xC004F00E, 'The Software Licensing Service determined that the license could not be used by the current version of the security processor component.'),
|
||||
'SL_E_OUT_OF_TOLERANCE' : (0xC004F00F, 'The Software Licensing Service reported that the hardware ID binding is beyond the level of tolerance.'),
|
||||
'SL_E_INVALID_PKEY' : (0xC004F010, 'The Software Licensing Service reported that the product key is invalid.'),
|
||||
'SL_E_LICENSE_FILE_NOT_INSTALLED' : (0xC004F011, 'The Software Licensing Service reported that the license file is not installed.'),
|
||||
'SL_E_VALUE_NOT_FOUND' : (0xC004F012, 'The Software Licensing Service reported that the call has failed because the value for the input key was not found.'),
|
||||
'SL_E_RIGHT_NOT_GRANTED' : (0xC004F013, 'The Software Licensing Service determined that there is no permission to run the software.'),
|
||||
'SL_E_PKEY_NOT_INSTALLED' : (0xC004F014, 'The Software Licensing Service reported that the product key is not available.'),
|
||||
'SL_E_PRODUCT_SKU_NOT_INSTALLED' : (0xC004F015, 'The Software Licensing Service reported that the license is not installed.'),
|
||||
'SL_E_NOT_SUPPORTED' : (0xC004F016, 'The Software Licensing Service determined that the request is not supported.'),
|
||||
'SL_E_PUBLISHING_LICENSE_NOT_INSTALLED' : (0xC004F017, 'The Software Licensing Service reported that the license is not installed.'),
|
||||
'SL_E_LICENSE_SERVER_URL_NOT_FOUND' : (0xC004F018, 'The Software Licensing Service reported that the license does not contain valid location data for the activation server.'),
|
||||
'SL_E_INVALID_EVENT_ID' : (0xC004F019, 'The Software Licensing Service determined that the requested event ID is invalid.'),
|
||||
'SL_E_EVENT_NOT_REGISTERED' : (0xC004F01A, 'The Software Licensing Service determined that the requested event is not registered with the service.'),
|
||||
'SL_E_EVENT_ALREADY_REGISTERED' : (0xC004F01B, 'The Software Licensing Service reported that the event ID is already registered.'),
|
||||
'SL_E_DECRYPTION_LICENSES_NOT_AVAILABLE' : (0xC004F01C, 'The Software Licensing Service reported that the license is not installed.'),
|
||||
'SL_E_LICENSE_SIGNATURE_VERIFICATION_FAILED' : (0xC004F01D, 'The Software Licensing Service reported that the verification of the license failed.'),
|
||||
'SL_E_DATATYPE_MISMATCHED' : (0xC004F01E, 'The Software Licensing Service determined that the input data type does not match the data type in the license.'),
|
||||
'SL_E_INVALID_LICENSE' : (0xC004F01F, 'The Software Licensing Service determined that the license is invalid.'),
|
||||
'SL_E_INVALID_PACKAGE' : (0xC004F020, 'The Software Licensing Service determined that the license package is invalid.'),
|
||||
'SL_E_VALIDITY_TIME_EXPIRED' : (0xC004F021, 'The Software Licensing Service reported that the validity period of the license has expired.'),
|
||||
'SL_E_LICENSE_AUTHORIZATION_FAILED' : (0xC004F022, 'The Software Licensing Service reported that the license authorization failed.'),
|
||||
'SL_E_LICENSE_DECRYPTION_FAILED' : (0xC004F023, 'The Software Licensing Service reported that the license is invalid.'),
|
||||
'SL_E_WINDOWS_INVALID_LICENSE_STATE' : (0xC004F024, 'The Software Licensing Service reported that the license is invalid.'),
|
||||
'SL_E_LUA_ACCESSDENIED' : (0xC004F025, 'The Software Licensing Service reported that the action requires administrator privilege.'),
|
||||
'SL_E_PROXY_KEY_NOT_FOUND' : (0xC004F026, 'The Software Licensing Service reported that the required data is not found.'),
|
||||
'SL_E_TAMPER_DETECTED' : (0xC004F027, 'The Software Licensing Service reported that the license is tampered.'),
|
||||
'SL_E_POLICY_CACHE_INVALID' : (0xC004F028, 'The Software Licensing Service reported that the policy cache is invalid.'),
|
||||
'SL_E_INVALID_RUNNING_MODE' : (0xC004F029, 'The Software Licensing Service cannot be started in the current OS mode.'),
|
||||
'SL_E_SLP_NOT_SIGNED' : (0xC004F02A, 'The Software Licensing Service reported that the license is invalid.'),
|
||||
'SL_E_CIDIID_INVALID_DATA' : (0xC004F02C, 'The Software Licensing Service reported that the format for the offline activation data is incorrect.'),
|
||||
'SL_E_CIDIID_INVALID_VERSION' : (0xC004F02D, 'The Software Licensing Service determined that the version of the offline Confirmation ID (CID) is incorrect.'),
|
||||
'SL_E_CIDIID_VERSION_NOT_SUPPORTED' : (0xC004F02E, 'The Software Licensing Service determined that the version of the offline Confirmation ID (CID) is not supported.'),
|
||||
'SL_E_CIDIID_INVALID_DATA_LENGTH' : (0xC004F02F, 'The Software Licensing Service reported that the length of the offline Confirmation ID (CID) is incorrect.'),
|
||||
'SL_E_CIDIID_NOT_DEPOSITED' : (0xC004F030, 'The Software Licensing Service determined that the Installation ID (IID) or the Confirmation ID (CID) could not been saved.'),
|
||||
'SL_E_CIDIID_MISMATCHED' : (0xC004F031, 'The Installation ID (IID) and the Confirmation ID (CID) do not match. Please confirm the IID and reacquire a new CID if necessary.'),
|
||||
'SL_E_INVALID_BINDING_BLOB' : (0xC004F032, 'The Software Licensing Service determined that the binding data is invalid.'),
|
||||
'SL_E_PRODUCT_KEY_INSTALLATION_NOT_ALLOWED' : (0xC004F033, 'The Software Licensing Service reported that the product key is not allowed to be installed. Please see the eventlog for details.'),
|
||||
'SL_E_EUL_NOT_AVAILABLE' : (0xC004F034, 'The Software Licensing Service reported that the license could not be found or was invalid.'),
|
||||
'SL_E_VL_NOT_WINDOWS_SLP' : (0xC004F035, 'The Software Licensing Service reported that the computer could not be activated with a Volume license product key. Volume-licensed systems require upgrading from a qualifying operating system. Please contact your system administrator or use a different type of key.'),
|
||||
'SL_E_VL_NOT_ENOUGH_COUNT' : (0xC004F038, 'The Software Licensing Service reported that the product could not be activated. The count reported by your Key Management Service (KMS) is insufficient. Please contact your system administrator.'),
|
||||
'SL_E_VL_BINDING_SERVICE_NOT_ENABLED' : (0xC004F039, 'The Software Licensing Service reported that the product could not be activated. The Key Management Service (KMS) is not enabled.'),
|
||||
'SL_E_VL_INFO_PRODUCT_USER_RIGHT' : (0x4004F040, 'The Software Licensing Service reported that the product was activated but the owner should verify the Product Use Rights.'),
|
||||
'SL_E_VL_KEY_MANAGEMENT_SERVICE_NOT_ACTIVATED' : (0xC004F041, 'The Software Licensing Service determined that the Key Management Service (KMS) is not activated. KMS needs to be activated. Please contact system administrator.'),
|
||||
'SL_E_VL_KEY_MANAGEMENT_SERVICE_ID_MISMATCH' : (0xC004F042, 'The Software Licensing Service determined that the specified Key Management Service (KMS) cannot be used.'),
|
||||
'SL_E_PROXY_POLICY_NOT_UPDATED' : (0xC004F047, 'The Software Licensing Service reported that the proxy policy has not been updated.'),
|
||||
'SL_E_CIDIID_INVALID_CHECK_DIGITS' : (0xC004F04D, 'The Software Licensing Service determined that the Installation ID (IID) or the Confirmation ID (CID) is invalid.'),
|
||||
'SL_E_LICENSE_MANAGEMENT_DATA_NOT_FOUND' : (0xC004F04F, 'The Software Licensing Service reported that license management information was not found in the licenses.'),
|
||||
'SL_E_INVALID_PRODUCT_KEY' : (0xC004F050, 'The Software Licensing Service reported that the product key is invalid.'),
|
||||
'SL_E_BLOCKED_PRODUCT_KEY' : (0xC004F051, 'The Software Licensing Service reported that the product key is blocked.'),
|
||||
'SL_E_DUPLICATE_POLICY' : (0xC004F052, 'The Software Licensing Service reported that the licenses contain duplicated properties.'),
|
||||
'SL_E_MISSING_OVERRIDE_ONLY_ATTRIBUTE' : (0xC004F053, 'The Software Licensing Service determined that the license is invalid. The license contains an override policy that is not configured properly.'),
|
||||
'SL_E_LICENSE_MANAGEMENT_DATA_DUPLICATED' : (0xC004F054, 'The Software Licensing Service reported that license management information has duplicated data.'),
|
||||
'SL_E_BASE_SKU_NOT_AVAILABLE' : (0xC004F055, 'The Software Licensing Service reported that the base SKU is not available.'),
|
||||
'SL_E_VL_MACHINE_NOT_BOUND' : (0xC004F056, 'The Software Licensing Service reported that the product could not be activated using the Key Management Service (KMS).'),
|
||||
'SL_E_SLP_MISSING_ACPI_SLIC' : (0xC004F057, 'The Software Licensing Service reported that the computer BIOS is missing a required license.'),
|
||||
'SL_E_SLP_MISSING_SLP_MARKER' : (0xC004F058, 'The Software Licensing Service reported that the computer BIOS is missing a required license.'),
|
||||
'SL_E_SLP_BAD_FORMAT' : (0xC004F059, 'The Software Licensing Service reported that a license in the computer BIOS is invalid.'),
|
||||
'SL_E_INVALID_PACKAGE_VERSION' : (0xC004F060, 'The Software Licensing Service determined that the version of the license package is invalid.'),
|
||||
'SL_E_PKEY_INVALID_UPGRADE' : (0xC004F061, 'The Software Licensing Service determined that this specified product key can only be used for upgrading, not for clean installations.'),
|
||||
'SL_E_ISSUANCE_LICENSE_NOT_INSTALLED' : (0xC004F062, 'The Software Licensing Service reported that a required license could not be found.'),
|
||||
'SL_E_SLP_OEM_CERT_MISSING' : (0xC004F063, 'The Software Licensing Service reported that the computer is missing a required OEM license.'),
|
||||
'SL_E_NONGENUINE_GRACE_TIME_EXPIRED' : (0xC004F064, 'The Software Licensing Service reported that the non-genuine grace period expired.'),
|
||||
'SL_I_NONGENUINE_GRACE_PERIOD' : (0x4004F065, 'The Software Licensing Service reported that the application is running within the valid non-genuine grace period.'),
|
||||
'SL_E_DEPENDENT_PROPERTY_NOT_SET' : (0xC004F066, 'The Software Licensing Service reported that the genuine information property can not be set before dependent property been set.'),
|
||||
'SL_E_NONGENUINE_GRACE_TIME_EXPIRED_2' : (0xC004F067, 'The Software Licensing Service reported that the non-genuine grace period expired (type 2).'),
|
||||
'SL_I_NONGENUINE_GRACE_PERIOD_2' : (0x4004F068, 'The Software Licensing Service reported that the application is running within the valid non-genuine grace period (type 2).'),
|
||||
'SL_E_MISMATCHED_PRODUCT_SKU' : (0xC004F069, 'The Software Licensing Service reported that the product SKU is not found.'),
|
||||
'SL_E_OPERATION_NOT_ALLOWED' : (0xC004F06A, 'The Software Licensing Service reported that the requested operation is not allowed.'),
|
||||
'SL_E_VL_KEY_MANAGEMENT_SERVICE_VM_NOT_SUPPORTED' : (0xC004F06B, 'The Software Licensing Service determined that it is running in a virtual machine. The Key Management Service (KMS) is not supported in this mode.'),
|
||||
'SL_E_VL_INVALID_TIMESTAMP' : (0xC004F06C, 'The Software Licensing Service reported that the product could not be activated. The Key Management Service (KMS) determined that the request timestamp is invalid.'),
|
||||
'SL_E_PLUGIN_INVALID_MANIFEST' : (0xC004F071, 'The Software Licensing Service reported that the plug-in manifest file is incorrect.'),
|
||||
'SL_E_APPLICATION_POLICIES_MISSING' : (0xC004F072, 'The Software Licensing Service reported that the license policies for fast query could not be found.'),
|
||||
'SL_E_APPLICATION_POLICIES_NOT_LOADED' : (0xC004F073, 'The Software Licensing Service reported that the license policies for fast query have not been loaded.'),
|
||||
'SL_E_VL_BINDING_SERVICE_UNAVAILABLE' : (0xC004F074, 'The Software Licensing Service reported that the product could not be activated. No Key Management Service (KMS) could be contacted. Please see the Application Event Log for additional information.'),
|
||||
'SL_E_SERVICE_STOPPING' : (0xC004F075, 'The Software Licensing Service reported that the operation cannot be completed because the service is stopping.'),
|
||||
'SL_E_PLUGIN_NOT_REGISTERED' : (0xC004F076, 'The Software Licensing Service reported that the requested plug-in cannot be found.'),
|
||||
'SL_E_AUTHN_WRONG_VERSION' : (0xC004F077, 'The Software Licensing Service determined incompatible version of authentication data.'),
|
||||
'SL_E_AUTHN_MISMATCHED_KEY' : (0xC004F078, 'The Software Licensing Service reported that the key is mismatched.'),
|
||||
'SL_E_AUTHN_CHALLENGE_NOT_SET' : (0xC004F079, 'The Software Licensing Service reported that the authentication data is not set.'),
|
||||
'SL_E_AUTHN_CANT_VERIFY' : (0xC004F07A, 'The Software Licensing Service reported that the verification could not be done.'),
|
||||
'SL_E_SERVICE_RUNNING' : (0xC004F07B, 'The requested operation is unavailable while the Software Licensing Service is running.'),
|
||||
'SL_E_SLP_INVALID_MARKER_VERSION' : (0xC004F07C, 'The Software Licensing Service determined that the version of the computer BIOS is invalid.'),
|
||||
'SL_E_INVALID_PRODUCT_KEY_TYPE' : (0xC004F07D, 'The Software Licensing Service reported that the product key cannot be used for this type of activation.'),
|
||||
'SL_E_CIDIID_MISMATCHED_PKEY' : (0xC004F07E, 'The Installation ID (IID) and the Confirmation ID (CID) do not match the product key.'),
|
||||
'SL_E_CIDIID_NOT_BOUND' : (0xC004F07F, 'The Installation ID (IID) and the Confirmation ID (CID) are not bound to the current environment.'),
|
||||
'SL_E_LICENSE_NOT_BOUND' : (0xC004F080, 'The Software Licensing Service reported that the license is not bound to the current environment.'),
|
||||
'SL_E_VL_AD_AO_NOT_FOUND' : (0xC004F081, 'The Software Licensing Service reported that the Active Directory Activation Object could not be found or was invalid.'),
|
||||
'SL_E_VL_AD_AO_NAME_TOO_LONG' : (0xC004F082, 'The Software Licensing Service reported that the name specified for the Active Directory Activation Object is too long.'),
|
||||
'SL_E_VL_AD_SCHEMA_VERSION_NOT_SUPPORTED' : (0xC004F083, 'The Software Licensing Service reported that Active Directory-Based Activation is not supported in the current Active Directory schema.'),
|
||||
'SL_E_NOT_GENUINE' : (0xC004F200, 'The Software Licensing Service reported that current state is not genuine.'),
|
||||
'SL_E_EDITION_MISMATCHED' : (0xC004F210, 'The Software Licensing Service reported that the license edition does match the computer edition.'),
|
||||
'SL_E_TKA_CHALLENGE_EXPIRED' : (0xC004F301, 'The Software Licensing Service reported that the product could not be activated. The token-based activation challenge has expired.'),
|
||||
'SL_E_TKA_SILENT_ACTIVATION_FAILURE' : (0xC004F302, 'The Software Licensing Service reported that Silent Activation failed. The Software Licensing Service reported that there are no certificates found in the system that could activate the product without user interaction.'),
|
||||
'SL_E_TKA_INVALID_CERT_CHAIN' : (0xC004F303, 'The Software Licensing Service reported that the certificate chain could not be built or failed validation.'),
|
||||
'SL_E_TKA_GRANT_NOT_FOUND' : (0xC004F304, 'The Software Licensing Service reported that required license could not be found.'),
|
||||
'SL_E_TKA_CERT_NOT_FOUND' : (0xC004F305, 'The Software Licensing Service reported that there are no certificates found in the system that could activate the product.'),
|
||||
'SL_E_TKA_INVALID_SKU_ID' : (0xC004F306, 'The Software Licensing Service reported that this software edition does not support token-based activation.'),
|
||||
'SL_E_TKA_INVALID_BLOB' : (0xC004F307, 'The Software Licensing Service reported that the product could not be activated. Activation data is invalid.'),
|
||||
'SL_E_TKA_TAMPERED_CERT_CHAIN' : (0xC004F308, 'The Software Licensing Service reported that the product could not be activated. Activation data is tampered.'),
|
||||
'SL_E_TKA_CHALLENGE_MISMATCH' : (0xC004F309, 'The Software Licensing Service reported that the product could not be activated. Activation challenge and response do not match.'),
|
||||
'SL_E_TKA_INVALID_CERTIFICATE' : (0xC004F30A, 'The Software Licensing Service reported that the product could not be activated. The certificate does not match the conditions in the license.'),
|
||||
'SL_E_TKA_INVALID_SMARTCARD' : (0xC004F30B, 'The Software Licensing Service reported that the inserted smartcard could not be used to activate the product.'),
|
||||
'SL_E_TKA_FAILED_GRANT_PARSING' : (0xC004F30C, 'The Software Licensing Service reported that the token-based activation license content is invalid.'),
|
||||
'SL_E_TKA_INVALID_THUMBPRINT' : (0xC004F30D, 'The Software Licensing Service reported that the product could not be activated. The thumbprint is invalid.'),
|
||||
'SL_E_TKA_THUMBPRINT_CERT_NOT_FOUND' : (0xC004F30E, 'The Software Licensing Service reported that the product could not be activated. The thumbprint does not match any certificate.'),
|
||||
'SL_E_TKA_CRITERIA_MISMATCH' : (0xC004F30F, 'The Software Licensing Service reported that the product could not be activated. The certificate does not match the criteria specified in the issuance license.'),
|
||||
'SL_E_TKA_TPID_MISMATCH' : (0xC004F310, 'The Software Licensing Service reported that the product could not be activated. The certificate does not match the trust point identifier (TPID) specified in the issuance license.'),
|
||||
'SL_E_TKA_SOFT_CERT_DISALLOWED' : (0xC004F311, 'The Software Licensing Service reported that the product could not be activated. A soft token cannot be used for activation.'),
|
||||
'SL_E_TKA_SOFT_CERT_INVALID' : (0xC004F312, 'The Software Licensing Service reported that the product could not be activated. The certificate cannot be used because its private key is exportable.'),
|
||||
'SL_E_TKA_CERT_CNG_NOT_AVAILABLE' : (0xC004F313, 'The Software Licensing Service reported that the CNG encryption library could not be loaded. The current certificate may not be available on this version of Windows.'),
|
||||
'E_RM_UNKNOWN_ERROR' : (0xC004FC03, 'A networking problem has occurred while activating your copy of Windows.'),
|
||||
'SL_I_TIMEBASED_VALIDITY_PERIOD' : (0x4004FC04, 'The Software Licensing Service reported that the application is running within the timebased validity period.'),
|
||||
'SL_I_PERPETUAL_OOB_GRACE_PERIOD' : (0x4004FC05, 'The Software Licensing Service reported that the application has a perpetual grace period.'),
|
||||
'SL_I_TIMEBASED_EXTENDED_GRACE_PERIOD' : (0x4004FC06, 'The Software Licensing Service reported that the application is running within the valid extended grace period.'),
|
||||
'SL_E_VALIDITY_PERIOD_EXPIRED' : (0xC004FC07, 'The Software Licensing Service reported that the validity period expired.'),
|
||||
'SL_E_IA_THROTTLE_LIMIT_EXCEEDED' : (0xC004FD00, "You've reached the request limit for automatic virtual machine activation. Try again later."),
|
||||
'SL_E_IA_INVALID_VIRTUALIZATION_PLATFORM' : (0xC004FD01, "Windows isn't running on a supported Microsoft Hyper-V virtualization platform."),
|
||||
'SL_E_IA_PARENT_PARTITION_NOT_ACTIVATED' : (0xC004FD02, "Windows isn't activated on the host machine. Please contact your system administrator."),
|
||||
'SL_E_IA_ID_MISMATCH' : (0xC004FD03, "The host machine can't activate the edition of Windows on the virtual machine."),
|
||||
'SL_E_IA_MACHINE_NOT_BOUND' : (0xC004FD04, "Windows isn't activated."),
|
||||
'SL_E_TAMPER_RECOVERY_REQUIRES_ACTIVATION' : (0xC004FE00, 'The Software Licensing Service reported that activation is required to recover from tampering of SL Service trusted store.'),
|
||||
}
|
85
py-kms/pykms_PidGenerator.py
Normal file
85
py-kms/pykms_PidGenerator.py
Normal file
@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import datetime
|
||||
import random
|
||||
import time
|
||||
import uuid
|
||||
from ast import literal_eval
|
||||
|
||||
from pykms_DB2Dict import kmsDB2Dict
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
def epidGenerator(kmsId, version, lcid):
|
||||
kmsdb = kmsDB2Dict()
|
||||
winbuilds, csvlkitems, appitems = kmsdb[0], kmsdb[1], kmsdb[2]
|
||||
hosts, pkeys = [ [] for _ in range(2) ]
|
||||
|
||||
# Product Specific Detection (Get all CSVLK GroupID and PIDRange good for EPID generation), then
|
||||
# Generate Part 2: Group ID and Product Key ID Range
|
||||
for csvlkitem in csvlkitems:
|
||||
try:
|
||||
if kmsId in [ uuid.UUID(kmsitem) for kmsitem in csvlkitem['Activate'] ]:
|
||||
pkeys.append( (csvlkitem['GroupId'], csvlkitem['MinKeyId'], csvlkitem['MaxKeyId'], csvlkitem['InvalidWinBuild']) )
|
||||
else:
|
||||
# fallback to Windows Server 2019 parameters.
|
||||
pkeys.append( ('206', '551000000', '570999999', '[0,1,2]') )
|
||||
except IndexError:
|
||||
# fallback to Windows Server 2019 parameters.
|
||||
pkeys.append( ('206', '551000000', '570999999', '[0,1,2]') )
|
||||
|
||||
pkey = random.choice(pkeys)
|
||||
GroupId, MinKeyId, MaxKeyId, Invalid = int(pkey[0]), int(pkey[1]), int(pkey[2]), literal_eval(pkey[3])
|
||||
|
||||
# Get all KMS Server Host Builds good for EPID generation, then
|
||||
# Generate Part 1 & 7: Host Type and KMS Server OS Build
|
||||
for winbuild in winbuilds:
|
||||
try:
|
||||
# Check versus "InvalidWinBuild".
|
||||
if int(winbuild['WinBuildIndex']) not in Invalid:
|
||||
hosts.append(winbuild)
|
||||
except KeyError:
|
||||
# fallback to Windows Server 2019 parameters.
|
||||
hosts.append( {'BuildNumber':'17763', 'PlatformId':'3612', 'MinDate':'02/10/2018'} )
|
||||
|
||||
host = random.choice(hosts)
|
||||
BuildNumber, PlatformId, MinDate = host['BuildNumber'], host['PlatformId'], host['MinDate']
|
||||
|
||||
# Generate Part 3 and Part 4: Product Key ID
|
||||
productKeyID = random.randint(MinKeyId, MaxKeyId)
|
||||
|
||||
# Generate Part 5: License Channel (00=Retail, 01=Retail, 02=OEM, 03=Volume(GVLK,MAK)) - always 03
|
||||
licenseChannel = 3
|
||||
|
||||
# Generate Part 6: Language - use system default language, 1033 is en-us
|
||||
languageCode = lcid # (C# CultureInfo.InstalledUICulture.LCID)
|
||||
|
||||
# Generate Part 8: KMS Host Activation Date
|
||||
d = datetime.datetime.strptime(MinDate, "%d/%m/%Y")
|
||||
minTime = datetime.date(d.year, d.month, d.day)
|
||||
|
||||
# Generate Year and Day Number
|
||||
randomDate = datetime.date.fromtimestamp(random.randint(time.mktime(minTime.timetuple()), time.mktime(datetime.datetime.now().timetuple())))
|
||||
firstOfYear = datetime.date(randomDate.year, 1, 1)
|
||||
randomDayNumber = int((time.mktime(randomDate.timetuple()) - time.mktime(firstOfYear.timetuple())) / 86400 + 0.5)
|
||||
|
||||
# Generate the EPID string
|
||||
result = []
|
||||
result.append(str(PlatformId).rjust(5, "0"))
|
||||
result.append("-")
|
||||
result.append(str(GroupId).rjust(5, "0"))
|
||||
result.append("-")
|
||||
result.append(str(productKeyID // 1000000).rjust(3, "0"))
|
||||
result.append("-")
|
||||
result.append(str(productKeyID % 1000000).rjust(6, "0"))
|
||||
result.append("-")
|
||||
result.append(str(licenseChannel).rjust(2, "0"))
|
||||
result.append("-")
|
||||
result.append(str(languageCode))
|
||||
result.append("-")
|
||||
result.append(str(BuildNumber).rjust(4, "0"))
|
||||
result.append(".0000-")
|
||||
result.append(str(randomDayNumber).rjust(3, "0"))
|
||||
result.append(str(randomDate.year).rjust(4, "0"))
|
||||
|
||||
return "".join(result)
|
16
py-kms/pykms_RequestUnknown.py
Normal file
16
py-kms/pykms_RequestUnknown.py
Normal file
@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import struct
|
||||
|
||||
from pykms_Base import kmsBase
|
||||
from pykms_Misc import ErrorCodes
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
class kmsRequestUnknown(kmsBase):
|
||||
def executeRequestLogic(self):
|
||||
finalResponse = bytearray()
|
||||
finalResponse.extend(bytearray(struct.pack('<I', 0)))
|
||||
finalResponse.extend(bytearray(struct.pack('<I', 0)))
|
||||
finalResponse.extend(bytearray(struct.pack('<I', ErrorCodes['SL_E_VL_KEY_MANAGEMENT_SERVICE_ID_MISMATCH'][0])))
|
||||
return finalResponse.decode('utf-8').encode('utf-8')
|
132
py-kms/pykms_RequestV4.py
Normal file
132
py-kms/pykms_RequestV4.py
Normal file
@ -0,0 +1,132 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import binascii
|
||||
import time
|
||||
import logging
|
||||
|
||||
from pykms_Base import kmsBase
|
||||
from pykms_Structure import Structure
|
||||
from pykms_Aes import AES
|
||||
from pykms_Format import justify, byterize, enco, deco, ShellMessage
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
loggersrv = logging.getLogger('logsrv')
|
||||
|
||||
# v4 AES Key
|
||||
key = bytearray([0x05, 0x3D, 0x83, 0x07, 0xF9, 0xE5, 0xF0, 0x88, 0xEB, 0x5E, 0xA6, 0x68, 0x6C, 0xF0, 0x37, 0xC7, 0xE4, 0xEF, 0xD2, 0xD6])
|
||||
|
||||
# Xor Buffer
|
||||
def xorBuffer(source, offset, destination, size):
|
||||
for i in range(0, size):
|
||||
destination[i] ^= source[i + offset]
|
||||
|
||||
class kmsRequestV4(kmsBase):
|
||||
class RequestV4(Structure):
|
||||
commonHdr = ()
|
||||
structure = (
|
||||
('bodyLength1', '<I'),
|
||||
('bodyLength2', '<I'),
|
||||
('request', ':', kmsBase.kmsRequestStruct),
|
||||
('hash', '16s'),
|
||||
('padding', ':'),
|
||||
)
|
||||
|
||||
class ResponseV4(Structure):
|
||||
commonHdr = ()
|
||||
structure = (
|
||||
('bodyLength1', '<I'),
|
||||
('unknown', '!I=0x00000200'),
|
||||
('bodyLength2', '<I'),
|
||||
('response', ':', kmsBase.kmsResponseStruct),
|
||||
('hash', '16s'),
|
||||
('padding', ':'),
|
||||
)
|
||||
|
||||
def executeRequestLogic(self):
|
||||
requestData = self.RequestV4(self.data)
|
||||
|
||||
response = self.serverLogic(requestData['request'])
|
||||
thehash = self.generateHash(bytearray(enco(str(response), 'latin-1')))
|
||||
|
||||
responseData = self.generateResponse(response, thehash)
|
||||
|
||||
time.sleep(1) # request sent back too quick for Windows 2008 R2, slow it down.
|
||||
|
||||
return responseData
|
||||
|
||||
def generateHash(self, message):
|
||||
"""
|
||||
The KMS v4 hash is a variant of CMAC-AES-128. There are two key differences:
|
||||
* The 'AES' used is modified in particular ways:
|
||||
* The basic algorithm is Rjindael with a conceptual 160bit key and 128bit blocks.
|
||||
This isn't part of the AES standard, but it works the way you'd expect.
|
||||
Accordingly, the algorithm uses 11 rounds and a 192 byte expanded key.
|
||||
* The trailing block is not XORed with a generated subkey, as defined in CMAC.
|
||||
This is probably because the subkey generation algorithm is only defined for
|
||||
situations where block and key size are the same.
|
||||
"""
|
||||
aes = AES()
|
||||
|
||||
messageSize = len(message)
|
||||
lastBlock = bytearray(16)
|
||||
hashBuffer = bytearray(16)
|
||||
|
||||
# MessageSize / Blocksize.
|
||||
j = messageSize >> 4
|
||||
|
||||
# Remainding bytes.
|
||||
k = messageSize & 0xf
|
||||
|
||||
# Hash.
|
||||
for i in range(0, j):
|
||||
xorBuffer(message, i << 4, hashBuffer, 16)
|
||||
hashBuffer = bytearray(aes.encrypt(hashBuffer, key, len(key)))
|
||||
|
||||
# Bit Padding.
|
||||
ii = 0
|
||||
for i in range(j << 4, k + (j << 4)):
|
||||
lastBlock[ii] = message[i]
|
||||
ii += 1
|
||||
lastBlock[k] = 0x80
|
||||
|
||||
xorBuffer(lastBlock, 0, hashBuffer, 16)
|
||||
hashBuffer = bytearray(aes.encrypt(hashBuffer, key, len(key)))
|
||||
|
||||
return bytes(hashBuffer)
|
||||
|
||||
def generateResponse(self, responseBuffer, thehash):
|
||||
response = self.ResponseV4()
|
||||
bodyLength = len(responseBuffer) + len(thehash)
|
||||
response['bodyLength1'] = bodyLength
|
||||
response['bodyLength2'] = bodyLength
|
||||
response['response'] = responseBuffer
|
||||
response['hash'] = thehash
|
||||
response['padding'] = bytes(bytearray(self.getPadding(bodyLength)))
|
||||
|
||||
## Debug stuff.
|
||||
ShellMessage.Process(16).run()
|
||||
response = byterize(response)
|
||||
loggersrv.debug("KMS V4 Response: \n%s\n" % justify(response.dump(print_to_stdout = False)))
|
||||
loggersrv.debug("KMS V4 Response Bytes: \n%s\n" % justify(deco(binascii.b2a_hex(enco(str(response), 'latin-1')), 'utf-8')))
|
||||
|
||||
return str(response)
|
||||
|
||||
def generateRequest(self, requestBase):
|
||||
thehash = self.generateHash(bytearray(enco(str(requestBase), 'latin-1')))
|
||||
|
||||
request = kmsRequestV4.RequestV4()
|
||||
bodyLength = len(requestBase) + len(thehash)
|
||||
request['bodyLength1'] = bodyLength
|
||||
request['bodyLength2'] = bodyLength
|
||||
request['request'] = requestBase
|
||||
request['hash'] = thehash
|
||||
request['padding'] = bytes(bytearray(self.getPadding(bodyLength)))
|
||||
|
||||
## Debug stuff.
|
||||
ShellMessage.Process(10).run()
|
||||
request = byterize(request)
|
||||
loggersrv.debug("Request V4 Data: \n%s\n" % justify(request.dump(print_to_stdout = False)))
|
||||
loggersrv.debug("Request V4: \n%s\n" % justify(deco(binascii.b2a_hex(enco(str(request), 'latin-1')), 'utf-8')))
|
||||
|
||||
return request
|
180
py-kms/pykms_RequestV5.py
Normal file
180
py-kms/pykms_RequestV5.py
Normal file
@ -0,0 +1,180 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import logging
|
||||
import binascii
|
||||
import hashlib
|
||||
import random
|
||||
|
||||
import pykms_Aes as aes
|
||||
from pykms_Base import kmsBase
|
||||
from pykms_Structure import Structure
|
||||
from pykms_Format import justify, byterize, enco, deco, ShellMessage
|
||||
|
||||
#--------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
loggersrv = logging.getLogger('logsrv')
|
||||
|
||||
class kmsRequestV5(kmsBase):
|
||||
class RequestV5(Structure):
|
||||
class Message(Structure):
|
||||
commonHdr = ()
|
||||
structure = (
|
||||
('salt', '16s'),
|
||||
('encrypted', '240s'),
|
||||
('padding', ':'),
|
||||
)
|
||||
|
||||
commonHdr = ()
|
||||
structure = (
|
||||
('bodyLength1', '<I'),
|
||||
('bodyLength2', '<I'),
|
||||
('versionMinor', '<H'),
|
||||
('versionMajor', '<H'),
|
||||
('message', ':', Message),
|
||||
)
|
||||
|
||||
class DecryptedRequest(Structure):
|
||||
commonHdr = ()
|
||||
structure = (
|
||||
('salt', '16s'),
|
||||
('request', ':', kmsBase.kmsRequestStruct),
|
||||
)
|
||||
|
||||
class ResponseV5(Structure):
|
||||
commonHdr = ()
|
||||
structure = (
|
||||
('bodyLength1', '<I'),
|
||||
('unknown', '!I=0x00000200'),
|
||||
('bodyLength2', '<I'),
|
||||
('versionMinor', '<H'),
|
||||
('versionMajor', '<H'),
|
||||
('salt', '16s'),
|
||||
('encrypted', ':'),
|
||||
('padding', ':'),
|
||||
)
|
||||
|
||||
class DecryptedResponse(Structure):
|
||||
commonHdr = ()
|
||||
structure = (
|
||||
('response', ':', kmsBase.kmsResponseStruct),
|
||||
('keys', '16s'),
|
||||
('hash', '32s'),
|
||||
)
|
||||
|
||||
key = bytearray([ 0xCD, 0x7E, 0x79, 0x6F, 0x2A, 0xB2, 0x5D, 0xCB, 0x55, 0xFF, 0xC8, 0xEF, 0x83, 0x64, 0xC4, 0x70 ])
|
||||
|
||||
v6 = False
|
||||
|
||||
ver = 5
|
||||
|
||||
def executeRequestLogic(self):
|
||||
requestData = self.RequestV5(self.data)
|
||||
|
||||
decrypted = self.decryptRequest(requestData)
|
||||
|
||||
responseBuffer = self.serverLogic(decrypted['request'])
|
||||
|
||||
iv, encrypted = self.encryptResponse(requestData, decrypted, responseBuffer)
|
||||
|
||||
responseData = self.generateResponse(iv, encrypted, requestData)
|
||||
|
||||
return responseData
|
||||
|
||||
def decryptRequest(self, request):
|
||||
encrypted = bytearray(enco(str(request['message']), 'latin-1'))
|
||||
iv = bytearray(enco(request['message']['salt'], 'latin-1'))
|
||||
|
||||
moo = aes.AESModeOfOperation()
|
||||
moo.aes.v6 = self.v6
|
||||
decrypted = moo.decrypt(encrypted, 256, moo.ModeOfOperation["CBC"], self.key, moo.aes.KeySize["SIZE_128"], iv)
|
||||
decrypted = aes.strip_PKCS7_padding(decrypted)
|
||||
decrypted = bytes(bytearray(decrypted))
|
||||
|
||||
return self.DecryptedRequest(decrypted)
|
||||
|
||||
def encryptResponse(self, request, decrypted, response):
|
||||
randomSalt = self.getRandomSalt()
|
||||
result = hashlib.sha256(randomSalt).digest()
|
||||
iv = bytearray(enco(request['message']['salt'], 'latin-1'))
|
||||
|
||||
randomStuff = bytearray(16)
|
||||
for i in range(0,16):
|
||||
randomStuff[i] = (bytearray(enco(decrypted['salt'], 'latin-1'))[i] ^ iv[i] ^ randomSalt[i]) & 0xff
|
||||
|
||||
responsedata = self.DecryptedResponse()
|
||||
responsedata['response'] = response
|
||||
responsedata['keys'] = bytes(randomStuff)
|
||||
responsedata['hash'] = result
|
||||
|
||||
padded = aes.append_PKCS7_padding(enco(str(responsedata), 'latin-1'))
|
||||
moo = aes.AESModeOfOperation()
|
||||
moo.aes.v6 = self.v6
|
||||
mode, orig_len, crypted = moo.encrypt(padded, moo.ModeOfOperation["CBC"], self.key, moo.aes.KeySize["SIZE_128"], iv)
|
||||
|
||||
return bytes(iv), bytes(bytearray(crypted))
|
||||
|
||||
def decryptResponse(self, response):
|
||||
paddingLength = self.getPadding(response['bodyLength1'])
|
||||
|
||||
iv = bytearray(enco(response['salt'], 'latin-1'))
|
||||
encrypted = bytearray(enco(response['encrypted'][:-paddingLength], 'latin-1'))
|
||||
moo = aes.AESModeOfOperation()
|
||||
moo.aes.v6 = self.v6
|
||||
decrypted = moo.decrypt(encrypted, 256, moo.ModeOfOperation["CBC"], self.key, moo.aes.KeySize["SIZE_128"], iv)
|
||||
decrypted = aes.strip_PKCS7_padding(decrypted)
|
||||
decrypted = bytes(bytearray(decrypted))
|
||||
|
||||
return self.DecryptedResponse(decrypted)
|
||||
|
||||
def getRandomSalt(self):
|
||||
return bytearray(random.getrandbits(8) for i in range(16))
|
||||
|
||||
def generateResponse(self, iv, encryptedResponse, requestData):
|
||||
response = self.ResponseV5()
|
||||
bodyLength = 2 + 2 + len(iv) + len(encryptedResponse)
|
||||
response['bodyLength1'] = bodyLength
|
||||
response['bodyLength2'] = bodyLength
|
||||
response['versionMinor'] = requestData['versionMinor']
|
||||
response['versionMajor'] = requestData['versionMajor']
|
||||
response['salt'] = iv
|
||||
response['encrypted'] = bytes(bytearray(encryptedResponse))
|
||||
response['padding'] = bytes(bytearray(self.getPadding(bodyLength)))
|
||||
|
||||
ShellMessage.Process(16).run()
|
||||
response = byterize(response)
|
||||
loggersrv.info("KMS V%d Response: \n%s\n" % (self.ver, justify(response.dump(print_to_stdout = False))))
|
||||
loggersrv.info("KMS V%d Structure Bytes: \n%s\n" % (self.ver, justify(deco(binascii.b2a_hex(enco(str(response), 'latin-1')), 'utf-8'))))
|
||||
|
||||
return str(response)
|
||||
|
||||
def generateRequest(self, requestBase):
|
||||
esalt = self.getRandomSalt()
|
||||
|
||||
moo = aes.AESModeOfOperation()
|
||||
moo.aes.v6 = self.v6
|
||||
dsalt = moo.decrypt(esalt, 16, moo.ModeOfOperation["CBC"], self.key, moo.aes.KeySize["SIZE_128"], esalt)
|
||||
dsalt = bytearray(dsalt)
|
||||
|
||||
decrypted = self.DecryptedRequest()
|
||||
decrypted['salt'] = bytes(dsalt)
|
||||
decrypted['request'] = requestBase
|
||||
|
||||
padded = aes.append_PKCS7_padding(enco(str(decrypted), 'latin-1'))
|
||||
mode, orig_len, crypted = moo.encrypt(padded, moo.ModeOfOperation["CBC"], self.key, moo.aes.KeySize["SIZE_128"], esalt)
|
||||
|
||||
message = self.RequestV5.Message(bytes(bytearray(crypted)))
|
||||
|
||||
request = self.RequestV5()
|
||||
bodyLength = 2 + 2 + len(message)
|
||||
request['bodyLength1'] = bodyLength
|
||||
request['bodyLength2'] = bodyLength
|
||||
request['versionMinor'] = requestBase['versionMinor']
|
||||
request['versionMajor'] = requestBase['versionMajor']
|
||||
request['message'] = message
|
||||
|
||||
ShellMessage.Process(10).run()
|
||||
request = byterize(request)
|
||||
loggersrv.info("Request V%d Data: \n%s\n" % (self.ver, justify(request.dump(print_to_stdout = False))))
|
||||
loggersrv.info("Request V%d: \n%s\n" % (self.ver, justify(deco(binascii.b2a_hex(enco(str(request), 'latin-1')), 'utf-8'))))
|
||||
|
||||
return request
|
108
py-kms/pykms_RequestV6.py
Normal file
108
py-kms/pykms_RequestV6.py
Normal file
@ -0,0 +1,108 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import hashlib
|
||||
import hmac
|
||||
import struct
|
||||
|
||||
import pykms_Aes as aes
|
||||
from pykms_Base import kmsBase
|
||||
from pykms_RequestV5 import kmsRequestV5
|
||||
from pykms_Structure import Structure
|
||||
from pykms_Format import enco, deco
|
||||
|
||||
#---------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
class kmsRequestV6(kmsRequestV5):
|
||||
class DecryptedResponse(Structure):
|
||||
class Message(Structure):
|
||||
commonHdr = ()
|
||||
structure = (
|
||||
('response', ':', kmsBase.kmsResponseStruct),
|
||||
('keys', '16s'),
|
||||
('hash', '32s'),
|
||||
('hwid', '8s'),
|
||||
('xorSalts', '16s'),
|
||||
)
|
||||
|
||||
commonHdr = ()
|
||||
structure = (
|
||||
('message', ':', Message),
|
||||
('hmac', '16s'),
|
||||
)
|
||||
|
||||
key = bytearray([ 0xA9, 0x4A, 0x41, 0x95, 0xE2, 0x01, 0x43, 0x2D, 0x9B, 0xCB, 0x46, 0x04, 0x05, 0xD8, 0x4A, 0x21 ])
|
||||
|
||||
v6 = True
|
||||
|
||||
ver = 6
|
||||
|
||||
def encryptResponse(self, request, decrypted, response):
|
||||
randomSalt = self.getRandomSalt()
|
||||
result = hashlib.sha256(randomSalt).digest()
|
||||
|
||||
SaltC = bytearray(enco(request['message']['salt'], 'latin-1'))
|
||||
DSaltC = bytearray(enco(decrypted['salt'], 'latin-1'))
|
||||
|
||||
randomStuff = bytearray(16)
|
||||
for i in range(0,16):
|
||||
randomStuff[i] = (SaltC[i] ^ DSaltC[i] ^ randomSalt[i]) & 0xff
|
||||
|
||||
# XorSalts
|
||||
XorSalts = bytearray(16)
|
||||
for i in range (0, 16):
|
||||
XorSalts[i] = (SaltC[i] ^ DSaltC[i]) & 0xff
|
||||
|
||||
message = self.DecryptedResponse.Message()
|
||||
message['response'] = response
|
||||
message['keys'] = bytes(randomStuff)
|
||||
message['hash'] = result
|
||||
message['xorSalts'] = bytes(XorSalts)
|
||||
message['hwid'] = self.srv_config['hwid']
|
||||
|
||||
# SaltS
|
||||
SaltS = self.getRandomSalt()
|
||||
|
||||
moo = aes.AESModeOfOperation()
|
||||
moo.aes.v6 = True
|
||||
decry = moo.decrypt(SaltS, 16, moo.ModeOfOperation["CBC"], self.key, moo.aes.KeySize["SIZE_128"], SaltS)
|
||||
|
||||
# DSaltS
|
||||
DSaltS = bytearray(decry)
|
||||
|
||||
# HMacMsg
|
||||
HMacMsg = bytearray(16)
|
||||
for i in range(0,16):
|
||||
HMacMsg[i] = (SaltS[i] ^ DSaltS[i]) & 0xff
|
||||
HMacMsg.extend(enco(str(message), 'latin-1'))
|
||||
|
||||
# HMacKey
|
||||
requestTime = decrypted['request']['requestTime']
|
||||
HMacKey = self.getMACKey(requestTime)
|
||||
HMac = hmac.new(HMacKey, bytes(HMacMsg), hashlib.sha256)
|
||||
digest = HMac.digest()
|
||||
|
||||
responsedata = self.DecryptedResponse()
|
||||
responsedata['message'] = message
|
||||
responsedata['hmac'] = digest[16:]
|
||||
|
||||
padded = aes.append_PKCS7_padding(enco(str(responsedata), 'latin-1'))
|
||||
mode, orig_len, crypted = moo.encrypt(padded, moo.ModeOfOperation["CBC"], self.key, moo.aes.KeySize["SIZE_128"], SaltS)
|
||||
|
||||
return bytes(SaltS), bytes(bytearray(crypted))
|
||||
|
||||
|
||||
def getMACKey(self, t):
|
||||
c1 = 0x00000022816889BD
|
||||
c2 = 0x000000208CBAB5ED
|
||||
c3 = 0x3156CD5AC628477A
|
||||
|
||||
i1 = (t // c1) & 0xFFFFFFFFFFFFFFFF
|
||||
i2 = (i1 * c2) & 0xFFFFFFFFFFFFFFFF
|
||||
seed = (i2 + c3) & 0xFFFFFFFFFFFFFFFF
|
||||
|
||||
sha256 = hashlib.sha256()
|
||||
sha256.update(struct.pack("<Q", seed))
|
||||
digest = sha256.digest()
|
||||
|
||||
return digest[16:]
|
||||
|
45
py-kms/pykms_RpcBase.py
Normal file
45
py-kms/pykms_RpcBase.py
Normal file
@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
class rpcBase:
|
||||
packetType = {
|
||||
'request': 0,
|
||||
'ping': 1,
|
||||
'response': 2,
|
||||
'fault': 3,
|
||||
'working': 4,
|
||||
'nocall': 5,
|
||||
'reject': 6,
|
||||
'ack': 7,
|
||||
'clCancel': 8,
|
||||
'fack': 9,
|
||||
'cancelAck': 10,
|
||||
'bindReq': 11,
|
||||
'bindAck': 12,
|
||||
'bindNak': 13,
|
||||
'alterContext': 14,
|
||||
'alterContextResp': 15,
|
||||
'shutdown': 17,
|
||||
'coCancel': 18,
|
||||
'orphaned': 19
|
||||
}
|
||||
|
||||
packetFlags = {
|
||||
'firstFrag': 1, # 0x01
|
||||
'lastFrag': 2, # 0x02
|
||||
'cancelPending': 4, # 0x04
|
||||
'reserved': 8, # 0x08
|
||||
'multiplex': 16, # 0x10
|
||||
'didNotExecute': 32, # 0x20
|
||||
'maybe': 64, # 0x40
|
||||
'objectUuid': 128 # 0x80
|
||||
}
|
||||
|
||||
def __init__(self, data, srv_config):
|
||||
self.data = data
|
||||
self.srv_config = srv_config
|
||||
|
||||
def populate(self):
|
||||
return self.generateResponse(self.parseRequest())
|
||||
|
||||
def parseRequest(self):
|
||||
return {}
|
175
py-kms/pykms_RpcBind.py
Normal file
175
py-kms/pykms_RpcBind.py
Normal file
@ -0,0 +1,175 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import logging
|
||||
import binascii
|
||||
import uuid
|
||||
|
||||
import pykms_RpcBase
|
||||
from pykms_Dcerpc import MSRPCHeader, MSRPCBindAck
|
||||
from pykms_Structure import Structure
|
||||
from pykms_Format import justify, byterize, enco, deco, ShellMessage
|
||||
|
||||
#--------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
loggersrv = logging.getLogger('logsrv')
|
||||
|
||||
uuidNDR32 = uuid.UUID('8a885d04-1ceb-11c9-9fe8-08002b104860')
|
||||
uuidNDR64 = uuid.UUID('71710533-beba-4937-8319-b5dbef9ccc36')
|
||||
uuidTime = uuid.UUID('6cb71c2c-9812-4540-0300-000000000000')
|
||||
uuidEmpty = uuid.UUID('00000000-0000-0000-0000-000000000000')
|
||||
|
||||
class CtxItem(Structure):
|
||||
structure = (
|
||||
('ContextID', '<H=0'),
|
||||
('TransItems', 'B=0'),
|
||||
('Pad', 'B=0'),
|
||||
('AbstractSyntaxUUID', '16s=""'),
|
||||
('AbstractSyntaxVer', '<I=0'),
|
||||
('TransferSyntaxUUID', '16s=""'),
|
||||
('TransferSyntaxVer', '<I=0'),
|
||||
)
|
||||
|
||||
def ts(self):
|
||||
return uuid.UUID(bytes_le = enco(self['TransferSyntaxUUID'], 'latin-1'))
|
||||
|
||||
class CtxItemResult(Structure):
|
||||
structure = (
|
||||
('Result', '<H=0'),
|
||||
('Reason', '<H=0'),
|
||||
('TransferSyntaxUUID', '16s=""'),
|
||||
('TransferSyntaxVer', '<I=0'),
|
||||
)
|
||||
|
||||
def __init__(self, result, reason, tsUUID, tsVer):
|
||||
Structure.__init__(self)
|
||||
self['Result'] = result
|
||||
self['Reason'] = reason
|
||||
self['TransferSyntaxUUID'] = tsUUID.bytes_le
|
||||
self['TransferSyntaxVer'] = tsVer
|
||||
|
||||
class MSRPCBind(Structure):
|
||||
class CtxItemArray:
|
||||
def __init__(self, data):
|
||||
self.data = data
|
||||
|
||||
def __len__(self):
|
||||
return len(self.data)
|
||||
|
||||
def __str__(self):
|
||||
return self.data
|
||||
|
||||
def __getitem__(self, i):
|
||||
return CtxItem(self.data[(len(CtxItem()) * i):])
|
||||
|
||||
_CTX_ITEM_LEN = len(CtxItem())
|
||||
|
||||
structure = (
|
||||
('max_tfrag', '<H=4280'),
|
||||
('max_rfrag', '<H=4280'),
|
||||
('assoc_group', '<L=0'),
|
||||
('ctx_num', 'B=0'),
|
||||
('Reserved', 'B=0'),
|
||||
('Reserved2', '<H=0'),
|
||||
('_ctx_items', '_-ctx_items', 'self["ctx_num"]*self._CTX_ITEM_LEN'),
|
||||
('ctx_items', ':', CtxItemArray),
|
||||
)
|
||||
|
||||
class handler(pykms_RpcBase.rpcBase):
|
||||
def parseRequest(self):
|
||||
request = MSRPCHeader(self.data)
|
||||
ShellMessage.Process(3).run()
|
||||
request = byterize(request)
|
||||
loggersrv.debug("RPC Bind Request Bytes: \n%s\n" % justify(deco(binascii.b2a_hex(self.data), 'utf-8')))
|
||||
loggersrv.debug("RPC Bind Request: \n%s\n%s\n" % (justify(request.dump(print_to_stdout = False)),
|
||||
justify(MSRPCBind(request['pduData']).dump(print_to_stdout = False))))
|
||||
|
||||
return request
|
||||
|
||||
def generateResponse(self, request):
|
||||
response = MSRPCBindAck()
|
||||
|
||||
bind = MSRPCBind(request['pduData'])
|
||||
|
||||
response['ver_major'] = request['ver_major']
|
||||
response['ver_minor'] = request['ver_minor']
|
||||
response['type'] = self.packetType['bindAck']
|
||||
response['flags'] = self.packetFlags['firstFrag'] | self.packetFlags['lastFrag'] | self.packetFlags['multiplex']
|
||||
response['representation'] = request['representation']
|
||||
response['frag_len'] = 36 + bind['ctx_num'] * 24
|
||||
response['auth_len'] = request['auth_len']
|
||||
response['call_id'] = request['call_id']
|
||||
|
||||
response['max_tfrag'] = bind['max_tfrag']
|
||||
response['max_rfrag'] = bind['max_rfrag']
|
||||
response['assoc_group'] = 0x1063bf3f
|
||||
|
||||
port = str(self.srv_config['port'])
|
||||
response['SecondaryAddrLen'] = len(port) + 1
|
||||
response['SecondaryAddr'] = port
|
||||
pad = (4 - ((response["SecondaryAddrLen"] + MSRPCBindAck._SIZE) % 4)) % 4
|
||||
response['Pad'] = '\0' * pad
|
||||
response['ctx_num'] = bind['ctx_num']
|
||||
|
||||
preparedResponses = {}
|
||||
preparedResponses[uuidNDR32] = CtxItemResult(0, 0, uuidNDR32, 2)
|
||||
preparedResponses[uuidNDR64] = CtxItemResult(2, 2, uuidEmpty, 0)
|
||||
preparedResponses[uuidTime] = CtxItemResult(3, 3, uuidEmpty, 0)
|
||||
|
||||
response['ctx_items'] = ''
|
||||
for i in range (0, bind['ctx_num']):
|
||||
ts_uuid = bind['ctx_items'][i].ts()
|
||||
resp = preparedResponses[ts_uuid]
|
||||
response['ctx_items'] += str(resp)
|
||||
|
||||
ShellMessage.Process(4).run()
|
||||
response = byterize(response)
|
||||
loggersrv.debug("RPC Bind Response: \n%s\n" % justify(response.dump(print_to_stdout = False)))
|
||||
loggersrv.debug("RPC Bind Response Bytes: \n%s\n" % justify(deco(binascii.b2a_hex(enco(str(response), 'latin-1')), 'utf-8')))
|
||||
|
||||
return response
|
||||
|
||||
def generateRequest(self):
|
||||
firstCtxItem = CtxItem()
|
||||
firstCtxItem['ContextID'] = 0
|
||||
firstCtxItem['TransItems'] = 1
|
||||
firstCtxItem['Pad'] = 0
|
||||
firstCtxItem['AbstractSyntaxUUID'] = uuid.UUID('51c82175-844e-4750-b0d8-ec255555bc06').bytes_le
|
||||
firstCtxItem['AbstractSyntaxVer'] = 1
|
||||
firstCtxItem['TransferSyntaxUUID'] = uuidNDR32.bytes_le
|
||||
firstCtxItem['TransferSyntaxVer'] = 2
|
||||
|
||||
secondCtxItem = CtxItem()
|
||||
secondCtxItem['ContextID'] = 1
|
||||
secondCtxItem['TransItems'] = 1
|
||||
secondCtxItem['Pad'] = 0
|
||||
secondCtxItem['AbstractSyntaxUUID'] = uuid.UUID('51c82175-844e-4750-b0d8-ec255555bc06').bytes_le
|
||||
secondCtxItem['AbstractSyntaxVer'] = 1
|
||||
secondCtxItem['TransferSyntaxUUID'] = uuidTime.bytes_le
|
||||
secondCtxItem['TransferSyntaxVer'] = 1
|
||||
|
||||
bind = MSRPCBind()
|
||||
bind['max_tfrag'] = 5840
|
||||
bind['max_rfrag'] = 5840
|
||||
bind['assoc_group'] = 0
|
||||
bind['ctx_num'] = 2
|
||||
bind['ctx_items'] = str(bind.CtxItemArray(str(firstCtxItem) + str(secondCtxItem)))
|
||||
|
||||
request = MSRPCHeader()
|
||||
request['ver_major'] = 5
|
||||
request['ver_minor'] = 0
|
||||
request['type'] = self.packetType['bindReq']
|
||||
request['flags'] = self.packetFlags['firstFrag'] | self.packetFlags['lastFrag'] | self.packetFlags['multiplex']
|
||||
request['call_id'] = self.srv_config['call_id']
|
||||
request['pduData'] = str(bind)
|
||||
|
||||
ShellMessage.Process(0).run()
|
||||
bind = byterize(bind)
|
||||
request = byterize(request)
|
||||
loggersrv.debug("RPC Bind Request: \n%s\n%s\n" % (justify(request.dump(print_to_stdout = False)),
|
||||
justify(MSRPCBind(request['pduData']).dump(print_to_stdout = False))))
|
||||
loggersrv.debug("RPC Bind Request Bytes: \n%s\n" % justify(deco(binascii.b2a_hex(enco(str(request), 'latin-1')), 'utf-8')))
|
||||
|
||||
return request
|
||||
|
||||
def parseResponse(self):
|
||||
return response
|
70
py-kms/pykms_RpcRequest.py
Normal file
70
py-kms/pykms_RpcRequest.py
Normal file
@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import binascii
|
||||
import logging
|
||||
|
||||
import pykms_Base
|
||||
import pykms_RpcBase
|
||||
from pykms_Dcerpc import MSRPCRequestHeader, MSRPCRespHeader
|
||||
from pykms_Format import justify, byterize, enco, deco, ShellMessage
|
||||
|
||||
#----------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
loggersrv = logging.getLogger('logsrv')
|
||||
|
||||
class handler(pykms_RpcBase.rpcBase):
|
||||
def parseRequest(self):
|
||||
request = MSRPCRequestHeader(self.data)
|
||||
ShellMessage.Process(14).run()
|
||||
request = byterize(request)
|
||||
loggersrv.debug("RPC Message Request Bytes: \n%s\n" % justify(binascii.b2a_hex(self.data).decode('utf-8')))
|
||||
loggersrv.debug("RPC Message Request: \n%s\n" % justify(request.dump(print_to_stdout = False)))
|
||||
|
||||
return request
|
||||
|
||||
def generateResponse(self, request):
|
||||
responseData = pykms_Base.generateKmsResponseData(request['pduData'], self.srv_config)
|
||||
envelopeLength = len(responseData)
|
||||
|
||||
response = MSRPCRespHeader()
|
||||
response['ver_major'] = request['ver_major']
|
||||
response['ver_minor'] = request['ver_minor']
|
||||
response['type'] = self.packetType['response']
|
||||
response['flags'] = self.packetFlags['firstFrag'] | self.packetFlags['lastFrag']
|
||||
response['representation'] = request['representation']
|
||||
response['call_id'] = request['call_id']
|
||||
|
||||
response['alloc_hint'] = envelopeLength
|
||||
response['ctx_id'] = request['ctx_id']
|
||||
response['cancel_count'] = 0
|
||||
|
||||
response['pduData'] = responseData
|
||||
|
||||
ShellMessage.Process(17).run()
|
||||
response = byterize(response)
|
||||
loggersrv.debug("RPC Message Response: \n%s\n" % justify(response.dump(print_to_stdout = False)))
|
||||
loggersrv.debug("RPC Message Response Bytes: \n%s\n" % justify(deco(binascii.b2a_hex(enco(str(response), 'latin-1')), 'utf-8')))
|
||||
|
||||
return response
|
||||
|
||||
def generateRequest(self):
|
||||
request = MSRPCRequestHeader()
|
||||
|
||||
request['ver_major'] = 5
|
||||
request['ver_minor'] = 0
|
||||
request['type'] = self.packetType['request']
|
||||
request['flags'] = self.packetFlags['firstFrag'] | self.packetFlags['lastFrag']
|
||||
request['representation'] = 0x10
|
||||
request['call_id'] = self.srv_config['call_id']
|
||||
request['alloc_hint'] = len(self.data)
|
||||
request['pduData'] = str(self.data)
|
||||
|
||||
ShellMessage.Process(11).run()
|
||||
request = byterize(request)
|
||||
loggersrv.debug("RPC Message Request: \n%s\n" % justify(request.dump(print_to_stdout = False)))
|
||||
loggersrv.debug("RPC Message Request Bytes: \n%s\n" % justify(deco(binascii.b2a_hex(enco(str(request), 'latin-1')), 'utf-8')))
|
||||
|
||||
return request
|
||||
|
||||
def parseResponse(self):
|
||||
return response
|
266
py-kms/pykms_Server.py
Normal file
266
py-kms/pykms_Server.py
Normal file
@ -0,0 +1,266 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import binascii
|
||||
import re
|
||||
import sys
|
||||
import socket
|
||||
import uuid
|
||||
import logging
|
||||
import os
|
||||
import errno
|
||||
import threading
|
||||
|
||||
try:
|
||||
# Python 2 import.
|
||||
import SocketServer as socketserver
|
||||
import Queue as Queue
|
||||
except ImportError:
|
||||
# Python 3 import.
|
||||
import socketserver
|
||||
import queue as Queue
|
||||
|
||||
import pykms_RpcBind, pykms_RpcRequest
|
||||
from pykms_RpcBase import rpcBase
|
||||
from pykms_Dcerpc import MSRPCHeader
|
||||
from pykms_Misc import ValidLcid, logger_create
|
||||
from pykms_Format import enco, deco, ShellMessage
|
||||
|
||||
srv_description = 'KMS Server Emulator written in Python'
|
||||
srv_version = 'py-kms_2019-05-15'
|
||||
srv_config = {}
|
||||
|
||||
##---------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
class server_thread(threading.Thread):
|
||||
def __init__(self):
|
||||
threading.Thread.__init__(self)
|
||||
self.queue = serverqueue
|
||||
self.is_running = False
|
||||
self.daemon = True
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
if not self.queue.empty():
|
||||
item = self.queue.get()
|
||||
if item == 'start':
|
||||
self.is_running = True
|
||||
# Check options.
|
||||
server_check()
|
||||
# Create and run threaded server.
|
||||
self.server = server_create()
|
||||
try:
|
||||
self.server.serve_forever()
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(0)
|
||||
elif item == 'stop':
|
||||
self.is_running = False
|
||||
self.server = None
|
||||
self.queue.task_done()
|
||||
|
||||
##-----------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
loggersrv = logging.getLogger('logsrv')
|
||||
|
||||
# 'help' string - 'default' value - 'dest' string.
|
||||
srv_options = {
|
||||
'ip' : {'help' : 'The IP address to listen on. The default is \"0.0.0.0\" (all interfaces).', 'def' : "0.0.0.0", 'des' : "ip"},
|
||||
'port' : {'help' : 'The network port to listen on. The default is \"1688\".', 'def' : 1688, 'des' : "port"},
|
||||
'epid' : {'help' : 'Use this option to manually specify an ePID to use. If no ePID is specified, a random ePID will be auto generated.',
|
||||
'def' : None, 'des' : "epid"},
|
||||
'lcid' : {'help' : 'Use this option to manually specify an LCID for use with randomly generated ePIDs. Default is \"1033\" (en-us)',
|
||||
'def' : 1033, 'des' : "lcid"},
|
||||
'count' : {'help' : 'Use this option to specify the current client count. A number >=25 is required to enable activation of client OSes; \
|
||||
for server OSes and Office >=5', 'def' : None, 'des' : "CurrentClientCount"},
|
||||
'activation' : {'help' : 'Use this option to specify the activation interval (in minutes). Default is \"120\" minutes (2 hours).',
|
||||
'def' : 120, 'des': "VLActivationInterval"},
|
||||
'renewal' : {'help' : 'Use this option to specify the renewal interval (in minutes). Default is \"10080\" minutes (7 days).',
|
||||
'def' : 1440 * 7, 'des' : "VLRenewalInterval"},
|
||||
'sql' : {'help' : 'Use this option to store request information from unique clients in an SQLite database. Desactivated by default.',
|
||||
'def' : False, 'des' : "sqlite"},
|
||||
'hwid' : {'help' : 'Use this option to specify a HWID. The HWID must be an 16-character string of hex characters. \
|
||||
The default is \"364F463A8863D35F\" or type \"RANDOM\" to auto generate the HWID.', 'def' : "364F463A8863D35F", 'des' : "hwid"},
|
||||
'time' : {'help' : 'Disconnect clients after time of inactivity (in seconds). The default is \"30\" seconds', 'def' : 30, 'des' : "timeout"},
|
||||
'llevel' : {'help' : 'Use this option to set a log level. The default is \"ERROR\".', 'def' : "ERROR", 'des' : "loglevel",
|
||||
'choi' : ["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG", "MINI"]},
|
||||
'lfile' : {'help' : 'Use this option to set or not an output log file. The default is \"pykms_logserver.log\" or type \"STDOUT\" to view log info on stdout.',
|
||||
'def' : os.path.dirname(os.path.abspath( __file__ )) + "/pykms_logserver.log", 'des' : "logfile"},
|
||||
'lsize' : {'help' : 'Use this flag to set a maximum size (in MB) to the output log file. Desactivated by default.', 'def' : 0, 'des': "logsize"},
|
||||
}
|
||||
|
||||
def server_options():
|
||||
parser = argparse.ArgumentParser(description = srv_description, epilog = 'version: ' + srv_version)
|
||||
parser.add_argument("ip", nargs = "?", action = "store", default = srv_options['ip']['def'], help = srv_options['ip']['help'], type = str)
|
||||
parser.add_argument("port", nargs = "?", action = "store", default = srv_options['port']['def'], help = srv_options['port']['help'], type = int)
|
||||
parser.add_argument("-e", "--epid", dest = srv_options['epid']['des'], default = srv_options['epid']['def'], help = srv_options['epid']['help'], type = str)
|
||||
parser.add_argument("-l", "--lcid", dest = srv_options['lcid']['des'], default = srv_options['lcid']['def'], help = srv_options['lcid']['help'], type = int)
|
||||
parser.add_argument("-c", "--client-count", dest = srv_options['count']['des'] , default = srv_options['count']['def'],
|
||||
help = srv_options['count']['help'], type = int)
|
||||
parser.add_argument("-a", "--activation-interval", dest = srv_options['activation']['des'], default = srv_options['activation']['def'],
|
||||
help = srv_options['activation']['help'], type = int)
|
||||
parser.add_argument("-r", "--renewal-interval", dest = srv_options['renewal']['des'], default = srv_options['renewal']['def'],
|
||||
help = srv_options['renewal']['help'], type = int)
|
||||
parser.add_argument("-s", "--sqlite", dest = srv_options['sql']['des'], action = "store_const", const = True, default = srv_options['sql']['def'],
|
||||
help = srv_options['sql']['help'])
|
||||
parser.add_argument("-w", "--hwid", dest = srv_options['hwid']['des'], action = "store", default = srv_options['hwid']['def'],
|
||||
help = srv_options['hwid']['help'], type = str)
|
||||
parser.add_argument("-t", "--timeout", dest = srv_options['time']['des'], action = "store", default = srv_options['time']['def'],
|
||||
help = srv_options['time']['help'], type = int)
|
||||
parser.add_argument("-V", "--loglevel", dest = srv_options['llevel']['des'], action = "store", choices = srv_options['llevel']['choi'],
|
||||
default = srv_options['llevel']['def'], help = srv_options['llevel']['help'], type = str)
|
||||
parser.add_argument("-F", "--logfile", dest = srv_options['lfile']['des'], action = "store", default = srv_options['lfile']['def'],
|
||||
help = srv_options['lfile']['help'], type = str)
|
||||
parser.add_argument("-S", "--logsize", dest = srv_options['lsize']['des'], action = "store", default = srv_options['lsize']['def'],
|
||||
help = srv_options['lsize']['help'], type = float)
|
||||
|
||||
srv_config.update(vars(parser.parse_args()))
|
||||
|
||||
|
||||
def server_check():
|
||||
# Setup hidden or not messages.
|
||||
ShellMessage.view = ( False if srv_config['logfile'] == 'STDOUT' else True )
|
||||
# Create log.
|
||||
logger_create(loggersrv, srv_config, mode = 'a')
|
||||
|
||||
# Random HWID.
|
||||
if srv_config['hwid'] == "RANDOM":
|
||||
randomhwid = uuid.uuid4().hex
|
||||
srv_config['hwid'] = randomhwid[:16]
|
||||
|
||||
# Sanitize HWID.
|
||||
try:
|
||||
srv_config['hwid'] = binascii.a2b_hex(re.sub(r'[^0-9a-fA-F]', '', srv_config['hwid'].strip('0x')))
|
||||
if len(binascii.b2a_hex(srv_config['hwid'])) < 16:
|
||||
loggersrv.error("HWID \"%s\" is invalid. Hex string is too short." % deco(binascii.b2a_hex(srv_config['hwid']), 'utf-8').upper())
|
||||
return
|
||||
elif len(binascii.b2a_hex(srv_config['hwid'])) > 16:
|
||||
loggersrv.error("HWID \"%s\" is invalid. Hex string is too long." % deco(binascii.b2a_hex(srv_config['hwid']), 'utf-8').upper())
|
||||
return
|
||||
except TypeError:
|
||||
loggersrv.error("HWID \"%s\" is invalid. Odd-length hex string." % deco(binascii.b2a_hex(srv_config['hwid']), 'utf-8').upper())
|
||||
return
|
||||
|
||||
# Check LCID.
|
||||
# http://stackoverflow.com/questions/3425294/how-to-detect-the-os-default-language-in-python
|
||||
if not srv_config['lcid'] or (srv_config['lcid'] not in ValidLcid):
|
||||
if hasattr(sys, 'implementation') and sys.implementation.name == 'cpython':
|
||||
srv_config['lcid'] = 1033
|
||||
elif os.name == 'nt':
|
||||
import ctypes
|
||||
|
||||
srv_config['lcid'] = ctypes.windll.kernel32.GetUserDefaultUILanguage()
|
||||
else:
|
||||
import locale
|
||||
|
||||
try:
|
||||
srv_config['lcid'] = next(k for k, v in locale.windows_locale.items() if v == locale.getdefaultlocale()[0])
|
||||
except StopIteration:
|
||||
srv_config['lcid'] = 1033
|
||||
|
||||
# Check sqlite.
|
||||
try:
|
||||
import sqlite3
|
||||
except:
|
||||
loggersrv.warning("Module \"sqlite3\" is not installed, database support disabled.")
|
||||
srv_config['dbSupport'] = False
|
||||
else:
|
||||
srv_config['dbSupport'] = True
|
||||
|
||||
# Check port.
|
||||
try:
|
||||
p = srv_config['port']
|
||||
if p > 65535:
|
||||
loggersrv.error('Please enter a valid port number between 1 - 65535')
|
||||
return
|
||||
except Exception as e:
|
||||
loggersrv.error('%s' %e)
|
||||
return
|
||||
|
||||
def server_create():
|
||||
socketserver.TCPServer.allow_reuse_address = True
|
||||
server = socketserver.TCPServer((srv_config['ip'], srv_config['port']), kmsServer)
|
||||
server.timeout = srv_config['timeout']
|
||||
loggersrv.info("\n\nTCP server listening at %s on port %d." % (srv_config['ip'], srv_config['port']))
|
||||
loggersrv.info("HWID: %s" % deco(binascii.b2a_hex(srv_config['hwid']), 'utf-8').upper())
|
||||
return server
|
||||
|
||||
def srv_main_without_gui():
|
||||
# Parse options.
|
||||
server_options()
|
||||
# Run threaded server.
|
||||
serverqueue.put('start')
|
||||
serverthread.join()
|
||||
|
||||
def srv_main_with_gui(width = 950, height = 660):
|
||||
import pykms_GuiBase
|
||||
|
||||
root = pykms_GuiBase.KmsGui()
|
||||
root.title(pykms_GuiBase.gui_description + ' ' + pykms_GuiBase.gui_version)
|
||||
# Main window initial position.
|
||||
## https://stackoverflow.com/questions/14910858/how-to-specify-where-a-tkinter-window-opens
|
||||
ws = root.winfo_screenwidth()
|
||||
hs = root.winfo_screenheight()
|
||||
x = (ws / 2) - (width / 2)
|
||||
y = (hs / 2) - (height / 2)
|
||||
root.geometry('+%d+%d' %(x, y))
|
||||
|
||||
root.mainloop()
|
||||
|
||||
|
||||
class kmsServer(socketserver.BaseRequestHandler):
|
||||
def setup(self):
|
||||
loggersrv.info("Connection accepted: %s:%d" % (self.client_address[0], self.client_address[1]))
|
||||
|
||||
def handle(self):
|
||||
while True:
|
||||
# self.request is the TCP socket connected to the client
|
||||
try:
|
||||
self.data = self.request.recv(1024)
|
||||
except socket.error as e:
|
||||
if e.errno == errno.ECONNRESET:
|
||||
loggersrv.error("Connection reset by peer.")
|
||||
break
|
||||
else:
|
||||
raise
|
||||
if self.data == '' or not self.data:
|
||||
loggersrv.warning("No data received !")
|
||||
break
|
||||
|
||||
packetType = MSRPCHeader(self.data)['type']
|
||||
if packetType == rpcBase.packetType['bindReq']:
|
||||
loggersrv.info("RPC bind request received.")
|
||||
ShellMessage.Process([-2, 2]).run()
|
||||
handler = pykms_RpcBind.handler(self.data, srv_config)
|
||||
elif packetType == rpcBase.packetType['request']:
|
||||
loggersrv.info("Received activation request.")
|
||||
ShellMessage.Process([-2, 13]).run()
|
||||
handler = pykms_RpcRequest.handler(self.data, srv_config)
|
||||
else:
|
||||
loggersrv.error("Invalid RPC request type ", packetType)
|
||||
break
|
||||
|
||||
res = enco(str(handler.populate()), 'latin-1')
|
||||
self.request.send(res)
|
||||
|
||||
if packetType == rpcBase.packetType['bindReq']:
|
||||
loggersrv.info("RPC bind acknowledged.")
|
||||
ShellMessage.Process([-3, 5, 6]).run()
|
||||
elif packetType == rpcBase.packetType['request']:
|
||||
loggersrv.info("Responded to activation request.")
|
||||
ShellMessage.Process([-3, 18, 19]).run()
|
||||
break
|
||||
|
||||
def finish(self):
|
||||
self.request.close()
|
||||
loggersrv.info("Connection closed: %s:%d" % (self.client_address[0], self.client_address[1]))
|
||||
|
||||
|
||||
serverqueue = Queue.Queue(maxsize = 0)
|
||||
serverthread = server_thread()
|
||||
serverthread.start()
|
||||
|
||||
if __name__ == "__main__":
|
||||
if sys.stdout.isatty():
|
||||
srv_main_without_gui()
|
||||
else:
|
||||
srv_main_with_gui()
|
96
py-kms/pykms_Sql.py
Normal file
96
py-kms/pykms_Sql.py
Normal file
@ -0,0 +1,96 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import logging
|
||||
|
||||
# sqlite3 is optional.
|
||||
try:
|
||||
import sqlite3
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
#--------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
logger = logging.getLogger('root')
|
||||
|
||||
def sql_initialize():
|
||||
dbName = 'clients.db'
|
||||
if not os.path.isfile(dbName):
|
||||
# Initialize the database.
|
||||
con = None
|
||||
try:
|
||||
con = sqlite3.connect(dbName)
|
||||
cur = con.cursor()
|
||||
cur.execute("CREATE TABLE clients(clientMachineId TEXT, machineName TEXT, applicationId TEXT, skuId TEXT, \
|
||||
licenseStatus TEXT, lastRequestTime INTEGER, kmsEpid TEXT, requestCount INTEGER)")
|
||||
|
||||
except sqlite3.Error as e:
|
||||
logger.error("Error %s:" % e.args[0])
|
||||
sys.exit(1)
|
||||
finally:
|
||||
if con:
|
||||
con.commit()
|
||||
con.close()
|
||||
return dbName
|
||||
|
||||
|
||||
def sql_update(dbName, infoDict):
|
||||
con = None
|
||||
try:
|
||||
con = sqlite3.connect(dbName)
|
||||
cur = con.cursor()
|
||||
cur.execute("SELECT * FROM clients WHERE clientMachineId=:clientMachineId;", infoDict)
|
||||
try:
|
||||
data = cur.fetchone()
|
||||
if not data:
|
||||
# Insert row.
|
||||
cur.execute("INSERT INTO clients (clientMachineId, machineName, applicationId, \
|
||||
skuId, licenseStatus, lastRequestTime, requestCount) VALUES (:clientMachineId, :machineName, :appId, :skuId, :licenseStatus, :requestTime, 1);", infoDict)
|
||||
else:
|
||||
# Update data.
|
||||
if data[1] != infoDict["machineName"]:
|
||||
cur.execute("UPDATE clients SET machineName=:machineName WHERE clientMachineId=:clientMachineId;", infoDict)
|
||||
if data[2] != infoDict["appId"]:
|
||||
cur.execute("UPDATE clients SET applicationId=:appId WHERE clientMachineId=:clientMachineId;", infoDict)
|
||||
if data[3] != infoDict["skuId"]:
|
||||
cur.execute("UPDATE clients SET skuId=:skuId WHERE clientMachineId=:clientMachineId;", infoDict)
|
||||
if data[4] != infoDict["licenseStatus"]:
|
||||
cur.execute("UPDATE clients SET licenseStatus=:licenseStatus WHERE clientMachineId=:clientMachineId;", infoDict)
|
||||
if data[5] != infoDict["requestTime"]:
|
||||
cur.execute("UPDATE clients SET lastRequestTime=:requestTime WHERE clientMachineId=:clientMachineId;", infoDict)
|
||||
# Increment requestCount
|
||||
cur.execute("UPDATE clients SET requestCount=requestCount+1 WHERE clientMachineId=:clientMachineId;", infoDict)
|
||||
|
||||
except sqlite3.Error as e:
|
||||
logger.error("Error %s:" % e.args[0])
|
||||
except sqlite3.Error as e:
|
||||
logger.error("Error %s:" % e.args[0])
|
||||
sys.exit(1)
|
||||
finally:
|
||||
if con:
|
||||
con.commit()
|
||||
con.close()
|
||||
|
||||
def sql_update_epid(dbName, kmsRequest, response):
|
||||
cmid = str(kmsRequest['clientMachineId'].get())
|
||||
con = None
|
||||
try:
|
||||
con = sqlite3.connect(self.dbName)
|
||||
cur = con.cursor()
|
||||
cur.execute("SELECT * FROM clients WHERE clientMachineId=?;", [cmid])
|
||||
try:
|
||||
data = cur.fetchone()
|
||||
if data[6]:
|
||||
response["kmsEpid"] = data[6].encode('utf-16le')
|
||||
else:
|
||||
cur.execute("UPDATE clients SET kmsEpid=? WHERE clientMachineId=?;", (str(response["kmsEpid"].decode('utf-16le')),
|
||||
cmid))
|
||||
except sqlite3.Error as e:
|
||||
logger.error("Error %s:" % e.args[0])
|
||||
except sqlite3.Error as e:
|
||||
logger.error("Error %s:" % e.args[0])
|
||||
sys.exit(1)
|
||||
finally:
|
||||
if con:
|
||||
con.commit()
|
||||
con.close()
|
||||
return response
|
763
py-kms/pykms_Structure.py
Normal file
763
py-kms/pykms_Structure.py
Normal file
@ -0,0 +1,763 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (c) 2003-2012 CORE Security Technologies
|
||||
#
|
||||
# This software is provided under under a slightly modified version
|
||||
# of the Apache Software License. See the accompanying LICENSE file
|
||||
# for more information.
|
||||
#
|
||||
"""
|
||||
Stripped down version of: https://github.com/CoreSecurity/impacket/blob/python3/impacket/structure.py
|
||||
with modifications in the function dump(...).
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
from struct import pack, unpack, calcsize
|
||||
|
||||
# Trying to support both Python 2 and 3
|
||||
import sys
|
||||
|
||||
if sys.version_info[0] == 2:
|
||||
# Python 2.x
|
||||
def b(x):
|
||||
return x
|
||||
def buildStr(x):
|
||||
return x
|
||||
else:
|
||||
import codecs
|
||||
def b(x):
|
||||
if isinstance(x, bytes) is False:
|
||||
return codecs.latin_1_encode(x)[0]
|
||||
return x
|
||||
def buildStr(x):
|
||||
if isinstance(x, bytes):
|
||||
return "".join(map(chr,x))
|
||||
else:
|
||||
return x
|
||||
|
||||
class Structure:
|
||||
""" sublcasses can define commonHdr and/or structure.
|
||||
each of them is an tuple of either two: (fieldName, format) or three: (fieldName, ':', class) fields.
|
||||
[it can't be a dictionary, because order is important]
|
||||
|
||||
where format specifies how the data in the field will be converted to/from bytes (string)
|
||||
class is the class to use when unpacking ':' fields.
|
||||
|
||||
each field can only contain one value (or an array of values for *)
|
||||
i.e. struct.pack('Hl',1,2) is valid, but format specifier 'Hl' is not (you must use 2 dfferent fields)
|
||||
|
||||
format specifiers:
|
||||
specifiers from module pack can be used with the same format
|
||||
see struct.__doc__ (pack/unpack is finally called)
|
||||
x [padding byte]
|
||||
c [character]
|
||||
b [signed byte]
|
||||
B [unsigned byte]
|
||||
h [signed short]
|
||||
H [unsigned short]
|
||||
l [signed long]
|
||||
L [unsigned long]
|
||||
i [signed integer]
|
||||
I [unsigned integer]
|
||||
q [signed long long (quad)]
|
||||
Q [unsigned long long (quad)]
|
||||
s [string (array of chars), must be preceded with length in format specifier, padded with zeros]
|
||||
p [pascal string (includes byte count), must be preceded with length in format specifier, padded with zeros]
|
||||
f [float]
|
||||
d [double]
|
||||
= [native byte ordering, size and alignment]
|
||||
@ [native byte ordering, standard size and alignment]
|
||||
! [network byte ordering]
|
||||
< [little endian]
|
||||
> [big endian]
|
||||
|
||||
usual printf like specifiers can be used (if started with %)
|
||||
[not recommeneded, there is no why to unpack this]
|
||||
|
||||
%08x will output an 8 bytes hex
|
||||
%s will output a string
|
||||
%s\\x00 will output a NUL terminated string
|
||||
%d%d will output 2 decimal digits (against the very same specification of Structure)
|
||||
...
|
||||
|
||||
some additional format specifiers:
|
||||
: just copy the bytes from the field into the output string (input may be string, other structure, or anything responding to __str__()) (for unpacking, all what's left is returned)
|
||||
z same as :, but adds a NUL byte at the end (asciiz) (for unpacking the first NUL byte is used as terminator) [asciiz string]
|
||||
u same as z, but adds two NUL bytes at the end (after padding to an even size with NULs). (same for unpacking) [unicode string]
|
||||
w DCE-RPC/NDR string (it's a macro for [ '<L=(len(field)+1)/2','"\\x00\\x00\\x00\\x00','<L=(len(field)+1)/2',':' ]
|
||||
?-field length of field named 'field', formated as specified with ? ('?' may be '!H' for example). The input value overrides the real length
|
||||
?1*?2 array of elements. Each formated as '?2', the number of elements in the array is stored as specified by '?1' (?1 is optional, or can also be a constant (number), for unpacking)
|
||||
'xxxx literal xxxx (field's value doesn't change the output. quotes must not be closed or escaped)
|
||||
"xxxx literal xxxx (field's value doesn't change the output. quotes must not be closed or escaped)
|
||||
_ will not pack the field. Accepts a third argument, which is an unpack code. See _Test_UnpackCode for an example
|
||||
?=packcode will evaluate packcode in the context of the structure, and pack the result as specified by ?. Unpacking is made plain
|
||||
?&fieldname "Address of field fieldname".
|
||||
For packing it will simply pack the id() of fieldname. Or use 0 if fieldname doesn't exists.
|
||||
For unpacking, it's used to know weather fieldname has to be unpacked or not, i.e. by adding a & field you turn another field (fieldname) in an optional field.
|
||||
|
||||
"""
|
||||
commonHdr = ()
|
||||
structure = ()
|
||||
debug = 0
|
||||
|
||||
def __init__(self, data = None, alignment = 0):
|
||||
if not hasattr(self, 'alignment'):
|
||||
self.alignment = alignment
|
||||
|
||||
self.fields = {}
|
||||
self.rawData = data
|
||||
if data is not None:
|
||||
self.fromString(data)
|
||||
else:
|
||||
self.data = None
|
||||
|
||||
def packField(self, fieldName, format = None):
|
||||
if self.debug:
|
||||
print("packField( %s | %s )" % (fieldName, format))
|
||||
|
||||
if format is None:
|
||||
format = self.formatForField(fieldName)
|
||||
|
||||
if fieldName in self.fields:
|
||||
ans = self.pack(format, self.fields[fieldName], field = fieldName)
|
||||
else:
|
||||
ans = self.pack(format, None, field = fieldName)
|
||||
|
||||
if self.debug:
|
||||
print("\tanswer %r" % ans)
|
||||
|
||||
return ans
|
||||
|
||||
def getData(self):
|
||||
if self.data is not None:
|
||||
return self.data
|
||||
data = b''
|
||||
for field in self.commonHdr+self.structure:
|
||||
try:
|
||||
data += b(self.packField(field[0], field[1]))
|
||||
except Exception as e:
|
||||
if field[0] in self.fields:
|
||||
e.args += ("When packing field '%s | %s | %r' in %s" % (field[0], field[1], self[field[0]], self.__class__),)
|
||||
else:
|
||||
e.args += ("When packing field '%s | %s' in %s" % (field[0], field[1], self.__class__),)
|
||||
raise
|
||||
if self.alignment:
|
||||
if len(data) % self.alignment:
|
||||
data += b('\x00'*self.alignment)[:-(len(data) % self.alignment)]
|
||||
|
||||
#if len(data) % self.alignment: data += ('\x00'*self.alignment)[:-(len(data) % self.alignment)]
|
||||
if isinstance(data,str):
|
||||
return data
|
||||
return buildStr(data)
|
||||
|
||||
def fromString(self, data):
|
||||
self.rawData = data
|
||||
data = buildStr(data)
|
||||
|
||||
for field in self.commonHdr+self.structure:
|
||||
if self.debug:
|
||||
print("fromString( %s | %s | %r )" % (field[0], field[1], data))
|
||||
size = self.calcUnpackSize(field[1], data, field[0])
|
||||
if self.debug:
|
||||
print(" size = %d" % size)
|
||||
dataClassOrCode = str
|
||||
if len(field) > 2:
|
||||
dataClassOrCode = field[2]
|
||||
try:
|
||||
self[field[0]] = self.unpack(field[1], data[:size], dataClassOrCode = dataClassOrCode, field = field[0])
|
||||
except Exception as e:
|
||||
e.args += ("When unpacking field '%s | %s | %r[:%d]'" % (field[0], field[1], data, size),)
|
||||
raise
|
||||
|
||||
size = self.calcPackSize(field[1], self[field[0]], field[0])
|
||||
if self.alignment and size % self.alignment:
|
||||
size += self.alignment - (size % self.alignment)
|
||||
data = data[size:]
|
||||
|
||||
return self
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
self.fields[key] = value
|
||||
self.data = None # force recompute
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.fields[key]
|
||||
|
||||
def __delitem__(self, key):
|
||||
del self.fields[key]
|
||||
|
||||
def __str__(self):
|
||||
return self.getData()
|
||||
|
||||
def __len__(self):
|
||||
# XXX: improve
|
||||
return len(self.getData())
|
||||
|
||||
def pack(self, format, data, field = None):
|
||||
if self.debug:
|
||||
print(" pack( %s | %r | %s)" % (format, data, field))
|
||||
|
||||
if field:
|
||||
addressField = self.findAddressFieldFor(field)
|
||||
if (addressField is not None) and (data is None):
|
||||
return b''
|
||||
|
||||
# void specifier
|
||||
if format[:1] == '_':
|
||||
return b''
|
||||
|
||||
# quote specifier
|
||||
if format[:1] == "'" or format[:1] == '"':
|
||||
return b(format[1:])
|
||||
|
||||
# code specifier
|
||||
two = format.split('=')
|
||||
if len(two) >= 2:
|
||||
try:
|
||||
return self.pack(two[0], data)
|
||||
except:
|
||||
fields = {'self':self}
|
||||
fields.update(self.fields)
|
||||
return self.pack(two[0], eval(two[1], {}, fields))
|
||||
|
||||
# address specifier
|
||||
two = format.split('&')
|
||||
if len(two) == 2:
|
||||
try:
|
||||
return self.pack(two[0], data)
|
||||
except:
|
||||
if (two[1] in self.fields) and (self[two[1]] is not None):
|
||||
return self.pack(two[0], id(self[two[1]]) & ((1<<(calcsize(two[0])*8))-1) )
|
||||
else:
|
||||
return self.pack(two[0], 0)
|
||||
|
||||
# length specifier
|
||||
two = format.split('-')
|
||||
if len(two) == 2:
|
||||
try:
|
||||
return self.pack(two[0],data)
|
||||
except:
|
||||
return self.pack(two[0], self.calcPackFieldSize(two[1]))
|
||||
|
||||
# array specifier
|
||||
two = format.split('*')
|
||||
if len(two) == 2:
|
||||
answer = b''
|
||||
for each in data:
|
||||
answer += self.pack(two[1], each)
|
||||
if two[0]:
|
||||
if two[0].isdigit():
|
||||
if int(two[0]) != len(data):
|
||||
raise Exception("Array field has a constant size, and it doesn't match the actual value")
|
||||
else:
|
||||
return self.pack(two[0], len(data))+answer
|
||||
return answer
|
||||
|
||||
# "printf" string specifier
|
||||
if format[:1] == '%':
|
||||
# format string like specifier
|
||||
return format % data
|
||||
|
||||
# asciiz specifier
|
||||
if format[:1] == 'z':
|
||||
return b(data)+b'\0'
|
||||
|
||||
# unicode specifier
|
||||
if format[:1] == 'u':
|
||||
return b(data)+b'\0\0' + (len(data) & 1 and b'\0' or b'')
|
||||
|
||||
# DCE-RPC/NDR string specifier
|
||||
if format[:1] == 'w':
|
||||
if len(data) == 0:
|
||||
data = '\0\0'
|
||||
elif len(data) % 2:
|
||||
data += '\0'
|
||||
l = pack('<L', int(len(data)/2))
|
||||
l = buildStr(l)
|
||||
return b('%s\0\0\0\0%s%s' % (l,l,data))
|
||||
|
||||
if data is None:
|
||||
raise Exception("Trying to pack None")
|
||||
|
||||
# literal specifier
|
||||
if format[:1] == ':':
|
||||
# Inner Structures?
|
||||
if isinstance(data,Structure):
|
||||
return b(data.getData())
|
||||
return b(data)
|
||||
|
||||
# struct like specifier
|
||||
if isinstance(data, str):
|
||||
return pack(format, b(data))
|
||||
else:
|
||||
return pack(format, data)
|
||||
|
||||
def unpack(self, format, data, dataClassOrCode = str, field = None):
|
||||
if self.debug:
|
||||
print(" unpack( %s | %r )" % (format, data))
|
||||
|
||||
if field:
|
||||
addressField = self.findAddressFieldFor(field)
|
||||
if addressField is not None:
|
||||
if not self[addressField]:
|
||||
return
|
||||
|
||||
# void specifier
|
||||
if format[:1] == '_':
|
||||
if dataClassOrCode != str:
|
||||
fields = {'self':self, 'inputDataLeft':data}
|
||||
fields.update(self.fields)
|
||||
return eval(dataClassOrCode, {}, fields)
|
||||
else:
|
||||
return None
|
||||
|
||||
# quote specifier
|
||||
if format[:1] == "'" or format[:1] == '"':
|
||||
answer = format[1:]
|
||||
if answer != data:
|
||||
raise Exception("Unpacked data doesn't match constant value '%r' should be '%r'" % (data, answer))
|
||||
return answer
|
||||
|
||||
# address specifier
|
||||
two = format.split('&')
|
||||
if len(two) == 2:
|
||||
return self.unpack(two[0],data)
|
||||
|
||||
# code specifier
|
||||
two = format.split('=')
|
||||
if len(two) >= 2:
|
||||
return self.unpack(two[0],data)
|
||||
|
||||
# length specifier
|
||||
two = format.split('-')
|
||||
if len(two) == 2:
|
||||
return self.unpack(two[0],data)
|
||||
|
||||
# array specifier
|
||||
two = format.split('*')
|
||||
if len(two) == 2:
|
||||
answer = []
|
||||
sofar = 0
|
||||
if two[0].isdigit():
|
||||
number = int(two[0])
|
||||
elif two[0]:
|
||||
sofar += self.calcUnpackSize(two[0], data)
|
||||
number = self.unpack(two[0], data[:sofar])
|
||||
else:
|
||||
number = -1
|
||||
while number and sofar < len(data):
|
||||
nsofar = sofar + self.calcUnpackSize(two[1],data[sofar:])
|
||||
answer.append(self.unpack(two[1], data[sofar:nsofar], dataClassOrCode))
|
||||
number -= 1
|
||||
sofar = nsofar
|
||||
return answer
|
||||
|
||||
# "printf" string specifier
|
||||
if format[:1] == '%':
|
||||
# format string like specifier
|
||||
return format % data
|
||||
|
||||
# asciiz specifier
|
||||
if format == 'z':
|
||||
if data[-1] != '\x00':
|
||||
raise Exception("%s 'z' field is not NUL terminated: %r" % (field, data))
|
||||
return data[:-1] # remove trailing NUL
|
||||
|
||||
# unicode specifier
|
||||
if format == 'u':
|
||||
if data[-2:] != '\x00\x00':
|
||||
raise Exception("%s 'u' field is not NUL-NUL terminated: %r" % (field, data))
|
||||
return data[:-2] # remove trailing NUL
|
||||
|
||||
# DCE-RPC/NDR string specifier
|
||||
if format == 'w':
|
||||
l = unpack('<L', b(data[:4]))[0]
|
||||
return data[12:12+l*2]
|
||||
|
||||
# literal specifier
|
||||
if format == ':':
|
||||
return dataClassOrCode(data)
|
||||
|
||||
# struct like specifier
|
||||
if format.find('s') >=0:
|
||||
return buildStr(unpack(format, b(data))[0])
|
||||
else:
|
||||
return unpack(format, b(data))[0]
|
||||
|
||||
def calcPackSize(self, format, data, field = None):
|
||||
#print( " calcPackSize %s:%r" % (format, data))
|
||||
if field:
|
||||
addressField = self.findAddressFieldFor(field)
|
||||
if addressField is not None:
|
||||
if not self[addressField]:
|
||||
return 0
|
||||
|
||||
# void specifier
|
||||
if format[:1] == '_':
|
||||
return 0
|
||||
|
||||
# quote specifier
|
||||
if format[:1] == "'" or format[:1] == '"':
|
||||
return len(format)-1
|
||||
|
||||
# address specifier
|
||||
two = format.split('&')
|
||||
if len(two) == 2:
|
||||
return self.calcPackSize(two[0], data)
|
||||
|
||||
# code specifier
|
||||
two = format.split('=')
|
||||
if len(two) >= 2:
|
||||
return self.calcPackSize(two[0], data)
|
||||
|
||||
# length specifier
|
||||
two = format.split('-')
|
||||
if len(two) == 2:
|
||||
return self.calcPackSize(two[0], data)
|
||||
|
||||
# array specifier
|
||||
two = format.split('*')
|
||||
if len(two) == 2:
|
||||
answer = 0
|
||||
if two[0].isdigit():
|
||||
if int(two[0]) != len(data):
|
||||
raise Exception("Array field has a constant size, and it doesn't match the actual value")
|
||||
elif two[0]:
|
||||
answer += self.calcPackSize(two[0], len(data))
|
||||
|
||||
for each in data:
|
||||
answer += self.calcPackSize(two[1], each)
|
||||
return answer
|
||||
|
||||
# "printf" string specifier
|
||||
if format[:1] == '%':
|
||||
# format string like specifier
|
||||
return len(format % data)
|
||||
|
||||
# asciiz specifier
|
||||
if format[:1] == 'z':
|
||||
return len(data)+1
|
||||
|
||||
# asciiz specifier
|
||||
if format[:1] == 'u':
|
||||
l = len(data)
|
||||
return l + (l & 1 and 3 or 2)
|
||||
|
||||
# DCE-RPC/NDR string specifier
|
||||
if format[:1] == 'w':
|
||||
l = len(data)
|
||||
return int((12+l+(l % 2)))
|
||||
|
||||
# literal specifier
|
||||
if format[:1] == ':':
|
||||
return len(data)
|
||||
|
||||
# struct like specifier
|
||||
return calcsize(format)
|
||||
|
||||
def calcUnpackSize(self, format, data, field = None):
|
||||
if self.debug:
|
||||
print(" calcUnpackSize( %s | %s | %r)" % (field, format, data))
|
||||
|
||||
# void specifier
|
||||
if format[:1] == '_':
|
||||
return 0
|
||||
|
||||
addressField = self.findAddressFieldFor(field)
|
||||
if addressField is not None:
|
||||
if not self[addressField]:
|
||||
return 0
|
||||
|
||||
try:
|
||||
lengthField = self.findLengthFieldFor(field)
|
||||
return int(self[lengthField])
|
||||
except:
|
||||
pass
|
||||
|
||||
# XXX: Try to match to actual values, raise if no match
|
||||
|
||||
# quote specifier
|
||||
if format[:1] == "'" or format[:1] == '"':
|
||||
return len(format)-1
|
||||
|
||||
# address specifier
|
||||
two = format.split('&')
|
||||
if len(two) == 2:
|
||||
return self.calcUnpackSize(two[0], data)
|
||||
|
||||
# code specifier
|
||||
two = format.split('=')
|
||||
if len(two) >= 2:
|
||||
return self.calcUnpackSize(two[0], data)
|
||||
|
||||
# length specifier
|
||||
two = format.split('-')
|
||||
if len(two) == 2:
|
||||
return self.calcUnpackSize(two[0], data)
|
||||
|
||||
# array specifier
|
||||
two = format.split('*')
|
||||
if len(two) == 2:
|
||||
answer = 0
|
||||
if two[0]:
|
||||
if two[0].isdigit():
|
||||
number = int(two[0])
|
||||
else:
|
||||
answer += self.calcUnpackSize(two[0], data)
|
||||
number = self.unpack(two[0], data[:answer])
|
||||
|
||||
while number:
|
||||
number -= 1
|
||||
answer += self.calcUnpackSize(two[1], data[answer:])
|
||||
else:
|
||||
while answer < len(data):
|
||||
answer += self.calcUnpackSize(two[1], data[answer:])
|
||||
return answer
|
||||
|
||||
# "printf" string specifier
|
||||
if format[:1] == '%':
|
||||
raise Exception("Can't guess the size of a printf like specifier for unpacking")
|
||||
|
||||
# asciiz specifier
|
||||
if format[:1] == 'z':
|
||||
return data.index('\x00')+1
|
||||
|
||||
# asciiz specifier
|
||||
if format[:1] == 'u':
|
||||
l = data.index('\x00\x00')
|
||||
return l + (l & 1 and 3 or 2)
|
||||
|
||||
# DCE-RPC/NDR string specifier
|
||||
if format[:1] == 'w':
|
||||
l = unpack('<L', b(data[:4]))[0]
|
||||
return 12+l*2
|
||||
|
||||
# literal specifier
|
||||
if format[:1] == ':':
|
||||
return len(data)
|
||||
|
||||
# struct like specifier
|
||||
return calcsize(format)
|
||||
|
||||
def calcPackFieldSize(self, fieldName, format = None):
|
||||
if format is None:
|
||||
format = self.formatForField(fieldName)
|
||||
|
||||
return self.calcPackSize(format, self[fieldName])
|
||||
|
||||
def formatForField(self, fieldName):
|
||||
for field in self.commonHdr+self.structure:
|
||||
if field[0] == fieldName:
|
||||
return field[1]
|
||||
raise Exception("Field %s not found" % fieldName)
|
||||
|
||||
def findAddressFieldFor(self, fieldName):
|
||||
descriptor = '&%s' % fieldName
|
||||
l = len(descriptor)
|
||||
for field in self.commonHdr+self.structure:
|
||||
if field[1][-l:] == descriptor:
|
||||
return field[0]
|
||||
return None
|
||||
|
||||
def findLengthFieldFor(self, fieldName):
|
||||
descriptor = '-%s' % fieldName
|
||||
l = len(descriptor)
|
||||
for field in self.commonHdr+self.structure:
|
||||
if field[1][-l:] == descriptor:
|
||||
return field[0]
|
||||
return None
|
||||
|
||||
def dump(self, msg = None, indent = 0, print_to_stdout = True):
|
||||
if msg is None:
|
||||
msg = self.__class__.__name__
|
||||
ind = ' '*indent
|
||||
allstr = "\n%s" % msg
|
||||
fixedFields = []
|
||||
for field in self.commonHdr+self.structure:
|
||||
i = field[0]
|
||||
if i in self.fields:
|
||||
fixedFields.append(i)
|
||||
if isinstance(self[i], Structure):
|
||||
tempstr = self[i].dump('%s%s:{' % (ind, i), indent = indent + 4, print_to_stdout = False)
|
||||
allstr += tempstr + "\n%s}" % ind
|
||||
else:
|
||||
allstr += "\n%s%s: {%r}" % (ind, i, self[i])
|
||||
|
||||
# Do we have remaining fields not defined in the structures? let's
|
||||
# print them.
|
||||
remainingFields = list(set(self.fields) - set(fixedFields))
|
||||
for i in remainingFields:
|
||||
if isinstance(self[i], Structure):
|
||||
tempstr = self[i].dump('%s%s:{' % (ind, i), indent = indent + 4, print_to_stdout = False)
|
||||
allstr += tempstr + "\n%s}" % ind
|
||||
else:
|
||||
allstr += "\n%s%s: {%r}" % (ind, i, self[i])
|
||||
# Finish job.
|
||||
if not print_to_stdout:
|
||||
# print(allstr) # Uncomment this line only for view that test is OK with "print_to_stdout = False".
|
||||
return allstr
|
||||
else:
|
||||
print(allstr)
|
||||
|
||||
|
||||
class _StructureTest:
|
||||
alignment = 0
|
||||
def create(self,data = None):
|
||||
if data is not None:
|
||||
return self.theClass(data, alignment = self.alignment)
|
||||
else:
|
||||
return self.theClass(alignment = self.alignment)
|
||||
|
||||
def run(self):
|
||||
print()
|
||||
print("-"*70)
|
||||
testName = self.__class__.__name__
|
||||
print("starting test: %s....." % testName)
|
||||
a = self.create()
|
||||
self.populate(a)
|
||||
a.dump("packing.....")
|
||||
a_str = a.getData()
|
||||
print("packed: %r, %d" % (a_str,len(a_str)))
|
||||
print("unpacking.....")
|
||||
b = self.create(a_str)
|
||||
b.dump("unpacked.....")
|
||||
print("repacking.....")
|
||||
b_str = b.getData()
|
||||
if b_str != a_str:
|
||||
print("ERROR: original packed and repacked don't match")
|
||||
print("packed: %r" % b_str)
|
||||
|
||||
class _Test_simple(_StructureTest):
|
||||
class theClass(Structure):
|
||||
commonHdr = ()
|
||||
structure = (
|
||||
('int1', '!L'),
|
||||
('len1','!L-z1'),
|
||||
('arr1','B*<L'),
|
||||
('z1', 'z'),
|
||||
('u1','u'),
|
||||
('', '"COCA'),
|
||||
('len2','!H-:1'),
|
||||
('', '"COCA'),
|
||||
(':1', ':'),
|
||||
('int3','>L'),
|
||||
('code1','>L=len(arr1)*2+0x1000'),
|
||||
)
|
||||
|
||||
def populate(self, a):
|
||||
a['default'] = 'hola'
|
||||
a['int1'] = 0x3131
|
||||
a['int3'] = 0x45444342
|
||||
a['z1'] = 'hola'
|
||||
a['u1'] = 'hola'.encode('utf_16_le')
|
||||
a[':1'] = ':1234:'
|
||||
a['arr1'] = (0x12341234,0x88990077,0x41414141)
|
||||
# a['len1'] = 0x42424242
|
||||
|
||||
class _Test_fixedLength(_Test_simple):
|
||||
def populate(self, a):
|
||||
_Test_simple.populate(self, a)
|
||||
a['len1'] = 0x42424242
|
||||
|
||||
class _Test_simple_aligned4(_Test_simple):
|
||||
alignment = 4
|
||||
|
||||
class _Test_nested(_StructureTest):
|
||||
class theClass(Structure):
|
||||
class _Inner(Structure):
|
||||
structure = (('data', 'z'),)
|
||||
|
||||
structure = (
|
||||
('nest1', ':', _Inner),
|
||||
('nest2', ':', _Inner),
|
||||
('int', '<L'),
|
||||
)
|
||||
|
||||
def populate(self, a):
|
||||
a['nest1'] = _Test_nested.theClass._Inner()
|
||||
a['nest2'] = _Test_nested.theClass._Inner()
|
||||
a['nest1']['data'] = 'hola manola'
|
||||
a['nest2']['data'] = 'chau loco'
|
||||
a['int'] = 0x12345678
|
||||
|
||||
class _Test_Optional(_StructureTest):
|
||||
class theClass(Structure):
|
||||
structure = (
|
||||
('pName','<L&Name'),
|
||||
('pList','<L&List'),
|
||||
('Name','w'),
|
||||
('List','<H*<L'),
|
||||
)
|
||||
|
||||
def populate(self, a):
|
||||
a['Name'] = 'Optional test'
|
||||
a['List'] = (1,2,3,4)
|
||||
|
||||
class _Test_Optional_sparse(_Test_Optional):
|
||||
def populate(self, a):
|
||||
_Test_Optional.populate(self, a)
|
||||
del a['Name']
|
||||
|
||||
class _Test_AsciiZArray(_StructureTest):
|
||||
class theClass(Structure):
|
||||
structure = (
|
||||
('head','<L'),
|
||||
('array','B*z'),
|
||||
('tail','<L'),
|
||||
)
|
||||
|
||||
def populate(self, a):
|
||||
a['head'] = 0x1234
|
||||
a['tail'] = 0xabcd
|
||||
a['array'] = ('hola','manola','te traje')
|
||||
|
||||
class _Test_UnpackCode(_StructureTest):
|
||||
class theClass(Structure):
|
||||
structure = (
|
||||
('leni','<L=len(uno)*2'),
|
||||
('cuchi','_-uno','leni/2'),
|
||||
('uno',':'),
|
||||
('dos',':'),
|
||||
)
|
||||
|
||||
def populate(self, a):
|
||||
a['uno'] = 'soy un loco!'
|
||||
a['dos'] = 'que haces fiera'
|
||||
|
||||
class _Test_AAA(_StructureTest):
|
||||
class theClass(Structure):
|
||||
commonHdr = ()
|
||||
structure = (
|
||||
('iv', '!L=((init_vector & 0xFFFFFF) << 8) | ((pad & 0x3f) << 2) | (keyid & 3)'),
|
||||
('init_vector', '_','(iv >> 8)'),
|
||||
('pad', '_','((iv >>2) & 0x3F)'),
|
||||
('keyid', '_','( iv & 0x03 )'),
|
||||
('dataLen', '_-data', 'len(inputDataLeft)-4'),
|
||||
('data',':'),
|
||||
('icv','>L'),
|
||||
)
|
||||
|
||||
def populate(self, a):
|
||||
a['init_vector']=0x01020304
|
||||
#a['pad']=int('01010101',2)
|
||||
a['pad']=int('010101',2)
|
||||
a['keyid']=0x07
|
||||
a['data']="\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9"
|
||||
a['icv'] = 0x05060708
|
||||
#a['iv'] = 0x01020304
|
||||
|
||||
if __name__ == '__main__':
|
||||
_Test_simple().run()
|
||||
|
||||
try:
|
||||
_Test_fixedLength().run()
|
||||
except:
|
||||
print("cannot repack because length is bogus")
|
||||
|
||||
_Test_simple_aligned4().run()
|
||||
_Test_nested().run()
|
||||
_Test_Optional().run()
|
||||
_Test_Optional_sparse().run()
|
||||
_Test_AsciiZArray().run()
|
||||
_Test_UnpackCode().run()
|
||||
_Test_AAA().run()
|
Loading…
Reference in New Issue
Block a user