From c7c8830ce5323f3d4ca2cdbe95498ae70b36ecae Mon Sep 17 00:00:00 2001 From: hakril Date: Wed, 15 Oct 2025 14:49:25 +0200 Subject: [PATCH 1/5] Add tests for NdrCString & NdrWString packing --- tests/test_ndr.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/test_ndr.py b/tests/test_ndr.py index 64f34fef..37d93fb6 100644 --- a/tests/test_ndr.py +++ b/tests/test_ndr.py @@ -58,6 +58,11 @@ class ComplexAlignementStructure(ndr.NdrStructure): NDR_PACK_TEST_CASE = [ # Simple case (ndr.make_structure([ndr.NdrLong, ndr.NdrLong]), (2, 2), b"\x02\x00\x00\x00\x02\x00\x00\x00"), + # String case, test packing works + \x00 is added if not present in string + (ndr.NdrCString, "Hello", b"\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00Hello\x00PP"), + (ndr.NdrCString, "Hello\x00", b"\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00Hello\x00PP"), + (ndr.NdrWString, "Hello", b"\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00H\x00e\x00l\x00l\x00o\x00\x00\x00"), + (ndr.NdrWString, "Hello\x00", b"\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00H\x00e\x00l\x00l\x00o\x00\x00\x00"), # Test GUID packing (ndr.NdrGuid, gdef.GUID.from_string("42424242-42424242-4242-4242-424242424242"), b"BBBBBBBBBBBBBBBB"), # Test CtxHandle packing From 1509f7bd5688b43c75a0c493fb98eb8af885792e Mon Sep 17 00:00:00 2001 From: hakril Date: Wed, 15 Oct 2025 15:01:03 +0200 Subject: [PATCH 2/5] Investigate bug in apisetmap testing on gitlab CI --- tests/test_apisetmap.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_apisetmap.py b/tests/test_apisetmap.py index d9e4a5e7..0ab8274f 100644 --- a/tests/test_apisetmap.py +++ b/tests/test_apisetmap.py @@ -32,6 +32,8 @@ def verify_apisetmap_parsing(apisetmap_base, version=None): # Verify that at least one entry resolve to kernel32.dll # This ensure that the ApiSetMap parsing works at least a little assert "kernel32.dll" in apisetmap_dict.values() + for dll in sorted(apisetmap_dict): + print(dll) assert all(any(dll.startswith(pref) for pref in KNOWN_APISETMAP_PREFIX) for dll in apisetmap_dict) # This first key was found in most of the tested version by hand # MS-Win found on: 6.1.7600 (Win7) From cf09ed86a96c83d1c3ecd501687d0f1c9ba5ef44 Mon Sep 17 00:00:00 2001 From: hakril Date: Wed, 15 Oct 2025 15:09:50 +0200 Subject: [PATCH 3/5] More investigation of apisetmap test bug --- tests/test_apisetmap.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test_apisetmap.py b/tests/test_apisetmap.py index 0ab8274f..c1a6e867 100644 --- a/tests/test_apisetmap.py +++ b/tests/test_apisetmap.py @@ -32,8 +32,11 @@ def verify_apisetmap_parsing(apisetmap_base, version=None): # Verify that at least one entry resolve to kernel32.dll # This ensure that the ApiSetMap parsing works at least a little assert "kernel32.dll" in apisetmap_dict.values() + print("Listing APISETMAP dlls") for dll in sorted(apisetmap_dict): print(dll) + if not any(dll.startswith(pref) for pref in KNOWN_APISETMAP_PREFIX): + print("Dll has unknown prefix".format(dll=dll)) assert all(any(dll.startswith(pref) for pref in KNOWN_APISETMAP_PREFIX) for dll in apisetmap_dict) # This first key was found in most of the tested version by hand # MS-Win found on: 6.1.7600 (Win7) From 7142a8ddb825d30ee6205557ee65d1b597d424d9 Mon Sep 17 00:00:00 2001 From: hakril Date: Wed, 15 Oct 2025 15:18:34 +0200 Subject: [PATCH 4/5] Add new found prefix to apiset map dll name : SchemaExt- --- tests/test_apisetmap.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/tests/test_apisetmap.py b/tests/test_apisetmap.py index c1a6e867..c1528cb0 100644 --- a/tests/test_apisetmap.py +++ b/tests/test_apisetmap.py @@ -20,7 +20,7 @@ def dumped_apisetmap_base_and_version(request): ctypes_data = ctypes.c_buffer(data) yield ctypes.addressof(ctypes_data), version -KNOWN_APISETMAP_PREFIX = ["api-", "ext-", "MS-Win-"] +KNOWN_APISETMAP_PREFIX = ["api-", "ext-", "MS-Win-", "SchemaExt-"] def verify_apisetmap_parsing(apisetmap_base, version=None): if version is not None: @@ -32,11 +32,6 @@ def verify_apisetmap_parsing(apisetmap_base, version=None): # Verify that at least one entry resolve to kernel32.dll # This ensure that the ApiSetMap parsing works at least a little assert "kernel32.dll" in apisetmap_dict.values() - print("Listing APISETMAP dlls") - for dll in sorted(apisetmap_dict): - print(dll) - if not any(dll.startswith(pref) for pref in KNOWN_APISETMAP_PREFIX): - print("Dll has unknown prefix".format(dll=dll)) assert all(any(dll.startswith(pref) for pref in KNOWN_APISETMAP_PREFIX) for dll in apisetmap_dict) # This first key was found in most of the tested version by hand # MS-Win found on: 6.1.7600 (Win7) From d6ad3343e86ddfdd7d34b00de10216a7f3bd6b62 Mon Sep 17 00:00:00 2001 From: hakril Date: Wed, 15 Oct 2025 14:40:38 +0200 Subject: [PATCH 5/5] Fix NdrCString not accepting strings in python3 --- windows/rpc/ndr.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/windows/rpc/ndr.py b/windows/rpc/ndr.py index 88af1431..065447b8 100644 --- a/windows/rpc/ndr.py +++ b/windows/rpc/ndr.py @@ -160,6 +160,9 @@ def pack(cls, data): return None if not data.endswith('\x00'): data += '\x00' + # Technically windows NDR seems to accept any bitstream that ends with '\x00\x00' here + # And not limited to valid utf-16 + # Exemple: b'\x41\x00\x00\xD8' data = data.encode("utf-16-le") l = (len(data) // 2) result = struct.pack("<3I", l, 0, l) @@ -179,7 +182,7 @@ def unpack(cls, stream): @classmethod def get_alignment(self): - # Not sur, but size is on 4 bytes so... + # Not sure, but size is on 4 bytes so... return 4 class NdrCString(object): @@ -190,6 +193,10 @@ def pack(cls, data): return None if not data.endswith('\x00'): data += '\x00' + # Windows NDR seems to accept any bitstream in a FC_C_CSTRING + # I was able to send range(1, 256) + b"\x00" + # For now play safe for user and only accept encoded with always keep the same number of bytes + data = data.encode("ascii") l = len(data) result = struct.pack("<3I", l, 0, l) result += data