Calling GetFileAttributes for a file such as C:/pagefile.sys returns INVALID_FILE_ATTRIBUTES, and GetLastError returns ERROR_SHARING_VIOLATION. Yet it should definitely be possible to retrieve information about system files - e.g. being able to tell if it is a file or a directory. Is there a workaround?
Using FindFirstFile you can get information of pagefile.sys file. You can get the file's other information from ffd.
WIN32_FIND_DATA ffd;
HANDLE hFind = FindFirstFile( "C:\\pagefile.sys", &ffd );
if ( INVALID_HANDLE_VALUE == hFind )
{
return 0;
}
if ( !( ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) )
{
_int64 filesize = ffd.nFileSizeHigh;
filesize <<= 32;
filesize |= ffd.nFileSizeLow;
printf( "%s is %I64u bytes", ffd.cFileName, filesize );
}
FindClose( hFind );
Related
I need precise Unicode-output to the console. If I imbue wcout to "en_US.UTF8" the characters are mapped to UTF-8 but they arent correctly displayed by the console. So I wrote a little helper function:
void writeOutput( wchar_t const *str, bool err )
{
static mutex mtx;
lock_guard<mutex> lock( mtx );
wstringstream wss;
wss << str << L"\n";
wstring strFmt = move( wss.str() );
DWORD dwWritten;
WriteConsoleW( GetStdHandle( !err ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE ), strFmt.c_str(), wcslen( strFmt.c_str() ), &dwWritten, nullptr );
}
This function correctly displays the Unicode-characters. But if I do I/O-redirection with "program > outfile" nothing is written in the file. So how do I detect that's there a redirection?
So how do I detect that's there a redirection?
As #Remy Lebeau alreay pointed out, GetFileType function will return FILE_TYPE_DISK (The specified file is a disk file.) if console output has been redirected to a file.
The following is how to do in C++:
DWORD nType = GetFileType(GetStdHandle(err ? STD_ERROR_HANDLE : STD_OUTPUT_HANDLE));
if (FILE_TYPE_DISK == nType)
{
printf("Output to a disk file.");
}
I am using pipes to get redirected stdout output from a command line executable. Unfortunately I don't get any output until the process has completed. The executable outputs progress status as it runs and this is what I would like to parse.
BOOL RunCmd( char *pCmd,
char *pWorkingDir,
int nWaitSecs,
BOOL fRegImport,
DWORD *pdwExitCode )
{
BOOL fSuccess = TRUE;
STARTUPINFO si;
PROCESS_INFORMATION pi;
SECURITY_ATTRIBUTES sFileSecurity;
ZeroMemory( &sFileSecurity, sizeof( sFileSecurity ) );
sFileSecurity.nLength = sizeof( sFileSecurity );
sFileSecurity.bInheritHandle = TRUE;
HANDLE hReadPipe = NULL;
HANDLE hWritePipe = NULL;
fSuccess = CreatePipe( &hReadPipe, &hWritePipe, &sFileSecurity, 0 );
SetHandleInformation( hReadPipe, HANDLE_FLAG_INHERIT, 0 );
ZeroMemory( &si, sizeof(si) );
ZeroMemory( &pi, sizeof(pi) );
si.cb = sizeof( si );
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
si.hStdOutput = hWritePipe;
si.hStdError = hWritePipe;
si.wShowWindow = SW_HIDE;
int rc;
// Start the child process.
rc = CreateProcess( NULL, // No module name (use command line).
pCmd, // Command line.
NULL, // Process handle not inheritable.
NULL, // Thread handle not inheritable.
TRUE,
CREATE_NO_WINDOW,
NULL, // Use parent's environment block.
pWorkingDir, // Working folder
&si, // Pointer to STARTUPINFO structure.
&pi ); // Pointer to PROCESS_INFORMATION structure.
if( ! rc )
return FALSE;
// Wait until child process exits.
DWORD dwWaitResult;
DWORD dwTimeStart = ::GetTickCount();
DWORD dwTimeNow;
#define BUFSIZE 4096
DWORD dwRead = 0;
DWORD dwAvail;
CHAR chBuf[ BUFSIZE ];
BOOL bSuccess = TRUE;
for( ;; )
{
dwTimeNow = ::GetTickCount();
dwWaitResult = ::WaitForSingleObject( pi.hProcess, ONE_SECOND );
dwRead = 0;
for( dwAvail = 0; PeekNamedPipe( hReadPipe, 0, 0, 0, &dwAvail, 0 ) && dwAvail; dwAvail = 0 )
{
dwRead = 0;
ReadFile( hReadPipe, chBuf, min( BUFSIZE, dwAvail ), &dwRead, NULL );
if( dwRead > 0 )
{
FILE *op = fopen( "c:\\REDIR.OUT", "a" );
if( op )
{
fwrite( chBuf, 1, dwRead, op );
fclose( op );
}
}
}
if( dwWaitResult == WAIT_OBJECT_0 )
{
DWORD dwExitCode;
GetExitCodeProcess( pi.hProcess, &dwExitCode );
if( pdwExitCode )
(*pdwExitCode) = dwExitCode;
break;
}
if( dwWaitResult == WAIT_TIMEOUT )
{
if( dwTimeNow - dwTimeStart < (DWORD)( ONE_SECOND * nWaitSecs ) )
continue;
else
{
fSuccess = FALSE;
break;
}
}
fSuccess = FALSE;
break;
}
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
CloseHandle( hReadPipe );
CloseHandle( hWritePipe );
return fSuccess;
}
The PeekNamedPipe() call is called every second and dwAvail is zero every time until the process completes.
How do I get output from the process sooner? When running the process from the console, I see progress output as it goes. The process will be using "\r" in it's output to display a percentage at the start of the same line.
Note: My answer only deals with executables compiled using MSVC.
The buffering policy is coded inside Microsoft C Runtime (CRT) Library. You can learn the details here. This article suggests using console handles and manipulate console buffers to receive unbuffered output.
However, there's an undocumented feature inside Microsoft C Runtime to inherit file handles with some internal flags directly from its parent process using lpReserved2 and cbReserved2 fields of STARTUPINFO structure. You can find the details in the crt source code provided by Microsoft Visual Studio. Or search for something like posfhnd on GitHub.
We can exploit this undocumented feature to provide a pipe handle and specify FOPEN | FDEV flags to the child process, to fool the child process treat that pipe handle the same way as a FILE_TYPE_CHAR handle.
I have a working Python3 script to demonstrate this method.
A simplified C/C++ version of the answer by #youfu.
STARTUPINFO si;
int nh = 2;
si.cbReserved2 = (WORD)(sizeof(int) + (nh *
(sizeof(char) + sizeof(HANDLE))));
si.lpReserved2 = (LPBYTE) calloc(si.cbReserved2, 1);
*((UNALIGNED int *)(si.lpReserved2)) = nh;
unsigned char* posfile = (unsigned char *)(si.lpReserved2 + sizeof(int));
UNALIGNED HANDLE* posfhnd = (UNALIGNED HANDLE *)(si.lpReserved2 + sizeof(int) +
(nh * sizeof(unsigned char)));
unsigned char FOPEN = 0x01;
unsigned char FDEV = 0x40;
*posfile = FOPEN | FDEV;
posfile++;
*posfile = FOPEN | FDEV;
*posfhnd = child_stdin_rd;
posfhnd++;
*posfhnd = child_stdout_wr;
-Suraj
I want to get the version info of a dll or exe. To do this I call the function VerQueryValue.
Here is my code:
UINT dwBytes;
DWORD dwSize = GetFileVersionInfoSizeA(pszFile, (DWORD*)&dwBytes);
if( dwSize == 0)
return;
struct LANGANDCODEPAGE {
WORD wLanguage;
WORD wCodePage;
} *lpTranslate;
UINT cbTranslate;
LPVOID lpData = (LPVOID)malloc(dwSize);
ZeroMemory(lpData, dwSize);
if(GetFileVersionInfoA(pszFile, 0, dwSize, lpData) )
{
VerQueryValueA(lpData,
"\\VarFileInfo\\Translation",
(LPVOID*)&lpTranslate,
&cbTranslate);
// Read the file description for each language and code page.
char strSubBlock[MAX_PATH] = {0};
char* lpBuffer;
for(int i=0; i < (cbTranslate/sizeof(struct LANGANDCODEPAGE)); i++ )
{
sprintf(strSubBlock,
"\\StringFileInfo\\%04x%04x\\FileDescription",
lpTranslate[i].wLanguage,
lpTranslate[i].wCodePage);
// Retrieve file description for language and code page "i".
VerQueryValueA(lpData,
strSubBlock,
(void**)&lpBuffer,
&dwBytes);
}
}
free( lpData );
I got a 1813 error when calling VerQueryValueA. This code is almost same with with url http://msdn.microsoft.com/zh-cn/library/ms647464%28v=vs.85%29 .
I have tested the code under vc++6 and vc++2005 and got the same error. My windows is win7.
How should I fix it? Thanks in advanced.
According to MSDN, this error code maps to ERROR_RESOURCE_TYPE_NOT_FOUND. Thus I would conclude that the Resource you are looking for (FileDescription) does not exist in the image file.
For backwards compatibility, my 64 process needs to see the the 32-bit view of the file system and registry.
I know how to make a 32-bit process see a 64-bit view of the file system and registry (using Wow64DisableWow64FsRedirection and Wow64RevertWow64FsRedirection)
But how do I make a 64 bit process have a 32 bit view of the file system and registry?
You need to explicitly look in the "WOW64" keys/directories. There is actually no "64-bit" registry, there's just "the registry" and the Wow64 redirection stuff simply redirects a 32-bit process to a different subkey. So when a 32-bit process asks for "HKLM\Software\foo" the registry API actually says, "hang on, you're 32-bit so I'm going to pretend you asked for 'HKLM\Software\Wow6432Node\foo' instead".
So with that in mind, there is no way to have a 64-bit process look in the "32-bit" registry, because there is no such thing as a "32-bit registry". Instead, you'll just have to do what the Wow64 redirection logic does automatically.
EDIT
For the registry, there's actually the KEY_WOW64_32KEY key which you can specify in various method calls.
For the filesystem, you might be able to try Wow64EnableWow64FsRedirection, but I'm not sure whether it'll work or not...
KEY_WOW64_32KEY works for 64 bit and 32 bit processes.
From experiment, Wow64EnableWow64FsRedirection/Wow64DisableWow64FsRedirection doesn't seem to work in a 64 bit process - and the name suggests it only seems to work in an WOW64 process.
So in order to have a 32 bit "view" of the file system from a 64 bit process the paths will need to be be altered to point to the correct locations
This is really ugly, but here is a c++ code sample of how to perform the file system redirection according to Microsoft. Requires Boost.
#include"boost/filesystem.hpp"
#include"wstring"
#include"shfolder.h"
#include"Shlobj.h"
bool redirectPathRoot( boost::filesystem::wpath pathFromRoot, boost::filesystem::wpath pathToRoot, boost::filesystem::wpath & pathToRedirect )
{
bool bPathWasRedirected = false;
boost::filesystem::wpath theNewPath;
boost::filesystem::wpath::iterator iPathToRedirect = pathToRedirect.begin();
boost::filesystem::wpath::iterator iFromRoot = pathFromRoot.begin();
bool bMatch = true;
while( iPathToRedirect != pathToRedirect.end() && iFromRoot != pathFromRoot.end() && bMatch )
{
//
// see if the root of the path we are checking matches
//
bMatch = ( std::wstring(*iPathToRedirect++) == std::wstring(*iFromRoot++) );
}
if( bMatch && iFromRoot == pathFromRoot.end() )
{
theNewPath = pathToRoot;
//
// these guys need to be redirected
//
while( iPathToRedirect != pathToRedirect.end() )
{
theNewPath /= *iPathToRedirect++;
}
bPathWasRedirected = true;
pathToRedirect = theNewPath;
}
return bPathWasRedirected;
}
std::wstring adjustPathFor32BitOn64BitProcess( LPCWSTR thePath )
{
std::wstring strPath(thePath);
boost::to_lower(strPath);
//
// default to the original path
//
boost::filesystem::wpath theNewPath(strPath.c_str());
theNewPath.normalize();
//
// init the supplied path
//
boost::filesystem::wpath pathToCheck( strPath.c_str() );
pathToCheck.normalize();
//
// get the path for the 32 bit folder on a 64 bit system
//
wchar_t strTemp[MAX_PATH] = L"\0";
GetSystemWow64Directory( strTemp, MAX_PATH );
std::wstring strSysWow64 = strTemp;
boost::to_lower( strSysWow64 );
boost::filesystem::wpath pathSysWow64( strSysWow64.c_str() );
pathSysWow64.normalize();
//
// get the path for the system directory
//
GetSystemDirectory( strTemp, MAX_PATH );
std::wstring strSys = strTemp;
boost::to_lower( strSys );
boost::filesystem::wpath pathSys( strSys.c_str() );
pathSys.normalize();
//
// get the path for the Program Files directory
//
SHGetFolderPath( NULL, CSIDL_PROGRAM_FILES, NULL, SHGFP_TYPE_DEFAULT, strTemp);
std::wstring strPrograms = strTemp;
boost::to_lower( strPrograms );
boost::filesystem::wpath pathPrograms( strPrograms.c_str() );
pathPrograms.normalize();
//
// get the path for the Program Files x86 directory
//
SHGetFolderPath( NULL, CSIDL_PROGRAM_FILESX86, NULL, SHGFP_TYPE_DEFAULT, strTemp);
std::wstring strProgramsX86 = strTemp;
boost::to_lower( strProgramsX86 );
boost::filesystem::wpath pathProgramsX86( strProgramsX86.c_str() );
pathProgramsX86.normalize();
//
// get the path for the Windows\lastgood\system32 directory
//
SHGetFolderPath( NULL, CSIDL_WINDOWS, NULL, SHGFP_TYPE_DEFAULT, strTemp);
std::wstring strWindows = strTemp;
boost::to_lower( strWindows );
boost::filesystem::wpath pathWindows( strWindows.c_str() );
pathWindows.normalize();
boost::filesystem::wpath pathWindowsLastGoodSystem32( strWindows.c_str() );
pathWindowsLastGoodSystem32 /= L"lastgood";
pathWindowsLastGoodSystem32 /= L"system32";
pathWindowsLastGoodSystem32.normalize();
boost::filesystem::wpath pathWindowsLastGoodSysWOW64( strWindows.c_str() );
pathWindowsLastGoodSysWOW64 /= L"lastgood";
pathWindowsLastGoodSysWOW64 /= L"syswow64";
pathWindowsLastGoodSysWOW64.normalize();
//
// finally, regedit...
//
boost::filesystem::wpath pathRegedit( strWindows.c_str() );
pathRegedit /= L"regedit.exe";
pathRegedit.normalize();
boost::filesystem::wpath pathRegeditSysWOW64( pathSysWow64 );
pathRegeditSysWOW64 /= L"regedit.exe";
pathRegeditSysWOW64.normalize();
//
// now see if the supplied path matches system directoy
//
boost::filesystem::wpath::iterator iPathToCheck = pathToCheck.begin();
boost::filesystem::wpath::iterator iSys = pathSys.begin();
bool bMatch = true;
while( iPathToCheck != pathToCheck.end() && iSys != pathSys.end() && bMatch )
{
//
// see if the beginning of the path we are checking matches the system path
//
bMatch = ( std::wstring(*iPathToCheck++) == std::wstring(*iSys++) );
}
if( bMatch && iSys == pathSys.end() )
{
//
// the supplied path matches at least as far as the system dir...
//
if( iPathToCheck == pathToCheck.end() )
{
//
// ...actually its an exact match, so redirect it
//
theNewPath = pathSysWow64;
}
else
{
//
// ...however, there are a few exceptions....
//
boost::filesystem::wpath::iterator iTemp = iPathToCheck;
if(
!(
std::wstring(*iTemp) == L"drivers" &&
(
(++iTemp) != pathToCheck.end() &&
std::wstring(*(iTemp)) == L"etc"
)
)
&&
(std::wstring(*iPathToCheck) != L"catroot") &&
(std::wstring(*iPathToCheck) != L"catroot2") &&
(std::wstring(*iPathToCheck) != L"logfiles") &&
(std::wstring(*iPathToCheck) != L"spool")
)
{
//
// all but the above dirs should be redirected
//
theNewPath = pathSysWow64;
while( iPathToCheck != pathToCheck.end() )
{
theNewPath /= *iPathToCheck++;
}
}
}
}
else
{
//
// didn't match the system dir... see if it matches the Program Files dir
//
if(!redirectPathRoot( pathPrograms, pathProgramsX86, theNewPath ))
{
//
// now try %windir%/lastgood/system32
//
if(!redirectPathRoot( pathWindowsLastGoodSystem32, pathWindowsLastGoodSysWOW64, theNewPath ))
{
//
// finally, regedit
//
redirectPathRoot( pathRegedit, pathRegeditSysWOW64, theNewPath );
}
}
}
return theNewPath.file_string();}
If you want to see the 32-bit registry you can use the KEY_WOW64_32KEY as described here
If you want to access the SysWOW64 directory you can use the GetSystemWow64Directory as described here
Bit late to the party, but could you not create a small 32-bit process that does your 32-bit work? Then all of the built in goodness of WOW64 will work.
Not sure what your development language/runtime is like, so not able to offer further suggestions on what the inter-process communication would look like.
I want to convert device path to a file path.
I want to get process name by process id, so I am using this code
PsLookupProcessByProcessId(processId,&pEProcess);
ObOpenObjectByPointer(pEProcess,
OBJ_KERNEL_HANDLE,
NULL,
0,
NULL,
KernelMode,
&hProcess);
ObDereferenceObject (pEProcess);
nts = ZwQueryInformationProcess (hProcess,27,0,0,&ulSize);
But it gives path as \Device\hardDiskVolume1\windows\system32\taskmgr.exe
But I want this as a plain filename C:\windows\system32\taskmgr.exe
There's an article in Dr. Dobb's (NT Handle-to-Path Conversion by Jim Conyngham) that describes a way of getting from a handle to DOS path name: See the listing of GetFileNameFromHandleNT().
In your case, since you already have the device path, you don't need the initial parts of that code that does the handle-to-memory-map-to-get-device-path work.
// From device file name to DOS filename
BOOL GetFsFileName( LPCTSTR lpDeviceFileName, CString& fsFileName )
{
BOOL rc = FALSE;
TCHAR lpDeviceName[0x1000];
TCHAR lpDrive[3] = _T("A:");
// Iterating through the drive letters
for ( TCHAR actDrive = _T('A'); actDrive <= _T('Z'); actDrive++ )
{
lpDrive[0] = actDrive;
// Query the device for the drive letter
if ( QueryDosDevice( lpDrive, lpDeviceName, 0x1000 ) != 0 )
{
// Network drive?
if ( _tcsnicmp( _T("\\Device\\LanmanRedirector\\"), lpDeviceName, 25 ) == 0 )
{
//Mapped network drive
char cDriveLetter;
DWORD dwParam;
TCHAR lpSharedName[0x1000];
if ( _stscanf( lpDeviceName,
_T("\\Device\\LanmanRedirector\\;%c:%d\\%s"),
&cDriveLetter,
&dwParam,
lpSharedName ) != 3 )
continue;
_tcscpy( lpDeviceName, _T("\\Device\\LanmanRedirector\\") );
_tcscat( lpDeviceName, lpSharedName );
}
// Is this the drive letter we are looking for?
if ( _tcsnicmp( lpDeviceName, lpDeviceFileName, _tcslen( lpDeviceName ) ) == 0 )
{
fsFileName = lpDrive;
fsFileName += (LPCTSTR)( lpDeviceFileName + _tcslen( lpDeviceName ) );
rc = TRUE;
break;
}
}
}
return rc;
}