早些时间看郁金香的教程,写过qq游戏练练看的挂,那时候CE附加QQ游戏大厅的时候貌似是没有任何保护的,昨天舍友让做个斗地主的记牌器,但是,我用CE附加的时候,被检测到了,其实不附加也会被检测,所以猜测可能只是检测窗口进程或是模块名称啥的吧,被检测到的时候主程序会退出,但是那个对话框还在,就是那个SX什么什么的,所以如果是QQgame启动了某个线程来检测非法的话,在主程序退出其他线程对象都释放掉的时候,那个检测的线程对象还是存在的(提示SX非法的对话框别关掉!)。借助pt很容易就找到了这个线程。
未开CE前线程状态:
开了CE被检测到后的线程状态:
然后该怎么办就不用说了吧,干掉这个线程就OK了。
若是嫌麻烦每次都要开pt找线程的话,可以写个结束这个模块内线程的程序
#include "stdafx.h"
#include "windows.h"
#include "TlHelp32.h"
const TCHAR QQ_GAME[] = _T("QQGame.exe");
const TCHAR QQ_THREAD_DLL[] = _T("TenSLX.dll");
typedef enum _THREADINFOCLASS {
ThreadBasicInformation,
ThreadTimes,
ThreadPriority,
ThreadBasePriority,
ThreadAffinityMask,
ThreadImpersonationToken,
ThreadDescriptorTableEntry,
ThreadEnableAlignmentFaultFixup,
ThreadEventPair_Reusable,
ThreadQuerySetWin32StartAddress,
ThreadZeroTlsCell,
ThreadPerformanceCount,
ThreadAmILastThread,
ThreadIdealProcessor,
ThreadPriorityBoost,
ThreadSetTlsArrayAddress,
ThreadIsIoPending,
ThreadHideFromDebugger,
ThreadBreakOnTermination,
MaxThreadInfoClass
} THREADINFOCLASS;
typedef LONG (__stdcall *_pfnZwQueryInformationThread) (
IN HANDLE ThreadHandle,
IN THREADINFOCLASS ThreadInformationClass,
OUT PVOID ThreadInformation,
IN ULONG ThreadInformationLength,
OUT PULONG ReturnLength OPTIONAL
);
HANDLE m_GameProcessHandle;
//记录QQ_THREAD_DLL信息
BYTE * m_pmodBaseAddr;
DWORD m_dwmodBaseSize;
_pfnZwQueryInformationThread m_pfnZwQueryInformationThread;
BOOL StartPatch();//PATCHQQ主函数
DWORD EnablePrivilege (LPCTSTR name);//提权函数
BOOL ListProcessModules(DWORD dwPID);//枚举指定进程的模块
BOOL ListProcessThreads( DWORD dwOwnerPID);//枚举指定进程创建的线程,并结束掉QQ保护线程
PVOID ShowThreadInfo(DWORD tid);//获取线程的起始地址
int _tmain(int argc, _TCHAR* argv[])
{
m_pfnZwQueryInformationThread =(_pfnZwQueryInformationThread)\
GetProcAddress (LoadLibrary(_T("ntdll.dll")),"ZwQueryInformationThread");
if (StartPatch())
{
printf("可以CE附加QQ游戏大厅了\n");
}
else
printf("失败!\n");
return 0;
}
BOOL StartPatch()
{
if(0!=EnablePrivilege (SE_DEBUG_NAME))
{
return FALSE;
}
HANDLE hProcessSnap;
PROCESSENTRY32 pe32;
hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
if( hProcessSnap == INVALID_HANDLE_VALUE )
{
return FALSE;
}
pe32.dwSize = sizeof( PROCESSENTRY32 );
if( !Process32First( hProcessSnap, &pe32 ) )
{
CloseHandle( hProcessSnap );
return FALSE;
}
BOOL bStartGame = FALSE;
do
{
if (_tcscmp(pe32.szExeFile, QQ_GAME) == 0)
{
bStartGame = TRUE;
m_GameProcessHandle = OpenProcess(PROCESS_VM_WRITE|PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION,\
FALSE, pe32.th32ProcessID);
if (m_GameProcessHandle == NULL)
{
return FALSE;
}
for (int i=0; i<5;i++)
{
if (!ListProcessModules(pe32.th32ProcessID))
{
return FALSE;
}
}
if (!ListProcessThreads(pe32.th32ProcessID))
{
return FALSE;
}
}
} while( Process32Next( hProcessSnap, &pe32 ) );
if (!bStartGame)
{
MessageBox(NULL,_T("运行QQ大厅后才能使用"),_T("提示"),MB_OK);
return FALSE;
}
CloseHandle( hProcessSnap );
return TRUE;
}
DWORD EnablePrivilege (LPCTSTR name)
{
HANDLE hToken;
BOOL rv;
//设置结构
TOKEN_PRIVILEGES priv = { 1, {0, 0, SE_PRIVILEGE_ENABLED} };
// 查找权限值
LookupPrivilegeValue (
0,
name,
&priv.Privileges[0].Luid
);
// 打开本进程Token
OpenProcessToken(
GetCurrentProcess (),
TOKEN_ADJUST_PRIVILEGES,
&hToken
);
// 提权
AdjustTokenPrivileges (
hToken,
FALSE,
&priv,
sizeof priv,
0,
0
);
// 返回值,错误信息,如果操作成功,则应为ERROR_SUCCESS,为O
rv = GetLastError();
// 关闭Token
CloseHandle (hToken);
return rv;
}
BOOL ListProcessModules(DWORD dwPID)
{
HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
MODULEENTRY32 me32;
hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, dwPID );
if( hModuleSnap == INVALID_HANDLE_VALUE )
{
return( FALSE );
}
me32.dwSize = sizeof( MODULEENTRY32 );
if( !Module32First( hModuleSnap, &me32 ) )
{
CloseHandle( hModuleSnap );
return( FALSE );
}
do
{
if (_tcscmp(me32.szModule, QQ_THREAD_DLL) == 0)
{
m_pmodBaseAddr = me32.modBaseAddr;
m_dwmodBaseSize = me32.modBaseSize;
}
}while( Module32Next( hModuleSnap, &me32 ));
CloseHandle( hModuleSnap );
return( TRUE );
}
BOOL ListProcessThreads( DWORD dwOwnerPID)
{
HANDLE hThreadSnap = INVALID_HANDLE_VALUE;
THREADENTRY32 te32;
PVOID addr;
hThreadSnap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
if( hThreadSnap == INVALID_HANDLE_VALUE )
return( FALSE );
te32.dwSize = sizeof(THREADENTRY32 );
if( !Thread32First( hThreadSnap, &te32 ) )
{
CloseHandle( hThreadSnap );
return( FALSE );
}
do
{
if( te32.th32OwnerProcessID == dwOwnerPID )
{
addr = ShowThreadInfo(te32.th32ThreadID);
if(((DWORD)addr>(DWORD)m_pmodBaseAddr)&&((DWORD)addr<\
((DWORD)m_pmodBaseAddr+(DWORD)m_dwmodBaseSize)))
{
HANDLE oth=OpenThread(THREAD_ALL_ACCESS,FALSE,te32.th32ThreadID);
//关闭这个线程
TerminateThread(oth, 0);
}
}
} while( Thread32Next(hThreadSnap, &te32 ) );
CloseHandle( hThreadSnap );
return( TRUE );
}
PVOID ShowThreadInfo(DWORD tid)
{
PVOID startaddr;
HANDLE thread;
//thread = m_pfnOpenThread_ex(THREAD_ALL_ACCESS,FALSE,tid);
thread=OpenThread(THREAD_ALL_ACCESS,FALSE,tid);
if (thread == NULL)
return FALSE;
m_pfnZwQueryInformationThread(thread,
ThreadQuerySetWin32StartAddress,
&startaddr,
sizeof(startaddr),
NULL);
CloseHandle (thread);
return startaddr;
}