Documents & code‎ > ‎

Assembler duplicator [Reflection only] создание дубликата внешней сборки через рефлектор

Assembler duplicator [Reflection only] создание дубликата внешней сборки через рефлектор   
post id38 
post length9827 
post datetime2/3/2010 5:19:51 PM 
post ip77.51.88.183 

 



Assembler duplicator [Reflection only] создание дубликата внешней сборки через рефлектор 


Info: 


Пытаемся сделать что-то похожее на ILMerge  urlhttp://research.microsoft.com/en-us/people/mbarnett/ILMerge.aspx 
при помощи исключительно рефлектора. 

Что реализовано : 
   
   перенос типов  [NN] 
   переменных типа 
   методов типа

что опущено: 
   
   перенос конструктора типа 
   + AssemblyRef 
   + MemberRef 



 



    Public IData(0) As Byte _ 
         , FileName As String = Nothing _ 
         , METADATA As Dictionary(Of String, METADATA_OBJECT_TOKEN) _ 
                 = New Dictionary(Of String, METADATA_OBJECT_TOKEN) _ 
         , ICheckID As Dictionary(Of String, Integer) _ 
                 = New Dictionary(Of String, Integer) _ 
         , DICT As Dictionary(Of Integer, OpCode) _ 
         , code As OpCode 
    ' 
    '|----------------------------------- 
    '|- структура описателей объектов   | 
    '|       где:                       | 
    '|           ID1 - новый описатель  | 
    '|           ID2 - старый описатель | 
    '|----------------------------------- 
    Structure METADATA_OBJECT_TOKEN 
        Dim ID1, ID2 As Integer _ 
          , Name As String 
    End Structure 

    Sub CorrectMethodBody(ByRef Body As Byte()) 
        For As Integer = 0 To Body.Length - 1 
            Dim instructionValue As UInt16 = 0 
            If i < Body.Length - 1 Then 
                instructionValue = BitConverter.ToUInt16(Body, i) 
                Select Case (instructionValue And OpCodes.Prefix1.Value) = OpCodes.Prefix1.Value 
                    Case True 
                        instructionValue = ((65280 And instructionValue) >> 8) Or ((255 And instructionValue) << 8) 
                        i = i + 1 
                    Case Else 
                        instructionValue = instructionValue And 255 
                End Select 
            Else 
                instructionValue = Buffer.GetByte(Body, i) 
            End If 
            If DICT.TryGetValue(instructionValue, code) Then 
                If code.OperandType = OperandType.InlineMethod Then 
                    Dim ObjData As Integer = BitConverter.ToInt32(Body, i + 1) _ 
                      , token As New METADATA_OBJECT_TOKEN 
                    Select Case code.Name.Trim.ToLower 
                        Case "call", "callvirt" 
                            If METADATA.TryGetValue(ObjData, token) Then 
                                Dim As Byte() _ 
                                    = BitConverter.GetBytes(token.ID1) 
                                Buffer.BlockCopy(b, 0, Body, i + 1, 4) 
                            End If 
                    End Select 
                    i = i + 4 
                End If 
            End If 
        Next 
    End Sub 

    Sub Processing() 
        IData = OpenFile(FileName) 
        If IsNothing(IData) Then 
            Exit Sub 
        End If 
        '-------- 
        'EDIT IT: 
        '-------- 
        FileName = FileName.Split("\")(FileName.Split("\").Length - 1) 
        Dim IAssemblyName As New AssemblyName() _ 
          , IFileName As String _ 
                = String.Concat("[!] ", FileName) 
        With IAssemblyName 
            .Name = Path.GetFileNameWithoutExtension(FileName) 
        End With 
        Dim IAssembly As AssemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(IAssemblyName, AssemblyBuilderAccess.Save) 
        '-------------------------------- 
        'Create opcodes array:          | 
        '   [заполняем словарь кодов]   | 
        '-------------------------------- 
        DICT = New Dictionary(Of Integer, OpCode) 
        For Each [FI] As FieldInfo In GetType(OpCodes).GetFields(BindingFlags.Static Or BindingFlags.Public) 
            Dim code As OpCode = DirectCast([FI].GetValue(Nothing), OpCode) 
            DICT.Add(code.Value, code) 
        Next 
        '----------------- 
        ' Парсим сборку: | 
        '----------------- 
        For Each T1 As [Module] In Reflection.Assembly.Load(IData).GetModules 
            '----------- 
            ' Module`s | 
            '----------- 
            Dim IModuleBuilder As ModuleBuilder = IAssembly.DefineDynamicModule(T1.ScopeName, IFileName) 
            For Each T2 As [Type] In T1.GetTypes 
                '----------- 
                ' Type`s   | 
                '----------- 
                If IsNothing(T2.DeclaringType) Then 
                    Dim ITypeBuilder As TypeBuilder = IModuleBuilder.DefineType(T2.Name, T2.Attributes) 
                    TCase1.Text = String.Concat(TCase1.Text, "The type is copied: ", T2.Name, vbCrLf) 
                    For Each T3 As [FieldInfo] In T2.GetFields() 
                        '------------------------ 
                        ' Type Field`s          | 
                        '   переменные [Типа]   | 
                        '------------------------ 
                        Dim IFieldBuilder As FieldBuilder _ 
                            = ITypeBuilder.DefineField(T3.Name, T3.FieldType, T3.Attributes) 
                        TCase1.Text = String.Concat(TCase1.Text, "  -> Field: ", T3.Name, vbCrLf) 
                    Next 
                    For Each T4 As [ConstructorInfo] In T2.GetConstructors() 
                        '---------------------- 
                        ' Type Constructor`s  | 
                        '---------------------- 
                        ' [!] Перенос методов конструктора класса требует   
                        ' более детального анализа, потому этот момент 
                        ' мы пока опустим 
                        '... 
                        ' 
                    Next 
                    For Each T5 As [MethodInfo] In T2.GetMethods() 
                        '-------------------
                        ' Method`s          | 
                        '   методы [Типа]   | 
                        '-------------------
                        If Not IsNothing(T5) Then 
                            Try 
                                Dim body As Byte() = T5.GetMethodBody.GetILAsByteArray() 
                                If body.Length - 1 > 0 Then 
                                    Try 
                                        ICheckID.Add(T5.MetadataToken, T5.MetadataToken) 
                                        Dim IMethodBuilder As MethodBuilder _ 
                                            = ITypeBuilder.DefineMethod(T5.Name, T5.Attributes, NothingNew Type() {}) 
                                        '------------------------------------------------------------ 
                                        ' Клонировать метод мы можем двумя вариантами:              | 
                                        '   1. либо через разбор кода метода                        | 
                                        '   2. либо через перенос его тела [наш выбор]              | 
                                        '                                                           | 
                                        '   [!] НО:                                                 | 
                                        '       При переносе тела необходимо поправить описатели    | 
                                        '       методов для всех операторов [CALL::], т.к.          | 
                                        '       структура метаданных в новой сборке                 | 
                                        '       не будет соответствовать оригиналу.                 | 
                                        '                                                           | 
                                        '   Здесь правим только вызовы [методов]                    | 
                                        '       логично было бы так же скорректировать:             | 
                                        '           + MemberRef     [!]                             | 
                                        '           + AssemblyRef   [!]                             | 
                                        '------------------------------------------------------------- 
                                        CorrectMethodBody(body) 
                                        IMethodBuilder.CreateMethodBody(body, body.Length) 
                                        Dim token As New METADATA_OBJECT_TOKEN 
                                        With token 
                                            .Name = T5.Name 
                                            .ID1 = IMethodBuilder.GetToken.Token 
                                            .ID2 = T5.MetadataToken 
                                        End With 
                                        METADATA.Add(token.ID2, token) 
                                        TCase1.Text = String.Concat(TCase1.Text, "      Method: ", T5.Name, " [", Hex(T5.MetadataToken), "] -> [", Hex(token.ID1), "]", vbCrLf) 
                                    Catch ex As Exception 
                                    End Try 
                                End If 
                            Catch ex As Exception 
                            End Try 
                        End If 
                    Next 
                    Dim IType As Type = ITypeBuilder.CreateType() 
                End If 
            Next 
        Next 
        IAssembly.Save(IFileName) 
    End Sub 



ċ
ABRef.rar
(19k)
DMITRY MENSHOV,
Sep 4, 2013, 8:38 AM
Comments