[Source]Anti-Debugging

Posts 1–15 of 25 · Page 1 of 2
[Source]Anti-Debugging
Sup, I've recently gotten into wanting to create an anti cheating software, so why the heck not?

Obviously this is extremely amateur, I've only just started, but I've gone through a few methods to prevent debuggers from being attached. I'd really appreciate if you guys could contribute to this, as in, give me some information on how other anti cheats might work, or how I can improve this, or other anti debugging techniques.

Check it.

AntiDebug.h
Code:
#ifndef ANTIDEBUG_H
#define ANTIDEBUG_H


#include <windows.h>
#include "Misc.h"

bool CheckForDebugger_CRDP	(void);
bool CheckForDebugger_NQIP	(void);
bool CheckForDebugger_PEB	(void);
bool CheckForDebugger_EH	(void);

bool MonitorDebugRegisters	(void);

#endif
AntiDebug.cpp
Code:
#include "AntiDebug.h"

bool CheckForDebugger_CRDP(void)
{
	BOOL Present = false;
	CheckRemoteDebuggerPresent(GetCurrentProcess(),&Present);
	return Present;
}

bool CheckForDebugger_NQIP(void)
{
	HMODULE hModNTDLL;
	FARPROC _NQIP;

	hModNTDLL = LoadLibrary("ntdll.dll");
	_NQIP = GetProcAddress(hModNTDLL,"NtQueryInformationProcess");

	PVOID ProcessInfo;
	DWORD *ad_ = (DWORD*)&ProcessInfo;

	__asm
	{
		push NULL
		push 4
		push ad_
		push 0x07		//debug port ( if there is one, that's what we're checking )
		push -1			//current process
		call _NQIP
	}

	if(ProcessInfo != 0)
	{
		return true;
	}
	return false;
}

bool CheckForDebugger_PEB(void)
{
	TIB* tib;
	__asm
	{
		push eax

		mov eax,fs:[18h]
		mov tib,eax

		pop eax
	}
	
	if( tib->Peb->BeingDebugged == 1 )
	{
		return true;
	} else {
		return false;
	}
}

bool MonitorDebugRegisters(void)
{
	CONTEXT* ct;
	GetThreadContext(GetCurrentProcess(),ct);
	if(ct->Dr0 != 0 || ct->Dr1 != 0 || ct->Dr2 != 0 || ct->Dr3 != 0 || ct->Dr6 != 0 || ct->Dr7 != 0)
	{
		return true;
	}
	return false;
}

int set=0;
bool done = false;

void EHCheck()
{
	__try 
	{
		__asm
		{
				int 3h
		}
	}__except(EXCEPTION_EXECUTE_HANDLER)
	{
			set=1;
	}
	done = true;
}

bool CheckForDebugger_EH(void)
{
	HANDLE EHThread = CreateThread(0,0,(LPTHREAD_START_ROUTINE)EHCheck,0,0,0);
	if(done == true)
	{
		if(set != 1)
		{
			return true;
		}
	}
	return false;
}
Misc.h
Code:
#ifndef MISC_H
#define MISC_H


#include <windows.h>

struct PEB
{
	BOOLEAN InheritedAddressSpace;		    // 00
	BOOLEAN ReadImageFileExecOptions;		// 01
	BOOLEAN BeingDebugged;					// 02
	BOOLEAN SpareBool;						// 03
	HANDLE Mutant;							// 04
	HMODULE ImageBaseAddress;				// 08
	char* reserved1[4];						// 0c
	int Parameters;							// 10
	PVOID SubSystemData;					// 14
	HANDLE ProcessHeap;						// 18
	char* reserved3[4];						// 1c
	PVOID FastPebLockRoutine;				// 20
	PVOID FastPebUnlockRoutine;				// 24
	ULONG EnvironmentUpdateCount;			// 28
	PVOID KernelCallbackTable;				// 2c
	PVOID EventLogSection;					// 30
	PVOID EventLog;							// 34
	PVOID FreeList;							// 38
	ULONG TlsExpansionCounter;				// 3c
	char* reserved4[4];						// 40
	ULONG TlsBitmapBits[2];					// 44
	PVOID ReadOnlySharedMemoryBase;			// 4c
	PVOID ReadOnlySharedMemoryHeap;			// 50
	PVOID *ReadOnlyStaticServerData;		// 54
	PVOID AnsiCodePageData;					// 58
	PVOID OemCodePageData;					// 5c
	PVOID UnicodeCaseTableData;				// 60
	ULONG NumberOfProcessors;				// 64
	ULONG NtGlobalFlag;						// 68
	BYTE Spare2[4];							// 6c
	LARGE_INTEGER CriticalSectionTimeout;   // 70
	ULONG HeapSegmentReserve;				// 78
	ULONG HeapSegmentCommit;				// 7c
	ULONG HeapDeCommitTotalFreeTh;			// 80
	ULONG HeapDeCommitFreeBlockTh;			// 84
	ULONG NumberOfHeaps;				    // 88
	ULONG MaximumNumberOfHeaps;				// 8c
	PVOID *ProcessHeaps;					// 90
	PVOID GdiSharedHandleTable;				// 94
	PVOID ProcessStarterHelper;				// 98
	PVOID GdiDCAttributeList;				// 9c
	PVOID LoaderLock;						// a0
	ULONG OSMajorVersion;					// a4
	ULONG OSMinorVersion;					// a8
	ULONG OSBuildNumber;					// ac
	ULONG OSPlatformId;						// b0
	ULONG ImageSubSystem;					// b4
	ULONG ImageSubSystemMajorVersion;		// b8
	ULONG ImageSubSystemMinorVersion;		// bc
	ULONG ImageProcessAffinityMask;			// c0
	ULONG GdiHandleBuffer[34];				// c4
	ULONG PostProcessInitRoutine;			// 14c
	char* reserved5[4];						// 150
	ULONG TlsExpansionBitmapBits[32];		// 154
	ULONG SessionId;						// 1d4
};

struct TIB
{
	NT_TIB Tib;								// 000 Info block
	PVOID EnvironmentPointer;				// 01c
	DWORD processId;						// 20
	DWORD threadId;							// 24
	PVOID ActiveRpcHandle;					// 028
	PVOID ThreadLocalStoragePointer;		// 02c
	PEB *Peb;								// 030
	DWORD LastErrorValue;					// 034
	ULONG CountOfOwnedCriticalSections;		// 038
	PVOID CsrClientThread;					// 03c
	PVOID Win32ThreadInfo;					// 040
	ULONG Win32ClientInfo[0x1f];			// 044
	PVOID WOW32Reserved;					// 0c0
	ULONG CurrentLocale;					// 0c4
	ULONG FpSoftwareStatusRegister;			// 0c8
	PVOID SystemReserved1[54];				// 0cc
	PVOID Spare1;							// 1a4
	LONG ExceptionCode;						// 1a8
	BYTE SpareBytes1[40];					// 1ac
	PVOID SystemReserved2[10];				// 1d4
	DWORD num_async_io;						// 1fc
	ULONG_PTR dpmi_vif;						// 200
	DWORD vm86_pending;						// 204
	DWORD pad6[309];						// 208
	ULONG gdiRgn;							// 6dc
	ULONG gdiPen;							// 6e0
	ULONG gdiBrush;							// 6e4
	DWORD RealProcessId;					// 6e8
	DWORD RealThreadId;						// 6ec
	HANDLE GdiCachedProcessHandle;			// 6f0
	ULONG GdiClientPID;						// 6f4
	ULONG GdiClientTID;						// 6f8
	PVOID GdiThreadLocaleInfo;				// 6fc
	PVOID UserReserved[5];					// 700
	PVOID glDispachTable[280];				// 714
	ULONG glReserved1[26];					// b74
	PVOID glReserved2;						// bdc
	PVOID glSectionInfo;					// be0
	PVOID glSection;						// be4
	PVOID glTable;							// be8
	PVOID glCurrentRC;						// bec
	PVOID glContext;						// bf0
	ULONG LastStatusValue;					// bf4
	char* reserved1[214];					// bf8
	WCHAR StaticUnicodeBuffer[261];			// c00
	PVOID DeallocationStack;				// e0c
	PVOID TlsSlots[64];						// e10
	char* reserved2[8];						// f10
	PVOID Vdm;								// f18
	PVOID ReservedForNtRpc;					// f1c
	PVOID DbgSsReserved[2];					// f20
	ULONG HardErrorDisabled;				// f28
	PVOID Instrumentation[16];				// f2c
	PVOID WinSockData;						// f6c
	ULONG GdiBatchCount;					// f70
	ULONG Spare2;							// f74
	ULONG Spare3;							// f78
	ULONG Spare4;							// f7c
	PVOID ReservedForOle;					// f80
	ULONG WaitingOnLoaderLock;				// f84
	PVOID Reserved5[3];						// f88
	PVOID *TlsExpansionSlots;				// f94
};

#endif
Main.cpp
Code:
#include <windows.h>

#include "AntiDebug.h"


void Thread()
{
	while(true)
	{
		if(CheckForDebugger_CRDP() || 
		   CheckForDebugger_NQIP() || 
		   CheckForDebugger_EH() ||
		   CheckForDebugger_PEB() ||
		   CheckForDebugger_EH() ||
		   MonitorDebugRegisters()
		   )
		{
				HANDLE handle = OpenProcess(PROCESS_QUERY_INFORMATION | 
											PROCESS_TERMINATE,
											0,
											GetCurrentProcessId()
											);

				TerminateProcess(handle,0);
		}
	}
}

bool __stdcall DllMain(HINSTANCE hInst,DWORD dwReason,void* lpReserved)
{
	if(dwReason == DLL_PROCESS_ATTACH)
	{
		CreateThread(0,0,(LPTHREAD_START_ROUTINE)Thread,0,0,0);
	}
	return true;
}
Yeah, pretty basic, don't bash on me. ):

ITT: You're opinions, suggestions, criticism. Gogogogo.
dont understand.
critism = make it noob friendly.
Quote Originally Posted by Kallisti View Post
dont understand.
critism = make it noob friendly.
I can understand it just fine...

It's also already clearly explained...

--"
Quote Originally Posted by Kallisti View Post
dont understand.
critism = make it noob friendly.
Quote Originally Posted by freedompeace
I can understand it just fine...

It's also already clearly explained...

--"

You don't count

@topic, nice one Void, this looks neat-o
Quote Originally Posted by Jason View Post





You don't count

@topic, nice one Void, this looks neat-o
Lol, even if I don't count - he even put an example in there !

noob == new. anyone new to this topic, and is willing to learn (which does not include people who love to copy-paste-build-release)

Main.cpp
[PHP]
#include <windows.h>

#include "AntiDebug.h"


void Thread()
{
while(true)
{
if(CheckForDebugger_CRDP() ||
CheckForDebugger_NQIP() ||
CheckForDebugger_EH() ||
CheckForDebugger_PEB() ||
CheckForDebugger_EH() ||
MonitorDebugRegisters()
)
{
HANDLE handle = OpenProcess(PROCESS_QUERY_INFORMATION |
PROCESS_TERMINATE,
0,
GetCurrentProcessId()
);

TerminateProcess(handle,0);
}
}
}

bool __stdcall DllMain(HINSTANCE hInst,DWORD dwReason,void* lpReserved)
{
if(dwReason == DLL_PROCESS_ATTACH)
{
CreateThread(0,0,(LPTHREAD_START_ROUTINE)Thread,0, 0,0);
}
return true;
}
[/PHP]
You could monitor the process for injected DLL's as well, by using CreateToolhelp32Snapshot API.

Your already covering a lot of techniques. I would just try covering as many as possible first, and then securing those techniques, because many of the API's ur using are easy to hook, and in most cases are hooked by anti-anti-debugger plugins. This is already some pretty good detection though.

You may also try scanning processlist for specific programs such as common debuggers.
Quote Originally Posted by why06 View Post
You could monitor the process for injected DLL's as well, by using CreateToolhelp32Snapshot API.

Your already covering a lot of techniques. I would just try covering as many as possible first, and then securing those techniques, because many of the API's ur using are easy to hook, and in most cases are hooked by anti-anti-debugger plugins. This is already some pretty good detection though.

You may also try scanning processlist for specific programs such as common debuggers.
Yeah, I'm going to try as many as possible. Before watching for module injection I still have a long way to go before this anti debug portion is done.

My other ideas were to set system wide hooks on API like NtSetInformationProcess and NtQueryInformationProcess, since those are what I saw IDA stealth hooking. Also, somehow, monitoring the IAT of every loaded process would be cool but I have no idea how to do that without injecting a DLL into every running process, which I'm definitely not doing...
Hook LoadLibrary and then in your hooked one loop through all active threads to see if they're trying to inject a dll with CreateRemoteThread
If anyone's interested there's some pretty good documentation on finding a loaded module into your process, even going as far as to take precautions against dll cloaking etc.

Find Injected DLLs In A Process?

I was just reading through the discussion there, I don't have enough core knowledge to make a whole lot of sense out of it but I think I got the main concepts. Don't know if it'll be much use to you but I thought I'd post it up.
Quote Originally Posted by Jason View Post
If anyone's interested there's some pretty good documentation on finding a loaded module into your process, even going as far as to take precautions against dll cloaking etc.

Find Injected DLLs In A Process?

I was just reading through the discussion there, I don't have enough core knowledge to make a whole lot of sense out of it but I think I got the main concepts. Don't know if it'll be much use to you but I thought I'd post it up.
Thanks Deezy, I'm definitely going to read over this later on in this project, anti DLL injection is going to come after anti debugging.

@Wes, how would I know if CreateRemoteThread is being used to inject DLLs? I mean, if I check if it's creating a thread at the LoadLibrary function, an extremely easy way to bypass this would be to write a jump or call somewhere in allocated memory space and start the thread there. |:
Quote Originally Posted by Void View Post
Thanks Deezy, I'm definitely going to read over this later on in this project, anti DLL injection is going to come after anti debugging.

@Wes, how would I know if CreateRemoteThread is being used to inject DLLs? I mean, if I check if it's creating a thread at the LoadLibrary function, an extremely easy way to bypass this would be to write a jump or call somewhere in allocated memory space and start the thread there. |:
Glad to be of some use. If only I knew enough above game design/C++ as a whole to understand what they're talking about with "rings" and stuff like that. Seems like a really interesting and complex concept.
Quote Originally Posted by Jason View Post


Glad to be of some use. If only I knew enough above game design/C++ as a whole to understand what they're talking about with "rings" and stuff like that. Seems like a really interesting and complex concept.
Each ring is a basically a level of authorisation, or privilege. The less the ring (number), the more priveleged your program is, and therefore, the more access you have to the system.

Having a higher privelege could means that you can control more things, such as memory and gain access to certain CPU instructions.

Ring 3 is the least privileged level, and Ring 0 the highest (for software) - Ring 0 is referred to as kernel mode, and is the mode that most rootkits attempt to gain access to.

Also, Ring -1 exists, but this is at a hardware (processor) level, present in a hypervisor state.
Also I would like to point out that the word privileged doesn't mean in the sense that it has to ask you for permission to run as admin or something. Firstly the kernel has higher authority then you, and doesn't have to ask the user or any user mode program for permission to do shit. What it means is that it can directly access your hardware devices, and windows has very little control over controlling what it does, because it runs on the same level as the operating system. This makes things harder as well, because a kernel driver, must be very stable even with out all the extra stability services the OS provides for usermode programs. It is for this reason driver programming is seen as some of the most difficult programming.
Quote Originally Posted by why06 View Post
Also I would like to point out that the word privileged doesn't mean in the sense that it has to ask you for permission to run as admin or something. Firstly the kernel has higher authority then you, and doesn't have to ask the user or any user mode program for permission to do shit. What it means is that it can directly access your hardware devices, and windows has very little control over controlling what it does, because it runs on the same level as the operating system. This makes things harder as well, because a kernel driver, must be very stable even with out all the extra stability services the OS provides for usermode programs. It is for this reason driver programming is seen as some of the most difficult programming.
And is very common among malware - because it can do anything, including hiding itself from the user and security software (unless the security software does something similar to detect it).

Also, by "it", why06 means a kernal driver, aka. some (compiled) code / program running in Ring 0, kernel mode.
As far as I remember CreateRemoteThread calls CreateThread in the remote process.

Also a system-wide hook on Nt/Zw APIs requires to be on ring0, the kernel mode. You would need to write a driver for all common operating systems (XP, XP x64, Vista, Vista x64, 7, 7 x64). Also on x64 operating systems you need a signed driver (which can be bypassed, but I wanted to mention it).

Every little mistake on kernel mode/ring0 gives you a bluescreen and can destroy your system. Be careful if you want to write a driver. WDK/DDK helps you.

@Void: you can read with ReadProcessMemory the whole DOS + PE-Header of every exe/dll. In the PE-Header are all informations you need - IAT/EAT, Relocations, etc..
Posts 1–15 of 25 · Page 1 of 2

Post a Reply

Similar Threads

Tags for this Thread

None

Talk with us