robloxmemoryapi 0.3.0__tar.gz → 0.3.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- robloxmemoryapi-0.3.2/.github/workflows/publish.yml +84 -0
- robloxmemoryapi-0.3.2/.gitignore +12 -0
- robloxmemoryapi-0.3.2/.luaurc +5 -0
- robloxmemoryapi-0.3.2/CMakeLists.txt +18 -0
- {robloxmemoryapi-0.3.0/src/robloxmemoryapi.egg-info → robloxmemoryapi-0.3.2}/PKG-INFO +15 -16
- robloxmemoryapi-0.3.2/example.py +106 -0
- robloxmemoryapi-0.3.2/misc/BytecodeGen.luau +16 -0
- {robloxmemoryapi-0.3.0 → robloxmemoryapi-0.3.2}/pyproject.toml +15 -13
- robloxmemoryapi-0.3.2/rokit.toml +7 -0
- robloxmemoryapi-0.3.2/src/robloxmemoryapi/__init__.py +231 -0
- robloxmemoryapi-0.3.2/src/robloxmemoryapi/_native/__init__.py +1 -0
- robloxmemoryapi-0.3.2/src/robloxmemoryapi/_native/memory.cpp +998 -0
- robloxmemoryapi-0.3.2/src/robloxmemoryapi/_version.py +44 -0
- robloxmemoryapi-0.3.2/src/robloxmemoryapi/utils/macos.py +153 -0
- robloxmemoryapi-0.3.2/src/robloxmemoryapi/utils/memory.py +42 -0
- robloxmemoryapi-0.3.2/src/robloxmemoryapi/utils/offsets.py +43 -0
- {robloxmemoryapi-0.3.0 → robloxmemoryapi-0.3.2}/src/robloxmemoryapi/utils/rbx/instance.py +14 -3
- robloxmemoryapi-0.3.0/PKG-INFO +0 -69
- robloxmemoryapi-0.3.0/setup.cfg +0 -4
- robloxmemoryapi-0.3.0/src/robloxmemoryapi/__init__.py +0 -108
- robloxmemoryapi-0.3.0/src/robloxmemoryapi/utils/memory.py +0 -450
- robloxmemoryapi-0.3.0/src/robloxmemoryapi/utils/offsets.py +0 -24
- robloxmemoryapi-0.3.0/src/robloxmemoryapi.egg-info/SOURCES.txt +0 -20
- robloxmemoryapi-0.3.0/src/robloxmemoryapi.egg-info/dependency_links.txt +0 -1
- robloxmemoryapi-0.3.0/src/robloxmemoryapi.egg-info/requires.txt +0 -4
- robloxmemoryapi-0.3.0/src/robloxmemoryapi.egg-info/top_level.txt +0 -1
- {robloxmemoryapi-0.3.0 → robloxmemoryapi-0.3.2}/LICENSE.md +0 -0
- {robloxmemoryapi-0.3.0 → robloxmemoryapi-0.3.2}/README.md +0 -0
- {robloxmemoryapi-0.3.0 → robloxmemoryapi-0.3.2}/src/robloxmemoryapi/utils/__init__.py +0 -0
- {robloxmemoryapi-0.3.0 → robloxmemoryapi-0.3.2}/src/robloxmemoryapi/utils/luau/__init__.py +0 -0
- {robloxmemoryapi-0.3.0 → robloxmemoryapi-0.3.2}/src/robloxmemoryapi/utils/luau/parser.py +0 -0
- {robloxmemoryapi-0.3.0 → robloxmemoryapi-0.3.2}/src/robloxmemoryapi/utils/rbx/__init__.py +0 -0
- {robloxmemoryapi-0.3.0 → robloxmemoryapi-0.3.2}/src/robloxmemoryapi/utils/rbx/bytecode/decryptor.py +0 -0
- {robloxmemoryapi-0.3.0 → robloxmemoryapi-0.3.2}/src/robloxmemoryapi/utils/rbx/bytecode/encryptor.py +0 -0
- {robloxmemoryapi-0.3.0 → robloxmemoryapi-0.3.2}/src/robloxmemoryapi/utils/rbx/datastructures.py +0 -0
- {robloxmemoryapi-0.3.0 → robloxmemoryapi-0.3.2}/src/robloxmemoryapi/utils/rbx/fflags.py +0 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
release:
|
|
6
|
+
types: [published]
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
build-sdist:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- name: Check out repository
|
|
13
|
+
uses: actions/checkout@v4
|
|
14
|
+
|
|
15
|
+
- name: Set up Python
|
|
16
|
+
uses: actions/setup-python@v5
|
|
17
|
+
with:
|
|
18
|
+
python-version: "3.11"
|
|
19
|
+
|
|
20
|
+
- name: Build source distribution
|
|
21
|
+
run: |
|
|
22
|
+
python -m pip install --upgrade pip
|
|
23
|
+
python -m pip install build
|
|
24
|
+
python -m build --sdist
|
|
25
|
+
|
|
26
|
+
- name: Upload source distribution
|
|
27
|
+
uses: actions/upload-artifact@v4
|
|
28
|
+
with:
|
|
29
|
+
name: sdist
|
|
30
|
+
path: dist/*.tar.gz
|
|
31
|
+
|
|
32
|
+
build-wheels:
|
|
33
|
+
name: Build wheels on ${{ matrix.os }}
|
|
34
|
+
runs-on: ${{ matrix.os }}
|
|
35
|
+
strategy:
|
|
36
|
+
fail-fast: false
|
|
37
|
+
matrix:
|
|
38
|
+
include:
|
|
39
|
+
- os: windows-latest
|
|
40
|
+
cibw_archs: AMD64
|
|
41
|
+
- os: macos-15-intel
|
|
42
|
+
cibw_archs: x86_64
|
|
43
|
+
- os: macos-15
|
|
44
|
+
cibw_archs: arm64
|
|
45
|
+
|
|
46
|
+
steps:
|
|
47
|
+
- name: Check out repository
|
|
48
|
+
uses: actions/checkout@v4
|
|
49
|
+
|
|
50
|
+
- name: Set up Python
|
|
51
|
+
uses: actions/setup-python@v5
|
|
52
|
+
with:
|
|
53
|
+
python-version: "3.11"
|
|
54
|
+
|
|
55
|
+
- name: Build wheels
|
|
56
|
+
uses: pypa/cibuildwheel@v2.20.0
|
|
57
|
+
env:
|
|
58
|
+
CIBW_BUILD: "cp39-* cp310-* cp311-* cp312-* cp313-*"
|
|
59
|
+
CIBW_SKIP: "pp* *-musllinux*"
|
|
60
|
+
CIBW_ARCHS: ${{ matrix.cibw_archs }}
|
|
61
|
+
|
|
62
|
+
- name: Upload wheels
|
|
63
|
+
uses: actions/upload-artifact@v4
|
|
64
|
+
with:
|
|
65
|
+
name: wheels-${{ matrix.os }}
|
|
66
|
+
path: wheelhouse/*.whl
|
|
67
|
+
|
|
68
|
+
publish:
|
|
69
|
+
needs: [build-sdist, build-wheels]
|
|
70
|
+
runs-on: ubuntu-latest
|
|
71
|
+
|
|
72
|
+
steps:
|
|
73
|
+
- name: Download distributions
|
|
74
|
+
uses: actions/download-artifact@v4
|
|
75
|
+
with:
|
|
76
|
+
pattern: "*"
|
|
77
|
+
merge-multiple: true
|
|
78
|
+
path: dist
|
|
79
|
+
|
|
80
|
+
- name: Publish to PyPI
|
|
81
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
82
|
+
with:
|
|
83
|
+
password: ${{ secrets.PYPI_API_TOKEN }}
|
|
84
|
+
skip-existing: true
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
cmake_minimum_required(VERSION 3.15)
|
|
2
|
+
|
|
3
|
+
project(robloxmemoryapi_native LANGUAGES CXX)
|
|
4
|
+
|
|
5
|
+
find_package(Python COMPONENTS Interpreter Development.Module REQUIRED)
|
|
6
|
+
find_package(pybind11 CONFIG REQUIRED)
|
|
7
|
+
|
|
8
|
+
pybind11_add_module(memory MODULE src/robloxmemoryapi/_native/memory.cpp)
|
|
9
|
+
target_compile_features(memory PRIVATE cxx_std_17)
|
|
10
|
+
|
|
11
|
+
if(WIN32)
|
|
12
|
+
target_link_libraries(memory PRIVATE psapi)
|
|
13
|
+
endif()
|
|
14
|
+
|
|
15
|
+
install(TARGETS memory
|
|
16
|
+
LIBRARY DESTINATION robloxmemoryapi/_native
|
|
17
|
+
RUNTIME DESTINATION robloxmemoryapi/_native
|
|
18
|
+
)
|
|
@@ -1,33 +1,32 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
2
|
Name: robloxmemoryapi
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary: Python Library that abstracts reading and writing data from the Roblox DataModel
|
|
5
|
-
|
|
5
|
+
Keywords: roblox,memory,windows,macOS
|
|
6
|
+
Author-Email: upio <notpoiu@users.noreply.github.com>, mstudio45 <mstudio45@users.noreply.github.com>, ActualMasterOogway <ActualMasterOogway@users.noreply.github.com>
|
|
6
7
|
License: Copyright 2025 upio, mstudio45, master oogway
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
Project-URL: Homepage, https://github.com/notpoiu/RobloxMemoryAPI
|
|
15
|
-
Project-URL: Issues, https://github.com/notpoiu/RobloxMemoryAPI/issues
|
|
16
|
-
Keywords: roblox,memory,windows
|
|
8
|
+
|
|
9
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
14
|
+
|
|
17
15
|
Classifier: Programming Language :: Python :: 3
|
|
18
16
|
Classifier: License :: OSI Approved :: MIT License
|
|
19
17
|
Classifier: Operating System :: Microsoft :: Windows
|
|
18
|
+
Classifier: Operating System :: MacOS
|
|
20
19
|
Classifier: Development Status :: 3 - Alpha
|
|
21
20
|
Classifier: Intended Audience :: Developers
|
|
22
21
|
Classifier: Topic :: Software Development :: Libraries
|
|
22
|
+
Project-URL: Homepage, https://github.com/notpoiu/RobloxMemoryAPI
|
|
23
|
+
Project-URL: Issues, https://github.com/notpoiu/RobloxMemoryAPI/issues
|
|
23
24
|
Requires-Python: >=3.9
|
|
24
|
-
Description-Content-Type: text/markdown
|
|
25
|
-
License-File: LICENSE.md
|
|
26
25
|
Requires-Dist: requests>=2.0
|
|
27
26
|
Requires-Dist: zstandard>=0.19.0
|
|
28
27
|
Requires-Dist: xxhash>=3.6.0
|
|
29
28
|
Requires-Dist: blake3>=1.0.8
|
|
30
|
-
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
31
30
|
|
|
32
31
|
# RobloxMemoryAPI
|
|
33
32
|
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
from robloxmemoryapi import RobloxGameClient, RobloxRandom
|
|
2
|
+
from robloxmemoryapi.utils.rbx.datastructures import UDim2
|
|
3
|
+
import platform
|
|
4
|
+
import os
|
|
5
|
+
import hashlib
|
|
6
|
+
|
|
7
|
+
## Random Class ##
|
|
8
|
+
Test = RobloxRandom(5)
|
|
9
|
+
print("Roblox Random Demo")
|
|
10
|
+
print("math.random() with seed '5' result:", Test.NextNumber())
|
|
11
|
+
|
|
12
|
+
## Memory Reading ###
|
|
13
|
+
if platform.system() != "Windows":
|
|
14
|
+
print("Sorry! The memory reading module only works in windows, trying to access it will cause client.failed = True")
|
|
15
|
+
exit()
|
|
16
|
+
|
|
17
|
+
# Create a client instance
|
|
18
|
+
# allow_write is by default False, but can be enabled by passing True
|
|
19
|
+
client = RobloxGameClient(allow_write=True)
|
|
20
|
+
# client = RobloxGameClient(pid=2398) # PID is also possible
|
|
21
|
+
|
|
22
|
+
if client.failed:
|
|
23
|
+
print("Failed to get data model")
|
|
24
|
+
exit()
|
|
25
|
+
|
|
26
|
+
# Get the client's data model
|
|
27
|
+
game = client.DataModel
|
|
28
|
+
|
|
29
|
+
print("")
|
|
30
|
+
|
|
31
|
+
# Refresh hooks let you react when Roblox swaps between home screen and game.
|
|
32
|
+
def on_refresh(datamodel):
|
|
33
|
+
if game.is_lua_app():
|
|
34
|
+
print("[Refresh] You are now in the Roblox Home Screen.")
|
|
35
|
+
else:
|
|
36
|
+
print(f"[Refresh] You are now in-game (PlaceId: {game.PlaceId})")
|
|
37
|
+
|
|
38
|
+
# Register callback (optional invoke to run immediately with the current model).
|
|
39
|
+
game.bind_to_refresh(on_refresh, invoke_if_ready=True)
|
|
40
|
+
|
|
41
|
+
LocalPlayer = game.Players.LocalPlayer
|
|
42
|
+
|
|
43
|
+
print("")
|
|
44
|
+
|
|
45
|
+
# Print some info about the game
|
|
46
|
+
print("RobloxMemoryAPI Demo:")
|
|
47
|
+
print("An External Roblox Memory Reader")
|
|
48
|
+
print("==============================")
|
|
49
|
+
print("PlaceID:", game.PlaceId)
|
|
50
|
+
print("GameID:", game.GameId)
|
|
51
|
+
print("JobId:", game.JobId)
|
|
52
|
+
print("Loaded:", game.IsLoaded())
|
|
53
|
+
print("==============================")
|
|
54
|
+
print("Player Name:", LocalPlayer.Name, f"({LocalPlayer.DisplayName} | userid: {LocalPlayer.UserId})")
|
|
55
|
+
|
|
56
|
+
# LuaApp = Roblox Home Screen
|
|
57
|
+
if not game.is_lua_app():
|
|
58
|
+
print("Player HRP Parent:", LocalPlayer.Character.PrimaryPart.GetFullName())
|
|
59
|
+
print("Health:", LocalPlayer.Character.Humanoid.Health, LocalPlayer.Character.Humanoid.MaxHealth)
|
|
60
|
+
print("Player Count:", len(game.Players.GetPlayers()))
|
|
61
|
+
print("==============================")
|
|
62
|
+
print("CurrentCamera CFrame:", game.Workspace.CurrentCamera.CFrame)
|
|
63
|
+
print("CurrentCamera FOV:", game.Workspace.CurrentCamera.FieldOfView)
|
|
64
|
+
print("CurrentCamera ViewportSize:", game.Workspace.CurrentCamera.ViewportSize)
|
|
65
|
+
|
|
66
|
+
print("")
|
|
67
|
+
|
|
68
|
+
# Attributes
|
|
69
|
+
print("Attributes:")
|
|
70
|
+
for name, attribute in game.Workspace.GetAttributes().items():
|
|
71
|
+
print(f"Attribute: '{name}' | Type: {attribute.type_name} | Value: {attribute.value}")
|
|
72
|
+
|
|
73
|
+
print("")
|
|
74
|
+
|
|
75
|
+
if game.Workspace.GetAttribute("Test") is not None:
|
|
76
|
+
print("Test attribute found, testing...")
|
|
77
|
+
print(f"Old attribute: {game.Workspace.GetAttribute("Test")}")
|
|
78
|
+
game.Workspace.SetAttribute("Test", "Hello World")
|
|
79
|
+
print(f"New attribute: {game.Workspace.GetAttribute("Test")}")
|
|
80
|
+
|
|
81
|
+
print("")
|
|
82
|
+
|
|
83
|
+
# Bytecode operations (READING)
|
|
84
|
+
PlayerModule = LocalPlayer.PlayerScripts.PlayerModule
|
|
85
|
+
if PlayerModule is not None and PlayerModule.Bytecode is not None:
|
|
86
|
+
print("PlayerModule Script Hash:", hashlib.sha384(PlayerModule.RawBytecode).hexdigest())
|
|
87
|
+
|
|
88
|
+
# Bytecode write operations (WRITING)
|
|
89
|
+
if os.path.exists("misc/BytecodeToWrite.luac"):
|
|
90
|
+
with open("misc/BytecodeToWrite.luac", "rb") as f:
|
|
91
|
+
BytecodeToWrite = f.read()
|
|
92
|
+
|
|
93
|
+
PlayerModule.Bytecode = BytecodeToWrite
|
|
94
|
+
print("Set bytecode of PlayerModule to BytecodeToWrite.luac")
|
|
95
|
+
else:
|
|
96
|
+
print("misc/BytecodeToWrite.luac not found")
|
|
97
|
+
else:
|
|
98
|
+
print("Roblox is not in a game. No preview data available.")
|
|
99
|
+
|
|
100
|
+
# Write to the client's memory (kills player)
|
|
101
|
+
#LocalPlayer.Character.Humanoid.Health = 0
|
|
102
|
+
|
|
103
|
+
print("")
|
|
104
|
+
|
|
105
|
+
input("Press Enter to close.\n\n")
|
|
106
|
+
client.close()
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
local fs = require("@lune/fs")
|
|
2
|
+
local luau = require("@lune/luau")
|
|
3
|
+
|
|
4
|
+
fs.writeFile("BytecodeToWrite.luac", luau.compile([[
|
|
5
|
+
print("Hello World! :D")
|
|
6
|
+
|
|
7
|
+
local function sum(...)
|
|
8
|
+
local s = 0
|
|
9
|
+
for i, v in {...} do
|
|
10
|
+
s += v
|
|
11
|
+
end
|
|
12
|
+
return s
|
|
13
|
+
end
|
|
14
|
+
return sum(1, 2, 3, 4)]], {
|
|
15
|
+
optimizationLevel = 2
|
|
16
|
+
}))
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
[build-system]
|
|
2
|
-
requires = ["
|
|
3
|
-
build-backend = "
|
|
2
|
+
requires = ["scikit-build-core>=0.10", "pybind11>=2.12"]
|
|
3
|
+
build-backend = "scikit_build_core.build"
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "robloxmemoryapi"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.2"
|
|
8
8
|
description = "Python Library that abstracts reading and writing data from the Roblox DataModel"
|
|
9
9
|
readme = { file = "README.md", content-type = "text/markdown" }
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -14,11 +14,12 @@ authors = [
|
|
|
14
14
|
{ name = "mstudio45", email = "mstudio45@users.noreply.github.com" },
|
|
15
15
|
{ name = "ActualMasterOogway", email = "ActualMasterOogway@users.noreply.github.com" },
|
|
16
16
|
]
|
|
17
|
-
keywords = ["roblox", "memory", "windows"]
|
|
17
|
+
keywords = ["roblox", "memory", "windows", "macOS"]
|
|
18
18
|
classifiers = [
|
|
19
19
|
"Programming Language :: Python :: 3",
|
|
20
20
|
"License :: OSI Approved :: MIT License",
|
|
21
21
|
"Operating System :: Microsoft :: Windows",
|
|
22
|
+
"Operating System :: MacOS",
|
|
22
23
|
"Development Status :: 3 - Alpha",
|
|
23
24
|
"Intended Audience :: Developers",
|
|
24
25
|
"Topic :: Software Development :: Libraries",
|
|
@@ -34,13 +35,14 @@ dependencies = [
|
|
|
34
35
|
Homepage = "https://github.com/notpoiu/RobloxMemoryAPI"
|
|
35
36
|
Issues = "https://github.com/notpoiu/RobloxMemoryAPI/issues"
|
|
36
37
|
|
|
37
|
-
[tool.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
[tool.setuptools.packages.find]
|
|
42
|
-
where = ["src"]
|
|
43
|
-
|
|
44
|
-
[tool.setuptools.package-data]
|
|
45
|
-
robloxmemoryapi = ["data/*.json"]
|
|
38
|
+
[tool.scikit-build]
|
|
39
|
+
minimum-version = "build-system.requires"
|
|
40
|
+
build-dir = "build/{wheel_tag}"
|
|
41
|
+
wheel.packages = ["src/robloxmemoryapi"]
|
|
46
42
|
|
|
43
|
+
[tool.scikit-build.sdist]
|
|
44
|
+
include = [
|
|
45
|
+
"CMakeLists.txt",
|
|
46
|
+
"src/robloxmemoryapi/**/*.cpp",
|
|
47
|
+
"src/robloxmemoryapi/**/*.py",
|
|
48
|
+
]
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import platform
|
|
2
|
+
import math
|
|
3
|
+
import os
|
|
4
|
+
import subprocess
|
|
5
|
+
import sys
|
|
6
|
+
import tempfile
|
|
7
|
+
|
|
8
|
+
from ._version import __version__
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"RobloxRandom",
|
|
12
|
+
"RobloxGameClient",
|
|
13
|
+
"codesign_roblox_macos",
|
|
14
|
+
"codesign_python_macos",
|
|
15
|
+
"__version__",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def codesign_roblox_macos(
|
|
20
|
+
app_path: str | os.PathLike[str] | None = None,
|
|
21
|
+
*,
|
|
22
|
+
silicon_app_path: str | os.PathLike[str] = "/Applications/Roblox.app",
|
|
23
|
+
intel_app_path: str | os.PathLike[str] = "/Applications/RobloxPlayer.app",
|
|
24
|
+
use_sudo: bool = True,
|
|
25
|
+
) -> str:
|
|
26
|
+
"""Ad-hoc sign a macOS Roblox app bundle for local memory access workflows."""
|
|
27
|
+
if platform.system() != "Darwin":
|
|
28
|
+
raise RuntimeError("codesign_roblox_macos is only available on macOS.")
|
|
29
|
+
|
|
30
|
+
if app_path is None:
|
|
31
|
+
app_path = silicon_app_path if platform.machine().lower() == "arm64" else intel_app_path
|
|
32
|
+
|
|
33
|
+
app_path = os.fspath(app_path)
|
|
34
|
+
if not os.path.exists(app_path):
|
|
35
|
+
raise FileNotFoundError(app_path)
|
|
36
|
+
|
|
37
|
+
sudo_prefix = ["sudo"] if use_sudo and os.geteuid() != 0 else []
|
|
38
|
+
subprocess.run(
|
|
39
|
+
sudo_prefix + ["codesign", "--remove-signature", app_path],
|
|
40
|
+
stdout=subprocess.DEVNULL,
|
|
41
|
+
stderr=subprocess.DEVNULL,
|
|
42
|
+
check=False,
|
|
43
|
+
)
|
|
44
|
+
subprocess.run(
|
|
45
|
+
sudo_prefix + ["codesign", "--force", "--deep", "--sign", "-", app_path],
|
|
46
|
+
check=True,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
return app_path
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def codesign_python_macos(
|
|
53
|
+
executable_path: str | os.PathLike[str] | None = None,
|
|
54
|
+
*,
|
|
55
|
+
use_sudo: bool = True,
|
|
56
|
+
) -> str:
|
|
57
|
+
"""Ad-hoc sign the Python executable/launcher with the macOS debugger entitlement."""
|
|
58
|
+
if platform.system() != "Darwin":
|
|
59
|
+
raise RuntimeError("codesign_python_macos is only available on macOS.")
|
|
60
|
+
|
|
61
|
+
if executable_path is None:
|
|
62
|
+
executable_path = sys.executable
|
|
63
|
+
|
|
64
|
+
executable_path = os.path.realpath(os.fspath(executable_path))
|
|
65
|
+
if not os.path.exists(executable_path):
|
|
66
|
+
raise FileNotFoundError(executable_path)
|
|
67
|
+
|
|
68
|
+
entitlements = """<?xml version="1.0" encoding="UTF-8"?>
|
|
69
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
|
|
70
|
+
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
71
|
+
<plist version="1.0">
|
|
72
|
+
<dict>
|
|
73
|
+
<key>com.apple.security.cs.debugger</key>
|
|
74
|
+
<true/>
|
|
75
|
+
<key>com.apple.security.get-task-allow</key>
|
|
76
|
+
<true/>
|
|
77
|
+
<key>SecTaskAccess</key>
|
|
78
|
+
<array><string>allowed</string></array>
|
|
79
|
+
</dict>
|
|
80
|
+
</plist>
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
sudo_prefix = ["sudo"] if use_sudo and os.geteuid() != 0 else []
|
|
84
|
+
with tempfile.NamedTemporaryFile("w", suffix=".plist", delete=False) as entitlement_file:
|
|
85
|
+
entitlement_file.write(entitlements)
|
|
86
|
+
entitlement_path = entitlement_file.name
|
|
87
|
+
|
|
88
|
+
try:
|
|
89
|
+
subprocess.run(
|
|
90
|
+
sudo_prefix + ["codesign", "--remove-signature", executable_path],
|
|
91
|
+
stdout=subprocess.DEVNULL,
|
|
92
|
+
stderr=subprocess.DEVNULL,
|
|
93
|
+
check=False,
|
|
94
|
+
)
|
|
95
|
+
subprocess.run(
|
|
96
|
+
sudo_prefix
|
|
97
|
+
+ [
|
|
98
|
+
"codesign",
|
|
99
|
+
"--force",
|
|
100
|
+
"--sign",
|
|
101
|
+
"-",
|
|
102
|
+
"--entitlements",
|
|
103
|
+
entitlement_path,
|
|
104
|
+
executable_path,
|
|
105
|
+
],
|
|
106
|
+
check=True,
|
|
107
|
+
)
|
|
108
|
+
finally:
|
|
109
|
+
try:
|
|
110
|
+
os.unlink(entitlement_path)
|
|
111
|
+
except OSError:
|
|
112
|
+
pass
|
|
113
|
+
|
|
114
|
+
return executable_path
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class RobloxRandom:
|
|
118
|
+
MULT = 6364136223846793005
|
|
119
|
+
INC = 105
|
|
120
|
+
MASK64 = (1 << 64) - 1
|
|
121
|
+
|
|
122
|
+
def __init__(self, seed):
|
|
123
|
+
s = math.floor(seed)
|
|
124
|
+
|
|
125
|
+
self._state = 0
|
|
126
|
+
self._inc = RobloxRandom.INC
|
|
127
|
+
self._next_internal() # warm-up #1
|
|
128
|
+
self._state = (self._state + s) & RobloxRandom.MASK64
|
|
129
|
+
self._next_internal() # warm-up #2
|
|
130
|
+
|
|
131
|
+
def _next_internal(self):
|
|
132
|
+
old = self._state
|
|
133
|
+
self._state = (old * RobloxRandom.MULT + self._inc) & RobloxRandom.MASK64
|
|
134
|
+
x = ((old >> 18) ^ old) >> 27
|
|
135
|
+
r = old >> 59
|
|
136
|
+
return ((x >> r) | (x << ((32 - r) & 31))) & 0xFFFFFFFF
|
|
137
|
+
|
|
138
|
+
def _next_fraction64(self):
|
|
139
|
+
lo = self._next_internal()
|
|
140
|
+
hi = self._next_internal()
|
|
141
|
+
bits = (hi << 32) | lo
|
|
142
|
+
return bits / 2**64
|
|
143
|
+
|
|
144
|
+
def NextNumber(self, minimum=0.0, maximum=1.0):
|
|
145
|
+
frac = self._next_fraction64()
|
|
146
|
+
return minimum + frac * (maximum - minimum)
|
|
147
|
+
|
|
148
|
+
def NextInteger(self, a, b=None):
|
|
149
|
+
if b is None:
|
|
150
|
+
u = a
|
|
151
|
+
r = self._next_internal()
|
|
152
|
+
return ((u * r) >> 32) + 1
|
|
153
|
+
else:
|
|
154
|
+
lo, hi = (a, b) if a <= b else (b, a)
|
|
155
|
+
u = hi - lo + 1
|
|
156
|
+
r = self._next_internal()
|
|
157
|
+
return ((u * r) >> 32) + lo
|
|
158
|
+
|
|
159
|
+
class RobloxGameClient:
|
|
160
|
+
def __init__(
|
|
161
|
+
self,
|
|
162
|
+
pid: int = None,
|
|
163
|
+
process_name: str = "RobloxPlayerBeta.exe",
|
|
164
|
+
allow_write: bool = False,
|
|
165
|
+
):
|
|
166
|
+
system = platform.system()
|
|
167
|
+
if system not in {"Windows", "Darwin"}:
|
|
168
|
+
self.failed = True
|
|
169
|
+
return
|
|
170
|
+
|
|
171
|
+
if system == "Darwin" and os.geteuid() != 0:
|
|
172
|
+
raise PermissionError(
|
|
173
|
+
"macOS memory access requires running the Python process with sudo/root. "
|
|
174
|
+
"Run this script with sudo and try again."
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
from .utils.memory import (
|
|
178
|
+
EvasiveProcess,
|
|
179
|
+
PROCESS_QUERY_INFORMATION,
|
|
180
|
+
PROCESS_VM_READ,
|
|
181
|
+
PROCESS_VM_WRITE,
|
|
182
|
+
PROCESS_VM_OPERATION,
|
|
183
|
+
get_pid_by_name,
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
if system == "Darwin" and process_name == "RobloxPlayerBeta.exe":
|
|
187
|
+
process_name = "RobloxPlayer"
|
|
188
|
+
|
|
189
|
+
if pid is None:
|
|
190
|
+
self.pid = get_pid_by_name(process_name)
|
|
191
|
+
else:
|
|
192
|
+
self.pid = pid
|
|
193
|
+
|
|
194
|
+
if self.pid is None or self.pid == 0:
|
|
195
|
+
raise ValueError("Failed to get PID.")
|
|
196
|
+
|
|
197
|
+
if system == "Darwin":
|
|
198
|
+
os.environ["ROBLOXMEMORYAPI_ROBLOX_PID"] = str(self.pid)
|
|
199
|
+
|
|
200
|
+
desired_access = PROCESS_VM_READ | PROCESS_QUERY_INFORMATION
|
|
201
|
+
if allow_write:
|
|
202
|
+
desired_access |= PROCESS_VM_WRITE | PROCESS_VM_OPERATION
|
|
203
|
+
|
|
204
|
+
self.memory_module = EvasiveProcess(self.pid, desired_access)
|
|
205
|
+
self.failed = False
|
|
206
|
+
self._fflags = None
|
|
207
|
+
|
|
208
|
+
def close(self):
|
|
209
|
+
self.memory_module.close()
|
|
210
|
+
|
|
211
|
+
@property
|
|
212
|
+
def FFlags(self):
|
|
213
|
+
if platform.system() not in {"Windows", "Darwin"}:
|
|
214
|
+
raise RuntimeError("This module is only compatible with Windows and macOS.")
|
|
215
|
+
elif self.failed:
|
|
216
|
+
raise RuntimeError("There was an error while getting access to memory. Please try again later.")
|
|
217
|
+
|
|
218
|
+
if self._fflags is None:
|
|
219
|
+
from .utils.rbx.fflags import FFlagManager
|
|
220
|
+
self._fflags = FFlagManager(self.memory_module)
|
|
221
|
+
return self._fflags
|
|
222
|
+
|
|
223
|
+
@property
|
|
224
|
+
def DataModel(self):
|
|
225
|
+
if platform.system() not in {"Windows", "Darwin"}:
|
|
226
|
+
raise RuntimeError("This module is only compatible with Windows and macOS.")
|
|
227
|
+
elif self.failed:
|
|
228
|
+
raise RuntimeError("There was an error while getting access to memory. Please try again later.")
|
|
229
|
+
|
|
230
|
+
from .utils.rbx.instance import DataModel
|
|
231
|
+
return DataModel(self.memory_module)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Native extension package for robloxmemoryapi."""
|