range(stack.top - 1, -1, -1) 中 stack.top 是 UINT64 字段,上界被推断为无符号时该递减循环的谓词退化为 ugt(-1 在无符号域即 UINT32_MAX) => 条件恒假、循环体不可达、_find_provider 恒返回 NULL,with 的 __mbuddy__ 注入失效(_str.upper 对 NULL 取 vtable 崩溃) 显式 t.CInt 转换使符号域与递减语义一致,与编译器侧 stop 为负字面量时退回有符号谓词的修复互为双保险
80 lines
3.2 KiB
Plaintext
80 lines
3.2 KiB
Plaintext
import t, c
|
||
from stdint import *
|
||
from w32.win32process import TlsAlloc, TlsGetValue, TlsSetValue
|
||
import stdlib
|
||
import stdio
|
||
import string
|
||
|
||
|
||
# Maximum provider stack depth (compiler verifies sufficiency; increase if needed)
|
||
_MAX_PROVIDER_DEPTH: t.CDefine = 32
|
||
|
||
|
||
@t.Object
|
||
class _ProviderStack:
|
||
"""Provider stack, stores pairs of field names and pointers."""
|
||
names: t.CArray[VOIDPTR, 32]
|
||
ptrs: t.CArray[VOIDPTR, 32]
|
||
top: UINT64
|
||
|
||
|
||
# TLS index (global; all threads share the same index)
|
||
_tls_index: ULONG = 0
|
||
|
||
|
||
@t.TLS
|
||
def _init_tls():
|
||
"""Initialize TLS index (executes once; subsequent calls are skipped)."""
|
||
global _tls_index
|
||
# 双保险:TPV 已正式实现 @t.TLS(函数级一次性守卫,首次执行后置
|
||
# __tls_init_done 标志,后续调用直接返回),此判重守卫保留以兼容
|
||
# 尚未重建的旧 TPV.exe。_tls_index 初始为 0(TlsAlloc 成功不会返回 0)。
|
||
if _tls_index == 0:
|
||
_tls_index = TlsAlloc()
|
||
|
||
|
||
def _get_stack() -> _ProviderStack | t.CPtr:
|
||
"""Obtain current thread's provider stack. Allocate one if none exists."""
|
||
_init_tls()
|
||
stack: _ProviderStack | t.CPtr = TlsGetValue(_tls_index)
|
||
if stack == None:
|
||
stack = stdlib.malloc(_ProviderStack.__sizeof__())
|
||
string.memset(stack, 0, _ProviderStack.__sizeof__())
|
||
TlsSetValue(_tls_index, stack)
|
||
return stack
|
||
|
||
|
||
def _push_provider(field_name: str, ptr: t.CPtr):
|
||
"""Push a provider (field_name, ptr) onto the stack."""
|
||
stack: _ProviderStack | t.CPtr = _get_stack()
|
||
if stack.top >= _MAX_PROVIDER_DEPTH:
|
||
stdio.printf("[with] ERROR: provider stack overflow (depth=%lu, max=%d), field '%s' not injected\n", stack.top, _MAX_PROVIDER_DEPTH, field_name)
|
||
return
|
||
stack.names[stack.top] = field_name
|
||
stack.ptrs[stack.top] = ptr
|
||
stack.top = stack.top + 1
|
||
|
||
|
||
def _pop_provider():
|
||
"""Pop the top provider entry from the stack."""
|
||
stack: _ProviderStack | t.CPtr = _get_stack()
|
||
if stack.top > 0:
|
||
stack.top = stack.top - 1
|
||
|
||
|
||
def _find_provider(field_name: str) -> t.CPtr:
|
||
"""Search for matching field_name starting from stack top.
|
||
Return associated pointer, or NULL if no match found."""
|
||
stack: _ProviderStack | t.CPtr = _get_stack()
|
||
# 上界显式转 t.CInt(有符号):本循环是「递减 + stop 为 -1」形态,若上界
|
||
# 被当作无符号(stack.top 是 UINT64 字段),比较谓词会退化为 ugt,而 -1 在
|
||
# 无符号域是 UINT32_MAX ⇒ 条件恒假、循环体不可达、本函数恒返回 NULL(with 的
|
||
# __mbuddy__ 注入全部失效,_str.upper 对 NULL 取 vtable 崩溃)。显式转换让
|
||
# 符号域与递减语义一致,与编译器侧「stop 为负字面量时退回有符号谓词」互为双保险。
|
||
for i in range(t.CInt(stack.top) - 1, -1, -1):
|
||
# 字段名用 strcmp 内容比较:编译器对每次 create_global_string 生成
|
||
# 独立的字符串常量(TPV 不去重),push/find 的指针地址不同,
|
||
# 指针 == 永假会导致 provider 匹配失败(__mbuddy__ 注入不上)。
|
||
if string.strcmp((str)(stack.names[i]), field_name) == 0:
|
||
return stack.ptrs[i]
|
||
return None |