Skip to content

Commit

Permalink
v1.2.7 - 05/12/2024 (14:15)
Browse files Browse the repository at this point in the history
  • Loading branch information
BUZZARDGTA committed Dec 5, 2024
1 parent 83bd1f2 commit 36bb3c0
Show file tree
Hide file tree
Showing 7 changed files with 381 additions and 188 deletions.
325 changes: 174 additions & 151 deletions GTA_V_Session_Sniffer.py

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion Modules/capture/capture.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,17 @@ def process_tshark_stdout(line: str):
with subprocess.Popen(
self._tshark_command,
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL,
stderr=subprocess.PIPE,
text=True
) as process:
self._tshark__process = process

yield from (Packet(fields) for fields in map(process_tshark_stdout, process.stdout))

# Check exit code after processing all stdout lines
if process.wait() != 0:
stderr_output = process.stderr.read()
raise TSharkCrashException(f"TShark exited with error code {process.returncode}:\n{stderr_output.strip()}")

def converts_tshark_packet_timestamp_to_datetime_object(packet_frame_time_epoch: str):
return datetime.fromtimestamp(timestamp=float(packet_frame_time_epoch))
164 changes: 129 additions & 35 deletions Modules/capture/utils.py
Original file line number Diff line number Diff line change
@@ -1,64 +1,158 @@
# Standard Python Libraries
import os
import subprocess
from pathlib import Path
from typing import Optional


class TSharkNotFoundException(Exception):
pass

class InvalidTSharkVersionException(Exception):
def __init__(self, version: str, tshark_path: Path):
self.version = version
self.path = tshark_path
self.message = f"Invalid TShark version: {version}"
super().__init__(self.message)


def get_tshark_path(tshark_path: Path = None):
"""Finds the path of the tshark executable.
If the user has provided a path it will be used
Otherwise default locations will be searched.
:param tshark_path: Path of the tshark binary
:raises TSharkNotFoundException in case TShark is not found in any location.
Args:
tshark_path (optional): If provided, the path of the tshark executable.
Raises:
TSharkNotFoundException: When TShark could not be found in any location.
"""
possible_paths: list[Path] = []

if tshark_path is not None:
user_tshark_path = None
import os
import winreg

def find_tshark_by_argument_path(possible_tshark_paths: list[Path]):
if tshark_path is not None:
user_tshark_path = None

if tshark_path.is_file():
if tshark_path.name == "tshark.exe":
user_tshark_path = tshark_path
elif tshark_path.is_dir():
if (tshark_path / "tshark.exe").is_file():
if tshark_path.is_file():
if tshark_path.name == "tshark.exe":
user_tshark_path = tshark_path
elif tshark_path.is_dir():
user_tshark_path = tshark_path / "tshark.exe"

if user_tshark_path:
possible_paths.insert(0, user_tshark_path)
if user_tshark_path:
possible_tshark_paths.insert(0, user_tshark_path)

return possible_tshark_paths

def find_tshark_by_wireshark_common_installation_path(possible_tshark_paths: list[Path]):
"""Adds common Wireshark installation paths to the provided list of possible paths.
This function checks the `ProgramFiles` and `ProgramFiles(x86)` environment variables to locate the
standard installation directories for Wireshark. If these directories exist, the path to `tshark.exe`
inside the `Wireshark` folder is appended to the list of possible paths.
Args:
possible_tshark_paths: A list of existing possible paths to Wireshark.
Returns:
list: The updated list of possible paths including standard installation paths.
"""
for env in ("ProgramFiles", "ProgramFiles(x86)"):
env_path = os.getenv(env)
if env_path is None:
continue

for env in ("ProgramFiles", "ProgramFiles(x86)"):
env_path = os.getenv(env)
if env_path is not None:
program_files = Path(env_path)
possible_paths.append(program_files / "Wireshark" / "tshark.exe")
possible_tshark_paths.append(program_files / "Wireshark" / "tshark.exe")

return possible_tshark_paths

def find_tshark_by_wireshark_regedit_installation_paths(possible_tshark_paths: list[Path]):
"""Find all possible installation paths of Wireshark by querying the Windows registry and add them to the provided list of potential paths."""
# Registry paths to check
registry_paths = [
R"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", # 64-bit programs
R"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall" # 32-bit programs
]

for registry_path in registry_paths:
try:
with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, registry_path) as reg_key:
for i in range(winreg.QueryInfoKey(reg_key)[0]): # Iterate through subkeys
subkey_name = winreg.EnumKey(reg_key, i)
with winreg.OpenKey(reg_key, subkey_name) as subkey:
try:
display_name = winreg.QueryValueEx(subkey, "DisplayName")[0]
if not isinstance(display_name, str):
continue
install_location = winreg.QueryValueEx(subkey, "InstallLocation")[0]
if not isinstance(install_location, str):
continue

if not display_name.startswith("Wireshark"):
continue

possible_tshark_paths.append(Path(install_location) / "tshark.exe")
except FileNotFoundError:
# Skip keys without the required values
continue
except FileNotFoundError:
# Skip if the registry path doesn't exist
continue

return possible_tshark_paths

def validate_tshark_path(possible_tshark_path: Path):
"""Validates if a given path points to a valid `tshark.exe` executable and matches the required version."""

import subprocess
from Modules.consts import WIRESHARK_REQUIRED_VERSION

def get_tshark_version(tshark_path: Path):
try:
result = subprocess.check_output([tshark_path, '--version'], text=True)
return result.splitlines()[0]
except (subprocess.CalledProcessError, FileNotFoundError):
pass

return None

if not possible_tshark_path.exists() or not possible_tshark_path.is_file():
return None

if tshark_version := get_tshark_version(possible_tshark_path):
if tshark_version is None:
return None

if tshark_version != WIRESHARK_REQUIRED_VERSION:
raise InvalidTSharkVersionException(tshark_version, possible_tshark_path)

return possible_tshark_path

possible_tshark_paths: list[Path] = []
possible_tshark_paths = find_tshark_by_argument_path(possible_tshark_paths)
possible_tshark_paths = find_tshark_by_wireshark_regedit_installation_paths(possible_tshark_paths)
possible_tshark_paths = find_tshark_by_wireshark_common_installation_path(possible_tshark_paths)

invalid_tshark_version_exception = None

for possible_tshark_path in possible_tshark_paths:
try:
if tshark_path := validate_tshark_path(possible_tshark_path):
return tshark_path
except InvalidTSharkVersionException as invalid_tshark_version:
invalid_tshark_version_exception = invalid_tshark_version

for path in possible_paths:
if path.exists():
return path
if invalid_tshark_version_exception:
raise invalid_tshark_version_exception

raise TSharkNotFoundException(
"TShark not found. Try adding its location to the configuration file.\n"
fR"Searched these paths: {', '.join(f'\"{path}\"' for path in possible_paths)}"
"TShark not found. Try adding its location to the configuration file.\n"
f"Searched these paths: {', '.join(f'\"{possible_tshark_path}\"' for possible_tshark_path in possible_tshark_paths)}"
)

def get_tshark_version(tshark_path: Optional[Path]):
tshark_path = get_tshark_path(tshark_path)

try:
result = subprocess.check_output([tshark_path, '--version'], text=True)
except (FileNotFoundError, subprocess.CalledProcessError):
return None
else:
return result.splitlines()[0]

def is_npcap_or_winpcap_installed():
import subprocess

service_names = ["npcap", "npf"]

for service in service_names:
Expand All @@ -69,4 +163,4 @@ def is_npcap_or_winpcap_installed():
else:
return True

return False
return False
21 changes: 21 additions & 0 deletions Modules/consts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from Modules.utils import get_documents_folder, resource_path

import re
from pathlib import Path
from datetime import datetime

USERIP_INI_SETTINGS_LIST = ["ENABLED", "COLOR", "NOTIFICATIONS", "VOICE_NOTIFICATIONS", "LOG", "PROTECTION", "PROTECTION_PROCESS_PATH", "PROTECTION_RESTART_PROCESS_PATH", "PROTECTION_SUSPEND_PROCESS_MODE"]
ANSI_ESCAPE = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])")
RE_MAC_ADDRESS_PATTERN = re.compile(r"^([0-9a-fA-F]{2}[:-]){5}([0-9a-fA-F]{2})$")
USERIP_DATABASES_PATH = Path("UserIP Databases")
SESSIONS_LOGGING_PATH = Path("Sessions Logging") / datetime.now().strftime("%Y/%m/%d") / f"{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.log"
USERIP_LOGGING_PATH = Path("UserIP_Logging.log")
TWO_TAKE_ONE__PLUGIN__LOG_PATH = Path.home() / "AppData/Roaming/PopstarDevs/2Take1Menu/scripts/GTA_V_Session_Sniffer-plugin/log.txt"
STAND__PLUGIN__LOG_PATH = Path.home() / "AppData/Roaming/Stand/Lua Scripts/GTA_V_Session_Sniffer-plugin/log.txt"
CHERAX__PLUGIN__LOG_PATH = get_documents_folder() / "Cherax/Lua/GTA_V_Session_Sniffer-plugin/log.txt"
TTS_PATH = resource_path(Path("TTS/"))
RE_SETTINGS_INI_PARSER_PATTERN = re.compile(r"^(?![;#])(?P<key>[^=]+)=(?P<value>[^;#]+)")
RE_USERIP_INI_PARSER_PATTERN = re.compile(r"^(?![;#])(?P<username>[^=]+)=(?P<ip>[^;#]+)")
RE_MODMENU_LOGS_USER_PATTERN = re.compile(r"^user:(?P<username>[\w._-]{1,16}), scid:\d{1,9}, ip:(?P<ip>[\d.]+), timestamp:\d{10}$")
WIRESHARK_REQUIRED_VERSION = "TShark (Wireshark) 4.2.9 (v4.2.9-0-g2acaabc9099c)."
WIRESHARK_REQUIRED_DL = "https://www.wireshark.org/download/win64/"
42 changes: 42 additions & 0 deletions Modules/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from pathlib import Path


def get_documents_folder():
"""Retrieves the Path object to the current user's \"Documents\" folder by querying the Windows registry."""
import winreg

reg_key = R"SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"

with winreg.OpenKey(winreg.HKEY_CURRENT_USER, reg_key) as key:
documents_path, _ = winreg.QueryValueEx(key, "Personal")

if not isinstance(documents_path, str):
raise TypeError(f'Expected "str", got "{type(documents_path)}"')

return Path(documents_path)

""" NOTE: Alternative code:
import os
import sys
from pathlib import Path
# Windows - Use SHGetKnownFolderPath for Documents
from win32com.shell import shell, shellcon
# Get the Documents folder path
documents_path = Path(shell.SHGetKnownFolderPath(shellcon.FOLDERID_Documents, 0))
# Append the desired file path
log_path = documents_path / "Cherax" / "Lua" / "GTA_V_Session_Sniffer-plugin" / "log.txt"
print(log_path)
"""

def resource_path(relative_path: Path):
"""Get absolute path to resource, works for dev and for PyInstaller."""
import sys

base_path = getattr(sys, "_MEIPASS", Path(__file__).resolve().parent.parent) # .parent twice because of modularizing bruh
if not isinstance(base_path, Path):
base_path = Path(base_path)
return base_path / relative_path
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,14 @@ This timer represents the duration between the timestamp of a captured packet an
When this timer is reached, the tshark process will be restarted.<br>
Valid values include any number greater than or equal to 3.

* `<CAPTURE_PREPEND_CUSTOM_CAPTURE_FILTER>`<br>
**For advanced users**; Allows you to specify a custom Tshark capture filter, which will be prepended to the filter used in the script.<br>
Learn more: [Wireshark Capture Filters](https://wiki.wireshark.org/CaptureFilters) / [Tshark Capture Filters](https://tshark.dev/capture/capture_filters/)

* `<CAPTURE_PREPEND_CUSTOM_DISPLAY_FILTER>`<br>
**For advanced users**; Allows you to specify a custom Tshark display filter, which will be prepended to the filter used in the script.<br>
Learn more: [Wireshark Display Filters](https://wiki.wireshark.org/DisplayFilters) / [Tshark Display Filters](https://tshark.dev/analyze/packet_hunting/packet_hunting/)

* `<STDOUT_SHOW_ADVERTISING_HEADER>`<br>
Determine if you want or not to show the developer's advertisements in the script's display.

Expand Down
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ colorama==0.4.6
geoip2==4.8.1
prettytable==3.12.0
psutil==6.1.0
pypresence==4.3.0
requests==2.32.3
rich==13.8.1
rich==13.9.4
urllib3==2.2.3
WMI==1.5.1

0 comments on commit 36bb3c0

Please sign in to comment.