Use CreateFile on locked file to get file handle - winapi

I deleted my other question. Thanks all for helping me realize how to post.
I have a file on my desktop named rawr.txt. The file is locked. I would like to open it for the sole reason of getting a filehandle to it. (i will search a list of enumerated filed handles to identify what process id's are locking this file).
This is my code:
Cu.import("resource://gre/modules/ctypes.jsm");
var lib_kernel32 = ctypes.open("kernel32.dll");
//var INVALID_HANDLE_VALUE = ctypes.voidptr_t(-1);
var GENERIC_READ = 0x80000000;
var GENERIC_WRITE = 0x40000000;
var OPEN_EXISTING = 3;
var FILE_ATTRIBUTE_NORMAL = 0x80;
var FILE_FLAG_OVERLAPPED = 0x40000000;
var OPEN_ALWAYS = 4;
var INVALID_HANDLE_VALUE = new ctypes.Int64(-1);
var FSCTL_SET_SPARSE = 0x900c4;
var FSCTL_SET_ZERO_DATA = 0x980c8;
var FILE_BEGIN = 0;
let CreateFile = lib_kernel32.declare(
"CreateFileW",
ctypes.winapi_abi,
ctypes.voidptr_t, // return type: handle to the file
ctypes.jschar.ptr, // in: lpFileName
ctypes.uint32_t, // in: dwDesiredAccess
ctypes.uint32_t, // in: dwShareMode
ctypes.voidptr_t, // in, optional: lpSecurityAttributes (note that
// we're cheating here by not declaring a
// SECURITY_ATTRIBUTES structure -- that's because
// we're going to pass in null anyway)
ctypes.uint32_t, // in: dwCreationDisposition
ctypes.uint32_t, // in: dwFlagsAndAttributes
ctypes.voidptr_t // in, optional: hTemplateFile
);
let CloseHandle = lib_kernel32.declare(
"CloseHandle",
ctypes.winapi_abi,
ctypes.int32_t, //bool // return type: 1 indicates success, 0 failure
ctypes.voidptr_t // in: hObject
);
var aFile = FileUtils.getFile('Desk', ['rawr.txt']);
let filePath = aFile.path;
let hFile = CreateFile(filePath, GENERIC_READ, 0, null, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, null);
let hFileInt = ctypes.cast(hFile, ctypes.intptr_t);
if (ctypes.Int64.compare(hFileInt.value, INVALID_HANDLE_VALUE) == 0) {
throw new Error("CreateFile failed for " + filePath + ", error " +
ctypes.winLastError);
}
CloseHandle(hFile);
lib_kernel32.close();
Problem with this is I always get some exception on the throw new Error line. I get error 32 most commonly and sometimes 87 when experimenting with flags.
Thanks

Since all you want is a handle to the file, you shouldn't be using GENERIC_READ. That requires that the other process opened the file with FILE_SHARE_READ.
Also, you need to allow other processes to have the file open, by specifying FILE_SHARE_READ, FILE_SHARE_WRITE, and FILE_SHARE_DELETE:
CreateFile(filepath, 0,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
...)
... and after all this, you've got a handle to the file with no access, which is pretty much useless. (The handle you get has no relationship to the handles of other processes, so having a handle yourself does not help you search a list of existing handles in any way I can see.)

let hFile = CreateFile(filePath, GENERIC_READ, 0, ...)
Passing 0 for the dwShareMode argument is not going to get you anywhere. That asks for exclusive access to the file, you cannot get that because another process already obtained read or write access. Usually GENERIC_WRITE access in the case of a log file. You'll need FILE_SHARE_READ | FILE_SHARE_WRITE to ask humbly.
If that still doesn't work then the other process was adamant about you not messing with the file. It intentionally omitted FILE_SHARE_READ. Not very common for a text file, but done when the programmer deems it impossible to read the file correctly because he is constantly changing it. You cannot override that decision, other than by picking up the phone and calling the programmer.

Related

Windows NDIS FilterDriver object IO access for non-admin processes

I have Windows NDIS FilterDriver and it has name \\Device\\MyFilter.
User application performs some DeviceIoControl operation with the FilterDriver and calls following code to open the device handle:
LPSECURITY_ATTRIBUTES lpSecurityAttributes = NULL;
DWORD CreationDistribution = OPEN_EXISTING;
DWORD FlagsAndAttributes = FILE_FLAG_OVERLAPPED;
DWORD DesiredAccess = GENERIC_READ | GENERIC_WRITE;
DWORD ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
DWORD lastErr = 0;
m_hFilter = CreateFileA(MY_FILTER_NAME, /* "\\\\.\\\\MyFilter" */
DesiredAccess, ShareMode, lpSecurityAttributes, CreationDistribution, FlagsAndAttributes, NULL);
if (m_hFilter == INVALID_HANDLE_VALUE)
{
lastErr = GetLastError();
return false;
}
It works great if user application was run "As Administrator", otherwise (if run as regular User) CreateFileA returns INVALID_HANDLE_VALUE, and lastErr = 5 (Access Denied)
Reasons why it returns "Access Denied" are clear.
How to make user's application to open the Filter Driver object?
The idea of creating an interface with IoRegisterDeviceInterface() looks promising, but it requires the pointer to PDO, which I do not know where to obtain for NDIS Filter.
DefaultSDDLString field of the NDIS_DEVICE_OBJECT_ATTRIBUTES argument should be properly set for call of NdisRegisterDeviceEx()
//...
DeviceAttribute.DefaultSDDLString = &SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RWX_RES_RWX;
// Register the filter driver
Status = NdisRegisterDeviceEx(g_FHandle, &DeviceAttribute, &g_Object, &g_Handle);
Thanks, Scott_Noone_(OSR)!

Cannot get user name for a pid using rust winapi

I'm trying to get the user that is associated with a PID on windows.
I'm looking at the source for NTop https://github.com/gsass1/NTop as an example.
I can build and debug NTop source on Clion and the following code works correctly.
HANDLE ProcessTokenHandle;
if(OpenProcessToken(Process.Handle, TOKEN_READ, &ProcessTokenHandle)) {
DWORD ReturnLength;
GetTokenInformation(ProcessTokenHandle, TokenUser, 0, 0, &ReturnLength);
if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
PTOKEN_USER TokenUserStruct = xmalloc(ReturnLength);
if(GetTokenInformation(ProcessTokenHandle, TokenUser, TokenUserStruct, ReturnLength, &ReturnLength)) {
SID_NAME_USE NameUse;
DWORD NameLength = UNLEN;
TCHAR DomainName[MAX_PATH];
DWORD DomainLength = MAX_PATH;
LookupAccountSid(0, TokenUserStruct->User.Sid, Process.UserName, &NameLength, DomainName, &DomainLength, &NameUse);
// FIXME: we cut user name here for display purposes because something like %9.9s does not work with MS's vsprintf function?
Process.UserName[9] = 0;
}
free(TokenUserStruct);
}
CloseHandle(ProcessTokenHandle);
}
When trying the same thing using rust winapi I get ERROR_NOACCESS every time no matter what I do.
Here's some example code that returns 0 as response code from OpenProcessToken and GetLastError will be ERROR_NOACCESS. It doesn't matter whether or not I run the program as administrator or not.
let pid: u32 = 8664; // process that is owned by me but can be any process, it will never work
let process_handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, 0, pid);
let mut process_token_handle: PHANDLE = null_mut();
let s = OpenProcessToken(process_handle, TOKEN_READ, process_token_handle);
let last_error = GetLastError();
Anyone have any idea why this code would work in NTop using the C api and not work using rust winapi?

CreateFile() failed with error code 32 while reading pendrive

I am trying to read raw bytes from a pen drive 'E:', but it gives error code 32 when trying to open the drive using CreateFIle(). My code is as follows:
wchar_t wszDrive[7];
wszDrive[0] = '\\';
wszDrive[1] = '\\';
wszDrive[2] = '.';
wszDrive[3] = '\\';
wszDrive[4] = 'e';
wszDrive[5] = ':';
wszDrive[6] = '\0';
hDevice = CreateFile(wszDrive, //drive name to open
GENERIC_READ | GENERIC_WRITE, ////must be opened with exclusive access(No Sharing)
0, // no access to the drive
NULL, // default security attributes
OPEN_EXISTING, // disposition i.e. if file already exist
0, // file attributes
NULL); // do not copy file attributes
if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive
{
printf("CreateFile() failed! from read with error %d.\n", GetLastError());// Program prints this line. with error code 32.
return (FALSE);
}
else
cout << "\nCreateFile() successful! in read";
Edit:
The CreateFile() runs fine without errors if I use FILE_SHARE_READ | FILE_SHARE_WRITE:
hDevice = CreateFile(wszDrive,
GENERIC_READ |
GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
Why cannot I run with exclusive access?
Error 32 is ERROR_SHARING_VIOLATION.
The process cannot access the file because it is being used by another process.
It means there is already an open handle to the drive, and that handle is using access/sharing rights which are not compatible with the access/sharing rights you are requesting.
That is why you can't open the drive for exclusive access, but you can open it for read/write sharing - the drive is already open elsewhere for reading/writing.
If you want to know where exactly, you can use a tool like SysInternals Process Explorer to see which processes have open handles to which files/folders, devices, etc.

In Win32, how can a text file be successfully read into memory?

I am trying to get simple file IO working in Win32. So far the writing is working fine, but the reading is not: although it successfully reads the contents, additional "garbage" is appended to the string. The code I have so far is below. The program has UNICODE defined.
For writing:
DWORD dwTextSize = GetWindowTextLength(hWndTextBox);
WCHAR *lpszText = new WCHAR[dwTextSize];
GetWindowText(hWndTextBox, lpszText, dwTextSize + 1);
hTextFile = CreateFile(lpszTextFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD dwBytesWritten;
WriteFile(hTextFile, lpszText, 2 * dwTextSize, &dwBytesWritten, NULL); // x2 for 2 bytes per Unicode character
CloseHandle(hTextFile);
DeleteObject(hTextFile);
For this example, Hello, World! is saved successfully as Hello, World!.
For reading:
lpszTextFileName = L"text.txt"; // LPCTSTR Variable
hTextFile = CreateFile(lpszTextFileName, GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD dwFileSize = GetFileSize(hTextFile, &dwFileSize);
DWORD dwBytesRead;
WCHAR *lpszText = new WCHAR[dwFileSize / 2];
ReadFile(hTextFile, lpszText, dwFileSize, &dwBytesRead, NULL);
CloseHandle(hTextFile);
The string is then used to set the text of an EDIT control:
SendMessage(hWndTextBox, WM_SETTEXT, NULL, (LPARAM)lpszText); // SetWindowText() also possible
When Hello, World! is read back in, it reads back in as Hello, World!﷽﷽ꮫꮫꮫꮫﻮ or a visual variation upon this, but basically "garbage"!
I have probably missed something rather obvious, but I cannot see where! Is there a solution to this problem and if so, what is it?
Ok I started this with a comment, but its getting out of control.
For Writing
This:
WCHAR *lpszText = new WCHAR[dwTextSize];
should be:
WCHAR *lpszText = new WCHAR[dwTextSize+1];
This:
DeleteObject(hTextFile);
should not be there at all.. Get rid of it.
I'm assuming you delete [] lpszText; somewhere when you're done with it. if not, do so.
For Reading
The second parameter to GetFileSize() should not be the same variable as your return value. It is the HIGH 32bit of a 64-bit value for large file sizes. If you know you're file size is smaller than 4gB, you can leave it NULL, so change this:
DWORD dwFileSize = GetFileSize(hTextFile, &dwFileSize);
to this:
DWORD dwFileSize = GetFileSize(hTextFile, NULL);
You must account for the null terminator of your file buffer, so this:
WCHAR *lpszText = new WCHAR[dwFileSize / 2];
should be changed to this:
WCHAR *lpszText = new WCHAR[dwFileSize / 2 + 1];
lpszText[dwFileSize / 2] = 0;
and the rest should work as you're hoping it would. No error checking, which is not good, but I've seen worse. And as before, I'm assuming you delete [] lpszText; somewhere when you're done with it. if not, do so.

playing files after accepting them through open dialog box

I am a new member and joined this site after referring to it loads of times when i was stuck with some programming problems. I am trying to code a media player (Win32 SDK VC++ 6.0) for my college project and I am stuck. I have searched on various forums and msdn and finally landed on the function GetShortPathName which enables me to play through folders and files which have a whitespace in their names. I will paste the code here so it will be much more clearer as to what i am trying to do.
case IDM_FILE_OPEN :
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hwnd;
ofn.lpstrFilter = "Media Files (All Supported Types)\0*.avi;*.mpg;*.mpeg;*.asf;*.wmv;*.mp2;*.mp3\0"
"Movie File (*.avi;*.mpg;*.mpeg)\0*.avi;*.mpg;*.mpeg\0"
"Windows Media File (*.asf;*.wmv)\0*.asf;*.wmv\0"
"Audio File (*.mp2;*.mp3)\0*.mp2;*.mp3\0"
"All Files(*.*)\0*.*\0";
ofn.lpstrFile = szFileName;
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_ALLOWMULTISELECT | OFN_CREATEPROMPT;
ofn.lpstrDefExt = "mp3";
if(GetOpenFileName(&ofn))
{
length = GetShortPathName(szFileName, NULL, 0);
buffer = (TCHAR *) malloc (sizeof(length));
length = GetShortPathName(szFileName, buffer, length);
for(i = 0 ; i < MAX_PATH ; i++)
{
if(buffer[i] == '\\')
buffer[i] = '/';
}
SendMessage(hList,LB_ADDSTRING,0,(LPARAM)buffer);
mciSendString("open buffer alias myFile", NULL, 0, NULL);
mciSendString("play buffer", NULL, 0, NULL);
}
return 0;
using the GetShortPathName function i get the path as : D:/Mp3z/DEEPBL~1/03SLEE~1.mp3
Putting this path directly in Play button case
mciSendString("open D:/Mp3jh/DEEPBL~1/03SLEE~1.mp3 alias myFile", NULL, 0, NULL);
mciSendString("play myFile", NULL, 0, NULL);
the file opens and plays fine. But as soon as i try to open and play it through the open file dialog box, nothing happens. Any input appreciated.
It looks like the problem is that you're passing the name of the buffer variable to the mciSendString function as a string, rather than passing the contents of the buffer.
You need to concatenate the arguments you want to pass (open and alias myFile) with the contents of buffer.
The code can also be much simplified by replacing malloc with an automatic array. You don't need to malloc it because you don't need it outside of the block scope. (And you shouldn't be using malloc in C++ code anyway; use new[] instead.)
Here's a modified snippet of the code shown in your question:
(Warning: changes made using only my eyes as a compiler! Handle with care.)
if(GetOpenFileName(&ofn))
{
// Get the short path name, and place it in the buffer array.
// We know that a short path won't be any longer than MAX_PATH, so we can
// simply allocate a statically-sized array without futzing with new[].
//
// Note: In production code, you should probably check the return value
// of the GetShortPathName function to make sure it succeeded.
TCHAR buffer[MAX_PATH];
GetShortPathName(szFileName, buffer, MAX_PATH);
// Add the short path name to your ListBox control.
//
// Note: In C++ code, you should probably use C++-style casts like
// reinterpret_cast, rather than C-style casts!
SendMessage(hList, LB_ADDSTRING, 0, reinterpret_cast<LPARAM>(buffer));
// Build the argument string to pass to the mciSendString function.
//
// Note: In production code, you probably want to use the more secure
// alternatives to the string concatenation functions.
// See the documentation for more details.
// And, as before, you should probably check return values for error codes.
TCHAR arguments[MAX_PATH * 2]; // this will definitely be large enough
lstrcat(arguments, TEXT("open"));
lstrcat(arguments, buffer);
lstrcat(arguments, TEXT("alias myFile"));
// Or, better yet, use a string formatting function, like StringCbPrintf:
// StringCbPrintf(arguments, MAX_PATH * 2, TEXT("open %s alias myFile"),
// buffer);
// Call the mciSendString function with the argument string we just built.
mciSendString(arguments, NULL, 0, NULL);
mciSendString("play myFile", NULL, 0, NULL);
}
Do note that, as the above code shows, working with C-style strings (character arrays) is a real pain in the ass. C++ provides a better alternative, in the form of the std::string class. You should strongly consider using that instead. To call Windows API functions, you'll still need a C-style string, but you can get one of those by using the c_str method of the std::string class.

Resources