コード例 #1
0
ファイル: VCFragment.cs プロジェクト: gibsonk1980/CaesarSuite
        public byte[] SetSubfragmentConfiguration(byte[] variantCodingValue, VCSubfragment subfragment)
        {
            byte[]      variantBits = BitUtility.ByteArrayToBitArray(variantCodingValue);
            List <byte> result      = new List <byte>(variantBits.Take(ByteBitPos));

            variantBits = variantBits.Skip(BitLength + ByteBitPos).ToArray();
            byte[] sfToSet = BitUtility.ByteArrayToBitArray(subfragment.Dump).Take(BitLength).ToArray();
            result.AddRange(sfToSet);
            result.AddRange(variantBits);
            return(BitUtility.BitArrayToByteArray(result.ToArray()));
        }
コード例 #2
0
ファイル: VCFragment.cs プロジェクト: gibsonk1980/CaesarSuite
        public VCSubfragment GetSubfragmentConfiguration(byte[] variantCodingValue)
        {
            byte[] variantBits  = BitUtility.ByteArrayToBitArray(variantCodingValue);
            byte[] affectedBits = variantBits.Skip(ByteBitPos).Take(BitLength).ToArray();

            foreach (VCSubfragment subfragment in Subfragments)
            {
                byte[] sfToCompare = BitUtility.ByteArrayToBitArray(subfragment.Dump).Take(BitLength).ToArray();
                if (sfToCompare.SequenceEqual(affectedBits))
                {
                    return(subfragment);
                }
            }
            return(null);
        }
コード例 #3
0
 private void PrintDebug(bool verbose = false)
 {
     if (verbose)
     {
         Console.WriteLine("------------- subfragment ------------- ");
         Console.WriteLine($"{nameof(Name_CTF)}, {Name_CTF}");
         Console.WriteLine($"{nameof(Dump)}, {BitUtility.BytesToHex(Dump)}");
         Console.WriteLine($"{nameof(Description_CTF)}, {Description_CTF}");
         Console.WriteLine($"{nameof(NameCTFResolved)}, {NameCTFResolved}");
         Console.WriteLine($"{nameof(QualifierUsuallyDisabled)}, {QualifierUsuallyDisabled}");
         Console.WriteLine($"{nameof(Unk3)}, {Unk3}");
         Console.WriteLine($"{nameof(Unk4)}, {Unk4}");
         Console.WriteLine($"{nameof(SupplementKey)}, {SupplementKey}");
     }
     else
     {
         Console.WriteLine($">> {BitUtility.BytesToHex(Dump)} : {NameCTFResolved}");
     }
 }
コード例 #4
0
 public void PrintDebug()
 {
     Console.WriteLine($"{nameof(Qualifier)} : {Qualifier}");
     Console.WriteLine($"{nameof(BitPosition)} : {BitPosition}");
     Console.WriteLine($"{nameof(ModeConfig)} : 0x{ModeConfig:X}");
     Console.WriteLine($"Mode H : 0x{ModeConfig & 0xFF0:X}, L : 0x{ModeConfig & 0xF:X}");
     Console.WriteLine($"{nameof(SizeInBits)} : 0x{SizeInBits:X}");
     Console.WriteLine($"{nameof(Name_CTF)} : {Name_CTF}");
     Console.WriteLine($"{nameof(Name_CTF)} : {Language.GetString(Name_CTF)}");
     Console.WriteLine($"{nameof(Unk1)} : {Unk1}");
     Console.WriteLine($"{nameof(Unk2)} : {Unk2}");
     Console.WriteLine($"{nameof(AlternativeBitWidth)} : {AlternativeBitWidth}");
     Console.WriteLine($"{nameof(IITOffset)} : {IITOffset}");
     Console.WriteLine($"{nameof(InfoPoolIndex)} : {InfoPoolIndex}");
     Console.WriteLine($"{nameof(PresPoolIndex)} : {PresPoolIndex}");
     Console.WriteLine($"{nameof(Field1E)} : {Field1E}");
     Console.WriteLine($"{nameof(SystemParam)} : {SystemParam}");
     // Console.WriteLine($"{nameof(noIdea_T)} : {language.GetString(noIdea_T)}");
     Console.WriteLine($"{nameof(Dump)} : {BitUtility.BytesToHex(Dump)}");
     Console.WriteLine("---------------");
 }
コード例 #5
0
 public void PrintDebug()
 {
     Console.WriteLine($"ComParam: id {ComParamIndex} ({ParamName}), v {ComParamValue} 0x{ComParamValue:X8} SI_Index:{SubinterfaceIndex} | parentIndex:{ParentInterfaceIndex} 5:{Unk5} DumpSize:{DumpSize} D: {BitUtility.BytesToHex(Dump)}");
     Console.WriteLine($"Pos 0x{BaseAddress:X}");
 }
コード例 #6
0
        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
                }
            }
        }
コード例 #7
0
        public string InterpretData(byte[] inBytes, DiagPreparation inPreparation, bool describe = true)
        {
            // might be relevant: DMPrepareSingleDatum, DMPresentSingleDatum

            bool isDebugBuild = false;

#if DEBUG
            isDebugBuild = true;
#endif

            string descriptionPrefix = describe ? $"{DescriptionString}: " : "";
            byte[] workingBytes      = inBytes.Skip(inPreparation.BitPosition / 8).Take(TypeLength_1A).ToArray();

            bool isEnumType = (EnumType_1E == 0) && ((Type_1C == 1) || (ScaleCountMaybe > 1));

            // hack: sometimes hybrid types (regularly parsed as an scaled value if within bounds) are misinterpreted as pure enums
            // this is a temporary fix for kilometerstand until there's a better way to ascertain its type
            // this also won't work on other similar cases without a unit string e.g. error instance counter (Häufigkeitszähler)
            if (DisplayedUnitString == "km")
            {
                isEnumType = false;
            }

            if (workingBytes.Length != TypeLength_1A)
            {
                return($"InBytes [{BitUtility.BytesToHex(workingBytes)}] length mismatch (expecting {TypeLength_1A})");
            }

            // handle booleans first since they're the edge case where they can cross byte boundaries
            if (inPreparation.SizeInBits == 1)
            {
                int  bytesToSkip  = (int)(inPreparation.BitPosition / 8);
                int  bitsToSkip   = inPreparation.BitPosition % 8;
                byte selectedByte = inBytes[bytesToSkip];

                int selectedBit = (selectedByte >> bitsToSkip) & 1;
                if (isEnumType && (Scales.Count > selectedBit))
                {
                    return($"{descriptionPrefix}{Language.GetString(Scales[selectedBit].EnumDescription)} {DisplayedUnitString}");
                }
                else
                {
                    return($"{descriptionPrefix}{selectedBit} {DisplayedUnitString}");
                }
            }

            // everything else should be aligned to byte boundaries
            if (inPreparation.BitPosition % 8 != 0)
            {
                return("BitOffset was outside byte boundary (skipped)");
            }
            int dataType             = GetDataType();
            int rawIntInterpretation = 0;

            string humanReadableType = $"UnhandledType:{dataType}";
            string parsedValue       = BitUtility.BytesToHex(workingBytes, true);
            if ((dataType == 6 || (dataType == 20)))
            {
                // parse as a regular int (BE)

                for (int i = 0; i < workingBytes.Length; i++)
                {
                    rawIntInterpretation <<= 8;
                    rawIntInterpretation  |= workingBytes[i];
                }

                humanReadableType = "IntegerType";

                parsedValue = rawIntInterpretation.ToString();
                if (dataType == 20)
                {
                    humanReadableType = "ScaledType";

                    double valueToScale = rawIntInterpretation;

                    // if there's only one scale, use it as-is
                    // if there's more than one, use the first scale as an interim solution;
                    // the results of stacking scales does not make sense
                    // there might be a better, non-hardcoded (0) solution to this, and perhaps with a sig-fig specifier

                    valueToScale *= Scales[0].MultiplyFactor;
                    valueToScale += Scales[0].AddConstOffset;

                    parsedValue = valueToScale.ToString("0.000000");
                }
            }
            else if (dataType == 18)
            {
                humanReadableType = "HexdumpType";
            }
            else if (dataType == 17)
            {
                humanReadableType = "StringType";
                parsedValue       = Encoding.UTF8.GetString(workingBytes);
            }

            if (isEnumType)
            {
                // discovered by @VladLupashevskyi in https://github.com/jglim/CaesarSuite/issues/27
                // if an enum is specified, the inclusive upper bound and lower bound will be defined in the scale object

                bool useNewInterpretation = false;
                foreach (Scale scale in Scales)
                {
                    if ((scale.EnumUpBound > 0) || (scale.EnumLowBound > 0))
                    {
                        useNewInterpretation = true;
                        break;
                    }
                }

                if (useNewInterpretation)
                {
                    foreach (Scale scale in Scales)
                    {
                        if ((rawIntInterpretation >= scale.EnumLowBound) && (rawIntInterpretation <= scale.EnumUpBound))
                        {
                            return($"{descriptionPrefix}{Language.GetString(scale.EnumDescription)} {DisplayedUnitString}");
                        }
                    }
                }
                else
                {
                    // original implementation, probably incorrect
                    if (rawIntInterpretation < Scales.Count)
                    {
                        return($"{descriptionPrefix}{Language.GetString(Scales[rawIntInterpretation].EnumDescription)} {DisplayedUnitString}");
                    }
                }
                return($"{descriptionPrefix}(Enum not found) {DisplayedUnitString}");
                // this bit below for troubleshooting problematic presentations

                /*
                 * if (rawIntInterpretation < Scales.Count)
                 * {
                 *  return $"{descriptionPrefix}{Language.GetString(Scales[rawIntInterpretation].EnumDescription)} {DisplayedUnitString}";
                 * }
                 * else
                 * {
                 *  // seems like an enum-like value broke
                 *  return $"{descriptionPrefix}{Language.GetString(Scales[0].EnumDescription)} {DisplayedUnitString} [!]";
                 * }
                 */
            }
            else
            {
                if (isDebugBuild)
                {
                    return($"{descriptionPrefix}{parsedValue} {DisplayedUnitString} ({humanReadableType})");
                }
                else
                {
                    return($"{descriptionPrefix}{parsedValue} {DisplayedUnitString}");
                }
            }
        }
コード例 #8
0
        public string InterpretData(byte[] inBytes, DiagPreparation inPreparation)
        {
            // might be relevant: DMPrepareSingleDatum, DMPresentSingleDatum

            byte[] workingBytes = inBytes.Skip(inPreparation.BitPosition / 8).Take(TypeLength_1a).ToArray();
            if (workingBytes.Length != TypeLength_1a)
            {
                return($"InBytes [{BitUtility.BytesToHex(workingBytes)}] length mismatch (expecting {TypeLength_1a})");
            }

            // handle booleans first since they're the edge case where they can cross byte boundaries
            if (inPreparation.SizeInBits == 1)
            {
                int  bytesToSkip  = (int)(inPreparation.BitPosition / 8);
                int  bitsToSkip   = inPreparation.BitPosition % 8;
                byte selectedByte = inBytes[bytesToSkip];

                int selectedBit = (selectedByte >> bitsToSkip) & 1;

                return($"{DescriptionString}: {selectedBit} {DisplayedUnitString} (BitType)");
            }

            // everything else should be aligned to byte boundaries
            if (inPreparation.BitPosition % 8 != 0)
            {
                return("BitOffset was outside byte boundary (skipped)");
            }
            int    dataType          = GetDataType();
            string humanReadableType = $"UnhandledType:{dataType}";
            string parsedValue       = BitUtility.BytesToHex(workingBytes, true);

            if ((dataType == 6 || (dataType == 20)))
            {
                // parse as a regular int (BE)
                int result = 0;

                for (int i = 0; i < workingBytes.Length; i++)
                {
                    result <<= 8;
                    result  |= workingBytes[i];
                }

                humanReadableType = "IntegerType";

                parsedValue = result.ToString();
                if (dataType == 20)
                {
                    humanReadableType = "ScaledType";

                    double valueToScale = result;
                    foreach (Scale scale in Scales)
                    {
                        valueToScale *= scale.MultiplyFactor;
                        valueToScale += scale.AddConstOffset;
                    }

                    parsedValue = valueToScale.ToString("0.000000");
                }
            }
            else if (dataType == 18)
            {
                humanReadableType = "HexdumpType";
            }
            else if (dataType == 17)
            {
                humanReadableType = "StringType";
                parsedValue       = Encoding.UTF8.GetString(workingBytes);
            }

            return($"{DescriptionString}: {parsedValue} {DisplayedUnitString} ({humanReadableType})");
        }
コード例 #9
0
        public string InterpretData(byte[] inBytes, DiagPreparation inPreparation, bool describe = true)
        {
            // might be relevant: DMPrepareSingleDatum, DMPresentSingleDatum

            bool isDebugBuild = false;

#if DEBUG
            isDebugBuild = true;
#endif

            string descriptionPrefix = describe ? $"{DescriptionString}: " : "";
            byte[] workingBytes      = inBytes.Skip(inPreparation.BitPosition / 8).Take(TypeLength_1A).ToArray();

            bool isEnumType = (EnumType_1E == 0) && ((Type_1C == 1) || (ScaleCountMaybe > 1));

            if (workingBytes.Length != TypeLength_1A)
            {
                return($"InBytes [{BitUtility.BytesToHex(workingBytes)}] length mismatch (expecting {TypeLength_1A})");
            }

            // handle booleans first since they're the edge case where they can cross byte boundaries
            if (inPreparation.SizeInBits == 1)
            {
                int  bytesToSkip  = (int)(inPreparation.BitPosition / 8);
                int  bitsToSkip   = inPreparation.BitPosition % 8;
                byte selectedByte = inBytes[bytesToSkip];

                int selectedBit = (selectedByte >> bitsToSkip) & 1;
                if (isEnumType && (Scales.Count > selectedBit))
                {
                    return($"{descriptionPrefix}{Language.GetString(Scales[selectedBit].EnumDescription)} {DisplayedUnitString}");
                }
                else
                {
                    return($"{descriptionPrefix}{selectedBit} {DisplayedUnitString}");
                }
            }

            // everything else should be aligned to byte boundaries
            if (inPreparation.BitPosition % 8 != 0)
            {
                return("BitOffset was outside byte boundary (skipped)");
            }
            int dataType             = GetDataType();
            int rawIntInterpretation = 0;

            string humanReadableType = $"UnhandledType:{dataType}";
            string parsedValue       = BitUtility.BytesToHex(workingBytes, true);
            if ((dataType == 6 || (dataType == 20)))
            {
                // parse as a regular int (BE)

                for (int i = 0; i < workingBytes.Length; i++)
                {
                    rawIntInterpretation <<= 8;
                    rawIntInterpretation  |= workingBytes[i];
                }

                humanReadableType = "IntegerType";

                parsedValue = rawIntInterpretation.ToString();
                if (dataType == 20)
                {
                    humanReadableType = "ScaledType";

                    double valueToScale = rawIntInterpretation;

                    // if there's only one scale, use it as-is
                    // if there's more than one, use the first scale as an interim solution;
                    // the results of stacking scales does not make sense
                    // there might be a better, non-hardcoded (0) solution to this, and perhaps with a sig-fig specifier

                    valueToScale *= Scales[0].MultiplyFactor;
                    valueToScale += Scales[0].AddConstOffset;

                    parsedValue = valueToScale.ToString("0.000000");
                }
            }
            else if (dataType == 18)
            {
                humanReadableType = "HexdumpType";
            }
            else if (dataType == 17)
            {
                humanReadableType = "StringType";
                parsedValue       = Encoding.UTF8.GetString(workingBytes);
            }

            if (isEnumType && (rawIntInterpretation < Scales.Count))
            {
                return($"{descriptionPrefix}{Language.GetString(Scales[rawIntInterpretation].EnumDescription)} {DisplayedUnitString}");
                // this bit below for troubleshooting problematic presentations

                /*
                 * if (rawIntInterpretation < Scales.Count)
                 * {
                 *  return $"{descriptionPrefix}{Language.GetString(Scales[rawIntInterpretation].EnumDescription)} {DisplayedUnitString}";
                 * }
                 * else
                 * {
                 *  // seems like an enum-like value broke
                 *  return $"{descriptionPrefix}{Language.GetString(Scales[0].EnumDescription)} {DisplayedUnitString} [!]";
                 * }
                 */
            }
            else
            {
                if (isDebugBuild)
                {
                    return($"{descriptionPrefix}{parsedValue} {DisplayedUnitString} ({humanReadableType})");
                }
                else
                {
                    return($"{descriptionPrefix}{parsedValue} {DisplayedUnitString}");
                }
            }
        }