Roblox Python External Process Tool
Roblox Python External Process Tool
pi180 = pi/180
aimbot_enabled = False
esp_enabled = False
esp_ignoreteam = False
esp_ignoredead = False
aimbot_ignoreteam = False
aimbot_ignoredead = False
aimbot_keybind = 2
aimbot_mode = "Hold"
aimbot_toggled = False
waiting_for_keybind = False
injected = False
VK_CODES = {
'Left Mouse': 1,
'Right Mouse': 2,
'Middle Mouse': 4,
'X1 Mouse': 5,
'X2 Mouse': 6,
'F1': 112, 'F2': 113, 'F3': 114, 'F4': 115, 'F5': 116, 'F6': 117,
'F7': 118, 'F8': 119, 'F9': 120, 'F10': 121, 'F11': 122, 'F12': 123,
'A': 65, 'B': 66, 'C': 67, 'D': 68, 'E': 69, 'F': 70, 'G': 71,
'H': 72, 'I': 73, 'J': 74, 'K': 75, 'L': 76, 'M': 77, 'N': 78,
'O': 79, 'P': 80, 'Q': 81, 'R': 82, 'S': 83, 'T': 84, 'U': 85,
'V': 86, 'W': 87, 'X': 88, 'Y': 89, 'Z': 90,
'Shift': 16, 'Ctrl': 17, 'Alt': 18, 'Space': 32,
'Enter': 13, 'Tab': 9, 'Caps Lock': 20
}
def get_key_name(vk_code):
for name, code in VK_CODES.items():
if code == vk_code:
return name
return f"Key {vk_code}"
def generate_random_title():
"""Generate a random title with 24 characters (letters and numbers, mixed
case)"""
characters = string.ascii_letters + [Link]
return ''.join([Link](characters) for _ in range(24))
def title_changer():
"""Background"""
while True:
try:
new_title = generate_random_title()
dpg.configure_item("Primary Window", label=new_title)
dpg.set_viewport_title(new_title)
except:
pass
# reduce CPU usage; adjust to taste (0.05s is reasonable)
sleep(0.05)
def normalize(vec):
norm = [Link](vec)
return vec / norm if norm != 0 else vec
try:
setOffsets(int(offsets['Name'], 16), int(offsets['Children'], 16))
except Exception:
pass
class RECT(Structure):
_fields_ = [('left', [Link]), ('top', [Link]), ('right',
[Link]), ('bottom', [Link])]
class POINT(Structure):
_fields_ = [('x', [Link]), ('y', [Link])]
def find_window_by_title(title):
return [Link](None, title)
def get_client_rect_on_screen(hwnd):
rect = RECT()
if [Link](hwnd, byref(rect)) == 0:
return 0, 0, 0, 0
top_left = POINT([Link], [Link])
bottom_right = POINT([Link], [Link])
[Link](hwnd, byref(top_left))
[Link](hwnd, byref(bottom_right))
return top_left.x, top_left.y, bottom_right.x, bottom_right.y
baseAddr = 0
camAddr = 0
dataModel = 0
wsAddr = 0
camCFrameRotAddr = 0
plrsAddr = 0
lpAddr = 0
matrixAddr = 0
camPosAddr = 0
esp = None
target = 0
def get_raw_processes():
return [[
[Link], [Link], [Link], [Link],
[Link], [Link], i.th32DefaultHeapID,
i.th32ModuleID, i.th32ParentProcessID, i.th32ProcessID
] for i in list_processes()]
def simple_get_processes():
return [{"Name": i[5].decode(), "Threads": i[0], "ProcessId": i[9]} for i in
get_raw_processes()]
def background_process_monitor():
global baseAddr
while True:
if is_process_dead():
while not yield_for_program("[Link]"):
sleep(0.5)
baseAddr = get_base_addr()
sleep(0.1)
# background monitor will be started later in __main__ after helper funcs are
defined
# Thread(target=background_process_monitor, daemon=True).start()
def show_main_features():
"""Show main features after injection delay and hide injector"""
dpg.hide_item("injector_text")
dpg.hide_item("inject_button")
dpg.show_item("main_features_text")
dpg.show_item("aimbot_checkbox")
dpg.show_item("esp_checkbox")
dpg.show_item("spacer1")
dpg.show_item("separator1")
dpg.show_item("spacer2")
def init():
global dataModel, wsAddr, camAddr, camCFrameRotAddr, plrsAddr, lpAddr,
matrixAddr, camPosAddr, injected, baseAddr, pm
try:
fakeDatamodel = pm.read_longlong(baseAddr +
int(offsets['FakeDataModelPointer'], 16))
print(f'Fake datamodel: {fakeDatamodel:x}')
dataModel = pm.read_longlong(fakeDatamodel +
int(offsets['FakeDataModelToDataModel'], 16))
print(f'Real datamodel: {dataModel:x}')
visualEngine = pm.read_longlong(baseAddr +
int(offsets['VisualEnginePointer'], 16))
matrixAddr = visualEngine + int(offsets['viewmatrix'], 16)
print(f'Matrix: {matrixAddr:x}')
# prefer finding by name because class name lookup can be unreliable across
versions
plrsAddr = FindFirstChildByName(dataModel, 'Players') or
FindFirstChildOfClass(dataModel, 'Players')
print(f'Players: {plrsAddr:x}')
# try to read LocalPlayer pointer from the Players service
try:
lpAddr = 0
if plrsAddr:
lpAddr = pm.read_longlong(plrsAddr + int([Link]('LocalPlayer',
'0'), 16))
print(f'LocalPlayer: {lpAddr:x}')
except Exception:
lpAddr = 0
print('LocalPlayer: 0 (could not read)')
for i, c in enumerate(children):
try:
model = pm.read_longlong(c + modelOff)
if not model:
print(f' [{i}] no model')
continue
head = FindFirstChildByName(model, 'Head')
if not head:
print(f' [{i}] no head')
continue
primitive = pm.read_longlong(head + primOff)
if not primitive:
print(f' [{i}] head has no primitive')
continue
world_pos = (
pm.read_float(primitive + posOff),
pm.read_float(primitive + posOff + 4),
pm.read_float(primitive + posOff + 8)
)
if view_proj is not None:
screen = world_to_screen_with_matrix(array(world_pos,
dtype=float32), view_proj, width, height)
else:
screen = None
print(f' [{i}] world={world_pos} screen={screen}')
except Exception as _e:
print(f' [{i}] pos read failed:', _e)
except Exception as e:
print('Players position debug failed:', e)
except Exception as e:
print('Players debug failed:', e)
except ProcessError:
print('You forget to open Roblox!')
return
except Exception as e:
print(f'Init failed: {e}')
return
globals()['lpAddr'] = lpAddr
globals()['matrixAddr'] = matrixAddr
globals()['plrsAddr'] = plrsAddr
print('Injected successfully\n-------------------------------')
injected = True
def delayed_show():
sleep(1)
show_main_features()
Thread(target=delayed_show, daemon=True).start()
def toogleEsp():
global hidden
try:
hidden = not hidden
except NameError:
# overlay not initialized yet; keep a module-level flag
globals().setdefault('hidden', True)
globals()['hidden'] = not globals()['hidden']
def toogleIgnoreTeamEsp():
global ignoreTeam
try:
ignoreTeam = not ignoreTeam
except NameError:
globals().setdefault('ignoreTeam', False)
globals()['ignoreTeam'] = not globals()['ignoreTeam']
def toogleIgnoreDeadEsp():
global ignoreDead
try:
ignoreDead = not ignoreDead
except NameError:
globals().setdefault('ignoreDead', False)
globals()['ignoreDead'] = not globals()['ignoreDead']
esp = None
def keybind_listener():
global waiting_for_keybind, aimbot_keybind
while True:
if waiting_for_keybind:
sleep(0.3)
key_found = False
while waiting_for_keybind and not key_found:
for vk_code in range(1, 256):
if [Link](vk_code) & 0x8000:
if vk_code == 27:
waiting_for_keybind = False
dpg.configure_item("keybind_button", label=f"Keybind:
{get_key_name(aimbot_keybind)}")
break
aimbot_keybind = vk_code
waiting_for_keybind = False
dpg.configure_item("keybind_button", label=f"Keybind:
{get_key_name(vk_code)}")
key_found = True
break
sleep(0.01)
else:
sleep(0.1)
Thread(target=keybind_listener, daemon=True).start()
def aimbotLoop():
global target, aimbot_toggled
key_pressed_last_frame = False
while True:
if aimbot_enabled:
key_pressed_this_frame = [Link](aimbot_keybind)
& 0x8000 != 0
if aimbot_mode == "Toggle":
if key_pressed_this_frame and not key_pressed_last_frame:
aimbot_toggled = not aimbot_toggled
key_pressed_last_frame = key_pressed_this_frame
should_aim = aimbot_toggled
else:
should_aim = key_pressed_this_frame
if should_aim:
if target > 0 and matrixAddr > 0:
from_pos = [pm.read_float(camPosAddr),
pm.read_float(camPosAddr+4), pm.read_float(camPosAddr+8)]
to_pos = [pm.read_float(target), pm.read_float(target+4),
pm.read_float(target+8)]
pm.write_float(camCFrameRotAddr, float(-right[0]))
pm.write_float(camCFrameRotAddr+4, float(up[0]))
pm.write_float(camCFrameRotAddr+8, float(-look[0]))
pm.write_float(camCFrameRotAddr+12, float(-right[1]))
pm.write_float(camCFrameRotAddr+16, float(up[1]))
pm.write_float(camCFrameRotAddr+20, float(-look[1]))
pm.write_float(camCFrameRotAddr+24, float(-right[2]))
pm.write_float(camCFrameRotAddr+28, float(up[2]))
pm.write_float(camCFrameRotAddr+32, float(-look[2]))
else:
target = 0
hwnd_roblox = find_window_by_title("Roblox")
if hwnd_roblox and matrixAddr > 0:
left, top, right, bottom =
get_client_rect_on_screen(hwnd_roblox)
matrix_flat = [pm.read_float(matrixAddr + i * 4) for i in
range(16)]
view_proj_matrix = reshape(array(matrix_flat,
dtype=float32), (4, 4))
# ensure local player / players pointers are valid before
reading memory
if lpAddr == 0 or plrsAddr == 0:
# not ready yet, back off and try again next loop
sleep(0.05)
continue
try:
lpTeam = pm.read_longlong(lpAddr + int(offsets['Team'],
16))
except Exception:
# failed to read local player (not initialized /
transient); retry later
sleep(0.05)
continue
width = right - left
height = bottom - top
widthCenter = width/2
heightCenter = height/2
minDistance = float('inf')
# precompute offsets locally (faster / clearer)
userIdOff = int([Link]('UserId', '0'), 16)
modelOff = int([Link]('ModelInstance', '0'), 16)
primOff = int([Link]('Primitive', '0'), 16)
posOff = int([Link]('Position', '0'), 16)
teamOff = int([Link]('Team', '0'), 16)
healthOff = int([Link]('Health', '0'), 16)
try:
localUserId = pm.read_int(lpAddr + userIdOff)
except Exception:
localUserId = None
for v in GetChildren(plrsAddr):
try:
# skip local player by UserId when possible
if localUserId is not None:
try:
otherId = pm.read_int(v + userIdOff)
if otherId == localUserId:
continue
except:
pass
if aimbot_ignoredead:
try:
health = pm.read_float(hum + healthOff)
if health <= 0:
continue
except:
continue
screen_coords =
world_to_screen_with_matrix(obj_pos, view_proj_matrix, width, height)
if screen_coords is not None:
distance = sqrt((widthCenter -
screen_coords[0])**2 + (heightCenter - screen_coords[1])**2)
if distance < minDistance:
minDistance = distance
target = targetPos
except Exception:
# skip this player on any transient memory/read
error
continue
else:
target = 0
else:
aimbot_toggled = False
sleep(0.1)
def keybind_callback():
global waiting_for_keybind
if not waiting_for_keybind:
waiting_for_keybind = True
dpg.configure_item("keybind_button", label="... (ESC to cancel)")
# ensure lib helpers are available at runtime (handles failed top-level import)
def ensure_lib():
global pm, yield_for_program, is_process_dead, get_base_addr
global DRP, GetName, GetClassName, GetChildren, FindFirstChild,
FindFirstChildOfClass, setOffsets
try:
# if already present, nothing to do
if 'yield_for_program' in globals() and 'pm' in globals():
return
from lib import pm as _pm, yield_for_program as _yfp, is_process_dead as
_ipd, get_base_addr as _gba
from lib import DRP as _drp, GetName as _getn, GetClassName as _getc,
GetChildren as _getc, FindFirstChild as _ffc, FindFirstChildOfClass as _ffcoc,
setOffsets as _so
pm = _pm
yield_for_program = _yfp
is_process_dead = _ipd
get_base_addr = _gba
DRP = _drp
GetName = _getn
GetClassName = _getc
GetChildren = _getc
FindFirstChild = _ffc
FindFirstChildOfClass = _ffcoc
setOffsets = _so
except Exception as e:
print("ensure_lib: failed to import lib helpers:", e)
def inject_callback():
# make sure lib helpers are available before attempting init()
ensure_lib()
init()
Thread(target=aimbotLoop, daemon=True).start()
dpg.create_context()
dpg.add_checkbox(label="Aimbot", default_value=aimbot_enabled,
callback=aimbot_callback, tag="aimbot_checkbox", show=False)
dpg.add_checkbox(label="ESP", default_value=esp_enabled, callback=esp_callback,
tag="esp_checkbox", show=False)
dpg.add_spacer(tag="spacer1", show=False)
dpg.add_separator(tag="separator1", show=False)
dpg.add_spacer(tag="spacer2", show=False)
dpg.add_button(label=f"Keybind: {get_key_name(aimbot_keybind)}",
tag="keybind_button", callback=keybind_callback)
dpg.add_combo(["Hold", "Toggle"], default_value=aimbot_mode,
tag="aimbot_mode_combo", callback=aimbot_mode_callback, width=100)
dpg.add_spacer()
dpg.add_separator()
dpg.add_spacer()
dpg.add_spacer()
dpg.add_button(label="Close", callback=lambda:
dpg.hide_item("aimbot_settings_popup"))
dpg.add_spacer()
dpg.add_button(label="Close", callback=lambda:
dpg.hide_item("esp_settings_popup"))
Thread(target=title_changer, daemon=True).start()
dpg.show_viewport()
dpg.start_dearpygui()
dpg.destroy_context()
# don't try to terminate an external process (we no longer spawn one)
GWL_EXSTYLE = -20
WS_EX_LAYERED = 0x80000
WS_EX_TRANSPARENT = 0x20
class RECT(Structure):
_fields_ = [('left', [Link]), ('top', [Link]), ('right',
[Link]), ('bottom', [Link])]
class POINT(Structure):
_fields_ = [('x', [Link]), ('y', [Link])]
def find_window_by_title(title):
return [Link](None, title)
def get_client_rect_on_screen(hwnd):
rect = RECT()
if [Link](hwnd, byref(rect)) == 0:
return 0, 0, 0, 0
top_left = POINT([Link], [Link])
bottom_right = POINT([Link], [Link])
[Link](hwnd, byref(top_left))
[Link](hwnd, byref(bottom_right))
return top_left.x, top_left.y, bottom_right.x, bottom_right.y
def GetChildren(instance: int) -> list:
if not instance:
return []
children = []
start = DRP(instance + childrenOffset)
if start == 0:
return []
end = DRP(start + 8)
current = DRP(start)
for _ in range(9000):
if current == end:
break
[Link](pm.read_longlong(current))
current += 0x10
return children
class ESPOverlay(QOpenGLWidget):
def __init__(self):
super().__init__()
[Link]([Link] | [Link] |
[Link])
[Link](Qt.WA_TranslucentBackground)
[Link](Qt.WA_NoSystemBackground)
[Link](1920, 1080)
[Link] = 0
[Link] = 0
[Link] = 0
self.plr_data = []
self.last_matrix = None
self.prev_geometry = (0, 0, 0, 0)
[Link] = 0
[Link] = 0
[Link] = 'white'
hwnd = [Link]().__int__()
ex_style = [Link](hwnd, GWL_EXSTYLE)
ex_style |= WS_EX_LAYERED | WS_EX_TRANSPARENT
[Link](hwnd, GWL_EXSTYLE, ex_style)
def initializeGL(self):
glClearColor(0.0, 0.0, 0.0, 0.0)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glLineWidth(3.0)
glEnable(GL_LINE_SMOOTH)
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST)
def paintGL(self):
glClear(GL_COLOR_BUFFER_BIT)
glLoadIdentity()
glColor3f(r, g, b)
glBegin(GL_LINES)
glVertex2f([Link], [Link])
glVertex2f(x, y)
glEnd()
def update_players(self):
if lpAddr == 0 or plrsAddr == 0 or matrixAddr == 0:
sleep(1)
return
if hidden:
sleep(1)
return
if [Link]():
sleep(0.1)
return
self.plr_data.clear()
if time() - [Link] > 1:
hwnd_roblox = find_window_by_title("Roblox")
if hwnd_roblox:
x, y, r, b = get_client_rect_on_screen(hwnd_roblox)
new_geom = (x, y, r - x, b - y)
if new_geom != self.prev_geometry:
[Link](*new_geom)
self.prev_geometry = new_geom
[Link] = [Link]() / 2
[Link] = [Link]() - [Link]() / 20
[Link] = time()
if count == 0:
return
try:
[Link] = colors[idx]
except IndexError:
pass
self.plr_data.append((x, y, [Link]))
[Link]()
hidden = True
def signalHandler():
global lpAddr, matrixAddr, plrsAddr, ignoreTeam, ignoreDead, hidden
while True:
for line in stdin:
line = [Link]()
if [Link]('addrs'):
addrs = line[5:].split(',')
lpAddr = int(addrs[0])
matrixAddr = int(addrs[1])
plrsAddr = int(addrs[2])
elif line == 'toogle1':
hidden = not hidden
if hidden:
esp.plr_data.clear()
[Link]()
sleep(0.1)
esp.plr_data.clear()
[Link]()
elif line == 'toogle2':
ignoreTeam = not ignoreTeam
elif line == 'toogle3':
ignoreDead = not ignoreDead
heads = []
colors = []
def headAndHumFinder():
global heads, colors
while True:
if lpAddr == 0 or plrsAddr == 0 or matrixAddr == 0:
sleep(1)
continue
if hidden:
sleep(1)
continue
tempColors = []
tempHeads = []
if __name__ == "__main__":
if hasattr(sys, '_MEIPASS'):
# previously spawned [Link] here — removed
esp = None
else:
# previously spawned [Link] here — removed
esp = None
rbxColors = {
1: "#F2F3F3",
2: "#A1A5A2",
3: "#F9E999",
5: "#D7C59A",
6: "#C2DAB8",
9: "#E8BAC8",
11: "#80BBDB",
12: "#CB8442",
18: "#CC8E69",
21: "#C4281C",
22: "#C470A0",
23: "#0D69AC",
24: "#F5CD30",
25: "#624732",
26: "#1B2A35",
27: "#6D6E6C",
28: "#287F47",
29: "#A1C48C",
36: "#F3CF9B",
37: "#4B974B",
38: "#A05F35",
39: "#C1CADE",
40: "#ECECEC",
41: "#CD544B",
42: "#C1DFF0",
43: "#7BB6E8",
44: "#F7F18D",
45: "#B4D2E4",
47: "#D9856C",
48: "#84B68D",
49: "#F8F184",
50: "#ECE8DE",
100: "#EEC4B6",
101: "#DA867A",
102: "#6E99CA",
103: "#C7C1B7",
104: "#6B327C",
105: "#E29B40",
106: "#DA8541",
107: "#008F9C",
108: "#685C43",
110: "#435493",
111: "#BFB7B1",
112: "#6874AC",
113: "#E5ADC8",
115: "#C7D23C",
116: "#55A5AF",
118: "#B7D7D5",
119: "#A4BD47",
120: "#D9E4A7",
121: "#E7AC58",
123: "#D36F4C",
124: "#923978",
125: "#EAB892",
126: "#A5A5CB",
127: "#DCBC81",
128: "#AE7A59",
131: "#9CA3A8",
133: "#D5733D",
134: "#D8DD56",
135: "#74869D",
136: "#877C90",
137: "#E09864",
138: "#958A73",
140: "#203A56",
141: "#27462D",
143: "#CFE2F7",
145: "#7988A1",
146: "#958EA3",
147: "#938767",
148: "#575857",
149: "#161D32",
150: "#ABADAC",
151: "#789082",
153: "#957979",
154: "#7B2E2F",
157: "#FFF67B",
158: "#E1A4C2",
168: "#756C62",
176: "#97695B",
178: "#B48455",
179: "#898787",
180: "#D7A94B",
190: "#F9D62E",
191: "#E8AB2D",
192: "#694028",
193: "#CF6024",
194: "#A3A2A5",
195: "#4667A4",
196: "#23478B",
198: "#8E4285",
199: "#635F62",
200: "#828A5D",
208: "#E5E4DF",
209: "#B08E44",
210: "#709578",
211: "#79B5B5",
212: "#9FC3E9",
213: "#6C81B7",
216: "#904C2A",
217: "#7C5C46",
218: "#96709F",
219: "#6B629B",
220: "#A7A9CE",
221: "#CD6298",
222: "#E4ADC8",
223: "#DC9095",
224: "#F0D5A0",
225: "#EBB87F",
226: "#FDEA8D",
232: "#7DBBDD",
268: "#342B75",
301: "#506D54",
302: "#5B5D69",
303: "#0010B0",
304: "#2C651D",
305: "#527CAE",
306: "#335882",
307: "#102ADC",
308: "#3D1585",
309: "#348E40",
310: "#5B9A4C",
311: "#9FA1AC",
312: "#592259",
313: "#1F801D",
314: "#9FADC0",
315: "#0989CF",
316: "#7B007B",
317: "#7C9C6B",
318: "#8AAB85",
319: "#B9C4B1",
320: "#CACBD1",
321: "#A75E9B",
322: "#7B2F7B",
323: "#94BE81",
324: "#A8BD99",
325: "#DFDFDE",
327: "#970000",
328: "#B1E5A6",
329: "#98C2DB",
330: "#FF98DC",
331: "#FF5959",
332: "#750000",
333: "#EFB838",
334: "#F8D96D",
335: "#E7E7EC",
336: "#C7D4E4",
337: "#FF9494",
338: "#BE6862",
339: "#562424",
340: "#F1E7C7",
341: "#FEF3BB",
342: "#E0B2D0",
343: "#D490BD",
344: "#965555",
345: "#8F4C2A",
346: "#D3BE96",
347: "#E2DCBC",
348: "#EDEAEA",
349: "#E9DADA",
350: "#883E3E",
351: "#BC9B5D",
352: "#C7AC78",
353: "#CABFA3",
354: "#BBB3B2",
355: "#6C584B",
356: "#A0844F",
357: "#958988",
358: "#ABA89E",
359: "#AF9483",
360: "#966766",
361: "#564236",
362: "#7E683F",
363: "#69665C",
364: "#5A4C42",
365: "#6A3909",
1001: "#F8F8F8",
1002: "#CDCDCD",
1003: "#111111",
1004: "#FF0000",
1005: "#FFB000",
1006: "#B080FF",
1007: "#A34B4B",
1008: "#C1BE42",
1009: "#FFFF00",
1010: "#0000FF",
1011: "#002060",
1012: "#2154B9",
1013: "#04AFEC",
1014: "#AA5500",
1015: "#AA00AA",
1016: "#FF66CC",
1017: "#FFAF00",
1018: "#12EED4",
1019: "#00FFFF",
1020: "#00FF00",
1021: "#3A7D15",
1022: "#7F8E64",
1023: "#8C5B9F",
1024: "#AFDDFF",
1025: "#FFC9C9",
1026: "#B1A7FF",
1027: "#9FF3E9",
1028: "#CCFFCC",
1029: "#FFFFCC",
1030: "#FFCC99",
1031: "#6225D1",
1032: "#FF00BF"
}
lpAddr = 0
matrixAddr = 0
plrsAddr = 0
ignoreTeam = False
ignoreDead = False
Thread(target=signalHandler, daemon=True).start()
def background_process_monitor():
global baseAddr
while True:
if is_process_dead():
while not yield_for_program("[Link]", False):
sleep(0.5)
baseAddr = get_base_addr()
sleep(0.1)
Thread(target=background_process_monitor, daemon=True).start()
Thread(target=headAndHumFinder, daemon=True).start()
app = QApplication([])
esp = ESPOverlay()
[Link]()
timer = QTimer()
[Link](esp.update_players)
[Link](8)
app.exec_()