Decrypt CW encrypted methods

This commit is contained in:
de4dot 2012-05-26 00:52:38 +02:00
parent ec9d911dc5
commit 20452fe964
7 changed files with 523 additions and 0 deletions

View File

@ -107,6 +107,11 @@
<Compile Include="deobfuscators\CodeVeil\Deobfuscator.cs" />
<Compile Include="deobfuscators\CodeVeil\ProxyDelegateFinder.cs" />
<Compile Include="deobfuscators\CodeVeil\TamperDetection.cs" />
<Compile Include="deobfuscators\CodeWall\Deobfuscator.cs" />
<Compile Include="deobfuscators\CodeWall\MethodsDecrypter.cs" />
<Compile Include="deobfuscators\CodeWall\randomc\CRandomMersenne.cs" />
<Compile Include="deobfuscators\CodeWall\randomc\CRandomMother.cs" />
<Compile Include="deobfuscators\CodeWall\KeyGenerator.cs" />
<Compile Include="deobfuscators\ConstantsReader.cs" />
<Compile Include="deobfuscators\CryptoObfuscator\AntiDebugger.cs" />
<Compile Include="deobfuscators\CryptoObfuscator\AssemblyResolver.cs" />

View File

@ -0,0 +1,136 @@
/*
Copyright (C) 2011-2012 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using Mono.Cecil;
using Mono.MyStuff;
using de4dot.blocks;
using de4dot.PE;
namespace de4dot.code.deobfuscators.CodeWall {
public class DeobfuscatorInfo : DeobfuscatorInfoBase {
public const string THE_NAME = "CodeWall";
public const string THE_TYPE = "cw";
public DeobfuscatorInfo()
: base() {
}
public override string Name {
get { return THE_NAME; }
}
public override string Type {
get { return THE_TYPE; }
}
public override IDeobfuscator createDeobfuscator() {
return new Deobfuscator(new Deobfuscator.Options {
ValidNameRegex = validNameRegex.get(),
});
}
protected override IEnumerable<Option> getOptionsInternal() {
return new List<Option>() {
};
}
}
class Deobfuscator : DeobfuscatorBase {
Options options;
MethodsDecrypter methodsDecrypter;
internal class Options : OptionsBase {
}
public override string Type {
get { return DeobfuscatorInfo.THE_TYPE; }
}
public override string TypeLong {
get { return DeobfuscatorInfo.THE_NAME; }
}
public override string Name {
get { return DeobfuscatorInfo.THE_NAME; }
}
public Deobfuscator(Options options)
: base(options) {
this.options = options;
}
protected override int detectInternal() {
int val = 0;
int sum = toInt32(methodsDecrypter.Detected);
if (sum > 0)
val += 100 + 10 * (sum - 1);
return val;
}
protected override void scanForObfuscator() {
methodsDecrypter = new MethodsDecrypter(module);
methodsDecrypter.find();
}
public override bool getDecryptedModule(ref byte[] newFileData, ref DumpedMethods dumpedMethods) {
if (!methodsDecrypter.Detected)
return false;
byte[] fileData = ModuleBytes ?? DeobUtils.readModule(module);
var peImage = new PeImage(fileData);
if (!methodsDecrypter.decrypt(peImage, ref dumpedMethods))
return false;
newFileData = fileData;
return true;
}
public override IDeobfuscator moduleReloaded(ModuleDefinition module) {
var newOne = new Deobfuscator(options);
newOne.setModule(module);
newOne.methodsDecrypter = new MethodsDecrypter(module, methodsDecrypter);
return newOne;
}
public override void deobfuscateBegin() {
base.deobfuscateBegin();
addAssemblyReferenceToBeRemoved(methodsDecrypter.AssemblyNameReference, "Obfuscator decrypter DLL reference");
}
public override void deobfuscateMethodEnd(Blocks blocks) {
methodsDecrypter.deobfuscate(blocks);
base.deobfuscateMethodEnd(blocks);
}
public override void deobfuscateEnd() {
base.deobfuscateEnd();
}
public override IEnumerable<int> getStringDecrypterMethods() {
var list = new List<int>();
//TODO:
return list;
}
}
}

View File

@ -0,0 +1,44 @@
/*
Copyright (C) 2011-2012 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using de4dot.code.deobfuscators.CodeWall.randomc;
namespace de4dot.code.deobfuscators.CodeWall {
class KeyGenerator {
CRandomMersenne mersenne;
CRandomMother mother;
public KeyGenerator(int seed) {
mersenne = new CRandomMersenne(seed);
mother = new CRandomMother(seed);
}
uint random() {
return (mersenne.BRandom() >> 1) ^ (uint)Math.Abs((int)(mother.Random() * int.MinValue));
}
public byte[] generate(int size) {
var key = new byte[size];
for (int i = 0; i < size; i++)
key[i] = (byte)random();
return key;
}
}
}

View File

@ -0,0 +1,167 @@
/*
Copyright (C) 2011-2012 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.MyStuff;
using de4dot.PE;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.CodeWall {
class MethodsDecrypter {
static readonly byte[] newCodeHeader = new byte[6] { 0x2B, 4, 0, 0, 0, 0 };
static readonly byte[] decryptKey = new byte[10] { 0x8D, 0xB5, 0x2C, 0x3A, 0x1F, 0xC7, 0x31, 0xC3, 0xCD, 0x47 };
ModuleDefinition module;
MethodReference initMethod;
public bool Detected {
get { return initMethod != null; }
}
public AssemblyNameReference AssemblyNameReference {
get { return initMethod == null ? null : (AssemblyNameReference)initMethod.DeclaringType.Scope; }
}
public MethodsDecrypter(ModuleDefinition module) {
this.module = module;
}
public MethodsDecrypter(ModuleDefinition module, MethodsDecrypter oldOne) {
this.module = module;
initMethod = lookup(oldOne.initMethod, "Could not find initMethod");
}
T lookup<T>(T def, string errorMessage) where T : MemberReference {
return DeobUtils.lookup(module, def, errorMessage);
}
public void find() {
foreach (var cctor in DeobUtils.getInitCctors(module, 3)) {
if (checkCctor(cctor))
return;
}
}
bool checkCctor(MethodDefinition method) {
if (method == null || method.Body == null)
return false;
foreach (var instr in method.Body.Instructions) {
if (instr.OpCode.Code != Code.Call)
continue;
var calledMethod = instr.Operand as MethodReference;
if (calledMethod == null)
continue;
if (calledMethod.DeclaringType.Scope == module)
return false;
if (calledMethod.FullName != "System.Void Q::X()")
return false;
initMethod = calledMethod;
return true;
}
return false;
}
public bool decrypt(PeImage peImage, ref DumpedMethods dumpedMethods) {
dumpedMethods = new DumpedMethods();
bool decrypted = false;
var metadataTables = peImage.Cor20Header.createMetadataTables();
var methodDef = metadataTables.getMetadataType(MetadataIndex.iMethodDef);
uint methodDefOffset = methodDef.fileOffset;
for (int i = 0; i < methodDef.rows; i++, methodDefOffset += methodDef.totalSize) {
uint bodyRva = peImage.offsetReadUInt32(methodDefOffset);
if (bodyRva == 0)
continue;
uint bodyOffset = peImage.rvaToOffset(bodyRva);
var dm = new DumpedMethod();
dm.token = (uint)(0x06000001 + i);
byte[] code, extraSections;
peImage.Reader.BaseStream.Position = bodyOffset;
var mbHeader = MethodBodyParser.parseMethodBody(peImage.Reader, out code, out extraSections);
if (code.Length < 6 || code[0] != 0x2A || code[1] != 0x2A)
continue;
dm.code = code;
dm.extraSections = extraSections;
int seed = BitConverter.ToInt32(code, 2);
Array.Copy(newCodeHeader, code, newCodeHeader.Length);
if (seed == 0)
decrypt(code);
else
decrypt(code, seed);
dm.mdImplFlags = peImage.offsetReadUInt16(methodDefOffset + (uint)methodDef.fields[1].offset);
dm.mdFlags = peImage.offsetReadUInt16(methodDefOffset + (uint)methodDef.fields[2].offset);
dm.mdName = peImage.offsetRead(methodDefOffset + (uint)methodDef.fields[3].offset, methodDef.fields[3].size);
dm.mdSignature = peImage.offsetRead(methodDefOffset + (uint)methodDef.fields[4].offset, methodDef.fields[4].size);
dm.mdParamList = peImage.offsetRead(methodDefOffset + (uint)methodDef.fields[5].offset, methodDef.fields[5].size);
dm.mhFlags = mbHeader.flags;
dm.mhMaxStack = mbHeader.maxStack;
dm.mhCodeSize = (uint)dm.code.Length;
dm.mhLocalVarSigTok = mbHeader.localVarSigTok;
dumpedMethods.add(dm);
decrypted = true;
}
return decrypted;
}
void decrypt(byte[] data) {
for (int i = 6; i < data.Length; i++)
data[i] ^= decryptKey[i % decryptKey.Length];
}
void decrypt(byte[] data, int seed) {
var key = new KeyGenerator(seed).generate(data.Length);
for (int i = 6; i < data.Length; i++)
data[i] ^= key[i];
}
public void deobfuscate(Blocks blocks) {
if (initMethod == null)
return;
if (blocks.Method.Name != ".cctor")
return;
foreach (var block in blocks.MethodBlocks.getAllBlocks()) {
var instrs = block.Instructions;
for (int i = 0; i < instrs.Count; i++) {
var instr = instrs[i];
if (instr.OpCode.Code != Code.Call)
continue;
var calledMethod = instr.Operand as MethodReference;
if (!MemberReferenceHelper.compareMethodReferenceAndDeclaringType(calledMethod, initMethod))
continue;
block.remove(i, 1);
i--;
}
}
}
}
}

View File

@ -0,0 +1,103 @@
/************************** mersenne.cpp **********************************
* Author: Agner Fog
* Date created: 2001
* Last modified: 2008-11-16
* Project: randomc.h
* Platform: Any C++
* Description:
* Random Number generator of type 'Mersenne Twister'
*
* This random number generator is described in the article by
* M. Matsumoto & T. Nishimura, in:
* ACM Transactions on Modeling and Computer Simulation,
* vol. 8, no. 1, 1998, pp. 3-30.
* Details on the initialization scheme can be found at
* http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
*
* Further documentation:
* The file ran-instructions.pdf contains further documentation and
* instructions.
*
* Copyright 2001-2008 by Agner Fog.
* GNU General Public License http://www.gnu.org/licenses/gpl.html
*******************************************************************************/
// Only the methods I need have been ported to C#...
namespace de4dot.code.deobfuscators.CodeWall.randomc {
class CRandomMersenne {
const int MERS_N = 624;
const int MERS_M = 397;
const int MERS_R = 31;
const int MERS_U = 11;
const int MERS_S = 7;
const int MERS_T = 15;
const int MERS_L = 18;
const uint MERS_A = 0x9908B0DF;
const uint MERS_B = 0x9D2C5680;
const uint MERS_C = 0xEFC60000;
uint[] mt = new uint[MERS_N]; // State vector
int mti; // Index into mt
public CRandomMersenne() {
}
public CRandomMersenne(int seed) {
RandomInit(seed);
}
void Init0(int seed) {
// Seed generator
const uint factor = 1812433253;
mt[0] = (uint)seed;
for (mti = 1; mti < MERS_N; mti++) {
mt[mti] = (factor * (mt[mti - 1] ^ (mt[mti - 1] >> 30)) + (uint)mti);
}
}
public void RandomInit(int seed) {
// Initialize and seed
Init0(seed);
// Randomize some more
for (int i = 0; i < 37; i++) BRandom();
}
static uint[] mag01 = new uint[2] { 0, MERS_A };
public uint BRandom() {
// Generate 32 random bits
uint y;
if (mti >= MERS_N) {
// Generate MERS_N words at one time
const uint LOWER_MASK = (1U << MERS_R) - 1; // Lower MERS_R bits
const uint UPPER_MASK = 0xFFFFFFFF << MERS_R; // Upper (32 - MERS_R) bits
int kk;
for (kk = 0; kk < MERS_N - MERS_M; kk++) {
y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
mt[kk] = mt[kk + MERS_M] ^ (y >> 1) ^ mag01[y & 1];
}
for (; kk < MERS_N - 1; kk++) {
y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
mt[kk] = mt[kk + (MERS_M - MERS_N)] ^ (y >> 1) ^ mag01[y & 1];
}
y = (mt[MERS_N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
mt[MERS_N - 1] = mt[MERS_M - 1] ^ (y >> 1) ^ mag01[y & 1];
mti = 0;
}
y = mt[mti++];
// Tempering (May be omitted):
y ^= y >> MERS_U;
y ^= (y << MERS_S) & MERS_B;
y ^= (y << MERS_T) & MERS_C;
y ^= y >> MERS_L;
return y;
}
}
}

View File

@ -0,0 +1,67 @@
/************************** mother.cpp ************************************
* Author: Agner Fog
* Date created: 1999
* Last modified: 2008-11-16
* Project: randomc.h
* Platform: This implementation uses 64-bit integers for intermediate calculations.
* Works only on compilers that support 64-bit integers.
* Description:
* Random Number generator of type 'Mother-Of-All generator'.
*
* This is a multiply-with-carry type of random number generator
* invented by George Marsaglia. The algorithm is:
* S = 2111111111*X[n-4] + 1492*X[n-3] + 1776*X[n-2] + 5115*X[n-1] + C
* X[n] = S modulo 2^32
* C = floor(S / 2^32)
*
* Further documentation:
* The file ran-instructions.pdf contains further documentation and
* instructions.
*
* Copyright 1999-2008 by Agner Fog.
* GNU General Public License http://www.gnu.org/licenses/gpl.html
******************************************************************************/
// Only the methods I need have been ported to C#...
namespace de4dot.code.deobfuscators.CodeWall.randomc {
class CRandomMother {
uint[] x = new uint[5]; // History buffer
public CRandomMother(int seed) {
RandomInit(seed);
}
// this function initializes the random number generator:
public void RandomInit(int seed) {
int i;
uint s = (uint)seed;
// make random numbers and put them into the buffer
for (i = 0; i < 5; i++) {
s = s * 29943829 - 1;
x[i] = s;
}
// randomize some more
for (i = 0; i < 19; i++) BRandom();
}
// Output random bits
public uint BRandom() {
ulong sum;
sum = (ulong)2111111111UL * (ulong)x[3] +
(ulong)1492 * (ulong)(x[2]) +
(ulong)1776 * (ulong)(x[1]) +
(ulong)5115 * (ulong)(x[0]) +
(ulong)x[4];
x[3] = x[2]; x[2] = x[1]; x[1] = x[0];
x[4] = (uint)(sum >> 32); // Carry
x[0] = (uint)sum; // Low 32 bits of sum
return x[0];
}
// returns a random number between 0 and 1:
public double Random() {
return (double)BRandom() * (1.0/(65536.0*65536.0));
}
}
}

View File

@ -40,6 +40,7 @@ namespace de4dot.cui {
new de4dot.code.deobfuscators.Babel_NET.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.CliSecure.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.CodeVeil.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.CodeWall.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.CryptoObfuscator.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.DeepSea.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Dotfuscator.DeobfuscatorInfo(),