Loading DLL in windows kernel mode driver's address space - c++

How to load a dll into a kernel mode driver's address space ?
In user mode we have LoadLibraryA( ) to load a dll. I'm looking for kernel mode windows API to load the dll in driver's address space.
I'm trying to do the following,
Below is the user space code
HMODULE hNtdll = LoadLibraryA("ntdll.dll");
if (hNtdll) {
NtAlpcCreatePort = (PNtAlpcCreatePort)GetProcAddress(hNtdll, "NtAlpcCreatePort");
}
Please suggest kernel mode equivalent of above piece of code.
For GetProcAddress i was able to find the kernel mode equivalent MmGetSystemRoutineAddress( ). But i couldn't find the LoadLibraryA( ) equivalent in kernel mode.

You can't load user-land libraries to kernel-land. They simply wouldn't work.

Related

How to resolve circular dependency of a forwarded WinAPI?

I'm trying to find a way to resolve a memory address and a DLL file name for a particular API when it's mapped into a process. Most of this can be resolved with the import/export tables in a DLL and by analyzing the Import Address Table of a mapped module. That is for most functions.
But the issue happens with some forwarded functions. An example of such function happens to be DeleteProcThreadAttributeList on my Windows 10 system. So for instance, if I build a test 32-bit process with such function, or better yet, let's use a 32-bit version of cmd.exe from c:\windows\syswow64\cmd.exe image, and then try to analyze its import table. It turns out that this function is imported from the API Set with a virtual name API-MS-WIN-CORE-PROCESSTHREADS-L1-1-2.DLL:
To find an actual file that it redirects to I do the following:
HMODULE hMM = ::LoadLibraryEx(L"API-MS-WIN-CORE-PROCESSTHREADS-L1-1-2.DLL",
NULL, DONT_RESOLVE_DLL_REFERENCES);
WCHAR buffModPath[MAX_PATH];
::GetModuleFileNameEx(::GetCurrentProcess(), hMM, buffModPath, _countof(buffModPath));
::FreeLibrary(hMM);
Which gives me buffModPath as C:\Windows\System32\KERNEL32.DLL.
Since I'm calling it from a 32-bit process, I now inspect the export table of c:\windows\syswow64\KERNEL32.DLL module:
that shows that DeleteProcThreadAttributeList is forwarded to api-ms-win-core-processthreads-l1-1-0.DeleteProcThreadAttributeList.
OK, I then use my method again to resolve redirection of the virtual api-ms-win-core-processthreads-l1-1-0.dll API set:
HMODULE hMM = ::LoadLibraryEx(L"api-ms-win-core-processthreads-l1-1-0.dll",
NULL, DONT_RESOLVE_DLL_REFERENCES);
WCHAR buffModPath[MAX_PATH];
::GetModuleFileNameEx(::GetCurrentProcess(), hMM, buffModPath, _countof(buffModPath));
::FreeLibrary(hMM);
Which gives me C:\Windows\System32\KERNEL32.DLL, that brings me back to where I started.
So how do I resolve this circular dependency to actual DLL address/entry point the way OS module loader does it?
I think whatever happens if you GetProcAddress one of these exports is supposed to be a black box.
The PEB has a ApiSetMap member in Windows 7+ that contains set information that the loader uses. The format of this data has changed at least 3 times but the mapping is not just from "API-*.dll" to "*32.dll".
You can read the Microsoft patent of this concept here.

LoadLibrary() : How to handle invalid DLLs?

I have an application that relies heavily on plugins.
On startup it scans a directory for DLLs and loads them one by one, looking for ones that implement a certain exported function. However - if someone were to rename a different type of file to *.dll and put it in the directory, that file would then also be loaded by LoadLibrary(). LoadLibrary() doesn't like that and produces an error [dialog].
Is there a way to simply ignore invalid / incompatible .dll files (either detecting them prior to the call or have LoadLibrary() return NULL rather than throwing a fit)?
You need to set the error mode for your process. Do this once and for all at startup:
UINT oldMode = SetErrorMode(0);
SetErrorMode(oldMode | SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
After you've set the process error mode, when LoadLibrary fails no dialog box will be displayed and LoadLibrary will return NULL.
The documentation says:
Best practice is that all applications call the process-wide SetErrorMode function with a parameter of SEM_FAILCRITICALERRORS at startup. This is to prevent error mode dialogs from hanging the application.
I also recommend adding SEM_NOOPENFILEERRORBOX for reasons that I guess should be obvious.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms684175%28v=vs.85%29.aspx
Remarks
To enable or disable error messages displayed by the loader during DLL loads, use the SetErrorMode function.
Don't forget to restore the error mode after you are finished.
If you wanted to do this yourself, in a primitive manner you could parse the PE header to identify obvious cases of bad DLL files, however it is not really possible to determine if a DLL is valid and loadable without a full PE loader which requires a lot of work and is already built into the operating system.
Updated answer after feedback in comments from djgandy and Remy Lebeau. Now a complete
function, better preservation of error mode at entry:
// This function will load the DLL named by pszPath if it is a valid library.
// If the function succeeds, it will return a valid HMODULE for the DLL. This
// handle should be passed to FreeLibrary when it is no longer needed.
// If the function fails, it will return NULL and no annoying dialog boxes will
// be displayed. It is therefore up to the caller to notify the user about what
// happened or take any other appropriate action. The reason for failure can
// be obtained from GetLastError(). Common problems:
// ERROR_BAD_EXE_FORMAT - Bad DLL (tested function with text file)
// ERROR_MOD_NOT_FOUND - Missing DLL (tested with file that did not exist)
//
// Module-loading functions can return several other errors, look at winerror.h
// list starting at ERROR_INVALID_MODULETYPE
//
// Obviously, since it's just a wrapper around LoadLibrary this function is not
// safe to call from DllMain.
//
// NB: GetErrorMode() is only available on Vista / Server 2003 or later.
HMODULE LoadLibraryIfValid(LPCTSTR pszPath)
{
HMODULE hModule = NULL;
UINT prevErrorMode = GetErrorMode();
SetErrorMode(prevErrorMode | SEM_FAILCRITICALERRORS);
hModule = LoadLibrary(pszPath);
SetErrorMode(prevErrorMode);
return hModule;
}
If targeting Windows 7 / Server 2008 R2 or later, the Get/SetThreadErrorMode()
functions are available, but might not be worth it or even a good alternative
(discussion in comments, below)
If anyone cared enough to put the time into it (I sure don't), a version of
this function could easily be written using GetModuleHandle for kernel32 and
GetProcAddress to be compatible with earlier versions of Windows as well as
provide a global/per-thread error mode option for platforms that support it
(truly pointless because it's only changed for the duration of one call anyway).
This is the largest commentary-to-code ratio in my life.

Virtual Webcam Driver

I want to develop a virtual webcam driver which from User mode I'll pass image to it and it will display as webcam output.
I don't want to use DirectX filter and CSourceStream etc. Because they don't work on some programs which doesn't use DirectX for capturing webcam image.
I have to write a kernel mode device driver so.
Any ideas? I tried testcap from DDK samples, but it doesn't process image from user mode and doesn't get any input, just it displays 7 colors in webcam...
Any help would be greatly appreciated.
Thanks
Thank you all!
I tried code from here:
http://tmhare.mvps.org/downloads.htm (find Capture Source Filter)
It worked well when I compiled it in Yahoo, MSN, but it crashed AIM, Internet Explorer Flash Webcam, Firefox Flash webcam and Skype... I got crash in QueryInterface after 8 time call to that, I found it with tracing it with a lot of tricks..
Now I know, it crashes on 8th call to
HRESULT CVCamStream::QueryInterface(REFIID riid, void **ppv)
8th call when it reaches to last if, I mean:
return CSourceStream::QueryInterface(riid, ppv);
It's in 17th line of Filters.cpp
Why do you think I'm getting crash??
Thank you all for guiding me to find correct solution which is DirectShow, not driver
There are several APIs from Microsoft which provide access to image data.
Twain: Used for single image capture from scanners, etc.
WIA: This seems to have degenerated to a single image codec library.
VfW: A very old (Win16) API which really works only Video-File encoding/decoding, but has support for some video acquisition.
DirectShow: previously part in the DirectX SDK, currently in the Platform SDK. This is the place to go for current (general) streaming solutions.
Windows Media/Media Foundation: This seems more to be geared at video playback/reencoding.
Manufacturer Specific Libraries: Pylon/Halcon/Imaging Control/...
DirectShow specific :
To create image acquisition devices under windows, you have to provide either a device (driver) which implements the streamclasses interfaces (or newer Avstream) or you have to write a usermode COM object which has to be added to the VideoInputCategory enumerator.
The Avstream sample provides everything for a real image acquisition device. Only the lower layer for the actual device really is missing.
If you can design a device, you should either create it DCAM or UVC compatible. For both there are built-in drivers supplied by windows.
How to write a software source device :
You have to create a DirectShow filter which provides at least one output pin and register this under the VideoInputCategory. There may be several interfaces certain applications require from a capture application, but these depend on the application itself. Simple applications to try out filters are GraphEdit and AMCap which are supplied in the Plattform SDK.
Some code :
#include <InitGuid.h>
#include <streams.h>
const AMOVIESETUP_MEDIATYPE s_VideoPinType =
{
&MEDIATYPE_Video, // Major type
&MEDIATYPE_NULL // Minor type
};
const AMOVIESETUP_PIN s_VideoOutputPin =
{
L"Output", // Pin string name
FALSE, // Is it rendered
TRUE, // Is it an output
FALSE, // Can we have none
FALSE, // Can we have many
&CLSID_NULL, // Connects to filter
NULL, // Connects to pin
1, // Number of types
&s_VideoPinType // Pin details
};
const AMOVIESETUP_FILTER s_Filter =
{
&CLSID_MyFilter, // Filter CLSID
L"bla", // String name
MERIT_DO_NOT_USE, // Filter merit
1, // Number pins
&s_VideoOutputPin // Pin details
};
REGFILTER2 rf2;
rf2.dwVersion = 1;
rf2.dwMerit = MERIT_DO_NOT_USE;
rf2.cPins = 1;
rf2.rgPins = s_Filter.lpPin;
HRESULT hr = pFilterMapper->RegisterFilter( CLSID_MyFilter, _FriendlyName.c_str(), 0,
&CLSID_VideoInputDeviceCategory, _InstanceID.c_str(), &rf2 );
if( FAILED( hr ) )
{
return false;
}
std::wstring inputCat = GUIDToWString( CLSID_VideoInputDeviceCategory );
std::wstring regPath = L"CLSID\\" + inputCat + L"\\Instance";
win32_utils::CRegKey hKeyInstancesDir;
LONG rval = openKey( HKEY_CLASSES_ROOT, regPath, KEY_WRITE, hKeyInstancesDir );
if( rval == ERROR_SUCCESS )
{
win32_utils::CRegKey hKeyInstance;
rval = createKey( hKeyInstancesDir, _InstanceID, KEY_WRITE, hKeyInstance );
....
_InstanceID is a GUID created for this 'virtual device' entry.
You can not decide how other program would call your driver. Most of programs will use DirectShow. Some would use the win3.x technology VFW. Many new programs, including Windows XP's scanner and camera wizard, may call you via the WIA interface. If you do not want to implement all that, you need to at least provide the DirectShow interface via WDM and let vfwwdm32.dll gives you a VFW interface, or write your own VFW driver.

WriteProcessMemory to SYSTEM process with SeDebugPrivilege enabled. (C, Vista)

I'm interested in injecting DLLs into SYSTEM owned processes on my Vista machine. I'm going about this using the traditional method of VirtualAllocEx, WriteProcessMemory and CreateRemoteThread. However, because this will be operating on SYSTEM processes, I enable SeDebugPivilege on the injecting process before opening the target process.
int EnableDebugPriv(LPCTSTR name) {
HANDLE hToken;
LUID luid;
TOKEN_PRIVILEGES tkp;
if(!OpenProcessToken(GetCurrentProcess(),
/*TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY*/
TOKEN_ALL_ACCESS,
&hToken))
return 0;
if(!LookupPrivilegeValue(NULL,name,&luid))
return 0;
tkp.PrivilegeCount=1;
tkp.Privileges[0].Luid=luid;
tkp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
if(!AdjustTokenPrivileges(hToken,false,&tkp,sizeof(tkp),NULL,NULL))
{
printf("!AdjustTokenPrivileges - %d\n",GetLastError());
return 0;
}
if(GetLastError()==ERROR_NOT_ALL_ASSIGNED)
{
return 0;
}
CloseHandle(hToken);
return 1;
}
Where the SE_DEBUG_NAME constant is passed as name.
After enabling SeDebugPrivilege, I go through the process of opening the target process, locating LoadLibrary, allocating space, writing the DLL path to memory, and creating the thread (checking all return values along the way):
if(NULL==(p=OpenProcess(PROCESS_ALL_ACCESS,FALSE,(DWORD)pid)))
...
if(NULL==(loadLib=(LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"),
"LoadLibraryA")))
...
if(NULL==(dllBuff=(LPVOID)VirtualAllocEx(p,
NULL,
strlen(dllPath)+1,
MEM_RESERVE|MEM_COMMIT,
PAGE_READWRITE)))
...
if(NULL==WriteProcessMemory(p,
(LPVOID)dllBuff,
dllPath,
strlen(dllPath),
&written))
...
if(!CreateRemoteThread(p,
NULL,
NULL,
(LPTHREAD_START_ROUTINE)loadLib,
(LPVOID)dllBuff,
NULL,
NULL))
...
dllPath is a char* of the DLL's path (obviously), and pid is the PID of the target process. Both of these values are taken in through the command line and validated before being used.
The problem I'm having is that nothing is returning errors until CreateRemoteThread, which is returning an 8 ("Not enough storage"). HOWEVER, WriteProcessMemory is NOT writing any bytes to the process. After the call the written variable is always 0. No bytes are being written, but the function is not failing. I'm not sure why this is happening. I looked into other privileges, like the SeRestorePrivilege which promises write access to all processes, but nothing works.
I'm executing this program with Administrator rights.
Note: this WriteProcessMemory and CreateRemoteThread problem only happen when I run this program against higher privileged users (SYSTEM, LOCAL SERVICE, etc...). It works perfectly against a program owned by me (same privileges).
Edit: Here's a link to the whole source. http://pastebin.com/m77110d8e There's not much else there besides basic error checking, but maybe it will help?
This has to do with session isolation in Vista or higher versions of Windows. Check out the source or disassembly for password dumping tools like Cain and Abel that purport Vista functionality. Essentially the process is the same but you'll be calling a different function for CreateRemoteThread (sorry, I don't think the function is exported, you just have to find it, so disassembly of working software is probably the best bet).
You could try using RtlCreateUserThread, instead of CreateRemoteThread. This routine doesn't care what session the target process lives in. Just remember to have the thread call RtlExitUserThread before it ends. These threads don't clean up after themselves, like the CreateThread/CreateRemoteThread ones do.
The reactos code can give you a good look at what these routines are doing.

How to allow 32 bit apps on 64 bit windows to execute 64 bit apps provided in Windows\System32

Say you have an app, that you want to provide users ability to browse the system32 directory and execute programs in (like telnet).
What is the best method for supporting this when you need to support XP onwards as a client and 2k onwards for server?
Having written all this up I wonder if it's just too much time/effort in providing a browse to do this, where they could just copy it from explorer. Still requires ability to launch.
I have found some discussion on Nynaeve.
So far it seems there are the following options
Create a sysnative folder in windows which will allow you to browse/execute 64 bit. Issues are:
only available in Vista/Longhorn, so no support for XP 64
leads to different path naming, can't use same path on multiple versions.
will be active for whole of windows, not just our app
may not (probably is not) appropriate to do when installing the app
allows to specify explicitly through path only which version of the app to launch if there is a 32 bit and 64 bit version
Use the windows API to temporarily disable the redirection when showing file lists or executing users run commands. Issues are:
Only available on 64 bit - have to mess with GetProcAddress
available only under certain service packs
must individually identify all locations that this should be implemented
user will need to provide seperate information about whether this is a 64 bit app or 32 bit.
If anybody had some example code which displayed a Windows OpenFile dialog (say using MFC CFileDialog) showing nativly for XP/Vista and allowing the viewing of 64 bit system32 directory, that would be awesome.
If anybody had an example of launching the named app, that would also be great!
Edit:
Currently we use CreateProcess for launching the app (which is failing).
err = CreateProcess((wchar_t*)exeName.c_str(), (wchar_t*)cmdLine.c_str(), NULL, NULL, FALSE, CREATE_SEPARATE_WOW_VDM, NULL, workingDir.c_str(), &startupInfo, &processInfo);
I've gone with option 2,
For those who might be interested; here is my quick hack at a scoped version of managing the disabling of Wow64 redirection based on notes from MS. Will redirect if the API is available, expects that kernel32.dll is already available.
class Wow64RedirectOff {
typedef BOOL (WINAPI *FN_Wow64DisableWow64FsRedirection) ( __out PVOID *OldValue );
typedef BOOL (WINAPI *FN_Wow64RevertWow64FsRedirection) ( __in PVOID OldValue );
public:
Wow64RedirectOff() {
LPFN_Disable = (FN_Wow64DisableWow64FsRedirection)GetProcAddress(
GetModuleHandle(TEXT("kernel32")),"Wow64DisableWow64FsRedirection");
if( LPFN_Disable ) {
LPFN_Disable(&OldValue);
}
}
~Wow64RedirectOff() {
if( LPFN_Disable ) {
FN_Wow64RevertWow64FsRedirection LPFN_Revert = (FN_Wow64RevertWow64FsRedirection)GetProcAddress(
GetModuleHandle(TEXT("kernel32")),"Wow64RevertWow64FsRedirection");
if( LPFN_Revert ) {
LPFN_Revert(OldValue);
}
}
}
private:
FN_Wow64DisableWow64FsRedirection LPFN_Disable;
PVOID OldValue;
};
And thus usage would be
Wow64RedirectOff scopedRedirect;
//CFileOpen
//CreateProcess
Are you getting redirected to Windows/SysWoW64? I can launch 64-bit apps from Windows/System32 from an OpenFile in a 32-bit managed executable.