VOID
IN_PROCESS_APPLICATION::ShutDownInternal()
{
DWORD dwThreadStatus = 0;
DWORD dwTimeout = m_pConfig->QueryShutdownTimeLimitInMS();
HANDLE handle = NULL;
WIN32_FIND_DATA fileData;
if (IsDebuggerPresent())
{
dwTimeout = INFINITE;
}
if (m_fShutdownCalledFromNative ||
m_status == APPLICATION_STATUS::STARTING ||
m_status == APPLICATION_STATUS::FAIL)
{
return;
}
{
SRWLockWrapper lock(m_srwLock);
if (m_fShutdownCalledFromNative ||
m_status == APPLICATION_STATUS::STARTING ||
m_status == APPLICATION_STATUS::FAIL)
{
return;
}
// We need to keep track of when both managed and native initiate shutdown
// to avoid AVs. If shutdown has already been initiated in managed, we don't want to call into
// managed. We still need to wait on main exiting no matter what. m_fShutdownCalledFromNative
// is used for detecting redundant calls and blocking more requests to OnExecuteRequestHandler.
m_fShutdownCalledFromNative = TRUE;
m_status = APPLICATION_STATUS::SHUTDOWN;
if (!m_fShutdownCalledFromManaged)
{
// We cannot call into managed if the dll is detaching from the process.
// Calling into managed code when the dll is detaching is strictly a bad idea,
// and usually results in an AV saying "The string binding is invalid"
if (!g_fProcessDetach)
{
m_ShutdownHandler(m_ShutdownHandlerContext);
m_ShutdownHandler = NULL;
}
}
// Release the lock before we wait on the thread to exit.
}
if (!m_fShutdownCalledFromManaged)
{
if (m_hThread != NULL &&
GetExitCodeThread(m_hThread, &dwThreadStatus) != 0 &&
dwThreadStatus == STILL_ACTIVE)
{
// wait for graceful shutdown, i.e., the exit of the background thread or timeout
if (WaitForSingleObject(m_hThread, dwTimeout) != WAIT_OBJECT_0)
{
// if the thread is still running, we need kill it first before exit to avoid AV
if (GetExitCodeThread(m_hThread, &dwThreadStatus) != 0 && dwThreadStatus == STILL_ACTIVE)
{
// Calling back into managed at this point is prone to have AVs
// Calling terminate thread here may be our best solution.
TerminateThread(m_hThread, STATUS_CONTROL_C_EXIT);
}
}
}
}
CloseHandle(m_hThread);
m_hThread = NULL;
s_Application = NULL;
CloseStdErrHandles();
if (m_pStdFile != NULL)
{
fflush(stdout);
fflush(stderr);
fclose(m_pStdFile);
}
if (m_hLogFileHandle != INVALID_HANDLE_VALUE)
{
m_Timer.CancelTimer();
CloseHandle(m_hLogFileHandle);
m_hLogFileHandle = INVALID_HANDLE_VALUE;
}
// delete empty log file
handle = FindFirstFile(m_struLogFilePath.QueryStr(), &fileData);
if (handle != INVALID_HANDLE_VALUE &&
fileData.nFileSizeHigh == 0 &&
fileData.nFileSizeLow == 0) // skip check of nFileSizeHigh
{
FindClose(handle);
// no need to check whether the deletion succeeds
//.........这里部分代码省略.........
int hook_enable() {
// Lock the thread control mutex. This will be unlocked when the
// thread has finished starting, or when it has fully stopped.
#ifdef _WIN32
WaitForSingleObject(hook_control_mutex, INFINITE);
#else
pthread_mutex_lock(&hook_control_mutex);
#endif
// Set the initial status.
int status = UIOHOOK_FAILURE;
#ifndef _WIN32
// Create the thread attribute.
pthread_attr_t hook_thread_attr;
pthread_attr_init(&hook_thread_attr);
// Get the policy and priority for the thread attr.
int policy;
pthread_attr_getschedpolicy(&hook_thread_attr, &policy);
int priority = sched_get_priority_max(policy);
#endif
#if defined(_WIN32)
DWORD hook_thread_id;
DWORD *hook_thread_status = malloc(sizeof(DWORD));
hook_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) hook_thread_proc, hook_thread_status, 0, &hook_thread_id);
if (hook_thread != INVALID_HANDLE_VALUE) {
#else
int *hook_thread_status = malloc(sizeof(int));
if (pthread_create(&hook_thread, &hook_thread_attr, hook_thread_proc, hook_thread_status) == 0) {
#endif
#if defined(_WIN32)
// Attempt to set the thread priority to time critical.
if (SetThreadPriority(hook_thread, THREAD_PRIORITY_TIME_CRITICAL) == 0) {
logger_proc(LOG_LEVEL_WARN, "%s [%u]: Could not set thread priority %li for thread %#p! (%#lX)\n",
__FUNCTION__, __LINE__, (long) THREAD_PRIORITY_TIME_CRITICAL,
hook_thread , (unsigned long) GetLastError());
}
#elif (defined(__APPLE__) && defined(__MACH__)) || _POSIX_C_SOURCE >= 200112L
// Some POSIX revisions do not support pthread_setschedprio so we will
// use pthread_setschedparam instead.
struct sched_param param = { .sched_priority = priority };
if (pthread_setschedparam(hook_thread, SCHED_OTHER, ¶m) != 0) {
logger_proc(LOG_LEVEL_WARN, "%s [%u]: Could not set thread priority %i for thread 0x%lX!\n",
__FUNCTION__, __LINE__, priority, (unsigned long) hook_thread);
}
#else
// Raise the thread priority using glibc pthread_setschedprio.
if (pthread_setschedprio(hook_thread, priority) != 0) {
logger_proc(LOG_LEVEL_WARN, "%s [%u]: Could not set thread priority %i for thread 0x%lX!\n",
__FUNCTION__, __LINE__, priority, (unsigned long) hook_thread);
}
#endif
// Wait for the thread to indicate that it has passed the
// initialization portion by blocking until either a EVENT_HOOK_ENABLED
// event is received or the thread terminates.
// NOTE This unlocks the hook_control_mutex while we wait.
#ifdef _WIN32
WaitForSingleObject(hook_control_cond, INFINITE);
#else
pthread_cond_wait(&hook_control_cond, &hook_control_mutex);
#endif
#ifdef _WIN32
if (WaitForSingleObject(hook_running_mutex, 0) != WAIT_TIMEOUT) {
#else
if (pthread_mutex_trylock(&hook_running_mutex) == 0) {
#endif
// Lock Successful; The hook is not running but the hook_control_cond
// was signaled! This indicates that there was a startup problem!
// Get the status back from the thread.
#ifdef _WIN32
WaitForSingleObject(hook_thread, INFINITE);
GetExitCodeThread(hook_thread, hook_thread_status);
#else
pthread_join(hook_thread, (void **) &hook_thread_status);
status = *hook_thread_status;
#endif
}
else {
// Lock Failure; The hook is currently running and wait was signaled
// indicating that we have passed all possible start checks. We can
// always assume a successful startup at this point.
status = UIOHOOK_SUCCESS;
}
free(hook_thread_status);
logger_proc(LOG_LEVEL_DEBUG, "%s [%u]: Thread Result: (%#X).\n",
__FUNCTION__, __LINE__, status);
}
else {
status = UIOHOOK_ERROR_THREAD_CREATE;
}
// Make sure the control mutex is unlocked.
//.........这里部分代码省略.........
BOOL CheckThreads(__in DWORD ProcId)
/*++
Routine Description:
Enumerates all threads (or optionally only threads for one
process) in the system. It the calls the WCT API on each of them.
Arguments:
ProcId--Specifies the process ID to analyze. If '0' all processes
in the system will be checked.
Return Value:
TRUE if processes could be checked; FALSE if a general failure
occurred.
--*/
{
DWORD processes[1024];
DWORD numProcesses;
DWORD i;
// Try to enable the SE_DEBUG_NAME privilege for this process.
// Continue even if this fails--we just won't be able to retrieve
// wait chains for processes not owned by the current user.
if (!GrantDebugPrivilege()) {
printf("Could not enable the debug privilege");
}
// Get a list of all processes currently running.
if (EnumProcesses(processes, sizeof(processes), &numProcesses) == FALSE) {
printf("Could not enumerate processes");
return FALSE;
}
for (i = 0; i < numProcesses / sizeof(DWORD); i++) {
HANDLE process;
HANDLE snapshot;
if (processes[i] == GetCurrentProcessId()) {
continue;
}
// If the caller specified a Process ID, check if we have a match.
if (ProcId != 0) {
if (processes[i] != ProcId) {
continue;
}
}
// Get a handle to this process.
process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processes[i]);
if (process) {
WCHAR file[MAX_PATH];
printf("Process 0x%x - ", processes[i]);
// Retrieve the executable name and print it.
if (GetProcessImageFileName(process, file, ARRAYSIZE(file)) > 0) {
PCWSTR filePart = wcsrchr(file, L'\\');
if (filePart) {
filePart++;
} else {
filePart = file;
}
printf("%S", filePart);
}
printf("\n----------------------------------\n");
// Get a snapshot of this process. This enables us to
// enumerate its threads.
snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, processes[i]);
if (snapshot) {
THREADENTRY32 thread;
thread.dwSize = sizeof(thread);
// Walk the thread list and print each wait chain
if (Thread32First(snapshot, &thread)) {
do {
if (thread.th32OwnerProcessID == processes[i]) {
// Open a handle to this specific thread
HANDLE threadHandle = OpenThread(THREAD_ALL_ACCESS, FALSE, thread.th32ThreadID);
if (threadHandle) {
// Check whether the thread is still running
DWORD exitCode;
GetExitCodeThread(threadHandle, &exitCode);
if (exitCode == STILL_ACTIVE) {
// Print the wait chain.
PrintWaitChain(thread.th32ThreadID);
}
CloseHandle(threadHandle);
}
}
} while (Thread32Next(snapshot, &thread));
//.........这里部分代码省略.........
int InjectCode ()
{
HANDLE hProcess = 0; // Process handle
HMODULE hUser32 = 0; // Handle of user32.dll
BYTE *pCodeRemote; // Address of InjectFunc() in the remote process.
BYTE *pGetSASWndRemote; // Address of GetSASWnd() in the remote process.
HANDLE hThread = 0; // The handle and ID of the thread executing
DWORD dwThreadId = 0; // the remote InjectFunc().
INJDATA DataLocal; // INJDATA structure
BOOL fUnicode; // TRUE if remote process is Unicode
int nSuccess = 0; // Subclassing succeded?
DWORD dwNumBytesCopied = 0; // Number of bytes written to the remote process.
DWORD size; // Calculated function size (= AfterFunc() - Func())
int SearchSize; // SASWindowProc() dummy addr. search size
int nDummyOffset; // Offset in SASWindowProc() of dummy addr.
BOOL FoundDummyAddr; // Dummy INJDATA reference found in SASWindowProc() ?
HWND hSASWnd; // Window handle of Winlogon process
BYTE *p;
// Enable Debug privilege (needed for some processes)
if (!EnablePrivilege(SE_DEBUG_NAME, TRUE))
return 0;
// Get handle of "USER32.DLL"
hUser32 = GetModuleHandle("user32");
if (!hUser32)
return 0;
// Get remote process ID
PID = GetPIDFromName(szProcessName);
if (PID == -1)
return 0;
// Open remote process
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);
if (!hProcess)
return 0;
__try
{
// Initialize INJDATA for GetSASWnd() call
strcpy(DataLocal.szClassName, "SAS Window class");
strcpy(DataLocal.szWindowName, "SAS window");
DataLocal.fnFindWindow = (FINDWINDOW) GetProcAddress(hUser32, "FindWindowA");
if (DataLocal.fnFindWindow == NULL)
__leave;
// Allocate memory in the remote process and write a copy of initialized INJDATA into it
size = sizeof(INJDATA);
pDataRemote = (PBYTE) VirtualAllocEx(hProcess, 0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (!pDataRemote)
__leave;
if (!WriteProcessMemory(hProcess, pDataRemote, &DataLocal, size, &dwNumBytesCopied) || dwNumBytesCopied != size)
__leave;
// Allocate memory in remote process and write a copy of GetSASWnd() into it
size = (PBYTE)AfterGetSASWnd - (PBYTE)GetSASWnd;
pGetSASWndRemote = (PBYTE) VirtualAllocEx(hProcess, 0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (!pGetSASWndRemote)
__leave;
if (!WriteProcessMemory(hProcess, pGetSASWndRemote, &GetSASWnd, size, &dwNumBytesCopied) || dwNumBytesCopied != size)
__leave;
// Start execution of remote GetSASWnd()
hThread = CreateRemoteThread(hProcess,
NULL,
0,
(LPTHREAD_START_ROUTINE) pGetSASWndRemote,
pDataRemote,
0 ,
&dwThreadId);
// Failed
if (!hThread)
__leave;
// Wait for GetSASWnd() to terminate and get return code (SAS Wnd handle)
WaitForSingleObject(hThread, INFINITE);
GetExitCodeThread(hThread, (PDWORD) &hSASWnd);
// Didn't found "SAS window"
if (!hSASWnd)
__leave;
// Cleanup
VirtualFreeEx(hProcess, pGetSASWndRemote, 0, MEM_RELEASE);
VirtualFreeEx(hProcess, pDataRemote, 0, MEM_RELEASE);
pGetSASWndRemote = NULL;
pDataRemote = NULL;
// Allocate memory in remote process and write a copy of SASWindowProc() into it
size = (PBYTE)AfterSASWindowProc - (PBYTE)SASWindowProc;
pSASWinProcRemote = (PBYTE) VirtualAllocEx(hProcess, 0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (!pSASWinProcRemote)
__leave;
if (!WriteProcessMemory(hProcess, pSASWinProcRemote, &SASWindowProc, size, &dwNumBytesCopied) || dwNumBytesCopied != size)
__leave;
// Is remote process unicode ?
fUnicode = IsWindowUnicode(hSASWnd);
//.........这里部分代码省略.........
int main()
{
// In this program we create 2 threads which each access the
// same Point object. Hence we will need to provide synchronization.
// Because in one case we set isMover = TRUE and in the other case
// we set isMover = FALSE, one of the threads continually changes
// the Point's x and y values while the other thread displays these
// values. Note that both threads have the same thread entry function
// even though they act completely differently.
// With the synchronization statements removed, you will have to
// look closely at the program output to spot those locations where
// x and y differ. They will differ by only 1, with x being the
// larger number.
Point * p = new Point();
ThreadY * o1 = new ThreadY(true, p);
HANDLE hth1;
unsigned uiThread1ID;
hth1 = (HANDLE)_beginthreadex(NULL, // security
0, // stack size
ThreadY::ThreadStaticStartUp,
o1, // arg list
CREATE_SUSPENDED, // so we can later call ResumeThread()
&uiThread1ID);
if (hth1 == 0)
printf("Failed to create thread 1\n");
DWORD dwExitCode;
GetExitCodeThread(hth1, &dwExitCode); // should be STILL_ACTIVE = 0x00000103 = 259
printf("initial thread 1 exit code = %u\n", dwExitCode);
ThreadY * o2 = new ThreadY(false, p);
HANDLE hth2;
unsigned uiThread2ID;
hth2 = (HANDLE)_beginthreadex(NULL, // security
0, // stack size
ThreadY::ThreadStaticStartUp,
o2, // arg list
CREATE_SUSPENDED, // so we can later call ResumeThread()
&uiThread2ID);
if (hth2 == 0)
printf("Failed to create thread 2\n");
GetExitCodeThread(hth2, &dwExitCode); // should be STILL_ACTIVE = 0x00000103 = 259
printf("initial thread 2 exit code = %u\n", dwExitCode);
// If we hadn't specified CREATE_SUSPENDED in the call to _beginthreadex()
// we wouldn't now need to call ResumeThread().
ResumeThread(hth1); // Jaeschke's // t1->Start();
ResumeThread(hth2);
// We now want the primary thread to sleep to allow time for
// the other threads to come alive. This ensures the primary
// thread will have to compete for access to the Point object.
Sleep(100);
// In C++/CLI the process continues until the last thread exits.
// That is, the thread's have independent lifetimes. Hence
// Jaeschke's original code was designed to show that the primary
// thread could exit and not influence the other threads.
// However in C++ the process terminates when the primary thread exits
// and when the process terminates all its threads are then terminated.
// Hence if you comment out the following waits, the non-primary
// threads will never get a chance to run.
WaitForSingleObject(hth1, INFINITE);
WaitForSingleObject(hth2, INFINITE);
GetExitCodeThread(hth1, &dwExitCode);
printf("thread 1 exited with code %u\n", dwExitCode);
GetExitCodeThread(hth2, &dwExitCode);
printf("thread 2 exited with code %u\n", dwExitCode);
// The handle returned by _beginthreadex() has to be closed
// by the caller of _beginthreadex().
CloseHandle(hth1);
CloseHandle(hth2);
delete o1;
o1 = NULL;
delete o2;
o2 = NULL;
printf("Primary thread terminating.\n");
//.........这里部分代码省略.........
bool WinMIDIDevice::Update()
{
// If the PlayerThread is signalled, then it's dead.
if (PlayerThread != nullptr &&
WaitForSingleObject(PlayerThread, 0) == WAIT_OBJECT_0)
{
static const char *const MMErrorCodes[] =
{
"No error",
"Unspecified error",
"Device ID out of range",
"Driver failed enable",
"Device already allocated",
"Device handle is invalid",
"No device driver present",
"Memory allocation error",
"Function isn't supported",
"Error value out of range",
"Invalid flag passed",
"Invalid parameter passed",
"Handle being used simultaneously on another thread",
"Specified alias not found",
"Bad registry database",
"Registry key not found",
"Registry read error",
"Registry write error",
"Registry delete error",
"Registry value not found",
"Driver does not call DriverCallback",
"More data to be returned",
};
static const char *const MidiErrorCodes[] =
{
"MIDI header not prepared",
"MIDI still playing something",
"MIDI no configured instruments",
"MIDI hardware is still busy",
"MIDI port no longer connected",
"MIDI invalid MIF",
"MIDI operation unsupported with open mode",
"MIDI through device 'eating' a message",
};
DWORD code = 0xABADCAFE;
GetExitCodeThread(PlayerThread, &code);
CloseHandle(PlayerThread);
PlayerThread = nullptr;
Printf("MIDI playback failure: ");
if (code < countof(MMErrorCodes))
{
Printf("%s\n", MMErrorCodes[code]);
}
else if (code >= MIDIERR_BASE && code < MIDIERR_BASE + countof(MidiErrorCodes))
{
Printf("%s\n", MidiErrorCodes[code - MIDIERR_BASE]);
}
else
{
Printf("%08x\n", code);
}
return false;
}
return true;
}
请发表评论