Advertisement
NeverCast

Top Level Coroutine Override

Jul 21st, 2013
1,835
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 3.90 KB | None | 0 0
  1. --[[
  2.     Author: NeverCast
  3.     Last Edited: 22/07/13
  4.     Published: 2/11/12
  5.     You're welcome to use this code however you like, but please leave my credit at the top. Thanks
  6. --]]
  7.  
  8. --[[
  9.     Changes:
  10.    
  11.     1.Replacing the for-loop with a while-loop to not limit the iterations required in finding the parent shell
  12.     2.Removing Rednet and reloading it to fix the already running issue.
  13.     3.Now clears the myEnv global variable once injection is complete.
  14.  
  15.     Thanks KaoS and TheOriginalBit for code fixes and bug reports.
  16. --]]
  17.  
  18. -- Prior code writing hypothosis:
  19. -- How to become top level,
  20.  
  21. -- Climb stack, Find single shell instance
  22. -- Kill shell instance, override pullEvent
  23. -- Override os.shutdown
  24. -- Exit code
  25. -- Wait for Bios to quit and hook that to fire up your own functions
  26.  
  27. -- Add the functions here that you want to run once the environment has been overridden
  28. -- In this bios this was shell and rednet.run, I've removed rednet.run as an example
  29. -- Any functions here will be top level and recieve all the events!
  30. local loadPool = {
  31.         function()
  32.             os.run( {}, "rom/programs/shell" )
  33.         end
  34. }
  35.  
  36. -- Feel free to set this to false if you don't want the text printed
  37. local showMessages = true
  38.  
  39.  
  40. if os.myEnv then
  41.     if showMessages then
  42.         print"Injection completed successfully"
  43.     end
  44.     -- Remove myEnv to prevent detection
  45.     os.myEnv = nil
  46.     return
  47. end
  48.  
  49. local prevState = {}
  50.  
  51. table.size = function(tbl)
  52.     local count = 0
  53.     for _,__ in pairs(tbl) do
  54.         count = count + 1
  55.     end
  56.     return count
  57. end
  58.  
  59. local function getParentShell()
  60.   local at=0
  61.   while true do
  62.     at=at+1
  63.     local ok,env = pcall(function() return getfenv(at) end)
  64.     if not ok then break end
  65.     if table.size(env) == 1 then
  66.           local i,v = next(env) -- Grab first
  67.           if i == "shell" then
  68.             return v
  69.           end
  70.     end  
  71.   end
  72.   return nil
  73. end
  74.  
  75. local function recover()
  76.     -- Set flag
  77.     os.myEnv = true
  78.     -- Put back the trampled environment
  79.     os.startTimer = prevState.startTimer
  80.     os.shutdown = prevState.shutdown
  81.     os.pullEvent = prevState.pullEvent
  82.     -- Launch shell like nothing happened
  83.    
  84.     prevState = nil
  85.    
  86.     term.setCursorPos(1,1)
  87.     term.clear()
  88.    
  89.     if showMessages then
  90.         -- Feel free to remove this line, It's just a proof thing
  91.         print"Look at me, I load before shell does"
  92.     end
  93.    
  94.     -- Because we killed rednet, we have to remove it and then reload it
  95.     _G['rednet'] = nil
  96.     os.loadAPI('/rom/apis/rednet')
  97.    
  98.     local ok, err = pcall( function()
  99.     parallel.waitForAny(
  100.         unpack(loadPool)
  101.     )
  102.     end )
  103. end
  104.  
  105. os.stage = {}
  106.  
  107. -- Stages:
  108. -- injected: Overriding os functions
  109. -- shutdown: Shutdown program has been called
  110. -- jstincse: Shell is doing it's just-in-case
  111. -- bioswait: Bios is waiting for a key press
  112. -- biosexit: Bios has quit
  113. -- complete: fully injected
  114.  
  115.  
  116. local function setStage(stage)
  117.     os.stage.currentStage = stage
  118. end
  119.  
  120. local function getStage()
  121.     return os.stage.currentStage
  122. end
  123.  
  124. local function _os_pullEvent(_filter)
  125.     _filter = _filter or ""
  126.     if _filter == "key" then
  127.         setStage("bioswait")
  128.         return "key", 0
  129.     elseif _filter == "timer" then
  130.         setStage("shutdown")
  131.         return "timer", 0
  132.     end
  133. end
  134.  
  135. local function _replSleep(dur)
  136.     local timer = prevState.startTimer( dur )
  137.     repeat
  138.         local sEvent, param = prevState.pullEvent( "timer" )
  139.     until param == timer
  140. end
  141.  
  142. local function _os_shutdown()
  143.     if getStage() == "shutdown" then
  144.         setStage("jstincse")
  145.     elseif getStage() == "bioswait" then
  146.         setStage("biosexit")
  147.     end
  148.     if getStage() == "biosexit" then
  149.         recover()
  150.     end
  151. end
  152.  
  153. local function _os_startTimer(seconds)
  154.     return 0
  155. end
  156.  
  157. local function inject()
  158.     prevState.startTimer = os.startTimer
  159.     prevState.shutdown = os.shutdown
  160.     prevState.pullEvent = os.pullEvent
  161.     os.shutdown = _os_shutdown
  162.     os.pullEvent = _os_pullEvent
  163.     os.startTimer = _os_startTimer
  164.     setStage("injected")
  165.     local shellImpl = getParentShell()
  166.     shellImpl.exit()
  167. end
  168.  
  169. -- Start everything
  170. inject()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement