Break photo.png
An example that will explain how to use common Linux programs to recover deleted images from any media support. Furthermore here is also a simple pascal utility to speed up recovery time. This tutorial is provided "as is" without any warranty. Use at own risk.

Contents

First example: only with standard Linux commands

A bash script that uses 'dd' command to extract a portion of data stored to disk or to other media support (may be a file also), 'file' command to get file-type, and ImageMagick 'convert' progam to adjust file length. This is an example of a process commonly referred as "data carving".

imagescan.sh

Note: this script is very slow as execution time.

#!/bin/sh
 
if [ $# -ne 2 ] ; then
 echo "------"
 echo "Usage:"
 echo "./imagescan.sh disk|file starting_sector"
 echo "Example:"
 echo "./imagescan.sh /dev/sda 100000"
 echo
 exit
fi
 
DISK=$1
START=$2
DELTA=1
SKIPS=$START
 
MAXBLK=`sfdisk -s $DISK`
 
let MAXBLK=$MAXBLK+$MAXBLK
 
echo "$DISK - $MAXBLK blocks"
 
while [ $MAXBLK -gt $SKIPS ]
do
 
 is_File=`dd if=$DISK of=/dev/stdout bs=512 count=1 skip=$SKIPS 2>/dev/null | \
          file -eapptype -eascii -eencoding -etokens -ecdf -ecompress -eelf -etar -`
 
 imgType=""
 
 is_IMAGE=`echo $is_File | grep JPEG`
 if [ "a$is_IMAGE" != "a" ] ; then
  imgType="jpg"
 fi
 
 #is_IMAGE=`echo $is_File | grep PNG`
 #if [ "a$is_IMAGE" != "a" ] ; then
 # imgType="png"
 #fi
 
 #is_IMAGE=`echo $is_File | grep BMP`
 #if [ "a$is_IMAGE" != "a" ] ; then
 # imgType="bmp"
 #fi
 
 if [ "a$imgType" != "a" ] ; then
 
  #dd if=$DISK of=/dev/stdout bs=512 count=200 skip=$SKIPS 2>/dev/null | xv -geometry 320x240 -
 
  dd if=$DISK of=$SKIPS.$imgType bs=512 count=2000 skip=$SKIPS 2>/dev/null
 
  isCorruptImage=`convert $SKIPS.$imgType $SKIPS.$imgType 2>&1`
 
  isCorruptImage=""
 
  if [ "a$isCorruptImage" != "a" ] ; then
   rm -f $SKIPS.$imgType
   echo "$SKIPS.$imgType corrupt, not saved"
  else
   echo "$SKIPS.$imgType saved"
  fi
 
 fi
 
 let SKIPS=$SKIPS+$DELTA
 
done
 
echo "$SKIPS blocks ... exit"

Second example: using an utility written in Pascal to speed up file searching

The script works as the script above, but uses an external program to improve performance. Note: it retrieves only common jpg files, but it is very fast as execution time.

getimages.sh, the script

#!/bin/sh
 
if [ $# -ne 2 ] ; then
 echo "------"
 echo "Usage:"
 echo "./getimages.sh disk|file starting_sector"
 echo "Example:"
 echo "./getimages.sh /dev/sda 100000"
 echo
 exit
fi
 
DISK=$1
START=$2
DELTA=1
SKIPS=$START
 
imgType="jpg"
 
WORKDIR=`pwd`
 
if [ ! -e $WORKDIR/findimgblock ] ; then
 echo
 echo "Binary program 'findimgblock' not found in path"
 echo "... exit"
 echo
 exit
fi
 
MAXBLK=`sfdisk -s $DISK`
 
let MAXBLK=$MAXBLK+$MAXBLK
 
echo "$DISK - $MAXBLK blocks"
 
while [ $MAXBLK -gt $SKIPS ]
do
 
 SKIPS=`$WORKDIR/findimgblock $DISK $SKIPS`
 
 dd if=$DISK of=$SKIPS.$imgType bs=512 count=4000 skip=$SKIPS 2>/dev/null
 
 isCorruptImage=`convert $SKIPS.$imgType $SKIPS.$imgType 2>&1`
 
 if [ "a$isCorruptImage" != "a" ] ; then
  rm -f $SKIPS.$imgType
  echo "$SKIPS.$imgType corrupt, not saved"
 else
  echo "$SKIPS.$imgType saved"
 fi
 
 let SKIPS=$SKIPS+$DELTA
 
done
 
echo "$SKIPS blocks ... exit"

findimgblock.pas, the utily that search jpg files

This program simply reads blocks sequentially and stops if a block contains the standard jpg header (6 bytes).

{$mode objfpc}
{$h+ }
Uses
	SysUtils;
type
	disk_B = array [0..32767] of byte;
const
	ImgSignature : array [0..5] of byte = ($FF,$D8,$FF,$E0,$00,$10);
var
	i, n : integer;
	sectorCount : longword;
	BB  : disk_B;
	P : pointer;
	deviceName : string;
	hddDevice : file;
 
function extended_Read (var hdd : file; sector : longword; var buffer : disk_B) : integer;
 
begin
 {$I-}
 seek  (hdd,sector);
 blockread  (hdd,buffer,64);
 {$I+}
 extended_Read := ioresult;
end;
 
function findImgSignature (pos : integer; buffer : disk_B) : boolean;
var
	i : integer;
	match : boolean;
begin
 match := true;
 for i := 0 to 5 do
  if buffer [pos+i] <> ImgSignature [i] then match := false;
 findImgSignature := match;
end;
 
begin
 
 if paramcount <> 2 then
 begin
  writeln ('Usage: findimgblock device startsector');
  exit;
 end;
 
 Try
  sectorCount:=StrToInt(paramstr(2));
 except
   On sectorCount : Exception do begin
    Writeln('Error exception when converting : ',sectorCount.Message);
    exit;
   end;
 end;
 
 deviceName := paramstr(1);
 assign (hddDevice,deviceName);
 
 {$I-}
 reset (hddDevice,512);
 {$I+}
 
 while true do
 begin
 extended_Read (hddDevice, sectorCount, BB);
 
 for i := 0 to 63 do
 begin
  if findImgSignature (i*512, BB) then
  begin
   sectorCount := sectorCount + i;
   write (sectorCount);
   exit;
  end;
 end;
 
 sectorCount := sectorCount + 64;
 end;
 
 close (hddDevice);
 
end.

to compile:

fpc -TLinux findimgblock.pas

Here you can also download a precompiled static binary: File:Findimgblock.gz (unpack it in working directory and set to executable). Also recovered images are saved in working directory.

Have fun!

Retrieved from "http://www.zoros.org/wiki/index.php?title=How_to_recover_jpg_images_using_standard_bash_linux_commands_and_other_examples"