尝试通过ICorProfilerCallback接口修改System.String.Concat方法的IL,但是出错了

I tried to modify the IL of the System.String.Concat method through the ICorProfilerCallback interface, but something went wrong

我尝试通过ICorProfilerCallback接口修改System.String.Concat方法的IL,在方法执行前添加自己的跟踪代码。 我修改了其他方法的IL,添加了跟踪代码,没有任何问题。编译通过后可以运行.

  ....

 if (!isStatic) {
   
            reWriterWrapper.LoadNull();// Ldnull  
            reWriterWrapper.StLocal(indexMethodTrace); //stloc  
            reWriterWrapper.LoadNull(); //Ldnull  
            reWriterWrapper.StLocal(indexEx); 
            reWriterWrapper.LoadNull();
            reWriterWrapper.StLocal(indexRet);
            ILInstr* pTryStartInstr = reWriterWrapper.CallMember0(getInstanceMemberRef, false);         
            reWriterWrapper.Cast(traceAgentTypeRef);  //castclass 
            reWriterWrapper.LoadToken(functionInfo.type.id);//ldtoken 
            reWriterWrapper.CallMember(moduleMetaInfo->getTypeFromHandleToken, false); 
            reWriterWrapper.LoadArgument(0); //ldarg 0  
            auto argNum = functionInfo.signature.NumberOfArguments();
            reWriterWrapper.CreateArray(objectTypeRef, argNum);           
            auto arguments = functionInfo.signature.GetMethodArguments();           
            for (unsigned i = 0; i < argNum; i++) {
                reWriterWrapper.BeginLoadValueIntoArray(i);
                reWriterWrapper.LoadArgument(i + 1);//ldarg                 
                auto argTypeFlags = arguments[i].GetTypeFlags(elementType);               
                if (argTypeFlags & TypeFlagByRef) {
                    reWriterWrapper.LoadIND(elementType); //ldind 中
                }              
                if (argTypeFlags & TypeFlagBoxedType) {
                    auto tok = arguments[i].GetTypeTok(pEmit, corLibAssemblyRef); /
                    if (tok == mdTokenNil) {
                        return S_OK;
                    }
                    reWriterWrapper.Box(tok);
                }
                reWriterWrapper.EndLoadValueIntoArray(); //stelem_ref 
            }
            reWriterWrapper.LoadInt32((INT32)function_token); //ldc_i4 
            reWriterWrapper.CallMember(beforeMemberRef, true); // call 
            reWriterWrapper.Cast(methodTraceTypeRef); //Castclass   
            reWriterWrapper.StLocal(rewriter.cNewLocals - 1); //STLOC 
            ILInstr* pRetInstr = pReWriter->NewILInstr();
            pRetInstr->m_opcode = CEE_RET;
            pReWriter->InsertAfter(pReWriter->GetILList()->m_pPrev, pRetInstr);
            bool isVoidMethod = (retTypeFlags & TypeFlagVoid) > 0;
            auto ret = functionInfo.signature.GetRet();
            bool retIsBoxedType = false;
            mdToken retTypeTok;
            if (!isVoidMethod) {
                retTypeTok = ret.GetTypeTok(pEmit, corLibAssemblyRef);
                if (ret.GetTypeFlags(elementType) & TypeFlagBoxedType) {
                    retIsBoxedType = true;
                }
            }
            reWriterWrapper.SetILPosition(pRetInstr);
            reWriterWrapper.StLocal(indexEx); //stloc 
            ILInstr* pRethrowInstr = reWriterWrapper.Rethrow(); //Rethrow
            reWriterWrapper.LoadLocal(indexMethodTrace); //ldloc
            ILInstr* pNewInstr = pReWriter->NewILInstr(); //Brfalse  
            pNewInstr->m_opcode = CEE_BRFALSE_S;
            pReWriter->InsertBefore(pRetInstr, pNewInstr);
            reWriterWrapper.LoadLocal(indexMethodTrace); //ldloc
            reWriterWrapper.LoadLocal(indexRet);//ldloc
            reWriterWrapper.LoadLocal(indexEx); //ldloc
            reWriterWrapper.CallMember(endMemberRef, true); // call  [
            ILInstr* pEndFinallyInstr = reWriterWrapper.EndFinally(); 

            pNewInstr->m_pTarget = pEndFinallyInstr;
            if (!isVoidMethod) {
                reWriterWrapper.LoadLocal(indexRet);//ldloc
                if (retIsBoxedType) {
                    reWriterWrapper.UnboxAny(retTypeTok); 
                }
                else {
                    reWriterWrapper.Cast(retTypeTok);  
                }
            }

            for (ILInstr* pInstr = pReWriter->GetILList()->m_pNext; pInstr != pReWriter->GetILList(); pInstr = pInstr->m_pNext) {
                switch (pInstr->m_opcode)
                {
                case CEE_RET:
                {
                    if (pInstr != pRetInstr) {
                        if (!isVoidMethod) {
                            reWriterWrapper.SetILPosition(pInstr); 
                            if (retIsBoxedType) {
                                reWriterWrapper.Box(retTypeTok); 
                            }
                            reWriterWrapper.StLocal(indexRet); //ldloc
                        }
                        pInstr->m_opcode = CEE_LEAVE_S;  //Leave_S 
                        pInstr->m_pTarget = pEndFinallyInstr->m_pNext;
                    }
                    break;
                }
                default:
                    break;
                }
            }

            EHClause exClause{};
            exClause.m_Flags = COR_ILEXCEPTION_CLAUSE_NONE;
            exClause.m_pTryBegin = pTryStartInstr;
            exClause.m_pTryEnd = pRethrowInstr->m_pPrev;
            exClause.m_pHandlerBegin = pRethrowInstr->m_pPrev;
            exClause.m_pHandlerEnd = pRethrowInstr;
            exClause.m_ClassToken = exTypeRef;
            EHClause finallyClause{};
            finallyClause.m_Flags = COR_ILEXCEPTION_CLAUSE_FINALLY;
            finallyClause.m_pTryBegin = pTryStartInstr;
            finallyClause.m_pTryEnd = pRethrowInstr->m_pNext;
            finallyClause.m_pHandlerBegin = pRethrowInstr->m_pNext;
            finallyClause.m_pHandlerEnd = pEndFinallyInstr;
            auto m_pEHNew = new EHClause[rewriter.m_nEH + 2];
            for (unsigned i = 0; i < rewriter.m_nEH; i++) {
                m_pEHNew[i] = rewriter.m_pEH[i];
            }

            rewriter.m_nEH += 2;
            m_pEHNew[rewriter.m_nEH - 2] = exClause;
            m_pEHNew[rewriter.m_nEH - 1] = finallyClause;
            rewriter.m_pEH = m_pEHNew;

        }
        else
        {
            //static method
    
            reWriterWrapper.LoadNull();// Ldnull  
            reWriterWrapper.StLocal(indexMethodTrace); //stloc  
            reWriterWrapper.LoadNull(); //Ldnull  
            reWriterWrapper.StLocal(indexEx); //stloc 
            reWriterWrapper.LoadNull();// Ldnull  
            reWriterWrapper.StLocal(indexRet);
            ILInstr* pTryStartInstr = reWriterWrapper.CallMember0(getInstanceMemberRef, false);
            reWriterWrapper.Cast(traceAgentTypeRef);  //castclass 
            reWriterWrapper.LoadNull(); //ldstr      
            reWriterWrapper.LoadNull();
            auto argNum = functionInfo.signature.NumberOfArguments();
            reWriterWrapper.CreateArray(objectTypeRef, argNum); //newarr 
            auto arguments = functionInfo.signature.GetMethodArguments();
            for (unsigned i = 0; i < argNum; i++) {
                    reWriterWrapper.BeginLoadValueIntoArray(i);                 
                    reWriterWrapper.LoadArgument(i);//ldarg  Static index 0 
                    auto argTypeFlags = arguments[i].GetTypeFlags(elementType);
                    if (argTypeFlags & TypeFlagByRef) {
                        reWriterWrapper.LoadIND(elementType); //ldind
                    }
                    if (argTypeFlags & TypeFlagBoxedType) {
                        auto tok = arguments[i].GetTypeTok(pEmit, corLibAssemblyRef); 
                        if (tok == mdTokenNil) {
                            return S_OK;
                        }
                        reWriterWrapper.Box(tok);
                    }

                    reWriterWrapper.EndLoadValueIntoArray(); //stelem_ref 
            }
            reWriterWrapper.LoadInt32((INT32)function_token); //ldc_i4 
            reWriterWrapper.CallMember(beforeMemberRef, true); // call  
            reWriterWrapper.Cast(methodTraceTypeRef); //Castclass   
            reWriterWrapper.StLocal(rewriter.cNewLocals - 1); //STLOC 
  
            ILInstr* pRetInstr = pReWriter->NewILInstr();/
            pRetInstr->m_opcode = CEE_RET;
            pReWriter->InsertAfter(pReWriter->GetILList()->m_pPrev, pRetInstr);

            bool isVoidMethod = (retTypeFlags & TypeFlagVoid) > 0;
            auto ret = functionInfo.signature.GetRet();
            bool retIsBoxedType = false;
            mdToken retTypeTok;
            if (!isVoidMethod) {
                retTypeTok = ret.GetTypeTok(pEmit, corLibAssemblyRef);
                if (ret.GetTypeFlags(elementType) & TypeFlagBoxedType) {
                    retIsBoxedType = true;
                }
            }

            reWriterWrapper.SetILPosition(pRetInstr);
            reWriterWrapper.StLocal(indexEx); //stloc 
            ILInstr* pRethrowInstr = reWriterWrapper.Rethrow(); //Rethrow
            reWriterWrapper.LoadLocal(indexMethodTrace); //ldloc
            ILInstr* pNewInstr = pReWriter->NewILInstr(); //Brfalse   
            pNewInstr->m_opcode = CEE_BRFALSE_S;
            pReWriter->InsertBefore(pRetInstr, pNewInstr);
            reWriterWrapper.LoadLocal(indexMethodTrace); //ldloc
            reWriterWrapper.LoadLocal(indexRet);//ldloc
            reWriterWrapper.LoadLocal(indexEx); //ldloc
            reWriterWrapper.CallMember(endMemberRef, true); // call  
            ILInstr* pEndFinallyInstr = reWriterWrapper.EndFinally(); //Endfinally   
            pNewInstr->m_pTarget = pEndFinallyInstr;
            if (!isVoidMethod) {
                reWriterWrapper.LoadLocal(indexRet);//ldloc
                if (retIsBoxedType) {
                    reWriterWrapper.UnboxAny(retTypeTok); // Unbox_Any 
                }
                else {
                    reWriterWrapper.Cast(retTypeTok); 
                }
            }
            for (ILInstr* pInstr = pReWriter->GetILList()->m_pNext; pInstr != pReWriter->GetILList(); pInstr = pInstr->m_pNext) {
                switch (pInstr->m_opcode)
                {
                case CEE_RET:
                {
                    if (pInstr != pRetInstr) {
                        if (!isVoidMethod) {
                            reWriterWrapper.SetILPosition(pInstr); 
                            if (retIsBoxedType) {
                                reWriterWrapper.Box(retTypeTok); 
                            }
                            reWriterWrapper.StLocal(indexRet); //ldloc
                        }
                        pInstr->m_opcode = CEE_LEAVE_S;  //Leave_S 
                        pInstr->m_pTarget = pEndFinallyInstr->m_pNext;
                    }
                    break;
                }
                default:
                    break;
                }
            }

            EHClause exClause{};
            exClause.m_Flags = COR_ILEXCEPTION_CLAUSE_NONE;
            exClause.m_pTryBegin = pTryStartInstr;
            exClause.m_pTryEnd = pRethrowInstr->m_pPrev;
            exClause.m_pHandlerBegin = pRethrowInstr->m_pPrev;
            exClause.m_pHandlerEnd = pRethrowInstr;
            exClause.m_ClassToken = exTypeRef;

            EHClause finallyClause{};
            finallyClause.m_Flags = COR_ILEXCEPTION_CLAUSE_FINALLY;
            finallyClause.m_pTryBegin = pTryStartInstr;
            finallyClause.m_pTryEnd = pRethrowInstr->m_pNext;
            finallyClause.m_pHandlerBegin = pRethrowInstr->m_pNext;
            finallyClause.m_pHandlerEnd = pEndFinallyInstr;

            auto m_pEHNew = new EHClause[rewriter.m_nEH + 2];
            for (unsigned i = 0; i < rewriter.m_nEH; i++) {
                m_pEHNew[i] = rewriter.m_pEH[i];
            }

            rewriter.m_nEH += 2;
            m_pEHNew[rewriter.m_nEH - 2] = exClause;
            m_pEHNew[rewriter.m_nEH - 1] = finallyClause;
            rewriter.m_pEH = m_pEHNew;

        }
        hr = rewriter.Export();
 ....

LocalSigCode

 HRESULT ModifyLocalSig(CComPtr<IMetaDataImport2>& pImport, CComPtr<IMetaDataEmit2>& pEmit, ILRewriter& reWriter,  mdTypeRef exTypeRef,mdTypeRef methodTraceTypeRef)
    {

        HRESULT hr;

        PCCOR_SIGNATURE rgbOrigSig = NULL;
        ULONG cbOrigSig = 0;
        UNALIGNED INT32 temp = 0;
        if (reWriter.m_tkLocalVarSig != mdTokenNil)
        {
            IfFailRet(pImport->GetSigFromToken(reWriter.m_tkLocalVarSig, &rgbOrigSig, &cbOrigSig));

            const auto len = CorSigCompressToken(methodTraceTypeRef, &temp);
            if(cbOrigSig - len > 0){
                if(rgbOrigSig[cbOrigSig - len -1]== ELEMENT_TYPE_CLASS){
                    if (memcmp(&rgbOrigSig[cbOrigSig - len], &temp, len) == 0) {
                        return E_FAIL;
                    }
                }
            }
        }

        auto exTypeRefSize = CorSigCompressToken(exTypeRef, &temp);
        auto methodTraceTypeRefSize = CorSigCompressToken(methodTraceTypeRef, &temp);
        ULONG cbNewSize = cbOrigSig + 1 + 1 + methodTraceTypeRefSize + 1 + exTypeRefSize;
       
        ULONG cOrigLocals;
        ULONG cNewLocalsLen;
        ULONG cbOrigLocals = 0;
        if (cbOrigSig == 0) {
            cbNewSize += 2;
            reWriter.cNewLocals = 3;
            cNewLocalsLen = CorSigCompressData(reWriter.cNewLocals, &temp);
        }
        else {
            cbOrigLocals = CorSigUncompressData(rgbOrigSig + 1, &cOrigLocals);
            reWriter.cNewLocals = cOrigLocals + 3;
            cNewLocalsLen = CorSigCompressData(reWriter.cNewLocals, &temp);
            cbNewSize += cNewLocalsLen - cbOrigLocals;
        }
         auto rgbNewSig = new COR_SIGNATURE[cbNewSize]; 
        *rgbNewSig = IMAGE_CEE_CS_CALLCONV_LOCAL_SIG; 
        ULONG rgbNewSigOffset = 1;
        memcpy(rgbNewSig + rgbNewSigOffset, &temp, cNewLocalsLen);
        rgbNewSigOffset += cNewLocalsLen;
        if (cbOrigSig > 0) {
            const auto cbOrigCopyLen = cbOrigSig - 1 - cbOrigLocals;
            memcpy(rgbNewSig + rgbNewSigOffset, rgbOrigSig + 1 + cbOrigLocals, cbOrigCopyLen);
            rgbNewSigOffset += cbOrigCopyLen;
        }
        rgbNewSig[rgbNewSigOffset++] = ELEMENT_TYPE_OBJECT;
        rgbNewSig[rgbNewSigOffset++] = ELEMENT_TYPE_CLASS;
        exTypeRefSize = CorSigCompressToken(exTypeRef, &temp);
        memcpy(rgbNewSig + rgbNewSigOffset, &temp, exTypeRefSize);
        rgbNewSigOffset += exTypeRefSize;
        rgbNewSig[rgbNewSigOffset++] = ELEMENT_TYPE_CLASS;
        methodTraceTypeRefSize = CorSigCompressToken(methodTraceTypeRef, &temp);
        memcpy(rgbNewSig + rgbNewSigOffset, &temp, methodTraceTypeRefSize);
        rgbNewSigOffset += methodTraceTypeRefSize;
        IfFailRet(pEmit->GetTokenFromSig(&rgbNewSig[0], cbNewSize, &reWriter.m_tkLocalVarSig));
        return S_OK;
    }

修改方法模板:

//before fixing method
private Task DataRead(string a, int b)
{
    return Task.Delay(10);
}
//After modification
private Task DataReadWrapper(string a, int b)
{
    object ret = null;
    Exception ex = null;
    MethodTrace methodTrace = null;
    try
    {
        methodTrace = (MethodTrace)((TraceAgent)TraceAgent.GetInstance())
            .BeforeMethod(this.GetType(), this, new object[]{ a, b }, functiontoken);

        ret = Task.Delay(10);
        goto T;
    }
    catch (Exception e)
    {
        ex = e;
        throw;
    }
    finally
    {
        if (methodTrace != null)
        {
            methodTrace.EndMethod(ret, ex);
        }
    }
T:
    return (Task)ret;
}

错误:

Unhandled exception. 
   Cannot print exception string because Exception.ToString() failed.

 Application '/LM/W3SVC/1/ROOT' with physical root 'C:\inetpub\wwwroot\DotNetRangeCore\' failed to load coreclr. Exception message: CLR worker thread exited prematurely 

如果我在其他方法中通过这段代码修改IL是没有问题的。比如:set_CommandText、System.Random.Next、System.Web.HttpContext.FinishPipelineRequest...

不知道为什么修改Concat会出错。

我通过更换解决了。如果这个IL修改后报错,我换成打包方式