How to get the physical drive's volume id? - c++

Problem
I'm trying to get the volume id from a physical drive.
My Code
// define disk handle
HANDLE VDHANDLE;
// set "open disk" parameters
OPEN_VIRTUAL_DISK_PARAMETERS VHD_OPEN_PARAM;
VHD_OPEN_PARAM.Version = OPEN_VIRTUAL_DISK_VERSION_1;
VHD_OPEN_PARAM.Version1.RWDepth = OPEN_VIRTUAL_DISK_RW_DEPTH_DEFAULT;
// set storage type
VIRTUAL_STORAGE_TYPE VHD_STORAGE;
VHD_STORAGE.DeviceId = VIRTUAL_STORAGE_TYPE_DEVICE_VHD;
VHD_STORAGE.VendorId = VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT;
// set "attach disk" parameters
ATTACH_VIRTUAL_DISK_PARAMETERS VHD_ATTACH_PARAM;
VHD_ATTACH_PARAM.Version = ATTACH_VIRTUAL_DISK_VERSION_1;
// open disk
if ( OpenVirtualDisk( &VHD_STORAGE, L"F:\\MyStorageBunker.vhd",
VIRTUAL_DISK_ACCESS_ALL, OPEN_VIRTUAL_DISK_FLAG_NONE,
&VHD_OPEN_PARAM, &VDHANDLE ) != ERROR_SUCCESS )
{
return ERR_MOUNT_SCRIPTCREATE;
}
// attach drive
if ( AttachVirtualDisk( VDHANDLE, 0, ATTACH_VIRTUAL_DISK_FLAG_PERMANENT_LIFETIME,
0, &VHD_ATTACH_PARAM, 0 ) != ERROR_SUCCESS )
{
return ERR_MOUNT_SCRIPTEXECUTE;
}
// Get attached drive & info
wchar_t DriveInfo[ MAX_PATH ];
ULONG bufferSize = sizeof( DriveInfo );
GetVirtualDiskPhysicalPath( VDHANDLE, &bufferSize, DriveInfo );
// DriveInfo raw output = \PHYSICALDISKX
// X = volume id
What I tried
std::wstringstream tmp;
int value;
char c;
std::wstringstream ss( DriveInfo );
ss >> tmp >> c >> value;
Issue
no operator ">>" matches these operands
Questions
How can I extract the volume id from wchar_t DriveInfo?
Is there any way to get the volume id except GetVirtualDiskPhysicalPath?

I cribbed this code from somewhere I can't recall, but it seems to work for getting the serial# from the first valid drive. Sorry if it doesn't compile, I had to replace our own string class with the general one. The thing you probably want out of this is the call to GetVolumeInformation()
template <class ELT> static const ELT* NextToken(const ELT* ptr) {
// Skip this null-terminated string
while (*ptr != 0) {
ptr++;
}
ptr++;
return ptr;
}
int getDiskId() {
int bufSize = GetLogicalDriveStrings(0, 0);
WCHAR* buffer = new WCHAR[bufSize];
GetLogicalDriveStrings(bufSize, buffer);
std::vector<std::string> driveStrings;
for (const WCHAR *ptr = buffer; *ptr != 0; ptr = NextToken(ptr)) {
if (toupper(*ptr) == 'A' || toupper(*ptr) == 'B') {
continue;
}
std::string tmp;
tmp += toupper(*ptr);
driveStrings.push_back(tmp);
}
// want lowest letter first
std::sort(driveStrings.begin(), driveStrings.end());
for (int i = 0; i < driveStrings.size(); i++) {
DWORD dummy(0);
DWORD serialNumber(0);
if (
GetVolumeInformation(
driveStrings[i].c_str(), // lpRootPathName
0, // lpVolumeNameBuffer
0, // nVolumeNameSize
&serialNumber,
&dummy, // lpMaximumComponentLength
&dummy, // lpFileSystemFlags
0, // lpFileSystemNameBuffer
0 // nFileSystemNameSize
)
) {
break;
}
}
delete [] buffer;
return serialNumber;
}

Related

How to fill a label with text read from a file .msg

I want to fill a label with some text read from a file.msg. I think i've somehow managed to read from the file but now i need to fill the label with what i've read.
void __fastcall TErrorPanel::lblOpMsgErClick(TObject *Sender)
{
char OutBuf[500];
char OutBuf2[500];
static int Func_exec = 0;
if (Func_exec == 0)
{
Func_exec = 1;
if (tpgm_cfg.TestMod.RejectModule == 0)
{
GetMessage(1, SYSMSGIMG, OutBuf, gPathMsgFile);
}
else
{
GetMessage(2, SYSMSGIMG, OutBuf2, gPathMsgFile);
}
Func_exec = 0;
}
return;
}
The GetMessage custom function, at the moment it shows MsgNF, it looks like it isn't picking up the content of the OutBuf
void GetMessage(int Code,char *Section, char *OutBuf, char *PathMsgFile, int InsErrCode)
{
char buff[512],Msg[500],sCode[10];
char *p;
int cmpres;
long rOffset = 0;
itoa(Code,sCode,10);
::GetPrivateProfileString(Section, sCode, "MsgNf", buff, sizeof(buff), PathMsgFile);
rOffset = ::GetPrivateProfileInt(Section, "Offset", 0, PathMsgFile);
cmpres=strcmp("MsgNf",buff);
if (cmpres==0)
{
sprintf(Msg,"Message[%ld]: Not Found !",Code + rOffset);
}
do
{
p = strchr (buff , '|');
if(p != NULL)
{
*p = '\n';
}
}while(p != NULL);
strcpy(OutBuf, buff);
if (strcmpi(SYSERRORMSG,Section)==0)
{
sprintf(buff,"Error[%ld]-%s", Code + rOffset, OutBuf);
strcpy(OutBuf,buff);
rmLastErrorCode = Code;
}
return;
}
This is how you generally set the text to display:
label_name->Caption = "Text to display";
However, I don't know how to fit that into the code you've shown.

How does one locate a pointer error?

I am attempting to create a program to create a Markov chain but I am having pointer problems. When I run the Program I get a segmentation fault.
#include <stdio.h>
#include <cstring>
#include <cstdlib>
struct word;
struct nextword
{
word* sourceword;
word* next = 0;
};
int wordcount;
struct word
{
char* wordstr;
struct word* next = 0;
nextword* followingword = 0;
int nextwordcount = 0;
};
int main()
{
word* firstword = 0;
char * buffer = 0;
long length;
FILE * f = fopen ("alice.txt", "rb");
if (f)
{
fseek (f, 0, SEEK_END);
length = ftell (f);
fseek (f, 0, SEEK_SET);
buffer = (char *)malloc (length);
if (buffer)
{
fread (buffer, 1, length, f);
}
fclose (f);
}
if (buffer)
{
char wordbuffer[500];
int fileindex = 0;
while(fileindex < length-1)
{
int wordindex = 0;
while(buffer[fileindex] != ' ')
{
wordbuffer[wordindex] = buffer[fileindex];
wordindex++;
fileindex++;
}
if(wordindex != 0)
{
wordbuffer[wordindex] = '\0';
word* newword = (word*)malloc(sizeof(word));
char* newwordstr = (char*)malloc((strlen(wordbuffer)+1)*sizeof(char));
strcpy(newword->wordstr, newwordstr);
if(!firstword)
{
firstword = newword;
}
else
{
word* testword = firstword;
while(!testword->next)
{
testword = (testword->next);
}
testword->next = newword;
printf(newword->wordstr);
}
}
return 0;
}
}
else
{
return 1;
}
}
I attempted to remove the file reading part and replace it with a hard coded string, but the problem remained.
You might want to read about STL and use a list. Or use a C list, see a couple of examples,
Adding node in front of linklist
How to pop element from tail in linked list?
Trying to make linkedlist in C
Several problems. Fixed some. compiles.
I have annotated the code with places where you need to fix bounds checking, and the big problem was likely the strcpy to the struct word->wordstr uninitialized char*,
#include <stdio.h>
#include <cstring>
#include <cstdlib>
struct word;
struct nextword
{
word* sourceword;
word* next = 0;
};
int wordcount;
struct word
{
char* wordstr; //what do you think this pointer points to?
struct word* next = 0;
nextword* followingword = 0;
int nextwordcount = 0;
};
int main()
{
FILE* fh = NULL;
word* firstword = 0;
char* buffer = 0;
char* fname = "alice.txt";
long length = 0; //you did not initialize length
if ( (fh = fopen ("alice.txt", "rb")) )
{
//why not use fstat to get file size?
//why not use mmap to read file?
fseek (fh, 0, SEEK_END);
length = ftell (fh); //ok, length set here
fseek (fh, 0, SEEK_SET);
if( (buffer = (char *)malloc (length)) )
{
fread (buffer, 1, length, fh);
}
fclose (fh);
}
else
{
printf("error: cannot open %s",fname);
exit(1);
}
printf("read %s, %ld\n",fname,length);
if (!buffer)
{
printf("error: cannot open %s",fname);
exit(1);
//use exit, to return from main() //return 1;
}
//already checked buffer
{
int fileindex = 0;
//put wordbuffer after fileindex, avoids stackoverflow overwrite
char wordbuffer[500]; //500 bytes on stack, initialize?
memset(wordbuffer,0,sizeof(wordbuffer));
while(fileindex < length-1)
{
int wordindex = 0;
//several errors in this line, check for null terminator,
//check for newline, tab, basically any whitespace
//while(buffer[fileindex] != ' ')
while( buffer[fileindex] && buffer[fileindex] != ' ' )
{
wordbuffer[wordindex] = buffer[fileindex];
wordindex++;
fileindex++;
//here is another error, do not overflow your stack based buffer
if( wordindex>sizeof(buffer)-1 ) break; //do not overflow buffer
}
wordbuffer[wordindex] = '\0'; //terminate wordbuffer
//since you chose wordindex signed, you want it > 0
if(wordindex > 0)
{
//use a constructor
word* newword = (word*)malloc(sizeof(word));
//use a constructor
//or just use strdup, since it is just a cstring
char* newwordstr = strdup(wordbuffer);
//no, just set pointer to the above allocated string
//strcpy(newword->wordstr, newwordstr);
newword->wordstr = newwordstr;
if(!firstword)
{
firstword = newword;
}
else
{
word* testword = firstword;
while(!testword->next)
{
testword = (testword->next);
}
testword->next = newword;
printf(newword->wordstr);
}
}
return 0;
}
}
exit(0); //done
}
This compiles and runs without error, you need to look up linked list handling. You should implement a linked list, and then add word elements to list.

How can I search for a string in the memory of another process?

Currently I'm using this function which I've cobbled together from reading several loosely related questions all over the internet. The problem I'm having is that the first time I ran it it returned an error, but unfortunately I haven't been able to reproduce it. Now when I run it it simply returns 0 every time.
DWORD GetAddressOfString(char *input)
{
unsigned char *p = NULL;
MEMORY_BASIC_INFORMATION info;
HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, _processID);
for (p = NULL; VirtualQueryEx(process, p, &info, sizeof(info)) == sizeof(info); p += info.RegionSize)
{
if (info.State == MEM_COMMIT && (info.Type == MEM_MAPPED || info.Type == MEM_PRIVATE))
{
char *buffer = new char[info.RegionSize];
SIZE_T bytesRead;
ReadProcessMemory(process, p, &buffer, info.RegionSize, &bytesRead);
for (int i = 0; i <= (info.RegionSize - sizeof(input)); i++)
{
if (memcmp(input, &buffer[i], sizeof(input)) == 0)
{
return i;
}
}
}
}
}
Here's a quick and dirty version that searches for data in itself. If you open up Notepad++, type "SomeDataToFind", replace the pid with the correct value, and run it, it should find the data as well. It might give you something to start with and embellish to suit your needs.
Your code was searching for the wrong length, returning the wrong offset, leaking memory like a sieve, and not always returning a value which is undefined behavior.
#include <Windows.h>
#include <iostream>
#include <string>
#include <vector>
char* GetAddressOfData(DWORD pid, const char *data, size_t len)
{
HANDLE process = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, pid);
if(process)
{
SYSTEM_INFO si;
GetSystemInfo(&si);
MEMORY_BASIC_INFORMATION info;
std::vector<char> chunk;
char* p = 0;
while(p < si.lpMaximumApplicationAddress)
{
if(VirtualQueryEx(process, p, &info, sizeof(info)) == sizeof(info))
{
p = (char*)info.BaseAddress;
chunk.resize(info.RegionSize);
SIZE_T bytesRead;
if(ReadProcessMemory(process, p, &chunk[0], info.RegionSize, &bytesRead))
{
for(size_t i = 0; i < (bytesRead - len); ++i)
{
if(memcmp(data, &chunk[i], len) == 0)
{
return (char*)p + i;
}
}
}
p += info.RegionSize;
}
}
}
return 0;
}
int main()
{
const char someData[] = "SomeDataToFind";
std::cout << "Local data address: " << (void*)someData << "\n";
//Pass whatever process id you like here instead.
DWORD pid = GetCurrentProcessId();
char* ret = GetAddressOfData(pid, someData, sizeof(someData));
if(ret)
{
std::cout << "Found: " << (void*)ret << "\n";
}
else
{
std::cout << "Not found\n";
}
return 0;
}

SendARP not writing out to mac array

SendARP is not setting my mac array, so likewise when I try to convert the mac array to BYTE to convert it to human readable, it also gets random characters in it. also the memset does not seem to make MacAddr 0!
std::wstring GetMacAddress(IPAddr destip)
{
DWORD ret;
ULONG MacAddr[2] = {0}; //initialize instead of memset
ULONG PhyAddrLen = 6; /* default to length of six bytes */
unsigned char mac[6];
//memset(MacAddr, 0, sizeof(MacAddr)); //MacAddr doesn't get set to 0!
//Send an arp packet
ret = SendARP(destip , 0, MacAddr , &PhyAddrLen); //MacAddr stays
//Prepare the mac address
if (ret == NO_ERROR)
{
BYTE *bMacAddr = (BYTE *) & MacAddr;
if(PhyAddrLen)
{
for (int i = 0; i < (int) PhyAddrLen; i++)
{
mac[i] = (char)bMacAddr[i];
}
}
}
}
I have tried numerous ways to get MacAddr to get set by the SendARP function, but it doesn't seem to work and it doesn't return an error.
Casting to char does not convert to a textual representation. If you want to convert to a textual representation one option is to use std::wstringstream
#include <sstream>
#include <string>
#include <iomanip>
std::wstring GetMacAddress(IPAddr destip)
{
// ... snip ...
std::wstringstream out;
for (int i = 0; i < (int) PhyAddrLen; i++)
{
out << std::setw(2) << std::setfill(L'0') << bMacAddr[i];
}
return out.str();
}
Try this:
static const wchar_t *HexChars = L"0123456789ABCDEF";
std::wstring GetMacAddress(IPAddr destip)
{
DWORD ret;
BYTE MacAddr[sizeof(ULONG)*2];
ULONG PhyAddrLen = sizeof(MacAddr);
std::wstring MacAddrStr;
ret = SendARP(destip, 0, (PULONG)MacAddr, &PhyAddrLen);
if ((ret == NO_ERROR) && (PhyAddrLen != 0))
{
MacAddrStr.resize((PhyAddrLen * 2) + (PhyAddrLen-1));
MacAddrStr[0] = HexChars[(MacAddr[0] & 0xF0) >> 4];
MacAddrStr[1] = HexChars[MacAddr[0] & 0x0F];
for (ULONG i = 1, j = 2; i < PhyAddrLen; ++i, j += 3)
{
MacAddrStr[j+0] = L':';
MacAddrStr[j+1] = HexChars[(MacAddr[i] & 0xF0) >> 4];
MacAddrStr[j+2] = HexChars[MacAddr[i] & 0x0F];
}
}
return MacAddrStr;
}

Stack overflow in recursive function

I am writing a simple app that outputs all files in some directory to console. To achieve this I dynamically allocate memory in function PathCreator() and return a pointer to this memory. I don't know how to correctly free this memory segment in GetAllFiles(). When I use the code below I get a stack overflow exception. How can I fix this? Please don't offer me to use something that doesn't need dynamically allocated memory, I just want to fix my code.
#include "stdafx.h"
#include <windows.h>
#include <iostream>
wchar_t *PathCreator(wchar_t *dir, wchar_t *fileName);
int is_directory(wchar_t *p)
{
wchar_t *t = PathCreator(p,L"\\");
WIN32_FIND_DATA file;
HANDLE search_hendle = FindFirstFile(t, &file);
long error = GetLastError();
if(error == 267)
{
return 0;
}
else
{
return 1;
}
}
wchar_t *PathCreator(wchar_t *dir, wchar_t *fileName)
{
wchar_t* path = 0;
int size = 0;
wchar_t *d = dir;
wchar_t *f = fileName;
while(*d != '\0')
{
d++;
size++;
}
while(*f != '\0')
{
f++;
size++;
}
path = new wchar_t[(size+=3) * sizeof(wchar_t)];
int j = 0;
while(j < size)
{
path[j] = '\0';
j++;
}
int i;
i = 0;
while(*dir != '\0')
{
path[i] = *dir;
i++;
dir++;
}
path[i++] = '\\';
wchar_t *t = fileName;
while(*t != '\0')
{
path[i] = *t;
i++;
t++;
}
path[i] = '\0';
return path;
}
void GetAllFiles(wchar_t* dir)
{
wchar_t *p = 0;
int i = 0;
WIN32_FIND_DATA file;
wchar_t *t = PathCreator(dir, L"*");
HANDLE search_hendle = FindFirstFile(t, &file);
if(search_hendle)
{
do
{
p = PathCreator(dir,file.cFileName);
if(!is_directory(p))
{
std::wcout << p << std::endl;
}
else
{
GetAllFiles(p);
}
delete [] p;
}
while(FindNextFile(search_hendle, &file));
}
delete [] t;
FindClose(search_hendle);
}
int _tmain(int argc, _TCHAR* argv[])
{
GetAllFiles(L"C:\\Users");
}
So, you have "." and ".." in your directory search.
The first entry is ".", so:
p = PathCreator(dir, file.cFilename)
yields:
"C:\Users\."
Then the next line:
if (!is_directory(p))
Is ALWAYS false, so it just keeps recursing into:
GetAllFiles(p)
forever ... or until your stack blows up, whichever comes first ;-)
I would recommend explicitly checking for "." and ".." and skipping those entries (also MFC and Qt, etc. have nice directory handling classes, but I think you want to do it this way).
My modification:
do
{
// I added this - guess I can't embolden code text
if (wcscmp(file.cFileName,L".") == 0 || wcscmp(file.cFileName,L"..")==0)
continue;
p = PathCreator(dir,file.cFileName);
if(!is_directory(p))
{
std::wcout << p << std::endl;
}
else
{
GetAllFiles(p);
}
delete [] p;
}
while(FindNextFile(search_hendle, &file));
Again you try to use C in place of C++ and you still using wcout?! no problem you are a programmer and I'm sure you have a reason for this! but memory management in C is much much harder than C++ and you should have some skills to use it. Here is a fully working code but as you see it is really harder to manage, use and understand than its C++ version using standard containers and string, so if you are allowed to use C++(as you use wcout) then use its C++ version for ease:
#include <Windows.h>
/*! \brief Merge \a folder and \a filename into a newly allocate memory and
* return it to the caller. Use free to free returned memory!
*/
wchar_t* PathCreator( wchar_t const* folder, wchar_t const* filename )
{
wchar_t* res;
size_t i, len, folderLen = wcslen( folder ), filenameLen = wcslen( filename );
len = folderLen + filenameLen;
if( folder[folderLen - 1] != '\\' ) ++len;
++len; // for \0
res = (wchar_t*) malloc( sizeof(wchar_t) * len );
if( !res ) return NULL;
wcscpy_s( res, len, folder );
/* Remove possible wide card at end of folder */
for( i = folderLen; i--; ) {
if( res[i] == '*' || res[i] == '?' ) {
res[i] = 0;
--folderLen;
} else {
break;
}
}
if( res[folderLen - 1] != '\\' ) wcscat_s( res, len, L"\\" );
wcscat_s( res, len, filename );
return res;
}
/*! \brief Free memory that returned by \ref GetAllFiles
*/
void FreeAllFilesMemory( wchar_t** p )
{
wchar_t** tmp = p;
if( !p ) return ;
while( *tmp ) free( *tmp++ );
free( p );
}
wchar_t** AddToArray( wchar_t** p, size_t* pAllocated, size_t* pUsed, wchar_t* s )
{
if( *pUsed >= *pAllocated ) {
size_t newAlloc = *pAllocated * 3 / 2; // Grow by 1.5
if( newAlloc < 16 ) newAlloc = 16;
p = (wchar_t**) realloc( p, newAlloc * sizeof(wchar_t*) );
if( !p ) return NULL;
*pAllocated = newAlloc;
}
p[*pUsed] = s;
++*pUsed;
return p;
}
wchar_t** GetAllFilesImpl( wchar_t const* folder, wchar_t** res, size_t* pAllocated, size_t* pUsed )
{
HANDLE hSearch;
WIN32_FIND_DATAW fileinfo;
size_t allocatedMemory = 0;
hSearch = FindFirstFileW( folder, &fileinfo );
if( hSearch != INVALID_HANDLE_VALUE ) {
do {
wchar_t* sFileName, ** tmp, sTmp[ 1024 ];
/* ignore ., .. */
if( !wcscmp(fileinfo.cFileName, L".") ||
!wcscmp(fileinfo.cFileName, L"..") )
continue;
sFileName = PathCreator( folder, fileinfo.cFileName );
wprintf( L"%s\n", sFileName ); /* Print result */
tmp = AddToArray( res, pAllocated, pUsed, sFileName );
if( !tmp ) return FreeAllFilesMemory(res), NULL;
res = tmp;
if( fileinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
wcscpy_s( sTmp, sFileName );
wcscat_s( sTmp, L"\\*" );
tmp = GetAllFilesImpl( sTmp, res, pAllocated, pUsed );
if( !tmp ) return NULL;
res = tmp;
}
} while( FindNextFileW(hSearch, &fileinfo) );
FindClose( hSearch );
}
return res;
}
/*! \brief List all files that match a pattern and return it as an array of
* wide strings, free result using \ref FreeAllFilesMemory
*/
wchar_t** GetAllFiles( wchar_t const* folder )
{
size_t nAllocated = 0, nUsed = 0;
wchar_t** res = GetAllFilesImpl( folder, NULL, &nAllocated, &nUsed );
if( res ) {
/* to indicate end of result add a NULL string */
wchar_t** tmp = AddToArray( res, &nAllocated, &nUsed, NULL );
if( !tmp ) return FreeAllFilesMemory(res), NULL;
res = tmp;
}
return res;
}