dev.nlited.com

>>

QueryProcess

<<<< prev
next >>>>

2015-10-22 16:33:07 chip Page 1423 📢 PUBLIC

Oct 22 2015

Today's task is to extract the original command line text for a running process.

There is a discussion about this subject on StackOverflow. The most useful hint was "You should be accessing the memory in-context during your capture phase, after which point you should operate only on the captured values. Otherwise you have a security vulnerability." Raymond Chen Dec 16 '11 at 15:23. This made sense, so I rewrote my Process module to capture the information at first contact into a lookup table, then return the recorded info during the NetMon queries.

12:45> My first BSoD. I tried to run too much untested code at the same time. I lost the VerProd.h, Control/VerFile.h, and Control.rc files; I lost the ProcInfo dialog box I created yesterday. I am again reminded that it is a good idea to commit early and often. This is why I use VM's for development, although I wish I weren't using my VS12 VM...

13:04> Doh! Another BSoD! I need to revive Win7, I can't keep clobbering VS12.

13:28> Doh! BAD_POOL_CALLER. Time to go for a walk.

14:10> I think I found it. I added the initial process list as a statically declared array. When the first new process was added I reallocated the list, then tried to free the original list. Since the original list was not allocated from the pool, this was a bad pool pointer and triggered the kernel panic. I also added an IRQL check, but I think it is probably not necessary.

14:21> The driver is working again, with the command line probe still disabled.

14:30> Success. I am now seeing the original command line. Now I need to recreate my lost ProcInfo dialog and print it out in the details window.

15:15> Hmmm... Now that I know how svchost was invoked, I need to follow it further down the rabbit hole. I most curious about "svchost.exe -k NetworkService" which seems to be pinging servers all over the world. This blog has some tips. For example:
Process: [29C] svchost.exe Command line: C:\WINDOWS\system32\svchost.exe -k NetworkService

I should be able to find a running Service with a matching command line.

NetworkService service

I still don't have the path to the "NetworkService" DLL. This SO pointed me to this page that showed the way. The -k parameter points to a key under
\\HKLM\Software\Microsoft\Windows NT\CurrentVersion\SvcHost\
But there is nothing there! Then I notice that the service name in the Services dialog is "NlaSvc". That is where I find the path to the DLL: %SystemRoot%\System32\nlasvc.dll.

svchost.exe NetworkService nlasvc

There doesn't seem to be any way for me to make the jump from the command line parameter "NetworkService" back to the originating service key. The only link I see is the value "ObjectName=NT AUTHORITY\NetworkService". The name of the DLL to be loaded is in the service registry key, but this information is not included in the command line. Somehow svchost knows to load, or is told to load, the library after the process is launched. This leaves me with no clear way to trace from a running process back to the service key. The best I can do is to enumerate all the modules loaded by the process and present that list en masse to Control, then pick through the list and cross-reference the library name against the parameters in service keys. I could also flag any unsigned/untrusted modules for further investigation.

Gathering the list of loaded modules for a running process will require some peeking into the internal Windows structures.

Now that I have access to the process PEB, I can go spelunking...

This would be easy if I had WinDbg running, but I'm not quite to the point where I think spending the time reviving Win7 is worth it. I'll need to pound my head against a few more BSoD's.

I found this link that helped explain how to walk the LDR_DATA_TABLE_ENTRY list.

17:30> I added the library lists. A lot of code went in, here's hoping it doesn't crash... The module list was empty in the Detail window, then it BSoD'ed after a few minutes with DRIVER_IRQL_NOT_LESS_OR_EQUAL. I know from experience that this error can be a red herring, it is most likely just a bad pointer crash. I will need to take this one step at a time...

21:00> Well, this is why I shouldn't debug drivers on the dev machine:

S:\Src\HQ\Dev\SB\Chip\win8\NetMon>git commit -m "NetMon: Debugging ProcProbeLibraries." error: inflate: data stream error (unknown compression method) fatal: loose object c3bb6658899cebd09ce5513170c5eb34490c7a82 (stored in .git/objects/c3/bb6658899cebd09ce5513170c5eb3449 0c7a82) is corrupt S:\Src\HQ\Dev\SB\Chip\win8\NetMon>

22:00> I think I have recovered. But it is clearly time to revive Win7 before doing any more driver testing. Tomorrow's task: Bring the Win7 VM back to life. Remote Kernel Debugging: Reviving Win7

12:50> (Two days later.) I am back in business with Win7. I added some code to prevent re-entry into ProcProbeLibraries() while I am stepping through it. Remote debugging is painfully, inexplicably, slow even when both machines are running on the same physical hardware. 8GB of RAM is simply not enough to run 3 complete copies of Windows without thrashing the swapfile. It takes about 3-4 seconds to step from one line to the next, but the ability to examine live data saves me from spending days writing throw-away hex dump code, rebooting crashed machines, and basically going insane.

13:10> It is one baffling problem after another... Now Process.cpp refuses to build, complaining that PEPROCESS is being defined more than once in WDM.h and NtIfs.h. Why? I guess I had uncommented NtDDK.h while trying to "clean up" the includes. Weird.

13:22> I am finally stepping through an un-optimized version of ProcProbeLibraries(). I am not seeing my printf output in the debugger. I will need to copy the text to a global buffer so I can monitor it in the watch window.

ProcProbeLibraries Win7 remote debugging

13:40> OK, it took about 20 minutes to step through a single iteration of the module loop. It seemed as though it crashed the first time it tried to use the Flink of the pEntry. I added gPrintText to hold the text from the most recent Print(). This time 'round I will try to walk the module list by hand.

13:56> It took 9 minutes from the time I launched Win7 to gaining control in VS15 at my breakpoint in ProcProbLibraries(). Now that I am there... There is some wierd syntax going on in the watch window, it is unable to evaluate "gPrintText" even though it works in the immediate window as "db gPrintText"


: pPeb= 7FF'FFFD:A000 pPeb->Ldr= 77A7:2640 pPeb->Ldr->InMemoryOrderModuleList= 0'77A7:2640 pPeb->Ldr->InMemoryOrderModuleList->Flink= 0'001B:2D40 pPeb->Ldr->InMemoryOrderModuleList->Blink= 0'001F:4790 The list terminator will be 0'77A7:2660, which is &InMemoryOrderModuleList. This is also the value of InMemoryOrderModuleList.Blink Following the links, I can validate each link by checking that pNext->Blink == pEntry->Flink. FullDllName.Buffer is &Flink + 0x40 1st Module: 0'001B:2D40 Flink= 0'001B:2E30 Blink= 0'77A7:2660 (Which is &InMemoryOrderModuleList->Flink) FullDllName.Buffer= +0x40= 1B:2C18= 'C:\NetMon\NetMonUI.exe' 2nd Module: 0'001B:2E30 Flink= 0'001B:31B0 Blink= 0'001B:2D40 (1st Module) FullDllName.Buffer= 1B:2CA0= 'C:\Windows\SYSTEM32\ntdll.dll' 3rd Module: 0'001B:31B0 Flink= 0'001B:3320 Blink= 0'001B:2E30 (2nd Module) FullDllName.Buffer= 1B:3150= 'C:\Windows\system32\kernel32.dll' 4th Module: 0'001B:3320 Flink= 0'001B:4040 Blink= 0'001B:31B0 ... 0'001B:4040= 0'001B:41B0 0'001B:41B0= 0'001B:43A0 0'001B:43A0= 0'001B:45D0 0'001B:45D0= 001B:4710 > 001E:F380 > 001E:F6F0 > 001E:F4C0 > 001E:FC30 > 001E:F8F0 > 001E:F9E0 > 001F:0800 > 001f:3ee0 > 001f:4010 > 001f4100 > 001f41f0 > 001f43d0 > 001f44c0 > 001f45b0 > 001f46a0 > 001f4790 > 77a72660 77A7:2660 terminates the list by being equal to &InMemoryOrderModuleList->Flink.

Oct 25 2015

Debugging ProcProbeLibraries is excruciatingly slow, as I spend most of my time waiting for the target system to reboot. It was especially painful today as I had to wait over two hours while Windows installed 53 updates.


Oct 26 2015

I spent most of yesterday watching the very interesting motoGP race in Sapang. My opinion is that Rossi knew exactly what he was doing. Nick's opinion is that Marc was asking for it and there was nothing wrong with what Rossi did.

Kernel debugging using the VS15 embedded debugger is unbearably slow. I am now trying to use the stand-alone WinDbg from the Windows 10 DDK. (C:\Programs and Files (x86)\Windows Kits\10\Debuggers\x64\windbg) At least I can edit files while I am waiting for the debugger. WinDbg responds to the hard breakpoint in DrvEntry much faster, there is no 5 minute delay. I can also see the debug text in real-time. This makes the debugger much more useful, but dramatically slows the overall performance of the target system.

I converted Process.cpp to ProcList.cpp and moved all the code into the ProcList class. I added a mutex to control access to the process list. Now the driver crashes every time during load.

12:35> NetMon no longer crashes after I completely disabled all code in ProcList. Now I will enable only ProcListCreate() and ProcListDestroy().

12:40> NetMon crashed, pointing the fickle finger of blame at ProcListCreate(), probably OSMUTEX. Using WinDbg is much better than VS15; not only can I edit and rebuild the code, but I can leave WinDbg connected and run multiple debug sessions without rebooting the target. Now I need to see if I can step through the code using WinDbg.

13:08> I stepped through DrvEntry and everything was fine, the crash happens after I return. I paid a bit more attention to the bugcheck and found that bugcheck 0x39 is SYSTEM_EXIT_OWNED_MUTEX. I had neglected to release hProbeMtx in ProcList::Create2(). Netmon now loads and unloads OK.

14:23> Enabling ProcListRecord()... This seems to be working, but printing the names of up to 126 modules through WinDbg causes big problems. I need to disable the debug print and try again.

14:52> ProcList is finally working. I am able to load, enumerate, download, and unload without any problems.

WinDbg is still slow, but much better than using VS15.

16:18> A crash during testing (IRQL_NOT_LESS_THAN) was fixed by lowering the required IRQL in ProcListRecord() to PASSIVE_LEVEL(0). A mutex with a timeout requires APC_LEVEL(1) or lower.


ProcList.cpp: /*************************************************************************/ /** ProcList.cpp: Manage information about running process. **/ /** (C)2015 nlited systems inc, Chip Doran **/ /*************************************************************************/ #include <ntifs.h> #include <ntstrsafe.h> #include <WinDef.h> #include "StdTypes.h" #include "Errors.h" #include "VerID.h" #include "OS.h" #include "NetMon.h" #include "Globals.h" #include "PEB.h" #pragma message(__FILE__": Optimizer disabled.") #pragma optimize("",off) static ZWQUERYINFORMATIONPROCESS _ZwQueryInformationProcess=0; struct ProcessInfo_s { UINT64 ProcID; WCHAR ImagePath[260]; WCHAR CmdLine[260]; UINT ChkCt; LARGE_INTEGER LastChk; WCHAR Libraries[4096]; //Packed strings, terminated by 0-length string. }; class ProcList { public: static ProcList *Ptr(HPROCLIST hProcList); static int Create(HPROCLIST *phProcList); int Destroy(); int Record(void); int Query(UINT Type, UINT Index, UINT64 ProcID, WCHAR *pDst, UINT DstSz); //Data UINT Signature; private: ProcList(void); ~ProcList(void); int Create2(void); int RecordCreate(UINT64 ProcID); int RecordUpdate(struct ProcessInfo_s *pProc); int GetImagePath(UINT64 ProcID, WCHAR *pDst, UINT DstSz); int GetCmdLine(UINT64 ProcID, WCHAR *pDst, UINT DstSz); int GetLibrary(UINT64 ProcID, UINT Index, WCHAR *pDst, UINT DstSz); ProcessInfo_s *FindID(UINT64 ProcID); int Grow(void); int Open(HANDLE *phProc, UINT64 ProcID); void *FindFunction(const WCHAR *Name); int ProbeImagePath(HANDLE hProc, UINT64 ProcID, WCHAR *pDst, UINT DstSz); int ProbeCmdLine(HANDLE hProc, UINT64 ProcID, WCHAR *pDst, UINT DstSz); int ProbeLibraries(HANDLE hProc, UINT64 ProcID, WCHAR *pDst, UINT DstSz); int ProbeLibraries2(HANDLE hProc, UINT64 ProcID, WCHAR *pDst, UINT DstSz); //Data OSMUTEX hProbeMtx; UINT ListSz; UINT ListCt; struct ProcessInfo_s *pList; }; static HPROCLIST ghProcList; static const struct ProcessDflt_s { UINT64 ProcID; const WCHAR *Name; } ProcDefaults[]={ { 4, L"NtKernel" }, { (UINT64)-1 } }; /*************************************************************************/ /** Public interface **/ /*************************************************************************/ int ProcListCreate(HPROCLIST *phProcList) { int Err= ERR_OK; HPROCLIST hProcList; if(IsErr(Err= ProcList::Create(&hProcList))) { Err= ErrorA(Err,FUNCA"Unable to create ProcList."); } else { if(!ghProcList) ghProcList= hProcList; if(phProcList) *phProcList= hProcList; } return(Err); } int ProcListDestroy(HPROCLIST hProcList) { int Err= ERR_OK; ProcList *pList= ProcList::Ptr(hProcList); if(!pList) { Err= WarnA(ERR_NO_INIT,FUNCA"Bad hProcList[%X]",hProcList); } else if(!IsErr(Err= pList->Destroy())) { if((HPROCLIST)pList==ghProcList) ghProcList= 0; } return(Err); } int ProcListRecord(void) { int Err= ERR_OK; ProcList *pList= ProcList::Ptr(ghProcList); if(!pList) { Err= ERR_NO_INIT; } else { Err= pList->Record(); } return(Err); } int ProcListQuery(UINT Type, UINT Index, UINT64 ProcID, WCHAR *pDst, UINT DstSz) { int Err= ERR_OK; ProcList *pList= ProcList::Ptr(ghProcList); if(!pList) { Err= ERR_NO_INIT; } else { Err= pList->Query(Type,Index,ProcID,pDst,DstSz); } return(Err); } /*************************************************************************/ /** Public internals **/ /*************************************************************************/ ProcList *ProcList::Ptr(HPROCLIST hList) { ProcList *pList=(ProcList*)(hList ? hList : ghProcList); if(!pList || IsBadPtr(pList,sizeof(*pList),BADPTR_RW) || pList->Signature!=SIGNATURE_PROCLIST) return(0); return(pList); } int ProcList::Create(HPROCLIST *phProcList) { int Err=ERR_OK; ProcList *pList= new ProcList(); if(!pList) { Err=ErrorA(ERR_NO_MEM, FUNCA"Unable to alloc %d.", sizeof(*pList)); } else if(IsErr(Err= pList->Create2())) { delete pList; } else { *phProcList=(HPROCLIST)pList; } return(Err); } int ProcList::Destroy(void) { int Err=ERR_OK; delete this; return(Err); } int ProcList::Record(void) { int Err=ERR_OK; UINT64 ProcID= (UINT64)PsGetCurrentProcessId(); struct ProcessInfo_s *pProc; //Need to be at DISPATCH_LEVEL to do anything. if(IsErr(IrqlChk(DISPATCH_LEVEL, "ProcRecord"))) { Err=ERR_OK; } else { OsMutexAcquire(hProbeMtx,1000,"Record"); if(pProc= FindID(ProcID)) { //Err= RecordUpdate(pProc); } else { Err= RecordCreate(ProcID); } OsMutexRelease(hProbeMtx); } return(Err); } int ProcList::Query(UINT Type, UINT Index, UINT64 ProcID, WCHAR *pDst, UINT DstSz) { int Err=ERR_OK; switch(Type) { case CMD_PROCESS_QUERY_PATH: Err= GetImagePath(ProcID, pDst, DstSz); break; case CMD_PROCESS_QUERY_CMDLINE: Err= GetCmdLine(ProcID, pDst, DstSz); break; case CMD_PROCESS_QUERY_LIBRARY: Err= GetLibrary(ProcID, Index, pDst, DstSz); break; default: Err= WarnA(ERR_BAD_ARG1, FUNCA"Invalid query type."); } return(Err); } /*************************************************************************/ /** Internals **/ /*************************************************************************/ ProcList::ProcList(void) { Signature= SIGNATURE_PROCLIST; OsMutexCreate(&hProbeMtx,"ProcProbeMtx"); } ProcList::~ProcList(void) { Signature|= SIGNATURE_INVALID; if(pList) MemFree(pList); OsMutexDestroy(hProbeMtx); } int ProcList::Create2(void) { int Err= ERR_OK; OsMutexAcquire(hProbeMtx,1000,"Create2"); for(UINT n1=0;!IsErr(Err) && ProcDefaults[n1].ProcID!=-1;n1++) { if(!IsErr(Err= Grow())) { struct ProcessInfo_s *pEntry= &pList[ListCt++]; pEntry->ProcID= ProcDefaults[n1].ProcID; wcsncpy(pEntry->ImagePath,ProcDefaults[n1].Name,STRSIZE(pEntry->ImagePath)); } } OsMutexRelease(hProbeMtx); return(Err); } int ProcList::RecordCreate(UINT64 ProcID) { int Err2, Err=ERR_OK; HANDLE hProc=0; struct ProcessInfo_s *pProc; if(IsErr(Err=Grow())) return(ErrorA(ERR_NO_MEM, FUNCA"Unable to grow process list beyond %d.", ListSz)); pProc=&pList[ListCt++]; pProc->ProcID=ProcID; if(IsErr(Err=Open(&hProc, ProcID))) { Err=WarnA(Err, FUNCA"Unable to open ProcID[%llX]", ProcID); } else { if(IsErr(Err2=ProbeImagePath(hProc, ProcID, pProc->ImagePath, STRSIZE(pProc->ImagePath)))) Err=WarnA(Err2, FUNCA"Unable to determine ProcID[%llX] image path.", ProcID); if(IsErr(Err2=ProbeCmdLine(hProc, ProcID, pProc->CmdLine, STRSIZE(pProc->CmdLine)))) Err=WarnA(Err2, FUNCA"Unable to determine ProcID[%llX] command line.", ProcID); if(IsErr(Err2=ProbeLibraries(hProc, ProcID, pProc->Libraries, STRSIZE(pProc->Libraries)))) Err=WarnA(Err2, FUNCA"Unable to read ProcID[%llX] library list.", ProcID); else PrintA(PRINT_DEBUG,"%S: %d modules.",pProc->ImagePath,Err2); ZwClose(hProc); } return(Err); } int ProcList::RecordUpdate(struct ProcessInfo_s *pProc) { int Err2, Err=ERR_OK; HANDLE hProc=0; //TODO: Reduce the number of times I walk the module list. LARGE_INTEGER tick; KeQueryTickCount(&tick); if(pProc->ChkCt < 3 && tick.QuadPart>=pProc->LastChk.QuadPart) { ULONG NextChk=(++pProc->ChkCt*100000000); pProc->LastChk.QuadPart=tick.QuadPart+NextChk/KeQueryTimeIncrement(); if(IsErr(Err=Open(&hProc, pProc->ProcID))) { Err=WarnA(Err, FUNCA"Unable to open ProcID[%llX]", pProc->ProcID); } else { if(IsErr(Err2=ProbeLibraries(hProc, pProc->ProcID, pProc->Libraries, STRSIZE(pProc->Libraries)))) Err=WarnA(Err2, FUNCA"Unable to read ProcID[%llX] library list.", pProc->ProcID); else PrintA(PRINT_DEBUG,"%S: %d modules",pProc->ImagePath,Err2); ZwClose(hProc); } } return(Err); } int ProcList::GetImagePath(UINT64 ProcID, WCHAR *pDst, UINT DstSz) { int Err=ERR_OK; struct ProcessInfo_s *pProc; if(!(pProc= FindID(ProcID))) { Err=WarnA(ERR_NOT_FOUND, FUNCA"ProcID[%llX] not found.", ProcID); } else { RtlStringCchCopyW(pDst, DstSz, pProc->ImagePath); } return(Err); } int ProcList::GetCmdLine(UINT64 ProcID, WCHAR *pDst, UINT DstSz) { int Err=ERR_OK; struct ProcessInfo_s *pProc; if(!(pProc= FindID(ProcID))) { Err=WarnA(ERR_NOT_FOUND, FUNCA"ProcID[%llX] not found.", ProcID); } else { RtlStringCchCopyW(pDst, DstSz, pProc->CmdLine); } return(Err); } int ProcList::GetLibrary(UINT64 ProcID, UINT Index, WCHAR *pDst, UINT DstSz) { int Err=ERR_OK; struct ProcessInfo_s *pProc; if(!(pProc= FindID(ProcID))) { Err=WarnA(ERR_NOT_FOUND, FUNCA"ProcID[%llX] not found.", ProcID); } else { UINT LibCt, ChrCt; for(LibCt=ChrCt=0;LibCt<Index && ChrCt<STRSIZE(pProc->Libraries);ChrCt++) { if(pProc->Libraries[ChrCt]==0) { LibCt++; if(pProc->Libraries[ChrCt+1]==0) ChrCt= STRSIZE(pProc->Libraries); } } if(ChrCt>=STRSIZE(pProc->Libraries)) { Err= ERR_NOT_FOUND; } else { RtlStringCchCopyW(pDst, DstSz, &pProc->Libraries[ChrCt]); } } return(Err); } ProcessInfo_s *ProcList::FindID(UINT64 ProcID) { UINT n1; for(n1=0;n1<ListCt;n1++) { if(pList[n1].ProcID==ProcID) { return(&pList[n1]); } } return(0); } int ProcList::Grow(void) { int Err=ERR_OK; struct ProcessInfo_s *pNew; UINT NewSz= ListSz+100; UINT MemCt= NewSz*sizeof(pNew[0]); if(ListCt>=ListSz) { if(!(pNew=(struct ProcessInfo_s*)MemAlloc("ProcList", MemCt))) { Err= ErrorA(ERR_NO_MEM, FUNCA"Unable to alloc %d.", MemCt); } else { if(pList) { RtlCopyMemory(pNew, pList, ListCt*sizeof(pList[0])); MemFree(pList); } ListSz= NewSz; pList= pNew; } } return(Err); } int ProcList::Open(HANDLE *phProc, UINT64 ProcID) { int Err=ERR_OK; NTSTATUS Status; PEPROCESS eProc=0; if(!_ZwQueryInformationProcess) _ZwQueryInformationProcess=(ZWQUERYINFORMATIONPROCESS)FindFunction(L"ZwQueryInformationProcess"); if(!_ZwQueryInformationProcess) { Err=WarnA(ERR_NOT_SUPPORTED, FUNCA "Bummer, ZwQueryInformationProcess not found."); } else if(!NT_SUCCESS(Status=PsLookupProcessByProcessId((HANDLE)ProcID, &eProc))) { Err=WarnA(ERR_NOT_FOUND, FUNCA"ProcID %X not found.", ProcID); } else if(!NT_SUCCESS(Status=ObOpenObjectByPointer(eProc, 0, 0, 0, 0, KernelMode, phProc))||!*phProc) { Err=WarnA(ERR_NOT_FOUND, FUNCA"Unable to transform eProc[%X] to hProc.", eProc); } if(eProc) ObDereferenceObject(eProc); return(Err); } void *ProcList::FindFunction(const WCHAR *Name) { UNICODE_STRING NameU; void *pFunc; RtlInitUnicodeString(&NameU, Name); pFunc=MmGetSystemRoutineAddress(&NameU); if(!pFunc) WarnA(ERR_NOT_SUPPORTED, FUNCA" System function '%S' not found.", Name); return(pFunc); } int ProcList::ProbeImagePath(HANDLE hProc, UINT64 ProcID, WCHAR *pDst, UINT DstSz) { int Err=ERR_OK; NTSTATUS Status; UNICODE_STRING *pName=0; ULONG MaxLength=1024; //Buffer length (bytes) if(!(pName=(UNICODE_STRING*)ExAllocatePoolWithTag(NonPagedPool, MaxLength, 'ipgD'))) { Err=WarnA(ERR_NO_MEM, FUNCA"Unable to alloc %d.", MaxLength); } else { RtlZeroMemory(pName, MaxLength); //pName will be initialized by ZwQuery() if(!NT_SUCCESS(Status=_ZwQueryInformationProcess(hProc, ProcessImageFileName, pName, MaxLength, &MaxLength))) { Err=WarnA(ERR_FAILED, FUNCA"ZwQueryInformationProcess failed. [%X]", Status); } else if(!pName->Length) { Err=WarnA(ERR_NOT_FOUND, FUNCA"No info for ProcID[%X]", ProcID); } else { PrintA(PRINT_DEBUG, FUNCA"ProcID[%X] is '%wZ'", ProcID, pName); RtlStringCchCopyUnicodeString(pDst, DstSz, pName); } ExFreePoolWithTag(pName, 'ipgD'); } return(Err); } int ProcList::ProbeCmdLine(HANDLE hProc, UINT64 ProcID, WCHAR *pDst, UINT DstSz) { int Err=ERR_OK; NTSTATUS Status; PROCESS_BASIC_INFORMATION Peb; ULONG readCt; RtlZeroMemory(&Peb, sizeof(Peb)); if(!NT_SUCCESS(Status=_ZwQueryInformationProcess(hProc, ProcessBasicInformation, &Peb, sizeof(Peb), &readCt))) { Err=WarnA(ERR_FAILED, FUNCA"ZwQuery(PEB) failed."); } else { PrintA(PRINT_DEBUG, FUNCA"PEB[%llX,%d]", Peb.PebBaseAddress, sizeof(Peb.PebBaseAddress)); __try { struct _PEB *pPeb=(_PEB*)Peb.PebBaseAddress; RTL_USER_PROCESS_PARAMETERS *pParms=pPeb->ProcessParameters; RtlStringCchCopyUnicodeString(pDst, DstSz, &pParms->CommandLine); PrintA(PRINT_DEBUG, FUNCA"ProcID[%llX] command line: '%S'", ProcID, pDst); } __except(EXCEPTION_EXECUTE_HANDLER) { Err=WarnA(ERR_FAILED, FUNCA"Exception while probing command line."); } } return(Err); } int ProcList::ProbeLibraries(HANDLE hProc, UINT64 ProcID, WCHAR *pDst, UINT DstSz) { int Err=ERR_OK; static BYTE IsProbing=0; if(!gpCfg->DisableProcProbe && !IsProbing++) { Err=ProbeLibraries2(hProc, ProcID, pDst, DstSz); IsProbing=0; } return(Err); } int ProcList::ProbeLibraries2(HANDLE hProc, UINT64 ProcID, WCHAR *pDst, UINT DstSz) { int Err=ERR_OK; NTSTATUS Status; PROCESS_BASIC_INFORMATION Peb; ULONG readCt; RtlZeroMemory(&Peb, sizeof(Peb)); if(!NT_SUCCESS(Status=_ZwQueryInformationProcess(hProc, ProcessBasicInformation, &Peb, sizeof(Peb), &readCt))) { Err=WarnA(ERR_FAILED, FUNCA"ZwQuery(PEB) failed."); } else __try { struct _PEB *pPeb=(_PEB*)Peb.PebBaseAddress; if(!pPeb->Ldr) { PrintA(PRINT_DEBUG, FUNCA"ProcID[%llX] No module list?", ProcID); } else { //InMemoryOrderModuleList is the entry point into a circular linked //list of LIST_ENTRY records. The list is terminated by a Flink that //points back to &InMemoryOrderModuleList to close the circle. //Each LIST_ENTRY (except the head) is embedded in a LDR_DATA_TABLE_ENTRY. //I created the alias LDR_DATA_TABLE_ENTRY2 that removes the need to do //calculate the offset to the module struct. UINT ChrCt=0, ModuleCt=0; LIST_ENTRY *pEntry, *pHead=&pPeb->Ldr->InMemoryOrderModuleList; LIST_ENTRY *pTerm=pHead->Blink; //Not necessary? LDR_DATA_TABLE_ENTRY2 *pModule; PrintA(PRINT_DEBUG, FUNCA"ProcID[%llX] Module list %llX (Term=%llX)", ProcID, pHead, pTerm); for(pEntry=pHead->Flink;pEntry!=0&&pEntry!=pTerm;pEntry=pEntry->Flink) { ModuleCt++; pModule=(LDR_DATA_TABLE_ENTRY2*)pEntry; const WCHAR *pModPath=pModule->FullDllName.Buffer; //PrintA(PRINT_DEBUG,FUNCA" pModule=%llX Dll.Buffer=%llX[%llX]",pModule,&pModPath,pModPath); //PrintA(PRINT_DEBUG, FUNCA" Module %d: %S", ModuleCt, pModPath); //Copy the FullDllName text into the packed string buffer pDst. if(ChrCt+pModule->FullDllName.Length/2+1 >= DstSz) { WarnA(ERR_TOO_SMALL,FUNCA"Ran out of room in Libraries[]"); break; } else { RtlStringCchCopyUnicodeString(&pDst[ChrCt],DstSz-ChrCt,&pModule->FullDllName); ChrCt+= pModule->FullDllName.Length/2; pDst[ChrCt++]= 0; //Redundant, but just to make sure. } } pDst[ChrCt]=0; //Terminate the packed list. if(!IsErr(Err)) Err= ModuleCt; } } __except(EXCEPTION_EXECUTE_HANDLER) { Err=WarnA(ERR_FAILED, FUNCA"Exception while probing library list."); } return(Err); }
PEB.h: /*************************************************************************/ /** PEB.h: Process structures copied from WDK/Include/um/wintrnl.h **/ /** (C)2015 nlited systems inc, Chip Doran **/ /*************************************************************************/ #ifndef __PEB_H__ #define __PEB_H__ 0x0101 typedef NTSTATUS(__stdcall *ZWQUERYINFORMATIONPROCESS)( __in HANDLE ProcessHandle, __in PROCESSINFOCLASS ProcessInformationClass, __out PVOID ProcessInformation, __in ULONG ProcessInformationLength, __out_opt PULONG ReturnLength ); typedef struct _PEB_LDR_DATA { BYTE Reserved1[8]; PVOID Reserved2[3]; LIST_ENTRY InMemoryOrderModuleList; } PEB_LDR_DATA, *PPEB_LDR_DATA; typedef struct _LDR_DATA_TABLE_ENTRY { PVOID Reserved1[2]; LIST_ENTRY InMemoryOrderLinks; PVOID Reserved2[2]; PVOID DllBase; PVOID Reserved3[2]; UNICODE_STRING FullDllName; BYTE Reserved4[8]; PVOID Reserved5[3]; union { ULONG CheckSum; PVOID Reserved6; } DUMMYUNIONNAME; ULONG TimeDateStamp; } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; typedef struct _LDR_DATA_TABLE_ENTRY2 { LIST_ENTRY InMemoryOrderLinks; PVOID Reserved2[2]; PVOID DllBase; PVOID Reserved3[2]; UNICODE_STRING FullDllName; BYTE Reserved4[8]; PVOID Reserved5[3]; union { ULONG CheckSum; PVOID Reserved6; } DUMMYUNIONNAME; ULONG TimeDateStamp; } LDR_DATA_TABLE_ENTRY2; typedef struct _RTL_USER_PROCESS_PARAMETERS { BYTE Reserved1[16]; PVOID Reserved2[10]; UNICODE_STRING ImagePathName; UNICODE_STRING CommandLine; } RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS; typedef VOID (NTAPI *PPS_POST_PROCESS_INIT_ROUTINE) ( VOID ); typedef struct _PEB { BYTE Reserved1[2]; BYTE BeingDebugged; BYTE Reserved2[1]; PVOID Reserved3[2]; PPEB_LDR_DATA Ldr; PRTL_USER_PROCESS_PARAMETERS ProcessParameters; PVOID Reserved4[3]; PVOID AtlThunkSListPtr; PVOID Reserved5; ULONG Reserved6; PVOID Reserved7; ULONG Reserved8; ULONG AtlThunkSListPtr32; PVOID Reserved9[45]; BYTE Reserved10[96]; PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine; BYTE Reserved11[128]; PVOID Reserved12[1]; ULONG SessionId; } PEB, *PPEB; typedef struct _TEB { PVOID Reserved1[12]; PPEB ProcessEnvironmentBlock; PVOID Reserved2[399]; BYTE Reserved3[1952]; PVOID TlsSlots[64]; BYTE Reserved4[8]; PVOID Reserved5[26]; PVOID ReservedForOle; // Windows 2000 only PVOID Reserved6[4]; PVOID TlsExpansionSlots; } TEB, *PTEB; #endif


WebV7 (C)2018 nlited | Rendered by tikope in 49.986ms | 13.58.32.115