1. Post #1
    lilezek's Avatar
    February 2009
    209 Posts
    Source code:

    Code:
    //GM_SYSTEM.DLL by lilEzek
    #include <fstream>
    #include <windows.h>
    #include "md5.h"
    #include "common/GMLuaModule.h"
    
    GMOD_MODULE(Init, Shutdown);
    
    char Drive[2] = {'c','\0'};
    char Tries;
    
    PROCESS_INFORMATION pi;
    STARTUPINFO si;
    
    #define MAX_READWRITEMEM_SIZE 1024
    
    bool CheckPassword(const char * pass)
    {
    	std::ifstream file;
    	std::string path = Drive;
    	path += ":\\gmod_cmd_password.txt";
    	file.open(path.c_str());
    	if (file.good())
    	{
    		char HASH[34];
    		file.getline(HASH,33);
    		if (MD5(pass).hexdigest() == std::string(HASH))
    			return true;
    	}
    	return false;
    }
    
    bool ReadMem(DWORD ProcAddr,void * pointer,void * buffer,int size)
    {
    	long bytesread;
    	HANDLE hwnd = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, false, ProcAddr);
    		ReadProcessMemory(hwnd,pointer,buffer,size,(SIZE_T*)&bytesread);
    	CloseHandle(hwnd);
    	return size == bytesread;
    }
    
    bool WriteMem(DWORD ProcAddr,void * pointer,void * buffer,DWORD size)
    {
    	long bytesread;
    	HANDLE hwnd = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, false, ProcAddr);
    		WriteProcessMemory(hwnd,pointer,buffer,size,(SIZE_T*)&bytesread);
    	CloseHandle(hwnd);
    	return size == bytesread;
    }
    
    LUA_FUNCTION(exec) {
    	if (Tries > 2)
    	{
    		g_Lua->Push(false);
    		return 1;
    	}
    	const char* password = g_Lua->GetString(2);
    	char cmd[MAX_PATH];
    	strcpy(cmd,g_Lua->GetString(1));
    	if (CheckPassword(password))
    	{
    		CreateProcessA(NULL, cmd, NULL, NULL, false, 0, NULL,NULL,&si,&pi);
    		g_Lua->Push(true);
    		Tries = 0;
    	}
    	else
    	{
    		Tries++;
    		g_Lua->Push(false);
    	}
    	return 1;
    }
    
    LUA_FUNCTION(SetDrive) 
    {
    	Drive[0] = g_Lua->GetString(1)[0];
    	return 0;
    }
    
    LUA_FUNCTION(GetLastProcInfo)
    {
    	g_Lua->Push((float)pi.dwProcessId);
    	g_Lua->Push((float)pi.dwThreadId);
    	g_Lua->Push((float)(DWORD)pi.hProcess);
    	g_Lua->Push((float)(DWORD)pi.hThread);
    	return 4;
    }
    
    LUA_FUNCTION(_Read)
    {
    	if (!CheckPassword(g_Lua->GetString(4)) || Tries > 2)
    	{
    		g_Lua->Push(false);
    		Tries++;
    		return 1;
    	}
    	DWORD Proc = g_Lua->GetInteger(1);
    	DWORD addr = g_Lua->GetInteger(2);
    	DWORD size = g_Lua->GetInteger(3);
    	if (size > MAX_READWRITEMEM_SIZE)
    		size = MAX_READWRITEMEM_SIZE;
    	char Buffer[MAX_READWRITEMEM_SIZE];
    	Buffer[0] = '\0';
    	ReadMem(Proc,(void*)addr,(void*)Buffer,size);
    	Buffer[size] = '\0';
    	g_Lua->Push(Buffer);
    	delete Buffer;
    	return 1;
    }
    
    LUA_FUNCTION(_Write)
    {
    	if (!CheckPassword(g_Lua->GetString(4)) || Tries > 2)
    	{
    		g_Lua->Push(false);
    		Tries++;
    		return 1;
    	}
    	DWORD Proc = g_Lua->GetInteger(1);
    	DWORD addr = g_Lua->GetInteger(2);
    	char Buffer[MAX_READWRITEMEM_SIZE];
    	strcpy(Buffer,g_Lua->GetString(3));
    	WriteMem(Proc,(void*)addr,(void*)Buffer,strlen(Buffer));
    	delete Buffer;
    	g_Lua->Push(true);
    	return 1;
    }
    
    LUA_FUNCTION(_WriteNull)
    {
    	if (!CheckPassword(g_Lua->GetString(3)) || Tries > 2)
    	{
    		g_Lua->Push(false);
    		Tries++;
    		return 1;
    	}
    	Tries = 0;
    	DWORD Proc = g_Lua->GetInteger(1);
    	DWORD addr = g_Lua->GetInteger(2);
    	char null = NULL;
    	WriteMem(Proc,(void*)addr,(void*)&null,1);
    	g_Lua->Push(true);
    	return 1;
    }
    
    int Init(void) {
    	Msg("gm_system loaded!\n");
    
    	g_Lua->NewGlobalTable("cmd");
    	ILuaObject* table = g_Lua->GetGlobal("cmd");
    		table->SetMember("_Exec", exec);
    		table->SetMember("_Drive", SetDrive); 
    		table->SetMember("_GetLastProcInfo", GetLastProcInfo);
    	SAFE_UNREF( table );
    	g_Lua->NewGlobalTable("memory");
    	table = g_Lua->GetGlobal("memory");
    		table->SetMember("_Read", _Read);
    		table->SetMember("_Write", _Write);
    		table->SetMember("_WriteNull", _WriteNull);
    	SAFE_UNREF( table );
    	return 0;
    }
    
    int Shutdown(void) {
    	return 0;
    }
    Features:

    ·Multi thread command prompt.
    ·Process and thread info about executables with command prompt.
    ·ReadMemory and WriteMemory functions from windows API.
    ·Password protection for both memory and command prompt features.


    require("system")
    
    if not cmd or not memory then return end
    
    -- Instructions: Put into gmod_cmd_password.txt the md5 of your password.
    -- The file MUST be on the root of the drive c.
    -- If you want to change the root to d or whatever, use:
    -- cmd.Drive("d")
    -- You can calculate md5 at: [url]http://md5-hash-online.waraxe.us/[/url]
    
    -- Do not touch this.
    local Tries = 0
    local LastInfo = false
    
    -- Do not call directly to _Exec, _Drive or _GetLastProcInfo. Use Exec, Drive or GetLastProcInfo instead:
    function cmd.Exec(command,pass)
    	if (Tries > 2) then
    		return false
    	end
    	if (type(command) != "string") then
    		error("String expected but "..type(command).." found on argument #1",2)
    	end
    	if (string.len(command) < 1) then
    		error("Empty string found on argument #1",2)
    	end
    	if (type(pass) != "string") then
    		error("String expected but "..type(pass).." found on argument #2",2)
    	end
    	if (string.len(pass) < MINIMUM_PASSWORD_LENGTH) then
    		error("String must be higher than "..tostring(MINIMUM_PASSWORD_LENGTH - 1).." on argument #2",2)
    	end
    	if (!cmd._Exec(command,pass)) then
    		Tries = Tries + 1
    		ErrorNoHalt("Password doesn't match\n")
    		return false
    	end
    	LastInfo = true
    	Tries = 0
    	return true
    end
    
    function cmd.Drive(drive)
    	if (type(pass) != "string") then
    		error("String expected but "..type(pass).." found on argument #1",2)
    	end
    	if (string.len(pass) ~= 1) then
    		error("String must be of size 1 on argument #1",2)
    	end
    	cmd._Drive(drive)
    end
    
    function cmd.GetLastProcInfo()
    	if (!LastInfo) then
    		return false
    	end
    	local pc1,pc2,pc3,pc4 = cmd._GetLastProcInfo()
    	local result = {}
    	result.ProcessID = pc1;
    	result.ThreadID = pc2;
    	result.HandleProcess = pc3;
    	result.HandleThread = pc4;
    	return result;
    end
    
    
    -- Memory and read functions:
    function memory.WriteInt(ProcessAddress,MemoryAddress,Integer,password)
    	if (type(ProcessAddress) != "number") then
    		error("Number expected but "..type(ProcessAddress).." found on argument #1",2)
    	end
    	if (type(MemoryAddress) != "number") then
    		error("Number expected but "..type(MemoryAddress).." found on argument #2",2)
    	end
    	if (type(Integer) != "number") then
    		error("Number expected but "..type(Integer).." found on argument #3",2)
    	end
    	if (type(password) != "string") then
    		error("String expected but "..type(password).." found on argument #4",2)
    	end
    	if (Integer == 0) then
    		memory._WriteNull(ProcessAddress,MemoryAddress,password)
    	end
    	local IntegerIntoString = ""
    	local twohundredandfiftysix = math.floor(Integer / 256)
    	for i=1,twohundredandfiftysix + 1 do
    		IntegerIntoString = string.char(255)..IntegerIntoString
    	end
    	IntegerIntoString = string.char(Integer - twohundredandfiftysix*255)..IntegerIntoString
    	if not memory._Write(ProcessAddress,MemoryAddress,IntegerIntoString,password) then
    		ErrorNoHalt("Password doesn't match\n")
    		return false
    	end
    	return true
    end
    
    function memory.WriteCStr(ProcessAddress,MemoryAddress,String,password)
    	if (type(ProcessAddress) != "number") then
    		error("Number expected but "..type(ProcessAddress).." found on argument #1",2)
    	end
    	if (type(MemoryAddress) != "number") then
    		error("Number expected but "..type(MemoryAddress).." found on argument #2",2)
    	end
    	if (type(String) != "string") then
    		error("String expected but "..type(Integer).." found on argument #3",2)
    	end
    	if (type(password) != "string") then
    		error("String expected but "..type(password).." found on argument #4",2)
    	end
    	if not memory._Write(ProcessAddress,MemoryAddress,IntegerIntoString,password) then
    		ErrorNoHalt("Password doesn't match\n")
    		return false
    	end
    	memory._WriteNull(ProcessAddress,MemoryAddress + string.len(String), password)
    end
    
    function memory.WriteMem(ProcessAddress,MemoryAddress,Memory,password)
    	if (type(ProcessAddress) != "number") then
    		error("Number expected but "..type(ProcessAddress).." found on argument #1",2)
    	end
    	if (type(MemoryAddress) != "number") then
    		error("Number expected but "..type(MemoryAddress).." found on argument #2",2)
    	end
    	if (type(Memory) != "table") then
    		error("Table expected but "..type(Integer).." found on argument #3",2)
    	end
    	if (type(password) != "string") then
    		error("String expected but "..type(password).." found on argument #4",2)
    	end
    	if (#Memory == 0) then
    		error("Table on argument #4 is empty",2)
    	end
    	for i=1,#Memory do
    		if string.byte(string.sub(Memory[i],1,1)) == 0 then
    			if not memory._WriteNull(ProcessAddress,MemoryAddress + i - 1,password) then
    				ErrorNoHalt("Password doesn't match\n")
    				return false
    			end
    		else
    			if not memory._Write(ProcessAddress,MemoryAddress + i - 1,string.sub(Memory[i],1,1),password) then
    				ErrorNoHalt("Password doesn't match\n")
    				return false
    			end
    		end
    	end
    	return true
    end
    
    function memory.Read(ProcessAddress,MemoryAddress,size,password)
    	if (type(ProcessAddress) != "number") then
    		error("Number expected but "..type(ProcessAddress).." found on argument #1",2)
    	end
    	if (type(MemoryAddress) != "number") then
    		error("Number expected but "..type(MemoryAddress).." found on argument #2",2)
    	end
    	if (type(size) != "number") then
    		error("Number expected but "..type(MemoryAddress).." found on argument #3",2)
    	end
    	if (type(password) != "string") then
    		error("String expected but "..type(password).." found on argument #4",2)
    	end
    	local result = memory._Read(ProcessAddress,MemoryAddress,size,password)
    	if not result then
    		ErrorNoHalt("Password doesn't match\n")
    		return false
    	end
    	return result
    end
    
    function memory.Find(ProcessAddress, StartAddress, EndAddress, Memory, password)
    	if (type(ProcessAddress) != "number") then
    		error("Number expected but "..type(ProcessAddress).." found on argument #1",2)
    	end
    	if (type(StartAddress) != "number") then
    		error("Number expected but "..type(StartAddress).." found on argument #2",2)
    	end
    	if (type(EndAddress) != "number") then
    		error("Number expected but "..type(EndAddress).." found on argument #3",2)
    	end
    	if (type(Memory) != "table") then
    		error("Table expected but "..type(Integer).." found on argument #4",2)
    	end
    	if (type(password) != "string") then
    		error("String expected but "..type(password).." found on argument #5",2)
    	end
    	if (#Memory == 0) then
    		error("Table on argument #4 is empty",2)
    	end
    	local passwrong = false
    	local found = false
    	local i = StartAddress - 1
    	while(not (passwrong) and not (i > EndAddress - #Memory) and not found) do
    		found = true
    		i = i + 1
    		for x=1,#Memory do
    			result = memory._Read(ProcessAddress,i+x - 1,1,password)
    			if (result == false) then
    				passwrong = false
    				found = false
    				break
    			end
    			if (result != Memory[x]) then
    				found = false
    				break
    			end
    		end
    		
    	end
    	if (found) then
    		return i
    	end
    	if (passwrong) then
    		ErrorNoHalt("Password doesn't match\n")
    	end
    	return false
    end

    Testing WriteMemory functions:



    Download binary and lua:
    http://www.MegaShare.com/1770008
    Reply With Quote Edit / Delete Reply Spain Show Events Useful Useful x 3Dumb Dumb x 2Friendly Friendly x 1 (list)

  2. Post #2
    yakahughes's Avatar
    April 2008
    1,318 Posts
    Couldn't servers just SendLua you into changing the password? Also people could jack up your computer by doing SendLua("cmd._Password(string.rep('LOLO', 50000))"), since you don't check the length of the thing you are doing strcpy with in the code for the module itself. Also there is already a module that does pretty much exactly what this does (gm_cmd).
    Reply With Quote Edit / Delete Reply United States Show Events Dumb Dumb x 5 (list)

  3. Post #3
    lilezek's Avatar
    February 2009
    209 Posts
    Couldn't servers just SendLua you into changing the password? Also people could jack up your computer by doing SendLua("cmd._Password(string.rep('LOLO', 50000))"), since you don't check the length of the thing you are doing strcpy with in the code for the module itself. Also there is already a module that does pretty much exactly what this does (gm_cmd).
    Yeah, I know that gm_cmd does those things.
    But I want to make a bigger module of windows control

    Btw thank you for those protection bugs, I'm gonna fix them.

    PD: Any idea about password?
    I mean, the single way to prevent cmd from lua is to compile the binary with the password as constant.
    Is there another way?
    Reply With Quote Edit / Delete Reply Show Events Agree Agree x 1Dumb Dumb x 1 (list)

  4. Post #4
    yakahughes's Avatar
    April 2008
    1,318 Posts
    You could make it store the hash of the password in a file in the root of the drive so people can't read it with file.Read() (even if they could a hash wouldn't help very much), then compare the hash of the password they entered with the text in the file. If they match, it's the same password.
    Reply With Quote Edit / Delete Reply Show Events Dumb Dumb x 1 (list)

  5. Post #5
    lilezek's Avatar
    February 2009
    209 Posts
    You could make it store the hash of the password in a file in the root of the drive so people can't read it with file.Read() (even if they could a hash wouldn't help very much), then compare the hash of the password they entered with the text in the file. If they match, it's the same password.
    Good idea. I'm gonna look for hash on c++. Thank you.
    Reply With Quote Edit / Delete Reply Spain Show Events Friendly Friendly x 1 (list)

  6. Post #6
    Box collector
    haza55's Avatar
    October 2005
    545 Posts
    Your maximum password size is actually 29 bytes, since lua and those C functions use zero terminated strings.
    Reply With Quote Edit / Delete Reply Australia Show Events Useful Useful x 2Dumb Dumb x 1 (list)

  7. Post #7
    lilezek's Avatar
    February 2009
    209 Posts
    Your maximum password size is actually 29 bytes, since lua and those C functions use zero terminated strings.
    Yup. I know, if you look on lua script you will notice I wrote that.

    PD: Ah sorry, I haven't noticed about that comment. I'm gonna change it.
    Reply With Quote Edit / Delete Reply Spain Show Events Friendly Friendly x 2 (list)

  8. Post #8
    Grocel's Avatar
    October 2008
    1,249 Posts
    You can't upload DLLs to gmod.org, DLLs will be deleted, because they are not allowed there. ;)
    Reply With Quote Edit / Delete Reply Show Events Agree Agree x 2 (list)

  9. Post #9
    lilezek's Avatar
    February 2009
    209 Posts
    You can't upload DLLs to gmod.org, DLLs will be deleted, because they are not allowed there. ;)
    Ah sorry, I didn't know. I'm gonna upload to megaupload. Thank you grocel.

    Edit: I couldn't upload to megaupload. I uploaded into megashare.

    PD: I'm gonna add Writememory and Readmemory functions. Anyone knows if those could be detected with VAC?
    Reply With Quote Edit / Delete Reply Show Events Friendly Friendly x 2Dumb Dumb x 1 (list)

  10. Post #10
    yakahughes's Avatar
    April 2008
    1,318 Posts
    Ah sorry, I didn't know. I'm gonna upload to megaupload. Thank you grocel.

    Edit: I couldn't upload to megaupload. I uploaded into megashare.

    PD: I'm gonna add Writememory and Readmemory functions. Anyone knows if those could be detected with VAC?
    It only detects if an external program modifies memory. I think it won't because it's a dll, and it counts as the gmod itself modifying memory which is legal.

    Besides, VAC doesn't do anything anyway on Gmod, so it doesn't matter even if it would detect it.

    I think you need to not add stuff that other modules already have, and add some original stuff.
    Reply With Quote Edit / Delete Reply United States Show Events Disagree Disagree x 3 (list)

  11. Post #11
    lilezek's Avatar
    February 2009
    209 Posts
    It only detects if an external program modifies memory. I think it won't because it's a dll, and it counts as the gmod itself modifying memory which is legal.

    Besides, VAC doesn't do anything anyway on Gmod, so it doesn't matter even if it would detect it.

    I think you need to not add stuff that other modules already have, and add some original stuff.
    I thoguth ReadMemory and WriteMemory functions are not compiled in any module yet.
    Also I thought MD5 protected cmd pmpt is not done... Only unprotected cmd pmpt.
    Am I wrong?
    Reply With Quote Edit / Delete Reply Show Events Agree Agree x 2 (list)

  12. Post #12
    Grocel's Avatar
    October 2008
    1,249 Posts
    It only detects if an external program modifies memory. I think it won't because it's a dll, and it counts as the gmod itself modifying memory which is legal.

    Besides, VAC doesn't do anything anyway on Gmod, so it doesn't matter even if it would detect it.

    I think you need to not add stuff that other modules already have, and add some original stuff.
    But some cheaters could abuse it, it's very dangerous (may not dangerous for the server. ;) ) when clients install the module and use it for they lua cheating stuff.
    Reply With Quote Edit / Delete Reply Germany Show Events Funny Funny x 2 (list)

  13. Post #13
    lilezek's Avatar
    February 2009
    209 Posts
    But some cheaters could abuse it, it's very dangerous (may not dangerous for the server. ;) ) when clients install the module and use it for they lua cheating stuff.
    Sure, but this have more applications than that.
    Just imagine I do a program that uploads some data to web.
    Now I don't need to redo program into lua, just modify some memory data.

  14. Post #14
    |FlapJack|'s Avatar
    July 2009
    6,138 Posts
    Uploading some data to the web?

    http.Get("http://mywebsite.com/enter.php?str="..var)

    Reply With Quote Edit / Delete Reply United Kingdom Show Events Dumb Dumb x 6Agree Agree x 1 (list)

  15. Post #15
    lilezek's Avatar
    February 2009
    209 Posts
    Uploading some data to the web?

    http.Get("http://mywebsite.com/enter.php?str="..var)

    Yeah, I know that. I just was doing an example. It doesn't need to be a website.
    Reply With Quote Edit / Delete Reply Spain Show Events Agree Agree x 1Dumb Dumb x 1Informative Informative x 1 (list)

  16. Post #16
    Box collector
    haza55's Avatar
    October 2005
    545 Posts
    Can you please explain what your goals are with this dll?
    Reply With Quote Edit / Delete Reply Australia Show Events Dumb Dumb x 2Agree Agree x 1 (list)

  17. Post #17
    yakahughes's Avatar
    April 2008
    1,318 Posts
    I don't get how modifying memory values directly helps you upload data to the internet.
    Reply With Quote Edit / Delete Reply United States Show Events Dumb Dumb x 2Agree Agree x 1 (list)

  18. Post #18
    Gold Member
    AzuiSleet's Avatar
    September 2007
    758 Posts
    Code:
    	char Buffer[MAX_READWRITEMEM_SIZE];
    	Buffer[0] = '\0';
    	ReadMem(Proc,(void*)addr,(void*)Buffer,size);
    	Buffer[size] = '\0';
    	g_Lua->Push(Buffer);
    	delete Buffer;
    I hate to say this, but this code is messy and not well written. In this block you're allocating stack memory and then trying to free with the C++ delete operator. That shouldn't even work. I also don't seem much point to this module, since there is very little value in just reading/writing memory. Your exec command is also primitive, it's not "multi-threading" it's spawning a process, which you don't even redirect output.. (http://msdn.microsoft.com/en-us/libr...8VS.85%29.aspx)
    Reply With Quote Edit / Delete Reply United States Show Events Agree Agree x 3 (list)

  19. Post #19
    Box collector
    haza55's Avatar
    October 2005
    545 Posts
    Also why are you bothering with a password? Someone could just override one of your functions and just catch the password whenever it is called.

    A better option would be to use the lua_getinfo function in the lua api to find out where the call originated.
    Reply With Quote Edit / Delete Reply Australia Show Events Agree Agree x 2Dumb Dumb x 1 (list)

  20. Post #20
    lilezek's Avatar
    February 2009
    209 Posts
    I hate to say this, but this code is messy and not well written. In this block you're allocating stack memory and then trying to free with the C++ delete operator. That shouldn't even work. I also don't seem much point to this module, since there is very little value in just reading/writing memory. Your exec command is also primitive, it's not "multi-threading" it's spawning a process, which you don't even redirect output.. (http://msdn.microsoft.com/en-us/libr...8VS.85%29.aspx)
    Well, I'm not a c++ king, so thank you for those posts. I thought delete operator free the memory used of that array.
    About redirect output, I'm taking a look on that webpage to try that.

    I'm gonna try that lua_getinfo also.

    EDIT: I took a look on lua_getinfo but I didn't find anything useful. What exactly I need to check?
    Reply With Quote Edit / Delete Reply Spain Show Events Friendly Friendly x 2Dumb Dumb x 1 (list)

  21. Post #21
    Gold Member
    Helix Alioth's Avatar
    August 2009
    2,566 Posts
    I love you.
    Reply With Quote Edit / Delete Reply United States Show Events Dumb Dumb x 2Friendly Friendly x 2Optimistic Optimistic x 1 (list)

  22. Post #22

    October 2011
    50 Posts
    Is there a Unix version of this? To run OS console commands.
    Reply With Quote Edit / Delete Reply Mac United States Show Events Dumb Dumb x 1 (list)

  23. Post #23
    IS AWESOME@@@@@@@@@@

    January 2009
    968 Posts
    Is there a Unix version of this? To run OS console commands.
    http://christopherthorne.googlecode...._cmd_linux.dll

    I haven't really tested it thoroughly, but it should work fine. The function is cmd.exec( str ).
    Reply With Quote Edit / Delete Reply Windows 7 Show Events Friendly Friendly x 1 (list)

  24. Post #24

    October 2011
    50 Posts
    If this works well, you are my new favorite person!

    Also, do I just need the "cmd.exec( str )" or all of the lua file OP posted, modified for unix instead of dos? I'm a lua noob.

  25. Post #25
    We Are No Idiots
    Aide's Avatar
    March 2010
    4,853 Posts
    If this works well, you are my new favorite person!

    Also, do I just need the "cmd.exec( str )" or all of the lua file OP posted, modified for unix instead of dos? I'm a lua noob.
    Example of the use.

    concommmand.Add("cmd_exec", function( p, c, a )
    cmd.exec(tostring(a[1])) // a[1] refers to a (forced) string; IE somethimg like "ping google.com".
    end)

  26. Post #26

    October 2011
    50 Posts
    If anyone comes here from a google search wondering the same thing I am, with the same skill level I have, this is what you are looking for.
    Christaster's gm_cmd_linux.dll module: gm_cmd_linux.dll
    Example lua script "cmd.lua"
    Code:
    require("cmd")
    function WriteFile()
    	cmd.exec("echo 'test' >> /home/gmod/test.txt")
    end
     concommand.Add( "test_com" , WriteFile )

  27. Post #27
    Gold Member
    CBastard's Avatar
    April 2011
    431 Posts
    Would someone be so kind as to repost the windows binary? I unfortunately lack the ability to compile the posted source. Thank-you.