The Moose and Squirrel Files

October 22, 2009

Detecting when Altiris Bootworks is Installed

Filed under: Code — Tags: , , , — networknerd @ 6:14 am

When installing Checkpoint full disk encryption we ran into some problems on computers with Altiris Bootworks still installed. Normally Bootworks can be detected through a registry key, and uninstalled if the key is present. However we found a number of computers with Bootworks were missing the key.

The quick solution to detect bootworks was to read the bootsector of the disk and look for some identifying strings. The code below shows how to read from a physical disk.  Note this has only been tested in Windows XP, and you require admin privileges.  The code below was called from a startup script so privilege wasn’t an issue.

When reading from a physical disk we need to seek, read and write in multiples of sector size and on sector boundaries. See Microsoft KB article 100027.  I use WMI to get the number of bytes per sector for the drive.

I found the signature by extracting the bootsector using a copy of dcfldd that was compiled for cygwin. I dumped it to file using the command below.
dcfldd if=”\\\\.\\physicaldrive0 of =”bootsec.bin” count=1

The file bootsec.bin can then be opened using good old debug to get the hex/ascii display

The same result can be achieved by booting to a linux live cd and using the command below.

 dd if=/dev/sda count=1 | hexdump -C

 Listing 1


using System;
using System.IO;
using System.Management;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;

namespace bwcheck
{
    class Program
    {
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError=true)]
        internal static extern SafeFileHandle CreateFile(string lpFileName, int dwDesiredAccess, int dwShareMode,
            IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, SafeFileHandle hTemplateFile);

        internal const int GENERIC_READ = unchecked((int)0x80000000);
        internal const int OPEN_EXISTING = 3;
        internal const int FILE_ATTRIBUTE_NORMAL = 0x80;
        const String SIGNATURE = "Altiris EBootMastr";
        const int SEEKOFFSET = 3;
        const int LENGTH_TO_READ = 18;   // LENGTH_TO_READ = SIGNATURE.Length;
        const int RETCODE_SUCCESS = 0;
        const int RETCODE_IOERROR = 1;
        const int RETCODE_BADSIGNATURE = 2;
        const int RETCODE_HIT_EOF = 3;
// NB The where clause requires additional escaping even with the @string literal
        const String WMIQRY = @"Select * from win32_diskdrive where Name='\\\\.\\PhysicalDrive0'";
        const String WMI_NS = @"\\.\root\cimv2";
        //const String WMIQRY = "Select * from win32_diskdrive ";

        public static int Main(string[] args)
        {

            // TODO: Implement Functionality Here
            int retcode = RETCODE_SUCCESS;
            SafeFileHandle h = null;
            h = CreateFile("\\\\.\\PhysicalDrive0",
                            GENERIC_READ, 0, IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
                            new SafeFileHandle(IntPtr.Zero, true));

            if (! h.IsInvalid ) {
                try {
                    //Find the bytes per sector for the disk
                    //We must read, write and seek in multiples of sector size (ref: http://support.microsoft.com/kb/q100027)
                    //This is true even when we convert the handle to a filestream.
                    ManagementObjectSearcher objSearch = new ManagementObjectSearcher(WMI_NS, WMIQRY);
                    int bytespersector = 0;
                    foreach (ManagementObject objResult in objSearch.Get()){
                        bytespersector = Convert.ToInt32(objResult["BytesPerSector"]);
                    }
                    FileStream fstream = new FileStream(h, FileAccess.Read);
                    // Read from stream
                    Byte[] chunk = new Byte[bytespersector];
                    int bytesRead;
                    int bytesTotal = 0;
                    int bytesToRead =  bytespersector;
                    while (bytesToRead > 0) {
                        bytesRead = fstream.Read(chunk,bytesTotal,bytesToRead);
                        if (bytesRead == 0) {
                            break; //end of filestream condition
                        }
                        bytesToRead -= bytesRead;
                        bytesTotal += bytesRead;
                    }
                    if (bytesToRead > 0 ) {
                        retcode = RETCODE_HIT_EOF;
                    }
                    System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
                    String s = enc.GetString(chunk,SEEKOFFSET,LENGTH_TO_READ);
                    Console.WriteLine("{0}", s);
                    if (! s.Equals(SIGNATURE)){
                        retcode = RETCODE_BADSIGNATURE;
                    }

                } catch (Exception e) {
                    Console.WriteLine(e.ToString());
                    retcode = RETCODE_IOERROR;
                }
            }
            else
            {
                // get error code and throw
                int error = Marshal.GetLastWin32Error();
                Console.WriteLine("Last WIN32 Error: {0}", error);
                retcode = RETCODE_IOERROR;
            }
            return retcode;
        }
    }
}

Create a free website or blog at WordPress.com.