void GraphicsCaptureSource::AttemptCapture() { //Log(TEXT("attempting to capture..")); if (!bUseHotkey) hwndTarget = FindWindow(strWindowClass, NULL); else { hwndTarget = hwndNextTarget; hwndNextTarget = NULL; } if (hwndTarget) { GetWindowThreadProcessId(hwndTarget, &targetProcessID); if(!targetProcessID) { AppWarning(TEXT("GraphicsCaptureSource::BeginScene: GetWindowThreadProcessId failed, GetLastError = %u"), GetLastError()); bErrorAcquiring = true; return; } } else { if (!bUseHotkey && !warningID) warningID = API->AddStreamInfo(Str("Sources.SoftwareCaptureSource.WindowNotFound"), StreamInfoPriority_High); bCapturing = false; 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); HANDLE hProcess = (*pOpenProcess)(PROCESS_ALL_ACCESS, FALSE, targetProcessID); if(hProcess) { //------------------------------------------- // 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) { SetEvent(hSignalRestart); bCapturing = true; captureWaitCount = 0; } else { BOOL bSameBit = TRUE; if(Is64BitWindows()) { BOOL bCurrentProcessWow64, bTargetProcessWow64; IsWow64Process(GetCurrentProcess(), &bCurrentProcessWow64); IsWow64Process(hProcess, &bTargetProcessWow64); bSameBit = (bCurrentProcessWow64 == bTargetProcessWow64); } if(bSameBit) { String strDLL; DWORD dwDirSize = GetCurrentDirectory(0, NULL); strDLL.SetLength(dwDirSize); GetCurrentDirectory(dwDirSize, strDLL); strDLL << TEXT("\\plugins\\GraphicsCapture\\GraphicsCaptureHook"); BOOL b32bit = TRUE; if(Is64BitWindows()) IsWow64Process(hProcess, &b32bit); if(!b32bit) strDLL << TEXT("64"); strDLL << TEXT(".dll"); if(InjectLibrary(hProcess, strDLL)) { captureWaitCount = 0; bCapturing = true; } else { AppWarning(TEXT("GraphicsCaptureSource::BeginScene: Failed to inject library, GetLastError = %u"), GetLastError()); CloseHandle(hProcess); hProcess = NULL; bErrorAcquiring = true; } } else { String strDLLPath; DWORD dwDirSize = GetCurrentDirectory(0, NULL); strDLLPath.SetLength(dwDirSize); GetCurrentDirectory(dwDirSize, strDLLPath); strDLLPath << TEXT("\\plugins\\GraphicsCapture"); BOOL b32bit = TRUE; if(Is64BitWindows()) IsWow64Process(hProcess, &b32bit); String strHelper = strDLLPath; strHelper << ((b32bit) ? TEXT("\\injectHelper.exe") : TEXT("\\injectHelper64.exe")); String strCommandLine; strCommandLine << TEXT("\"") << strHelper << TEXT("\" ") << UIntString(targetProcessID); //--------------------------------------- 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; WaitForSingleObject(pi.hProcess, INFINITE); GetExitCodeProcess(pi.hProcess, (DWORD*)&exitCode); CloseHandle(pi.hThread); CloseHandle(pi.hProcess); if(exitCode == 0) { captureWaitCount = 0; bCapturing = true; } else { AppWarning(TEXT("GraphicsCaptureSource::BeginScene: Failed to inject library, error code = %d"), exitCode); bErrorAcquiring = true; } } else { AppWarning(TEXT("GraphicsCaptureSource::BeginScene: Could not create inject helper, GetLastError = %u"), GetLastError()); bErrorAcquiring = true; } } } CloseHandle(hProcess); hProcess = NULL; if (!bCapturing) { CloseHandle(hOBSIsAlive); hOBSIsAlive = NULL; } } else { AppWarning(TEXT("GraphicsCaptureSource::BeginScene: OpenProcess failed, GetLastError = %u"), GetLastError()); bErrorAcquiring = true; } }
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine, int nShowCmd) { LPWSTR pCommandLineW = GetCommandLineW(); int retVal = 0; DWORD procID = 0; int numArgs = 0; #ifdef _WIN64 const wchar_t pDLLName[] = L"GraphicsCaptureHook64.dll"; #else const wchar_t pDLLName[] = L"GraphicsCaptureHook.dll"; #endif /* -------------------------- */ LPWSTR *pCommandLineArgs = CommandLineToArgvW(pCommandLineW, &numArgs); LoadSeDebugPrivilege(); if (numArgs > 1) { procID = wcstoul(pCommandLineArgs[1], NULL, 10); if (procID != 0) { OPPROC pOpenProcess; HANDLE hProcess; char pOPStr[12]; int i; memcpy(pOPStr, "NpflUvhel{x", 12); //OpenProcess obfuscated for (i=0; i<11; i++) pOPStr[i] ^= i^1; pOpenProcess = (OPPROC)GetProcAddress(GetModuleHandle(TEXT("KERNEL32")), pOPStr); hProcess = (*pOpenProcess)(PROCESS_ALL_ACCESS, FALSE, procID); if (hProcess) { UINT dirLen = GetCurrentDirectory(0, 0); /* includes null terminator */ const UINT fileNameLen = (sizeof(pDLLName) / sizeof(wchar_t))-1; UINT len = dirLen + fileNameLen + 1; /* 1 for '/' */ wchar_t *pPath; /* -------------------------- */ if (dirLen) { pPath = (wchar_t*)malloc(len * sizeof(wchar_t)); memset(pPath, 0, len * sizeof(wchar_t)); GetCurrentDirectoryW(dirLen, pPath); pPath[dirLen-1] = '\\'; wcsncpy_s(pPath+dirLen, len-dirLen, pDLLName, fileNameLen); if(!InjectLibrary(hProcess, pPath, len-1)) { retVal = GetLastError(); if(!retVal) retVal = -5; } free(pPath); } else retVal = -4; CloseHandle(hProcess); } else retVal = -3; } else retVal = -2; } else retVal = -1; LocalFree(pCommandLineArgs); return retVal; }
int Main(int argc, char const * const argv[], char const * const envp[]) { _aprcall(apr_initialize()); apr_pool_t *pool; apr_pool_create(&pool, NULL); bool tty(isatty(STDIN_FILENO)); bool compile(false); CYOptions options; append_history$ = (int (*)(int, const char *)) (dlsym(RTLD_DEFAULT, "append_history")); #ifdef CY_ATTACH pid_t pid(_not(pid_t)); #endif const char *host(NULL); const char *port(NULL); apr_getopt_t *state; _aprcall(apr_getopt_init(&state, pool, argc, argv)); for (;;) { char opt; const char *arg; apr_status_t status(apr_getopt(state, "cg:n:" #ifdef CY_ATTACH "p:" #endif "r:" "s" , &opt, &arg)); switch (status) { case APR_EOF: goto getopt; case APR_BADCH: case APR_BADARG: fprintf(stderr, "usage: cycript [-c]" #ifdef CY_ATTACH " [-p <pid|name>]" #endif " [-r <host:port>]" " [<script> [<arg>...]]\n" ); return 1; default: _aprcall(status); } switch (opt) { case 'c': compile = true; break; case 'g': if (false); else if (strcmp(arg, "rename") == 0) options.verbose_ = true; #if YYDEBUG else if (strcmp(arg, "bison") == 0) bison_ = true; #endif else { fprintf(stderr, "invalid name for -g\n"); return 1; } break; case 'n': if (false); else if (strcmp(arg, "minify") == 0) pretty_ = true; else { fprintf(stderr, "invalid name for -n\n"); return 1; } break; #ifdef CY_ATTACH case 'p': { size_t size(strlen(arg)); char *end; pid = strtoul(arg, &end, 0); if (arg + size != end) { // XXX: arg needs to be escaped in some horrendous way of doom const char *command(apr_pstrcat(pool, "ps axc|sed -e '/^ *[0-9]/{s/^ *\\([0-9]*\\)\\( *[^ ]*\\)\\{3\\} *-*\\([^ ]*\\)/\\3 \\1/;/^", arg, " /{s/^[^ ]* //;q;};};d'", NULL)); if (FILE *pids = popen(command, "r")) { char value[32]; size = 0; for (;;) { size_t read(fread(value + size, 1, sizeof(value) - size, pids)); if (read == 0) break; else { size += read; if (size == sizeof(value)) { pid = _not(pid_t); goto fail; } } } size: if (size == 0) goto fail; if (value[size - 1] == '\n') { --size; goto size; } value[size] = '\0'; size = strlen(value); pid = strtoul(value, &end, 0); if (value + size != end) fail: pid = _not(pid_t); _syscall(pclose(pids)); } if (pid == _not(pid_t)) { fprintf(stderr, "invalid pid for -p\n"); return 1; } } } break; #endif case 'r': { //size_t size(strlen(arg)); char *colon(strrchr(arg, ':')); if (colon == NULL) { fprintf(stderr, "missing colon in hostspec\n"); return 1; } /*char *end; port = strtoul(colon + 1, &end, 10); if (end != arg + size) { fprintf(stderr, "invalid port in hostspec\n"); return 1; }*/ host = arg; *colon = '\0'; port = colon + 1; } break; case 's': strict_ = true; break; } } getopt:; const char *script; int ind(state->ind); #ifdef CY_ATTACH if (pid != _not(pid_t) && ind < argc - 1) { fprintf(stderr, "-p cannot set argv\n"); return 1; } if (pid != _not(pid_t) && compile) { fprintf(stderr, "-p conflicts with -c\n"); return 1; } #endif if (ind == argc) script = NULL; else { #ifdef CY_EXECUTE // XXX: const_cast?! wtf gcc :( CYSetArgs(argc - ind - 1, const_cast<const char **>(argv + ind + 1)); #endif script = argv[ind]; if (strcmp(script, "-") == 0) script = NULL; } #ifdef CY_ATTACH if (pid != _not(pid_t) && script == NULL && !tty) { fprintf(stderr, "non-terminal attaching to remote console\n"); return 1; } #endif #ifdef CY_ATTACH if (pid == _not(pid_t)) client_ = -1; else { int server(_syscall(socket(PF_UNIX, SOCK_STREAM, 0))); try { struct sockaddr_un address; memset(&address, 0, sizeof(address)); address.sun_family = AF_UNIX; sprintf(address.sun_path, "/tmp/.s.cy.%u", getpid()); _syscall(bind(server, reinterpret_cast<sockaddr *>(&address), SUN_LEN(&address))); _syscall(chmod(address.sun_path, 0777)); try { _syscall(listen(server, 1)); InjectLibrary(pid); client_ = _syscall(accept(server, NULL, NULL)); } catch (...) { // XXX: exception? unlink(address.sun_path); throw; } } catch (...) { _syscall(close(server)); throw; } } #else client_ = -1; #endif if (client_ == -1 && host != NULL && port != NULL) { struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = 0; hints.ai_flags = 0; struct addrinfo *infos; _syscall(getaddrinfo(host, port, &hints, &infos)); _assert(infos != NULL); try { for (struct addrinfo *info(infos); info != NULL; info = info->ai_next) { int client(_syscall(socket(info->ai_family, info->ai_socktype, info->ai_protocol))); try { _syscall(connect(client, info->ai_addr, info->ai_addrlen)); client_ = client; break; } catch (...) { _syscall(close(client)); throw; } } } catch (...) { freeaddrinfo(infos); throw; } } if (script == NULL && tty) Console(options); else { CYLocalPool pool; char *start, *end; std::istream *indirect; if (script == NULL) { start = NULL; end = NULL; indirect = &std::cin; } else { size_t size; start = reinterpret_cast<char *>(Map(script, &size)); end = start + size; if (size >= 2 && start[0] == '#' && start[1] == '!') { start += 2; if (void *line = memchr(start, '\n', end - start)) start = reinterpret_cast<char *>(line); else start = end; } indirect = NULL; } CYStream direct(start, end); std::istream &stream(indirect == NULL ? direct : *indirect); CYDriver driver(stream, script ?: "<stdin>"); cy::parser parser(driver); Setup(driver, parser); if (parser.parse() != 0 || !driver.errors_.empty()) { for (CYDriver::Errors::const_iterator i(driver.errors_.begin()); i != driver.errors_.end(); ++i) std::cerr << i->location_.begin << ": " << i->message_ << std::endl; } else if (driver.program_ != NULL) if (client_ != -1) { // XXX: this code means that you can't pipe to another process std::string code(start, end-start); Run(client_, false, code, &std::cout); } else { std::ostringstream str; CYOutput out(str, options); Setup(out, driver, options); out << *driver.program_; std::string code(str.str()); if (compile) std::cout << code; else Run(client_, false, code, &std::cout); } } apr_pool_destroy(pool); return 0; }