[.Net] Methodheader from Methodbody

05/09/2014 13:14 tolio#1
So falls jemand auch mal in die Verlegenheit kommen sollte den Methodheader einer Methode per Hand erstellen zu müssen, hier meine Funktion dafür. Wenn möglich wird ein tiny-header erstellt, es kann aber auch ein fat-header erzwungen werden.
Die fat-header Struktur ist vor dem code zu finden.
Bei Fragen oder sonst was, hier rein oder ne pn, ansonsten, viel Spaß damit ;)
Quellen:
[Only registered and activated users can see links. Click Here To Register...] S. 205ff
X:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Include\CorHdr.h

Code:
'  31                 15              0
'  |--------|--------|--------|--------|
' 0|size  flags  type|     maxstack    |
'  |--------|--------|--------|--------|
' 4|             codesize              |
'  |--------|--------|--------|--------|
' 8|             local sig             |
'  |--------|--------|--------|--------|

Function CreateMethodHeader(body As MethodBody, Optional forceFatHeader As Boolean = False) As Byte()

        If body Is Nothing Then Throw New ArgumentNullException("body")

        Dim header As List(Of Byte) = New List(Of Byte)

        If forceFatHeader = False _
            AndAlso body.GetILAsByteArray().Count < 64 _
            AndAlso body.LocalVariables.Count = 0 _
            AndAlso body.ExceptionHandlingClauses.Count = 0 _
            AndAlso body.MaxStackSize < 9 Then
#If DEBUG Then
            Debug.Print("creating tiny header")
#End If
            Const CorILMethod_TinyFormat As Byte = &H2 '00000010'

            header.Add((CByte(body.GetILAsByteArray.Count)) << 2 Or CorILMethod_TinyFormat)
#If DEBUG Then
            If header.Count <> 1 Then Throw New InvalidProgramException(String.Format("invalid tiny header{0}found: {1}, should be 1 byte.", Environment.NewLine, header.Count))
#End If

        Else

#If DEBUG Then
            Debug.Print("creating fat header")
#End If
            Const CorILMethod_FatFormat As Byte = &H3 '00000011'
            Const CorILMethod_InitLocals As Byte = &H10 '00010000'
            Const CorILMethod_MoreSects As Byte = &H8 '00001000'

            If BitConverter.IsLittleEndian Then 'endianness fix'
                header.Add(CByte(CorILMethod_FatFormat Or If(body.ExceptionHandlingClauses.Count > 0, CorILMethod_MoreSects, &H0) Or If(body.LocalVariables.Count > 0 AndAlso body.InitLocals, CorILMethod_InitLocals, &H0)))
                header.Add(&H30) '00110000 (&H3 << 4)'
            Else
                header.Add(&H30) '00110000 (&H3 << 4)'
                header.Add(CByte(CorILMethod_FatFormat Or If(body.ExceptionHandlingClauses.Count > 0, CorILMethod_MoreSects, &H0) Or If(body.LocalVariables.Count > 0 AndAlso body.InitLocals, CorILMethod_InitLocals, &H0)))
            End If

            header.AddRange(BitConverter.GetBytes(CShort(body.MaxStackSize)))
            header.AddRange(BitConverter.GetBytes(body.GetILAsByteArray.Count))
            header.AddRange(BitConverter.GetBytes(If(body.LocalVariables.Count > 0, body.LocalSignatureMetadataToken, 0)))

#If DEBUG Then
            If header.Count <> 12 Then Throw New InvalidProgramException(String.Format("invalid fat header{0}found: {1}, should be 12 bytes.", Environment.NewLine, header.Count))
#End If
        End If

        Return header.ToArray()
    End Function