Jump to content
Tuts 4 You

[C#] Decrypt {SmartAssembly} 3.2.3268.0 resources.


high6

Recommended Posts

This is the decrypt function ripped from the latest {smartassembly}.

Credits:

High6 - Coding a deobfuscator (UnControl flowing).

Kurapica - Deobfuscator (For renaming)

public static class BlockDecryption
{
class Class_72_Object
{
// Fields
private static int[] Field_0 = new int[] {
0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xd, 0xf, 0x11, 0x13, 0x17, 0x1b, 0x1f,
0x23, 0x2b, 0x33, 0x3b, 0x43, 0x53, 0x63, 0x73, 0x83, 0xa3, 0xc3, 0xe3, 0x102
};
private static int[] Field_1 = new int[] {
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2,
0x3, 0x3, 0x3, 0x3, 0x4, 0x4, 0x4, 0x4, 0x5, 0x5, 0x5, 0x5, 0x0
};
private BlockDecryption.Class_73_Object Field_10 = new BlockDecryption.Class_73_Object();
private BlockDecryption.Class_74_Object Field_11 = new BlockDecryption.Class_74_Object();
private BlockDecryption.Class_76_Object Field_12;
private BlockDecryption.Class_75_Object Field_13;
private BlockDecryption.Class_75_Object Field_14;
private static int[] Field_2 = new int[] {
0x1, 0x2, 0x3, 0x4, 0x5, 0x7, 0x9, 0xd, 0x11, 0x19, 0x21, 0x31, 0x41, 0x61, 0x81, 0xc1,
0x101, 0x181, 0x201, 0x301, 0x401, 0x601, 0x801, 0xc01, 0x1001, 0x1801, 0x2001, 0x3001, 0x4001, 0x6001
};
private static int[] Field_3 = new int[] {
0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x2, 0x2, 0x3, 0x3, 0x4, 0x4, 0x5, 0x5, 0x6, 0x6,
0x7, 0x7, 0x8, 0x8, 0x9, 0x9, 0xa, 0xa, 0xb, 0xb, 0xc, 0xc, 0xd, 0xd
};
private int Field_4 = 0x2;
private int Field_5;
private int Field_6;
private int Field_7;
private int Field_8;
private bool Field_9; // Methods
public Class_72_Object(byte[] buffer1)
{
this.Field_10.Method_7(buffer1, 0x0, buffer1.Length);
} private bool Method_0()
{
int num = this.Field_11.Method_4();
while (num >= 0x102)
{
int num2;
switch (this.Field_4)
{
case 0x7:
goto Label_0057; case 0x8:
goto Label_00C9; case 0x9:
goto Label_011E; case 0xa:
goto Label_0156; default:
{
continue;
}
}
Label_0037:
this.Field_11.Method_0(num2);
if (--num < 0x102)
{
return true;
}
Label_0057:
if (((num2 = this.Field_13.Method_1(this.Field_10)) & 0xffffff00) == 0x0)
{
goto Label_0037;
}
if (num2 < 0x101)
{
if (num2 < 0x0)
{
return false;
}
this.Field_14 = null;
this.Field_13 = null;
this.Field_4 = 0x2;
return true;
}
this.Field_6 = Field_0[num2 - 0x101];
this.Field_5 = Field_1[num2 - 0x101];
Label_00C9:
if (this.Field_5 > 0x0)
{
this.Field_4 = 0x8;
int num3 = this.Field_10.Method_0(this.Field_5);
if (num3 < 0x0)
{
return false;
}
this.Field_10.Method_1(this.Field_5);
this.Field_6 += num3;
}
this.Field_4 = 0x9;
Label_011E:
num2 = this.Field_14.Method_1(this.Field_10);
if (num2 < 0x0)
{
return false;
}
this.Field_7 = Field_2[num2];
this.Field_5 = Field_3[num2];
Label_0156:
if (this.Field_5 > 0x0)
{
this.Field_4 = 0xa;
int num4 = this.Field_10.Method_0(this.Field_5);
if (num4 < 0x0)
{
return false;
}
this.Field_10.Method_1(this.Field_5);
this.Field_7 += num4;
}
this.Field_11.Method_2(this.Field_6, this.Field_7);
num -= this.Field_6;
this.Field_4 = 0x7;
}
return true;
} private bool Method_1()
{
int num3;
switch (this.Field_4)
{
case 0x2:
if (!this.Field_9)
{
int num = this.Field_10.Method_0(0x3);
if (num < 0x0)
{
return false;
}
this.Field_10.Method_1(0x3);
if ((num & 0x1) != 0x0)
{
this.Field_9 = true;
}
switch ((num >> 0x1))
{
case 0x0:
this.Field_10.Method_4();
this.Field_4 = 0x3;
break; case 0x1:
this.Field_13 = BlockDecryption.Class_75_Object.Field_2;
this.Field_14 = BlockDecryption.Class_75_Object.Field_3;
this.Field_4 = 0x7;
break; case 0x2:
this.Field_12 = new BlockDecryption.Class_76_Object();
this.Field_4 = 0x6;
break;
}
break;
}
this.Field_4 = 0xc;
return false; case 0x3:
this.Field_8 = this.Field_10.Method_0(0x10);
if (this.Field_8 >= 0x0)
{
this.Field_10.Method_1(0x10);
this.Field_4 = 0x4;
goto Label_0127;
}
return false; case 0x4:
goto Label_0127; case 0x5:
goto Label_0155; case 0x6:
if (this.Field_12.Method_0(this.Field_10))
{
this.Field_13 = this.Field_12.Method_1();
this.Field_14 = this.Field_12.Method_2();
this.Field_4 = 0x7;
goto Label_01E8;
}
return false; case 0x7:
case 0x8:
case 0x9:
case 0xa:
goto Label_01E8; case 0xc:
return false; default:
return false;
}
return true;
Label_0127:
if (this.Field_10.Method_0(0x10) < 0x0)
{
return false;
}
this.Field_10.Method_1(0x10);
this.Field_4 = 0x5;
Label_0155:
num3 = this.Field_11.Method_3(this.Field_10, this.Field_8);
this.Field_8 -= num3;
if (this.Field_8 == 0x0)
{
this.Field_4 = 0x2;
return true;
}
return !this.Field_10.Method_5();
Label_01E8:
return this.Method_0();
} public int Method_2(byte[] buffer1, int num1, int num4)
{
int num = 0x0;
do
{
if (this.Field_4 != 0xb)
{
int num2 = this.Field_11.Method_6(buffer1, num1, num4);
num1 += num2;
num += num2;
num4 -= num2;
if (num4 == 0x0)
{
return num;
}
}
}
while (this.Method_1() || ((this.Field_11.Method_5() > 0x0) && (this.Field_4 != 0xb)));
return num;
}
}
class Class_73_Object
{
// Fields
private byte[] Field_0;
private int Field_1;
private int Field_2;
private uint Field_3;
private int Field_4; // Methods
public int Method_0(int num1)
{
if (this.Field_4 < num1)
{
if (this.Field_1 == this.Field_2)
{
return -1;
}
this.Field_3 |= (uint)(((this.Field_0[this.Field_1++] & 0xff) | ((this.Field_0[this.Field_1++] & 0xff) << 0x8)) << this.Field_4);
this.Field_4 += 0x10;
}
return (((int)this.Field_3) & ((((int)0x1) << num1) - 0x1));
} public void Method_1(int num1)
{
this.Field_3 = this.Field_3 >> num1;
this.Field_4 -= num1;
} public int Method_2()
{
return this.Field_4;
} public int Method_3()
{
return ((this.Field_2 - this.Field_1) + (this.Field_4 >> 0x3));
} public void Method_4()
{
this.Field_3 = this.Field_3 >> (this.Field_4 & 0x7);
this.Field_4 = (int)(this.Field_4 & 0xfffffff8);
} public bool Method_5()
{
return (this.Field_1 == this.Field_2);
} public int Method_6(byte[] buffer1, int num1, int num5)
{
int num = 0x0;
while ((this.Field_4 > 0x0) && (num5 > 0x0))
{
buffer1[num1++] = (byte)this.Field_3;
this.Field_3 = this.Field_3 >> 0x8;
this.Field_4 -= 0x8;
num5--;
num++;
}
if (num5 == 0x0)
{
return num;
}
int num2 = this.Field_2 - this.Field_1;
if (num5 > num2)
{
num5 = num2;
}
Array.Copy(this.Field_0, this.Field_1, buffer1, num1, num5);
this.Field_1 += num5;
if (((this.Field_1 - this.Field_2) & 0x1) != 0x0)
{
this.Field_3 = (uint)(this.Field_0[this.Field_1++] & 0xff);
this.Field_4 = 0x8;
}
return (num + num5);
} public void Method_7(byte[] buffer1, int num1, int num2)
{
if (this.Field_1 < this.Field_2)
{
throw new InvalidOperationException();
}
int num = num1 + num2;
if (((0x0 > num1) || (num1 > num)) || (num > buffer1.Length))
{
throw new ArgumentOutOfRangeException();
}
if ((num2 & 0x1) != 0x0)
{
this.Field_3 |= (uint)((buffer1[num1++] & 0xff) << this.Field_4);
this.Field_4 += 0x8;
}
this.Field_0 = buffer1;
this.Field_1 = num1;
this.Field_2 = num;
}
}
class Class_74_Object
{
// Fields
private static int Field_0 = 0x8000;
private static int Field_1 = (Field_0 - 0x1);
private byte[] Field_2 = new byte[Field_0];
private int Field_3;
private int Field_4; // Methods
public void Method_0(int num1)
{
if (this.Field_4++ == Field_0)
{
throw new InvalidOperationException();
}
this.Field_2[this.Field_3++] = (byte)num1;
this.Field_3 &= Field_1;
} private void Method_1(int num1, int num2, int num3)
{
while (num2-- > 0x0)
{
this.Field_2[this.Field_3++] = this.Field_2[num1++];
this.Field_3 &= Field_1;
num1 &= Field_1;
}
} public void Method_2(int num1, int num5)
{
if ((this.Field_4 += num1) > Field_0)
{
throw new InvalidOperationException();
}
int sourceIndex = (this.Field_3 - num5) & Field_1;
int num2 = Field_0 - num1;
if ((sourceIndex > num2) || (this.Field_3 >= num2))
{
this.Method_1(sourceIndex, num1, num5);
}
else if (num1 > num5)
{
while (num1-- > 0x0)
{
this.Field_2[this.Field_3++] = this.Field_2[sourceIndex++];
}
}
else
{
Array.Copy(this.Field_2, sourceIndex, this.Field_2, this.Field_3, num1);
this.Field_3 += num1;
}
} public int Method_3(BlockDecryption.Class_73_Object obj1, int num1)
{
int num;
num1 = Math.Min(Math.Min(num1, Field_0 - this.Field_4), obj1.Method_3());
int num2 = Field_0 - this.Field_3;
if (num1 > num2)
{
num = obj1.Method_6(this.Field_2, this.Field_3, num2);
if (num == num2)
{
num += obj1.Method_6(this.Field_2, 0x0, num1 - num2);
}
}
else
{
num = obj1.Method_6(this.Field_2, this.Field_3, num1);
}
this.Field_3 = (this.Field_3 + num) & Field_1;
this.Field_4 += num;
return num;
} public int Method_4()
{
return (Field_0 - this.Field_4);
} public int Method_5()
{
return this.Field_4;
} public int Method_6(byte[] buffer1, int num5, int num1)
{
int num = this.Field_3;
if (num1 > this.Field_4)
{
num1 = this.Field_4;
}
else
{
num = ((this.Field_3 - this.Field_4) + num1) & Field_1;
}
int num2 = num1;
int length = num1 - num;
if (length > 0x0)
{
Array.Copy(this.Field_2, Field_0 - length, buffer1, num5, length);
num5 += length;
num1 = num;
}
Array.Copy(this.Field_2, num - num1, buffer1, num5, num1);
this.Field_4 -= num2;
if (this.Field_4 < 0x0)
{
throw new InvalidOperationException();
}
return num2;
}
}
class Class_75_Object
{
// Fields
private static int Field_0 = 0xf;
private short[] Field_1;
public static BlockDecryption.Class_75_Object Field_2;
public static BlockDecryption.Class_75_Object Field_3; // Methods
static Class_75_Object()
{
byte[] buffer = new byte[0x120];
int num = 0x0;
while (num < 0x90)
{
buffer[num++] = 0x8;
}
while (num < 0x100)
{
buffer[num++] = 0x9;
}
while (num < 0x118)
{
buffer[num++] = 0x7;
}
while (num < 0x120)
{
buffer[num++] = 0x8;
}
Field_2 = new BlockDecryption.Class_75_Object(buffer);
buffer = new byte[0x20];
num = 0x0;
while (num < 0x20)
{
buffer[num++] = 0x5;
}
Field_3 = new BlockDecryption.Class_75_Object(buffer);
} public Class_75_Object(byte[] buffer1)
{
this.Method_0(buffer1);
} private void Method_0(byte[] buffer1)
{
int[] numArray = new int[Field_0 + 0x1];
int[] numArray2 = new int[Field_0 + 0x1];
for (int i = 0x0; i < buffer1.Length; i++)
{
int index = buffer1[i];
if (index > 0x0)
{
numArray[index]++;
}
}
int num3 = 0x0;
int num4 = 0x200;
for (int j = 0x1; j <= Field_0; j++)
{
numArray2[j] = num3;
num3 += numArray[j] << (0x10 - j);
if (j >= 0xa)
{
int num6 = numArray2[j] & 0x1ff80;
int num7 = num3 & 0x1ff80;
num4 += (num7 - num6) >> (0x10 - j);
}
}
this.Field_1 = new short[num4];
int num8 = 0x200;
for (int k = Field_0; k >= 0xa; k--)
{
int num10 = num3 & 0x1ff80;
num3 -= numArray[k] << (0x10 - k);
int num11 = num3 & 0x1ff80;
for (int n = num11; n < num10; n += 0x80)
{
this.Field_1[BlockDecryption.Class_78_Object.Method_0(n)] = (short)((-num8 << 0x4) | k);
num8 += ((int)0x1) << (k - 0x9);
}
}
for (int m = 0x0; m < buffer1.Length; m++)
{
int num14 = buffer1[m];
if (num14 != 0x0)
{
num3 = numArray2[num14];
int num15 = BlockDecryption.Class_78_Object.Method_0(num3);
if (num14 <= 0x9)
{
do
{
this.Field_1[num15] = (short)((m << 0x4) | num14);
num15 += ((int)0x1) << num14;
}
while (num15 < 0x200);
}
else
{
int num16 = this.Field_1[num15 & 0x1ff];
int num17 = ((int)0x1) << (num16 & 0xf);
num16 = -(num16 >> 0x4);
do
{
this.Field_1[num16 | (num15 >> 0x9)] = (short)((m << 0x4) | num14);
num15 += ((int)0x1) << num14;
}
while (num15 < num17);
}
numArray2[num14] = num3 + (((int)0x1) << (0x10 - num14));
}
}
} public int Method_1(BlockDecryption.Class_73_Object obj1)
{
int num2;
int index = obj1.Method_0(0x9);
if (index >= 0x0)
{
num2 = this.Field_1[index];
if (num2 >= 0x0)
{
obj1.Method_1(num2 & 0xf);
return (num2 >> 0x4);
}
int num3 = -(num2 >> 0x4);
int num4 = num2 & 0xf;
index = obj1.Method_0(num4);
if (index >= 0x0)
{
num2 = this.Field_1[num3 | (index >> 0x9)];
obj1.Method_1(num2 & 0xf);
return (num2 >> 0x4);
}
int num5 = obj1.Method_2();
index = obj1.Method_0(num5);
num2 = this.Field_1[num3 | (index >> 0x9)];
if ((num2 & 0xf) <= num5)
{
obj1.Method_1(num2 & 0xf);
return (num2 >> 0x4);
}
return -1;
}
int num6 = obj1.Method_2();
index = obj1.Method_0(num6);
num2 = this.Field_1[index];
if ((num2 >= 0x0) && ((num2 & 0xf) <= num6))
{
obj1.Method_1(num2 & 0xf);
return (num2 >> 0x4);
}
return -1;
}
}
class Class_76_Object
{
// Fields
private static readonly int[] Field_0 = new int[ ] { 0x3, 0x3, 0xb };
private static readonly int[] Field_1 = new int[ ] { 0x2, 0x3, 0x7 };
private int Field_10;
private byte Field_11;
private int Field_12;
private static readonly int[] Field_13 = new int[] {
0x10, 0x11, 0x12, 0x0, 0x8, 0x7, 0x9, 0x6, 0xa, 0x5, 0xb, 0x4, 0xc, 0x3, 0xd, 0x2,
0xe, 0x1, 0xf
};
private byte[] Field_2;
private byte[] Field_3;
private BlockDecryption.Class_75_Object Field_4;
private int Field_5;
private int Field_6;
private int Field_7;
private int Field_8;
private int Field_9; // Methods
public bool Method_0(BlockDecryption.Class_73_Object obj1)
{
int num2;
int num3;
Label_0000:
switch (this.Field_5)
{
case 0x0:
this.Field_6 = obj1.Method_0(0x5);
if (this.Field_6 >= 0x0)
{
this.Field_6 += 0x101;
obj1.Method_1(0x5);
this.Field_5 = 0x1;
break;
}
return false; case 0x1:
break; case 0x2:
goto Label_00C7; case 0x3:
goto Label_0155; case 0x4:
goto Label_01C8; case 0x5:
goto Label_0204; default:
goto Label_0000;
}
this.Field_7 = obj1.Method_0(0x5);
if (this.Field_7 < 0x0)
{
return false;
}
this.Field_7++;
obj1.Method_1(0x5);
this.Field_9 = this.Field_6 + this.Field_7;
this.Field_3 = new byte[this.Field_9];
this.Field_5 = 0x2;
Label_00C7:
this.Field_8 = obj1.Method_0(0x4);
if (this.Field_8 < 0x0)
{
return false;
}
this.Field_8 += 0x4;
obj1.Method_1(0x4);
this.Field_2 = new byte[0x13];
this.Field_12 = 0x0;
this.Field_5 = 0x3;
Label_0155:
while (this.Field_12 < this.Field_8)
{
int num = obj1.Method_0(0x3);
if (num < 0x0)
{
return false;
}
obj1.Method_1(0x3);
this.Field_2[Field_13[this.Field_12]] = (byte)num;
this.Field_12++;
}
this.Field_4 = new BlockDecryption.Class_75_Object(this.Field_2);
this.Field_2 = null;
this.Field_12 = 0x0;
this.Field_5 = 0x4;
Label_01C8:
while (((num2 = this.Field_4.Method_1(obj1)) & 0xfffffff0) == 0x0)
{
this.Field_3[this.Field_12++] = this.Field_11 = (byte)num2;
if (this.Field_12 == this.Field_9)
{
return true;
}
}
if (num2 < 0x0)
{
return false;
}
if (num2 >= 0x11)
{
this.Field_11 = 0x0;
}
this.Field_10 = num2 - 0x10;
this.Field_5 = 0x5;
Label_0204:
num3 = Field_1[this.Field_10];
int num4 = obj1.Method_0(num3);
if (num4 < 0x0)
{
return false;
}
obj1.Method_1(num3);
num4 += Field_0[this.Field_10];
while (num4-- > 0x0)
{
this.Field_3[this.Field_12++] = this.Field_11;
}
if (this.Field_12 == this.Field_9)
{
return true;
}
this.Field_5 = 0x4;
goto Label_0000;
} public BlockDecryption.Class_75_Object Method_1()
{
byte[] destinationArray = new byte[this.Field_6];
Array.Copy(this.Field_3, 0x0, destinationArray, 0x0, this.Field_6);
return new BlockDecryption.Class_75_Object(destinationArray);
} public BlockDecryption.Class_75_Object Method_2()
{
byte[] destinationArray = new byte[this.Field_7];
Array.Copy(this.Field_3, this.Field_6, destinationArray, 0x0, this.Field_7);
return new BlockDecryption.Class_75_Object(destinationArray);
}
} class Class_78_Object
{
static byte[] Field_9 = new byte[ ] { 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf };
public static short Method_0(int num1)
{
return (short)((((Field_9[num1 & 0xf] << 0xc) | (Field_9[(num1 >> 0x4) & 0xf] << 0x8)) | (Field_9[(num1 >> 0x8) & 0xf] << 0x4)) | Field_9[num1 >> 0xc]);
}
}
public static byte[] Decrypt(byte[] buffer1)
{
BinaryReader stream = new BinaryReader(new MemoryStream(buffer1));
byte[] buffer = new byte[0x0];
int num = stream.ReadInt32();
if (num == 0x4034b50)
{
short num2 = stream.ReadInt16();
int num3 = stream.ReadInt16();
int num4 = stream.ReadInt16();
if (((num != 0x4034b50) || (num2 != 0x14)) || ((num3 != 0x0) || (num4 != 0x8)))
{
throw new FormatException("Invalid?(1)");
}
stream.ReadInt32();
stream.ReadInt32();
stream.ReadInt32();
int num5 = stream.ReadInt32();
int count = stream.ReadInt16();
int num7 = stream.ReadInt16();
if (count > 0x0)
{
byte[] buffer2 = new byte[count];
stream.Read(buffer2, 0x0, count);
}
if (num7 > 0x0)
{
byte[] buffer3 = new byte[num7];
stream.Read(buffer3, 0x0, num7);
}
byte[] buffer4 = new byte[stream.BaseStream.Length - stream.BaseStream.Position];
stream.Read(buffer4, 0x0, buffer4.Length);
Class_72_Object obj2 = new Class_72_Object(buffer4);
buffer = new byte[num5];
obj2.Method_2(buffer, 0x0, buffer.Length);
buffer4 = null;
}
else
{
int num11;
if (num != 0x17d7a7b)
{
throw new FormatException("Invalid?(2)");
}
int num8 = stream.ReadInt32();
buffer = new byte[num8];
for (int i = 0x0; i < num8; i += num11)
{
int num10 = stream.ReadInt32();
num11 = stream.ReadInt32();
byte[] buffer5 = new byte[num10];
stream.Read(buffer5, 0x0, buffer5.Length);
new Class_72_Object(buffer5).Method_2(buffer, i, num11);
}
}
stream.Close();
stream = null;
return buffer;
}
}

Use:

byte[] ResourceData = AnEmbededResource.Data;
byte[] decrypted = BlockDecryption.Decrypt(ResourceData);
Edited by high6
Link to comment
Nice work , why don't you code a tool that can unpack resources and deobfuscate control flow ?

I am, was working on it last night. I just need to have it remove the delegates and I will post it.

Link to comment
  • 1 month later...

@high6:

The string will be encrypted with an ID in {SmartAssembly}. But in your code I didn't see where I can pass the ID to decrypt the string. Did you forget a function?

Edited by rongchaua
Link to comment

@high6: I have applied your code in my tool to decrypt string. But it doesn't work. It gives false result back. Have you ever tried to decrypt string with your code?

Link to comment

Here is my string class for 3.2 (latest {smartassembly} evaluation)

And yes, I have tested it on {smartassembly} evaluation

using Mono.Cecil;
using Mono.Cecil.Binary;
using Mono.Cecil.Cil;
using Mono.Cecil.Metadata;public class Strings_v3_2 : Strings
{
AssemblyDefinition Assembly;
Stream stream;
int BasePos; public void DecryptStrings(AssemblyDefinition asm)
{
SetAssembly(asm); MethodDefinition dec = FindDecryptMethod(Assembly); foreach (TypeDefinition td in asm.MainModule.Types)
{
foreach (MethodDefinition md in td.Methods)
{
DecryptStringsMethod(dec, md);
}
foreach (MethodDefinition md in td.Constructors)
{
DecryptStringsMethod(dec, md);
}
}
DecryptStringsMethod(dec, asm.EntryPoint);
}
void SetAssembly(AssemblyDefinition asm)
{
Assembly = asm;
}
void DecryptStringsMethod(MethodDefinition decryptcall, MethodDefinition md)
{
if (!md.HasBody)
return;
foreach (Instruction i in md.Body.Instructions)
{
if (i.OpCode != OpCodes.Call)
continue;
if (i.Previous == null)
continue;
if (i.Previous.OpCode != OpCodes.Ldc_I4)
continue; if (i.Operand == decryptcall) //Direct call to the decrypt string method
{
int num2 = (int)i.Previous.Operand;
i.OpCode = OpCodes.Ldstr;
i.Operand = ReadString(num2);
i.Previous.OpCode = OpCodes.Nop;
continue;
} //Delegate call to decrypt string method MethodReference m = (MethodReference)i.Operand; if (m.Parameters.Count != 1)
continue; if (m.Parameters[0].ParameterType != Assembly.MainModule.Import(typeof(int)))
continue; if (m.DeclaringType == null)
continue; if (i.Previous.Previous == null)
continue; if (i.Previous.Previous.OpCode != OpCodes.Ldsfld && i.Previous.Previous.OpCode != OpCodes.Ldfld)
continue; FieldReference f = (FieldReference)i.Previous.Previous.Operand; if (!(f.FieldType is TypeDefinition))
continue; if (((TypeDefinition)f.FieldType).BaseType != Assembly.MainModule.Import(typeof(MulticastDelegate)))
continue; int num = (int)i.Previous.Operand;
i.OpCode = OpCodes.Ldstr;
i.Operand = ReadString(num - (int)(f.MetadataToken.ToUInt() & 0xFFFFFF));
i.Previous.OpCode = OpCodes.Nop;
i.Previous.Previous.OpCode = OpCodes.Nop;
}
}
MethodDefinition FindDecryptMethod(AssemblyDefinition asm)
{
foreach (TypeDefinition td in asm.MainModule.Types)
{
foreach (MethodDefinition md in td.Methods)
{
if (!md.HasBody)
continue;
if (md.ReturnType.ReturnType != asm.MainModule.Import(typeof(string)))
continue;
if (md.Parameters.Count != 1)
continue;
if (md.Parameters[0].ParameterType != asm.MainModule.Import(typeof(int)))
continue;
if (md.Body.Instructions[0].OpCode != OpCodes.Ldtoken)
continue; return md; }
}
return null;
}
string ReadString(int num1)
{
if (stream == null)
{
EmbeddedResource er = GetManifestResource(Assembly);
if (er == null)
return string.Empty;
stream = new MemoryStream(BlockDecryption.Decrypt(er.Data));
byte[] publicKeyToken = Assembly.Name.PublicKeyToken;
if (publicKeyToken != null)
{
for (int i = 0x0; i < (publicKeyToken.Length - 0x1); i += 0x2)
{
BasePos ^= (publicKeyToken[i] << 0x8) + publicKeyToken[i + 0x1];
}
}
MethodDefinition dec = FindDecryptMethod(Assembly);
int num2 = (int)((dec.MetadataToken.ToUInt() & 0xffffff) - 0x1);
BasePos ^= num2;
}
stream.Position = num1 - BasePos;
int num3 = stream.ReadByte();
int count = 0x0;
if ((num3 & 0x80) == 0x0)
{
count = num3;
}
else if ((num3 & 0x40) == 0x0)
{
count = ((num3 & 0x3f) << 0x8) + stream.ReadByte();
}
else
{
count = ((((num3 & 0x1f) << 0x18) + (stream.ReadByte() << 0x10)) + (stream.ReadByte() << 0x8)) + stream.ReadByte();
}
byte[] buffer = new byte[count];
stream.Read(buffer, 0x0, count);
if (buffer.Length == 0x0)
{
return string.Empty;
}
byte[] bytes = Convert.FromBase64String(Encoding.UTF8.GetString(buffer, 0x0, buffer.Length));
return string.Intern(Encoding.UTF8.GetString(bytes, 0x0, bytes.Length));
}
}
public static class BlockDecryption
{
class Class_72_Object
{
// Fields
private static int[] Field_0 = new int[] {
0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xd, 0xf, 0x11, 0x13, 0x17, 0x1b, 0x1f,
0x23, 0x2b, 0x33, 0x3b, 0x43, 0x53, 0x63, 0x73, 0x83, 0xa3, 0xc3, 0xe3, 0x102
};
private static int[] Field_1 = new int[] {
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2,
0x3, 0x3, 0x3, 0x3, 0x4, 0x4, 0x4, 0x4, 0x5, 0x5, 0x5, 0x5, 0x0
};
private BlockDecryption.Class_73_Object Field_10 = new BlockDecryption.Class_73_Object();
private BlockDecryption.Class_74_Object Field_11 = new BlockDecryption.Class_74_Object();
private BlockDecryption.Class_76_Object Field_12;
private BlockDecryption.Class_75_Object Field_13;
private BlockDecryption.Class_75_Object Field_14;
private static int[] Field_2 = new int[] {
0x1, 0x2, 0x3, 0x4, 0x5, 0x7, 0x9, 0xd, 0x11, 0x19, 0x21, 0x31, 0x41, 0x61, 0x81, 0xc1,
0x101, 0x181, 0x201, 0x301, 0x401, 0x601, 0x801, 0xc01, 0x1001, 0x1801, 0x2001, 0x3001, 0x4001, 0x6001
};
private static int[] Field_3 = new int[] {
0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x2, 0x2, 0x3, 0x3, 0x4, 0x4, 0x5, 0x5, 0x6, 0x6,
0x7, 0x7, 0x8, 0x8, 0x9, 0x9, 0xa, 0xa, 0xb, 0xb, 0xc, 0xc, 0xd, 0xd
};
private int Field_4 = 0x2;
private int Field_5;
private int Field_6;
private int Field_7;
private int Field_8;
private bool Field_9; // Methods
public Class_72_Object(byte[] buffer1)
{
this.Field_10.Method_7(buffer1, 0x0, buffer1.Length);
} private bool Method_0()
{
int num = this.Field_11.Method_4();
while (num >= 0x102)
{
int num2;
switch (this.Field_4)
{
case 0x7:
goto Label_0057; case 0x8:
goto Label_00C9; case 0x9:
goto Label_011E; case 0xa:
goto Label_0156; default:
{
continue;
}
}
Label_0037:
this.Field_11.Method_0(num2);
if (--num < 0x102)
{
return true;
}
Label_0057:
if (((num2 = this.Field_13.Method_1(this.Field_10)) & 0xffffff00) == 0x0)
{
goto Label_0037;
}
if (num2 < 0x101)
{
if (num2 < 0x0)
{
return false;
}
this.Field_14 = null;
this.Field_13 = null;
this.Field_4 = 0x2;
return true;
}
this.Field_6 = Field_0[num2 - 0x101];
this.Field_5 = Field_1[num2 - 0x101];
Label_00C9:
if (this.Field_5 > 0x0)
{
this.Field_4 = 0x8;
int num3 = this.Field_10.Method_0(this.Field_5);
if (num3 < 0x0)
{
return false;
}
this.Field_10.Method_1(this.Field_5);
this.Field_6 += num3;
}
this.Field_4 = 0x9;
Label_011E:
num2 = this.Field_14.Method_1(this.Field_10);
if (num2 < 0x0)
{
return false;
}
this.Field_7 = Field_2[num2];
this.Field_5 = Field_3[num2];
Label_0156:
if (this.Field_5 > 0x0)
{
this.Field_4 = 0xa;
int num4 = this.Field_10.Method_0(this.Field_5);
if (num4 < 0x0)
{
return false;
}
this.Field_10.Method_1(this.Field_5);
this.Field_7 += num4;
}
this.Field_11.Method_2(this.Field_6, this.Field_7);
num -= this.Field_6;
this.Field_4 = 0x7;
}
return true;
} private bool Method_1()
{
int num3;
switch (this.Field_4)
{
case 0x2:
if (!this.Field_9)
{
int num = this.Field_10.Method_0(0x3);
if (num < 0x0)
{
return false;
}
this.Field_10.Method_1(0x3);
if ((num & 0x1) != 0x0)
{
this.Field_9 = true;
}
switch ((num >> 0x1))
{
case 0x0:
this.Field_10.Method_4();
this.Field_4 = 0x3;
break; case 0x1:
this.Field_13 = BlockDecryption.Class_75_Object.Field_2;
this.Field_14 = BlockDecryption.Class_75_Object.Field_3;
this.Field_4 = 0x7;
break; case 0x2:
this.Field_12 = new BlockDecryption.Class_76_Object();
this.Field_4 = 0x6;
break;
}
break;
}
this.Field_4 = 0xc;
return false; case 0x3:
this.Field_8 = this.Field_10.Method_0(0x10);
if (this.Field_8 >= 0x0)
{
this.Field_10.Method_1(0x10);
this.Field_4 = 0x4;
goto Label_0127;
}
return false; case 0x4:
goto Label_0127; case 0x5:
goto Label_0155; case 0x6:
if (this.Field_12.Method_0(this.Field_10))
{
this.Field_13 = this.Field_12.Method_1();
this.Field_14 = this.Field_12.Method_2();
this.Field_4 = 0x7;
goto Label_01E8;
}
return false; case 0x7:
case 0x8:
case 0x9:
case 0xa:
goto Label_01E8; case 0xc:
return false; default:
return false;
}
return true;
Label_0127:
if (this.Field_10.Method_0(0x10) < 0x0)
{
return false;
}
this.Field_10.Method_1(0x10);
this.Field_4 = 0x5;
Label_0155:
num3 = this.Field_11.Method_3(this.Field_10, this.Field_8);
this.Field_8 -= num3;
if (this.Field_8 == 0x0)
{
this.Field_4 = 0x2;
return true;
}
return !this.Field_10.Method_5();
Label_01E8:
return this.Method_0();
} public int Method_2(byte[] buffer1, int num1, int num4)
{
int num = 0x0;
do
{
if (this.Field_4 != 0xb)
{
int num2 = this.Field_11.Method_6(buffer1, num1, num4);
num1 += num2;
num += num2;
num4 -= num2;
if (num4 == 0x0)
{
return num;
}
}
}
while (this.Method_1() || ((this.Field_11.Method_5() > 0x0) && (this.Field_4 != 0xb)));
return num;
}
}
class Class_73_Object
{
// Fields
private byte[] Field_0;
private int Field_1;
private int Field_2;
private uint Field_3;
private int Field_4; // Methods
public int Method_0(int num1)
{
if (this.Field_4 < num1)
{
if (this.Field_1 == this.Field_2)
{
return -1;
}
this.Field_3 |= (uint)(((this.Field_0[this.Field_1++] & 0xff) | ((this.Field_0[this.Field_1++] & 0xff) << 0x8)) << this.Field_4);
this.Field_4 += 0x10;
}
return (((int)this.Field_3) & ((((int)0x1) << num1) - 0x1));
} public void Method_1(int num1)
{
this.Field_3 = this.Field_3 >> num1;
this.Field_4 -= num1;
} public int Method_2()
{
return this.Field_4;
} public int Method_3()
{
return ((this.Field_2 - this.Field_1) + (this.Field_4 >> 0x3));
} public void Method_4()
{
this.Field_3 = this.Field_3 >> (this.Field_4 & 0x7);
this.Field_4 = (int)(this.Field_4 & 0xfffffff8);
} public bool Method_5()
{
return (this.Field_1 == this.Field_2);
} public int Method_6(byte[] buffer1, int num1, int num5)
{
int num = 0x0;
while ((this.Field_4 > 0x0) && (num5 > 0x0))
{
buffer1[num1++] = (byte)this.Field_3;
this.Field_3 = this.Field_3 >> 0x8;
this.Field_4 -= 0x8;
num5--;
num++;
}
if (num5 == 0x0)
{
return num;
}
int num2 = this.Field_2 - this.Field_1;
if (num5 > num2)
{
num5 = num2;
}
Array.Copy(this.Field_0, this.Field_1, buffer1, num1, num5);
this.Field_1 += num5;
if (((this.Field_1 - this.Field_2) & 0x1) != 0x0)
{
this.Field_3 = (uint)(this.Field_0[this.Field_1++] & 0xff);
this.Field_4 = 0x8;
}
return (num + num5);
} public void Method_7(byte[] buffer1, int num1, int num2)
{
if (this.Field_1 < this.Field_2)
{
throw new InvalidOperationException();
}
int num = num1 + num2;
if (((0x0 > num1) || (num1 > num)) || (num > buffer1.Length))
{
throw new ArgumentOutOfRangeException();
}
if ((num2 & 0x1) != 0x0)
{
this.Field_3 |= (uint)((buffer1[num1++] & 0xff) << this.Field_4);
this.Field_4 += 0x8;
}
this.Field_0 = buffer1;
this.Field_1 = num1;
this.Field_2 = num;
}
}
class Class_74_Object
{
// Fields
private static int Field_0 = 0x8000;
private static int Field_1 = (Field_0 - 0x1);
private byte[] Field_2 = new byte[Field_0];
private int Field_3;
private int Field_4; // Methods
public void Method_0(int num1)
{
if (this.Field_4++ == Field_0)
{
throw new InvalidOperationException();
}
this.Field_2[this.Field_3++] = (byte)num1;
this.Field_3 &= Field_1;
} private void Method_1(int num1, int num2, int num3)
{
while (num2-- > 0x0)
{
this.Field_2[this.Field_3++] = this.Field_2[num1++];
this.Field_3 &= Field_1;
num1 &= Field_1;
}
} public void Method_2(int num1, int num5)
{
if ((this.Field_4 += num1) > Field_0)
{
throw new InvalidOperationException();
}
int sourceIndex = (this.Field_3 - num5) & Field_1;
int num2 = Field_0 - num1;
if ((sourceIndex > num2) || (this.Field_3 >= num2))
{
this.Method_1(sourceIndex, num1, num5);
}
else if (num1 > num5)
{
while (num1-- > 0x0)
{
this.Field_2[this.Field_3++] = this.Field_2[sourceIndex++];
}
}
else
{
Array.Copy(this.Field_2, sourceIndex, this.Field_2, this.Field_3, num1);
this.Field_3 += num1;
}
} public int Method_3(BlockDecryption.Class_73_Object obj1, int num1)
{
int num;
num1 = Math.Min(Math.Min(num1, Field_0 - this.Field_4), obj1.Method_3());
int num2 = Field_0 - this.Field_3;
if (num1 > num2)
{
num = obj1.Method_6(this.Field_2, this.Field_3, num2);
if (num == num2)
{
num += obj1.Method_6(this.Field_2, 0x0, num1 - num2);
}
}
else
{
num = obj1.Method_6(this.Field_2, this.Field_3, num1);
}
this.Field_3 = (this.Field_3 + num) & Field_1;
this.Field_4 += num;
return num;
} public int Method_4()
{
return (Field_0 - this.Field_4);
} public int Method_5()
{
return this.Field_4;
} public int Method_6(byte[] buffer1, int num5, int num1)
{
int num = this.Field_3;
if (num1 > this.Field_4)
{
num1 = this.Field_4;
}
else
{
num = ((this.Field_3 - this.Field_4) + num1) & Field_1;
}
int num2 = num1;
int length = num1 - num;
if (length > 0x0)
{
Array.Copy(this.Field_2, Field_0 - length, buffer1, num5, length);
num5 += length;
num1 = num;
}
Array.Copy(this.Field_2, num - num1, buffer1, num5, num1);
this.Field_4 -= num2;
if (this.Field_4 < 0x0)
{
throw new InvalidOperationException();
}
return num2;
}
}
class Class_75_Object
{
// Fields
private static int Field_0 = 0xf;
private short[] Field_1;
public static BlockDecryption.Class_75_Object Field_2;
public static BlockDecryption.Class_75_Object Field_3; // Methods
static Class_75_Object()
{
byte[] buffer = new byte[0x120];
int num = 0x0;
while (num < 0x90)
{
buffer[num++] = 0x8;
}
while (num < 0x100)
{
buffer[num++] = 0x9;
}
while (num < 0x118)
{
buffer[num++] = 0x7;
}
while (num < 0x120)
{
buffer[num++] = 0x8;
}
Field_2 = new BlockDecryption.Class_75_Object(buffer);
buffer = new byte[0x20];
num = 0x0;
while (num < 0x20)
{
buffer[num++] = 0x5;
}
Field_3 = new BlockDecryption.Class_75_Object(buffer);
} public Class_75_Object(byte[] buffer1)
{
this.Method_0(buffer1);
} private void Method_0(byte[] buffer1)
{
int[] numArray = new int[Field_0 + 0x1];
int[] numArray2 = new int[Field_0 + 0x1];
for (int i = 0x0; i < buffer1.Length; i++)
{
int index = buffer1[i];
if (index > 0x0)
{
numArray[index]++;
}
}
int num3 = 0x0;
int num4 = 0x200;
for (int j = 0x1; j <= Field_0; j++)
{
numArray2[j] = num3;
num3 += numArray[j] << (0x10 - j);
if (j >= 0xa)
{
int num6 = numArray2[j] & 0x1ff80;
int num7 = num3 & 0x1ff80;
num4 += (num7 - num6) >> (0x10 - j);
}
}
this.Field_1 = new short[num4];
int num8 = 0x200;
for (int k = Field_0; k >= 0xa; k--)
{
int num10 = num3 & 0x1ff80;
num3 -= numArray[k] << (0x10 - k);
int num11 = num3 & 0x1ff80;
for (int n = num11; n < num10; n += 0x80)
{
this.Field_1[BlockDecryption.Class_78_Object.Method_0(n)] = (short)((-num8 << 0x4) | k);
num8 += ((int)0x1) << (k - 0x9);
}
}
for (int m = 0x0; m < buffer1.Length; m++)
{
int num14 = buffer1[m];
if (num14 != 0x0)
{
num3 = numArray2[num14];
int num15 = BlockDecryption.Class_78_Object.Method_0(num3);
if (num14 <= 0x9)
{
do
{
this.Field_1[num15] = (short)((m << 0x4) | num14);
num15 += ((int)0x1) << num14;
}
while (num15 < 0x200);
}
else
{
int num16 = this.Field_1[num15 & 0x1ff];
int num17 = ((int)0x1) << (num16 & 0xf);
num16 = -(num16 >> 0x4);
do
{
this.Field_1[num16 | (num15 >> 0x9)] = (short)((m << 0x4) | num14);
num15 += ((int)0x1) << num14;
}
while (num15 < num17);
}
numArray2[num14] = num3 + (((int)0x1) << (0x10 - num14));
}
}
} public int Method_1(BlockDecryption.Class_73_Object obj1)
{
int num2;
int index = obj1.Method_0(0x9);
if (index >= 0x0)
{
num2 = this.Field_1[index];
if (num2 >= 0x0)
{
obj1.Method_1(num2 & 0xf);
return (num2 >> 0x4);
}
int num3 = -(num2 >> 0x4);
int num4 = num2 & 0xf;
index = obj1.Method_0(num4);
if (index >= 0x0)
{
num2 = this.Field_1[num3 | (index >> 0x9)];
obj1.Method_1(num2 & 0xf);
return (num2 >> 0x4);
}
int num5 = obj1.Method_2();
index = obj1.Method_0(num5);
num2 = this.Field_1[num3 | (index >> 0x9)];
if ((num2 & 0xf) <= num5)
{
obj1.Method_1(num2 & 0xf);
return (num2 >> 0x4);
}
return -1;
}
int num6 = obj1.Method_2();
index = obj1.Method_0(num6);
num2 = this.Field_1[index];
if ((num2 >= 0x0) && ((num2 & 0xf) <= num6))
{
obj1.Method_1(num2 & 0xf);
return (num2 >> 0x4);
}
return -1;
}
}
class Class_76_Object
{
// Fields
private static readonly int[] Field_0 = new int[] { 0x3, 0x3, 0xb };
private static readonly int[] Field_1 = new int[] { 0x2, 0x3, 0x7 };
private int Field_10;
private byte Field_11;
private int Field_12;
private static readonly int[] Field_13 = new int[] {
0x10, 0x11, 0x12, 0x0, 0x8, 0x7, 0x9, 0x6, 0xa, 0x5, 0xb, 0x4, 0xc, 0x3, 0xd, 0x2,
0xe, 0x1, 0xf
};
private byte[] Field_2;
private byte[] Field_3;
private BlockDecryption.Class_75_Object Field_4;
private int Field_5;
private int Field_6;
private int Field_7;
private int Field_8;
private int Field_9; // Methods
public bool Method_0(BlockDecryption.Class_73_Object obj1)
{
int num2;
int num3;
Label_0000:
switch (this.Field_5)
{
case 0x0:
this.Field_6 = obj1.Method_0(0x5);
if (this.Field_6 >= 0x0)
{
this.Field_6 += 0x101;
obj1.Method_1(0x5);
this.Field_5 = 0x1;
break;
}
return false; case 0x1:
break; case 0x2:
goto Label_00C7; case 0x3:
goto Label_0155; case 0x4:
goto Label_01C8; case 0x5:
goto Label_0204; default:
goto Label_0000;
}
this.Field_7 = obj1.Method_0(0x5);
if (this.Field_7 < 0x0)
{
return false;
}
this.Field_7++;
obj1.Method_1(0x5);
this.Field_9 = this.Field_6 + this.Field_7;
this.Field_3 = new byte[this.Field_9];
this.Field_5 = 0x2;
Label_00C7:
this.Field_8 = obj1.Method_0(0x4);
if (this.Field_8 < 0x0)
{
return false;
}
this.Field_8 += 0x4;
obj1.Method_1(0x4);
this.Field_2 = new byte[0x13];
this.Field_12 = 0x0;
this.Field_5 = 0x3;
Label_0155:
while (this.Field_12 < this.Field_8)
{
int num = obj1.Method_0(0x3);
if (num < 0x0)
{
return false;
}
obj1.Method_1(0x3);
this.Field_2[Field_13[this.Field_12]] = (byte)num;
this.Field_12++;
}
this.Field_4 = new BlockDecryption.Class_75_Object(this.Field_2);
this.Field_2 = null;
this.Field_12 = 0x0;
this.Field_5 = 0x4;
Label_01C8:
while (((num2 = this.Field_4.Method_1(obj1)) & 0xfffffff0) == 0x0)
{
this.Field_3[this.Field_12++] = this.Field_11 = (byte)num2;
if (this.Field_12 == this.Field_9)
{
return true;
}
}
if (num2 < 0x0)
{
return false;
}
if (num2 >= 0x11)
{
this.Field_11 = 0x0;
}
this.Field_10 = num2 - 0x10;
this.Field_5 = 0x5;
Label_0204:
num3 = Field_1[this.Field_10];
int num4 = obj1.Method_0(num3);
if (num4 < 0x0)
{
return false;
}
obj1.Method_1(num3);
num4 += Field_0[this.Field_10];
while (num4-- > 0x0)
{
this.Field_3[this.Field_12++] = this.Field_11;
}
if (this.Field_12 == this.Field_9)
{
return true;
}
this.Field_5 = 0x4;
goto Label_0000;
} public BlockDecryption.Class_75_Object Method_1()
{
byte[] destinationArray = new byte[this.Field_6];
Array.Copy(this.Field_3, 0x0, destinationArray, 0x0, this.Field_6);
return new BlockDecryption.Class_75_Object(destinationArray);
} public BlockDecryption.Class_75_Object Method_2()
{
byte[] destinationArray = new byte[this.Field_7];
Array.Copy(this.Field_3, this.Field_6, destinationArray, 0x0, this.Field_7);
return new BlockDecryption.Class_75_Object(destinationArray);
}
}
class Class_78_Object
{
static byte[] Field_9 = new byte[] { 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf };
public static short Method_0(int num1)
{
return (short)((((Field_9[num1 & 0xf] << 0xc) | (Field_9[(num1 >> 0x4) & 0xf] << 0x8)) | (Field_9[(num1 >> 0x8) & 0xf] << 0x4)) | Field_9[num1 >> 0xc]);
}
}
public static byte[] Decrypt(byte[] buffer1)
{
BinaryReader stream = new BinaryReader(new MemoryStream(buffer1));
byte[] buffer = new byte[0x0];
int num = stream.ReadInt32();
if (num == 0x4034b50)
{
short num2 = stream.ReadInt16();
int num3 = stream.ReadInt16();
int num4 = stream.ReadInt16();
if (((num != 0x4034b50) || (num2 != 0x14)) || ((num3 != 0x0) || (num4 != 0x8)))
{
throw new FormatException("Invalid?(1)");
}
stream.ReadInt32();
stream.ReadInt32();
stream.ReadInt32();
int num5 = stream.ReadInt32();
int count = stream.ReadInt16();
int num7 = stream.ReadInt16();
if (count > 0x0)
{
byte[] buffer2 = new byte[count];
stream.Read(buffer2, 0x0, count);
}
if (num7 > 0x0)
{
byte[] buffer3 = new byte[num7];
stream.Read(buffer3, 0x0, num7);
}
byte[] buffer4 = new byte[stream.BaseStream.Length - stream.BaseStream.Position];
stream.Read(buffer4, 0x0, buffer4.Length);
Class_72_Object obj2 = new Class_72_Object(buffer4);
buffer = new byte[num5];
obj2.Method_2(buffer, 0x0, buffer.Length);
buffer4 = null;
}
else
{
int num11;
if (num != 0x17d7a7b)
{
throw new FormatException("Invalid?(2)");
}
int num8 = stream.ReadInt32();
buffer = new byte[num8];
for (int i = 0x0; i < num8; i += num11)
{
int num10 = stream.ReadInt32();
num11 = stream.ReadInt32();
byte[] buffer5 = new byte[num10];
stream.Read(buffer5, 0x0, buffer5.Length);
new Class_72_Object(buffer5).Method_2(buffer, i, num11);
}
}
stream.Close();
stream = null;
return buffer;
}
}

You want to upload the file you are having trouble with? I can take a look at it.

Edited by high6
Link to comment

Also would be cool if you made it options in desmart. So that you can choose the decrypt string and/or anti control flow and/or renaming.

Also something I added to my code.

Instruction GetNext(Instruction ins)
{
ins = ins.Next;
while (ins != null && (ins.OpCode == OpCodes.Br || ins.OpCode == OpCodes.Br_S))
{
ins = ins.Operand as Instruction;
}
return ins;
}

Because control flow obfuscation is applied after string encryption so sometimes you get.

ldc 435

br somewhere

call stringdecrypt

Link to comment

@high6:

Thanx for your code. But your code maybe doesn't work with this file.

http://reteam.org/board/showthread.php?t=1386

Please use the original file at that thread. The file I posted was strong-name-removed. It has no PublickKeyToken anymore which leads to error in decryption. When you work with this file you can find out that your FindDecryptMethod won't work.

Edited by rongchaua
Link to comment

You have to decrypt the strings before removing the strongname. After you remove strongname it messes with the metadatatokens so you can't decrypt the strings.

Link to comment

@high6: Thank you for your help. I can already finish my DeSmart. http://rongchaua.net/tools-mainmenu-36/85-...r-smartassembly.

After removing strong name the metadatatoken of decrypt function was also changed therefore when I applied your code, it gave false result back.

I did not think that value will be changed if we removed strong name. But now it's ok. I can already decrypt the string.

Link to comment
  • 1 month later...
  • 1 year later...

4.2 just added DES on top of the current encryption.

int id = num & 0xFFFFFF;
int type = num >> 24;
if (num != 0x7d7a7b)
{
throw new FormatException("Invalid resource header");
}
if (type == 1)
{
int num11;
int num8 = stream.ReadInt32();
buffer = new byte[num8];
for (int i = 0x0; i < num8; i += num11)
{
int num10 = stream.ReadInt32();
num11 = stream.ReadInt32();
byte[] buffer5 = new byte[num10];
stream.Read(buffer5, 0x0, buffer5.Length);
new Class_72_Object(buffer5).Method_2(buffer, i, num11);
}
}
else if (type == 2)
{
DESCryptoServiceProvider provider = new DESCryptoServiceProvider {
Key = new byte[] { 0x47, 0xc9, 0x24, 0xd4, 0x6d, 0x39, 0x2f, 0x4d },
IV = new byte[] { 0xca, 0x9d, 5, 0xef, 0x6d, 20, 0xdf, 13 }
};
byte[] buffer6 = provider.CreateDecryptor().TransformFinalBlock(buffer1, 4, buffer1.Length - 4);
provider.Clear();
buffer = Decrypt(buffer6); }
else
{
throw new FormatException("Invalid resource type");
}

Key/IV are different for every executable though.

Link to comment

Any idea how to retrieve the correct offset of the decrypted strings? They seem to differ between every exe I try decrypting.

Edit: 5.0 RC1 is also the same, by the way.

Edited by bball0002
Link to comment

Any idea how to retrieve the correct offset of the decrypted strings? They seem to differ between every exe I try decrypting.

Edit: 5.0 RC1 is also the same, by the way.

Haven't looked at 5.0 yet.

4.2 uses delegates. It calls a method which then checks the callers class for a delegate and creates a dynamic method which calls the decrypt function.

I can pass you a deobfuscated 4.2(removed control flow, removed invokes) if you like. I am going to check out 5.0 later.

Edited by high6
Link to comment

Haven't looked at 5.0 yet.

4.2 uses delegates. It calls a method which then checks the callers class for a delegate and creates a dynamic method which calls the decrypt function.

I can pass you a deobfuscated 4.2(removed control flow, removed invokes) if you like. I am going to check out 5.0 later.

I have it deobbed (invokes too thanks to your tool), but thank you for the info. And I can decrypt strings in 5.0 the same way as 4.2, so I'm pretty sure it's done the exact same way.

Edited by bball0002
Link to comment

I have it deobbed (invokes too thanks to your tool), but thank you for the info. And I can decrypt strings in 5.0 the same way as 4.2, so I'm pretty sure it's done the exact same way.

So whats wrong with the offsets then? Cause I have tried multiple exes and my deober decrypts the strings fine.

Link to comment

So whats wrong with the offsets then? Cause I have tried multiple exes and my deober decrypts the strings fine.

Oh, I can decrypt strings fine. It's just that the offset of the string in the resource doesn't match the ID that is passed by the exe. For example, look at this code:


L_01a6: ldc.i4 0xe8c2
L_01ab: call instance string .::Invoke(int32)
L_01b0: call instance bool ::Invoke(string, string)

But that ID (0xe8c2) differs from the offset of the string in the resources. Just wondering if you knew anything about that, or if it's my code that is bad.

Link to comment

Oh, I can decrypt strings fine. It's just that the offset of the string in the resource doesn't match the ID that is passed by the exe. For example, look at this code:


L_01a6: ldc.i4 0xe8c2
L_01ab: call instance string .::Invoke(int32)
L_01b0: call instance bool ::Invoke(string, string)

But that ID (0xe8c2) differs from the offset of the string in the resources. Just wondering if you knew anything about that, or if it's my code that is bad.

You are forgetting to subtract the metadatatoken of the delegate.

iLGenerator.Emit(OpCodes.Ldc_I4, (int) (info.MetadataToken & 0xffffff));
iLGenerator.Emit(OpCodes.Sub);
Edited by high6
Link to comment
  • 4 months later...

found this while playing around with sa ,)


static c000015()
{
byte[] buffer = null;
int num = 0;
Stream stream = null;
Assembly assembly = null;
c000003.m000001();
f000030 = "1";
f000031 = "15";
f000015 = null;
f000032 = null;
f000033 = false;
f000009 = 0;
if (delegate690.f000474(f000030, "1"))
{
f000033 = true;
f000032 = new Hashtable();
}
f000009 = delegate862.f0006fb(f000031);
assembly = delegate949.f0007c8();
stream = delegate626.f0003ad(assembly, "{aca30f4f-64c2-49c8-890c-2fc6511c5bc8}");
try
{
num = delegate860.f0006f8(delegate863.f0006ff(stream));
buffer = new byte[num];
delegate822.f00068d(stream, buffer, 0, num);
f000015 = c000007.m000003(buffer);
buffer = null;
delegate656.f00040a(stream);
}
finally
{
if (stream != null)
{
delegate656.f00042a(stream);
}
}
}

---------------------------------------------------------

the delegates

The delegates call m000002() with the address ;) like :

]static delegate949()
{
c000004.m000002(0x3b4);
}public static void m000002(int p0)
{
int arg = 0;
ILGenerator iLGenerator = null;
DynamicMethod method = null;
int index = 0;
Type[] parameterTypes = null;
int num4 = 0;
ParameterInfo[] parameters = null;
Delegate delegate2 = null;
MethodInfo methodFromHandle = null;
int num3 = 0;
char ch = ' ';
int num2 = 0;
int num = 0;
bool flag = false;
string name = null;
info = null;
Type owner = null;
try
{
owner = Type.GetTypeFromHandle(f000001.ResolveTypeHandle(0x2000001 + p0));
}
catch
{
return;
}
foreach (FieldInfo info in owner.GetFields(BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Static))
{
name = info.Name;
flag = false;
num = 0;
for (num2 = name.Length - 1; num2 >= 0; num2--)
{
ch = name[num2];
if (ch == '~')
{
flag = true;
break;
}
for (num3 = 0; num3 < 0x3a; num3++)
{
if (f000002[num3] == ch)
{
num = (num * 0x3a) + num3;
break;
}
}
}
try
{
methodFromHandle = (MethodInfo) MethodBase.GetMethodFromHandle(f000001.ResolveMethodHandle(num + 0xa000001));
}
catch
{
goto Label_027C;
}
if (methodFromHandle.IsStatic)
{
try
{
delegate2 = Delegate.CreateDelegate(info.FieldType, methodFromHandle);
goto Label_0268;
}
catch (Exception)
{
goto Label_027C;
}
}
parameters = methodFromHandle.GetParameters();
num4 = parameters.Length + 1;
parameterTypes = new Type[num4];
parameterTypes[0] = typeof(object);
for (index = 1; index < num4; index++)
{
parameterTypes[index] = parameters[index - 1].ParameterType;
}
method = new DynamicMethod(string.Empty, methodFromHandle.ReturnType, parameterTypes, owner, true);
iLGenerator = method.GetILGenerator();
iLGenerator.Emit(OpCodes.Ldarg_0);
if (num4 > 1)
{
iLGenerator.Emit(OpCodes.Ldarg_1);
}
if (num4 > 2)
{
iLGenerator.Emit(OpCodes.Ldarg_2);
}
if (num4 > 3)
{
iLGenerator.Emit(OpCodes.Ldarg_3);
}
if (num4 > 4)
{
for (arg = 4; arg < num4; arg++)
{
iLGenerator.Emit(OpCodes.Ldarg_S, arg);
}
}
iLGenerator.Emit(flag ? OpCodes.Callvirt : OpCodes.Call, methodFromHandle);
iLGenerator.Emit(OpCodes.Ret);
try
{
delegate2 = method.CreateDelegate(owner);
}
catch
{
goto Label_027C;
}
Label_0268:
try
{
info.SetValue(null, delegate2);
}
catch
{
}
Label_027C:;
}
}public static byte[] m000003(byte[] p0)
{
byte[] buffer5 = null;
DESCryptoServiceProvider provider = null;
byte[] buffer6 = null;
int num12 = 0;
int num11 = 0;
int num10 = 0;
int num9 = 0;
int num8 = 0;
c000008 c = null;
byte[] buffer4 = null;
byte[] buffer3 = null;
byte[] buffer2 = null;
int count = 0;
int num6 = 0;
int num5 = 0;
int num4 = 0;
int num3 = 0;
short num2 = 0;
int num = 0;
byte[] buffer = null;
c00000e ce = null;
ce = new c00000e(p0);
buffer = new byte[0];
num = ce.m00000a();
if (num == 0x4034b50)
{
num2 = (short) ce.m000009();
num3 = ce.m000009();
num4 = ce.m000009();
if (((num != 0x4034b50) || (num2 != 20)) || ((num3 != 0) || (num4 != 8)))
{
throw new FormatException("Wrong Header Signature");
}
ce.m00000a();
ce.m00000a();
ce.m00000a();
num5 = ce.m00000a();
num6 = ce.m000009();
count = ce.m000009();
if (num6 > 0)
{
buffer2 = new byte[num6];
ce.Read(buffer2, 0, num6);
}
if (count > 0)
{
buffer3 = new byte[count];
ce.Read(buffer3, 0, count);
}
buffer4 = new byte[ce.Length - ce.Position];
ce.Read(buffer4, 0, buffer4.Length);
c = new c000008(buffer4);
buffer = new byte[num5];
c.m000006(buffer, 0, buffer.Length);
buffer4 = null;
}
else
{
num8 = num >> 0x18;
num -= num8 << 0x18;
if (num != 0x7d7a7b)
{
throw new FormatException("Unknown Header");
}
switch (num8)
{
case 1:
num9 = ce.m00000a();
buffer = new byte[num9];
for (num10 = 0; num10 < num9; num10 += num12)
{
num11 = ce.m00000a();
num12 = ce.m00000a();
buffer5 = new byte[num11];
ce.Read(buffer5, 0, buffer5.Length);
new c000008(buffer5).m000006(buffer, num10, num12);
}
break; case 2:
provider = new DESCryptoServiceProvider();
provider.Key = new byte[] { 0x2e, 80, 0x72, 0x61, 0x63, 0x74, 0x69, 0x63 };
provider.IV = new byte[] { 0x65, 0x73, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6f };
buffer6 = provider.CreateDecryptor().TransformFinalBlock(p0, 4, p0.Length - 4);
provider.Clear();
buffer = m000003(buffer6);
goto Label_025B;
}
}
Label_025B:
ce.Close();
ce = null;
return buffer;
}

stream.rar

Edited by sirp
Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...