Function getrawmetatable() written in pure Luau (copyrawmetatable())

Very cool!

1 Like

Behavioural update

I recently discovered that the instance metamethods that are functions all interact with each other much more than I previously thought.

Hence, when one was detected to have a suspicious return value (i.e. it has been sethiddenstack()'d), it caused some others to be incorrect and not the actual metamethod.

I have changed it to hide all the function metamethods of an instance if one is detected to be hidden or modified.

Some executors also appear to automatically sethiddenstack() metamethods they hook, or return a similar return value to a function that has been sethiddenstack()'d. This also means copyrawmetatable can detect metamethod hooks for some executors.

1 Like

How did you make a message less than 30 letters?

Bro just do this for isMetatableProtected

local function isMetatableProtected(target: Instance|any): boolean
	return not pcall(setmetatable, target, target)
end

No, because that would set the target’s metatable to the target itself if it wasn’t protected.

Ok? Lol

local function isMetatableProtected(target: Instance|any): boolean
	return not pcall(setmetatable, target, getmetatable(target))
end
  1. that’d return two values sometimes.
  2. that’d introduce the possibility of false code logic provided that the target isn’t a table or an instance. The future logic actually relies on the return logic of isMetatableProtected and an error such as invalid argument #1 to 'setmetatable' (table expected, got string (for example) would mess with the entire function.

I’ll admit this code isn’t as optimised as it could be, but some of that is necessary. It’s designed defensively as I was originally making it for anticheat purposes, and we don’t want exploiters passing a userdata made in c++ with __type set. type or typeof could get hooked, I used them where necessary.

If you get a string from getmetatable(target) that means it’s metatable protected

setmetatable({}, {
    __metatable = "awef"
})

Like what will a different error do?

Yes, I’m aware, but you could still get a table depending on what it’s set to. Please refer to my previous post.

Wdym that would return two values

pcall(...)

Yes, it returns two values, but in a tuple
If you try to do things with it it will refer to the first one in the tuple

Okay?

local function isMetatableProtected(target: Instance|any): boolean
	return not pcall(setmetatable, target, getmetatable(target))
end 

local metatable = setmetatable({}, {__metatable = {}}) 
print(isMetatableProtected(metatable))

image

Yes it may get disregarded should it not be stored in a second variable, but should you want the error message returned too, it could cause some issues.

Like I said before, this is all in context of my more defensive design. Please refer to the context of the code and it’s intention.

Explain‮‮‮‮‮‮‮‮‮‮‮‮‮‮‮‮‮‮‮‮‮‮‮

Like I said, why do you even need the error message?

This is absolutely useless for any kind of exploit prevention simply because they will anyway find a way. But what is it useful for? Optimization: directly calling __index and __newindex is a lot faster than Instance.Property. I actually made a library called RawLib which collects some of the common metamethods. It also includes some other data types like CFrames, Vector2, etc.

1 Like

By your logic, that means you could just typecheck it to see if it should have a metatable, and just try to re-set that metatable, correct?

I need the error message to ensure the error was related to setting the metatable. If it wasn’t, then the call was invalid.

I will not be adjusting this, as it lies in the partial defensive design of this code. Feel free to change this yourself if you use it in your own code, but I will not be changing it on the community resource.

Changing that would mean I need to change a lot more code, which I am not going to do right now. I’ll probably take a look at a later date.

Ive taken an adaptation of this and used it in my own anticheat, with a few other hook checks. It’s proven incredibly effective so far.

Please don’t come to other resources and begin plugging your own resources. If you want to use that, use that.

local function isMetatableProtected(target: Instance|any): boolean
	local success, err = pcall(function()
		local old = getmetatable(target) -- Making extra variables for no reason

		setmetatable(target, {}) -- Bro just set it to getmetatable(target)?

		setmetatable(target, old) -- Unnecessary
	end)

        -- Oh, why is "not success" here? 
	return (not success and string.match(err:lower(), "protected metatable") ~= nil)
end

And why anything after “not success” is unnecessary:

local function isMetatableProtected(target: Instance|any): boolean
	print(pcall(setmetatable, target, getmetatable(target))) 
        return not pcall(setmetatable, target, getmetatable(target))
end 
local metatable = setmetatable({}, {__metatable = {}}) 
print("metatable (__metatable is table)")
print(isMetatableProtected(metatable)) 

local metatable1 = setmetatable({}, {__metatable = "A"})
print("metatable1 (__metatable is string)")
print(isMetatableProtected(metatable1))

local metatable2 = setmetatable({}, {})
print("metatable2 (no __metatable)")
print(isMetatableProtected(metatable2))

Result:

  17:01:37.892  metatable (__metatable is table)  -  Edit
  17:01:37.892  false cannot change a protected metatable  -  Edit
  17:01:37.892  true  -  Edit

  17:01:37.893  metatable1 (__metatable is string)  -  Edit
  17:01:37.893  false invalid argument #2 to 'setmetatable' (nil or table expected, got string)  -  Edit
  17:01:37.893  true  -  Edit

  17:01:37.894  metatable2 (no __metatable)  -  Edit
  17:01:37.895  true {}  -  Edit
  17:01:37.895  false  -  Edit

You literally don’t even have to change anything besides the function
Just because It’s the weekend doesn’t mean you shouldn’t listen to other people’s suggestions Lol

Any kind of client-side anti-cheat is incredibly pointless and a waste of time. It’s bypassed quickly, and the only thing it does is clog your client and code and prevent you from making actual improvements. Also, if clients somehow manage to give the server a table with a metatable, then the problem is not in checking the received object but in the design of your networking.

I wrote about my own experience with using raw metamethods. You can’t stop people from speaking

1 Like