I guess it should work to copy the original data from the surface into a temporary bitmap before drawing the rectangle, and then draw the bitmap back in place.
Update
There is already an accepted answer, but I thought I could share a code sample anyway. This one draws the given rectangle in red on the given control, and restores the area after 500 ms.
public void ShowRectangleBriefly(Control ctl, Rectangle rect)
{
    Image toRestore = DrawRectangle(ctl, rect);
    ThreadPool.QueueUserWorkItem((WaitCallback)delegate
    {
        Thread.Sleep(500);
        this.Invoke(new Action<Control, Rectangle, Image>(RestoreBackground), ctl, rect, toRestore);
    });
}
private void RestoreBackground(Control ctl, Rectangle rect, Image image)
{
    using (Graphics g = ctl.CreateGraphics())
    {
        g.DrawImage(image, rect.Top, rect.Left, image.Width, image.Height);
    }
    image.Dispose();
}
private Image DrawRectangle(Control ctl, Rectangle rect)
{
    Bitmap tempBmp = new Bitmap(rect.Width + 1, rect.Height + 1);
    using (Graphics g = Graphics.FromImage(tempBmp))
    {
        g.CopyFromScreen(ctl.PointToScreen(new Point(rect.Top, rect.Left)), new Point(0, 0), tempBmp.Size);
    }
    using (Graphics g = this.CreateGraphics())
    {
        g.DrawRectangle(Pens.Red, rect);
    }
    return tempBmp;
}