Introduction

After seeing Vista and IE 7 at PDC 2005, I remarked
that protected mode was going to make life difficult for legitimate IE extensions, not just spyware. Last year
while trying out Vista beta 2, I saw just how difficult - one of my products has an IE toolbar, and protected mode
broke many of the major features because the toolbar needs to communicate with another process outside of IE. After
a lot of trial and error, and some not-kid-sister-safe language, I eventually got the features working again. After
all that work, I wanted to summarize the necessary changes into this survival guide and give folks all the relevant
information in one place.

This article assumes you are familiar with C++, GUI, and COM programming. The sample code is built with Visual
Studio 2005, WTL 7.5, and the
Windows SDK. If you need to get up to speed with WTL, check out my series of articles
on WTL. WTL is only used for the GUI; the concepts presented here apply to all applications, and are independent
of any class library.

Introduction to Protected Mode

Internet Explorer's Protected Mode is a new feature in Vista, and is one of the pieces of User Account
Control (UAC). Protected mode is designed to protect the computer by restricting the parts of the system that code
running in the IE process can affect. If a malicious web page exploits a code-injection bug in IE or an IE plugin,
that code will not be able to do damage to the system.

Before we dive into what protected mode means for IE plugin developers, we need a quick tour of the security
features involved.

Integrity Levels and UIPI

Vista introduces a new attribute on securable objects called the mandatory integrity level. There are
four levels:

System: Used by OS components, should not be used by applications.

High: Processes that are running elevated with full admin rights.

Medium: Processes launched in the normal fashion.

Low: Used by IE and Windows Mail to provide protected mode.

The information that Windows keeps about a process includes which integrity level it was launched with. This
level can never change once the process is started, it can only be set at the time the process is created. A process's
integrity level has three main effects:

Any securable objects that the process creates get that same integrity level.

The process cannot access a resource whose integrity level is higher than the process's own level.

The process cannot send window messages to a process that has a higher integrity level.

That is not a complete list, but the three listed above have the greatest impact on plugins. The first two items
prevent a low-integrity process from tampering with IPC resources, like shared memory, that contain sensitive data
or data that is crucial for the proper operation of an application. The last item is called User Interface Process
Isolation (UIPI), and is designed to prevent attacks like the shatter
attack, where an attacker induces a process into running untrusted code by sending it messages that it was
not expecting to receive.

Virtualization

Virtualization (also called redirection in some Microsoft documentation) is a feature that prevents
a process from writing to protected areas of the registry and file system, while still allowing the application
to function normally. For medium-integrity processes, the protected areas are system-critical areas like HKLM,
the system32 and Program Files directories, and so on. A low-integrity process is even
more restricted -- it can only write to special low-rights areas of the registry and file system, and any
attempts to write outside those areas are prevented.

When a process tries to write to an area it doesn't have rights to, virtualization kicks in and redirects the
write operation to a directory (or registry key) under the current user's profile, and the write operation actually
happens there. Then later, when the app tries to read that data, the read operation is also redirected so the app
will see the data that it wrote earlier.

Virtualization affects IE extensions because they can no longer do things like write settings to the registry
(even under HKCU) for other processes to use. Extensions are also very restricted in where they can
write data files -- only a few IE-specific directories like Favorites and Cookies
are writable.

When Is Protected Mode Turned On?

In Vista's default configuration, IE always runs in protected mode. The status bar, pictured below, has an indicator
that shows when protected mode is on:

You can turn protected mode off entirely by disabling UAC, or by unchecking Enabled Protected Mode on
the Security tab of the IE options dialog. You can also temporarily bypass protected mode by running a new
elevated instance of IE, but keep in mind that doing so will make IE run at high integrity, not at medium like
a normal application.

The Sample App and Extension

The sample code for this article combines two projects. The first project, IEExtension, is a band that
is docked to the bottom of the IE window:

The second project, DemoApp, is an EXE that the band communicates with. DemoApp doesn't do much by itself,
the interesting parts are in IEExtension where it needs to communicate with the EXE. This communication is greatly
impacted by protected mode, and both projects demonstrate how to work within protected mode's restrictions and
still be able to do inter-process communication.

The band has several buttons for doing various IPC tasks. The buttons that are in pairs show both an old technique
that no longer works in protected mode (button 1) and a new protected mode-aware technique that does work (button
2). The list control shows various status messages, such as the return value from Windows APIs.

The rest of the article will focus on what the extension needs to do to function properly in protected mode.
I'll be introducing some APIs, then showing the code in the sample extension that uses that API. Each topic corresponds
to a button (or pair of buttons) in the band, so you can refer to the corresponding code while reading through
the article.

Working Within Protected Mode Restrictions

IE 7 has several new APIs that extensions can use to perform functions that are restricted in protected mode.
These APIs are in ieframe.dll. You can either link directly to these APIs by using the iepmapi.lib
import library, or use LoadLibrary()/GetProcAddress() to get pointers to the functions
at runtime. The latter method is the one you must use if you want your extension to load on versions of Windows
prior to Vista.

Many of the features that perform privileged actions use a broker process, ieuser.exe. Since the IE process
is running at low integrity, it can't do higher-privileged tasks on its own; ieuser.exe fulfills that role. You'll
see this broker process mentioned often in this article and in Microsoft documentation.

Detecting Protected Mode at Runtime

To determine if our extension is running in a protected mode IE process, we use IEIsProtectedModeProcess():

HRESULT IEIsProtectedModeProcess(BOOL* pbResult);

If the return value is a successful HRESULT and *pbResult is TRUE, then
protected mode is enabled. Based on the value returned in *pbResult, you can take different action
in your code if necessary:

The sample band extension calls this API on startup, and shows a message indicating the status of protected
mode.

Writing to the File System

When protected mode is enabled, an extension can only write to a few directories under the user's profile. There
are special low-integrity directories under the Temp, Temporary Internet Files, Cookies,
and Favorites directories that are writable. IE also has some compatibility shims, which virtualize
other commonly-used directories. (I haven't seen a full list of those "common directories." This
post on the IEBlog mentions the shim feature, but doesn't elaborate on which directories are covered.) Write
operations to those directories will be redirected to a subdirectory of Temporary Internet Files.
If an extension tries to write to a sensitive location, like the windows directory, the operation
will fail.

When an extension wants to write to the file system, it should use the IEGetWriteableFolderPath()
API instead of GetSpecialFolderPath(), GetFolderPath(), or SHGetKnownFolderPath().
IEGetWriteableFolderPath() is aware of protected mode, and if the extension asks for a directory that
it is not allowed to write to, IEGetWriteableFolderPath() will return E_ACCESSDENIED.
The prototype for IEGetWriteableFolderPath() is:

The GUID is one of these, defined in knownfolders.h: FOLDERID_InternetCache, FOLDERID_Cookies,
FOLDERID_History. There doesn't seem to be a GUID for the Temp directory, so I recommend
using FOLDERID_InternetCache when you need to write temp files.

If IEGetWriteableFolderPath() succeeds, it allocates a buffer and returns its address in pwszCacheDir.
We pass that directory to GetTempFileName(), then free the buffer with CoTaskMemFree().

IEGetWriteableFolderPath() is not just for writing temp files. An extension will also use it when
it uses the protected mode version of the save file dialog, as explained in the Prompting the User to Save Files
section below. The demo project uses this API when you click the Save Log button.

Writing to the Registry

Since the registry is a critical part of the system, it's crucial that code running in the browser not be allowed
to change any parts of the registry that could allow malicious code to run. To this end, there is only one
key that extensions can write to. As with the file system, this key is in a special low-rights area under the current
user's profile. To get a handle to this key, call IEGetWriteableHKCU():

HRESULT IEGetWriteableHKCU(HKEY* phKey);

If it succeeds, you can use the returned HKEY in other registry APIs to write whatever data is
necessary. The demo project does not use the registry, but this API is quite simple and there should be no trouble
in using it.

Prompting the User to Save Files

When IE is running in protected mode, there is still a way for extensions to (indirectly) write to the file
system, outside of the low-rights areas. An extension can show a common save file dialog by calling IEShowSaveFileDialog().
If the user enters a file name, the extension can then have IE write the file by calling IESaveFile().
Note that this operation always results in the user seeing the save file dialog; this ensures that the user is
always aware that a file is about to be written.

The steps when saving a file are:

Call IEShowSaveFileDialog() to show the save file dialog.

Call IEGetWriteableFolderPath() to get the IE cache directory.

Write the data to a temp file in the cache directory.

Call IESaveFile() to copy that data to the filename that the user selected.

Clean up the temp file.

IEShowSaveFileDialog() is a wrapper around the common file save dialog:

hwnd is a window owned by the extension, IE will use the topmost owner window as the parent window
of the dialog. lppwstrDestinationFilePath is a pointer to an LPWSTR that is set to the
file path that the user selects. This is only informational, since the extension can't write to that path directly.
phState is a pointer to a HANDLE that is filled in if the user chooses a file, this handle
is used when calling other APIs. The other parameters are used like the corresponding members in the OPENFILENAME
struct.

IEShowSaveFileDialog() returns S_OK if the user chooses a filename, S_FALSE
if he cancels the dialog, or a failure HRESULT if the API fails.

Here is the code in the demo project that saves the log to a file. We first call IEShowSaveFileDialog()
to prompt the user for a file path:

If everything has succeeded to far, we call another protected mode API, IESaveFile(). IESaveFile()
takes the state handle that IEShowSaveFileDialog() returned, and the path to our temp file. Note that
this HANDLE isn't a standard handle and doesn't need to be closed; after the IESaveFile()
call, the HANDLE is automatically freed.

If for some reason we don't end up calling IESaveFile() -- for example, if an error happens
while writing to the temp file -- we do need to clean up the HANDLE and any internal data
that IEShowSaveFileDialog() allocated. We do this by calling IECancelSaveFile().

Enabling Communication Between Your Extension and Other Applications

All the file system and registry topics we've seen so far have been dealing with code running in the IE process.
With the availability of virtualization and compatibility shims, it is straightforward for IE to restrict code
running in its own process and prevent it from making calls to APIs that could end up damaging the system. Now
we'll see a more complex subject, which has a more complex solution: IPC with another process running at a higher
integrity level. We'll cover two different forms of IPC: kernel objects and window messages.

Creating IPC Objects

When an extension and a separate process want to communicate, that communication happens between the two pieces
of code, without going through IE wrappers. The NT security APIs and the mandatory integrity level come into play,
and by default communication from the extension to the separate app is blocked because the app is running at a
higher integrity level than IE.

If the separate app creates a kernel object (for example, an event or mutex) that the extension needs to use,
the app must lower the integrity level of the object before the extension can access it. The app can use the security
APIs to change the ACL on the object and lower its integrity. The code below, taken from the MSDN article "Understanding
and Working in Protected Mode Internet Explorer", takes a HANDLE to a kernel object and sets
its integrity level to low.

The sample code uses two mutexes whose purpose is to allow the extension to tell when the app is running. The
DemoApp EXE creates them when the process starts, and the extension tries to open them when you click one of the
Open Mutex buttons. Mutex 1 has the default integrity level, while mutex 2 is set to low integrity using
the SetObjectToLowIntegrity() function listed above. This means that when protected mode is on, the
extension will only be able to access mutex 2. Here are the results you'll see when you click both of the Open
Mutex buttons:

Another effect of protected mode is that an extension can't have a separate app inherit a kernel object handle.
For example, when protected mode is enabled, our extension can't create a file mapping object, run the separate
app (passing TRUE for the bInheritHandles parameter to CreateProcess()),
and have the app inherit the handle on the file mapping object.

DemoApp would then read the handle value from the /h switch, and use that value to call MapViewOfFile()
and read the data. This is a standard technique to make the new process automatically receive a handle to a kernel
object, but when protected mode is enabled, the new process is actually launched by the broker process. Since the
IE process doesn't directly launch the new process, handle inheritance doesn't work.

To work around this restriction, the extension can use a pre-defined name for an IPC object, and the separate
app will be able to access that object since the object will have low integrity. If you don't want to use a pre-defined
name, you can generate a name at runtime (for example, use a GUID for the name) and pass that name to the separate
app:

Using this method, the EXE receives the IPC object's name on the command line. It can then call OpenFileMapping()
to access the object. There is one complication with this method, however, in that you need to be careful about
object lifetime management. When using handle inheritance, the sequence of events is:

The extension creates the IPC object, giving it a reference count of 1.

The extension launches the new process, which inherits the handle. This increases the object's reference count
to 2.

The extension can immediately close its handle since it doesn't need to the object anymore. The reference count
drops to 1.

The new process does whatever it needs to with the IPC object. Since it still has an open handle, the object
remains around until the new process closes its handle.

If we used the above steps when passing just the name of the object to the EXE, we would create a race condition
where the extension could close its handle (and therefore delete the IPC object) before the EXE has a chance to
open a handle on it.

The extension creates the IPC object, giving it a reference count of 1.

The extension launches the new process, passing it the name of the IPC object. The reference count is
still 1.

The extension cannot close its handle right away, it needs to wait until the new process has opened a handle
to the object. Some sort of synchronization is necessary to do this.

The new process opens a handle to the object and reads the data. At this point, it can signal the extension
to wake the extension's thread. It's now safe for the extension to close its handle.

What I chose to do in the sample project is have DemoApp read the data from shared memory before it creates
the main dialog. The extension then calls WaitForInputIdle() after CreateProcess(), which
makes the thread block until DemoApp's main dialog has been created and displayed. Once the DemoApp's thread goes
idle, it has finished using the shared memory, and it's safe for the extension to close its handle.

The band demonstrates both methods of passing data through shared memory. When you click the Run EXE 1
button, the band writes the current date and time to shared memory, and passes a handle to DemoApp. When protected
mode is enabled, this method will fail and DemoApp will report and invalid handle error. Clicking Run EXE 2
passes the name of the file mapping object to DemoApp, which will then show the data it reads from shared memory:

Accepting Window Messages

UIPI prevents certain window messages (and all messages with a value greater than or equal to WM_USER)
from being sent from a lower-integrity process to a higher-integrity one. If your application needs to receive
messages from your extension, you can call ChangeWindowMessageFilter() to allow one specific message
through:

BOOL ChangeWindowMessageFilter(UINT message, DWORD dwFlag);

message is the value of the message, and dwFlag indicates whether the message should
be allowed or blocked. Pass MSGFLT_ADD to allow the message, or MSGFLT_REMOVE to block
it. Be very careful when processing window messages from other processes - if you accept data via a message, you
must treat it as untrusted and you should validate it before acting on it. (Remember that inter-process messages
can be sent from anywhere, and such messages can be used for attacks, as mentioned earlier.)

The demo project shows how to communicate via registered window messages. As with the mutex example, there are
two messages. DemoApp allows the second message through the filter with this code in OnInitDialog():

When you click the two Send Message buttons in the band, you'll see these results:

The first message is not allowed through the filter, and SendMessage() returns 0.

Other Restrictions in Protected Mode

Running Other Applications

IE has another mechanism that prevents malicious code from communicating with or launching other processes.
If an extension tries to start another process, IE will ask the user for permission before starting the process.
For example, using the View Source command results in this prompt:

If your extension needs to run a separate EXE, you can add a registry key that tells IE that your EXE is trusted
and can be run without a prompt. The registry key that controls this behavior is HKLM\Software\Microsoft\Internet
Explorer\Low Rights\ElevationPolicy. Create a new GUID, then add a key under ElevationPolicy
whose name is that GUID. In that new key, create three values:

AppName: The filename of the executable, for example "DempApp.exe".

AppPath: The directory where the EXE is located.

Policy: A DWORD set to 3.

If your installer doesn't create a key like that, IE itself will create one if you check the Do not show
me the warning for this program again checkbox.

Drag and Drop to Other Applications

A similar prompt will be shown if you try to drag content from a web page and drop it in another app:

This prompt can be suppressed with a registry key as well. The format is the same as described above, but your
app's key goes under DragDrop instead of ElevationPolicy.

DemoApp registers as a drop target, and if you select text in IE and drag it into the DemoApp dialog, it will
show a message indicating that it received the drag:

The demo code that accompanies this article is released to the public domain. I release it this way so that
the code can benefit everyone. (I don't make the article itself public domain because having the article available
only on CodeProject helps both my own visibility and the CodeProject site.) If you use the demo code in your own
application, an email letting me know would be appreciated (just to satisfy my curiosity about whether folks are
benefitting from my code) but is not required. Attribution in your own source code is also appreciated but not
required.

Revision History

May 21, 2007: Article first published.
May 24, 2007: Added License section. Fixed IEExtension project in the sample code, it was missing the IDL file.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

Share

About the Author

Michael lives in sunny Mountain View, California. He started programming with an Apple //e in 4th grade, graduated from UCLA with a math degree in 1994, and immediately landed a job as a QA engineer at Symantec, working on the Norton AntiVirus team. He pretty much taught himself Windows and MFC programming, and in 1999 he designed and coded a new interface for Norton AntiVirus 2000.
Mike has been a a developer at Napster and at his own lil' startup, Zabersoft, a development company he co-founded with offices in Los Angeles and Odense, Denmark. Mike is now a senior engineer at VMware.

He also enjoys his hobbies of playing pinball, bike riding, photography, and Domion on Friday nights (current favorite combo: Village + double Pirate Ship). He would get his own snooker table too if they weren't so darn big! He is also sad that he's forgotten the languages he's studied: French, Mandarin Chinese, and Japanese.

I failed to run the demo app and IeExtension.dll with IE. What I did: call "regsvr32" for IeExtension.dll and then launch IE, nothing displays at the bottom corner. I'm using windows 7 64bit (with UAC off) and IE8 32bit. When checking the settings of IE by clicking "Tools" menu and then "Manage Add-Ons", the IeExtension.dll does get loaded and enabled.

Thanks for the great article. It touches on some of the issues I have been facing with our application, but what we are doing is a bit different. We use an IWebBrowser2 object to create a new instance of IE and then drive that instance with our application to browse to internet sites and download information in xml. We also use it to open local html files that our application creates and then print them.

Since the new security features have been added to IE and windows this doesn't work anymore. IE doesn't allow access to the xml object in its memory and doesn't run the print command when instructed. If we have our users run our application as administrator it works, but otherwise it doesn't. In windows XP user's can't run our application as administrator so that approach doesn't even work.

Can anyone tell me the trick to getting our application to work again or at least point me to some resources that might help me find it?

i am a newbie on Win7. I write an application to install a mouse hook on IE8 with Protected Mode and complie it with highestAvailable right, but it doesn't work well. Can i install a mouse hook on IE Protected mode? and How?

Hello - I have an IE extension that needs to communicate with an OOP COM server. Because the *.exe is running on a higher level than IE, I get the talked about security alert. Adding my *.exe to the Elevation Policy list does get rid of the alert, but any CoCreateInstance i use from the BHO fails with the "... elevation required .. " error.

Is there any workaround for this? You talked about changing the ACL on Kernel objects created on a process outside IE - is there a parallel to this in COM objects?

Hi ,
I am using VS2005 and writing my code on Winxp SP2 I download SDK from internet and include header file iepmapi.h but I am getting error iepmapi.lib not found . I include iepmapi.lib in my Setting->linker->input->additional dependencies but still i get error.

Thanks for this wonderfull article.I had a problem with deploying my activex into Vista machines.

1) I have created a C# class library project called MyActivex and signed with a strong key Which has methods and propeties with COMVislble true.
2)Created a manifest file and did a post build event to attach the manifest info to the dll it creates .
3)after build is done i signed with verisign code signer.
4)I have one more project file which is a Shared add-in project for Excel.
5)I added the Activex.dll to this add-in project as a reference.(i added it as a referncc because most of the activex class methods are common to Excel addin Functunalities.(Like httpRequest,XML Parser)
6)Repeated the step 2 and 3 for this DLL.
7)Added a setup deploymenet project in VS2005 and added the project output of the Excel add-in project.
8)setup.exe and the MSI file is created on build is completed.
9)Created a CAB file through Microsoft CABARC and added both the setup.exe and MSI File with a .inf file
10)Signed the Cab file with verisign
11)Copied it to my appserver CAB folder.

Case XP:

When user logs on to our application through IE.
Detect_activex.jsp checks for the activex presense or not in machine
If it is not presenet then it is installing and registering the MSI and Activex.
Then activex starts running and doing some job through HTML <object>

Case Vista:

Its not able to install the Activex component into user's machine if UAC is enabled and the user is a standard user or a local admin

But its working fine for Domain ADMIN Rights or if we disable the UAC as well as Protection mode

Can you help me on this project and guide me how to design my activex so that it will install and register to user's machine for Vista standard user.

Thanks for this article, it helped to add PM support to app really quickly,
but there is minor bug in definition of IEGetWriteableFolderPath.
it should be:
HRESULT IEGetWriteableFolderPath(REFGUID clsidFolderID, LPWSTR* lppwstrPath);
so, REFGUID instead of GUID. Then LoadLibrary/GetProcAddress linking works.

Under Vista applications can no longer write to the HKLM Registry section, so unfortunately you example in the section "Running Other Applications" won't work. You would need to do this from the application Installer.

I have an IE7 add-in that contains a CHM help file. And whenever I launch the file via the ::HTMLHelp Api, clicking on any of the help pages opens a new IE7 window, and displays the contents of that page in the browser.

When I turn protected mode off, I don't have the problem. But I can't seem to find a workaround for this issue...Any ideas?

Thank you for your informative article on the issues with IE. I wish I had found it sooner! I ran into similar issues with getting my BHO to communicate properly with an external app that may or may not be running.

The external app sets up a MMF and the BHO checks for it's existance, and the app state if it finds it. I found that due to the low integrity setting of IE, my BHO was not able to access the MMF. As a consequence, I had to change the security on my MMF to low integrity, and as soon as I did that, my BHO was able to read and write to the MMF.

One other issue I ran into is that I have a DLL that gets injected into other applications, and as soon as it got injected into IE, it hung up IE. On further investigation, I found the same thing. A different MMF that the DLL was using it could no longer write to. The solution was the same.

Hopefully this additional piece of information will be of use to someone. I posted a query on the MSDN forums and someone posted a function that will create a SECURITY_ATTRIBUTE structure with the necessary pieces to pass to CreateFile() that nicely resolved the issue for me.

I am still looking for a way to write to a file from my BHO that is outside the protected areas without the interactive Save dialog that I you mentioned above. Basically I want to log some debugging code there for my use and I want both my BHO and external app to use it. If you have a way to resolve that, I would greatly appreciate it.

The response to the thread you posted just saved me another couple of days of work with my service. That function posted there really saved me a lot of grief and got me over a huge wall. I hope the author of this article will put it under the IPC part.

I don't know if you can help me because my problem occurs under a .NET scenario described at http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2386649&SiteID=1. I have a IE BHO written in C# that communicates with a console application (vb.net) by IPC Remoting channel. My BHO is a DLL that runs in-proccess with IE. I tried everything to solve the "access denied" RemotingException, and this "Protected Mode" is driving me crazy! Do you think if it's possible to adapt your C++ IPC approach with C# ? I don't know too much C++ and the architecture that involves your solution, but I would apreciate if you could give some advice or tip. Thanks in advance.