Data Integrity: Resurrection

Posted by cwright on 2007.07.10 @ 16:35

Filed under:

flame signFaced with a need to recover images from Robert’s camera after a defective card-reader nuked the filesystem superblock, a quick utility came to mind. Nuked superblocks mean no file allocation table. It means no metadata. But it does not mean no data.

  • Target medium: 1GB XD card from a digital camera.
  • Data to recover: JPEGs. Lots of them.

Whipping out some jpeg-format-and-filesystem-jutsu, here’s the solution (for less than that $20 shareware recovery utility):

Step one: Create a disk image of the card. sudo dd if=/dev/disk2 of=~/Desktop/roberts.xd.card.image bs=1048576

Step two: Create a utility to extract JPEGs.

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
 
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
 
#include <unistd .h>
 
int main(int argc, char**argv)
{
        int file, filesize, i, j;
        int outfile=0, outfilenum = 0;
        int blocksWritten = 0;
        char outname[42];
        unsigned char *data;
        struct stat fileStat;
 
        if(stat(argv[1],&fileStat))
        {
                printf("Couldn't stat file!\n");
                return -1;
        }
 
        file = open(argv[1],O_RDONLY);
 
        if(!file)
        {
                printf("Couldn't open file!\n");
                return -1;
        }
 
        filesize = fileStat.st_size;
        if(fileStat.st_size % getpagesize())
        {
                // if we're unaligned, we add the difference to pad up.
                filesize = fileStat.st_size + (getpagesize() - (fileStat.st_size % getpagesize()));
        }
 
        printf("mmapping %i bytes...\n",filesize);
 
        data = mmap(0,filesize,PROT_READ,MAP_PRIVATE,file,0);
 
        if(data == -1)
        {
                printf("Couldn't mmap file...\n");
                perror("mmap");
                return -1;
        }
 
        printf("Scanning %i blocks for jpegs...\n",filesize/1024);
 
        j = 0; // found count
        outfile = -1;
        for(i=0;i < (fileStat.st_size/1024);++i)
        {
                if(data[i*1024 + 0] == 0xff && // SOI (Start of Image) Tag
                   data[i*1024 + 1] == 0xd8 && //
                   data[i*1024 + 2] == 0xff && // APP1 (Application 1; exif) Tag
                   data[i*1024 + 3] == 0xe1) // 
                {
                        printf("Probable jpeg at block %i (#%i)\n",i,j++);
                        if(outfile != -1)
                        {
                                close(outfile);
                                outfile = -1;
                        }
                        snprintf(outname, 42,"recovered.%i.jpg",outfilenum++);
                        outfile = open(outname,O_RDWR|O_CREAT,0666);
                        write(outfile,data+i*1024,1024);
                        blocksWritten = 1;
                }
                else // non-header block.  write it if we're in a file
                {
                        // write another block.  stop at 4096 blocks (4MB jpegs)
                        if(outfile != -1 && outfile > 2)
                        {
                                write(outfile,data+i*1024,1024);
                                ++blocksWritten;
                                if(blocksWritten >= 4096)
                                {
                                        close(outfile);
                                        outfile = -1;
                                        blocksWritten = 0;
                                }
                        }
                }
 
                // for progress view
                if( (i%10000) == 0 && i)
                {
                        printf("block %i...\n",i);
                }
        }
 
        return 0;
}

Step three: compile it. Since we’re dealing with huge images and I was lazy and used mmap, we need to make it a 64-bit binary. To do this, we simply run gcc -m64 main.c -o main and we’re in business.

Step four: run and enjoy

cwright@phendrana:~/projects/getjpeg>./main ~/Desktop/roberts.xd.card.image 
mmapping 1048481792 bytes...
Scanning 1023908 blocks for jpegs...
Probable jpeg at block 1632 (#0)
Probable jpeg at block 2864 (#1)
Probable jpeg at block 4208 (#2)
Probable jpeg at block 5424 (#3)
Probable jpeg at block 6640 (#4)
Probable jpeg at block 7840 (#5)
Probable jpeg at block 8976 (#6)
block 10000...
Probable jpeg at block 10224 (#7)
Probable jpeg at block 11488 (#8)
Probable jpeg at block 12768 (#9)
Probable jpeg at block 14192 (#10)
Probable jpeg at block 15520 (#11)
Probable jpeg at block 16880 (#12)
Probable jpeg at block 17760 (#13)
Probable jpeg at block 19024 (#14)
block 20000...
Probable jpeg at block 20208 (#15)
Probable jpeg at block 21408 (#16)
Probable jpeg at block 22608 (#17)
Probable jpeg at block 23840 (#18)
Probable jpeg at block 24976 (#19)
Probable jpeg at block 26128 (#20)
Probable jpeg at block 27296 (#21)
Probable jpeg at block 28432 (#22)
Probable jpeg at block 29584 (#23)
block 30000...
Probable jpeg at block 30720 (#24)
Probable jpeg at block 31968 (#25)
Probable jpeg at block 33056 (#26)
Probable jpeg at block 34272 (#27)
Probable jpeg at block 35456 (#28)
Probable jpeg at block 36720 (#29)
Probable jpeg at block 38000 (#30)
Probable jpeg at block 39120 (#31)
block 40000...
Probable jpeg at block 40336 (#32)
Probable jpeg at block 41488 (#33)
Probable jpeg at block 42800 (#34)
Probable jpeg at block 44064 (#35)
Probable jpeg at block 45312 (#36)
Probable jpeg at block 46528 (#37)
Probable jpeg at block 47648 (#38)
Probable jpeg at block 48864 (#39)
Probable jpeg at block 49984 (#40)
block 50000...
Probable jpeg at block 51088 (#41)
Probable jpeg at block 52192 (#42)
Probable jpeg at block 53280 (#43)
Probable jpeg at block 54416 (#44)
Probable jpeg at block 55536 (#45)
Probable jpeg at block 56480 (#46)
Probable jpeg at block 57488 (#47)
Probable jpeg at block 58448 (#48)
Probable jpeg at block 59360 (#49)
block 60000...
Probable jpeg at block 60352 (#50)
Probable jpeg at block 61040 (#51)
Probable jpeg at block 61808 (#52)
Probable jpeg at block 62736 (#53)
Probable jpeg at block 63472 (#54)
Probable jpeg at block 64256 (#55)
Probable jpeg at block 65072 (#56)
Probable jpeg at block 66016 (#57)
Probable jpeg at block 66832 (#58)
Probable jpeg at block 67680 (#59)
Probable jpeg at block 68368 (#60)
Probable jpeg at block 69168 (#61)
block 70000...
Probable jpeg at block 70016 (#62)
Probable jpeg at block 70736 (#63)
Probable jpeg at block 71504 (#64)
Probable jpeg at block 72688 (#65)
Probable jpeg at block 73776 (#66)
Probable jpeg at block 74960 (#67)
Probable jpeg at block 76016 (#68)
Probable jpeg at block 77040 (#69)
Probable jpeg at block 78176 (#70)
Probable jpeg at block 79248 (#71)
block 80000...
Probable jpeg at block 80400 (#72)
Probable jpeg at block 81504 (#73)
Probable jpeg at block 82640 (#74)
Probable jpeg at block 83840 (#75)
Probable jpeg at block 84752 (#76)
Probable jpeg at block 85664 (#77)
Probable jpeg at block 86560 (#78)
Probable jpeg at block 87552 (#79)
Probable jpeg at block 88528 (#80)
Probable jpeg at block 89456 (#81)
block 90000...
Probable jpeg at block 90416 (#82)
Probable jpeg at block 91392 (#83)
Probable jpeg at block 92384 (#84)
Probable jpeg at block 93312 (#85)
Probable jpeg at block 94400 (#86)
Probable jpeg at block 95536 (#87)
Probable jpeg at block 96688 (#88)
Probable jpeg at block 97824 (#89)
Probable jpeg at block 98832 (#90)
Probable jpeg at block 99824 (#91)
block 100000...
Probable jpeg at block 100656 (#92)
Probable jpeg at block 101520 (#93)
Probable jpeg at block 102624 (#94)
Probable jpeg at block 103776 (#95)
Probable jpeg at block 104880 (#96)
Probable jpeg at block 105952 (#97)
Probable jpeg at block 107056 (#98)
Probable jpeg at block 108208 (#99)
Probable jpeg at block 109472 (#100)
block 110000...
Probable jpeg at block 110672 (#101)
Probable jpeg at block 111824 (#102)
Probable jpeg at block 112976 (#103)
Probable jpeg at block 114096 (#104)
Probable jpeg at block 115296 (#105)
Probable jpeg at block 116384 (#106)
Probable jpeg at block 117584 (#107)
Probable jpeg at block 118704 (#108)
Probable jpeg at block 119888 (#109)
block 120000...
Probable jpeg at block 120864 (#110)
Probable jpeg at block 122016 (#111)
Probable jpeg at block 123216 (#112)
Probable jpeg at block 124352 (#113)
Probable jpeg at block 125408 (#114)
Probable jpeg at block 126480 (#115)
Probable jpeg at block 127536 (#116)
Probable jpeg at block 128752 (#117)
Probable jpeg at block 129952 (#118)
block 130000...
Probable jpeg at block 131104 (#119)
Probable jpeg at block 132192 (#120)
Probable jpeg at block 133264 (#121)
Probable jpeg at block 134416 (#122)
Probable jpeg at block 135568 (#123)
Probable jpeg at block 136784 (#124)
Probable jpeg at block 138016 (#125)
Probable jpeg at block 139264 (#126)
block 140000...
Probable jpeg at block 140496 (#127)
Probable jpeg at block 141168 (#128)
Probable jpeg at block 141952 (#129)
Probable jpeg at block 142912 (#130)
Probable jpeg at block 143856 (#131)
Probable jpeg at block 144944 (#132)
Probable jpeg at block 146000 (#133)
Probable jpeg at block 147056 (#134)
Probable jpeg at block 148272 (#135)
Probable jpeg at block 149504 (#136)
block 150000...
Probable jpeg at block 150672 (#137)
Probable jpeg at block 151888 (#138)
Probable jpeg at block 153120 (#139)
Probable jpeg at block 154352 (#140)
Probable jpeg at block 155648 (#141)
Probable jpeg at block 156944 (#142)
Probable jpeg at block 158192 (#143)
Probable jpeg at block 159472 (#144)
block 160000...
Probable jpeg at block 160768 (#145)
Probable jpeg at block 162016 (#146)
Probable jpeg at block 163264 (#147)
Probable jpeg at block 164480 (#148)
Probable jpeg at block 165760 (#149)
Probable jpeg at block 167008 (#150)
Probable jpeg at block 168272 (#151)
Probable jpeg at block 169536 (#152)
block 170000...
Probable jpeg at block 170800 (#153)
Probable jpeg at block 172224 (#154)
Probable jpeg at block 173456 (#155)
Probable jpeg at block 174704 (#156)
Probable jpeg at block 175936 (#157)
Probable jpeg at block 177184 (#158)
Probable jpeg at block 178432 (#159)
Probable jpeg at block 179712 (#160)
block 180000...
Probable jpeg at block 180992 (#161)
Probable jpeg at block 182240 (#162)
Probable jpeg at block 183568 (#163)
Probable jpeg at block 184976 (#164)
Probable jpeg at block 186288 (#165)
Probable jpeg at block 187744 (#166)
Probable jpeg at block 189104 (#167)
block 190000...
Probable jpeg at block 190512 (#168)
Probable jpeg at block 191792 (#169)
Probable jpeg at block 193184 (#170)
Probable jpeg at block 194496 (#171)
Probable jpeg at block 195776 (#172)
Probable jpeg at block 197136 (#173)
Probable jpeg at block 198512 (#174)
Probable jpeg at block 199808 (#175)
block 200000...
Probable jpeg at block 201088 (#176)
Probable jpeg at block 202352 (#177)
Probable jpeg at block 203664 (#178)
Probable jpeg at block 204992 (#179)
Probable jpeg at block 206304 (#180)
Probable jpeg at block 207504 (#181)
Probable jpeg at block 208816 (#182)
block 210000...
Probable jpeg at block 210144 (#183)
Probable jpeg at block 211472 (#184)
Probable jpeg at block 212832 (#185)
Probable jpeg at block 214240 (#186)
Probable jpeg at block 215632 (#187)
Probable jpeg at block 217056 (#188)
Probable jpeg at block 218416 (#189)
Probable jpeg at block 219808 (#190)
block 220000...
Probable jpeg at block 221072 (#191)
Probable jpeg at block 222400 (#192)
Probable jpeg at block 223808 (#193)
Probable jpeg at block 225232 (#194)
Probable jpeg at block 226576 (#195)
Probable jpeg at block 227888 (#196)
Probable jpeg at block 229296 (#197)
block 230000...
Probable jpeg at block 230560 (#198)
Probable jpeg at block 231904 (#199)
Probable jpeg at block 233216 (#200)
Probable jpeg at block 234544 (#201)
Probable jpeg at block 235920 (#202)
Probable jpeg at block 237216 (#203)
Probable jpeg at block 238528 (#204)
Probable jpeg at block 239888 (#205)
block 240000...
Probable jpeg at block 241232 (#206)
Probable jpeg at block 242512 (#207)
Probable jpeg at block 243904 (#208)
Probable jpeg at block 245280 (#209)
Probable jpeg at block 246592 (#210)
Probable jpeg at block 247952 (#211)
Probable jpeg at block 249328 (#212)
block 250000...
Probable jpeg at block 250672 (#213)
Probable jpeg at block 252000 (#214)
Probable jpeg at block 253264 (#215)
Probable jpeg at block 254608 (#216)
Probable jpeg at block 255904 (#217)
Probable jpeg at block 257200 (#218)
Probable jpeg at block 258480 (#219)
Probable jpeg at block 260000 (#220)
block 260000...
Probable jpeg at block 261504 (#221)
Probable jpeg at block 262896 (#222)
Probable jpeg at block 264320 (#223)
Probable jpeg at block 265744 (#224)
Probable jpeg at block 267120 (#225)
Probable jpeg at block 268592 (#226)
block 270000...
Probable jpeg at block 270064 (#227)
Probable jpeg at block 271488 (#228)
Probable jpeg at block 272912 (#229)
Probable jpeg at block 274400 (#230)
Probable jpeg at block 275936 (#231)
Probable jpeg at block 277360 (#232)
Probable jpeg at block 278800 (#233)
block 280000...
Probable jpeg at block 280176 (#234)
Probable jpeg at block 281712 (#235)
Probable jpeg at block 283200 (#236)
Probable jpeg at block 284688 (#237)
Probable jpeg at block 286016 (#238)
Probable jpeg at block 287552 (#239)
Probable jpeg at block 288992 (#240)
block 290000...
Probable jpeg at block 290544 (#241)
Probable jpeg at block 292000 (#242)
Probable jpeg at block 293440 (#243)
Probable jpeg at block 294800 (#244)
Probable jpeg at block 296208 (#245)
Probable jpeg at block 297472 (#246)
Probable jpeg at block 298720 (#247)
block 300000...
Probable jpeg at block 300080 (#248)
Probable jpeg at block 301504 (#249)
Probable jpeg at block 302784 (#250)
Probable jpeg at block 304064 (#251)
Probable jpeg at block 305008 (#252)
Probable jpeg at block 306016 (#253)
Probable jpeg at block 306976 (#254)
Probable jpeg at block 307984 (#255)
Probable jpeg at block 309216 (#256)
block 310000...
Probable jpeg at block 310592 (#257)
Probable jpeg at block 311888 (#258)
Probable jpeg at block 313152 (#259)
Probable jpeg at block 314352 (#260)
Probable jpeg at block 315664 (#261)
Probable jpeg at block 317024 (#262)
Probable jpeg at block 318272 (#263)
Probable jpeg at block 319568 (#264)
block 320000...
Probable jpeg at block 320928 (#265)
Probable jpeg at block 322176 (#266)
Probable jpeg at block 323568 (#267)
Probable jpeg at block 324800 (#268)
Probable jpeg at block 325984 (#269)
Probable jpeg at block 327232 (#270)
Probable jpeg at block 328480 (#271)
Probable jpeg at block 329776 (#272)
block 330000...
Probable jpeg at block 331088 (#273)
Probable jpeg at block 332320 (#274)
Probable jpeg at block 333616 (#275)
Probable jpeg at block 334912 (#276)
Probable jpeg at block 336256 (#277)
Probable jpeg at block 337648 (#278)
Probable jpeg at block 338880 (#279)
block 340000...
Probable jpeg at block 340208 (#280)
Probable jpeg at block 341264 (#281)
Probable jpeg at block 342272 (#282)
Probable jpeg at block 343552 (#283)
Probable jpeg at block 344832 (#284)
Probable jpeg at block 346080 (#285)
Probable jpeg at block 346992 (#286)
Probable jpeg at block 348368 (#287)
Probable jpeg at block 349760 (#288)
block 350000...
Probable jpeg at block 351168 (#289)
Probable jpeg at block 352448 (#290)
Probable jpeg at block 353760 (#291)
Probable jpeg at block 355136 (#292)
Probable jpeg at block 356368 (#293)
Probable jpeg at block 357712 (#294)
Probable jpeg at block 359040 (#295)
block 360000...
Probable jpeg at block 360464 (#296)
Probable jpeg at block 361808 (#297)
Probable jpeg at block 363200 (#298)
Probable jpeg at block 364144 (#299)
Probable jpeg at block 365488 (#300)
Probable jpeg at block 366752 (#301)
Probable jpeg at block 367808 (#302)
Probable jpeg at block 368848 (#303)
Probable jpeg at block 369856 (#304)
block 370000...
Probable jpeg at block 371072 (#305)
Probable jpeg at block 372272 (#306)
Probable jpeg at block 373568 (#307)
Probable jpeg at block 374864 (#308)
Probable jpeg at block 376144 (#309)
Probable jpeg at block 377504 (#310)
Probable jpeg at block 378512 (#311)
Probable jpeg at block 379824 (#312)
block 380000...
Probable jpeg at block 381120 (#313)
Probable jpeg at block 382320 (#314)
block 390000...
block 400000...
block 410000...
block 420000...
block 430000...
block 440000...
block 450000...
block 460000...
block 470000...
block 480000...
block 490000...
block 500000...
block 510000...
block 520000...
block 530000...
block 540000...
block 550000...
block 560000...
block 570000...
block 580000...
block 590000...
block 600000...
block 610000...
block 620000...
block 630000...
block 640000...
block 650000...
block 660000...
block 670000...
block 680000...
block 690000...
block 700000...
block 710000...
block 720000...
block 730000...
block 740000...
block 750000...
block 760000...
block 770000...
block 780000...
block 790000...
block 800000...
block 810000...
block 820000...
block 830000...
block 840000...
block 850000...
block 860000...
block 870000...
block 880000...
block 890000...
block 900000...
block 910000...
block 920000...
block 930000...
block 940000...
block 950000...
block 960000...
block 970000...
block 980000...
block 990000...
block 1000000...
block 1010000...
block 1020000...

Yay, images from yesterday: Recovered.

Take it down, flip it, and reverse it.

Just as a side note, if the flash is failing it may be necessary to skip some blocks at the beginning. In this case, the image-acquiring command becomes something like this: sudo dd if=/dev/disk2 of=~/Desktop/roberts.xd.card.image skip=2048. This risks losing a picture or two, but it beats nothing.