Intel Pin NtQuerySystemInformation and PIN_SafeCopy

78 Views Asked by At

I am learning Pin and trying to conceal the presence of cmd.exe in the SYSTEM_PROCESS_INFORMATION linked list

This is what I have so far.

VOID HooksHandler::NtQuerySystemInformationIntercept(CONTEXT* ctxt, W::SYSTEM_INFORMATION_CLASS SystemInformationClass, PSYSTEM_PROCESS_INFO ProcessInformation, ADDRINT ret)
 {
    if (SystemInformationClass == SystemProcessInformation) {

        // cast to our structure to retrieve the information returned
        // from the NtSystemQueryInformation function
        PSYSTEM_PROCESS_INFO spi = (PSYSTEM_PROCESS_INFO)ProcessInformation;
        if (spi == NULL) {
            return;
        }
        
        // iterate through all processes 
        while (spi->NextEntryOffset) {
            if (spi->ImageName.Buffer != nullptr) {
                char value[PATH_BUFSIZE];
                GET_STR_TO_UPPER(spi->ImageName.Buffer, value, PATH_BUFSIZE);
                std::stringstream sss;
                sss << value;
                EVASION("NtQuerySystemInformation ImageName.Buffer", sss.str().c_str());

                if (wcscmp(spi->ImageName.Buffer, L"cmd.exe") == 0) {
                
                
                    MYINFO("NtQuerySystemInformation ImageName.Length before change", "%p", spi->ImageName.Length);

                    MYINFO("NtQuerySystemInformation ImageName.MaximumLength before change", "%p", spi->ImageName.MaximumLength);
                    
                    if (spi->ImageName.MaximumLength >= sizeof(L"abc.exe") && spi->ImageName.Length >= sizeof(L"abc.exe")) {
                        PIN_SafeCopy(spi->ImageName.Buffer, L"abc.exe", sizeof(L"abc.exe"));
                        char value1[PATH_BUFSIZE];
                        GET_STR_TO_UPPER(spi->ImageName.Buffer, value1, PATH_BUFSIZE);
                        std::stringstream sss1;
                        sss1 << value1;
                        EVASION("NtQuerySystemInformation ImageName.Buffer in the if, after change", sss1.str().c_str());
                        break;
                    }
                    
                }
                    
            }
            // calculate the address of the next entry.
            spi = (PSYSTEM_PROCESS_INFO)((W::LPBYTE)spi + spi->NextEntryOffset);
        }
        
    }
}

typedef struct _SYSTEM_PROCESS_INFO
{
    W::ULONG NextEntryOffset;
    W::ULONG NumberOfThreads;
    W::LARGE_INTEGER WorkingSetPrivateSize; // since VISTA
    W::ULONG HardFaultCount; // since WIN7
    W::ULONG NumberOfThreadsHighWatermark; // since WIN7
    W::ULONGLONG CycleTime; // since WIN7
    W::LARGE_INTEGER CreateTime;
    W::LARGE_INTEGER UserTime;
    W::LARGE_INTEGER KernelTime;
    W::UNICODE_STRING ImageName;
    W::KPRIORITY BasePriority;
    W::HANDLE UniqueProcessId;
    W::HANDLE InheritedFromUniqueProcessId;
    W::ULONG HandleCount;
    W::ULONG SessionId;
    W::ULONG_PTR UniqueProcessKey; // since VISTA (requires SystemExtendedProcessInformation)
    W::SIZE_T PeakVirtualSize;
    W::SIZE_T VirtualSize;
    W::ULONG PageFaultCount;
    W::SIZE_T PeakWorkingSetSize;
    W::SIZE_T WorkingSetSize;
    W::SIZE_T QuotaPeakPagedPoolUsage;
    W::SIZE_T QuotaPagedPoolUsage;
    W::SIZE_T QuotaPeakNonPagedPoolUsage;
    W::SIZE_T QuotaNonPagedPoolUsage;
    W::SIZE_T PagefileUsage;
    W::SIZE_T PeakPagefileUsage;
    W::SIZE_T PrivatePageCount;
    W::LARGE_INTEGER ReadOperationCount;
    W::LARGE_INTEGER WriteOperationCount;
    W::LARGE_INTEGER OtherOperationCount;
    W::LARGE_INTEGER ReadTransferCount;
    W::LARGE_INTEGER WriteTransferCount;
    W::LARGE_INTEGER OtherTransferCount;
    W::SYSTEM_THREAD_INFORMATION Threads[1];
} SYSTEM_PROCESS_INFO, * PSYSTEM_PROCESS_INFO;

I have tried various ways to change the ImageName.Buffer, including

PIN_SafeCopy(spi->ImageName.Buffer, L"abc.exe\0", sizeof(L"abc.exe\0"));
PIN_SafeCopy(spi->ImageName.Buffer, L"ab.exe", sizeof(L"ab.exe"));
PIN_SafeCopy(spi->ImageName.Buffer, L"a.exe", sizeof(L"a.exe"));
wcscpy(spi->ImageName.Buffer, L"abc.exe");

and

// Without the L prefix
PIN_SafeCopy(spi->ImageName.Buffer, "abc.exe", sizeof("abc.exe"));

and this works (does not cause an exception) around half of the time, it mangles the ImageName.Buffer which is a PWSTR and I can see in the log after the change that the ImageName.Buffer is ace.x

typedef struct _UNICODE_STRING { 
USHORT Length; 
USHORT MaximumLength; 
PWSTR Buffer; 
} UNICODE_STRING, *PUNICODE_STRING;

For all of this ways of changing ImageName.Buffer I can see in the log that after the PIN_SafeCopy the new Buffer reflects the change for example abc.exe but immediately after the break it throws and exception

EXCEPT_HANDLING_RESULT myExceptionHandler(THREADID tid, EXCEPTION_INFO* pExceptInfo, PHYSICAL_CONTEXT* pPhysCtxt, VOID* v) {
    MYINFO("ExceptionHandler", "ExceptionHandler");
    
    MYINFO("Pin Exception String ", "%s", PIN_ExceptionToString(pExceptInfo).c_str());
    MYINFO("Pin Exception Code ", "%s", pExceptInfo->GetExceptCode());
        
    return EHR_CONTINUE_SEARCH;
}

which logs "Pin Exception String" :Exception Code: RECEIVED_ACCESS_FAULT. Exception ADDRESS = 0x668c597. Access Type Read. Access Address 0x1d

I think it indicates that the Pin tool is trying to read from an invalid or inaccessible memory address and it could be I am not aligning the L"abc.exe" correctly.

One last thing, this is running on Win10 64 bit, and both the Pin tool (v3.25) and binary being instrumented are 32 bit, and I wonder if it could be a Wow64 issue with how it maps NTDLL.dll

Any pointers would be much appreciated, thank you

0

There are 0 best solutions below