Intercepting Windows
Printing by Modifying
    GDI Subsystem
           by Artyom Shishkin,
          Positive Technologies
What for?

 Basically it’s a data source for
   Monitoring systems
   DLP solutions
What do we have?

 FindNextPrinterChangeNotification():
   Printer name
   Timestamp
   Job status
   Pages count
   Print providOr is the source of this info, so I
   wouldn’t rely on it too much.
API levels


     Spooler

Driver components
Driver components

 Print providers send jobs to a local or a remote
  machine
 A print processor converts the spooled data into
  a format suitable for a print monitor
 The print monitor passes the data to a port
  monitor
 A port monitor is an interface between the
  usermode and the kernelmode parts of the
  printing system
 What a mess!
Spooler API

 A set of Spooler service functions, which serve as
  wrappers for driver components
 At this level, we can only get the spooled data
   This is a level of raw printing

   Try to parse this data
GDI API

 The same set of functions used for Windows graphics
 A printer is a device context suitable for GDI drawing
  functions
     hPrinter = CreateDC(‘SuperLaserJet’, params);
     StartDoc(hPrinter);
     TextOut(hPrinter, ‘Text’);
     …
 Graphical data is Windows graphical data – NT EMF
  format
Inside GDI
                     Found with the help of PEB
                     Thanks to Feng Yuan


                               GDI cell
   Process               Object kernel address
Address Space            Selection count
                         Process ID
GDI shared handle        Upper handle value
      table              Object type
                         Usermode info
The trick
hOriginalPrinter                       hPrintInterceptor



                   Shared handle table


                   Magical operation
    Cell                                   Cell
  contents                               contents
Profit

 Swap GDI cells to send documents to a fake printer
 It is not always necessary to create your own virtual
  printer, you can use something like Microsoft XPS
  Writer
 The intercepted image can be easily forwarded to the
  original printer
The concept
Application wants to print things
                                    I’ll save the original parameters
                                    of this printing request
   DLL: It’s using GDI, I’ll load
   here using windows hooks
                                    Hey, you’ve decided to print! I’ll
      and patch some GDI
                                    swap the GDI cells so that you use
             functions
                                    the old handle for a new device
           CreateDC()
                                    Okay, done here, I’ll
                                    print your document on
            StartDoc()
                                    the real printer
            EndDoc()
                                    Let’s clean everything up and
           DeleteDC()               make things look like they did
                                    before
Sample implementation
                 Settings file

 Dll used for
  function       .xps image
interception                      Application
                                  that fulfills
 GUI-based                        the original
 application                        request
   that is
supposed to
                 Kernelmode
    print
 something
                magic performer
Thank you!
 Any questions?

Artyom Shishkin - Printing interception via modifying Windows GDI

  • 1.
    Intercepting Windows Printing byModifying GDI Subsystem by Artyom Shishkin, Positive Technologies
  • 2.
    What for?  Basicallyit’s a data source for  Monitoring systems  DLP solutions
  • 3.
    What do wehave?  FindNextPrinterChangeNotification():  Printer name  Timestamp  Job status  Pages count Print providOr is the source of this info, so I wouldn’t rely on it too much.
  • 4.
    API levels Spooler Driver components
  • 5.
    Driver components  Printproviders send jobs to a local or a remote machine  A print processor converts the spooled data into a format suitable for a print monitor  The print monitor passes the data to a port monitor  A port monitor is an interface between the usermode and the kernelmode parts of the printing system  What a mess!
  • 6.
    Spooler API  Aset of Spooler service functions, which serve as wrappers for driver components  At this level, we can only get the spooled data  This is a level of raw printing  Try to parse this data
  • 7.
    GDI API  Thesame set of functions used for Windows graphics  A printer is a device context suitable for GDI drawing functions  hPrinter = CreateDC(‘SuperLaserJet’, params);  StartDoc(hPrinter);  TextOut(hPrinter, ‘Text’);  …  Graphical data is Windows graphical data – NT EMF format
  • 8.
    Inside GDI  Found with the help of PEB  Thanks to Feng Yuan GDI cell Process Object kernel address Address Space Selection count Process ID GDI shared handle Upper handle value table Object type Usermode info
  • 9.
    The trick hOriginalPrinter hPrintInterceptor Shared handle table Magical operation Cell Cell contents contents
  • 10.
    Profit  Swap GDIcells to send documents to a fake printer  It is not always necessary to create your own virtual printer, you can use something like Microsoft XPS Writer  The intercepted image can be easily forwarded to the original printer
  • 11.
    The concept Application wantsto print things I’ll save the original parameters of this printing request DLL: It’s using GDI, I’ll load here using windows hooks Hey, you’ve decided to print! I’ll and patch some GDI swap the GDI cells so that you use functions the old handle for a new device CreateDC() Okay, done here, I’ll print your document on StartDoc() the real printer EndDoc() Let’s clean everything up and DeleteDC() make things look like they did before
  • 12.
    Sample implementation Settings file Dll used for function .xps image interception Application that fulfills GUI-based the original application request that is supposed to Kernelmode print something magic performer
  • 13.