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
AntiDebug.cppCode:#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
Misc.hCode:#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; }
Main.cppCode:#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
Yeah, pretty basic, don't bash on me. ):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; }
ITT: You're opinions, suggestions, criticism. Gogogogo.
Last edited by Hassan; 02-05-2012 at 02:18 PM. Reason: Added code tag because dave is a lazy rat :@
dont understand.
critism = make it noob friendly.
未来が見えなくて怖いから
未来が見えてしまって悲しいから
目を閉じて優しい思い出に浸ってしまう
Melodia (09-13-2010)
You can win the rat race,Originally Posted by Jeremy S. Anderson
But you're still nothing but a fucking RAT.
++Latest Projects++
[Open Source] Injection Library
Simple PE Cipher
FilthyHooker - Simple Hooking Class
CLR Injector - Inject .NET dlls with ease
Simple Injection - An in-depth look
MPGH's .NET SDK
eJect - Simple Injector
Basic PE Explorer (BETA)
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.
"Every gun that is made, every warship launched, every rocket fired signifies, in the final sense, a theft from those who hunger and are not fed, those who are cold and are not clothed. This world in arms is not spending money alone. It is spending the sweat of its laborers, the genius of its scientists, the hopes of its children. The cost of one modern heavy bomber is this: a modern brick school in more than 30 cities. It is two electric power plants, each serving a town of 60,000 population. It is two fine, fully equipped hospitals. It is some fifty miles of concrete pavement. We pay for a single fighter plane with a half million bushels of wheat. We pay for a single destroyer with new homes that could have housed more than 8,000 people. This is, I repeat, the best way of life to be found on the road the world has been taking. This is not a way of life at all, in any true sense. Under the cloud of threatening war, it is humanity hanging from a cross of iron."- Dwight D. Eisenhower
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...
therofl (10-01-2010)
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
Ah we-a blaze the fyah, make it bun dem!
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.
You can win the rat race,Originally Posted by Jeremy S. Anderson
But you're still nothing but a fucking RAT.
++Latest Projects++
[Open Source] Injection Library
Simple PE Cipher
FilthyHooker - Simple Hooking Class
CLR Injector - Inject .NET dlls with ease
Simple Injection - An in-depth look
MPGH's .NET SDK
eJect - Simple Injector
Basic PE Explorer (BETA)
Hell_Demon (09-13-2010),Void (09-13-2010)
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. |:
therofl (10-01-2010)
You can win the rat race,Originally Posted by Jeremy S. Anderson
But you're still nothing but a fucking RAT.
++Latest Projects++
[Open Source] Injection Library
Simple PE Cipher
FilthyHooker - Simple Hooking Class
CLR Injector - Inject .NET dlls with ease
Simple Injection - An in-depth look
MPGH's .NET SDK
eJect - Simple Injector
Basic PE Explorer (BETA)
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.
Hell_Demon (09-15-2010),why06 (09-14-2010)
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.
"Every gun that is made, every warship launched, every rocket fired signifies, in the final sense, a theft from those who hunger and are not fed, those who are cold and are not clothed. This world in arms is not spending money alone. It is spending the sweat of its laborers, the genius of its scientists, the hopes of its children. The cost of one modern heavy bomber is this: a modern brick school in more than 30 cities. It is two electric power plants, each serving a town of 60,000 population. It is two fine, fully equipped hospitals. It is some fifty miles of concrete pavement. We pay for a single fighter plane with a half million bushels of wheat. We pay for a single destroyer with new homes that could have housed more than 8,000 people. This is, I repeat, the best way of life to be found on the road the world has been taking. This is not a way of life at all, in any true sense. Under the cloud of threatening war, it is humanity hanging from a cross of iron."- Dwight D. Eisenhower
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.
why06 (09-14-2010)
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..
Last edited by Gordon`; 09-14-2010 at 05:23 AM.
Void (09-14-2010)