added JIT anti tamper protection
This commit is contained in:
Родитель
a4c44faa1c
Коммит
8ece9c8533
|
@ -85,6 +85,9 @@ namespace Confuser.Protections
|
|||
case Mode.Normal:
|
||||
modeHandler = new NormalMode();
|
||||
break;
|
||||
case Mode.JIT:
|
||||
modeHandler = new JITMode();
|
||||
break;
|
||||
default:
|
||||
throw new UnreachableException();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,281 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using dnlib.DotNet.Emit;
|
||||
using dnlib.DotNet.Writer;
|
||||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
using dnlib.IO;
|
||||
using dnlib.PE;
|
||||
using dnlib.DotNet;
|
||||
|
||||
namespace Confuser.Protections.AntiTamper
|
||||
{
|
||||
struct JITEHClause
|
||||
{
|
||||
public uint Flags;
|
||||
public uint TryOffset;
|
||||
public uint TryLength;
|
||||
public uint HandlerOffset;
|
||||
public uint HandlerLength;
|
||||
public uint ClassTokenOrFilterOffset;
|
||||
}
|
||||
|
||||
class JITMethodBody : IChunk
|
||||
{
|
||||
public byte[] ILCode;
|
||||
public uint MaxStack;
|
||||
public JITEHClause[] EHs;
|
||||
public byte[] LocalVars;
|
||||
public uint Options;
|
||||
public uint MulSeed;
|
||||
|
||||
public uint Offset;
|
||||
public byte[] Body;
|
||||
|
||||
public void Serialize(uint token, uint key)
|
||||
{
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
BinaryWriter writer = new BinaryWriter(ms);
|
||||
writer.Write((uint)ILCode.Length);
|
||||
writer.Write(MaxStack);
|
||||
writer.Write((uint)EHs.Length);
|
||||
writer.Write((uint)LocalVars.Length);
|
||||
writer.Write(Options);
|
||||
writer.Write(MulSeed);
|
||||
|
||||
writer.Write(ILCode);
|
||||
writer.Write(LocalVars);
|
||||
foreach (var clause in EHs)
|
||||
{
|
||||
writer.Write(clause.Flags);
|
||||
writer.Write(clause.TryOffset);
|
||||
writer.Write(clause.TryLength);
|
||||
writer.Write(clause.HandlerOffset);
|
||||
writer.Write(clause.HandlerLength);
|
||||
writer.Write(clause.ClassTokenOrFilterOffset);
|
||||
}
|
||||
writer.WriteZeros(4 - ((int)ms.Length & 3)); // pad to 4 bytes
|
||||
Body = ms.ToArray();
|
||||
}
|
||||
Debug.Assert(Body.Length % 4 == 0);
|
||||
// encrypt body
|
||||
uint state = token * key;
|
||||
uint counter = state;
|
||||
for (uint i = 0; i < Body.Length; i+=4)
|
||||
{
|
||||
uint data = Body[i] | (uint)(Body[i + 1] << 8) | (uint)(Body[i + 2] << 16) | (uint)(Body[i + 3] << 24);
|
||||
Body[i + 0] ^= (byte)(state >> 0);
|
||||
Body[i + 1] ^= (byte)(state >> 8);
|
||||
Body[i + 2] ^= (byte)(state >> 16);
|
||||
Body[i + 3] ^= (byte)(state >> 24);
|
||||
state += data ^ counter;
|
||||
counter ^= (state >> 5) | (state << 27);
|
||||
}
|
||||
}
|
||||
|
||||
FileOffset offset;
|
||||
RVA rva;
|
||||
|
||||
public FileOffset FileOffset { get { return offset; } }
|
||||
|
||||
public RVA RVA { get { return rva; } }
|
||||
|
||||
public void SetOffset(FileOffset offset, RVA rva)
|
||||
{
|
||||
this.offset = offset;
|
||||
this.rva = rva;
|
||||
}
|
||||
|
||||
public uint GetFileLength()
|
||||
{
|
||||
return (uint)Body.Length + 4;
|
||||
}
|
||||
|
||||
public uint GetVirtualSize()
|
||||
{
|
||||
return GetFileLength();
|
||||
}
|
||||
|
||||
public void WriteTo(BinaryWriter writer)
|
||||
{
|
||||
writer.Write((uint)(Body.Length >> 2));
|
||||
writer.Write(Body);
|
||||
}
|
||||
}
|
||||
|
||||
class JITMethodBodyWriter : MethodBodyWriterBase
|
||||
{
|
||||
MetaData metadata;
|
||||
CilBody body;
|
||||
JITMethodBody jitBody;
|
||||
bool keepMaxStack;
|
||||
|
||||
public JITMethodBodyWriter(MetaData md, CilBody body, JITMethodBody jitBody, uint mulSeed, bool keepMaxStack) :
|
||||
base(body.Instructions, body.ExceptionHandlers)
|
||||
{
|
||||
this.metadata = md;
|
||||
this.body = body;
|
||||
this.jitBody = jitBody;
|
||||
this.keepMaxStack = keepMaxStack;
|
||||
this.jitBody.MulSeed = mulSeed;
|
||||
}
|
||||
|
||||
public void Write()
|
||||
{
|
||||
uint codeSize = InitializeInstructionOffsets();
|
||||
jitBody.MaxStack = keepMaxStack ? body.MaxStack : GetMaxStack();
|
||||
|
||||
jitBody.Options = 0;
|
||||
if (body.InitLocals)
|
||||
jitBody.Options |= 0x10;
|
||||
|
||||
if (body.Variables.Count > 0)
|
||||
{
|
||||
LocalSig local = new LocalSig(body.Variables.Select(var => var.Type).ToList());
|
||||
jitBody.LocalVars = SignatureWriter.Write(metadata, local);
|
||||
}
|
||||
else
|
||||
jitBody.LocalVars = new byte[0];
|
||||
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
uint _codeSize = WriteInstructions(new BinaryWriter(ms));
|
||||
Debug.Assert(codeSize == _codeSize);
|
||||
jitBody.ILCode = ms.ToArray();
|
||||
}
|
||||
|
||||
jitBody.EHs = new JITEHClause[exceptionHandlers.Count];
|
||||
if (exceptionHandlers.Count > 0)
|
||||
{
|
||||
jitBody.Options |= 8;
|
||||
for (int i = 0; i < exceptionHandlers.Count; i++)
|
||||
{
|
||||
var eh = exceptionHandlers[i];
|
||||
jitBody.EHs[i].Flags = (uint)eh.HandlerType;
|
||||
|
||||
uint tryStart = GetOffset(eh.TryStart);
|
||||
uint tryEnd = GetOffset(eh.TryEnd);
|
||||
jitBody.EHs[i].TryOffset = tryStart;
|
||||
jitBody.EHs[i].TryLength = tryEnd - tryStart;
|
||||
|
||||
uint handlerStart = GetOffset(eh.HandlerStart);
|
||||
uint handlerEnd = GetOffset(eh.HandlerEnd);
|
||||
jitBody.EHs[i].HandlerOffset = handlerStart;
|
||||
jitBody.EHs[i].HandlerLength = handlerEnd - handlerStart;
|
||||
|
||||
if (eh.HandlerType == ExceptionHandlerType.Catch)
|
||||
{
|
||||
var token = metadata.GetToken(eh.CatchType).Raw;
|
||||
if ((token & 0xff000000) == 0x1b000000)
|
||||
jitBody.Options |= 0x80;
|
||||
|
||||
jitBody.EHs[i].ClassTokenOrFilterOffset = token;
|
||||
}
|
||||
else if (eh.HandlerType == ExceptionHandlerType.Filter)
|
||||
{
|
||||
jitBody.EHs[i].ClassTokenOrFilterOffset = GetOffset(eh.FilterStart);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void WriteInlineField(BinaryWriter writer, Instruction instr)
|
||||
{
|
||||
writer.Write(metadata.GetToken(instr.Operand).Raw);
|
||||
}
|
||||
|
||||
protected override void WriteInlineMethod(BinaryWriter writer, Instruction instr)
|
||||
{
|
||||
writer.Write(metadata.GetToken(instr.Operand).Raw);
|
||||
}
|
||||
|
||||
protected override void WriteInlineSig(BinaryWriter writer, Instruction instr)
|
||||
{
|
||||
writer.Write(metadata.GetToken(instr.Operand).Raw);
|
||||
}
|
||||
|
||||
protected override void WriteInlineString(BinaryWriter writer, Instruction instr)
|
||||
{
|
||||
writer.Write(metadata.GetToken(instr.Operand).Raw);
|
||||
}
|
||||
|
||||
protected override void WriteInlineTok(BinaryWriter writer, Instruction instr)
|
||||
{
|
||||
writer.Write(metadata.GetToken(instr.Operand).Raw);
|
||||
}
|
||||
|
||||
protected override void WriteInlineType(BinaryWriter writer, Instruction instr)
|
||||
{
|
||||
writer.Write(metadata.GetToken(instr.Operand).Raw);
|
||||
}
|
||||
}
|
||||
|
||||
class JITBodyIndex : IChunk
|
||||
{
|
||||
Dictionary<uint, JITMethodBody> bodies;
|
||||
|
||||
public JITBodyIndex(IEnumerable<uint> tokens)
|
||||
{
|
||||
bodies = tokens.ToDictionary(token => token, token => (JITMethodBody)null);
|
||||
}
|
||||
|
||||
public void Add(uint token, JITMethodBody body)
|
||||
{
|
||||
Debug.Assert(bodies.ContainsKey(token));
|
||||
bodies[token] = body;
|
||||
}
|
||||
|
||||
public void PopulateSection(PESection section)
|
||||
{
|
||||
uint offset = 0;
|
||||
foreach (var entry in bodies.OrderBy(entry => entry.Key))
|
||||
{
|
||||
Debug.Assert(entry.Value != null);
|
||||
section.Add(entry.Value, 4);
|
||||
entry.Value.Offset = offset;
|
||||
|
||||
Debug.Assert(entry.Value.GetFileLength() % 4 == 0);
|
||||
offset += entry.Value.GetFileLength();
|
||||
}
|
||||
}
|
||||
|
||||
FileOffset offset;
|
||||
RVA rva;
|
||||
|
||||
public FileOffset FileOffset { get { return offset; } }
|
||||
|
||||
public RVA RVA { get { return rva; } }
|
||||
|
||||
public void SetOffset(FileOffset offset, RVA rva)
|
||||
{
|
||||
this.offset = offset;
|
||||
this.rva = rva;
|
||||
}
|
||||
|
||||
public uint GetFileLength()
|
||||
{
|
||||
return (uint)bodies.Count * 8 + 4;
|
||||
}
|
||||
|
||||
public uint GetVirtualSize()
|
||||
{
|
||||
return GetFileLength();
|
||||
}
|
||||
|
||||
public void WriteTo(BinaryWriter writer)
|
||||
{
|
||||
uint length = GetFileLength() - 4; // minus length field
|
||||
writer.Write((uint)bodies.Count);
|
||||
foreach (var entry in bodies.OrderBy(entry => entry.Key))
|
||||
{
|
||||
writer.Write(entry.Key);
|
||||
Debug.Assert(entry.Value != null);
|
||||
Debug.Assert((length + entry.Value.Offset) % 4 == 0);
|
||||
writer.Write((length + entry.Value.Offset) >> 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,301 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Confuser.Core;
|
||||
using dnlib.DotNet;
|
||||
using Confuser.Core.Services;
|
||||
using dnlib.DotNet.Writer;
|
||||
using dnlib.DotNet.Emit;
|
||||
using Confuser.Core.Helpers;
|
||||
using System.Diagnostics;
|
||||
using Confuser.Renamer;
|
||||
using System.IO;
|
||||
|
||||
namespace Confuser.Protections.AntiTamper
|
||||
{
|
||||
class JITMode : IModeHandler
|
||||
{
|
||||
RandomGenerator random;
|
||||
uint z, x, c, v;
|
||||
uint name1, name2;
|
||||
uint key;
|
||||
IKeyDeriver deriver;
|
||||
|
||||
MethodDef initMethod;
|
||||
MethodDef cctor;
|
||||
MethodDef cctorRepl;
|
||||
List<MethodDef> methods;
|
||||
public void HandleInject(AntiTamperProtection parent, ConfuserContext context, ProtectionParameters parameters)
|
||||
{
|
||||
random = context.Registry.GetService<IRandomService>().GetRandomGenerator(parent.FullId);
|
||||
z = random.NextUInt32();
|
||||
x = random.NextUInt32();
|
||||
c = random.NextUInt32();
|
||||
v = random.NextUInt32();
|
||||
name1 = random.NextUInt32() & 0x7f7f7f7f;
|
||||
name2 = random.NextUInt32() & 0x7f7f7f7f;
|
||||
key = random.NextUInt32();
|
||||
|
||||
switch (parameters.GetParameter<Mode>(context, context.CurrentModule, "key", Mode.Normal))
|
||||
{
|
||||
case Mode.Normal:
|
||||
deriver = new NormalDeriver();
|
||||
break;
|
||||
case Mode.Dynamic:
|
||||
deriver = new DynamicDeriver();
|
||||
break;
|
||||
default:
|
||||
throw new UnreachableException();
|
||||
}
|
||||
deriver.Init(context, random);
|
||||
|
||||
var rt = context.Registry.GetService<IRuntimeService>();
|
||||
var initType = rt.GetRuntimeType("Confuser.Runtime.AntiTamperJIT");
|
||||
var defs = InjectHelper.Inject(initType, context.CurrentModule.GlobalType, context.CurrentModule);
|
||||
initMethod = defs.OfType<MethodDef>().Single(method => method.Name == "Initialize");
|
||||
|
||||
initMethod.Body.SimplifyMacros(initMethod.Parameters);
|
||||
var instrs = initMethod.Body.Instructions.ToList();
|
||||
for (int i = 0; i < instrs.Count; i++)
|
||||
{
|
||||
var instr = instrs[i];
|
||||
if (instr.OpCode == OpCodes.Ldtoken)
|
||||
{
|
||||
instr.Operand = context.CurrentModule.GlobalType;
|
||||
}
|
||||
else if (instr.OpCode == OpCodes.Call)
|
||||
{
|
||||
IMethod method = (IMethod)instr.Operand;
|
||||
if (method.DeclaringType.Name == "Mutation" &&
|
||||
method.Name == "Crypt")
|
||||
{
|
||||
Instruction ldDst = instrs[i - 2];
|
||||
Instruction ldSrc = instrs[i - 1];
|
||||
Debug.Assert(ldDst.OpCode == OpCodes.Ldloc && ldSrc.OpCode == OpCodes.Ldloc);
|
||||
instrs.RemoveAt(i);
|
||||
instrs.RemoveAt(i - 1);
|
||||
instrs.RemoveAt(i - 2);
|
||||
instrs.InsertRange(i - 2, deriver.EmitDerivation(initMethod, context, (Local)ldDst.Operand, (Local)ldSrc.Operand));
|
||||
}
|
||||
}
|
||||
}
|
||||
initMethod.Body.Instructions.Clear();
|
||||
foreach (var instr in instrs)
|
||||
initMethod.Body.Instructions.Add(instr);
|
||||
|
||||
MutationHelper.InjectKeys(initMethod,
|
||||
new int[] { 0, 1, 2, 3, 4 },
|
||||
new int[] { (int)(name1 * name2), (int)z, (int)x, (int)c, (int)v });
|
||||
|
||||
var name = context.Registry.GetService<INameService>();
|
||||
var marker = context.Registry.GetService<IMarkerService>();
|
||||
|
||||
cctor = context.CurrentModule.GlobalType.FindStaticConstructor();
|
||||
|
||||
cctorRepl = new MethodDefUser(name.RandomName(), MethodSig.CreateStatic(context.CurrentModule.CorLibTypes.Void));
|
||||
cctorRepl.IsStatic = true;
|
||||
cctorRepl.Access = MethodAttributes.CompilerControlled;
|
||||
cctorRepl.Body = new CilBody();
|
||||
cctorRepl.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
|
||||
context.CurrentModule.GlobalType.Methods.Add(cctorRepl);
|
||||
name.MarkHelper(cctorRepl, marker);
|
||||
|
||||
MutationHelper.InjectKeys(defs.OfType<MethodDef>().Single(method => method.Name == "HookHandler"),
|
||||
new int[] { 0 }, new int[] { (int)key });
|
||||
foreach (var def in defs)
|
||||
{
|
||||
name.MarkHelper(def, marker);
|
||||
if (def is MethodDef)
|
||||
parent.ExcludeMethod(context, (MethodDef)def);
|
||||
}
|
||||
parent.ExcludeMethod(context, cctor);
|
||||
}
|
||||
|
||||
public void HandleMD(AntiTamperProtection parent, ConfuserContext context, ProtectionParameters parameters)
|
||||
{
|
||||
methods = parameters.Targets.OfType<MethodDef>().Where(method => method.HasBody).ToList();
|
||||
context.CurrentModuleWriterListener.OnWriterEvent += OnWriterEvent;
|
||||
}
|
||||
|
||||
static readonly dnlib.DotNet.Emit.CilBody NopBody = new dnlib.DotNet.Emit.CilBody()
|
||||
{
|
||||
Instructions =
|
||||
{
|
||||
Instruction.Create(OpCodes.Ldnull),
|
||||
Instruction.Create(OpCodes.Throw)
|
||||
}
|
||||
};
|
||||
|
||||
void OnWriterEvent(object sender, ModuleWriterListenerEventArgs e)
|
||||
{
|
||||
var writer = (ModuleWriter)sender;
|
||||
if (e.WriterEvent == ModuleWriterEvent.MDBeginWriteMethodBodies)
|
||||
{
|
||||
CreateSection(writer);
|
||||
}
|
||||
else if (e.WriterEvent == ModuleWriterEvent.BeginStrongNameSign)
|
||||
{
|
||||
EncryptSection(writer);
|
||||
}
|
||||
}
|
||||
|
||||
void CreateSection(ModuleWriter writer)
|
||||
{
|
||||
// move some PE parts to separate section to prevent it from being hashed
|
||||
var peSection = new PESection("", 0x60000020);
|
||||
bool moved = false;
|
||||
uint alignment;
|
||||
if (writer.StrongNameSignature != null)
|
||||
{
|
||||
alignment = writer.TextSection.Remove(writer.StrongNameSignature).Value;
|
||||
peSection.Add(writer.StrongNameSignature, alignment);
|
||||
moved = true;
|
||||
}
|
||||
if (writer.ImportAddressTable != null)
|
||||
{
|
||||
alignment = writer.TextSection.Remove(writer.ImportAddressTable).Value;
|
||||
peSection.Add(writer.ImportAddressTable, alignment);
|
||||
moved = true;
|
||||
}
|
||||
if (writer.StartupStub != null)
|
||||
{
|
||||
alignment = writer.TextSection.Remove(writer.StartupStub).Value;
|
||||
peSection.Add(writer.StartupStub, alignment);
|
||||
moved = true;
|
||||
}
|
||||
if (moved)
|
||||
writer.Sections.Add(peSection);
|
||||
|
||||
// create section
|
||||
byte[] nameBuffer = new byte[8];
|
||||
nameBuffer[0] = (byte)(name1 >> 0);
|
||||
nameBuffer[1] = (byte)(name1 >> 8);
|
||||
nameBuffer[2] = (byte)(name1 >> 16);
|
||||
nameBuffer[3] = (byte)(name1 >> 24);
|
||||
nameBuffer[4] = (byte)(name2 >> 0);
|
||||
nameBuffer[5] = (byte)(name2 >> 8);
|
||||
nameBuffer[6] = (byte)(name2 >> 16);
|
||||
nameBuffer[7] = (byte)(name2 >> 24);
|
||||
var newSection = new PESection(Encoding.ASCII.GetString(nameBuffer), 0xE0000040);
|
||||
writer.Sections.Insert(random.NextInt32(writer.Sections.Count), newSection);
|
||||
|
||||
// random padding at beginning to prevent revealing hash key
|
||||
newSection.Add(new ByteArrayChunk(random.NextBytes(0x10)), 0x10);
|
||||
|
||||
// create index
|
||||
JITBodyIndex bodyIndex = new JITBodyIndex(methods.Select(method => writer.MetaData.GetToken(method).Raw));
|
||||
newSection.Add(bodyIndex, 0x10);
|
||||
|
||||
// move initialization away from module initializer
|
||||
cctorRepl.Body = cctor.Body;
|
||||
cctor.Body = new CilBody();
|
||||
cctor.Body.Instructions.Add(Instruction.Create(OpCodes.Call, initMethod));
|
||||
cctor.Body.Instructions.Add(Instruction.Create(OpCodes.Call, cctorRepl));
|
||||
cctor.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
|
||||
|
||||
// save methods
|
||||
foreach (var method in methods)
|
||||
{
|
||||
if (!method.HasBody)
|
||||
continue;
|
||||
|
||||
MDToken token = writer.MetaData.GetToken(method);
|
||||
|
||||
var jitBody = new JITMethodBody();
|
||||
var bodyWriter = new JITMethodBodyWriter(writer.MetaData, method.Body, jitBody, random.NextUInt32(), writer.MetaData.KeepOldMaxStack || method.Body.KeepOldMaxStack);
|
||||
bodyWriter.Write();
|
||||
jitBody.Serialize(token.Raw, key);
|
||||
bodyIndex.Add(token.Raw, jitBody);
|
||||
|
||||
method.Body = NopBody;
|
||||
writer.MetaData.TablesHeap.MethodTable[token.Rid].ImplFlags |= (ushort)MethodImplAttributes.NoInlining;
|
||||
|
||||
}
|
||||
bodyIndex.PopulateSection(newSection);
|
||||
|
||||
// padding to prevent bad size due to shift division
|
||||
newSection.Add(new ByteArrayChunk(new byte[4]), 4);
|
||||
}
|
||||
|
||||
void EncryptSection(ModuleWriter writer)
|
||||
{
|
||||
var stream = writer.DestinationStream;
|
||||
var reader = new BinaryReader(writer.DestinationStream);
|
||||
stream.Position = 0x3C;
|
||||
stream.Position = reader.ReadUInt32();
|
||||
|
||||
stream.Position += 6;
|
||||
ushort sections = reader.ReadUInt16();
|
||||
stream.Position += 0xc;
|
||||
ushort optSize = reader.ReadUInt16();
|
||||
stream.Position += 2 + optSize;
|
||||
|
||||
uint encLoc = 0, encSize = 0;
|
||||
for (int i = 0; i < sections; i++)
|
||||
{
|
||||
uint nameHash = reader.ReadUInt32() * reader.ReadUInt32();
|
||||
stream.Position += 8;
|
||||
if (nameHash == name1 * name2)
|
||||
{
|
||||
encSize = reader.ReadUInt32();
|
||||
encLoc = reader.ReadUInt32();
|
||||
}
|
||||
else if (nameHash != 0)
|
||||
{
|
||||
uint sectSize = reader.ReadUInt32();
|
||||
uint sectLoc = reader.ReadUInt32();
|
||||
Hash(stream, reader, sectLoc, sectSize);
|
||||
}
|
||||
stream.Position += 16;
|
||||
}
|
||||
|
||||
uint[] key = DeriveKey();
|
||||
encSize >>= 2;
|
||||
stream.Position = encLoc;
|
||||
uint[] result = new uint[encSize];
|
||||
for (uint i = 0; i < encSize; i++)
|
||||
{
|
||||
uint data = reader.ReadUInt32();
|
||||
result[i] = data ^ key[i & 0xf];
|
||||
key[i & 0xf] = (key[i & 0xf] ^ data) + 0x3dbb2819;
|
||||
}
|
||||
byte[] byteResult = new byte[encSize << 2];
|
||||
Buffer.BlockCopy(result, 0, byteResult, 0, byteResult.Length);
|
||||
stream.Position = encLoc;
|
||||
stream.Write(byteResult, 0, byteResult.Length);
|
||||
}
|
||||
|
||||
void Hash(Stream stream, BinaryReader reader, uint offset, uint size)
|
||||
{
|
||||
long original = stream.Position;
|
||||
stream.Position = offset;
|
||||
size >>= 2;
|
||||
for (uint i = 0; i < size; i++)
|
||||
{
|
||||
uint data = reader.ReadUInt32();
|
||||
uint tmp = (z ^ data) + x + c * v;
|
||||
z = x;
|
||||
x = c;
|
||||
x = v;
|
||||
v = tmp;
|
||||
}
|
||||
stream.Position = original;
|
||||
}
|
||||
|
||||
uint[] DeriveKey()
|
||||
{
|
||||
uint[] dst = new uint[0x10], src = new uint[0x10];
|
||||
for (int i = 0; i < 0x10; i++)
|
||||
{
|
||||
dst[i] = v;
|
||||
src[i] = x;
|
||||
z = (x >> 5) | (x << 27);
|
||||
x = (c >> 3) | (c << 29);
|
||||
c = (v >> 7) | (v << 25);
|
||||
v = (z >> 11) | (z << 21);
|
||||
}
|
||||
return deriver.DeriveKey(dst, src);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -50,6 +50,7 @@ namespace Confuser.Protections.AntiTamper
|
|||
initMethod = InjectHelper.Inject(initMethod, context.CurrentModule);
|
||||
context.CurrentModule.GlobalType.Methods.Add(initMethod);
|
||||
|
||||
initMethod.Body.SimplifyMacros(initMethod.Parameters);
|
||||
var instrs = initMethod.Body.Instructions.ToList();
|
||||
for (int i = 0; i < instrs.Count; i++)
|
||||
{
|
||||
|
|
|
@ -47,6 +47,8 @@
|
|||
<Compile Include="AntiTamper\DynamicDeriver.cs" />
|
||||
<Compile Include="AntiTamper\IKeyDeriver.cs" />
|
||||
<Compile Include="AntiTamper\IModeHandler.cs" />
|
||||
<Compile Include="AntiTamper\JITBody.cs" />
|
||||
<Compile Include="AntiTamper\JITMode.cs" />
|
||||
<Compile Include="AntiTamper\NormalDeriver.cs" />
|
||||
<Compile Include="AntiTamper\NormalMode.cs" />
|
||||
<Compile Include="Constants\CEContext.cs" />
|
||||
|
|
|
@ -284,7 +284,15 @@ namespace Confuser.Protections.ReferenceProxy
|
|||
ctx.Module.AddAsNonNestedType(injectedAttr);
|
||||
|
||||
foreach (var def in injectedAttr.FindDefinitions())
|
||||
ctx.Name.MarkHelper(def, ctx.Marker);
|
||||
{
|
||||
if (def.Name == "GetHashCode")
|
||||
{
|
||||
ctx.Name.MarkHelper(def, ctx.Marker);
|
||||
((MethodDef)def).Access = MethodAttributes.Public;
|
||||
}
|
||||
else
|
||||
ctx.Name.MarkHelper(def, ctx.Marker);
|
||||
}
|
||||
}
|
||||
return keyAttrs[index].Item1;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,592 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Confuser.Runtime
|
||||
{
|
||||
unsafe static class AntiTamperJIT
|
||||
{
|
||||
static uint* ptr;
|
||||
static uint len;
|
||||
static IntPtr moduleHnd;
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
var m = typeof(AntiTamperNormal).Module;
|
||||
string n = m.FullyQualifiedName;
|
||||
bool f = n.Length > 0 && n[0] == '<';
|
||||
byte* b = (byte*)Marshal.GetHINSTANCE(m);
|
||||
byte* p = b + *(uint*)(b + 0x3c);
|
||||
ushort s = *(ushort*)(p + 0x6);
|
||||
ushort o = *(ushort*)(p + 0x14);
|
||||
|
||||
uint* e = null;
|
||||
uint l = 0;
|
||||
uint* r = (uint*)(p + 0x18 + o);
|
||||
uint z = (uint)Mutation.KeyI1, x = (uint)Mutation.KeyI2, c = (uint)Mutation.KeyI3, v = (uint)Mutation.KeyI4;
|
||||
for (int i = 0; i < s; i++)
|
||||
{
|
||||
uint g = (*r++) * (*r++);
|
||||
if (g == (uint)Mutation.KeyI0)
|
||||
{
|
||||
e = (uint*)(b + (f ? *(r + 3) : *(r + 1)));
|
||||
l = (f ? *(r + 2) : *(r + 0)) >> 2;
|
||||
}
|
||||
else if (g != 0)
|
||||
{
|
||||
uint* q = (uint*)(b + (f ? *(r + 3) : *(r + 1)));
|
||||
uint j = *(r + 2) >> 2;
|
||||
for (uint k = 0; k < j; k++)
|
||||
{
|
||||
uint t = (z ^ (*q++)) + x + c * v;
|
||||
z = x;
|
||||
x = c;
|
||||
x = v;
|
||||
v = t;
|
||||
}
|
||||
}
|
||||
r += 8;
|
||||
}
|
||||
|
||||
uint[] y = new uint[0x10], d = new uint[0x10];
|
||||
for (int i = 0; i < 0x10; i++)
|
||||
{
|
||||
y[i] = v;
|
||||
d[i] = x;
|
||||
z = (x >> 5) | (x << 27);
|
||||
x = (c >> 3) | (c << 29);
|
||||
c = (v >> 7) | (v << 25);
|
||||
v = (z >> 11) | (z << 21);
|
||||
}
|
||||
Mutation.Crypt(y, d);
|
||||
|
||||
uint h = 0;
|
||||
uint* u = e;
|
||||
for (uint i = 0; i < l; i++)
|
||||
{
|
||||
*e ^= y[h & 0xf];
|
||||
y[h & 0xf] = (y[h & 0xf] ^ (*e++)) + 0x3dbb2819;
|
||||
h++;
|
||||
}
|
||||
|
||||
ptr = u + 4;
|
||||
len = *ptr++;
|
||||
|
||||
ver = RuntimeEnvironment.GetSystemVersion()[1] == '4';
|
||||
ModuleHandle hnd = m.ModuleHandle;
|
||||
if (ver)
|
||||
{
|
||||
ulong* str = stackalloc ulong[1];
|
||||
str[0] = 0x0061746144705f6d; //m_pData.
|
||||
moduleHnd = (IntPtr)m.GetType().GetField(new string((sbyte*)str), BindingFlags.NonPublic | BindingFlags.Instance).GetValue(m);
|
||||
}
|
||||
else
|
||||
moduleHnd = *(IntPtr*)(&hnd);
|
||||
|
||||
|
||||
Init();
|
||||
Hook();
|
||||
}
|
||||
|
||||
#region JIT internal
|
||||
|
||||
static bool hasLinkInfo;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct ICorJitInfo
|
||||
{
|
||||
public IntPtr* vfptr;
|
||||
public int* vbptr;
|
||||
|
||||
public static ICorDynamicInfo* ICorDynamicInfo(ICorJitInfo* ptr)
|
||||
{
|
||||
hasLinkInfo = ptr->vbptr[10] > 0 && ptr->vbptr[10] >> 16 == 0; // != 0 and hiword byte == 0
|
||||
return (ICorDynamicInfo*)((byte*)&ptr->vbptr + ptr->vbptr[hasLinkInfo ? 10 : 9]);
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct ICorDynamicInfo
|
||||
{
|
||||
public IntPtr* vfptr;
|
||||
public int* vbptr;
|
||||
|
||||
public static ICorStaticInfo* ICorStaticInfo(ICorDynamicInfo* ptr)
|
||||
{
|
||||
return (ICorStaticInfo*)((byte*)&ptr->vbptr + ptr->vbptr[hasLinkInfo ? 9 : 8]);
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct ICorStaticInfo
|
||||
{
|
||||
public IntPtr* vfptr;
|
||||
public int* vbptr;
|
||||
|
||||
public static ICorMethodInfo* ICorMethodInfo(ICorStaticInfo* ptr)
|
||||
{
|
||||
return (ICorMethodInfo*)((byte*)&ptr->vbptr + ptr->vbptr[1]);
|
||||
}
|
||||
public static ICorModuleInfo* ICorModuleInfo(ICorStaticInfo* ptr)
|
||||
{
|
||||
return (ICorModuleInfo*)((byte*)&ptr->vbptr + ptr->vbptr[2]);
|
||||
}
|
||||
public static ICorClassInfo* ICorClassInfo(ICorStaticInfo* ptr)
|
||||
{
|
||||
return (ICorClassInfo*)((byte*)&ptr->vbptr + ptr->vbptr[3]);
|
||||
}
|
||||
public static ICorFieldInfo* ICorFieldInfo(ICorStaticInfo* ptr)
|
||||
{
|
||||
return (ICorFieldInfo*)((byte*)&ptr->vbptr + ptr->vbptr[4]);
|
||||
}
|
||||
public static ICorDebugInfo* ICorDebugInfo(ICorStaticInfo* ptr)
|
||||
{
|
||||
return (ICorDebugInfo*)((byte*)&ptr->vbptr + ptr->vbptr[5]);
|
||||
}
|
||||
public static ICorArgInfo* ICorArgInfo(ICorStaticInfo* ptr)
|
||||
{
|
||||
return (ICorArgInfo*)((byte*)&ptr->vbptr + ptr->vbptr[6]);
|
||||
}
|
||||
public static ICorLinkInfo* ICorLinkInfo(ICorStaticInfo* ptr)
|
||||
{
|
||||
return (ICorLinkInfo*)((byte*)&ptr->vbptr + ptr->vbptr[7]);
|
||||
}
|
||||
public static ICorErrorInfo* ICorErrorInfo(ICorStaticInfo* ptr)
|
||||
{
|
||||
return (ICorErrorInfo*)((byte*)&ptr->vbptr + ptr->vbptr[hasLinkInfo ? 8 : 7]);
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct ICorMethodInfo
|
||||
{
|
||||
public IntPtr* vfptr;
|
||||
}
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct ICorModuleInfo
|
||||
{
|
||||
public IntPtr* vfptr;
|
||||
}
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct ICorClassInfo
|
||||
{
|
||||
public IntPtr* vfptr;
|
||||
}
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct ICorFieldInfo
|
||||
{
|
||||
public IntPtr* vfptr;
|
||||
}
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct ICorDebugInfo
|
||||
{
|
||||
public IntPtr* vfptr;
|
||||
}
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct ICorArgInfo
|
||||
{
|
||||
public IntPtr* vfptr;
|
||||
}
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct ICorLinkInfo
|
||||
{
|
||||
public IntPtr* vfptr;
|
||||
}
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct ICorErrorInfo
|
||||
{
|
||||
public IntPtr* vfptr;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct CORINFO_METHOD_INFO
|
||||
{
|
||||
public IntPtr ftn;
|
||||
public IntPtr scope;
|
||||
public byte* ILCode;
|
||||
public uint ILCodeSize;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct CORINFO_SIG_INST_x86
|
||||
{
|
||||
public uint classInstCount;
|
||||
public IntPtr* classInst;
|
||||
public uint methInstCount;
|
||||
public IntPtr* methInst;
|
||||
}
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct CORINFO_SIG_INST_x64
|
||||
{
|
||||
public uint classInstCount;
|
||||
uint pad1;
|
||||
public IntPtr* classInst;
|
||||
public uint methInstCount;
|
||||
uint pad2;
|
||||
public IntPtr* methInst;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct CORINFO_SIG_INFO_x86
|
||||
{
|
||||
public uint callConv;
|
||||
public IntPtr retTypeClass;
|
||||
public IntPtr retTypeSigClass;
|
||||
public byte retType;
|
||||
public byte flags;
|
||||
public ushort numArgs;
|
||||
public CORINFO_SIG_INST_x86 sigInst;
|
||||
public IntPtr args;
|
||||
public IntPtr sig;
|
||||
public IntPtr scope;
|
||||
public uint token;
|
||||
}
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct CORINFO_SIG_INFO_x64
|
||||
{
|
||||
public uint callConv;
|
||||
uint pad1;
|
||||
public IntPtr retTypeClass;
|
||||
public IntPtr retTypeSigClass;
|
||||
public byte retType;
|
||||
public byte flags;
|
||||
public ushort numArgs;
|
||||
uint pad2;
|
||||
public CORINFO_SIG_INST_x64 sigInst;
|
||||
public IntPtr args;
|
||||
public IntPtr sig;
|
||||
public IntPtr scope;
|
||||
public uint token;
|
||||
uint pad3;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x18)]
|
||||
struct CORINFO_EH_CLAUSE
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct MethodData
|
||||
{
|
||||
public uint ILCodeSize;
|
||||
public uint MaxStack;
|
||||
public uint EHCount;
|
||||
public uint LocalVars;
|
||||
public uint Options;
|
||||
public uint MulSeed;
|
||||
}
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
|
||||
delegate uint compileMethod(IntPtr self, ICorJitInfo* comp, CORINFO_METHOD_INFO* info, uint flags, byte** nativeEntry, uint* nativeSizeOfCode);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
delegate void getEHinfo(IntPtr self, IntPtr ftn, uint EHnumber, CORINFO_EH_CLAUSE* clause);
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
|
||||
delegate uint getMethodDefFromMethod(IntPtr self, IntPtr ftn);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
static extern IntPtr LoadLibrary(string lib);
|
||||
[DllImport("kernel32.dll")]
|
||||
static extern IntPtr GetProcAddress(IntPtr lib, string proc);
|
||||
[DllImport("kernel32.dll")]
|
||||
static extern bool VirtualProtect(IntPtr lpAddress, uint dwSize, uint flNewProtect, out uint lpflOldProtect);
|
||||
|
||||
delegate IntPtr* getJit();
|
||||
|
||||
static IntPtr hookPosition;
|
||||
static IntPtr original;
|
||||
static compileMethod originalDelegate;
|
||||
|
||||
static bool ver;
|
||||
static void Init()
|
||||
{
|
||||
ulong* ptr = stackalloc ulong[2];
|
||||
if (ver)
|
||||
{
|
||||
ptr[0] = 0x642e74696a726c63; //clrjit.d
|
||||
ptr[1] = 0x0000000000006c6c; //ll......
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr[0] = 0x74696a726f63736d; //mscorjit
|
||||
ptr[1] = 0x000000006c6c642e; //.dll....
|
||||
}
|
||||
IntPtr jit = LoadLibrary(new string((sbyte*)ptr));
|
||||
ptr[0] = 0x000074694a746567; //getJit
|
||||
getJit get = (getJit)Marshal.GetDelegateForFunctionPointer(GetProcAddress(jit, new string((sbyte*)ptr)), typeof(getJit));
|
||||
hookPosition = *get();
|
||||
original = *(IntPtr*)hookPosition;
|
||||
|
||||
IntPtr trampoline;
|
||||
if (IntPtr.Size == 8)
|
||||
{
|
||||
trampoline = Marshal.AllocHGlobal(16);
|
||||
ulong* tptr = (ulong*)trampoline;
|
||||
tptr[0] = 0xffffffffffffb848;
|
||||
tptr[1] = 0x90909090e0ffffff;
|
||||
|
||||
uint oldPl;
|
||||
VirtualProtect(trampoline, 12, 0x40, out oldPl);
|
||||
Marshal.WriteIntPtr(trampoline, 2, original);
|
||||
}
|
||||
else
|
||||
{
|
||||
trampoline = Marshal.AllocHGlobal(8);
|
||||
ulong* tptr = (ulong*)trampoline;
|
||||
tptr[0] = 0x90e0ffffffffffb8;
|
||||
|
||||
uint oldPl;
|
||||
VirtualProtect(trampoline, 7, 0x40, out oldPl);
|
||||
Marshal.WriteIntPtr(trampoline, 1, original);
|
||||
}
|
||||
|
||||
originalDelegate = (compileMethod)Marshal.GetDelegateForFunctionPointer(trampoline, typeof(compileMethod));
|
||||
RuntimeHelpers.PrepareDelegate(originalDelegate);
|
||||
}
|
||||
|
||||
static compileMethod handler;
|
||||
static void Hook()
|
||||
{
|
||||
handler = new compileMethod(HookHandler);
|
||||
RuntimeHelpers.PrepareDelegate(handler);
|
||||
|
||||
uint oldPl;
|
||||
VirtualProtect(hookPosition, (uint)IntPtr.Size, 0x40, out oldPl);
|
||||
Marshal.WriteIntPtr(hookPosition, Marshal.GetFunctionPointerForDelegate(handler));
|
||||
VirtualProtect(hookPosition, (uint)IntPtr.Size, oldPl, out oldPl);
|
||||
}
|
||||
|
||||
class CorMethodInfoHook
|
||||
{
|
||||
public IntPtr ftn;
|
||||
public ICorMethodInfo* info;
|
||||
public ICorJitInfo* comp;
|
||||
public IntPtr* oriVfTbl;
|
||||
public IntPtr* newVfTbl;
|
||||
|
||||
public CORINFO_EH_CLAUSE* clauses;
|
||||
public getEHinfo o_getEHinfo;
|
||||
public getEHinfo n_getEHinfo;
|
||||
|
||||
void hookEHInfo(IntPtr self, IntPtr ftn, uint EHnumber, CORINFO_EH_CLAUSE* clause)
|
||||
{
|
||||
if (ftn == this.ftn)
|
||||
{
|
||||
*clause = clauses[EHnumber];
|
||||
}
|
||||
else
|
||||
{
|
||||
o_getEHinfo(self, ftn, EHnumber, clause);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Marshal.FreeHGlobal((IntPtr)newVfTbl);
|
||||
info->vfptr = oriVfTbl;
|
||||
}
|
||||
|
||||
static int ehNum = -1;
|
||||
public static CorMethodInfoHook Hook(ICorJitInfo* comp, IntPtr ftn, CORINFO_EH_CLAUSE* clauses)
|
||||
{
|
||||
ICorMethodInfo* mtdInfo = ICorStaticInfo.ICorMethodInfo(ICorDynamicInfo.ICorStaticInfo(ICorJitInfo.ICorDynamicInfo(comp)));
|
||||
IntPtr* vfTbl = mtdInfo->vfptr;
|
||||
const int SLOT_NUM = 0x1B;
|
||||
IntPtr* newVfTbl = (IntPtr*)Marshal.AllocHGlobal(SLOT_NUM * IntPtr.Size);
|
||||
for (int i = 0; i < SLOT_NUM; i++)
|
||||
newVfTbl[i] = vfTbl[i];
|
||||
if (ehNum == -1)
|
||||
for (int i = 0; i < SLOT_NUM; i++)
|
||||
{
|
||||
bool isEh = true;
|
||||
for (byte* func = (byte*)vfTbl[i]; *func != 0xe9; func++)
|
||||
if (IntPtr.Size == 8 ?
|
||||
(*func == 0x48 && *(func + 1) == 0x81 && *(func + 2) == 0xe9) :
|
||||
(*func == 0x83 && *(func + 1) == 0xe9))
|
||||
{
|
||||
isEh = false;
|
||||
break;
|
||||
}
|
||||
if (isEh)
|
||||
{
|
||||
ehNum = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CorMethodInfoHook ret = new CorMethodInfoHook()
|
||||
{
|
||||
ftn = ftn,
|
||||
info = mtdInfo,
|
||||
comp = comp,
|
||||
clauses = clauses,
|
||||
newVfTbl = newVfTbl,
|
||||
oriVfTbl = vfTbl
|
||||
};
|
||||
|
||||
ret.n_getEHinfo = new getEHinfo(ret.hookEHInfo);
|
||||
ret.o_getEHinfo = (getEHinfo)Marshal.GetDelegateForFunctionPointer(vfTbl[ehNum], typeof(getEHinfo));
|
||||
newVfTbl[ehNum] = Marshal.GetFunctionPointerForDelegate(ret.n_getEHinfo);
|
||||
|
||||
mtdInfo->vfptr = newVfTbl;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
static void ExtractLocalVars(CORINFO_METHOD_INFO* info, uint len, byte* localVar)
|
||||
{
|
||||
void* sigInfo;
|
||||
if (ver)
|
||||
{
|
||||
if (IntPtr.Size == 8)
|
||||
sigInfo = (CORINFO_SIG_INFO_x64*)((uint*)(info + 1) + 5) + 1;
|
||||
else
|
||||
sigInfo = (CORINFO_SIG_INFO_x86*)((uint*)(info + 1) + 4) + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IntPtr.Size == 8)
|
||||
sigInfo = (CORINFO_SIG_INFO_x64*)((uint*)(info + 1) + 3) + 1;
|
||||
else
|
||||
sigInfo = (CORINFO_SIG_INFO_x86*)((uint*)(info + 1) + 3) + 1;
|
||||
}
|
||||
|
||||
if (IntPtr.Size == 8)
|
||||
((CORINFO_SIG_INFO_x64*)sigInfo)->sig = (IntPtr)localVar;
|
||||
else
|
||||
((CORINFO_SIG_INFO_x86*)sigInfo)->sig = (IntPtr)localVar;
|
||||
localVar++;
|
||||
byte b = *localVar;
|
||||
ushort numArgs;
|
||||
IntPtr args;
|
||||
if ((b & 0x80) == 0)
|
||||
{
|
||||
numArgs = b;
|
||||
args = (IntPtr)(localVar + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
numArgs = (ushort)(((uint)(b & ~0x80) << 8) | *(localVar + 1));
|
||||
args = (IntPtr)(localVar + 2);
|
||||
}
|
||||
|
||||
if (IntPtr.Size == 8)
|
||||
{
|
||||
CORINFO_SIG_INFO_x64* sigInfox64 = (CORINFO_SIG_INFO_x64*)sigInfo;
|
||||
sigInfox64->callConv = 0;
|
||||
sigInfox64->retType = 1;
|
||||
sigInfox64->flags = 1;
|
||||
sigInfox64->numArgs = numArgs;
|
||||
sigInfox64->args = args;
|
||||
}
|
||||
else
|
||||
{
|
||||
CORINFO_SIG_INFO_x86* sigInfox86 = (CORINFO_SIG_INFO_x86*)sigInfo;
|
||||
sigInfox86->callConv = 0;
|
||||
sigInfox86->retType = 1;
|
||||
sigInfox86->flags = 1;
|
||||
sigInfox86->numArgs = numArgs;
|
||||
sigInfox86->args = args;
|
||||
}
|
||||
}
|
||||
|
||||
static uint HookHandler(IntPtr self, ICorJitInfo* comp, CORINFO_METHOD_INFO* info, uint flags, byte** nativeEntry, uint* nativeSizeOfCode)
|
||||
{
|
||||
var sigInfo = (CORINFO_SIG_INFO_x86*)((uint*)(info + 1) + 4);
|
||||
|
||||
if (info != null &&
|
||||
info->scope == moduleHnd &&
|
||||
info->ILCode[0] == 0x14)
|
||||
{
|
||||
var clsInfo = ICorStaticInfo.ICorClassInfo(ICorDynamicInfo.ICorStaticInfo(ICorJitInfo.ICorDynamicInfo(comp)));
|
||||
int gmdSlot = 12 + (ver ? 2 : IntPtr.Size / 4);
|
||||
var getMethodDef = (getMethodDefFromMethod)Marshal.GetDelegateForFunctionPointer(clsInfo->vfptr[gmdSlot], typeof(getMethodDefFromMethod));
|
||||
uint token = getMethodDef((IntPtr)clsInfo, info->ftn);
|
||||
|
||||
uint lo = 0, hi = len;
|
||||
uint? offset = null;
|
||||
while (hi >= lo)
|
||||
{
|
||||
uint mid = lo + ((hi - lo) >> 1);
|
||||
uint midTok = *(ptr + (mid << 1));
|
||||
if (midTok == token)
|
||||
{
|
||||
offset = *(ptr + (mid << 1) + 1);
|
||||
break;
|
||||
}
|
||||
else if (midTok < token)
|
||||
lo = mid + 1;
|
||||
else
|
||||
hi = mid - 1;
|
||||
}
|
||||
if (offset == null)
|
||||
return originalDelegate(self, comp, info, flags, nativeEntry, nativeSizeOfCode);
|
||||
|
||||
uint* dataPtr = ptr + (uint)offset;
|
||||
uint dataLen = *dataPtr++;
|
||||
uint* newPtr = (uint*)Marshal.AllocHGlobal((int)dataLen << 2);
|
||||
try
|
||||
{
|
||||
MethodData* data = (MethodData*)newPtr;
|
||||
uint* copyData = newPtr;
|
||||
|
||||
uint state = token * (uint)Mutation.KeyI0;
|
||||
uint counter = state;
|
||||
for (uint i = 0; i < dataLen; i++)
|
||||
{
|
||||
*copyData = *dataPtr++ ^ state;
|
||||
state += (*copyData++) ^ counter;
|
||||
counter ^= (state >> 5) | (state << 27);
|
||||
}
|
||||
|
||||
info->ILCodeSize = data->ILCodeSize;
|
||||
RuntimeMethodHandle rmh;
|
||||
*(IntPtr*)(&rmh) = info->ftn;
|
||||
if (ver)
|
||||
{
|
||||
*((uint*)(info + 1) + 0) = data->MaxStack;
|
||||
*((uint*)(info + 1) + 1) = data->EHCount;
|
||||
*((uint*)(info + 1) + 2) = data->Options;
|
||||
}
|
||||
else
|
||||
{
|
||||
*((ushort*)(info + 1) + 0) = (ushort)data->MaxStack;
|
||||
*((ushort*)(info + 1) + 1) = (ushort)data->EHCount;
|
||||
*((uint*)(info + 1) + 1) = data->Options;
|
||||
}
|
||||
|
||||
byte* body = (byte*)(data + 1);
|
||||
|
||||
info->ILCode = body;
|
||||
body += info->ILCodeSize;
|
||||
|
||||
if (data->LocalVars != 0)
|
||||
{
|
||||
ExtractLocalVars(info, data->LocalVars, body);
|
||||
body += data->LocalVars;
|
||||
}
|
||||
|
||||
CORINFO_EH_CLAUSE* ehPtr = (CORINFO_EH_CLAUSE*)body;
|
||||
|
||||
var hook1 = CorMethodInfoHook.Hook(comp, info->ftn, ehPtr);
|
||||
uint ret = originalDelegate(self, comp, info, flags, nativeEntry, nativeSizeOfCode);
|
||||
hook1.Dispose();
|
||||
|
||||
return ret;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal((IntPtr)newPtr);
|
||||
}
|
||||
}
|
||||
else
|
||||
return originalDelegate(self, comp, info, flags, nativeEntry, nativeSizeOfCode);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -42,6 +42,7 @@
|
|||
<Compile Include="antinet\HandleProcessCorruptedStateExceptionsAttribute.cs" />
|
||||
<Compile Include="antinet\PEInfo.cs" />
|
||||
<Compile Include="Constant.cs" />
|
||||
<Compile Include="AntiTamper.JIT.cs" />
|
||||
<Compile Include="Lzma.cs" />
|
||||
<Compile Include="Mutation.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
|
|
Загрузка…
Ссылка в новой задаче