diff --git a/src/sticker_convert/cli.py b/src/sticker_convert/cli.py index 47d5de5..4cc01a8 100755 --- a/src/sticker_convert/cli.py +++ b/src/sticker_convert/cli.py @@ -506,7 +506,7 @@ def get_opt_cred(self, args: Namespace) -> CredOption: ) if args.viber_get_auth: - get_viber_auth = GetViberAuth() + get_viber_auth = GetViberAuth(self.cb.ask_str) viber_bin_path = None if args.viber_bin_path: diff --git a/src/sticker_convert/gui_components/windows/viber_get_auth_window.py b/src/sticker_convert/gui_components/windows/viber_get_auth_window.py index 078b591..fbdeec3 100644 --- a/src/sticker_convert/gui_components/windows/viber_get_auth_window.py +++ b/src/sticker_convert/gui_components/windows/viber_get_auth_window.py @@ -103,7 +103,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: GUIUtils.finalize_window(self) def cb_get_cred(self) -> None: - m = GetViberAuth() + m = GetViberAuth(self.cb_ask_str_viber) viber_bin_path = None if self.gui.viber_bin_path_var.get(): @@ -123,7 +123,7 @@ def cb_get_cred(self) -> None: self.cb_msg_block_viber(msg) def cb_launch_viber(self) -> None: - m = GetViberAuth() + m = GetViberAuth(self.cb_ask_str_viber) viber_bin_path = m.get_viber_desktop() if self.gui.viber_auth_var.get(): diff --git a/src/sticker_convert/resources/memdump.sh b/src/sticker_convert/resources/memdump.sh new file mode 100755 index 0000000..1c79e2b --- /dev/null +++ b/src/sticker_convert/resources/memdump.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# Reference: https://github.com/hajzer/bash-memory-dump + +OS_PAGESIZE=`getconf PAGESIZE` + +PID=$1 +PID_MAPS=/proc/$PID/maps +PID_MEM=/proc/$PID/mem + +rm -f /tmp/viber.dmp.$PID +grep rw-p $PID_MAPS | +while IFS='' read -r line || [[ -n "$line" ]]; do + range=`echo $line | awk '{print $1;}'` + + vma_start=$(( 0x`echo $range | cut -d- -f1` )) + vma_end=$(( 0x`echo $range | cut -d- -f2` )) + vma_size=$(( $vma_end - $vma_start )) + + dd_start=$(( $vma_start / $OS_PAGESIZE )) + dd_bs=$OS_PAGESIZE + dd_count=$(( $vma_size / $OS_PAGESIZE )) + + set +e + dd if="$PID_MEM" bs="$dd_bs" skip="$dd_start" count="$dd_count" + set -e +done \ No newline at end of file diff --git a/src/sticker_convert/utils/auth/get_viber_auth.py b/src/sticker_convert/utils/auth/get_viber_auth.py index 281723c..5f820b5 100755 --- a/src/sticker_convert/utils/auth/get_viber_auth.py +++ b/src/sticker_convert/utils/auth/get_viber_auth.py @@ -4,8 +4,11 @@ import shutil import subprocess import time +from getpass import getpass from pathlib import Path -from typing import Optional, Tuple, cast +from typing import Callable, Optional, Tuple, cast + +from sticker_convert.definitions import ROOT_DIR # psutil is missing on arm64 linux appimage # Note: There is no Viber Desktop on arm64 linux anyway @@ -40,15 +43,29 @@ def killall(name: str) -> bool: result = False for proc in psutil.process_iter(): # type: ignore - if proc.name() == name: + if name in proc.name().lower(): proc.kill() result = True return result +def find_pid_by_name(name: str) -> Optional[int]: + if not PSUTIL_LOADED: + return None + + for proc in psutil.process_iter(): # type: ignore + if name in proc.name().lower(): + return proc.pid + + return None + + class GetViberAuth: - def get_auth(self, viber_bin_path: str) -> Tuple[Optional[str], str]: + def __init__(self, cb_ask_str: Callable[..., str] = input): + self.cb_ask_str = cb_ask_str + + def get_auth_windows(self, viber_bin_path: str) -> Tuple[Optional[str], str]: if not PSUTIL_LOADED: return None, MSG_NO_PSUTIL @@ -56,9 +73,7 @@ def get_auth(self, viber_bin_path: str) -> Tuple[Optional[str], str]: m_token = None m_ts = None - viber_process_name = Path(viber_bin_path).name.replace(".AppImage", "") - - killed = killall(viber_process_name) + killed = killall("viber") if killed: time.sleep(5) subprocess.Popen([viber_bin_path]) @@ -66,7 +81,8 @@ def get_auth(self, viber_bin_path: str) -> Tuple[Optional[str], str]: from PyMemoryEditor import OpenProcess # type: ignore - with OpenProcess(process_name=viber_process_name) as process: + viber_pid = find_pid_by_name("viber") + with OpenProcess(pid=viber_pid) as process: for address in process.search_by_value(str, 18, "X-Viber-Auth-Mid: "): # type: ignore member_id_addr = cast(int, address) + 18 member_id_bytes = process.read_process_memory(member_id_addr, bytes, 20) @@ -92,7 +108,93 @@ def get_auth(self, viber_bin_path: str) -> Tuple[Optional[str], str]: if m_ts is None: return None, MSG_NO_AUTH - killall(viber_process_name) + killall("viber") + + viber_auth = f"member_id:{member_id};m_token:{m_token};m_ts:{m_ts}" + msg = "Got viber_auth successfully:\n" + msg += f"{viber_auth=}\n" + + return viber_auth, msg + + def get_auth_linux(self, viber_bin_path: str) -> Tuple[Optional[str], str]: + if not PSUTIL_LOADED: + return None, MSG_NO_PSUTIL + + member_id = None + m_token = None + m_ts = None + + killed = killall("viber") + if killed: + time.sleep(5) + subprocess.Popen([viber_bin_path]) + time.sleep(10) + + viber_pid = find_pid_by_name("viber") + memdump_sh_path = (ROOT_DIR / "resources/memdump.sh").as_posix() + + s = subprocess.run( + [ + memdump_sh_path, + str(viber_pid), + ], + capture_output=True, + ).stdout + + if s.find(b"X-Viber-Auth-Mid: ") != -1: + pass + elif shutil.which("pkexec") and os.getenv("DISPLAY"): + s = subprocess.run( + [ + "pkexec", + memdump_sh_path, + str(viber_pid), + ], + capture_output=True, + ).stdout + else: + prompt = "Enter sudo password: " + if self.cb_ask_str != input: + sudo_password = self.cb_ask_str( + prompt, initialvalue="", cli_show_initialvalue=False + ) + else: + sudo_password = getpass(prompt) + sudo_password_pipe = subprocess.Popen( + ("echo", sudo_password), stdout=subprocess.PIPE + ) + s = subprocess.run( + [ + "sudo", + "-S", + memdump_sh_path, + str(viber_pid), + ], + capture_output=True, + stdin=sudo_password_pipe.stdout, + ).stdout + + member_id_addr = s.find(b"X-Viber-Auth-Mid: ") + m_token_addr = s.find(b"X-Viber-Auth-Token: ") + m_ts_addr = s.find(b"X-Viber-Auth-Timestamp: ") + + if member_id_addr == -1 or m_token_addr == -1 or m_ts_addr == -1: + return None, MSG_NO_AUTH + + member_id_addr += 18 + m_token_addr += 20 + m_ts_addr += 24 + + member_id_bytes = s[member_id_addr : member_id_addr + 20] + member_id_term = member_id_bytes.find(b"\x0d\x0a") + if member_id_term == -1: + return None, MSG_NO_AUTH + member_id = member_id_bytes[:member_id_term].decode(encoding="ascii") + + m_token = s[m_token_addr : m_token_addr + 64].decode(encoding="ascii") + m_ts = s[m_ts_addr : m_ts_addr + 13].decode(encoding="ascii") + + killall("viber") viber_auth = f"member_id:{member_id};m_token:{m_token};m_ts:{m_ts}" msg = "Got viber_auth successfully:\n" @@ -112,7 +214,7 @@ def get_auth_darwin(self, viber_bin_path: str) -> Tuple[Optional[str], str]: if "enabled" in csrutil_status: return None, MSG_SIP_ENABLED - killed = killall("Viber") + killed = killall("viber") if killed: time.sleep(5) subprocess.run( @@ -143,15 +245,19 @@ def get_auth_darwin(self, viber_bin_path: str) -> Tuple[Optional[str], str]: s = f.read() os.remove("/tmp/viber.dmp") - killall("Viber") + killall("viber") - member_id_addr = s.find(b"X-Viber-Auth-Mid: ") + 18 - m_token_addr = s.find(b"X-Viber-Auth-Token: ") + 20 - m_ts_addr = s.find(b"X-Viber-Auth-Timestamp: ") + 24 + member_id_addr = s.find(b"X-Viber-Auth-Mid: ") + m_token_addr = s.find(b"X-Viber-Auth-Token: ") + m_ts_addr = s.find(b"X-Viber-Auth-Timestamp: ") if member_id_addr == -1 or m_token_addr == -1 or m_ts_addr == -1: return None, MSG_NO_AUTH + member_id_addr += 18 + m_token_addr += 20 + m_ts_addr += 24 + member_id_bytes = s[member_id_addr : member_id_addr + 20] member_id_term = member_id_bytes.find(b"\x0d\x0a") if member_id_term == -1: @@ -201,7 +307,9 @@ def get_cred( if not viber_bin_path: return None, MSG_NO_BIN - if platform.system() == "Darwin": + if platform.system() == "Windows": + return self.get_auth_windows(viber_bin_path) + elif platform.system() == "Darwin": return self.get_auth_darwin(viber_bin_path) else: - return self.get_auth(viber_bin_path) + return self.get_auth_linux(viber_bin_path)