www.pudn.com > remote_thread.zip > spec_apis.cpp
/* Remote Run Library
Copyright (C) 2001, Sting Feng(冯越)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
The author of this program may be contacted at fenny@163.net. */
#include
#include
#include "ntthread.h"
#include "RemoteRunLib.h"
#include "spec_apis.h"
#include "log.h"
#ifdef _DEBUG
#define TRACE(s) ::OutputDebugString(s);
#define EXIT_TIME_OUT 5000//INFINITE
#else
#define TRACE(s)
#define EXIT_TIME_OUT 3000
#endif // _DEBUG
//-----------------------------------------------------
// 对这些API做特殊处理
//-----------------------------------------------------
DETOUR_TRAMPOLINE(VOID WINAPI Real_ExitProcess(UINT uExitCode),ExitProcess);
DETOUR_TRAMPOLINE(HANDLE WINAPI Real_CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,DWORD dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId),CreateThread);
DETOUR_TRAMPOLINE(VOID WINAPI Real_ExitThread(DWORD dwExitCode),ExitThread);
DETOUR_TRAMPOLINE(LONG WINAPI Real_UnhandledExceptionFilter(_EXCEPTION_POINTERS *ExceptionInfo),UnhandledExceptionFilter);
DETOUR_TRAMPOLINE(HMODULE WINAPI Real_LoadLibraryExW(LPCWSTR lpFileName,HANDLE hFile,DWORD dwFlags),LoadLibraryExW);
DETOUR_TRAMPOLINE(BOOL WINAPI Real_FreeLibrary(HMODULE hModule),FreeLibrary);
DETOUR_TRAMPOLINE(HMODULE WINAPI Real_GetModuleHandleA(LPCSTR lpModuleName), GetModuleHandleA);
DETOUR_TRAMPOLINE(HMODULE WINAPI Real_GetModuleHandleW(LPCWSTR lpModuleName), GetModuleHandleW);
DETOUR_TRAMPOLINE(HGLOBAL WINAPI Real_LoadResource(HMODULE hModule,HRSRC hResInfo), LoadResource);
DETOUR_TRAMPOLINE(HRSRC WINAPI Real_FindResourceExA(HMODULE hModule,LPCSTR lpType,LPCSTR lpName,WORD wLanguage),FindResourceExA);
DETOUR_TRAMPOLINE(HRSRC WINAPI Real_FindResourceExW(HMODULE hModule,LPCWSTR lpType,LPCWSTR lpName,WORD wLanguage),FindResourceExW);
DETOUR_TRAMPOLINE(BOOL WINAPI Real_EnumResourceLanguagesA(HMODULE hModule,LPCSTR lpType,LPCSTR lpName,ENUMRESLANGPROCA lpEnumFunc,LONG_PTR lParam),EnumResourceLanguagesA);
DETOUR_TRAMPOLINE(BOOL WINAPI Real_EnumResourceLanguagesW(HMODULE hModule,LPCWSTR lpType,LPCWSTR lpName,ENUMRESLANGPROCW lpEnumFunc,LONG_PTR lParam),EnumResourceLanguagesW);
DETOUR_TRAMPOLINE(BOOL WINAPI Real_EnumResourceNamesA(HMODULE hModule,LPCSTR lpszType,ENUMRESNAMEPROCA lpEnumFunc,LONG_PTR lParam),EnumResourceNamesA);
DETOUR_TRAMPOLINE(BOOL WINAPI Real_EnumResourceNamesW(HMODULE hModule,LPCWSTR lpszType,ENUMRESNAMEPROCW lpEnumFunc,LONG_PTR lParam),EnumResourceNamesW);
DETOUR_TRAMPOLINE(BOOL WINAPI Real_EnumResourceTypesA(HMODULE hModule,ENUMRESTYPEPROCA lpEnumFunc,LONG_PTR lParam),EnumResourceTypesA);
DETOUR_TRAMPOLINE(BOOL WINAPI Real_EnumResourceTypesW(HMODULE hModule,ENUMRESTYPEPROCW lpEnumFunc,LONG_PTR lParam),EnumResourceTypesW);
DETOUR_TRAMPOLINE(DWORD WINAPI Real_GetModuleFileNameA(HMODULE hModule,LPSTR lpFilename,DWORD nSize),GetModuleFileNameA);
DETOUR_TRAMPOLINE(DWORD WINAPI Real_GetModuleFileNameW(HMODULE hModule,LPWSTR lpFilename,DWORD nSize),GetModuleFileNameW);
void WINAPI RmRaiseException()
{
::RaiseException( SE_KILLTHREAD, 0, 0, NULL );
}
void SafeKillThread( DWORD tid, BOOL fPostQuitMsg )
{
if( tid == ::GetCurrentThreadId() )
return;
HANDLE h = NtThread::NtOpenThread( THREAD_ALL_ACCESS, FALSE, tid, ::GetCurrentProcessId() );
if( h != NULL )
{
//-------------------------------
// 试图让线程自己退出,如果不行,
// 让线程抛出异常
//-------------------------------
if( fPostQuitMsg )
{
::PostThreadMessage( tid, WM_QUIT, 0, 0 );
if( ::WaitForSingleObject( h, EXIT_TIME_OUT ) != WAIT_TIMEOUT )
{
::CloseHandle( h );
return;
}
}
//-------------------------------
// 抛出异常
//-------------------------------
SuspendThread( h );
CONTEXT context;
context.ContextFlags = CONTEXT_CONTROL;
GetThreadContext( h, &context );
//-----------------------------------------------
// 让主线程调用ExitProcess,这样主线程会终止属于
// 该exe的所有子线程
//-----------------------------------------------
context.Eip = (DWORD)RmRaiseException;
SetThreadContext( h, &context );
ResumeThread( h );
WaitForSingleObject( h, INFINITE );
CloseHandle( h );
}
}
//-----------------------------------------------------
// 不让exe把我们的异常(SE_KILLTHREAD),当成未处理异常,
// 这个异常将被RealRun捕获
//-----------------------------------------------------
static LONG WINAPI Mine_UnhandledExceptionFilter(_EXCEPTION_POINTERS *ExceptionInfo)
{
if( ExceptionInfo->ExceptionRecord->ExceptionCode == SE_KILLTHREAD )
return EXCEPTION_CONTINUE_SEARCH;
return Real_UnhandledExceptionFilter( ExceptionInfo );
}
static DWORD KillAllChildThread( DWORD tid )
{
int i, c;
CRemoteRunLib *lib = CRemoteRunLib::Instance();
int index = lib->FindEXEIndex( tid );
if( index == -1 )
return 0;
lib->Lock();
vector& threadList = lib->GetEXEInfoByIndex( index )->ThreadList;
//--------------------------------------------
// 遍历线程列表,如果还有线程活着,终止他
// 除了本线程和exe的主线程
//--------------------------------------------
DWORD pid = ::GetCurrentProcessId();
c = threadList.size();
//---------------------
// 保留exe的主线程
//---------------------
DWORD dwMainThreadId = threadList[0];
for( i = 1; i < c; i++)
{
if( threadList[i] != 0 && threadList[i] != tid )
{
HANDLE h = NtThread::NtOpenThread( SYNCHRONIZE | THREAD_TERMINATE,
FALSE,
threadList[i],
pid );
if( h != NULL )
{
//------------------------------------------------
// 试图让线程自己终止自己,如果不行就强行终止
//------------------------------------------------
::PostThreadMessage( threadList[i], WM_QUIT, 0, 0 );
if( ::WaitForSingleObject( h, 1000 ) == WAIT_TIMEOUT )
::TerminateThread( h, -1 );
::CloseHandle( h );
}
}
}
//------------------------------------------------
// 从模块信息列表中删除该exe信息
//------------------------------------------------
CRemoteRunLib::UnregisterEXE( index );
lib->Unlock();
return dwMainThreadId;
}
//-------------------------------------------------
// 进程即将结束,释放所有资源
//-------------------------------------------------
static VOID WINAPI Mine_ExitProcess(UINT uExitCode)
{
PrintLog( "Process exiting...\n" );
int i, c;
DWORD tid = ::GetCurrentThreadId();
DWORD dwMainThreadId = 0;
CRemoteRunLib *lib = CRemoteRunLib::Instance();
lib->Lock();
int index = lib->FindEXEIndex( tid );
//----------------------------------------------------
// 如果这是加载remote.dll的线程或者这是进程的主线程,
// 则先让exe的主线程退出
//----------------------------------------------------
if( index == -1 )
{
//----------------------------------------
// 增加remote.dll使用计数,禁止卸载
//----------------------------------------
CRemoteRunLib::AddRef();
//---------------------------------------
// 先保存一份主线程ID列表
// 确保加载remote.dll的线程最后退出
//---------------------------------------
vector mainThreadList;
lib->GetMainThreadList( mainThreadList );
//----------------------------------------
// 先解锁,让其他线程处理
//----------------------------------------
lib->Unlock();
//---------------------------------------
// 依次在主线程中抛出异常
//---------------------------------------
c = mainThreadList.size();
for( i = c-1; i >= 0; i-- )
{
// KillAllChildThread( mainThreadList[i] );
SafeKillThread( mainThreadList[i], TRUE );
}
//---------------------------------------
// 让CRemoteRunLib::UnloadLibrary调用
// ExitProcess退出进程
//---------------------------------------
lib->SetExitProcessFlag();
//---------------------------------------
// 释放资源
//---------------------------------------
CRemoteRunLib::Release();
//---------------------------------------------
// 退出进程。事实上程序永远不会执行到这里
//---------------------------------------------
Real_ExitProcess(uExitCode);
return; // 程序不会走到这里了
}
//-----------------------------------------------------
// 终止列表中所有线程,并从exe信息列表中删除该exe信息
//-----------------------------------------------------
dwMainThreadId = KillAllChildThread( tid );
lib->Unlock();
if( dwMainThreadId == tid )
{
//------------------------------------------------
// 抛出一个异常。这个异常会被RealRun捕捉
//------------------------------------------------
RmRaiseException();
}
else
{
//--------------------------------------------
// 优雅的终止主线程
//--------------------------------------------
SafeKillThread( dwMainThreadId, FALSE );
//--------------------------------------------
// 退出线程
//--------------------------------------------
Real_ExitThread( -1 );
}
}
static HANDLE WINAPI Mine_CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,DWORD dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId)
{
DWORD tid;
HANDLE hThread = Real_CreateThread(lpThreadAttributes,dwStackSize,lpStartAddress,lpParameter,dwCreationFlags,&tid);
if( hThread != NULL )
{
PrintLog( "Thread Created:%d\n", tid );
if( lpThreadId != NULL ) *lpThreadId = tid;
//------------------------------
// 把新线程加入到列表
//------------------------------
CRemoteRunLib::Instance()->AddThread( tid );
}
return hThread;
}
static VOID WINAPI Mine_ExitThread(DWORD dwExitCode)
{
DWORD tid = ::GetCurrentThreadId();
PrintLog( "Thread Removed:%d\n", tid );
//----------------------------------
// 从列表中删除该线程
//----------------------------------
CRemoteRunLib::Instance()->RemoveThread( tid );
Real_ExitThread(dwExitCode);
}
//----------------------------------------------------------------
// 在以下函数中,如果以缺省参数调用,我们要做特殊处理
//----------------------------------------------------------------
static HMODULE WINAPI Mine_GetModuleHandleA(LPCSTR lpModuleName)
{
HMODULE hInstance;
if( lpModuleName == NULL &&
(hInstance = CRemoteRunLib::Instance()->FindEXEHandle( ::GetCurrentThreadId() ) ) != NULL )
return hInstance;
return Real_GetModuleHandleA(lpModuleName);
}
static HMODULE WINAPI Mine_GetModuleHandleW(LPCWSTR lpModuleName)
{
HMODULE hInstance;
if( lpModuleName == NULL &&
(hInstance = CRemoteRunLib::Instance()->FindEXEHandle( ::GetCurrentThreadId() ) ) != NULL )
return hInstance;
return Real_GetModuleHandleW(lpModuleName);
}
static inline HMODULE GetRealHandle( HMODULE hModule )
{
CRemoteRunLib *lib = CRemoteRunLib::Instance();
if( hModule == lib->GetMainEXEHandle() || hModule == NULL )
{
return lib->FindEXEHandle( ::GetCurrentThreadId() );
}
return hModule;
}
static HGLOBAL WINAPI Mine_LoadResource(HMODULE hModule,HRSRC hResInfo)
{
return Real_LoadResource( GetRealHandle(hModule), hResInfo );
}
static HRSRC WINAPI Mine_FindResourceExA(HMODULE hModule,LPCSTR lpType,LPCSTR lpName,WORD wLanguage)
{
return Real_FindResourceExA( GetRealHandle(hModule), lpType, lpName, wLanguage);
}
static HRSRC WINAPI Mine_FindResourceExW(HMODULE hModule,LPCWSTR lpType,LPCWSTR lpName,WORD wLanguage)
{
return Real_FindResourceExW( GetRealHandle(hModule), lpType, lpName, wLanguage);
}
static BOOL WINAPI Mine_EnumResourceLanguagesA(HMODULE hModule,LPCSTR lpType,LPCSTR lpName,ENUMRESLANGPROCA lpEnumFunc,LONG_PTR lParam)
{
return Real_EnumResourceLanguagesA(GetRealHandle(hModule),lpType,lpName,lpEnumFunc,lParam);
}
static BOOL WINAPI Mine_EnumResourceLanguagesW(HMODULE hModule,LPCWSTR lpType,LPCWSTR lpName,ENUMRESLANGPROCW lpEnumFunc,LONG_PTR lParam)
{
return Real_EnumResourceLanguagesW(GetRealHandle(hModule),lpType,lpName,lpEnumFunc,lParam);
}
static BOOL WINAPI Mine_EnumResourceNamesA(HMODULE hModule,LPCSTR lpszType,ENUMRESNAMEPROCA lpEnumFunc,LONG_PTR lParam)
{
return Real_EnumResourceNamesA(GetRealHandle(hModule),lpszType,lpEnumFunc,lParam);
}
static BOOL WINAPI Mine_EnumResourceNamesW(HMODULE hModule,LPCWSTR lpszType,ENUMRESNAMEPROCW lpEnumFunc,LONG_PTR lParam)
{
return Real_EnumResourceNamesW(GetRealHandle(hModule),lpszType,lpEnumFunc,lParam);
}
static BOOL WINAPI Mine_EnumResourceTypesA(HMODULE hModule,ENUMRESTYPEPROCA lpEnumFunc,LONG_PTR lParam)
{
return Real_EnumResourceTypesA(GetRealHandle(hModule),lpEnumFunc,lParam);
}
static BOOL WINAPI Mine_EnumResourceTypesW(HMODULE hModule,ENUMRESTYPEPROCW lpEnumFunc,LONG_PTR lParam)
{
return Real_EnumResourceTypesW(GetRealHandle(hModule),lpEnumFunc,lParam);
}
static DWORD WINAPI Mine_GetModuleFileNameA(HMODULE hModule,LPSTR lpFilename,DWORD nSize)
{
return Real_GetModuleFileNameA(GetRealHandle(hModule),lpFilename,nSize);
}
static DWORD WINAPI Mine_GetModuleFileNameW(HMODULE hModule,LPWSTR lpFilename,DWORD nSize)
{
DWORD tid;
CRemoteRunLib *lib = CRemoteRunLib::Instance();
//--------------------------------------------------------------
// 是不是后加载的remote.dll在寻找我们?
//--------------------------------------------------------------
if( hModule == (HMODULE)-1 && lpFilename == NULL && nSize == 0 )
return (DWORD)lib->GetLibHandle();
//-------------------------------------------
// 不是,照常处理
//-------------------------------------------
tid = ::GetCurrentThreadId();
CRemoteRunLib::PEXEINFO pExeInfo = lib->GetEXEInfoByIndex( lib->FindEXEIndex( tid ) );
if( pExeInfo != NULL )
{
if( hModule == NULL || hModule == pExeInfo->hInstance )
{
//-----------------------------
// 找到!!!
//-----------------------------
return ::MultiByteToWideChar( CP_ACP, 0,
pExeInfo->strExePath.c_str(), -1,
lpFilename, nSize );
}
}
return Real_GetModuleFileNameW(hModule,lpFilename,nSize);
}
//---------------------------------------------------------------------
// LoadLibrary和FreeLibrary只在Debug时处理,打印一些模块加载/卸载信息
//---------------------------------------------------------------------
static HMODULE WINAPI Mine_LoadLibraryExW(LPCWSTR lpFileName,HANDLE hFile,DWORD dwFlags)
{
#ifdef _DEBUG
if( lpFileName != NULL )
{
WCHAR szInfo[MAX_PATH+100];
wsprintfW( szInfo, L"Load Library: %s\n", lpFileName );
::OutputDebugStringW( szInfo );
}
#endif // _DEBUG
return Real_LoadLibraryExW(lpFileName,hFile,dwFlags);
}
static BOOL WINAPI Mine_FreeLibrary(HMODULE hModule)
{
#ifdef _DEBUG
WCHAR szLibPath[MAX_PATH];
if( Mine_GetModuleFileNameW( hModule, szLibPath, MAX_PATH ) != 0 )
{
WCHAR szInfo[MAX_PATH+100];
wsprintfW( szInfo, L"Free Library: %s\n", szLibPath );
::OutputDebugStringW( szInfo );
}
#endif // _DEBUG
return Real_FreeLibrary(hModule);
}
//----------------------------------------------------------
// 截获这些函数
//----------------------------------------------------------
static BOOL CALLBACK DetoursFunctions()
{
PrintLog( "Detouring some functions...\n" );
DetourFunctionWithTrampoline((PBYTE)Real_ExitProcess, (PBYTE)Mine_ExitProcess);
DetourFunctionWithTrampoline((PBYTE)Real_CreateThread, (PBYTE)Mine_CreateThread);
DetourFunctionWithTrampoline((PBYTE)Real_ExitThread, (PBYTE)Mine_ExitThread);
DetourFunctionWithTrampoline((PBYTE)Real_UnhandledExceptionFilter, (PBYTE)Mine_UnhandledExceptionFilter);
// DetourFunctionWithTrampoline((PBYTE)Real_LoadLibraryExW, (PBYTE)Mine_LoadLibraryExW);
// DetourFunctionWithTrampoline((PBYTE)Real_FreeLibrary, (PBYTE)Mine_FreeLibrary);
DetourFunctionWithTrampoline((PBYTE)Real_GetModuleHandleA, (PBYTE)Mine_GetModuleHandleA);
DetourFunctionWithTrampoline((PBYTE)Real_GetModuleHandleW, (PBYTE)Mine_GetModuleHandleW);
DetourFunctionWithTrampoline((PBYTE)Real_LoadResource, (PBYTE)Mine_LoadResource);
DetourFunctionWithTrampoline((PBYTE)Real_FindResourceExA, (PBYTE)Mine_FindResourceExA);
DetourFunctionWithTrampoline((PBYTE)Real_FindResourceExW, (PBYTE)Mine_FindResourceExW);
DetourFunctionWithTrampoline((PBYTE)Real_EnumResourceLanguagesA, (PBYTE)Mine_EnumResourceLanguagesA);
DetourFunctionWithTrampoline((PBYTE)Real_EnumResourceLanguagesW, (PBYTE)Mine_EnumResourceLanguagesW);
DetourFunctionWithTrampoline((PBYTE)Real_EnumResourceNamesA, (PBYTE)Mine_EnumResourceNamesA);
DetourFunctionWithTrampoline((PBYTE)Real_EnumResourceNamesW, (PBYTE)Mine_EnumResourceNamesW);
DetourFunctionWithTrampoline((PBYTE)Real_EnumResourceTypesA, (PBYTE)Mine_EnumResourceTypesA);
DetourFunctionWithTrampoline((PBYTE)Real_EnumResourceTypesW, (PBYTE)Mine_EnumResourceTypesW);
DetourFunctionWithTrampoline((PBYTE)Real_GetModuleFileNameA, (PBYTE)Mine_GetModuleFileNameA);
DetourFunctionWithTrampoline((PBYTE)Real_GetModuleFileNameW, (PBYTE)Mine_GetModuleFileNameW);
return TRUE;
}
static BOOL CALLBACK UndetoursFunctions()
{
PrintLog( "Undetouring some functions...\n" );
DetourRemove((PBYTE)Real_ExitProcess, (PBYTE)Mine_ExitProcess);
DetourRemove((PBYTE)Real_CreateThread, (PBYTE)Mine_CreateThread);
DetourRemove((PBYTE)Real_ExitThread, (PBYTE)Mine_ExitThread);
DetourRemove((PBYTE)Real_UnhandledExceptionFilter, (PBYTE)Mine_UnhandledExceptionFilter);
// DetourRemove((PBYTE)Real_LoadLibraryExW, (PBYTE)Mine_LoadLibraryExW);
// DetourRemove((PBYTE)Real_FreeLibrary, (PBYTE)Mine_FreeLibrary);
DetourRemove((PBYTE)Real_GetModuleHandleA, (PBYTE)Mine_GetModuleHandleA);
DetourRemove((PBYTE)Real_GetModuleHandleW, (PBYTE)Mine_GetModuleHandleW);
DetourRemove((PBYTE)Real_LoadResource, (PBYTE)Mine_LoadResource);
DetourRemove((PBYTE)Real_FindResourceExA, (PBYTE)Mine_FindResourceExA);
DetourRemove((PBYTE)Real_FindResourceExW, (PBYTE)Mine_FindResourceExW);
DetourRemove((PBYTE)Real_EnumResourceLanguagesA, (PBYTE)Mine_EnumResourceLanguagesA);
DetourRemove((PBYTE)Real_EnumResourceLanguagesW, (PBYTE)Mine_EnumResourceLanguagesW);
DetourRemove((PBYTE)Real_EnumResourceNamesA, (PBYTE)Mine_EnumResourceNamesA);
DetourRemove((PBYTE)Real_EnumResourceNamesW, (PBYTE)Mine_EnumResourceNamesW);
DetourRemove((PBYTE)Real_EnumResourceTypesA, (PBYTE)Mine_EnumResourceTypesA);
DetourRemove((PBYTE)Real_EnumResourceTypesW, (PBYTE)Mine_EnumResourceTypesW);
DetourRemove((PBYTE)Real_GetModuleFileNameA, (PBYTE)Mine_GetModuleFileNameA);
DetourRemove((PBYTE)Real_GetModuleFileNameW, (PBYTE)Mine_GetModuleFileNameW);
return TRUE;
}
//--------------------------------------------------------------------
// 在截获函数前,应该挂起其他线程,防止访问冲突
// 里面用到了两个未公开接口:NtOpenThread和NtQuerySystemInformation
//--------------------------------------------------------------------
static void SafeProcessAPIs( BOOL (WINAPI *fnCallBack)() )
{
DWORD i, count, processId, threadId;
if( fnCallBack == NULL )
return;
//-----------------------------------------------------------------------
// 假定进程里的线程不会超过1024个,这样处理比较简单。:)
//-----------------------------------------------------------------------
DWORD tid[1024];
HANDLE hThread[1024];
count = 1024;
processId = ::GetCurrentProcessId();
threadId = ::GetCurrentThreadId();
ZeroMemory( hThread, sizeof(hThread) );
__try {
//-----------------------------------------
// 枚举进程中所有线程ID
//-----------------------------------------
if( NtThread::EnumThread( processId, tid, &count ) )
{
//---------------------------------
// 挂起所有线程,当然,除了自己。
//---------------------------------
for( i = 0; i < count; i++)
{
if( threadId != tid[i] )
hThread[i] = NtThread::NtOpenThread( THREAD_SUSPEND_RESUME, FALSE, tid[i], processId );
if( hThread[i] != NULL )
::SuspendThread( hThread[i] );
}
//---------------------------------
// 截获必要的API
// Detours some functions
//---------------------------------
fnCallBack();
}
}__finally {
//----------------------------------
// 确保完事后激活所有线程
//----------------------------------
for( i = 0; i < count; i++)
{
if( hThread[i] != NULL )
::ResumeThread( hThread[i] );
}
}
}
BOOL InitializeHookAPIs()
{
//----------------------------------------------
// 对一些API做特殊处理
//----------------------------------------------
SafeProcessAPIs( DetoursFunctions );
return TRUE;
}
BOOL UninitializeHookAPIs()
{
SafeProcessAPIs( UndetoursFunctions );
return TRUE;
}