Skip to content

Commit 3ceea09

Browse files
committed
PhotoRec: recover Snagit .snag files
1 parent ef8c70e commit 3ceea09

File tree

5 files changed

+131
-24
lines changed

5 files changed

+131
-24
lines changed

src/Makefile.am

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ file_C = filegen.c \
291291
file_sit.c \
292292
file_skd.c \
293293
file_skp.c \
294+
file_snag.c \
294295
file_sp3.c \
295296
file_spe.c \
296297
file_spf.c \
@@ -357,7 +358,7 @@ file_C = filegen.c \
357358
file_zip.c \
358359
file_zpr.c
359360

360-
file_H = ext2.h ext2_common.h filegen.h file_jpg.h file_gz.h file_sp3.h file_tar.h file_tiff.h file_txt.h ole.h pe.h suspend.h
361+
file_H = ext2.h ext2_common.h filegen.h file_doc.h file_jpg.h file_gz.h file_sp3.h file_tar.h file_tiff.h file_txt.h ole.h pe.h suspend.h
361362

362363
photorec_C = photorec.c phcfg.c addpart.c chgarch.c dir.c exfatp.c ext2grp.c ext2_dir.c ext2p.c fat_dir.c fatp.c file_found.c geometry.c ntfs_dir.c ntfsp.c pdisksel.c phcli.c poptions.c sessionp.c setdate.c dfxml.c
363364

src/file_doc.c

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,14 @@
3838
#include "log.h"
3939
#include "memmem.h"
4040
#include "setdate.h"
41+
#include "file_doc.h"
4142

4243
static void register_header_check_doc(file_stat_t *file_stat);
4344
static void file_check_doc(file_recovery_t *file_recovery);
4445
static int header_check_doc(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
4546
static void file_rename_doc(file_recovery_t *file_recovery);
46-
static uint32_t *OLE_load_FAT(FILE *IN, const struct OLE_HDR *header);
47-
static uint32_t *OLE_load_MiniFAT(FILE *IN, const struct OLE_HDR *header, const uint32_t *fat, const unsigned int fat_entries);
47+
static uint32_t *OLE_load_FAT(FILE *IN, const struct OLE_HDR *header, const uint64_t offset);
48+
static uint32_t *OLE_load_MiniFAT(FILE *IN, const struct OLE_HDR *header, const uint32_t *fat, const unsigned int fat_entries, const uint64_t offset);
4849

4950
const file_hint_t file_hint_doc= {
5051
.extension="doc",
@@ -67,7 +68,7 @@ const char WilcomDesignInformationDDD[56]=
6768
'D', '\0', 'D', '\0', 'D', '\0', '\0', '\0'
6869
};
6970

70-
static void file_check_doc(file_recovery_t *file_recovery)
71+
void file_check_doc_aux(file_recovery_t *file_recovery, const uint64_t offset)
7172
{
7273
unsigned char buffer_header[512];
7374
uint64_t doc_file_size;
@@ -76,9 +77,9 @@ static void file_check_doc(file_recovery_t *file_recovery)
7677
unsigned int freesect_count=0;
7778
const struct OLE_HDR *header=(const struct OLE_HDR*)&buffer_header;
7879
const uint64_t doc_file_size_org=file_recovery->file_size;
79-
file_recovery->file_size=0;
80+
file_recovery->file_size=offset;
8081
/*reads first sector including OLE header */
81-
if(my_fseek(file_recovery->handle, 0, SEEK_SET) < 0 ||
82+
if(my_fseek(file_recovery->handle, offset, SEEK_SET) < 0 ||
8283
fread(&buffer_header, sizeof(buffer_header), 1, file_recovery->handle) != 1)
8384
return ;
8485
#ifdef DEBUG_OLE
@@ -92,7 +93,7 @@ static void file_check_doc(file_recovery_t *file_recovery)
9293
le32(header->num_extra_FAT_blocks)>50 ||
9394
le32(header->num_FAT_blocks)>109+le32(header->num_extra_FAT_blocks)*((1<<le16(header->uSectorShift))-1))
9495
return ;
95-
if((fat=OLE_load_FAT(file_recovery->handle, header))==NULL)
96+
if((fat=OLE_load_FAT(file_recovery->handle, header, offset))==NULL)
9697
{
9798
#ifdef DEBUG_OLE
9899
log_info("OLE_load_FAT failed\n");
@@ -104,11 +105,12 @@ static void file_check_doc(file_recovery_t *file_recovery)
104105
i>0 && le32(fat[i])==0xFFFFFFFF;
105106
i--)
106107
freesect_count++;
107-
doc_file_size=((1+(le32(header->num_FAT_blocks)<<le16(header->uSectorShift))/4-freesect_count)<<le16(header->uSectorShift));
108+
doc_file_size=offset + ((1+(le32(header->num_FAT_blocks)<<le16(header->uSectorShift))/4-freesect_count)<<le16(header->uSectorShift));
108109
if(doc_file_size > doc_file_size_org)
109110
{
110111
#ifdef DEBUG_OLE
111-
log_info("doc_file_size=(1+(%u<<%u)/4-%u)<<%u\n",
112+
log_info("doc_file_size=%llu + (1+(%u<<%u)/4-%u)<<%u\n",
113+
(unsigned long long)offset,
112114
le32(header->num_FAT_blocks), le16(header->uSectorShift),
113115
freesect_count, le16(header->uSectorShift));
114116
log_info("doc_file_size %llu > doc_file_size_org %llu\n",
@@ -143,7 +145,7 @@ static void file_check_doc(file_recovery_t *file_recovery)
143145
free(fat);
144146
return ;
145147
}
146-
if(my_fseek(file_recovery->handle, (1+block)<<le16(header->uSectorShift), SEEK_SET)<0)
148+
if(my_fseek(file_recovery->handle, offset + ((1+block)<<le16(header->uSectorShift)), SEEK_SET)<0)
147149
{
148150
#ifdef DEBUG_OLE
149151
log_info("fseek failed\n");
@@ -168,7 +170,8 @@ static void file_check_doc(file_recovery_t *file_recovery)
168170
sid<(1<<le16(header->uSectorShift))/sizeof(struct OLE_DIR) && dir_entry->type!=NO_ENTRY;
169171
sid++,dir_entry++)
170172
{
171-
if(le32(dir_entry->start_block) > 0 && le32(dir_entry->size) > 0 &&
173+
if(offset +
174+
le32(dir_entry->start_block) > 0 && le32(dir_entry->size) > 0 &&
172175
((le32(dir_entry->size) >= le32(header->miniSectorCutoff)
173176
&& le32(dir_entry->start_block) > fat_entries) ||
174177
le32(dir_entry->size) > doc_file_size))
@@ -189,6 +192,11 @@ static void file_check_doc(file_recovery_t *file_recovery)
189192
file_recovery->file_size=doc_file_size;
190193
}
191194

195+
static void file_check_doc(file_recovery_t *file_recovery)
196+
{
197+
file_check_doc_aux(file_recovery, 0);
198+
}
199+
192200
static const char *ole_get_file_extension(const unsigned char *buffer, const unsigned int buffer_size)
193201
{
194202
const struct OLE_HDR *header=(const struct OLE_HDR *)buffer;
@@ -489,7 +497,7 @@ static int header_check_doc(const unsigned char *buffer, const unsigned int buff
489497
return 1;
490498
}
491499

492-
static uint32_t *OLE_load_FAT(FILE *IN, const struct OLE_HDR *header)
500+
static uint32_t *OLE_load_FAT(FILE *IN, const struct OLE_HDR *header, const uint64_t offset)
493501
{
494502
uint32_t *fat;
495503
uint32_t *dif;
@@ -504,7 +512,7 @@ static uint32_t *OLE_load_FAT(FILE *IN, const struct OLE_HDR *header)
504512
i<le32(header->num_extra_FAT_blocks) && block!=0xFFFFFFFF && block!=0xFFFFFFFE;
505513
i++, block=le32(dif[109+i*(((1<<le16(header->uSectorShift))/4)-1)]))
506514
{
507-
if(my_fseek(IN, (1+block)<<le16(header->uSectorShift), SEEK_SET) < 0)
515+
if(my_fseek(IN, offset + ((1+block)<<le16(header->uSectorShift)), SEEK_SET) < 0)
508516
{
509517
free(dif);
510518
return NULL;
@@ -525,7 +533,7 @@ static uint32_t *OLE_load_FAT(FILE *IN, const struct OLE_HDR *header)
525533
j<le32(header->num_FAT_blocks);
526534
j++, data+=(1<<le16(header->uSectorShift)))
527535
{
528-
if(my_fseek(IN, (1+le32(dif[j]))<<le16(header->uSectorShift), SEEK_SET)<0)
536+
if(my_fseek(IN, offset + ((1+le32(dif[j]))<<le16(header->uSectorShift)), SEEK_SET)<0)
529537
{
530538
free(dif);
531539
free(fat);
@@ -545,7 +553,7 @@ static uint32_t *OLE_load_FAT(FILE *IN, const struct OLE_HDR *header)
545553

546554
static void *OLE_read_stream(FILE *IN,
547555
const uint32_t *fat, const unsigned int fat_entries, const unsigned int uSectorShift,
548-
const unsigned int block_start, const unsigned int len)
556+
const unsigned int block_start, const unsigned int len, const uint64_t offset)
549557
{
550558
unsigned char *dataPt;
551559
unsigned int block;
@@ -560,7 +568,7 @@ static void *OLE_read_stream(FILE *IN,
560568
free(dataPt);
561569
return NULL;
562570
}
563-
if(my_fseek(IN, (1+block)<<uSectorShift, SEEK_SET)<0)
571+
if(my_fseek(IN, offset + ((1+block)<<uSectorShift), SEEK_SET)<0)
564572
{
565573
free(dataPt);
566574
return NULL;
@@ -574,7 +582,7 @@ static void *OLE_read_stream(FILE *IN,
574582
return dataPt;
575583
}
576584

577-
static uint32_t *OLE_load_MiniFAT(FILE *IN, const struct OLE_HDR *header, const uint32_t *fat, const unsigned int fat_entries)
585+
static uint32_t *OLE_load_MiniFAT(FILE *IN, const struct OLE_HDR *header, const uint32_t *fat, const unsigned int fat_entries, const uint64_t offset)
578586
{
579587
unsigned char*minifat_pos;
580588
uint32_t *minifat;
@@ -587,7 +595,7 @@ static uint32_t *OLE_load_MiniFAT(FILE *IN, const struct OLE_HDR *header, const
587595
block=le32(header->MiniFat_block);
588596
for(i=0; i < le32(header->csectMiniFat) && block < fat_entries; i++)
589597
{
590-
if(my_fseek(IN, ((uint64_t)1+block) << le16(header->uSectorShift), SEEK_SET) < 0)
598+
if(my_fseek(IN, offset + (((uint64_t)1+block) << le16(header->uSectorShift)), SEEK_SET) < 0)
591599
{
592600
free(minifat);
593601
return NULL;
@@ -794,7 +802,8 @@ static void *OLE_read_ministream(unsigned char *ministream,
794802

795803
static void OLE_parse_summary(FILE *file, const uint32_t *fat, const unsigned int fat_entries,
796804
const struct OLE_HDR *header, const unsigned int ministream_block, const unsigned int ministream_size,
797-
const unsigned int block, const unsigned int len, const char **ext, char **title, time_t *file_time)
805+
const unsigned int block, const unsigned int len, const char **ext, char **title, time_t *file_time,
806+
const uint64_t offset)
798807
{
799808
unsigned char *summary=NULL;
800809
if(len < 48 || len>1024*1024)
@@ -806,11 +815,11 @@ static void OLE_parse_summary(FILE *file, const uint32_t *fat, const unsigned in
806815
const unsigned int mini_fat_entries=(le32(header->csectMiniFat) << le16(header->uSectorShift)) / 4;
807816
uint32_t *minifat;
808817
unsigned char *ministream;
809-
if((minifat=OLE_load_MiniFAT(file, header, fat, fat_entries))==NULL)
818+
if((minifat=OLE_load_MiniFAT(file, header, fat, fat_entries, offset))==NULL)
810819
return ;
811820
ministream=(unsigned char *)OLE_read_stream(file,
812821
fat, fat_entries, le16(header->uSectorShift),
813-
ministream_block, ministream_size);
822+
ministream_block, ministream_size, offset);
814823
if(ministream != NULL)
815824
{
816825
summary=(unsigned char*)OLE_read_ministream(ministream,
@@ -824,7 +833,7 @@ static void OLE_parse_summary(FILE *file, const uint32_t *fat, const unsigned in
824833
else
825834
summary=(unsigned char *)OLE_read_stream(file,
826835
fat, fat_entries, le16(header->uSectorShift),
827-
block, len);
836+
block, len, offset);
828837
if(summary!=NULL)
829838
{
830839
OLE_parse_summary_aux(summary, len, ext, title, file_time);
@@ -864,7 +873,7 @@ static void file_rename_doc(file_recovery_t *file_recovery)
864873
fclose(file);
865874
return ;
866875
}
867-
if((fat=OLE_load_FAT(file, header))==NULL)
876+
if((fat=OLE_load_FAT(file, header, 0))==NULL)
868877
{
869878
fclose(file);
870879
return ;
@@ -1039,7 +1048,7 @@ static void file_rename_doc(file_recovery_t *file_recovery)
10391048
OLE_parse_summary(file, fat, fat_entries, header,
10401049
ministream_block, ministream_size,
10411050
le32(dir_entry->start_block), le32(dir_entry->size),
1042-
&ext, &title, &file_time);
1051+
&ext, &title, &file_time, 0);
10431052
}
10441053
else if(memcmp(dir_entry->name,"P\0o\0w\0e\0r\0P\0o\0i\0n\0t\0 \0D\0o\0c\0u\0m\0e\0n\0t\0\0\0", 40)==0)
10451054
ext="ppt";

src/file_doc.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
3+
File: file_doc.h
4+
5+
Copyright (C) 2018 Christophe GRENIER <grenier@cgsecurity.org>
6+
7+
This software is free software; you can redistribute it and/or modify
8+
it under the terms of the GNU General Public License as published by
9+
the Free Software Foundation; either version 2 of the License, or
10+
(at your option) any later version.
11+
12+
This program is distributed in the hope that it will be useful,
13+
but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
GNU General Public License for more details.
16+
17+
You should have received a copy of the GNU General Public License along
18+
with this program; if not, write the Free Software Foundation, Inc., 51
19+
Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20+
21+
*/
22+
#ifdef __cplusplus
23+
extern "C" {
24+
#endif
25+
26+
void file_check_doc_aux(file_recovery_t *file_recovery, const uint64_t offset);
27+
28+
#ifdef __cplusplus
29+
} /* closing brace for extern "C" */
30+
#endif

src/file_list.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,7 @@ extern const file_hint_t file_hint_sig;
294294
extern const file_hint_t file_hint_sit;
295295
extern const file_hint_t file_hint_skd;
296296
extern const file_hint_t file_hint_skp;
297+
extern const file_hint_t file_hint_snag;
297298
extern const file_hint_t file_hint_snz;
298299
extern const file_hint_t file_hint_sp3;
299300
extern const file_hint_t file_hint_spe;
@@ -628,6 +629,7 @@ file_enable_t list_file_enable[]=
628629
{ .enable=0, .file_hint=&file_hint_sit },
629630
{ .enable=0, .file_hint=&file_hint_skd },
630631
{ .enable=0, .file_hint=&file_hint_skp },
632+
{ .enable=0, .file_hint=&file_hint_snag },
631633
{ .enable=0, .file_hint=&file_hint_snz },
632634
{ .enable=0, .file_hint=&file_hint_sp3 },
633635
{ .enable=0, .file_hint=&file_hint_spe },

src/file_snag.c

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
3+
File: file_snag.c
4+
5+
Copyright (C) 2018 Christophe GRENIER <grenier@cgsecurity.org>
6+
7+
This software is free software; you can redistribute it and/or modify
8+
it under the terms of the GNU General Public License as published by
9+
the Free Software Foundation; either version 2 of the License, or
10+
(at your option) any later version.
11+
12+
This program is distributed in the hope that it will be useful,
13+
but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
GNU General Public License for more details.
16+
17+
You should have received a copy of the GNU General Public License along
18+
with this program; if not, write the Free Software Foundation, Inc., 51
19+
Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20+
21+
*/
22+
23+
#ifdef HAVE_CONFIG_H
24+
#include <config.h>
25+
#endif
26+
#ifdef HAVE_STRING_H
27+
#include <string.h>
28+
#endif
29+
#include <stdio.h>
30+
#include "types.h"
31+
#include "filegen.h"
32+
#include "file_doc.h"
33+
34+
static void register_header_check_snag(file_stat_t *file_stat);
35+
36+
const file_hint_t file_hint_snag= {
37+
.extension="snag",
38+
.description="Snagit",
39+
.max_filesize=PHOTOREC_MAX_FILE_SIZE,
40+
.recover=1,
41+
.enable_by_default=1,
42+
.register_header_check=&register_header_check_snag
43+
};
44+
45+
static void file_check_snag(file_recovery_t *file_recovery)
46+
{
47+
file_check_doc_aux(file_recovery, 24);
48+
}
49+
50+
static int header_check_snag(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
51+
{
52+
reset_file_recovery(file_recovery_new);
53+
file_recovery_new->extension=file_hint_snag.extension;
54+
file_recovery_new->file_check=&file_check_snag;
55+
file_recovery_new->min_filesize=24+512;
56+
return 1;
57+
}
58+
59+
static void register_header_check_snag(file_stat_t *file_stat)
60+
{
61+
static const unsigned char snag_header[8]= {
62+
0xcb, 'T' , 'S' , 'C' , 'S' , 'N' , 'A' , 'G'
63+
};
64+
register_header_check(0, snag_header, sizeof(snag_header), &header_check_snag, file_stat);
65+
}

0 commit comments

Comments
 (0)