Created
March 16, 2024 21:01
-
-
Save arisada/0423d42cfb04727ab0006392aadf42b1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
"""This script patches PixInsight 1.8.9-2 to nop the call to QWidget::raise() | |
in PixInsightWorkspace::OnMainWindowUnblocked(). | |
This works around the very annoying behavior of PixInsight putting itself | |
as top window when it receives focus. This happens often when you have other | |
windows open on top of Pix and you have "focus follows mouse" active in your | |
WM. | |
Tested for me, your mileage may vary. | |
This doesn't circumvent any security from PI. | |
2024 Aris Adamantiadis | |
""" | |
#from pwn import ELF | |
import struct | |
from hexdump import hexdump | |
import subprocess | |
import shutil | |
filename = 'PixInsight/bin/PixInsight' | |
#filename = 'pi-1.8.9-2-old/PixInsight/bin/PixInsight' | |
function_name = '_ZN2pi19PixInsightWorkspace21OnMainWindowUnblockedEv' | |
qwidget_raise = '_ZN7QWidget5raiseEv' | |
def patch_function_pwn(filename): | |
elf = ELF(filename) | |
print("ELF loaded") | |
function = elf.functions[function_name] | |
if function is None: | |
print(f"Function '{function_name}' not found.") | |
return | |
print(f'Function: {function}') | |
# Find the PLT entry for the symbol | |
plt_entry_offset = elf.plt[qwidget_raise] | |
if plt_entry_offset is None: | |
print(f"PLT entry for '{qwidget_raise}' not found.") | |
return | |
print(f'PLT entry: 0x{plt_entry_offset:x}') | |
fct = elf.read(function.address, function.size) | |
hexdump(fct) | |
for i in range(len(fct)-5): | |
if fct[i] != 0xe8: | |
continue | |
reladdr=struct.unpack("<I", fct[i+1:i+5])[0] | |
dst = (function.address + i + 5 + 4 + reladdr) & 0xffffffff | |
print(f"Call reladdr 0x{reladdr:x}, dst 0x{dst:x}") | |
if dst == plt_entry_offset: | |
print("Match") | |
else: | |
print("Call not found") | |
return | |
print(f"Call to '{function_name}' patched successfully.") | |
def exec_cmd(cmd): | |
result = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True) | |
return result.strip() | |
def patch_function_objdump(): | |
plt_entry_offset = exec_cmd(f"objdump -d {filename} | grep {qwidget_raise}") | |
plt_entry_offset = int(plt_entry_offset.split(':')[0], 16) | |
print(f'PLT entry: 0x{plt_entry_offset:x}') | |
function_address = exec_cmd(f"nm {filename} | grep -w 'T {function_name}'") | |
function_address = int(function_address.split(' ')[0], 16) | |
print(f'function address: 0x{function_address:x}') | |
shutil.copyfile(filename, filename + ".bak") | |
with open(filename, "r+b") as f: | |
f.seek(function_address) | |
fct = f.read(0x250) | |
# hexdump(fct) | |
matches = [] | |
for i in range(len(fct)-5): | |
if fct[i] != 0xe8: | |
continue | |
reladdr=struct.unpack("<I", fct[i+1:i+5])[0] | |
dst = (function_address + i + 5 + 4 + reladdr) & 0xffffffff | |
print(f"Call reladdr 0x{reladdr:x}, dst 0x{dst:x}") | |
if dst == plt_entry_offset: | |
print("Match") | |
matches.append(i) | |
if len(matches) != 1: | |
print("Won't patch, !=0 matches") | |
return | |
f.seek(function_address + matches[0]) | |
f.write(b"\x90"*5) | |
print(f"Call to '{function_name}' patched successfully.") | |
if __name__ == "__main__": | |
patch_function_objdump() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment