/* Copyright (C) 1996-1997 Id Software, Inc. 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. */ // sys_win.h #include "quakedef.h" #include "winquake.h" #include "resource.h" #include "errno.h" #include "fcntl.h" #include #define MINIMUM_WIN_MEMORY 0x1000000 #define MAXIMUM_WIN_MEMORY 0x4000000 #define PAUSE_SLEEP 50 // sleep time on pause or minimization #define NOT_FOCUS_SLEEP 20 // sleep time when not focus int starttime; qboolean ActiveApp, Minimized; qboolean WinNT; HWND hwnd_dialog; // startup dialog box static double pfreq; static double curtime = 0.0; static double lastcurtime = 0.0; static int lowshift; static HANDLE hinput, houtput; HANDLE qwclsemaphore; static HANDLE tevent; void Sys_InitFloatTime (void); void MaskExceptions (void); void Sys_PopFPCW (void); void Sys_PushFPCW_SetHigh (void); void Sys_DebugLog(char *file, char *fmt, ...) { va_list argptr; static char data[1024]; int fd; va_start(argptr, fmt); vsprintf(data, fmt, argptr); va_end(argptr); fd = open(file, O_WRONLY | O_CREAT | O_APPEND, 0666); write(fd, data, strlen(data)); close(fd); }; /* =============================================================================== FILE IO =============================================================================== */ /* ================ filelength ================ */ int filelength (FILE *f) { int pos; int end; pos = ftell (f); fseek (f, 0, SEEK_END); end = ftell (f); fseek (f, pos, SEEK_SET); return end; } int Sys_FileTime (char *path) { FILE *f; int t, retval; t = VID_ForceUnlockedAndReturnState (); f = fopen(path, "rb"); if (f) { fclose(f); retval = 1; } else { retval = -1; } VID_ForceLockState (t); return retval; } void Sys_mkdir (char *path) { _mkdir (path); } /* =============================================================================== SYSTEM IO =============================================================================== */ /* ================ Sys_MakeCodeWriteable ================ */ void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length) { DWORD flOldProtect; //@@@ copy on write or just read-write? if (!VirtualProtect((LPVOID)startaddr, length, PAGE_READWRITE, &flOldProtect)) Sys_Error("Protection change failed\n"); } /* ================ Sys_Init ================ */ void Sys_Init (void) { LARGE_INTEGER PerformanceFreq; unsigned int lowpart, highpart; OSVERSIONINFO vinfo; #ifndef SERVERONLY // allocate a named semaphore on the client so the // front end can tell if it is alive // mutex will fail if semephore allready exists qwclsemaphore = CreateMutex( NULL, /* Security attributes */ 0, /* owner */ "qwcl"); /* Semaphore name */ if (!qwclsemaphore) Sys_Error ("QWCL is already running on this system"); CloseHandle (qwclsemaphore); qwclsemaphore = CreateSemaphore( NULL, /* Security attributes */ 0, /* Initial count */ 1, /* Maximum count */ "qwcl"); /* Semaphore name */ #endif MaskExceptions (); Sys_SetFPCW (); #if 0 if (!QueryPerformanceFrequency (&PerformanceFreq)) Sys_Error ("No hardware timer available"); // get 32 out of the 64 time bits such that we have around // 1 microsecond resolution lowpart = (unsigned int)PerformanceFreq.LowPart; highpart = (unsigned int)PerformanceFreq.HighPart; lowshift = 0; while (highpart || (lowpart > 2000000.0)) { lowshift++; lowpart >>= 1; lowpart |= (highpart & 1) << 31; highpart >>= 1; } pfreq = 1.0 / (double)lowpart; Sys_InitFloatTime (); #endif // make sure the timer is high precision, otherwise // NT gets 18ms resolution timeBeginPeriod( 1 ); vinfo.dwOSVersionInfoSize = sizeof(vinfo); if (!GetVersionEx (&vinfo)) Sys_Error ("Couldn't get OS info"); if ((vinfo.dwMajorVersion < 4) || (vinfo.dwPlatformId == VER_PLATFORM_WIN32s)) { Sys_Error ("QuakeWorld requires at least Win95 or NT 4.0"); } if (vinfo.dwPlatformId == VER_PLATFORM_WIN32_NT) WinNT = true; else WinNT = false; } void Sys_Error (char *error, ...) { va_list argptr; char text[1024], text2[1024]; DWORD dummy; Host_Shutdown (); va_start (argptr, error); vsprintf (text, error, argptr); va_end (argptr); MessageBox(NULL, text, "Error", 0 /* MB_OK */ ); #ifndef SERVERONLY CloseHandle (qwclsemaphore); #endif exit (1); } void Sys_Printf (char *fmt, ...) { va_list argptr; char text[1024]; DWORD dummy; va_start (argptr,fmt); vprintf (fmt, argptr); va_end (argptr); } void Sys_Quit (void) { VID_ForceUnlockedAndReturnState (); Host_Shutdown(); #ifndef SERVERONLY if (tevent) CloseHandle (tevent); if (qwclsemaphore) CloseHandle (qwclsemaphore); #endif exit (0); } #if 0 /* ================ Sys_DoubleTime ================ */ double Sys_DoubleTime (void) { static int sametimecount; static unsigned int oldtime; static int first = 1; LARGE_INTEGER PerformanceCount; unsigned int temp, t2; double time; Sys_PushFPCW_SetHigh (); QueryPerformanceCounter (&PerformanceCount); temp = ((unsigned int)PerformanceCount.LowPart >> lowshift) | ((unsigned int)PerformanceCount.HighPart << (32 - lowshift)); if (first) { oldtime = temp; first = 0; } else { // check for turnover or backward time if ((temp <= oldtime) && ((oldtime - temp) < 0x10000000)) { oldtime = temp; // so we can't get stuck } else { t2 = temp - oldtime; time = (double)t2 * pfreq; oldtime = temp; curtime += time; if (curtime == lastcurtime) { sametimecount++; if (sametimecount > 100000) { curtime += 1.0; sametimecount = 0; } } else { sametimecount = 0; } lastcurtime = curtime; } } Sys_PopFPCW (); return curtime; } /* ================ Sys_InitFloatTime ================ */ void Sys_InitFloatTime (void) { int j; Sys_DoubleTime (); j = COM_CheckParm("-starttime"); if (j) { curtime = (double) (Q_atof(com_argv[j+1])); } else { curtime = 0.0; } lastcurtime = curtime; } #endif double Sys_DoubleTime (void) { static DWORD starttime; static qboolean first = true; DWORD now; double t; now = timeGetTime(); if (first) { first = false; starttime = now; return 0.0; } if (now < starttime) // wrapped? return (now / 1000.0) + (LONG_MAX - starttime / 1000.0); if (now - starttime == 0) return 0.0; return (now - starttime) / 1000.0; } char *Sys_ConsoleInput (void) { static char text[256]; static int len; INPUT_RECORD recs[1024]; int count; int i, dummy; int ch, numread, numevents; HANDLE th; char *clipText, *textCopied; for ( ;; ) { if (!GetNumberOfConsoleInputEvents (hinput, &numevents)) Sys_Error ("Error getting # of console events"); if (numevents <= 0) break; if (!ReadConsoleInput(hinput, recs, 1, &numread)) Sys_Error ("Error reading console input"); if (numread != 1) Sys_Error ("Couldn't read console input"); if (recs[0].EventType == KEY_EVENT) { if (!recs[0].Event.KeyEvent.bKeyDown) { ch = recs[0].Event.KeyEvent.uChar.AsciiChar; switch (ch) { case '\r': WriteFile(houtput, "\r\n", 2, &dummy, NULL); if (len) { text[len] = 0; len = 0; return text; } break; case '\b': WriteFile(houtput, "\b \b", 3, &dummy, NULL); if (len) { len--; putch('\b'); } break; default: Con_Printf("Stupid: %d\n", recs[0].Event.KeyEvent.dwControlKeyState); if (((ch=='V' || ch=='v') && (recs[0].Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))) || ((recs[0].Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) && (recs[0].Event.KeyEvent.wVirtualKeyCode ==VK_INSERT))) { if (OpenClipboard(NULL)) { th = GetClipboardData(CF_TEXT); if (th) { clipText = GlobalLock(th); if (clipText) { textCopied = malloc(GlobalSize(th)+1); strcpy(textCopied, clipText); /* Substitutes a NULL for every token */strtok(textCopied, "\n\r\b"); i = strlen(textCopied); if (i+len>=256) i=256-len; if (i>0) { textCopied[i]=0; text[len]=0; strcat(text, textCopied); len+=dummy; WriteFile(houtput, textCopied, i, &dummy, NULL); } free(textCopied); } GlobalUnlock(th); } CloseClipboard(); } } else if (ch >= ' ') { WriteFile(houtput, &ch, 1, &dummy, NULL); text[len] = ch; len = (len + 1) & 0xff; } break; } } } } return NULL; } void Sys_Sleep (void) { } void Sys_SendKeyEvents (void) { MSG msg; while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)) { // we always update if there are any event, even if we're paused scr_skipupdate = 0; if (!GetMessage (&msg, NULL, 0, 0)) Sys_Quit (); TranslateMessage (&msg); DispatchMessage (&msg); } } /* ============================================================================== WINDOWS CRAP ============================================================================== */ /* ================== WinMain ================== */ void SleepUntilInput (int time) { MsgWaitForMultipleObjects(1, &tevent, FALSE, time, QS_ALLINPUT); } /* ================== WinMain ================== */ HINSTANCE global_hInstance; int global_nCmdShow; char *argv[MAX_NUM_ARGVS]; static char *empty_string = ""; HWND hwnd_dialog; // Cyt0plas - Activation #include "flact.h" //#include "wk.h" #include #include #include #include qboolean is_activated = false; extern cvar_t bsphack; // Cyt0plas - anti-debugging __inline qboolean IsBPX_v2(void * address) { _asm { mov esi,address mov al,[esi] mov ah,0x66 // loads ah with 66h (half CCh) add ah,ah // add it to itself, it results to 0xCC, and check cmp ah,al je BPXed xor eax,eax // no breakpoint jmp NOBPX BPXed: mov eax,1 // breakpoint found NOBPX: } } // Cyt0plas - dongle #if 0 qboolean dongle_ok; #if defined(_WIN32) #define EXPORT #else #define EXPORT __export #endif // definitions for the sample #define FIRM_CODE 10 // sample Firm Code #define USER_CODE 65535 // sample User Code #define DRV_VERSION 3 // major driver version number (required) #define DRV_SUBVERSION 1 // minor driver version number (required) #define IS_ENCRYPTED // flag "will be encrypted by (WK)CRYPT" #define USE_ERRMSG // flag "show error message window" #define APPNAME "CheatWorld" // structure that holds all important WIBU-KEY informations typedef struct { LONG lFirmCode; // FirmCode to use LONG lUserCode; // UserCode to use ULONG ulSelection; // SelectionCode to use WKBSELECT wkbsel; // Selection informations HWKBENTRY hwkbe; // handle of opened WIBU-BOX entry HWKBSYSTEM hwkbsys; // handle of used subsystem INT nVersion; // Version number as integer TCHAR szVersion[10]; // Version number as string BOOL fSysDrv; // flag "using kernel driver" BOOL fCheckRunning; // flag "CheckBox is running" } WIBUKEYDATA; // prefix "wkdata" // prototypes for the WIBU-BOX access BOOL OpenBox(WIBUKEYDATA *pwkdata); BOOL CheckBox(WIBUKEYDATA *pwkdata); BOOL CloseBox(WIBUKEYDATA *pwkdata); // window functions BOOL EXPORT CALLBACK AboutDlgProc (HWND, UINT, UINT, LONG); BOOL EXPORT CALLBACK MainDlgProc (HWND, UINT, UINT, LONG); // global variables WIBUKEYDATA wibudata; HINSTANCE hThisInstance; VOID PrintWkError(const TCHAR *pszFunction) { #ifdef USE_ERRMSG INT nErr; TCHAR szMsg[200]; TCHAR szError[100]; ULONG flCtrl; sprintf(szMsg, "Error: Function = %s()", pszFunction); // read the error text from the wkwin(32).dll flCtrl = WKB_STDCTRL|WKB_QI_ERRTEXT; nErr = WkbQueryInfo2 (HWKB_LOCAL, flCtrl, szError, 100); sprintf(szMsg + strlen(szMsg), "\n%s", szError); // print the whole text in a message box. //Sys_Error(szMsg); dongle_ok = false; #endif } // PrintWkError() /***************************************************************************** R e a d P g m C o d e ============================================================================== This function reads the expected Firm and User Code of the program and sets these values into global variables. A message displays the expected values at screen. Parameters pwkdata points to the global WIBU-KEY data *****************************************************************************/ VOID ReadPgmCode(WIBUKEYDATA *pwkdata) { #ifdef IS_ENCRYPTED // read Firm and User Code from program code INT idError; idError = WkbGetFC(&(pwkdata->lFirmCode), 0); /* if (idError == WKB_ERROR_NOT_CRYPTIC) { Sys_Error("Program is not encrypted by CRYPT 1.32 or higher."); exit(255); } // if*/ WkbGetUC(&(pwkdata->lUserCode), 0); #else pwkdata->lFirmCode = FIRM_CODE; pwkdata->lUserCode = USER_CODE; #endif } // ReadPgmCode() // OpenBox Function BOOL OpenBox(WIBUKEYDATA *pwkdata) { ULONG ulVersion, ulSubVersion; USHORT usMinDrvVersion; ULONG flCtrl; WKBSTATUS wkbst; TCHAR szMsg[250]; // initialize the whole structure with 0. memset(pwkdata, 0, sizeof(WIBUKEYDATA)); // NOTE: version checking and querying status is not needed for an application. // We do it here only to show how it works. If you always install the latest // driver files with your application you don“t need to check the version. // determine version of API pwkdata->nVersion = WkbGetVersion3(HWKB_LOCAL); // calculate the minimal version of the driver which should be set usMinDrvVersion = 256 * DRV_VERSION + DRV_SUBVERSION; // set the version string ulVersion = pwkdata->nVersion / 256; ulSubVersion = pwkdata->nVersion % 256; wsprintf((LPSTR)pwkdata->szVersion, "%lu.%s%lu", ulVersion, (ulSubVersion < 10) ? (LPSTR)"0" : (LPSTR)"", ulSubVersion); // compare version to needed version if (pwkdata->nVersion < usMinDrvVersion) { // print warning wsprintf(szMsg, "Program needs WIBU-KEY API Version %d.%02d or higher!\n", DRV_VERSION, DRV_SUBVERSION); Sys_Error(szMsg); } // if // determine driver type flCtrl = WKB_STDCTRL|WKB_QST_DRIVER; WkbQueryStatus2(HWKB_LOCAL, flCtrl, &wkbst, sizeof(WKBSTATUS)); if (wkbst.usFlags & WKB_ST_KRNL) { pwkdata->fSysDrv = TRUE; } else { pwkdata->fSysDrv = FALSE; } // if pwkdata->hwkbe = NULL; pwkdata->hwkbsys = NULL; pwkdata->fCheckRunning = FALSE; // read Firm Code and User Code ReadPgmCode(pwkdata); // search & open WIBU-BOX entry of accessed WIBU-KEY subsystem // NOTE: Using WKB_VERSION_STD automatically selects the highest // possible algorithm for the found box flCtrl = WKB_STDCTRL|WKB_OPEN_FIND|WKB_VERSION_STD; pwkdata->hwkbe = WkbOpen2( HWKB_LOCAL, // handle to local system flCtrl, // control flags (use best version, find entry) NULL, // ports (NULL for all available ports) pwkdata->lFirmCode, // Firm Code pwkdata->lUserCode, // User Code NULL // no optional data ); if (!pwkdata->hwkbe) { PrintWkError("WkbOpen2"); return FALSE; } // if return TRUE;; } // OpenBox() // Cyt0plas - End Dongle #endif // Cyt0plas - anti-debugging HANDLE (WINAPI *IsDebug)(VOID); int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { MSG msg; quakeparms_t parms; double time, oldtime, newtime; MEMORYSTATUS lpBuffer; static char cwd[1024]; int t; RECT rect; // Cyt0plas - ANTI-Debugging HANDLE softice; HINSTANCE hwn; qboolean dbg; void *addr; // Cyt0plas - Activation int Res, Payload, Mode; char HardwareHashString[15]; // Cyt0plas - Dongle #if 0 dongle_ok = true; if (!OpenBox(&wibudata)) dongle_ok = false; #endif // Cyt0plas - anti-debugging hwn = LoadLibrary("KERNEL32.DLL"); if (hwn == NULL) { MessageBox(NULL,"Error loading Kernel32.dll","Debug",MB_OK|MB_ICONSTOP); ExitProcess(0); } IsDebug = (HANDLE (WINAPI *)(void))GetProcAddress(hwn,"IsDebuggerPresent"); dbg = ( IsDebug() || (CreateFile("\\.\\NTICE",GENERIC_WRITE,FILE_SHARE_READ,(LPSECURITY_ATTRIBUTES)NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,(HANDLE)NULL) != INVALID_HANDLE_VALUE) || (CreateFile("\\.\\SICE",GENERIC_WRITE,FILE_SHARE_READ,(LPSECURITY_ATTRIBUTES)NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,(HANDLE)NULL) != INVALID_HANDLE_VALUE) ); // Check the API hooks addr = MessageBox; dbg = dbg || IsBPX_v2(addr); /* previous instances do not exist in Win32 */ if (hPrevInstance) return 0; // Cyt0plas - Activation __FLInitContext(hInstance, &__FLContext); Res = FLCheckActivation("000000D5", &Payload); if (dbg) { // If there is a debugger, don't activate! is_activated = false; } else if ((Res == FL_NO_ERROR)) { // || dongle_ok) { // Yeah, this is bad. I'm not too worried about crackers, though. is_activated = (Res == FL_NO_ERROR);// || dongle_ok; bsphack.value = 1; } else { if (MessageBox(NULL, "This client is not activated. Without Activation, many advanced\nfeatures will not be enabled. Would you like to activate now?", "Not Activated", MB_YESNO | MB_SETFOREGROUND | MB_ICONEXCLAMATION) == IDYES) { // Step 1 Res = FLWinStep1("000000D5", &Mode); if (Res != FL_NO_ERROR) { MessageBox(NULL, FLErrorString(Res), "Activation Step 1", 0); return 0; } // Step 2 Res = FLWinStep2("000000D5", HardwareHashString, Mode); if (Res != FL_NO_ERROR) { MessageBox(NULL, FLErrorString(Res), "Activation Step 2", 0); return 0; } // Step 3 Res = FLWinStep3("000000D5", &Payload, HardwareHashString, Mode); if (Res != FL_NO_ERROR) { MessageBox(NULL, FLErrorString(Res), "Activation Step 3", 0); return 0; } // If we made it this far, we have been successfully activated. // Make it slightly harder for crackers is_activated = (Res == FL_NO_ERROR);// || dongle_ok; } } global_hInstance = hInstance; global_nCmdShow = nCmdShow; lpBuffer.dwLength = sizeof(MEMORYSTATUS); GlobalMemoryStatus (&lpBuffer); if (!GetCurrentDirectory (sizeof(cwd), cwd)) Sys_Error ("Couldn't determine current directory"); if (cwd[Q_strlen(cwd)-1] == '/') cwd[Q_strlen(cwd)-1] = 0; parms.basedir = cwd; parms.cachedir = NULL; parms.argc = 1; argv[0] = empty_string; while (*lpCmdLine && (parms.argc < MAX_NUM_ARGVS)) { while (*lpCmdLine && ((*lpCmdLine <= 32) || (*lpCmdLine > 126))) lpCmdLine++; if (*lpCmdLine) { argv[parms.argc] = lpCmdLine; parms.argc++; while (*lpCmdLine && ((*lpCmdLine > 32) && (*lpCmdLine <= 126))) lpCmdLine++; if (*lpCmdLine) { *lpCmdLine = 0; lpCmdLine++; } } } parms.argv = argv; COM_InitArgv (parms.argc, parms.argv); parms.argc = com_argc; parms.argv = com_argv; hwnd_dialog = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_DIALOG0), NULL, NULL); if (hwnd_dialog) { if (GetWindowRect (hwnd_dialog, &rect)) { if (rect.left > (rect.top * 2)) { SetWindowPos (hwnd_dialog, 0, (rect.left / 2) - ((rect.right - rect.left) / 2), rect.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE); } } ShowWindow (hwnd_dialog, SW_SHOWDEFAULT); UpdateWindow (hwnd_dialog); SetForegroundWindow (hwnd_dialog); } // take the greater of all the available memory or half the total memory, // but at least 8 Mb and no more than 16 Mb, unless they explicitly // request otherwise parms.memsize = lpBuffer.dwAvailPhys; if (parms.memsize < MINIMUM_WIN_MEMORY) parms.memsize = MINIMUM_WIN_MEMORY; if (parms.memsize < (lpBuffer.dwTotalPhys >> 1)) parms.memsize = lpBuffer.dwTotalPhys >> 1; if (parms.memsize > MAXIMUM_WIN_MEMORY) parms.memsize = MAXIMUM_WIN_MEMORY; if (COM_CheckParm ("-heapsize")) { t = COM_CheckParm("-heapsize") + 1; if (t < com_argc) parms.memsize = Q_atoi (com_argv[t]) * 1024; } parms.membase = malloc (parms.memsize); if (!parms.membase) Sys_Error ("Not enough memory free; check disk space\n"); tevent = CreateEvent(NULL, FALSE, FALSE, NULL); if (!tevent) Sys_Error ("Couldn't create event"); Sys_Init (); // because sound is off until we become active S_BlockSound (); Sys_Printf ("Host_Init\n"); Host_Init (&parms); oldtime = Sys_DoubleTime (); /* main window message loop */ while (1) { // yield the CPU for a little while when paused, minimized, or not the focus if ((cl.paused && (!ActiveApp && !DDActive)) || Minimized || block_drawing) { SleepUntilInput (PAUSE_SLEEP); scr_skipupdate = 1; // no point in bothering to draw } else if (!ActiveApp && !DDActive) { SleepUntilInput (NOT_FOCUS_SLEEP); } newtime = Sys_DoubleTime (); time = newtime - oldtime; Host_Frame (time); oldtime = newtime; } /* return success of application */ return TRUE; }