Jump to content
Sign in to follow this  
Decipher

Retrieve full file paths of files opened by a process!

Recommended Posts

Decipher

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

  • Like 2

Spoiler

censored.jpg

 

Share this post


Link to post
Share on other sites
Ascend4nt

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..

Share this post


Link to post
Share on other sites
Decipher

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

 

Share this post


Link to post
Share on other sites
Ascend4nt

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

Share this post


Link to post
Share on other sites
Decipher

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

 

Share this post


Link to post
Share on other sites
Ascend4nt
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.

Share this post


Link to post
Share on other sites
Decipher

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

 

Share this post


Link to post
Share on other sites
Ascend4nt

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:

Share this post


Link to post
Share on other sites
Decipher

I just tested it on Windows 7 Pro x64 and it worked properly. I was testing it using wmplayer.exe(Windows Media Player) on XP.

Edited by Decipher

Spoiler

censored.jpg

 

Share this post


Link to post
Share on other sites
Ascend4nt

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..

Share this post


Link to post
Share on other sites
Decipher

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.

Edited by Decipher

Spoiler

censored.jpg

 

Share this post


Link to post
Share on other sites
BrewManNH

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

Share this post


Link to post
Share on other sites
Decipher

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

 

Share this post


Link to post
Share on other sites
Ascend4nt

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)

Share this post


Link to post
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
Sign in to follow this  

  • Similar Content

    • xiantez
      By xiantez
      This script used to work on an older version of AutoIT. Currently I am running AutoIT v3.3.14.5 and it's failing.
      Func PublicIP() ;Post public facing IP address Local $url = 'https://www.google.com/search?client=opera&q=what+is+my+ip&sourceid=opera&ie=UTF-8&oe=UTF-8' Local $getIPaddress = BinaryToString(InetRead($url)) Local $sStart = 'clamp:2">' Local $sEnd = '</div>' Local $ipaddress = _StringBetween($getIPaddress, $sStart, $sEnd For $i In $ipaddress MsgBox(0, 'External IP', "Your public IP address is " & $i) Next EndFunc ;==>PublicIP The console output shows:
      "C:\Users\user\Documents\AutoIT\Scripts\WSI Tools.au3" (197) : ==> Variable must be of type "Object".: For $i In $ipaddress For $i In $ipaddress^ ERROR ->14:12:16 AutoIt3.exe ended.rc:1 +>14:12:16 AutoIt3Wrapper Finished. >Exit code: 1 Time: 9.811
    • tuffgong
      By tuffgong
      Good morning. I have a system I am trying to automate that works like this: user fills a column in an Excel spreadsheet with values they would like printed and saves it to a folder on their desktop, they start the script and it formats their data into a text file (adding a prefix) and sends the text file as a .bch file where it needs to go. This is working:
      #include <Array.au3> #include <Excel.au3> #include <File.au3> #include <MsgBoxConstants.au3> Global $sSTCArray Global $sFilename = @DesktopDir & "\Labels\print.txt" Global $sWorkbook = @DesktopDir & "\Labels\Labels.xlsx" Global $oExcel = _Excel_Open(False,False,False,False,True) barcodePrint() Func barcodePrint() $Read = _Excel_BookOpen($oExcel, $sWorkbook, True, False, Default, Default, Default) FileOpen($sFilename, $FO_OVERWRITE) ;Global $oWorkbook = _Excel_BookAttach($oExcel) Global $sSTCArray = _Excel_RangeRead($Read) For $i = 0 to UBound($sSTCArray, 1) - 1 FileWriteLine($sFilename, "!StaticShelving1x3_ZPL," & $sSTCArray[$i]) Next _Excel_Close($oExcel) FileMove($sFilename, "***file path***\print.bch") EndFunc However, it only works if the user first formats the spreadsheet to text. I want to automate that. From what I have read it appears AutoIt does not like formatting cells that already have values. True? Can I pull the values from an un-formatted (default GENERAL format) spreadsheet and go straight to my text file? I have also considered opening a second spreadsheet, formatting it, and copying the values over. Like this:
        
      Global $sPrefix Global $oPath Global $sSTCArray Global $sFilename = @DesktopDir & "\Labels\print.txt" Global $sWorkbook = @DesktopDir & "\Labels\Labels.xlsx" Global $oExcel = _Excel_Open(False,False,False,False,True) Global $aArray Global $bExcel _Excel_BookNew($bExcel) While 1 $nMsg = GUIGetMsg() Switch $nMsg Case $GUI_EVENT_CLOSE Exit Case $Button1 $aArray = IniReadSection("***File path***\barcode.ini", "stc/rvt/mgm") $sPrefix = $aArray[1][1] $oPath = $aArray[2][1] barcodePrint() EndSwitch WEnd Func barcodePrint() $oWorkbook = _Excel_BookOpen($bExcel, @DesktopDir & "\Labels\print.xlsx") $oWorkbook.ActiveSheet.Columns("A").NumberFormat = "@" Local $Read = _Excel_BookOpen($oExcel, $sWorkbook, True, False, Default, Default, Default) $oCopy = _Excel_RangeRead($sWorkbook) _Excel_RangeWrite($oWorkbook, Default, $oCopy) FileOpen($sFilename, $FO_OVERWRITE) $sSTCArray = _Excel_RangeRead($Read,"Default","Default",3) ;_ArrayDisplay($sSTCArray) For $i = 0 to UBound($sSTCArray, 1) - 1 FileWriteLine($sFilename, $sPrefix & $sSTCArray[$i]) Next _Excel_Close($oExcel) ;FileMove($sFilename, $oPath) Exit EndFunc This does not like the formatting of $oWorkbook: "Variable must be of type 'Object'".  Do I need this second sheet? If so, how can I format it? Is there a better way to get the Excel values into a .txt file? Any ideas would be appreciated. Thanks!
    • marcoauto
      By marcoauto
      Ciao
      I would like to control an ATEM Video Mixer from autoit. I downloaded his SDK which is written in c ++ and I found the sequences to interface, but I was not able to convert the script to self.
      The instructions say to follow this sequence:
      and to connectTo with C++ is:
      string address = "192.168.1.240"; _BMDSwitcherConnectToFailure failureReason = 0; IBMDSwitcher switcher = null; var discovery = new CBMDSwitcherDiscovery(); discovery.ConnectTo(address, out switcher, out failureReason); From Blackmagic SDK:
      IBMDSwitcherDiscovery::ConnectTo method
      The ConnectTo method connects to the specified switcher and returns an IBMDSwitcher object interface for the switcher.
      Syntax HRESULT ConnectTo (string deviceAddress, IBMDSwitcher** switcherDevice, BMDSwitcherConnectToFailure* failReason); Parameters: deviceAddress in Network hostname or IP address of switcher to connect to. switcherDevice out IBMDSwitcher object interface for the connected switcher. failReason out Reason for connection failure as a BMDSwitcherConnectToFailure value. So, I have I tried these solutions but with non success:
      $DllName =@ScriptDir&"\BMDSwitcherAPI.dll" $result = DllCall($DllName, "none", "IBMDSwitcherDiscovery::ConnectTo" & @CRLF) ConsoleWrite("DLLCall Result: " & $result & @CRLF) and I have tried also create an Object (That I think is the best way solution):
      #include <MsgBoxConstants.au3> $oSwitcher=ObjCreate("IBMDSwitcher") If IsObj($oSwitcher) Then MsgBox(64, "", "Object $oSwitcher created successfully") EndIf $oAtem=ObjCreate("IBMDSwitcherDiscovery") If IsObj($oAtem) Then MsgBox(64, "", "Object $oAtem created successfully") EndIf $failureReason =ObjCreate("_BMDSwitcherConnectToFailure") If IsObj($failureReason) Then MsgBox(64, "", "Object $failureReason created successfully") EndIf $oMyError = ObjEvent("AutoIt.Error", "MyErrFunc") ; Install a custom error handler Global $errore,$oSwitcher1 $oAtem.ConnectTo("192.168.1.36",$oSwitcher,$failureReason); ; This is the custom error handler Func MyErrFunc() $HexNumber = Hex($oMyError.number, 8) MsgBox(0, "", "We intercepted a COM Error !" & @CRLF & _ "Number is: " & $HexNumber & @CRLF & _ "Windescription is: " & $oMyError.windescription & @CRLF & _ "Source is: " & $oMyError.source & @CRLF & _ "Description is: " & $oMyError.description & @CRLF & _ "Helpfile is: " & $oMyError.helpfile & @CRLF & _ "Helpcontext is: " & $oMyError.helpcontext & @CRLF & _ "Lastdllerror is: " & $oMyError.lastdllerror & @CRLF & _ "Scriptline is: " & $oMyError.scriptline) EndFunc ;==>MyErrFunc But the result is:
      We intercepted a COM Error !
      Number is: 000000A9
      Windescription is: Variable must be of type 'Object'.
      Source is: 
      Description is: 
      Helpfile is: 
      Helpcontext is: 
      Lastdllerror is: 0
      Scriptline is: 17
      The BMDSwitcherAPI.dll is registered in system. Can someone help me?
      Grazie
      Marco
    • genius257
      By genius257
      I've made a library, based on AutoItObject UDF with the goal of implementing getter and setter functionality and make it possible to define new object properties in as few steps as possible.
      Thank you to @trancexx for getting me on the right track, and all users in Hooking into the IDispatch interface for the code to get me going.
      If I've forgotten to add credit, please let me know
      Example:
      #include "AutoItObject_Internal.au3" $myCar = IDispatch() $myCar.make = 'Ford' $myCar.model = 'Mustang' $myCar.year = 1969 $myCar.__defineGetter('DisplayCar', DisplayCar) Func DisplayCar($oThis) Return 'A Beautiful ' & $oThis.parent.year & ' ' & $oThis.parent.make & ' ' & $oThis.parent.model EndFunc MsgBox(0, "", $myCar.DisplayCar) More examples: https://github.com/genius257/AutoItObject-Internal/tree/master/Examples
      Version: 2.0.0
      AutoItObject_Internal.au3
      Documentation
      Edit2 (19th March 2017):
      First of all, sorry about the lack of updates on this project. I always start too many projects and end up ignoring old projects, if I run into problems ^^'.
      So I've started moving my AutoIt scripts to GitHub. I will still post the most recent script version here.
    • nacerbaaziz
      By nacerbaaziz
      Hello
      I have a query please
      It is about windows file explorer
      If i design a tool in autoit language to delete files for example
      and i  added it in the context menu in File Explorer
      If i right-click on any file And you choose the tool, it will be get the path of the selected file or folder
      The problem here is
      If i select a set of files or folders
      it only detect the first one
      The code that i  used is
      if $CMDLine[0] = 0 then
      msgBox(16, "error", "you don't selecte any files")
      exit
      else
      for $i = 1 to $CMDLine[0]
      msgBox(0, "files", $CMDLine[$i]
      next
      endIf
      exit
×