Anti DLL Injection

I thought this would be a good idea or a step further in client security so, here’s my idea. I believe there should be Anti DLL Injection. I’m sure most of you are aware of what a DLL(Dynamic Link Library) is. I’m also sure a lot of you are familiar with these “Alx” and “Nyx” exploits and all those programs that do the same thing. I’m positive that they’ve annoyed the people who develop games on here a lot and have at times, made your game unplayable. So I’ve come up with a fairly basic solution to this if you guys haven’t thought of it or aren’t able to do it because it’ll open more errors, but why not make it so that the client stores the list of the modules that the client actually uses in an array and then keep checking if the length of the array goes above what it’s supposed to? Example:

 // sorry you may not like the way I program, keep in mind this is example code
void AntiDLLInjection()
{
	HANDLE RobloxProcess = OpenProcess(Access, InheritHandle, rpid);
	HMODULE OriginalModules[ModuleCount];
	while (true)
	{
		for (int i = 60; i <= ModuleCount; i++) // 60 is an example number
		{
			EnumProcessModules(RobloxProcess, OriginalModules, sizeof(OriginalModules), BytesNeeded);
			if (sizeof(OriginalModules)*4/8/2-1 > 60)
			{
				closesocket(clientsocket);
			}
		}
	}
}

Another idea is that you can make a whitelist and allow certain dlls like Xfire to operate but most others to not operate
When I say “modules” I mean things like: RobloxPlayerBeta.exe, ntdll.dll, KERNEL32.dll
just my thoughts, but I think a form of anti DLL injection is a good idea, not ordering you guys around though.

2 Likes

Only issue I see is that this isn’t a cross-platform solution. But neither is the current method ROBLOX uses for prevention of things like Cheat Engine.

Yeah, I don’t think ROBLOX does as much security for the client as it does on other operating systems, a majority of the client security is written using Windows functions.

So what exactly prevents the injector from hooking EnumProcessModules() and simply filtering its outputs?

If the module count is greater than what it was supposed to be when the first EnumProcessModules() was scanned and stored in the array then it’ll just shut the game down.

if (sizeof(Modules)*4/8/2-1 > 60)
{
	closesocket(clientsocket);
}

So 60 is an example number count of how many modules roblox uses, if the array is greater than 60 then it’ll shut down, I know ROBLOX doesn’t use closesocket() to disconnect a player and a RakNet method, but this is just pseudo-code after all. It doesn’t really prevent the DLL from being injected, but just detects it.

So what if the injector-modified EnumProcessModules() returns exactly the same number of modules?

Also, module count is unreliable, because antiviruses, graphics drivers and even Windows IME (e.g. support for Chinese language input) are known to inject DLLs into processes.

[quote] So what if the injector-modified EnumProcessModules() returns exactly the same number of modules?

Also, module count is unreliable, because antiviruses, graphics drivers and even Windows IME (e.g. support for Chinese language input) are known to inject DLLs into processes. [/quote]

Wouldn’t it be possible to get a certificate for those DLLs? Do they even have certificates? If they do, you can check the certificate to make sure it is a valid certificate. If it’s not, shutdown the client.

This assumes that the process knows that the dlls are present. You haven’t addressed the first part of my post.

[quote] So what if the injector-modified EnumProcessModules() returns exactly the same number of modules?

Also, module count is unreliable, because antiviruses, graphics drivers and even Windows IME (e.g. support for Chinese language input) are known to inject DLLs into processes. [/quote]

  1. Do you mean if the injector actually modifies the function for EnumProcessModules() via the memory?

  2. There’s also the idea for a DLL white list. So that would store the DLLs roblox uses and wants to allow and checking for incorrect matches

Yes! It’s a perpetual game of cat and mouse.

The problem is, DLLs can load other dlls, e.g. opengl32.dll loads either nvoglv32.dll or atioglxx.dl depending on what graphics hardware you happen to run. Or rather, nvidia and ati supply their own version of openg32.lib with their graphics drivers.

Yes! It’s a perpetual game of cat and mouse.

The problem is, DLLs can load other dlls, e.g. opengl32.dll loads either nvoglv32.dll or atioglxx.dl depending on what graphics hardware you happen to run. Or rather, nvidia and ati supply their own version of openg32.lib with their graphics drivers.[/quote]

  1. The EnumProcessModules() function being used in the client could be in some VMProtected area or protected by the memory check, so I don’t think it matters too much. But for the actual Windows Function of it in Kernel32.dll can also be scanned by some sort of memory check, a method for that I can think of for that off of the top of my head would be using memcmp & memcpy for a basic security check.

  2. I see that problem and I’m not really sure how you’d go about solving that other than adding as much DLLs as possible to the white list, but that’s a little time consuming.

Look, I would suggest you learn a bit more about Windows programming, before we get further into the topic.
You cannot vmprotect system functions.
You cannot scan system functions because you’ve got nothing to compare the code against.
Also you cannot possibly scan all internal Windows functions that EnumProcessModules() might be calling.
And ultimately, you cannot scan kernel-mode memory.

1 Like

Look, I would suggest you learn a bit more about Windows programming, before we get further into the topic.
You cannot vmprotect system functions.
You cannot scan system functions because you’ve got nothing to compare the code against.
Also you cannot possibly scan all internal Windows functions that EnumProcessModules() might be calling.
And ultimately, you cannot scan kernel-mode memory.[/quote]

“You cannot vmprotect system functions.”
I think you’re misunderstanding what I’m saying a bit, you can’t vmprotect system functions, yes, but where ROBLOX calls the function from the module that area of code can be vmprotected because the memory check is vmprotected too.

“You cannot scan system functions because you’ve got nothing to compare the code against.”
You can compare system functions by allocating memory, copying it with memcpy, and comparing it with memcmp, I did it in my program.

HANDLE KernelGetTickCount = GetProcAddress(GetModuleHandle(L"KERNEL32.DLL"), "GetTickCount");
	if ((LPVOID*)KernelGetTickCount != 0)
	{
		void* kerneltickcheck = calloc(24,26);
		memcpy((LPVOID*)kerneltickcheck, (LPVOID*)KernelGetTickCount, 26);
		while (true)
		{
			if(memcmp((LPVOID*)KernelGetTickCount, (LPVOID*)kerneltickcheck, sizeof((LPVOID*)kerneltickcheck))!=0)
			{
				ExitProcess(0);
			}
			else
			{
				cout << "Kernel Tick Address: " << "0x";
				cout << (LPVOID*)KernelGetTickCount << endl;
				newline
				cout << "Kernel Copy Tick Address: " << "0x";
				cout << (LPVOID*)kerneltickcheck << endl;
				newline
				cout << "Returned fine" << endl;
			}
		}

“Also you cannot possibly scan all internal Windows functions that EnumProcessModules() might be calling.”
I don’t recall mentioning this unless I misworded something.

"And ultimately, you cannot scan kernel-mode memory. "
I probably misworded this as well, but I didn’t mean actually scanning kernel-mode memory, I meant KERNEL32.DLL which is already loaded within the ROBLOX process. Refer to where I addressed: “You cannot scan system functions because you’ve got nothing to compare the code against.”

sigh. Look, comparing things requires at least two things. One thing here is the machine code of EnumProcessModules() function. What’s the other thing? What will you be comparing it against?
Hint: there are multiple Windows versions with multiple service packs and thousands of updates. It is impractical to maintain a hash of every possible version of EnumProcessModules().

Yes, that’s exactly the problem here. You seem to have overlooked the obvious counter to protecting a single function: the attacker may elect to change any portion of code that EnumProcessModules() calls into. Even the OS kernel.

1 Like

[quote] sigh. Look, comparing things requires at least two things. One thing here is the machine code of EnumProcessModules() function. What’s the other thing? What will you be comparing it against?
Hint: there are multiple Windows versions with multiple service packs and thousands of updates. It is impractical to maintain a hash of every possible version of EnumProcessModules(). [/quote]
For now, I’ve been talking about comparing using memcmp & memcpy(I know it’s impractical) which has been my original idea and I’m not really focused on changing it because that’d cause some confusion and we’d be jumping all over the place. This is the documentation for memcmp:

[quote]int memcmp ( const void * ptr1, const void * ptr2, size_t num );
Compare two blocks of memory[/quote]
memcmp doesn’t require you to actually input code yourself, it retrieves it for you when you give a pointer.

HANDLE KernelEnumMod = GetProcAddress(GetModuleHandle(L"KERNEL32.DLL"), "K32EnumProcessModules");

then you’d allocate memory and use memcpy().

memcpy((LPVOID*)AllocatedMemory, (LPVOID*)KernelEnumMod, size);

Then you can finally use memcmp() with AllocatedMemory and KernelEnumMod.

[quote]
Yes, that’s exactly the problem here. You seem to have overlooked the obvious counter to protecting a single function: the attacker may elect to change any portion of code that EnumProcessModules() calls into. Even the OS kernel. [/quote]
For fairness, you’re speaking about all these complicated attacks yet they’re using methods like Kernel32.IsDebuggerPresent (which also makes a jump to KERNELBASE and that memory can still be compared) when people can do the exact same to IsDebuggerPresent and that also makes it vulnerable. The goal for this was to just prevent anti-dll injection and we kind of have strayed from that.
Also, plenty of other games also have anti-dll injection, why not just use the kind of protection they’re using if this method doesn’t agree with you guys, but I don’t think those will give you the kind of security you’re looking for either.

I give up.

2 Likes

Well that escalated quickly.

OpenBlox currently uses code based on provided psuedocode in release builds of the client.

1 Like

I didn’t see this one.

DLL injection detection is actually much more difficult than this. For example, many DLLs can be inserted legitimately without the original developer knowing. This is because system DLLs can insert other DLLs. Graphics drivers can also load DLLs. Various other hardware, anti-virus, and virus applications also insert DLLs.

The second issue is that DLL injection has been heavily researched. Existing tools have reimplemented LoadLibrary. This means there is no need to hook EnumProcessModules, put your DLL in any of the module listings accessible from the PEB, etc… Multiple tools exist for this purpose, so security based on EPM will not be effective, even with a whitelist/blacklist.

(even hidden DLLs are not evidence of exploits…)

1 Like

External Media