AddPrinterDriver fails with ERROR_ACCESS_DENIED - c++

On a few computers a call to AddPrinterDriver fails with ERROR_ACCESS_DENIED. My program is ensured to run with administrator rights, and it copies the driver DLLs into C:\WINDOWS without any errors (access denied or other).
// structure for AddPrinterDriver
DRIVER_INFO_3 di3 = { 0 };
di3.cVersion = 3;
di3.pName = _T(MyAppPrinterName) _T(" Driver");
di3.pDefaultDataType = _T("");
// path to driver dll
FilePath file1(strDriverDirectory.c_str());
di3.pDriverPath = (LPTSTR) file1.Append(MyAppPrinterDriverDllFileName).ToString();
// path to driver ui dll
FilePath file2(strDriverDirectory.c_str());
di3.pConfigFile = (LPTSTR) file2.Append(MyAppPrinterUiDllFileName).ToString();
// path to license file
FilePath file3(strDriverDirectory.c_str());
di3.pDataFile = (LPTSTR) file3.Append(_T(MyAppPrinterName) _T(".dat")).ToString();
// add driver
bResult = AddPrinterDriver(NULL, 3, (LPBYTE) &di3);
StoreLastError(_T("AddPrinterDriver"));
if (!bResult)
return FALSE;
This is my DrvPrinterEvent function:
BOOL DrvPrinterEvent(
LPWSTR lpwstrPrinterName,
INT iEvent,
DWORD dwFlags,
LPARAM lParam
)
{
return TRUE;
}

Related

Dll injection - LoadLibraryA fails

I'm trying to inject a dll into a process. The dll does nothing except return TRUE.
I attached a debugger to the process that I want to inject into and confirmed that LoadLibraryA is called correctly but returns NULL.
Now I think that this might have something to do with my dll's dependencies. So I checked them and found out that it requires vcruntime140.dll.
The process that I want to inject my dll into does not load that dll.
#include "pch.h"
extern "C" int __stdcall APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
return TRUE;
}
#include "Source.h"
const char* DllName = "InjectMe.dll";
int main()
{
DWORD processID = 0;
printf("Process ID: ");
scanf_s("%i", &processID);
HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID);
if (handle == nullptr) {
printf("Process could not be opened.");
return -1;
}
LPVOID memDllName = VirtualAllocEx(handle, nullptr, strlen(DllName) + 1, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
assert(memDllName != nullptr);
assert(WriteProcessMemory(handle, memDllName, DllName, strlen(DllName) + 1, nullptr));
LPVOID loadLibraryAddr = GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA");
assert(loadLibraryAddr != nullptr);
HANDLE thread = CreateRemoteThreadEx(handle, nullptr, 0, (LPTHREAD_START_ROUTINE)loadLibraryAddr, memDllName, CREATE_SUSPENDED, nullptr, nullptr);
assert(thread != nullptr);
ResumeThread(thread);
DWORD returnCode = WaitForSingleObject(thread, 5000);
CloseHandle(thread);
if (returnCode == WAIT_TIMEOUT) {
printf("DLL was not loaded. Thread timed out.");
return -1;
}
else if (returnCode == WAIT_OBJECT_0) {
printf("DLL was successfully injected into the process.");
}
CloseHandle(handle);
std::cin.get();
return 0;
}
You must use a full file path not a relative file path when calling LoadLibrary()
const char* DllName = "InjectMe.dll";
needs to be changed to something like this
const char* DllName = "c:\\Users\User\\Desktop\\InjectMe.dll";
Also make sure you run as administrator if OpenProcess fails or sometimes you also need to use SeDebugPrivelage
In order to test if it is a pathing issue, try the following. Keep the
const char* DllName = "InjectMe.dll";
Then put the InjectMe.dll and your .exe in the same directory and try to run your exe. If the dll is loaded successfully, then it is a pathing issue.
To work around that, you can either specify the full path like GuidedHacking said, OR you can put your InjectMe.dll in the same directory as the .vcxproj and .cpp files (not where the .sln file is)

CreateRemoteThread MessageBoxA causes remote process to crash

I made a simple program that calculates the RVA of the function MessaegBoxA in user32.dll and then adds that offset to the base loading address of the dll in the remote process's memory to get the address of the function MessageBoxA. I made a dummy program that outputs the address of the function in its memory using GetProcAddress and then implement my own function in my program to display the address it calculated for the same function in the remote process. They always match so I'm certain my function for finding the address of MessageBoxA in remote process's is not the problem.
I made a struct that contains all the necessary information and parameters needed for ThreadProc to execute MessageBoxA in the remote process once I load it using WriteProcessMemory.
typedef struct
{
typedef int (WINAPI* _MessageBoxA)(HWND, LPCSTR, LPCSTR, UINT);
_MessageBoxA MessageBoxA;
//These are the four parameters passed to MessageBoxA
HWND hwnd;
LPCSTR msg;
LPCSTR caption;
UINT mb;
}MB_DATA, *PMB_DATA;
When I try this on my own dummy program, the message box shows up but with weird text contrary to the strings I specified in the msg and caption members of MB_DATA. It says the following for the caption asic_string::erase and for the message it says u). And when I try to do this in any other process than my dummy process it crashes the remote process. I made a function to iterate through the modules that have been loaded in the process with tlhelp32 functions to make sure user32.dll is present and it is and my function for finding the address of the function in the process doesn't return NULL like it would if the dll were not present.
Here all relevant functions and my main function:
dependencies.hpp
#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>
#include <iostream>
using namespace std;
typedef struct
{
typedef int (WINAPI* _MessageBoxA)(HWND, LPCSTR, LPCSTR, UINT);
_MessageBoxA MessageBoxA;
HWND hwnd;
LPCSTR msg;
LPCSTR caption;
UINT mb;
}MB_DATA, *PMB_DATA;
//Map the dll into memory
void* GetFileImage(char path[])
{
HANDLE hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
if(hFile == INVALID_HANDLE_VALUE){printf("Error getting file handle: %d", (int)GetLastError());return NULL;}
HANDLE file_map = CreateFileMapping(hFile, NULL, PAGE_READONLY|SEC_IMAGE, 0, 0, "KernelMap");
if(file_map == INVALID_HANDLE_VALUE){printf("Error mapping file: %d", (int)GetLastError());return NULL;}
LPVOID file_image = MapViewOfFile(file_map, FILE_MAP_READ, 0, 0, 0);
if(file_image == 0){printf("Error getting mapped view: %d", (int)GetLastError());return NULL;}
return file_image;
}
//Get to the function export directory and find the offset for the specified function from the
//address in memory the dll was loaded at
DWORD_PTR RVAddress(char* image, const char* proc_name)
{
PIMAGE_DOS_HEADER pDos_hdr = (PIMAGE_DOS_HEADER)image;
PIMAGE_NT_HEADERS pNt_hdr = (PIMAGE_NT_HEADERS)(image+pDos_hdr->e_lfanew);
IMAGE_OPTIONAL_HEADER opt_hdr = pNt_hdr->OptionalHeader;
IMAGE_DATA_DIRECTORY exp_entry = opt_hdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
PIMAGE_EXPORT_DIRECTORY pExp_dir = (PIMAGE_EXPORT_DIRECTORY)(image+exp_entry.VirtualAddress);
DWORD* func_table = (DWORD*)(image+pExp_dir->AddressOfFunctions);
WORD* ord_table = (WORD*)(image+pExp_dir->AddressOfNameOrdinals);
DWORD* name_table = (DWORD*)(image+pExp_dir->AddressOfNames);
for(u_int i=0;i<pExp_dir->NumberOfNames;i++)
{
char* name = (char*)(image+name_table[i]);
if(strcmp(proc_name, name) == 0)
{
return (DWORD_PTR)func_table[ord_table[i]];
}
}
return (DWORD_PTR)0;
}
//Add the RVA returned from RVAddress to the address of the dll to find the function in the
//process memory
LPVOID GetProcAddressEx(DWORD dwPid, char* mod_path, char* function_name, char* mod_name)
{
HANDLE hSnapshot = INVALID_HANDLE_VALUE;
MODULEENTRY32 me32;
me32.dwSize = sizeof(MODULEENTRY32);
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE|TH32CS_SNAPMODULE32, dwPid);
if(hSnapshot == INVALID_HANDLE_VALUE){printf("Snapshot failed");return 0;}
if(!(Module32First(hSnapshot, &me32)))
{
printf("Mod32First failed");
return 0;
}
BOOL found = FALSE;
while(Module32Next(hSnapshot, &me32))
{
if(stricmp(me32.szModule, mod_name) == 0)
{
CloseHandle(hSnapshot);
found = TRUE;
break;
}
}
if(found == FALSE){return 0;}
DWORD_PTR RVA = (DWORD_PTR)RVAddress((char*)GetFileImage(mod_path), function_name);
LPVOID func_addr = me32.modBaseAddr+RVA;
return func_addr;
}
main.cpp
#include "dependencies.hpp"
#define FUNC_SIZE 1024
typedef int (WINAPI* _MessageBoxA)(HWND, LPCSTR, LPCSTR, UINT);
int main()
{
MB_DATA mb_data;
mb_data.hwnd = NULL;
mb_data.msg = "Hey";
mb_data.caption = "Yo";
mb_data.mb = MB_OK;
SIZE_T nBytes = 0;
char proc_path[MAX_PATH];
char kernel_path[MAX_PATH];
char user32_path[MAX_PATH];
//get full path to the current process and store it in proc_path
GetModuleFileName(GetModuleHandle(NULL), proc_path, MAX_PATH);
//get full path to kernel32.dll and store it in kernel_path
GetModuleFileName(GetModuleHandle("kernel32.dll"), kernel_path, MAX_PATH);
//get full path to user3.dll and store it in user32_path
GetModuleFileName(GetModuleHandle("user32.dll"), user32_path, MAX_PATH);
//show all processes running and their PID's
system("tasklist");
DWORD dwPid = 0;
printf("PID: ");
scanf("%lu", &dwPid);
//if dwPid is 0 assign it the pid of the current process
if(dwPid == 0)
{
dwPid = GetCurrentProcessId();
}
//Get a handle to the process with all access rights
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
//make sure the handle is valid
if(hProc == NULL){printf("Error obtaining handle to process: %lu", GetLastError());return 1;}
//Get the address of the function in the remote process
LPVOID _MessageBoxA1 = GetProcAddressEx(dwPid, user32_path, (char*)"MessageBoxA", (char*)"user32.dll");
//assign the pointer to the address to the member MessageBoxA of the MB_DATA structure
mb_data.MessageBoxA = (_MessageBoxA)_MessageBoxA1;
//allocate 2mb for our the ThreadProc callback function and the MB_DATA structure
LPVOID lpBase = VirtualAllocEx(hProc, NULL, 2048, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE);
//did the allocation work
if(lpBase == NULL){printf("Error allocating space: %lu", GetLastError());return 1;}
//so I can check what was written with CheatEngine
cout << "Base address of memory allocated in remote process: " << lpBase << endl;
//Write the function into memory
if(WriteProcessMemory(hProc, lpBase, (LPVOID)ThreadProc, FUNC_SIZE, &nBytes) == 0)
{
printf("Error writing function to process");
return 1;
}
//the address the space left after having written ThreadProc into memory
LPVOID lpBuffer = lpBase+FUNC_SIZE;
//Write the MB_DATA structure into the memory of the remote process
if(WriteProcessMemory(hProc, lpBuffer, &mb_data, sizeof(MB_DATA), &nBytes) == 0)
{
printf("Error writing buffer to process");
}
//Run the ThreadProc function passing the MB_DATA structure to it as its lpParam parameter
if(CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)lpBase, lpBuffer, 0, NULL) == NULL)
{
printf("Error creating remote thread: %lu", GetLastError());
return 1;
}
//print a list of all the dll's being used by the process
EnumerateModules(dwPid);
system("pause");
return 0;
}
Any help would be greatly appreciated. Thank you very much! :)
mb_data.msg and mb_data.caption point to what in the another process ?? this is already enough for crash error. what is in ThreadProc not visible, but i not sure that it have no relocs. really ThreadProc must be member function of MB_DATA and access only it members. from you post obviously that you not debug remote process at injection time. also obviously that task is over your current level

How to use GetMonitorCapabilities and GetMonitorBrightness functions

I'm trying to adjust my monitor brightness programmatically. After little bit of research, I came up with this link, and wrote the following code (mostly copy paste from other links that one lead me).
#include "Windows.h"
#include "WinUser.h"
#include "PhysicalMonitorEnumerationAPI.h"
#include "HighLevelMonitorConfigurationAPI.h"
#include <strsafe.h>
void ShowError(LPTSTR lpszFunction);
int main()
{
HMONITOR hMonitor = NULL;
DWORD cPhysicalMonitors;
LPPHYSICAL_MONITOR pPhysicalMonitors = NULL;
HWND hWnd = GetDesktopWindow();
// Get the monitor handle.
hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTOPRIMARY);
// Get the number of physical monitors.
BOOL bSuccess = GetNumberOfPhysicalMonitorsFromHMONITOR(hMonitor, &cPhysicalMonitors);
if (bSuccess)
{
// Allocate the array of PHYSICAL_MONITOR structures.
pPhysicalMonitors = (LPPHYSICAL_MONITOR)malloc(cPhysicalMonitors* sizeof(PHYSICAL_MONITOR));
if (pPhysicalMonitors != NULL)
{
// Get the array.
bSuccess = GetPhysicalMonitorsFromHMONITOR( hMonitor, cPhysicalMonitors, pPhysicalMonitors);
// Get physical monitor handle.
HANDLE hPhysicalMonitor = pPhysicalMonitors[0].hPhysicalMonitor;
LPDWORD pdwMinimumBrightness = NULL;
LPDWORD pdwCurrentBrightness = NULL;
LPDWORD pdwMaximumBrightness = NULL;
bSuccess = GetMonitorBrightness(hPhysicalMonitor, pdwMinimumBrightness, pdwCurrentBrightness, pdwMaximumBrightness);
if (bSuccess == FALSE)
{
ShowError(TEXT("GetMonitorBrightness"));
}
// Close the monitor handles.
bSuccess = DestroyPhysicalMonitors(cPhysicalMonitors, pPhysicalMonitors);
// Free the array.
free(pPhysicalMonitors);
}
}
return 0;
}
void ShowError(LPTSTR lpszFunction)
{
// Retrieve the system error message for the last-error code
LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );
// Display the error message and exit the process
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
StringCchPrintf((LPTSTR)lpDisplayBuf,
LocalSize(lpDisplayBuf) / sizeof(TCHAR),
TEXT("%s failed with error %d: %s"),
lpszFunction, dw, lpMsgBuf);
MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
}
This code crashes when executing this line:
bSuccess = GetMonitorBrightness(hPhysicalMonitor, pdwMinimumBrightness, pdwCurrentBrightness, pdwMaximumBrightness);
According to documentation, that function might not be supported.
If this function is supported, the GetMonitorCapabilities function
returns the MC_CAPS_BRIGHTNESS flag.
So, in order to check that, I add the following block to my code, just before calling GetMonitorBrightness.
LPDWORD pdwMonitorCapabilities = NULL;
LPDWORD pdwSupportedColorTemperatures = NULL;
bSuccess = GetMonitorCapabilities(hPhysicalMonitor, pdwMonitorCapabilities, pdwSupportedColorTemperatures);
if (bSuccess == FALSE)
{
ShowError(TEXT("GetMonitorCapabilities"));
}
Unfortunately after I added that block, I received the following error:
Again, according to documentation, GetMonitorCapabilities function fails if the monitor does not support DDC/CI.
Then I checked if my monitor is supporting DDC/CI, and found out that it is. Moreover, when I manually disable DDC/CI support from monitor settings, previous error message switches to following one, so now I'm pretty sure my monitor has DDC/CI support.
I feel like I'm doing everything correct but apparently I'm not. In short, GetMonitorCapabilities function fails with an error message that I can't give any meaning, and GetMonitorBrightness function gets crashed.
Notes:
My monitor is Dell U2713H.
I'm on 64 bit Windows 7.
I'm using Microsoft Visual C++ Compiler 12.0 (x86)
Your calls to GetMonitorBrightness() and GetMonitorCapabilities() are wrong. You are passing NULL pointers, but they expect pointers to actual DWORD variables instead:
DWORD dwMinimumBrightness = 0;
DWORD dwCurrentBrightness = 0;
DWORD dwMaximumBrightness = 0;
bSuccess = GetMonitorBrightness(hPhysicalMonitor, &dwMinimumBrightness, &dwCurrentBrightness, &dwMaximumBrightness);
DWORD dwMonitorCapabilities = 0;
DWORD dwSupportedColorTemperatures = 0;
bSuccess = GetMonitorCapabilities(hPhysicalMonitor, &dwMonitorCapabilities, &dwSupportedColorTemperatures);

SHGetFileInfo not return the icon location

I try to extract the icon of file and return it to GetIconLocation of shell extension.
in general I change the icons of files (te.docx.xx) with the extension of xx and returns the icon of file without the xx. (for this I cretae temp file in temp directory with the original extension e.g te.docx)
my operating system is windows 7 x64.
my code is:
STDMETHODIMP CTxtIconShlExt::GetIconLocation (
UINT uFlags, LPTSTR szIconFile, UINT cchMax,
int* piIndex, UINT* pwFlags )
{
DWORD dwFileSizeLo, dwFileSizeHi;
DWORDLONG qwSize;
HANDLE hFile;
OutputDebugStringW(L"Hello world, from GetIconLocation !");
std::string strFilePath;
std::string tempFolder="c:\\.tmp";
std::string tempFile="tmpfile";
std::string fileWithOutDN;
SHFILEINFO retShFileInfo;
for(int i = 0; m_szFilename[i] != 0; i++)
{
strFilePath += m_szFilename[i];
}
fileWithOutDN= strFilePath.substr(0,strFilePath.size()-3 );
std::string extension = fileWithOutDN.substr(fileWithOutDN.find_last_of("."));
CreateDirectory(tempFolder.c_str(),NULL);
tempFile=tempFolder+"\\"+tempFile+extension;
GetFileAttributes(tempFile.c_str()); // from winbase.h
if(INVALID_FILE_ATTRIBUTES == GetFileAttributes(tempFile.c_str()) && GetLastError()==ERROR_FILE_NOT_FOUND)
{
//File not found
HANDLE h = CreateFile(tempFile.c_str(), // name of the file
GENERIC_WRITE, // open for writing
0, // sharing mode, none in this case
0, // use default security descriptor
CREATE_ALWAYS, // overwrite if exists
FILE_ATTRIBUTE_NORMAL,
0);
if (h)
{
CloseHandle(h);
}else
{
return S_FALSE; //faild to create file
}
}
ZeroMemory(&retShFileInfo, sizeof(SHFILEINFO));
CoInitialize(NULL);
SHGetFileInfo(tempFile.c_str(),256,&retShFileInfo,sizeof(SHFILEINFO),SHGFI_ICON | SHGFI_LARGEICON);
lstrcpyn ( szIconFile, retShFileInfo.szDisplayName, cchMax );
*piIndex = retShFileInfo.iIcon;
*pwFlags = 0;
return S_OK;
my problem is that the retShFileInfo.szDisplayName return an empty array (all items are zero), it should return full path to icon location.
I try to play with the combination of the flags but nothing was helpful

Installing a driver programmatically using INF file c++

Could someone here please let me know how to install 3rd party device drivers
programmatically if all the required files i.e. inf file, .sys etc are provided. The
minimum operating system this solution SHOULD work on is Windows2000.
I tried copying the .inf file into the Win Folder\INF folder and the sys file
into the Win folder\system32\drivers but each time plug in the device, windows
pops up Found New Hardware user interface which is what i am trying to avoid.
Below is something i tried but the function returns error 87 (The parameter is incorrect).
HINF HInf;
UINT ErrorLine;
BOOL bRes = FALSE;
PBOOL FileWasInUse = FALSE;
LPCSTR szSourceFileName = _T("C:\\Drivers_HypercomP1320\\hypvcpusb.inf");
LPCSTR szInfFileName = _T("hypvcpusb.inf");
PVOID Context = NULL;
HInf = SetupOpenInfFile ( szSourceFileName, NULL, INF_STYLE_WIN4, &ErrorLine);
LPCSTR SourceFile = ("hypvcp.sys");
LPCSTR SourcePathRoot = _T("C:\\Drivers_HypercomP1320");
LPCSTR DestinationName = _T("C:\\WINDOWS\\system32\\drivers\\hypvcp.sys");
bRes = SetupInstallFileEx ( HInf, NULL, SourceFile, SourcePathRoot, DestinationName, SP_COPY_FORCE_IN_USE,
(PSP_FILE_CALLBACK)CopyMsgHandler, Context, FileWasInUse);
DWORD dwVal = GetLastError();
SetupCloseInfFile(HInf);
// Callback function
UINT CopyMsgHandler (UINT Context, UINT Notification,UINT_PTR Param1, UINT_PTR Param2)
{
UINT rtnValue = NO_ERROR;
return rtnValue;
}
Thanks.
Yes. You start by calling
SC_HANDLE manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (manager)
{
wprintf(L"Opened SC Manager\n");
}
else
{
wprintf(L"Open SC Manager failed\n");
return;
}
Then having the .inf file stored in szInfFileName you call:
HInf = SetupOpenInfFile(szInfFileName.c_str(), NULL, INF_STYLE_WIN4, &ErrorLine);
Then you call
if (SetupInstallFileEx(HInf, NULL, SourceFile, SourcePathRoot, DestinationName, SP_COPY_NEWER_OR_SAME, NULL, Context, &FileWasInUse) == NULL)
SourceFile = the driver file name (ending with .sys)
SourcePathRoot = the location of the driver file (would be the path where your program runs from)
DestinationName = full path of the driver to be installed (for example:
c:\windows\system32\drivers\yourdriver.sys
Then there is the Registry. You need to add an entry for your driver under
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\
this entry (key) should have:
Driver name, display name, description, ErrorControl and Group.
Next step, you start the driver using:
SC_HANDLE service = CreateService(manager,
DRIVER_NAME,
DRIVER_NAME,
SERVICE_ALL_ACCESS,
SERVICE_KERNEL_DRIVER,
SERVICE_AUTO_START,
SERVICE_ERROR_NORMAL,
KeyName,
NULL, NULL, NULL, NULL, NULL);
When KeyName is the driver's path under System32 as appeared in the Registry entry. For example:
system32\drivers\yourdriver.sys
Last step:
BOOL result = StartService(service, 0, NULL);
and cleaning up
CloseServiceHandle(manager)
You can use InstallHinfSection.
It might be your use of
PBOOL FileWasInUse = FALSE;
. You should change it in
BOOL FileWasInUse = FALSE;
and use it in the function-call with &FileWasInUse (note the &-character).