During one of my Dynamics CRM projects, I faced the request where a customer asked to change the behavior of some processes in the system. That’s was the legacy implementation of Dynamics CRM 2011 and customer was not able to provide the source code of the plugins, because all responsible people have already left the company. The codebase was big enough, so I decided to analyze if it would be possible to update the behavior of some processes without the source code.
In this article, I will provide information regarding scenarios and tools which could help you to handle such kind of requests.
The process of reverse engineering and decompilation in most cases is illegal, so the content of this article should only be used for learning purposes and to study tools and methods which might help you in some instances where you own the code you research.
As an example, I will take a simple plugin from Microsoft Docs. The plug-in creates a task activity after a new account is created. The activity reminds the user to follow-up with the new account customer one week after the account was created.
Please find the code snippet below:
public class FollowupPlugin : IPlugin { public void Execute(IServiceProvider serviceProvider) { //Extract the tracing service for use in debugging sandboxed plug-ins. var tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService)); // Obtain the execution context from the service provider. var context = (IPluginExecutionContext) serviceProvider.GetService(typeof(IPluginExecutionContext)); // The InputParameters collection contains all the data passed in the message request. if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity entity) { if (entity.LogicalName != "account") return; try { var followup = new Entity("task") { ["subject"] = "Send e-mail to the new customer.", ["description"] = "Follow up with the customer. Check if there are any new issues that need resolution.", ["scheduledstart"] = DateTime.Now.AddDays(7), ["scheduledend"] = DateTime.Now.AddDays(7), ["category"] = context.PrimaryEntityName }; if (context.OutputParameters.Contains("id")) { var regardingobjectid = new Guid(context.OutputParameters["id"].ToString()); var regardingobjectidType = "account"; followup["regardingobjectid"] = new EntityReference(regardingobjectidType, regardingobjectid); } var serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory)); var service = serviceFactory.CreateOrganizationService(context.UserId); tracingService.Trace("FollowupPlugin: Creating the task activity."); service.Create(followup); } catch (FaultException ex) { throw new InvalidPluginExecutionException("An error occurred.", ex); } catch (Exception ex) { tracingService.Trace("FollowupPlugin: {0}", ex.ToString()); throw; } } } }
Let’s assume that you want to make a reminder not one week, but three days after the account was created. So let’s install all the tools needed.
1. ILSpy. – ILSpy is the open-source .NET assembly browser and decompiler.
2. Reflexil -Reflexil is an assembly editor and runs as a plug-in for Red Gate’s Reflector, ILSpy and Telerik’s JustDecompile. Please download the latest version of reflexil as ILSpy plugin. The file name should be something like this: reflexil.for.ILSpy.2.2.bin.zip.
Once you downloaded this two tools extract ILSpy to some folder on your PC and then extract the content of Reflexil into the same folder. Launch ILSpy and check that you have Reflexil loaded.
On the picture above you can see how it should look like.
Now you can compile the plugin and sign it with strong name key. After that you should have a dll file which you can register in your Dynamics 365 environment. Let’s now open this dll file in ILSpy.
On the picture above you can see my dll file called MoveStages which is opened in ILSpy. Also, I’ve opened method Execute from class FollowupPlugin. You can see the source code of our plugin. Now let’s click on the Reflexil plugin icon. This will open Reflexil plugin with IL code which you can actually change. But it is not so easy, as you can’t just change a code and save the assembly. Our assembly signed by strong name key and can’t be changed.
Let’s see now how to remove strong name key from our assembly. To do that we need to save assembly, so open context menu and click save as like on the picture below
After that, you will see the “Save as” dialog. Try to save assembly to someplace. After this operation, you will get another dialog with the information that “Original assembly is signed and will not load correctly until you fix it”. There is a button “Remove Strong Name”, so click on this button. New dialog with information regarding your assembly signature will pop up. You can see how it looks like on the picture below:
Now click on the button “Remove Strong Name and update referencing assemblies”. After this operation field “Signed assembly” should change the value to following: “YourAssemblyName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null“. That means that you have successfully remove strong name key of the assembly. Now we have the saved version of our assembly which doesn’t contain strong name key. The next step is to change the behavior of the plugin as we can now save the assembly without issues.
Now let’s open our saved assembly. If you didn’t change the name it should be something like following: “YourAssemblyName.Patched.dll”. Our patched assembly doesn’t contain the strong name key. Let’s open our method Execute and click on Reflexil plugin to see the IL Code. Now we can change the behavior of the plugin. As you remember we want to change scheduledstart and scheduledend parameters of our plugin. Currently, they are equal to DateTime.Now + 7 days, we want to have DateTime.Now + 3 days. Let’s review the IL code. So once you open Reflexil plugin on our Execute method you will see the IL code, you don’t need to understand all of the instruction to find the right place. On the picture below I’ve highlighted the most important parts.
I don’t want to go into details, as if you’re going to study IL it is better to read a book about it and have some practice. As you see instruction 043 loads field name, after this we call DateTime.Now, then we push on stack 7 and call function AddDays to get the final result, so it is evident that we need to change this 7 value to 3. And the same for instruction 056. To change this, you need to call the context menu and choose the item “Edit”. Pretty easy. Once you change these two instructions, you can again save the assembly. This time Reflexil will not ask you about strong name key.
So now we have a correct assembly, but we can’t register it as it is not signed right? To sign this assembly we need to generate a strong name key, you can take one you already have or generate a new one. Once we have a key we can use ildasm utility from Visual Studio to sign our plugin with the new key. First of all let’s save our patched assembly to some folder like C:\assembly. Now using Developer Command Prompt for Visual Studio you can call ildasm with following parameters.
ildasm C:\assembly\YourAssemblyName.Patched.dll /out:YourAssemblyName.il
This command will generate IL code from your assembly. You can review the il file with the notepad. Now to create a signed version of our assembly we need to call another command.
ilasm C:\assembly\YourAssemblyName.il /dll /key=test.snk
This command will generate dll file which you can register in your Dynamics 365 environment. You can check the dll again with the ILspy to be sure that your changes are saved.
In case you are using Dynamics 365 V9, please be sure that you are using .net framework 4.5.2 for this exercise, otherwise, you will not be able to register the assembly. More information here: At this time Microsoft Dynamics 365 requires version 4.6.2 of the .NET Framework for plugin assemblies. Of course, you can also change the target framework for dll without code recompilation, but this is another story.