Ejemplo n.º 1
0
        public CppDeclarationGenerator(Il2CppModel model, UnityVersion version)
        {
            this.model = model;
            if (version == null)
            {
                UnityHeader  = UnityHeader.GuessHeadersForModel(model)[0];
                UnityVersion = UnityHeader.MinVersion;
            }
            else
            {
                UnityVersion = version;
                UnityHeader  = UnityHeader.GetHeaderForVersion(version);
                if (UnityHeader.MetadataVersion != model.Package.BinaryImage.Version)
                {
                    /* this can only happen in the CLI frontend with a manually-supplied version number */
                    Console.WriteLine($"Warning: selected version {UnityVersion} (metadata version {UnityHeader.MetadataVersion})" +
                                      $" does not match metadata version {model.Package.BinaryImage.Version}.");
                }
            }

            InitializeNaming();
            InitializeConcreteImplementations();

            // Configure inheritance style based on binary type; this can be overridden by setting InheritanceStyle in the object initializer
            InheritanceStyle = CppCompiler.GuessFromImage(model.Package.BinaryImage);
        }
Ejemplo n.º 2
0
        public CppApplicationModel(Il2CppModel model, UnityVersion unityVersion = null, CppCompiler.Type compiler = CppCompiler.Type.BinaryFormat)
        {
            // Set key properties
            Compiler = compiler == CppCompiler.Type.BinaryFormat ? CppCompiler.GuessFromImage(model.Package.BinaryImage) : compiler;

            var unityHeader = unityVersion != null?UnityHeader.GetHeaderForVersion(unityVersion) : UnityHeader.GuessHeadersForModel(model)[0];

            UnityVersion = unityVersion ?? unityHeader.MinVersion;
            ILModel      = model;

            // Check for matching metadata and binary versions
            if (unityHeader.MetadataVersion != model.Package.BinaryImage.Version)
            {
                Console.WriteLine($"Warning: selected version {UnityVersion} (metadata version {unityHeader.MetadataVersion})" +
                                  $" does not match metadata version {model.Package.BinaryImage.Version}.");
            }

            // Get addresses of IL2CPP API function exports
            Exports = model.Package.Binary.Image.GetExports().ToList();

            // Start creation of type model by parsing all of the Unity IL2CPP headers
            Types = CppTypes.FromUnityHeaders(unityHeader, WordSize);

            // TODO: Process every type in the binary
            //var decl = new CppDeclarationGenerator(this);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// User has selected an image
        /// </summary>
        private void LstImages_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            // Selection has been removed?
            if (((ListBox)sender).SelectedItem == null)
            {
                trvNamespaces.ItemsSource = null;
                return;
            }

            // Get selected image
            var model = (Il2CppModel)((ListBox)sender).SelectedItem;

            // Get namespaces
            var namespaces = model.Assemblies.SelectMany(x => x.DefinedTypes).GroupBy(t => t.Namespace).Select(n => n.Key);

            // Break namespaces down into a tree
            var namespaceTree = deconstructNamespaces(namespaces);

            // Uncheck the default exclusions
            foreach (var exclusion in Constants.DefaultExcludedNamespaces)
            {
                var          parts = exclusion.Split('.');
                CheckboxNode node  = null;
                foreach (var part in parts)
                {
                    node = (node?.Children ?? namespaceTree).FirstOrDefault(c => c.Name == part);
                    if (node == null)
                    {
                        break;
                    }
                }
                if (node != null)
                {
                    node.IsChecked = false;
                }
            }

            // Populate TreeView with namespace hierarchy
            trvNamespaces.ItemsSource = namespaceTree;

            // Populate Unity version combo boxes
            var prevSelection    = cboUnityVersion.SelectedItem;
            var prevCppSelection = cboCppUnityVersion.SelectedItem;

            cboUnityVersion.Items.Clear();
            cboCppUnityVersion.Items.Clear();
            foreach (var version in UnityHeader.GuessHeadersForModel(model))
            {
                cboUnityVersion.Items.Add(version);
                cboCppUnityVersion.Items.Add(version);
            }
            cboUnityVersion.SelectedIndex    = 0;
            cboCppUnityVersion.SelectedIndex = 0;
            if (prevSelection != null)
            {
                cboUnityVersion.SelectedItem    = prevSelection;
                cboCppUnityVersion.SelectedItem = prevCppSelection;
            }
        }
Ejemplo n.º 4
0
 public void TestVersions()
 {
     Assert.That(UnityHeader.GetHeaderForVersion("5.3.1p4").ToString(), Is.EqualTo("5.3.0 - 5.3.1"));
     Assert.That(UnityHeader.GetHeaderForVersion("5.6.4").ToString(), Is.EqualTo("5.6.0 - 5.6.7"));
     Assert.That(new UnityVersion("2020.1.0b5").ToString(), Is.EqualTo("2020.1.0b5"));
     Assert.That(new UnityVersion("2020.1").ToString(), Is.EqualTo("2020.1.0"));
     Assert.That(new UnityVersion("5.3.1").CompareTo("5.3.1p4") == 0);
     Assert.That(new UnityVersion("5.3.1rc0").CompareTo("5.3.1p2") < 0);
     Assert.That(new UnityVersion("5.3.1f1").CompareTo("5.3.1p0") < 0);
 }
Ejemplo n.º 5
0
        public void TestCppTypes()
        {
            // NOTE: This test doesn't check for correct results, only that parsing doesn't fail!

            var unityAllHeaders = UnityHeader.GetAllHeaders();

            // Ensure we have read the embedded assembly resources
            Assert.IsTrue(unityAllHeaders.Any());

            // Ensure we can interpret every header from every version of Unity without errors
            // This will throw InvalidOperationException if there is a problem
            foreach (var unityHeader in unityAllHeaders)
            {
                var cppTypes = CppTypes.FromUnityHeaders(unityHeader);

                foreach (var cppType in cppTypes.Types)
                {
                    Debug.WriteLine("// " + cppType.Key + "\n" + cppType.Value.ToString("o") + "\n");
                }
            }

            // Do a few sanity checks taken from real applications
            // NOTE: Does not provide full code coverage!

            var cppTypes2 = CppTypes.FromUnityVersion(new UnityVersion("2019.3.1f1"), 64);

            CppComplexType ct;
            CppField       field;

            // Un-nested class
            ct = (CppComplexType)cppTypes2["Il2CppClass"];

            field = ct[0xD8].First();

            Assert.AreEqual(field.Name, "cctor_finished");

            field = ct[0x128].First();

            Assert.AreEqual(field.Name, "vtable");

            field = ct["cctor_finished"];

            Assert.AreEqual(field.OffsetBytes, 0xD8);

            field = ct["vtable"];

            Assert.AreEqual(field.OffsetBytes, 0x128);

            // Nested class
            ct = (CppComplexType)cppTypes2["Il2CppClass_Merged"];
            var fields = ct.Flattened;

            field = fields[0xD8].First();

            Assert.AreEqual(field.Name, "cctor_finished");

            field = fields[0x128].First();

            Assert.AreEqual(field.Name, "vtable");

            field = fields["cctor_finished"];

            Assert.AreEqual(field.OffsetBytes, 0xD8);

            field = fields["vtable"];

            Assert.AreEqual(field.OffsetBytes, 0x128);
        }
Ejemplo n.º 6
0
    public static void BuildCounterfeit()
    {
        const string texturePath     = "Assets/Turtle.jpg";
        const string textureMetaPath = texturePath + ".meta";

        var metaContent = new StringReader(File.ReadAllText(textureMetaPath));
        var yaml        = new YamlStream();

        yaml.Load(metaContent);

        var    rootNode            = yaml.Documents[0].RootNode;
        var    guidNode            = Utility.FindYamlChildNode((YamlMappingNode)rootNode, "guid");
        string guid                = ((YamlScalarNode)guidNode).Value;
        var    textureImporterNode = Utility.FindYamlChildNode((YamlMappingNode)rootNode, "TextureImporter");
        var    assetBundleNameNode = Utility.FindYamlChildNode((YamlMappingNode)textureImporterNode, "assetBundleName");
        string assetBundleName     = ((YamlScalarNode)assetBundleNameNode).Value;
        string cabFilename         = Utility.GetCabFilename(assetBundleName);
        string cabRessFilename     = Utility.GetCabRessFilename(cabFilename);
        string archivePath         = Utility.GetArchivePath(cabFilename, cabRessFilename);

        // TODO: Replace jpeg loading library
        var unityTexture2D = AssetDatabase.LoadAssetAtPath <UnityEngine.Texture2D>(texturePath);

        byte[] textureRawData = unityTexture2D.GetRawTextureData();
        int    width          = unityTexture2D.width;
        int    height         = unityTexture2D.height;

        int   textureFileId = 2800000;
        Int64 texturePathId = Utility.GetPathId(guid, textureFileId);

        var blocksInfoAndDirectory = new BlocksInfoAndDirectory
        {
            UncompressedDataHash = new byte[16] {
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
            },
            StorageBlocks = new[]
            {
                new StorageBlock
                {
                    CompressedSize   = 302100,
                    UncompressedSize = 302100,
                    Flags            = 64
                }
            },
            Nodes = new[]
            {
                new Node
                {
                    Offset = 0,
                    Size   = 4424,
                    Flags  = 4,
                    Path   = cabFilename
                },
                new Node
                {
                    Offset = 4424,
                    Size   = 297676,
                    Flags  = 0,
                    Path   = cabRessFilename
                }
            }
        };

        byte[] compressedBuffer;
        int    uncompressedSize;
        int    compressedSize;

        using (var memoryStream = new MemoryStream())
            using (var memoryBinaryWriter = new BinaryWriter(memoryStream))
                using (var endiannessWriterCompressed = new EndiannessWriter(memoryBinaryWriter, Endianness.Big))
                {
                    blocksInfoAndDirectory.Write(endiannessWriterCompressed);

                    byte[] uncompressedBuffer = memoryStream.ToArray();
                    uncompressedSize = uncompressedBuffer.Length;
                    // Assume compressed buffer always smaller than uncompressed
                    compressedBuffer = new byte[uncompressedSize];

                    compressedSize = LZ4Codec.Encode
                                     (
                        uncompressedBuffer,
                        0,
                        uncompressedSize,
                        compressedBuffer,
                        0,
                        uncompressedSize,
                        LZ4Level.L11_OPT
                                     );

                    compressedBuffer = compressedBuffer.Take(compressedSize).ToArray();
                }

        var serializedFileHeader = new SerializedFileHeader
        {
            MetadataSize      = 125,
            FileSize          = 4424,
            Version           = 17,
            DataOffset        = 4096,
            Endianness        = Endianness.Little,
            Reserved          = new byte[] { 0, 0, 0 },
            UnityVersion      = "2018.4.20f1\n2",
            BuildTarget       = BuildTarget.Android,
            IsTypeTreeEnabled = false,
            SerializedTypes   = new[]
            {
                new SerializedType
                {
                    // https://docs.unity3d.com/Manual/ClassIDReference.html
                    ClassID         = 142,
                    IsStrippedType  = false,
                    ScriptTypeIndex = -1,
                    OldTypeHash     = new byte[]
                    { 151, 218, 95, 70, 136, 228, 90, 87, 200, 180, 45, 79, 66, 73, 114, 151 }
                },
                new SerializedType
                {
                    ClassID         = 28,
                    IsStrippedType  = false,
                    ScriptTypeIndex = -1,
                    OldTypeHash     = new byte[]
                    { 238, 108, 64, 129, 125, 41, 81, 146, 156, 219, 79, 90, 96, 135, 79, 93 }
                }
            },
            ObjectInfos = new[]
            {
                new ObjectInfo
                {
                    PathID    = 1,
                    ByteStart = 0,
                    ByteSize  = 132,
                    TypeID    = 0
                },
                new ObjectInfo
                {
                    PathID    = texturePathId,
                    ByteStart = 136,
                    ByteSize  = 192,
                    TypeID    = 1
                }
            }
        };

        var assetBundle = new AssetBundle
        {
            Name         = assetBundleName,
            PreloadTable = new[]
            {
                new PPtr {
                    FileID = 0, PathID = texturePathId
                }
            },
            Container = new[]
            {
                new KeyValuePair <string, AssetInfo>
                (
                    texturePath.ToLower(),
                    new AssetInfo
                {
                    PreloadIndex = 0,
                    PreloadSize  = 1,
                    Asset        = new PPtr
                    {
                        FileID = 0,
                        PathID = texturePathId
                    }
                }
                )
            },
            MainAsset = new AssetInfo
            {
                PreloadIndex = 0,
                PreloadSize  = 0,
                Asset        = new PPtr
                {
                    FileID = 0,
                    PathID = 0
                }
            },
            RuntimeCompatibility       = 1,
            AssetBundleName            = assetBundleName,
            DependencyAssetBundleNames = new string[0],
            IsStreamedSceneAssetBundle = false,
            ExplicitDataLayout         = 0,
            PathFlags   = 7,
            SceneHashes = new Dictionary <string, string>()
        };

        var texture2D = new Texture2D
        {
            Name = Path.GetFileNameWithoutExtension(texturePath),

            ForcedFallbackFormat = (int)TextureFormat.RGBA32,
            DownscaleFallback    = false,

            Width             = width,
            Height            = height,
            CompleteImageSize = textureRawData.Length,

            TextureFormat = TextureFormat.RGB24,

            MipCount                 = 1,
            IsReadable               = false,
            IsReadAllowed            = false,
            StreamingMipmapsPriority = 0,
            ImageCount               = 1,
            TextureDimension         = 2,
            TextureSettings          = new GLTextureSettings
            {
                FilterMode = 1,
                Aniso      = 1,
                MipBias    = 0,
                WrapMode   = 0,
                WrapV      = 0,
                WrapW      = 0
            },
            LightmapFormat = 0,
            ColorSpace     = 1,
            ImageDataSize  = 0,
            StreamData     = new StreamingInfo
            {
                Offset = 0,
                Size   = (UInt32)textureRawData.Length,
                Path   = archivePath
            }
        };

        byte[] serializeFileBuffer;
        int    metadataSize;
        int    assetBundleObjectPosition;
        int    assetBundleObjectOffset;
        int    assetBundleObjectSize;
        int    texture2DPosition;
        int    texture2DOffset;
        int    texture2DObjectSize;

        using (var memoryStream = new MemoryStream())
            using (var memoryBinaryWriter = new BinaryWriter(memoryStream))
                using (var endiannessWriterStorage = new EndiannessWriter(memoryBinaryWriter, Endianness.Big))
                {
                    serializedFileHeader.Write(endiannessWriterStorage);
                    metadataSize = (Int32)endiannessWriterStorage.Position;

                    endiannessWriterStorage.Align((int)serializedFileHeader.DataOffset);
                    assetBundleObjectPosition = (Int32)endiannessWriterStorage.Position;
                    assetBundleObjectOffset   = (Int32)(assetBundleObjectPosition - serializedFileHeader.DataOffset);
                    assetBundle.Write(endiannessWriterStorage, serializedFileHeader.Version);
                    assetBundleObjectSize = (Int32)(endiannessWriterStorage.Position - assetBundleObjectPosition);

                    // TODO: What is this padding?
                    endiannessWriterStorage.WriteUInt32(0);

                    texture2DPosition = (Int32)endiannessWriterStorage.Position;
                    texture2DOffset   = (Int32)(texture2DPosition - serializedFileHeader.DataOffset);
                    texture2D.Write(endiannessWriterStorage);
                    texture2DObjectSize = (Int32)(endiannessWriterStorage.Position - texture2DPosition);

                    endiannessWriterStorage.WriteWithoutEndianness(textureRawData);

                    // TODO: What is this padding?
                    endiannessWriterStorage.Write(0);

                    serializeFileBuffer = memoryStream.ToArray();
                }

        var header = new UnityHeader
        {
            Signature                  = "UnityFS",
            Version                    = 6,
            UnityVersion               = "5.x.x",
            UnityRevision              = "2018.4.20f1",
            Size                       = 302235,
            CompressedBlocksInfoSize   = compressedSize,
            UncompressedBlocksInfoSize = uncompressedSize,
            Flags                      = 67
        };

        using (var fileStream = File.Create("Counterfeit/texture"))
            using (var binaryWriter = new BinaryWriter(fileStream))
                using (var endiannessWriter = new EndiannessWriter(binaryWriter, Endianness.Big))
                {
                    header.Write(endiannessWriter);
                    endiannessWriter.WriteWithoutEndianness(compressedBuffer);
                    endiannessWriter.WriteWithoutEndianness(serializeFileBuffer);
                }
    }
Ejemplo n.º 7
0
        public void TestCppTypeDeclarations()
        {
            // NOTE: This test doesn't check for correct results, only that parsing doesn't fail!

            var unityAllHeaders = UnityHeader.GetAllHeaders();

            // Ensure we have read the embedded assembly resources
            Assert.IsTrue(unityAllHeaders.Any());

            // Ensure we can interpret every header from every version of Unity without errors
            // This will throw InvalidOperationException if there is a problem
            foreach (var unityHeader in unityAllHeaders)
            {
                var cppTypes = CppTypeCollection.FromUnityHeaders(unityHeader);
                foreach (var cppType in cppTypes.Types)
                {
                    Debug.WriteLine("// " + cppType.Key + "\n" + cppType.Value.ToString("o"));
                }
            }

            // Do a few sanity checks taken from real applications
            // NOTE: Does not provide full code coverage!

            var cppTypes2 = CppTypeCollection.FromUnityVersion(new UnityVersion("2019.3.1f1"), 64);

            CppComplexType ct;
            CppField       field;

            // Un-nested class
            ct = (CppComplexType)cppTypes2["Il2CppClass"];

            field = ct[0xD8].First();

            Assert.AreEqual(field.Name, "cctor_finished");

            field = ct[0x128].First();

            Assert.AreEqual(field.Name, "vtable");

            field = ct["cctor_finished"];

            Assert.AreEqual(field.OffsetBytes, 0xD8);

            field = ct["vtable"];

            Assert.AreEqual(field.OffsetBytes, 0x128);

            // Nested class
            ct = (CppComplexType)cppTypes2["Il2CppClass_Merged"];
            var fields = ct.Flattened;

            field = fields[0xD8].First();

            Assert.AreEqual(field.Name, "cctor_finished");

            field = fields[0x128].First();

            Assert.AreEqual(field.Name, "vtable");

            field = fields["cctor_finished"];

            Assert.AreEqual(field.OffsetBytes, 0xD8);

            field = fields["vtable"];

            Assert.AreEqual(field.OffsetBytes, 0x128);

            // Bitfield
            ct = (CppComplexType)cppTypes2["Il2CppType"];

            field = ct.Fields[0xB * 8 + 7].First();

            Assert.AreEqual(field.Name, "pinned");

            // Nested fields
            ct     = (CppComplexType)cppTypes2["Il2CppWin32Decimal"];
            fields = ct.Flattened;

            field = fields[0x08].First();

            Assert.AreEqual(field.Name, "lo32");

            field = fields[0x08].Last();

            Assert.AreEqual(field.Name, "lo64");

            field = fields[0x0C].First();

            Assert.AreEqual(field.Name, "mid32");

            // Pointer alias
            var alias = (CppAlias)cppTypes2.GetType("Il2CppHString");

            Assert.AreEqual(alias.ElementType.GetType(), typeof(CppPointerType));
            Assert.AreEqual(alias.ElementType.Name, "Il2CppHString__ *");

            // Typedef struct with no tag
            Assert.True(cppTypes2.Types.ContainsKey("Il2CppGenericMethodIndices"));
            Assert.True(((CppComplexType)cppTypes2["Il2CppGenericMethodIndices"]).ComplexValueType == ComplexValueType.Struct);
        }