Click here to Skip to main content
Click here to Skip to main content
Articles » Languages » MSIL » General » Downloads
 
Add your own
alternative version
Go to top

ILRewriting for beginners

, 27 Sep 2012
Runtime IL-Rewriting can be used to add behavior such as logging to applications, or redirect calls from one API to another. This article and accompanying source code explains how to substitute a method call at runtime.
ILRewriting_demo-noexe.zip
ILRewriting_demo
ILRewriting_demo.zip
ILRewriteProfiler.dll
InterceptApp.exe
InterceptLib.dll
SampleApp1.exe
ILRewriting_src.zip
ILRewriting_src
ILEmitTest
Properties
ILRewriteProfiler
exports.def
ILRewriteProfiler.vcxproj.filters
ILRewriteProfiler.vcxproj.user
InterceptApp
app.aps
app.ico
InterceptApp.vcxproj.filters
InterceptApp.vcxproj.user
InterceptLib
InterceptLib.snk
Properties
SampleApp1
Properties
SampleApp1.snk
// ----------------------------------------------------------------------------------------------
// Copyright (c) Mattias H�gstr�m.
// ----------------------------------------------------------------------------------------------
// This source code is subject to terms and conditions of the Microsoft Public License. A 
// copy of the license can be found in the License.html file at the root of this distribution. 
// If you cannot locate the Microsoft Public License, please send an email to 
// dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
// by the terms of the Microsoft Public License.
// ----------------------------------------------------------------------------------------------
// You must not remove this notice, or any other, from this software.
// ----------------------------------------------------------------------------------------------

#include "stdafx.h"
#include <cor.h>
#include "OpCodeParser.h"


ULONG OpCodeParser::ReplaceFunctionCall(BYTE* opCodeBytes, ULONG length, mdMemberRef fromMemberRef, mdMemberRef toMemberRef)
{
   ULONG count = 0;
   ULONG index = 0;
   while (index < length)
   {
      BYTE opCode = opCodeBytes[index];
      if (IsFunctionCall(opCode))
      {
         int addressIndex = index + 1;
         BYTE* address = opCodeBytes + addressIndex;
         mdMemberRef* memberRefAddress = reinterpret_cast<mdMemberRef*>(address);
         mdMemberRef memberRef = *memberRefAddress;

         if (fromMemberRef == memberRef)
         {
            *memberRefAddress = toMemberRef;
            count++;
         }
      }
      ULONG opCodeSize = InstructionSize(opCodeBytes + index);
      index += opCodeSize;
   }
   return count;
}

ULONG OpCodeParser::CountFunctionCalls(const BYTE* opCodeBytes, ULONG length)
{
   ULONG count = 0;
   ULONG index = 0;
   while (index < length)
   {
      BYTE opCode = opCodeBytes[index];
      if (IsFunctionCall(opCode))
         count++;
      ULONG opCodeSize = InstructionSize(opCodeBytes + index);
      index += opCodeSize;
   }
   return count;
}

bool OpCodeParser::IsFunctionCall(BYTE opCode)
{
   switch (opCode)
   {
   case 0x28:
      return true;
   case 0x29:
   default:
      return false;
   }
}

 ULONG OpCodeParser::InstructionSize(const BYTE* opCodeBytes)
 {
    const int tokenSize = sizeof(mdToken);
    const int int8Size = 1;
    const int int32Size = 4;
    const int int64Size = 8;
    const int float32Size = 4;
    const int float64Size = 8;



    BYTE opCode = *opCodeBytes;
    //__debugbreak();
    if ((0x00 <= opCode) && (opCode <= 0x0d))
       return 1;
    if ((0x0e <= opCode) && (opCode <= 0x13))
       return 1 + int8Size;
    if ((0x14 <= opCode) && (opCode <= 0x1e))
       return 1;
    if ((0x2b <= opCode) && (opCode <= 0x37))
       return 1 + int8Size;
    if ((0x38 <= opCode) && (opCode <= 0x44))
       return 1 + int32Size;
    if ((0x46 <= opCode) && (opCode <= 0x6e))
       return 1;
    if ((0x6f <= opCode) && (opCode <= 0x75))
       return 1 + tokenSize;
    if ((0x7b <= opCode) && (opCode <= 0x81))
       return 1 + tokenSize;
    if ((0x82 <= opCode) && (opCode <= 0x8b))
       return 1;
    if ((0x90 <= opCode) && (opCode <= 0xa2))
       return 1;
    if ((0xb3 <= opCode) && (opCode <= 0xba))
       return 1;
    if ((0xd1 <= opCode) && (opCode <= 0xdc))
       return 1;

    switch (opCode)
    {
    case 0x1f:
       return 1 + int8Size;
    case 0x20:
       return 1 + int32Size;
    case 0x21:
       return 1 + int64Size;
    case 0x22:
       return 1 + float32Size;
    case 0x23:
       return 1 + float64Size;
    case 0x25:
    case 0x26:
       return 1;
    case 0x27:
    case 0x28:
    case 0x29:
       return 1 + tokenSize;
    case 0x2a:
       return 1;
    case 0x45:
       {
          BYTE length = opCodeBytes[1];
          return 1 + 1+ length;
       }
    case 0x76:
    case 0x7a:
       return 1;
    case 0x79:
    case 0x8c:
    case 0x8d:
       return 1 + tokenSize;
    case 0x8e:
       return 1;
    case 0x8f:
       return 1 + tokenSize;
    case 0xa3:
    case 0xa4:
    case 0xa5:
       return 1 + tokenSize;
    case 0xc2:
    case 0xc6:
    case 0xd0:
       return 1+ tokenSize;
    case 0xc3:
       return 1;
    case 0xdd:
       return 1 + int32Size;
    case 0xde:
       return 1 + int8Size;
    case 0xdf:
    case 0xe0:
       return 1;
    }

    if (opCode == 0xfe)
    {
       BYTE extOpCode = opCodeBytes[1];

       if ((0x00 <= extOpCode) && (extOpCode <= 0x05))
          return 1;
       if ((0x09 <= extOpCode) && (extOpCode <= 0x0e))
          return 1 + int32Size;
       switch (extOpCode)
       {
       case 0x06:
       case 0x07:
          return 1 + tokenSize;
       case 0x0f:
       case 0x11:
          return 1;
       case 0x12:
          return 1 + int8Size;
       case 0x13:
       case 0x14:
          return 1;
       case 0x15:
       case 0x16:
          return 1 + tokenSize;
       case 0x17:
       case 0x18:
       case 0x1a:
          return 1;
       case 0x1c:
          return 1 + tokenSize;
       case 0x1d:
       case 0x1e:
          return 1;
       }
    }    
    __debugbreak();
    throw "Unrecognized opcode";
 }

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)

Share

About the Author

Mattias Högström
Architect Visma Software AB
Sweden Sweden
Mattias works at Visma, a leading Nordic ERP solution provider. He has good knowledge in C++/.Net development, test tool development, and debugging. His great passion is memory dump analysis. He likes giving talks and courses.
Follow on   Twitter

| Advertise | Privacy | Mobile
Web04 | 2.8.140926.1 | Last Updated 27 Sep 2012
Article Copyright 2012 by Mattias Högström
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid