I have a driver code which works good on 32 bit. On 64 bit i compiled it and also digitally signed it. The driver loads but fails to work properly. The main functionality of the driver to to register process creation and termination to my program in call back. So i have two IOCTL working. The code is as follows..
NTSTATUS DispatchIoctl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
PDEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
PPROCESS_CALLBACK_INFO pProcCallbackInfo;
//
// These IOCTL handlers are the set and get interfaces between
// the driver and the user mode app
//
switch(irpStack->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_PROCOBSRV_ACTIVATE_MONITORING:
{
ntStatus = ActivateMonitoringHanlder( Irp );
break;
}
case IOCTL_PROCOBSRV_GET_PROCINFO:
{
if (irpStack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(PROCESS_CALLBACK_INFO))
{
pProcCallbackInfo = Irp->AssociatedIrp.SystemBuffer;
pProcCallbackInfo->hParentId = extension->hParentId;
pProcCallbackInfo->hProcessId = extension->hProcessId;
pProcCallbackInfo->bCreate = extension->bCreate;
ntStatus = STATUS_SUCCESS;
}
break;
}
default:
break;
}
Irp->IoStatus.Status = ntStatus;
//
// Set number of bytes to copy back to user-mode
//
if(ntStatus == STATUS_SUCCESS)
Irp->IoStatus.Information = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
else
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return ntStatus;
}
when i call
bReturnCode = ::DeviceIoControl(
hDriverFile,
IOCTL_PROCOBSRV_ACTIVATE_MONITORING,
&activateInfo,
sizeof(activateInfo),
NULL,
0,
&dwBytesReturned,
NULL
);
The code succeeds but when i call
bReturnCode = ::DeviceIoControl(
m_hDriverFile,
IOCTL_PROCOBSRV_GET_PROCINFO,
0,
0,
&callbackInfo, sizeof(callbackInfo),
&dwBytesReturned,
&ov
);
getLastError returns 31. Can anyone help me with this. Is it a problem of IOCTL structure with 64 bit? Please help me find a solution to this. Thanks..
If you don't have driver debugging experience, try to diagnose this problem using trace. Add KdPrint lines to your code in all places where it is necessary, for example:
case IOCTL_PROCOBSRV_GET_PROCINFO:
{
KdPrint(("IOCTL_PROCOBSRV_GET_PROCINFO. OutputBufferLength = %d\n", irpStack->Parameters.DeviceIoControl.OutputBufferLength));
KdPrint(("sizeof(PROCESS_CALLBACK_INFO) = %d\n", sizeof(PROCESS_CALLBACK_INFO)));
if (irpStack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(PROCESS_CALLBACK_INFO))
{
pProcCallbackInfo = Irp->AssociatedIrp.SystemBuffer;
pProcCallbackInfo->hParentId = extension->hParentId;
pProcCallbackInfo->hProcessId = extension->hProcessId;
pProcCallbackInfo->bCreate = extension->bCreate;
KdPrint(("IOCTL_PROCOBSRV_GET_PROCINFO. STATUS_SUCCESS\n"));
ntStatus = STATUS_SUCCESS;
}
break;
}
This is just a sample, add KdPrint lines to all places to understand what happens. Build the driver in checked configuration, install it and run your program. See KdPrint output in DbgView program, with Caprure Kernel option enabled.
You can use DbgPrint instead of KdPrint, in this case it will work also in free driver configuration.
Edit:
How is PROCESS_CALLBACK_INFO defined? What is client code that calls the driver? Is client compiled as 32 or 64 bit? Passing a structure between client and driver, ensure that it doesn't contain bitness-dependent fields (has the same size when compiled both in 32 and 64 bit), and structure padding is the same.
Not too much information here, but you could always check that the size of your own defined structures are the same in the compiled user-mode client and the driver when running 64-bit. There might be packing/alignment issues that can be fixed by using #pragma pack (or whatever your compiler supports) for your structs.
As a general rule also try to set the status code to a more specific value on detected problems, such as e.g. STATUS_BUFFER_TOO_SMALL if you detect that a passed buffer is too small. I suspect that this isn't the actual issue here when using the IOCTL_PROCOBSRV_GET_PROCINFO IOCTL as you are getting back Win32 error 31, but it helps clients to troubleshoot their problems in general.
Update: As the differences actually seem to mismatch judging from your comments, try to surround the struct definitions with packing and then make sure to recompile both the client and driver. Example if you are using the Visual C++ compiler:
#pragma pack(push, 8) // Save current packing and set to 8-byte
typedef struct _PROCESS_CALLBACK_INFO
{
// Whatever ...
} PROCESS_CALLBACK_INFO;
#pragma pack(pop) // Restore previous packing
I found the answer. Thanks to the debugging. As mention earlier the outputBufferLength was less than the structure length due to which the driver was failing.
The outputBufferLength depands on the size of the struct you pass while calling the following function..
bReturnCode = ::DeviceIoControl(
m_hDriverFile,
IOCTL_PROCOBSRV_GET_PROCINFO,
0,
0,
&callbackInfo, sizeof(callbackInfo),
&dwBytesReturned,
&ov
);
So callbackInfo size was 12 so the outputBufferLength = 12. The structure callbackInfo has DWORD datamember which for 64 bit had to be DWORD64. When i changed the datatype of the member in the structure and then called the DeviceIOControl function , the driver worked great and the outputBufferLength was = 24 as expected. Thanks for all your help.
Related
I have a modified driver and must be installed when driver signing is disabled, so I want to detect this status to remind users to reboot to SafeMode.
I had tried this command : Bcdedit.exe -set TESTSIGNING OFF, but failed and prompted
An error has occurred setting the element data.
The value is protected by Secure Boot policy and cannot be modified or deleted.
Umm..is there any way can do it?
————————
PS:
In fact, my laptop model is MSI GS70 2PE. I don't think it's a cheap one even the lastest published GS73 cannot supported full win10 gestures.And it supports Windows10 but MSI truly doesn't release the lastest driver.If I only modified and use it by myself, nothing worth mentioning.However, I want to share it in forum to help other general users to use.
Am I doing something wrong? Cannot understanding why someone talks about other things.
Use the following code to detect whether or not TESTSIGNING is enabled:
#include <Winternl.h>
#pragma comment(lib, "ntdll.lib")
//Check if testsigning is enabled
SYSTEM_CODEINTEGRITY_INFORMATION sci = {0};
ULONG dwcbSz = 0;
sci.Length = sizeof(sci);
if(NtQuerySystemInformation(
/*SystemCodeIntegrityInformation*/ (SYSTEM_INFORMATION_CLASS)0x67,
&sci,
sizeof(sci),
&dwcbSz) >= 0 &&
dwcbSz == sizeof(sci))
{
BOOL bTestsigningEnabled = !!(sci.CodeIntegrityOptions & /*CODEINTEGRITY_OPTION_TESTSIGN*/ 0x2);
//Note that testsigning will play no role if bit CODEINTEGRITY_OPTION_ENABLED (or 0x1) is not set in sci.CodeIntegrityOptions
}
I would rather wrap this into a nicer function like so:
bool IsSystemCodeIntegrityEnabled() {
typedef NTSTATUS(__stdcall* td_NtQuerySystemInformation)(
ULONG SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
);
struct SYSTEM_CODEINTEGRITY_INFORMATION {
ULONG Length;
ULONG CodeIntegrityOptions;
};
static td_NtQuerySystemInformation NtQuerySystemInformation = (td_NtQuerySystemInformation)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQuerySystemInformation");
SYSTEM_CODEINTEGRITY_INFORMATION Integrity ={ sizeof(SYSTEM_CODEINTEGRITY_INFORMATION), 0 };
NTSTATUS status = NtQuerySystemInformation(103, &Integrity, sizeof(Integrity), NULL);
return (NT_SUCCESS(status) && (Integrity.CodeIntegrityOptions & 1));
}
I need access to the ACPI tables from my driver so AuxKlibEnumerateSystemFirmwareTables and AuxKlibGetSystemFirmwareTable are clearly the functions I need.
I call AuxKlibInitialize to start with to initialize the Auxiliary Kernel-Mode Library.
What I really want is the "MCFG" table so I started by trying this.
NTSTATUS ntStatus = AuxKlibInitialize();
const char kMcfgHeaderSignature[] = "MCFG";
// Table name is passed little-endian order
ULONG headerSignature = 0;
headerSignature += kMcfgHeaderSignature[3] << 24;
headerSignature += kMcfgHeaderSignature[2] << 16;
headerSignature += kMcfgHeaderSignature[1] << 8;
headerSignature += kMcfgHeaderSignature[0];
ULONG tableSize = 0;
ntStatus = AuxKlibGetSystemFirmwareTable(
'ACPI',
headerSignature,
NULL, // No buffer, just get the size for now.
0, // (No buffer size)
&tableSize
);
unsigned char * table = new unsigned char[tableSize];
ntStatus = AuxKlibGetSystemFirmwareTable(
'ACPI',
headerSignature,
table,
tableSize,
NULL // Don't need the size back.
);
delete[] table;
Walking through the code in a debugger, AuxKlibInitialize succeeds but both calls to AuxKlibGetSystemFirmwareTable return 0xC0000002 which is STATUS_NOT_IMPLEMENTED.
I figured there may be an issue with the specific table I need so I tried to get a list of the tables doing this.
NTSTATUS ntStatus = AuxKlibInitialize();
const char kMcfgHeaderSignature[] = "MCFG";
// Table name is passed little-endian order
ULONG headerSignature = 0;
headerSignature += kMcfgHeaderSignature[3] << 24;
headerSignature += kMcfgHeaderSignature[2] << 16;
headerSignature += kMcfgHeaderSignature[1] << 8;
headerSignature += kMcfgHeaderSignature[0];
ULONG sigListSize = 0;
ntStatus = AuxKlibEnumerateSystemFirmwareTables(
'ACPI',
NULL,
0,
&sigListSize
);
uint32_t * sigList = new uint32_t[sigListSize/4];
ntStatus = AuxKlibEnumerateSystemFirmwareTables(
'ACPI',
reinterpret_cast<void*>(sigList),
sigListSize,
NULL
);
delete[] sigList;
Again I got STATUS_NOT_IMPLEMENTED this time from the AuxKlibEnumerateSystemFirmwareTables calls.
I looked around quite a bit to figure out why I could be getting a not implemented error from Windows but found no references of this error from these functions anywhere. It seems to be implemented in the 8.0 DDK and later and supported by Windows Vista and later. I am using the Win 10 DDK and testing on a Win 10 system.
Why is the Auxiliary Kernel-Mode Library returning not implemented errors when getting ACPI information?
UPDATE
This got a lot more strange when I reconfigured the hardware. Now it seems to only return the error when a specific PCIe card is in the system. No idea why Windows would say the function is not implemented depending on what hardware is in the system.
UPDATE 2
It now seems this is a timing issue. Even if I have the card that exposes the failure in the system, if I force the code to run after the system is fully booted it works. So it seems that with some hardware configurations I end up calling the Auxiliary Kernel-Mode Library too early in boot. This is really frustrating because there is no information from MS about when you can safely start calling the Auxiliary Kernel-Mode Library.
I use the following code to verify that a serial port name is valid on the computer:
typedef std::pair<StrAsc const, bool> port_pair_type;
typedef std::list<port_pair_type> port_pairs_type;
port_pairs_type pairs;
StrBin config_buffer;
config_buffer.fill(0,sizeof(COMMCONFIG));
while(!pairs.empty())
{
port_pair_type pair(pairs.front());
pairs.pop_front();
if(!pair.second)
{
// we need to get the default configuration for the port. This may
// require some fudging on the buffer size. That is why two calls
// are being made.
uint4 config_size = config_buffer.length();
StrUni temp(pair.first);
COMMCONFIG *config(reinterpret_cast<COMMCONFIG *>(config_buffer.getContents_writable()));
config->dwSize = sizeof(COMMCONFIG);
rcd = GetDefaultCommConfigW(
temp.c_str(), config, &config_size);
if(!rcd && config_buffer.length() < config_size)
{
config_buffer.fill(0, config_size);
config = reinterpret_cast<COMMCONFIG *>(config_buffer.getContents_writable());
config->dwSize = sizeof(COMMCONFIG);
rcd = GetDefaultCommConfigW(
temp.c_str(),
reinterpret_cast<COMMCONFIG *>(config_buffer.getContents_writable()),
&config_size);
}
// if the call succeeded, we can go ahead and look at the
// configuration structure.
if(rcd)
{
COMMCONFIG const *config = reinterpret_cast<COMMCONFIG const *>(
config_buffer.getContents());
if(config->dwProviderSubType == PST_RS232)
port_names.push_back(pair.first);
}
else
{
OsException error("GetDefaultCommConfig Failed");
trace("\"%s\"", error.what());
}
}
else
port_names.push_back(pair.first);
}
On windows 10, when trying to confirm a serial port that uses usbser.sys, the call to GetDefaultCommConfig() is failing and the error code returned by GetLastError() is 87 (invalid parameter). As I am aware, the usbser.sys driver has been rewritten on windows 10 and I suspect that this is a problem with that driver. Does anyone else have an idea of what might be going wrong?
This had been a bug in usbser.sys and was fixed with the Windows 10 Update KB3124262 from 27.01.2016.
The Microsoft employee explained:
The COM port name in the HKLM\HARDWARE\DEVICEMAP\SERIALCOMM registry is not NULL terminated.
Related discussion on MSDN
Because of Windows 10's update policies this issue should not appear in the future anymore.
When you call GetDefaultCommConfigW the second time you probably need to config->dwSize to the new size the structure. Eg:
config->dwSize = config_size;
I just asked a question earlier today because I wanted to run an executable file that takes parameters from my C++ code and it wasn't working.
It works now, but I'm still having problems since I thought I was going the right way about this, but it seems like what I want to accomplish can't be done the way I'm approaching it...
This is my corrected code from my other question:
#include <stdlib.h>
#include <conio.h>
int main (){
system("\"\"C:\\Users\\Adam\\Desktop\\pdftotext\" -layout \"C:\\Users\\Adam\\Desktop\\week 4.pdf\"\"");
_getch();
}
which is me running "pdftotext -layout myfile.pdf" as if I was running it from a CMD window.
The thing is, I don't actually want the cmd to show up since I have a GUI interface on top of it and I want to display a nicer progress bar instead of seeing the windows pop-up for every file I need to parse.
I looked around and either I don't understand what I'm reading since I'm relatively new to C++, or I just didn't find what I was looking for. I found that using CreateProcess, I should be able to do this, but after copying some code I found somewhere else, the cmd window pops-up anyway.
I'd like it if someone could give me the name of a function I could use to accomplish something like this or if someone could give some example code for this small case in the code I posted since I'm not sure I understand everything as I should, being new to C++ and all.
Edit: As requested in a comment, the code for CreateProcess that I tried is what I found at this url:
http://www.goffconcepts.com/techarticles/development/cpp/createprocess.html
Which is (with my own parameters that I think should go there):
#include <windows.h>
#include <string>
#include <conio.h>
size_t ExecuteProcess(std::wstring FullPathToExe, std::wstring Parameters, size_t SecondsToWait)
{
size_t iMyCounter = 0, iReturnVal = 0, iPos = 0;
DWORD dwExitCode = 0;
std::wstring sTempStr = L"";
/* - NOTE - You should check here to see if the exe even exists */
/* Add a space to the beginning of the Parameters */
if (Parameters.size() != 0)
{
if (Parameters[0] != L' ')
{
Parameters.insert(0,L" ");
}
}
/* The first parameter needs to be the exe itself */
sTempStr = FullPathToExe;
iPos = sTempStr.find_last_of(L"\\");
sTempStr.erase(0, iPos +1);
Parameters = sTempStr.append(Parameters);
/* CreateProcessW can modify Parameters thus we allocate needed memory */
wchar_t * pwszParam = new wchar_t[Parameters.size() + 1];
if (pwszParam == 0)
{
return 1;
}
const wchar_t* pchrTemp = Parameters.c_str();
wcscpy_s(pwszParam, Parameters.size() + 1, pchrTemp);
/* CreateProcess API initialization */
STARTUPINFOW siStartupInfo;
PROCESS_INFORMATION piProcessInfo;
memset(&siStartupInfo, 0, sizeof(siStartupInfo));
memset(&piProcessInfo, 0, sizeof(piProcessInfo));
siStartupInfo.cb = sizeof(siStartupInfo);
if (CreateProcessW(const_cast<LPCWSTR>(FullPathToExe.c_str()),
pwszParam, 0, 0, false,
CREATE_DEFAULT_ERROR_MODE, 0, 0,
&siStartupInfo, &piProcessInfo) != false)
{
/* Watch the process. */
dwExitCode = WaitForSingleObject(piProcessInfo.hProcess, (SecondsToWait * 1000));
}
else
{
/* CreateProcess failed */
iReturnVal = GetLastError();
}
/* Free memory */
delete[]pwszParam;
pwszParam = 0;
/* Release handles */
CloseHandle(piProcessInfo.hProcess);
CloseHandle(piProcessInfo.hThread);
return iReturnVal;
}
int main(void){
ExecuteProcess(L"C:\\Users\\Adam\\Desktop\\pdftotext", L"-layout \"C:\\Users\\Adam\\Desktop\\week 4.pdf\"", 0);
_getch();
}
I'm a little bit overwhelmed since it uses some things I've never used before, but I think I understand the core (keyword: think). It doesn't solve my problem, though, because the cmd shows up and by retesting it I actually noticed that the cmd doesn't even run the .exe and doesn't give me an error message.
I hope this bit of code helps... I didn't want to look into it further since it seemed like I wasn't even going in the right direction.
Use CreateProcess instead of system.
--EDIT--
the code for CreateProcess that I tried is what I found at this url:
The code is a mess, I'd advise to avoid that url in future.
At the end of "CreateProcess" article is a link named "Creating Processes", which contains simpler example that is easier to read. Use it as a starting point.
After adding the following lines for siStartupInfo, cmd window won't pop up any more with my own test *.exe.
siStartupInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
siStartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
siStartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
siStartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
siStartupInfo.wShowWindow = SW_HIDE;
But I have another problem. As I try to run some other executable, whose command line would be
TEST.exe <input-file> output-file
in a cmd window, WaitForSingleObject() return 258, and GetLastError() return 1813 ("The specified resource type cannot be found in the image file.").
See system() and CreateProcess() / CreateProcessW() for more details.
Any ideas would be highly appreciated!
The only way I found how to execute an external program is:
system("start C:\file path\ file");
The only problem is that the file or directory can't have spaces.
I have the following C++ code and when I run the program sometimes it works and sometimes it does not!
I think the problem occurs when I try to open the serial port while there is data left to be read.
Sometimes after running this program, it makes Windows XP restart unexpectedly! It does not Blue Screen, it justs restarts.
I am using Visual Studio 2010 to compile it.
main()
{
while(0) { // BIG FAT WARNING: MIGHT SUDDEN REBOOT YOUR MACHINE IF ENABLED
read_from_serial(_data);
}
}
bool read_from_serial(octed_string &_data)
{
HANDLE hSerial;
hSerial = CreateFile(TEXT("COM2"),
GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
if (hSerial == INVALID_HANDLE_VALUE)
{
if (GetLastError() == ERROR_FILE_NOT_FOUND)
{
cout << "1:";
return false;
//serialportdoesnotexist.Informuser.
}
cout << "2:";
return false;
//someothererroroccurred.Informuser.
}
DCB dcbSerialParams = {0};
dcbSerialParams.DCBlength=sizeof(dcbSerialParams);
if(!GetCommState(hSerial,&dcbSerialParams))
{
cout<<"3:";
return false;
//errorgettingstate
}
dcbSerialParams.BaudRate=CBR_9600;
dcbSerialParams.ByteSize=7;
dcbSerialParams.StopBits=ONESTOPBIT;
dcbSerialParams.Parity=EVENPARITY;
if (!SetCommState(hSerial,&dcbSerialParams))
{
cout<<"4:";
return false;
//errorsettingserialportstate
}
COMMTIMEOUTS timeouts={0};
timeouts.ReadIntervalTimeout=50;
timeouts.ReadTotalTimeoutConstant=10;
timeouts.ReadTotalTimeoutMultiplier=10;
timeouts.WriteTotalTimeoutConstant=50;
timeouts.WriteTotalTimeoutMultiplier=10;
if (!SetCommTimeouts(hSerial,&timeouts))
{
cout<<"5:";
return false;
//erroroccureed.Informuser
}
const int n=1;
DWORD dwBytesRead=0;
char_t tmp_receive[255]={0};
char_t buff[255];
int len=255;
if (!ReadFile(hSerial,tmp_receive,len,&dwBytesRead,NULL))
{
cout<<"6:";
CloseHandle(hSerial);
return false;
}
CloseHandle(hSerial);
tmp_receive[dwBytesRead+1]=END_OF_STRING;
string tmp_buff_str=tmp_receive;
_data.append(tmp_buff_str);
return true;
}
Cause
I have a suspicion that your program is crashing on this line
tmp_receive[dwBytesRead+1]=END_OF_STRING;
You defined the tmp_receive array with 255 elements, which makes the possible indexes 0 to 254. You then initialized len to 255. If there are 255 bytes available to read on the call to ReadFile(...), then dwBytesRead will be equal to 255 and the line I mentioned above will effectively be as follows, and would mean you're attempting to write to memory outside of the scope of the tmp_receive array.
tmp_receive[256] = END_OF_STRING;
As for the rebooting, I don't know for sure, but maybe your program is causing a system crash when it attempts to write to invalid memory and you have Windows XP configured to reboot instead of displaying a BSOD.
Solutions
In order to keep your program from crashing I see that you have 2 options. I can't say which one is better since I don't know what the format of the data you're expecting to receive is, so you will have to analyize the outcomes of each option and decide for yourself.
Option #1
Use an element count of 257 when defining the tmp_receive array.
Option #2
Subtract 2 from len when making the call to ReadFile(...)
if (!ReadFile(hSerial,tmp_receive,len-2,&dwBytesRead,NULL))
Additional Information
Have a look at the MSDN documentation on ReadFile(...) for more information on the behaviour of the ReadFile(...) Windows API.
If you would like to learn more about how strings are stored in memory, I would suggest having a look at the Character Sequences article on www.cplusplus.com.