////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Description : // Generates a message using "pid", "message" and "parameter" and sends it back to userland throught // a filter communication port. // Parameters : // _in_opt_ ULONG pid : Process ID from which the logs are produced. // _in_opt_ PWCHAR message : Message (function name most of the time). // _in_opt_ PWCHAR parameter : Function args. // Return value : // NTSTATUS : FltSendMessage return value. // Process : // - Retrieves the process name from the pid and saves the whole data into an ANSI string. // - Generates an ANSI string with the message, with the process name, pid, and function name, and the // - generic "parameter" parameter. The resulting output will basically follow this scheme: // "pid","proces_name","function_name","FAILED/SUCCESS(0/1)","return_value","number_of_arguments","argument1->value","argument2->value"... // - Uses the "mutex" mutex to avoid concurrency when using the FltSendMessage() function. ////////////////////////////////////////////////////////////////////////////////////////////////////////////// NTSTATUS sendLogs(ULONG pid, PWCHAR message, PWCHAR parameter) { NTSTATUS status = STATUS_SUCCESS; CHAR buf[MAXSIZE]; UNICODE_STRING processName; ULONG sizeBuf; LARGE_INTEGER timeout; timeout.QuadPart = -((LONGLONG)0.5*10*1000*1000); if(message == NULL) return STATUS_INVALID_PARAMETER; #ifdef DEBUG DbgPrint("SendLogs\n"); #endif processName.Length = 0; processName.MaximumLength = NTSTRSAFE_UNICODE_STRING_MAX_CCH * sizeof(WCHAR); processName.Buffer = ExAllocatePoolWithTag(NonPagedPool, processName.MaximumLength, PROCNAME_TAG); if(!processName.Buffer) { KeWaitForMutexObject(&mutex, Executive, KernelMode, FALSE, NULL); status = FltSendMessage(filter, &clientPort, "0,error,error,error\n", 20, NULL, 0, &timeout); KeReleaseMutex(&mutex, FALSE); return STATUS_NO_MEMORY; } status = getProcNameByPID(pid, &processName); if(!NT_SUCCESS(status)) { KeWaitForMutexObject(&mutex, Executive, KernelMode, FALSE, NULL); status = FltSendMessage(filter, &clientPort, "0,error,error,error\n", 20, NULL, 0, &timeout); KeReleaseMutex(&mutex, FALSE); ExFreePool(processName.Buffer); return status; } status = RtlStringCbPrintfA(buf, MAXSIZE, "%d,%wZ,%ws,%ws\n", pid, &processName, message, parameter); if(!NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) { KeWaitForMutexObject(&mutex, Executive, KernelMode, FALSE, NULL); status = FltSendMessage(filter, &clientPort, "0,error,error,error\n", 20, NULL, 0, &timeout); KeReleaseMutex(&mutex, FALSE); ExFreePool(processName.Buffer); return status; } status = RtlStringCbLengthA(buf, MAXSIZE, &sizeBuf); if(!NT_SUCCESS(status)) { KeWaitForMutexObject(&mutex, Executive, KernelMode, FALSE, NULL); status = FltSendMessage(filter, &clientPort, "0,error,error,error\n", 20, NULL, 0, &timeout); KeReleaseMutex(&mutex, FALSE); ExFreePool(processName.Buffer); return status; } KeWaitForMutexObject(&mutex, Executive, KernelMode, FALSE, NULL); #ifdef DEBUG DbgPrint("\tmsg : %s\n", buf); #endif status = FltSendMessage(filter, &clientPort, buf, sizeBuf, NULL, 0, NULL); if(status == STATUS_TIMEOUT) DbgPrint("STATUS_TIMEOUT !!\n"); KeReleaseMutex(&mutex, FALSE); ExFreePool(processName.Buffer); #ifdef DEBUG if(!NT_SUCCESS(status)) DbgPrint("return : 0x%08x\n", status); #endif DEBUG return status; }
PSYMBOL_ENTRY SympFindSymbol(IN PCHAR pszSymbolName) { ASSERTMSG("Passed symbol name is NULL", pszSymbolName != NULL); ASSERTMSG("SymbolEngine must be initialized prior to this call", bIsSymEngineInitialized == TRUE); PLIST_ENTRY symbolListEntry = SymbolsListHead.Flink; // we are not at dispatch level yet, so getting length of the input string is allowed size_t nSymbolNameLength = 0; if(RtlStringCbLengthA(pszSymbolName, MAX_SYM_NAME, &nSymbolNameLength) == STATUS_INVALID_PARAMETER) { KdPrint(("[DEBUG] ERROR - Could not obtain the length of the symbol name\n")); return NULL; } // iterate through symbols list ASSERTMSG("Fast mutex acquire must occur at or below APC_LEVEL", KeGetCurrentIrql() <= APC_LEVEL); ExAcquireFastMutex(&SymbolsListMutex); while(symbolListEntry != &SymbolsListHead) { PSYMBOL_ENTRY pSymbolEntry = CONTAINING_RECORD(symbolListEntry, SYMBOL_ENTRY, ListEntry); // if this is the wanted entry if(RtlCompareMemory((PVOID) pszSymbolName, (PVOID)pSymbolEntry->Symbol.name, nSymbolNameLength) == nSymbolNameLength) { // return it to caller ASSERTMSG("Fast mutex release must occur at APC_LEVEL", KeGetCurrentIrql() == APC_LEVEL); ExReleaseFastMutex(&SymbolsListMutex); return pSymbolEntry; } symbolListEntry = symbolListEntry->Flink; } // wanted symbol entry is not present in the list, return NULL ASSERTMSG("Fast mutex release must occur at APC_LEVEL", KeGetCurrentIrql() == APC_LEVEL); ExReleaseFastMutex(&SymbolsListMutex); return NULL; }
NTSTATUS dumpEatEntriesToDefFile(PVOID pEatEntryList, ULONGLONG listBufferSize, PUCHAR pModuleName){ OBJECT_ATTRIBUTES defFileAttr; UNICODE_STRING uDefFileName; IO_STATUS_BLOCK ioSb; NTSTATUS status, fatalStatus = STATUS_CLUSTER_NETINTERFACE_EXISTS; PCHAR pDefPreamble = NULL; ///Keep it simple. We can't allocate less than 4 kB using NtXxx funcs anyway, ///so just allocate 4 kB although we never will need that much. ULONGLONG defPreambleSize = PAGE_SIZE; HANDLE hDefFile = NULL; HANDLE hParentDir = NULL; ///Quite some ugly hacking... char szDefPreamblePart[] = { 0x0D, 0x0A, 0x0D, 0x0A, 'E', 'X', 'P', 'O', 'R', 'T', 'S', 0x0D, 0x0A, 0x0 }; status = NtAllocateVirtualMemory(INVALID_HANDLE_VALUE, &pDefPreamble, 0, &defPreambleSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); if (status) return status; status = RtlStringCbPrintfA(pDefPreamble, defPreambleSize, "LIBRARY %s%s", pModuleName, szDefPreamblePart); if (status){ fatalStatus = NtFreeVirtualMemory(INVALID_HANDLE_VALUE, &pDefPreamble, &defPreambleSize, MEM_RELEASE); if (fatalStatus) mydie(status, fatalStatus); return status; } status = RtlStringCbLengthA(pDefPreamble, defPreambleSize, &defPreambleSize); if (status){ fatalStatus = NtFreeVirtualMemory(INVALID_HANDLE_VALUE, &pDefPreamble, &defPreambleSize, MEM_RELEASE); if (fatalStatus) mydie(status, fatalStatus); return status; } hParentDir = NtCurrentPeb()->ProcessParameters->CurrentDirectory.Handle; RtlInitUnicodeString(&uDefFileName, L"exports.def"); InitializeObjectAttributes(&defFileAttr, &uDefFileName, OBJ_CASE_INSENSITIVE, hParentDir, NULL); status = NtCreateFile(&hDefFile, FILE_ALL_ACCESS | SYNCHRONIZE, &defFileAttr, &ioSb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_SUPERSEDE, FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE, NULL, 0); if (status){ fatalStatus = NtFreeVirtualMemory(INVALID_HANDLE_VALUE, &pDefPreamble, &defPreambleSize, MEM_RELEASE); if (fatalStatus) mydie(status, fatalStatus); return status; } status = NtWriteFile(hDefFile, NULL, NULL, NULL, &ioSb, pDefPreamble, (ULONG)defPreambleSize, NULL, NULL); if (!status) status = NtWriteFile(hDefFile, NULL, NULL, NULL, &ioSb, pEatEntryList, (ULONG)listBufferSize, NULL, NULL); fatalStatus = NtClose(hDefFile); if (fatalStatus) mydie(status, fatalStatus); fatalStatus = NtFreeVirtualMemory(INVALID_HANDLE_VALUE, &pDefPreamble, &defPreambleSize, MEM_RELEASE); if (fatalStatus) mydie(status, fatalStatus); return status; }
NTSTATUS AFSDbgLogMsg( IN ULONG Subsystem, IN ULONG Level, IN PCCH Format, ...) { NTSTATUS ntStatus = STATUS_SUCCESS; va_list va_args; ULONG ulBytesWritten = 0; BOOLEAN bReleaseLock = FALSE; char *pCurrentTrace = NULL; __Enter { if( AFSDbgBuffer == NULL) { try_return( ntStatus = STATUS_DEVICE_NOT_READY); } if( Subsystem > 0 && (Subsystem & AFSTraceComponent) == 0) { // // Not tracing this subsystem // try_return( ntStatus); } if( Level > 0 && Level > AFSTraceLevel) { // // Not tracing this level // try_return( ntStatus); } AFSAcquireExcl( &AFSDbgLogLock, TRUE); bReleaseLock = TRUE; // // Check again under lock // if( AFSDbgBuffer == NULL) { try_return( ntStatus = STATUS_DEVICE_NOT_READY); } if( AFSDbgLogRemainingLength < 255) { AFSDbgLogRemainingLength = AFSDbgBufferLength; AFSDbgCurrentBuffer = AFSDbgBuffer; SetFlag( AFSDbgLogFlags, AFS_DBG_LOG_WRAPPED); } pCurrentTrace = AFSDbgCurrentBuffer; RtlStringCchPrintfA( AFSDbgCurrentBuffer, 10, "%08lX:", AFSDbgLogCounter++); AFSDbgCurrentBuffer += 9; AFSDbgLogRemainingLength -= 9; va_start( va_args, Format); ntStatus = RtlStringCbVPrintfA( AFSDbgCurrentBuffer, AFSDbgLogRemainingLength, Format, va_args); if( ntStatus == STATUS_BUFFER_OVERFLOW) { RtlZeroMemory( AFSDbgCurrentBuffer, AFSDbgLogRemainingLength); AFSDbgLogRemainingLength = AFSDbgBufferLength; AFSDbgCurrentBuffer = AFSDbgBuffer; SetFlag( AFSDbgLogFlags, AFS_DBG_LOG_WRAPPED); pCurrentTrace = AFSDbgCurrentBuffer; RtlStringCchPrintfA( AFSDbgCurrentBuffer, 10, "%08lX:", AFSDbgLogCounter++); AFSDbgCurrentBuffer += 9; AFSDbgLogRemainingLength -= 9; ntStatus = RtlStringCbVPrintfA( AFSDbgCurrentBuffer, AFSDbgLogRemainingLength, Format, va_args); } if( NT_SUCCESS( ntStatus)) { RtlStringCbLengthA( AFSDbgCurrentBuffer, AFSDbgLogRemainingLength, (size_t *)&ulBytesWritten); AFSDbgCurrentBuffer += ulBytesWritten; AFSDbgLogRemainingLength -= ulBytesWritten; } va_end( va_args); if( BooleanFlagOn( AFSDebugFlags, AFS_DBG_TRACE_TO_DEBUGGER) && pCurrentTrace != NULL) { DbgPrint( pCurrentTrace); } try_exit: if( bReleaseLock) { AFSReleaseResource( &AFSDbgLogLock); } } return ntStatus; }
////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Description : // Generates a message using "pid", "message" and "parameter" and sends it back to userland throught // a filter communication port. // Parameters : // _in_opt_ ULONG pid : Process ID from which the logs are produced. // _in_opt_ PWCHAR message : Message (function name most of the time). // _in_opt_ PWCHAR parameter : Function args. // Return value : // NTSTATUS : FltSendMessage return value. // Process : // - Retrieves the process name from the pid and saves the whole data into an ANSI string. // - Generates an ANSI string with the message, with the process name, pid, and function name, and the // - generic "parameter" parameter. The resulting output will basically follow this scheme: // "pid","process_name","function_name","FAILED/SUCCESS/BLOCKED(0/1/2)","return_value","number_of_arguments","argument1->value","argument2->value"... // - Uses the "mutex" mutex to avoid concurrency when using the FltSendMessage() function. ////////////////////////////////////////////////////////////////////////////////////////////////////////////// NTSTATUS sendLogs(ULONG pid, PWCHAR message, PWCHAR parameter) { NTSTATUS status = STATUS_SUCCESS; CHAR buf[MAXSIZE]; UNICODE_STRING processName; ULONG sizeBuf; if(message == NULL) return STATUS_INVALID_PARAMETER; processName.Length = 0; processName.MaximumLength = NTSTRSAFE_UNICODE_STRING_MAX_CCH * sizeof(WCHAR); processName.Buffer = ExAllocatePoolWithTag(NonPagedPool, processName.MaximumLength, PROCNAME_TAG); if(!processName.Buffer) { DbgPrint("ProcessName.Buffer error\n"); KeWaitForMutexObject(&mutex, Executive, KernelMode, FALSE, NULL); status = FltSendMessage(filter, &clientPort, "0,error,error,error\n", 20, NULL, 0, NULL); KeReleaseMutex(&mutex, FALSE); return STATUS_NO_MEMORY; } status = getProcNameByPID(pid, &processName); if(!NT_SUCCESS(status)) { DbgPrint("getProcNameByPID() error\n"); KeWaitForMutexObject(&mutex, Executive, KernelMode, FALSE, NULL); status = FltSendMessage(filter, &clientPort, "0,error,error,error\n", 20, NULL, 0, NULL); KeReleaseMutex(&mutex, FALSE); ExFreePool(processName.Buffer); return status; } status = RtlStringCbPrintfA(buf, MAXSIZE, "%d,%wZ,%ws,%ws\n", pid, &processName, message, parameter); if(!NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) { DbgPrint("RtlStringCbPrintfA() error\n"); KeWaitForMutexObject(&mutex, Executive, KernelMode, FALSE, NULL); status = FltSendMessage(filter, &clientPort, "0,error,error,error\n", 20, NULL, 0, NULL); KeReleaseMutex(&mutex, FALSE); ExFreePool(processName.Buffer); return status; } status = RtlStringCbLengthA(buf, MAXSIZE, &sizeBuf); if(!NT_SUCCESS(status)) { DbgPrint("RtlStringCbLengthA() error\n"); KeWaitForMutexObject(&mutex, Executive, KernelMode, FALSE, NULL); status = FltSendMessage(filter, &clientPort, "0,error,error,error\n", 20, NULL, 0, NULL); KeReleaseMutex(&mutex, FALSE); ExFreePool(processName.Buffer); return status; } KeWaitForMutexObject(&mutex, Executive, KernelMode, FALSE, NULL); status = FltSendMessage(filter, &clientPort, buf, sizeBuf, NULL, 0, NULL); KeReleaseMutex(&mutex, FALSE); ExFreePool(processName.Buffer); return status; }
////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Description : // Parses received PIDs IOCTL from analyzer.py and adds ths PIDs in the hidden and monitored // lists. // Parameters : // IRP buffer data. // Return value : // NTSTATUS : STATUS_SUCCESS on success. ////////////////////////////////////////////////////////////////////////////////////////////////////////////// NTSTATUS parse_pids(PCHAR pids) { PCHAR start = NULL, current = NULL, data = NULL; ULONG len, pid; BOOLEAN first_pid = TRUE; NTSTATUS status; if(pids == NULL) return STATUS_INVALID_PARAMETER; status = RtlStringCbLengthA(pids, MAXSIZE, &len); if(!NT_SUCCESS(status)) return status; data = ExAllocatePoolWithTag(NonPagedPool, len+1, TEMP_TAG); if(data == NULL) return STATUS_NO_MEMORY; status = RtlStringCbPrintfA(data, len+1, "%s", pids); if(!NT_SUCCESS(status)) { ExFreePool(data); return status; } start = data; current = data; while(*current != 0x00) { if(*current == '_' && current!=start) { *current = 0x00; status = RtlCharToInteger(start, 10, &pid); if(NT_SUCCESS(status) && pid!=0) { if(first_pid) { startMonitoringProcess(pid); first_pid=FALSE; } else addHiddenProcess(pid); } start = current+1; } current++; } if(start != current) { status = RtlCharToInteger(start, 10, &pid); if(NT_SUCCESS(status) && pid!=0) { if(first_pid) startMonitoringProcess(pid); else addHiddenProcess(pid); } } ExFreePool(data); return STATUS_SUCCESS; }
VOID MyThreadStart(__in PVOID StartContext){ HANDLE handle;//Create File handle NTSTATUS ntstatus; NTSTATUS timerStatus; //IO_STATUS_BLOCK ioStatusBlock; //OBJECT_ATTRIBUTES ObjAttr; //UNICODE_STRING path; LARGE_INTEGER timeout; //#define BUFFER_SIZE 30 // CHAR buffer[BUFFER_SIZE]; //size_t cb; NTSTATUS Status; HANDLE hEvent; //OBJECT_ATTRIBUTES oa; //UNICODE_STRING us; int counter=20; SIZE_T BytesNUM; char* dataPtr; __debugbreak(); dataPtr="123"; BytesNUM=strlen(dataPtr)*sizeof(char); WriteToRingBuffer(&dataPtr, BytesNUM); FlushRingBuffre(); RtlInitUnicodeString( &path, L"\\DosDevices\\C:\\MyLogger.txt"); InitializeObjectAttributes( &ObjAttr, &path, //ObjectName OBJ_CASE_INSENSITIVE, //Attributes NULL, //RootDirectory NULL); //SecurityDescriptor // Do not try to perform any file operations at higher IRQL levels. // Instead, you may use a work item or a system worker thread to perform file operations. if(KeGetCurrentIrql() != PASSIVE_LEVEL) // return STATUS_INVALID_DEVICE_STATE; DbgPrint("STATUS_INVALID_DEVICE_STATE\n"); ntstatus = ZwCreateFile(&handle, GENERIC_WRITE, &ObjAttr, &ioStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OVERWRITE_IF, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); timeout.QuadPart = -5 * 1000000; RtlInitUnicodeString( &us, L"\\BaseNamedObjects\\TestEvent"); InitializeObjectAttributes( &oa, &us, //ObjectName OBJ_CASE_INSENSITIVE, //Attributes NULL, //RootDirectory NULL); //SecurityDescriptor Status = ZwCreateEvent(&hEvent, EVENT_ALL_ACCESS, &oa, NotificationEvent, FALSE); if(NT_SUCCESS(Status)){ DbgPrint("Event created"); } else { DbgPrint("Event Not created"); } Status = ObReferenceObjectByHandle( hEvent, //Handle EVENT_ALL_ACCESS, //DesiredAccess NULL, //ObjectType KernelMode, //AccessMode &pEvent, //Object NULL); //HandleInformation if (!NT_SUCCESS(Status)) { ZwClose(hEvent); DbgPrint("Failed to reference event \n"); //return Status; }; while(counter!=0){ timerStatus = KeWaitForSingleObject( pEvent, Executive, KernelMode, FALSE, &timeout ); if(timerStatus == STATUS_TIMEOUT){ if(NT_SUCCESS(ntstatus)) { ntstatus = RtlStringCbPrintfA(buffer, sizeof(buffer), "This is %d test\r\n", counter); if(NT_SUCCESS(ntstatus)) { ntstatus = RtlStringCbLengthA(buffer, sizeof(buffer), &cb); if(NT_SUCCESS(ntstatus)) { ntstatus = ZwWriteFile(handle, NULL, NULL, NULL, &ioStatusBlock, buffer, cb, NULL, NULL); } } //ZwClose(handle); } } counter--; } ZwClose(handle); }