Jump to content

Retrieve full file paths of files opened by a process!


Decipher
 Share

Recommended Posts

Credits go to the authors of AutoIt Unlocker!

#NoTrayIcon
#include "WinAPIEx.au3"
#include <WinAPI.au3>


Dim $hTimer = TimerInit()
Dim $aFiles = _ProcessListFiles("firefox.exe") ; Get a list of files currently opened by the process
ConsoleWrite("+>Took " & Round(TimerDiff($hTimer)) & " milliseconds" & @CRLF)

#include <Array.au3>
_ArrayDisplay($aFiles)

Exit

Func _ProcessListFiles($vProcess, $nMaxFiles = 1000)
    Static Local $aPrivilege = DllCall("ntdll.dll", "int", "RtlAdjustPrivilege", "int", 20, "int", 1, "int", 0, "int*", 0)
    Local $nProcessId = ProcessExists($vProcess), $aRet
    Static Local $hCurrentProcess = _WinAPI_GetCurrentProcess()
    Local $aHandles = _WinAPI_EnumProcessHandles($nProcessId)
    Local $hObject, $aFiles[$nMaxFiles+1], $sPath
    Local $hProcess = _WinAPI_OpenProcess(0x0040, 0, $nProcessId, True)
    For $i = 1 To $aHandles[0][0] Step 1
        If $aHandles[$i][3] = 0x00120189 Or $aHandles[$i][3] = 0x0012019f Or $aHandles[$i][3] = 0x00100000 Then ContinueLoop
        $hObject = _WinAPI_DuplicateHandle($hProcess, $aHandles[$i][0], $hCurrentProcess, 0, False, $DUPLICATE_SAME_ACCESS)
        If Not $hObject Then ContinueLoop
        If __IsFileObject($hObject) Then
            $sPath = __FileObjectPath($hObject)
            _WinAPI_CloseHandle($hObject)
            If FileExists($sPath) Then
                For $n = 1 To $aFiles[0]
                    If $aFiles[$n] = $sPath Then
                        $sPath = 0
                        ExitLoop
                    EndIf
                Next
                If $sPath Then
                    $aFiles[0] += 1
                    $aFiles[$aFiles[0]] = $sPath
                    If $aFiles[0] >= $nMaxFiles Then ExitLoop
                EndIf
            EndIf
        EndIf
    Next
    ReDim $aFiles[$aFiles[0]+1]
    Return $aFiles
EndFunc
Func __IsFileObject(ByRef $hObject)
    Static Local $tPOTI = DllStructCreate('ushort;ushort;ptr;byte[128]'), $pData, $Length, $tString
    Local $aRet = DllCall("ntdll.dll", 'uint', 'NtQueryObject', 'ptr', $hObject, 'uint', 2, 'ptr', DllStructGetPtr($tPOTI), 'ulong', DllStructGetSize($tPOTI), 'ptr', 0)
    If @error Or $aRet[0] Then Return
    $pData = DllStructGetData($tPOTI, 3)
    If Not $pData Then Return
    $Length = DllCall("kernel32.dll", 'int', 'lstrlenW', 'ptr', $pData)
    If @error Or Not $Length[0] Then Return
    $Length = $Length[0]
    $tString = DllStructCreate('wchar[' & ($Length + 1) & ']', $pData)
    If @error Then Return
    Return (DllStructGetData($tString, 1) == "File")
EndFunc
Func __FileObjectPath($hObject)
    Static Local $tStruct = DllStructCreate("char[255];")
    Local $aDrive = DriveGetDrive("ALL"), $sPath
    Local $aDrivesInfo[UBound($aDrive) - 1][2]
    For $I = 0 To UBound($aDrivesInfo) - 1
        $aDrivesInfo[$I][0] = $aDrive[$I + 1]
        DllCall("kernel32.dll", "dword", "QueryDosDevice", "str", $aDrivesInfo[$I][0], "ptr", DllStructGetPtr($tStruct), "dword", 255)
        $aDrivesInfo[$I][1] = DllStructGetData($tStruct, 1)
    Next
    Local Static $tPOTI = DllStructCreate("ushort Length;ushort MaximumLength;ptr Buffer;wchar Reserved[260];"), $sDeviceStr, $vSolid = False
    DllCall("ntdll.dll", "ulong", "NtQueryObject", "ptr", $hObject, "int", 1, "ptr", DllStructGetPtr($tPOTI), "ulong", DllStructGetSize($tPOTI), "ulong*", "")
    $sDeviceStr = DllStructGetData(DllStructCreate("wchar[" & Ceiling(DllStructGetData($tPOTI, "Length") / 2) & "];", DllStructGetData($tPOTI, "buffer")), 1)
    For $y = 0 To UBound($aDrivesInfo) - 1
        If StringLeft($sDeviceStr, StringLen($aDrivesInfo[$y][1])) = $aDrivesInfo[$y][1] Then
            $sPath = StringUpper($aDrivesInfo[$y][0]) & StringTrimLeft($sDeviceStr, StringLen($aDrivesInfo[$y][1]))
        EndIf
    Next
    Return $sPath
EndFunc

Anonymous

Spoiler

censored.jpg

 

Link to comment
Share on other sites

That is really weird, I've been working on getting Handles for processes this whole past week!  And I didn't know there was _WinAPI_EnumProcessHandles() in the beta.. might have saved me some work!

However I've spent a LOT of time trying to figure out how to overcome the NamedPipes issue. There's absolutely NO other way around that than to somehow filter them out, or to launch a thread to try and grab it, and abort it if unsuccessful.  In fact, I've just finished the helper-thread code today :)

I'm curious where all those access mask 'magic numbers' came from.. unfortunately 0x0012019f matches both a regular file handle AND a NamedPipe handle in an example I've been testing against.  So, I suppose your code errs on the side of caution in filtering those out..  but are those 3 values the only possibly NamedPipes access masks? :think:

Other types falling under 'File' classification include Filters, Mailslots, some KsecDD Device (?), unnamed pipes, and some other things I still can't identify. 

Anyway, cheers on the example.  When I release my UDF it will cover all types of handles, so it'll be a bit different.  I'm still pondering if it should be part of the Process functions UDF's..

Link to comment
Share on other sites

Ascend4nt,

The magic numbers were found in the AutoIt Unlocker source. I've also found them on many forums where others have troubleshooted why NtQueryObject hangs. It has to do with Synchronous Named Pipes causing the call to wait for events and it hangs during that process. So the majority of coders decide to use a separate thread to check for this as a hack, not a very good one at that because the thread won't close or the process won't terminate even during system shutdown. I've been doing research on how to identify these synchronous named pipes by their access rights and I agree that these rights correspond to legitimate file handles at times but how else can you get past the kernel call failing?!? There might be better work arounds in Vista+ but this is becoming very annoying! You mentioned a helper thread, sounds like your running another process and terminating it on failure? Anyway I look forward to seeing your code bro. :)

Edit - Another one that causing hanging: 0x001F01FF

Anonymous

Edited by Decipher
Spoiler

censored.jpg

 

Link to comment
Share on other sites

Huh.  I haven't had any problems with the thread or process not terminating..  I suppose I haven't given it a full workout yet, but so far its remained pretty steady.

Here, try using this function in lieu of access mask checks.  Let me know if you encounter any problems.  Also, keep in mind this is still in the early stages - it hasn't been optimized at all, and the first call is usually a bit slow.

*edit: forgot to close thread handle

; ==============================================================================================
; Func _ObjectGetNameUD_Threaded($hObject)
;
; Gets the Name associated with a Kernel Object Handle.
;  Most useful for 'File' Types
;
; This differs from _ObjectGetNameUD() in that it launches a thread to try and get the name
; If the thread times-out, it is killed.
;
; This is a workaround for the NamedPipes issue - often these types of Objects will be
; locked in reads/writes/waits for long periods of time and cause any type of querying
; attempts on the Object to lockup indefinitely.
;
; Returns:
;  Success: String representing the name of the Object
;  Failure: "" with @error set
;
; Author: Ascend4nt
; ==============================================================================================

Func _ObjectGetNameUD_Threaded($hObject)
    Local $OGNT_CODE

    ;~     $aRet=DllCall("ntdll.dll", "long", "NtQueryObject", "handle", $hObject, "int", 1, _
    ;~         "ptr", DllStructGetPtr($stBuffer), "ulong", DllStructGetSize($stBuffer), "ulong*", 0)
    If @AutoItX64 Then
        $OGNT_CODE='0x4831C04889CE483906742D483946087427504883EC2049C7C1FF7F00004C8D461848C7C201000000488B4E08488B1EFFD34883C428894610C3'
    Else
        $OGNT_CODE='0x5589E531C08B750839067421394604741C50B8FF7F0000508D461050B801000000508B4604508B1EFFD38946085DC3'
    EndIf

    Local $aRet, $sStr = "", $iErr = 0, $iExt = 0, $stData
    Local $stCode, $iCodeSize, $pThreadMem, $hThread = 0

    If Not IsPtr($hObject) Or $hObject = 0 Then Return SetError(1,0,"")

    $iCodeSize = BinaryLen($OGNT_CODE)

    $aRet = DllCall("kernel32.dll", "ptr", "GetModuleHandleA", "str", "ntdll.dll")
    If @error Then Return SetError(2, @error, "")
    If $aRet[0] = 0 Then Return SetError(3, 0, "")

    $aRet = DllCall("kernel32.dll", "ptr", "GetProcAddress", "handle", $aRet[0], "str", "NtQueryObject")
    If @error Then Return SetError(2, @error, "")
    If $aRet[0] = 0 Then Return SetError(3, 0, "")
    ;$pNTQO = $aRet[0]

    ; Data to receive (must be kept alive while thread exists!)
    $stData = DllStructCreate("ptr NTQO;handle Object;ulong StatusRet;ulong StructPad;ushort Length;ushort MaximumLength;ptr Buffer;" & "byte [32768];")
    DllStructSetData($stData, "Object", $hObject)
    DllStructSetData($stData, "NTQO", $aRet[0])    ; $pNTQO

    $aRet = DllCall("kernel32.dll", "ptr", "VirtualAllocEx", "handle", -1, _
        "ptr", 0, "ulong_ptr", $iCodeSize, "dword", 0x1000, "dword", 0x40)
    If @error Then Return SetError(2, @error, "")
    If $aRet[0] = 0 Then Return SetError(3, 0, "")

    $pThreadMem = $aRet[0]
    ConsoleWrite("...Return from VirtualAllocEx = " & $pThreadMem & @CRLF)

    ; Code area (set in newly allocated space)
    $stCode = DllStructCreate("byte ["&$iCodeSize&"];", $pThreadMem)
    ; Set the code
    DllStructSetData($stCode, 1, $OGNT_CODE)

    ;MsgBox(0, "Code Set", "Code set at " & $pThreadMem)    ; For setting Breakpoints

    ; Create the Thread - passing a pointer to $stData
    $aRet = DllCall("kernel32.dll", "handle", "CreateThread", "ptr", 0, _
        "ulong_ptr", 0, "ptr", $pThreadMem, "ulong_ptr", DllStructGetPtr($stData), "dword", 0, "dword*", 0)

    If @error Then
        $iExt = @error
        $iErr = 2
        ConsoleWrite("CreateThread error:" & @error & @CRLF)
    ElseIf $aRet[0] = 0 Then
        $iErr = 3
    Else
        ConsoleWrite("...Created Thread, Commencing Wait.."&@CRLF)
        $hThread = $aRet[0]
        ; Wait a suitable amount of time for thread to complete (100 ms here)
        $aRet = DllCall("kernel32.dll", "dword", "WaitForSingleObject", "handle", $hThread, "dword", 100)
        If @error Then
            $iExt = @error
            $iErr = 2
            ConsoleWrite("WaitForSingleObject error: " & @error & @CRLF)

        ; Anything other than WAIT_OBJECT_0 (i.e., success)
        ElseIf $aRet[0] <> 0 Then
            $iErr = -1
            ; Terminate thread - probably was locked up on querying a NamedPipe
            $aRet = DllCall("kernel32.dll", "bool", "TerminateThread", "handle", $hThread, "int", -1)
            ConsoleWrite("..TerminateThread return: " & $aRet[0] & @CRLF)
        Else
            ConsoleWrite("..Checking status return and looking for string.."&@CRLF)
            $iExt = DllStructGetData($stData, "StatusRet")
            ; Check for NTSTATUS return of STATUS_SUCCESS (0)
            If $iExt = 0 Then
                ; Success, let's check and grab the string return
                Local $pStr, $stString
                $pStr = DllStructGetData($stData, "Buffer")
                If $pStr = 0 Then
                    ;ConsoleWrite(@TAB&"-- No Object Name string --"&@CRLF)
                    ;$sStr = ""
                Else
                    $stString = DllStructCreate("wchar ["&(DllStructGetData($stData, "Length")/2)&"];", $pStr)
                    $sStr = DllStructGetData($stString, 1)
                    ;ConsoleWrite(@TAB&"Object Name string = " & $aHandleInfo[$i][6] & @CRLF)
                EndIf
            Else
                $iErr = 3
            EndIf
        EndIf
    EndIf

    ; Now free the memory the code was in
    $aRet = DllCall("kernel32.dll", "bool", "VirtualFreeEx", "handle", -1, "ptr", $pThreadMem, "ulong_ptr", 0, "dword", 0x8000)
    ConsoleWrite("..Return from VirtualFreeEx = " & $aRet[0] & @CRLF)
    _WinAPI_CloseHandle($hThread)

    ; Any errors?
    If $iErr Then Return SetError($iErr, $iExt, "")

    ; Yay, we have a string (or a "" if there was none)
    Return $sStr
EndFunc
Edited by Ascend4nt
Link to comment
Share on other sites

Ascend4nt,

Thats  :censored:  awesome! :thumbsup:

I can't wait to see the resulting UDF!

Edit -

It returns files that I was having to skip before but the process doesn't exit. :ermm:

No threads are terminated.

Anonymous

Edited by Decipher
Spoiler

censored.jpg

 

Link to comment
Share on other sites

Edit -

It returns files that I was having to skip before but the process doesn't exit. :ermm:

No threads are terminated.

Anonymous

 

Can you elaborate?  Which process isn't ending? AutoIt?  The threads launched by _ObjectGetNameUD_Threaded() all return success for me, and I verify that they are shutdown when I use a tool to inspect running threads.. plus it should say in the console if 'Terminate' is successful.

Link to comment
Share on other sites

Ascend4nt,

The AutoIt3 process doesn't exit. No threads are terminated because as you mentioned if that code is executed it will also print that information on the console.

XP HOME SP3

Edit - I thought to mention that the process can't be terminated even when using pskill. Its probably something that they fixed in Vista+.

Anonymous

Edited by Decipher
Spoiler

censored.jpg

 

Link to comment
Share on other sites

Hmm..  I've only tested it with Win 7 x64 and XP RTM in a Virtual Machine.  Both terminated correctly.  However, I haven't tested the function against all processes.  I've stayed away from system level processes and services because I'm a bit nervous about mucking about with the core operating system.  Like 'csrss.exe' seems a bit risky for one.

What kind of processes have you been testing it against?  I've been considering using the same safety-detection method I put into my _ProcessCreateRemoteThread() function (in Process functions UDF) - basically I test what the process 'subsystem' is.  If the function detects a Native System Process (vs. a CUI or GUI), it will return immediately without attempting to run a remote thread.  I'm not sure I even documented that part for anyone using those functions, but its one of my attempts to keep the programmer from f'ing with things they shouldn't mess with :lol:

Link to comment
Share on other sites

hmm.  Can't seem to reproduce it in my VM.. I've tested it against WMP 11 playing video and audio, with your code and my code, but to no avail.  I'll have to try booting into XP natively and experiment some more..

Link to comment
Share on other sites

I should've mentioned the WMP version..Its 11. I hope you can figure this out but if not MS will be dropping support for XP SP3 in a couple of years anyway so.

Less than a year actually. :)

If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Link to comment
Share on other sites

Incase your interested, here is the code I've been testing:

#NoTrayIcon
#include "WinAPIEx.au3"
#include <WinAPI.au3>

Dim $hTimer = TimerInit()
Dim $aFiles = _ProcessListFiles("wmplayer.exe") ; Get a list of files currently opened by the process
ConsoleWrite("+>Took " & Round(TimerDiff($hTimer)) & " milliseconds" & @CRLF)

#include <Array.au3>
_ArrayDisplay($aFiles)


Func _ProcessListFiles($vProcess, $nMaxFiles = 1000)
    Static Local $aPrivilege = DllCall("ntdll.dll", "int", "RtlAdjustPrivilege", "int", 20, "int", 1, "int", 0, "int*", 0)
    Local $nProcessId = ProcessExists($vProcess), $aRet
    Static Local $hCurrentProcess = _WinAPI_GetCurrentProcess()
    Local $aHandles = _WinAPI_EnumProcessHandles($nProcessId)
    Local $hObject, $aFiles[$nMaxFiles+1], $sPath
    Local $hProcess = _WinAPI_OpenProcess(0x0040, 0, $nProcessId, True)
    For $i = 1 To $aHandles[0][0] Step 1
        $hObject = _WinAPI_DuplicateHandle($hProcess, $aHandles[$i][0], $hCurrentProcess, 0, False, $DUPLICATE_SAME_ACCESS)
        If Not $hObject Then ContinueLoop
        If __IsFileObject($hObject) Then
            If $aHandles[$i][3] = 0x00120189 Or $aHandles[$i][3] = 0x0012019f Or $aHandles[$i][3] = 0x00100000 Or $aHandles[$i][3] = 0x001F01FF Then
                $sPath = __FileObjectPath_UD($hObject)
            Else
                $sPath = __FileObjectPath($hObject)
            EndIf
            _WinAPI_CloseHandle($hObject)
            If FileExists($sPath) Then
                For $n = 1 To $aFiles[0]
                    If $aFiles[$n] = $sPath Then
                        $sPath = 0
                        ExitLoop
                    EndIf
                Next
                If $sPath Then
                    $aFiles[0] += 1
                    $aFiles[$aFiles[0]] = $sPath
                    If $aFiles[0] >= $nMaxFiles Then ExitLoop
                EndIf
            EndIf
        EndIf
    Next
    ReDim $aFiles[$aFiles[0]+1]
    Return $aFiles
EndFunc
Func __IsFileObject(ByRef $hObject)
    Static Local $tPOTI = DllStructCreate('ushort;ushort;ptr;byte[128]'), $pData, $Length, $tString
    Local $aRet = DllCall("ntdll.dll", 'uint', 'NtQueryObject', 'ptr', $hObject, 'uint', 2, 'ptr', DllStructGetPtr($tPOTI), 'ulong', DllStructGetSize($tPOTI), 'ptr', 0)
    If @error Or $aRet[0] Then Return
    $pData = DllStructGetData($tPOTI, 3)
    If Not $pData Then Return
    $Length = DllCall("kernel32.dll", 'int', 'lstrlenW', 'ptr', $pData)
    If @error Or Not $Length[0] Then Return
    $Length = $Length[0]
    $tString = DllStructCreate('wchar[' & ($Length + 1) & ']', $pData)
    If @error Then Return
    Return (DllStructGetData($tString, 1) == "File")
EndFunc
Func __FileObjectPath_UD($hObject)
    Static Local $tStruct = DllStructCreate("char[255];")
    Local $aDrive = DriveGetDrive("ALL"), $sPath
    Local $aDrivesInfo[UBound($aDrive) - 1][2]
    For $I = 0 To UBound($aDrivesInfo) - 1
        $aDrivesInfo[$I][0] = $aDrive[$I + 1]
        DllCall("kernel32.dll", "dword", "QueryDosDevice", "str", $aDrivesInfo[$I][0], "ptr", DllStructGetPtr($tStruct), "dword", 255)
        $aDrivesInfo[$I][1] = DllStructGetData($tStruct, 1)
    Next
    $sDeviceStr = _ObjectGetNameUD_Threaded($hObject)
    If Not $sDeviceStr Then Return
    For $y = 0 To UBound($aDrivesInfo) - 1
        If StringLeft($sDeviceStr, StringLen($aDrivesInfo[$y][1])) = $aDrivesInfo[$y][1] Then
            $sPath = StringUpper($aDrivesInfo[$y][0]) & StringTrimLeft($sDeviceStr, StringLen($aDrivesInfo[$y][1]))
        EndIf
    Next
    Return $sPath
EndFunc
Func __FileObjectPath($hObject)
    Static Local $tStruct = DllStructCreate("char[255];")
    Local $aDrive = DriveGetDrive("ALL"), $sPath
    Local $aDrivesInfo[UBound($aDrive) - 1][2]
    For $I = 0 To UBound($aDrivesInfo) - 1
        $aDrivesInfo[$I][0] = $aDrive[$I + 1]
        DllCall("kernel32.dll", "dword", "QueryDosDevice", "str", $aDrivesInfo[$I][0], "ptr", DllStructGetPtr($tStruct), "dword", 255)
        $aDrivesInfo[$I][1] = DllStructGetData($tStruct, 1)
    Next
    Local Static $tPOTI = DllStructCreate("ushort Length;ushort MaximumLength;ptr Buffer;wchar Reserved[260];"), $sDeviceStr, $vSolid = False
    DllCall("ntdll.dll", "ulong", "NtQueryObject", "ptr", $hObject, "int", 1, "ptr", DllStructGetPtr($tPOTI), "ulong", DllStructGetSize($tPOTI), "ulong*", "")
    $sDeviceStr = DllStructGetData(DllStructCreate("wchar[" & Ceiling(DllStructGetData($tPOTI, "Length") / 2) & "];", DllStructGetData($tPOTI, "buffer")), 1)
    For $y = 0 To UBound($aDrivesInfo) - 1
        If StringLeft($sDeviceStr, StringLen($aDrivesInfo[$y][1])) = $aDrivesInfo[$y][1] Then
            $sPath = StringUpper($aDrivesInfo[$y][0]) & StringTrimLeft($sDeviceStr, StringLen($aDrivesInfo[$y][1]))
        EndIf
    Next
    Return $sPath
EndFunc
; ==============================================================================================
; Func _ObjectGetNameUD_Threaded($hObject)
;
; Gets the Name associated with a Kernel Object Handle.
;  Most useful for 'File' Types
;
; This differs from _ObjectGetNameUD() in that it launches a thread to try and get the name
; If the thread times-out, it is killed.
;
; This is a workaround for the NamedPipes issue - often these types of Objects will be
; locked in reads/writes/waits for long periods of time and cause any type of querying
; attempts on the Object to lockup indefinitely.
;
; Returns:
;  Success: String representing the name of the Object
;  Failure: "" with @error set
;
; Author: Ascend4nt
; ==============================================================================================

Func _ObjectGetNameUD_Threaded($hObject)
    Local $OGNT_CODE

    ;~     $aRet=DllCall("ntdll.dll", "long", "NtQueryObject", "handle", $hObject, "int", 1, _
    ;~         "ptr", DllStructGetPtr($stBuffer), "ulong", DllStructGetSize($stBuffer), "ulong*", 0)
    If @AutoItX64 Then
        $OGNT_CODE='0x4831C04889CE483906742D483946087427504883EC2049C7C1FF7F00004C8D461848C7C201000000488B4E08488B1EFFD34883C428894610C3'
    Else
        $OGNT_CODE='0x5589E531C08B750839067421394604741C50B8FF7F0000508D461050B801000000508B4604508B1EFFD38946085DC3'
    EndIf

    Local $aRet, $sStr = "", $iErr = 0, $iExt = 0, $stData
    Local $stCode, $iCodeSize, $pThreadMem, $hThread = 0

    If Not IsPtr($hObject) Or $hObject = 0 Then Return SetError(1,0,"")

    $iCodeSize = BinaryLen($OGNT_CODE)

    $aRet = DllCall("kernel32.dll", "ptr", "GetModuleHandleA", "str", "ntdll.dll")
    If @error Then Return SetError(2, @error, "")
    If $aRet[0] = 0 Then Return SetError(3, 0, "")

    $aRet = DllCall("kernel32.dll", "ptr", "GetProcAddress", "handle", $aRet[0], "str", "NtQueryObject")
    If @error Then Return SetError(2, @error, "")
    If $aRet[0] = 0 Then Return SetError(3, 0, "")
    ;$pNTQO = $aRet[0]

    ; Data to receive (must be kept alive while thread exists!)
    $stData = DllStructCreate("ptr NTQO;handle Object;ulong StatusRet;ulong StructPad;ushort Length;ushort MaximumLength;ptr Buffer;" & "byte [32768];")
    DllStructSetData($stData, "Object", $hObject)
    DllStructSetData($stData, "NTQO", $aRet[0])    ; $pNTQO

    $aRet = DllCall("kernel32.dll", "ptr", "VirtualAllocEx", "handle", -1, _
        "ptr", 0, "ulong_ptr", $iCodeSize, "dword", 0x1000, "dword", 0x40)
    If @error Then Return SetError(2, @error, "")
    If $aRet[0] = 0 Then Return SetError(3, 0, "")

    $pThreadMem = $aRet[0]
    ConsoleWrite("...Return from VirtualAllocEx = " & $pThreadMem & @CRLF)

    ; Code area (set in newly allocated space)
    $stCode = DllStructCreate("byte ["&$iCodeSize&"];", $pThreadMem)
    ; Set the code
    DllStructSetData($stCode, 1, $OGNT_CODE)

    ;MsgBox(0, "Code Set", "Code set at " & $pThreadMem)    ; For setting Breakpoints

    ; Create the Thread - passing a pointer to $stData
    $aRet = DllCall("kernel32.dll", "handle", "CreateThread", "ptr", 0, _
        "ulong_ptr", 0, "ptr", $pThreadMem, "ulong_ptr", DllStructGetPtr($stData), "dword", 0, "dword*", 0)

    If @error Then
        $iExt = @error
        $iErr = 2
        ConsoleWrite("CreateThread error:" & @error & @CRLF)
    ElseIf $aRet[0] = 0 Then
        $iErr = 3
    Else
        ConsoleWrite("...Created Thread, Commencing Wait.."&@CRLF)
        $hThread = $aRet[0]
        ; Wait a suitable amount of time for thread to complete (100 ms here)
        $aRet = DllCall("kernel32.dll", "dword", "WaitForSingleObject", "handle", $hThread, "dword", 100)
        If @error Then
            $iExt = @error
            $iErr = 2
            ConsoleWrite("WaitForSingleObject error: " & @error & @CRLF)

        ; Anything other than WAIT_OBJECT_0 (i.e., success)
        ElseIf $aRet[0] <> 0 Then
            $iErr = -1
            ; Terminate thread - probably was locked up on querying a NamedPipe
            $aRet = DllCall("kernel32.dll", "bool", "TerminateThread", "handle", $hThread, "int", -1)
            ConsoleWrite("..TerminateThread return: " & $aRet[0] & @CRLF)
        Else
            ConsoleWrite("..Checking status return and looking for string.."&@CRLF)
            $iExt = DllStructGetData($stData, "StatusRet")
            ; Check for NTSTATUS return of STATUS_SUCCESS (0)
            If $iExt = 0 Then
                ; Success, let's check and grab the string return
                Local $pStr, $stString
                $pStr = DllStructGetData($stData, "Buffer")
                If $pStr = 0 Then
                    ;ConsoleWrite(@TAB&"-- No Object Name string --"&@CRLF)
                    ;$sStr = ""
                Else
                    $stString = DllStructCreate("wchar ["&(DllStructGetData($stData, "Length")/2)&"];", $pStr)
                    $sStr = DllStructGetData($stString, 1)
                    ;ConsoleWrite(@TAB&"Object Name string = " & $aHandleInfo[$i][6] & @CRLF)
                EndIf
            Else
                $iErr = 3
            EndIf
        EndIf
    EndIf

    ; Now free the memory the code was in
    $aRet = DllCall("kernel32.dll", "bool", "VirtualFreeEx", "handle", -1, "ptr", $pThreadMem, "ulong_ptr", 0, "dword", 0x8000)
    ConsoleWrite("..Return from VirtualFreeEx = " & $aRet[0] & @CRLF)
    _WinAPI_CloseHandle($hThread)

    ; Any errors?
    If $iErr Then Return SetError($iErr, $iExt, "")

    ; Yay, we have a string (or a "" if there was none)
    Return $sStr
EndFunc
Spoiler

censored.jpg

 

Link to comment
Share on other sites

Haven't been able to reproduce this yet.  I'm wondering if maybe running a higher level API call to test the object (one that also locks up on NamedPipes) would allow the script to be terminated, since NtQueryObject is a lower level API and maybe for whatever reason that's more likely to cause a process to not be able to be terminated.

For example, if we put this API call in the script prior to getting the name of the object, it will freeze just like NtQueryObject. But it's a higher level API..  maybe you can still terminate the script if it locks up here?:

DllCall("kernel32.dll", "bool", "GetNamedPipeHandleStateW", "handle", $hObject, "dword*", 0, "ptr", 0, "ptr", 0, "ptr", 0, "ptr", 0, "dword", 0)
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...