All I’ll say is, watch the first 10 seconds of the song “Boom Boom Pow” by Black Eyed Peas (Preferably in HD: http://www.youtube.com/watch?v=ULocY5jitXQ).

My only question is: what’s with all these errors!?

Advertisements

I was reversing someone’s game cheat the other day, and I found something peculiar. nProtect had blacklisted two entire functions used by this person’s cheat, so they had used an XOR-based encryption (Using a minuscule one-byte key) to mask the function in memory, decrypting it on call, then re-encrypting it.

  do {
    temp = Buffer[bufferlength]; // Copy first byte
    Buffer[length] = Buffer[length + 1]; // Increment buffer
    newBuffer[bufferlength++] = ( int ) temp ^ 0x17; // XOR for changes
  } while ( temp != 0x3C ); // Loop until RETN

Pretty sloppy, but I guess it gets the job done!


Well, the last build had some an XP-only trick, and a problem with the GetHeapFlags function (Vista’s default heap handling is a bit different than XP’s; luckily, the heap behavior for debugging is still identifiable).

The OutputDebugString trick was only available on XP, but, as an alternative, I setup a formatting exploit that’s been reported to cause problems in a few different debuggers (Most notably, OllyDBG).

On top of that, I added a few new lesser documented tricks, and another one I pioneered myself to ensure the anti-debug was running. Enjoy!

e

After some testing, I was able to figure out which anti-debug functions did not work on Vista, and marked them to be filtered out. Enjoy! 🙂

#include <windows.h>

#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN

bool DebugBit = TRUE;
int countExceptions = 0;

char GetBeingDebugged( )
{
	char BeingDebuggedBit;
	__asm {
		MOV EAX,DWORD PTR FS:[0x30]
		XOR EAX, 0x2
		SUB EBX, EBX
		XOR BL, [EAX]
		MOV BeingDebuggedBit, BL
	};
	return( BeingDebuggedBit );
}

char GetNtGlobalFlags( )
{
	char *NtGlobalFlags;
	__asm {
		MOV EAX, FS:[0x30] 
		MOV EAX, [EAX+0x68]
		MOV [NtGlobalFlags], EAX
	};
	return( ( char ) NtGlobalFlags );
}

char GetHeapFlags( )
{
	char *HeapFlags;
	__asm {
		MOV EAX, FS:[0x30]
		MOV EAX, [EAX+0x18]
		MOV EAX, [EAX+0x10]
		MOV [HeapFlags], EAX
	};
	return ( ( char ) HeapFlags );
}

LONG WINAPI suefDebugCheck( struct _EXCEPTION_POINTERS *excInfo ) {
	DebugBit = FALSE;
	countExceptions++;
	return( EXCEPTION_CONTINUE_EXECUTION );
}

void suefTrick( void )
{
	countExceptions = 1 / countExceptions;
}

void swapDebug( void )
{
	MessageBox( 0, "Debugger not found.", "Success?", MB_OK );
	DebugBit = FALSE;
}

void __inline antiDebug( void )
{
	DWORD beginTime = GetTickCount( );
	__try {
	__asm INT 0x2D
	} __except( true ) {
		DebugBit = FALSE;
	}
	if( DebugBit == TRUE )
		exit( 0x00000005 );

	if( ( int ) GetNtGlobalFlags( ) == 0x70 )
		exit( 0xFFFFFFFB );


// I think the fetch method I used needs to be checked
// for Vista support..
	/*
	if( ( int ) GetBeingDebugged( ) == TRUE )
		exit( 0x04012AD0 );

	if( ( int ) GetHeapFlags( ) != 0 )
		exit( 0xFFFFFFFF );
		*/

	if( IsDebuggerPresent( ) != 0 )
		exit( 0x21473361  );


// I don't even know about this one; doesn't work on Vista..
	/*
	CheckRemoteDebuggerPresent( GetCurrentProcess( ), ( PBOOL ) &DebugBit );
	if( DebugBit == TRUE )
		exit( 0xC0000005 );
		*/



// SetHandledExceptionFilter and OutputDebugString tricks
// need to be fixed for Vista..
	/*
	SetUnhandledExceptionFilter( suefDebugCheck );
	suefTrick( );
	if( DebugBit == TRUE )
		exit( 0x041A9C35 );

	SetLastError( 0xC0000005 );
	OutputDebugString( "" );
	if( GetLastError( ) == 0xC0000005 )
		exit( 0x9348134F );
		*/



	// Requires admin access
	typedef NTSTATUS ( NTAPI *NSIT )( HANDLE, UINT, PVOID, ULONG );
	NSIT NtSetInformationThread = ( NSIT )GetProcAddress( GetModuleHandle( "ntdll.dll" ), "NtSetInformationThread" );
	NtSetInformationThread( GetCurrentProcess( ), 0x11, 0, 0 );
	// End

	__try {
		CloseHandle( ( HANDLE ) 0xFF );
	} __except( true ) {
		exit( 0x00000006 );
	}

	__try {
		__asm	INT 3;
	} __except( true ) {
		DebugBit = FALSE;
	}
	if( DebugBit == TRUE )
		exit( 0x0ADE0005 );

	if( GetTickCount( ) != beginTime )
		exit( 0xD000BE05 );


	typedef NTSTATUS ( WINAPI *NQIP )( HANDLE, LONG, PVOID, ULONG, PULONG );
	NQIP NtQueryInformationProcess = ( NQIP )GetProcAddress( GetModuleHandle( "ntdll.dll" ), "NtQueryInformationProcess" );
	int returnValue = 0;
	NtQueryInformationProcess( GetCurrentProcess( ), 0x7, &returnValue, 4, 0 );
	if( returnValue != 0 )
		exit( 0xCCCCCCCC );

	__try {
		DebugBreak( );
	} __except( true ) {
		DebugBit = FALSE;
	}
	if( DebugBit == TRUE )
		exit( 0x9000000D );
}

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd )
{
	antiDebug( );

	if( DebugBit == TRUE )
		return( EXIT_FAILURE );

	MessageBox( 0, "Debugger not found.", "Success?", MB_OK );

	return( EXIT_SUCCESS );
}

Whenever dealing with a Gunz client (Be it from an official server or private server), one piece of valuable information you may want to dump is the MRS decryption algorithm used. Therefore, here’s a neat little signature you can use in fingerprinting the decryption scheme:

\x56\x8B // MOV ECX, [ESP+4]
\x74\x24\x0C // MOV ESI, [ESP+C]
\x85\xF6 // TEST ESI, ESI
\x7E // JE SHORT (Missing byte)

One byte after the above signature will be the signature. Dump until a RETN instruction (0xC3) is found.


A recent project of mine branched into anti-debug techniques I compiled based off anti-anti-debug plugins I found, and some experimental techniques I discovered myself (e.g. SEH with CloseHandle giving an invalid handle).

#include <windows.h>

#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN

bool DebugBit = TRUE;
int countExceptions = 0;

char GetBeingDebugged( )
{
	char BeingDebuggedBit;
	__asm {
		MOV EAX,DWORD PTR FS:[0x30]
		XOR EAX, 0x2
		SUB EBX, EBX
		XOR BL, [EAX]
		MOV BeingDebuggedBit, BL
	};
	return( BeingDebuggedBit );
}

char GetNtGlobalFlags( )
{
	char *NtGlobalFlags;
	__asm {
		MOV EAX, FS:[0x30] 
		MOV EAX, [EAX+0x68]
		MOV [NtGlobalFlags], EAX
	};
	return( ( char ) NtGlobalFlags );
}

char GetHeapFlags( )
{
	char *HeapFlags;
	__asm {
		MOV EAX, FS:[0x30]
		MOV EAX, [EAX+0x18]
		MOV EAX, [EAX+0x10]
		MOV [HeapFlags], EAX
	};
	return ( ( char ) HeapFlags );
}

LONG WINAPI suefDebugCheck( struct _EXCEPTION_POINTERS *excInfo ) {
	DebugBit = FALSE;
	countExceptions++;
	return( EXCEPTION_CONTINUE_EXECUTION );
}

void suefTrick( void )
{
	countExceptions = 1 / countExceptions;
}

void swapDebug( void )
{
	MessageBox( 0, "Debugger not found.", "Success?", MB_OK );
	DebugBit = FALSE;
}

void __inline antiDebug( void )
{
	DWORD beginTime = GetTickCount( );
	__try {
	__asm INT 0x2D
	} __except( true ) {
		DebugBit = FALSE;
	}
	if( DebugBit == TRUE )
		exit( 0x00000005 );

	if( ( int ) GetNtGlobalFlags( ) == 0x70 )
		exit( 0xFFFFFFFB );

	if( ( int ) GetBeingDebugged( ) == TRUE )
		exit( 0x04012AD0 );

	if( ( int ) GetHeapFlags( ) != 0 )
		exit( 0xFFFFFFFF );

	if( IsDebuggerPresent( ) != 0 )
		exit( 0x21473361  );

	CheckRemoteDebuggerPresent( GetCurrentProcess( ), ( PBOOL ) &DebugBit );
	if( DebugBit == TRUE )
		exit( 0xC0000005 );

	SetUnhandledExceptionFilter( suefDebugCheck );
	suefTrick( );
	if( DebugBit == TRUE )
		exit( 0x041A9C35 );

	SetLastError( 0xC0000005 );
	OutputDebugString( "" );
	if( GetLastError( ) == 0xC0000005 )
		exit( 0x9348134F );

	// Requires admin access
	typedef NTSTATUS ( NTAPI *NSIT )( HANDLE, UINT, PVOID, ULONG );
	NSIT NtSetInformationThread = ( NSIT )GetProcAddress( GetModuleHandle( "ntdll.dll" ), "NtSetInformationThread" );
	NtSetInformationThread( GetCurrentProcess( ), 0x11, 0, 0 );
	// End

	__try {
		CloseHandle( ( HANDLE ) 0xFF );
	} __except( true ) {
		exit( 0x00000006 );
	}

	__try {
		__asm	INT 3;
	} __except( true ) {
		DebugBit = FALSE;
	}
	if( DebugBit == TRUE )
		exit( 0x0ADE0005 );

	if( GetTickCount( ) != beginTime )
		exit( 0xD000BE05 );


	typedef NTSTATUS ( WINAPI *NQIP )( HANDLE, LONG, PVOID, ULONG, PULONG );
	NQIP NtQueryInformationProcess = ( NQIP )GetProcAddress( GetModuleHandle( "ntdll.dll" ), "NtQueryInformationProcess" );
	int returnValue = 0;
	NtQueryInformationProcess( GetCurrentProcess( ), 0x7, &returnValue, 4, 0 );
	if( returnValue != 0 )
		exit( 0xCCCCCCCC );

	__try {
		DebugBreak( );
	} __except( true ) {
		DebugBit = FALSE;
	}
	if( DebugBit == TRUE )
		exit( 0x9000000D );
}

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd )
{
	antiDebug( );

	if( DebugBit == TRUE )
		return( EXIT_FAILURE );
	
	MessageBox( 0, "Debugger not found.", "Success?", MB_OK );

	return( EXIT_SUCCESS );
}

That’s a total of 15 anti-debugger techniques, with 14/15 being able to run from within user-mode 😉


An idea I had to prevent threads from being launched outside the code segment (e.g. Via DLL injection) would be to kill all threads found to have a start address outside the code segment.

To battle against such an idea, you would have to either:

a) Spoof the TIB.
b) Launch a thread from within the code segment, which would involve modification of the code segment (Wouldn’t work if checks on the code segment were done during runtime).

A very poorly formatted program I’ve been working on that makes use of the PEB’s BeingDebugged bit and an anti-debug technique involving a software interrupt with Microsoft’s proprietary __try/__except extensions:

#include <strsafe.h>
#include <tlhelp32.h>
#include <windows.h>

#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN

#define CODEBEGIN	0x00401000
#define CODEEND		0x00401A5E

char BeingDebugged( )
{
  char BeingDebuggedBit;
  __asm {
    MOV EAX,DWORD PTR FS:[0x30]
	XOR EAX, 0x2
	SUB EBX, EBX
	XOR BL, [EAX]
    MOV BeingDebuggedBit, BL
  };
  return( BeingDebuggedBit );
}

DWORD WINAPI GetThreadStartAddress( HANDLE hThread )
{
    NTSTATUS ntStatus;
    HANDLE hDupHandle;
    DWORD dwStartAddress;
    typedef NTSTATUS ( WINAPI *NQIT )( HANDLE, LONG, PVOID, ULONG, PULONG );
    NQIT NtQueryInformationThread = ( NQIT )GetProcAddress( GetModuleHandle( "ntdll.dll" ), "NtQueryInformationThread" );

    HANDLE hCurrentProcess = GetCurrentProcess( );

    if( !DuplicateHandle( hCurrentProcess, hThread, hCurrentProcess, &hDupHandle, THREAD_QUERY_INFORMATION, FALSE, 0 ) ) {
        return( ERROR_ACCESS_DENIED );
    }

    ntStatus = NtQueryInformationThread( hDupHandle, 9, &dwStartAddress, sizeof( DWORD ), NULL );

    CloseHandle( hDupHandle ); 

    return( dwStartAddress );
}

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd )
{
  bool noDebugger = FALSE;
  __try {
	__asm INT 0x2D
  } __except( true ) {
	  noDebugger = TRUE;
  }
  if( noDebugger == FALSE )
	  return( EXIT_FAILURE );

  if( ( int ) BeingDebugged( ) == TRUE )
	  return( EXIT_FAILURE );


  HANDLE h = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
  if( h != INVALID_HANDLE_VALUE ) {
    THREADENTRY32 te;
    te.dwSize = sizeof(te);
    if( Thread32First( h, &te ) ) {
      do {
       if ( te.dwSize >= FIELD_OFFSET(THREADENTRY*** th32OwnerProcessID) +
                      sizeof(te.th32OwnerProcessID) &&
					  GetCurrentProcessId( ) == te.th32OwnerProcessID ) {
			DWORD dwStartAddress;
			HANDLE lclThread = OpenThread( THREAD_GET_CONTEXT, FALSE, te.th32ThreadID );
			dwStartAddress = GetThreadStartAddress( lclThread );
			if( dwStartAddress < CODEBEGIN || dwStartAddress > CODEEND )
				TerminateThread( lclThread, EXIT_SUCCESS );

			CloseHandle( lclThread );
	  }
      te.dwSize = sizeof( te );
    } while( Thread32Next( h, &te ) );
   }
  }
  CloseHandle( h );
 

  MessageBox( 0, "Debugger not found.", "Success?", MB_OK );

  return( EXIT_SUCCESS );
}

Credits to:
http://blogs.msdn.com/oldnewthing/archive/2006/02/23/537856.aspx – Enumerating threads of all active processes

http://forum.sysinternals.com/printer_friendly_posts.asp?TID=5127 – Getting the start address of a thread via accessing the TIB using NtQuerySystemInformation.

Thoughts?