public ECUInterface(BinaryReader reader, long baseAddress) { BaseAddress = baseAddress; reader.BaseStream.Seek(BaseAddress, SeekOrigin.Begin); // we can now properly operate on the interface block ulong interfaceBitflags = reader.ReadUInt32(); Qualifier = CaesarReader.ReadBitflagStringWithReader(ref interfaceBitflags, reader, BaseAddress); Name_CTF = CaesarReader.ReadBitflagInt32(ref interfaceBitflags, reader, -1); Description_CTF = CaesarReader.ReadBitflagInt32(ref interfaceBitflags, reader, -1); VersionString = CaesarReader.ReadBitflagStringWithReader(ref interfaceBitflags, reader, BaseAddress); Version = CaesarReader.ReadBitflagInt32(ref interfaceBitflags, reader); ComParamCount = CaesarReader.ReadBitflagInt32(ref interfaceBitflags, reader); ComParamListOffset = CaesarReader.ReadBitflagInt32(ref interfaceBitflags, reader); Unk6 = CaesarReader.ReadBitflagInt16(ref interfaceBitflags, reader); long comparamFileOffset = ComParamListOffset + BaseAddress; // Console.WriteLine($"interface string table offset from definition block : {interfaceStringTableOffset_fromDefinitionBlock:X}"); for (int interfaceStringIndex = 0; interfaceStringIndex < ComParamCount; interfaceStringIndex++) { // seek to string pointer reader.BaseStream.Seek(comparamFileOffset + (interfaceStringIndex * 4), SeekOrigin.Begin); // from pointer, seek to string long interfaceStringReadoutPtr = reader.ReadInt32() + comparamFileOffset; reader.BaseStream.Seek(interfaceStringReadoutPtr, SeekOrigin.Begin); string comParameter = CaesarReader.ReadStringFromBinaryReader(reader); comParameters.Add(comParameter); } }
public void LoadStrings(BinaryReader reader, int headerSize, Encoding encoding) { StringEntries = new List <string>(); int caesarStringTableOffset = headerSize + 0x410 + 4; // header.CffHeaderSize; strange that this has to be manually computed for (int i = 0; i < StringCount; i++) { reader.BaseStream.Seek(caesarStringTableOffset + (i * 4), SeekOrigin.Begin); int stringOffset = reader.ReadInt32(); reader.BaseStream.Seek(caesarStringTableOffset + stringOffset, SeekOrigin.Begin); string result = CaesarReader.ReadStringFromBinaryReader(reader, encoding); StringEntries.Add(result); } }
public DSCContext(byte[] dscContainerBytes) { const int fnTableEntrySize = 50; using (BinaryReader reader = new BinaryReader(new MemoryStream(dscContainerBytes))) { reader.BaseStream.Seek(0x10, SeekOrigin.Begin); int fnTableOffset = reader.ReadInt32(); // @ 0x10, originally i16 int numberOfFunctions = reader.ReadInt16(); // @ 0x14 int dscOffsetA = reader.ReadInt32(); // @ 0x16, originally i16 int caesarHash = reader.ReadInt16(); // @ 0x1A, size is u32? int idk_field_1c = reader.ReadInt16(); // ?? @ 1C, padding int globalVarAllocSize = reader.ReadInt16(); // @ 1E int idk_field_20 = reader.ReadInt16(); // ?? @ 20, padding int globalVariablesBufferPtr = reader.ReadInt32(); // ?? @ 22 int globalVariablesCount = reader.ReadInt16(); // ?? @ 26 int globalVariablesIdk1 = reader.ReadInt32(); // ?? @ 28 int globalVariablesIdk2 = reader.ReadInt16(); // ?? @ 2C int globalVariablesPreinitBufferPtr = reader.ReadInt32(); // ?? @ 2E int globalVariablesBytesToRead = reader.ReadInt16(); // ?? @ 32 byte[] globalVarByteBuffer = new byte[globalVarAllocSize]; Console.WriteLine($"{nameof(dscOffsetA)} : {dscOffsetA} (0x{dscOffsetA:X})\n"); Console.WriteLine($"{nameof(caesarHash)} : {caesarHash} (0x{caesarHash:X})\n"); Console.WriteLine($"{nameof(globalVarAllocSize)} : {globalVarAllocSize} (0x{globalVarAllocSize:X})\n"); Console.WriteLine($"{nameof(globalVariablesBufferPtr)} : {globalVariablesBufferPtr} (0x{globalVariablesBufferPtr:X})"); Console.WriteLine($"{nameof(globalVariablesCount)} : {globalVariablesCount} (0x{globalVariablesCount:X})\n"); Console.WriteLine($"{nameof(globalVariablesIdk1)} : {globalVariablesIdk1} (0x{globalVariablesIdk1:X})"); Console.WriteLine($"{nameof(globalVariablesIdk2)} : {globalVariablesIdk2} (0x{globalVariablesIdk2:X})\n"); Console.WriteLine($"{nameof(globalVariablesPreinitBufferPtr)} : {globalVariablesPreinitBufferPtr} (0x{globalVariablesPreinitBufferPtr:X})"); Console.WriteLine($"{nameof(globalVariablesBytesToRead)} : {globalVariablesBytesToRead} (0x{globalVariablesBytesToRead:X})\n"); // assemble global vars: MIGlobalVarBuild (parent: MIInterpreterRun) int gvBytesRemaining = globalVariablesBytesToRead; reader.BaseStream.Seek(globalVariablesPreinitBufferPtr, SeekOrigin.Begin); while (gvBytesRemaining > 0) { int gvAddress = reader.ReadInt16(); int gvSize = reader.ReadByte(); byte[] gvData = reader.ReadBytes(gvSize); Console.WriteLine($"GV Fill: 0x{gvAddress:X} ({gvSize} bytes) : {BitUtility.BytesToHex(gvData)}"); Buffer.BlockCopy(gvData, 0, globalVarByteBuffer, gvAddress, gvSize); gvBytesRemaining -= gvSize; gvBytesRemaining -= 3; } if (gvBytesRemaining != 0) { throw new Exception("Global variable preinit has leftover data in the read cursor"); } // CreateGlobalVar for (int gvIndex = 0; gvIndex < globalVariablesCount; gvIndex++) { /* * guesses: * base * 1 -> char * 2 -> word * 3 -> dword * * * derived * 1 -> native * 2 -> array * 3 -> pointer * */ reader.BaseStream.Seek(globalVariablesBufferPtr + (gvIndex * 12), SeekOrigin.Begin); int varName = reader.ReadInt32(); DSCBasicType baseType = (DSCBasicType)reader.ReadInt16(); DSCDerivedType derivedType = (DSCDerivedType)reader.ReadInt16(); int arraySize = reader.ReadInt16(); int positionInGlobalBuffer = reader.ReadInt16(); reader.BaseStream.Seek(varName, SeekOrigin.Begin); string varNameResolved = CaesarReader.ReadStringFromBinaryReader(reader, CaesarReader.DefaultEncoding); int dataSizeInBytes = GetDscTypeSize((int)baseType, (int)derivedType); if (derivedType == DSCDerivedType.Array) { dataSizeInBytes *= arraySize; } byte[] varBytes = new byte[dataSizeInBytes]; Buffer.BlockCopy(globalVarByteBuffer, positionInGlobalBuffer, varBytes, 0, dataSizeInBytes); Console.WriteLine($"\nVar: {baseType}/{derivedType} [{arraySize}] @ {positionInGlobalBuffer} : {varNameResolved}"); Console.WriteLine($"{BitUtility.BytesToHex(varBytes)}"); // actual insertion into global var list is in MIGlobalVarCallback, stored in interpreter's ->GlobalVarList } for (int fnIndex = 0; fnIndex < numberOfFunctions; fnIndex++) { long fnBaseAddress = fnTableEntrySize * fnIndex + fnTableOffset; reader.BaseStream.Seek(fnBaseAddress, SeekOrigin.Begin); int fnIdentifier = reader.ReadInt16(); // @ 0 int fnNameOffset = reader.ReadInt32(); // @ 2 // not exactly sure if int32 is right -- the first fn's ep looks incorrect in both cases. // 16 bit would limit the filesize to ~32KB which seems unlikely int fnEntryPoint = reader.ReadInt32(); // @ 6 //int fnEntryPoint = reader.ReadInt16(); // @ 6 //int fnIdkIsThisStandalone = reader.ReadInt16(); // @ 6 reader.BaseStream.Seek(fnBaseAddress + 38, SeekOrigin.Begin); int inputParamOffset = reader.ReadInt32(); // @ 38 int inputParamCount = reader.ReadInt16(); // @ 42 int outputParamOffset = reader.ReadInt32(); // @ 44 int outputParamCount = reader.ReadInt16(); // @ 48 reader.BaseStream.Seek(fnNameOffset, SeekOrigin.Begin); string fnName = CaesarReader.ReadStringFromBinaryReader(reader); Console.WriteLine($"Fn: {fnName} Ordinal: {fnIdentifier} EP: 0x{fnEntryPoint:X}, InParam: {inputParamCount} @ 0x{inputParamOffset:X}, OutParam: {outputParamCount} @ 0x{outputParamOffset}"); // the EP points to an int16 to initialize the stack height // after the EP, the raw bytecode can be directly interpreted } } }