Thread-local storage#

class cle.backends.tls.ThreadManager[source]#

Bases: object

This class tracks what data is thread-local and can generate thread initialization images

Most of the heavy lifting will be handled in a subclass

__init__(loader, arch, max_modules=256)[source]#
register_object(obj)[source]#
static initialization_image(obj) bytes | None[source]#
Return type:

Optional[bytes]

new_thread(insert=True)[source]#
class cle.backends.tls.InternalTLSRelocation[source]#

Bases: Relocation

AUTO_HANDLE_NONE = True#
__init__(val, offset, owner)[source]#
property value#
resolvedby: Optional[Symbol]#
resolved: bool#
class cle.backends.tls.TLSObject[source]#

Bases: Backend

__init__(loader, arch)[source]#
Parameters:
  • binary – The path to the binary to load

  • binary_stream – The open stream to this binary. The reference to this will be held until you call close.

  • is_main_bin – Whether this binary should be loaded as the main executable

imports: typing.Dict[str, 'Relocation']#
relocs: List[Relocation]#
child_objects: List['Backend']#
exception_handlings: List[ExceptionHandling]#
function_hints: List[FunctionHint]#
memory: Clemory#
cached_content: Optional[bytes]#
class cle.backends.tls.ELFThreadManager[source]#

Bases: ThreadManager

__init__(*args, **kwargs)[source]#
register_object(obj)[source]#
class cle.backends.tls.ELFCoreThreadManager[source]#

Bases: ThreadManager

__init__(loader, arch, **kwargs)[source]#
new_thread(insert=False)[source]#
register_object(obj)[source]#
class cle.backends.tls.PEThreadManager[source]#

Bases: ThreadManager

register_object(obj)[source]#
class cle.backends.tls.MinidumpThreadManager[source]#

Bases: ThreadManager

__init__(loader, arch, **kwargs)[source]#
new_thread(insert=False)[source]#
register_object(obj)[source]#
class cle.backends.tls.tls_object.ThreadManager[source]#

Bases: object

This class tracks what data is thread-local and can generate thread initialization images

Most of the heavy lifting will be handled in a subclass

__init__(loader, arch, max_modules=256)[source]#
register_object(obj)[source]#
static initialization_image(obj) bytes | None[source]#
Return type:

Optional[bytes]

new_thread(insert=True)[source]#
class cle.backends.tls.tls_object.InternalTLSRelocation[source]#

Bases: Relocation

AUTO_HANDLE_NONE = True#
__init__(val, offset, owner)[source]#
property value#
resolvedby: Optional[Symbol]#
resolved: bool#
class cle.backends.tls.tls_object.TLSObject[source]#

Bases: Backend

__init__(loader, arch)[source]#
Parameters:
  • binary – The path to the binary to load

  • binary_stream – The open stream to this binary. The reference to this will be held until you call close.

  • is_main_bin – Whether this binary should be loaded as the main executable

imports: typing.Dict[str, 'Relocation']#
relocs: List[Relocation]#
child_objects: List['Backend']#
exception_handlings: List[ExceptionHandling]#
function_hints: List[FunctionHint]#
memory: Clemory#
cached_content: Optional[bytes]#

This module is used when parsing the Thread Local Storage of an ELF binary. It heavily uses the TLSArchInfo namedtuple from archinfo.

ELF TLS is implemented based on the following documents:

cle.backends.tls.elf_tls.roundup(val, to=16)[source]#
class cle.backends.tls.elf_tls.ELFThreadManager[source]#

Bases: ThreadManager

__init__(*args, **kwargs)[source]#
register_object(obj)[source]#
class cle.backends.tls.elf_tls.ELFTLSObject[source]#

Bases: TLSObject

__init__(thread_manager: ELFThreadManager)[source]#
Parameters:
  • binary – The path to the binary to load

  • binary_stream – The open stream to this binary. The reference to this will be held until you call close.

  • is_main_bin – Whether this binary should be loaded as the main executable

  • thread_manager (ELFThreadManager) –

property thread_pointer#

The thread pointer. This is a technical term that refers to a specific location in the TLS segment.

property user_thread_pointer#

The thread pointer that is exported to the user

property max_addr#

This returns the highest virtual address contained in any loaded segment of the binary.

get_addr(module_id, offset)[source]#

basically __tls_get_addr.

imports: typing.Dict[str, 'Relocation']#
relocs: List[Relocation]#
child_objects: List['Backend']#
exception_handlings: List[ExceptionHandling]#
function_hints: List[FunctionHint]#
memory: Clemory#
cached_content: Optional[bytes]#
class cle.backends.tls.elf_tls.ELFTLSObjectV1[source]#

Bases: ELFTLSObject

imports: typing.Dict[str, 'Relocation']#
relocs: List[Relocation]#
child_objects: List['Backend']#
exception_handlings: List[ExceptionHandling]#
function_hints: List[FunctionHint]#
memory: Clemory#
cached_content: Optional[bytes]#
tcb_offset: int#
dtv_offset: int#
tp_offset: int#
head_offset: int#
class cle.backends.tls.elf_tls.ELFTLSObjectV2[source]#

Bases: ELFTLSObject

imports: typing.Dict[str, 'Relocation']#
relocs: List[Relocation]#
child_objects: List['Backend']#
exception_handlings: List[ExceptionHandling]#
function_hints: List[FunctionHint]#
memory: Clemory#
cached_content: Optional[bytes]#
tcb_offset: int#
dtv_offset: int#
tp_offset: int#
head_offset: int#
class cle.backends.tls.pe_tls.PEThreadManager[source]#

Bases: ThreadManager

register_object(obj)[source]#
class cle.backends.tls.pe_tls.PETLSObject[source]#

Bases: TLSObject

This class is used when parsing the Thread Local Storage of a PE binary. It represents both the TLS array and the TLS data area for a specific thread.

In memory the PETLSObj is laid out as follows:

+----------------------+---------------------------------------+
| TLS array            | TLS data area                         |
+----------------------+---------------------------------------+

A more detailed description of the TLS array and TLS data areas is given below.

TLS array

The TLS array is an array of addresses that points into the TLS data area. In memory it is laid out as follows:

+-----------+-----------+-----+-----------+
|  address  |  address  | ... |  address  |
+-----------+-----------+-----+-----------+
| index = 0 | index = 1 |     | index = n |
+-----------+-----------+-----+-----------+

The size of each address is architecture independent (e.g. on X86 it is 4 bytes). The number of addresses in the TLS array is equal to the number of modules that contain TLS data. At load time (i.e. in the finalize method), each module is assigned an index into the TLS array. The address of this module’s TLS data area is then stored at this location in the array.

TLS data area

The TLS data area directly follows the TLS array and contains the actual TLS data for each module. In memory it is laid out as follows:

+----------+-----------+----------+-----------+-----+
| TLS data | zero fill | TLS data | zero fill | ... |
+----------+-----------+----------+-----------+-----+
|       module a       |       module b       | ... |
+---------------------------------------------------+

The size of each module’s TLS data area is variable and can be found in the module’s tls_data_size property. The same applies to the zero fill. At load time (i.e in the finalize method), the initial TLS data values are copied into the TLS data area. Because a TLS index is also assigned to each module, we can access a module’s TLS data area using this index into the TLS array to get the start address of the TLS data.

__init__(thread_manager: PEThreadManager)[source]#
Parameters:
  • binary – The path to the binary to load

  • binary_stream – The open stream to this binary. The reference to this will be held until you call close.

  • is_main_bin – Whether this binary should be loaded as the main executable

  • thread_manager (PEThreadManager) –

get_tls_data_addr(tls_idx)[source]#

Get the start address of a module’s TLS data area via the module’s TLS index.

From the PE/COFF spec:

The code uses the TLS index and the TLS array location (multiplying the index by the word size and using it as an offset into the array) to get the address of the TLS data area for the given program and module.

property max_addr#

This returns the highest virtual address contained in any loaded segment of the binary.

property thread_pointer#
property user_thread_pointer#
imports: typing.Dict[str, 'Relocation']#
relocs: List[Relocation]#
child_objects: List['Backend']#
exception_handlings: List[ExceptionHandling]#
function_hints: List[FunctionHint]#
memory: Clemory#
cached_content: Optional[bytes]#
class cle.backends.tls.elfcore_tls.ELFCoreThreadManager[source]#

Bases: ThreadManager

__init__(loader, arch, **kwargs)[source]#
new_thread(insert=False)[source]#
register_object(obj)[source]#
class cle.backends.tls.elfcore_tls.ELFCoreThread[source]#

Bases: object

__init__(loader, arch: Arch, threadinfo)[source]#
Parameters:

arch (Arch) –

property dtv#
get_addr(module_id, offset)[source]#

basically __tls_get_addr.

class cle.backends.tls.minidump_tls.MinidumpThreadManager[source]#

Bases: ThreadManager

__init__(loader, arch, **kwargs)[source]#
new_thread(insert=False)[source]#
register_object(obj)[source]#
class cle.backends.tls.minidump_tls.MinidumpThread[source]#

Bases: object

__init__(loader, arch: Arch, registers)[source]#
Parameters:

arch (Arch) –

get_tls_data_addr(tls_idx)[source]#