ResultType Clipboard::Open() { if (mIsOpen) return OK; #ifdef _WIN64 DWORD aThreadID = __readgsdword(0x48); // Used to identify if code is called from different thread (AutoHotkey.dll) #else DWORD aThreadID = __readfsdword(0x24); #endif for (DWORD start_time = GetTickCount();;) { if (OpenClipboard(g_hWnd)) { mIsOpen = true; return OK; } if (g_ClipboardTimeout != -1) // We were not told to wait indefinitely... if (!g_ClipboardTimeout // ...and we were told to make only one attempt, or ... || (int)(g_ClipboardTimeout - (GetTickCount() - start_time)) <= SLEEP_INTERVAL_HALF) //...it timed out. // Above must cast to int or any negative result will be lost due to DWORD type. return FAIL; // Use SLEEP_WITHOUT_INTERRUPTION to prevent MainWindowProc() from accepting new hotkeys // during our operation, since a new hotkey subroutine might interfere with // what we're doing here (e.g. if it tries to use the clipboard, or perhaps overwrites // the deref buffer if this object's caller gave it any pointers into that memory area): SLEEP_WITHOUT_INTERRUPTION(INTERVAL_UNSPECIFIED) } }
__declspec(dllexport) int APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID reserved) #endif { unsigned long TID = __readgsdword(0x48); if (loadSystemDebugControl == NULL) { HMODULE dNTdll = GetModuleHandleA("ntdll.dll"); loadSystemDebugControl = (NtSystemDebugControl)GetProcAddress(dNTdll, "NtSystemDebugControl"); } if (reason == DLL_PROCESS_ATTACH) { if (AllocConsole()) { freopen("CONOUT$", "w", stdout); SetConsoleTitle(L"EhTrace Debug Window"); wprintf(L"DLL loaded.\n"); if (loadSystemDebugControl != NULL) wprintf(L"also ready for DEBUG MSR WRITE"); } ConfigMap = ConnectConfig(); wprintf(L"Connecting ConfigMap %p\n", ConfigMap); // logger will spin the thread if logs are not picked up fast enough SetupLogger(STRACE_LOG_BUFFER_SIZE); Initalize(NULL); InstallThread(TID, 2); //hPulseThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PulseThreads, 0, 0, NULL); //NoLogThrId = GetThreadId(hPulseThread); //wprintf(L"Symbol count is %llx\n", ConfigMap->SymCnt); //ConnectSymbols(ConfigMap->SymCnt); } else if (reason == DLL_THREAD_ATTACH) { // setup monitoring of this thread UnTracedThreadCount++; InstallThread(TID, 3); } else if (reason == DLL_THREAD_DETACH) { ExitThreadTable(TID, true); if(CtxTable[TID].insn != NULL) cs_free(CtxTable[TID].insn, 1); memset(&CtxTable[TID], 0, sizeof(ExecutionBlock)); wprintf(L"Cleaned up thread %d\n", TID); } wprintf(L"done in dllmain\n"); return TRUE; }
// In the spirt of so many exceptions! =D blah! https://msdn.microsoft.com/en-us/library/1eyas8tf.aspx LONG WINAPI vEhTracer(PEXCEPTION_POINTERS ExceptionInfo) { DWORD OldPerm; PExecutionBlock pCtx = NULL; ULONG64 dwThr = __readgsdword(0x48); // TODO: just put the whole context in the array to remove an indirect anyhow if (CtxTable != NULL && CtxTable[dwThr].TID != 0) pCtx = &CtxTable[dwThr]; else pCtx = InitBlock(dwThr); // allow exec //pCtx->DisabledUntil = (LPVOID)((ULONG64) ExceptionInfo->ExceptionRecord->ExceptionAddress & ~0x4095); pCtx->pExeption = ExceptionInfo; pCtx->TSC = __rdtsc(); // check if my thread is a thread that's already entered into the VEH logging something lower on the stack // this means were probably getting an exception for something we did ourselves during the logging // which is sort of pointless // we could test all Exception address against known entries we provide if (AmIinThreadTable()) return EXCEPTION_CONTINUE_EXECUTION; if (ExceptionInfo->ExceptionRecord->ExceptionCode != STATUS_SINGLE_STEP) return EXCEPTION_CONTINUE_SEARCH; // no re-entrance while servicing exceptions EnterThreadTable(dwThr, false); // since we like to do logging //LogRIP(pCtx); // to dump info //_DumpContext(pCtx); // Loop through all of the block fighters Fight(pCtx); // Thanks Feryno // http://x86asm.net/articles/backdoor-support-for-control-transfer-breakpoint-features/ // ExceptionInfo->ContextRecord->EFlags |= 0x100; // single step ExceptionInfo->ContextRecord->Dr7 |= 0x300; // setup branch tracing // record keeping pCtx->BlockFrom = ExceptionInfo->ContextRecord->Rip; // exit lock ExitThreadTable(dwThr, false); return EXCEPTION_CONTINUE_EXECUTION; }
HANDLE Clipboard::GetClipboardDataTimeout(UINT uFormat, BOOL *aNullIsOkay) // Update for v1.1.16: The comments below are obsolete; search for "v1.1.16" for related comments. // Same as GetClipboardData() except that it doesn't give up if the first call to GetClipboardData() fails. // Instead, it continues to retry the operation for the number of milliseconds in g_ClipboardTimeout. // This is necessary because GetClipboardData() has been observed to fail in repeatable situations (this // is strange because our thread already has the clipboard locked open -- presumably it happens because the // GetClipboardData() is unable to start a data stream from the application that actually serves up the data). // If cases where the first call to GetClipboardData() fails, a subsequent call will often succeed if you give // the owning application (such as Excel and Word) a little time to catch up. This is especially necessary in // the OnClipboardChange label, where sometimes a clipboard-change notification comes in before the owning // app has finished preparing its data for subsequent readers of the clipboard. { #ifdef DEBUG_BY_LOGGING_CLIPBOARD_FORMATS // Provides a convenient log of clipboard formats for analysis. static FILE *fp = fopen("c:\\debug_clipboard_formats.txt", "w"); #endif if (aNullIsOkay) *aNullIsOkay = FALSE; // Set default. TCHAR format_name[MAX_PATH + 1]; // MSDN's RegisterClipboardFormat() doesn't document any max length, but the ones we're interested in certainly don't exceed MAX_PATH. if (uFormat < 0xC000 || uFormat > 0xFFFF) // It's a registered format (you're supposed to verify in-range before calling GetClipboardFormatName()). Also helps performance. *format_name = '\0'; // Don't need the name if it's a standard/CF_* format. else { // v1.0.42.04: // Probably need to call GetClipboardFormatName() rather than comparing directly to uFormat because // MSDN implies that OwnerLink and other registered formats might not always have the same ID under // all OSes (past and future). GetClipboardFormatName(uFormat, format_name, MAX_PATH); // Since RegisterClipboardFormat() is case insensitive, the case might vary. So use stricmp() when // comparing format_name to anything. // "Link Source", "Link Source Descriptor" , and anything else starting with "Link Source" is likely // to be data that should not be attempted to be retrieved because: // 1) It causes unwanted bookmark effects in various versions of MS Word. // 2) Tests show that these formats are on the clipboard only if MS Word is open at the time // ClipboardAll is accessed. That implies they're transitory formats that aren't as essential // or well suited to ClipboardAll as the other formats (but if it weren't for #1 above, this // wouldn't be enough reason to omit it). // 3) Although there is hardly any documentation to be found at MSDN or elsewhere about these formats, // it seems they're related to OLE, with further implications that the data is transitory. // Here are the formats that Word 2002 removes from the clipboard when it the app closes: // 0xC002 ObjectLink >>> Causes WORD bookmarking problem. // 0xC003 OwnerLink // 0xC00D Link Source >>> Causes WORD bookmarking problem. // 0xC00F Link Source Descriptor >>> Doesn't directly cause bookmarking, but probably goes with above. // 0xC0DC Hyperlink if ( !_tcsnicmp(format_name, _T("Link Source"), 11) || !_tcsicmp(format_name, _T("ObjectLink")) || !_tcsicmp(format_name, _T("OwnerLink")) // v1.0.44.07: The following were added to solve interference with MS Outlook's MS Word editor. // If a hotkey like ^F1::ClipboardSave:=ClipboardAll is pressed after pressing Ctrl-C in that // editor (perhaps only when copying HTML), two of the following error dialogs would otherwise // be displayed (this occurs in Outlook 2002 and probably later versions): // "An outgoing call cannot be made since the application is dispatching an input-synchronous call." || !_tcsicmp(format_name, _T("Native")) || !_tcsicmp(format_name, _T("Embed Source")) ) return NULL; if (!_tcsicmp(format_name, _T("MSDEVColumnSelect")) || !_tcsicmp(format_name, _T("MSDEVLineSelect"))) { // v1.1.16: These formats are used by Visual Studio, Scintilla controls and perhaps others for // copying whole lines and rectangular blocks. Because their very presence/absence is used as // a boolean indicator, the data is irrelevant. Presumably for this reason, Scintilla controls // set NULL data, though doing so and then not handling WM_RENDERFORMAT is probably invalid. // Note newer versions of Visual Studio use "VisualStudioEditorOperationsLineCutCopyClipboardTag" // for line copy, but that doesn't need to be handled here because it has non-NULL data (and the // latest unreleased Scintilla [as at 2014-08-19] uses both, so we can discard the long one). // Since we just want to preserve this format's presence, indicate to caller that NULL is okay: if (aNullIsOkay) // i.e. caller passed a variable for us to set. *aNullIsOkay = TRUE; return NULL; } } #ifdef DEBUG_BY_LOGGING_CLIPBOARD_FORMATS _ftprintf(fp, _T("%04X\t%s\n"), uFormat, format_name); // Since fclose() is never called, the program has to exit to close/release the file. #endif #ifndef ENABLE_CLIPBOARDGETDATA_TIMEOUT // v1.1.16: The timeout and retry behaviour of this function is currently disabled, since it does more // harm than good. It previously did NO GOOD WHATSOEVER, because SLEEP_WITHOUT_INTERRUPTION indirectly // calls g_clip.Close() via CLOSE_CLIPBOARD_IF_OPEN, so any subsequent attempts to retrieve data by us // or our caller always fail. The main point of failure where retrying helps is OpenClipboard(), when // another program has the clipboard open -- and that's handled elsewhere. If the timeout is re-enabled // for this function, the following format will need to be excluded to prevent unnecessary delays: // - FileContents (CSTR_FILECONTENTS): MSDN says it is used "to transfer data as if it were a file, // regardless of how it is actually stored". For example, it could be a file inside a zip folder. // However, on Windows 8 it seems to also be present for normal files. It might be possible to // retrieve its data via OleGetClipboard(), though it could be very large. // Just return the data, even if NULL: return GetClipboardData(uFormat); #else HANDLE h; #ifdef _WIN64 DWORD aThreadID = __readgsdword(0x48); // Used to identify if code is called from different thread (AutoHotkey.dll) #else DWORD aThreadID = __readfsdword(0x24); #endif for (DWORD start_time = GetTickCount();;) { // Known failure conditions: // GetClipboardData() apparently fails when the text on the clipboard is greater than a certain size // (Even though GetLastError() reports "Operation completed successfully"). The data size at which // this occurs is somewhere between 20 to 96 MB (perhaps depending on system's memory and CPU speed). if (h = GetClipboardData(uFormat)) // Assign return h; // It failed, so act according to the type of format and the timeout that's in effect. // Certain standard (numerically constant) clipboard formats are known to validly yield NULL from a // call to GetClipboardData(). Never retry these because it would only cause unnecessary delays // (i.e. a failure until timeout). // v1.0.42.04: More importantly, retrying them appears to cause problems with saving a Word/Excel // clipboard via ClipboardAll. if (uFormat == CF_HDROP // This format can fail "normally" for the reasons described at "clipboard_contains_files". || !_tcsicmp(format_name, _T("OwnerLink"))) // Known to validly yield NULL from a call to GetClipboardData(), so don't retry it to avoid having to wait the full timeout period. return NULL; if (g_ClipboardTimeout != -1) // We were not told to wait indefinitely and... if (!g_ClipboardTimeout // ...we were told to make only one attempt, or ... || (int)(g_ClipboardTimeout - (GetTickCount() - start_time)) <= SLEEP_INTERVAL_HALF) //...it timed out. // Above must cast to int or any negative result will be lost due to DWORD type. return NULL; // Use SLEEP_WITHOUT_INTERRUPTION to prevent MainWindowProc() from accepting new hotkeys // during our operation, since a new hotkey subroutine might interfere with // what we're doing here (e.g. if it tries to use the clipboard, or perhaps overwrites // the deref buffer if this object's caller gave it any pointers into that memory area): SLEEP_WITHOUT_INTERRUPTION(INTERVAL_UNSPECIFIED) } #endif }