Jump to content

File Unlock Pitfalls


Recommended Posts

I have the means to introduce functionality for closing handles to processes that are keeping a file "locked". This would allow you to replace stubborn files during software deployment and/or delete BHO type viruses.

Alot of the code necessary already exists within AutoIt and would be rather simple to add to an existing function such as ProcessClose() where a full path is passed rather than a process name or PID.

I am sure there are issues of safety involved, but I have no first hand experience with the pitfalls of my proposal. So such things could be vetted here before I pursue inclusion of this functionality or development of a UDF.

banzai...

Lar.

f_mrcleansmalm_77ce002.jpgAutoIt has helped make me wealthy

Link to comment
Share on other sites

Hi,

you mean something like: http://ccollomb.free.fr/unlocker/

Mega

Scripts & functions Organize Includes Let Scite organize the include files

Yahtzee The game "Yahtzee" (Kniffel, DiceLion)

LoginWrapper Secure scripts by adding a query (authentication)

_RunOnlyOnThis UDF Make sure that a script can only be executed on ... (Windows / HD / ...)

Internet-Café Server/Client Application Open CD, Start Browser, Lock remote client, etc.

MultipleFuncsWithOneHotkey Start different funcs by hitting one hotkey different times

Link to comment
Share on other sites

So here is some code I found for you:

#include <stdio.h>

#include <windows.h>

#include <psapi.h>

#include <wchar.h>

#include <process.h>

#include <ntsecapi.h>

#include "ntdll.h"





#define STATUS_SUCCESS (long)0x00000000L



typedef struct _GetFileNameThreadParam

{

      HANDLE           hFile;
 
      wchar_t*   &nbs p; pName;

      bool  &n bsp;  rc;
 
} GetFileNameThreadParam;





// From device file name to DOS filename

BOOL GetFsFileName( wchar_t* lpDeviceFileName, wchar_t* fsFileName )

{

     BOOL rc = FALSE;



     WCHAR lpDeviceName[0x1000];

     WCHAR lpDrive[3] = L"A:";



     // Iterating through the drive letters

     for (WCHAR actDrive = L'A'; actDrive <= L'Z'; actDrive++ )

     {

            lpDrive[0] = actDrive;



            // Query the device for the drive letter

            if ( QueryDosDevice( lpDrive, lpDeviceName, 0x1000 ) != 0 )

            {

                 // Network drive?

                 if ( _wcsnicmp( L"\\Device\\LanmanRedirector\\", lpDeviceName, 25 ) == 0 )

                 {

                      //Mapped network drive 

                       char cDriveLetter;

                       DWORD dwParam;



                       WCHAR lpSharedName[0x1000];



                      if ( swscanf(  lpDeviceName, 

                                          L"\\Device\\ LanmanRedirector\\;%c:%d\\%s",  

                                          &cDriveLette r, 

                                          &dwParam,  

                                          lpSharedName  ) != 3 )

                            continue;
 


                       wcscpy( lpDeviceName, L"\\Device\\LanmanRedirector\\" );

                       wcscat( lpDeviceName, lpSharedName );

                 }
 
                 
 
                 // Is this the drive letter we are looking for?

                 if ( _wcsnicmp( lpDeviceName, lpDeviceFileName, wcslen( lpDeviceName ) ) == 0 )

                 {

                       wchar_t* p = (wchar_t*)( lpDeviceFileName + wcslen(lpDeviceName));

                       wcscpy(fsFileName,lpDrive);

                       wcscat(fsFileName, p);



                       rc = TRUE;



                       break;

                 }
 
            }

     }



     return rc;

}





void mmMsg(wchar_t* message, int exitCode=0)

{

     wprintf(message);

     //if (!exitCode) exit(exitCode);

}

//--- WRAPERS ----

HANDLE OpenProcess( DWORD processId )

{

     // Open the process for handle duplication

     return ::OpenProcess( PROCESS_DUP_HANDLE, TRUE, processId );

}



HANDLE DuplicateHandle( HANDLE hProcess, HANDLE hRemote )

{

     HANDLE hDup = NULL;



     // Duplicate the remote handle for our process

     ::DuplicateHandle( hProcess, hRemote,   GetCurrentProcess(), &hDup,     0, FALSE, DUPLICATE_SAME_ACCESS );



     return hDup;

}

 //---------------------------------------------------------- -----



//API FUNCS

bool EnableDebugPriv( void ) 

{

     HANDLE hToken;

     LUID sedebugnameValue;

     TOKEN_PRIVILEGES tkp;



     // enable the SeDebugPrivilege

     if ( ! OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ) )

     {

            //_tprintf( _T("OpenProcessToken() failed, Error = %d SeDebugPrivilege is not available.\n") , GetLastError() );

            return false;

     }



     if ( ! LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &sedebugnameValue ) )

     {

            //_tprintf( _T("LookupPrivilegeValue() failed, Error = %d SeDebugPrivilege is not available.\n"), GetLastError() );

            CloseHandle( hToken );

            return false;

     }





     tkp.PrivilegeCount = 1;

     tkp.Privileges[0].Luid = sedebugnameValue;

     tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;



     if ( ! AdjustTokenPrivileges( hToken, FALSE, &tkp, sizeof tkp, NULL, NULL ) )

            return false; //_tprintf( _T("AdjustTokenPrivileges() failed, Error = %d SeDebugPrivilege is not available.\n"), GetLastError() );

            

     CloseHandle( hToken );

     return true;

}



bool InitNativeFunctions()

{

     NtQuerySystemInformation = (PNtQuerySystemInformation)

                            GetProcAddress(GetModuleHandle ( L"ntdll.dll"  ),    (LPCSTR)"NtQuerySystemInform ation" );

     

     NtQueryObject = (PNtQueryObject)

                            GetProcAddress(GetModuleHandle ( L"ntdll.dll" ),     (LPCSTR)"NtQueryObject");



     NtQueryInformationFile = (PNtQueryInformationFile)

                            GetProcAddress(GetModuleHandle (  L"ntdll.dll"),     (LPCSTR)"NtQuery InformationFile" );



     return NtQuerySystemInformation && NtQueryObject && NtQueryInformationFile;

}





WCHAR GetFileDevice(wchar_t* pName)

{

     WCHAR fileName[MAX_PATH+3];

     fileName[0] = L'\0';

     wcsncat(fileName, L"C:", 2);

     wcsncat(fileName, pName, MAX_PATH);

     

     HANDLE h;

     int err;

     

     for (WCHAR actDrive = L'C'; actDrive <= L'D'; actDrive++ )

     {

            fileName[0] = actDrive;

            h = CreateFile(fileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

            err = GetLastError();

            

            //32     Used by another process

            //3       The system cannot find the path specified

            switch (err)

            {

                 case  3 : continue;

                 case  32: return actDrive;

            }

     }



     return 0;

}



void GetFileNameThread( PVOID pParam )

{

     int len;

     GetFileNameThreadParam* p = (GetFileNameThreadParam*)pParam;

     p->rc = false;

     

     UCHAR lpBuffer[MAX_PATH*2];

     PFILE_NAME_INFORMATION pFNI = (PFILE_NAME_INFORMATION)lpBuffer; 

     DWORD iob[2];

     

     DWORD ntRet = NtQueryInformationFile( p->hFile, iob, lpBuffer, MAX_PATH*2, 9 );

     if ( ntRet == STATUS_SUCCESS){

                 len  = pFNI->FileNameLength/2;

                 if (len > MAX_PATH)     len = MAX_PATH-1;



                 wcsncpy(p->pName,  pFNI->FileName, len );

                 p->pName [len] = L'\0';

                 p->rc  = true;

     }

     

}





//Returns file name if handle h is file handle or FALSE if not.

bool GetFileName (HANDLE h, PWCHAR pName, DWORD processId )

{

     ULONG size = 0x2000;

     UCHAR* lpBuffer = NULL;

     bool ret = FALSE;

     

     HANDLE handle;

     HANDLE hRemoteProcess = NULL;

     bool remote = processId != GetCurrentProcessId();

     

     if ( remote )

     {

            // Open the remote process

            hRemoteProcess = OpenProcess( processId );

            if ( hRemoteProcess == NULL ) return FALSE;



            // Duplicate the handle

            handle = DuplicateHandle( hRemoteProcess, h );

     }

     else handle = h;



     // Query the info size

     NtQueryObject( handle, 2, NULL, 0, &size );



     lpBuffer = new UCHAR[size];

     // Query the info size ( type = 2 = ObjectTypeInformation)

     if ( NtQueryObject( handle, 2, lpBuffer, size, NULL ) == 0 )

     {

            int i = _wcsicmp (L"File", (wchar_t*)(lpBuffer+0x60));

            if (i != 0) goto cleanup;



            GetFileNameThreadParam tp;

            tp.hFile = handle;

            tp.pName = pName;



            //Start the thread to get the file name

            HANDLE hThread = (HANDLE)_beginthread( GetFileNameThread, 0, &tp );

            if ( hThread == NULL ) goto cleanup;

            

            if ( WaitForSingleObject(hThread, 50 ) == WAIT_TIMEOUT)

            {    
 
                 // Access denied, terminate the thread

                 TerminateThread(  hThread, 0 );

                 wcscpy(pName,  L"");

                 ret  = false;

            }

            else ret = tp.rc;

     }



cleanup:

     if ( remote )

     {

            if ( hRemoteProcess != NULL )

                 CloseHandle( hRemoteProcess );



            if ( handle != NULL )

                 CloseHandle( handle );

     }

     if ( lpBuffer != NULL )     delete [] lpBuffer;



     return ret;

}

 //---------------------------------------------------------- -----



PSYSTEM_HANDLE_INFORMATION Snapshot()

{

     DWORD size   = 0x2000;

     DWORD needed = 0;

     PSYSTEM_HANDLE_INFORMATION pHI;



     pHI = (PSYSTEM_HANDLE_INFORMATION)

              VirtualAlloc( NULL, size, MEM_COMMIT, PAGE_READWRITE );

     if (! pHI) return NULL;





     // SYSTEM_INFORMATION_CLASS SystemHandleInformation <-- 16

     if ( NtQuerySystemInformation( 16, pHI, size, &needed ) != 0 )

     {

            if ( needed == 0 )   {

                 VirtualFree(  pHI, 0, MEM_RELEASE );

                 return NULL;

            }



            // The size was not enough

            VirtualFree( pHI, 0, MEM_RELEASE );



            pHI = (PSYSTEM_HANDLE_INFORMATION)

                    VirtualAlloc( NULL, size = needed + 256, MEM_COMMIT, PAGE_READWRITE );

     }

     if ( pHI == NULL )  return NULL;



     // Query the objects ( system wide )

     if ( NtQuerySystemInformation( 16, pHI, size, NULL ) != 0 ) {

            VirtualFree( pHI, 0, MEM_RELEASE );

            return NULL;

     }



     

     return pHI; 

}



bool GetProcessName(DWORD processID, wchar_t* name)

{ bool res;

  int k;



  HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID );

  res = GetProcessImageFileName(hProcess, name, MAX_PATH) != 0;

  if (! res) k = GetLastError();



  return res;

}

void PrintHandles(PSYSTEM_HANDLE_INFORMATION pHI)

{    

     wchar_t processName[MAX_PATH], fileName[MAX_PATH], tmp[MAX_PATH];

     bool res;

     wchar_t driveLetter;



     if ( !pHI ) mmMsg(L"Snapshot failed", 3);

     

     int j=0;

     for (unsigned int i = 0; i < pHI->NumberOfHandles; i++ )

     {

            SYSTEM_HANDLE_TABLE_ENTRY_INFO  h = pHI->Handles;

            

            res = GetFileName((HANDLE)h.HandleValue, (wchar_t*)&fileName, h.UniqueProcessId);

            if (!res) continue;



            driveLetter = GetFileDevice(fileName);

            if ( driveLetter == 0 ) continue;



            res = GetProcessName(h.UniqueProcessId, tmp);

            if (res) GetFsFileName((wchar_t*)&tmp, (wchar_t*)&processName);

            if ( h.UniqueProcessId == 4 ) wcscpy(processName, L"System");

            wprintf(L"NO:%i | %i\t\t H:%-5i  PID:%i\n", i, j++, h.HandleValue, h.UniqueProcessId);

            wprintf(L"P : %s",processName  );        &nbs p;         &nbs p;     wprintf(L"\n");
 
            wprintf(L"FN: %c:%s", driveLetter, fileName  );      &nbs p;wprintf(L"\n");

            wprintf(L"----------------------------------\n");
 
     }
}

int  wmain(int argc, WCHAR* argv[])
{    

     if (! EnableDebugPriv()  )       ;mmMsg(L"debug failed\n", 1);

     if (! InitNativeFunctions() )   mmMsg(L"Import function failed\n", 2);

     PrintHandles ( Snapshot() );
     wprintf(L"\n\n\nfinished");

     return 0;

}

Sorry about all the random breaks, I copied a copied code.

Here is the website I got it from, SysInternals

Link to comment
Share on other sites

Thanks brother... yeah, I have that code and others ...

I guess I am interested in "File Unlocking Gone Wild" experiences, where someone has deleted or corrupted system files. I would like to read any horror stories associated with unlocking files. Meanwhile I will google for stories.

Lar.

f_mrcleansmalm_77ce002.jpgAutoIt has helped make me wealthy

Link to comment
Share on other sites

He can, and is very capable, of making it not only work, but giving it to us in AutoIt. What he's asking for is reasons/examples of why doing this might crash a computer, and if so, he would like to know before he gives us Weapons of Mass Destruction, AutoIt style.

Link to comment
Share on other sites

See, I thought he could do it, I just didn't understand why he was saying he has the code and others. This in AutoIt would rock, I guess the dangers of using it are the facts that system files can obviously be deleted, maybe a database of system files, so if you do accidentally delete it then it can be bought back??

Link to comment
Share on other sites

The major danger is applications becoming unstable and crashing. You take a handle and you close it outside the parameters of the program. Imagine you open a file and are writing to it and suddenly the handle is closed on you and you do not have any clue that it happened. This could crash the program. Now, if the program happens to be Explorer, then your whole shell is likely to go down. If the program were, say, Microsoft Word, then it's feasible that killing the entire application will kill all document windows leading to potential data-loss in those other windows.

It's unlikely this will ever be included in AutoIt (built-in or UDF). It's too much of a hack and there's too much theoretical potential for introducing application instability. First it simulates being a debugger, which it is not, just to get access to the information. Then it uses system calls with bright scary warnings not to use them. Then it goes on to perform things outside the rules of conventional program flow.

I'm not saying it's not useful, but I am saying it's not the kind of thing we need to be handing out like Halloween treats.

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

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...