早些时间看郁金香的教程,写过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; }