2

I am writing a Windows kernel mode driver which uses API

PsSetCreateProcessNotifyRoutineEx

In its callback function, I need to get the current working directory of process. How this can be done? Any ideas, leads would be very useful.

Thanks in advance.

Hemant
  • 767
  • 6
  • 20
  • 2
    get `PEB` address via `PsGetProcessPeb`, attach to process, and read `ProcessParameters->CurrentDirectory.DosPath` – RbMm Jan 31 '20 at 11:58
  • 2
    What for? It seems like a bad idea to use this in a driver. The process working directory is a convenience that's intended for single-threaded code in user mode, and it's ignored even by most Windows programs, including PowerShell. In the kernel, the object and I/O managers do not use the working directory of a process. In the NT API, a relative file path is relative to a handle for a file object, and a leading "." component has no significance. – Eryk Sun Jan 31 '20 at 14:19
  • Hi @RbMm, I am very new to driver development so my knowledge is very basic. From your earlier comment what I found is that the PsGetProcessPeb is undocumented windows API which might make the driver fragile. So is there any way to get CWD from standard APIs from driver code? – Hemant Jan 31 '20 at 16:45
  • if you afraid use "undocumenred" api - not take such tasks – RbMm Jan 31 '20 at 17:35
  • @Hemant: can you please clarify what does "current working directory" of the process mean ? The process might have open handles to many directories. You can definitely get the handles of all of them. May be tell us what bigger problem are you trying to solve ? – user4848830 Feb 02 '20 at 05:48
  • The "current working directory" is the directory from where the process is invoked. I want to search a perticular file in this directory everytime some specific process is invoked. – Hemant Feb 03 '20 at 06:32
  • Thanks @RbMm, solved the problem with your suggestion. – Hemant Feb 10 '20 at 09:34

1 Answers1

3

Following code solved the issue

KAPC_STATE ka_state;
WCHAR   CWDBuffer[MAX_PATH] = { 0 };
USHORT  CWDBytes = 0;

UNICODE_STRING GetProcessPeb = RTL_CONSTANT_STRING(L"PsGetProcessPeb");
PsGetPeb = (PsGetProcessPeb)MmGetSystemRoutineAddress(&GetProcessPeb);
if (PsGetPeb)
{
    Peb = PsGetPeb(Process); // Process is handle to current process
    if (Peb) {
        KeStackAttachProcess(Process, &ka_state);

        if (Peb->ProcessParameters->CurrentDirectory.DosPath.Length < (MAX_PATH * sizeof(WCHAR)))
        {
            CWDBytes = Peb->ProcessParameters->CurrentDirectory.DosPath.Length;
        }
        else
        {
            CWDBytes = MAX_PATH * sizeof(WCHAR);
        }

        memcpy(CWDBuffer, Peb->ProcessParameters->CurrentDirectory.DosPath.Buffer, CWDBytes);

        KeUnstackDetachProcess(&ka_state);
    }
    else {
        DbgPrintEx(
            DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL,
            "Unable to get PEB\n"
        );
    }
}
Hemant
  • 767
  • 6
  • 20
  • I was trying something similar by accessing the PEB during the loadimage event, except I wanted to report the command line arguments for each non-DLL image as the system loaded them. After hours of trying different things that didn't work, the technique used here was the best and most straightforward solution. – byteptr Feb 20 '20 at 08:01
  • You got a serious buffer overflow problem here. CWDBuffer is maximum size of 260, but later you are trying to write 520 (MAX_PATH * sizeof(WCHAR)). – Mecanik Oct 08 '20 at 09:46