kerneltest/f32test/loader/security/t_fuzzldr.cpp
changeset 0 a41df078684a
child 6 0173bcd7697c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/f32test/loader/security/t_fuzzldr.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,920 @@
+// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// f32test\loader\security\t_fuzzldr.cpp
+// 
+//
+
+#define __E32TEST_EXTENSION__
+#include <e32test.h>
+#include <e32uid.h>
+#include <f32file.h>
+#include <f32image.h>
+#include "t_hash.h"
+
+// Fuzzing parameters
+
+const TInt KFuzzImages = 5;
+const TInt KRandomFieldIterations = 8;
+const TTimeIntervalMicroSeconds32 KDllTimeout = 10 * 1000000;
+
+#define FUZZFIELD(OBJ, NAME) { (const TText*)(L ## #OBJ L"." L ## #NAME), sizeof(((OBJ*)8)->NAME), _FOFF(OBJ, NAME) }
+#define DUMBFIELD(NAME, SIZE, OFFSET) { (const TText*)L ## NAME, SIZE, OFFSET }
+#define FUZZEND { NULL, 0, 0 }
+
+struct SFuzzField
+	{
+	const TText* name;
+	TInt size;
+	TInt offset;
+	};
+
+const SFuzzField HeaderFields[] =
+	{
+	FUZZFIELD(E32ImageHeaderV, iUid1),
+	FUZZFIELD(E32ImageHeaderV, iUid2),
+	FUZZFIELD(E32ImageHeaderV, iUid3),
+	FUZZFIELD(E32ImageHeaderV, iUidChecksum),
+	FUZZFIELD(E32ImageHeaderV, iSignature),
+	FUZZFIELD(E32ImageHeaderV, iHeaderCrc),
+	FUZZFIELD(E32ImageHeaderV, iModuleVersion),
+	FUZZFIELD(E32ImageHeaderV, iCompressionType),
+	FUZZFIELD(E32ImageHeaderV, iToolsVersion.iMajor),
+	FUZZFIELD(E32ImageHeaderV, iToolsVersion.iMinor),
+	FUZZFIELD(E32ImageHeaderV, iToolsVersion.iBuild),
+	FUZZFIELD(E32ImageHeaderV, iTimeLo),
+	FUZZFIELD(E32ImageHeaderV, iTimeHi),
+	FUZZFIELD(E32ImageHeaderV, iFlags),
+	FUZZFIELD(E32ImageHeaderV, iCodeSize),
+	FUZZFIELD(E32ImageHeaderV, iDataSize),
+	FUZZFIELD(E32ImageHeaderV, iHeapSizeMin),
+	FUZZFIELD(E32ImageHeaderV, iHeapSizeMax),
+	FUZZFIELD(E32ImageHeaderV, iStackSize),
+	FUZZFIELD(E32ImageHeaderV, iBssSize),
+	FUZZFIELD(E32ImageHeaderV, iEntryPoint),
+	FUZZFIELD(E32ImageHeaderV, iCodeBase),
+	FUZZFIELD(E32ImageHeaderV, iDataBase),
+	FUZZFIELD(E32ImageHeaderV, iDllRefTableCount),
+	FUZZFIELD(E32ImageHeaderV, iExportDirOffset),
+	FUZZFIELD(E32ImageHeaderV, iExportDirCount),
+	FUZZFIELD(E32ImageHeaderV, iTextSize),
+	FUZZFIELD(E32ImageHeaderV, iCodeOffset),
+	FUZZFIELD(E32ImageHeaderV, iDataOffset),
+	FUZZFIELD(E32ImageHeaderV, iImportOffset),
+	FUZZFIELD(E32ImageHeaderV, iCodeRelocOffset),
+	FUZZFIELD(E32ImageHeaderV, iDataRelocOffset),
+	FUZZFIELD(E32ImageHeaderV, iProcessPriority),
+	FUZZFIELD(E32ImageHeaderV, iCpuIdentifier),
+	FUZZFIELD(E32ImageHeaderV, iUncompressedSize),
+	FUZZFIELD(E32ImageHeaderV, iS.iSecureId),
+	FUZZFIELD(E32ImageHeaderV, iS.iVendorId),
+	FUZZFIELD(E32ImageHeaderV, iS.iCaps.iCaps[0]),
+	FUZZFIELD(E32ImageHeaderV, iS.iCaps.iCaps[1]),
+	FUZZFIELD(E32ImageHeaderV, iExceptionDescriptor),
+	FUZZFIELD(E32ImageHeaderV, iSpare2),
+	FUZZFIELD(E32ImageHeaderV, iExportDescSize),
+	FUZZFIELD(E32ImageHeaderV, iExportDescType),
+	FUZZFIELD(E32ImageHeaderV, iExportDesc[0]),
+	FUZZEND
+	};
+
+const SFuzzField ImportSectionFields[] =
+	{
+	FUZZFIELD(E32ImportSection, iSize),
+	FUZZEND
+	};
+
+const SFuzzField ImportBlockFields[] =
+	{
+	FUZZFIELD(E32ImportBlock, iOffsetOfDllName), // we should fuzz the string also
+	FUZZFIELD(E32ImportBlock, iNumberOfImports),
+	FUZZEND
+	};
+
+const SFuzzField ImportEntryFields[] =
+	{
+	DUMBFIELD("import", 4, 0),
+	FUZZEND
+	};
+
+const SFuzzField RelocSectionFields[] =
+	{
+	FUZZFIELD(E32RelocSection, iSize),
+	FUZZFIELD(E32RelocSection, iNumberOfRelocs),
+	FUZZEND
+	};
+
+const SFuzzField RelocBlockFields[] =
+	{
+	FUZZFIELD(E32RelocBlock, iPageOffset),
+	FUZZFIELD(E32RelocBlock, iBlockSize),
+	FUZZEND
+	};
+
+const SFuzzField RelocEntryFields[] =
+	{
+	DUMBFIELD("reloc", 2, 0),
+	FUZZEND
+	};
+
+const SFuzzField ExportEntryFields[] =
+	{
+	DUMBFIELD("export", 4, 0),
+	FUZZEND
+	};
+
+const SFuzzField CompressedDataFields[] =
+	{
+	DUMBFIELD("data1", 4, 0),
+	DUMBFIELD("data2", 4, 4),
+	DUMBFIELD("data3", 4, 16),
+	DUMBFIELD("data4", 4, 64),
+	DUMBFIELD("data5", 4, 256),
+	DUMBFIELD("data6", 4, 1024),
+	DUMBFIELD("data7", 4, 4096),
+	FUZZEND
+	};
+
+// Values to try for different sizes, signed here but can be interpreted as either
+// each will also try the smaller sizes' values
+const TInt8 Values8[] = { KMinTInt8, -100, -10, -2, -1, 0, 1, 2, 10, 100, KMaxTInt8 };
+const TInt Values8Count = sizeof(Values8)/sizeof(TInt8);
+const TInt16 Values16[] = { KMinTInt16, -10000, -256, -255, 128, 255, 256, 10000, KMaxTInt16 };
+const TInt Values16Count = sizeof(Values16)/sizeof(TInt16);
+const TInt32 Values32[] = { KMinTInt32, -1000000000, -65536, -65535, 32768, 65535, 65536, 268435455, 268435456, 1000000000, KMaxTInt32 };
+const TInt Values32Count = sizeof(Values32)/sizeof(TInt32);
+const TInt ValuesCount[] = { 0, Values8Count, Values8Count+Values16Count, 0, Values8Count+Values16Count+Values32Count };
+const TInt Offsets[] = { 1, 2, 4, 16, -1, -2, -4, -16 };
+const TInt OffsetsCount = sizeof(Offsets)/sizeof(TInt);
+
+// Regular boring definitions and stuff
+
+RTest test(_L("T_FUZZLDR"));
+RFs TheFs;
+CFileMan* FileMan;
+
+_LIT(KOrigDir, "Z:\\sys\\bin\\");
+_LIT(KSysBin, ":\\sys\\bin\\");
+_LIT(KSysHash, ":\\sys\\hash\\");
+_LIT(KImageName, "fuzzv");
+_LIT(KExeExt, ".exe");
+_LIT(KDllExt, ".dll");
+_LIT(KMyself, "t_fuzzldr");
+_LIT(KSlaveArg, "-l ");
+
+TFileName Provided;
+TFileName Original;
+TFileName Current;
+TFileName Hash;
+TFileName HashDir;
+TBool LoadDll;
+RFile File;
+RTimer Timer;
+TUint8* Target;
+E32ImageHeaderV* Header;
+E32ImageHeaderV* CleanHeader;
+CSHA1* Hasher;
+
+TInt FileSize;
+TInt OutFileSize;
+TUint8* CleanFileData;
+TPtr8 CleanFileDes(CleanFileData, 0);
+TUint8* FileData;
+TPtr8 FileDes(FileData, 0);
+TUint8* EndOfFile;
+TChar Drive = '?', InternalDrive = '?', RemovableDrive = '?';
+
+TBool Verbose;
+TBool Forever = EFalse;
+TUint32 Seed = 0;
+typedef void (*TFieldFuzzer)(const SFuzzField*, TInt);
+
+enum SetMode {
+	ESetLiteral,
+	ESetOffset,
+	ESetRandom,
+	ESetXor,
+};
+
+enum ValueMode {
+	EValLiteral,
+	EValOffset,
+	EValRandom,
+	EValXor,
+	EValList,
+	EValOffsetList,
+};
+
+
+TUint32 Rand()
+	{
+	Seed *= 69069;
+	Seed += 5;
+	return Seed;
+	}
+
+
+TUint32 Rand(TUint32 aLimit)
+	{
+	TUint64 temp = (TUint64)Rand() * (TUint64)aLimit;
+	return (TUint32)(temp>>32);
+	}
+
+
+void PrepareName(TInt aNum, TBool aDll)
+	{
+	Original = KOrigDir;
+	Original += KImageName;
+	Original.AppendNum(aNum);
+	Original += aDll ? KDllExt : KExeExt;
+	Current.Zero();
+	Current.Append(Drive);
+	Current += KSysBin;
+	Current += KImageName;
+	Current.AppendNum(aNum);
+	Current += aDll ? KDllExt : KExeExt;
+	Hash = HashDir;
+	Hash += KImageName;
+	Hash.AppendNum(aNum);
+	Hash += aDll ? KDllExt : KExeExt;
+	}
+
+
+void PrepareProvidedName()
+	{
+	Original = KOrigDir;
+	Original += Provided;
+	Current.Zero();
+	Current.Append(Drive);
+	Current += KSysBin;
+	Current += Provided;
+	Hash = HashDir;
+	Hash += Provided;
+	}
+
+
+void MakeCleanCopy()
+	{
+	Mem::Copy(FileData, CleanFileData, FileSize);
+	}
+
+
+void LoadCleanFile()
+	{
+	test_KErrNone(File.Open(TheFs, Original, EFileRead));
+	test_KErrNone(File.Size(FileSize));
+	OutFileSize = FileSize;
+	CleanFileData = new TUint8[FileSize];
+	test_NotNull(CleanFileData);
+	FileData = new TUint8[FileSize];
+	EndOfFile = FileData + FileSize;
+	test_NotNull(FileData);
+	CleanFileDes.Set(CleanFileData, 0, FileSize);
+	test_KErrNone(File.Read(CleanFileDes));
+	File.Close();
+	Header = (E32ImageHeaderV*)FileData;
+	CleanHeader = (E32ImageHeaderV*)CleanFileData;
+	FileDes.Set(FileData, FileSize, FileSize);
+	MakeCleanCopy();
+	test(CleanHeader->iUid1==(TUint32)KExecutableImageUidValue || CleanHeader->iUid1==(TUint32)KDynamicLibraryUidValue);
+	LoadDll = CleanHeader->iUid1==(TUint32)KDynamicLibraryUidValue;
+	}
+
+
+void DoneFile()
+	{
+	delete[] FileData;
+	delete[] CleanFileData;
+	}
+
+
+void RecalcChecksums()
+	{
+	if (Header->iUidChecksum == CleanHeader->iUidChecksum)
+		{
+		TUidType uids = *(const TUidType*)Header;
+		TCheckedUid chkuid(uids);
+		const TUint32* pChkUid = (const TUint32*)&chkuid;
+		Header->iUidChecksum = pChkUid[3];
+		}
+	if (Header->iHeaderCrc == CleanHeader->iHeaderCrc)
+		{
+		Header->iHeaderCrc = KImageCrcInitialiser;
+		TUint32 crc = 0;
+		Mem::Crc32(crc, Header, sizeof(E32ImageHeaderV));
+		Header->iHeaderCrc = crc;
+		}
+	}
+
+
+void Load()
+	{
+	RecalcChecksums();
+	test_KErrNone(File.Replace(TheFs, Current, EFileWrite));
+	test_KErrNone(File.Write(FileDes, OutFileSize));
+	test_KErrNone(File.Flush());
+	File.Close();
+	if (Drive == RemovableDrive)
+		{
+		TPtrC8 data(FileData, OutFileSize);
+		Hasher->Reset();
+		Hasher->Update(data);
+		TBuf8<SHA1_HASH> hashVal = Hasher->Final();
+		test_KErrNone(File.Replace(TheFs, Hash, EFileWrite));
+		test_KErrNone(File.Write(hashVal));
+		test_KErrNone(File.Flush());
+		File.Close();
+		}
+	RProcess p;
+	TInt r;
+	if (LoadDll)
+		{
+		TFileName args;
+		args.Copy(KSlaveArg);
+		args.Append(Current);
+		test_KErrNone(p.Create(KMyself, args));
+		TRequestStatus logon, rendez, timeout;
+		p.Logon(logon);
+		p.Rendezvous(rendez);
+		p.Resume();
+		User::WaitForRequest(rendez);
+		test(rendez==KErrNone);
+		Timer.After(timeout, KDllTimeout);
+		User::WaitForRequest(logon, timeout);
+		if (logon == KRequestPending)
+			{
+			p.Kill(0);
+			User::WaitForRequest(logon);
+			}
+		else
+			{
+			Timer.Cancel();
+			User::WaitForRequest(timeout);
+			}
+		p.Close();
+		// we don't check the return code as passing it back makes the log output
+		// super spammy with KPANIC on - it prints for every nonzero return code.
+		if (Verbose) test.Printf(_L("\n"));
+		}
+	else
+		{
+		r = p.Create(Current, KNullDesC);
+		if (r==KErrNone)
+			p.Kill(0);
+		if (Verbose) test.Printf(_L("=> %d\n"), r);
+		}
+	p.Close();
+	}
+
+
+template <typename T> void SetFieldTo(const SFuzzField* aField, T aSetTo, SetMode aMode)
+	{
+	T* field = (T*)(Target + aField->offset);
+	if ((TUint8*)field >= EndOfFile)
+		{
+		if (Verbose) test.Printf(_L("skipping, eof "));
+		return;
+		}
+	if (aMode == ESetOffset)
+		aSetTo += *field;
+	else if (aMode == ESetRandom)
+		aSetTo = (T)Rand();
+	else if (aMode == ESetXor)
+		aSetTo ^= *field;
+	*field = aSetTo;
+	if (Verbose) test.Printf(_L("%d "), aSetTo);
+	}
+
+
+void SetField(const SFuzzField* aField, TInt aValue, ValueMode aMode)
+	{
+	if (aMode < EValList)
+		{
+		switch(aField->size)
+			{
+		case 1:
+			SetFieldTo<TInt8>(aField, aValue, (SetMode)aMode);
+			break;
+		case 2:
+			SetFieldTo<TInt16>(aField, aValue, (SetMode)aMode);
+			break;
+		case 4:
+			SetFieldTo<TInt32>(aField, aValue, (SetMode)aMode);
+			break;
+			}
+		}
+	else if (aMode == EValList)
+		{
+		switch(aField->size)
+			{
+		case 1:
+			SetFieldTo<TInt8>(aField, Values8[aValue], ESetLiteral);
+			break;
+		case 2:
+			if (aValue < ValuesCount[1])
+				SetFieldTo<TInt16>(aField, Values8[aValue], ESetLiteral);
+			else
+				SetFieldTo<TInt16>(aField, Values16[aValue-ValuesCount[1]], ESetLiteral);
+			break;
+		case 4:
+			if (aValue < ValuesCount[1])
+				SetFieldTo<TInt32>(aField, Values8[aValue], ESetLiteral);
+			else if (aValue < ValuesCount[2])
+				SetFieldTo<TInt32>(aField, Values16[aValue-ValuesCount[1]], ESetLiteral);
+			else
+				SetFieldTo<TInt32>(aField, Values32[aValue-ValuesCount[2]], ESetLiteral);
+			break;
+			}
+		}
+	else if (aMode == EValOffsetList)
+		{
+		switch(aField->size)
+			{
+		case 1:
+			SetFieldTo<TInt8>(aField, Offsets[aValue], ESetOffset);
+			break;
+		case 2:
+			SetFieldTo<TInt16>(aField, Offsets[aValue], ESetOffset);
+			break;
+		case 4:
+			SetFieldTo<TInt32>(aField, Offsets[aValue], ESetOffset);
+			break;
+			}
+		}
+	}
+
+
+void FuzzFieldsDeterministically(const SFuzzField* aFields, TInt aOffset)
+	{
+	Target = FileData + aOffset;
+
+	TInt f = -1;
+   	while (aFields[++f].name)
+		{
+		test.Printf(_L("FIELD: %s ...\n"), aFields[f].name);
+		TInt v;
+		if (Verbose) test.Next(_L("Using preset values"));
+		for (v = 0; v < ValuesCount[aFields[f].size]; ++v)
+			{
+			MakeCleanCopy();
+			SetField(&aFields[f], v, EValList);
+			Load();
+			}
+		if (Verbose) test.Next(_L("Using preset offsets"));
+		for (v = 0; v < OffsetsCount; ++v)
+			{
+			MakeCleanCopy();
+			SetField(&aFields[f], v, EValOffsetList);
+			Load();
+			}
+		if (Verbose) test.Next(_L("Flipping single bits"));
+		for (v = 0; v < aFields[f].size*8; ++v)
+			{
+			MakeCleanCopy();
+			SetField(&aFields[f], 1<<v, EValXor);
+			Load();
+			}
+		if (Verbose) test.Next(_L("Inverting"));
+		MakeCleanCopy();
+		SetField(&aFields[f], 0xffffffffu, EValXor);
+		Load();
+
+		// things that are offsets all go below, pointless on
+		// narrow fields
+		if (aFields[f].size == 4)
+			{
+			if (Verbose) test.Next(_L("Using filesize relative values"));
+			for (v = FileSize-4; v <= FileSize+4; ++v)
+				{
+				MakeCleanCopy();
+				SetField(&aFields[f], v, EValLiteral);
+				Load();
+				}
+			if (Verbose) test.Next(_L("Using code-end relative values"));
+			TInt codeend = CleanHeader->iCodeSize + CleanHeader->iCodeOffset;
+			for (v = codeend-4; v <= codeend+4; ++v)
+				{
+				MakeCleanCopy();
+				SetField(&aFields[f], v, EValLiteral);
+				Load();
+				}
+			}
+		}
+	}
+
+
+void FuzzFieldsRandomly(const SFuzzField* aFields, TInt aOffset)
+	{
+	Target = FileData + aOffset;
+
+	TInt f = 0;
+   	while (aFields[f].name)
+		{
+		test.Printf(_L("FIELD: %s ... (random)\n"), aFields[f].name);
+		TInt v;
+		for (v = 0; v < KRandomFieldIterations; ++v)
+			{
+			MakeCleanCopy();
+			SetField(&aFields[f], 0, EValRandom);
+			Load();
+			}
+		f++;
+		}
+	}
+
+
+void FuzzBlockRandomly(TInt aOffset, TInt aSize)
+	{
+	SFuzzField field;
+	field.size = 1;
+	Target = FileData + aOffset;
+	
+	test.Printf(_L("FIELD: random words in data\n"));
+	TInt v;
+	for (v = 0; v < KRandomFieldIterations * 4; ++v)
+		{
+		MakeCleanCopy();
+		field.offset = Rand(aSize);
+		if (Verbose) test.Printf(_L("@ %d, "), field.offset);
+		SetField(&field, 0, EValRandom);
+		Load();
+		}
+	}
+
+
+void FuzzFile(TBool aRandom)
+	{
+	TTime before, after;
+	before.UniversalTime();
+	LoadCleanFile();
+	
+	TFieldFuzzer FuzzFields = aRandom ? FuzzFieldsRandomly : FuzzFieldsDeterministically;
+
+	// E32ImageHeader
+	FuzzFields(HeaderFields, 0);
+
+	if (CleanHeader->iCompressionType == KFormatNotCompressed)
+		{
+		// import table
+		TInt offset = CleanHeader->iImportOffset;
+		if (offset != 0)
+			{
+			FuzzFields(ImportSectionFields, offset);
+			offset += sizeof(E32ImportSection);
+			FuzzFields(ImportBlockFields, offset);
+			offset += sizeof(E32ImportBlock);
+			FuzzFields(ImportEntryFields, offset);
+			}
+
+		// code relocations
+		offset = CleanHeader->iCodeRelocOffset;
+		if (offset != 0)
+			{
+			FuzzFields(RelocSectionFields, offset);
+			offset += sizeof(E32RelocSection);
+			FuzzFields(RelocBlockFields, offset);
+			offset += sizeof(E32RelocBlock);
+			FuzzFields(RelocEntryFields, offset);
+			}
+
+		// data relocations
+		offset = CleanHeader->iDataRelocOffset;
+		if (offset != 0)
+			{
+			FuzzFields(RelocSectionFields, offset);
+			offset += sizeof(E32RelocSection);
+			FuzzFields(RelocBlockFields, offset);
+			offset += sizeof(E32RelocBlock);
+			FuzzFields(RelocEntryFields, offset);
+			}
+
+		// export table
+		offset = CleanHeader->iExportDirOffset;
+		if (offset != 0)
+			{
+			FuzzFields(ExportEntryFields, offset);
+			}
+		}
+	else
+		{
+		if (aRandom)
+			{
+			// random bits of the compressed data
+			FuzzBlockRandomly(CleanHeader->iCodeOffset, FileSize - CleanHeader->iCodeOffset);
+			}
+		else
+			{
+			// arbitrary bits of the compressed data
+			FuzzFields(CompressedDataFields, CleanHeader->iCodeOffset);
+			}
+		}
+
+	DoneFile();
+	after.UniversalTime();
+	TTimeIntervalSeconds interval;
+	after.SecondsFrom(before, interval);
+	test.Printf(_L("Took %d seconds\n"), interval.Int());
+	}
+
+
+void FuzzTruncateTo(TInt size)
+	{
+	OutFileSize = size - 4;
+	if (Verbose) test.Printf(_L("%d "), OutFileSize);
+	Load();
+	OutFileSize = size - 1;
+	if (Verbose) test.Printf(_L("%d "), OutFileSize);
+	Load();
+	if (size == FileSize)
+		return;
+	OutFileSize = size;
+	if (Verbose) test.Printf(_L("%d "), OutFileSize);
+	Load();
+	OutFileSize = size + 1;
+	if (Verbose) test.Printf(_L("%d "), OutFileSize);
+	Load();
+	OutFileSize = size + 4;
+	if (Verbose) test.Printf(_L("%d "), OutFileSize);
+	Load();
+	}
+
+
+void FuzzTruncate()
+	{
+	TTime before, after;
+	before.UniversalTime();
+	LoadCleanFile();
+
+	FuzzTruncateTo(CleanHeader->iCodeOffset);
+	if (CleanHeader->iCompressionType == KFormatNotCompressed)
+		FuzzTruncateTo(CleanHeader->iCodeOffset+CleanHeader->iCodeSize);
+	FuzzTruncateTo(FileSize);
+
+	DoneFile();
+	after.UniversalTime();
+	TTimeIntervalSeconds interval;
+	after.SecondsFrom(before, interval);
+	test.Printf(_L("Took %d seconds\n"), interval.Int());
+	}
+
+
+void FuzzAllTestImages()
+	{
+	TInt i;
+	Drive = InternalDrive;
+	test.Next(_L("Fuzzing deterministically"));
+	for (i=1; i<=KFuzzImages; ++i)
+		{
+		test.Next(_L("Next binary..."));
+		test.Printf(_L("Fuzzing exe %d\n"), i);
+		PrepareName(i, EFalse);
+		FuzzFile(EFalse);
+		if(i==5)
+			continue; // DLL 5 doesn't exist because toolchain doesn't like DLLs with no exports
+		test.Next(_L("Next binary..."));
+		test.Printf(_L("Fuzzing dll %d\n"), i);
+		PrepareName(i, ETrue);
+		FuzzFile(EFalse);
+		}
+	Drive = RemovableDrive;
+	test.Next(_L("Fuzzing deterministically on removable media"));
+	for (i=1; i<=KFuzzImages; ++i)
+		{
+		test.Next(_L("Next binary..."));
+		test.Printf(_L("Fuzzing exe %d\n"), i);
+		PrepareName(i, EFalse);
+		FuzzFile(EFalse);
+		if(i==5)
+			continue; // DLL 5 doesn't exist because toolchain doesn't like DLLs with no exports
+		test.Next(_L("Next binary..."));
+		test.Printf(_L("Fuzzing dll %d\n"), i);
+		PrepareName(i, ETrue);
+		FuzzFile(EFalse);
+		}
+	Drive = InternalDrive;
+	test.Next(_L("Fuzzing by truncation"));
+	for (i=1; i<=KFuzzImages; ++i)
+		{
+		test.Next(_L("Next binary..."));
+		test.Printf(_L("Fuzzing exe %d\n"), i);
+		PrepareName(i, EFalse);
+		FuzzTruncate();
+		if(i==5)
+			continue; // DLL 5 doesn't exist because toolchain doesn't like DLLs with no exports
+		test.Next(_L("Next binary..."));
+		test.Printf(_L("Fuzzing dll %d\n"), i);
+		PrepareName(i, ETrue);
+		FuzzTruncate();
+		}	
+	Drive = RemovableDrive;
+	test.Next(_L("Fuzzing by truncation on removable media"));
+	for (i=1; i<=KFuzzImages; ++i)
+		{
+		test.Next(_L("Next binary..."));
+		test.Printf(_L("Fuzzing exe %d\n"), i);
+		PrepareName(i, EFalse);
+		FuzzTruncate();
+		if(i==5)
+			continue; // DLL 5 doesn't exist because toolchain doesn't like DLLs with no exports
+		test.Next(_L("Next binary..."));
+		test.Printf(_L("Fuzzing dll %d\n"), i);
+		PrepareName(i, ETrue);
+		FuzzTruncate();
+		}	
+	test.Next(_L("Fuzzing randomly"));
+	do
+		{
+		for (i=1; i<=KFuzzImages; ++i)
+			{
+			Drive = InternalDrive;
+			test.Next(_L("Next binary..."));
+			test.Printf(_L("Fuzzing exe %d\n"), i);
+			PrepareName(i, EFalse);
+			FuzzFile(ETrue);
+			if(i==5)
+				continue; // DLL 5 doesn't exist because toolchain doesn't like DLLs with no exports
+			test.Next(_L("Next binary..."));
+			test.Printf(_L("Fuzzing dll %d\n"), i);
+			PrepareName(i, ETrue);
+			FuzzFile(ETrue);
+			Drive = RemovableDrive;
+			test.Next(_L("Next binary..."));
+			test.Printf(_L("Fuzzing exe %d on removable media\n"), i);
+			PrepareName(i, EFalse);
+			FuzzFile(ETrue);
+			if(i==5)
+				continue; // DLL 5 doesn't exist because toolchain doesn't like DLLs with no exports
+			test.Next(_L("Next binary..."));
+			test.Printf(_L("Fuzzing dll %d on removable media\n"), i);
+			PrepareName(i, ETrue);
+			FuzzFile(ETrue);
+			}
+		}
+	while (Forever);
+	}
+
+
+void FuzzProvidedImage()
+	{
+	test.Printf(_L("Fuzzing file %S\n"), &Provided);
+	PrepareProvidedName();
+	Drive = InternalDrive;
+	test.Next(_L("Fuzzing deterministically"));
+	FuzzFile(EFalse);
+	Drive = RemovableDrive;
+	test.Next(_L("Fuzzing deterministically on removable media"));
+	FuzzFile(EFalse);
+	test.Next(_L("Fuzzing by truncation"));
+	FuzzTruncate();
+	Drive = RemovableDrive;
+	test.Next(_L("Fuzzing by truncation on removable media"));
+	FuzzTruncate();
+	test.Next(_L("Fuzzing randomly"));
+	do
+		{
+		Drive = InternalDrive;
+		test.Next(_L("Internal drive"));
+		FuzzFile(ETrue);
+		Drive = RemovableDrive;
+		test.Next(_L("Removable drive"));
+		FuzzFile(ETrue);
+		}
+	while (Forever);
+	}
+
+
+GLDEF_C TInt E32Main()
+	{
+	// default to verbose unless the fasttest trace flag is on
+	Verbose = (UserSvr::DebugMask(2)&0x00000002) == 0;
+
+	TFileName cmd;
+	User::CommandLine(cmd);
+	TLex lex(cmd);
+	FOREVER
+		{
+		lex.SkipSpace();
+		if (lex.Eos())
+			break;
+		TChar next = lex.Peek();
+		if (next == '-' || next == '/')
+			{
+			// option
+			lex.Inc();
+			switch(lex.Get())
+				{
+			case 'v':
+				Verbose = ETrue;
+				break;
+			case 'q':
+				Verbose = EFalse;
+				break;
+			case 'l':
+				{
+				// being used as a slave to load a DLL
+				TPtrC libname(lex.NextToken());
+				RLibrary l;
+				RProcess::Rendezvous(KErrNone);
+				l.Load(libname);
+				return KErrNone;
+				}
+			case 's':
+				// random seed
+				lex.SkipSpace();
+				test_KErrNone(lex.Val(Seed, EHex));
+				test.Printf(_L("Using supplied random seed %08x\n"), Seed);
+				break;
+			case 'f':
+				// run forever
+				Forever = ETrue;
+				break;
+				}
+			}
+		else
+			{
+			// filename, at least i assume it is :)
+			Provided.Copy(lex.NextToken());
+			}
+		}
+
+	test.Title();
+	test.Next(_L("Setup"));
+	__UHEAP_MARK;
+	CTrapCleanup* cleanup;
+	cleanup=CTrapCleanup::New();
+
+	if (Seed == 0)
+		{
+		TTime time;
+		time.UniversalTime();
+		Seed = (TUint32)time.Int64();
+		test.Printf(_L("Random seed is %08x\n"), Seed);
+		}
+
+	test_KErrNone(TheFs.Connect());
+	test_TRAP(FileMan=CFileMan::NewL(TheFs));
+	test_KErrNone(Timer.CreateLocal());
+	test_TRAP(Hasher=CSHA1::NewL());
+	HashDir.Append(TheFs.GetSystemDriveChar());
+	HashDir.Append(KSysHash);
+	TInt r = TheFs.MkDirAll(HashDir);
+	test(r == KErrNone || r == KErrAlreadyExists);	
+
+	// Find some interesting drives
+	for (TInt driveno = EDriveA; driveno <= EDriveZ; ++driveno)
+		{
+		TDriveInfo di;
+		test_KErrNone(TheFs.Drive(di, driveno));
+		if (di.iType == EMediaNotPresent)
+			continue;
+		TChar drivechar;
+		test_KErrNone(TheFs.DriveToChar(driveno, drivechar));
+		if ((di.iDriveAtt & KDriveAttInternal) && InternalDrive == '?')
+			InternalDrive = drivechar;
+		else if ((di.iDriveAtt & KDriveAttRemovable) && RemovableDrive == '?')
+			RemovableDrive = drivechar;
+		else
+			continue;
+
+		TFileName fn;
+		fn.Append(drivechar);
+		fn.Append(KSysBin);
+		TheFs.MkDirAll(fn);
+		test(r == KErrNone || r == KErrAlreadyExists);	
+		}
+	test.Printf(_L("Using %c as internal drive, %c as removable\n"), (TUint)InternalDrive, (TUint)RemovableDrive);
+
+	// Turn off evil lazy dll unloading
+	RLoader l;
+	test_KErrNone(l.Connect());
+	test_KErrNone(l.CancelLazyDllUnload());
+	l.Close();
+
+	test.Start(_L("Fuzzing loader"));
+	if (Provided.Length() == 0)
+		FuzzAllTestImages();
+	else
+		FuzzProvidedImage();
+	test.End();
+
+	delete Hasher;
+	Timer.Close();
+	delete FileMan;
+	TheFs.Close();
+	test.Close();
+	delete cleanup;
+	__UHEAP_MARKEND;
+	return KErrNone;
+	}
+
+