Ejemplo n.º 1
0
bool DecoderWindows::decodeCreateThread( DEBUG_EVENT &e, Event::ptr &newEvt, int_process* &proc, std::vector<Event::ptr> &events )
{
	pthrd_printf("Decoded CreateThread event, PID: %d, TID: %d\n", e.dwProcessId, e.dwThreadId);
	proc = ProcPool()->findProcByPid(e.dwProcessId);
	assert(proc);

	// FIXME once things actually work
	windows_process* wproc = dynamic_cast<windows_process*>(proc);
	assert(wproc);

	if(e.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT) {
		newEvt = WinEventThreadInfo::ptr(new WinEventThreadInfo((Dyninst::LWP)(e.dwThreadId), e.u.CreateProcessInfo.hThread,
			e.u.CreateProcessInfo.lpStartAddress, e.u.CreateProcessInfo.lpThreadLocalBase));
		newEvt->setThread(proc->threadPool()->initialThread()->thread());
		wproc->plat_setHandles(e.u.CreateProcessInfo.hProcess, e.u.CreateProcessInfo.hFile, (Dyninst::Address)e.u.CreateProcessInfo.lpBaseOfImage);
	} else {
		newEvt = WinEventNewThread::ptr(new WinEventNewThread((Dyninst::LWP)(e.dwThreadId), e.u.CreateThread.hThread,
			e.u.CreateThread.lpStartAddress, e.u.CreateThread.lpThreadLocalBase));
	}


	newEvt->setProcess(proc->proc());
	newEvt->setSyncType(Event::sync_process);
	events.push_back(newEvt);
	return true;
}
Ejemplo n.º 2
0
PCEventHandler::RTSignalResult
PCEventHandler::handleRTSignal(EventSignal::const_ptr ev, PCProcess *evProc) const {
    // Check whether the signal was sent from the RT library by checking variables
    // in the library -- if we cannot be determine whether this signal came from
    // the RT library, assume it did not.
    
    if( evProc->runtime_lib.size() == 0 ) return NotRTSignal;

    Address sync_event_breakpoint_addr = evProc->getRTEventBreakpointAddr();
    Address sync_event_id_addr = evProc->getRTEventIdAddr();
    Address sync_event_arg1_addr = evProc->getRTEventArg1Addr();

    int breakpoint = 0;
    int status = 0;
    Address arg1 = 0;
    int zero = 0;

    // Check that all addresses could be determined
    if(    sync_event_breakpoint_addr == 0 
        || sync_event_id_addr == 0 
        || sync_event_arg1_addr == 0 ) 
    {
        return NotRTSignal;
    }

    // First, check breakpoint...
    if( !evProc->readDataWord((const void *)sync_event_breakpoint_addr,
                sizeof(int), &breakpoint, false) ) return NotRTSignal;

    switch(breakpoint) {
        case NoRTBreakpoint:
            proccontrol_printf("%s[%d]: signal is not RT library signal\n",
                    FILE__, __LINE__);
            return NotRTSignal;
        case NormalRTBreakpoint:
        case SoftRTBreakpoint:
            // More work to do
            break;
        default:
            proccontrol_printf("%s[%d]: invalid value for RT library breakpoint variable\n",
                    FILE__, __LINE__);
            return NotRTSignal;
    }

    // Make sure we don't get this event twice....
    if( !evProc->writeDataWord((void *)sync_event_breakpoint_addr, sizeof(int), &zero) ) {
        proccontrol_printf("%s[%d]: failed to reset RT library breakpoint variable\n",
                FILE__, __LINE__);
        return NotRTSignal;
    }

    // Get the type of the event
    if( !evProc->readDataWord((const void *)sync_event_id_addr, sizeof(int),
                &status, false) ) return NotRTSignal;

    if( status == DSE_undefined ) {
        proccontrol_printf("%s[%d]: signal is not RT library signal\n", FILE__, __LINE__);
        return NotRTSignal;
    }

    // get runtime library arg1 address
    if( !evProc->readDataWord((const void *)sync_event_arg1_addr,
                evProc->getAddressWidth(), &arg1, false) ) {
        proccontrol_printf("%s[%d]: failed to read RT library arg1 variable\n",
                FILE__, __LINE__);
        return NotRTSignal;
    }

    if( !isValidRTSignal(ev->getSignal(), (RTBreakpointVal) breakpoint, arg1, status) ) return NotRTSignal;

    BPatch_process *bproc = BPatch::bpatch->getProcessByPid(evProc->getPid());
    if( bproc == NULL ) {
        proccontrol_printf("%s[%d]: no corresponding BPatch_process for process %d\n",
                FILE__, __LINE__, evProc->getPid());
        return ErrorInDecoding;
    }

    // See pcEventHandler.h (SYSCALL HANDLING) for a description of what
    // is going on here

    Event::ptr newEvt;

    switch(status) {
    case DSE_forkEntry:
        proccontrol_printf("%s[%d]: decoded forkEntry, arg = %lx\n",
                      FILE__, __LINE__, arg1);
		if (PCEventMuxer::useBreakpoint(EventType(EventType::Pre, EventType::Fork)))
		{
                proccontrol_printf("%s[%d]: reporting fork entry event to BPatch layer\n",
                        FILE__, __LINE__);
                BPatch::bpatch->registerForkingProcess(evProc->getPid(), NULL);
              
        }
        break;
    case DSE_forkExit:
        proccontrol_printf("%s[%d]: decoded forkExit, arg = %lx\n",
                      FILE__, __LINE__, arg1);
		if (PCEventMuxer::useBreakpoint(EventType(EventType::Post, EventType::Fork))) {
                proccontrol_printf("%s[%d]: reporting fork exit event to ProcControlAPI\n",
                        FILE__, __LINE__);
                newEvt = Event::ptr(new EventFork(EventType::Pre, (Dyninst::PID)arg1));
        }
        break;
    case DSE_execEntry:
        proccontrol_printf("%s[%d]: decoded execEntry, arg = %lx\n",
                      FILE__, __LINE__, arg1);
        // For now, just note that the process is going to exec
        evProc->setExecing(true);
        break;
    case DSE_execExit:
        proccontrol_printf("%s[%d]: decoded execExit, arg = %lx\n",
                      FILE__, __LINE__, arg1);
        // This is not currently used by Dyninst internals for anything
        // We rely on ProcControlAPI for this and it should be impossible
        // to get this via a breakpoint
        return ErrorInDecoding;
    case DSE_exitEntry:
        proccontrol_printf("%s[%d]: decoded exitEntry, arg = %lx\n",
                      FILE__, __LINE__, arg1);
        /* Entry of exit, used for the callback. We need to trap before
           the process has actually exited as the callback may want to
           read from the process */
		if (PCEventMuxer::useBreakpoint(EventType(EventType::Pre, EventType::Exit))) {
			if (PCEventMuxer::useCallback(EventType(EventType::Pre, EventType::Exit))) {
                proccontrol_printf("%s[%d]: reporting exit entry event to ProcControlAPI\n",
                        FILE__, __LINE__);
                newEvt = Event::ptr(new EventExit(EventType::Pre, (int)arg1));
			}
			else {
                proccontrol_printf("%s[%d]: reporting exit entry event to BPatch layer\n",
                        FILE__, __LINE__);
                evProc->triggerNormalExit((int)arg1);
			}
        }
        break;
    case DSE_loadLibrary:
        proccontrol_printf("%s[%d]: decoded loadLibrary (error), arg = %lx\n",
                      FILE__, __LINE__, arg1);
        // This is no longer used
        return ErrorInDecoding;
    case DSE_lwpExit:
        proccontrol_printf("%s[%d]: decoded lwpExit (error), arg = %lx\n",
                      FILE__, __LINE__, arg1);
        // This is not currently used on any platform
        return ErrorInDecoding;
    case DSE_snippetBreakpoint:
        proccontrol_printf("%s[%d]: decoded snippetBreak, arg = %lx\n",
                      FILE__, __LINE__, arg1);
        bproc->setLastSignal(ev->getSignal());
        evProc->setDesiredProcessState(PCProcess::ps_stopped);
        break;
    case DSE_stopThread:
        proccontrol_printf("%s[%d]: decoded stopThread, arg = %lx\n",
                      FILE__, __LINE__, arg1);
        bproc->setLastSignal(ev->getSignal());
        if( !handleStopThread(evProc, arg1) ) {
            proccontrol_printf("%s[%d]: failed to handle stopped thread event\n",
                    FILE__, __LINE__);
            return ErrorInDecoding;
        }
        break;
    case DSE_dynFuncCall:
        proccontrol_printf("%s[%d]: decoded dynamic callsite event, arg = %lx\n",
                FILE__, __LINE__, arg1);
        if( !handleDynFuncCall(evProc, bproc, arg1) ) {
            proccontrol_printf("%s[%d]: failed to handle dynamic callsite event\n",
                    FILE__, __LINE__);
            return ErrorInDecoding;
        }
        break;
    case DSE_userMessage:
        proccontrol_printf("%s[%d]: decoded user message event, arg = %lx\n",
                FILE__, __LINE__, arg1);
        if( !handleUserMessage(evProc, bproc, arg1) ) {
            proccontrol_printf("%s[%d]: failed to handle user message event\n",
                    FILE__, __LINE__);
            return ErrorInDecoding;
        }
        break;
    default:
        return NotRTSignal;
    }

    // Behavior common to all syscalls
    if( newEvt != NULL ) {
        // Report the event to ProcControlAPI, make sure process remains stopped
        evProc->setReportingEvent(true);

        newEvt->setProcess(ev->getProcess());
        newEvt->setThread(ev->getThread());

        // In the callback thread, the process and thread are stopped
        newEvt->setSyncType(Event::sync_process);
        newEvt->setUserEvent(true);

        ProcControlAPI::mbox()->enqueue(newEvt);
    }

    return IsRTSignal;
}
Ejemplo n.º 3
0
bool DecoderWindows::decode(ArchEvent *ae, std::vector<Event::ptr> &events)
{
	static Address ntdll_ignore_breakpoint_address = 0;

	assert(ae);
	ArchEventWindows* winEvt = static_cast<ArchEventWindows*>(ae);
	assert(winEvt);
	Event::ptr newEvt = Event::ptr();
	int_thread *thread = ProcPool()->findThread((Dyninst::LWP)(winEvt->evt.dwThreadId));
	int_process* proc = ProcPool()->findProcByPid(winEvt->evt.dwProcessId);
	if(!proc) { return false; }
	windows_process* windows_proc = dynamic_cast<windows_process*>(proc);
	if(!windows_proc)
	{
		perr_printf("DecoderWindows::decode() called on nonexistent/deleted process %d/%d\n", 
			winEvt->evt.dwProcessId, winEvt->evt.dwThreadId);
		return false;
	}
	//windows_proc->clearPendingDebugBreak();

	DEBUG_EVENT e = winEvt->evt;

	switch(e.dwDebugEventCode)
	{
	case CREATE_PROCESS_DEBUG_EVENT:
	case CREATE_THREAD_DEBUG_EVENT:
		pthrd_printf("decodeProcess/decodeThreadEvent\n");
		return decodeCreateThread(e, newEvt, proc, events);
	case EXCEPTION_DEBUG_EVENT:
		pthrd_printf("decodeException\n");
		switch(e.u.Exception.ExceptionRecord.ExceptionCode)
		{
		case EXCEPTION_SINGLE_STEP:
			pthrd_printf("Decoding singleStep event on PID %d, TID %d\n", e.dwProcessId, e.dwThreadId);
			newEvt = decodeSingleStepEvent(e, proc, thread);
			break;
			//fprintf(stderr, "Decoded Single-step event at 0x%lx, PID: %d, TID: %d\n", e.u.Exception.ExceptionRecord.ExceptionAddress, e.dwProcessId, e.dwThreadId);
		case EXCEPTION_BREAKPOINT:
			// Case 1: breakpoint is real breakpoint
			pthrd_printf("Caught breakpoint for pid %d, tid %d, PC 0x%lx\n", e.dwProcessId, e.dwThreadId, e.u.Exception.ExceptionRecord.ExceptionAddress);
			newEvt = decodeBreakpointEvent(e, proc, thread);
			if(newEvt)
			{
				pthrd_printf("Decoded Breakpoint event at 0x%lx, PID: %d, TID: %d\n", e.u.Exception.ExceptionRecord.ExceptionAddress, e.dwProcessId, e.dwThreadId);
				//fprintf(stderr, "Decoded Breakpoint event at 0x%lx, PID: %d, TID: %d\n", e.u.Exception.ExceptionRecord.ExceptionAddress, e.dwProcessId, e.dwThreadId);
				break;
			}
			else
			{
				if(proc->getState() != int_process::neonatal &&
					proc->getState() != int_process::neonatal_intermediate)
				{
					bool didSomething = false;

				   if (windows_proc->pendingDebugBreak())
					{
						pthrd_printf("Decoded Stop event, PID: %d, TID: %d\n", e.dwProcessId, e.dwThreadId);
						//newEvt = Event::ptr(new EventStop());
						windows_proc->setStopThread(e.dwThreadId);
						return true;
					}
					else
					{
						pthrd_printf("Decoded unhandled exception (breakpoint) event, PID: %d, TID: %d\n", e.dwProcessId, e.dwThreadId);
						// Case 3: breakpoint that's not from us, while running. Pass on exception.
						GeneratorWindows* winGen = static_cast<GeneratorWindows*>(GeneratorWindows::getDefaultGenerator());
						newEvt = EventSignal::ptr(new EventSignal(e.u.Exception.ExceptionRecord.ExceptionCode));
					}
				}
				else
				{
					// Case 4: breakpoint in ntdll.dll due to startup. This should be skipped and we should bootstrap.
					pthrd_printf("Breakpoint due to startup, ignoring\n");
					newEvt = Event::ptr(new EventBootstrap());
					ntdll_ignore_breakpoint_address = (Address) e.u.Exception.ExceptionRecord.ExceptionAddress;
					if(!thread) {
						pthrd_printf("DEBUG: Missing thread on startup breakpoint\n");
					}
				}
			}
			break;
		case EXCEPTION_ILLEGAL_INSTRUCTION:
			{
				pthrd_printf("SIGILL in mutatee\n");
				GeneratorWindows* winGen = static_cast<GeneratorWindows*>(GeneratorWindows::getDefaultGenerator());
				winGen->markUnhandledException(e.dwProcessId);
				newEvt = EventSignal::ptr(new EventSignal(e.u.Exception.ExceptionRecord.ExceptionCode));
				assert(0);
			}
			break;
		case EXCEPTION_ACCESS_VIOLATION:
			{
                // check if this is first chance or second chance:
                if (e.u.Exception.dwFirstChance != 0) {
                    int sig = e.u.Exception.ExceptionRecord.ExceptionCode;
                    int cause = e.u.Exception.ExceptionRecord.ExceptionInformation[0];
                    Address addr = e.u.Exception.ExceptionRecord.ExceptionInformation[1];
                    EventSignal* evSig = nullptr;
                    switch (cause) {
                    case 0: evSig = new EventSignal(sig, addr, EventSignal::ReadViolation, true); break;
                    case 1: evSig = new EventSignal(sig, addr, EventSignal::WriteViolation, true); break;
                    case 8: evSig = new EventSignal(sig, addr, EventSignal::ExecuteViolation, true); break;
                    default: evSig = new EventSignal(sig, addr, EventSignal::Unknown, true); break;
                    }
                    newEvt = EventSignal::ptr(evSig);
                } else {
                    pthrd_printf("segfault in mutatee, thread %d/%d\n", e.dwProcessId, e.dwThreadId);
				    unsigned problemArea = (unsigned int)(e.u.Exception.ExceptionRecord.ExceptionAddress);
				    cerr << "SEGFAULT @ " << hex << problemArea << dec << endl;
				    dumpSurroundingMemory(problemArea, proc);
				    GeneratorWindows* winGen = static_cast<GeneratorWindows*>(GeneratorWindows::getDefaultGenerator());
				    winGen->markUnhandledException(e.dwProcessId);
				    newEvt = EventSignal::ptr(new EventSignal(e.u.Exception.ExceptionRecord.ExceptionCode));
				    cerr << "Signal is " << e.u.Exception.ExceptionRecord.ExceptionCode << endl;
                }
			}
			break;
			// Thread naming exception. Ignore.
		case EXCEPTION_DEBUGGER_IO: {
			pthrd_printf("Debugger I/O exception: %lx\n", e.u.Exception.ExceptionRecord.ExceptionInformation[0]);
			newEvt = EventNop::ptr(new EventNop());
			newEvt->setSyncType(Event::async);
			break;
		}
		default:
			{
				pthrd_printf("Decoded unhandled exception event, PID: %d, TID: %d, Exception code = 0x%lx, Exception addr = 0x%lx\n", e.dwProcessId, e.dwThreadId,
					e.u.Exception.ExceptionRecord.ExceptionCode, e.u.Exception.ExceptionRecord.ExceptionAddress);
				GeneratorWindows* winGen = static_cast<GeneratorWindows*>(GeneratorWindows::getDefaultGenerator());
				winGen->markUnhandledException(e.dwProcessId);
				newEvt = EventSignal::ptr(new EventSignal(e.u.Exception.ExceptionRecord.ExceptionCode));
			}
			break;
		}
		break;
	case EXIT_PROCESS_DEBUG_EVENT:
		{
			pthrd_printf("Decoded ProcessExit event, PID: %d, TID: %d\n", e.dwProcessId, e.dwThreadId);
			if(proc->wasForcedTerminated()) {
				newEvt = EventForceTerminate::ptr(new EventForceTerminate(e.u.ExitProcess.dwExitCode));
			}
			else {
				newEvt = EventExit::ptr(new EventExit(EventType::Pre, e.u.ExitProcess.dwExitCode));
			}
//			GeneratorWindows* winGen = static_cast<GeneratorWindows*>(GeneratorWindows::getDefaultGenerator());
//			winGen->removeProcess(proc);
			newEvt->setSyncType(Event::sync_process);
			newEvt->setProcess(proc->proc());
			// Since we're doing thread exit/proc exit, and this means the thread will go away first,
			// we don't set the thread here
			if(thread)
				newEvt->setThread(thread->thread());
			// We do this here because the generator thread will exit before updateSyncState otherwise
//			int_threadPool::iterator i = proc->threadPool()->begin();
//			for (; i != proc->threadPool()->end(); i++) {
//				(*i)->getGeneratorState().setState(int_thread::exited);
//		 		(*i)->setExitingInGenerator(true);
//			}
			events.push_back(newEvt);

			return true;
		}
		break;
	case EXIT_THREAD_DEBUG_EVENT:
		pthrd_printf("Decoded ThreadExit event, PID: %d, TID: %d\n", e.dwProcessId, e.dwThreadId);
		if(thread) {
			thread->getGeneratorState().setState(int_thread::exited);
			thread->setExitingInGenerator(true);
			if (e.dwThreadId == windows_proc->getStopThread()) {
				newEvt = EventWinStopThreadDestroy::ptr(new EventWinStopThreadDestroy(EventType::Pre));
				windows_proc->clearStopThread();
			}
			else {
				newEvt = EventLWPDestroy::ptr(new EventLWPDestroy(EventType::Pre));
			}
		} else {
			// If the thread is NULL, we can't give the user an event with a valid thread object anymore.
			// So fail the decode.
			return false;
		}
		break;
	case LOAD_DLL_DEBUG_EVENT:
		pthrd_printf("Decoded LoadDLL event, PID: %d, TID: %d\n", e.dwProcessId, e.dwThreadId);
		newEvt = decodeLibraryEvent(e, proc);
		break;
	case UNLOAD_DLL_DEBUG_EVENT:
		pthrd_printf("Decoded UnloadDLL event, PID: %d, TID: %d\n", e.dwProcessId, e.dwThreadId);
		newEvt = decodeLibraryEvent(e, proc);
		break;
	case OUTPUT_DEBUG_STRING_EVENT:
		{
			TCHAR buf[1024];
			unsigned long bytes_read = 0;
			windows_process* winProc = dynamic_cast<windows_process*>(proc);
			BOOL result = ::ReadProcessMemory(winProc->plat_getHandle(), e.u.DebugString.lpDebugStringData, buf, 
				e.u.DebugString.nDebugStringLength, &bytes_read);
			if(result) {
				pthrd_printf("Decoded DebugString event, string: %s\n", buf);
			} else {
				pthrd_printf("Decoded DebugString event, but string was not readable!\n");
			}

			break;
		}
	case RIP_EVENT:
		pthrd_printf("Decoded RIP event, PID: %d, TID: %d, error = 0x%lx\n", e.dwProcessId, e.dwThreadId,
			e.u.RipInfo.dwError);
		newEvt = EventCrash::ptr(new EventCrash(e.u.RipInfo.dwError));
		assert(0);
		break;
	default:
		assert(!"invalid event type");
		return false;
	}
	if(newEvt)
	{
		assert(proc);
		if(newEvt->getSyncType() == Event::unset)
			newEvt->setSyncType(Event::sync_process);
		if(thread) {
			newEvt->setThread(thread->thread());
		}
		newEvt->setProcess(proc->proc());
		events.push_back(newEvt);
	}
	return true;
}