Add RpcClient with DCOM capabilities handling multiple versions (localthis/localthat)

This commit is contained in:
hakril
2025-01-06 16:28:07 +01:00
parent c040ec368e
commit 4b034fc0fe
8 changed files with 399 additions and 47 deletions
@@ -26,4 +26,8 @@
#define SORF_OXRES7 ( 0x400 )
#define SORF_OXRES8 ( 0x800 )
#define SORF_NULL ( 0 )
#define SORF_NOPING ( 0x1000 )
#define SORF_NOPING ( 0x1000 )
#define UNIQUE_FLAG_PADDING 2
#define MAINHDRSIG 0x414E554B
#define ENTRYHDRSIG 0x494E414E
@@ -405,4 +405,35 @@ typedef struct tagORPCTHAT {
typedef struct ORPCTHAT32 {
ULONG flags;
PVOID32 extensions; // tagORPC_EXTENT_ARRAY tagORPC_EXTENT_ARRAY
} ORPCTHAT32;
} ORPCTHAT32;
// From: com\ole32\com\dcomrem\chock.hxx
typedef struct
{
ULONG size; // Number of extents.
ULONG reserved; // Must be zero.
ULONG unique; // Flag to indicate presence of unique_flag array.
ULONG rounded_size; // Actual number of extents.
ULONG unique_flag[UNIQUE_FLAG_PADDING]; // Flags to indicate presense of ORPC_EXTENTs
} WireExtentArray;
typedef struct
{
ULONG rounded_size; // Actual number of extents.
GUID id; // Extension identifier.
ULONG size; // Extension size.
// byte data[]; // Extension data.
} WireExtent;
typedef struct tagMainHeader
{
ULONG Signature;
ULONG Version;
ULONG cPolicies;
ULONG cbBuffer;
ULONG cbSize;
LONG hr;
LONG hrServer;
LONG reserved;
} MainHeader;
@@ -1,3 +1,94 @@
/* Summary of seen version on combase symbols for LOCALTHIS:
Nb fields: 2
6.1.7601.17514 -> 6.2.9200.22376
* 6.1.7601.17514
* 6.1.7601.17514
* 6.2.9200.22376
Nb fields: 4
6.3.9600.17031 -> 6.3.9600.20772
* 6.3.9600.17031
* 6.3.9600.20772
Nb fields: 5
10.0.10240.16384 -> 10.0.15063.2679
* 10.0.10240.16384
* 10.0.10240.20747
* 10.0.10586.0
* 10.0.14393.576
* 10.0.14393.6451
* 10.0.14393.7426
* 10.0.15063.251
* 10.0.15063.1563
* 10.0.15063.2500
* 10.0.15063.2679
Nb fields: 7
10.0.16299.1 -> 10.0.26100.2454
* 10.0.16299.1
* 10.0.16299.15
* 10.0.17134.1
* 10.0.17134.48
* 10.0.17134.2145
* 10.0.17134.2145
* 10.0.17763.1
* 10.0.17763.2931
* 10.0.22621.2792
* 10.0.22621.3958
* 10.0.22621.4111
* 10.0.22621.4541
* 10.0.26100.2454
*/
/* Summary of seen version on combase symbols for LOCALTHAT:
Nb fields: 2
6.3.9600.17031 -> 6.3.9600.20772
* 6.3.9600.17031
* 6.3.9600.17031
* 6.3.9600.17031
* 6.3.9600.20772
Nb fields: 3
10.0.18362.900 -> 10.0.18362.1916
* 10.0.18362.900
* 10.0.18362.900
* 10.0.18362.1016
* 10.0.18362.1916
Nb fields: 4
10.0.10240.16384 -> 10.0.17763.6040
* 10.0.10240.16384
* 10.0.10240.16384
* 10.0.10240.20747
* 10.0.10586.0
* 10.0.14393.576
* 10.0.14393.6451
* 10.0.14393.7426
* 10.0.15063.251
* 10.0.15063.1563
* 10.0.15063.2500
* 10.0.15063.2679
* 10.0.16299.1
* 10.0.16299.15
* 10.0.17134.1
* 10.0.17134.48
* 10.0.17134.2145
* 10.0.17134.2145
* 10.0.17763.1
* 10.0.17763.2931
* 10.0.17763.6040
Nb fields: 5
10.0.19039.1 -> 10.0.26100.2454
* 10.0.19039.1
* 10.0.19041.84
* 10.0.19041.4894
* 10.0.22000.65
* 10.0.22621.2792
* 10.0.22621.3958
* 10.0.22621.4111
* 10.0.22621.4541
* 10.0.26100.2454
* 10.0.26100.2454
*/
/* Seen on 6.2.9200.22376 (win8_ldr_escrow.180222-0941) */
/* also seen on previous version : XP / Win7 / Server 2012 */
@@ -6,7 +97,7 @@ typedef struct LOCALTHIS32_NT_62 {
ULONG dwClientThread;
};
// NO LOCALTHAT for these previous version as far as 1 now
// NO LOCALTHAT for these previous version as far as I now
/* Seen on 6.3.9600.17031 (winblue_gdr.140221-1952) */
@@ -39,18 +130,18 @@ typedef struct __MIDL_XmitDefs_0002_NT_1607 {
typedef struct __MIDL_XmitDefs_0001_NT_1607 {
_GUID asyncOperationId;
UINT32 oxidClientProcessNA;
UINT64 oxidClientProcessNA;
_GUID originalClientLogicalThreadId;
UINT uClientCausalityTraceId;
};
UINT64 uClientCausalityTraceId;
} MIDL_XmitDefs_0001_NT_1607;
typedef struct LOCALTHIS32_NT_1607 {
typedef struct _LOCALTHIS32_NT_1607 {
ULONG dwFlags;
ULONG dwClientThread;
__MIDL_XmitDefs_0001_NT_1607 asyncRequestBlock;
MIDL_XmitDefs_0001_NT_1607 asyncRequestBlock;
ULONG reserved;
PVOID32 *pTouchedAstaArray;
};
PVOID32 pTouchedAstaArray;
} LOCALTHIS32_NT_1607;
typedef struct __MIDL_XmitDefs_0007 {
INT pointOfFailure;
@@ -58,19 +149,19 @@ typedef struct __MIDL_XmitDefs_0007 {
ULONG sizeOfMarshaledErrorInfo;
ULONG reserved;
BYTE *pMarshaledErrorInfo;
};
} MIDL_XmitDefs_0007;
typedef struct __MIDL_XmitDefs_0005 {
ULONG sizeOfMarshaledResults;
ULONG reserved;
BYTE *pMarshaledResults;
};
} MIDL_XmitDefs_0005;
typedef struct __MIDL_XmitDefs_0008 {
INT outcome;
__MIDL_XmitDefs_0005 successDetails;
__MIDL_XmitDefs_0007 failureDetails;
};
MIDL_XmitDefs_0005 successDetails;
MIDL_XmitDefs_0007 failureDetails;
} MIDL_XmitDefs_0008;
typedef struct __MIDL_XmitDefs_0010 {
ULONG asyncStatus;
@@ -78,17 +169,28 @@ typedef struct __MIDL_XmitDefs_0010 {
UINT64 uServerCausalityTraceId;
ULONG reserved2;
PVOID32 *pOutcomeDetails; //__MIDL_XmitDefs_0008
};
} MIDL_XmitDefs_0010;
typedef struct LOCALTHAT32_NT_1607 {
UINT64 marshalingSetAcknowledgmentOxid;
UINT64 marshalingSetId;
ULONG reserved;
PVOID32 *pAsyncResponseBlock;
PVOID32 pAsyncResponseBlock;
};
/* ! NT_1607: combase 10.0.14393.576 */
/* */
/* Seen only in 10.0.18362 versions of combase */
typedef struct _LOCALTHAT32_10_1903 {
UINT64 marshalingSetId;
PVOID32 pAsyncResponseBlock;
PVOID32 containerPassthroughData;
} LOCALTHAT32_10_1903;
/* NT 10.22 ? seen on 10.0.22621.1 */
typedef struct _LOCALTHIS32 {
+11 -1
View File
@@ -156,4 +156,14 @@ def test_psid_from_to_string():
initial_str = "S-1-5-12345"
sid = gdef.PSID.from_string(initial_str)
assert str(sid) == initial_str
assert gdef.PSID.from_string(str(sid)) == sid
assert gdef.PSID.from_string(str(sid)) == sid
def test_MIDL_XmitDefs_0001_NT_1607():
# First definition was broken
# 0:000> dt combase_32!__MIDL_XmitDefs_0001
# +0x000 asyncOperationId : _GUID
# +0x010 oxidClientProcessNA : Uint8B
# +0x018 originalClientLogicalThreadId : _GUID
# +0x028 uClientCausalityTraceId : Uint8B
assert gdef.MIDL_XmitDefs_0001_NT_1607.originalClientLogicalThreadId.offset == 0x018
assert gdef.MIDL_XmitDefs_0001_NT_1607.uClientCausalityTraceId.offset == 0x028
+15
View File
@@ -943,6 +943,7 @@ windef = {'ABOVE_NORMAL_PRIORITY_CLASS',
'DUPLICATE_SAME_ACCESS',
'DWORDLONG_MAX',
'DWORD_MAX',
'ENTRYHDRSIG',
'ERROR_AUTHENTICODE_DISALLOWED',
'ERROR_AUTHENTICODE_PUBLISHER_NOT_TRUSTED',
'ERROR_AUTHENTICODE_TRUSTED_PUBLISHER',
@@ -1868,6 +1869,7 @@ windef = {'ABOVE_NORMAL_PRIORITY_CLASS',
'LPC_REQUEST',
'MAILSLOT_NO_MESSAGE',
'MAILSLOT_WAIT_FOREVER',
'MAINHDRSIG',
'MAXIMUM_ALLOWED',
'MAXIMUM_XSTATE_FEATURES',
'MAXLEN_IFDESCR',
@@ -3164,6 +3166,7 @@ windef = {'ABOVE_NORMAL_PRIORITY_CLASS',
'TXFS_MINIVERSION_COMMITTED_VIEW',
'TXFS_MINIVERSION_DEFAULT_VIEW',
'TXFS_MINIVERSION_DIRTY_VIEW',
'UNIQUE_FLAG_PADDING',
'UNLOAD_DLL_DEBUG_EVENT',
'UNPROTECTED_DACL_SECURITY_INFORMATION',
'UNPROTECTED_SACL_SECURITY_INFORMATION',
@@ -12544,6 +12547,7 @@ structs = {'ACCESS_ALLOWED_ACE',
'LOCALGROUP_MEMBERS_INFO_3',
'LOCALTHAT',
'LOCALTHAT32',
'LOCALTHAT32_10_1903',
'LOCALTHAT32_NT_1607',
'LOCALTHAT32_NT_63',
'LOCALTHIS',
@@ -12694,9 +12698,15 @@ structs = {'ACCESS_ALLOWED_ACE',
'MIB_UDPTABLE_OWNER_PID',
'MIDL_ILocalObjectExporter_0007',
'MIDL_XmitDefs_0001',
'MIDL_XmitDefs_0001_NT_1607',
'MIDL_XmitDefs_0005',
'MIDL_XmitDefs_0007',
'MIDL_XmitDefs_0008',
'MIDL_XmitDefs_0010',
'MInterfacePointer',
'MODLOAD_DATA',
'MULTI_QI',
'MainHeader',
'Mem_Des_s',
'Mem_Large_Des_s',
'Mem_Large_Range_s',
@@ -13542,6 +13552,8 @@ structs = {'ACCESS_ALLOWED_ACE',
'WSAPROTOCOLCHAIN',
'WSAPROTOCOL_INFOA',
'WSAPROTOCOL_INFOW',
'WireExtent',
'WireExtentArray',
'XSAVE_FORMAT_32',
'XSAVE_FORMAT_64',
'XSTATE_CONFIGURATION',
@@ -13850,8 +13862,10 @@ structs = {'ACCESS_ALLOWED_ACE',
'_LOCALGROUP_MEMBERS_INFO_3',
'_LOCALTHAT',
'_LOCALTHAT32',
'_LOCALTHAT32_10_1903',
'_LOCALTHIS',
'_LOCALTHIS32',
'_LOCALTHIS32_NT_1607',
'_LSA_OBJECT_ATTRIBUTES',
'_LSA_REFERENCED_DOMAIN_LIST',
'_LSA_TRANSLATED_NAME',
@@ -14135,6 +14149,7 @@ structs = {'ACCESS_ALLOWED_ACE',
'tagIDLDESC',
'tagMInterfacePointer',
'tagMULTI_QI',
'tagMainHeader',
'tagOBJREF',
'tagOBJREFDATA',
'tagORPCTHAT',
+3
View File
@@ -169,6 +169,9 @@ SORF_OXRES7 = make_flag("SORF_OXRES7", ( 0x400 ))
SORF_OXRES8 = make_flag("SORF_OXRES8", ( 0x800 ))
SORF_NULL = make_flag("SORF_NULL", ( 0 ))
SORF_NOPING = make_flag("SORF_NOPING", ( 0x1000 ))
UNIQUE_FLAG_PADDING = make_flag("UNIQUE_FLAG_PADDING", 2)
MAINHDRSIG = make_flag("MAINHDRSIG", 0x414E554B)
ENTRYHDRSIG = make_flag("ENTRYHDRSIG", 0x494E414E)
CWCSTORAGENAME = make_flag("CWCSTORAGENAME", 32)
STGM_DIRECT = make_flag("STGM_DIRECT", 0x00000000)
STGM_TRANSACTED = make_flag("STGM_TRANSACTED", 0x00010000)
+53 -14
View File
@@ -1563,6 +1563,37 @@ class ORPCTHAT32(Structure):
]
class WireExtentArray(Structure):
_fields_ = [
("size", ULONG),
("reserved", ULONG),
("unique", ULONG),
("rounded_size", ULONG),
("unique_flag", ULONG * (UNIQUE_FLAG_PADDING)),
]
class WireExtent(Structure):
_fields_ = [
("rounded_size", ULONG),
("id", GUID),
("size", ULONG),
]
class tagMainHeader(Structure):
_fields_ = [
("Signature", ULONG),
("Version", ULONG),
("cPolicies", ULONG),
("cbBuffer", ULONG),
("cbSize", ULONG),
("hr", LONG),
("hrServer", LONG),
("reserved", LONG),
]
MainHeader = tagMainHeader
class LOCALTHIS32_NT_62(Structure):
_fields_ = [
("dwFlags", ULONG),
@@ -1605,21 +1636,21 @@ class __MIDL_XmitDefs_0002_NT_1607(Structure):
class __MIDL_XmitDefs_0001_NT_1607(Structure):
_fields_ = [
("asyncOperationId", _GUID),
("oxidClientProcessNA", UINT32),
("oxidClientProcessNA", UINT64),
("originalClientLogicalThreadId", _GUID),
("uClientCausalityTraceId", UINT),
("uClientCausalityTraceId", UINT64),
]
MIDL_XmitDefs_0001_NT_1607 = __MIDL_XmitDefs_0001_NT_1607
class LOCALTHIS32_NT_1607(Structure):
class _LOCALTHIS32_NT_1607(Structure):
_fields_ = [
("dwFlags", ULONG),
("dwClientThread", ULONG),
("asyncRequestBlock", __MIDL_XmitDefs_0001_NT_1607),
("asyncRequestBlock", MIDL_XmitDefs_0001_NT_1607),
("reserved", ULONG),
("pTouchedAstaArray", POINTER(PVOID32)),
("pTouchedAstaArray", PVOID32),
]
LOCALTHIS32_NT_1607 = _LOCALTHIS32_NT_1607
class __MIDL_XmitDefs_0007(Structure):
_fields_ = [
@@ -1629,7 +1660,7 @@ class __MIDL_XmitDefs_0007(Structure):
("reserved", ULONG),
("pMarshaledErrorInfo", POINTER(BYTE)),
]
MIDL_XmitDefs_0007 = __MIDL_XmitDefs_0007
class __MIDL_XmitDefs_0005(Structure):
_fields_ = [
@@ -1637,15 +1668,15 @@ class __MIDL_XmitDefs_0005(Structure):
("reserved", ULONG),
("pMarshaledResults", POINTER(BYTE)),
]
MIDL_XmitDefs_0005 = __MIDL_XmitDefs_0005
class __MIDL_XmitDefs_0008(Structure):
_fields_ = [
("outcome", INT),
("successDetails", __MIDL_XmitDefs_0005),
("failureDetails", __MIDL_XmitDefs_0007),
("successDetails", MIDL_XmitDefs_0005),
("failureDetails", MIDL_XmitDefs_0007),
]
MIDL_XmitDefs_0008 = __MIDL_XmitDefs_0008
class __MIDL_XmitDefs_0010(Structure):
_fields_ = [
@@ -1655,17 +1686,25 @@ class __MIDL_XmitDefs_0010(Structure):
("reserved2", ULONG),
("pOutcomeDetails", POINTER(PVOID32)),
]
MIDL_XmitDefs_0010 = __MIDL_XmitDefs_0010
class LOCALTHAT32_NT_1607(Structure):
_fields_ = [
("marshalingSetAcknowledgmentOxid", UINT64),
("marshalingSetId", UINT64),
("reserved", ULONG),
("pAsyncResponseBlock", POINTER(PVOID32)),
("pAsyncResponseBlock", PVOID32),
]
class _LOCALTHAT32_10_1903(Structure):
_fields_ = [
("marshalingSetId", UINT64),
("pAsyncResponseBlock", PVOID32),
("containerPassthroughData", PVOID32),
]
LOCALTHAT32_10_1903 = _LOCALTHAT32_10_1903
class _LOCALTHIS32(Structure):
_fields_ = [
("dwFlags", DWORD),
+163 -15
View File
@@ -62,9 +62,26 @@ class ALPC_RPC_CALL(ctypes.Structure):
("orpc_ipid", gdef.GUID)
]
# Was an array of 6 DWORD, new class inspired by :
# https://github.com/googleprojectzero/sandbox-attacksurface-analysis-tools/blob/main/NtCoreLib/Win32/Rpc/Transport/Alpc/LRPC_IMMEDIATE_RESPONSE_MESSAGE.cs#L22
class ALPC_RPC_RESPONSE(ctypes.Structure):
_pack_ = 1
_fields_ = [
("request_type", gdef.DWORD),
("UNK1", gdef.DWORD),
("flags",gdef.DWORD),
("request_id", gdef.DWORD),
("UNK2", gdef.DWORD),
("UNK3", gdef.DWORD),
]
class RPCClient(object):
"""A client for RPC-over-ALPC able to bind to interface and perform calls using NDR32 marshalling"""
REQUEST_IDENTIFIER = 0x11223344
REQUEST_IDENTIFIER = 0x42424242
# Used to recognize ORPC call we made
# thus we know the response contains a orpcthat & localthat
REQUEST_IDENTIFIER_ORPC = 0x43434343
def __init__(self, port):
self.alpc_client = alpc.AlpcClient(port) #: The :class:`windows.alpc.AlpcClient` used to communicate with the server
@@ -138,17 +155,15 @@ class RPCClient(object):
req.if_nb = interface_nb
req.method_offset = method_offset
if ipid:
req.request_id = self.REQUEST_IDENTIFIER_ORPC
req.flags = 1 # We have a IPID
req.orpc_ipid = ipid
this = gdef.ORPCTHIS32() # we use NDR32
this.version = (5,7)
this.flags = gdef.ORPCF_LOCAL
# Not mandatory
# this.cid = gdef.GUID.from_string("42424242-4242-4242-4242-424242424242")
lthis = gdef.LOCALTHIS32() # we use NDR32
# RPC_E_INVALID_HEADER is NULL
lthis.callTraceActivity = gdef.GUID.from_string("42424242-4242-4242-4242-424242424242")
lthis.dwClientThread = windows.current_thread.tid
# Returned correct type with mandatory fields filed
lthis = find_correct_localthis_for_version()
print("lthis is : {0}".format(lthis))
return buffer(req)[:] + buffer(this)[:] + buffer(lthis)[:] + params
return buffer(req)[:] + params
@@ -188,17 +203,150 @@ class RPCClient(object):
request_type = struct.unpack("<I", response.data[:4])[0]
if request_type == gdef.RPC_RESPONSE_TYPE_FAIL:
error_code = struct.unpack("<5I", response.data)[2]
raise ValueError("RPC Response error {0} ({1})".format(error_code, KNOWN_RPC_ERROR_CODE.get(error_code, error_code)))
raise ValueError("RPC Response error {0} ({1!r})".format(error_code, KNOWN_RPC_ERROR_CODE.get(error_code, error_code)))
return request_type
def _get_response_effective_data(self, response):
"""Response is a `AlpcMessage` needed to handle response in message vs response in view"""
response_header = ALPC_RPC_RESPONSE.from_buffer_copy(response.data)
if not response.view_is_valid:
# Reponse directly in PORT_MESSAGE
return response.data[0x18:] # 4 * 6
# Response in view M extract size from PORT_MESSAGE & read data from view
assert response.port_message.u1.s1.TotalLength >= 0x48 # At least 0x20 of data
rpcdatasize = struct.unpack("<I", response.data[0x18:0x1c])[0]
viewattr = response.view_attribute
assert viewattr.ViewSize >= rpcdatasize
return windows.current_process.read_memory(viewattr.ViewBase, rpcdatasize)
data = response.data[ctypes.sizeof(ALPC_RPC_RESPONSE):]
else:
# Response in view M extract size from PORT_MESSAGE & read data from view
assert response.port_message.u1.s1.TotalLength >= 0x48 # At least 0x20 of data
rpcdatasize = struct.unpack("<I", response.data[0x18:0x1c])[0] # ctypes.sizeof(ALPC_RPC_RESPONSE)
viewattr = response.view_attribute
assert viewattr.ViewSize >= rpcdatasize
data = windows.current_process.read_memory(viewattr.ViewBase, rpcdatasize)
if response_header.request_id == self.REQUEST_IDENTIFIER_ORPC:
# Parse & remove ORPC headers (orpcthat + LocalThat)
orpcthat = gdef.ORPCTHAT32.from_buffer_copy(data)
data = data[ctypes.sizeof(orpcthat):]
if orpcthat.extensions != 0:
print("Parsing extension !")
# Parse extension : code have not been tested a lot
write_array_extend = gdef.WireExtentArray.from_buffer_copy(data)
data = data[ctypes.sizeof(gdef.WireExtentArray):]
if write_array_extend.rounded_size != 2:
raise NotImplementedError("orpcthat.extensions: WireExtentArray.rounded_size != 2")
for value in write_array_extend.unique_flag:
if value != 0:
data = self._pass_wire_extend(data)
localthat_type = find_correct_localthat_for_version()
if localthat_type is not None:
localthat = localthat_type.from_buffer_copy(data)
# Check localthat pointers are empty
for field in ("pAsyncResponseBlock", "containerErrorInformation", "containerPassthroughData"):
if getattr(localthat, field, 0) != 0:
raise NotImplementedError("ORPC Response with localthat.{0} != 0".format(field))
data = data[ctypes.sizeof(localthat):]
return data
def _pass_wire_extend(self, data):
wire_extend = gdef.WireExtent.from_buffer_copy(data)
# We don't care -> jump over the size only
return data[ctypes.sizeof(gdef.WireExtent) + wire_extend.rounded_size:]
# Based on combase.dll analysis
# LOCALTHIS
# Nb fields: 2
# 6.1.7601.17514 -> 6.2.9200.22376
# * 6.1.7601.17514
# * 6.1.7601.17514
# * 6.2.9200.22376
# Nb fields: 4
# 6.3.9600.17031 -> 6.3.9600.20772
# * 6.3.9600.17031
# * 6.3.9600.20772
# Nb fields: 5
# 10.0.10240.16384 -> 10.0.15063.2679
# Nb fields: 7
# 10.0.16299.1 -> 10.0.26100.2454
def find_correct_localthis_for_version():
vmaj, vmin = windows.system.version
if (vmaj, vmin) < (6, 1):
return None
if (vmaj, vmin) in ((6, 1), (6, 2)):
return gdef.LOCALTHIS32_NT_62(dwClientThread = windows.current_thread.tid)
elif (vmaj, vmin) == (6,3):
return gdef.LOCALTHIS32_NT_63(dwClientThread = windows.current_thread.tid)
assert vmaj == 10
vnumber = windows.system.get_file_version(r"C:\windows\system32\combase.dll")
# Extract version number from combase
# as it was used to find the struct per version
build_number = int(vnumber.split(".")[2])
if build_number <= 15063:
return gdef.LOCALTHIS32_NT_1607(dwClientThread = windows.current_thread.tid)
return gdef.LOCALTHIS32(callTraceActivity=gdef.GUID.from_string("42424242-4242-4242-4242-424242424242"),
dwClientThread = windows.current_thread.tid)
# LOCALTHAT
# Nb fields: 2
# 6.3.9600.17031 -> 6.3.9600.20772
# * 6.3.9600.17031
# * 6.3.9600.17031
# * 6.3.9600.17031
# * 6.3.9600.20772
# Nb fields: 3
# 10.0.18362.900 -> 10.0.18362.1916
# * 10.0.18362.900
# * 10.0.18362.900
# * 10.0.18362.1016
# * 10.0.18362.1916
# Nb fields: 4
# 10.0.10240.16384 -> 10.0.17763.6040
# * 10.0.10240.16384
# * 10.0.10240.16384
# * 10.0.10240.20747
# * 10.0.10586.0
# * 10.0.14393.576
# * 10.0.14393.6451
# * 10.0.14393.7426
# * 10.0.15063.251
# * 10.0.15063.1563
# * 10.0.15063.2500
# * 10.0.15063.2679
# * 10.0.16299.1
# * 10.0.16299.15
# * 10.0.17134.1
# * 10.0.17134.48
# * 10.0.17134.2145
# * 10.0.17134.2145
# * 10.0.17763.1
# * 10.0.17763.2931
# * 10.0.17763.6040
# Nb fields: 5
# 10.0.19039.1 -> 10.0.26100.2454
# * 10.0.19039.1
# * 10.0.19041.84
# * 10.0.19041.4894
# * 10.0.22000.65
# * 10.0.22621.2792
# * 10.0.22621.3958
# * 10.0.22621.4111
# * 10.0.22621.4541
# * 10.0.26100.2454
# * 10.0.26100.2454
def find_correct_localthat_for_version():
vmaj, vmin = windows.system.version
if (vmaj, vmin) < (6, 3):
return None
elif (vmaj, vmin) == (6,3):
return gdef.LOCALTHAT32_NT_63
assert vmaj == 10
vnumber = windows.system.get_file_version(r"C:\windows\system32\combase.dll")
# Extract version number from combase
# as it was used to find the struct per version
build_number = int(vnumber.split(".")[2])
if build_number <= 17763:
return gdef.LOCALTHAT32_NT_1607
elif build_number == 18362:
return gdef.LOCALTHAT32_10_1903
elif build_number >= 19039:
return gdef.LOCALTHAT32
raise NotImplementedError("Unknown LOCALTHAT32 structure for version {0}, please share me your combase.dll file".format(windows.system.versionstr))