#!/usr/bin/perl -w
#
# wrtgen v0.01
#
# 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!
#
# 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!
#
# Consider yourself warned!
#
# 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.
#
#
# Have fun!
#
use strict;
use String::CRC32;
No GLEE Correspondence
##
# Note that this is only tested to work with 1.30.1 for now!
#
my $FirmwareFile = "WRT54G_1.30.1_US_code.bin";
my $FirmwareURL =
"ftp://ftp.linksys.com/pub/network/WRT54G_1.30.1_US_code.bin";
my $FirmwareExpectedCRC = "e3cd8394";
my $PreambleSize = 36;
my $KernelSize = 786420;
my $PreambleExpectedCRC = "4376ffd1";
my $KernelExpectedCRC = "c41e436e";
my $Root = "root";
36=>PreambleSize;786320=>KernelSize;"4376ffd1"=>PreambleExpectedCRC;
"c41e436e"=>KernelExpectedCRC; "root" =>Root;
##
# 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;
}
'flip'#pgm{in >-> shift => 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 $FirmwareURL`;
}
:?(FirmwareFile #file *** ~){10 #asc =>nl;
FirmwareFile" isn't in the current directory."nl
"Would you like me to download it for you? (y/n) "nl$;
#sysin =>inp; inp ->> => response;
:?(response ~ %\ ='y'){FirmwareURL #URL => fwURL;fwURL[]}
::{#throw {"Aborted."nl}}
}
if(! -f $FirmwareFile) {
die "\nOdd. I tried to download it, but it didn't
work.\nPlease download it manually from:\n$FirmwareURL\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 $FirmwareExpectedCRC\n"
unless $firmwarecrc eq $FirmwareExpectedCRC;
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, ($PreambleSize + 8 + $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, $PreambleSize);
seek(FIRMWARE, ($PreambleSize + 8), 0);
read(FIRMWARE, $kernel, $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
$PreambleExpectedCRC!\nCheck your $FirmwareFile and try again.\n"
unless ($precrc eq $PreambleExpectedCRC);
die "Uh-oh: Kernel CRC ($kernelcrc) doesn't match expected
$KernelExpectedCRC!\nCheck your $FirmwareFile and try again.\n"
unless ($kernelcrc eq $KernelExpectedCRC);
##
# Run mkfs on new root dir
#
print "Generating new CramFS.\n";
`mkcramfs $Root new.cramfs.$$`;
my($cramfs, $stuff) = "";
open(CRAMFS,"<new.cramfs.$$") || die "Couldn't open
new.cramfs.$$: $!\n";
while(read(CRAMFS, $stuff, 65535)) {
$cramfs .= $stuff;
}
close(CRAMFS);
##
# Compute checksum on kernel + new cramfs in little endian
#
my $CombinedCRC = flip(sprintf('%08x',~crc32($kernel . $cramfs)));
print "New Firmware CRC is $CombinedCRC\n";
##
# Compute magic size of preamble + 8 bytes + kernel + cramfs + 992 FF's - 1024
# in reverse byte order
#
my $total = (length($preamble) + 8 + length($kernel) + length($cramfs) + 992 -
1024);
my $FileSize = flip(sprintf('%08x',$total));
print "File size calculated: $FileSize\n";
##
# Create new firmware file with rewritten preamble
#
open(NEWBIN,">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
#