📄 procpath.asm
字号:
; DesiredAccess is also doesn't matter, by the way !!! It can be any value :)
;
; To make it really check the object type we must specify UserMode.
;
; The above note is applicable to all ObReferenceObjectByPointer calls in this source code.
;
; Also bear in mind that existence of AccessMode parameter for ObReferenceObjectByPointer
; is odd (in my humble opinion). It's OK for ObReferenceObjectByHandle because we may deal
; with handle passed from user mode, but if we already have a pointer to object it means we
; have managed to get it somehow from kernel. So no need to check access type.
; I've tested this driver on 2000, XP & 2003 and it seems to be workable.
; But I'm afraid that behaviour of ObReferenceObjectByPointer may change in the future.
;
; Although DesiredAccess doesn't matter we will always pass valid access mask.
PROCESS_QUERY_INFORMATION equ 400h ; winnt.inc
mov ecx, PsProcessType
mov ecx, [ecx]
mov ecx, [ecx] ; PTR OBJECT_TYPE
invoke ObReferenceObjectByPointer, peProcess, PROCESS_QUERY_INFORMATION, ecx, UserMode
.if eax == STATUS_SUCCESS
.if g_dwWinVer == WINVER_UNINITIALIZED
; We are first time here
; What Windows we are running on?
invoke IoIsWdmVersionAvailable, 1, 20h
.if al
; If WDM 1.20 is supported, this is Windows XP or better
mov g_dwWinVer, WINVER_XP_OR_HIGHER
.else
; If not, this is Windows 2000
mov g_dwWinVer, WINVER_2K
.endif
.endif
.if g_dwWinVer == WINVER_XP_OR_HIGHER
;
; This is Windows XP or better
; So we should find EPROCESS.SectionObject
; XP: EPROCESS.SectionObject at 0138h
; 2003: EPROCESS.SectionObject at 0114h
; We could hardcode offset but better try to find it
;
; I hope to find section object pointer
; in the range 80h - 200h from beginning of EPROCESS
;
mov esi, peProcess
mov ebx, 80h ; Start at offset 80h
.while ebx < 204h
; Filter unreasonable candidates
mov edi, [esi][ebx]
invoke IsLikeObjectPointer, edi
.if eax == TRUE
; Additional check. At the moment of process creation/destruction
; base section object PointerCount equal to 3/2 and
; HandleCount equal to 1/0. This is true under XP+.
; Assume that PointerCount may grow up to 4.
; This check let us filter the rest.
mov eax, edi
sub eax, sizeof OBJECT_HEADER
.if ([OBJECT_HEADER PTR [eax]].PointerCount <= 4) && ([OBJECT_HEADER PTR [eax]].HandleCount <= 1)
; Very high chances that edi holds base section object pointer.
mov ecx, MmSectionObjectType
mov ecx, [ecx]
mov ecx, [ecx] ; PTR OBJECT_TYPE
invoke ObReferenceObjectByPointer, edi, SECTION_QUERY, ecx, UserMode
.if eax == STATUS_SUCCESS
; edi seems really to be a pointer to base section object
mov status, eax
mov pSection, edi
;invoke DbgPrint, \
; $CTA0("ProcessMon: Section object pointer found at offset %X\n"), \
; ebx
.break
.endif
.endif
.endif
add ebx, 4 ; Pointer must be DWORD aligned
; So lets try next DWORD
.endw
.else
;
; We are under Windows 2000. On this system the section handle that
; process image file mapped into is stored in EPROCESS.SectionHandle
; and is always (with one exception) equal to 4 because it's very
; first object created in the process. Handle tables are implemented
; as a three-level arrays, similar to the way that the x86 memory
; management unit implements virtual to physical address translation.
; The object manager treats the low 24 bits of an object handle's value
; as three 8-bit fields that index into each of the three levels
; in the handle table. The arrays at each level consist of 256 entries.
; Each entry is 4 bytes long because it contains pointer to the object.
; The last entry in the subhandle table is initialized with a value of -1.
;
; So when a process is created, the object manager starts to fill subhandle
; tables from the beginning of the subhandle table. (The 0 handle index
; is reserved, first handle index is 4, the second 8, and so on).
; So we can just reference handle 4 to get section object pointer.
;
; On w2k+sp4 if the process is started from command line (cmd.exe)
; or bat file the section handle is not value of 4! Don't know why
; but in this particular case the object manager fills subhandle tables
; in reverse order (from top to bottom). So the first index it uses
; is not 4 but 254 (255 initialized with a value of -1.)
; 254*sizeof(pointer) = 03F8h
;
; I can't be shure it's so on any sp4 box, but it appears to be so
; at least on 5-6 test machines. So my first workaround
; is to try reference handle 3F8h.
;
; If it still fails our last try just to reference whatever value
; in EPROCESS.SectionHandle.
xor ebx, ebx ; counter of tries
mov edi, 4 ; First try to reference handle 4 (most common).
.while ebx < 3
invoke IoGetCurrentProcess
.if eax == peProcess
; The same process context
mov ecx, MmSectionObjectType
mov ecx, [ecx]
mov ecx, [ecx] ; PTR OBJECT_TYPE
invoke ObReferenceObjectByHandle, edi, SECTION_QUERY, ecx, KernelMode, addr pSection, NULL
mov status, eax
.else
; Different process. Since handles are process specific switch to target.
invoke KeAttachProcess, peProcess
mov ecx, MmSectionObjectType
mov ecx, [ecx]
mov ecx, [ecx] ; PTR OBJECT_TYPE
invoke ObReferenceObjectByHandle, edi, SECTION_QUERY, ecx, KernelMode, addr pSection, NULL
mov status, eax
invoke KeDetachProcess
.endif
; If section referenced successefuly break.
.break .if status == STATUS_SUCCESS
; It seams we are under SP4 and process started from command line.
; Handle invalid or object we probably tried to reference is not a section object
; (it can be while process destruction because process still has many handles)
; or access denied. Whatever value it can be try to workaround anyway.
.if ebx == 0
mov edi, 03F8h ; Try 03F8h handle.
.elseif ebx == 1
; Last chance.
mov eax, peProcess
add eax, 01ACh ; + SectionHandle field offset
mov eax, [eax] ; [EPROCESS.SectionHandle]
mov edi, eax
; The handle value is multiple of 4. And the section handle
; must have some reasonable value. If not, better go away.
and eax, (4 - 1)
.break .if ( eax != 0 ) || ( edi >= 800h )
.endif
inc ebx ; Next workaround.
.endw
;invoke DbgPrint, $CTA0("ProcessMon: Reference section. status: %08X\n"), status
.endif
; If status != STATUS_SUCCESS we failed to get section object pointer
; Very bad. No section no image file name :(
.if status == STATUS_SUCCESS
; OK. We have section pointer in pSection and it is referenced
mov status, STATUS_UNSUCCESSFUL
mov ebx, pSection
mov ebx, (SECTION PTR [ebx])._Segment ; -> _SEGMENT
invoke IsAddressInPoolRanges, ebx
push eax
invoke MmIsAddressValid, ebx
pop ecx
.if al && ( ecx == TRUE )
mov esi, ebx ; save PTR _SEGMENT
mov ebx, (_SEGMENT PTR [ebx]).ControlArea ; -> CONTROL_AREA
invoke IsAddressInPoolRanges, ebx
push eax
invoke MmIsAddressValid, ebx
pop ecx
.if al && ( ecx == TRUE ) && ([CONTROL_AREA PTR [ebx]]._Segment == esi ) ; check for shure
mov ebx, (CONTROL_AREA PTR [ebx]).FilePointer ; -> FILE_OBJECT
invoke IsLikeObjectPointer, ebx
.if eax == TRUE
; Check object type and reference it for sure
mov ecx, IoFileObjectType
mov ecx, [ecx]
mov ecx, [ecx] ; PTR OBJECT_TYPE
invoke ObReferenceObjectByPointer, ebx, FILE_READ_ATTRIBUTES, ecx, UserMode
.if eax == STATUS_SUCCESS
; Allocate memory for full image file path
invoke ExAllocatePool, PagedPool, (IMAGE_FILE_PATH_LEN+1) * sizeof WCHAR
.if eax != NULL
mov edi, pusImageFilePath
assume edi:ptr UNICODE_STRING
mov [edi].Buffer, eax
invoke memset, eax, 0, (IMAGE_FILE_PATH_LEN+1) * sizeof WCHAR ; Zero out
; MaximumLength is one char less than allocated/zeroed
; because I want to have zero char for shure
mov [edi].MaximumLength, IMAGE_FILE_PATH_LEN * sizeof WCHAR
and [edi]._Length, 0
; Get dos name for volume. DDK stands that drivers written for
; Windows XP and later must use IoVolumeDeviceToDosName instead of
; RtlVolumeDeviceToDosName. But on XP and later both functions
; have the same entry point. So it's OK to call RtlVolumeDeviceToDosName
; under any.
invoke RtlVolumeDeviceToDosName, \
(FILE_OBJECT PTR [ebx]).DeviceObject, addr usDosName
.if eax == STATUS_SUCCESS
; Copy drive letter
invoke RtlCopyUnicodeString, edi, addr usDosName
; Free memory allocated by DeviceToDosName
invoke ExFreePool, usDosName.Buffer
.else
; If we fail to get drive letter we could query device name instead.
; So instead of
; "\WINNT\system32\notepad.exe"
; we would get
; "\Device\HarddiskVolume1\system32\notepad.exe"
; But I do nothing to simplify the things
.endif
; Append relative file path
; We could use ObQueryNameString to obtain file name.
; I just get it directly from file object. It's much more faster.
invoke RtlAppendUnicodeStringToString, edi, \
addr (FILE_OBJECT PTR [ebx]).FileName
;invoke DbgPrint, $CTA0("ProcessMon: %ws\n"), [edi].Buffer
assume edi:nothing
mov status, STATUS_SUCCESS
.endif
invoke ObDereferenceObject, ebx ; FILE_OBJECT
.endif
.endif
.endif
.endif
invoke ObDereferenceObject, pSection
.endif
invoke ObDereferenceObject, peProcess
.endif
mov eax, status
ret
GetImageFilePath endp
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -