#!/usr/bin/env python3 """Rigorous verification: is the fixed SendInput code in the compiled run_win?""" import marshal import types import dis from PyInstaller.archive.readers import CArchiveReader EXE = r'dist\KiwySignagePlayer\KiwySignagePlayer.exe' def collect_strings(code, acc): for c in code.co_consts: if isinstance(c, str): acc.append(c) elif isinstance(c, types.CodeType): collect_strings(c, acc) def collect_codes(code, acc): acc.append(code) for c in code.co_consts: if isinstance(c, types.CodeType): collect_codes(c, acc) def main(): arc = CArchiveReader(EXE) data = arc.extract('run_win') code = marshal.loads(data) all_codes = [] collect_codes(code, all_codes) strings = [] collect_strings(code, strings) # 1) c_ulonglong can ONLY come from the fixed code (old used c_ulong + POINTER) has_c_ulonglong = any('c_ulonglong' in c.co_names for c in all_codes) print(f'c_ulonglong in co_names of any code object: {has_c_ulonglong}') # 2) INPUTUNION should be STORE_DEREF/STORE_NAME'd inside # _force_foreground_sendinput (classes are defined in a closure, # so they're stored via STORE_DEREF). store_names = set() for c in all_codes: for instr in dis.get_instructions(c): if instr.opname in ('STORE_NAME', 'STORE_FAST', 'STORE_DEREF'): store_names.add(instr.argval) print(f'INPUTUNION stored: {"INPUTUNION" in store_names}') print(f'KEYBDINPUT stored: {"KEYBDINPUT" in store_names}') print(f'MOUSEINPUT stored: {"MOUSEINPUT" in store_names}') print(f'HARDWAREINPUT stored: {"HARDWAREINPUT" in store_names}') # 3) The new code uses INPUT() + field assignment (type, u.ki.wVk, u.ki.dwFlags) names = set() for c in all_codes: names.update(c.co_names) print(f'Has "u" attribute usage: {"u" in names}') # 4) string markers print(f'string "undersized buffer": {any("undersized buffer" in s for s in strings)}') print(f'string "real Win32 x64": {any("real Win32 x64" in s for s in strings)}') print(f'string "ULONG_PTR": {any("ULONG_PTR" in s for s in strings)}') # 5) Console-window fix in _find_kivy_hwnd: cellvars/freevars + tuple consts find_kv = [c for c in all_codes if c.co_name == '_find_kivy_hwnd'] cell_vars = set() for c in find_kv: cell_vars.update(c.co_cellvars) cell_vars.update(c.co_freevars) enum_cb = [c for c in all_codes if c.co_name == '_enum_cb' and 'SDL_CLASSES' in c.co_freevars] tuple_strs = set() for c in enum_cb: for x in c.co_consts: if isinstance(x, tuple): tuple_strs.update(str(v) for v in x) print(f'_find_kivy_hwnd cell/free vars (SDL_CLASSES/sdl_windows/our_pid): ' f'{"SDL_CLASSES" in cell_vars and "sdl_windows" in cell_vars and "our_pid" in cell_vars}') print(f'console class excluded (ConsoleWindowClass in _enum_cb tuple): ' f'{"ConsoleWindowClass" in tuple_strs}') verdict = has_c_ulonglong and 'INPUTUNION' in store_names console_fix = ('SDL_CLASSES' in cell_vars and 'ConsoleWindowClass' in tuple_strs) print(f'\nVerdict SendInput: {"FIX PRESENT" if verdict else "FIX ABSENT - rebuild needed"}') print(f'Verdict console-hwnd: {"FIX PRESENT" if console_fix else "FIX ABSENT - rebuild needed"}') if __name__ == '__main__': main()