Overkillz Posted April 17, 2019 Share Posted April 17, 2019 (edited) Hello dear community. Some time ago I started to work with loadstring and load functions. Nowadays I've realized that I got some issue with load so I decided to chose loadstring to reach my purpose. I have read some @IIYAMA topics and other people which had a similar problem some months/years ago, but sadly. I couldn't get the solution. I have currently 2 resource. One is to create the maps, gets the map files, scripts, store them in the cache ...etc, lets call it (MapCreator) and the other one is to execute the map scripts, lets call it (scriptRunner). Well, I have done a little version of them to make it more understable. I have found some problems with the mapCreator. to be clear, the whileIsEOF part. If I comment this part, the script runs correctly, but If I leave them uncommented, it doesn't read the script file. --##MapCreator local cachePath = "tempCache" local scriptList = {"client.lua","water.lua","shaders.lua"} function scriptRead() for i,mapScripts in ipairs(scriptList) do local scriptData local file = fileOpen(cachePath.."/"..mapScripts) if not file then error("Not file found") return end while not fileIsEOF(file) do scriptData = fileRead(file, fileGetSize(file)) end fileClose(file) if i == #scriptList then exports.scriptLoaderResource:runScript(scriptData, true) return end exports.scriptLoaderResource:runScript(scriptData, false) end end Well, on the other hand, at (scriptRunner). I have read that enviroments bring you more security to prevent that other people stole or execute your scripts. Im not sure if Im following the right way to run map scripts (Obyously no. Because sometimes in a X map. the song is executed like 3 times at the sime time) and Im not sure if the enviroments must be created like in my code. local enviroment = {} local blockedFunctions = { ["enviroment"] = true, ["newEnviroment"] = true, } function newEnviroment() enviroment = {} for name, valor in pairs(_G) do if not blockedFunctions[name] then enviroment[name] = valor end end end function runScript(scriptData, executeIt) newEnviroment() local loaded = loadstring(script) local ex = pcall(loaded) if ex then if executeIt then loaded() triggerEvent("onClientResourceStart", resourceRoot, getResourceFromName("scriptLoaderResource")) outputDebugString("Scripts Executed") end else outputDebugString("Not Executed") end end I hope you can help me to fix the issue that if the map has a script that play a song, it doesn't get execute more than 3 times (And not, on the script is only executed one time. It is a problem of my code.).And, can you tell me if the enviroments must be created like this ? I have to clean them or something when I change the map. And, how can I stop the runned scripts? I know that just setting the loaded variable as nil it should work but. How to deal properly with it. PS: the scripts that are inside the array scriptList are correctly coded. Thanks for reading. Best regards. Edited April 17, 2019 by Overkillz Link to comment
Moderators IIYAMA Posted April 17, 2019 Moderators Share Posted April 17, 2019 @Overkillz For each script you run, you are destroying the previous environment by overwriting the 'enviroment' variable. That does not go well. To be honest I haven't worked much with environments. But you will need to use setfenv function for cutting off the environment. Here a tutorial about the way to go, on the very BOTTOM of this page: http://lua-users.org/wiki/EnvironmentsTutorial A recommendation, based on just things that might be handy. Merge all the strings/scripts together and wrap each of them with: do --script end This will make sure that all local variables stay in their scope. An IIFE will do as well: (in case of an overflow of 200+ local variables in total) (function () -- script end)() Link to comment
Overkillz Posted April 17, 2019 Author Share Posted April 17, 2019 @IIYAMA How can I merge all of them with do ... end The only way I have learned currently is to add the new data to a string local scriptDataString for i,loopData in ipairs(whatever) do scriptDataString = scriptDataString.."\n"..loopData end Link to comment
Moderators IIYAMA Posted April 17, 2019 Moderators Share Posted April 17, 2019 (edited) 21 minutes ago, Overkillz said: ow can I merge all of them with More or less the same way scriptDataString .. "\n do \n" .. loopData .. "\n end \n" Edited April 17, 2019 by IIYAMA 1 Link to comment
Overkillz Posted April 18, 2019 Author Share Posted April 18, 2019 Well, I have just came at home to try it and Im still having the same issue with for example, playSound. The sound is executed more than one time, even if the scripts data are merged and I cant figure out why does it happen. local cachePath = "tempCache" local scriptList = {"client.lua","water.lua","shaders.lua"} function scriptRead() local scriptData = "" for i,mapScripts in ipairs(scriptList) do local file = fileOpen(cachePath.."/"..mapScripts) if not file then error("Not file found") return end while not fileIsEOF(file) do scriptData = scriptData .. "\n do \n" .. fileRead(file, fileGetSize(file)) .. "\n end \n" end fileClose(file) if i == #scriptList then exports.scriptLoaderResource:runScript(scriptData, true) end end end function runScript(scriptData, executeIt) local loaded = loadstring(script) local ex = pcall(loaded) if ex then if executeIt then loaded() triggerEvent("onClientResourceStart", resourceRoot, getResourceFromName("scriptLoaderResource")) end end end Probably the issue is on the triggerEvent, but I don't use it, the scripts are not executed. Weird no ? Regards. Link to comment
Moderators IIYAMA Posted April 18, 2019 Moderators Share Posted April 18, 2019 (edited) 7 hours ago, Overkillz said: Well, I have just came at home to try it and Im still having the same issue with for example, playSound. The sound is executed more than one time, even if the scripts data are merged and I cant figure out why does it happen. local cachePath = "tempCache" local scriptList = {"client.lua","water.lua","shaders.lua"} function scriptRead() local scriptData = "" for i,mapScripts in ipairs(scriptList) do local file = fileOpen(cachePath.."/"..mapScripts) if not file then error("Not file found") return end while not fileIsEOF(file) do scriptData = scriptData .. " do " .. fileRead(file, fileGetSize(file)) .. " end " end fileClose(file) if i == #scriptList then exports.scriptLoaderResource:runScript(scriptData, true) end end end function runScript(scriptData, executeIt) local loaded = loadstring(script) local ex = pcall(loaded) if ex then if executeIt then loaded() triggerEvent("onClientResourceStart", resourceRoot, getResourceFromName("scriptLoaderResource")) end end end Probably the issue is on the triggerEvent, but I don't use it, the scripts are not executed. Weird no ? Regards. Not really, pcall is already running the code. After that you are calling it without pcall again. pcall(loaded) -- call 1 loaded() -- call 2 Note: pcall executions do hide most of the debug information. So even if you did debug it, you wouldn't have noticed it. It is recommended to develop without pcall and when you are finish use it. I also saw you use triggerEvent on the resourceRoot. It is better if you do NOT use that at first. It is very important to understand that you can't just use the same element for all the resources. It will go bad... If you really want to use that. Top: local resourceRoot = createElement("resourceRootFaked") Bottom: triggerEvent("onClientResourceStart", resourceRoot, getResourceFromName("scriptLoaderResource")) And try to use the setfenv function as I have recommended before. In your current code all the global variables are exposed. Edited April 18, 2019 by IIYAMA 1 Link to comment
Overkillz Posted April 18, 2019 Author Share Posted April 18, 2019 @IIYAMA Well, as far as I read pcall executes the string and if it detecs an error it just ignores it. So, the code should be like this local resourceRoot = createElement("resourceRootFaked") local enviroment = {} local blockedFunctions = { ["enviroment"] = true, ["newEnviroment"] = true, } function newEnviroment() enviroment = {} for name, valor in pairs(_G) do if not blockedFunctions[name] then enviroment[name] = valor end end end function runScript(scriptData, executeIt) newEnviroment() local loaded = loadstring(script) local ex = pcall(loaded) setfenv(ex, enviroment) if ex then if executeIt then triggerEvent("onClientResourceStart", resourceRoot, getResourceFromName("scriptLoaderResource")) end end end 1 Link to comment
Scripting Moderators thisdp Posted April 18, 2019 Scripting Moderators Share Posted April 18, 2019 newEnv = {} setmetatable(newEnv,{__index=_G}) local fnc = loadstring(code) if fnc then setfenv(fnc,newEnv) fnc() end Maybe this can be better for new enviroment 1 Link to comment
Overkillz Posted April 18, 2019 Author Share Posted April 18, 2019 (edited) 1 hour ago, thisdp said: newEnv = {} setmetatable(newEnv,{__index=_G}) local fnc = loadstring(code) if fnc then setfenv(fnc,newEnv) fnc() end Maybe this can be better for new enviroment but what about if I want to block some variables/arrays ? Edited April 18, 2019 by Overkillz 1 Link to comment
Overkillz Posted April 19, 2019 Author Share Posted April 19, 2019 Well, I have done some test and looks that it is getting a better look. Btw, which one should be the way to test if my code is vulnerable to be read by those codes ? Tried with fileOpen, fileread ...etc but not success. (Obyously, the enviroment is removed during this test.) 1 Link to comment
Moderators IIYAMA Posted April 19, 2019 Moderators Share Posted April 19, 2019 1 hour ago, Overkillz said: Well, I have done some test and looks that it is getting a better look. Btw, which one should be the way to test if my code is vulnerable to be read by those codes ? Tried with fileOpen, fileread ...etc but not success. (Obyously, the enviroment is removed during this test.) You mean protection from stealers? Or access to files from different resources? 1 Link to comment
Ayush Rathore Posted April 19, 2019 Share Posted April 19, 2019 On 17/04/2019 at 20:22, Overkillz said: Hello dear community. Some time ago I started to work with loadstring and load functions. Nowadays I've realized that I got some issue with load so I decided to chose loadstring to reach my purpose. I have read some @IIYAMA topics and other people which had a similar problem some months/years ago, but sadly. I couldn't get the solution. I have currently 2 resource. One is to create the maps, gets the map files, scripts, store them in the cache ...etc, lets call it (MapCreator) and the other one is to execute the map scripts, lets call it (scriptRunner). Well, I have done a little version of them to make it more understable. I have found some problems with the mapCreator. to be clear, the whileIsEOF part. If I comment this part, the script runs correctly, but If I leave them uncommented, it doesn't read the script file. --##MapCreator local cachePath = "tempCache" local scriptList = {"client.lua","water.lua","shaders.lua"} function scriptRead() for i,mapScripts in ipairs(scriptList) do local scriptData local file = fileOpen(cachePath.."/"..mapScripts) if not file then error("Not file found") return end while not fileIsEOF(file) do scriptData = fileRead(file, fileGetSize(file)) end fileClose(file) if i == #scriptList then exports.scriptLoaderResource:runScript(scriptData, true) return end exports.scriptLoaderResource:runScript(scriptData, false) end end Well, on the other hand, at (scriptRunner). I have read that enviroments bring you more security to prevent that other people stole or execute your scripts. Im not sure if Im following the right way to run map scripts (Obyously no. Because sometimes in a X map. the song is executed like 3 times at the sime time) and Im not sure if the enviroments must be created like in my code. local enviroment = {} local blockedFunctions = { ["enviroment"] = true, ["newEnviroment"] = true, } function newEnviroment() enviroment = {} for name, valor in pairs(_G) do if not blockedFunctions[name] then enviroment[name] = valor end end end function runScript(scriptData, executeIt) newEnviroment() local loaded = loadstring(script) local ex = pcall(loaded) if ex then if executeIt then loaded() triggerEvent("onClientResourceStart", resourceRoot, getResourceFromName("scriptLoaderResource")) outputDebugString("Scripts Executed") end else outputDebugString("Not Executed") end end I hope you can help me to fix the issue that if the map has a script that play a song, it doesn't get execute more than 3 times (And not, on the script is only executed one time. It is a problem of my code.).And, can you tell me if the enviroments must be created like this ? I have to clean them or something when I change the map. And, how can I stop the runned scripts? I know that just setting the loaded variable as nil it should work but. How to deal properly with it. PS: the scripts that are inside the array scriptList are correctly coded. Thanks for reading. Best regards. https://github.com/Bonsai11/Multigamemode this resource might help you as it deals with loading map script files for specific player ( only client sided but might give you an idea on how to do it). CCS_wrapper This resources handles the loading of map scripts. Only clientside scripts are supported. CSS_wrapper is what you are looking for ! 1 Link to comment
Overkillz Posted April 19, 2019 Author Share Posted April 19, 2019 @IIYAMA I mean protection from the loaded string. Which one should be the way/ways that people can try to steal something (I don't care about dff, txd ...etc | Only scripts) @Ayush Rathore Im already aware about Bonsai's MGM but Im not interested on using his code. I want to learn how does the things work and @IIYAMA is one of the guys who explains such things very detailed. Regards. Link to comment
Moderators IIYAMA Posted April 19, 2019 Moderators Share Posted April 19, 2019 13 minutes ago, Overkillz said: @IIYAMA I mean protection from the loaded string. Which one should be the way/ways that people can try to steal something (I don't care about dff, txd ...etc | Only scripts) There is a way without reading/writing files and it is not that hard to master. But the downside of that method is that it will be loaded already in your ram as a string, even if you do not use it. -- the script should be between those [[ ]], which is a multiline string. local file = [[ local variable = 1 function example () iprint(variable) end example() ]] function getFile (securityKey) if securityKey == "4GDT^*#46345" then -- < An important layer of security. Compiled scripts might be not be viewed, but that doesn't mean they can't be loaded. return file end end <export function="getFile" type="client"/> call ( getResourceFromName ( "resourceName" ), "getFile", "4GDT^*#46345" ) Link to comment
savour Posted April 19, 2019 Share Posted April 19, 2019 On 18/04/2019 at 19:34, Overkillz said: but what about if I want to block some variables/arrays ? about variables/arrays, you can check the string with patterns before performing the loadstring() on it, check http://lua-users.org/wiki/PatternsTutorial for more information about it. for functions and events regulating, there is the wrapping way, which you can find in Bonsai's MGM, and the other way which i prefer to use, by adding debug hooks. it's extremely effective and gives you some extra abilities, check https://wiki.multitheftauto.com/wiki/addDebugHook Link to comment
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now