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