1 /*
2 
3     File: fat_cluster.c
4 
5     Copyright (C) 1998-2009 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 
27 #include <stdio.h>
28 #ifdef HAVE_STRING_H
29 #include <string.h>
30 #endif
31 #ifdef HAVE_STDLIB_H
32 #include <stdlib.h>
33 #endif
34 #include "types.h"
35 #include "common.h"
36 #include "intrf.h"
37 #include "intrfn.h"
38 #include "log.h"
39 #include "fat_cluster.h"
40 #include "fat.h"
41 #include "fat_common.h"
42 
43 /* Using a couple of inodes of "." directory entries, get the cluster size and where the first cluster begins.
44  * */
find_sectors_per_cluster(disk_t * disk_car,partition_t * partition,const int verbose,const int dump_ind,unsigned int * sectors_per_cluster,uint64_t * offset_org,const upart_type_t upart_type)45 int find_sectors_per_cluster(disk_t *disk_car, partition_t *partition, const int verbose, const int dump_ind, unsigned int *sectors_per_cluster, uint64_t *offset_org, const upart_type_t upart_type)
46 {
47   unsigned int nbr_subdir=0;
48   sector_cluster_t sector_cluster[10];
49   uint64_t offset;
50   uint64_t skip_offset;
51   int ind_stop=0;
52   unsigned char *buffer=(unsigned char *)MALLOC(disk_car->sector_size);
53 #ifdef HAVE_NCURSES
54   wmove(stdscr,22,0);
55   wattrset(stdscr, A_REVERSE);
56   waddstr(stdscr,"  Stop  ");
57   wattroff(stdscr, A_REVERSE);
58 #endif
59   /* 2 fats, maximum cluster size=128 */
60   skip_offset=(uint64_t)((partition->part_size-32*disk_car->sector_size)/disk_car->sector_size/128*3/2/disk_car->sector_size*2)*disk_car->sector_size;
61   if(verbose>0)
62   {
63     log_verbose("find_sectors_per_cluster skip_sectors=%lu (skip_offset=%lu)\n",
64 	(unsigned long)(skip_offset/disk_car->sector_size),
65 	(unsigned long)skip_offset);
66   }
67   for(offset=skip_offset;
68       offset<partition->part_size && !ind_stop && nbr_subdir<10;
69       offset+=disk_car->sector_size)
70   {
71 #ifdef HAVE_NCURSES
72     if((offset&(1024*disk_car->sector_size-1))==0)
73     {
74       wmove(stdscr,9,0);
75       wclrtoeol(stdscr);
76       wprintw(stdscr,"Search subdirectory %10lu/%lu %u",(unsigned long)(offset/disk_car->sector_size),(unsigned long)(partition->part_size/disk_car->sector_size),nbr_subdir);
77       wrefresh(stdscr);
78       ind_stop|=check_enter_key_or_s(stdscr);
79     }
80 #endif
81     if((unsigned)disk_car->pread(disk_car, buffer, disk_car->sector_size, partition->part_offset + offset) == disk_car->sector_size)
82     {
83       if(buffer[0]=='.' && is_fat_directory(buffer))
84       {
85 	const unsigned long int cluster=fat_get_cluster_from_entry((const struct msdos_dir_entry *)buffer);
86 	log_info("sector %lu, cluster %lu\n",
87 	    (unsigned long)(offset/disk_car->sector_size), cluster);
88 	sector_cluster[nbr_subdir].cluster=cluster;
89 	sector_cluster[nbr_subdir].sector=offset/disk_car->sector_size;
90 	nbr_subdir++;
91 #ifdef HAVE_NCURSES
92 	if(dump_ind>0)
93 	  dump_ncurses(buffer,disk_car->sector_size);
94 #endif
95       }
96     }
97   }
98   free(buffer);
99   return find_sectors_per_cluster_aux(sector_cluster,nbr_subdir,sectors_per_cluster,offset_org,verbose,partition->part_size/disk_car->sector_size, upart_type);
100 }
101 
find_sectors_per_cluster_aux(const sector_cluster_t * sector_cluster,const unsigned int nbr_sector_cluster,unsigned int * sectors_per_cluster,uint64_t * offset,const int verbose,const unsigned long int part_size_in_sectors,const upart_type_t upart_type)102 int find_sectors_per_cluster_aux(const sector_cluster_t *sector_cluster, const unsigned int nbr_sector_cluster,unsigned int *sectors_per_cluster, uint64_t *offset, const int verbose, const unsigned long int part_size_in_sectors, const upart_type_t upart_type)
103 {
104   cluster_offset_t *cluster_offset;
105   unsigned int i,j;
106   unsigned int nbr_sol=0;
107   if(nbr_sector_cluster<2)
108     return 0;
109   cluster_offset=(cluster_offset_t *)MALLOC(nbr_sector_cluster*nbr_sector_cluster*sizeof(cluster_offset_t));
110   log_info("find_sectors_per_cluster_aux\n");
111   for(i=0;i<nbr_sector_cluster-1;i++)
112   {
113     for(j=i+1;j<nbr_sector_cluster;j++)
114     {
115       if(sector_cluster[j].cluster > sector_cluster[i].cluster)
116       {
117         unsigned int sectors_per_cluster_tmp=(sector_cluster[j].sector-sector_cluster[i].sector)/(sector_cluster[j].cluster-sector_cluster[i].cluster);
118         switch(sectors_per_cluster_tmp)
119         {
120           case 1:
121           case 2:
122           case 4:
123           case 8:
124           case 16:
125           case 32:
126           case 64:
127           case 128:
128             if(sector_cluster[i].sector > (uint64_t)(sector_cluster[i].cluster-2) * sectors_per_cluster_tmp)
129             {
130               unsigned int sol_cur;
131               unsigned int found=0;
132               uint64_t offset_tmp=sector_cluster[i].sector-(uint64_t)(sector_cluster[i].cluster-2)*sectors_per_cluster_tmp;
133               for(sol_cur=0;sol_cur<nbr_sol && !found;sol_cur++)
134               {
135                 if(cluster_offset[sol_cur].sectors_per_cluster==sectors_per_cluster_tmp &&
136                     cluster_offset[sol_cur].offset==offset_tmp)
137                 {
138                   if(cluster_offset[sol_cur].first_sol==i)
139                   {
140                     cluster_offset[sol_cur].nbr++;
141                   }
142                   /* log_debug("sectors_per_cluster=%u offset=%lu nbr=%u\n",cluster_offset[sol_cur].sectors_per_cluster,cluster_offset[sol_cur].offset,cluster_offset[sol_cur].nbr); */
143                   found=1;
144                 }
145               }
146               if(!found)
147               {
148                 cluster_offset[nbr_sol].sectors_per_cluster=sectors_per_cluster_tmp;
149                 cluster_offset[nbr_sol].offset=offset_tmp;
150                 cluster_offset[nbr_sol].nbr=1;
151                 cluster_offset[nbr_sol].first_sol=i;
152                 nbr_sol++;
153               }
154             }
155             break;
156         }
157       }
158     }
159   }
160   /* Show results */
161   {
162     unsigned int nbr_max=0;
163     for(i=0;i<nbr_sol;i++)
164     {
165       const upart_type_t upart_type_new=no_of_cluster2part_type((part_size_in_sectors-cluster_offset[i].offset)/cluster_offset[i].sectors_per_cluster);
166       if(verbose>0)
167       {
168         log_verbose("sectors_per_cluster=%u offset=%lu nbr=%u ",
169             cluster_offset[i].sectors_per_cluster,
170             cluster_offset[i].offset,
171             cluster_offset[i].nbr);
172         switch(upart_type_new)
173         {
174           case UP_FAT12:
175             log_info("FAT : 12\n");
176             break;
177           case UP_FAT16:
178             log_info("FAT : 16\n");
179             break;
180           case UP_FAT32:
181             log_info("FAT : 32\n");
182             break;
183           default:	/* No compiler warning */
184             break;
185         }
186       }
187       if((upart_type==UP_UNK || upart_type==upart_type_new) &&
188 	  cluster_offset[i].nbr>nbr_max)
189       {
190 	nbr_max=cluster_offset[i].nbr;
191 	*sectors_per_cluster=cluster_offset[i].sectors_per_cluster;
192 	*offset=cluster_offset[i].offset;
193       }
194     }
195     free(cluster_offset);
196     if(nbr_max==0)
197       return 0;
198     log_info("Selected: sectors_per_cluster=%u, cluster 2 at sector %lu, nbr=%u\n",
199 	*sectors_per_cluster, (long unsigned int)(*offset), nbr_max);
200     return 1;
201   }
202 }
203 
no_of_cluster2part_type(const unsigned long int no_of_cluster)204 upart_type_t no_of_cluster2part_type(const unsigned long int no_of_cluster)
205 {
206   if(no_of_cluster<65525)
207   {
208     if(no_of_cluster<4085)
209       return UP_FAT12;
210     else
211       return UP_FAT16;
212   }
213   return UP_FAT32;
214 }
215 
216