#pragma once
// Apr 21th, 2009 - liusiyang
//
#ifdef _ANTIDEBUG
// ..
#define JUNK_CODE_ONE \
__asm {push eax} \
__asm {xor eax, eax} \
__asm {setpo al} \
__asm {push edx} \
__asm {xor edx, eax} \
__asm {sal edx, 2} \
__asm {xchg eax, edx} \
__asm {pop edx} \
__asm {or eax, ecx} \
__asm {pop eax}
// ..
#define JUNK_CODE_TWO_2(lineno, value) \
__asm {jz _1##lineno} \
__asm {jnz _1##lineno} \
__asm {_emit 0x##value} \
__asm {_1##lineno: }
#define JUNK_CODE_TWO_1(name, value) JUNK_CODE_TWO_2(name, value)
#define JUNK_CODE_TWO JUNK_CODE_TWO_1(__LINE__, __LINE__*1111%253)
// ..
#define JUNK_CODE_TWO_2_2(lineno) \
__asm {jz _112##lineno} \
__asm {jnz _112##lineno} \
__asm {_emit 0e8h} \
__asm {_112##lineno: }
#define JUNK_CODE_TWO_1_2(name) JUNK_CODE_TWO_2_2(name)
#define JUNK_CODE_TWO2 JUNK_CODE_TWO_1_2(__LINE__)
// ..
#define JUNK_CODE_TWO_2_3(lineno) \
__asm { xor eax, eax } \
__asm { test eax, eax } \
__asm {jz _1121##lineno} \
__asm {jnz _1120##lineno} \
__asm {_1120##lineno: } \
__asm {_emit 0e8h} \
__asm {_1121##lineno: } \
__asm { xor eax, 3 } \
__asm { add eax, 4 } \
__asm { xor eax, 5 }
#define JUNK_CODE_TWO_1_3(name) JUNK_CODE_TWO_2_3(name)
#define JUNK_CODE_TWO3 JUNK_CODE_TWO_1_3(__LINE__)
// ..
#define JUNK_CODE_THREE_2(lineno, value1, value2) \
__asm {clc} \
__asm {jnb _3t##lineno} \
__asm {_emit 0x##value1} \
__asm {_emit 0x##value2} \
__asm {_3t##lineno: }
#define JUNK_CODE_THREE_1(name, value1, value2) JUNK_CODE_THREE_2(name, value1, value2)
#define JUNK_CODE_THREE JUNK_CODE_THREE_1(__LINE__, __LINE__*1222%253, __LINE__*1111%253)
// ..
#define JUNK_CODE_FOUR_2(lineno, value) \
__asm {jl _11f##lineno} \
__asm {_12f##lineno: } \
__asm {jmp _13f##lineno } \
__asm {_emit 0x##value } \
__asm {_11f##lineno: } \
__asm {jz _12f##lineno } \
__asm {_13f##lineno: }
#define JUNK_CODE_FOUR_1(name, value) JUNK_CODE_FOUR_2(name, value)
#define JUNK_CODE_FOUR JUNK_CODE_FOUR_1(__LINE__, __LINE__*1111%253)
// ..
#define JUNK_CODE_FIVE_2(lineno) \
__asm {pushf} \
__asm {push 0x0a} \
__asm {_51f##lineno: jnb _53f##lineno} \
__asm {jmp _52f##lineno} \
__asm {_52f##lineno: call _54f##lineno} \
__asm {_53f##lineno: jnb _52f##lineno} \
__asm {_54f##lineno: add esp,4} \
__asm {jmp _55f##lineno} \
__asm {_55f##lineno: } \
__asm {dec dword ptr [esp]} \
__asm {jno _56f##lineno} \
__asm {_56f##lineno: jns _51f##lineno} \
__asm {jp _57f##lineno} \
__asm {_57f##lineno: add esp,4} \
__asm {popf} \
__asm {jmp _58f##lineno} \
__asm {_58f##lineno: }
#define JUNK_CODE_FIVE_1(name) JUNK_CODE_FIVE_2(name)
#define JUNK_CODE_FIVE JUNK_CODE_FIVE_1(__LINE__)
#else
#define JUNK_CODE_ONE
#define JUNK_CODE_TWO
#define JUNK_CODE_TWO2
#define JUNK_CODE_TWO3
#define JUNK_CODE_THREE
#define JUNK_CODE_FOUR
#define JUNK_CODE_FIVE
#endif
bool start_anti_debug();
bool stop_anti_debug();
bool is_under_debug();
bool test_under_debug();
#include "AntiDebug.h"
#include <windows.h>
#include <tlhelp32.h>
#include <tchar.h>
#include <stdio.h>
#include "thread.h"
#include <time.h>
#if 0
Windows allow you to call the CreateProcess function with CREATE_SUSPENDED flag, that tells the API to keep the process suspended until the ResumeThread function is called.
This gives us time to grab the suspended thread's context using GetThreadContext function, then the EBX register will hold a pointer to the PBE(Process Enviroment Block) structure, which we need to determine the base address.
From the layout of the PBE structure we can see that the ImageBaseAddress is stored at the 8th byte, therefore [EBX+8] will give us actual base address of the process being suspended.
Now we need the in-memory EXE and do appropiate alignment if the alignment of memory and in-memory EXE differs.
If the base address of suspended process and in-memory exe matches, plus if the imageSize of the in-memory exe is lesser or equal to the suspended process' we can simply use WriteProcessMemory to write in-memory exe into the memory space of the suspended process.
But if the aforementioned conditions weren't met, we need a little more magic. First, we need to unmap the original image using ZwUnmapViewOfSection, and then allocate enough memory using VirtualAllocEx within the memory space of the suspended process. Now we need to write the in-memory exe into the memory space of the suspended process using the WriteProcessMemory function.
Next, patch the BaseAddress of the in-memory exe into the PEB->ImageBaseAddress of the suspended process.
EAX register of the thread context holds EntryPoint address, which we need to rewrite with the EntryPoint address of the in-memory exe. Now we need to save the altered thread context using the SetThreadContext function.
Voila! We're ready to call the ResumeThread function on the suspended process to execute it!
#endif
//#pragma warning(push)
#pragma warning(disable: 4733)
#pragma warning(disable: 4731)
#pragma warning(disable: 4355)
#define test_out printf
class CCheckThread : public CThread
{
protected:
BOOL under_debug_;
public:
BOOL under_debug() {
return under_debug_;
}
CCheckThread() : under_debug_(FALSE) {}
};
// µ÷ÊÔ¼ì²â·½·¨1
BOOL CheckDebugger_Method1(HANDLE process)
{
typedef BOOL (WINAPI *CHECK_REMOTE_DEBUGGER_PRESENT)(HANDLE, PBOOL);
HMODULE module = ::GetModuleHandle(_T("Kernel32"));
if (module)
{
CHECK_REMOTE_DEBUGGER_PRESENT CheckRemoteDebuggerPresent_;
CheckRemoteDebuggerPresent_ = (CHECK_REMOTE_DEBUGGER_PRESENT)GetProcAddress(module, "CheckRemoteDebuggerPresent");
if (CheckRemoteDebuggerPresent_)
{
BOOL bDebuggerPresent = FALSE;
if ((*CheckRemoteDebuggerPresent_)(process, &bDebuggerPresent))
{
if (bDebuggerPresent) {
test_out("cdm 1 check debug!\n");
}
return bDebuggerPresent;
}
}
else
{
// Èç¹ûûÓлñÈ¡µ½CheckRemoteDebugger£¬Ôòµ÷ÓÃÔʼµÄ¼ì²âº¯Êý
return IsDebuggerPresent();
}
}
return FALSE;
}
class CDM1 : public CCheckThread
{
virtual UINT on_execute()
{
__try {
if (CheckDebugger_Method1(::GetCurrentProcess())) {
under_debug_ = TRUE;
return -10000;
}
} __except(1) {
}
under_debug_ = FALSE;
return 100;
}
};
/
/
/
BOOL CheckDebugger_Method2()
{
// Ö»Äܼì²â×Ô¼ºµÄ½ø³ÌÊÇ·ñÔÚµ÷ÊÔÖÐ
__asm {
mov eax, fs:[30h]
mov eax, [eax+0x68]
and eax, 0x70
}
}
class CDM2 : public CCheckThread
{
virtual UINT on_execute()
{
__try {
if (CheckDebugger_Method2()) {
test_out("cdm 2 check debug!\n");
under_debug_ = TRUE;
return -20000;
}
} __except(1) {
}
under_debug_ = FALSE;
return 200;
}
};
/
/
/
BOOL CheckDebugger_Method3(HANDLE hProcess)
{
typedef long NTSTATUS;
#define STATUS_SUCCESS ((NTSTATUS)0L)
typedef struct _SYSTEM_KERNEL_DEBUGGER_INFORMATION {
BOOLEAN DebuggerEnabled;
BOOLEAN DebuggerNotPresent;
} SYSTEM_KERNEL_DEBUGGER_INFORMATION, *PSYSTEM_KERNEL_DEBUGGER_INFORMATION;
typedef struct _PROCESS_DEBUG_PORT_INFO {
HANDLE DebugPort;
} PROCESS_DEBUG_PORT_INFO;
enum SYSTEM_INFORMATION_CLASS { SystemKernelDebuggerInformation = 35 };
enum THREAD_INFO_CLASS { ThreadHideFromDebugger = 17 };
enum PROCESS_INFO_CLASS { ProcessDebugPort = 7 };
typedef NTSTATUS (__stdcall *ZW_QUERY_SYSTEM_INFORMATION)(IN SYSTEM_INFORMATION_CLASS SystemInformationClass, IN OUT PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength);
typedef NTSTATUS (__stdcall *ZW_SET_INFORMATION_THREAD)(IN HANDLE ThreadHandle, IN THREAD_INFO_CLASS ThreadInformationClass, IN PVOID ThreadInformation, IN ULONG ThreadInformationLength);
typedef NTSTATUS (__stdcall *ZW_QUERY_INFORMATION_PROCESS)(IN HANDLE ProcessHandle, IN PROCESS_INFO_CLASS ProcessInformationClass, OUT PVOID ProcessInformation, IN ULONG ProcessInformationLength, OUT PULONG ReturnLength);
// ¿ªÊ¼¼ì²â
ZW_QUERY_SYSTEM_INFORMATION ZwQuerySystemInformation;
ZW_QUERY_INFORMATION_PROCESS ZwQueryInformationProcess;
SYSTEM_KERNEL_DEBUGGER_INFORMATION Info;
PROCESS_DEBUG_PORT_INFO ProcessInfo;
HMODULE hModule = GetModuleHandle("ntdll.dll");
if (!hModule) {
return FALSE;
}
ZwQuerySystemInformation = (ZW_QUERY_SYSTEM_INFORMATION)GetProcAddress(hModule, "ZwQuerySystemInformation");
ZwQueryInformationProcess = (ZW_QUERY_INFORMATION_PROCESS)GetProcAddress(hModule, "ZwQueryInformationProcess");
// ¼ì²âÈ«¾Öµ÷ÊÔÆ÷
if (ZwQuerySystemInformation) {
if (STATUS_SUCCESS == ZwQuerySystemInformation(SystemKernelDebuggerInformation, &Info, sizeof(Info), NULL)) {
if (Info.DebuggerEnabled&&!Info.DebuggerNotPresent) {
return TRUE;
}
}
}
// ¼ì²â¾Ö²¿µ÷ÊÔÆ÷
if (ZwQueryInformationProcess) {
if (STATUS_SUCCESS == ZwQueryInformationProcess(hProcess, ProcessDebugPort, &ProcessInfo, sizeof(ProcessInfo), NULL)) {
if (ProcessInfo.DebugPort) {
return TRUE;
}
}
}
return FALSE;
}
class CDM3 : public CCheckThread
{
virtual UINT on_execute()
{
__try {
if (CheckDebugger_Method3(::GetCurrentProcess())) {
test_out("cdm 3 check debug!\n");
under_debug_ = TRUE;
return -30000;
}
} __except(1) {
}
under_debug_ = FALSE;
return 300;
}
};
/
/
/
BOOL GetPIDPath(DWORD dwPID, LPTSTR exe_path, int max_path)
{
BOOL success = FALSE;
HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
MODULEENTRY32 me32;
// Take a snapshot of all modules in the specified process.
hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID);
if( hModuleSnap == INVALID_HANDLE_VALUE )
{
return( FALSE );
}
// Set the size of the structure before using it.
me32.dwSize = sizeof( MODULEENTRY32 );
// Retrieve information about the first module, and exit if unsuccessful
if( !Module32First( hModuleSnap, &me32 ) )
{
CloseHandle( hModuleSnap ); // Must clean up the
return( FALSE );
}
do
{
if (me32.th32ProcessID == dwPID)
{
_tcsncpy(exe_path, me32.szExePath, max_path-1);
success = TRUE;
break;
}
} while(Module32Next(hModuleSnap, &me32));
CloseHandle(hModuleSnap);
return success;
}
BOOL CheckDebugger_Method4(DWORD processid)
{
BOOL has_debugger = FALSE;
HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
PROCESSENTRY32 me32;
// Take a snapshot of all modules in the specified process.
hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
if( hModuleSnap == INVALID_HANDLE_VALUE )
{
return( FALSE );
}
// Set the size of the structure before using it.
me32.dwSize = sizeof( PROCESSENTRY32 );
// Retrieve information about the first module, and exit if unsuccessful
if( !Process32First( hModuleSnap, &me32 ) )
{
CloseHandle( hModuleSnap ); // Must clean up the
return( FALSE );
}
// Now walk the module list of the process, and display information about each module
do
{
if (me32.th32ProcessID == processid)
{
TCHAR full_path[MAX_PATH] = {0};
if (GetPIDPath(me32.th32ParentProcessID, full_path, MAX_PATH))
{
// Èç¹ûÊÇϵͳĿ¼µÄ»°£¬
TCHAR system_path[MAX_PATH] = {0};
GetSystemWindowsDirectory(system_path, MAX_PATH);
if (!_tcsstr(full_path, system_path))
{
TCHAR cur_path[MAX_PATH] = {0};
::GetModuleFileName(NULL, cur_path, MAX_PATH);
TCHAR* p2 = _tcsrchr(cur_path, _T('\\'));
if (p2)
{
*p2 = 0;
if (!_tcsstr(full_path, cur_path))
{
has_debugger = TRUE;
}
}
}
}
break;
}
} while( Process32Next ( hModuleSnap, &me32 ) );
CloseHandle( hModuleSnap );
return has_debugger;
}
class CDM4 : public CCheckThread
{
virtual UINT on_execute()
{
__try {
if (CheckDebugger_Method4(::GetCurrentProcessId())) {
test_out("cdm 4 check debug!\n");
under_debug_ = TRUE;
return -40000;
}
} __except(1) {
}
under_debug_ = FALSE;
return 400;
}
};
/
/
/
BOOL CheckDebugger_Method5()
{
// APIs making user of the ZwClose syscall (such as CloseHandle, indirectly)
//can be used to detect a debugger. When a process is debugged, calling ZwClose
//with an invalid handle will generate a STATUS_INVALID_HANDLE (0xC0000008) exception.
// As with all anti-debugs that rely on information made directly available
//from the kernel (therefore involving a syscall), the only proper way to bypass
//the "CloseHandle" anti-debug is to either modify the syscall data from ring3,
//before it is called, or set up a kernel hook.
// This anti-debug, though extremely powerful, does not seem to be widely used
//by malicious programs.
__try {
CloseHandle((HANDLE)0x3333);
} __except(1) {
return TRUE;
}
return FALSE;
}
class CDM5 : public CCheckThread
{
virtual UINT on_execute()
{
__try {
if (CheckDebugger_Method5()) {
test_out("cdm 5 check debug!\n");
under_debug_ = TRUE;
return -50000;
}
} __except(1) {
}
under_debug_ = FALSE;
return 500;
}
};
/
/
/
BOOL CheckDebugger_Method6()
{
DWORD csrss_id = -1;
HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
PROCESSENTRY32 me32;
// Take a snapshot of all modules in the specified process.
hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
if( hModuleSnap == INVALID_HANDLE_VALUE )
{
return( FALSE );
}
// Set the size of the structure before using it.
me32.dwSize = sizeof( PROCESSENTRY32 );
// Retrieve information about the first module, and exit if unsuccessful
if( !Process32First( hModuleSnap, &me32 ) )
{
CloseHandle( hModuleSnap ); // Must clean up the
return( FALSE );
}
// Now walk the module list of the process, and display information about each module
do
{
if (!_tcsicmp(me32.szExeFile, _T("csrss.exe")))
{
csrss_id = me32.th32ProcessID;
break;
}
} while( Process32Next ( hModuleSnap, &me32 ) );
CloseHandle( hModuleSnap );
// Èç¹ûûÓÐÕÒµ½£¬Ö±½Ó·µ»Ø
if (csrss_id==-1)
{
return FALSE;
}
// Ö»Äܼì²â±¾½ø³Ì
HANDLE handle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, csrss_id);
if (handle)
{
// Èç¹ûÄÜ´ò¿ª£¬±íʾ¾ÍÓÐÎÊÌâ
CloseHandle(handle);
return TRUE;
}
return FALSE;
}
class CDM6 : public CCheckThread
{
virtual UINT on_execute()
{
__try {
if (CheckDebugger_Method6()) {
test_out("cdm 6 check debug!\n");
under_debug_ = TRUE;
return -60000;
}
} __except(1) {
}
under_debug_ = FALSE;
return 600;
}
};
/
/
/
BOOL CheckDebugger_Method7()
{
HWND hwnd = ::GetForegroundWindow();
if (hwnd)
{
TCHAR title[260];
::GetWindowText(hwnd, title, 260);
_tcslwr(title);
if (_tcsstr(title, _T("lly")))
{
return TRUE;
}
else if (_tcsstr(title, _T("debug")))
{
return TRUE;
}
else if (_tcsstr(title, _T("dbg")))
{
return TRUE;
}
else if (_tcsstr(title, _T("ida")))
{
return TRUE;
}
else if (_tcsstr(title, _T("asm")))
{
return TRUE;
}
}
if (FindWindow(NULL, _T("ollydbg"))) {
return TRUE;
}
if (FindWindow(NULL, _T("TIdaWindow"))) {
return TRUE;
}
return FALSE;
}
class CDM7 : public CCheckThread
{
virtual UINT on_execute()
{
__try {
if (CheckDebugger_Method7()) {
test_out("cdm 7 check debug!\n");
under_debug_ = TRUE;
return -70000;
}
} __except(1) {
}
under_debug_ = FALSE;
return 700;
}
};
/
/
/
BOOL CheckDeleteFib()
{
char fib[1024] = {0};
__try {
DeleteFiber(fib);
}
__except(1) {
return FALSE;
}
if(GetLastError() == 0x00000057)
return FALSE;
return TRUE;
}
class CDM8 : public CCheckThread
{
virtual UINT on_execute()
{
try {
if (CheckDeleteFib()) {
test_out("cdm 8 check debug!\n");
under_debug_ = TRUE;
return -80000;
}
} catch (...) {
}
under_debug_ = FALSE;
return 800;
}
};
/
/
/
BOOL TimeChecker()
{
DWORD time_begin;
DWORD time_end;
int time_low, time_high;
JUNK_CODE_FOUR
JUNK_CODE_THREE
time_begin = ::GetTickCount();
JUNK_CODE_TWO
JUNK_CODE_THREE
time_low = ::GetTickCount();
JUNK_CODE_ONE
JUNK_CODE_ONE
JUNK_CODE_ONE
time_high = ::GetTickCount();
JUNK_CODE_FIVE
for (int i=0;i<200;++i) {
time_low += time_high;
time_low -= i;
}
JUNK_CODE_ONE
__asm
{
rdtsc
mov time_low,eax
mov time_high,edx
}
for (int i=0;i<200;++i) {
time_low -= time_high;
JUNK_CODE_ONE
time_low += i;
}
JUNK_CODE_ONE
JUNK_CODE_ONE
time_end = GetTickCount();
__asm
{
nop
nop
nop
nop
nop
nop
nop
nop
}
__try
{
__asm {
int 2dh
inc eax ;any opcode of singlebyte.
JUNK_CODE_FIVE
}
}
__except(1)
{
JUNK_CODE_THREE
JUNK_CODE_ONE
// ãÐÖµÉèΪ13Ãë°É£¬·ÀÖ¹»úÆ÷ͻȻ¿¨ËÀµÈÎÊÌâ
if (time_end>=time_begin&&(time_end-time_begin < 13000)) {
return FALSE;
}
}
return TRUE;
}
class CDM9 : public CCheckThread
{
virtual UINT on_execute()
{
try {
if (TimeChecker()) {
test_out("cdm 9 check debug!\n");
under_debug_ = TRUE;
return -90000;
}
} catch (...) {
}
under_debug_ = FALSE;
return 900;
}
};
/
/
/
BOOL FTPushSSPopSS()
{
__asm
{
push ebp
mov ebp, esp
push ss
pop ss
pushf
pop eax
and eax, 0x100
or eax, eax
jnz _debugged
xor eax, eax
jmp _end
_debugged:
mov eax, 1
_end:
mov esp,ebp
pop ebp
}
}
class CDM10 : public CCheckThread
{
virtual UINT on_execute()
{
try {
if (FTPushSSPopSS()) {
test_out("cdm 10 check debug!\n");
under_debug_ = TRUE;
return -100000;
}
} catch (...) {
}
under_debug_ = FALSE;
return 1000;
}
};
/
/
/
// The IsDbgPresentPrefixCheck works in at least two debuggers
// OllyDBG and VS 2008, by utilizing the way the debuggers handle
// prefixes we can determine their presence. Specifically if this code
// is ran under a debugger it will simply be stepped over;
// however, if there is no debugger SEH will fire :D
BOOL IsDbgPresentPrefixCheck()
{
__try
{
__asm __emit 0xF3 // 0xF3 0x64 disassembles as PREFIX REP:
__asm __emit 0x64
__asm __emit 0xF1 // One byte INT 1
}
__except(1)
{
return FALSE;
}
return TRUE;
}
class CDM11 : public CCheckThread
{
virtual UINT on_execute()
{
try {
if (IsDbgPresentPrefixCheck()) {
test_out("cdm 11 check debug!\n");
under_debug_ = TRUE;
return -110000;
}
} catch (...) {
}
under_debug_ = FALSE;
return 1100;
}
};
/
/
/
// Ö±½ÓÍ£Ö¹µ÷ÊÔ
BOOL DisableDebugEvent()
{
// ¹Ø±Õµ÷ÊԶ˿Ú
typedef DWORD (WINAPI *ZW_SET_INFORMATION_THREAD)(HANDLE, DWORD, PVOID, ULONG);
static const DWORD ThreadHideFromDebugger = 17;
HMODULE module = ::GetModuleHandle(_T("NtDll"));
if (module)
{
ZW_SET_INFORMATION_THREAD ZwSetInformationThread_;
ZwSetInformationThread_ = (ZW_SET_INFORMATION_THREAD)GetProcAddress(module, "ZwSetInformationThread");
if (ZwSetInformationThread_)
{
(*ZwSetInformationThread_)(GetCurrentThread(), ThreadHideFromDebugger, 0, 0);
}
}
return TRUE;
}
class CDM12 : public CCheckThread
{
virtual UINT on_execute()
{
try {
if (DisableDebugEvent()) {
test_out("cdm 12 check debug!\n");
under_debug_ = TRUE;
return -120000;
}
} catch (...) {
}
under_debug_ = FALSE;
return 1200;
}
};
/
/
/
#ifdef _ANTIDEBUG
VOID NTAPI test_PIMAGE_TLS_CALLBACK(PVOID DllHandle, DWORD Reason, PVOID Reserved)
{
#if 0
IMAGE_DOS_HEADER *dos_head=(IMAGE_DOS_HEADER *)GetModuleHandle(NULL);
PIMAGE_NT_HEADERS32 nt_head=(PIMAGE_NT_HEADERS32)((DWORD)dos_head+(DWORD)dos_head->e_lfanew);
BYTE*OEP=(BYTE*)(nt_head->OptionalHeader.AddressOfEntryPoint+(DWORD)dos_head);
//ÏÂÃæµÄ´úÂëÔòͨ¹ýɨÃè³ÌÐòÈë¿ÚµãµÄ20×Ö½Ú£¬ÅжÏÆäÖÐÓÐÎÞµ÷ÊԶϵ㣬ÈçÓУ¬ÔòÍ˳ö½ø³Ì¡£
for(unsigned long index=0;index<20;index++)
{
if (OEP[index]==0xcc) {
ExitProcess(0);
}
}
#endif
DisableDebugEvent();
return;
}
#pragma comment(linker, "/INCLUDE:__tls_used")
#pragma data_seg(".CRT$XLB")
PIMAGE_TLS_CALLBACK TlsCallBackArray[] = {
test_PIMAGE_TLS_CALLBACK,
NULL
};
#pragma data_seg()
#endif
///
///
///
///
///
///
///
///
///
///
///
///
///
// case ºê
#define CREATE_THREAD(x) case x: thread_ = new CDM##x; break
class AntiThread : public CThread
{
// µ±Ç°¼ì²âÏß³Ì
CCheckThread* thread_;
DWORD update_tick_;
DWORD thread_count_;
BOOL under_debug_;
HANDLE last_handle_;
int last_thread_idx_;
public:
AntiThread() :
thread_(NULL),
update_tick_(0),
thread_count_(0),
last_thread_idx_(0),
last_handle_(INVALID_HANDLE_VALUE)
{}
int get_last_thread_idx() {
return last_thread_idx_;
}
DWORD get_update_tick() {
return update_tick_;
}
BOOL is_under_debug()
{
DWORD now = ::GetTickCount();
if (now>update_tick_&&(now-update_tick_>1200000)) {
printf("---time update!\n");
return TRUE;
}
//if (under_debug_) {
// printf("---in debug(%d)!\n", last_thread_idx_);
//} else {
// printf("ok!\n");
//}
return under_debug_;
}
virtual UINT on_execute()
{
while (!terminated_)
{
update_tick_ = ::GetTickCount();
JUNK_CODE_ONE
// ´´½¨Ò»¸öÏß³Ì
last_thread_idx_ = rand() % 11 + 1;
//printf("thread = %d!\n", last_thread_idx_);
JUNK_CODE_THREE
switch (last_thread_idx_) {
default:
CREATE_THREAD(1);
CREATE_THREAD(2);
CREATE_THREAD(3);
CREATE_THREAD(4);
CREATE_THREAD(5);
CREATE_THREAD(6);
CREATE_THREAD(7);
CREATE_THREAD(8);
CREATE_THREAD(9);
CREATE_THREAD(10);
CREATE_THREAD(11);
}
if (!thread_) {
continue;
}
//char temp[30];
//sprintf(temp, "%d", last_thread_idx_);
//MessageBox(NULL, temp, "asdfdsafa", MB_OK);
test_out("select = %d .", last_thread_idx_);
thread_->start_thread();
++thread_count_;
// µÈ´ý¼ì²âÏß³ÌÊÇ·ñ½áÊø
while (!terminated_) {
if (thread_->is_valid()&&WAIT_TIMEOUT == thread_->wait_for(50)) {
continue;
} else {
break;
}
}
JUNK_CODE_ONE
JUNK_CODE_ONE
// ÔÚµ÷ÊÔÖÐ
under_debug_ |= thread_->under_debug();
JUNK_CODE_ONE
JUNK_CODE_TWO
JUNK_CODE_ONE
// ¼Ç¼×îºóÒ»´Î¾ä±ú
last_handle_ = thread_->get_handle();
JUNK_CODE_THREE
JUNK_CODE_ONE
// µÃµ½Ïß³ÌÍ˳öÖµ
DWORD last_code = 0;
if (::GetExitCodeThread(last_handle_, &last_code))
{
if ((int)last_code<-10000)
{
JUNK_CODE_THREE
under_debug_ = TRUE;
}
}
JUNK_CODE_FIVE
// ɾ³ý
delete thread_;
thread_ = NULL;
// ÐÝÏ¢
//#ifdef _DEBUG
// int s_time = rand() % 20 + 100;
//#else
// int s_time = rand() % 60000 + 30000;
//#endif
int s_time = 200;
// ÐÝÏ¢Ò»»á£¬È»ºó½øÐÐÏÂÒ»´Î¼ì²â
JUNK_CODE_TWO
JUNK_CODE_ONE
for (int i=0;i<s_time/100;++i) {
Sleep(100);
if (terminated_) {
break;
}
}
}
return 0;
}
};
AntiThread* global_thread = NULL;
// ¿ªÊ¼·´µ÷ÊÔ¼ì²â
bool start_anti_debug()
{
#ifdef _ANTIDEBUG
srand((unsigned int)time(NULL));
// ¿ªÆôÒ»¸öºǫ́³ÌÐò£¬²»Ê±´´½¨·´µ÷ÊÔỊ̈߳¬Ã»´´½¨Ò»¸öÔö¼ÓÒ»¸ö¼ÆÊý
global_thread = new AntiThread;
global_thread->start_thread();
#endif
return true;
}
// Í£Ö¹·´µ÷ÊÔ¼ì²â
bool stop_anti_debug()
{
#ifdef _ANTIDEBUG
if (global_thread) {
global_thread->stop_thread();
delete global_thread;
global_thread = NULL;
}
#endif
return false;
}
// ÊÇ·ñÔÚµ÷ÊÔÖÐ
bool is_under_debug()
{
#ifdef _ANTIDEBUG
if (global_thread) {
return global_thread->is_under_debug() ? true : false;
}
#endif
return false;
}
bool test_under_debug()
{
return false;
#ifdef _ANTIDEBUG
CCheckThread* thread_ = NULL;
int last_thread_idx_ = rand() % 10 + 1;
//printf("thread = %d!\n", last_thread_idx_);
JUNK_CODE_THREE
switch (last_thread_idx_) {
default:
CREATE_THREAD(1);
CREATE_THREAD(2);
CREATE_THREAD(3);
CREATE_THREAD(4);
CREATE_THREAD(5);
CREATE_THREAD(6);
CREATE_THREAD(7);
CREATE_THREAD(8);
CREATE_THREAD(9);
CREATE_THREAD(10);
}
if (!thread_) {
return false;
}
thread_->start_thread();
if (WAIT_TIMEOUT == thread_->wait_for(200))
{
if (thread_->is_valid()) {
thread_->stop_thread(0);
return false;
}
}
BOOL under_debug_ = thread_->under_debug();
delete thread_;
return under_debug_ ? true : false;
#endif
return false;
}