zoukankan      html  css  js  c++  java
  • [转载]Modifying IL at runtime (step II+)

    In my previous entry on IL modification we looked at the details for inserting a method call with a known (hardcoded) method token. We also used metadata to list the available methods, as a way to avoid this hardcoding.

    When listing the methods on a given class, the method signatures were available, but we didn't use them. In this short entry, we'll extend our metadata inspection a little bit by using an existing method's signature to search for another method with a matching signature.

    Update: I posted the zipped project.

    Using a known signature to find a method
    Here is today's Hello.cs. It contains multiple versions of the Log method, with different signatures, and a unique Test with a signature that matches one of the Log methods.

    using System;

    public class Hello
    {
      public static void Main(string[] prms)
      {
       Console.WriteLine("main!");
      }

      public static void Log()
      {
       Console.WriteLine("log!");
      }

      public static void Log(string test)
      {
       Console.WriteLine("log!");
      }

      public static void Test()
      {
       Console.WriteLine("test!");
      }
    }

    Last time, when we enumerated the methods on the current class, we only printed their tokens and names out. Below is the modification to this loop, to have it search for a method called "Test" and use its signature to find the "Log" method with the matching signature.

    The code refers to a PrintSignature method that cracks signature blobs open and outputs then in a readable format. I'll write about the details of this method sometime soon (when I understand it better), but if you are impatient, you should check out the "metainfo" sample from the "Tools Developper Guide".

     ...

     ProfilerPrintf("tok:%X\n", rToks[i]);

     // Get metadata for this method
     mdTypeDef mdClassTok;
     wchar_t wszFunctionName[512];
     ULONG count = 0;
     DWORD dwAttr;
     PCCOR_SIGNATURE signature;
     ULONG signatureLen;
     ULONG ulCodeRVA; // ignored
     DWORD dwImplFlags; // ignored

     // Get the signature for the method with token rToks[i]
     hr = pMetaDataImport->GetMethodProps(rToks[i], &mdClassTok, wszFunctionName, 512, &count, &dwAttr, &signature, &signatureLen, &ulCodeRVA, &dwImplFlags);
     if (FAILED(hr)) { goto exit; }

     fwprintf(m_pOutFile, L"function name: %s\n", wszFunctionName);


     // Look at the signature
     PrintSignature(signature, signatureLen, wszFunctionName, pMetaDataImport);

     if (wcscmp(wszFunctionName, L"Test") == 0) {
       ProfilerPrintf("found Test method\n");
       mdMethodDef mdMatchTok;

       hr = pMetaDataImport->FindMember(tkClass, L"Log", signature, signatureLen, &mdMatchTok);
       if (FAILED(hr)) { goto exit; }

       ProfilerPrintf("found Log method with matching signature, token: %X\n", mdMatchTok);
     }
     ...

    The IMetaDataImport::FindMember method looks methods up in a class, given a name and a signature blob. We can use the returned method token in the IL method call that we insert at runtime, to avoid hardcoding it.
    Here the token that is found is 60 00 00 02, as we can see from the output of the modified profiler:

    tok:6000001
    function name: Main
    void Main(class System.String[])

    tok:6000002
    function name: Log
    void Log()

    tok:6000003
    function name: Log
    void Log(class System.String)

    tok:6000004
    function name: Test
    void Test()
    found Test method
    found Log method with matching signature, token: 6000002

    tok:6000005
    function name: .ctor
    instance void .ctor()

    It is probably also possible to use a built signature blob instead of that of an existing method, but I didn't get that far yet.


    Calling another class's method
    Once you have the token for a method, even it belong to another class, you can easily use it in the IL modification.
    If you look at the dis-assembly for Hello.exe (code below), you'll notice that the tokens for methods appear unique in the assembly. This means the call operation only needs a method's token, and doesn't care which class this method belongs to, as long as it remains within the current module.

    So when modifying the Main method, if you lookup the Logger class token with FindTypeDefByName(L"Logger", 0, &tkLogger), then find the Log method token with EnumMethodsWithName(..., tkLogger, L"Log", ...) (or other technique of your liking), it is then just a matter of changing ILCode.method_token with the token you found for Log. This way we don't need to hardcode the method token in the generated call IL.

    using System;

    public class Hello
    {
      public static void Main(string[] prms)
      {
       Console.WriteLine("main!");
      }
    }

    public class Logger
    {
      public static void Log()
      {
       Console.WriteLine("log!");
      }
    }


    Next time, I'll either try to call a method from another assembly or a method that takes some parameters.

  • 相关阅读:
    poj 1084 Brainman(归并排序)
    Poj 2299 Ultra-QuickSort(归并排序)
    poj 1068 Parencodings(栈)
    Poj 2499 Binary Tree(贪心)
    Poj 2255 Tree Recovery(二叉搜索树)
    poj 2021 Relative Relatives(暴力)
    Poj 2092 Grandpa is Famous(基数排序)
    解决UMeditor上传图片失败
    解决使用了属性overflow:scroll、overflow-y:scroll、overflow-x:scroll;的网页在iPhone iOS Safari浏览器中滑动不流畅问题
    Kindeditor上传图片报错
  • 原文地址:https://www.cnblogs.com/rick/p/833677.html
Copyright © 2011-2022 走看看