First of all, hi! I'm new to this community

So here we go..
This will cripple VAC2 completely, making it unable to detect your hacks.
I will make this in 2 parts, first explanation and step-by-step, then full working source-code.
--------------
Step-by-step tutorial and explanation
Inject your DLL to Steam.exe (this is where VAC2 now resides, not like VAC1 which was inside the actual game)
When a game is started, VAC2 module is generated and loaded into Steam.exe.
To check for this event, let's do this:
BOOL CheckForVAC2()
{
HANDLE hSnapShot = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, 0 );
MODULEENTRY32 mModule32 = { sizeof( MODULEENTRY32 ) };
if( Module32First( hSnapShot, &mModule32 ) )
{
bool meNext = false;
if( oModule32Next != 0 )
meNext = oModule32Next( hSnapShot, &mModule32 );
else
meNext = Module32Next( hSnapShot, &mModule32 );
while( meNext )
{
if( strstr( (char*)mModule32.szModule, ".tmp" ) )
{
if( stricmp( (char*)mModule32.szModule, szVac2Module ) )
{
strcpy( szVac2Module, (char*)mModule32.szModule );
dwVac2Base = (DWORD)mModule32.modBaseAddr;
if( dwVac2Base == 0 )
dwOldVac2Base = 0;
dwVac2Size = mModule32.modBaseSize;//mModule32.dwSize;
}
CloseHandle ( hSnapShot );
return TRUE;
}
if( oModule32Next != 0 )
meNext = oModule32Next( hSnapShot, &mModule32 );
else
meNext = Module32Next( hSnapShot, &mModule32 );
}
}
CloseHandle( hSnapShot );
return FALSE;
}
The file-extension of VAC2 module is always .tmp so this is a safe method of finding it.
Then once we've found that it's loaded we hook API-functions used by VAC2, use detours or IAT/EAT hooking..
Hook Module32Next (kernel32.dll) and ReadProcessMemory (kernel32.dll)
In our Module32Next hook we do this:
BOOL WINAPI hModule32Next( HANDLE hSnapshot, LPMODULEENTRY32 lpme )
{
ZeroMemory( lpme->szModule, MAX_MODULE_NAME32 ); //Let's remove module-name from the struct so they surely don't get any
lpme->modBaseAddr = 0;
lpme->modBaseSize = 0;
lpme->hModule = NULL;
lpme->th32ModuleID = 0;
lpme->th32ProcessID = 0;
SetLastError( ERROR_NO_MORE_FILES ); //Tells them there's no more modules
return FALSE; //Failed.
BOOL bReturn = oModule32Next( hSnapshot, lpme );
return bReturn;
}
Then VAC2 thinks that it has gone thru the whole list of loaded modules (DLL's) in the process and found no hacks.
Now in our ReadProcessMemory hook we simply return 0:
BOOL WINAPI hReadProcessMemory( HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesRead )
{
return 0; //Same thing as returning FALSE
}
Because, as MSDN (
http://msdn.microsoft.com/en-us/library/ms680553(VS.85).aspx) tells us:
"If the function fails, the return value is 0 (zero)."
Then VAC2 thinks it can't read memory.
If this causes your game quitting etc, an alternative (and better) method is to let it perform the read, but modify the bytes in the return buffer so that they are "clean"..
Say you changed a EB (Jump) to a 90 (NOP) in the game, for example to do radar-hack, then VAC2 will notice this if they read that memory.
BUT if you let it read, then take the original bytes (from cache or from original game-module on harddrive (just read file)) then VAC2 will see there is nothing wrong with this memory and think it is real

Most people now only make their hacks "VAC2-proof" by unlinking module from PEB and hiding etc.
Much better is to attack VAC2 directly, kill it and bypass it, such as my tip above..
---------------------
Fully working source code
Ok, this is from my private VAC2 disabler and has been stripped some, but it's working fine.
//n! yo
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <TlHelp32.h>
#include "Detours.h"
#pragma comment(lib, "Detours.lib")
HMODULE hMod;
typedef BOOL ( WINAPI *tReadProcessMemory ) ( HANDLE, LPCVOID, LPVOID, SIZE_T, SIZE_T* );
tReadProcessMemory oReadProcessMemory = NULL;
BOOL WINAPI hReadProcessMemory( HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesRead )
{
return 0;
}
typedef BOOL ( WINAPI *tModule32Next ) ( HANDLE, LPMODULEENTRY32 );
tModule32Next oModule32Next = NULL;
BOOL WINAPI hModule32Next( HANDLE hSnapshot, LPMODULEENTRY32 lpme )
{
ZeroMemory( lpme->szModule, MAX_MODULE_NAME32 ); //Let's remove module-name from the struct so they surely don't get any
lpme->modBaseAddr = 0;
lpme->modBaseSize = 0;
lpme->hModule = NULL;
lpme->th32ModuleID = 0;
lpme->th32ProcessID = 0;
SetLastError( ERROR_NO_MORE_FILES ); //Tells them there's no more modules
return FALSE; //Failed.
return oModule32Next( hSnapshot, lpme );
}
DWORD MainThread( LPVOID lpArgs )
{
//////////////////////////////////////////////////////////////////////////
// Hook shit
//
oReadProcessMemory = ( tReadProcessMemory )DetourFunction( (PBYTE)ReadProcessMemory, (PBYTE)hReadProcessMemory );
//WriteLog( "ReadProcessMemory hooked, original: %p, hook: %p", oReadProcessMemory, hReadProcessMemory );
Sleep( 1000 );
oModule32Next = ( tModule32Next )DetourFunction( (PBYTE)Module32Next, (PBYTE)hModule32Next );
//WriteLog( "Module32Next hooked, original: %p, hook: %p", oModule32Next, hModule32Next );
return 0;
}
BOOL WINAPI DllMain( HMODULE hModule, DWORD dwReason, LPVOID lpReserved )
{
if( dwReason == DLL_PROCESS_ATTACH )
{
//////////////////////////////////////////////////////////////////////////
// Initialize
hMod = hModule;
DisableThreadLibraryCalls( hMod );
//////////////////////////////////////////////////////////////////////////
// Start our main thread
DWORD dwThreadID;
HANDLE hThread = CreateThread( NULL, NULL, (LPTHREAD_START_ROUTINE)MainThread, NULL, NULL, &dwThreadID );
}
return true;
}
----------
And last, a little tip some of you might not know..
This is usefull when hooking functions
First, in your includes:
#include <intrin.h>
#pragma intrinsic(_ReturnAddress)
Then use like this in your hooked function:
WriteLog( "Function returns to %p", _ReturnAddress() );
Then you see where the function returns to.
Can be usefull eg. to see if return is inside VAC2-module..
Good luck and have fun hacking

Best regards,
Reconsider.