Online Judge新增安全防护——API Hook:在Windows,64位系统调试OK。
参见:https://gitee.com/jungle/online-judge/tree/master/judger-kernel/code/product/hook
直接上代码了:/* Online judge 最重要的安全防护技术: API-HOOK */ #include#include #include #include #include #include #pragma comment(lib,"ws2_32") #define BOOL_OK 1 #define BOOL_ERR 1 typedef struct { LPCSTR szCalleeModName; LPCSTR oldFuncName; PROC newFuncAddr; PROC oldFuncAddr; } API_FUNC_ID; int APIHOOK_TRACE(char *szFuncName) { //printf("API Hook:%s.\r\n",szFuncName); return 0; } /* 进程线程相关 */ HANDLE WINAPI MyGetCurrentProcess( VOID ) { APIHOOK_TRACE("GetCurrentProcess"); return 0; } WINBOOL WINAPI MyCreateProcess(LPCTSTR lApplicationName, LPTSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCTSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation ) { APIHOOK_TRACE("CreateProcess"); return 0; } HANDLE WINAPI MyCreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ) { APIHOOK_TRACE("CreateThread"); return 0; } /* 文件相关 */ HANDLE WINAPI MyCreateFileA( LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { APIHOOK_TRACE("CreateFileA"); return 0; } HANDLE WINAPI MyCreateFileW( LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { APIHOOK_TRACE("CreateFileW"); return 0; } WINBOOL WINAPI MyDeleteFileA(LPCSTR lpFileName) { APIHOOK_TRACE("DeleteFileA"); return 0; } WINBOOL WINAPI MyDeleteFileW(LPCSTR lpFileName) { APIHOOK_TRACE("DeleteFileW"); return 0; } /* CMD相关 */ UINT WINAPI MyShellExecuteA(HWND hwnd, LPCSTR lpOperation, LPCSTR lpFile, LPCSTR lpParameters, LPCSTR lpDirectory, INT nShowCmd) { APIHOOK_TRACE("ShellExecuteA"); return 0; } UINT WINAPI MyShellExecuteW(HWND hwnd, LPCSTR lpOperation, LPCSTR lpFile, LPCSTR lpParameters, LPCSTR lpDirectory, INT nShowCmd) { APIHOOK_TRACE("ShellExecuteW"); return 0; } UINT WINAPI MyWinExec(LPCSTR lpCmdLine, UINT uCmdShow) { APIHOOK_TRACE("WinExec"); return 0; } /* 窗口相关 */ int WINAPI MyMessageBoxA(HWND hWnd , LPCSTR lpText, LPCSTR lpCaption, UINT uType) { APIHOOK_TRACE("MessageBoxA"); return 0; } int WINAPI MyMessageBoxW(HWND hWnd , LPCSTR lpText, LPCSTR lpCaption, UINT uType) { APIHOOK_TRACE("MessageBoxW"); return 0; } /* Socket相关 */ int WSAAPI MyWSAStartup(WORD wVersionRequired, LPWSADATA lpWSAData) { APIHOOK_TRACE("WSAStartup"); return WSAStartup(wVersionRequired, lpWSAData); } WINBOOL WINAPI Myaccept(SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen) { APIHOOK_TRACE("accept"); return 0; } WINBOOL WINAPI Mysocket(int af, int type, int protocol) { APIHOOK_TRACE("socket"); return 0; } DWORD WINAPI MyGetCurrentProcessId(void) { APIHOOK_TRACE("GetCurrentProcessId"); return 0; } WINBOOL WINAPI MyTerminateProcess (HANDLE hProcess, UINT uExitCode) { APIHOOK_TRACE("TerminateProcess"); return 0; } HANDLE WINAPI MyOpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId) { APIHOOK_TRACE("OpenProcess"); return NULL; } #define MakePtr(cast, ptr, AddValue) (cast)((size_t)(ptr)+(size_t)(AddValue)) static PIMAGE_IMPORT_DESCRIPTOR GetNamedImportDescriptor(HMODULE hModule, LPCSTR szImportModule) { PIMAGE_DOS_HEADER pDOSHeader; PIMAGE_NT_HEADERS pNTHeader; PIMAGE_IMPORT_DESCRIPTOR pImportDesc; if ((szImportModule == NULL) || (hModule == NULL)) return NULL; pDOSHeader = (PIMAGE_DOS_HEADER) hModule; if (IsBadReadPtr(pDOSHeader, sizeof(IMAGE_DOS_HEADER)) || (pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE)) { return NULL; } pNTHeader = MakePtr(PIMAGE_NT_HEADERS, pDOSHeader, pDOSHeader->e_lfanew); if (IsBadReadPtr(pNTHeader, sizeof(IMAGE_NT_HEADERS)) || (pNTHeader->Signature != IMAGE_NT_SIGNATURE)) return NULL; if (pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress == 0) return NULL; pImportDesc = MakePtr(PIMAGE_IMPORT_DESCRIPTOR, pDOSHeader, pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); while (pImportDesc->Name) { PSTR szCurrMod = MakePtr(PSTR, pDOSHeader, pImportDesc->Name); if (_stricmp(szCurrMod, szImportModule) == 0) break; pImportDesc++; } if (pImportDesc->Name == (DWORD)0) return NULL; return pImportDesc; } static BOOL IsNT() { OSVERSIONINFO stOSVI; BOOL bRet; memset(&stOSVI, 0, sizeof(OSVERSIONINFO)); stOSVI.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); bRet = GetVersionEx(&stOSVI); if (FALSE == bRet) return FALSE; return (VER_PLATFORM_WIN32_NT == stOSVI.dwPlatformId); } static BOOL HookImportFunction(HMODULE hModule, LPCSTR szImportModule, LPCSTR szFunc, PROC paHookFuncs, PROC* paOrigFuncs) { PIMAGE_IMPORT_DESCRIPTOR pImportDesc; PIMAGE_THUNK_DATA pOrigThunk; PIMAGE_THUNK_DATA pRealThunk; if (!IsNT() && ((size_t)hModule >= 0x80000000)) return FALSE; pImportDesc = GetNamedImportDescriptor(hModule, szImportModule); if (pImportDesc == NULL) return FALSE; pOrigThunk = MakePtr(PIMAGE_THUNK_DATA, hModule, pImportDesc->OriginalFirstThunk); pRealThunk = MakePtr(PIMAGE_THUNK_DATA, hModule, pImportDesc->FirstThunk); while (pOrigThunk->u1.Function) { if (IMAGE_ORDINAL_FLAG != (pOrigThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG)) { PIMAGE_IMPORT_BY_NAME pByName = MakePtr(PIMAGE_IMPORT_BY_NAME, hModule, pOrigThunk->u1.AddressOfData); BOOL bDoHook; // When hook EditPlus, read pByName->Name[0] will case this dll terminate, so call IsBadReadPtr() here. if (IsBadReadPtr(pByName, sizeof(IMAGE_IMPORT_BY_NAME))) { pOrigThunk++; pRealThunk++; continue; } if ('\0' == pByName->Name[0]) { pOrigThunk++; pRealThunk++; continue; } bDoHook = FALSE; if ((szFunc[0] == pByName->Name[0]) && (_strcmpi(szFunc, (char*)pByName->Name) == 0)) { if (paHookFuncs) bDoHook = TRUE; } if (bDoHook) { MEMORY_BASIC_INFORMATION mbi_thunk; DWORD dwOldProtect; VirtualQuery(pRealThunk, &mbi_thunk, sizeof(MEMORY_BASIC_INFORMATION)); VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize, PAGE_READWRITE, &mbi_thunk.Protect); if (paOrigFuncs) *paOrigFuncs = (PROC)pRealThunk->u1.Function; pRealThunk->u1.Function = (DWORD)paHookFuncs; VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize, mbi_thunk.Protect, &dwOldProtect); return TRUE; } } pOrigThunk++; pRealThunk++; } return FALSE; } BOOL HookAPI(LPCSTR szImportModule, LPCSTR szFunc, PROC paHookFuncs, PROC* paOrigFuncs) { HANDLE hSnapshot; MODULEENTRY32 me = {sizeof(MODULEENTRY32)}; BOOL bOk; if ((szImportModule == NULL) || (szFunc == NULL) || (paHookFuncs == NULL)) { return FALSE; } //printf("szImportModule=%s, szFunc=%s, paHookFuncs=0x%x\r\n", szImportModule, szFunc, paHookFuncs); hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,0); bOk = Module32First(hSnapshot,&me); while (bOk) { HookImportFunction(me.hModule, szImportModule, szFunc, paHookFuncs, paOrigFuncs); bOk = Module32Next(hSnapshot,&me); } return TRUE; } API_FUNC_ID MANDATORY_API_FUNCS[] = { {"Kernel32.dll", (LPCSTR)"OpenProcess", (PROC)MyOpenProcess, NULL}, {"Kernel32.dll", (LPCSTR)"GetCurrentProcess", (PROC)MyGetCurrentProcess, NULL}, {"Kernel32.dll", (LPCSTR)"CreateProcess", (PROC)MyCreateProcess, NULL}, //{"Kernel32.dll", (LPCSTR)"CreateThread", (PROC)MyCreateThread, NULL}, Ruby //{"Kernel32.dll", (LPCSTR)"GetCurrentProcessId", (PROC)MyGetCurrentProcessId, NULL}, java //{"Kernel32.dll", (LPCSTR)"CreateFileA", (PROC)MyCreateFileA, NULL}, java {"Kernel32.dll", (LPCSTR)"CreateFileW", (PROC)MyCreateFileW, NULL}, {"Kernel32.dll", (LPCSTR)"DeleteFileA", (PROC)MyDeleteFileA, NULL}, {"Kernel32.dll", (LPCSTR)"DeleteFileW", (PROC)MyDeleteFileW, NULL}, {"Kernel32.dll", (LPCSTR)"TerminateProcess", (PROC)MyTerminateProcess, NULL}, {"Kernel32.dll", (LPCSTR)"WinExec", (PROC)MyWinExec, NULL}, {"shell32.dll", (LPCSTR)"ShellExecuteA", (PROC)MyShellExecuteA, NULL}, {"shell32.dll", (LPCSTR)"ShellExecuteW", (PROC)MyShellExecuteW, NULL}, {"User32.dll", (LPCSTR)"MessageBoxA", (PROC)MyMessageBoxA, NULL}, {"User32.dll", (LPCSTR)"MessageBoxW", (PROC)MyMessageBoxW, NULL}, //{"Ws2_32.dll", (LPCSTR)"WSAStartup", (PROC)MyWSAStartup, NULL}, Ruby {"Ws2_32.dll", (LPCSTR)"accept", (PROC)Myaccept, NULL}, {"Ws2_32.dll", (LPCSTR)"socket", (PROC)Mysocket, NULL}, }; VOID DLL_InstallHook() { int iLoop = 0; int num = sizeof(MANDATORY_API_FUNCS)/sizeof(API_FUNC_ID); for (iLoop = 0; iLoop < num; ++iLoop) { (VOID)HookAPI(MANDATORY_API_FUNCS[iLoop].szCalleeModName, MANDATORY_API_FUNCS[iLoop].oldFuncName, (PROC)MANDATORY_API_FUNCS[iLoop].newFuncAddr, &MANDATORY_API_FUNCS[iLoop].oldFuncAddr); } } VOID DLL_UnstallHook() { int iLoop = 0; int num = sizeof(MANDATORY_API_FUNCS)/sizeof(API_FUNC_ID); for (iLoop = 0; iLoop < num; ++iLoop) { (VOID)HookAPI(MANDATORY_API_FUNCS[iLoop].szCalleeModName, MANDATORY_API_FUNCS[iLoop].oldFuncName, MANDATORY_API_FUNCS[iLoop].oldFuncAddr, NULL); } } extern "C" bool WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: DLL_InstallHook(); break; case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: break; case DLL_PROCESS_DETACH: DLL_UnstallHook(); break; } return TRUE; }
/* 注入: Add For API HOOK, 2013-05-18 */ /* 全局APIKooh标记 */ ULONG ulNeedApiHookFlag = OS_TRUE; char szApiHookDllPath[MAX_PATH] = "hook.dll"; int EnableDebugPriv(const char * name) { HANDLE hToken; TOKEN_PRIVILEGES tp; LUID luid; //打开进程令牌环 if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &hToken) ) { write_log(JUDGE_ERROR,"OpenProcessToken error\n"); return 1; } //获得进程本地唯一ID if(!LookupPrivilegeValue(NULL,name,&luid)) { write_log(JUDGE_ERROR,"LookupPrivilege error!\n"); } tp.PrivilegeCount = 1; tp.Privileges[0].Attributes =SE_PRIVILEGE_ENABLED; tp.Privileges[0].Luid = luid; //调整进程权限 if(!AdjustTokenPrivileges(hToken,0,&tp,sizeof(TOKEN_PRIVILEGES),NULL,NULL) ) { write_log(JUDGE_ERROR,"AdjustTokenPrivileges error!\n"); return 1; } return 0; } BOOL InjectAPIHookDll(DWORD dwProcessID, char* dllPath) { FARPROC FuncAddr = NULL; if( (_access(dllPath, 0 )) == -1 ) { write_log(JUDGE_ERROR,"InjectAPIHookDll failed, the file %s is not exist.", dllPath); return FALSE; } if(EnableDebugPriv(SE_DEBUG_NAME)) { write_log(JUDGE_ERROR,"add privilege error %u", GetLastError()); return FALSE; } HMODULE hdll = LoadLibrary(TEXT("Kernel32.dll")); if (hdll != NULL) { FuncAddr = GetProcAddress(hdll, "LoadLibraryA"); if (FuncAddr == NULL) { write_log(JUDGE_ERROR,"GetProcAddress error %u", GetLastError()); return FALSE; } } HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessID); if (hProcess == NULL) { write_log(JUDGE_ERROR,"OpenProcess error %u", GetLastError()); return FALSE; } DWORD dwSize = strlen(dllPath) + 1; LPVOID RemoteBuf = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE); if (NULL == RemoteBuf) { write_log(JUDGE_ERROR,"VirtualAllocEx error %u", GetLastError()); return FALSE; } DWORD dwRealSize; if (WriteProcessMemory(hProcess, RemoteBuf, dllPath, dwSize, &dwRealSize)) { HANDLE hRemoteThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)FuncAddr, RemoteBuf, 0, NULL); if (hRemoteThread == NULL) { VirtualFreeEx(hProcess, RemoteBuf, dwSize, MEM_COMMIT); CloseHandle(hProcess); write_log(JUDGE_ERROR,"CreateRemoteThread error %u", GetLastError()); return FALSE; } /* 释放资源 */ WaitForSingleObject(hRemoteThread, INFINITE); CloseHandle(hRemoteThread); VirtualFreeEx(hProcess, RemoteBuf, dwSize, MEM_COMMIT); CloseHandle(hProcess); return TRUE; } else { write_log(JUDGE_ERROR,"WriteProcessMemory error %u", GetLastError()); VirtualFreeEx(hProcess, RemoteBuf, dwSize, MEM_COMMIT); CloseHandle(hProcess); return FALSE; } } unsigned _stdcall Judge_RunProgramThread(void *pData) { /* cmd/c solution.exedata.out 2>error.txt */ /* ChildIn_Write是子进程的输入句柄,ChildIn_Read是父进程用于写入子进程输入的句柄 */ HANDLE ChildIn_Read, ChildIn_Write; /*ChildOut_Write是子进程的输出句柄,ChildOut_Read是父进程用于读取子进程输出的句柄*/ HANDLE ChildOut_Read, ChildOut_Write; SECURITY_ATTRIBUTES saAttr = {0}; JUDGE_SUBMISSION_ST *pstJudgeSubmission = (JUDGE_SUBMISSION_ST *)pData; if (NULL == pstJudgeSubmission) { write_log(JUDGE_ERROR,"Judge_RunProgramThread ERROR, pstJudgeSubmission is NULL...."); return 0; } saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.bInheritHandle = TRUE; saAttr.lpSecurityDescriptor = NULL; if(! CreatePipe(&ChildIn_Read, &ChildIn_Write, &saAttr, 0)) { write_log(JUDGE_ERROR,"Judge_RunProgramThread ERROR, input CreatePipe failed...."); return 0; } SetHandleInformation(ChildIn_Write, HANDLE_FLAG_INHERIT, 0); if(! CreatePipe(&ChildOut_Read, &ChildOut_Write, &saAttr, 0)) { write_log(JUDGE_ERROR,"Judge_RunProgramThread ERROR, output CreatePipe failed...."); CloseHandle(ChildIn_Read); CloseHandle(ChildIn_Write); return 0; } SetHandleInformation(ChildOut_Read, HANDLE_FLAG_INHERIT, 0); SetErrorMode(SEM_NOGPFAULTERRORBOX ); STARTUPINFO StartupInfo = {0}; StartupInfo.cb = sizeof(STARTUPINFO); // StartupInfo.hStdError = h_ErrorFile; StartupInfo.hStdOutput = ChildOut_Write; StartupInfo.hStdInput = ChildIn_Read; StartupInfo.dwFlags |= STARTF_USESTDHANDLES; write_log(JUDGE_INFO,"CreateProcess(%s)", pstJudgeSubmission->runCmd); /* |CREATE_NEW_CONSOLE */ if(CreateProcess(NULL, pstJudgeSubmission->runCmd, NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, NULL, &StartupInfo, &pstJudgeSubmission->pProRunInfo)) { Judge_DisableAllPriv(pstJudgeSubmission->pProRunInfo.hProcess); write_log(JUDGE_INFO,"CreateProcess ok..."); /* Begin add for apihook 2013/05/18 */ if (OS_TRUE == ulNeedApiHookFlag) { if (FALSE == InjectAPIHookDll(pstJudgeSubmission->pProRunInfo.dwProcessId, szApiHookDllPath)) { write_log(JUDGE_ERROR,"InjectAPIHookDll Error, dwProcessId[%u]", pstJudgeSubmission->pProRunInfo.dwProcessId); } else { write_log(JUDGE_INFO,"InjectAPIHookDll OK, dwProcessId[%u]", pstJudgeSubmission->pProRunInfo.dwProcessId); } } /* End add for apihook 2013/05/18 */ ResumeThread(pstJudgeSubmission->pProRunInfo.hThread); CloseHandle(pstJudgeSubmission->pProRunInfo.hThread); write_log(JUDGE_INFO,"CreateFile inFileName(%s)", pstJudgeSubmission->inFileName); pstJudgeSubmission->hInputFile = CreateFile(pstJudgeSubmission->inFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_READONLY, NULL); if (pstJudgeSubmission->hInputFile <= 0) { write_log(JUDGE_ERROR,"CreateFile inFileName(%s) Error:%d", pstJudgeSubmission->inFileName, GetLastError()); } BOOL flag = FALSE; while (true) { char buffer[BUFSIZE] = {0}; DWORD BytesRead, BytesWritten; flag = ReadFile(pstJudgeSubmission->hInputFile, buffer, BUFSIZE, &BytesRead, NULL); if (!flag || (BytesRead == 0)) break; flag = WriteFile(ChildIn_Write, buffer, BytesRead, &BytesWritten, NULL); if (!flag){ break;} } CloseHandle(pstJudgeSubmission->hInputFile);pstJudgeSubmission->hInputFile=NULL; CloseHandle(ChildIn_Write);ChildIn_Write=NULL; CloseHandle(ChildOut_Write);ChildOut_Write=NULL; write_log(JUDGE_INFO,"CreateFile outFileName(%s)", pstJudgeSubmission->outFileName); /* 读取子进程的标准输出,并将其传递给文件输出 */ pstJudgeSubmission->hOutputFile= CreateFile(pstJudgeSubmission->outFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (NULL == pstJudgeSubmission->hOutputFile) { write_log(JUDGE_ERROR,"CreateFile outFileName(%s) Error:%d", pstJudgeSubmission->outFileName, GetLastError()); } pstJudgeSubmission->startt = clock(); DWORD limit_output =0; while (true) { char buffer[BUFSIZE] = {0}; DWORD BytesRead, BytesWritten; flag = ReadFile(ChildOut_Read, buffer, BUFSIZE, &BytesRead, NULL); if (!flag || (BytesRead == 0)) { write_log(JUDGE_INFO,"ReadFile over."); break; } //write_log(JUDGE_INFO,"ReadFile over. buffer=%s", buffer); flag = WriteFile(pstJudgeSubmission->hOutputFile, buffer, BytesRead, &BytesWritten, NULL); if (!flag) { write_log(JUDGE_ERROR,"WriteFile error."); break; } limit_output+=BytesWritten; if(limit_output>OutputLimit) { write_log(JUDGE_INFO,"OLE"); pstJudgeSubmission->stSolution.verdictId = V_OLE; break; } } pstJudgeSubmission->endt = clock(); CloseHandle(ChildIn_Read);ChildIn_Read=NULL; CloseHandle(ChildOut_Read);ChildOut_Read=NULL; CloseHandle(pstJudgeSubmission->hOutputFile);pstJudgeSubmission->hOutputFile=NULL; write_log(JUDGE_INFO,"Judge_RunProgramThread test OK..inFileName(%s)",pstJudgeSubmission->inFileName); return 1; } else { write_log(JUDGE_SYSTEM_ERROR,"CreateProcess [Error:%d]\n",GetLastError()); } pstJudgeSubmission->stSolution.verdictId = V_SE; if (ChildIn_Read == NULL) CloseHandle(ChildIn_Read); if (ChildIn_Write == NULL) CloseHandle(ChildIn_Write); if (ChildOut_Read == NULL) CloseHandle(ChildOut_Read); if (ChildOut_Write == NULL) CloseHandle(ChildOut_Write); return 0; }