UEFI News and Commentary

Friday, September 21, 2012

UEFI/Win8 Security Vulnerability (Yawn...)

Put "UEFI" or "Win8" next to rootkit in an article, as was done by The Register, and you are sure to generate some buzz. Based on a technical report by ITSEC (found here), it talks about how you can install a root kit, if you can get your code loaded so that it can modify the Windows 8 boot loader. As taken apart by Matthew Garrett (analysis here), Linux developer, the rootkit is neither new nor unexpected.

Basically, to quote the rootkit author (Marco Giuliani) in the Register article: "Our research attempts to show the industry that the new UEFI platform is still as insecure as the old BIOS technology, it's still vulnerable to the old attacks if the SecureBoot technology is not turned on by default," [emphasis mine] Which, by the way, Microsoft is requiring every OEM to do as part of its partner program.

So the, how did The Register come up with the tag line, "Arr, 'tis typical: Redmond swabs lag behind OS X, again" Really? I am not sure how Secure Boot lags behind the OS X validation scheme, but this ITSEC report sure doesn't show it. In fact, it seems to me that OS X is pretty much in the same camp as Win 8 when it comes to multi-OS booting.


Thursday, September 20, 2012

HOW TO: Move an Image Using a Timer

Now that I've been able to get images to move using keyboard input, my next project has been to get an image to move around on its own and bounce off the edges of the screen.  This article will describe the process to do that, and it assumes that you have followed the directions for previous articles detailing how to move an image using keyboard input.

The first thing I realized about this is that getting an image to move on its own will require a timer.  SetTimer() is a function in Boot Services that will signal an event every so often. I can then use WaitForEvent() to wait until the timer signals an event and then move the image according to that event, rather than user input.

So let's walk through the code that we use to get this image bouncing around.

Firstly, we have our global variables.  We still need the instance of EFI_GRAPHICS_OUTPUT_PROTOCOL, the dimensions of the image, and the black pixel to clear the image, so we can keep those.  Only one more is needed, and that's a pointer to an EFI_EVENT.  This event  will be a simple, empty event that the timer will signal after every given time interval.

EFI_GRAPHICS_OUTPUT_PROTOCOL *mGraphicsOutput;
UINTN mHeight;
UINTN mWidth;

EFI_GRAPHICS_OUTPUT_BLT_PIXEL mBlack = {0, 0, 1};

EFI_EVENT mEvent;

Now we can get into the meat of the actual function that bounces this image around the screen.  We start off by initializing the EFI_EVENT using CreateEvent().  Like I mentioned earlier, it's an empty timer event so we set the first parameter (the event type) to EVT_TIMER, the last one as a pointer to mEvent, and the others are 0 and NULL.

  gBS->CreateEvent (
    EVT_TIMER,
    0,
    NULL,
    NULL,
    &mEvent
    );

After that, we call SetTimer() to create our timer that'll be the signal when to move the image.  The first parameter is mEvent, the event that is signaled whenever the timer goes off.  Second, we have to specify what sort of a timer this is, so we put TimerPeriodic, which means the timer will go off every interval, rather than only once.  The final parameter is the time interval that determines how often we want the timer to signal.  It's measured in increments of 100 nanoseconds, so I put a large number in.

  gBS->SetTimer (
    mEvent,
    TimerPeriodic,
    1000000  
    );

Next, we need to initialize all our variables to their starting values.  We give the ScanCode an intial value of NULL just to start.  DeltaX and DeltaY are the values that help determine which direction the image will be moving.  I set them both to a non-zero number so that the image won't simply bounce up and down.  After that, we have to initialize the array of events that WaitForEvent() is going to wait for.  First is one that reads if the user pressed something on the keyboard so that we can have an exit condition.  Second is mEvent, which is what the timer will signal every time interval. And finally, we initialize the current coordinates of the image.

  Key.ScanCode = SCAN_NULL;

  DeltaX = 5;
  DeltaY = 5;
  events[0] = gST->ConIn->WaitForKey;
  events[1] = mEvent;
  CurrentX = (mGraphicsOutput->Mode->Info->HorizontalResolution / 2) - (mWidth / 2);
  CurrentY = (mGraphicsOutput->Mode->Info->VerticalResolution / 2) - (mHeight / 2);

Finally, we get to our loop.  The condition for this loop is that the [End] key is not pressed.  If it is, the application will quit.  We start off by waiting for an event.  It will be waiting either for a timer signal or for a keyboard key to be pressed.  So once an event is signaled, we have to check to see which it is.  If it was a key press, we read which key was pressed and check the loop condition.  If [End] was pressed, we exit the loop.

do {
    gBS->WaitForEvent (2, events, &index);

    if (index == 0)  {
      gST->ConIn->ReadKeyStroke(gST->ConIn, &Key);
      continue;

So if it wasn't a keyboard event that was signaled, it must have been a timer event, so we have to move the image.  The first step is to set the new values of the X and Y coordinates.  We do that by adding the values of DeltaX and DeltaY to the current coordinates.  We then have to check to see if the image would go beyond the borders of the window.  If they do, set the new coordinates to the value so the image is right on the edge of the screen, and then change DeltaX or DeltaY so that the image will "bounce" off the wall.  If it hits the left or right borders, change the sign of DeltaX.  If it hits the top or bottom, change the sign of DeltaY.

} else {
      
      NewX = CurrentX + DeltaX;
      NewY = CurrentY + DeltaY;

      if (NewX + mWidth > mGraphicsOutput->Mode->Info->HorizontalResolution) {
        NewX = mGraphicsOutput->Mode->Info->HorizontalResolution - mWidth;
        DeltaX = -DeltaX;
      } else if (NewX < 0) {
        NewX = 0;
        DeltaX = -DeltaX;
      }
      if (NewY + mHeight > mGraphicsOutput->Mode->Info->VerticalResolution) {
        NewY = mGraphicsOutput->Mode->Info->VerticalResolution - mHeight;
        DeltaY = -DeltaY;
      } else if (NewY < 0) {
        NewY = 0;
        DeltaY = -DeltaY;
      }

The final parts of the loop are mainly concerned with displaying the image.  We use the EfiBltVideoFill operation of Blt() to clear the image and then call our own function, DisplayImageAt() to display the image, using the new coordinates.  Lastly, we set the current coordinates to the coordinates of the newly displayed image.

      mGraphicsOutput->Blt(
                      mGraphicsOutput,
                      &mBlack,
                      EfiBltVideoFill,
                      0,
                      0,
                      CurrentX,
                      CurrentY,
                      mWidth,
                      mHeight,
                      0
                      );
      DisplayImageAt (NewX, NewY);
    
      CurrentX = NewX;
      CurrentY = NewY;
    }
   
  } while (Key.ScanCode != SCAN_END);

The last two lines of the function lie outside the loop, and they simply clear the screen and return EFI_SUCCESS.  

  gST->ConOut->Reset (gST->ConOut, FALSE);
  return EFI_SUCCESS;

And that's it!  The image will move around the screen on its own and "bounce" off the edges of the window, and the application will quit when the [End] key is pressed.

If you are interested in seeing the entirety of the code, let me know and I'll get it sent to you.






Monday, September 17, 2012

HOW TO: Move an Image using Keyboard Input

The most recent project I've been working on has been to move an image around the screen using keyboard input.  I described in a previous post how I had put together a function that displayed an image.  After making a few changes and doing some more work, I was able to create a function that allows the user to use the arrow keys to move the image around the display window.  This article will describe the process to achieve this.  It assumes you have followed the instructions described in the post mentioned above to display an image.

My plans were pretty basic.  The arrow keys would be used to move the image, and I'd use some other key to quit the application.  I would need some sort of loop that would read keyboard input and break out when the proper key was pressed.  In the UEFI spec, I found a function, WaitForEvent(), that would halt execution until a specified event occurred, as well as functions for reading which key was pressed on the keyboard.  After getting that working, it was simply a matter of making sure it dealt with the edges of the graphics output window properly and consolidating some code.

Now, let's go through the code.  Firstly, I made some changes to the DisplayImage() function that I wrote previously.  Since I knew I'd have to display the image over and over again, I wanted to repeat as little code as possible.  Blt() is the function that actually displays the image.  Among the parameters, the data buffer, the instance of EFI_GRAPHICS_OUTPUT_PROTOCOL, and the dimensions of the image all remain constant once they have been initialized, so I made them global variables that can be reached by other functions.

EFI_GRAPHICS_OUTPUT_PROTOCOL *mGraphicsOutput;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *mBlt;
UINTN mHeight;
UINTN mWidth;

I then created a new function, DisplayImageAt(), that simply took the new coordinates of the image as parameters and called Blt().  It made the code cleaner and easier to read.

int DisplayImageAt (UINTN X, UINTN Y) 
{
  mGraphicsOutput->Blt (
                     mGraphicsOutput,
                     mBlt,
                     EfiBltBufferToVideo,
                     0,
                     0,
                     X,
                     Y,
                     mWidth,
                     mHeight,
                     mWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
                     );
  return 0;
}

Now, when we move the image around the screen, we'll have to clear where the image previously was before displaying the image in its new location.  Instead of clearing the entire screen, we can use Blt() to clear it by setting EfiBltVideoFill as the operation.  Now, EfiBltVideoFill takes the top left-hand pixel in an image and fills the specified area with the color of that pixel.  To ensure we always have a black pixel, we can just make one of our own outside the function declaration so we can access it later.

EFI_GRAPHICS_OUTPUT_BLT_PIXEL mBlack = {0, 0, 1};

Next we have to write the function that actually lets us move the image around.  So let's walk through this.

First, we set the current coordinates to wherever the image was initially displayed (in my case, it was centered on the screen).

  XCoordinate = (mGraphicsOutput->Mode->Info->HorizontalResolution / 2) - (mWidth / 2);
  YCoordinate = (mGraphicsOutput->Mode->Info->VerticalResolution / 2) - (mHeight / 2);

Next we start the actual loop that waits for input and acts on it.  First is WaitForEvent(), which will just wait until the specified event happens.  In this case, I found an already-existing event that referred to a keyboard action, WaitForKey, so I used that.  After someone hits a key on the keyboard, ReadKeyStroke() will store which key was pressed into the variable Key.

do {
    gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &index);
    gST->ConIn->ReadKeyStroke(gST->ConIn, &Key);

The next part makes up the bulk of the function.  It's simply deciding which key was pressed, and updating the coordinates accordingly.  This part also makes sure that the image doesn't try to move past the edges of the window.  The instance of EFI_GRAPHICS_OUTPUT_PROTOCOL keeps track of the resolution of the display window, so we can use that to keep our image from trying to go past the borders.  If the key pressed wasn't one of the arrow keys, the coordinates remain the same.

if (Key.ScanCode != SCAN_NULL) {
      if (Key.ScanCode == SCAN_UP) {
        NewX = XCoordinate;
        if (YCoordinate >= 5) {
          NewY = YCoordinate - 5;
        } else {
          NewY = 0;
        }
        
      } else if (Key.ScanCode == SCAN_DOWN) {
        NewX = XCoordinate;
        NewY = YCoordinate + 5;
        if (NewY > mGraphicsOutput->Mode->Info->VerticalResolution - mHeight) {
          NewY = mGraphicsOutput->Mode->Info->VerticalResolution - mHeight;
        }
      } else if (Key.ScanCode == SCAN_RIGHT) {
        NewY = YCoordinate;
        NewX = XCoordinate + 5;
        if (NewX > mGraphicsOutput->Mode->Info->HorizontalResolution - mWidth) {
          NewX = mGraphicsOutput->Mode->Info->HorizontalResolution - mWidth;
        }
      } else if (Key.ScanCode == SCAN_LEFT) {
        NewY = YCoordinate;
        if (XCoordinate >= 5) {
          NewX = XCoordinate - 5;
        } else {
          NewX = 0;
        }
        
      } else {
        NewX = XCoordinate;
        NewY = YCoordinate;
      }
    } else {
      continue;
    }

Now we need to clear the area where the image is currently displayed before we draw the new one.  So, using the pixel we defined earlier, we can call Blt() to clear the area.

    mGraphicsOutput->Blt(
                      mGraphicsOutput,
                      &mBlack,
                      EfiBltVideoFill,
                      0,
                      0,
                      XCoordinate,
                      YCoordinate,
                      mWidth,
                      mHeight,
                      0
                      );

In the last part of our loop, we call DisplayImageAt() with the new coordinates and set the current coordinates to the correct values.  The condition to continue the loop is whether or not the key pressed was the [End] key.  This way, if the user presses the [End] key, the application will exit.

    DisplayImageAt (NewX, NewY);
    
    XCoordinate = NewX;
    YCoordinate = NewY;

  } while (Key.ScanCode != SCAN_END);

And finally, to finish off the function, the screen is cleared and the success code is returned.

 gST->ConOut->Reset (gST->ConOut, FALSE);

  return EFI_SUCCESS;

Now we can build and run the project.  The image movement is controlled by the arrow keys, and pressing [End] will exit the application back to the Shell.

As usual, if you would like me to send you the code, let me know, and I'll get it sent to you.


Thursday, September 06, 2012

HOW TO: Display Your Own Image

In this article, I'll talk about how to get your own image to display on the screen.  As much as we love the Tiano logo, sometimes it just doesn't serve our purposes.  This article assumes that you have already followed the directions described in the previous post to display an image.

The first step is to get your image file into a format we can work with.  My previous article only supports .BMP files, so be sure the image you want is saved as such.  If it's a different file type, just open it in Paint or a similar program and save it in the proper format.  To make things simpler, save the image in the same directory as the application.

Next is to create a GUID for our image.  You can use uuidgen from the command line if you like, or in Visual Studio, you can go to Tools > Create GUID.  Now, we copy the GUID and go to Main.c (our entry point).  Change the declaration for gImageFileGuid to the new value.  If you are not sure how to convert a GUID into the format used in the EFI_GUID declaration, take a look at this article.

Open up Nt32Pkg.fdf [1].  Search for "Logo.bmp".  Below that statement, add a similar statement, in the following format:

FILE FREEFORM = 0E1FAAC7-82A4-41DA-90A4-EE1F6F3E81DC {
SECTION RAW = AppPkg/Applications/Main/6.bmp
}

Be sure to replace the GUID and filepath with your own.  


And there it is!  Build it and run Main like you would normally, and your own beautiful image will be displayed in place of the Tiano logo.

Next time, I'll talk about getting an image to moving an image around the screen using keyboard input.

Tuesday, September 04, 2012

HOW TO: Display an Image Using UEFI

The next project that I'm working on involves displaying an image.  This means that I have to rely a lot more on UEFI functions rather than simply the basic C functions.  Because I'm still learning about how UEFI works and am not completely familiar it yet, I decided to go looking for something that already did something similar and pull out the bits that I need.

I knew that NT32 displayed the Tiano logo, so I decided to go find the function that did that and base my own image-displaying function off of theirs.  The function is EnableQuietBoot() located in BdsConsole.c [1].  There's a lot of unnecessary stuff in that function that we don't need to display an image, so we can definitely cut it out when we piece together our own function.  I cut out all the stuff that dealt with UGA, since I only need the Graphics Output Protocol to display the image.  I also got rid of anything to do with badging and deciding where on the screen to display the image.  All I really needed was something to get the protocol, get the image from the file, convert it to a format that can be displayed by the GOP, and display it.  So after determining what I did and didn't need, I went ahead and pieced together my own function.

The next step was to make sure all the proper files are included so that all the functions and global variables used to display this image can actually be accessed.  One of the functions, ConvertBmpToGopBlt(), was already in BdsConsole.c, so I simply copied and pasted the function into my new file.  The only thing that needs to be changed in that function, is that instead of calling AllocatePool(), call malloc(), and instead of calling FreePool(), call free().  For the most part, it was simple enough to find where everything was defined by searching through the EDK2 folder, and I went ahead and included them at the top of the file.  My programming background is mainly in Java, so I'm still figuring out how #include statements work.  It took me a while to realize that there were no forward references in C, so I had to switch the order of the statements before it would work.

It also was difficult to figure out how INF files worked.  I had included DxeServicesLib.h in my file, but it still was unable to recognize the function whose prototype was located in that .H file.  In order for my file to be able to access the code for that function and actually call it, I had to make sure the code for that function is also pulled into the project.  The way to do that is through the INF files.  In my project's .INF file, there's a list of "Library Classes," which lists other INFs that have to be acknowledged when the project is built.  To make sure the code that defines the functions in DxeServicesLib.h was built, I put DxeServicesLib into that list.  Below is the body for the .INF file.  Click the picture to enlarge it.

Finally, we have to put together main().  This is our entry point for the application, so it's fairly simple.  All it does is call to the function we put together to display the image, but the function has an EFI_GUID as a parameter (the GUID for the image).  We could use uuidgen to produce one for us, but since NT32 already displays an image, we simply have to find the GUID for that image.  It is located in Logo.inf [2].  So, since we have to pass an EFI_GUID into the function, we take that long GUID and put it properly into a struct.  The declaration goes outside the function so we have a global variable.


STATIC
EFI_GUID
gImageFileGuid = {0x7bb28b99, 0x61bb, 0x11d5, {0x9a, 0x5d, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d}};


Then the only line inside main() is as follows:


DisplayImage(&gImageFileGuid);


So let's walk through the code that I have that actually displays the image:

First, clear the screen.  Without it, the image will simply be drawn over whatever has already been displayed (which, in most cases, is text).  

gST->ConOut-> Reset(gST->ConOut, FALSE);

Check to see if the Graphics Output Protocol is supported.  If not, return an error code.

Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput);

  if (EFI_ERROR (Status)) {
    return EFI_UNSUPPORTED;
  }


Get the image information from the image file.  If an error occurs, return error code.

Status = GetSectionFromAnyFv (LogoFile, EFI_SECTION_RAW, 0, (VOID **) &ImageData, &ImageSize);
  if (EFI_ERROR (Status)) {
    return EFI_UNSUPPORTED;
  }

Convert the image to a format that GOP can work with (GOP Blt).  Right now, .BMP files are the only supported image files.


  Status = ConvertBmpToGopBlt (
            ImageData,
            ImageSize,
            (VOID **) &Blt,
            &BltSize,
            &Height,
            &Width
            );
  if (EFI_ERROR (Status)) {
    free (ImageData);
  }

Set the coordinates for where the image is going to be displayed.  The coordinates you give will be the location of the upper left-hand corner of the image.  The upper left-hand corner of the window is (0, 0).


CoordinateX = (GraphicsOutput->Mode->Info->HorizontalResolution / 2) - (Width / 2);
CoordinateY = (GraphicsOutput->Mode->Info->VerticalResolution / 2) - (Height / 2);

Finally, call Blt() to actually display the image.  We've got quite a few parameters here, so let's go through them.  First is the instance of the GRAPHICS_OUTPUT_PROTOCOL that's calling the function.  Next is the image data that we have to transfer to the screen.  We filled this buffer when we called ConvertBmpToGopBlt().  Now, the third parameter specifies which operation to perform in order to copy the image to the screen.  The operation selected in this parameter affects the values of other parameters as well.  Details of the different functions are in the UEFI spec.  The next two parameters are the X and Y coordinates for the source for the operation specified in the previous parameter.  After that come the coordinates for where on the screen the image will be displayed.  The last three are data about the image itself.  Width and Height are the width and height, respectively, of the image in pixels.  Finally, the last parameter specifies the number of bytes in a row of the image, by taking the number of pixels in a row (the width) and multiplying it by the size of a pixel.


GraphicsOutput->Blt (
                 GraphicsOutput,
                 Blt,
                 EfiBltBufferToVideo,
                 0,
                 0,
                 (UINTN) CoordinateX,
                 (UINTN) CoordinateY,
                 Width,
                 Height,
                 Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
                 );
  
  return EFI_SUCCESS;

The next step in this project is to get the image to move around according to keyboard instructions.

And, of course, if anyone is interested in seeing the code for this project, let me know, and I'll get it sent to you.

[1] IntelFrameworkModulePkg\Library\GenericBdsLib\BdsConsole.c
[2] MdeModulePkg\Logo\Logo.inf