#!/usr/bin/perl -w # # wrtgen v0.02 # # Make a new custom firmware for the Linksys WRT54G access point # # Rob Flickenger, 7/21/03 # # This code released under the GPL. If you don't like it, write your own! # # Available from http://nocat.net/download/wrtgen/ # # This code is also very, very alpha. The author assumes no responsibility # for the actual use of this code. It just might write bad firmware that # turns your AP into a paperweight! Or worse! # # Just in case you missed that: # # *** *** WARNING WARNING WARNING WARNING WARNING WARNING WARNING *** *** # # This code only verifies the CRC and file size contained in the headers of # the WRT54G firmware, and creates a new technically valid firmware based # on a filesystem you define. It does NOT guarantee that any firmware you # make will actually work on the AP, and could easily turn your access # point into a paper weight! It happened to me personally! It could # happen to you! Be very, very careful about what you upload to your AP! # # *** *** WARNING WARNING WARNING WARNING WARNING WARNING WARNING *** *** # # Good. Now that that's out of the way... # # Requirements: # # String::CRC32 (from the CPAN) # # wget if you want this script to download the original firmware for you # (or alternately, a copy of $FirmwareFile) # # mkcramfs, somewhere in your PATH. Version 1.1 from Sourceforge is # known to work with the WRT54G v1.30.1 and 1.30.7. Get mkcramfs from # http://sourceforge.net/projects/cramfs/ # # Have fun! # use strict; use String::CRC32; ## # Which firmware to use? # my $FirmwareFile="WRT54G_1.30.7_US_code.bin"; ## # Where to find the root fs? # my $Root = "root"; ## # Note that this is only tested to work with 1.30.1 and 1.30.7. Just # update this hash as new firmware is released. # my %Firmware = ( 'WRT54G_1.30.1_US_code.bin' => { URL => "ftp://ftp.linksys.com/pub/network/WRT54G_1.30.1_US_code.bin", ExpectedCRC => "e3cd8394", PreambleSize => 36, KernelSize => 786420, PreambleExpectedCRC => "4376ffd1", KernelExpectedCRC => "c41e436e", }, 'WRT54G_1.30.7_US_code.bin' => { URL => "ftp://ftp.linksys.com/pub/network/WRT54G_1.30.7_US_code.bin", ExpectedCRC => "dd1e1e33", PreambleSize => 36, KernelSize => 786420, PreambleExpectedCRC => "9a120175", KernelExpectedCRC => "7edf04a7", }, ); ## # No user serviceable parts below! # sub flip { my $in = shift; my $out = ""; while($in) { $out .= substr($in, -2, 2); chop($in); chop($in); } return $out; } ## # Check to see if firmware exists, and if not, offer to download it # if(! -f $FirmwareFile) { print "$FirmwareFile isn't in the current directory.\n"; print "Would you like me to download it for you? (y/n) "; my $response = <>; chomp($response); die "Aborted.\n" unless $response =~ /y/i; `wget $Firmware{$FirmwareFile}{URL}`; } if(! -f $FirmwareFile) { die "\nOdd. I tried to download it, but it didn't work.\nPlease download it manually from:\n$Firmware{$FirmwareFile}{URL}\n"; } print "$FirmwareFile found.\n"; ## # Grab the preamble and kernel from the firmware # open(FIRMWARE,"<$FirmwareFile") || die "Couldn't open $FirmwareFile: $!\n"; my $firmwarecrc = flip(sprintf('%08x',~crc32(*FIRMWARE))); die "Uh-oh: $FirmwareFile appears to be corrupt!\n$firmwarecrc doesn't match expected $Firmware{$FirmwareFile}{ExpectedCRC}\n" unless $firmwarecrc eq $Firmware{$FirmwareFile}{ExpectedCRC}; close(FIRMWARE); print "$FirmwareFile CRC verified.\n"; ## # Check if new root directory exists, and if not, offer to extract the cramfs # from the original firmware (and exit) # if(! -d $Root) { print "I can't find your new root filesystem (./$Root)\n"; print "Would you like me to extract the cramfs from $FirmwareFile? (y/n) "; my $response = <>; chomp($response); die "Aborted.\n" unless $response =~ /y/i; my $stuff = ""; open(FIRMWARE,"<$FirmwareFile") || die "Couldn't open $FirmwareFile: $!\n"; seek(FIRMWARE, ($Firmware{$FirmwareFile}{PreambleSize} + 8 + $Firmware{$FirmwareFile}{KernelSize}), 0); open(CRAMFS,">original.cramfs") || die "Couldn't write to original.cramfs: $!\n"; while(read(FIRMWARE, $stuff, 65535)) { print CRAMFS $stuff; } close(CRAMFS); close(FIRMWARE); print "Original CramFS extracted to ./original.cramfs\n"; exit; } open(FIRMWARE,"<$FirmwareFile") || die "Couldn't open $FirmwareFile: $!\n"; my ($preamble, $kernel) = ""; read(FIRMWARE, $preamble, $Firmware{$FirmwareFile}{PreambleSize}); seek(FIRMWARE, ($Firmware{$FirmwareFile}{PreambleSize} + 8), 0); read(FIRMWARE, $kernel, $Firmware{$FirmwareFile}{KernelSize}); my $precrc = flip(sprintf('%08x',~crc32($preamble))); my $kernelcrc = flip(sprintf('%08x',~crc32($kernel))); die "Uh-oh: Preamble CRC ($precrc) doesn't match expected $Firmware{$FirmwareFile}{PreambleExpectedCRC}!\nCheck your $FirmwareFile and try again.\n" unless ($precrc eq $Firmware{$FirmwareFile}{PreambleExpectedCRC}); die "Uh-oh: Kernel CRC ($kernelcrc) doesn't match expected $Firmware{$FirmwareFile}{KernelExpectedCRC}!\nCheck your $FirmwareFile and try again.\n" unless ($kernelcrc eq $Firmware{$FirmwareFile}{KernelExpectedCRC}); ## # Run mkfs on new root dir # print "Generating new CramFS.\n"; `mkcramfs $Root new.cramfs.$$`; my($cramfs, $stuff) = ""; open(CRAMFS,"new.bin") || die "Couldn't write to new.bin: $!\n"; print NEWBIN $preamble; print NEWBIN pack("H*",$FileSize); print NEWBIN pack("H*",$CombinedCRC); print NEWBIN $kernel; print NEWBIN $cramfs; print NEWBIN chr(255) x 992; close(NEWBIN); print "new.bin created. Good luck.\n"; unlink "new.cramfs.$$"; # # Ende #