Benchmarking Microsoft Office’s PowerPoint Application Packages: Microsoft App-V Vs. Symantec Workspace Virtualization

Introduction

Benchmarking virtualization products is an addictive game. Below we use SpyStudio to compare how long it takes to load a 21 slides PowertPoint presentation, with text and graphics, in three environments: Microsoft App-V 5 (MNT), Symantec Workspace Virtualization 6.4.1603, and natively. We measure the time elapsed until the slides show up on the GUI.

Both end-users and developers benefit from the virtualization of Microsoft Office applications. One benefit for end-users is that the virtualization of Microsoft Office does not leave the footprints that the installed program would: Microsoft Office natively installs a lot of components on the user machine that impact on their performance. Developers benefit from the chance to develop add-ins for different versions of the same application without having to run different virtual machines. For example, it is possible to develop an extension for Outlook and run it on Outlook 2007, 2010, and 2013 on a single machine.

Microsoft has been encouraging the virtualization of Microsoft Office. They are still deploying the usual Office applications but they are also introducing App-V packages for them. Other virtualization companies are following suit.

Benchmark

NativeApp-VWorkspace Virtualization
Min31.5137.2634.33
Max48.7351.5440.71
Avg36.7741.6937.52
Median35.3540.3137.52
SD5.424.301.80

Conclusions

In general, the overhead for this benchmark is low. Microsoft App-V is just 12% slower, while Symantec Workspace Virtualization is only 2 % slower. Symantec wins again.

Acknowledgments

Thanks to Windows driver developmentData Loss Prevention Solution Development, Windows Software DevelopmentApplication Packaging Services and Outlook Plugin Development

Related Services

  1. Windows driver development
  2. Office 365 Plugin Development
  3. Custom Software Development Company
  4. Data Loss Prevention Solution Development

See Also

  1. Application Virtualization Testing and Troubleshooting with Spy Studio and Deviare
  2. Benchmarking IE6 Virtualization: VMWare ThinApp vs. Symantec Workspace

Benchmarking IE6 Virtualization: VMware ThinApp vs. Symantec Workspace Virtualization

Introduction

Our Application Packaging Services team wanted to measure the performance of different virtualization products. Below we use SpyStudio to compare ThinApp and Workspace Virtualization performance. Both Symantec and VMware highlight the use of application virtualization to run legacy web applications. There is a huge number of mission critical web applications that only run correctly on Internet Explorer 6 and while companies may be able to afford the cost of migrating applications to modern browsers, they cannot afford even a short application interruption. Virtualization allows companies to continue to run their legacy applications while moving to more modern technology.

The challenges of virtualizing IE6 are not limited to rendering HTML: Java applets, ActiveX, and Flash must also be virtualized. This benchmark compares how long it takes to: launch Internet Explorer 6, launch IE6 and navigate to Nektra’s blog, and open Internet options. We ran each test ten times. SpyStudio can also be used to benchmark specific bottlenecks in plugins and components and to identify compatibility issues.

Benchmark

Launch IE6

Symantec Workspace VirtualizationVMWare ThinApp
Min1.5730167 secs2.217207 secs
Max1.800602 secs2.5048638 secs
Avg1.681593789 secs2.360678356 secs
Median1.6773198 secs2.3479585 secs
SD0.076693291 secs0.104027481 secs

Launch IE6 and Navigate to http://blog.nektra.com

Symantec Workspace VirtualizationVMWare ThinApp
Min7.0385753 secs9.0458817 secs
Max7.3155127 secs
10.1313509 secs
Avg7.152178211 secs
9.4426123 secs
Median7.1880917 secs9.3928642 secs
SD0.098509252 secs0.293977928 secs

Open Internet Options

Symantec Workspace VirtualizationVMWare ThinApp
Min1.8866595 secs2.5610158 secs
Max2.215396 secs2.9904516 secs
Avg2.025388122 secs2.767548167 secs
Median2.0197439 secs2.7876525 secs
SD0.101490761 secs0.152657664 secs

Conclusions

These benchmark results show that Symantec Workspace Virtualization is faster in all three tests.

Symantec Workspace Virtualization was an average of 71 % faster when launching IE6, 75 % faster when launching IE6 and opening Nektra’s blog, and 73 % faster when launching IE6 and opening Internet options.

You can easily benchmark these and other virtualization products yourself with SpyStudio. Download a free trial here.

Related Services

  1. Windows driver development
  2. Office 365 Plugin Development
  3. Custom Software Development Company
  4. Data Loss Prevention Solution Development

See Also

  1. Application Virtualization Testing and Troubleshooting with Spy Studio and Deviare
  2. Benchmarking Microsoft Office’s PowerPoint Virtualization: Microsoft App-V Vs. Symantec 

 

Injecting a DLL in a Modern UI Metro Application

Dll injection is one of the oldest techniques used to run custom code inside a target application in Windows. It is usually used to intercept and modify normal application behavior or add new functionality.

Injecting a DLL in a target process is a relatively easy task: you simply create a remote thread that calls LoadLibrary using CreateRemoteThread or NtCreateThreadEx. You will need some privileges to be able to access the injected process but that is beyond the scope of this article.

When you try to inject a library into a Windows 8 Modern UI Metro application you will find that although the injection code works as expected, your DLL will NOT load, LoadLibrary will return FALSE and GetLastError will return ERROR_ACCESS_DENIED.

Well, you think… Modern UI applications have very limited access to computer resources and run in a sandboxed environment, so problems are to be expected.

While doing some research on how to add new functionallity to the Windows Mail application that comes with Windows 8 and how to hook Modern UI apps using Deviare, we needed find out why LoadLibrary was failing.

Reverse engineering comes into play

We started to analyze what LoadLibrary does. It calls LoadLibraryEx with dwFlags=0 and LoadLibraryEx does some checks. First stop.

If you want to load a package you must use the LoadPackagedLibrary API. If you want to load a normal DLL, you have to use LoadLibrary[Ex]. LoadPackagedLibrary documentation says that the path cannot be absolute or contain “..” but these checks are mainly done in the LoadLibraryEx routine. The only difference between LoadLibrary and LoadPackagedLibrary is wether the dwFlags parameter has a value of 4 or of zero.

Among other things, LoadLibraryEx will build the search path to locate your DLL and then call the undocumented LdrLoadDll. Because we want to enforce using the path where our library is located, we changed our code to call LdrLoadDll directly.

Second Try:

Although LdrLoadDll correctly found our dll, when we used SpyStudio to check for errors, we saw that a call to NtOpenFile failed, reporting STATUS_ACCESS_DENIED. We realized that there was a security-related issue.

Using the icacls.exe utility, we set the DLL file privileges to allow read and execute access to low integrity processes. Also we added a special Windows 8 user named “ALL APPLICATION PACKAGES” to the list of users with permission to read and execute the DLL code.

Third Try:

NtOpenFile passed initial security checks, but our DLL was still not loading.

Continuing to research LdrLoadDll, we jumped into the kernel-mode of the “NtCreateSection” API and got that the “CiValidateImageHeader” function of ci.dll was returning  a STATUS_INVALID_IMAGE_HASH error so we added a digital signature to the file. To prevent future problems, we used a real certificate instead of the self-signed one.

Now CiValidateImageHeader was ok, but a later call to “CiValidateImageData” returned the same error. We then added the “/ph” parameter to the SignTool.exe utility to include pages hashes in the signing process.

Fourth Try:

Well, we thought: we have a signed dll, privileges are ok. Let’s try again.

FAIL.

This time, the culprit was a function named “SeGetImageRequiredSigningLevel” located in ntoskrnl.exe. SeGetImageRequiredSigningLevel checks the minimum certificate requirements to load a DLL inside a WinRT application.

We realized we needed to sign our DLL with a cross-certificate, like those used to sign kernel-mode drivers.

Conclusion:

We could not continue our tests because we do not have that kind of certificate right now, but we discovered that a kernel setting determines what kind of certificate is checked by SeGetImageRequiredSigningLevel.

This blog post explains how to manually bypass the security check and run untrusted applications on a Microsoft Surface device using WinDbg. We can follow a similar procedure to manually bypass the security check and correctly map and inject the DLL in the WinRT application on the desktop Windows operating system.

The exception:

Before starting our whole research, we already had a method for injecting a DLL in WinRT applications: copy the DLL file inside the System32 folder and voilá! Although you need administrative privileges to copy a file to the System32 folder, once there, you can load it using LoadLibrary without using a path, since this folder is one of the default locations the Windows operating system will search. In addition, because you are using a relative-path, some security checks are skipped. Another plus is that you will not ever need to digitally sign the file!

But like many companies, we want to avoid copying DLL files into the ever-growing System32 folder and keep our files in the same location as our application. This is why we started our research.

Related Services

  1. Windows driver development
  2. Office 365 Plugin Development
  3. Custom Software Development Company
  4. Data Loss Prevention Solution Development

Application Virtualization Testing and Troubleshooting with SpyStudio and Deviare

In Spy Studio: Solving an Issue on IE6 we troubleshot an issue that happens while virtualizing an Internet Explorer 6 (IE6) layer for Japanese using Symantec Workspace Virtualization. IE6 worked when IE8 was installed as the base operating system but not when the base was IE9. In the following screenshot we show how Spy Studio’s trace compare function analyzes the difference between running IE6 with the IE8 and with the IE9 base on the Windows 7 operating system.

As you can see, this user interface is much more informative than comparing a long list of line-oriented logs.

Imagine that an App-V Package does not work as expected. Can it be solved with the App-V Sequencer alone or do you need more advanced tools? Or what if the IT department tries to simplify the process of application virtualization with VMware ThinApp Factory, while the virtualization team tries to pinpoint an issue with Process Monitor? Comparing long logs is tedious and error prone. How can testing and troubleshooting be improved? These common issues extend to all application virtualization products, including: Symantec’s Workspace Virtualization, Spoon, and Cameyo.

Spy Studio and Deviare can both be used to troubleshoot virtualization. Spy Studio’s graphic console allows you to record application behavior and compare different runs in different environments. You can compare the differences between running a fully virtualized application and running it in a physical environment. Spy Studio complements Process Monitor, and can also import Process Monitor’s logs for comparison. In Comparing Traces with Spy Studio we provide a step by step example of how to compare traces.

Deviare is a more advanced tool which enables application virtualization professionals and QA engineers to build their own custom troubleshooting software.

If you are interested in learning how to develop and customize your own registry monitor visualization tool please take a look at Instrumenting Instrumenting Binary Applications with VBScript and Deviare.

Resources

  1. Application Virtualization Solution Overview and Feature Comparison Matrix
  2. Application Virtualization Troubleshooting and Support
  3. APP-V Troubleshooting … Demystified
  4. VMWare ThinApp Troubleshooting Blog
  5. P2V

Related Services

  1. Windows driver development
  2. Office 365 Plugin Development
  3. Application Packaging Services
  4. Custom Software Development Company
  5. Data Loss Prevention Solution Development

See Also

  1. Benchmarking IE6 Virtualization: VMWare ThinApp vs. Symantec Workspace Virtualization
  2. Benchmarking Microsoft Office’s PowerPoint Virtualization: Microsoft App-V Vs. Symantec Workspace Virtualization

Registration-Free COM in Deviare Plugins

The Deviare Interception Engine includes a feature that allows developers to add plugins to hooks. When a hooked API is called, it will raise the OnFunctionCalled method of all attached plugins to allow the reading and writing of parameters, and passing custom parameters to the INktSpyMgr object. Since the method is called in the context of the hooked application, the plugin will have local access to all process data.

We use COM as the bridge between the plugin code and the internal engine to support plugin development in C/C++ and any other .NET language. To use COM, the programmer must either register DeviareCOM libraries using RegSvr32 or use Registration Free COM.

The second method is best as it avoids registering components on the computer and asking for elevated privileges to accomplish the task. However in order to enable RegFree-COM, you will need to access the hooked executable manifest file, which is usually embedded in the application, and modify it, which may infringe copyright and have undesirable side effects. In addition, you cannot attach a manifest file to Deviare’s agent module: it will simply be ignored because the OS loader only parses executable manifests, and only on startup.

When a hooked api is called, an INktHookCallInfoPlugin object is created and passed to the plugins to let them know the context of the api call. But, how did we solve the management of COM objects without registering COM classes nor using a manifest file? Here is where Activation Context API comes in.

Activation context API lets us create, activate and manage activation contexts in the same way Windows loader does. First we embed our manifest file as a resource inside DvAgent.dll. Once the agent is attached to the hooked process, it creates an activation context using the data of the embedded resource.

When a hooked API is called, we must:

  1. Activate our custom context.
  2. Create the INktHookCallInfoPlugin object.
  3. Call the plugins callbacks (letting them manage all DeviareCOM objects as they want)
  4. Deactivate the custom context and continue execution.

Our benchmark shows that performance penalty in activating/deactivating contexts is minimal. If you need additional help using registration free COM please do not hesitate to ask in our forum.

Related Services

  1. Reverse Engineering Services
  2. Windows driver development
  3. Custom Software Development Company
  4. Office 365 Plugin Development
  5. Data Loss Prevention Solution Development

See Also

  1. Improving Deviare Hooking Performance with Custom Hooks

Improving Deviare Hooking Performance with Custom Hooks

More Binary Instrumentation Alternatives

Deviare now has custom hooks to improve hooking performance. With custom hooks, two “OnFunctionCall” events are triggered: one in the SpyMgr process, and the other within the agent. The custom hook can send data, or custom parameters. to the SpyMgr process. The custom Deviare modules running in the agent have access to all process data, including file and registry handles. Since custom hooks access local process data, it is now possible to get the full key path of a registry HKEY value and transmit the resulting string as a custom parameter instead of doing a “DuplicateHandle” call in the SpyMgr process. You can also combine asynchronous hooking with custom hooks to keep the “OnFunctionCall” event in SpyMgr from blocking the flow of the application.

The Deviare Hooking Engine aims to simplify the “hooking experience” for people who are outside the Windows internals, x86/x64 Assembly, and reverse engineering fields, there is usually a penalty when you want to abstract something complex like API function hooking in a developer friendly COM component like Deviare. Our custom hooks are designed to meet different needs.

Another interesting advantage of using custom hooks is that you can mix different programming languages. For example, you can add a custom hook in C++ but notify the SpyMgr in C#, or vice versa.

The sample code below monitors and intercepts file mappings via the function MapViewOfFile on notepad.exe 32 and 64 bit. The custom hook analyzes the buffer in search of a specific string posing as malware. The read is cancelled if that string is found in the buffer. The sample code has two modes to illustrate the difference between only using SpyMgr, and relying on custom hooks: the displayed combo switches from one mode to the other. Custom hooks are also essential for video and audio processing. If you are interested in bootstrapping a project that requires audio hooking, do not hesitate to look at our Audio Recorder API. It will save you a lot of time and money. This code also hooks both 32 and 64 bit process from the same (“Any CPU”) assembly.

Code

The code is available on github.

Prerequisites

  1. Install the latest Deviare version
  2. Register 32 and 64 bit COM DLLs (although registration-free COM can be used in custom hooks too)
  3. Download the source code
  4. Copy Nektra.Deviare2.dll to the Lib directory inside the project
  5. Build the Debug configuration
  6. Run Notepad
  7. Run the hooking console

Related Services

  1. Windows driver development
  2. Reverse Engineering Services
  3. Custom Software Development Company
  4. Data Loss Prevention Solution Development

 

WLMailAPI Works With Windows Live Mail 2012 and Windows 8

Nektra announces the release of the new version of WLMailApi, the most used SDK designed to develop plugins in Windows Live Mail 2009 2011 and 2012

What’s new

WLMailAPI Works With Windows Live Mail 2012 and Windows 8
Released on September of 2012

  •     Works with all versions that Microsoft Supports
  •     Works with Windows Live Mail 2012
  •     Works with Windows 8 (all builds)
  •     Improved Performance

Request trial version here!  License: Some changes were introduced to the license for WLMailApi. Now, it is necessary to purchase a license for each developer that will use the library or by each product that will be developed using the library, taking into account whichever number is greater. Contact us to ask any commercial question or use the technical inquiries.

Thanks,
Leo Pasut
Business Development

Automating Google’s Doodles: 4.9 Second Record on Hurdles

And now for something completely different. The AutoIt script below will make you run Google’s hurdles doodle faster than Usain Bolt: 4.9 seconds is our automation record. Can you improve it? Surely there is room for more records before the London 2012 Olympics end.

We deal with AutoIt on a daily basis since we use it to test Internet Explorer layers in the Symantec Endpoint Virtualization suite. The script was written by Matias Palomera, one of our junior testing guys who also likes to automate Facebook games. It is amazing how motivational the first programming language you learnt can be, even if that language is AutoIt.

The script provided is very simple and blind: it only sends keyboard events based on manual adjustments (time delays, coordinates, and Google Chrome path) without retrieving infrormation from the browser. Our script would have to get the information from the browser to adjust the speed of the runner more precisely. We used AutoIt’s APIs to send information to IE. It does not provide APIs for WPF, Silverlight, and legacy VB6 controls such as TreeView, FlexGrid, DataGrid, and ListView. Our Deviare hooking technology would be a good choice when dealing with these user interface controls.

AutoIt Script

The code is available at github.

Windows Live Mail API Anti-Virus Example

One of the top uses of our Windows Live Mail API is integrating a vendor antivirus to the Windows Live Mail desktop client. For example, Trend Micro’s Titanium Security Solutions uses it to integrate with Windows Live Mail and recognize viruses. The C# code sample below uses the nClam library to interface with an open source project: Clam AntiVirus.

While integrating Windows Live Mail API with an antivirus engine helps to mitigate risks from e-mails there are obviously many other sources of security risks. Exploits came in many disguises: they can take advantage of vulnerabilities of web browsers or of network services running on your machine. The Deviare Interception Engine can unmask them. It intercepts network APIs and can be used to discover and deactivate malware at the network level, not just within a specific application.

The code can be modified to work with commercial antivirus engines such as those by Symantec, Trend Micro, McAfee, Kaspersky, F-Secure, ESET, AVG, Microsoft, Bitdefender, and GFI. Since the list is long and each of those APIs has different idiosyncrasies, companies such as OPSWAT have developed a unified API. The various “Malware Analysis Online Services” can also be easily integrated to a custom solution.

Code

Prerequisites

  1. Visual Studio 2010
  2. Request a trial for Windows Live Mail API here
  3. Download ClamAV here and VC redistributables if needed
  4. Extract the Clam Anti Virus binaries to a specific directory and create an empty folder called DB there
  5. Run CMD as Administrator, go to the ClamAV directory and run freshclam.exe
  6. Install the ClamAV service by running: clamd –install
  7. Install the ClamAV update service by running: freshclam –install
  8. Download nClam from here and add/modify it as a reference in the project
  9. Get the Windows Live Mail API Anti-Virus example from github

Main.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Microsoft.Win32;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using NktWLMailApi;
using NktWLMailApiInit;
using NktWLMailStore;
using nClam;

namespace Antivirus
{
    public class Main
    {
        static string pluginsKey = "Software\Nektra\WLMailApi\Plugins";
        static string pluginValueName = "AntivirusDemo";
        static string pluginValueData = "Antivirus.Main";
        private NktWLMailApiInit.WLMailApiInit wlmailApiInit;
        private NktWLMailApi.WLMailApi wlmailApiCore;
        private NktWLMailStore.FolderManager folderManager;
        private NktWLMailStore.MailAccountManager accountManager;
        private Utils utils;
        private nClam.ClamClient clamClient;
        private const string CLAM_HOST = "localhost";
        private const int CLAM_PORT = 3310;

        [ComRegisterFunctionAttribute]
        public static void RegisterFunction(Type t)
        {
            RegistryKey key = Registry.LocalMachine.OpenSubKey(pluginsKey, true);
            if (key == null)
            {
                key = Registry.LocalMachine.CreateSubKey(pluginsKey);
                if (key == null)
                {
                    System.Windows.Forms.MessageBox.Show("Error registering component");

                    return;
                }
            }

            key.SetValue(pluginValueName, pluginValueData);
            key.Close();
        }

        [ComUnregisterFunctionAttribute]
        public static void UnregisterFunction(Type t)
        {
            RegistryKey key = Registry.LocalMachine.OpenSubKey(pluginsKey, true);
            if (key == null)
            {
                return;
            }

            key.DeleteValue(pluginValueName, false);
            key.Close();
        }

        public Main()
        {
            wlmailApiInit = new NktWLMailApiInit.WLMailApiInit();
            wlmailApiInit.OnInit += new NktWLMailApiInit.IWLMailApiInitEvents_OnInitEventHandler(wlmailApiInit_OnInit);
            wlmailApiInit.OnShutdown += new NktWLMailApiInit.IWLMailApiInitEvents_OnShutdownEventHandler(wlmailApiInit_OnShutdown);

        }

        void wlmailApiInit_OnShutdown()
        {
            wlmailApiCore = null;
            wlmailApiInit.OnInit -= new NktWLMailApiInit.IWLMailApiInitEvents_OnInitEventHandler(wlmailApiInit_OnInit);
            wlmailApiInit.OnShutdown -= new NktWLMailApiInit.IWLMailApiInitEvents_OnShutdownEventHandler(wlmailApiInit_OnShutdown);

            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }

        void wlmailApiInit_OnInit()
        {
            wlmailApiCore = new NktWLMailApi.WLMailApi();
            folderManager = new NktWLMailStore.FolderManager();
            accountManager = new NktWLMailStore.MailAccountManager();

            utils = new Utils(wlmailApiCore, folderManager, accountManager);

            this.clamClient = new ClamClient(CLAM_HOST, CLAM_PORT);

            this.wlmailApiCore.OnDatabaseChange += new NktWLMailApi.IWLMailApiEvents_OnDatabaseChangeEventHandler(wlmailApiCore_OnDatabaseChange);
        }

        void wlmailApiCore_OnDatabaseChange(NktWLMailApi.tagDATABASE_TRANSACTION dt, ulong folderId, ulong objId, ulong newParentId)
        {
            var folder = folderManager.GetFolder(folderId);

            if (utils.IsFromQuickViews(folder) || !ShouldBeHandled(dt))
            {
                utils.ReleaseComObject(folder);
                return;
            }

            var message = folder.GetMessage((int)objId);

            switch (dt)
            {
                case tagDATABASE_TRANSACTION.NKT_TR_INSERT_MESSAGE:
                    if (folder.IsSent() == 0 && folder.IsOutbox() == 0)
                    {
                        List<string&rt; virusList = MessageAttachmentsContainViruses(message);

                        if (virusList.Count &rt; 0)
                        {
                            string virusNames = "";
                            foreach (string virusName in virusList)
                            {
                                if (virusNames != "")
                                    virusNames += "," + virusName;
                                else
                                    virusNames = virusName;
                            }
                            MessageBox.Show(string.Format("The message contains the following viruses: {0}", virusNames));
                        }
                    }
                    break;
            }
            utils.ReleaseComObject(message);
            utils.ReleaseComObject(folder);
        }

        private string ClamAntiVirusScanning(string filename) {
            var scanResult = this.clamClient.ScanFileOnServer("c:\users\Admin\Desktop\Temp");

            switch (scanResult.Result)
            {
                case ClamScanResults.Clean:
                    return null;
                    break;

                case ClamScanResults.VirusDetected:
                    return scanResult.InfectedFiles.First().VirusName;
                    break;

                case ClamScanResults.Error:
                    return null;
                    break;
            }

            return null;

        }

        private string GetTemporaryDirectory() // http://stackoverflow.com/questions/278439/creating-a-temporary-directory-in-windows
        {
            string tempDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
            Directory.CreateDirectory(tempDirectory);
            return tempDirectory;
        }

        private List<string&rt; MessageAttachmentsContainViruses(NktWLMailStore.Message message)
        {
            List<string&rt; virusList = new List<string&rt;();

            var attachment = message.GetFirstAttachment();
            string temporaryDirectory = this.GetTemporaryDirectory();

            while (attachment != 0)
            {
                string fullpath = Path.Combine(temporaryDirectory, message.GetFilename(attachment).ToLower() + Path.GetRandomFileName());

                if (message.SaveBodyToFile(attachment, fullpath, 0) == 0)
                {
                    utils.ShowMsgBox("An error occurred while saving message attachments.");

                    break;
                }

                string scanResultString = ClamAntiVirusScanning(fullpath);
                if (scanResultString != null)
                {
                    virusList.Add(scanResultString);
                }

                attachment = message.GetNextAttachment();
            }

            utils.ReleaseComObject(message);

            return virusList;
        }        

        private bool ShouldBeHandled(tagDATABASE_TRANSACTION dt)
        {
            return (dt == tagDATABASE_TRANSACTION.NKT_TR_INSERT_MESSAGE ||
                    dt == tagDATABASE_TRANSACTION.NKT_TR_DELETE_MESSAGE ||
                    dt == tagDATABASE_TRANSACTION.NKT_TR_RENAME_FOLDER ||
                    dt == tagDATABASE_TRANSACTION.NKT_TR_DELETE_FOLDER);
        }
    }

    // Do not pay attention to this class.
    public class WindowWrapper : IWin32Window
    {
        public WindowWrapper(IntPtr handle)
        {
            _hwnd = handle;
        }

        public IntPtr Handle
        {
            get { return _hwnd; }
        }

        private readonly IntPtr _hwnd;
    }
}

Utils.cs

using System;
using System.Globalization;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using NktWLMailApi;
using NktWLMailApiInit;
using NktWLMailStore;
using System.Windows.Forms;
using Message = NktWLMailStore.Message;

namespace Antivirus
{
    public class Utils
    {
        private WLMailApi _wlmailApiCore;
        private FolderManager _folderManager;
        private MailAccountManager _accountManager;

        private const ulong QuickViewsFolderID = 7;

        public Utils(WLMailApi wlmailApiCore, FolderManager folderManager, MailAccountManager accountManager)
        {
            _wlmailApiCore = wlmailApiCore;
            _folderManager = folderManager;
            _accountManager = accountManager;
        }

        public void ShowMsgBox(string text)
        {
            ShowMsgBoxHwnd(_wlmailApiCore.GetMainWindow(), text);
        }

        public void ShowMsgBox(IntPtr ownerWindow, string text)
        {
            ShowMsgBoxHwnd((int)ownerWindow, text);
        }

        private static void ShowMsgBoxHwnd(int hwnd, string text)
        {
            MessageBox.Show(new WindowWrapper((IntPtr)hwnd), text, @"WLMailApi", MessageBoxButtons.OK,
                            MessageBoxIcon.Information);
        }

        public Message GetFirstSelectedMessage()
        {
            var folder = GetCurrentFolder();

            var messageID = _wlmailApiCore.GetFirstSelectedMessageID();

            var message = folder.GetMessage(messageID);

            ReleaseComObject(folder);

            return message.GetID() == -1 ? null : message;
        }

        public Message GetNextSelectedMessage()
        {
            var folder = GetCurrentFolder();

            var messageID = _wlmailApiCore.GetNextSelectedMessageID();

            var message = folder.GetMessage(messageID);

            ReleaseComObject(folder);

            return message.GetID() == -1 ? null : message;
        }

        public Folder GetCurrentFolder()
        {
            var folderId = (ulong)_wlmailApiCore.GetSelectedFolderID();
            return _folderManager.GetFolder(folderId);
        }

        public bool IsFromQuickViews(Folder folder)
        {
            var rootFolder = _folderManager.GetFolder((int)tagSPECIALFOLDERID.NKT_FOLDER_ROOT);
            var rootFolderId = rootFolder.GetID();
            ReleaseComObject(rootFolder);
            rootFolder = null;

            var childrenIds = GetChildrenIds((int)rootFolderId);

            var quickViewsFoldersIds = new List<int&rt;();

            foreach (var childId in childrenIds)
            {
                var child = _folderManager.GetFolder((ulong)childId);
                if (child.GetID() == QuickViewsFolderID)
                {
                    quickViewsFoldersIds = GetChildrenIds(childId);
                    ReleaseComObject(child);
                    break;
                }
                ReleaseComObject(child);
            }

            return quickViewsFoldersIds.Contains((int)folder.GetID());
        }

        private List<int&rt; GetChildrenIds(int folderId)
        {
            var folder = _folderManager.GetFolder((ulong)folderId);

            var childFolder = folder.GetFirstChild();

            var childrenIds = new List<int&rt;();

            while (childFolder != null)
            {
                childrenIds.Add((int)childFolder.GetID());
                ReleaseComObject(childFolder);
                childFolder = folder.GetNextChild();
            }

            childFolder = null;

            ReleaseComObject(folder);
            folder = null;

            return childrenIds;
        }

        public int CommitIfNotInQuickViews(Message msg)
        {
            var folder = _folderManager.GetFolder(msg.GetFolderID());

            if (IsFromQuickViews(folder))
            {
                ShowMsgBox("You can't save nor modify a message " +
                           "in a Quick Views folder.n");
                return 0;
            }

            ReleaseComObject(folder);
            folder = null;

            return msg.Commit();

        }

        public int MoveIfNotInQuickViews(Message msg, int destFolderId)
        {
            var folder = _folderManager.GetFolder(msg.GetFolderID());

            if (IsFromQuickViews(folder))
            {
                ShowMsgBox("You can't move a message you selected " +
                            "from a Quick Views folder.n");
                return 0;
            }

            ReleaseComObject(folder);
            folder = null;

            return _folderManager.MoveMessage(msg.GetFolderID(), (ulong)destFolderId, msg.GetID());
        }

        public void CleanWLMailApiReferences()
        {
            _wlmailApiCore = null;
            _folderManager = null;
            _accountManager = null;
        }

        public int ReleaseComObject(object obj)
        {
            var remainingRefs = -1;

            if (obj != null)
            {
                remainingRefs = Marshal.ReleaseComObject(obj);
                obj = null;
            }

            return remainingRefs;
        }

        public class RegexUtils
        {
            static bool _invalid;

            public static bool IsValidEmail(string strIn)
            {
                _invalid = false;
                if (String.IsNullOrEmpty(strIn))
                    return false;

                // Use IdnMapping class to convert Unicode domain names.
                strIn = Regex.Replace(strIn, @"(@)(.+)$", DomainMapper);
                if (_invalid)
                    return false;

                // Return true if strIn is in valid e-mail format.
                return Regex.IsMatch(strIn,
                       @"^(?("")(""[^""]+?""@)|(([0-9a-z]((.(?!.))|[-!#$%&'*+/=?^`{}|~w])*)(?<=[0-9a-z])@))" +
                       @"(?([)([(d{1,3}.){3}d{1,3}])|(([0-9a-z][-w]*[0-9a-z]*.)+[a-z0-9]{2,17}))$",
                       RegexOptions.IgnoreCase);
            }

            private static string DomainMapper(Match match)
            {
                // IdnMapping class with default property values.
                var idn = new IdnMapping();

                string domainName = match.Groups[2].Value;
                try
                {
                    domainName = idn.GetAscii(domainName);
                }
                catch (ArgumentException)
                {
                    _invalid = true;
                }
                return match.Groups[1].Value + domainName;
            }
        }

    }
}

Related Services

  1. Windows driver development
  2. Office 365 Plugin Development
  3. Custom Software Development Company
  4. Data Loss Prevention Solution Development

Windows API Hooking in Python with Deviare

The code below uses Python to intercept the CreateFile function on the kernel32.dll to forbid opening certain files. It hooks the CreateFile function for the notepad.exe application. The Python code is very small and to the point, and you can customize it for your own purposes. For example, it can be used to sandbox an application to restrict it to a certain set of files, registry keys, and network accesses.

Python has a relatively long history of being used in the computer security field. Among IDA Pro plugins, IDAPython is more popular than IDARub. If search results can be used as a measure of success, a search for each major scripting language plus “reverse engineering” returns:

Query# of results
“python” AND “reverse engineering”215K
“perl” AND “reverse engineering”184K
“ruby” AND “reverse engineering”95.2K

 

Why is that? some people wrote specifically about that in Python and Reverse EngineeringPython Arsenal for Reverse Engineering Whitepaper, and a good video of RECON 2008: Reverse Engineering Dynamic Languages a Focus on Python, Aaron Portn.  The bias towards a programming language might be related to a network effect, but even so, a programming language with a vibrant community is fertile ground for trying out new ideas.

Code

Prerequisites

  1. Install Python 2.7.3 for Windows
  2. Download Deviare and Register DeviareCOM.dll and DeviareCOM64.dll if the script should under an x64 platform: open a command prompt with administrator rights, navigate to the folder where the Deviare’s *.dll files are located, execute “regsvr32 DeviareCOM.dll” and “regsvr32 DeviareCOM64.dll”
  3. Download and install Python Win32 Extensions
  4. The code is also available on github

Python Win32 Extensions Notes

Be careful to download the appropriate version for your platform and Python version.
If you get a message stating that you haven’t installed Python in your system yet (but you did and you are completely sure that you downloaded the correct Python Win32 Extensions installer) you can copy the registry folder HKEY_LOCAL_MACHINESOFTWAREWow6432NodePython to HKEY_LOCAL_MACHINESOFTWAREPython (or viceversa). To do this, you should:
  1. Open the registry editor (start -> run… -> “regedit”)
  2. Find the folder you want to copy
  3. Right click on the folder and select “Export”. This will allow you to save a file with the registry folder content
  4. Edit the file you just created and change all the paths in the file accordingly to where you want to move the folder
  5. Save the file and then double-click it. A message box should appear prompting if you want to add information to the registry. Click “yes” and you are done
  6. Once you’ve done this, the Python Win32 Extensions installer should recognize your Python installation
If you still have problems to install this demo, please visit our forum to get further assistance.

DeviarePythonDemo.py

import win32com.client
import ctypes

from EventHandlers import NktSpyMgrEvents
from AuxFunctions import *

spyManager = win32com.client.DispatchWithEvents('DeviareCOM.NktSpyMgr', NktSpyMgrEvents)
spyManager.Initialize()

StartNotepadAndHook(spyManager)

MessageBox = ctypes.windll.user32.MessageBoxA
MessageBox(None, 'Press OK to end the demo.', 'Deviare Python Demo', 0)

EventHandlers.py

import win32com.client

class NktSpyMgrEvents:
	def OnProcessStarted(self, nktProcessAsPyIDispatch):
		nktProcess = win32com.client.Dispatch(nktProcessAsPyIDispatch)
		if (nktProcess.Name == "notepad.exe"):
			print 'Notepad was started.'

	def OnProcessTerminated(self, nktProcessAsPyIDispatch):
		nktProcess = win32com.client.Dispatch(nktProcessAsPyIDispatch)
		if (nktProcess.Name == "notepad.exe"):
			print 'Notepad was terminated.'

	def OnFunctionCalled(self, nktHookAsPyIDispatch, nktProcessAsPyIDispatch, nktHookCallInfoAsPyIDispatch):
		nktHookCallInfo = win32com.client.Dispatch(nktHookCallInfoAsPyIDispatch)
		nktProcess = win32com.client.Dispatch(nktProcessAsPyIDispatch)

		if (nktHookCallInfo.IsPreCall):
			fileName = self.GetFileNameParam(nktHookCallInfo.Params())
			if (fileName.endswith('.txt')):
				self.SkipCall(nktHookCallInfo, nktProcess)

# Aux Functions

	def SkipCall(self, nktHookCallInfo, nktProcess):
		nktHookCallInfo.SkipCall()
		if (nktProcess.PlatformBits == 64):
			nktHookCallInfo.Result().LongLongVal = -1
		else:
			nktHookCallInfo.Result().LongVal = -1
		nktHookCallInfo.LastError = 5

	def GetFileNameParam(self, nktParamsEnum):
		nktParam = nktParamsEnum.First()
		return nktParam.Value

AuxFunctions.py

from subprocess import *

def GetPIDByProcessName(aProcessName):
	for proc in psutil.process_iter():
		if proc.name == aProcessName:
			return proc.pid

def OpenNotepadAndGetPID():
	print 'Starting Notepad...'
	pid = Popen("notepad").pid
	print 'Notepad started successfully'
	return pid

def HookFunctionForProcess(spyManager, functionModuleAndName, notepadPID):
	print 'Hooking function ' + functionModuleAndName + ' for Notepad...'
	hook = spyManager.CreateHook(functionModuleAndName, 0)
	hook.Attach(notepadPID, True)
	hook.Hook(True)
	print 'Notepad successfully hooked'
	return hook

def StartNotepadAndHook(spyManager):

	notepadPID = OpenNotepadAndGetPID()
	hook = HookFunctionForProcess(spyManager, "kernel32.dll!CreateFileW", notepadPID)

Related Services

  1. Office 365 Plugin Development
  2. Custom Software Development Company
  3. Data Loss Prevention Solution Development

Related Services

  1. Reverse Engineering Services
  2. Windows driver development
  3. Application Packaging Services
  4. Custom Software Development Company
  5. Data Loss Prevention Solution Development

If you liked this article, you might also like: