added JIT anti tamper protection

This commit is contained in:
yck1509 2014-05-14 18:49:14 +08:00
Родитель a4c44faa1c
Коммит 8ece9c8533
8 изменённых файлов: 1190 добавлений и 1 удалений

Просмотреть файл

@ -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())
{
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" />