Accessing CoreGui in localscript?

Hello, everyone.

I’ve been studying some exploit scripts recently, and I’ve noticed that they inject their interface into the CoreGui. I was wondering if there’s any way to access the CoreGui inside of a localscript so I can ban the player as soon as an object matching that name comes up.

Any help would be appreciated. :slight_smile:

15 Likes

You can access CoreGui by doing game.CoreGui.

What are you going to do with it exactly? What you said doesn’t work because CoreGui obviously is from Roblox and comes with every player, which would mean it would ban everyone.

2 Likes

I know what he’s talking about. This is dev support so I’ll keep it vague, but a certain 3 lettered explorer and property editor script injects it’s UI into CoreGui. Parts of CoreGui can be read from, but not wrote to. Theoretically, if written correctly, you can make a policy to check for said exploit UIs in your anti exploit. Then again, this is obviously a client side check. Easily disabled.

6 Likes

It could however be crafted in such a way that destroys gameplay by removing all client-side and interface functionality when disabled, however. Exploiting a game isn’t as fun if you can’t really play it.

3 Likes

How would you check for this? Exploiters can modify all code. They can delete only sections of scripts or modify those scripts such that it looks like it’s doing its job to the rest of your scripts but it’s actually making no checks and just reporting “all good” constantly.

Exploiters can stick their UI in existing CoreGui objects anyways, so you can’t just check for new ScreenGuis in CoreGui, you’d have to check to make sure it’s not added as a descendant to CoreGui. The exploiter’s GUI could start using randomized names or existing CoreGui names to make it hard to detect or differentiate from real GUI, too. GUIs can also be put in BillboardGuis, SurfaceGuis, or in the PlayerGui. It would take a ton of checks to find all of these, and all of those checks can be disabled individually no matter where you put them.

Checks like that can be good for slowing exploiters down, anyways, but it won’t be 100% prevention. Exploiters will work around it. To prevent exploits, you need to run exploit detection code on a computer that they don’t control i.e. the server.


game.DescendantAdded will fire when any object is added to the game, even for locked objects.

You can’t access any properties, events, or methods of locked objects. You can use tostring on them though to get their name. You can use this to detect when objects with certain names are added to the game at a performance cost. Running code any time an object is added to the game is bad for performance.

You can also use the game.ItemChanged event with the tostring technique to detect object and property changes. This would be really bad for performance, though.

If developers start using this, exploiters will just start using names of existing CoreGuis for their exploitation GUIs. I might have just spoiled this technique a bit early as I’m sure some exploit developer will read this. :man_shrugging:

13 Likes

I suppose you could then scan the children of said GUI, because not too many interfaces I know of would have thousands of buttons (because bad UI programming xd.)

Not to mention, you could have a table of allowed objects. Obviously, if two object’s names overlap, it flags the second GUI as being a hack and destroys it, quite possibly forcing the exploiter to restart his or her game. I don’t name more than one gui the same name ( to keep things organized.) There’s also being able to read the text from the GUI buttons themselves. I don’t know of any time you’d set a button to say “Execute” or anything.

There’s also ways of seeing what scripts are firing the remote event. If the source isn’t allowed, count it as a hack or a failed exploit attempt and ban the player.

I’ll see what I can come up with though.

AFAIK you can’t access descendants of CoreGui but you can index the object itself. Exploiters and their code are run on a different permission level which lets them directly access CoreGui and allow themselves to put things there. That’s to circumvent any checks and to ensure their Guis remain.

1 Like

I’m thinking I could modify a Roblox core script ( I mean, it seems to still allow access to the CoreGui within the modified script.)

I think I might write my anti-exploit code within a core script.

Not sure if that would work though!

2 Likes

Rip u can’t touch CoreScripts

1 Like

You can though.

They’re accessible at runtime through StarterPlayer.

It appears as though my idea has been defeated.

Is there an exact reason why developers can’t access the CoreGui?

I feel like it would make patching exploits far easier.

1 Like

The CoreGui is how the player accesses important functions in all Roblox games, such as the settings menu, the leave button, and purchase prompts. In fact, nearly all CoreGuis except the menu can be disabled.

If developers could change the CoreGui, then a malicious developer could trap kids in a game with seemingly no way out. There are many kids that don’t know other ways to close Roblox, especially if it’s in fullscreen or on the console.

Reading – not changing – the CoreGui isn’t as big of a deal, but it could be used to detect CoreGuis such as the menu or the purchase prompts in order to change or modify the game in order to misdirect or deceive the player. You should never need to access the built-in CoreGuis if you’re developing a legitimate game.

In essence, CoreGui is locked to prevent malicious developers from being malicious. Legitimate developers have no need to access it except for detecting exploits – which as previously stated won’t even work all the time. You’re better off programming your game with a good server/client relationship.


There’s no reason that Roblox cannot implement the same checks that you’re wanting to implement. If they did implement checks for new objects in the CoreGui, exploiters would just disable those checks. Client-side exploit detection is never permanent and is a constant battle. Server-side exploit detection is permanent and can’t be changed by the exploiter.

6 Likes

Oh wow.

So the coregui is just more than well, chat, backpack, and leaderboard. I can see why it’s locked to developers.

Still though, I think having readaccess would be sufficient to detect exploit interfaces, as most exploiters use the coreGui service and store their interface under a pretty obvious name, such as “Exploit Menu v2” or something similar. When a particular name is detected, and the children are similar to a logged exploit tool (within a module script) then it should be able to fire a server event that bans or kicks the player from the game.

I’ll see if there are other ways of detecting exploit menus, as there are RemoteEvent scrapers that run client-side inside of Roblox (for whatever reason…)

2 Likes

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