Resolve Windows device path to drive letter - windows

How do you resolve an NT style device path, e.g. \Device\CdRom0, to its logical drive letter, e.g. G:\ ?
Edit: A Volume Name isn't the same as a Device Path so unfortunately GetVolumePathNamesForVolumeName() won't work.

Hopefully the following piece of code will give you enough to solve this - after you've initialised it, you just need to iterate through the collection to find your match. You may want to convert everything to upper/lower case before you insert into the collection to help with lookup performance.
typedef basic_string<TCHAR> tstring;
typedef map<tstring, tstring> HardDiskCollection;
void Initialise( HardDiskCollection &_hardDiskCollection )
{
TCHAR tszLinkName[MAX_PATH] = { 0 };
TCHAR tszDevName[MAX_PATH] = { 0 };
TCHAR tcDrive = 0;
_tcscpy_s( tszLinkName, MAX_PATH, _T("a:") );
for ( tcDrive = _T('a'); tcDrive < _T('z'); ++tcDrive )
{
tszLinkName[0] = tcDrive;
if ( QueryDosDevice( tszLinkName, tszDevName, MAX_PATH ) )
{
_hardDiskCollection.insert( pair<tstring, tstring>( tszLinkName, tszDevName ) );
}
}
}

Maybe you could use GetVolumeNameForMountPoint and iterate through all mount points A:\ through Z:\, breaking when you find a match?
http://msdn.microsoft.com/en-us/library/aa364994(VS.85).aspx
(I haven't tried this)

Following function does the job using C only
BOOL GetWin32FileName(const TCHAR* pszNativeFileName, TCHAR *pszWin32FileName)
{
BOOL bFound = FALSE;
// Translate path with device name to drive letters.
TCHAR szTemp[MAX_PATH];
szTemp[0] = '\0';
if (GetLogicalDriveStrings(MAX_PATH - 1, szTemp))
{
TCHAR szName[MAX_PATH];
TCHAR szDrive[3] = TEXT(" :");
TCHAR* p = szTemp;
do
{
// Copy the drive letter to the template string
*szDrive = *p;
// Look up each device name
if (QueryDosDevice(szDrive, szName, MAX_PATH))
{
size_t uNameLen = _tcslen(szName);
if (uNameLen < MAX_PATH)
{
bFound = _tcsnicmp(pszNativeFileName, szName, uNameLen) == 0
&& *(pszNativeFileName + uNameLen) == _T('\\');
if (bFound)
{
// Replace device path with DOS path
StringCchPrintf(pszWin32FileName,
MAX_PATH,
TEXT("%s%s"),
szDrive,
pszNativeFileName + uNameLen);
}
}
}
// Go to the next NULL character.
while (*p++);
} while (!bFound && *p);
}
return(bFound);
}

You can lookup all volumes' name to match a device name and get drive letter.Here is a sample:
int DeviceNameToVolumePathName(WCHAR *filepath) {
WCHAR fileDevName[MAX_PATH];
WCHAR devName[MAX_PATH];
WCHAR fileName[MAX_PATH];
HANDLE FindHandle = INVALID_HANDLE_VALUE;
WCHAR VolumeName[MAX_PATH];
DWORD Error = ERROR_SUCCESS;
size_t Index = 0;
DWORD CharCount = MAX_PATH + 1;
int index = 0;
// \Device\HarddiskVolume1\windows,locate \windows.
for (int i = 0; i < lstrlenW(filepath); i++) {
if (!memcmp(&filepath[i], L"\\", 2)) {
index++;
if (index == 3) {
index = i;
break;
}
}
}
filepath[index] = L'\0';
memcpy(fileDevName, filepath, (index + 1) * sizeof(WCHAR));
FindHandle = FindFirstVolumeW(VolumeName, ARRAYSIZE(VolumeName));
if (FindHandle == INVALID_HANDLE_VALUE)
{
Error = GetLastError();
wprintf(L"FindFirstVolumeW failed with error code %d\n", Error);
return FALSE;
}
for (;;)
{
// Skip the \\?\ prefix and remove the trailing backslash.
Index = wcslen(VolumeName) - 1;
if (VolumeName[0] != L'\\' ||
VolumeName[1] != L'\\' ||
VolumeName[2] != L'?' ||
VolumeName[3] != L'\\' ||
VolumeName[Index] != L'\\')
{
Error = ERROR_BAD_PATHNAME;
wprintf(L"FindFirstVolumeW/FindNextVolumeW returned a bad path: %s\n", VolumeName);
break;
}
VolumeName[Index] = L'\0';
CharCount = QueryDosDeviceW(&VolumeName[4], devName, 100);
if (CharCount == 0)
{
Error = GetLastError();
wprintf(L"QueryDosDeviceW failed with error code %d\n", Error);
break;
}
if (!lstrcmpW(devName, filepath)) {
VolumeName[Index] = L'\\';
Error = GetVolumePathNamesForVolumeNameW(VolumeName, fileName, CharCount, &CharCount);
if (!Error) {
Error = GetLastError();
wprintf(L"GetVolumePathNamesForVolumeNameW failed with error code %d\n", Error);
break;
}
// concat drive letter to path
lstrcatW(fileName, &filepath[index + 1]);
lstrcpyW(filepath, fileName);
Error = ERROR_SUCCESS;
break;
}
Error = FindNextVolumeW(FindHandle, VolumeName, ARRAYSIZE(VolumeName));
if (!Error)
{
Error = GetLastError();
if (Error != ERROR_NO_MORE_FILES)
{
wprintf(L"FindNextVolumeW failed with error code %d\n", Error);
break;
}
//
// Finished iterating
// through all the volumes.
Error = ERROR_BAD_PATHNAME;
break;
}
}
FindVolumeClose(FindHandle);
if (Error != ERROR_SUCCESS)
return FALSE;
return TRUE;
}
If you want to resolve it in driver,you can check this link for reference.

Here is refactored version of the solution.
I replaced TChAR with wchar_t because afaik it's not a good idea to use it in most projects.
std::map<std::wstring, std::wstring> GetDosPathDevicePathMap()
{
// It's not really related to MAX_PATH, but I guess it should be enough.
// Though the docs say "The first null-terminated string stored into the buffer is the current mapping for the device.
// The other null-terminated strings represent undeleted prior mappings for the device."
wchar_t devicePath[MAX_PATH] = { 0 };
std::map<std::wstring, std::wstring> result;
std::wstring dosPath = L"A:";
for (wchar_t letter = L'A'; letter <= L'Z'; ++letter)
{
dosPath[0] = letter;
if (QueryDosDeviceW(dosPath.c_str(), devicePath, MAX_PATH)) // may want to properly handle errors instead ... e.g. check ERROR_INSUFFICIENT_BUFFER
{
result[dosPath] = devicePath;
}
}
return result;
}

Related

Nic address spoofing driver doesn't work after restart

https://github.com/btbd/hwid/blob/master/Kernel/main.c
VOID SpoofNIC() {
SwapControl(RTL_CONSTANT_STRING(L"\\Driver\\nsiproxy"), NsiControl, NsiControlOriginal);
PVOID base = GetBaseAddress("ndis.sys", 0);
if (!base) {
printf("! failed to get \"ndis.sys\" !\n");
return;
}
PNDIS_FILTER_BLOCK ndisGlobalFilterList = FindPatternImage(base, "\x40\x8A\xF0\x48\x8B\x05", "xxxxxx");
if (ndisGlobalFilterList) {
PDWORD ndisFilter_IfBlock = FindPatternImage(base, "\x48\x85\x00\x0F\x84\x00\x00\x00\x00\x00\x8B\x00\x00\x00\x00\x00\x33", "xx?xx?????x???xxx");
if (ndisFilter_IfBlock) {
DWORD ndisFilter_IfBlock_offset = *(PDWORD)((PBYTE)ndisFilter_IfBlock + 12);
ndisGlobalFilterList = (PNDIS_FILTER_BLOCK)((PBYTE)ndisGlobalFilterList + 3);
ndisGlobalFilterList = *(PNDIS_FILTER_BLOCK *)((PBYTE)ndisGlobalFilterList + 7 + *(PINT)((PBYTE)ndisGlobalFilterList + 3));
DWORD count = 0;
for (PNDIS_FILTER_BLOCK filter = ndisGlobalFilterList; filter; filter = filter->NextFilter) {
PNDIS_IF_BLOCK block = *(PNDIS_IF_BLOCK *)((PBYTE)filter + ndisFilter_IfBlock_offset);
if (block) {
PWCHAR copy = SafeCopy(filter->FilterInstanceName->Buffer, MAX_PATH);
if (copy) {
WCHAR adapter[MAX_PATH] = { 0 };
swprintf(adapter, L"\\Device\\%ws", TrimGUID(copy, MAX_PATH / 2));
ExFreePool(copy);
printf("found NIC %ws\n", adapter);
UNICODE_STRING name = { 0 };
RtlInitUnicodeString(&name, adapter);
PFILE_OBJECT file = 0;
PDEVICE_OBJECT device = 0;
NTSTATUS status = IoGetDeviceObjectPointer(&name, FILE_READ_DATA, &file, &device);
if (NT_SUCCESS(status)) {
PDRIVER_OBJECT driver = device->DriverObject;
if (driver) {
BOOL exists = FALSE;
for (DWORD i = 0; i < NICs.Length; ++i) {
if (NICs.Drivers[i].DriverObject == driver) {
exists = TRUE;
break;
}
}
if (exists) {
printf("%wZ already swapped\n", &driver->DriverName);
} else {
PNIC_DRIVER nic = &NICs.Drivers[NICs.Length];
nic->DriverObject = driver;
AppendSwap(driver->DriverName, &driver->MajorFunction[IRP_MJ_DEVICE_CONTROL], NICControl, nic->Original);
++NICs.Length;
}
}
// Indirectly dereferences device object
ObDereferenceObject(file);
} else {
printf("! failed to get %wZ: %p !\n", &name, status);
}
}
// Current MAC
PIF_PHYSICAL_ADDRESS_LH addr = &block->ifPhysAddress;
SpoofBuffer(SEED, addr->Address, addr->Length);
addr = &block->PermanentPhysAddress;
SpoofBuffer(SEED, addr->Address, addr->Length);
++count;
}
}
printf("handled %d MACs\n", count);
} else {
printf("! failed to find ndisFilter_IfBlock !\n");
}
} else {
printf("! failed to find ndisGlobalFilterList !\n");
}
}
I'm using this piece of code to spoof mac address, it works fine after I first installed it, my mac address has been changed.
but after I restart my computer, the mac address returns to what is was before I installed this driver, I had to manually uninstall and install this driver every single time after I restart my computer.
So I checked what's happening, when I restart my computer, the driver jumped over this loop:
for (PNDIS_FILTER_BLOCK filter = ndisGlobalFilterList; filter; filter = filter->NextFilter)
Seems that ndisGlobalFilterList is null ,but why ,is this by design or is it not achievable to make it work through restarts ?

Can I Write Version Information API For Both CHAR And WCHAR?

I'm a little bit short of reaching my goal.
GetFileVersionInfoSize() is working fine along with other two functions GetFileVersionInfo() and VerQueryValue(). I would like to just add more features to it to make it complete.
I've coded it to run on WCHAR and would like to know making it run for CHAR would make sense?
Is there a way around it so that I code it once and it would work for both?
Also, is there a way I could enumerate the contents of \\StringFileInfo\\lang-codepage\\* ?
DWORD GetFileVersionInfo3(const TCHAR *pszFilePath, std::vector<std::pair<std::wstring, std::wstring>> *lplist)
{
DWORD dwSize = 0;
BYTE *pbVersionInfo = NULL;
VS_FIXEDFILEINFO *pFileInfo = NULL;
UINT puLenFileInfo = 0;
dwSize = GetFileVersionInfoSize(pszFilePath, NULL);
if (dwSize == 0)
{
printf("\nError in GetFileVersionInfoSize: %d\n", GetLastError());
return 1;
}
pbVersionInfo = new BYTE[dwSize];
memset(pbVersionInfo, '\0', dwSize);
if (!GetFileVersionInfo(pszFilePath, 0, dwSize, pbVersionInfo))
{
printf("\nError in GetFileVersionInfo: %d\n", GetLastError());
delete[] pbVersionInfo;
return 1;
}
if (!VerQueryValue(pbVersionInfo, TEXT("\\"), (LPVOID*)&pFileInfo, &puLenFileInfo))
{
printf("\nError in VerQueryValue: %d\n", GetLastError());
delete[] pbVersionInfo;
return 1;
}
if (!VerQueryValue(pbVersionInfo, TEXT("\\VarFileInfo\\Translation"), (LPVOID*)&lpTranslate, &puLenFileInfo))
{
printf("\nError in VerQueryValue: %d\n", GetLastError());
return 1;
}
std::vector<std::wstring>::iterator itr;
std::vector<std::wstring> wlist;
wlist.clear();
wlist.push_back(L"FileDescription");
wlist.push_back(L"InternalName");
wlist.push_back(L"OriginalFilename");
wlist.push_back(L"CompanyName");
wlist.push_back(L"FileVersion");
wlist.push_back(L"ProductName");
wlist.push_back(L"ProductVersion");
wlist.push_back(L"LegalCopyright");
char fileEntry[1024];
for (int i = 0; i < (puLenFileInfo / sizeof(struct LANGANDCODEPAGE)); i++)
{
sprintf_s(fileEntry, 1024, "\\StringFileInfo\\%04x%04x\\",
lpTranslate[i].wLanguage,
lpTranslate[i].wCodePage);
lplist->push_back(std::pair<std::wstring, std::wstring>(L"File: ", pszFilePath));
std::string s1(fileEntry);
for (itr = wlist.begin(); itr != wlist.end(); itr++)
{
std::wstring item = *itr;
std::wstring wstr;
wstr.append(s1.begin(), s1.end());
wstr.append(item);
LPVOID lpBuffer = NULL;
UINT dwBytes = 0;
bool bRes = VerQueryValue(pbVersionInfo, wstr.c_str(), (LPVOID*)&lpBuffer, &dwBytes);
if (!bRes)
{
continue;
}
LPTSTR wsResult;
wsResult = (LPTSTR)lpBuffer;
lplist->push_back(std::pair<std::wstring, std::wstring>(item, wsResult));
}
}
return 0;
}
Since you are using TCHAR, use std:::basic_string<TCHAR> instead of std::wstring to match. Otherwise, drop TCHAR and use WCHAR for everything.

When I load my filedisk driver, I got the ERROR_PROC_NOT_FOUND(127) error code

I want to develop an encrypt-virtual-disk based on the FileDisk-17 opensource project.
Here is my solution:
In IPR_MJ_READ, when the ZwReadFile returns, I use function 'DecryptData' to decrypt the data read by ZwReadFile.
In IPR_MJ_WRITE, before call ZwWriteFile, I use function 'EncryptData' to encrypt the data which will be written to the disk.
I put EncryptData & DecryptData functions in a single C source file.
The question is; when I loaded my driver, I get the ERROR_PROC_NOT_FOUND(127) error code
every time, even there are only one line in the EncryptData or DecryptData function.
Who can tell me what caused this and how to fix it?
filedisk.c
switch (io_stack->MajorFunction)
{
case IRP_MJ_READ:
system_buffer = (PUCHAR) MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority);
if (system_buffer == NULL)
{
irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
irp->IoStatus.Information = 0;
break;
}
buffer = (PUCHAR) ExAllocatePool(PagedPool, io_stack->Parameters.Read.Length);
if (buffer == NULL)
{
irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
irp->IoStatus.Information = 0;
break;
}
ZwReadFile(
device_extension->file_handle,
NULL,
NULL,
NULL,
&irp->IoStatus,
buffer,
io_stack->Parameters.Read.Length,
&io_stack->Parameters.Read.ByteOffset,
NULL
);
*if(bEncrypt)
{
cipher = (PUCHAR)ExAllocatePoolWithTag(NonPagedPool, irp->IoStatus.Information, 'TAG');
if(cipher)
{
**DecryptData**(buffer, cipher, irp->IoStatus.Information);
RtlCopyMemory(system_buffer, cipher, irp->IoStatus.Information);
ExFreePool(cipher);
}
else
{
irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
irp->IoStatus.Information = 0;
break;
}
}*
else
{
RtlCopyMemory(system_buffer, buffer, io_stack->Parameters.Read.Length);
ExFreePool(buffer);
}
crypto.c
VOID EncryptData(PUCHAR src, PUCHAR dst, ULONG length)
{
BF_LONG data[2];
BF_KEY key;
BF_set_key(&key, pCryptoInformation->CryptoKey, sizeof(pCryptoInformation->CryptoKey));
}
VOID DecryptData(PUCHAR src, PUCHAR dst, ULONG length)
{
BF_LONG data[2];
BF_KEY key;
BF_set_key(&key, pCryptoInformation->CryptoKey, sizeof(pCryptoInformation->CryptoKey));
}

Map Isn't Returning Correct Numbers

I have a map that is acting up and not returning the correct number. It did then it didn't, now it's just not returning. Any help is appreciated. Thank you.
struct file_data
{
std::wstring sLastAccessTime;
__int64 nFileSize ;
};
int GetFileList(const wchar_t *searchkey, std::map<std::wstring, file_data> &map)
{
WIN32_FIND_DATA fd;
HANDLE h = FindFirstFile(searchkey,&fd);
if(h == INVALID_HANDLE_VALUE)
{
return 0; // no files found
}
while(1)
{
wchar_t buf[128];
FILETIME ft = fd.ftLastWriteTime;
SYSTEMTIME sysTime;
FileTimeToSystemTime(&ft, &sysTime);
wsprintf(buf, L"%d-%02d-%02d",sysTime.wYear, sysTime.wMonth, sysTime.wDay);
file_data filedata;
filedata.sLastAccessTime= buf;
filedata.nFileSize = (((__int64)fd.nFileSizeHigh) << 32) + fd.nFileSizeLow;
map[fd.cFileName]= filedata;
if (FindNextFile(h, &fd) == FALSE)
break;
}
return map.size();
}
int main()
{
std::map<std::wstring, file_data> map;
int count = GetFileList(L"C:\\Users\\DS\\Downloads\\*.pdf", map);
int count1 = GetFileList(L"C:\\Users\\DS\\Downloads\\*.txt", map);
int count2 = GetFileList(L"C:\\Users\\DS\\Downloads\\*.jpg", map);
for(std::map<std::wstring, file_data>::const_iterator it = map.begin(); it != map.end(); ++it)
{
if (count2 != 0)
{
printf("\n How Many: %i \n", count2);
}
else
{
printf ("%s \n", "Nothing");
}
return 0;
}
}
Note that GetFileList() returns the number of items in the map.
In your implementation it is cumulative. Maybe you want to clear the map between consecutive calls to GetFileList().
OK found the solution. This is it.
GetFileList(L"C:\\Users\\DS\\Downloads\\*.pdf", map);
GetFileList(L"C:\\Users\\DS\\Downloads\\*.txt", map);
GetFileList(L"C:\\Users\\DS\\Downloads\\*.jpg", map);
if( map.size() > 0
then...........

renaming multiple file

int rename_file()
{
WIN32_FIND_DATA FindFileData;
HANDLE hFind;
hFind = FindFirstFile(L"\\Hard Disk\\*.*", &FindFileData);
LPTSTR oldfilename;
LPTSTR newfilename;
if (hFind == INVALID_HANDLE_VALUE)
{
printf ("FindFirstFile failed (%d)\n", GetLastError());
return 0;
}
else
{
int i=1000;
while (FindNextFile(hFind, &FindFileData) != 0)
{
_tprintf (TEXT("The first file found is %s\n"),FindFileData.cFileName);
oldfilename =FindFileData.cFileName;
StringCchPrintf(newfilename, 30, TEXT("%s\\newfile_%d.txt"),dirname, i);
BOOL rs = MoveFile(oldfilename,newfilename);
i++;
}
FindClose(hFind);
return 1;
}
}
i am unable to rename file ,i am working on wince 6 ,while debugging at StringCchPrintf iam getting exception in coredll.dll can any one help me ....
You have not allocated any buffer for newFileName, so when you use it in the StringCchPrintf it's just an uninitialized pointer.
Try this:
TCHAR newFile[260]; // or whatever length you wish
LPTSTR newfilename = &newFile[0];
Also you should check the return code from MoveFile, and output something sensible on error. Make a habit of doing this for all your function calls that can return an error.

Resources