diff --git a/Apps/BlockTheSpot/install.bash b/apps/BlockTheSpot/install.bash similarity index 100% rename from Apps/BlockTheSpot/install.bash rename to apps/BlockTheSpot/install.bash diff --git a/Apps/Termux/install-termux-x11.bash b/apps/Termux/install-termux-x11.bash similarity index 100% rename from Apps/Termux/install-termux-x11.bash rename to apps/Termux/install-termux-x11.bash diff --git a/Apps/pinEApple/pinEApple-portable-launcher.sh b/apps/pinEApple/pinEApple-portable-launcher.sh similarity index 100% rename from Apps/pinEApple/pinEApple-portable-launcher.sh rename to apps/pinEApple/pinEApple-portable-launcher.sh diff --git a/Apps/proxytext/proxytext-wrapper.sh b/apps/proxytext/proxytext-wrapper.sh similarity index 100% rename from Apps/proxytext/proxytext-wrapper.sh rename to apps/proxytext/proxytext-wrapper.sh diff --git a/Apps/rclone/rclone-mount.bash b/apps/rclone/rclone-mount.bash similarity index 100% rename from Apps/rclone/rclone-mount.bash rename to apps/rclone/rclone-mount.bash diff --git a/Apps/rclone/setup-rclone-termux.bash b/apps/rclone/setup-rclone-termux.bash similarity index 100% rename from Apps/rclone/setup-rclone-termux.bash rename to apps/rclone/setup-rclone-termux.bash diff --git a/Apps/ws-scrcpy/README.md b/apps/ws-scrcpy/README.md similarity index 100% rename from Apps/ws-scrcpy/README.md rename to apps/ws-scrcpy/README.md diff --git a/Apps/ws-scrcpy/ws-scrcpy-launcher.py b/apps/ws-scrcpy/ws-scrcpy-launcher.py similarity index 100% rename from Apps/ws-scrcpy/ws-scrcpy-launcher.py rename to apps/ws-scrcpy/ws-scrcpy-launcher.py diff --git a/Games/Arena_of_Valor/.gitkeep b/games/Arena_of_Valor/.gitkeep similarity index 100% rename from Games/Arena_of_Valor/.gitkeep rename to games/Arena_of_Valor/.gitkeep diff --git a/Games/Arena_of_Valor/AWC_AutoSpin.js b/games/Arena_of_Valor/AWC_AutoSpin.js similarity index 100% rename from Games/Arena_of_Valor/AWC_AutoSpin.js rename to games/Arena_of_Valor/AWC_AutoSpin.js diff --git a/Games/Arena_of_Valor/README.md b/games/Arena_of_Valor/README.md similarity index 100% rename from Games/Arena_of_Valor/README.md rename to games/Arena_of_Valor/README.md diff --git a/Games/Cities_Skylines/NotParadoxLauncher_Win_Proton.sh b/games/Cities_Skylines/NotParadoxLauncher_Win_Proton.sh similarity index 100% rename from Games/Cities_Skylines/NotParadoxLauncher_Win_Proton.sh rename to games/Cities_Skylines/NotParadoxLauncher_Win_Proton.sh diff --git a/Games/Cities_Skylines/README.md b/games/Cities_Skylines/README.md similarity index 100% rename from Games/Cities_Skylines/README.md rename to games/Cities_Skylines/README.md diff --git a/Games/Cities_Skylines/Win_Proton_dowser_patch.sh b/games/Cities_Skylines/Win_Proton_dowser_patch.sh similarity index 100% rename from Games/Cities_Skylines/Win_Proton_dowser_patch.sh rename to games/Cities_Skylines/Win_Proton_dowser_patch.sh diff --git a/games/LoL/linux/README.md b/games/LoL/linux/README.md new file mode 100644 index 0000000..cc97623 --- /dev/null +++ b/games/LoL/linux/README.md @@ -0,0 +1,16 @@ +# leagueoflinux scripts +## `sulaunchhelper2.sh` +This script is a wrapper for `sulaunchhelper2.py` and `syscall_check.sh`, for use with Lutris pre-game launch script. ++ To install you must have `sulaunchhelper2.py` and `syscall_check.sh` present, if not you can execute these to quickly download them (to current directory): +```sh +curl -OL sulaunchhelper2.py +curl -OL syscall_check.sh +chmod +x sulaunchhelper2.py syscall_check.sh +``` ++ Then to download `sulaunchhelper2.sh` itself: +```sh +curl -OL sulaunchhelper2.sh +chmod +x sulaunchhelper2.sh +``` ++ After that, copy all these files to the game prefix you want to use, then set pre-launch script in Lutris to where `sulaunchhelper2.sh` is located. ++ Enjoy your LoL experience :P diff --git a/games/LoL/linux/sulaunchhelper2.py b/games/LoL/linux/sulaunchhelper2.py new file mode 100644 index 0000000..7ad455d --- /dev/null +++ b/games/LoL/linux/sulaunchhelper2.py @@ -0,0 +1,199 @@ +#!/usr/bin/env python3 + +import frida +import socket +import ssl +import psutil +import time +import subprocess +import sys + +""" + requires psutil, frida (pip install psutil frida) + + suLaunchhelper2 will try to lauch the League of Legends client by instrumenting frida (https://frida.re/) + This version requires sudo or `sysctl kernel.yama.ptrace_scope=0`. + It will launch frida directly from outside of wine. +""" + +WINEDUMP = 'winedump' # path to winedump, does not necessarily need to be the same version as wine + +SELECT_SIGNATURE = "'long', ['long', 'pointer', 'pointer', 'pointer'], 'stdcall'" # return type, [arg types...], abi + +sleep_time = 1 +timeout = 0 # 0 to disable + +hide_backtrace = True + + +class FridaWrapper(): + def __init__(self, process, module=None, export=None, position=None, signature=None): + self.session = None + self.process = process + self.module = module + self.export = export + self.position = position + self.signature = signature + + def get_location(self): + if self.module and self.export: + return f"Process.getModuleByName('{self.module}').getExportByName('{self.export}')" + if self.position and self.signature: + return f"new NativeFunction(ptr({hex(self.position)}), {self.signature})" + + def attach(self): + if self.session: return + self.session = frida.attach(self.process) + + + script = self.session.create_script(""" + Interceptor.attach( + """ + self.get_location() + """, { + onEnter: function(args) { + args[4].writeInt(0x0); + } + } + ); + """) + script.load() + + def detach(self): + if not self.session: return + script = self.session.create_script("Interceptor.detachAll();") + script.load() + self.session.detach() + self.session = None + + def attached(self): + return self.session is not None + +class TimeoutException(Exception): + pass + +class Process: + def __init__(self, name, internal=None): + self.name = name + self.internal = internal or name + self.process = None + + def find(self): + if p := find_process_by_name(self.internal): + self.process = p + return True + return False + + def wait_for(self, tsleep=1, timeout=0): + start = time.time() + while not self.find(): + time.sleep(sleep_time) + if timeout and time.time() - start > timeout: + raise TimeoutException(f'Timeout while waiting for {self.name}') + + def __repr__(self): + return self.name + +class Symbol: + def __init__(self, offset, position, name): + self.offset = offset if type(offset) == int else int(offset, 16) + self.position = int(position) + self.name = name + + def __repr__(self): + return f'Symbol(offset={hex(self.offset)}, position={self.position}, name=\'{self.name}\')' + +def check_ssl_connect(host, port, verify=True): + ctx = ssl.create_default_context() + if not verify: + ctx.check_hostname = False + ctx.verify_mode = ssl.CERT_NONE + try: + with socket.create_connection((host, port)) as sock: + with ctx.wrap_socket(sock) as ssock: + return True + except: + return False + +def find_process_by_name(name): + for p in psutil.process_iter(attrs=['pid', 'name']): + if p.info['name'] == name: + return p + +def find_section(proc, name): + for m in proc.memory_maps(grouped=False): + if m.path.lower().endswith(name.lower()): + return int(m.addr.split('-')[0], 16), m + +def get_dll_exports(dll): + exports = subprocess.run(['winedump', '-j', 'export', dll], stdout=subprocess.PIPE).stdout + exports = str(exports, 'utf-8') + exports = exports.split('\n') + exports = exports[19:-3] # everything before this is just the pretext + exports = [Symbol(sym[0], sym[1], sym[2]) for sym in [e.strip().split() for e in exports]] + return exports + +def find_dll_export(dll, export): + exports = get_dll_exports(dll) + for e in exports: + if e.name == export: + return e + +if __name__ == '__main__': + # hide backtrace + if hide_backtrace: + sys.tracebacklimit = None + + rclient = Process('RiotClientServices.exe', 'RiotClientServi') + lclient = Process('LeagueClient.exe') + lclientux = Process('LeagueClientUx.exe') + + # Wait for RiotClientServices.exe + print(f'Waiting for {rclient}') + rclient.wait_for(tsleep=sleep_time, timeout=timeout) + print(f'Found {rclient}: pid {rclient.process.pid}') + + base, module = find_section(rclient.process, 'ws2_32.dll') + exp_select = find_dll_export(module.path, 'select') + + # Wait for LeagueClient.exe + print(f'Waiting for {lclient}') + lclient.wait_for(tsleep=sleep_time, timeout=timeout) + print(f'Found {lclient}: pid {lclient.process.pid}') + + f = FridaWrapper(rclient.process.pid, position = base + exp_select.offset, signature = SELECT_SIGNATURE) + + # Wait for LeagueClientUx.exe + print(f'Waiting for {lclientux}') + start = time.time() + while not lclientux.find(): + if not f.attached(): + print('Attaching...') + f.attach() + time.sleep(sleep_time) + if timeout and time.time() - start > timeout: + f.detach() + raise TimeoutException(f'Timeout while waiting for {lclientux}') + print(f'Found {lclientux}: pid {lclientux.process.pid}') + + # Find app-port + port_xarg = next(x for x in lclientux.process.cmdline() if '--app-port=' in x) + port = port_xarg.split('=')[1] + + # Wait for SSL response on app-port + print(f'Waiting for port {port}') + start = time.time() + while not check_ssl_connect('127.0.0.1', port, verify=False): + if not f.attached(): + print('Attaching...') + f.attach() + time.sleep(sleep_time) + if timeout and time.time() - start > timeout: + f.detach() + raise TimeoutException(f'Timeout while waiting for SSL response') + + if f.attached(): + print('Detaching...') + f.detach() + else: + print('Nothing to do') + + print('Done') \ No newline at end of file diff --git a/games/LoL/linux/sulaunchhelper2.sh b/games/LoL/linux/sulaunchhelper2.sh new file mode 100755 index 0000000..e71eee4 --- /dev/null +++ b/games/LoL/linux/sulaunchhelper2.sh @@ -0,0 +1,54 @@ +#!/bin/bash +# This script is a wrapper for sulaunchhelper2.py and somewhat based on syscall_check.sh for kernel.yama.ptrace_scope wrapper +# Because this is for Lutris pre-launch script, you're required to have both sulaunchhelper2.py and syscall_check.sh +# present in the game' wineprefix + +SCC_SH='syscall_check.sh' +SULH_PY='sulaunchhelper2.py' + +dialog() { + zenity "$@" --icon-name='lutris' --width="400" --title="League of Legends launch helper (root version)" +} + +own_dir="$(realpath .)" +# try to call syscall_check.sh +if ! [ -x "${own_dir}/${SCC_SH}" ]; then + dialog "Please place this script into the same directory as '${SCC_SH}'!" +else + sh "${own_dir}/${SCC_SH}" +fi + + +if [ "$(cat /proc/sys/kernel/yama/ptrace_scope)" -ne 0 ]; then + once="Change setting until next reboot" + persist="Change setting and persist after reboot" + manual="Show me the commands; I'll handle it myself" + + if dialog --question --text="League of Legends' client UI launch much faster with some modification to your system. but as far as this script can detect, the setting has not been changed yet.\n\nWould you like to change the setting now?" + then + # I tried to embed the command in the dialog and run the output, but + # parsing variables with embedded quotes is an excercise in frustration. + RESULT=$(dialog --list --radiolist --height="200" \ + --column="" --column="Command" \ + "TRUE" "$once" \ + "FALSE" "$persist" \ + "FALSE" "$manual") + + case "$RESULT" in + "$once") + pkexec sysctl -w kernel.yama.ptrace_scope=0 + ;; + "$persist") + pkexec sh -c 'echo "kernel.yama.ptrace_scope=0" >> /etc/sysctl.conf && sysctl -p' + ;; + "$manual") + dialog --info --no-wrap --text="To change the setting (a kernel parameter) until next boot, run:\n\nsudo sh -c 'sysctl -w kernel.yama.ptrace_scope=0'\n\nTo persist the setting between reboots, run:\n\nsudo sh -c 'echo \"kernel.yama.ptrace_scope=0\" >> /etc/sysctl.conf && sysctl -p'\nChange the setting then press OK or script will NOT work." + ;; + *) + echo "Dialog canceled or unknown option selected: $RESULT" + ;; + esac + fi +fi + +python3 "${own_dir}/${SULH_PY}" diff --git a/games/LoL/linux/syscall_check.sh b/games/LoL/linux/syscall_check.sh new file mode 100755 index 0000000..a987c09 --- /dev/null +++ b/games/LoL/linux/syscall_check.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env sh + +# If abi.vsyscall32=0 is already set, no need to do anything +if [ "$(cat /proc/sys/abi/vsyscall32)" -eq 0 ]; then + exit 0 +fi + +dialog() { + zenity "$@" --icon-name='lutris' --width="400" --title="League of Legends anticheat compatibility check" +} + +final_check() { + if [ "$(cat /proc/sys/abi/vsyscall32)" -ne 0 ]; then + dialog --warning --text="As far as this script can detect, your system is not configured to work with League's anticheat. Please verify that you can get into the practice too before playing a multiplayer game." + fi +} + +trap final_check EXIT + +if grep -E -x -q "abi.vsyscall32( )?=( )?0" /etc/sysctl.conf; then + if dialog --question --text="It looks like you already configured your system to work with League anticheat, and saved the setting to persist across reboots. However, for some reason the persistence part did not work.\n\nFor now, would you like to enable the setting again until the next reboot?" + then + pkexec sh -c 'sysctl -w abi.vsyscall32=0' + fi + exit 0 +fi + +once="Change setting until next reboot" +persist="Change setting and persist after reboot" +manual="Show me the commands; I'll handle it myself" + +if dialog --question --text="League of Legends' anticheat requires using a modified version of wine and changing a system setting. Otherwise, the game will crash after champion select. Wine-lol comes with the Lutris installer, but as far as this script can detect, the setting has not been changed yet.\nNote: The setting (abi.vsyscall32=0) may reduce the performance of some 32 bit applications.\n\nWould you like to change the setting now?" +then + # I tried to embed the command in the dialog and run the output, but + # parsing variables with embedded quotes is an excercise in frustration. + RESULT=$(dialog --list --radiolist --height="200" \ + --column="" --column="Command" \ + "TRUE" "$once" \ + "FALSE" "$persist" \ + "FALSE" "$manual") + + case "$RESULT" in + "$once") + pkexec sh -c 'sysctl -w abi.vsyscall32=0' + ;; + "$persist") + pkexec sh -c 'echo "abi.vsyscall32 = 0" >> /etc/sysctl.conf && sysctl -p' + ;; + "$manual") + dialog --info --no-wrap --text="To change the setting (a kernel parameter) until next boot, run:\n\nsudo sh -c 'sysctl -w abi.vsyscall32=0'\n\nTo persist the setting between reboots, run:\n\nsudo sh -c 'echo \"abi.vsyscall32 = 0\" >> /etc/sysctl.conf && sysctl -p'" + # Anyone who wants to do it manually doesn't need another warning + trap - EXIT + ;; + *) + echo "Dialog canceled or unknown option selected: $RESULT" + ;; + esac +fi