#include        "defs.h"


//[1] WaitForSingleObject(DBWinMutex, INFINITE);
//[2] wait_status = WaitForSingleObject(DWBIN_BUFFER_READY, 10000);      //10 sec
//[3] if (wait_status == WAIT_TIMEOUT) __goto [7]
//[4] OpenMapSection(DBWIN_BUFFER);
//[5] write string to this section
//[6] SetEvent(DBWIN_DATA_READY);
//[7] ReleaseMutex(DBWinMutex);
//[8] continue with execution

HANDLE  hDirectoryObject;

VOID    ntOutputDebugString(__in char *szMessage){
        PROCESS_SESSION_INFORMATION psi;
        UNICODE_STRING              us;
        HANDLE                      hDBWIN_BUFFER_READY = NULL;
        HANDLE                      hDBWIN_DATA_READY   = NULL;
        HANDLE                      hDBWinMutex         = NULL;
        HANDLE                      hSection            = NULL;
        NTSTATUS                    status;
        ULONG                       cbNeeded;
        WCHAR                       wsObjectName[MAX_PATH];
        WCHAR                       wsSessionId[2];  
        OBJECT_ATTRIBUTES           oa;             
        PVOID                       pBaseAddress = NULL;
        SIZE_T                      ViewSize = 0;
        LARGE_INTEGER               SectionOffset;
        LARGE_INTEGER               timeout;
        
        if (!hDirectoryObject){                        
                status = NtQueryInformationProcess((HANDLE)(ULONG_PTR)-1,
                                                   ProcessSessionInformation,
                                                   &psi,
                                                   sizeof(psi),
                                                   &cbNeeded);
                memset(wsSessionId, 0, sizeof(wsSessionId));
                wsSessionId[0] = (WCHAR)psi.SessionId + 0x30; 
                
                memset(wsObjectName, 0, sizeof(wsObjectName));
                wcscpy(wsObjectName, L"\\Sessions\\");
                wcscat(wsObjectName, wsSessionId);
                wcscat(wsObjectName, L"\\BaseNamedObjects");
                RtlInitUnicodeString(&us, wsObjectName);
                InitializeObjectAttributes(&oa, &us, OBJ_CASE_INSENSITIVE, NULL, NULL);       
                status = NtOpenDirectoryObject(&hDirectoryObject, READ_CONTROL | 0xF, &oa); //DIRECTORY_ALL_ACCESS, &oa);        
                if (status != STATUS_SUCCESS){
                        /********************************************
                         * try to open \\BaseNamedObjects...
                         ********************************************/        
                        RtlInitUnicodeString(&us, L"\\BaseNamedObjects");
                        InitializeObjectAttributes(&oa, &us, OBJ_CASE_INSENSITIVE, NULL, NULL);
                        status = NtOpenDirectoryObject(&hDirectoryObject, READ_CONTROL | 0xF, &oa); //DIRECTORY_ALL_ACCESS, &oa);
                        if (status != STATUS_SUCCESS) goto __Exit0;
                }
        }
        
        RtlInitUnicodeString(&us, L"DBWinMutex");
        InitializeObjectAttributes(&oa, &us, OBJ_CASE_INSENSITIVE, hDirectoryObject, NULL);
        status = NtOpenMutant(&hDBWinMutex, SYNCHRONIZE, &oa);
        if (status != STATUS_SUCCESS) goto __Exit0;
        
        RtlInitUnicodeString(&us, L"DBWIN_BUFFER_READY");
        InitializeObjectAttributes(&oa, &us, OBJ_CASE_INSENSITIVE, hDirectoryObject, NULL);
        status = NtOpenEvent(&hDBWIN_BUFFER_READY,  EVENT_MODIFY_STATE | SYNCHRONIZE, &oa);
        if (status != STATUS_SUCCESS) goto __Exit0;
        
        RtlInitUnicodeString(&us, L"DBWIN_DATA_READY");
        InitializeObjectAttributes(&oa, &us, OBJ_CASE_INSENSITIVE, hDirectoryObject, NULL);
        status = NtOpenEvent(&hDBWIN_DATA_READY,  EVENT_MODIFY_STATE | SYNCHRONIZE, &oa);
        if (status != STATUS_SUCCESS) goto __Exit0;
        
        status = NtWaitForSingleObject(hDBWinMutex, FALSE, NULL);
        if (status != STATUS_SUCCESS && status != STATUS_ABANDONED_WAIT_0) goto __Exit0;
        
        timeout.QuadPart = RELATIVE(SECONDS(10));
        status = NtWaitForSingleObject(hDBWIN_BUFFER_READY, FALSE, &timeout);
        if (status != STATUS_SUCCESS) goto __Exit0;
        
        RtlInitUnicodeString(&us, L"DBWIN_BUFFER");
        InitializeObjectAttributes(&oa, &us, OBJ_CASE_INSENSITIVE, hDirectoryObject, NULL);
        status = NtOpenSection(&hSection,
                               GENERIC_READ | GENERIC_WRITE,
                               &oa);
        if (status != STATUS_SUCCESS) goto __Exit0;
        
        
        SectionOffset.QuadPart = 0;
        status = NtMapViewOfSection(hSection,
                                    (HANDLE)(ULONG_PTR)-1,
                                    &pBaseAddress,
                                    0,
                                    0,
                                    &SectionOffset,
                                    &ViewSize,
                                    ViewShare,
                                    0,
                                    PAGE_READWRITE);     
        if (status != STATUS_SUCCESS) goto __Exit0;
                
        *(ULONG *)pBaseAddress = get_currentprocessid();
        strncpy((char *)((ULONG_PTR)pBaseAddress + sizeof(DWORD)), (const char *)szMessage, 0x1000-4-1);
       
        NtSetEvent(hDBWIN_DATA_READY, &cbNeeded);
        NtReleaseMutant(hDBWinMutex, &cbNeeded);

__Exit0:        
        if (pBaseAddress)        
                NtUnmapViewOfSection((HANDLE)(ULONG_PTR)-1,
                                      pBaseAddress);
        if (hSection)
                NtClose(hSection);
        
        if (hDBWinMutex)
                NtClose(hDBWinMutex);
        if (hDBWIN_DATA_READY)
                NtClose(hDBWIN_DATA_READY);
        if (hDBWIN_BUFFER_READY)
                NtClose(hDBWIN_BUFFER_READY);
        
        return;
}