obfuz/Editor/Virtualization/DataNodes/ConstFromFieldRvaDataNode.cs

131 lines
5.9 KiB
C#

using dnlib.DotNet;
using dnlib.DotNet.Emit;
using Obfuz.Emit;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static UnityEngine.Networking.UnityWebRequest;
using UnityEngine.UIElements;
namespace Obfuz.Virtualization
{
[NodeOutput(DataNodeType.Int32)]
[NodeOutput(DataNodeType.Int64)]
[NodeOutput(DataNodeType.Float32)]
[NodeOutput(DataNodeType.Float64)]
[NodeOutput(DataNodeType.Bytes)]
[NodeOutput(DataNodeType.String)]
public class ConstFromFieldRvaDataNode : DataNodeAny
{
private RvaData AllocateRvaData(CompileContext ctx)
{
ModuleDef mod = ctx.method.Module;
RvaDataAllocator allocator = ctx.rvaDataAllocator;
switch (Type)
{
case DataNodeType.Int32: return allocator.Allocate(mod, IntValue);
case DataNodeType.Int64: return allocator.Allocate(mod, LongValue);
case DataNodeType.Float32: return allocator.Allocate(mod, FloatValue);
case DataNodeType.Float64: return allocator.Allocate(mod, DoubleValue);
case DataNodeType.Bytes: return allocator.Allocate(mod, BytesValue);
case DataNodeType.String: return allocator.Allocate(mod, StringValue);
default:
throw new NotSupportedException($"Unsupported type: {Type}.");
}
}
private static IMethod s_convertInt;
private static IMethod s_convertLong;
private static IMethod s_convertFloat;
private static IMethod s_convertDouble;
private static IMethod s_convertString;
private static IField s_Encoding_Utf8;
private static IMethod s_convertBytes;
private void InitImportMetadatas(ModuleDef mod)
{
if (s_convertInt != null)
{
return;
}
s_convertInt = mod.Import(typeof(BitConverter).GetMethod("ToInt32", new[] { typeof(byte[]), typeof(int) }));
s_convertLong = mod.Import(typeof(BitConverter).GetMethod("ToInt64", new[] { typeof(byte[]), typeof(int) }));
s_convertFloat = mod.Import(typeof(BitConverter).GetMethod("ToSingle", new[] { typeof(byte[]), typeof(int) }));
s_convertDouble = mod.Import(typeof(BitConverter).GetMethod("ToDouble", new[] { typeof(byte[]), typeof(int) }));
s_convertString = mod.Import(typeof(Encoding).GetMethod("GetString", new[] { typeof(byte[]), typeof(int), typeof(int) }));
s_Encoding_Utf8 = mod.Import(typeof(Encoding).GetField("UTF8"));
s_convertBytes = mod.Import(typeof(Array).GetMethod("Copy", new[] { typeof(Array), typeof(int), typeof(Array), typeof(int), typeof(int) }));
}
IMethod GetConvertMethod(ModuleDef mod)
{
InitImportMetadatas(mod);
switch (Type)
{
case DataNodeType.Int32: return s_convertInt;
case DataNodeType.Int64: return s_convertLong;
case DataNodeType.Float32: return s_convertFloat;
case DataNodeType.Float64: return s_convertDouble;
case DataNodeType.String: return s_convertString;
case DataNodeType.Bytes: return s_convertBytes;
default: throw new NotSupportedException($"Unsupported type: {Type}.");
}
}
public override void Compile(CompileContext ctx)
{
// only support Int32, int64, bytes.
// string can only create from StringFromBytesNode
// x = memcpy array.GetRange(index, length);
var output = ctx.output;
RvaData rvaData = AllocateRvaData(ctx);
ModuleDef mod = ctx.method.Module;
IMethod convertMethod = GetConvertMethod(mod);
switch (Type)
{
case DataNodeType.Int32:
case DataNodeType.Int64:
case DataNodeType.Float32:
case DataNodeType.Float64:
{
ctx.output.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
output.Add(Instruction.Create(OpCodes.Ldc_I4, rvaData.offset));
output.Add(Instruction.Create(OpCodes.Call, convertMethod));
break;
}
case DataNodeType.String:
{
// Encoding.UTF8.GetString(data, offset, length);
ctx.output.Add(Instruction.Create(OpCodes.Ldsfld, s_Encoding_Utf8));
ctx.output.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
output.Add(Instruction.Create(OpCodes.Ldc_I4, rvaData.offset));
output.Add(Instruction.Create(OpCodes.Ldc_I4, rvaData.size));
output.Add(Instruction.Create(OpCodes.Call, convertMethod));
break;
}
case DataNodeType.Bytes:
{
// byte[] result = new byte[length];
// Array.Copy(data, offset, result, 0, length);
ctx.output.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
output.Add(Instruction.Create(OpCodes.Ldc_I4, rvaData.offset));
output.Add(Instruction.Create(OpCodes.Ldc_I4, rvaData.size));
output.Add(Instruction.Create(OpCodes.Newarr, mod.CorLibTypes.Byte.ToTypeDefOrRef()));
output.Add(Instruction.Create(OpCodes.Ldc_I4, 0));
output.Add(Instruction.Create(OpCodes.Ldc_I4, rvaData.size));
output.Add(Instruction.Create(OpCodes.Call, convertMethod));
break;
}
default:
throw new NotSupportedException($"Unsupported type: {Type}.");
}
}
}
}