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/>.
* /
2012-04-06 02:45:16 +08:00
using System ;
2011-11-01 02:40:57 +08:00
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.
2012-04-06 02:45:16 +08:00
abstract class TypesRestorerBase {
2011-11-01 02:40:57 +08:00
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 ;
}
2012-07-07 13:11:32 +08:00
public void add ( TypeReference type ) {
add ( type , false ) ;
}
public void add ( TypeReference type , bool wasNewobj ) {
2011-11-04 15:22:25 +08:00
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
}
}
2012-04-06 02:45:16 +08:00
public TypesRestorerBase ( ModuleDefinition module ) {
2011-11-01 02:40:57 +08:00
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 > ( ) ;
2012-04-06 02:45:16 +08:00
addAllMethods ( ) ;
addAllFields ( ) ;
deobfuscateLoop ( ) ;
restoreFieldTypes ( ) ;
restoreMethodTypes ( ) ;
}
void addAllMethods ( ) {
2011-11-01 06:58:19 +08:00
foreach ( var type in module . GetTypes ( ) )
2012-04-06 02:45:16 +08:00
addMethods ( type . Methods ) ;
}
2011-11-01 06:58:19 +08:00
2012-04-06 02:45:16 +08:00
void addMethods ( IEnumerable < MethodDefinition > methods ) {
allMethods . AddRange ( methods ) ;
}
void addMethod ( MethodDefinition method ) {
allMethods . Add ( method ) ;
}
void addAllFields ( ) {
2011-11-01 02:40:57 +08:00
foreach ( var type in module . GetTypes ( ) ) {
foreach ( var field in type . Fields ) {
2012-04-06 02:45:16 +08:00
if ( ! isUnknownType ( field ) )
2011-11-01 02:40:57 +08:00
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
}
}
2012-04-06 02:45:16 +08:00
}
2011-11-01 02:40:57 +08:00
2012-04-06 02:45:16 +08:00
void deobfuscateLoop ( ) {
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 ;
}
2012-04-06 02:45:16 +08:00
}
2011-11-01 06:58:19 +08:00
2012-04-06 02:45:16 +08:00
void restoreFieldTypes ( ) {
2011-11-04 02:46:29 +08:00
var fields = new List < UpdatedField > ( updatedFields . Values ) ;
2012-04-06 02:45:16 +08:00
if ( fields . Count = = 0 )
return ;
Log . v ( "Changing field types to real type" ) ;
fields . Sort ( ( a , b ) = > Utils . compareInt32 ( a . token , b . token ) ) ;
Log . indent ( ) ;
foreach ( var updatedField in fields )
Log . v ( "Field {0:X8}: type {1} ({2:X8})" , updatedField . token , Utils . removeNewlines ( updatedField . newFieldType . FullName ) , updatedField . newFieldType . MetadataToken . ToInt32 ( ) ) ;
Log . deIndent ( ) ;
}
2011-11-01 06:58:19 +08:00
2012-04-06 02:45:16 +08:00
void restoreMethodTypes ( ) {
2011-11-04 02:46:29 +08:00
var methods = new List < UpdatedMethod > ( updatedMethods . Values ) ;
2012-04-06 02:45:16 +08:00
if ( methods . Count = = 0 )
return ;
Log . v ( "Changing method args and return types to real type" ) ;
methods . Sort ( ( a , b ) = > Utils . compareInt32 ( a . token , b . token ) ) ;
Log . indent ( ) ;
foreach ( var updatedMethod in methods ) {
Log . v ( "Method {0:X8}" , updatedMethod . token ) ;
2011-11-01 09:22:05 +08:00
Log . indent ( ) ;
2012-04-06 02:45:16 +08:00
if ( updatedMethod . newReturnType ! = null ) {
Log . v ( "ret: {0} ({1:X8})" ,
Utils . removeNewlines ( updatedMethod . newReturnType . FullName ) ,
updatedMethod . newReturnType . MetadataToken . ToInt32 ( ) ) ;
}
for ( int i = 0 ; i < updatedMethod . newArgTypes . Length ; i + + ) {
var updatedArg = updatedMethod . newArgTypes [ i ] ;
if ( updatedArg = = null )
continue ;
Log . v ( "arg {0}: {1} ({2:X8})" ,
i ,
Utils . removeNewlines ( updatedArg . FullName ) ,
updatedArg . MetadataToken . ToInt32 ( ) ) ;
2011-11-01 09:22:05 +08:00
}
Log . deIndent ( ) ;
}
2012-04-06 02:45:16 +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-01 06:58:19 +08:00
void deobfuscateMethod ( MethodDefinition method ) {
if ( ! method . IsStatic | | method . Body = = null )
return ;
2012-04-06 02:45:16 +08:00
bool fixReturnType = isUnknownType ( method . MethodReturnType ) ;
2011-11-01 09:22:05 +08:00
2011-11-01 06:58:19 +08:00
argInfos . Clear ( ) ;
foreach ( var arg in method . Parameters ) {
2012-04-06 02:45:16 +08:00
if ( ! isUnknownType ( arg ) )
2011-11-01 06:58:19 +08:00
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 ;
2012-04-06 02:45:16 +08:00
var type = getLoadedType ( method , 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 :
2012-04-05 23:11:24 +08:00
pushedArgs = MethodStack . 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-04-06 01:38:05 +08:00
addMethodArgType ( method , getParameter ( methodParams , ldInstr ) , DotNetUtils . getParameter ( calledMethodParams , calledMethodParamIndex ) ) ;
2011-11-01 06:58:19 +08:00
break ;
default :
break ;
}
}
break ;
case Code . Castclass :
2012-04-05 23:11:24 +08:00
pushedArgs = MethodStack . getPushedArgInstructions ( instructions , i ) ;
2011-11-04 06:01:51 +08:00
if ( pushedArgs . NumValidArgs < 1 )
2011-11-01 06:58:19 +08:00
break ;
2012-04-06 01:38:05 +08:00
addMethodArgType ( method , 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 :
2012-04-05 23:11:24 +08:00
pushedArgs = MethodStack . getPushedArgInstructions ( instructions , i ) ;
2011-11-04 06:01:51 +08:00
if ( pushedArgs . NumValidArgs < 1 )
2011-11-01 06:58:19 +08:00
break ;
2012-04-06 01:38:05 +08:00
addMethodArgType ( method , getParameter ( methodParams , pushedArgs . getEnd ( 0 ) ) , DotNetUtils . getLocalVar ( method . Body . Variables , instr ) ) ;
2011-11-01 06:58:19 +08:00
break ;
case Code . Stsfld :
2012-04-05 23:11:24 +08:00
pushedArgs = MethodStack . getPushedArgInstructions ( instructions , i ) ;
2011-11-04 06:01:51 +08:00
if ( pushedArgs . NumValidArgs < 1 )
2011-11-01 06:58:19 +08:00
break ;
2012-04-06 01:38:05 +08:00
addMethodArgType ( method , getParameter ( methodParams , pushedArgs . getEnd ( 0 ) ) , instr . Operand as FieldReference ) ;
2011-11-01 06:58:19 +08:00
break ;
case Code . Stfld :
2012-04-05 23:11:24 +08:00
pushedArgs = MethodStack . getPushedArgInstructions ( instructions , i ) ;
2011-11-04 06:01:51 +08:00
if ( pushedArgs . NumValidArgs > = 1 ) {
2011-11-01 06:58:19 +08:00
var field = instr . Operand as FieldReference ;
2012-04-06 01:38:05 +08:00
addMethodArgType ( method , getParameter ( methodParams , pushedArgs . getEnd ( 0 ) ) , field ) ;
2011-11-04 06:01:51 +08:00
if ( pushedArgs . NumValidArgs > = 2 & & field ! = null )
2012-04-06 01:38:05 +08:00
addMethodArgType ( method , 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 :
2012-04-05 23:11:24 +08:00
pushedArgs = MethodStack . getPushedArgInstructions ( instructions , i ) ;
2011-11-04 06:01:51 +08:00
if ( pushedArgs . NumValidArgs < 1 )
2011-11-01 22:53:51 +08:00
break ;
2012-04-06 01:38:05 +08:00
addMethodArgType ( method , 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 ;
}
}
2012-04-06 02:45:16 +08:00
bool addMethodArgType ( IGenericParameterProvider gpp , ParameterDefinition methodParam , FieldReference field ) {
2011-11-01 06:58:19 +08:00
if ( field = = null )
return false ;
2012-04-06 02:45:16 +08:00
return addMethodArgType ( gpp , methodParam , field . FieldType ) ;
2011-11-01 06:58:19 +08:00
}
2012-04-06 02:45:16 +08:00
bool addMethodArgType ( IGenericParameterProvider gpp , ParameterDefinition methodParam , VariableDefinition otherLocal ) {
2011-11-01 06:58:19 +08:00
if ( otherLocal = = null )
return false ;
2012-04-06 02:45:16 +08:00
return addMethodArgType ( gpp , methodParam , otherLocal . VariableType ) ;
2011-11-01 06:58:19 +08:00
}
2012-04-06 02:45:16 +08:00
bool addMethodArgType ( IGenericParameterProvider gpp , ParameterDefinition methodParam , ParameterDefinition otherParam ) {
2011-11-01 06:58:19 +08:00
if ( otherParam = = null )
return false ;
2012-04-06 02:45:16 +08:00
return addMethodArgType ( gpp , methodParam , otherParam . ParameterType ) ;
2011-11-01 06:58:19 +08:00
}
2012-04-06 02:45:16 +08:00
bool addMethodArgType ( IGenericParameterProvider gpp , ParameterDefinition methodParam , TypeReference type ) {
2011-11-01 06:58:19 +08:00
if ( methodParam = = null | | type = = null )
return false ;
2012-04-06 02:45:16 +08:00
if ( ! isValidType ( gpp , 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 ;
}
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 ;
2012-04-06 02:45:16 +08:00
fieldType = getLoadedType ( info . arg . DeclaringType , 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 :
2012-04-05 23:11:24 +08:00
var pushedArgs = MethodStack . getPushedArgInstructions ( instructions , i ) ;
2011-11-04 06:01:51 +08:00
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 ] ;
2012-04-06 02:45:16 +08:00
if ( ! isValidType ( info . arg . DeclaringType , fieldType ) )
2011-11-04 06:01:51 +08:00
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
2012-04-06 02:45:16 +08:00
TypeReference getLoadedType ( IGenericParameterProvider gpp , MethodDefinition method , IList < Instruction > instructions , int instrIndex , out bool wasNewobj ) {
2012-04-05 23:11:24 +08:00
var fieldType = MethodStack . getLoadedType ( method , instructions , instrIndex , out wasNewobj ) ;
2012-04-06 02:45:16 +08:00
if ( fieldType = = null | | ! isValidType ( gpp , fieldType ) )
2011-11-01 09:22:05 +08:00
return null ;
return fieldType ;
}
2011-11-01 02:40:57 +08:00
2012-04-06 02:45:16 +08:00
protected virtual bool isValidType ( IGenericParameterProvider gpp , TypeReference type ) {
2011-11-01 09:22:05 +08:00
if ( type = = null )
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 . GenericInstanceType :
2012-09-20 04:51:49 +08:00
foreach ( var ga in ( ( GenericInstanceType ) type ) . GenericArguments ) {
if ( ! isValidType ( gpp , ga ) )
return false ;
}
break ;
case CecilType . ArrayType :
2011-12-05 03:01:02 +08:00
case CecilType . PointerType :
case CecilType . TypeDefinition :
case CecilType . TypeReference :
break ;
2011-11-04 06:25:07 +08:00
2012-04-06 01:38:05 +08:00
case CecilType . GenericParameter :
var gp = ( GenericParameter ) type ;
2012-04-06 02:45:16 +08:00
var methodRef = gpp as MethodReference ;
var typeRef = gpp as TypeReference ;
if ( methodRef ! = null ) {
if ( methodRef . DeclaringType ! = gp . Owner & & methodRef ! = gp . Owner )
return false ;
}
else if ( typeRef ! = null ) {
if ( typeRef ! = gp . Owner )
return false ;
}
else
2012-04-06 01:38:05 +08:00
return false ;
break ;
2011-12-05 03:01:02 +08:00
case CecilType . ByReferenceType :
case CecilType . FunctionPointerType :
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
}
2012-04-06 02:45:16 +08:00
protected abstract bool isUnknownType ( object o ) ;
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:
}
}
2012-04-06 02:45:16 +08:00
class TypesRestorer : TypesRestorerBase {
public TypesRestorer ( ModuleDefinition module )
: base ( module ) {
}
protected override bool isValidType ( IGenericParameterProvider gpp , TypeReference type ) {
if ( type = = null )
return false ;
if ( type . IsValueType )
return false ;
if ( MemberReferenceHelper . isSystemObject ( type ) )
return false ;
return base . isValidType ( gpp , type ) ;
}
protected override bool isUnknownType ( object o ) {
var arg = o as ParameterDefinition ;
if ( arg ! = null )
return MemberReferenceHelper . isSystemObject ( arg . ParameterType ) ;
var field = o as FieldDefinition ;
if ( field ! = null )
return MemberReferenceHelper . isSystemObject ( field . FieldType ) ;
var retType = o as MethodReturnType ;
if ( retType ! = null )
return MemberReferenceHelper . isSystemObject ( retType . ReturnType ) ;
throw new ApplicationException ( string . Format ( "Unknown type: {0}" , o . GetType ( ) ) ) ;
}
}
2011-11-01 02:40:57 +08:00
}