修复float加密的bug

backup
walon 2025-05-14 14:36:25 +08:00
parent 78b08a9069
commit 334ff8095f
5 changed files with 151 additions and 56 deletions

View File

@ -4,6 +4,7 @@ using Obfuz.Editor;
using Obfuz.Emit;
using Obfuz.Utils;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
@ -17,7 +18,7 @@ namespace Obfuz.Data
public class ModuleConstFieldAllocator : IGroupByModuleEntity
{
private ModuleDef _module;
private readonly IRandom _random;
private readonly RandomCreator _randomCreator;
private readonly IEncryptor _encryptor;
private readonly RvaDataAllocator _rvaDataAllocator;
private readonly GroupByModuleEntityManager _moduleEntityManager;
@ -29,17 +30,40 @@ namespace Obfuz.Data
public FieldDef field;
public object value;
}
private readonly Dictionary<object, ConstFieldInfo> _allocatedFields = new Dictionary<object, ConstFieldInfo>();
class AnyComparer : IEqualityComparer<object>
{
public new bool Equals(object x, object y)
{
if (x is byte[] xBytes && y is byte[] yBytes)
{
return StructuralComparisons.StructuralEqualityComparer.Equals(xBytes, yBytes);
}
return x.Equals(y);
}
public static int ComputeHashCode(object obj)
{
return HashUtil.ComputePrimitiveOrStringOrBytesHashCode(obj);
}
public int GetHashCode(object obj)
{
return ComputeHashCode(obj);
}
}
private readonly Dictionary<object, ConstFieldInfo> _allocatedFields = new Dictionary<object, ConstFieldInfo>(new AnyComparer());
private readonly Dictionary<FieldDef, ConstFieldInfo> _field2Fields = new Dictionary<FieldDef, ConstFieldInfo>();
private readonly List<TypeDef> _holderTypeDefs = new List<TypeDef>();
private bool _done;
public ModuleConstFieldAllocator(IEncryptor encryptor, IRandom random, RvaDataAllocator rvaDataAllocator, GroupByModuleEntityManager moduleEntityManager)
public ModuleConstFieldAllocator(IEncryptor encryptor, RandomCreator randomCreator, RvaDataAllocator rvaDataAllocator, GroupByModuleEntityManager moduleEntityManager)
{
_encryptor = encryptor;
_random = random;
_randomCreator = randomCreator;
_rvaDataAllocator = rvaDataAllocator;
_moduleEntityManager = moduleEntityManager;
}
@ -135,16 +159,6 @@ namespace Obfuz.Data
return AllocateAny(value);
}
private int GenerateEncryptionOperations()
{
return _random.NextInt();
}
public int GenerateSalt()
{
return _random.NextInt();
}
private DefaultMetadataImporter GetModuleMetadataImporter()
{
return _moduleEntityManager.GetDefaultModuleMetadataImporter(_module);
@ -171,8 +185,9 @@ namespace Obfuz.Data
foreach (var field in type.Fields)
{
ConstFieldInfo constInfo = _field2Fields[field];
int ops = GenerateEncryptionOperations();
int salt = GenerateSalt();
IRandom localRandom = _randomCreator(HashUtil.ComputePrimitiveOrStringOrBytesHashCode(constInfo.value));
int ops = EncryptionUtil.GenerateEncryptionOpCodes(localRandom, _encryptor, 4);
int salt = localRandom.NextInt();
switch (constInfo.value)
{
case int i:
@ -221,13 +236,12 @@ namespace Obfuz.Data
}
case string s:
{
int stringByteLength = Encoding.UTF8.GetByteCount(s);
byte[] encryptedValue = _encryptor.Encrypt(s, ops, salt);
RvaData rvaData = _rvaDataAllocator.Allocate(_module, encryptedValue);
ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
ins.Add(Instruction.CreateLdcI4(rvaData.offset));
//// should use stringByteLength, can't use rvaData.size, because rvaData.size is align to 4, it's not the actual length.
ins.Add(Instruction.CreateLdcI4(stringByteLength));
Assert.AreEqual(encryptedValue.Length, rvaData.size);
ins.Add(Instruction.CreateLdcI4(encryptedValue.Length));
ins.Add(Instruction.CreateLdcI4(ops));
ins.Add(Instruction.CreateLdcI4(salt));
ins.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaString));
@ -236,10 +250,10 @@ namespace Obfuz.Data
case byte[] bs:
{
byte[] encryptedValue = _encryptor.Encrypt(bs, 0, bs.Length, ops, salt);
Assert.AreEqual(encryptedValue.Length, bs.Length);
RvaData rvaData = _rvaDataAllocator.Allocate(_module, encryptedValue);
ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
ins.Add(Instruction.CreateLdcI4(rvaData.offset));
//// should use stringByteLength, can't use rvaData.size, because rvaData.size is align to 4, it's not the actual length.
ins.Add(Instruction.CreateLdcI4(bs.Length));
ins.Add(Instruction.CreateLdcI4(ops));
ins.Add(Instruction.CreateLdcI4(salt));
@ -270,21 +284,21 @@ namespace Obfuz.Data
public class ConstFieldAllocator
{
private readonly IEncryptor _encryptor;
private readonly IRandom _random;
private readonly RandomCreator _randomCreator;
private readonly RvaDataAllocator _rvaDataAllocator;
private readonly GroupByModuleEntityManager _moduleEntityManager;
public ConstFieldAllocator(IEncryptor encryptor, IRandom random, RvaDataAllocator rvaDataAllocator, GroupByModuleEntityManager moduleEntityManager)
public ConstFieldAllocator(IEncryptor encryptor, RandomCreator randomCreator, RvaDataAllocator rvaDataAllocator, GroupByModuleEntityManager moduleEntityManager)
{
_encryptor = encryptor;
_random = random;
_randomCreator = randomCreator;
_rvaDataAllocator = rvaDataAllocator;
_moduleEntityManager = moduleEntityManager;
}
private ModuleConstFieldAllocator GetModuleAllocator(ModuleDef mod)
{
return _moduleEntityManager.GetEntity<ModuleConstFieldAllocator>(mod, () => new ModuleConstFieldAllocator(_encryptor, _random, _rvaDataAllocator, _moduleEntityManager));
return _moduleEntityManager.GetEntity<ModuleConstFieldAllocator>(mod, () => new ModuleConstFieldAllocator(_encryptor, _randomCreator, _rvaDataAllocator, _moduleEntityManager));
}
public FieldDef Allocate(ModuleDef mod, int value)

View File

@ -33,7 +33,7 @@ namespace Obfuz.EncryptionVM
{
int encryptedValue = _opCodes[i].Encrypt(value, _secretKey, i);
int decryptedValue = _opCodes[i].Decrypt(encryptedValue, _secretKey, i);
Debug.Log($"instruction type:{_opCodes[i].function.GetType()}");
//Debug.Log($"instruction type:{_opCodes[i].function.GetType()}");
Assert.AreEqual(value, decryptedValue);
}

View File

@ -128,7 +128,17 @@ namespace Obfuz
var gvmInstance = (IEncryptor)Activator.CreateInstance(generatedVmTypes[0], new object[] { _byteSecret } );
int testValue = 11223344;
VerifyVm(vm, vms, gvmInstance);
return vms;
}
private void VerifyVm(VirtualMachine vm, VirtualMachineSimulator vms, IEncryptor gvmInstance)
{
int testInt = 11223344;
long testLong = 1122334455667788L;
float testFloat = 1234f;
double testDouble = 1122334455.0;
string testString = "hello,world";
for (int i = 0; i < vm.opCodes.Length; i++)
{
@ -136,23 +146,80 @@ namespace Obfuz
//int salt = i;
//int ops = -1135538782;
int salt = -879409147;
int encryptedValueOfVms = vms.Encrypt(testValue, ops, salt);
int decryptedValueOfVms = vms.Decrypt(encryptedValueOfVms, ops, salt);
if (decryptedValueOfVms != testValue)
{
throw new Exception($"VirtualMachineSimulator decrypt failed! opCode:{i}, originalValue:{testValue} decryptedValue:{decryptedValueOfVms}");
int encryptedIntOfVms = vms.Encrypt(testInt, ops, salt);
int decryptedIntOfVms = vms.Decrypt(encryptedIntOfVms, ops, salt);
if (decryptedIntOfVms != testInt)
{
throw new Exception($"VirtualMachineSimulator decrypt failed! opCode:{i}, originalValue:{testInt} decryptedValue:{decryptedIntOfVms}");
}
int encryptedValueOfGvm = gvmInstance.Encrypt(testValue, ops, salt);
int encryptedValueOfGvm = gvmInstance.Encrypt(testInt, ops, salt);
int decryptedValueOfGvm = gvmInstance.Decrypt(encryptedValueOfGvm, ops, salt);
if (encryptedValueOfGvm != encryptedValueOfVms)
if (encryptedValueOfGvm != encryptedIntOfVms)
{
throw new Exception($"encryptedValue not match! opCode:{i}, originalValue:{testValue} encryptedValue VirtualMachineSimulator:{encryptedValueOfVms} GeneratedEncryptionVirtualMachine:{encryptedValueOfGvm}");
throw new Exception($"encryptedValue not match! opCode:{i}, originalValue:{testInt} encryptedValue VirtualMachineSimulator:{encryptedIntOfVms} GeneratedEncryptionVirtualMachine:{encryptedValueOfGvm}");
}
if (decryptedValueOfGvm != testValue)
if (decryptedValueOfGvm != testInt)
{
throw new Exception($"GeneratedEncryptionVirtualMachine decrypt failed! opCode:{i}, originalValue:{testValue} decryptedValue:{decryptedValueOfGvm}");
throw new Exception($"GeneratedEncryptionVirtualMachine decrypt failed! opCode:{i}, originalValue:{testInt} decryptedValue:{decryptedValueOfGvm}");
}
}
{
long encryptedLongOfVms = vms.Encrypt(testLong, ops, salt);
long decryptedLongOfVms = vms.Decrypt(encryptedLongOfVms, ops, salt);
if (decryptedLongOfVms != testLong)
{
throw new Exception($"VirtualMachineSimulator decrypt long failed! opCode:{i}, originalValue:{testLong} decryptedValue:{decryptedLongOfVms}");
}
long encryptedValueOfGvm = gvmInstance.Encrypt(testLong, ops, salt);
long decryptedValueOfGvm = gvmInstance.Decrypt(encryptedValueOfGvm, ops, salt);
if (encryptedValueOfGvm != encryptedLongOfVms)
{
throw new Exception($"encryptedValue not match! opCode:{i}, originalValue:{testLong} encryptedValue VirtualMachineSimulator:{encryptedLongOfVms} GeneratedEncryptionVirtualMachine:{encryptedValueOfGvm}");
}
if (decryptedValueOfGvm != testLong)
{
throw new Exception($"GeneratedEncryptionVirtualMachine decrypt long failed! opCode:{i}, originalValue:{testLong} decryptedValue:{decryptedValueOfGvm}");
}
}
{
float encryptedFloatOfVms = vms.Encrypt(testFloat, ops, salt);
float decryptedFloatOfVms = vms.Decrypt(encryptedFloatOfVms, ops, salt);
if (decryptedFloatOfVms != testFloat)
{
throw new Exception("encryptedFloat not match");
}
float encryptedValueOfGvm = gvmInstance.Encrypt(testFloat, ops, salt);
float decryptedValueOfGvm = gvmInstance.Decrypt(encryptedFloatOfVms, ops, salt);
if (encryptedFloatOfVms != encryptedValueOfGvm)
{
throw new Exception($"encryptedValue not match! opCode:{i}, originalValue:{testFloat} encryptedValue");
}
if (decryptedValueOfGvm != testFloat)
{
throw new Exception($"GeneratedEncryptionVirtualMachine decrypt float failed! opCode:{i}, originalValue:{testFloat}");
}
}
{
double encryptedFloatOfVms = vms.Encrypt(testDouble, ops, salt);
double decryptedFloatOfVms = vms.Decrypt(encryptedFloatOfVms, ops, salt);
if (decryptedFloatOfVms != testDouble)
{
throw new Exception("encryptedFloat not match");
}
double encryptedValueOfGvm = gvmInstance.Encrypt(testDouble, ops, salt);
double decryptedValueOfGvm = gvmInstance.Decrypt(encryptedFloatOfVms, ops, salt);
if (encryptedFloatOfVms != encryptedValueOfGvm)
{
throw new Exception($"encryptedValue not match! opCode:{i}, originalValue:{testDouble} encryptedValue");
}
if (decryptedValueOfGvm != testDouble)
{
throw new Exception($"GeneratedEncryptionVirtualMachine decrypt float failed! opCode:{i}, originalValue:{testDouble}");
}
}
{
byte[] encryptedStrOfVms = vms.Encrypt(testString, ops, salt);
string descryptedStrOfVms = vms.DecryptString(encryptedStrOfVms, 0, encryptedStrOfVms.Length, ops, salt);
if (descryptedStrOfVms != testString)
@ -170,8 +237,7 @@ namespace Obfuz
throw new Exception($"GeneratedEncryptionVirtualMachine decrypt string failed! opCode:{i}, originalValue:{testString} decryptedValue:{descryptedStrOfGvm}");
}
}
return vms;
}
}
private void OnPreObfuscation(Pipeline pipeline)
@ -182,10 +248,11 @@ namespace Obfuz
LoadAssemblies(assemblyCache, toObfuscatedModules, obfuscatedAndNotObfuscatedModules);
var random = new RandomWithKey(_intSecret, _randomSeed);
RandomCreator localRandomCreator = (seed) => new RandomWithKey(_intSecret, _randomSeed ^ seed);
var encryptor = CreateEncryptionVirtualMachine();
var moduleEntityManager = new GroupByModuleEntityManager();
var rvaDataAllocator = new RvaDataAllocator(random, encryptor, moduleEntityManager);
var constFieldAllocator = new ConstFieldAllocator(encryptor, random, rvaDataAllocator, moduleEntityManager);
var constFieldAllocator = new ConstFieldAllocator(encryptor, localRandomCreator, rvaDataAllocator, moduleEntityManager);
_ctx = new ObfuscationPassContext
{
assemblyCache = assemblyCache,
@ -197,7 +264,7 @@ namespace Obfuz
moduleEntityManager = moduleEntityManager,
globalRandom = random,
localRandomCreator = (seed) => new RandomWithKey(_intSecret, _randomSeed ^ seed),
localRandomCreator = localRandomCreator,
encryptor = encryptor,
rvaDataAllocator = rvaDataAllocator,
constFieldAllocator = constFieldAllocator,

View File

@ -1,5 +1,6 @@
using dnlib.DotNet;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@ -49,5 +50,18 @@ namespace Obfuz.Utils
return num + num2 * 1566083941;
}
}
public static int ComputePrimitiveOrStringOrBytesHashCode(object obj)
{
if (obj is byte[] bytes)
{
return StructuralComparisons.StructuralEqualityComparer.GetHashCode(bytes);
}
if (obj is string s)
{
return HashUtil.ComputeHash(s);
}
return obj.GetHashCode();
}
}
}

View File

@ -101,13 +101,13 @@ namespace Obfuz
public static float DecryptFromRvaFloat(byte[] data, int offset, int ops, int salt)
{
int encryptedValue = ConstUtility.GetInt(data, offset);
float encryptedValue = ConstUtility.GetFloat(data, offset);
return Decrypt(encryptedValue, ops, salt);
}
public static double DecryptFromRvaDouble(byte[] data, int offset, int ops, int salt)
{
long encryptedValue = ConstUtility.GetLong(data, offset);
double encryptedValue = ConstUtility.GetDouble(data, offset);
return Decrypt(encryptedValue, ops, salt);
}