修复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.Emit;
using Obfuz.Utils; using Obfuz.Utils;
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net.NetworkInformation; using System.Net.NetworkInformation;
@ -17,7 +18,7 @@ namespace Obfuz.Data
public class ModuleConstFieldAllocator : IGroupByModuleEntity public class ModuleConstFieldAllocator : IGroupByModuleEntity
{ {
private ModuleDef _module; private ModuleDef _module;
private readonly IRandom _random; private readonly RandomCreator _randomCreator;
private readonly IEncryptor _encryptor; private readonly IEncryptor _encryptor;
private readonly RvaDataAllocator _rvaDataAllocator; private readonly RvaDataAllocator _rvaDataAllocator;
private readonly GroupByModuleEntityManager _moduleEntityManager; private readonly GroupByModuleEntityManager _moduleEntityManager;
@ -29,17 +30,40 @@ namespace Obfuz.Data
public FieldDef field; public FieldDef field;
public object value; 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 Dictionary<FieldDef, ConstFieldInfo> _field2Fields = new Dictionary<FieldDef, ConstFieldInfo>();
private readonly List<TypeDef> _holderTypeDefs = new List<TypeDef>(); private readonly List<TypeDef> _holderTypeDefs = new List<TypeDef>();
private bool _done; 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; _encryptor = encryptor;
_random = random; _randomCreator = randomCreator;
_rvaDataAllocator = rvaDataAllocator; _rvaDataAllocator = rvaDataAllocator;
_moduleEntityManager = moduleEntityManager; _moduleEntityManager = moduleEntityManager;
} }
@ -135,16 +159,6 @@ namespace Obfuz.Data
return AllocateAny(value); return AllocateAny(value);
} }
private int GenerateEncryptionOperations()
{
return _random.NextInt();
}
public int GenerateSalt()
{
return _random.NextInt();
}
private DefaultMetadataImporter GetModuleMetadataImporter() private DefaultMetadataImporter GetModuleMetadataImporter()
{ {
return _moduleEntityManager.GetDefaultModuleMetadataImporter(_module); return _moduleEntityManager.GetDefaultModuleMetadataImporter(_module);
@ -171,8 +185,9 @@ namespace Obfuz.Data
foreach (var field in type.Fields) foreach (var field in type.Fields)
{ {
ConstFieldInfo constInfo = _field2Fields[field]; ConstFieldInfo constInfo = _field2Fields[field];
int ops = GenerateEncryptionOperations(); IRandom localRandom = _randomCreator(HashUtil.ComputePrimitiveOrStringOrBytesHashCode(constInfo.value));
int salt = GenerateSalt(); int ops = EncryptionUtil.GenerateEncryptionOpCodes(localRandom, _encryptor, 4);
int salt = localRandom.NextInt();
switch (constInfo.value) switch (constInfo.value)
{ {
case int i: case int i:
@ -221,13 +236,12 @@ namespace Obfuz.Data
} }
case string s: case string s:
{ {
int stringByteLength = Encoding.UTF8.GetByteCount(s);
byte[] encryptedValue = _encryptor.Encrypt(s, ops, salt); byte[] encryptedValue = _encryptor.Encrypt(s, ops, salt);
RvaData rvaData = _rvaDataAllocator.Allocate(_module, encryptedValue); RvaData rvaData = _rvaDataAllocator.Allocate(_module, encryptedValue);
ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
ins.Add(Instruction.CreateLdcI4(rvaData.offset)); 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. Assert.AreEqual(encryptedValue.Length, rvaData.size);
ins.Add(Instruction.CreateLdcI4(stringByteLength)); ins.Add(Instruction.CreateLdcI4(encryptedValue.Length));
ins.Add(Instruction.CreateLdcI4(ops)); ins.Add(Instruction.CreateLdcI4(ops));
ins.Add(Instruction.CreateLdcI4(salt)); ins.Add(Instruction.CreateLdcI4(salt));
ins.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaString)); ins.Add(Instruction.Create(OpCodes.Call, importer.DecryptFromRvaString));
@ -236,10 +250,10 @@ namespace Obfuz.Data
case byte[] bs: case byte[] bs:
{ {
byte[] encryptedValue = _encryptor.Encrypt(bs, 0, bs.Length, ops, salt); byte[] encryptedValue = _encryptor.Encrypt(bs, 0, bs.Length, ops, salt);
Assert.AreEqual(encryptedValue.Length, bs.Length);
RvaData rvaData = _rvaDataAllocator.Allocate(_module, encryptedValue); RvaData rvaData = _rvaDataAllocator.Allocate(_module, encryptedValue);
ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field)); ins.Add(Instruction.Create(OpCodes.Ldsfld, rvaData.field));
ins.Add(Instruction.CreateLdcI4(rvaData.offset)); 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(bs.Length));
ins.Add(Instruction.CreateLdcI4(ops)); ins.Add(Instruction.CreateLdcI4(ops));
ins.Add(Instruction.CreateLdcI4(salt)); ins.Add(Instruction.CreateLdcI4(salt));
@ -270,21 +284,21 @@ namespace Obfuz.Data
public class ConstFieldAllocator public class ConstFieldAllocator
{ {
private readonly IEncryptor _encryptor; private readonly IEncryptor _encryptor;
private readonly IRandom _random; private readonly RandomCreator _randomCreator;
private readonly RvaDataAllocator _rvaDataAllocator; private readonly RvaDataAllocator _rvaDataAllocator;
private readonly GroupByModuleEntityManager _moduleEntityManager; 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; _encryptor = encryptor;
_random = random; _randomCreator = randomCreator;
_rvaDataAllocator = rvaDataAllocator; _rvaDataAllocator = rvaDataAllocator;
_moduleEntityManager = moduleEntityManager; _moduleEntityManager = moduleEntityManager;
} }
private ModuleConstFieldAllocator GetModuleAllocator(ModuleDef mod) 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) 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 encryptedValue = _opCodes[i].Encrypt(value, _secretKey, i);
int decryptedValue = _opCodes[i].Decrypt(encryptedValue, _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); Assert.AreEqual(value, decryptedValue);
} }

View File

@ -128,7 +128,17 @@ namespace Obfuz
var gvmInstance = (IEncryptor)Activator.CreateInstance(generatedVmTypes[0], new object[] { _byteSecret } ); 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"; string testString = "hello,world";
for (int i = 0; i < vm.opCodes.Length; i++) for (int i = 0; i < vm.opCodes.Length; i++)
{ {
@ -136,42 +146,98 @@ namespace Obfuz
//int salt = i; //int salt = i;
//int ops = -1135538782; //int ops = -1135538782;
int salt = -879409147; 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(testInt, ops, salt);
int decryptedValueOfGvm = gvmInstance.Decrypt(encryptedValueOfGvm, ops, salt);
if (encryptedValueOfGvm != encryptedIntOfVms)
{
throw new Exception($"encryptedValue not match! opCode:{i}, originalValue:{testInt} encryptedValue VirtualMachineSimulator:{encryptedIntOfVms} GeneratedEncryptionVirtualMachine:{encryptedValueOfGvm}");
}
if (decryptedValueOfGvm != testInt)
{
throw new Exception($"GeneratedEncryptionVirtualMachine decrypt failed! opCode:{i}, originalValue:{testInt} decryptedValue:{decryptedValueOfGvm}");
}
} }
int encryptedValueOfGvm = gvmInstance.Encrypt(testValue, ops, salt);
int decryptedValueOfGvm = gvmInstance.Decrypt(encryptedValueOfGvm, ops, salt);
if (encryptedValueOfGvm != encryptedValueOfVms)
{ {
throw new Exception($"encryptedValue not match! opCode:{i}, originalValue:{testValue} encryptedValue VirtualMachineSimulator:{encryptedValueOfVms} GeneratedEncryptionVirtualMachine:{encryptedValueOfGvm}"); 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}");
}
} }
if (decryptedValueOfGvm != testValue)
{ {
throw new Exception($"GeneratedEncryptionVirtualMachine decrypt failed! opCode:{i}, originalValue:{testValue} 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)
{ {
throw new Exception($"VirtualMachineSimulator decrypt string failed! opCode:{i}, originalValue:{testString} decryptedValue:{descryptedStrOfVms}"); byte[] encryptedStrOfVms = vms.Encrypt(testString, ops, salt);
} string descryptedStrOfVms = vms.DecryptString(encryptedStrOfVms, 0, encryptedStrOfVms.Length, ops, salt);
byte[] encryptedStrOfGvm = gvmInstance.Encrypt(testString, ops, salt); if (descryptedStrOfVms != testString)
string descryptedStrOfGvm = gvmInstance.DecryptString(encryptedStrOfGvm, 0, encryptedStrOfGvm.Length, ops, salt); {
if (!encryptedStrOfGvm.SequenceEqual(encryptedStrOfVms)) throw new Exception($"VirtualMachineSimulator decrypt string failed! opCode:{i}, originalValue:{testString} decryptedValue:{descryptedStrOfVms}");
{ }
throw new Exception($"encryptedValue not match! opCode:{i}, originalValue:{testString} encryptedValue VirtualMachineSimulator:{encryptedStrOfVms} GeneratedEncryptionVirtualMachine:{encryptedStrOfGvm}"); byte[] encryptedStrOfGvm = gvmInstance.Encrypt(testString, ops, salt);
} string descryptedStrOfGvm = gvmInstance.DecryptString(encryptedStrOfGvm, 0, encryptedStrOfGvm.Length, ops, salt);
if (descryptedStrOfGvm != testString) if (!encryptedStrOfGvm.SequenceEqual(encryptedStrOfVms))
{ {
throw new Exception($"GeneratedEncryptionVirtualMachine decrypt string failed! opCode:{i}, originalValue:{testString} decryptedValue:{descryptedStrOfGvm}"); throw new Exception($"encryptedValue not match! opCode:{i}, originalValue:{testString} encryptedValue VirtualMachineSimulator:{encryptedStrOfVms} GeneratedEncryptionVirtualMachine:{encryptedStrOfGvm}");
}
if (descryptedStrOfGvm != testString)
{
throw new Exception($"GeneratedEncryptionVirtualMachine decrypt string failed! opCode:{i}, originalValue:{testString} decryptedValue:{descryptedStrOfGvm}");
}
} }
} }
return vms;
} }
private void OnPreObfuscation(Pipeline pipeline) private void OnPreObfuscation(Pipeline pipeline)
@ -182,10 +248,11 @@ namespace Obfuz
LoadAssemblies(assemblyCache, toObfuscatedModules, obfuscatedAndNotObfuscatedModules); LoadAssemblies(assemblyCache, toObfuscatedModules, obfuscatedAndNotObfuscatedModules);
var random = new RandomWithKey(_intSecret, _randomSeed); var random = new RandomWithKey(_intSecret, _randomSeed);
RandomCreator localRandomCreator = (seed) => new RandomWithKey(_intSecret, _randomSeed ^ seed);
var encryptor = CreateEncryptionVirtualMachine(); var encryptor = CreateEncryptionVirtualMachine();
var moduleEntityManager = new GroupByModuleEntityManager(); var moduleEntityManager = new GroupByModuleEntityManager();
var rvaDataAllocator = new RvaDataAllocator(random, encryptor, moduleEntityManager); 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 _ctx = new ObfuscationPassContext
{ {
assemblyCache = assemblyCache, assemblyCache = assemblyCache,
@ -197,7 +264,7 @@ namespace Obfuz
moduleEntityManager = moduleEntityManager, moduleEntityManager = moduleEntityManager,
globalRandom = random, globalRandom = random,
localRandomCreator = (seed) => new RandomWithKey(_intSecret, _randomSeed ^ seed), localRandomCreator = localRandomCreator,
encryptor = encryptor, encryptor = encryptor,
rvaDataAllocator = rvaDataAllocator, rvaDataAllocator = rvaDataAllocator,
constFieldAllocator = constFieldAllocator, constFieldAllocator = constFieldAllocator,

View File

@ -1,5 +1,6 @@
using dnlib.DotNet; using dnlib.DotNet;
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@ -49,5 +50,18 @@ namespace Obfuz.Utils
return num + num2 * 1566083941; 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) 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); return Decrypt(encryptedValue, ops, salt);
} }
public static double DecryptFromRvaDouble(byte[] data, int offset, int ops, int 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); return Decrypt(encryptedValue, ops, salt);
} }