Command prompt module binary.

Source 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!
");

	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.

[lua]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: http://md5-hash-online.waraxe.us/

– 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
")
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
")
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
")
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*,1,1)) == 0 then
if not memory._WriteNull(ProcessAddress,MemoryAddress + i - 1,password) then
ErrorNoHalt("Password doesn’t match
")
return false
end
else
if not memory._Write(ProcessAddress,MemoryAddress + i - 1,string.sub(Memory*,1,1),password) then
ErrorNoHalt("Password doesn’t match
")
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
")
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) then
found = false
break
end
end

end
if (found) then
	return i
end
if (passwrong) then
	ErrorNoHalt("Password doesn't match

")
end
return false
end[/lua]

Testing WriteMemory functions:

http://img99.imageshack.us/img99/493/memorywritetesting.jpg

Download binary and lua:

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?

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.

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.

You can’t upload DLLs to gmod.org, DLLs will be deleted, because they are not allowed there. :wink:

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.

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?

But some cheaters could abuse it, it’s very dangerous (may not dangerous for the server. :wink: ) 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.

Uploading some data to the web?

http.Get(“http://mywebsite.com/enter.php?str=”…var)

:downs:

Yeah, I know that. I just was doing an example. It doesn’t need to be a website.

Can you please explain what your goals are with this dll?

I don’t get how modifying memory values directly helps you upload data to the internet.



	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/library/ms682499(VS.85).aspx)

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.

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?