4 # Redirect system calls of the specified file system driver to TraceFS.sys
5 # Copyright (C) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
7 # This program 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; exactly version 2 of June 1991 is required
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 use Carp qw(cluck confess);
28 my $IMAGE_FILE_IMPORT_DIRECTORY=1;
29 my $IMAGE_FILE_EXPORT_DIRECTORY=0;
30 my $IMAGE_DATA_DIRECTORY_sizeof=8;
31 my $VirtualAddress_rel_to_DATA_DIRECTORY_offs=0;
32 my $Size_rel_to_DATA_DIRECTORY_offs=4;
33 my $IMAGE_EXPORT_DIRECTORY_sizeof=0x28;
34 my $IMAGE_IMPORT_DESCRIPTOR_sizeof=0x14;
35 my $Name_rel_to_IMAGE_EXPORT_DIRECTORY_offs=0xC;
36 my $NumberOfNames_rel_to_IMAGE_EXPORT_DIRECTORY_offs=0x18;
37 my $AddressOfNames_rel_to_IMAGE_EXPORT_DIRECTORY_offs=0x20;
38 my $OriginalFirstThunk_rel_to_IMPORT_DIRECTORY_offs=0x0;
39 my $FirstThunk_rel_to_IMPORT_DIRECTORY_offs=0x10;
40 my $Name_rel_to_IMAGE_IMPORT_BY_NAME_offs=0x2;
41 my $IMAGE_SECTION_HEADER_sizeof=0x28;
42 my $Name_rel_to_IMAGE_SECTION_HEADER_offs=0x00;
43 my $VirtualSize_rel_to_IMAGE_SECTION_HEADER_offs=0x08;
44 my $VirtualAddress_rel_to_IMAGE_SECTION_HEADER_offs=0x0C;
45 my $SizeOfRawData_rel_to_IMAGE_SECTION_HEADER_offs=0x10;
46 my $PointerToRawData_rel_to_IMAGE_SECTION_HEADER_offs=0x14;
47 my $Characteristics_rel_to_IMAGE_SECTION_HEADER_offs=0x24;
52 my($file,$offset,$bits)=@_;
55 for (my $byte=0;$byte<$bits/8;$byte++) {
56 confess if !defined $file->[$offset+$byte];
57 $r|=($file->[$offset+$byte])<<($byte*8);
61 sub uint32_get($$) { return uintX_get($_[0],$_[1],32); }
62 sub uint16_get($$) { return uintX_get($_[0],$_[1],16); }
63 sub uint8_get($$) { return uintX_get($_[0],$_[1], 8); }
67 my($file,$offset,$num,$bits)=@_;
69 for (my $byte=0;$byte<$bits/8;$byte++) {
70 confess if !defined $offset;
71 $file->[$offset+$byte]=($num>>($byte*8))&0xFF;
74 sub uint32_put($$$) { return uintX_put($_[0],$_[1],$_[2],32); }
75 sub uint16_put($$$) { return uintX_put($_[0],$_[1],$_[2],16); }
76 sub uint8_put($$$) { return uintX_put($_[0],$_[1],$_[2], 8); }
77 sub uint32_push($$) { return uintX_put($_[0],@{$_[0]},$_[1],32); }
78 sub uint16_push($$) { return uintX_put($_[0],@{$_[0]},$_[1],16); }
79 sub uint8_push($$) { return uintX_put($_[0],@{$_[0]},$_[1], 8); }
86 return uint32_get($file,0x3C) # 3c: Offset to extended header
87 +0x18 # OptionalHeader
95 return uint32_get($file,sum_offs($file));
102 return uint32_put($file,sum_offs($file),$sum);
114 $sum+=(shift @$file || 0) | (shift @$file || 0)<<8;
115 $sum=($sum&0xFFFF)+($sum>>16);
125 push @$file,0 while @$file%$align;
130 my($file,$offset,$stringz)=@_;
132 $stringz=[ map({ ord(); } split //,$stringz),0 ];
134 uint8_put($file,$offset,shift @$stringz);
141 my($file,$stringz)=@_;
143 stringz_put($file,@$file,$stringz);
149 my($file,$offset)=@_;
152 while ((my $ord=uint8_get($file,$offset))) {
163 push @$file,0 while $count-->0;
166 sub SizeOfImage_offs($)
170 return uint32_get($file,0x3C) # 3c: Offset to extended header
171 +0x18 # OptionalHeader
179 my($file,$file_id)=@_;
181 my $calced=sum_calc($file);
182 if ($calced!=sum_get($file)) {
183 warn sprintf "$file_id: Original checksum wrong: found=0x%08X, calced=0x%08X",sum_get($file),$calced;
186 die sprintf "$file_id: Length 0x%X not aligned",scalar(@$file) if @$file%$align;
187 my $SizeOfImage=uint32_get($file,SizeOfImage_offs($file));
188 die sprintf "$file_id: SizeOfImage==0x%X but file size==0x%X",$SizeOfImage,scalar(@$file) if $SizeOfImage!=@$file;
191 sub export_names_get($)
195 my $EXPORT_DIRECTORY_offs=uint32_get($tracefs,0x3C) # 3c: Offset to extended header
196 +0x18 # OptionalHeader
197 +0x60 # DataDirectory
198 +$IMAGE_FILE_EXPORT_DIRECTORY*$IMAGE_DATA_DIRECTORY_sizeof;
199 my $EXPORT_DIRECTORY_VirtualAddress=uint32_get($tracefs,$EXPORT_DIRECTORY_offs+$VirtualAddress_rel_to_DATA_DIRECTORY_offs);
200 my $EXPORT_DIRECTORY_Size=uint32_get($tracefs,$EXPORT_DIRECTORY_offs+$Size_rel_to_DATA_DIRECTORY_offs);
201 die sprintf "EXPORT_DIRECTORY_Size 0x%X less than IMAGE_IMPORT_DESCRIPTOR_sizeof 0x%X",
202 $EXPORT_DIRECTORY_Size,$IMAGE_IMPORT_DESCRIPTOR_sizeof if $EXPORT_DIRECTORY_Size<$IMAGE_IMPORT_DESCRIPTOR_sizeof;
203 my $IMAGE_EXPORT_DIRECTORY_Name=uint32_get($tracefs,$EXPORT_DIRECTORY_VirtualAddress
204 +$Name_rel_to_IMAGE_EXPORT_DIRECTORY_offs);
205 my $tracefs_export_name=stringz_get($tracefs,$IMAGE_EXPORT_DIRECTORY_Name);
206 my $tracefs_export_names_num=uint32_get($tracefs,$EXPORT_DIRECTORY_VirtualAddress
207 +$NumberOfNames_rel_to_IMAGE_EXPORT_DIRECTORY_offs);
208 my $tracefs_export_AddressOfNames=uint32_get($tracefs,$EXPORT_DIRECTORY_VirtualAddress
209 +$AddressOfNames_rel_to_IMAGE_EXPORT_DIRECTORY_offs);
210 my @tracefs_export_names;
211 print STDERR "$tracefs_export_name exports:\n" if $D;
212 for (my $namei=0;$namei<$tracefs_export_names_num;$namei++) {
213 my $name_address=uint32_get($tracefs,$tracefs_export_AddressOfNames+4*$namei);
214 my $name=stringz_get($tracefs,$name_address);
215 push @tracefs_export_names,$name;
216 print STDERR "\t$name\n" if $D;
219 return ($tracefs_export_name,@tracefs_export_names);
224 my $file=[ map({ ord(); } split //,<>) ];
225 my $tracefs=[ map({ ord(); } split //,<>) ];
227 sanity($tracefs,"tracefs");
228 my($tracefs_export_name,@tracefs_export_names)=export_names_get($tracefs);
229 for my $tname (@tracefs_export_names) {
230 die "tracefs exported tname is not /^T/ compliant: $tname" if $tname!~/^T/;
232 # FIXME: compiled to .sys tracefs contains internal export name .dll but we need import .sys !
233 $tracefs_export_name=~s/[.]dll$/.sys/i;
235 sanity($file,"file");
238 # import directory load
240 my $IMPORT_DIRECTORY_offs=uint32_get($file,0x3C) # 3c: Offset to extended header
241 +0x18 # OptionalHeader
242 +0x60 # DataDirectory
243 +$IMAGE_FILE_IMPORT_DIRECTORY*$IMAGE_DATA_DIRECTORY_sizeof;
244 my $IMPORT_DIRECTORY_VirtualAddress=uint32_get($file,$IMPORT_DIRECTORY_offs+$VirtualAddress_rel_to_DATA_DIRECTORY_offs);
245 my $IMPORT_DIRECTORY_Size=uint32_get($file,$IMPORT_DIRECTORY_offs+$Size_rel_to_DATA_DIRECTORY_offs);
246 die sprintf "IMPORT_DIRECTORY_Size 0x%X not aligned to IMAGE_IMPORT_DESCRIPTOR_sizeof 0x%X",
247 $IMPORT_DIRECTORY_Size,$IMAGE_IMPORT_DESCRIPTOR_sizeof if $IMPORT_DIRECTORY_Size%$IMAGE_IMPORT_DESCRIPTOR_sizeof;
249 my $IMPORT_DIRECTORY=[ @{$file}[$IMPORT_DIRECTORY_VirtualAddress
250 ..($IMPORT_DIRECTORY_VirtualAddress+$IMPORT_DIRECTORY_Size-1)] ];
251 uintX_put($file,$IMPORT_DIRECTORY_VirtualAddress,0,8*$IMPORT_DIRECTORY_Size); # zero the original space
252 for (my $zerotail=0;$zerotail<$IMAGE_IMPORT_DESCRIPTOR_sizeof;$zerotail++) {
253 die "IMPORT_DIRECTORY tail not zeroed" if pop @$IMPORT_DIRECTORY;
257 # import directory entries processing
259 my %name_to_FirstThunk; # name->FirstThunk
260 my %tname_to_name; # string->string{^.->T}
262 my $IMPORT_DIRECTORY_offset=0;
263 $IMPORT_DIRECTORY_offset<@$IMPORT_DIRECTORY;
264 $IMPORT_DIRECTORY_offset+=$IMAGE_IMPORT_DESCRIPTOR_sizeof) {
265 my $OriginalFirstThunk_base=uint32_get($IMPORT_DIRECTORY,$IMPORT_DIRECTORY_offset
266 +$OriginalFirstThunk_rel_to_IMPORT_DIRECTORY_offs);
267 my $FirstThunk_base=uint32_get($IMPORT_DIRECTORY,$IMPORT_DIRECTORY_offset
268 +$FirstThunk_rel_to_IMPORT_DIRECTORY_offs);
269 for (my $OriginalFirstThunk=$OriginalFirstThunk_base;;$OriginalFirstThunk+=4) {
270 my $AddressOfData=uint32_get($file,$OriginalFirstThunk);
271 last if !$AddressOfData;
272 my $name=stringz_get($file,$AddressOfData+$Name_rel_to_IMAGE_IMPORT_BY_NAME_offs);
273 print STDERR "import $name\n" if $D;
274 die "Invalid name import as it has leading 'T': $name" if $name=~/^T/;
275 (my $tname=$name)=~s/^./T/;
276 die "Name conflict in tname map: $name->$tname" if exists $tname_to_name{$tname};
277 $tname_to_name{$tname}=$name;
278 die if exists $name_to_FirstThunk{$name};
279 $name_to_FirstThunk{$name}=$FirstThunk_base+($OriginalFirstThunk-$OriginalFirstThunk_base);
284 # add-on import directories generation
285 my $addon_section_base=@$file;
287 my $tracefs_export_name_offs=@$file;
288 stringz_push($file,$tracefs_export_name);
291 for my $tname (@tracefs_export_names) {
292 do { warn "tracefs exported tname $tname not found in imports"; next; } if !exists $tname_to_name{$tname};
293 my $name=$tname_to_name{$tname};
294 my $FirstThunk=$name_to_FirstThunk{$name};
296 my $IMAGE_IMPORT_BY_NAME_offs=@$file;
297 uint16_push($file,$ordinal++); # Hint
298 stringz_push($file,$tname); # Name
300 my $OriginalFirstThunk_offs=@$file;
301 uint32_push($file,$IMAGE_IMPORT_BY_NAME_offs);
302 uint32_push($file,0); # zero terminator
304 uint32_push($IMPORT_DIRECTORY,$OriginalFirstThunk_offs);
305 uint32_push($IMPORT_DIRECTORY,0); # TimeDateStamp
306 uint32_push($IMPORT_DIRECTORY,0); # ForwarderChain
307 uint32_push($IMPORT_DIRECTORY,$tracefs_export_name_offs); # Name
308 uint32_push($IMPORT_DIRECTORY,$FirstThunk);
311 zeroes_push $IMPORT_DIRECTORY,$IMAGE_IMPORT_DESCRIPTOR_sizeof;
312 uint32_put($file,$IMPORT_DIRECTORY_offs+$VirtualAddress_rel_to_DATA_DIRECTORY_offs,scalar(@$file));
313 uint32_put($file,$IMPORT_DIRECTORY_offs+$Size_rel_to_DATA_DIRECTORY_offs,scalar(@$IMPORT_DIRECTORY));
314 push @$file,@$IMPORT_DIRECTORY;
317 # rebuild the sections for add-on data
319 # concatenate .rdata to .data
320 my $SizeOfOptionalHeader_offs=uint32_get($file,0x3C) # 3c: Offset to extended header
322 +0x10; # SizeOfOptionalHeader
323 my $SizeOfOptionalHeader=uint16_get($file,$SizeOfOptionalHeader_offs);
324 my $NumberOfSections_offs=uint32_get($file,0x3C) # 3c: Offset to extended header
326 +0x2; # NumberOfSections
327 my $NumberOfSections=uint16_get($file,$NumberOfSections_offs);
328 my $IMAGE_SECTION_HEADER_offs=uint32_get($file,0x3C) # 3c: Offset to extended header
329 +0x18 # OptionalHeader
330 +$SizeOfOptionalHeader;
332 my($offset_data,$offset_rdata);
334 my $IMAGE_SECTION_HEADER_offset=$IMAGE_SECTION_HEADER_offs;
335 $IMAGE_SECTION_HEADER_offset<$IMAGE_SECTION_HEADER_offs+$NumberOfSections*$IMAGE_SECTION_HEADER_sizeof;
336 $IMAGE_SECTION_HEADER_offset+=$IMAGE_SECTION_HEADER_sizeof) {
337 my $VirtualAddress=uint32_get($file,$IMAGE_SECTION_HEADER_offset+$VirtualAddress_rel_to_IMAGE_SECTION_HEADER_offs);
338 my $PointerToRawData=uint32_get($file,$IMAGE_SECTION_HEADER_offset+$PointerToRawData_rel_to_IMAGE_SECTION_HEADER_offs);
339 die sprintf "VirtualAddress 0x%X != PointerToRawData 0x%X in IMAGE_SECTION_HEADER at 0x%X",
340 $VirtualAddress,$PointerToRawData,$IMAGE_SECTION_HEADER_offset if $VirtualAddress!=$PointerToRawData;
341 my $SizeOfRawData=uint32_get($file,$IMAGE_SECTION_HEADER_offset+$SizeOfRawData_rel_to_IMAGE_SECTION_HEADER_offs);
342 my $VirtualSize=uint32_get($file,$IMAGE_SECTION_HEADER_offset+$VirtualSize_rel_to_IMAGE_SECTION_HEADER_offs);
343 $VirtualSize+=$align-1;
344 $VirtualSize-=$VirtualSize%$align;
345 die sprintf "up_align(VirtualSize,0x%X) 0x%X != SizeOfRawData 0x%X in IMAGE_SECTION_HEADER at 0x%X",
346 $align,$VirtualSize.$SizeOfRawData,$IMAGE_SECTION_HEADER_offset if $VirtualSize!=$SizeOfRawData;
347 my $Characteristics=uint32_get($file,$IMAGE_SECTION_HEADER_offset+$Characteristics_rel_to_IMAGE_SECTION_HEADER_offs);
348 my $is_data =($Characteristics==0xC8000040);
349 my $is_rdata=($Characteristics==0x48000040);
350 die sprintf "Duplicate .data in IMAGE_SECTION_HEADER at 0x%X",$IMAGE_SECTION_HEADER_offset if $is_data && $offset_data;
351 die sprintf "Duplicate .rdata in IMAGE_SECTION_HEADER at 0x%X",$IMAGE_SECTION_HEADER_offset if $is_rdata && $offset_rdata;
352 $offset_data=$IMAGE_SECTION_HEADER_offset if $is_data;
353 $offset_rdata=$IMAGE_SECTION_HEADER_offset if $is_rdata;
355 die ".data section not found" if !$offset_data;
356 die ".rdata section not found" if !$offset_rdata;
357 my $data_PointerToRawData=uint32_get($file,$offset_data+$PointerToRawData_rel_to_IMAGE_SECTION_HEADER_offs);
358 my $data_SizeOfRawData=uint32_get($file,$offset_data+$SizeOfRawData_rel_to_IMAGE_SECTION_HEADER_offs);
359 my $data_VirtualSize=uint32_get($file,$offset_data+$VirtualSize_rel_to_IMAGE_SECTION_HEADER_offs);
360 my $rdata_PointerToRawData=uint32_get($file,$offset_rdata+$PointerToRawData_rel_to_IMAGE_SECTION_HEADER_offs);
361 my $rdata_SizeOfRawData=uint32_get($file,$offset_rdata+$SizeOfRawData_rel_to_IMAGE_SECTION_HEADER_offs);
362 my $rdata_VirtualSize=uint32_get($file,$offset_rdata+$VirtualSize_rel_to_IMAGE_SECTION_HEADER_offs);
363 die ".data is not right after .rdata" if $rdata_PointerToRawData+$rdata_SizeOfRawData!=$data_PointerToRawData;
364 uint32_put($file,$offset_data+$PointerToRawData_rel_to_IMAGE_SECTION_HEADER_offs,$rdata_PointerToRawData);
365 uint32_put($file,$offset_data+$VirtualAddress_rel_to_IMAGE_SECTION_HEADER_offs,$rdata_PointerToRawData);
366 uint32_put($file,$offset_data+$SizeOfRawData_rel_to_IMAGE_SECTION_HEADER_offs,$rdata_SizeOfRawData+$data_SizeOfRawData);
367 uint32_put($file,$offset_data+$VirtualSize_rel_to_IMAGE_SECTION_HEADER_offs,$rdata_SizeOfRawData+$data_VirtualSize);
368 # .rdata coalesced to .data, .rdata to be rebuilt now:
369 uintX_put($file,$offset_rdata,0,8*$IMAGE_SECTION_HEADER_sizeof); # zero the original space
370 stringz_put($file,$offset_rdata+$Name_rel_to_IMAGE_SECTION_HEADER_offs,"INIT");
371 uint32_put($file,$offset_rdata+$VirtualSize_rel_to_IMAGE_SECTION_HEADER_offs,@$file-$addon_section_base);
372 uint32_put($file,$offset_rdata+$VirtualAddress_rel_to_IMAGE_SECTION_HEADER_offs,$addon_section_base);
373 uint32_put($file,$offset_rdata+$SizeOfRawData_rel_to_IMAGE_SECTION_HEADER_offs,@$file-$addon_section_base);
374 uint32_put($file,$offset_rdata+$PointerToRawData_rel_to_IMAGE_SECTION_HEADER_offs,$addon_section_base);
375 uint32_put($file,$offset_rdata+$Characteristics_rel_to_IMAGE_SECTION_HEADER_offs,0xE2000020);
378 # file output finalization
379 uint32_put($file,SizeOfImage_offs($file),scalar(@$file));
380 sum_put($file,sum_calc($file));
381 print join("",map({ chr; } @$file));