示例#1
0
        // See: Bin2Object/BinaryObjectStream.cs
        public void PreProcessImage(BinaryObjectStream stream, PluginPreProcessImageEventInfo data)
        {
            // This is called once when the user selects an application binary

            // Example: try to read 64-bit ELF header
            try {
                var header = stream.ReadObject <elf_header <ulong> >();

                // Check for magic bytes
                if ((Elf)header.m_dwFormat == Elf.ELFMAG)
                {
                    // Do something with ELF file
                    Console.WriteLine("ELF image found");
                }
            } catch { }

            // The file is loaded into memory so you can make edits without affecting the file

            // BinaryObjectStream provides many useful methods and properties
            // Set endianness with Endianness property
            // Set text encoding with Encoding property

            // Map reading of one primitive type to another (for both reading and writing):
            // This will cause all uints in the stream to be converted to ulongs when read with ReadObject<uint>()
            // This allows you to use one execution path to read 32-bit and 64-bit files
            stream.AddPrimitiveMapping(typeof(ulong), typeof(uint));

            // Map reading of one object to another (for both reading and writing):
            // This will cause all fields that exist in ObjectInMemory to be populated with
            // the correspondingly named fields in ObjectInStream
            // This is useful if items have been re-ordered via obfuscation
            stream.AddObjectMapping(typeof(ObjectInMemory), typeof(ObjectInStream));

            // With the above mapping, this will read an ObjectInStream and translate it to an ObjectInMemory
            try {
                var obj = stream.ReadObject <ObjectInMemory>();
            } catch { }

            // Mappings will be persisted for the entire lifetime of the stream,
            // so you can use them to alter the order in which Il2CppInspector reads fields in structs

            // Clear mappings:
            stream.Reader.PrimitiveMappings.Clear();
            stream.Reader.ObjectMappings.Clear();
            stream.Writer.PrimitiveMappings.Clear();
            stream.Writer.PrimitiveMappings.Clear();

            // Other useful methods:
            // ReadObject<T>, ReadArray<T>, ReadNullTerminatedString, ReadFixedLengthString
            // + equivalent write methods

            // You can also use a number of attributes:
            // ArrayLengthAttribute, StringAttribute, VersionAttribute, SkipWhenReadingAttribute

            // Set data.IsStreamModified if you change the stream contents
        }
示例#2
0
        public override IFileFormatStream this[uint index] {
            get {
                Position   = 0x8 + 0x14 * index; // sizeof(FatHeader), sizeof(FatArch)
                Endianness = Endianness.Big;

                var arch = ReadObject <FatArch>();

                Position   = arch.Offset;
                Endianness = Endianness.Little;

                using var s = new BinaryObjectStream(ReadBytes((int)arch.Size));
                return((IFileFormatStream)MachOReader32.Load(s, LoadOptions, OnStatusUpdate) ?? MachOReader64.Load(s, LoadOptions, OnStatusUpdate));
            }
        }
示例#3
0
        // See: Bin2Object/BinaryObjectStream.cs
        public void PreProcessMetadata(BinaryObjectStream stream, PluginPreProcessMetadataEventInfo info)
        {
            // Example: check if metadata has correct signature
            if (stream.ReadUInt32() != Il2CppConstants.MetadataSignature)
            {
                Console.Error.WriteLine("Metadata signature is invalid");
            }

            // The file is loaded into memory so you can make edits without affecting the file

            // See PreProcessImage below for information about using BinaryObjectStream for de-obfuscation

            // Set info.IsStreamModified if you change the stream contents
        }
示例#4
0
        // This executes as soon as the raw global-metadata.dat has been read from storage,
        // before any attempt is made to analyze its contents
        public void PreProcessMetadata(BinaryObjectStream stream, PluginPreProcessMetadataEventInfo info)
        {
            stream.Position = 21;

            var key = presetKey.Value == "custom"? customKey.Value : PresetKeys[presetKey.Value];

            if (string.IsNullOrEmpty(key))
            {
                throw new ArgumentException("Game version or decryption key must be specified");
            }

            var sig = stream.ReadBytes(4);

            sig = sig.Select((b, i) => (byte)(b - key[i % key.Length])).ToArray();
            if (BitConverter.ToUInt32(sig) != Il2CppConstants.MetadataSignature)
            {
                return;
            }

            PluginServices.For(this).StatusUpdate("Decrypting metadata");

            // Subtract key bytes from metadata bytes, skipping the first bytes,
            // and cycling through the key bytes repeatedly
            var bytesToSkipAtStart = 21;
            var length             = stream.Length;

            var bytes    = stream.ToArray();
            var keyBytes = Encoding.ASCII.GetBytes(key);

            for (int index = 0, pos = bytesToSkipAtStart; pos < length; index = (index + 1) % key.Length, pos++)
            {
                bytes[pos] -= keyBytes[index];
            }

            // We replace the loaded global-metadata.dat with the newly decrypted version,
            // allowing Il2CppInspector to analyze it as normal
            stream.Write(0, bytes.Skip(bytesToSkipAtStart).ToArray());

            info.IsStreamModified = true;
        }
示例#5
0
 public static PluginPreProcessImageEventInfo PreProcessImage(BinaryObjectStream stream)
 => PluginManager.Try <ILoadPipeline, PluginPreProcessImageEventInfo>((p, e) => p.PreProcessImage(stream, e));
示例#6
0
 public static PluginPreProcessMetadataEventInfo PreProcessMetadata(BinaryObjectStream stream)
 => PluginManager.Try <ILoadPipeline, PluginPreProcessMetadataEventInfo>((p, e) => {
     stream.Position = 0;
     p.PreProcessMetadata(stream, e);
 });
        // This executes as soon as the raw global-metadata.dat has been read from storage,
        // before any attempt is made to analyze its contents
        // We use it to call UnityPlayer.dll to decrypt the file in memory
        public void PreProcessMetadata(BinaryObjectStream stream, PluginPreProcessMetadataEventInfo info)
        {
            // Assume that your plugin is enabled regardless of what is loading
            // Therefore, we don't want to process global-metadata.dat files that are not for us!
            // miHoYo metadata has an invalid signature at the start of the file so we use that as the criteria
            IsOurs = stream.ReadUInt32(0) != Il2CppConstants.MetadataSignature;
            if (!IsOurs)
            {
                return;
            }

            // The DWORD 0x4008 bytes from the end should be an offset to itself
            var lastBlockPointer = stream.Length - 0x4008;

            IsOurs = stream.ReadUInt32(lastBlockPointer) == lastBlockPointer;
            if (!IsOurs)
            {
                return;
            }

            // Tell the user what is happening in case it takes a while
            PluginServices.For(this).StatusUpdate("Decrypting metadata");

            // Create a delegate which internally is a function pointer to the DecryptMetadata function in the DLL
            var pDecryptMetadata = (DecryptMetadata)Marshal.GetDelegateForFunctionPointer(ModuleBase + Offsets[game.Value].DecryptMetadata, typeof(DecryptMetadata));

            // Call the delegate with the encrypted metadata byte array and length as arguments
            var decryptedBytesUnmanaged = pDecryptMetadata(stream.ToArray(), (int)stream.Length);

            // Copy the decrypted data back from unmanaged memory to a byte array
            metadataBlob = new byte[stream.Length];
            Marshal.Copy(decryptedBytesUnmanaged, metadataBlob, 0, (int)stream.Length);

            // Genshin Impact adds some spice by encrypting 0x10 bytes for every 'step' bytes of the metadata
            // with a simple XOR key, so we need to apply that too
            if (game.Value.StartsWith("genshin-impact"))
            {
                var key = new byte [] { 0xAD, 0x2F, 0x42, 0x30, 0x67, 0x04, 0xB0, 0x9C, 0x9D, 0x2A, 0xC0, 0xBA, 0x0E, 0xBF, 0xA5, 0x68 };

                // The step is based on the file size
                var step = (int)(stream.Length >> 14) << 6;

                for (var pos = 0; pos < metadataBlob.Length; pos += step)
                {
                    for (var b = 0; b < 0x10; b++)
                    {
                        metadataBlob[pos + b] ^= key[b];
                    }
                }
            }

            // We replace the loaded global-metadata.dat with the newly decrypted version,
            // allowing Il2CppInspector to analyze it as normal
            stream.Write(0, metadataBlob);

            // Some types have reordered fields - these calls tell Il2CppInspector what the correct field order is
            // See MappedTypes.cs for details
            stream.AddObjectMapping(typeof(Il2CppInspector.Il2CppGlobalMetadataHeader), typeof(Il2CppGlobalMetadataHeader));
            stream.AddObjectMapping(typeof(Il2CppInspector.Il2CppTypeDefinition), typeof(Il2CppTypeDefinition));
            stream.AddObjectMapping(typeof(Il2CppInspector.Il2CppMethodDefinition), typeof(Il2CppMethodDefinition));
            stream.AddObjectMapping(typeof(Il2CppInspector.Il2CppFieldDefinition), typeof(Il2CppFieldDefinition));
            stream.AddObjectMapping(typeof(Il2CppInspector.Il2CppPropertyDefinition), typeof(Il2CppPropertyDefinition));

            // We tell Il2CppInspector that we have taken care of the metadata
            // IsStreamModified marks the original data stream as modified so that the user is able to save the changes
            // SkipValidation tells Il2CppInspector not to check this global-metadata.dat for validity;
            // if we don't set this, it will report that the metadata is invalid
            info.IsStreamModified = true;
            info.SkipValidation   = true;
        }