int
bu_fchmod(int fd,
	  unsigned long pmode)
{
#ifdef HAVE_FCHMOD
    return fchmod(fd, (mode_t)pmode);
#else
    /* Presumably Windows, so get dirty.  We can call chmod() instead
     * of fchmod(), but that means we need to know the file name.
     * This isn't portably knowable, but Windows provides a roundabout
     * way to figure it out.
     *
     * If we were willing to limit ourselves to Windows 2000 or 7+, we
     * could call GetModuleFileNameEx() but there are reports that
     * it's rather unreliable.
     */
    {
	char filepath[MAXPATHLEN+1];
	HANDLE h = (HANDLE)_get_osfhandle(fd);
	GetFileNameFromHandle(h, filepath);
	return chmod(filepath, pmode);
    }
#endif
}
Exemple #2
0
void *Ploopgrab(LPVOID args)
{
    DEBUG_EVENT  dbg;
    DWORD cont = DBG_CONTINUE, size = 0;
    TCHAR pszFilename[MAX_PATH+1];
    DWORD64 mod;
    struct proc_uc *tmp = args;
    struct ps_prochandle *P = tmp->ps;
    int first_execp = 0;
    BOOL wow = 0;
    char *s;
    DWORD Options = SymGetOptions();

    if (DebugActiveProcess(P->pid) == 0) {
        dprintf( "failed to debug process (%d): %d\n", P->pid, GetLastError() );
        pthread_mutex_lock(&P->mutex);
        P->status = PS_STOP;
        P->flags = CREATE_FAILED;
        if (P->status == PS_STOP)
            pthread_cond_signal(&P->cond);
        pthread_mutex_unlock(&P->mutex);
        return NULL;
    }

    DebugSetProcessKillOnExit(FALSE);

    P->wstat = 0;
    P->exitcode = 0;
    P->event = CreateEvent(NULL,FALSE,FALSE,NULL);
    P->dll_load_order = 1;
    SymSetOptions(Options|SYMOPT_INCLUDE_32BIT_MODULES|SYMOPT_DEFERRED_LOADS|SYMOPT_DEBUG);

    while (1) {
        if (WaitForDebugEvent(&dbg, INFINITE) == 0) {
            return NULL;
        }

        cont = DBG_CONTINUE;
        pthread_mutex_lock(&P->mutex);

        switch (dbg.dwDebugEventCode) {
        case CREATE_PROCESS_DEBUG_EVENT:
            P->thandle = dbg.u.CreateProcessInfo.hThread;
            P->phandle = dbg.u.CreateProcessInfo.hProcess;
            if ((SymInitialize(P->phandle, 0, FALSE) == FALSE)) {
                dprintf("SymInitialize failed (%d): %d\n", P->pid, GetLastError());
                break;
            }

            s = GetFileNameFromHandle(dbg.u.CreateProcessInfo.hFile, pszFilename);
            addmodule(P, dbg.u.CreateProcessInfo.hFile, s, dbg.u.CreateProcessInfo.lpBaseOfImage, PE_TYPE_EXE, P->dll_load_order);
            size = GetFileSize(dbg.u.CreateProcessInfo.hFile, NULL);
            if (size == INVALID_FILE_SIZE) {
                size = 0;
            }

            if ((mod = SymLoadModuleEx(P->phandle,  dbg.u.CreateProcessInfo.hFile, s, NULL,
                                       (ULONG_PTR) dbg.u.CreateProcessInfo.lpBaseOfImage, size, NULL, 0)) == FALSE) {
                dprintf("SymLoadModule64 Failed for %s: %d\n", s, GetLastError());
                break;
            }

#if __amd64__
            if (Is32bitProcess(P->phandle)) {
                P->model = PR_MODEL_ILP32;
                wow = 1;
            } else
                P->model = PR_MODEL_ILP64;
#else
            P->model = PR_MODEL_ILP32;
#endif

            CloseHandle(dbg.u.CreateProcessInfo.hFile);
            P->status = PS_RUN;
            P->msg.type = 0;
            break;
        case CREATE_THREAD_DEBUG_EVENT:
            P->status = PS_RUN;
            P->msg.type = 0;
            break;
        case LOAD_DLL_DEBUG_EVENT:
            s = GetFileNameFromHandle(dbg.u.LoadDll.hFile, pszFilename);
            if (first_execp) {
                P->dll_load_order++;
            }
            addmodule(P, dbg.u.LoadDll.hFile, s, dbg.u.LoadDll.lpBaseOfDll, PE_TYPE_DLL, P->dll_load_order);
            size = GetFileSize(dbg.u.CreateProcessInfo.hFile, NULL);
            if (size == INVALID_FILE_SIZE) {
                size = 0;
            }
#if __amd64__
            /* Not tracing 64 bit dlls for 32 bit process */
            if (P->model == PR_MODEL_ILP32 && is64bitmodule(dbg.u.LoadDll.lpBaseOfDll, s)) {
                CloseHandle(dbg.u.LoadDll.hFile );
                break;
            }
#endif
            if ((mod = SymLoadModuleEx(P->phandle,  dbg.u.LoadDll.hFile, s, NULL,
                                       (ULONG_PTR) dbg.u.LoadDll.lpBaseOfDll, size, NULL, 0)) == FALSE) {
                dprintf("SymLoadModule64 failed for %s: %d\n", s, GetLastError());
                break;
            }

            CloseHandle(dbg.u.LoadDll.hFile );

            if (first_execp == 0) {
                P->status = PS_RUN;
                P->msg.type = RD_DLACTIVITY;
            } else {
                P->status = PS_STOP;
                P->msg.type = RD_DLACTIVITY;
            }
            break;
        case UNLOAD_DLL_DEBUG_EVENT:
            if (SymUnloadModule64(P->phandle, (ULONG_PTR) dbg.u.UnloadDll.lpBaseOfDll) ==  FALSE) {
                dprintf("SymUnloadModule64 failed-Imagebase %p: %d\n", dbg.u.UnloadDll.lpBaseOfDll, GetLastError());
                break;
            }
            delmodule(P, (ULONG64) dbg.u.UnloadDll.lpBaseOfDll);
            P->status = PS_RUN;
            P->msg.type = RD_DLACTIVITY;
            break;
        case EXIT_PROCESS_DEBUG_EVENT:
            P->exitcode = dbg.u.ExitProcess.dwExitCode;
            P->status = PS_UNDEAD;
            P->msg.type = RD_NONE;
            //SymCleanup(P->phandle);
            break;
        case EXIT_THREAD_DEBUG_EVENT:
            P->status = PS_RUN;
            P->msg.type = 0;
            break;
        case EXCEPTION_DEBUG_EVENT:
            switch(dbg.u.Exception.ExceptionRecord.ExceptionCode) {
            case EXCEPTION_BREAKPOINT:
                if (first_execp++ == 0) {
                    pthread_cond_signal(&P->cond);
                }
                P->status = PS_STOP;
                P->msg.type = 0;

                break;
            default:
                if (dbg.u.Exception.dwFirstChance == 0)
                    P->wstat = dbg.u.Exception.ExceptionRecord.ExceptionCode;
                P->status = PS_RUN;
                cont = DBG_EXCEPTION_NOT_HANDLED;
                break;
            }
            break;
        default:
            P->status = PS_RUN;
            dprintf("Debug Event not processed: %d\n", dbg.dwDebugEventCode);
            break;
        }

        if (P->status != PS_RUN)
            SetEvent(P->event);

        while (P->status == PS_STOP)
            pthread_cond_wait(&P->cond, &P->mutex);
        pthread_mutex_unlock(&P->mutex);

        ContinueDebugEvent(dbg.dwProcessId, dbg.dwThreadId, cont);
    }

}
Exemple #3
0
static void *Ploopcreate(LPVOID args)
{
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    DEBUG_EVENT  dbg;
    DWORD cont;
    BOOL wow = 0;
    DWORD Options = SymGetOptions(), excep, size = 0;
    TCHAR pszFilename[MAX_PATH+1];
    struct proc_uc *tmp = args;
    struct ps_prochandle *P = tmp->ps;
    int first_execp = 0;
    char *s, targs[256], *ctmp;
    char *const *argv = tmp->args;
    int len;

    ctmp = targs;
    while (*argv != NULL) {
        len = strlen(*argv);
        sprintf(ctmp, "%s ", *argv);
        ctmp = ctmp + len + 1;
        argv++;
    }

    *ctmp = '\0';
    ZeroMemory( &si, sizeof(si) );
    si.cb = sizeof(si);
    ZeroMemory( &pi, sizeof(pi) );
    if(!CreateProcess( NULL,   //  module name
                       targs,        // Command line
                       NULL,           // Process handle not inheritable
                       NULL,           // Thread handle not inheritable
                       FALSE,          // Set handle inheritance to FALSE
                       DEBUG_ONLY_THIS_PROCESS,              // No creation flags
                       NULL,           // Use parent's environment block
                       NULL,           // Use parent's starting directory
                       &si,            // Pointer to STARTUPINFO structure
                       &pi )           // Pointer to PROCESS_INFORMATION structure
      ) {
        pthread_mutex_lock(&P->mutex);
        P->status = PS_STOP;
        P->flags = CREATE_FAILED;
        pthread_cond_signal(&P->cond);
        pthread_mutex_unlock(&P->mutex);
        return NULL;
    }
    P->pid = pi.dwProcessId;
    P->tid = pi.dwThreadId;
    P->wstat = 0;
    P->exitcode = 0;
    P->event = CreateEvent(NULL,FALSE,FALSE,NULL);
    P->dll_load_order = 1;
#if __amd64__
    /* There seems to be a bug in 64 bit version of dbghelp.dll
     * when SYMOPT_DEFERRED_LOADS is set,
     * dtrace -n "pid$target:kernel32::entry, pid$target:KernelBase::entry" -c test.exe,
     * when SymEnumSymbols (Psymbol_iter_by_addr) is called on this two dll,
     * the second call (KernelBase) will enumerate the
     * symbols from the previous enumurated (kernel32) dll (from the first call).
     * This behaviour is not present in 32 bit.
     */
    Options &= ~SYMOPT_DEFERRED_LOADS;
#endif
    SymSetOptions(Options|SYMOPT_INCLUDE_32BIT_MODULES|SYMOPT_DEBUG);

    while (1) {
        if (WaitForDebugEvent(&dbg, INFINITE) == 0) {
            return NULL;
        }
        cont = DBG_CONTINUE;
        pthread_mutex_lock(&P->mutex);

        switch (dbg.dwDebugEventCode) {
        case CREATE_PROCESS_DEBUG_EVENT:

            P->phandle = dbg.u.CreateProcessInfo.hProcess;
            P->thandle = dbg.u.CreateProcessInfo.hThread;
            if ((SymInitialize(P->phandle, 0, FALSE) == FALSE)) {
                dprintf("SymInitialize failed: %d\n", GetLastError());
                break;
            }

            s = GetFileNameFromHandle(dbg.u.CreateProcessInfo.hFile, pszFilename);
            addmodule(P, dbg.u.CreateProcessInfo.hFile, s, dbg.u.CreateProcessInfo.lpBaseOfImage,
                      PE_TYPE_EXE, P->dll_load_order);
            size = GetFileSize(dbg.u.CreateProcessInfo.hFile, NULL);
            if (size == INVALID_FILE_SIZE) {
                size = 0;
            }
            if (SymLoadModuleEx(P->phandle, dbg.u.CreateProcessInfo.hFile, s, NULL,
                                (ULONG_PTR) dbg.u.CreateProcessInfo.lpBaseOfImage, size, NULL, 0) == 0) {
                dprintf("SymLoadModule64 failed for %s:%d\n", s, GetLastError());
                break;
            }

#if __amd64__
            if (Is32bitProcess(P->phandle)) {
                P->model = PR_MODEL_ILP32;
                wow = 1;
            } else
                P->model = PR_MODEL_ILP64;
#else
            P->model = PR_MODEL_ILP32;
#endif
            P->status = PS_STOP;
            P->msg.type = 0;
            CloseHandle(dbg.u.CreateProcessInfo.hFile);
            pthread_cond_signal(&P->cond);
            break;
        case CREATE_THREAD_DEBUG_EVENT:
            P->status = PS_RUN;
            P->msg.type = 0;
            break;
        case LOAD_DLL_DEBUG_EVENT:
            s = GetFileNameFromHandle(dbg.u.LoadDll.hFile, pszFilename);
            if (first_execp == 2) {
                P->dll_load_order++;
            }
            addmodule(P, dbg.u.LoadDll.hFile, s, dbg.u.LoadDll.lpBaseOfDll, PE_TYPE_DLL, P->dll_load_order);

            size = GetFileSize(dbg.u.LoadDll.hFile, NULL);
            if (size == INVALID_FILE_SIZE) {
                size = 0;
            }
#if __amd64__
            /* Not tracing 64 bit dlls for 32 bit process */
            if (P->model == PR_MODEL_ILP32 && is64bitmodule(dbg.u.LoadDll.lpBaseOfDll, s)) {
                CloseHandle(dbg.u.LoadDll.hFile );
                break;
            }
#endif
            if (SymLoadModuleEx(P->phandle, dbg.u.LoadDll.hFile, s, NULL,
                                (ULONG_PTR) dbg.u.LoadDll.lpBaseOfDll, size, NULL, 0) == FALSE) {
                dprintf("SymLoadModule64 dailed for %s:%d\n", s, GetLastError());
                break;
            }

            CloseHandle(dbg.u.LoadDll.hFile );
            P->status = PS_STOP;
            P->msg.type = RD_DLACTIVITY;
            break;
        case UNLOAD_DLL_DEBUG_EVENT:
            if (SymUnloadModule64(P->phandle, (ULONG_PTR) dbg.u.UnloadDll.lpBaseOfDll) ==  FALSE) {
                dprintf("SymUnloadModule64 failed-Imagebase %p:%d\n", dbg.u.UnloadDll.lpBaseOfDll, GetLastError());
                break;
            }
            delmodule(P, (ULONG64) dbg.u.UnloadDll.lpBaseOfDll);
            P->status = PS_RUN;
            P->msg.type = RD_DLACTIVITY;
            break;
        case EXIT_PROCESS_DEBUG_EVENT:
            P->exitcode = dbg.u.ExitProcess.dwExitCode;
            P->status = PS_UNDEAD;
            P->msg.type = RD_NONE;
            break;
        case EXIT_THREAD_DEBUG_EVENT:
            P->status = PS_RUN;
            P->msg.type = 0;
            break;
        case EXCEPTION_DEBUG_EVENT:
            switch(excep = dbg.u.Exception.ExceptionRecord.ExceptionCode) {
            case EXCEPTION_BREAKPOINT:
            case 0x4000001F:	/* WOW64 exception breakpoint */
                /* NOTE: Dtrace sets a BP at main (entry point of the process), which is implemented
                 * with Psetbkpt, Pdelbkpt & Pexecbkpt. But I have implemnted it here.
                 */
                if ((excep == EXCEPTION_BREAKPOINT && first_execp == 0 && wow == 0) ||
                        (excep == 0x4000001F && first_execp == 0 && wow == 1) ) {
                    SYMBOL_INFO *Symbol;
                    GElf_Sym sym;
                    ULONG64 buffer[(sizeof(SYMBOL_INFO) +  MAX_SYM_NAME * sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)];

                    Symbol = (SYMBOL_INFO *) buffer;
                    Symbol->SizeOfStruct= sizeof(SYMBOL_INFO );
                    Symbol->MaxNameLen = MAX_SYM_NAME;

                    if (Pxlookup_by_name(P, LM_ID_BASE, "a.out", "main", &sym, NULL) != 0 &&
                            Pxlookup_by_name(P, LM_ID_BASE, "a.out", "WinMain", &sym, NULL) != 0) {
                        dprintf("failed to find entry point (main):%d\n", GetLastError());
                        break;
                    }

                    if (setbkpt(P, (uintptr_t) sym.st_value) != 0) {
                        dprintf("failed to set breakpoint for %s at address %p\n", Symbol->Name, Symbol->Address);
                        break;
                    }

                    first_execp = 1;
                    P->status = PS_RUN;
                    P->msg.type = 0;
                    break;
                }

                if (dbg.u.Exception.ExceptionRecord.ExceptionAddress != (PVOID) P->addr) {
                    dprintf("expecting execption at %p:but recived from %p\n", P->addr,
                            dbg.u.Exception.ExceptionRecord.ExceptionAddress);
                    P->status = PS_RUN;
                    cont = DBG_EXCEPTION_NOT_HANDLED;
                    break;
                }

                if (delbkpt(P, P->addr) != 0) {
                    dprintf("failed to delete brk point at %p:(main)\n", P->addr);
                    break;
                }

                if (adjbkpt(P, wow) != 0) {
                    dprintf("failed to normalize brk point (main)\n");
                    break;
                }
                first_execp = 2;
                P->status = PS_STOP;
                P->msg.type = RD_MAININIT;
                break;/*
				if (first_execp == 0) {
					P->status = PS_STOP;
					P->msg.type = RD_MAININIT;
					first_execp = 2;
				} else {
					P->status = PS_RUN;
					cont = DBG_EXCEPTION_NOT_HANDLED;
				}
				break;*/

            default:
                if (dbg.u.Exception.dwFirstChance == 0)
                    P->wstat = dbg.u.Exception.ExceptionRecord.ExceptionCode;
                P->status = PS_RUN;
                cont = DBG_EXCEPTION_NOT_HANDLED;
                break;
            }
            break;
        default:
            P->status = PS_RUN;
            dprintf("Debug Event not processed: %d\n", dbg.dwDebugEventCode);
            break;
        }

        if (P->status != PS_RUN)
            SetEvent(P->event);
        while (P->status == PS_STOP)
            pthread_cond_wait(&P->cond, &P->mutex);
        pthread_mutex_unlock(&P->mutex);

        ContinueDebugEvent(dbg.dwProcessId, dbg.dwThreadId, cont);
    }

}
int wmain(int argc, WCHAR *argv[])
{

	/* Display welcome message */
	printf("handle_monitor %s - Adam Kramer\n", VERSION_NUMBER);

	/* These variables hold configuration options, which can be altered by arguments passed */
	BOOL bIncludeSigned = FALSE;
	BOOL bSuspendProcess = FALSE;
	BOOL bVerbose = FALSE;
	DWORD dNumberCycles = 10;
	DWORD dHandleChangeThreshold = 10;
	DWORD dIterationPause = 1000;

	/* Process arguments */
	if (argc > 1)
	{
		for (int iNumberArgs = 1; iNumberArgs < argc; iNumberArgs++)
		{
			/* /signed - will include signed files in the alerts */
			if (!wcscmp(argv[iNumberArgs], L"/signed"))
			{
				bIncludeSigned = TRUE;
				printf("Info: Will show signed files as well as unsigned\n");
			}
			/* /suspect - will attempt to suspend suspicious processes */
			else if (!wcscmp(argv[iNumberArgs], L"/suspend"))
			{
				bSuspendProcess = TRUE;
				printf("Info: Will attempt to suspend suspicious processes\n");
			}
			/* /verbose - will display details of iterations and hidden results */
			else if (!wcscmp(argv[iNumberArgs], L"/verbose"))
			{
				bVerbose = TRUE;
				printf("Info: Will display verbose status messages\n");
			}
			/* /cycles - allows the user to set cycles completed before analysis */
			else if (WCHAR* wSetCycles = wcsstr(argv[iNumberArgs], L"/cycles="))
			{
				wSetCycles = wcschr(wSetCycles, '=');

				if (!(dNumberCycles = _wtol(++wSetCycles)))
				{
					printf("Error: Invalid /cycles parameter\n");
					return 1;
				}

				printf("Info: Setting number of cycles to %d\n", dNumberCycles);
			}
			/* /threshold - allows the user to set the threshold for minimum number of new handles which are suspicious */
			else if (WCHAR* wSetThreshold = wcsstr(argv[iNumberArgs], L"/threshold="))
			{
				wSetThreshold = wcschr(wSetThreshold, '=');

				if (!(dHandleChangeThreshold = _wtol(++wSetThreshold)))
				{
					printf("Error: Invalid /threshold parameter\n");
					return 1;
				}

				printf("Info: Setting handle threshold to %d\n", dHandleChangeThreshold);
			}
			/* /pause - allows the user to set a pause between cycles (reduce system load, increase window for finding something) */
			else if (WCHAR* wSetPause = wcsstr(argv[iNumberArgs], L"/pause="))
			{
				wSetPause = wcschr(wSetPause, '=');

				dIterationPause = _wtol(++wSetPause);
				printf("Info: Setting pause between cycles to %dms\n", dIterationPause);
			}
		}
		/* End of argument processing */
	}
	else
	{
		/* No argument passed, accordingly display the usage instructions */
		printf("Usage: handle_monitor.exe <optional parameters>\n\n");
		printf("Optional parameters:\n");
		printf("/cycles=X - Set number of cycles before a review [Default: 10]\n");
		printf("/threshold=X - Set suspicion threshold for number of new handles [Default: 10]\n");
		printf("/pause=X - Set pause in milliseconds between cycles [Default: 1000]\n");
		printf("/signed - Include signed executables in review process\n");
		printf("/suspend - Suspend processes identified as suspicious\n");
		printf("/verbose - Display verbose progress messages\n\n");
		printf("Info: No parameters specified, launching monitoring (Ctrl+C to stop)\n");
	}

	/* Import functions manually from NTDLL */
	_NtQuerySystemInformation NtQuerySystemInformation =
		(_NtQuerySystemInformation)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQuerySystemInformation");

	_NtDuplicateObject NtDuplicateObject =
		(_NtDuplicateObject)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtDuplicateObject");

	_NtQueryObject NtQueryObject =
		(_NtQueryObject)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQueryObject");

	/* Master loop! - This runs forever until a user presses Ctrl+C */
	for (;;)
	{
		/* Update user that process is starting (if /verbose mode activiated) */
		if (bVerbose)
			printf("Verbose Info: Starting sequence\n");

		/* Variables used for retrieving handles */
		NTSTATUS status;
		ULONG handleInfoSize = 0x10000;
		HANDLE processHandle;
		ULONG i;
		PSYSTEM_HANDLE_INFORMATION handleInfo;

		/* Used in each handle iteration to identify the index in iProcessArray of the specific process */
		int iCurrentProcess_ArrayIndex = -1;

		/* Handle array - PROCESS INDEX / HANDLE NUMBER / TEXT OF HANDLE
			This holds all handles which have been found per process */
		auto cHandleArray = new WCHAR[MAX_PROCESSES][MAX_FILE_HANDLES][MAX_PATH]();
		signed int iProcessArray[MAX_PROCESSES][3] = { 0 };

		/* Set process array to -1, which indicates nothing has been set */
		for (int j = 0; j < (MAX_PROCESSES - 1); j++)
			iProcessArray[j][0] = -1;

		/* Loop dNumberCycles [default: 10] times before analysing result */
		for (unsigned int iCycleCounter = 1; iCycleCounter <= dNumberCycles; iCycleCounter++)
		{
			handleInfoSize = 0x10000;
			handleInfo = (PSYSTEM_HANDLE_INFORMATION)malloc(handleInfoSize);

			/* NtQuerySystemInformation won't give us the correct buffer size, so we guess by doubling the buffer size. */
			while ((status = NtQuerySystemInformation(SystemHandleInformation, handleInfo, handleInfoSize, NULL)) == STATUS_INFO_LENGTH_MISMATCH)
				handleInfo = (PSYSTEM_HANDLE_INFORMATION)realloc(handleInfo, handleInfoSize *= 2);

			/* NtQuerySystemInformation stopped giving us STATUS_INFO_LENGTH_MISMATCH. */
			if (!NT_SUCCESS(status))
			{
				printf("NtQuerySystemInformation failed!\n");
				return 1;
			}

			/* Loop for each handle on the system, processing it accordingly... */
			for (i = 0; i < handleInfo->HandleCount; i++)
			{
				SYSTEM_HANDLE handle = handleInfo->Handles[i];
				HANDLE dupHandle = NULL;
				POBJECT_TYPE_INFORMATION objectTypeInfo;

				/* Open a handle to the process associated with the handle */
				if (!(processHandle = OpenProcess(PROCESS_DUP_HANDLE, FALSE, handle.ProcessId)))
					continue;

				/* Duplicate the handle so we can query it. */
				if (!NT_SUCCESS(NtDuplicateObject(processHandle, (HANDLE)handle.Handle, GetCurrentProcess(), &dupHandle, GENERIC_READ, 0, 0)))
				{
					CloseHandle(processHandle);
					CloseHandle(dupHandle);
					continue;
				}

				/* Query the object type */
				objectTypeInfo = (POBJECT_TYPE_INFORMATION)malloc(0x1000);
				if (!NT_SUCCESS(NtQueryObject(dupHandle, ObjectTypeInformation, objectTypeInfo, 0x1000, NULL)))
				{
					free(objectTypeInfo);
					CloseHandle(processHandle);
					CloseHandle(dupHandle);
					continue;
				}

				/* If it's not a file handle, go to next one (as we're only interested in file handles) */
				if (wcscmp(objectTypeInfo->Name.Buffer, L"File"))
				{
					free(objectTypeInfo);
					CloseHandle(processHandle);
					CloseHandle(dupHandle);
					continue;
				}

				/* Identify the filename from the handle we're looking at */
				WCHAR* wHandleFileName = new WCHAR[MAX_PATH]();

				if (!GetFileNameFromHandle(dupHandle, wHandleFileName))
				{
					free(objectTypeInfo);
					free(wHandleFileName);
					CloseHandle(processHandle);
					CloseHandle(dupHandle);
					continue;
				}

				/* This is where we add our findings to the database */
				iCurrentProcess_ArrayIndex = -1;

				/* Check whether we've already got an entry for the process we're looking at */
				for (int j = 0; j < (MAX_PROCESSES - 1); j++)
					if (iProcessArray[j][PROCESS_ARRAY_INDEX] == handle.ProcessId)
						iCurrentProcess_ArrayIndex = j;

				/* If not, create a new entry for the process associated with the current handle */
				if (iCurrentProcess_ArrayIndex == -1)
					for (int j = 0; j < (MAX_PROCESSES - 1); j++)
						if (iProcessArray[j][PROCESS_ARRAY_INDEX] == -1)
						{
							iProcessArray[j][PROCESS_ARRAY_INDEX] = handle.ProcessId;
							iCurrentProcess_ArrayIndex = j;
							break;
						}

				/* If there's more than MAX_PROCESSES, throw an error
					TODO: Tidy this up, identify number of running processes dynamically and set array size accordingly */
				if (iCurrentProcess_ArrayIndex == -1)
				{
					printf("Error: Too many processes running!\n");
					return 1;
				}

				/* Look through the handle array, to see whether the filename can be found */
				WCHAR cCurrentHandleText[MAX_PATH];
				for (int j = 0; j < (MAX_FILE_HANDLES - 1); j++)
				{
					/* If we hit NULL, there are no more to find, so add ours */
					swprintf_s(cCurrentHandleText, MAX_PATH, L"%ls", wHandleFileName);

					if (!wcscmp(cHandleArray[iCurrentProcess_ArrayIndex][j], L"")){
						wcscpy_s(cHandleArray[iCurrentProcess_ArrayIndex][j], cCurrentHandleText);
						break;
					}
					/* If we find ours, then stop searching */
					else if (!wcscmp(cHandleArray[iCurrentProcess_ArrayIndex][j], cCurrentHandleText))
						break;
				}

				/* If it's the first (or last) cycle, tally how many entries in the handle array for this
					particular process we have so far */

				if (iCycleCounter == 1)
					for (int j = 0; j < (MAX_FILE_HANDLES - 1); j++)
						if (!wcscmp(cHandleArray[iCurrentProcess_ArrayIndex][j], L"")){
							iProcessArray[iCurrentProcess_ArrayIndex][PROCESS_ARRAY_COUNT_START_CYCLE] = (j - 1);
							break;
						}

				if (iCycleCounter == dNumberCycles)
					for (int j = 0; j < (MAX_FILE_HANDLES - 1); j++)
						if (!wcscmp(cHandleArray[iCurrentProcess_ArrayIndex][j], L"")) {
							iProcessArray[iCurrentProcess_ArrayIndex][PROCESS_ARRAY_COUNT_END_CYCLE] = (j - 1);
							break;
						}

				free(objectTypeInfo);
				free(wHandleFileName);
				CloseHandle(dupHandle);
				CloseHandle(processHandle);
			}
			free(handleInfo);

			/* If the iteration pause is not 0, sleep for the requested time [Default: 1000ms] */
			if (dIterationPause)
				Sleep(dIterationPause);

			/* If /verbose active - inform user which cycle we are on */
			if (bVerbose)
				if (iCycleCounter == 1)
					printf("Verbose Info: Completed cycle %d", iCycleCounter);
				else if (iCycleCounter == dNumberCycles)
					printf(" %d\n", iCycleCounter);
				else
					printf(" %d", iCycleCounter);
		}

		/* If /verbose active - inform user we are now starting a review */
		if (bVerbose)
			printf("Verbose Info: Cycles completed, beginning review\n");

		/* Check if any of them met threshold*/
		for (int j = 0; j < (MAX_PROCESSES - 1); j++)
		{
			if (iProcessArray[j][PROCESS_ARRAY_COUNT_END_CYCLE] < iProcessArray[j][PROCESS_ARRAY_COUNT_START_CYCLE])
				continue;

			/* dHandleDelta is the difference between number of handles for a process from first cycle to the last one  */
			DWORD dHandleDelta = (iProcessArray[j][PROCESS_ARRAY_COUNT_END_CYCLE] - iProcessArray[j][PROCESS_ARRAY_COUNT_START_CYCLE]);

			/* Check whether the delta is equal or above the threshold */
			if (dHandleDelta >= dHandleChangeThreshold)
			{
				HANDLE pHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, iProcessArray[j][PROCESS_ARRAY_INDEX]);
				TCHAR tProcessName[MAX_PATH];
				GetModuleFileNameEx(pHandle, 0, tProcessName, MAX_PATH);
				CloseHandle(pHandle);

				/* If we don't want signed, yet it is signed, skip... */
				if (!bIncludeSigned && (is_signed(tProcessName) == 0))
				{
					if (bVerbose)
						wprintf(L"Verbose Info: Skipping alert on %s (%d) despite trigger, as it is signed (use /signed to alert on signed executables too)\n", tProcessName, iProcessArray[j][PROCESS_ARRAY_INDEX]);
					continue;
				}

				/* Inform the user if we have a suspicious process */
				wprintf(L"Alert! Process: %s (%d) has had a suspicious number of handles (%d) created in the last cycle\nNew handles created during this cycle:\n", tProcessName, iProcessArray[j][PROCESS_ARRAY_INDEX], dHandleDelta);

				for (DWORD k = 1; k <= dHandleDelta; k++)
					wprintf(L"%s\n", cHandleArray[j][iProcessArray[j][PROCESS_ARRAY_COUNT_START_CYCLE] + k]);

				if (bSuspendProcess)
				{

					printf("Info: Attempting to suspend process %d\n", iProcessArray[j][PROCESS_ARRAY_INDEX]);

					/* Attach debugger to process (freeze it!)*/
					if (!DebugActiveProcess(iProcessArray[j][PROCESS_ARRAY_INDEX]))
					{
						printf("Info: Could not attach to process %d as a debugger\n", iProcessArray[j][PROCESS_ARRAY_INDEX]);
					}
					else
					{
						DebugSetProcessKillOnExit(FALSE);

						printf("Info: Successfully attached to process %d as debugger\n", iProcessArray[j][PROCESS_ARRAY_INDEX]);
						printf("Info: It will remain frozen until this process is terminated\n");
					}
				}

				printf("------------------------------------------------------------------------------\n");

			}
		}

		if (bVerbose)
			printf("Verbose Info: Review complete\n");

		free(cHandleArray);

	}

	return 0;
}
Exemple #5
0
BOOL DebugMainLoop(const DebugOptions *pOptions)
{
    BOOL fFinished = FALSE;
    BOOL fBreakpointSignalled = FALSE;
    BOOL fWowBreakpointSignalled = FALSE;
    BOOL fTerminating = FALSE;

    while(!fFinished)
    {
        DEBUG_EVENT DebugEvent;            // debugging event information
        DWORD dwContinueStatus = DBG_CONTINUE;    // exception continuation
        PPROCESS_INFO pProcessInfo;
        PTHREAD_INFO pThreadInfo;
        HANDLE hProcess;

        // Wait for a debugging event to occur. The second parameter indicates
        // that the function does not return until a debugging event occurs.
        if(!WaitForDebugEvent(&DebugEvent, INFINITE))
        {
            OutputDebug("WaitForDebugEvent: 0x%08lx", GetLastError());

            return FALSE;
        }

        // Process the debugging event code.
        switch (DebugEvent.dwDebugEventCode) {
        case EXCEPTION_DEBUG_EVENT: {
            PEXCEPTION_RECORD pExceptionRecord = &DebugEvent.u.Exception.ExceptionRecord;
            NTSTATUS ExceptionCode = pExceptionRecord->ExceptionCode;

            // Process the exception code. When handling
            // exceptions, remember to set the continuation
            // status parameter (dwContinueStatus). This value
            // is used by the ContinueDebugEvent function.
            if (pOptions->verbose_flag) {
                lprintf("EXCEPTION PID=%lu TID=%lu ExceptionCode=0x%lx dwFirstChance=%lu\r\n",
                        DebugEvent.dwProcessId,
                        DebugEvent.dwThreadId,
                        pExceptionRecord->ExceptionCode,
                        DebugEvent.u.Exception.dwFirstChance
                );
            }

            // Find the process in the process list
            pProcessInfo = &g_Processes[DebugEvent.dwProcessId];

            dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;

            if (DebugEvent.u.Exception.dwFirstChance) {
                if (pExceptionRecord->ExceptionCode == (DWORD)STATUS_BREAKPOINT) {
                    // Signal the aedebug event
                    if (!fBreakpointSignalled) {
                        fBreakpointSignalled = TRUE;

                        if (pOptions->hEvent) {
                            SetEvent(pOptions->hEvent);
                            CloseHandle(pOptions->hEvent);
                        }

                        if (pOptions->dwThreadId) {
                            DWORD dwThreadId = pOptions->dwThreadId;
                            const DWORD dwFailed = (DWORD)-1;
                            DWORD dwRet = dwFailed;
                            pThreadInfo = &pProcessInfo->Threads[dwThreadId];
                            HANDLE hThread = pThreadInfo->hThread;
                            if (hThread != NULL) {
                                dwRet = ResumeThread(hThread);
                            }
                            if (dwRet == dwFailed) {
                                lprintf("error: failed to resume thread %lu\n", dwThreadId);
                            }
                        }

                        /*
                         * We ignore first-chance breakpoints by default.
                         *
                         * We get one of these whenever we attach to a process.
                         * But in some cases, we never get a second-chance, e.g.,
                         * when we're attached through MSVCRT's abort().
                         */
                        if (!pOptions->breakpoint_flag) {
                            dwContinueStatus = DBG_CONTINUE;
                            break;
                        }
                    }
                }

                if (ExceptionCode == STATUS_WX86_BREAKPOINT) {
                    if (!fWowBreakpointSignalled) {
                        fWowBreakpointSignalled = TRUE;
                        dwContinueStatus = DBG_CONTINUE;
                        break;
                    }
                }

               /*
                 * Ignore thread naming exception.
                 *
                 * http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
                 *
                 * TODO: Note down the thread name
                 */
                if (ExceptionCode == 0x406d1388) {
                    dwContinueStatus = DBG_CONTINUE;
                    break;
                }

                if (!pOptions->first_chance) {
                    break;
                }
            }

            // XXX: Deferred symbols don't get loaded without this
            SymRefreshModuleList(pProcessInfo->hProcess);

            dumpException(pProcessInfo->hProcess,
                          &DebugEvent.u.Exception.ExceptionRecord);

            // Find the thread in the thread list
            THREAD_INFO_LIST::const_iterator it;
            for (it = pProcessInfo->Threads.begin(); it != pProcessInfo->Threads.end(); ++it) {
                DWORD dwThreadId = it->first;
                HANDLE hThread = it->second.hThread;
                if (dwThreadId != DebugEvent.dwThreadId &&
                    ExceptionCode != STATUS_BREAKPOINT &&
                    ExceptionCode != STATUS_WX86_BREAKPOINT) {
                        continue;
                }

                dumpStack(pProcessInfo->hProcess, hThread, NULL);
            }

            if (!DebugEvent.u.Exception.dwFirstChance) {
                /*
                 * Terminate the process. As continuing would cause the JIT debugger
                 * to be invoked again.
                 */
                fTerminating = TRUE;
                TerminateProcess(pProcessInfo->hProcess, (UINT)ExceptionCode);
            }

            break;
        }

        case CREATE_THREAD_DEBUG_EVENT:
            if (pOptions->verbose_flag) {
                lprintf("CREATE_THREAD PID=%lu TID=%lu\r\n",
                        DebugEvent.dwProcessId,
                        DebugEvent.dwThreadId
                );
            }

            // Add the thread to the thread list
            pProcessInfo = &g_Processes[DebugEvent.dwProcessId];
            pThreadInfo = &pProcessInfo->Threads[DebugEvent.dwThreadId];
            pThreadInfo->hThread = DebugEvent.u.CreateThread.hThread;
            break;

        case CREATE_PROCESS_DEBUG_EVENT: {
            HANDLE hFile = DebugEvent.u.CreateProcessInfo.hFile;

            char szImageName[MAX_PATH];
            char *lpImageName = NULL;
            if (hFile && GetFileNameFromHandle(hFile, szImageName, _countof(szImageName))) {
                lpImageName = szImageName;
            }

            if (pOptions->verbose_flag) {
                PCSTR lpModuleName = lpImageName ? getBaseName(lpImageName) : "";

                lprintf("CREATE_PROCESS PID=%lu TID=%lu lpBaseOfImage=%p %s\r\n",
                        DebugEvent.dwProcessId,
                        DebugEvent.dwThreadId,
                        DebugEvent.u.CreateProcessInfo.lpBaseOfImage,
                        lpModuleName
                );
            }

            hProcess = DebugEvent.u.CreateProcessInfo.hProcess;

            pProcessInfo = &g_Processes[DebugEvent.dwProcessId];
            pProcessInfo->hProcess = hProcess;

            pThreadInfo = &pProcessInfo->Threads[DebugEvent.dwThreadId];
            pThreadInfo->hThread = DebugEvent.u.CreateProcessInfo.hThread;

            if (!InitializeSym(hProcess, FALSE)) {
                OutputDebug("error: SymInitialize failed: 0x%08lx\n", GetLastError());
                exit(EXIT_FAILURE);
            }

            SymRegisterCallback64(hProcess, &symCallback, 0);

            loadModule(hProcess, hFile, lpImageName, DebugEvent.u.CreateProcessInfo.lpBaseOfImage);

            break;
        }

        case EXIT_THREAD_DEBUG_EVENT:
            if (pOptions->verbose_flag) {
                lprintf("EXIT_THREAD PID=%lu TID=%lu dwExitCode=0x%lx\r\n",
                        DebugEvent.dwProcessId,
                        DebugEvent.dwThreadId,
                        DebugEvent.u.ExitThread.dwExitCode
                );
            }

            // Remove the thread from the thread list
            pProcessInfo = &g_Processes[DebugEvent.dwProcessId];
            hProcess = pProcessInfo->hProcess;

            // Dump the stack on abort()
            if (!fTerminating && isAbnormalExitCode(DebugEvent.u.ExitThread.dwExitCode)) {
                pThreadInfo = &pProcessInfo->Threads[DebugEvent.dwThreadId];
                refreshSymbolsAndDumpStack(hProcess, pThreadInfo->hThread);
            }

            pProcessInfo->Threads.erase(DebugEvent.dwThreadId);
            break;

        case EXIT_PROCESS_DEBUG_EVENT: {
            if (pOptions->verbose_flag) {
                lprintf("EXIT_PROCESS PID=%lu TID=%lu dwExitCode=0x%lx\r\n",
                        DebugEvent.dwProcessId,
                        DebugEvent.dwThreadId,
                        DebugEvent.u.ExitProcess.dwExitCode
                );
            }

            pProcessInfo = &g_Processes[DebugEvent.dwProcessId];
            hProcess = pProcessInfo->hProcess;

            // Dump the stack on abort()
            if (!fTerminating && isAbnormalExitCode(DebugEvent.u.ExitThread.dwExitCode)) {
                pThreadInfo = &pProcessInfo->Threads[DebugEvent.dwThreadId];
                refreshSymbolsAndDumpStack(hProcess, pThreadInfo->hThread);
            }

            // Remove the process from the process list
            g_Processes.erase(DebugEvent.dwProcessId);

            if (!SymCleanup(hProcess)) {
                OutputDebug("SymCleanup failed with 0x%08lx\n", GetLastError());
            }

            if (g_Processes.empty()) {
                fFinished = TRUE;
            }

            break;
        }

        case LOAD_DLL_DEBUG_EVENT: {
            HANDLE hFile = DebugEvent.u.LoadDll.hFile;

            char szImageName[MAX_PATH];
            char *lpImageName = NULL;
            if (hFile && GetFileNameFromHandle(hFile, szImageName, _countof(szImageName))) {
                lpImageName = szImageName;
            }

            if (pOptions->verbose_flag) {
                PCSTR lpModuleName = lpImageName ? getBaseName(lpImageName) : "";

                lprintf("LOAD_DLL PID=%lu TID=%lu lpBaseOfDll=%p %s\r\n",
                        DebugEvent.dwProcessId,
                        DebugEvent.dwThreadId,
                        DebugEvent.u.LoadDll.lpBaseOfDll,
                        lpModuleName
                );
            }

            pProcessInfo = &g_Processes[DebugEvent.dwProcessId];
            hProcess = pProcessInfo->hProcess;

            loadModule(hProcess, hFile, lpImageName, DebugEvent.u.LoadDll.lpBaseOfDll);

            break;
        }

        case UNLOAD_DLL_DEBUG_EVENT:
            if (pOptions->verbose_flag) {
                lprintf("UNLOAD_DLL PID=%lu TID=%lu lpBaseOfDll=%p\r\n",
                        DebugEvent.dwProcessId,
                        DebugEvent.dwThreadId,
                        DebugEvent.u.UnloadDll.lpBaseOfDll
                );
            }

            pProcessInfo = &g_Processes[DebugEvent.dwProcessId];
            hProcess = pProcessInfo->hProcess;

            SymUnloadModule64(hProcess, (UINT_PTR)DebugEvent.u.UnloadDll.lpBaseOfDll);

            break;

        case OUTPUT_DEBUG_STRING_EVENT: {
            if (pOptions->verbose_flag) {
                lprintf("OUTPUT_DEBUG_STRING PID=%lu TID=%lu\r\n",
                        DebugEvent.dwProcessId,
                        DebugEvent.dwThreadId
                );
            }

            pProcessInfo = &g_Processes[DebugEvent.dwProcessId];

            assert(!DebugEvent.u.DebugString.fUnicode);

            LPSTR lpDebugStringData = readProcessString(pProcessInfo->hProcess,
                                                        DebugEvent.u.DebugString.lpDebugStringData,
                                                        DebugEvent.u.DebugString.nDebugStringLength);

            lprintf("%s", lpDebugStringData);

            free(lpDebugStringData);
            break;
        }

        case RIP_EVENT:
            if (pOptions->verbose_flag) {
                lprintf("RIP PID=%lu TID=%lu\r\n",
                        DebugEvent.dwProcessId,
                        DebugEvent.dwThreadId
                );
            }
            break;

        default:
            if (pOptions->verbose_flag) {
                lprintf("EVENT%lu PID=%lu TID=%lu\r\n",
                    DebugEvent.dwDebugEventCode,
                    DebugEvent.dwProcessId,
                    DebugEvent.dwThreadId
                );
            }
            break;
        }

        // Resume executing the thread that reported the debugging event.
        ContinueDebugEvent(
            DebugEvent.dwProcessId,
            DebugEvent.dwThreadId,
            dwContinueStatus
        );
    }

    return TRUE;
}