Skip to content

Commit 4bbdb53

Browse files
committed
Add support for remote TEB + tests
1 parent 6ccccf7 commit 4bbdb53

4 files changed

Lines changed: 107 additions & 28 deletions

File tree

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# From: ctypes_generation\extended_structs\_LIST_ENTRY.py
2+
# _LIST_ENTRY is a self referencing structure
3+
# Currently ctypes generation does not support extending self referencing structures
4+
# Ass the _fields_ assignement should happen after the extended structure definition
5+
# So we just redefine fully _LIST_ENTRY without inheriting the real one
6+
7+
class _LIST_ENTRY(Structure):
8+
def get_real_struct(self, targetcls, target_field):
9+
# >>> gdef.LDR_DATA_TABLE_ENTRY.InMemoryOrderLinks
10+
# <Field type=_LIST_ENTRY, ofs=16, size=16>
11+
# This field object does not allow to retrieve the type..
12+
# So we need to basse the target class AND the target field..
13+
return targetcls.from_address(ctypes.addressof(self) - target_field.offset)
14+
15+
_LIST_ENTRY._fields_ = [
16+
("Flink", POINTER(_LIST_ENTRY)),
17+
("Blink", POINTER(_LIST_ENTRY)),
18+
]

tests/test_process.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def test_get_current_process_peb(self):
2828
return windows.current_process.peb
2929

3030
def test_get_current_process_modules(self):
31-
# Use module filename because this executable can be:
31+
# Use module filename because this executable can be:
3232
# 1. A PyInstaller exe
3333
# 2. A Windows App execution alias (Microsoft Store builds)
3434
assert os.path.basename(windows.current_process.peb.ProcessParameters[0].ImagePathName.str) in windows.current_process.peb.modules[0].name
@@ -474,19 +474,44 @@ def test_mapped_filename(self, proc32_64):
474474
with proc32_64.allocated_memory(0x1000) as addr:
475475
assert proc32_64.get_mapped_filename(addr) is None
476476

477+
def test_current_thread_teb():
478+
teb = windows.current_thread.teb
479+
assert ctypes.addressof(teb) == ctypes.addressof(windows.current_thread.teb.NtTib.Self[0])
480+
assert ctypes.addressof(windows.current_process.peb) == ctypes.addressof(teb.ProcessEnvironmentBlock[0])
481+
# Check type of teb.peb is the correct subclass (with modules & co)
482+
assert teb.peb.modules
477483

478484
def test_thread_teb_base(self, proc32_64):
479485
t = proc32_64.threads[0]
480486
assert t.teb_base != 0
481487

488+
def test_teb(self, proc32_64):
489+
teb = proc32_64.threads[0].teb
490+
if proc32_64.bitness == 32:
491+
assert type(teb) == windows.winobject.process.RemoteTEB32
492+
else:
493+
assert type(teb) == windows.winobject.process.RemoteTEB64
494+
assert teb.NtTib.Self.value == teb._base_addr
495+
assert teb.ProcessEnvironmentBlock.value == teb.peb._base_addr
496+
# Check type of teb.peb is the correct subclass (with modules & co)
497+
assert teb.peb.modules
498+
482499
@windows_64bit_only
483500
def test_thread_teb_syswow_base(self, proc32):
484501
t = proc32.threads[0]
485502
assert t.teb_base != 0
486503
assert t.teb_syswow_base != 0
487504
assert t.teb_base == t.teb_syswow_base + 0x2000
488505

489-
506+
@windows_64bit_only
507+
def test_thread_teb_syswow(self, proc32):
508+
teb_syswow = proc32.threads[0].teb_syswow
509+
assert type(teb_syswow) == windows.winobject.process.RemoteTEB64
510+
assert type(teb_syswow.peb) == windows.winobject.process.RemotePEB64
511+
assert teb_syswow.NtTib.Self.value == teb_syswow._base_addr
512+
assert teb_syswow.ProcessEnvironmentBlock.value == teb_syswow.peb._base_addr
513+
# Check type of teb.peb is the correct subclass (with modules & co)
514+
assert teb.peb.modules
490515

491516
def test_thread_owner_from_tid(self, proc32_64):
492517
thread = proc32_64.threads[0]

windows/generated_def/winstructs.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3896,6 +3896,27 @@ class _LIST_ENTRY(Structure):
38963896
("Blink", POINTER(_LIST_ENTRY)),
38973897
]
38983898

3899+
# From: ctypes_generation\extended_structs\_LIST_ENTRY.py
3900+
# _LIST_ENTRY is a self referencing structure
3901+
# Currently ctypes generation does not support extending self referencing structures
3902+
# Ass the _fields_ assignement should happen after the extended structure definition
3903+
# So we just redefine fully _LIST_ENTRY without inheriting the real one
3904+
3905+
class _LIST_ENTRY(Structure):
3906+
def get_real_struct(self, targetcls, target_field):
3907+
# >>> gdef.LDR_DATA_TABLE_ENTRY.InMemoryOrderLinks
3908+
# <Field type=_LIST_ENTRY, ofs=16, size=16>
3909+
# This field object does not allow to retrieve the type..
3910+
# So we need to basse the target class AND the target field..
3911+
return targetcls.from_address(ctypes.addressof(self) - target_field.offset)
3912+
3913+
_LIST_ENTRY._fields_ = [
3914+
("Flink", POINTER(_LIST_ENTRY)),
3915+
("Blink", POINTER(_LIST_ENTRY)),
3916+
]
3917+
LIST_ENTRY = _LIST_ENTRY
3918+
PLIST_ENTRY = POINTER(_LIST_ENTRY)
3919+
PRLIST_ENTRY = POINTER(_LIST_ENTRY)
38993920
class _LSA_UNICODE_STRING(Structure):
39003921
_fields_ = [
39013922
("Length", USHORT),

windows/winobject/process.py

Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -899,7 +899,9 @@ def teb_base(self):
899899

900900
@property
901901
def teb(self):
902-
return RemoteTEB(self.teb_base, target=self.owner)
902+
if self.owner.bitness == 32:
903+
return RemoteTEB32(self.teb_base, target=self.owner)
904+
return RemoteTEB64(self.teb_base, target=self.owner)
903905

904906
@property
905907
def teb_syswow_base(self):
@@ -914,7 +916,7 @@ def teb_syswow_base(self):
914916

915917
@property
916918
def teb_syswow(self):
917-
return TEB64.from_address(self.teb_syswow_base)
919+
return RemoteTEB64.from_address(self.teb_syswow_base)
918920

919921

920922
def exit(self, code=0):
@@ -1222,8 +1224,6 @@ def exit(self, code=0):
12221224
return winproxy.TerminateProcess(self.handle, code)
12231225

12241226

1225-
1226-
12271227
def transform_ctypes_fields(struct, replacement):
12281228
return [(name, replacement.get(name, type)) for name, type in struct._fields_]
12291229

@@ -1266,11 +1266,6 @@ def pe(self):
12661266
return pe_parse.GetPEFile(self.baseaddr)
12671267

12681268

1269-
class LIST_ENTRY_PTR(PVOID):
1270-
def TO_LDR_ENTRY(self):
1271-
return LDR_DATA_TABLE_ENTRY.from_address(self.value - sizeof(PVOID) * 2)
1272-
1273-
12741269
class PEB(gdef.PEB):
12751270
"""The PEB (Process Environment Block) of the current process"""
12761271

@@ -1305,13 +1300,13 @@ def modules(self):
13051300
:type: [:class:`LoadedModule`] -- List of loaded modules
13061301
"""
13071302
res = []
1308-
list_entry_ptr = ctypes.cast(self.Ldr.contents.InMemoryOrderModuleList.Flink, LIST_ENTRY_PTR)
1309-
current_dll = list_entry_ptr.TO_LDR_ENTRY()
1303+
first_flink = self.Ldr.contents.InMemoryOrderModuleList.Flink[0]
1304+
current_dll = first_flink.get_real_struct(LoadedModule, LoadedModule.InMemoryOrderLinks)
13101305
while current_dll.DllBase:
13111306
res.append(current_dll)
1312-
list_entry_ptr = ctypes.cast(current_dll.InMemoryOrderLinks.Flink, LIST_ENTRY_PTR)
1313-
current_dll = list_entry_ptr.TO_LDR_ENTRY()
1314-
return [LoadedModule.from_address(addressof(LDR)) for LDR in res]
1307+
next_flink = current_dll.InMemoryOrderLinks.Flink[0]
1308+
current_dll = next_flink.get_real_struct(LoadedModule, LoadedModule.InMemoryOrderLinks)
1309+
return res
13151310

13161311
@staticmethod
13171312
def _extract_environment(env_block_addr, target):
@@ -1341,15 +1336,6 @@ def apisetmap(self):
13411336
raise NotImplementedError("ApiSetMap does not exist prior to Windows 7")
13421337
return apisetmap.get_api_set_map_for_current_process(self.ApiSetMap)
13431338

1344-
# TEB enhanced, same bitness as PEB (current process)
1345-
class TEB(gdef.TEB):
1346-
def peb(self):
1347-
return ctypes.cast(self.ProcessEnvironmentBlock, ctypes.POINTER(PEB))[0]
1348-
1349-
class RemoteTEB(rctypes.RemoteStructure.from_structure(TEB)):
1350-
def peb(self):
1351-
return ctypes.cast(self.ProcessEnvironmentBlock, ctypes.POINTER(PEB))[0]
1352-
13531339
# Memory stuff
13541340

13551341
class EPSAPI_WORKING_SET_BLOCK_BASE(object):
@@ -1461,10 +1447,24 @@ def apisetmap(self):
14611447
raise NotImplementedError("ApiSetMap for remote process not implemented yet")
14621448

14631449

1450+
# TEB enhanced, same bitness as PEB (current process)
1451+
class TEB(gdef.TEB):
1452+
@property
1453+
def peb(self):
1454+
return ctypes.cast(self.ProcessEnvironmentBlock, ctypes.POINTER(PEB))[0]
14641455

1465-
1456+
# mote TEB enhanced, same bitness as PEB (current process)
1457+
class RemoteTEB(rctypes.RemoteStructure.from_structure(TEB)):
1458+
@property
1459+
def peb(self):
1460+
ctypes_peb = self.ProcessEnvironmentBlock.value
1461+
return RemotePEB(ctypes_peb, self._target)
14661462

14671463
if CurrentProcess().bitness == 32:
1464+
RemoteLoadedModule32 = RemoteLoadedModule
1465+
RemotePEB32 = RemotePEB
1466+
RemoteTEB32 = RemoteTEB
1467+
14681468
class RemoteLoadedModule64(rctypes.transform_type_to_remote64bits(LoadedModule)):
14691469
@property
14701470
def pe(self):
@@ -1479,7 +1479,6 @@ class RemotePEB64(rctypes.transform_type_to_remote64bits(PEB)):
14791479
def ptr_flink_to_remote_module(self, ptr_value):
14801480
return RemoteLoadedModule64(ptr_value - ctypes.sizeof(rctypes.c_void_p64) * 2, self._target)
14811481

1482-
14831482
@property
14841483
def exe(self):
14851484
"""The executable of the process, as pointed by PEB.ImageBaseAddress
@@ -1512,7 +1511,17 @@ def environment(self):
15121511

15131512
apisetmap = RemotePEB.apisetmap
15141513

1514+
class RemoteTEB64(rctypes.transform_type_to_remote64bits(TEB)):
1515+
@property
1516+
def peb(self):
1517+
ctypes_peb = self.ProcessEnvironmentBlock.value
1518+
return RemotePEB64(ctypes_peb, self._target)
1519+
1520+
15151521
if CurrentProcess().bitness == 64:
1522+
RemoteLoadedModule64 = RemoteLoadedModule
1523+
RemotePEB64 = RemotePEB
1524+
RemoteTEB64 = RemoteTEB
15161525

15171526
class RemoteLoadedModule32(rctypes.transform_type_to_remote32bits(LoadedModule)):
15181527
@property
@@ -1558,4 +1567,10 @@ def environment(self):
15581567
# TODO: Tests
15591568
return self._extract_environment(self.ProcessParameters.contents.Environment, self._target)
15601569

1561-
apisetmap = RemotePEB.apisetmap
1570+
apisetmap = RemotePEB.apisetmap
1571+
1572+
class RemoteTEB32(rctypes.transform_type_to_remote32bits(TEB)):
1573+
@property
1574+
def peb(self):
1575+
ctypes_peb = self.ProcessEnvironmentBlock.value
1576+
return RemotePEB32(ctypes_peb, self._target)

0 commit comments

Comments
 (0)