String& String::AppendString(CTSTR str, UINT count) { UINT strLength; if(!str) strLength = 0; else if(count) strLength = MIN(slen(str), count); else strLength = slen(str); if(!strLength) return *this; UINT oldLen = curLength; curLength += strLength; if(curLength) { lpString = (TSTR)ReAllocate(lpString, (curLength+1)*sizeof(TCHAR)); scpy_n(lpString+oldLen, str, strLength); } else { if(lpString) Free(lpString); lpString = NULL; } return *this; }
HFONT OBS::GetFont(CTSTR lpFontFace, int fontSize, int fontWeight) { for(UINT i=0; i<Fonts.Num(); i++) { if(Fonts[i].strFontFace.CompareI(lpFontFace) && Fonts[i].fontSize == fontSize && Fonts[i].fontWeight == fontWeight) return Fonts[i].hFont; } //--------------------- HFONT hFont = NULL; LOGFONT lf; zero(&lf, sizeof(lf)); scpy_n(lf.lfFaceName, lpFontFace, 31); lf.lfHeight = fontSize; lf.lfWeight = fontWeight; lf.lfQuality = ANTIALIASED_QUALITY; if(hFont = CreateFontIndirect(&lf)) { FontInfo &fi = *Fonts.CreateNew(); fi.hFont = hFont; fi.fontSize = fontSize; fi.fontWeight = fontWeight; fi.strFontFace = lpFontFace; } return hFont; }
OSFileChangeData * STDCALL OSMonitorFileStart(String path) { HANDLE hDirectory; OSFileChangeData *data = (OSFileChangeData *)Allocate(sizeof(*data)); String strDirectory = path; strDirectory.FindReplace(TEXT("\\"), TEXT("/")); strDirectory = GetPathDirectory(strDirectory); strDirectory.FindReplace(TEXT("/"), TEXT("\\")); strDirectory << TEXT("\\"); scpy_n (data->strDirectory, strDirectory.Array(), _countof(data->strDirectory)-1); hDirectory = CreateFile(data->strDirectory, FILE_LIST_DIRECTORY, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED, NULL); if(hDirectory != INVALID_HANDLE_VALUE) { DWORD test; zero(&data->directoryChange, sizeof(data->directoryChange)); data->directoryChange.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL); if(ReadDirectoryChangesW(hDirectory, data->changeBuffer, 2048, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE, &test, &data->directoryChange, NULL)) { scpy_n (data->targetFileName, path.Array(), _countof(data->targetFileName)-1); data->hDirectory = hDirectory; return data; } else { int err = GetLastError(); CloseHandle(data->directoryChange.hEvent); CloseHandle(hDirectory); Log(TEXT("OSMonitorFileStart: Unable to monitor file '%s', error %d"), path.Array(), err); Free(data); return NULL; } } else { int err = GetLastError(); Log(TEXT("OSMonitorFileStart: Unable to open directory '%s', error %d"), data->strDirectory, err); Free(data); return NULL; } }
BOOL CALLBACK EnumerateLoadedModulesProcInfo (PCTSTR ModuleName, DWORD64 ModuleBase, ULONG ModuleSize, PVOID UserContext) { moduleinfo_t *moduleInfo = (moduleinfo_t *)UserContext; if (moduleInfo->faultAddress >= ModuleBase && moduleInfo->faultAddress <= ModuleBase + ModuleSize) { scpy_n(moduleInfo->moduleName, ModuleName, _countof(moduleInfo->moduleName)-1); return FALSE; } return TRUE; }
BOOL STDCALL OSFileHasChanged (OSFileChangeData *data) { BOOL hasModified = FALSE; if(HasOverlappedIoCompleted(&data->directoryChange)) { FILE_NOTIFY_INFORMATION *notify = (FILE_NOTIFY_INFORMATION*)data->changeBuffer; for (;;) { if (notify->Action != FILE_ACTION_RENAMED_OLD_NAME && notify->Action != FILE_ACTION_REMOVED) { String strFileName; strFileName.SetLength(notify->FileNameLength); scpy_n(strFileName, notify->FileName, notify->FileNameLength/2); strFileName.KillSpaces(); String strFileChanged; strFileChanged << data->strDirectory << strFileName; if(strFileChanged.CompareI(data->targetFileName)) { hasModified = TRUE; break; } } if (!notify->NextEntryOffset) break; notify = (FILE_NOTIFY_INFORMATION*)((BYTE *)notify + notify->NextEntryOffset); } CloseHandle (data->directoryChange.hEvent); DWORD test; zero(&data->directoryChange, sizeof(data->directoryChange)); zero(data->changeBuffer, sizeof(data->changeBuffer)); data->directoryChange.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL); if(ReadDirectoryChangesW(data->hDirectory, data->changeBuffer, 2048, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE, &test, &data->directoryChange, NULL)) { } else { CloseHandle(data->directoryChange.hEvent); CloseHandle(data->hDirectory); return hasModified; } } return hasModified; }
String STDCALL GetStringSection(const TCHAR *lpStart, const TCHAR *lpOffset) { assert(lpStart && lpOffset && lpOffset > lpStart); if(lpStart >= lpOffset) return String(); String newStr; newStr.SetLength((UINT)(lpOffset-lpStart)); scpy_n(newStr, lpStart, (UINT)(lpOffset-lpStart)); return newStr; }
String GetPathWithoutExtension(CTSTR lpPath) { assert(lpPath); if(!lpPath) return String(); TSTR lpExtensionStart = srchr(lpPath, '.'); if(lpExtensionStart) { UINT newLength = (UINT)(UPARAM)(lpExtensionStart-lpPath); if(!newLength) return String(); String newString; newString.SetLength(newLength); scpy_n(newString, lpPath, newLength); return newString; } else return String(lpPath); }
void GraphicsCaptureSource::AttemptCapture() { OSDebugOut(TEXT("attempting to capture..\n")); if (scmpi(strWindowClass, L"dwm") == 0) { hwndTarget = FindWindow(strWindowClass, NULL); } else { FindWindowData fwd; //FIXME: duplicated code, but we need OpenProcess here char pOPStr[12]; mcpy(pOPStr, "NpflUvhel{x", 12); //OpenProcess obfuscated for (int i = 0; i<11; i++) pOPStr[i] ^= i ^ 1; fwd.pOpenProcess = (OPPROC)GetProcAddress(GetModuleHandle(TEXT("KERNEL32")), pOPStr); fwd.classname = strWindowClass; fwd.exename = strExecutable; fwd.hwnd = nullptr; EnumWindows(GraphicsCaptureFindWindow, (LPARAM)&fwd); hwndTarget = fwd.hwnd; } // use foregroundwindow as fallback (should be NULL if not using hotkey capture) if (!hwndTarget) hwndTarget = hwndNextTarget; hwndNextTarget = nullptr; OSDebugOut(L"Window: %s: ", strWindowClass.Array()); if (hwndTarget) { OSDebugOut(L"Valid window\n"); targetThreadID = GetWindowThreadProcessId(hwndTarget, &targetProcessID); if (!targetThreadID || !targetProcessID) { AppWarning(TEXT("GraphicsCaptureSource::AttemptCapture: GetWindowThreadProcessId failed, GetLastError = %u"), GetLastError()); bErrorAcquiring = true; return; } } else { OSDebugOut(L"Bad window\n"); if (!bUseHotkey && !warningID) { //Log(TEXT("GraphicsCaptureSource::AttemptCapture: Window '%s' [%s] not found."), strWindowClass.Array(), strExecutable.Array()); //warningID = API->AddStreamInfo(Str("Sources.SoftwareCaptureSource.WindowNotFound"), StreamInfoPriority_High); } bCapturing = false; return; } if (injectHelperProcess && WaitForSingleObject(injectHelperProcess, 0) == WAIT_TIMEOUT) return; if(warningID) { //API->RemoveStreamInfo(warningID); warningID = 0; } //------------------------------------------- // see if we already hooked the process. if not, inject DLL char pOPStr[12]; mcpy(pOPStr, "NpflUvhel{x", 12); //OpenProcess obfuscated for (int i=0; i<11; i++) pOPStr[i] ^= i^1; OPPROC pOpenProcess = (OPPROC)GetProcAddress(GetModuleHandle(TEXT("KERNEL32")), pOPStr); DWORD permission = useSafeHook ? (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ) : (PROCESS_ALL_ACCESS); HANDLE hProcess = (*pOpenProcess)(permission, FALSE, targetProcessID); if(hProcess) { DWORD dwSize = MAX_PATH; wchar_t processName[MAX_PATH]; memset(processName, 0, sizeof(processName)); QueryFullProcessImageName(hProcess, 0, processName, &dwSize); if (dwSize != 0 && scmpi(processName, lastProcessName) != 0) { if (processName[0]) { wchar_t *fileName = srchr(processName, '\\'); Log(L"Trying to hook process: %s", (fileName ? fileName+1 : processName)); } scpy_n(lastProcessName, processName, MAX_PATH-1); } //------------------------------------------- // load keepalive event hOBSIsAlive = CreateEvent(NULL, FALSE, FALSE, String() << OBS_KEEPALIVE_EVENT << UINT(targetProcessID)); //------------------------------------------- hwndCapture = hwndTarget; hSignalRestart = OpenEvent(EVENT_ALL_ACCESS, FALSE, String() << RESTART_CAPTURE_EVENT << UINT(targetProcessID)); if(hSignalRestart) { OSDebugOut(L"Setting signal for process ID %u\n", targetProcessID); SetEvent(hSignalRestart); bCapturing = true; captureWaitCount = 0; } else { BOOL bSameBit = TRUE; BOOL b32bit = TRUE; if (Is64BitWindows()) { BOOL bCurrentProcessWow64, bTargetProcessWow64; IsWow64Process(GetCurrentProcess(), &bCurrentProcessWow64); IsWow64Process(hProcess, &bTargetProcessWow64); bSameBit = (bCurrentProcessWow64 == bTargetProcessWow64); } if(Is64BitWindows()) IsWow64Process(hProcess, &b32bit); //verify the hook DLL is accessible String strDLL; DWORD dwDirSize = GetCurrentDirectory(0, NULL); strDLL.SetLength(dwDirSize); GetCurrentDirectory(dwDirSize, strDLL); strDLL << TEXT("\\plugins\\GraphicsCapture\\GraphicsCaptureHook"); if (!b32bit) strDLL << TEXT("64"); strDLL << TEXT(".dll"); if (!CheckFileIntegrity(strDLL.Array())) { OSDebugOut(L"Error acquiring\n"); bErrorAcquiring = true; } else { if (bSameBit && !useSafeHook) { if (InjectLibrary(hProcess, strDLL)) { captureWaitCount = 0; OSDebugOut(L"Inject successful\n"); bCapturing = true; } else { AppWarning(TEXT("GraphicsCaptureSource::AttemptCapture: Failed to inject library, GetLastError = %u"), GetLastError()); bErrorAcquiring = true; } } else { String strDLLPath; DWORD dwDirSize = GetCurrentDirectory(0, NULL); strDLLPath.SetLength(dwDirSize); GetCurrentDirectory(dwDirSize, strDLLPath); strDLLPath << TEXT("\\plugins\\GraphicsCapture"); String strHelper = strDLLPath; strHelper << ((b32bit) ? TEXT("\\injectHelper.exe") : TEXT("\\injectHelper64.exe")); if (!CheckFileIntegrity(strHelper.Array())) { bErrorAcquiring = true; } else { String strCommandLine; strCommandLine << TEXT("\"") << strHelper << TEXT("\" "); if (useSafeHook) strCommandLine << UIntString(targetThreadID) << " 1"; else strCommandLine << UIntString(targetProcessID) << " 0"; //--------------------------------------- PROCESS_INFORMATION pi; STARTUPINFO si; zero(&pi, sizeof(pi)); zero(&si, sizeof(si)); si.cb = sizeof(si); if (CreateProcess(strHelper, strCommandLine, NULL, NULL, FALSE, 0, NULL, strDLLPath, &si, &pi)) { int exitCode = 0; CloseHandle(pi.hThread); if (!useSafeHook) { WaitForSingleObject(pi.hProcess, INFINITE); GetExitCodeProcess(pi.hProcess, (DWORD*)&exitCode); CloseHandle(pi.hProcess); } else { injectHelperProcess = pi.hProcess; } if (exitCode == 0) { captureWaitCount = 0; bCapturing = true; } else { AppWarning(TEXT("GraphicsCaptureSource::AttemptCapture: Failed to inject library, error code = %d"), exitCode); bErrorAcquiring = true; } } else { AppWarning(TEXT("GraphicsCaptureSource::AttemptCapture: Could not create inject helper, GetLastError = %u"), GetLastError()); bErrorAcquiring = true; } } } } } //save a copy of the process handle which we injected into, this lets us check for process exit in Tick() if (!hTargetProcess) { if (!DuplicateHandle(GetCurrentProcess(), hProcess, GetCurrentProcess(), &hTargetProcess, 0, FALSE, DUPLICATE_SAME_ACCESS)) { Log(TEXT("Warning: Couldn't DuplicateHandle, %d"), GetLastError()); } } CloseHandle(hProcess); if (!bCapturing) { CloseHandle(hOBSIsAlive); hOBSIsAlive = NULL; } } else { AppWarning(TEXT("GraphicsCaptureSource::AttemptCapture: OpenProcess failed, GetLastError = %u"), GetLastError()); bErrorAcquiring = true; } }