I have to implement cross view file integrity checker for my University project. For that how do I list the files of a Directory in Kernel Mode??
Your starting point would be ZwCreateFile - which has options such as "FILE_LIST_DIRECTORY".
You will then use ZwQueryDirectoryFile to get the information about the file(s) within that directory.
Make SURE that you are not forgetting to ZwClose after you open something - it's not so critical in a user-mode application that closes again after it's been used. But the kernel doesn't know when a driver stops using a file (or, for that matter, if some other driver has been given that filehandle, and will be using it at some point), so even if your driver is unloaded, files that it opened will remain open until the system restarts - I quite like to "not restart" my systems, and with a good set of drivers, running a machine for more than a year should be possible. If your driver so much as leaks one handle a day, that's 365 handles leaked.
So, the code would look something like this:
HANDLE h;
NTSTATUS status;
OBJECT_ATTRIBUTES oa = { sizeof(OBJECT_ATTRIBUTES), NULL, L"mydir",
OPEN_CASE_INSENSITIVE, NULL, NULL };
IO_STATUS_BLOCK iosb = {};
status = ZwCreateFile(&h, FILE_LIST_DIRECTORY, &oa, &iosb, NULL,
FILE_ATTRIBUTE_NORMAL, FILE_OPEN, FILE_DIRECTORY_FILE,
NULL, 0);
if (status != STATUS_SUCCESS)
{
... do something...
return errorcode;
}
else
{
FILE_DIRECTORY_INFORMATION info;
for(;;)
{
status = ZwQueryDirectoryFile(h, NULL, NULL, &iosb, &info, sizeof(info),
FileDirectoryInformation, TRUE, L"*.*",
FALSE);
if (status != STATUS_SUCCESS)
{
... check error code and perhaps print if unexpected error ...
break;
}
... do soemthing with `info` ...
}
}
ZwClose(h);
This is just a "rough sketch". I don't have a setup to compile this right now, and I may have missed something important. But it should give you some idea. There are LOTS of optional parameters and optional choices here, and some I've "guessed" what you'd want, but I think I've made reasonable choices. There may be details missing that make this not work, but as a rough starting point, it should give you an idea at least.
Related
I'm trying to use the Leadtools API version 21 for automatically scanning some documents and here is a sudo code of what I have done (it runs in a secondary thread and the unlock has been done in the main thread):
void CheckRetCode(int rc)
{
if (SUCCESS != rc)
{
L_TCHAR errMsg[1024];
memset(errMsg, 0, sizeof(errMsg));
L_GetFriendlyErrorMessage(rc, errMsg, 1024, L_FALSE);
throw TLeadException(errMsg, rc);
}
}
void OnThreadExecute(void)
{
HTWAINSESSION hSession = nullptr;
APPLICATIONDATA appData;
L_INT nRet;
L_TCHAR pszTwnSourceName[1024];
LTWAINSOURCE sInfo;
memset(&appData, 0, sizeof(APPLICATIONDATA));
appData.uStructSize = sizeof(APPLICATIONDATA);
appData.hWnd = hWnd;// hWnd is valid handle of my main window
appData.uLanguage = TWLG_ENGLISH_USA;
appData.uCountry = TWCY_USA;
wcscpy(appData.szManufacturerName, L"MyCompanyName");
wcscpy(appData.szAppProductFamily, L"MyProductName");
wcscpy(appData.szAppName, appData.szAppProductFamily);
wcscpy(appData.szVersionInfo, L"Version 0.1.0.1");
nRet = L_TwainInitSession2(&hSession, &appData, LTWAIN_INIT_MULTI_THREADED);
CheckRetCode(nRet);// the exception gets catched elsewhere but no error reported here
memset(pszTwnSourceName, 0, sizeof(pszTwnSourceName));
wcscpy(pszTwnSourceName, L"EPSON Artisan837/PX830"); // the name of the scanner is verifyed
sInfo.uStructSize = sizeof(LTWAINSOURCE);
sInfo.pszTwainSourceName = pszTwnSourceName;
CheckRetCode(L_TwainSelectSource(hSession, &sInfo)); // No error reported here
CheckRetCode(L_TwainStartCapsNeg(hSession)); // in here I get the return value -84 which is reported as "TWAIN DS or DSM reported error, app shouldn't (no need for your app to report the error)."
// the rest of the code but we cannot get there since above code reports error
}
Can anyone tell me what I'm doing wrong? Is there a step that I'm missing here?
EditThe function L_TwainSelectSource() make no effort to make sure the supplied source is valid and does not even return an error. As result, if you set the selected source to a garbage name, it will act as if it accepted it. From that point on if you try to Get/Set anything or try to acquire an image, every function returns -84.
Thank you
Sam
To test your code, I put the main window’s handle in a global variable:
globalhWnd = hWnd;
And modified your function to use that handle like this:
void OnThreadExecute(void *)
{
...
appData.hWnd = globalhWnd; // hWnd is valid handle of my main window
...
}
Then created a thread for it from the main program like this:
globalhWnd = hWnd;
_beginthread(OnThreadExecute, 0, 0);
I tried this with 5 different Twain sources: 2 virtual and 3 physical scanners (one of them an old Epson). All 5 drivers returned SUCCESS when calling L_TwainStartCapsNeg() from within the thread.
Two possibilities come to mind:
The problem might be caused by something else in your code other than the thread function.
Or the problem could be specific to your Twain driver.
To rule out the first possibility, I suggest creating a small test project that only creates a similar thread and does nothing else and trying it with different scanners. If it causes the same problem with all scanners, send that test project (not your full application) to support#leadtools.com and our support engineers with test it for you.
If the problem only happens with a specific Twain driver, try contacting the scanner’s vendor to see if they have an updated driver.
I've been trying to call a sample driver. I have written DriverEntry method, where I initialize both the driver name and symbolic ling pointing to the driver.
// UNICODE_STRING DriverName, SymbolName; // Driver registry paths
...
// Driver Entrypoint
NTSTATUS
DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath) {
Q_UNUSED(pRegistryPath);
DbgPrintEx(0, 0, "Driver Loaded\n");
// The PsSetLoadImageNotifyRoutine routine registers a driver-supplied
// callback that is subsequently notified whenever
// an image is loaded (or mapped into memory).
PsSetLoadImageNotifyRoutine(ImageLoadCallback);
// initialize driver name
RtlInitUnicodeString(&DriverName, L"\\Device\\Explorer");
// initialize symbolic link
RtlInitUnicodeString(&SymbolName, L"\\DosDevices\\Explorer");
IoCreateDevice(pDriverObject, 0, &SymbolName, FILE_DEVICE_UNKNOWN,
FILE_DEVICE_SECURE_OPEN, FALSE, &pDeviceObject);
IoCreateSymbolicLink(&DriverName, &SymbolName);
pDriverObject->MajorFunction[IRP_MJ_CREATE] = CreateCall;
pDriverObject->MajorFunction[IRP_MJ_CLOSE] = CloseCall;
pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IoControl;
pDriverObject->DriverUnload = UnloadDriver;
pDeviceObject->Flags |= DO_DIRECT_IO;
pDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
return STATUS_SUCCESS;
}
When I load the driver up (using OSR Driver Loader, could be done using cmd also, by registering the driver as a new service), I get expected output in DebugView (sysinternals tool allowing to see kernel debug logs)
Now I needed to make sure that both the device and symlink are present in Windows Object Directories. To do that, I use WinObj (another tool from sysinternals), here is the output
What confuses me here, is that the symbolic link is in Device folder, instead of GLOBAL??.
Symbolic link in Device
Device in GLOBAL??
Now, finally, calling the driver itself. I use c++ for that purpose and this is my code,
class Test
{
public:
HANDLE hDriver; // Handle to driver
// Initializer
Test::Test(LPCSTR RegistryPath)
{
LPCSTR path = "\\\\.\\Explorer";
hDriver = CreateFileA(path, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
if (hDriver == INVALID_HANDLE_VALUE)
{
// Handle the error.
char result = GetLastError();
bool zadek = false;
}
}
The problem is that I can't get a valid handle for the driver. The value of hDriver is always either 0x00000000000000a0 or 0xffffffff, no matter the path I use. I'm using createFileA because I want to access system memory.
Is there some blatant mistake I made?
I should say it is over 8-9 year since last time I written a device driver, but what comes off the top of my head are:
You say you get 0xa0 for hDriver which is a valid handle value.
Right now, you can only use device IO control, because you only have callback for IRP_MJ_DEVICE_CONTROL.
Try L"\\??\\Explorer" or L"\\GLOBAL??\\Explorer" for symbolic link.
You need to use DriverName for IoCreateDevice.
You are passing incorrect arguments to IoCreateSymbolicLink.
So your code should become like this:
...
// initialize driver name
RtlInitUnicodeString(&DriverName, L"\\Device\\Explorer");
// initialize symbolic link
RtlInitUnicodeString(&SymbolName, L"\\??\\Explorer");
IoCreateDevice(pDriverObject, 0, &DriverName, FILE_DEVICE_UNKNOWN,
FILE_DEVICE_SECURE_OPEN, FALSE, &pDeviceObject);
IoCreateSymbolicLink(&SymbolName, &DriverName);
...
I'm creating a Windows Add/Remove Programs application in Qt 5.4 and I'm becaming crazy to solve a little "puzzle":
My application (APP_0) runs another application (APP_1) and waits for this APP_1 until it terminates.
APP_1 is an uninstaller (i.e. uninstall.exe) and I've not the source code of the APP_1, just of my Qt APP_0.
APP_1, instead of doing the uninstall job, it simply copies itself somewhere in the filesystem (I saw as Au_.exe but other apps could use different names and locations), runs this copy of itself (APP_2) and terminates.
The APP_2 has a GUI and the job I'm waiting for (uninstall) is demanded to the final user of the running APP_2.
In this situation my application (APP_0) stops waiting for APP_1 pratically immediately (because it launches APP_1 and waits for APP_1). But to work properly, obviously, I need to know instead when APP_2 is terminated...
So the question is:
is there a way (using some techniques (hooking?)) to know if and when APP_2 terminates?
Note: Consider that the standard Windows Add/Remove Programs utility does the job successfully (it seems it waits for APP_2). You can test this, for example, installing Adobe Digital Edition. Its uninstaller (uninstall.exe) copies itself into a new folder in the User_Local_Temp folder as Au_.exe, runs it and terminates. But the OS utility successfully waits for Au_.exe and only after it terminates refreshes the list of installed programs.
If this kind of technique (uninstall.exe copies itself somewhere ALWAYS with THE SAME name (Au_.exe) ) the problem could be resolved, obviously, very simply. But I don't think that the name of the copied uninstaller is always the same and also I don't like to assume things I'm not sure are real.
Many thanks in advance
Thanks to IInspectable's suggestion (see his comment... and many thanks guy!) I created a function which solves my problems! I'll share here this function which could be useful to other people with the same (or similar) problem.
For my needs, the function receives as parameter the index of the item to be uninstalled (from a QList) and gets the uninstall string (for example: C:\ProgramFiles\MyApp\uninstall.exe).
Then with this uninstall string, I'll create a process (CreateProcess) and put its handle into a Job Object, so that my function will wait for all the processes ran by this process.
The function itself is pretty simple and can be improved.
Notice that the process MUST be created with the CREATE_BREAKAWAY_FROM_JOB option, otherwise the AssignProcessToJobObject will fail with a "Access Denied" error.
void MainWindow::uniButtonClick(int idx)
{
QMessageBox::StandardButton reply;
QMessageBox::StandardButton err;
reply = QMessageBox::question(this, "Uninstall/Change", "Uninstall " +
ip[idx].displayName +"?\r\n\r\n" + ip[idx].uninstallString,
QMessageBox::Yes|QMessageBox::No);
if (reply == QMessageBox::Yes)
{
//QString s = "C:\\windows\\notepad.exe"; // Just to test Job assignment and createprocess
QString s = ip[idx].uninstallString; // the real uninstaller string
QString jobName = "MyJobObject";
try
{
PROCESS_INFORMATION ProcessInfo; //This is what we get as an [out] parameter
STARTUPINFO StartupInfo; //This is an [in] parameter
PJOBOBJECT_BASIC_PROCESS_ID_LIST pList;
HANDLE hProcess;
BOOL bJobAllEnd;
ZeroMemory(&StartupInfo, sizeof(StartupInfo));
StartupInfo.cb = sizeof StartupInfo ; //Only compulsory field
wchar_t* path;
path = (wchar_t*) malloc (sizeof(wchar_t)*s.length()+1);
s.toWCharArray(path);
path[s.length()]=0; // Null terminate the string
// Create the process with CREATE_BREAKAWAY_FROM_JOB to overcome the AccessDenied issue on AssignProcessToJobObject.
if(CreateProcess(NULL, path, NULL, NULL, FALSE, CREATE_BREAKAWAY_FROM_JOB|CREATE_SUSPENDED, NULL, NULL,&StartupInfo, &ProcessInfo))
{
pList = (PJOBOBJECT_BASIC_PROCESS_ID_LIST)GlobalAlloc(GMEM_FIXED, 10000);
HANDLE jobObj = CreateJobObject(NULL, (const wchar_t*)jobName.utf16());
if (AssignProcessToJobObject(jobObj, ProcessInfo.hProcess) != 0)
{
ResumeThread(ProcessInfo.hThread); // Process assigned to JobObjext, resume it now
do
{
QueryInformationJobObject(jobObj, JobObjectBasicProcessIdList, pList, 10000, NULL);
bJobAllEnd = TRUE;
for(DWORD i=0; i<pList->NumberOfProcessIdsInList; i++)
{
hProcess = OpenProcess(SYNCHRONIZE, FALSE, pList->ProcessIdList[i]);
if(hProcess != NULL)
{
CloseHandle(hProcess);
bJobAllEnd = FALSE;
}
}
Sleep(500);
} while(!bJobAllEnd);
}
else
qDebug() << "AssignProcess to Job failed: error = " << QString::number(GetLastError());
GlobalFree(pList);
CloseHandle(jobObj);
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
}
}
catch(QString error)
{
QMessageBox::critical(this, "File not found!", "The requested uninstaller doesn't exists", QMessageBox::Ok);
}
// refresh list
handleButton();
}
}
I am trying to open a com port for reading and writing using C++ but I can't seem to pass the first stage of actually opening it. I get an INVALID_HANDLE_VALUE on the handle
with GetLastError FILE_NOT_FOUND. I have searched around the web for a couple of days I'm fresh out of ideas. I have searched through all the questions regarding COM on this website too.
I have scanned through the existing ports (or so I believe) to get the name of the port right.
I also tried combinations of _T("COM1") with the slashes, without the slashes, with colon, without colon and without the _T
I'm using windows 7 on 64 bit machine.
this is the code i got
I'll be glad for any input on this
void SendToCom(char* data, int len)
{
DWORD cbNeeded = 0;
DWORD dwPorts = 0;
EnumPorts(NULL, 1, NULL, 0, &cbNeeded, &dwPorts);
//What will be the return value
BOOL bSuccess = FALSE;
LPCSTR COM1 ;
BYTE* pPorts = static_cast<BYTE*>(malloc(cbNeeded));
bSuccess = EnumPorts(NULL, 1, pPorts, cbNeeded, &cbNeeded, &dwPorts);
if (bSuccess){
PORT_INFO_1* pPortInfo = reinterpret_cast<PORT_INFO_1*>(pPorts);
for (DWORD i=0; i<dwPorts; i++)
{
//If it looks like "COMX" then
size_t nLen = _tcslen(pPortInfo->pName);
if (nLen > 3)
{
if ((_tcsnicmp(pPortInfo->pName, _T("COM"), 3) == 0) ){
COM1 =pPortInfo->pName;
//COM1 ="\\\\.\\COM1";
HANDLE m_hCommPort = CreateFile( COM1 ,
GENERIC_READ|GENERIC_WRITE, // access ( read and write)
0, // (share) 0:cannot share the COM port
NULL, // security (None)
OPEN_EXISTING, // creation : open_existing
FILE_FLAG_OVERLAPPED, // we want overlapped operation
NULL // no templates file for COM port...
);
if (m_hCommPort==INVALID_HANDLE_VALUE)
{
DWORD err = GetLastError();
if (err == ERROR_FILE_NOT_FOUND) {
MessageBox(hWnd,"ERROR_FILE_NOT_FOUND",NULL,MB_ABORTRETRYIGNORE);
}
else
if(err == ERROR_INVALID_NAME) {
MessageBox(hWnd,"ERROR_INVALID_NAME",NULL,MB_ABORTRETRYIGNORE);
}
else
{
MessageBox(hWnd,"unkown error",NULL,MB_ABORTRETRYIGNORE);
}
}
else{
WriteAndReadPort(m_hCommPort,data);
}
}
pPortInfo++;
}
}
}
}
The Solution is to use
The Problem is, if your port is Bigger then 9 then you have to use the Syntax
LPCWSTR szPortName = L"\\\\.\\COM11";.
If you are on Windows 10 - running all system updates might help !
I had the same issue that opening port "COM4" returned an error ERROR_FILE_NOT_FOUND. When running the program as "Administrator" it worked. Now after a updating to 1511 the program can open "COM4" even not running as "Administrator".
http://www.cplusplus.com/forum/windows/163855/
Use CreateFileA(...) instead of CreateFile(...)
ERROR_FILE_NOT_FOUND can be produced from CreateFile(L"\\\\.\\COM1", ...) and CreateFile(L"COM1:", ...) after using the Device Manager to change the assigned COM Port number. Disabling and re-enabling the device, or unplugging and reconnecting the USB adapter resolves the issue.
A useful test to confirm whether it is your program or the system is to send data to the port in command prompt. A successful test will show an empty line. A failed test will show an error message.
C:\drop>echo > \\.\COM1
The system cannot find the file specified.
C:\drop>echo > \\.\COM1
C:\drop>
I'm trying to use CreateFileMapping and OpenFileMapping to share memory between processes. This isn't working as I want it to - OpenFileMapping returns null and GetLastError is 5 - access denied. Any ideas what I am doing wrong? Name is something like MemoryTest.
Edit:
using CreateFileMapping both times I can read the data written in the other process. The reason this is a problem is that I get Error 183 - memory area already exists. However, it still returns a handle to the existing memory.
var map_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(int), name.c_str());
....
var handle = MapViewOfFile(map_handle, FILE_MAP_ALL_ACCESS , 0, 0, 0)
*handle = 10;
UnMapViewOfFile(map_handle);
getchar();
Other process:
var map_handle = OpenFileMapping(PAGE_READWRITE, false, name.c_str())
....
var handle = MapViewOfFile(map_handle, FILE_MAP_ALL_ACCESS , 0, 0, 0) //returns null
var out = *handle;
getchar();
This works for the second process though:
var map_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(int), name.c_str());
....
var handle = MapViewOfFile(map_handle, FILE_MAP_ALL_ACCESS , 0, 0, 0) //returns null
var out = *handle;
getchar();
Simple things to be aware of from the very start:
Error code 5: ERROR_ACCESS_DENIED "Access is denied."
Error code 183: ERROR_ALREADY_EXISTS "Cannot create a file when that file already exists."
ERROR_ALREADY_EXISTS is a documented behavior and is an indication of scenario that you do receive handle, but it is a handle to already existing object, not created.
The problem with not working OpenFileMapping is around its first argument: the API function expects values/flags from another enumeration, it takes FILE_MAP_* values and not PAGE_*. Incorrect argument results in failure to open you the mapping you want.
In case someone else needed, in my case the error has nothing to do with the access to the file, it's with the size provided to the CreateFileMapping, after spending hours with a similar error I'd to use a working sample posted somewhere else and line by line compare what was the difference.
If you don't know the size of the file when executing the CreateFileMapping you need to use 0, this will tell the API to use the file size of the mapped file. Most of the answers in SO around this are wrong and people is not bothering testing what is the problem about, I wasted hours reading other posts with similar suggestions.
To solve the problem the code should look like this:
var map_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 0, name.c_str());
Hope this saves hours to other fellow developers.