Accessing CoreGui in localscript?

Technically, they could make CoreGui and all descendants read-only. Making the assumption that ROBLOX wouldn’t be able to protect real CoreGuis from being deleted by a normal LocalScript is wrong.

Personally, I agree with allowing access to the Descendants of CoreGui - it really would help with exploiter detection. Howeeeeeverrrrrrr - unless changes are made so that you can’t even index certain things, people would be able to check the value of the “13+” or “<13” TextLabel near the leaderboard, and get a basic jist of the user’s age (which probably violates the privacy policy and COPPA guidelines)

I agree. To be clear, I didn’t assume that Roblox can’t make it read-only, I only considered a hypothetical scenario where Roblox allows changes. I followed that with a separate hypothetical scenario for if the CoreGui was read-only or otherwise protected.

Roblox exposes APIs for what we should have access to, and moves GUIs that don’t need privileged access to the PlayerGui. What’s left in the CoreGui has information that developers shouldn’t know or are GUIs that the developer should not mess with.

This means that the only uses for accessing the CoreGui are:

  • To get information you shouldn’t have
  • Or exploit prevention

I don’t think Roblox wants developers building exploit prevention around their CoreGuis. CoreGuis can be updated without any notification to developers, so a badly written exploit detection script could start punishing legitimate users after a Roblox update to the CoreGuis. Exposing read access to the CoreGuis also risks exposing information that developers shouldn’t have, which I’m sure Roblox wants to avoid. It’s easier to design with “no one can access this” than having to constantly consider, “can anyone access this, and how so?”


This makes me curious: are there any GUI (or other) objects that only show for either <13 or 13+, other than the age label? I’m not aware of any other ones.

1 Like

We could probably do that anyway by sending a string containing a word that doesn’t exist (not whitelisted) and checking if it is filtered for that user whereas not filtered for normal users. For best results probably test against multiple strings that aren’t filtered for >13 users and if they all come back filtered they’d know the user is <13

The filter changes way too much for this to be accurate. Heck, you can’t even get consistent filtering if you say something and then say it again in 30 seconds, so something like this would not work.

1 Like

Adding on: The filter is made to be adaptive. If you try to flat out say flol and get censored, it’ll be more sensitive as it assumes what comes next is you trying to bypass something that looks like flol.

2 Likes

Sorry for necrobumping this thread but I don’t think he ever got his question answered.

This is the script I used for my anti-exploit just make it into a local script and it’ll detect whenever a non roblox made GUI is put into the CoreGui and proceed to kick whatever player set it off.

wait(0)
bin = Instance.new("HopperBin", nil)
script.Parent = bin

local Player = game:GetService('Players').LocalPlayer
local coreFunctions = {}

function coreFunctions.CoreLocked(object) -- RobloxLocked Parent
    local active, status = pcall(function() object.Parent = object.Parent end)
    if active then return false end 
    return true
end

function coreFunctions.ServiceDescendant(object) -- First Parent
    local services = {
	    game:GetService('Workspace'),
	    game:GetService('Players'),
	    game:GetService('Lighting'),
	    game:GetService('ReplicatedFirst'),
	    game:GetService('ReplicatedStorage'),
	    --game:GetService('StarterGui'),
	    game:GetService('StarterPack'),
	    game:GetService('StarterPlayer'),
	    game:GetService('SoundService'),
	    game:GetService('HttpService'),
    }
	pcall(function()
	    for i,v in pairs(services) do
		    if object:IsDescendantOf(v) then return false end
	    end
    end)
    return true
end

function coreFunctions.ClientMember(object) -- ClassName Check
    local classes = {
    	'Script',
	    'LocalScript',
	    'CoreScript',
	    'ModuleScript',
    	'ScreenGui',
	    'SurfaceGui',
	    'Frame',
	    'ScrollingFrame',
	    'ImageButton',
	    'ImageLabel',
	    'TextBox',
	    'TextButton',
	    'TextLabel',
    }
    local objectName = tostring(tick()) 
    local active, status = pcall(function()
	    local objectTest = object[objectName]
    end)
    if status then 
	    local errorClass = status:match(objectName.." is not a valid member of (.*)")
	    for i,v in pairs(classes) do
		    if errorClass == v then 
			    return true
		    end
	    end
    end
    return false
end

function coreFunctions.IntegrityCheck(object) -- Valid Object Check
    local objectName = tostring(tick())
    local active, status = pcall(function()
	    game:GetService('GuiService'):AddSelectionParent(objectName, object)
    	game:GetService('GuiService'):RemoveSelectionGroup(objectName) 
    end)
    if status and status:find(objectName) and status:find('GuiService') then return true end
    wait()
    for i,v in pairs(game:GetService('LogService'):GetLogHistory()) do
    	if v.message:find(objectName) and v.message:find('GuiService') then return true end
	end
    return false
end

game.DescendantAdded:connect(function(object) -- DescendantAdded Object Check
	if type(object) == 'userdata' and coreFunctions.CoreLocked(object) then
    	if coreFunctions.ServiceDescendant(object) then
	    	if coreFunctions.ClientMember(object) then
		    	if coreFunctions.IntegrityCheck(object) then -- Confirmed H4X.
			    	Player:Kick() -- Reasonable.
			    end
		    end
	    end
    end
end)
58 Likes

The question was vaguely answered by responding to the actual problem (as this is an XY problem - the X being “how do I prevent Guis from being injected” and the Y being “how do I access CoreGui so I can delete unintended descendants”). You can’t access CoreGui descendants and you shouldn’t in the first place, because client-based checks can be circumvented. This is a waste of time and resources on your behalf.

1 Like

What Colbert has said is correct, the only way Ive found of accessing if a player has added an item into coregui is very hacky and requires you to process the error called by game.Descendantadded if you need a higher script context. There is however the menu in game which is part of the coregui which gets triggered by opening and closing which you will need to integrate into your anti exploit if you take this path. The only way I’ve managed to detect it is by having a trigger point for the amount of items which can be added to coregui. This method allows for me to catch Dex as a large amount of items are added but won’t work for smaller things depending on how many times you allow the “items” to be added for false positive prevention (speaking on the menu in the top left being open here). You can detect if the menu itself has been opened and disregard those items checked using the MenuIsOpen() but it will not allow you to detect the reset portion of the menu being opened (at least so far) so I have a bindable event in place to keep that greyed out and set the trigger point to 70 items max to prevent false positives and be able to catch Bigger guis.

Circumventable or not, this is still better than not having anything on the client. The strawman argument that it’s a “waste of time because it can be circumvented” serves no purpose other than to shut down any solutions that will work to an extent, if you know what you are doing. For instance, you could tie the above code to your game’s framework, set the script’s parent to nil, etc. etc.

Would really love it if people would stop using strawman arguments when it comes to solving problems that need fixing - they’re not constructive at all and honestly serve no purpose. I’m pretty sure other games use client-sided checks that aren’t circumventable by 99% of people.

11 Likes

It’s better how though? I don’t see the point, which is why I’m using the strawman argument in the first place. Explanations help to not have that brought up - it’s used when there’s not enough understanding.

The least you’re going to stop is a casual exploiter who isn’t spending the time to find out how your checks work or bother to circumvent them - it’s not going to stop a dedicated exploiter. I prefer to secure my server and close up as many open leverage points as possible, rather than bother myself with what someone is doing with a device they have full control over.

I don’t see client-side checks “working to an extent”. They sound more like band-aid solutions to me, which those band-aids can be pulled apart fairly quickly.

Like this. I don’t see how it works out for you. I’m not trying to shut it down; I genuinely don’t understand where you’re coming from. If you embed it into a game script then deleting the script means also breaking the rest of the game client-side; fine. It still comes off to me as a band-aid though.

Setting your script to nil won’t do anything except, as mentioned earlier, stop a casual without a function that can fetch nil instances. I don’t even believe LocalScripts run in nil.


See:

1 Like

It’s better because for casual exploiters, they won’t know how break the checking system, and I’m sure a developer with enough knowledge on coding could easily stop any attempt to get past the checks. I know viruses in the past had a function that would re-add themselves upon being destroyed, but I’m not sure if that’s still possible.

8 Likes

There’s a better way. You can check the ClassName of an object added to CoreGui in descendantadded, by indexing a nonexistant property in a pcall, like return obj[math.random()]. It will return a string like 0.123456789 is not a valid member of ScreenGui. From that point just grab the last part, check the name with tostring() and match it against your exceptions/black list.

A dedicated dev can stop a dedicated exploiter :wink:

I made an anti exploit place myself for pure fun, and so far only one exploiter managed to bypass it.
While making it, I focused on using non obvious ways of detecting things, such as using game.ItemChanged to detect WalkSpeed rather than connecting to a player’s Humanoid’s GetProppertyChangedSignal each time (since they can spoof :Connect()).
I also have a bunch of obstacles in place, such as

  • not using remotes to send to the server unless necessary
  • memchecks to prevent function replacing
  • a method which crashes the exploiter when they try to use a function called “getconnections” to disconnect my events
  • garbage collecting the primary modulescript and using a method which prevents them from obtaining a reference to it via “getloadedmodules”
  • using LinkedSource which breaks the decompiler of a particular exploit
  • having two methods of breaking unluac spread all over my script
  • constants validation with string.char (or rather ("").char, non-obvious as I said)
  • a few traps

Feel free to pm me a theoretical way you would use to bypass my checks if you were an exploiter, and I’ll see and tell you if it would work or not and why.

7 Likes

Not necessarily. Our code has lower context levels than their injected code. What I suggested is proper securing of the server, which is quite a bit of what you’ve done and that’s fine. Though a lot of it seems like obscurity. What client-side checks are you performing?

Okay so deep breath

  1. Connecting to script.Changed
  2. Connecting to ScriptContext.Error and checking for stuff such as if the script argument is nil
  3. If the script itself errored > instant crash (but again, without using while true do end as a primary way, because it can be easily bypassed with ScriptContext:SetTimeout()
  4. Some variables which are metatables with __tostring field that when triggered, kicks the player
  5. Checking for guis under CoreGui
  6. Setting TextService's name to "CoreGui" so when some exploits do game.CoreGui, they will index that service instead, which I connected ChildAdded to
  7. Checking for any changes to TextService
  8. Comparing if Instance.new("RemoteFunction").InvokeServer == cachedInvokeServer
  9. Comparing error messages to check if InvokeServer has been spoofed
  10. Xpcalling workspace:_____() and workspace[math.random()] and comparing the stack trace returned by setting the error handler argument to debug.traceback
  11. Comparring error messages returned by the xpcall
  12. Checking if Enum.HumanoidStateType.StrafingNoPhysics == cached and if typeof(it) == "EnumItem" to detect NoClip bypass attempts
  13. Setting the name of game.Players to " " and detecting if it’s renamed
  14. Checking for BodyMovers using FindFirstChildWhichIsA("BodyMover") (non obvious)
  15. Detecting any changes to remotes
  16. Checking for JumpPower, WalkSpeed and HipHeight changes
  17. Checking for Position, CFrame and Velocity changes of HumanoidRootPart
  18. Checking for a fake humanoid
  19. Checking for noclip
  20. A method which sometimes detects a particular exploit that spoofs __tostring of robloxlocked guis to return a fake name
  21. Checking if the main while loop has been aborted
  22. The only server-sided check - ping check (retcheck) with a remote function
  23. Checking for mismatch of string.char(str bytes) == str
  24. Another check if the while loop was aborted, but in a different script
  25. Checking if game:FindService("ServerStorage") returns nil or not in order to detect Dex
  26. Checking for FPS unlockers with RenderStepped
  27. Memchecks

(all detections kick the player)

14 Likes

A lot of that seems useless personally without embedding it into core game logic (standalone checks are meh, circumvent A+). If they work for you, then by all means go ahead and do it if you want, I guess. As a personal preference, I will never perform any kind of client-side checks. I am always going to be focused on securing my server. What a client does with their device is nothing of my concern.

2 Likes

If you hide the checks inside of a localscript that is crucial to gameplay then it would break their game when they try to disable it.

1 Like

See:


Again, this statement misses the point of anything I’m trying to say. See:

Don’t just assume that a client is able to leverage a point and give themselves advantages on my games. The only kind of advantage they would be able to receive in a model similar to mine (secure model) would only be for things they have authoritative control over.

I keep my server secure. I ensure my server checks any requests and validates their legitimacy. My problem is solved. Just because I don’t run checks on the client-side, doesn’t mean my game is insecure.


All in all, it comes down to preference. Kiriot thinks they are useful; I do not. That’s the end of it. I don’t waste my time doing client-side checks, Kiriot prefers to do them. I personally do not want to waste my time trying to add things to the client that can be circumvented, when I can focus my productivity on actually expanding and scaling my game.

I’m simply asking how kiriot finds them useful and what he does to gain an understanding of his view point on client-side checks not being “completely unnecessary”.

I could say it’s my hobby. If I know what other games are doing wrong in their clientsided anti exploits and if I also have some knowledge of how certain stuff works or how to patch it, then why couldn’t I cumulate all my knowledge and experience in one script? :smiley:

If an exploiter wants to idk make an autofarm script for your game, they will most likely use stuff such as Dex or a remote spy. Kicking them each time they use either of these or make a mistake can make them finally get bored and give up.

It may seem like a waste of time to you and I understand that, but it’s not like it takes weeks to make a clientsided anti exploit either. That’s why i said “a dedicated dev can stop a dedicated exploiter”

4 Likes

Ad Hominem attacks are a fallacious and unproductive form of logic. To many of us, they say more about the attacker than the victim.

The success of one method does not prove that is it better than another method. Both methods can stop exploits, the difference is that client side patches can ALWAYS be circumvented where as server sided patches have the potential to be ineluctable. Admittedly, client side checks are usually simpler to implement and can prevent the unmotivated or unskilled from performing an exploit. The bottom line is, however, that client side security is fundamentally flawed. If you don’t believe so, I’d be happy to have a lengthier discussion on another topic to prevent derailing this one any further.

4 Likes

See:

Please do not make ad hominem attacks on the forums. I have flagged your post (and the second one for being off-topic).

It’s not that I don’t “understand the usefulness” of client-side checks: it’s that I don’t want them, nor do I see their usefulness. Securing my server along with productivity is my focus in development. Whereas you have to set aside some time to maintain such checks that are circumventable depending on your implementation, server-side checks are fairly flawless AND I can focus on pushing new content.

In a game with proper server-side security there is very little that can be leveraged from the client-side alone for gameplay-inhibiting effects. Client-side checks to me are merely something extraneous to pursue in a pocket of time for maximising how much you can “mitigate exploitation”.

4 Likes