2011-11-01 02:40:57 +08:00
/ *
2014-03-12 05:15:43 +08:00
Copyright ( C ) 2011 - 2014 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 ;
2012-12-20 09:06:09 +08:00
using dnlib.DotNet ;
using dnlib.DotNet.Emit ;
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.
2015-05-17 19:29:48 +08:00
public abstract class TypesRestorerBase {
2012-11-01 21:39:39 +08:00
ModuleDef module ;
List < MethodDef > allMethods ;
Dictionary < Parameter , TypeInfo < Parameter > > argInfos = new Dictionary < Parameter , TypeInfo < Parameter > > ( ) ;
TypeInfo < Parameter > methodReturnInfo ;
2012-11-03 05:53:24 +08:00
Dictionary < IField , TypeInfo < FieldDef > > fieldWrites = new Dictionary < IField , TypeInfo < FieldDef > > ( FieldEqualityComparer . CompareDeclaringTypes ) ;
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 ;
2012-11-01 21:39:39 +08:00
public TypeSig [ ] newArgTypes ;
public TypeSig newReturnType ;
2011-11-04 02:46:29 +08:00
2012-11-01 21:39:39 +08:00
public UpdatedMethod ( MethodDef method ) {
token = method . MDToken . ToInt32 ( ) ;
2013-01-19 20:03:57 +08:00
newArgTypes = new TypeSig [ DotNetUtils . GetArgsCount ( method ) ] ;
2011-11-04 02:46:29 +08:00
}
}
class UpdatedField {
public int token ;
2012-11-01 21:39:39 +08:00
public TypeSig newFieldType ;
2011-11-04 02:46:29 +08:00
2012-11-01 21:39:39 +08:00
public UpdatedField ( FieldDef field ) {
token = field . MDToken . ToInt32 ( ) ;
2011-11-04 02:46:29 +08:00
}
}
2011-11-01 02:40:57 +08:00
2011-11-01 09:22:05 +08:00
class TypeInfo < T > {
2012-11-02 04:09:09 +08:00
Dictionary < TypeSig , bool > types = new Dictionary < TypeSig , bool > ( TypeEqualityComparer . Instance ) ;
public TypeSig newType = null ;
2011-11-01 09:22:05 +08:00
public T arg ;
2011-11-04 15:22:25 +08:00
bool newobjTypes ;
2012-11-02 04:09:09 +08:00
public Dictionary < TypeSig , bool > Types {
2011-11-04 15:22:25 +08:00
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 ;
}
2013-01-19 20:03:57 +08:00
public void Add ( TypeSig type ) {
Add ( type , false ) ;
2012-07-07 13:11:32 +08:00
}
2013-01-19 20:03:57 +08:00
public void Add ( TypeSig type , bool wasNewobj ) {
2011-11-04 15:22:25 +08:00
if ( wasNewobj ) {
if ( ! newobjTypes )
2013-01-19 20:03:57 +08:00
Clear ( ) ;
2011-11-04 15:22:25 +08:00
newobjTypes = true ;
}
else if ( newobjTypes )
return ;
2012-11-02 04:09:09 +08:00
types [ type ] = true ;
2011-11-04 15:22:25 +08:00
}
2013-01-19 20:03:57 +08:00
public void Clear ( ) {
2011-11-04 15:22:25 +08:00
types . Clear ( ) ;
}
2013-01-19 20:03:57 +08:00
public bool UpdateNewType ( ModuleDef module ) {
2011-11-01 09:22:05 +08:00
if ( types . Count = = 0 )
return false ;
2012-11-02 04:09:09 +08:00
TypeSig theNewType = null ;
2011-11-01 09:22:05 +08:00
foreach ( var key in types . Keys ) {
if ( theNewType = = null ) {
2012-11-02 04:09:09 +08:00
theNewType = key ;
2011-11-01 09:22:05 +08:00
continue ;
}
2013-01-19 20:03:57 +08:00
theNewType = GetCommonBaseClass ( module , theNewType , key ) ;
2011-11-01 09:22:05 +08:00
if ( theNewType = = null )
break ;
}
if ( theNewType = = null )
return false ;
2012-11-02 04:09:09 +08:00
if ( new SigComparer ( ) . Equals ( theNewType , newType ) )
2011-11-01 09:22:05 +08:00
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-11-01 21:39:39 +08:00
public TypesRestorerBase ( ModuleDef module ) {
2011-11-01 02:40:57 +08:00
this . module = module ;
}
2013-01-19 20:03:57 +08:00
UpdatedMethod GetUpdatedMethod ( MethodDef method ) {
2012-11-01 21:39:39 +08:00
int token = method . MDToken . ToInt32 ( ) ;
2011-11-04 02:46:29 +08:00
UpdatedMethod updatedMethod ;
if ( updatedMethods . TryGetValue ( token , out updatedMethod ) )
return updatedMethod ;
return updatedMethods [ token ] = new UpdatedMethod ( method ) ;
}
2013-01-19 20:03:57 +08:00
UpdatedField GetUpdatedField ( FieldDef field ) {
2012-11-01 21:39:39 +08:00
int token = field . MDToken . ToInt32 ( ) ;
2011-11-04 02:46:29 +08:00
UpdatedField updatedField ;
if ( updatedFields . TryGetValue ( token , out updatedField ) )
return updatedField ;
return updatedFields [ token ] = new UpdatedField ( field ) ;
}
2013-01-19 20:03:57 +08:00
public void Deobfuscate ( ) {
2012-11-01 21:39:39 +08:00
allMethods = new List < MethodDef > ( ) ;
2012-04-06 02:45:16 +08:00
2013-01-19 20:03:57 +08:00
AddAllMethods ( ) ;
AddAllFields ( ) ;
2012-04-06 02:45:16 +08:00
2013-01-19 20:03:57 +08:00
DeobfuscateLoop ( ) ;
2012-04-06 02:45:16 +08:00
2013-01-19 20:03:57 +08:00
RestoreFieldTypes ( ) ;
RestoreMethodTypes ( ) ;
2012-04-06 02:45:16 +08:00
}
2013-01-19 20:03:57 +08:00
void AddAllMethods ( ) {
2011-11-01 06:58:19 +08:00
foreach ( var type in module . GetTypes ( ) )
2013-01-19 20:03:57 +08:00
AddMethods ( type . Methods ) ;
2012-04-06 02:45:16 +08:00
}
2011-11-01 06:58:19 +08:00
2013-01-19 20:03:57 +08:00
void AddMethods ( IEnumerable < MethodDef > methods ) {
2012-04-06 02:45:16 +08:00
allMethods . AddRange ( methods ) ;
}
2013-01-19 20:03:57 +08:00
void AddMethod ( MethodDef method ) {
2012-04-06 02:45:16 +08:00
allMethods . Add ( method ) ;
}
2013-01-19 20:03:57 +08:00
void AddAllFields ( ) {
2011-11-01 02:40:57 +08:00
foreach ( var type in module . GetTypes ( ) ) {
foreach ( var field in type . Fields ) {
2013-01-19 20:03:57 +08:00
if ( ! IsUnknownType ( field ) )
2011-11-01 02:40:57 +08:00
continue ;
2012-11-03 05:53:24 +08:00
fieldWrites [ field ] = new TypeInfo < FieldDef > ( 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
2013-01-19 20:03:57 +08:00
void DeobfuscateLoop ( ) {
2011-11-01 02:40:57 +08:00
for ( int i = 0 ; i < 10 ; i + + ) {
2013-04-30 18:15:07 +08:00
bool modified = false ;
modified | = DeobfuscateFields ( ) ;
modified | = DeobfuscateMethods ( ) ;
if ( ! modified )
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
2013-01-19 20:03:57 +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 ;
2012-11-11 12:31:11 +08:00
Logger . v ( "Changing field types to real type" ) ;
2012-11-01 23:42:02 +08:00
fields . Sort ( ( a , b ) = > a . token . CompareTo ( b . token ) ) ;
2013-01-19 20:03:57 +08:00
Logger . Instance . Indent ( ) ;
2012-04-06 02:45:16 +08:00
foreach ( var updatedField in fields )
2013-01-19 20:03:57 +08:00
Logger . v ( "Field {0:X8}: type {1} ({2:X8})" , updatedField . token , Utils . RemoveNewlines ( updatedField . newFieldType . FullName ) , updatedField . newFieldType . MDToken . ToInt32 ( ) ) ;
Logger . Instance . DeIndent ( ) ;
2012-04-06 02:45:16 +08:00
}
2011-11-01 06:58:19 +08:00
2013-01-19 20:03:57 +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 ;
2012-11-11 12:31:11 +08:00
Logger . v ( "Changing method args and return types to real type" ) ;
2012-11-01 23:42:02 +08:00
methods . Sort ( ( a , b ) = > a . token . CompareTo ( b . token ) ) ;
2013-01-19 20:03:57 +08:00
Logger . Instance . Indent ( ) ;
2012-04-06 02:45:16 +08:00
foreach ( var updatedMethod in methods ) {
2012-11-11 12:31:11 +08:00
Logger . v ( "Method {0:X8}" , updatedMethod . token ) ;
2013-01-19 20:03:57 +08:00
Logger . Instance . Indent ( ) ;
2012-04-06 02:45:16 +08:00
if ( updatedMethod . newReturnType ! = null ) {
2012-11-11 12:31:11 +08:00
Logger . v ( "ret: {0} ({1:X8})" ,
2013-01-19 20:03:57 +08:00
Utils . RemoveNewlines ( updatedMethod . newReturnType . FullName ) ,
2012-11-01 21:39:39 +08:00
updatedMethod . newReturnType . MDToken . ToInt32 ( ) ) ;
2012-04-06 02:45:16 +08:00
}
for ( int i = 0 ; i < updatedMethod . newArgTypes . Length ; i + + ) {
var updatedArg = updatedMethod . newArgTypes [ i ] ;
if ( updatedArg = = null )
continue ;
2012-11-11 12:31:11 +08:00
Logger . v ( "arg {0}: {1} ({2:X8})" ,
2012-04-06 02:45:16 +08:00
i ,
2013-01-19 20:03:57 +08:00
Utils . RemoveNewlines ( updatedArg . FullName ) ,
2012-11-01 21:39:39 +08:00
updatedArg . MDToken . ToInt32 ( ) ) ;
2011-11-01 09:22:05 +08:00
}
2013-01-19 20:03:57 +08:00
Logger . Instance . DeIndent ( ) ;
2011-11-01 09:22:05 +08:00
}
2013-01-19 20:03:57 +08:00
Logger . Instance . DeIndent ( ) ;
2011-11-04 02:46:29 +08:00
}
2011-11-01 06:58:19 +08:00
2013-01-19 20:03:57 +08:00
bool DeobfuscateMethods ( ) {
2013-04-30 18:15:07 +08:00
bool modified = false ;
2011-11-04 02:46:29 +08:00
foreach ( var method in allMethods ) {
2012-11-02 04:09:09 +08:00
methodReturnInfo = new TypeInfo < Parameter > ( method . Parameters . ReturnParameter ) ;
2013-01-19 20:03:57 +08:00
DeobfuscateMethod ( method ) ;
2011-11-04 02:46:29 +08:00
2013-01-19 20:03:57 +08:00
if ( methodReturnInfo . UpdateNewType ( module ) ) {
GetUpdatedMethod ( method ) . newReturnType = methodReturnInfo . newType ;
2012-11-02 04:09:09 +08:00
method . MethodSig . RetType = methodReturnInfo . newType ;
2013-04-30 18:15:07 +08:00
modified = 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 ) {
2013-01-19 20:03:57 +08:00
if ( info . UpdateNewType ( module ) ) {
GetUpdatedMethod ( method ) . newArgTypes [ info . arg . Index ] = info . newType ;
2012-11-02 04:09:09 +08:00
info . arg . Type = info . newType ;
2013-04-30 18:15:07 +08:00
modified = true ;
2011-11-04 02:46:29 +08:00
}
}
}
2013-04-30 18:15:07 +08:00
return modified ;
2011-11-01 06:58:19 +08:00
}
2013-01-19 20:03:57 +08:00
static int SortTypeInfos ( TypeInfo < Parameter > a , TypeInfo < Parameter > b ) {
2012-11-01 21:39:39 +08:00
if ( a . arg . Method . MDToken . ToInt32 ( ) < b . arg . Method . MDToken . ToInt32 ( ) ) return - 1 ;
if ( a . arg . Method . MDToken . ToInt32 ( ) > b . arg . Method . MDToken . ToInt32 ( ) ) return 1 ;
2011-11-02 01:56:44 +08:00
2012-11-02 04:09:09 +08:00
return a . arg . Index . CompareTo ( b . arg . Index ) ;
2011-11-01 09:22:05 +08:00
}
2013-01-19 20:03:57 +08:00
void DeobfuscateMethod ( MethodDef method ) {
2012-11-06 22:58:55 +08:00
if ( ! method . IsStatic | | method . Body = = null )
2011-11-01 06:58:19 +08:00
return ;
2013-01-19 20:03:57 +08:00
bool fixReturnType = IsUnknownType ( method . MethodSig . GetRetType ( ) ) ;
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-11-05 05:41:45 +08:00
if ( arg . IsHiddenThisParameter )
continue ;
2013-01-19 20:03:57 +08:00
if ( ! IsUnknownType ( arg ) )
2011-11-01 06:58:19 +08:00
continue ;
2012-11-01 21:39:39 +08:00
argInfos [ arg ] = new TypeInfo < Parameter > ( 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 ;
2012-11-02 04:09:09 +08:00
var methodParams = method . Parameters ;
2011-11-04 06:01:51 +08:00
PushedArgs pushedArgs ;
2012-11-06 22:58:55 +08:00
var instructions = method . Body . Instructions ;
2011-11-01 06:58:19 +08:00
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 ;
2013-01-19 20:03:57 +08:00
var type = GetLoadedType ( method , method , instructions , i , out wasNewobj ) ;
2011-11-01 09:22:05 +08:00
if ( type = = null )
break ;
2013-01-19 20:03:57 +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 :
2013-01-19 20:03:57 +08:00
pushedArgs = MethodStack . GetPushedArgInstructions ( instructions , i ) ;
2012-11-02 04:09:09 +08:00
var calledMethod = instr . Operand as IMethod ;
2011-11-01 06:58:19 +08:00
if ( calledMethod = = null )
break ;
2013-01-19 20:03:57 +08:00
var calledMethodParams = DotNetUtils . GetArgs ( 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 ;
2013-01-19 20:03:57 +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 :
2013-01-19 20:03:57 +08:00
AddMethodArgType ( method , GetParameter ( methodParams , ldInstr ) , DotNetUtils . GetArg ( calledMethodParams , calledMethodParamIndex ) ) ;
2011-11-01 06:58:19 +08:00
break ;
default :
break ;
}
}
break ;
case Code . Castclass :
2013-01-19 20:03:57 +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 ;
2013-01-19 20:03:57 +08:00
AddMethodArgType ( method , GetParameter ( methodParams , pushedArgs . GetEnd ( 0 ) ) , instr . Operand as ITypeDefOrRef ) ;
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 :
2013-01-19 20:03:57 +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 ;
2013-01-19 20:03:57 +08:00
AddMethodArgType ( method , GetParameter ( methodParams , pushedArgs . GetEnd ( 0 ) ) , instr . GetLocal ( method . Body . Variables ) ) ;
2011-11-01 06:58:19 +08:00
break ;
case Code . Stsfld :
2013-01-19 20:03:57 +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 ;
2013-01-19 20:03:57 +08:00
AddMethodArgType ( method , GetParameter ( methodParams , pushedArgs . GetEnd ( 0 ) ) , instr . Operand as IField ) ;
2011-11-01 06:58:19 +08:00
break ;
case Code . Stfld :
2013-01-19 20:03:57 +08:00
pushedArgs = MethodStack . GetPushedArgInstructions ( instructions , i ) ;
2011-11-04 06:01:51 +08:00
if ( pushedArgs . NumValidArgs > = 1 ) {
2012-11-02 04:09:09 +08:00
var field = instr . Operand as IField ;
2013-01-19 20:03:57 +08:00
AddMethodArgType ( method , GetParameter ( methodParams , pushedArgs . GetEnd ( 0 ) ) , field ) ;
2011-11-04 06:01:51 +08:00
if ( pushedArgs . NumValidArgs > = 2 & & field ! = null )
2013-01-19 20:03:57 +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 :
2013-01-19 20:03:57 +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 ;
2013-01-19 20:03:57 +08:00
AddMethodArgType ( method , GetParameter ( methodParams , pushedArgs . GetEnd ( 0 ) ) , instr . Operand as IField ) ;
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 :
2012-11-01 21:39:39 +08:00
case Code . Ldelem :
2011-11-01 06:58:19 +08:00
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 :
2012-11-01 21:39:39 +08:00
case Code . Stelem :
2011-11-01 06:58:19 +08:00
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 ;
}
}
}
2013-01-19 20:03:57 +08:00
static Parameter GetParameter ( IList < Parameter > 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-11-02 04:09:09 +08:00
return instr . GetParameter ( parameters ) ;
2011-11-01 06:58:19 +08:00
default :
return null ;
}
}
2013-01-19 20:03:57 +08:00
bool AddMethodArgType ( IGenericParameterProvider gpp , Parameter methodParam , IField field ) {
2012-11-18 07:20:07 +08:00
if ( field = = null )
2011-11-01 06:58:19 +08:00
return false ;
2013-01-19 20:03:57 +08:00
return AddMethodArgType ( gpp , methodParam , field . FieldSig . GetFieldType ( ) ) ;
2011-11-01 06:58:19 +08:00
}
2013-01-19 20:03:57 +08:00
bool AddMethodArgType ( IGenericParameterProvider gpp , Parameter methodParam , Local otherLocal ) {
2011-11-01 06:58:19 +08:00
if ( otherLocal = = null )
return false ;
2013-01-19 20:03:57 +08:00
return AddMethodArgType ( gpp , methodParam , otherLocal . Type ) ;
2011-11-01 06:58:19 +08:00
}
2013-01-19 20:03:57 +08:00
bool AddMethodArgType ( IGenericParameterProvider gpp , Parameter methodParam , Parameter otherParam ) {
2011-11-01 06:58:19 +08:00
if ( otherParam = = null )
return false ;
2013-01-19 20:03:57 +08:00
return AddMethodArgType ( gpp , methodParam , otherParam . Type ) ;
2011-11-01 06:58:19 +08:00
}
2013-01-19 20:03:57 +08:00
bool AddMethodArgType ( IGenericParameterProvider gpp , Parameter methodParam , ITypeDefOrRef type ) {
return AddMethodArgType ( gpp , methodParam , type . ToTypeSig ( ) ) ;
2012-11-02 04:09:09 +08:00
}
2013-01-19 20:03:57 +08:00
bool AddMethodArgType ( IGenericParameterProvider gpp , Parameter methodParam , TypeSig type ) {
2011-11-01 06:58:19 +08:00
if ( methodParam = = null | | type = = null )
return false ;
2013-01-19 20:03:57 +08:00
if ( ! IsValidType ( gpp , type ) )
2011-11-01 06:58:19 +08:00
return false ;
2012-11-01 21:39:39 +08:00
TypeInfo < Parameter > info ;
2011-11-01 06:58:19 +08:00
if ( ! argInfos . TryGetValue ( methodParam , out info ) )
return false ;
2012-11-02 04:09:09 +08:00
if ( info . Types . ContainsKey ( type ) )
2011-11-01 06:58:19 +08:00
return false ;
2013-01-19 20:03:57 +08:00
info . Add ( type ) ;
2011-11-01 06:58:19 +08:00
return true ;
}
2013-01-19 20:03:57 +08:00
bool DeobfuscateFields ( ) {
2011-11-01 02:40:57 +08:00
foreach ( var info in fieldWrites . Values )
2013-01-19 20:03:57 +08:00
info . Clear ( ) ;
2011-11-01 02:40:57 +08:00
foreach ( var method in allMethods ) {
2012-11-06 22:58:55 +08:00
if ( method . Body = = null )
2011-11-01 02:40:57 +08:00
continue ;
2012-11-06 22:58:55 +08:00
var instructions = method . Body . Instructions ;
2011-11-01 02:40:57 +08:00
for ( int i = 0 ; i < instructions . Count ; i + + ) {
var instr = instructions [ i ] ;
2012-11-02 04:09:09 +08:00
TypeSig fieldType = null ;
2012-11-01 21:39:39 +08:00
TypeInfo < FieldDef > info = null ;
2012-11-02 04:09:09 +08:00
IField field ;
2011-11-04 06:01:51 +08:00
switch ( instr . OpCode . Code ) {
case Code . Stfld :
case Code . Stsfld :
2012-11-02 04:09:09 +08:00
field = instr . Operand as IField ;
2011-11-04 06:01:51 +08:00
if ( field = = null )
continue ;
2012-11-03 05:53:24 +08:00
if ( ! fieldWrites . TryGetValue ( field , out info ) )
2011-11-04 06:01:51 +08:00
continue ;
2011-11-04 15:22:25 +08:00
bool wasNewobj ;
2013-01-19 20:03:57 +08:00
fieldType = GetLoadedType ( info . arg . DeclaringType , method , instructions , i , out wasNewobj ) ;
2011-11-04 06:01:51 +08:00
if ( fieldType = = null )
continue ;
2013-01-19 20:03:57 +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 :
2013-01-19 20:03:57 +08:00
var pushedArgs = MethodStack . GetPushedArgInstructions ( instructions , i ) ;
2012-11-02 04:09:09 +08:00
var calledMethod = instr . Operand as IMethod ;
2011-11-04 06:01:51 +08:00
if ( calledMethod = = null )
continue ;
2012-11-18 01:57:36 +08:00
var calledMethodDefOrRef = calledMethod as IMethodDefOrRef ;
var calledMethodSpec = calledMethod as MethodSpec ;
if ( calledMethodSpec ! = null )
calledMethodDefOrRef = calledMethodSpec . Method ;
if ( calledMethodDefOrRef = = null )
continue ;
2013-01-19 20:03:57 +08:00
IList < TypeSig > calledMethodArgs = DotNetUtils . GetArgs ( calledMethodDefOrRef ) ;
calledMethodArgs = DotNetUtils . ReplaceGenericParameters ( calledMethodDefOrRef . DeclaringType . TryGetGenericInstSig ( ) , calledMethodSpec , calledMethodArgs ) ;
2011-11-04 06:01:51 +08:00
for ( int j = 0 ; j < pushedArgs . NumValidArgs ; j + + ) {
2013-01-19 20:03:57 +08:00
var pushInstr = pushedArgs . GetEnd ( j ) ;
2011-11-04 06:01:51 +08:00
if ( pushInstr . OpCode . Code ! = Code . Ldfld & & pushInstr . OpCode . Code ! = Code . Ldsfld )
continue ;
2012-11-02 04:09:09 +08:00
field = pushInstr . Operand as IField ;
2011-11-04 06:01:51 +08:00
if ( field = = null )
continue ;
2012-11-03 05:53:24 +08:00
if ( ! fieldWrites . TryGetValue ( field , out info ) )
2011-11-04 06:01:51 +08:00
continue ;
fieldType = calledMethodArgs [ calledMethodArgs . Count - 1 - j ] ;
2013-01-19 20:03:57 +08:00
if ( ! IsValidType ( info . arg . DeclaringType , fieldType ) )
2011-11-04 06:01:51 +08:00
continue ;
2013-01-19 20:03:57 +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
2013-04-30 18:15:07 +08:00
bool modified = false ;
2012-11-01 21:39:39 +08:00
var removeThese = new List < FieldDef > ( ) ;
2011-11-04 02:46:29 +08:00
foreach ( var info in fieldWrites . Values ) {
2013-01-19 20:03:57 +08:00
if ( info . UpdateNewType ( module ) ) {
2011-11-04 02:46:29 +08:00
removeThese . Add ( info . arg ) ;
2013-01-19 20:03:57 +08:00
GetUpdatedField ( info . arg ) . newFieldType = info . newType ;
2012-11-02 04:09:09 +08:00
info . arg . FieldSig . Type = info . newType ;
2013-04-30 18:15:07 +08:00
modified = true ;
2011-11-04 02:46:29 +08:00
}
}
foreach ( var field in removeThese )
2012-11-03 05:53:24 +08:00
fieldWrites . Remove ( field ) ;
2013-04-30 18:15:07 +08:00
return modified ;
2011-11-01 09:22:05 +08:00
}
2011-11-01 02:40:57 +08:00
2013-01-19 20:03:57 +08:00
TypeSig GetLoadedType ( IGenericParameterProvider gpp , MethodDef method , IList < Instruction > instructions , int instrIndex , out bool wasNewobj ) {
var fieldType = MethodStack . GetLoadedType ( method , instructions , instrIndex , out wasNewobj ) ;
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
2013-01-19 20:03:57 +08:00
protected virtual bool IsValidType ( IGenericParameterProvider gpp , TypeSig type ) {
2011-11-01 09:22:05 +08:00
if ( type = = null )
return false ;
2012-11-02 04:09:09 +08:00
if ( type . ElementType = = 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 ) {
2012-11-02 04:09:09 +08:00
switch ( type . ElementType ) {
case ElementType . GenericInst :
foreach ( var ga in ( ( GenericInstSig ) type ) . GenericArguments ) {
2013-01-19 20:03:57 +08:00
if ( ! IsValidType ( gpp , ga ) )
2012-09-20 04:51:49 +08:00
return false ;
}
break ;
2012-11-02 04:09:09 +08:00
case ElementType . SZArray :
case ElementType . Array :
case ElementType . Ptr :
case ElementType . Class :
case ElementType . ValueType :
2012-11-18 07:20:07 +08:00
case ElementType . Void :
case ElementType . Boolean :
case ElementType . Char :
case ElementType . I1 :
case ElementType . U1 :
case ElementType . I2 :
case ElementType . U2 :
case ElementType . I4 :
case ElementType . U4 :
case ElementType . I8 :
case ElementType . U8 :
case ElementType . R4 :
case ElementType . R8 :
case ElementType . TypedByRef :
case ElementType . I :
case ElementType . U :
case ElementType . String :
case ElementType . Object :
2011-12-05 03:01:02 +08:00
break ;
2011-11-04 06:25:07 +08:00
2012-11-02 04:09:09 +08:00
case ElementType . Var :
case ElementType . MVar :
// TODO: Return false for now. We don't know whether the Var is a Var in
// this type or from some other type.
return false ;
2012-04-06 01:38:05 +08:00
2012-11-02 04:09:09 +08:00
case ElementType . ByRef :
case ElementType . FnPtr :
case ElementType . CModOpt :
case ElementType . CModReqd :
case ElementType . Pinned :
case ElementType . Sentinel :
2012-11-18 07:20:07 +08:00
case ElementType . ValueArray :
case ElementType . R :
case ElementType . End :
case ElementType . Internal :
case ElementType . Module :
2011-12-05 03:01:02 +08:00
default :
return false ;
}
2012-11-18 01:57:36 +08:00
if ( type . Next = = null )
break ;
2012-11-02 04:09:09 +08:00
type = type . Next ;
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
}
2013-01-19 20:03:57 +08:00
protected abstract bool IsUnknownType ( object o ) ;
2012-04-06 02:45:16 +08:00
2013-01-19 20:03:57 +08:00
static TypeSig GetCommonBaseClass ( ModuleDef module , TypeSig a , TypeSig b ) {
if ( DotNetUtils . IsDelegate ( a ) & & DotNetUtils . DerivesFromDelegate ( module . Find ( b . ToTypeDefOrRef ( ) ) ) )
2011-11-04 07:09:51 +08:00
return b ;
2013-01-19 20:03:57 +08:00
if ( DotNetUtils . IsDelegate ( b ) & & DotNetUtils . DerivesFromDelegate ( module . Find ( a . ToTypeDefOrRef ( ) ) ) )
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
2015-05-17 19:29:48 +08:00
public class TypesRestorer : TypesRestorerBase {
2012-11-01 21:39:39 +08:00
public TypesRestorer ( ModuleDef module )
2012-04-06 02:45:16 +08:00
: base ( module ) {
}
2013-01-19 20:03:57 +08:00
protected override bool IsValidType ( IGenericParameterProvider gpp , TypeSig type ) {
2012-04-06 02:45:16 +08:00
if ( type = = null )
return false ;
2012-11-06 02:21:33 +08:00
if ( type . IsValueType )
2012-04-06 02:45:16 +08:00
return false ;
2012-11-02 04:09:09 +08:00
if ( type . ElementType = = ElementType . Object )
2012-04-06 02:45:16 +08:00
return false ;
2013-01-19 20:03:57 +08:00
return base . IsValidType ( gpp , type ) ;
2012-04-06 02:45:16 +08:00
}
2013-01-19 20:03:57 +08:00
protected override bool IsUnknownType ( object o ) {
2012-11-01 21:39:39 +08:00
var arg = o as Parameter ;
2012-04-06 02:45:16 +08:00
if ( arg ! = null )
2012-11-18 07:20:07 +08:00
return arg . Type . GetElementType ( ) = = ElementType . Object ;
2012-04-06 02:45:16 +08:00
2012-11-01 21:39:39 +08:00
var field = o as FieldDef ;
2012-04-06 02:45:16 +08:00
if ( field ! = null )
2012-11-06 07:17:58 +08:00
return field . FieldSig . GetFieldType ( ) . GetElementType ( ) = = ElementType . Object ;
2012-04-06 02:45:16 +08:00
2012-11-17 22:46:02 +08:00
var sig = o as TypeSig ;
if ( sig ! = null )
return sig . ElementType = = ElementType . Object ;
2012-04-06 02:45:16 +08:00
throw new ApplicationException ( string . Format ( "Unknown type: {0}" , o . GetType ( ) ) ) ;
}
}
2011-11-01 02:40:57 +08:00
}