2011-11-01 02:40:57 +08:00
/ *
2012-01-10 06:02:47 +08:00
Copyright ( C ) 2011 - 2012 de4dot @gmail . com
2011-11-01 02:40:57 +08:00
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.Collections.Generic ;
using Mono.Cecil ;
using Mono.Cecil.Cil ;
2012-01-27 05:40:19 +08:00
using Mono.Cecil.Metadata ;
2011-11-01 02:40:57 +08:00
using de4dot.blocks ;
2011-12-09 16:02:06 +08:00
namespace de4dot.code.deobfuscators {
2011-11-01 02:40:57 +08:00
// Restore the type of all fields / parameters that have had their type turned into object.
// This thing requires a lot more code than I have time to do now (similar to symbol renaming)
// so it will be a basic implementation only.
class TypesRestorer {
ModuleDefinition module ;
2011-11-01 06:58:19 +08:00
List < MethodDefinition > allMethods ;
2011-11-01 09:22:05 +08:00
Dictionary < ParameterDefinition , TypeInfo < ParameterDefinition > > argInfos = new Dictionary < ParameterDefinition , TypeInfo < ParameterDefinition > > ( ) ;
TypeInfo < ParameterDefinition > methodReturnInfo ;
Dictionary < FieldReferenceAndDeclaringTypeKey , TypeInfo < FieldDefinition > > fieldWrites = new Dictionary < FieldReferenceAndDeclaringTypeKey , TypeInfo < FieldDefinition > > ( ) ;
2011-11-04 02:46:29 +08:00
Dictionary < int , UpdatedMethod > updatedMethods = new Dictionary < int , UpdatedMethod > ( ) ;
Dictionary < int , UpdatedField > updatedFields = new Dictionary < int , UpdatedField > ( ) ;
class UpdatedMethod {
public int token ;
public TypeReference [ ] newArgTypes ;
public TypeReference newReturnType ;
public UpdatedMethod ( MethodDefinition method ) {
token = method . MetadataToken . ToInt32 ( ) ;
newArgTypes = new TypeReference [ DotNetUtils . getArgsCount ( method ) ] ;
}
}
class UpdatedField {
public int token ;
public TypeReference newFieldType ;
public UpdatedField ( FieldDefinition field ) {
token = field . MetadataToken . ToInt32 ( ) ;
}
}
2011-11-01 02:40:57 +08:00
2011-11-01 09:22:05 +08:00
class TypeInfo < T > {
2011-11-04 15:22:25 +08:00
Dictionary < TypeReferenceKey , bool > types = new Dictionary < TypeReferenceKey , bool > ( ) ;
2011-11-01 06:58:19 +08:00
public TypeReference newType = null ;
2011-11-01 09:22:05 +08:00
public T arg ;
2011-11-04 15:22:25 +08:00
bool newobjTypes ;
public Dictionary < TypeReferenceKey , bool > Types {
get { return types ; }
}
2011-11-01 06:58:19 +08:00
2011-11-01 09:22:05 +08:00
public TypeInfo ( T arg ) {
2011-11-01 06:58:19 +08:00
this . arg = arg ;
}
2011-11-04 15:22:25 +08:00
public void add ( TypeReference type , bool wasNewobj = false ) {
if ( wasNewobj ) {
if ( ! newobjTypes )
clear ( ) ;
newobjTypes = true ;
}
else if ( newobjTypes )
return ;
types [ new TypeReferenceKey ( type ) ] = true ;
}
public void clear ( ) {
types . Clear ( ) ;
}
2011-11-04 07:09:51 +08:00
public bool updateNewType ( ModuleDefinition module ) {
2011-11-01 09:22:05 +08:00
if ( types . Count = = 0 )
return false ;
TypeReference theNewType = null ;
foreach ( var key in types . Keys ) {
if ( theNewType = = null ) {
theNewType = key . TypeReference ;
continue ;
}
2011-11-04 07:09:51 +08:00
theNewType = getCommonBaseClass ( module , theNewType , key . TypeReference ) ;
2011-11-01 09:22:05 +08:00
if ( theNewType = = null )
break ;
}
if ( theNewType = = null )
return false ;
if ( MemberReferenceHelper . compareTypes ( theNewType , newType ) )
return false ;
2011-11-01 02:40:57 +08:00
2011-11-01 09:22:05 +08:00
newType = theNewType ;
return true ;
2011-11-01 02:40:57 +08:00
}
}
public TypesRestorer ( ModuleDefinition module ) {
this . module = module ;
}
2011-11-04 02:46:29 +08:00
UpdatedMethod getUpdatedMethod ( MethodDefinition method ) {
int token = method . MetadataToken . ToInt32 ( ) ;
UpdatedMethod updatedMethod ;
if ( updatedMethods . TryGetValue ( token , out updatedMethod ) )
return updatedMethod ;
return updatedMethods [ token ] = new UpdatedMethod ( method ) ;
}
UpdatedField getUpdatedField ( FieldDefinition field ) {
int token = field . MetadataToken . ToInt32 ( ) ;
UpdatedField updatedField ;
if ( updatedFields . TryGetValue ( token , out updatedField ) )
return updatedField ;
return updatedFields [ token ] = new UpdatedField ( field ) ;
}
2011-11-01 02:40:57 +08:00
public void deobfuscate ( ) {
2011-11-01 06:58:19 +08:00
allMethods = new List < MethodDefinition > ( ) ;
foreach ( var type in module . GetTypes ( ) )
allMethods . AddRange ( type . Methods ) ;
2011-11-01 02:40:57 +08:00
foreach ( var type in module . GetTypes ( ) ) {
foreach ( var field in type . Fields ) {
if ( ! MemberReferenceHelper . isSystemObject ( field . FieldType ) )
continue ;
var key = new FieldReferenceAndDeclaringTypeKey ( field ) ;
2011-11-01 09:22:05 +08:00
fieldWrites [ key ] = new TypeInfo < FieldDefinition > ( field ) ;
2011-11-01 02:40:57 +08:00
}
}
for ( int i = 0 ; i < 10 ; i + + ) {
2011-11-01 06:58:19 +08:00
bool changed = false ;
changed | = deobfuscateFields ( ) ;
changed | = deobfuscateMethods ( ) ;
if ( ! changed )
2011-11-01 02:40:57 +08:00
break ;
}
2011-11-01 06:58:19 +08:00
2011-11-04 02:46:29 +08:00
var fields = new List < UpdatedField > ( updatedFields . Values ) ;
if ( fields . Count > 0 ) {
Log . v ( "Changing field types from object -> real type" ) ;
2011-11-21 17:32:36 +08:00
fields . Sort ( ( a , b ) = > Utils . compareInt32 ( a . token , b . token ) ) ;
2011-11-04 02:46:29 +08:00
Log . indent ( ) ;
foreach ( var updatedField in fields )
2012-01-04 02:52:40 +08:00
Log . v ( "Field {0:X8}: type {1} ({2:X8})" , updatedField . token , Utils . removeNewlines ( updatedField . newFieldType . FullName ) , updatedField . newFieldType . MetadataToken . ToInt32 ( ) ) ;
2011-11-04 02:46:29 +08:00
Log . deIndent ( ) ;
2011-11-01 06:58:19 +08:00
}
2011-11-04 02:46:29 +08:00
var methods = new List < UpdatedMethod > ( updatedMethods . Values ) ;
if ( methods . Count > 0 ) {
Log . v ( "Changing method args and return types from object -> real type" ) ;
2011-11-21 17:32:36 +08:00
methods . Sort ( ( a , b ) = > Utils . compareInt32 ( a . token , b . token ) ) ;
2011-11-01 09:22:05 +08:00
Log . indent ( ) ;
2011-11-04 02:46:29 +08:00
foreach ( var updatedMethod in methods ) {
Log . v ( "Method {0:X8}" , updatedMethod . token ) ;
Log . indent ( ) ;
if ( updatedMethod . newReturnType ! = null )
2012-01-04 02:52:40 +08:00
Log . v ( "ret: {0} ({1:X8})" , Utils . removeNewlines ( updatedMethod . newReturnType . FullName ) , updatedMethod . newReturnType . MetadataToken . ToInt32 ( ) ) ;
2011-11-04 02:46:29 +08:00
for ( int i = 0 ; i < updatedMethod . newArgTypes . Length ; i + + ) {
var updatedArg = updatedMethod . newArgTypes [ i ] ;
if ( updatedArg = = null )
continue ;
2012-01-04 02:52:40 +08:00
Log . v ( "arg {0}: {1} ({2:X8})" , i , Utils . removeNewlines ( updatedArg . FullName ) , updatedArg . MetadataToken . ToInt32 ( ) ) ;
2011-11-01 09:22:05 +08:00
}
2011-11-04 02:46:29 +08:00
Log . deIndent ( ) ;
2011-11-01 09:22:05 +08:00
}
Log . deIndent ( ) ;
}
2011-11-04 02:46:29 +08:00
}
2011-11-01 06:58:19 +08:00
2011-11-04 02:46:29 +08:00
bool deobfuscateMethods ( ) {
bool changed = false ;
foreach ( var method in allMethods ) {
methodReturnInfo = new TypeInfo < ParameterDefinition > ( method . MethodReturnType . Parameter2 ) ;
deobfuscateMethod ( method ) ;
2011-11-04 07:09:51 +08:00
if ( methodReturnInfo . updateNewType ( module ) ) {
2011-11-04 02:46:29 +08:00
getUpdatedMethod ( method ) . newReturnType = methodReturnInfo . newType ;
method . MethodReturnType . ReturnType = methodReturnInfo . newType ;
2011-11-01 09:22:05 +08:00
changed = true ;
2011-11-01 06:58:19 +08:00
}
2011-11-01 09:22:05 +08:00
2011-11-04 02:46:29 +08:00
foreach ( var info in argInfos . Values ) {
2011-11-04 07:09:51 +08:00
if ( info . updateNewType ( module ) ) {
2012-01-22 03:31:47 +08:00
getUpdatedMethod ( method ) . newArgTypes [ DotNetUtils . getArgIndex ( info . arg ) ] = info . newType ;
2011-11-04 02:46:29 +08:00
info . arg . ParameterType = info . newType ;
changed = true ;
}
}
}
2011-11-01 06:58:19 +08:00
return changed ;
}
2011-11-01 09:22:05 +08:00
static int sortTypeInfos ( TypeInfo < ParameterDefinition > a , TypeInfo < ParameterDefinition > b ) {
2011-11-02 01:56:44 +08:00
if ( a . arg . Method . MetadataToken . ToInt32 ( ) < b . arg . Method . MetadataToken . ToInt32 ( ) ) return - 1 ;
if ( a . arg . Method . MetadataToken . ToInt32 ( ) > b . arg . Method . MetadataToken . ToInt32 ( ) ) return 1 ;
2012-01-22 03:31:47 +08:00
return Utils . compareInt32 ( a . arg . Sequence , b . arg . Sequence ) ;
2011-11-01 09:22:05 +08:00
}
2011-11-04 06:01:51 +08:00
class PushedArgs {
List < Instruction > args ;
int nextIndex ;
public bool CanAddMore {
get { return nextIndex > = 0 ; }
}
public int NumValidArgs {
get { return args . Count - ( nextIndex + 1 ) ; }
}
public PushedArgs ( int numArgs ) {
nextIndex = numArgs - 1 ;
args = new List < Instruction > ( numArgs ) ;
for ( int i = 0 ; i < numArgs ; i + + )
args . Add ( null ) ;
}
public void add ( Instruction instr ) {
args [ nextIndex - - ] = instr ;
}
public void set ( int i , Instruction instr ) {
args [ i ] = instr ;
}
public Instruction get ( int i ) {
2011-11-04 06:25:07 +08:00
if ( 0 < = i & & i < args . Count )
return args [ i ] ;
return null ;
2011-11-04 06:01:51 +08:00
}
public Instruction getEnd ( int i ) {
2011-11-04 06:25:07 +08:00
return get ( args . Count - 1 - i ) ;
2011-11-04 06:01:51 +08:00
}
public void fixDups ( ) {
Instruction prev = null , instr ;
for ( int i = 0 ; i < NumValidArgs ; i + + , prev = instr ) {
instr = args [ i ] ;
if ( instr = = null | | prev = = null )
continue ;
if ( instr . OpCode . Code ! = Code . Dup )
continue ;
args [ i ] = prev ;
instr = prev ;
}
}
}
2011-11-01 06:58:19 +08:00
void deobfuscateMethod ( MethodDefinition method ) {
if ( ! method . IsStatic | | method . Body = = null )
return ;
2011-11-01 09:22:05 +08:00
bool fixReturnType = MemberReferenceHelper . isSystemObject ( method . MethodReturnType . ReturnType ) ;
2011-11-01 06:58:19 +08:00
argInfos . Clear ( ) ;
foreach ( var arg in method . Parameters ) {
if ( arg . ParameterType = = null | | arg . ParameterType . IsValueType )
continue ;
if ( ! MemberReferenceHelper . isSystemObject ( arg . ParameterType ) )
continue ;
2011-11-01 09:22:05 +08:00
argInfos [ arg ] = new TypeInfo < ParameterDefinition > ( arg ) ;
2011-11-01 06:58:19 +08:00
}
2011-11-01 09:22:05 +08:00
if ( argInfos . Count = = 0 & & ! fixReturnType )
2011-11-01 06:58:19 +08:00
return ;
var methodParams = DotNetUtils . getParameters ( method ) ;
2011-11-04 06:01:51 +08:00
PushedArgs pushedArgs ;
2011-11-01 06:58:19 +08:00
var instructions = method . Body . Instructions ;
for ( int i = 0 ; i < instructions . Count ; i + + ) {
var instr = instructions [ i ] ;
switch ( instr . OpCode . Code ) {
2011-11-01 09:22:05 +08:00
case Code . Ret :
if ( ! fixReturnType )
break ;
2011-11-04 15:22:25 +08:00
bool wasNewobj ;
var type = getLoadedType ( method , instructions , i , out wasNewobj ) ;
2011-11-01 09:22:05 +08:00
if ( type = = null )
break ;
2011-11-04 15:22:25 +08:00
methodReturnInfo . add ( type ) ;
2011-11-01 09:22:05 +08:00
break ;
2011-11-01 06:58:19 +08:00
case Code . Call :
case Code . Calli :
case Code . Callvirt :
2011-11-04 07:09:51 +08:00
case Code . Newobj :
2011-11-04 06:01:51 +08:00
pushedArgs = getPushedArgInstructions ( instructions , i ) ;
2011-11-01 06:58:19 +08:00
var calledMethod = instr . Operand as MethodReference ;
if ( calledMethod = = null )
break ;
var calledMethodParams = DotNetUtils . getParameters ( calledMethod ) ;
2011-11-04 06:01:51 +08:00
for ( int j = 0 ; j < pushedArgs . NumValidArgs ; j + + ) {
2011-11-01 06:58:19 +08:00
int calledMethodParamIndex = calledMethodParams . Count - j - 1 ;
2011-11-04 06:01:51 +08:00
var ldInstr = pushedArgs . getEnd ( j ) ;
2011-11-01 06:58:19 +08:00
switch ( ldInstr . OpCode . Code ) {
case Code . Ldarg :
case Code . Ldarg_S :
case Code . Ldarg_0 :
case Code . Ldarg_1 :
case Code . Ldarg_2 :
case Code . Ldarg_3 :
2012-01-22 03:31:47 +08:00
addMethodArgType ( getParameter ( methodParams , ldInstr ) , DotNetUtils . getParameter ( calledMethodParams , calledMethodParamIndex ) ) ;
2011-11-01 06:58:19 +08:00
break ;
default :
break ;
}
}
break ;
case Code . Castclass :
2011-11-04 06:01:51 +08:00
pushedArgs = getPushedArgInstructions ( instructions , i ) ;
if ( pushedArgs . NumValidArgs < 1 )
2011-11-01 06:58:19 +08:00
break ;
2012-01-22 03:31:47 +08:00
addMethodArgType ( getParameter ( methodParams , pushedArgs . getEnd ( 0 ) ) , instr . Operand as TypeReference ) ;
2011-11-01 06:58:19 +08:00
break ;
case Code . Stloc :
case Code . Stloc_S :
case Code . Stloc_0 :
case Code . Stloc_1 :
case Code . Stloc_2 :
case Code . Stloc_3 :
2011-11-04 06:01:51 +08:00
pushedArgs = getPushedArgInstructions ( instructions , i ) ;
if ( pushedArgs . NumValidArgs < 1 )
2011-11-01 06:58:19 +08:00
break ;
2012-01-22 03:31:47 +08:00
addMethodArgType ( getParameter ( methodParams , pushedArgs . getEnd ( 0 ) ) , DotNetUtils . getLocalVar ( method . Body . Variables , instr ) ) ;
2011-11-01 06:58:19 +08:00
break ;
case Code . Stsfld :
2011-11-04 06:01:51 +08:00
pushedArgs = getPushedArgInstructions ( instructions , i ) ;
if ( pushedArgs . NumValidArgs < 1 )
2011-11-01 06:58:19 +08:00
break ;
2012-01-22 03:31:47 +08:00
addMethodArgType ( getParameter ( methodParams , pushedArgs . getEnd ( 0 ) ) , instr . Operand as FieldReference ) ;
2011-11-01 06:58:19 +08:00
break ;
case Code . Stfld :
2011-11-04 06:01:51 +08:00
pushedArgs = getPushedArgInstructions ( instructions , i ) ;
if ( pushedArgs . NumValidArgs > = 1 ) {
2011-11-01 06:58:19 +08:00
var field = instr . Operand as FieldReference ;
2012-01-22 03:31:47 +08:00
addMethodArgType ( getParameter ( methodParams , pushedArgs . getEnd ( 0 ) ) , field ) ;
2011-11-04 06:01:51 +08:00
if ( pushedArgs . NumValidArgs > = 2 & & field ! = null )
2012-01-22 03:31:47 +08:00
addMethodArgType ( getParameter ( methodParams , pushedArgs . getEnd ( 1 ) ) , field . DeclaringType ) ;
2011-11-01 06:58:19 +08:00
}
break ;
2011-11-01 22:53:51 +08:00
case Code . Ldfld :
case Code . Ldflda :
2011-11-04 06:01:51 +08:00
pushedArgs = getPushedArgInstructions ( instructions , i ) ;
if ( pushedArgs . NumValidArgs < 1 )
2011-11-01 22:53:51 +08:00
break ;
2012-01-22 03:31:47 +08:00
addMethodArgType ( getParameter ( methodParams , pushedArgs . getEnd ( 0 ) ) , instr . Operand as FieldReference ) ;
2011-11-01 22:53:51 +08:00
break ;
2011-11-01 06:58:19 +08:00
//TODO: For better results, these should be checked:
case Code . Starg :
case Code . Starg_S :
case Code . Ldelema :
case Code . Ldelem_Any :
case Code . Ldelem_I :
case Code . Ldelem_I1 :
case Code . Ldelem_I2 :
case Code . Ldelem_I4 :
case Code . Ldelem_I8 :
case Code . Ldelem_R4 :
case Code . Ldelem_R8 :
case Code . Ldelem_Ref :
case Code . Ldelem_U1 :
case Code . Ldelem_U2 :
case Code . Ldelem_U4 :
case Code . Ldind_I :
case Code . Ldind_I1 :
case Code . Ldind_I2 :
case Code . Ldind_I4 :
case Code . Ldind_I8 :
case Code . Ldind_R4 :
case Code . Ldind_R8 :
case Code . Ldind_Ref :
case Code . Ldind_U1 :
case Code . Ldind_U2 :
case Code . Ldind_U4 :
case Code . Ldobj :
case Code . Stelem_Any :
case Code . Stelem_I :
case Code . Stelem_I1 :
case Code . Stelem_I2 :
case Code . Stelem_I4 :
case Code . Stelem_I8 :
case Code . Stelem_R4 :
case Code . Stelem_R8 :
case Code . Stelem_Ref :
case Code . Stind_I :
case Code . Stind_I1 :
case Code . Stind_I2 :
case Code . Stind_I4 :
case Code . Stind_I8 :
case Code . Stind_R4 :
case Code . Stind_R8 :
case Code . Stind_Ref :
case Code . Stobj :
default :
break ;
}
}
}
2012-01-22 03:31:47 +08:00
static ParameterDefinition getParameter ( IList < ParameterDefinition > parameters , Instruction instr ) {
2011-11-01 06:58:19 +08:00
switch ( instr . OpCode . Code ) {
case Code . Ldarg :
case Code . Ldarg_S :
case Code . Ldarg_0 :
case Code . Ldarg_1 :
case Code . Ldarg_2 :
case Code . Ldarg_3 :
2012-01-22 03:31:47 +08:00
return DotNetUtils . getParameter ( parameters , instr ) ;
2011-11-01 06:58:19 +08:00
default :
return null ;
}
}
bool addMethodArgType ( ParameterDefinition methodParam , FieldReference field ) {
if ( field = = null )
return false ;
return addMethodArgType ( methodParam , field . FieldType ) ;
}
bool addMethodArgType ( ParameterDefinition methodParam , VariableDefinition otherLocal ) {
if ( otherLocal = = null )
return false ;
return addMethodArgType ( methodParam , otherLocal . VariableType ) ;
}
bool addMethodArgType ( ParameterDefinition methodParam , ParameterDefinition otherParam ) {
if ( otherParam = = null )
return false ;
return addMethodArgType ( methodParam , otherParam . ParameterType ) ;
}
bool addMethodArgType ( ParameterDefinition methodParam , TypeReference type ) {
if ( methodParam = = null | | type = = null )
return false ;
2011-11-01 09:22:05 +08:00
if ( ! isValidType ( type ) )
2011-11-01 06:58:19 +08:00
return false ;
2011-11-01 09:22:05 +08:00
TypeInfo < ParameterDefinition > info ;
2011-11-01 06:58:19 +08:00
if ( ! argInfos . TryGetValue ( methodParam , out info ) )
return false ;
2011-11-04 15:22:25 +08:00
if ( info . Types . ContainsKey ( new TypeReferenceKey ( type ) ) )
2011-11-01 06:58:19 +08:00
return false ;
2011-11-04 15:22:25 +08:00
info . add ( type ) ;
2011-11-01 06:58:19 +08:00
return true ;
}
// May not return all args. The args are returned in reverse order.
2011-11-04 06:01:51 +08:00
PushedArgs getPushedArgInstructions ( IList < Instruction > instructions , int index ) {
2011-11-04 14:43:24 +08:00
try {
int pushes , pops ;
DotNetUtils . calculateStackUsage ( instructions [ index ] , false , out pushes , out pops ) ;
if ( pops ! = - 1 )
return getPushedArgInstructions ( instructions , index , pops ) ;
}
catch ( System . NullReferenceException ) {
// Here if eg. invalid metadata token in a call instruction (operand is null)
}
return new PushedArgs ( 0 ) ;
2011-11-01 06:58:19 +08:00
}
// May not return all args. The args are returned in reverse order.
2011-11-04 06:01:51 +08:00
PushedArgs getPushedArgInstructions ( IList < Instruction > instructions , int index , int numArgs ) {
var pushedArgs = new PushedArgs ( numArgs ) ;
2011-11-01 06:58:19 +08:00
2011-11-04 06:01:51 +08:00
Instruction instr ;
2011-11-01 06:58:19 +08:00
int skipPushes = 0 ;
2011-11-04 06:01:51 +08:00
while ( index > = 0 & & pushedArgs . CanAddMore ) {
instr = getPreviousInstruction ( instructions , ref index ) ;
2011-11-01 06:58:19 +08:00
if ( instr = = null )
break ;
int pushes , pops ;
DotNetUtils . calculateStackUsage ( instr , false , out pushes , out pops ) ;
if ( pops = = - 1 )
break ;
2011-11-04 06:01:51 +08:00
if ( instr . OpCode . Code = = Code . Dup ) {
pushes = 1 ;
pops = 0 ;
}
2011-11-01 06:58:19 +08:00
if ( pushes > 1 )
2011-11-04 06:01:51 +08:00
break ;
2011-11-01 06:58:19 +08:00
if ( skipPushes > 0 ) {
skipPushes - = pushes ;
if ( skipPushes < 0 )
break ;
skipPushes + = pops ;
}
else {
if ( pushes = = 1 )
2011-11-04 06:01:51 +08:00
pushedArgs . add ( instr ) ;
2011-11-01 06:58:19 +08:00
skipPushes + = pops ;
}
}
2011-11-04 06:01:51 +08:00
instr = pushedArgs . get ( 0 ) ;
if ( instr ! = null & & instr . OpCode . Code = = Code . Dup ) {
instr = getPreviousInstruction ( instructions , ref index ) ;
if ( instr ! = null ) {
int pushes , pops ;
DotNetUtils . calculateStackUsage ( instr , false , out pushes , out pops ) ;
if ( pushes = = 1 & & pops = = 0 )
pushedArgs . set ( 0 , instr ) ;
}
}
pushedArgs . fixDups ( ) ;
2011-11-01 06:58:19 +08:00
2011-11-04 06:01:51 +08:00
return pushedArgs ;
2011-11-01 06:58:19 +08:00
}
bool deobfuscateFields ( ) {
2011-11-01 02:40:57 +08:00
foreach ( var info in fieldWrites . Values )
2011-11-04 15:22:25 +08:00
info . clear ( ) ;
2011-11-01 02:40:57 +08:00
foreach ( var method in allMethods ) {
if ( method . Body = = null )
continue ;
var instructions = method . Body . Instructions ;
for ( int i = 0 ; i < instructions . Count ; i + + ) {
var instr = instructions [ i ] ;
2011-11-04 06:01:51 +08:00
TypeReference fieldType = null ;
TypeInfo < FieldDefinition > info = null ;
FieldReference field ;
switch ( instr . OpCode . Code ) {
case Code . Stfld :
case Code . Stsfld :
field = instr . Operand as FieldReference ;
if ( field = = null )
continue ;
if ( ! fieldWrites . TryGetValue ( new FieldReferenceAndDeclaringTypeKey ( field ) , out info ) )
continue ;
2011-11-04 15:22:25 +08:00
bool wasNewobj ;
fieldType = getLoadedType ( method , instructions , i , out wasNewobj ) ;
2011-11-04 06:01:51 +08:00
if ( fieldType = = null )
continue ;
2011-11-04 15:22:25 +08:00
info . add ( fieldType , wasNewobj ) ;
2011-11-04 06:01:51 +08:00
break ;
2011-11-01 02:40:57 +08:00
2011-11-04 06:01:51 +08:00
case Code . Call :
case Code . Calli :
case Code . Callvirt :
case Code . Newobj :
var pushedArgs = getPushedArgInstructions ( instructions , i ) ;
var calledMethod = instr . Operand as MethodReference ;
if ( calledMethod = = null )
continue ;
IList < TypeReference > calledMethodArgs = DotNetUtils . getArgs ( calledMethod ) ;
calledMethodArgs = DotNetUtils . replaceGenericParameters ( calledMethod . DeclaringType as GenericInstanceType , calledMethod as GenericInstanceMethod , calledMethodArgs ) ;
for ( int j = 0 ; j < pushedArgs . NumValidArgs ; j + + ) {
var pushInstr = pushedArgs . getEnd ( j ) ;
if ( pushInstr . OpCode . Code ! = Code . Ldfld & & pushInstr . OpCode . Code ! = Code . Ldsfld )
continue ;
field = pushInstr . Operand as FieldReference ;
if ( field = = null )
continue ;
if ( ! fieldWrites . TryGetValue ( new FieldReferenceAndDeclaringTypeKey ( field ) , out info ) )
continue ;
fieldType = calledMethodArgs [ calledMethodArgs . Count - 1 - j ] ;
if ( ! isValidType ( fieldType ) )
continue ;
2011-11-04 15:22:25 +08:00
info . add ( fieldType ) ;
2011-11-04 06:01:51 +08:00
}
break ;
2011-11-01 02:40:57 +08:00
2011-11-04 06:01:51 +08:00
default :
2011-11-01 02:40:57 +08:00
continue ;
2011-11-04 06:01:51 +08:00
}
2011-11-01 09:22:05 +08:00
}
}
2011-11-01 02:40:57 +08:00
2011-11-01 09:22:05 +08:00
bool changed = false ;
2011-11-04 02:46:29 +08:00
var removeThese = new List < FieldDefinition > ( ) ;
foreach ( var info in fieldWrites . Values ) {
2011-11-04 07:09:51 +08:00
if ( info . updateNewType ( module ) ) {
2011-11-04 02:46:29 +08:00
removeThese . Add ( info . arg ) ;
getUpdatedField ( info . arg ) . newFieldType = info . newType ;
info . arg . FieldType = info . newType ;
changed = true ;
}
}
foreach ( var field in removeThese )
fieldWrites . Remove ( new FieldReferenceAndDeclaringTypeKey ( field ) ) ;
2011-11-01 09:22:05 +08:00
return changed ;
}
2011-11-01 02:40:57 +08:00
2011-11-04 15:22:25 +08:00
TypeReference getLoadedType ( MethodDefinition method , IList < Instruction > instructions , int instrIndex , out bool wasNewobj ) {
wasNewobj = false ;
2011-11-04 06:01:51 +08:00
var pushedArgs = getPushedArgInstructions ( instructions , instrIndex ) ;
2011-11-04 06:25:07 +08:00
var pushInstr = pushedArgs . getEnd ( 0 ) ;
2011-11-04 06:01:51 +08:00
if ( pushInstr = = null )
2011-11-01 09:22:05 +08:00
return null ;
2011-11-01 02:40:57 +08:00
2011-11-01 09:22:05 +08:00
TypeReference fieldType ;
2011-11-04 06:01:51 +08:00
switch ( pushInstr . OpCode . Code ) {
2011-11-01 09:22:05 +08:00
case Code . Ldstr :
fieldType = module . TypeSystem . String ;
break ;
case Code . Call :
case Code . Calli :
case Code . Callvirt :
2011-11-04 06:01:51 +08:00
var calledMethod = pushInstr . Operand as MethodReference ;
2011-11-01 09:22:05 +08:00
if ( calledMethod = = null )
return null ;
fieldType = calledMethod . MethodReturnType . ReturnType ;
break ;
2011-11-01 02:40:57 +08:00
2011-11-01 09:22:05 +08:00
case Code . Newarr :
2011-11-04 06:01:51 +08:00
fieldType = pushInstr . Operand as TypeReference ;
2011-11-01 09:22:05 +08:00
if ( fieldType = = null )
return null ;
fieldType = new ArrayType ( fieldType ) ;
2011-11-04 15:22:25 +08:00
wasNewobj = true ;
2011-11-01 09:22:05 +08:00
break ;
2011-11-01 02:40:57 +08:00
2011-11-01 09:22:05 +08:00
case Code . Newobj :
2011-11-04 06:01:51 +08:00
var ctor = pushInstr . Operand as MethodReference ;
2011-11-01 09:22:05 +08:00
if ( ctor = = null )
return null ;
fieldType = ctor . DeclaringType ;
2011-11-04 15:22:25 +08:00
wasNewobj = true ;
2011-11-01 09:22:05 +08:00
break ;
2011-11-01 02:40:57 +08:00
2011-11-01 09:22:05 +08:00
case Code . Castclass :
case Code . Isinst :
2011-11-04 06:01:51 +08:00
fieldType = pushInstr . Operand as TypeReference ;
2011-11-01 09:22:05 +08:00
break ;
2011-11-01 02:40:57 +08:00
2011-11-01 09:22:05 +08:00
case Code . Ldarg :
case Code . Ldarg_S :
case Code . Ldarg_0 :
case Code . Ldarg_1 :
case Code . Ldarg_2 :
case Code . Ldarg_3 :
2011-11-04 06:01:51 +08:00
fieldType = DotNetUtils . getArgType ( method , pushInstr ) ;
2011-11-01 09:22:05 +08:00
break ;
case Code . Ldloc :
case Code . Ldloc_S :
case Code . Ldloc_0 :
case Code . Ldloc_1 :
case Code . Ldloc_2 :
case Code . Ldloc_3 :
2011-11-04 06:01:51 +08:00
var local = DotNetUtils . getLocalVar ( method . Body . Variables , pushInstr ) ;
2011-11-01 09:22:05 +08:00
if ( local = = null )
return null ;
fieldType = local . VariableType ;
break ;
2011-11-01 02:40:57 +08:00
2011-11-01 09:22:05 +08:00
case Code . Ldfld :
case Code . Ldsfld :
2011-11-04 06:01:51 +08:00
var field2 = pushInstr . Operand as FieldReference ;
2011-11-01 09:22:05 +08:00
if ( field2 = = null )
return null ;
fieldType = field2 . FieldType ;
break ;
2011-11-01 02:40:57 +08:00
2011-11-01 09:22:05 +08:00
default :
return null ;
2011-11-01 02:40:57 +08:00
}
2011-11-01 09:22:05 +08:00
if ( ! isValidType ( fieldType ) )
return null ;
2011-11-01 02:40:57 +08:00
2011-11-01 09:22:05 +08:00
return fieldType ;
}
2011-11-01 02:40:57 +08:00
2011-11-01 09:22:05 +08:00
static bool isValidType ( TypeReference type ) {
if ( type = = null )
return false ;
if ( type . IsValueType )
return false ;
if ( MemberReferenceHelper . isSystemObject ( type ) )
return false ;
2012-01-27 05:40:19 +08:00
if ( type . EType = = ElementType . Void )
2011-11-01 09:22:05 +08:00
return false ;
2011-11-04 06:25:07 +08:00
2011-12-05 03:01:02 +08:00
while ( type ! = null ) {
switch ( MemberReferenceHelper . getMemberReferenceType ( type ) ) {
case CecilType . ArrayType :
case CecilType . GenericInstanceType :
case CecilType . PointerType :
case CecilType . TypeDefinition :
case CecilType . TypeReference :
break ;
2011-11-04 06:25:07 +08:00
2011-12-05 03:01:02 +08:00
case CecilType . ByReferenceType :
case CecilType . FunctionPointerType :
case CecilType . GenericParameter :
case CecilType . OptionalModifierType :
case CecilType . PinnedType :
case CecilType . RequiredModifierType :
case CecilType . SentinelType :
default :
return false ;
}
if ( ! ( type is TypeSpecification ) )
break ;
type = ( ( TypeSpecification ) type ) . ElementType ;
2011-11-04 06:25:07 +08:00
}
2011-12-05 03:01:02 +08:00
return type ! = null ;
2011-11-01 02:40:57 +08:00
}
2011-11-04 07:09:51 +08:00
static TypeReference getCommonBaseClass ( ModuleDefinition module , TypeReference a , TypeReference b ) {
2011-11-04 07:39:48 +08:00
if ( DotNetUtils . isDelegate ( a ) & & DotNetUtils . derivesFromDelegate ( DotNetUtils . getType ( module , b ) ) )
2011-11-04 07:09:51 +08:00
return b ;
2011-11-04 07:39:48 +08:00
if ( DotNetUtils . isDelegate ( b ) & & DotNetUtils . derivesFromDelegate ( DotNetUtils . getType ( module , a ) ) )
2011-11-04 07:09:51 +08:00
return a ;
2011-11-01 02:40:57 +08:00
return null ; //TODO:
}
static Instruction getPreviousInstruction ( IList < Instruction > instructions , ref int instrIndex ) {
while ( true ) {
instrIndex - - ;
if ( instrIndex < 0 )
return null ;
var instr = instructions [ instrIndex ] ;
if ( instr . OpCode . Code = = Code . Nop )
continue ;
2011-11-01 06:58:19 +08:00
if ( instr . OpCode . OpCodeType = = OpCodeType . Prefix )
continue ;
2011-11-01 02:40:57 +08:00
switch ( instr . OpCode . FlowControl ) {
case FlowControl . Next :
case FlowControl . Call :
return instr ;
default :
return null ;
}
}
}
}
}