整理总结一波il2cpp攻防的知识点,希望能从插件脚本小子稍微变强一点点
Unity il2cpp由来已久,由于il2cpp本身是开源的,自然也就诞生了很多针对未加密Unity项目的自动化破解工具,Hack工具,比较为人熟知的有:
对于一些较为基础的概念和说明,网上也有很多文章分享,这里推荐大家去逛逛看雪论坛,贴几篇文章在这:
一般对IL2CPP的反编译流程是:
- ida强行分析加载流程,从内存Dump出global-metadata.dat,可以无视加密,并存储成文件,例如:IL2CPP 逆向初探
- 使用上述工具对global-metadata.dat进行反编译,得到dummy dll以及各种反编译需要的数据,里面包含了所有方法,字段的地址偏移
- ida加载可执行文件,根据地址和第二步拿到的数据,查看指定函数,字段的反汇编代码,分析逻辑
- 使用Hook工具,对相应函数Hook,强制更改逻辑
相对应的,就有很多防御方案
- global-metadata.dat魔法数字加密
- 更改Il2CppMetadataRegistration字段顺序,使自动Dump失败,不过Il2CppInspector已经做了处理
- 针对自动化反编译工具魔改il2cpp源码,使其自动化失败
- 针对动态dump工具隐藏il2cpp的系统api,或者检测相应进程名称,直接闪退游戏
- 对可执行文件(GameAssembly.dll,il2cpp.so)进行混淆加密
推荐阅读:https://www.lfzxb.top/il2cpp-code-gen/ 了解IL2CPP的基础知识
加密头
位于Unity.IL2CPP.AssemblyConversion.SecondaryWrite.Steps.Global.WriteGlobalMetadataDat.WriteFinalDat
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| private static void WriteFinalDat( WorkItemData<GlobalWriteContext, ReadOnlyCollection<ResultData<BaseSectionWriter, ReadOnlyCollection<DatSection>>>, object> data) { using (data.Context.Services.TinyProfiler.Section("Write Metadata Dat")) { SourceWritingContext sourceWritingContext = data.Context.CreateSourceWritingContext(); DatSection[] array = data.Item.SelectMany<ResultData<BaseSectionWriter, ReadOnlyCollection<DatSection>>, DatSection>((Func<ResultData<BaseSectionWriter, ReadOnlyCollection<DatSection>>, IEnumerable<DatSection>>) (r => (IEnumerable<DatSection>) r.Result)).ToArray<DatSection>(); using (FileStream fileStream = new FileStream(sourceWritingContext.Global.InputData.MetadataFolder.MakeAbsolute().CreateDirectory().Combine("global-metadata.dat").ToString(), FileMode.Create, FileAccess.Write)) { int capacity = array.Length * 2 + 2; List<uint> headerData = new List<uint>(capacity); headerData.Add(4205910959U); headerData.Add(31U ); fileStream.Seek((long) (capacity * 4), SeekOrigin.Begin); foreach (DatSection datSection in array) { WriteGlobalMetadataDat.WriteStreamAndRecordHeader(sourceWritingContext, datSection.Name, (Stream) fileStream, (Stream) datSection.Stream, headerData, datSection.SectionAlignment); datSection.Dispose(); } fileStream.Seek(0L, SeekOrigin.Begin); foreach (uint num in headerData) fileStream.WriteUInt(num); } } }
|
模板文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
| typedef int32 TypeIndex; typedef int32 TypeDefinitionIndex; typedef int32 FieldIndex; typedef int32 DefaultValueIndex; typedef int32 DefaultValueDataIndex; typedef int32 CustomAttributeIndex; typedef int32 ParameterIndex; typedef int32 MethodIndex; typedef int32 GenericMethodIndex; typedef int32 PropertyIndex; typedef int32 EventIndex; typedef int32 GenericContainerIndex; typedef int32 GenericParameterIndex; typedef int16 GenericParameterConstraintIndex; typedef int32 NestedTypeIndex; typedef int32 InterfacesIndex; typedef int32 VTableIndex; typedef int32 InterfaceOffsetIndex; typedef int32 RGCTXIndex; typedef int32 StringIndex; typedef int32 StringLiteralIndex; typedef int32 GenericInstIndex; typedef int32 ImageIndex; typedef int32 AssemblyIndex; typedef int32 InteropDataIndex; typedef struct Il2CppGlobalMetadataHeader { int32 sanity; int32 version; int32 stringLiteralOffset; // string data for managed code int32 stringLiteralSize; int32 stringLiteralDataOffset; int32 stringLiteralDataSize; int32 stringOffset; // string data for metadata int32 stringSize; int32 eventsOffset; // Il2CppEventDefinition int32 eventsSize; int32 propertiesOffset; // Il2CppPropertyDefinition int32 propertiesSize; int32 methodsOffset; // Il2CppMethodDefinition int32 methodsSize; int32 parameterDefaultValuesOffset; // Il2CppParameterDefaultValue int32 parameterDefaultValuesSize; int32 fieldDefaultValuesOffset; // Il2CppFieldDefaultValue int32 fieldDefaultValuesSize; int32 fieldAndParameterDefaultValueDataOffset; // uint8_t int32 fieldAndParameterDefaultValueDataSize; int32 fieldMarshaledSizesOffset; // Il2CppFieldMarshaledSize int32 fieldMarshaledSizesSize; int32 parametersOffset; // Il2CppParameterDefinition int32 parametersSize; int32 fieldsOffset; // Il2CppFieldDefinition int32 fieldsSize; int32 genericParametersOffset; // Il2CppGenericParameter int32 genericParametersSize; int32 genericParameterConstraintsOffset; // TypeIndex int32 genericParameterConstraintsSize; int32 genericContainersOffset; // Il2CppGenericContainer int32 genericContainersSize; int32 nestedTypesOffset; // TypeDefinitionIndex int32 nestedTypesSize; int32 interfacesOffset; // TypeIndex int32 interfacesSize; int32 vtableMethodsOffset; // EncodedMethodIndex int32 vtableMethodsSize; int32 interfaceOffsetsOffset; // Il2CppInterfaceOffsetPair int32 interfaceOffsetsSize; int32 typeDefinitionsOffset; // Il2CppTypeDefinition int32 typeDefinitionsSize; int32 imagesOffset; // Il2CppImageDefinition int32 imagesSize; int32 assembliesOffset; // Il2CppAssemblyDefinition int32 assembliesSize; int32 fieldRefsOffset; // Il2CppFieldRef int32 fieldRefsSize; int32 referencedAssembliesOffset; // int32_t int32 referencedAssembliesSize; int32 attributeDataOffset; int32 attributeDataSize; int32 attributeDataRangeOffset; int32 attributeDataRangeSize; int32 unresolvedIndirectCallParameterTypesOffset; // TypeIndex int32 unresolvedIndirectCallParameterTypesSize; int32 unresolvedIndirectCallParameterRangesOffset; // Il2CppMetadataRange int32 unresolvedIndirectCallParameterRangesSize; int32 windowsRuntimeTypeNamesOffset; // Il2CppWindowsRuntimeTypeNamePair int32 windowsRuntimeTypeNamesSize; int32 windowsRuntimeStringsOffset; // const char* int32 windowsRuntimeStringsSize; int32 exportedTypeDefinitionsOffset; // TypeDefinitionIndex int32 exportedTypeDefinitionsSize; } Il2CppGlobalMetadataHeader; typedef struct Il2CppStringLiteralInfoDefinition { uint32 Length; uint32 Offset; } Il2CppStringLiteralInfoDefinition; typedef struct (uint infoSize, uint stringLiteralDataOffset, Il2CppStringLiteralInfoDefinition StringLiteralInfos[]) { typedef struct (uint stringLiteralDataOffset, uint index, Il2CppStringLiteralInfoDefinition StringLiteralInfos[]) { local uint infoOffset = StringLiteralInfos[index].Offset; local uint infoLength = StringLiteralInfos[index].Length; FSeek(stringLiteralDataOffset + infoOffset); if (infoLength > 0) char data[infoLength] <optimize=false>; } StringLiteralDefinition <read=(infoLength > 0 ? data : "null")>; local uint index = 0; while (index + 1 < infoSize) StringLiteralDefinition StringLiteralDefinitions(stringLiteralDataOffset, index++, StringLiteralInfos); } Il2CppStringLiteralDefinition; typedef struct Il2CppImageDefinition { StringIndex nameIndex; AssemblyIndex assemblyIndex; TypeDefinitionIndex typeStart; uint32 typeCount; TypeDefinitionIndex exportedTypeStart; uint32 exportedTypeCount; MethodIndex entryPointIndex; uint32 token; CustomAttributeIndex customAttributeStart; uint32 customAttributeCount; } Il2CppImageDefinition; #define PUBLIC_KEY_BYTE_LENGTH 8 typedef struct Il2CppAssemblyNameDefinition { StringIndex nameIndex; StringIndex cultureIndex; StringIndex hashValueIndex; StringIndex publicKeyIndex; uint32 hash_alg; int32 hash_len; uint32 flags; int32 major; int32 minor; int32 build; int32 revision; ubyte public_key_token[PUBLIC_KEY_BYTE_LENGTH]; } Il2CppAssemblyNameDefinition; typedef struct Il2CppAssemblyDefinition { ImageIndex imageIndex; uint32 token; int32 referencedAssemblyStart; int32 referencedAssemblyCount; Il2CppAssemblyNameDefinition aname; } Il2CppAssemblyDefinition; typedef struct Il2CppMethodDefinition { StringIndex nameIndex; TypeDefinitionIndex declaringType; TypeIndex returnType; ParameterIndex parameterStart; GenericContainerIndex genericContainerIndex; GenericMethodIndex methodIndex; CustomAttributeIndex customAttributeStart; uint32 token; uint16 flags; uint16 iflags; uint16 slot; uint16 parameterCount; } Il2CppMethodDefinition;
typedef struct Il2CppParameterDefinition { StringIndex nameIndex; uint32 token; CustomAttributeIndex customAttributeStart; TypeIndex typeIndex; uint32 attrs; } Il2CppParameterDefinition;
typedef struct Il2CppFieldDefinition { StringIndex nameIndex; TypeIndex typeIndex; uint32 attrs; DefaultValueDataIndex defaultValueIndex; CustomAttributeIndex customAttributeStart; uint32 token; } Il2CppFieldDefinition;
typedef struct Il2CppPropertyDefinition { StringIndex nameIndex; MethodIndex get; MethodIndex set; uint32 attrs; CustomAttributeIndex customAttributeStart; uint32 token; } Il2CppPropertyDefinition;
typedef struct Il2CppEventDefinition { StringIndex nameIndex; TypeIndex type; MethodIndex add; MethodIndex remove; MethodIndex raise; CustomAttributeIndex customAttributeStart; uint32 token; } Il2CppEventDefinition;
typedef struct Il2CppTypeDefinition { StringIndex nameIndex; StringIndex namespaceIndex; TypeIndex byvalTypeIndex; TypeIndex byrefTypeIndex; TypeIndex declaringTypeIndex; TypeIndex parentIndex; TypeIndex elementTypeIndex; // we can probably remove this one. Only used for enums RGCTXIndex rgctxStartIndex; int32 rgctxCount; GenericContainerIndex genericContainerIndex; uint32 flags; FieldIndex fieldStart; MethodIndex methodStart; EventIndex eventStart; PropertyIndex propertyStart; NestedTypeIndex nestedTypesStart; InterfacesIndex interfacesStart; VTableIndex vtableStart; InterfacesIndex interfaceOffsetsStart; uint16 method_count; uint16 property_count; uint16 field_count; uint16 event_count; uint16 nested_type_count; uint16 vtable_count; uint16 interfaces_count; uint16 interface_offsets_count; // bitfield to portably encode boolean values as single bits // 01 - valuetype; // 02 - enumtype; // 03 - has_finalize; // 04 - has_cctor; // 05 - is_blittable; // 06 - is_import_or_windows_runtime; // 07-10 - One of nine possible PackingSize values (0, 1, 2, 4, 8, 16, 32, 64, or 128) uint32 bitfield; uint32 token; } Il2CppTypeDefinition; Il2CppGlobalMetadataHeader metadataHeader <comment="metadata header information">; local uint infoSize = metadataHeader.stringLiteralSize / sizeof(Il2CppStringLiteralInfoDefinition); FSeek(metadataHeader.stringLiteralOffset); Il2CppStringLiteralInfoDefinition StringLiteralInfoDefinitions[infoSize] <comment="metadata define StringLiteralInfo">; Il2CppStringLiteralDefinition StringLiteralDefinitions(infoSize, metadataHeader.stringLiteralDataOffset, StringLiteralInfoDefinitions) <comment="metadata define StringLiteralDefinitions">; // 正确计算images数组大小 local uint imagesCount = metadataHeader.imagesSize / sizeof(Il2CppImageDefinition); FSeek(metadataHeader.imagesOffset); Il2CppImageDefinition imagesDefinitions[imagesCount] <comment="metadata define images">; // 正确计算assemblies数组大小 local uint assembliesCount = metadataHeader.assembliesSize / sizeof(Il2CppAssemblyDefinition); FSeek(metadataHeader.assembliesOffset); Il2CppAssemblyDefinition assemblyDefinitions[assembliesCount] <comment="metadata define assemblys">; // 正确计算typeDefinitions数组大小 local uint typeDefinitionsCount = metadataHeader.typeDefinitionsSize / sizeof(Il2CppTypeDefinition); FSeek(metadataHeader.typeDefinitionsOffset); Il2CppTypeDefinition typeDefinitions[typeDefinitionsCount] <comment="metadata define types">;
// 正确计算methods数组大小 local uint methodsCount = metadataHeader.methodsSize / sizeof(Il2CppMethodDefinition); FSeek(metadataHeader.methodsOffset); Il2CppMethodDefinition methodDefinitions[methodsCount] <comment="metadata define methods">;
// 正确计算parameters数组大小 local uint parametersCount = metadataHeader.parametersSize / sizeof(Il2CppParameterDefinition); FSeek(metadataHeader.parametersOffset); Il2CppParameterDefinition parameterDefinitions[parametersCount] <comment="metadata define parameters">;
// 正确计算fields数组大小 local uint fieldsCount = metadataHeader.fieldsSize / sizeof(Il2CppFieldDefinition); FSeek(metadataHeader.fieldsOffset); Il2CppFieldDefinition fieldDefinitions[fieldsCount] <comment="metadata define fields">;
// 正确计算properties数组大小 local uint propertiesCount = metadataHeader.propertiesSize / sizeof(Il2CppPropertyDefinition); FSeek(metadataHeader.propertiesOffset); Il2CppPropertyDefinition propertyDefinitions[propertiesCount] <comment="metadata define properties">;
// 正确计算events数组大小 local uint eventsCount = metadataHeader.eventsSize / sizeof(Il2CppEventDefinition); FSeek(metadataHeader.eventsOffset); Il2CppEventDefinition eventDefinitions[eventsCount] <comment="metadata define events">; // 注意:在当前版本的IL2CPP中,metadataUsagePairs和metadataUsageList已被移除 // 如果需要解析其他部分的数据,请参考IL2CPP源码中的GlobalMetadataFileInternals.h
|