SetFileTime() behaving strangeley - winapi

The Windows function SetFileTime() in my company's application is behaving anomalously in 2 ways:
a.) In one case, I'm trying to update the date times (access, create, modify) of a file to "01/01/1980 00:00:00" and the file winds up having its original date times removed.
b.) In another case, the file will have its create and modified date updated to some seemingly random date time like "March ‎17, ‎1817, ‏‎6:26:56 AM". This one is not easily replicable - the same file can update just fine if I try subsequent times.
Please advise/assist.
In both cases, the update is being done remotely - so the files reside on a different server. The language is MFC C++
Code below:
CString csTime;
COleDateTime tCreate, tAccess, tModify;
SYSTEMTIME stCreate, stAccess, stModify;
FILETIME ftCreate, ftAccess, ftModify;
csTime = pMeta->Get( _T("CreateTime") );
if ( !csTime.IsEmpty() )
tCreate.ParseDateTime( csTime, 0UL, 1033 );
else
tCreate = COleDateTime::GetCurrentTime();
tCreate.GetAsSystemTime( stCreate );
BOOL stBool = SystemTimeToFileTime( &stCreate, &ftCreate );
csTime = pMeta->Get( _T("ModifyTime") );
if ( !csTime.IsEmpty() )
tModify.ParseDateTime( csTime, 0UL, 1033 );
else
tModify = COleDateTime::GetCurrentTime();
tModify.GetAsSystemTime( stModify );
BOOL stBool2 = SystemTimeToFileTime( &stModify, &ftModify );
csTime = pMeta->Get( _T("AccessTime") );
if ( !csTime.IsEmpty() )
tAccess.ParseDateTime( csTime, 0UL, 1033 );
else
tAccess = COleDateTime::GetCurrentTime();
tAccess.GetAsSystemTime( stAccess );
BOOL stBool3 = SystemTimeToFileTime( &stAccess, &ftAccess );
// write MAC times
HANDLE hTarget = CreateFile( csTest, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
BOOL winAPI = SetFileTime( hTarget, &ftCreate, &ftAccess, &ftModify );
CloseHandle( hTarget );

Related

Where are positions of desktop shortcuts stored?

Where are the positions of Windows desktop shortcuts stored?
I am asking about the screen positions of the icons not the actual icons themselves. I know the icons themselves are stored in various DLLs, EXEs etc. The positions are clearly stored in some non-volatile store because they persists through re-boots.
My end goal is to write an app to display, and optionally re-arrange icons on my desktop.
I know this is possible because many available apps do this (e.g., "WinTidy").
I find much talk about "Windows Shell Bags". An interesting article about these are in http://williballethin.com.forensics/shellbags, but that only addresses directories not shortcuts. These are in the registry at various places including
`HKEY_CURRENT_USER/Software/Microsoft/Windows/Shell/Bags/1/Desktop`
`HKEY_USERS/.DEFAULT/Software/Microsoft/Windows/Shell/Bags/1/Desktop`
I wrote a program to extract these but the format of the key values is incomprehensible.
Any body know where and how they are stored?
UPDATE 6/3/20
++++++++++++++++++++++++++++++++++++++
I just switched over to a Win10 64-bit machine and find the solution below no longer works. I believe because of a change in the desktop internals. I figured out how to do this. See "WIN10 ADDENDUM" at the end of this answer.
++++++++++++++++++++++++++++++++++++++
I finally figured out how to do what I want (display and re-arrange desktop icons). My original question concerned locating, reading and writing to the file where the icon info is stored, but this is not a useful approach. Here is what I learned:
Explorer.exe displays desktop items in a giant ListView covering the whole desktop with ListView items corresponding to each visible icon. At startup, Explorer reads info from some arcane file and populates the ListView. On exit, it re-writes that file from the ListView. So modifying the file would not help because it would be overwritten on exit.
The right way to manipulate desktop items is to directly manipulate items in the ListView. Any changes are immediately visible on change, and are saved on exit. To access the items, we can use several Windows messages: LVM_GETITEM, LVM_GETITEMCOUNT, LVM_GETITEMPOSITION and LVM_SETITEMPOSITION. These messages are fairly simple to use with one complication: some require pointers to parameter structures. These structures must be in Explorer's address space not my app's, so some trickery is needed. Here's how to do it. I use LVM_GETITEMPOSITION as an example, which requires a pointer to a POINT structure.
Declare a POINT structure in your app.
Allocate a mirror structure in Explorer's address space using API VirtualAllocEx().
Send LVM_GETITEMPOSITION to Explorer specifying a pointer to this structure.
Read back the result into your app's POINT using API ReadProcessMemory(). This function can read memory across different address spaces.
I have prototyped these operations and they work as I wanted. My code is quite long but I will post excerpts as soon as I clean it up.
UPDATE 10/4/2019 ------------------------------------
CODE EXCERPTS
A set of commonly used utility functions was created to make code more compact and readable. These are named "exp*()" and are included at the end. A reference can be found at http://ramrodtechnology.com/explorer. Much of the basic technique herein was shamelessly stolen from https://www.codeproject.com/Articles/5570/Stealing-Program-s-Memory
Setup
// COMMONLY USED VARS
HANDLE hProcess; // explorer process handle
HWND hWndLV; // explorer main window
// SET UP CONVENIENCE VARS
hProcess = expGetProcessHandle(); // get explorer process handle
if( !hProcess ) exit( 1 );
hWndLV = expGetListView(); // get main ListView of Desktop
if( !hWndLV ) exit( 1 );
Function to Print All Item Names
//# Process a list view window and print item names
int
printAllNames()
{
int ok,icount,indx;
LVITEM item; // point in app space
LVITEM *_pitem; // point in exp space
char text[512];
char *_ptext;
int nr,nwrite; // count of bytes read/written
printf( "\n" );
// ALLOC ITEMS IN EXP SPACE
_pitem = expAlloc( sizeof(LVITEM) );
_ptext = expAlloc( sizeof(text ) );
printf( " NAME\n" );
printf( " ==================================\n" );
icount = expGetItemCount();
for( indx=0; indx<icount; indx++ ) { // for each item in LV
// SETUP ITEM IN EXP SPACE
memset( &item, 0, sizeof(LVITEM) ); // preclear
item.iItem = indx; // index of item to read
item.iSubItem = 0; // sub index (always 0)
item.mask = LVIF_TEXT; // component to read
item.pszText = _ptext; // buffer to recv text
item.cchTextMax = sizeof(text); // size of buffer
// WRITE ITEM REQ TO EXP SPACE
ok = WriteProcessMemory( hProcess, _pitem, &item, sizeof(LVITEM), &nwrite );
// SEND MESSAGE TO GET ITEM INTO EXP SPACE
ok = SendMessage( hWndLV, LVM_GETITEM, indx, (LPARAM)_pitem );
// READ EXP TEXT INTO APP SPACE
memset( &item, 0, sizeof(LVITEM) );
ok = ReadProcessMemory( hProcess, _pitem, &item, sizeof(POINT), &nr );
ok = ReadProcessMemory( hProcess, _ptext, &text, sizeof(text), &nr );
// PRINT RESULT
printf( " %s\n", text );
}
ok = expFree( _pitem );
ok = expFree( _ptext );
return( TRUE );
//r Returns TRUE on success, FALSE on error
}
Function To Print All Item Positions
//# Process a list view window and print position
int
printAllPositions()
{
int ok,icount,indx,nr;
POINT pt; // point in app space
POINT *_ppt; // point in exp space
icount = expGetItemCount();
_ppt = expAlloc( sizeof(POINT) );
if( !_ppt ) return( FALSE );
printf( " X Y\n" );
printf( "---- ----\n" );
for( indx=0; indx<icount; indx++ ) { // for each item in LV
ok = SendMessage( hWndLV, LVM_GETITEMPOSITION, indx, (LPARAM)_ppt );
ok = ReadProcessMemory( hProcess, _ppt, &pt, sizeof(POINT), &nr );
printf( "%4d %4d\n", pt.x, pt.y );
}
ok = expFree( _ppt );
return( TRUE );
//r Returns TRUE on success
}
Function To Move Item
See 'expSetItemPosition' below. UPDATED 10/6/19
Explorer Utility Functions
// EXPLORER UTILITY FUNCTIONS
//# Allocate a block of memory in explorer space
void *
expAlloc(
int size) // size of block
{
void *p;
p = VirtualAllocEx(
hProcess,
NULL,
size,
MEM_COMMIT,
PAGE_READWRITE );
return( p );
//r Returns addr of memory in EXPLORER space or NULL on error
}
//# Free virtual memory in EXPLORER space
int
expFree(
void *p) // pointer to free
{
int ok;
ok = VirtualFreeEx( hProcess, p, 0, MEM_RELEASE );
return( ok );
//r Returns TRUE on success, else FALSE
}
static int aBiggest; // biggest area so far
static HWND hWndBiggest; // hWnd with biggest area
//# Find main list view of explorer
HWND
expGetListView()
{
//n Approach: Enumerate all child windows of desktop and find largest.
//n This will be the main explorer window.
HWND hWndDesktop;
hWndDesktop = GetDesktopWindow();
if( !hWndDesktop ) return( NULL );
aBiggest = -1; // init
hWndBiggest = NULL; // init
EnumChildWindows( hWndDesktop, CallbackDesktopChild, 0 );
return( hWndBiggest );
//r Returns hWnd of largest explorer list view
}
//# Callback for EnumChildWindows
BOOL CALLBACK CallbackDesktopChild(
HWND hWnd,
LPARAM dwUser)
{
//n Get size of child. If biggest, save hWnd.
int i,w,h,a;
char classname[MAXPATH+1];
RECT rect;
i = GetClassName( hWnd, classname, MAXPATH ); // get class
if( stricmp( classname, "SysListView32" ) ) { // not a list view?
return( TRUE ); // skip it
}
// CALC SIZE
i = GetWindowRect( hWnd, &rect );
w = rect.right - rect.left;
h = rect.bottom - rect.top;
// CHECK IF BIGGEST
a = w * h;
if( a > aBiggest ) { // is biggest?
aBiggest = a;
hWndBiggest = hWnd;
}
return( TRUE ); // TRUE to continue enumeration
}
//# Get process handle of explorer.exe
HANDLE
expGetProcessHandle()
{
//n Approach: take process snapshot and loop through to find "explorer.exe"
//n Needs tlhelp32.h and comctl32.lib
int i,stat;
PROCESSENTRY32 pe;
HANDLE hSnapshot;
char *name;
HANDLE h;
// TAKE A SNAPSHOT
hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
if( !hSnapshot ) return( NULL );
// LOOP THROUGH PROCESSES AND FIND "explorer.exe"
for( i=0;;i++ ) {
pe.dwSize = sizeof( PROCESSENTRY32 );
if( i == 0 ) stat = Process32First( hSnapshot, &pe );
else stat = Process32Next ( hSnapshot, &pe );
if( !stat ) break; // done or error?
name = pe.szExeFile;
if( !stricmp( name, "explorer.exe" ) ) { // matches?
h = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pe.th32ProcessID );
return( h );
}
}
return( NULL );
//r Returns explorer process handle or NULL on error
}
//# Get count of items in explorer list view
int
expGetItemCount()
{
int count;
count = SendMessage( hWndLV, LVM_GETITEMCOUNT, 0, 0 );
return( count );
//r Returns count of item
}
//# Get position of list view icon by index
int
expGetItemPosition(
int indx, // index of item
int *x, // ptr to int to recv x
int *y) // ptr to int to recv y
{
int i,ok,icount;
char classname[MAXPATH+1];
POINT pt; // point in app space
POINT *_ppt; // point in exp space
int nr; // count of bytes read
//int w,h;
i = GetClassName( hWndLV, classname, MAXPATH );
// GET COUNT OF ITEMS IN LIST VIEW
icount = expGetItemCount();
if( indx < 0 || indx >= icount ) return( FALSE );
// ALLOC POINT IN EXP SPACE
_ppt = expAlloc( sizeof(POINT) );
if( !_ppt ) return( FALSE );
// SEND MESSAGE TO GET POS INTO EXP SPACE POINT
ok = SendMessage( hWndLV, LVM_GETITEMPOSITION, indx, (LPARAM)_ppt );
if( !ok ) return( FALSE );
// READ EXP SPACE POINT INTO APP SPACE POINT
ok = ReadProcessMemory( hProcess, _ppt, &pt, sizeof(POINT), &nr );
if( !ok ) return( FALSE );
ok = expFree( _ppt );
if( !ok ) return( FALSE );
if( x ) *x = pt.x;
if( y ) *y = pt.y;
//r Returns TRUE on success
return( TRUE );
}
//# Move item
int
expSetItemPosition(
char *name, // icon name
int x, // new x coord
int y) // new y coord
{
int ok,indx;
LPARAM lParam;
indx = expGetItemIndex( name );
if( indx < 0 ) return( FALSE );
lParam = MAKELPARAM( x, y );
ok = SendMessage( hWndLV, LVM_SETITEMPOSITION, indx, lParam );
if( !ok ) return( FALSE );
return( TRUE );
//r Returns TRUE on success
}
WIN10 ADDENDUM
6/19/20
++++++++++++++++++++++++++++++++++
Under Win10, the solution is much more complicated. You must use various COM objects and interfaces, e.g. IShellWindows, etc. (God, I hate COM). I did not create a library but rather offer a complete working program below. I compiled this using MSVC 2019. Error checking has been omitted for clarity (but you should do it).
// icons.cpp - Display (and optionally move) desktop icons
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <ShlObj.h>
#include <atlbase.h>
int
main(int argc,char** argv)
{
CComPtr<IShellWindows> spShellWindows;
CComPtr<IShellBrowser> spBrowser;
CComPtr<IDispatch> spDispatch;
CComPtr<IShellView> spShellView;
CComPtr<IFolderView> spView;
CComPtr<IShellFolder> spFolder;
CComPtr<IEnumIDList> spEnum;
CComHeapPtr<ITEMID_CHILD> spidl;
CComVariant vtLoc(CLSID_ShellWindows);
CComVariant vtEmpty;
STRRET str;
int count=0;
HRESULT hr;
long lhWnd;
// INITIALIZE COM
CoInitialize(NULL);
// GET ShellWindows INTERFACE
hr = spShellWindows.CoCreateInstance(CLSID_ShellWindows);
// FIND WINDOW
hr = spShellWindows->FindWindowSW(
&vtLoc, &vtEmpty, SWC_DESKTOP, &lhWnd, SWFO_NEEDDISPATCH, &spDispatch);
// GET DISPATCH INTERFACE
CComQIPtr<IServiceProvider>(spDispatch)->
QueryService(SID_STopLevelBrowser, IID_PPV_ARGS(&spBrowser));
spBrowser->QueryActiveShellView(&spShellView);
spShellView->QueryInterface(IID_PPV_ARGS(&spView) );
hr = spView->GetFolder(IID_PPV_ARGS(&spFolder));
// GET ENUMERATOR
spView->Items(SVGIO_ALLVIEW, IID_PPV_ARGS(&spEnum)); // get enumerator
// ENUMERATE ALL DESKTOP ITEMS
for (; spEnum->Next(1, &spidl, nullptr) == S_OK; spidl.Free()) {
// GET/PRINT ICON NAME AND POSITION
char* name;
POINT pt;
spFolder->GetDisplayNameOf(spidl, SHGDN_NORMAL, &str);
StrRetToStr(&str, spidl, &name);
spView->GetItemPosition(spidl, &pt);
printf("%5d %5d \"%s\"\n", pt.x, pt.y, name);
#define MOVE_ICON
#ifdef MOVE_ICON
// OPTIONAL: MOVE *SINGLE* SELECTED ITEM
{
if( !_stricmp(name, "ICON_NAME_TO_MOVE") ) {
PCITEMID_CHILD apidl[1] = { spidl };
int numitems = 1;
// SET pt TO NEW POSITION HERE
hr = spView->SelectAndPositionItems(numitems, apidl, &pt, 0);
}
}
#endif
count++;
}
CoUninitialize(); // release COM
fprintf(stderr, "enumerated %d desktop icons\n", count);
fprintf(stderr, "Press any key to exit...\n");
_getch();
exit(0 );
}

Windows: How to stop buffering of redirected Stdout using CreateProcess

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

GetFileAttributes on (locked) system file

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 );

How can a 64-bit process have a 32-bit view of file system and registry?

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.

Get file path from NT/Device Name

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;
}

Resources