A customer’s urgent bug, I used two ways to c# decompile and modify the source code

Time:2021-11-24

1: Background

1. Tell a story

On Friday afternoon, the operation fed back an urgent bug, saying that the customer couldn’t open an information list and needed to be solved urgently. The attached log file was also sent. After reading the log, it was like this:

Date: 2020-11-13 12:25:45923 thread ID: [3924] log level: Info error class: XXX property: [(null)] - Error Description: an uncapped exception occurred in the application, message: the string was not recognized as a valid datetime.;
 Stacktrace: in system.datetimeparse.parse (string s, datetimeformatinfo dtfi, datetimestyles styles)
   In system. Data. Constnode.. ctor (datatable, table, ValueType, object constant, Boolean fparsequotes)
   In system. Data. Expressionparser. Parse()
   In system. Data. Dataexpression.. ctor (datatable, table, string expression, type)
   In system. Data. Select.. ctor (datatable, table, string filterexpression, string sort, dataviewrowstate recordstates)
   In system. Data. Datatable. Select (string filterexpression)

From the exception information, we can see that the exception was thrown during datatable. Select, and the code was traced through the call stack.

public Task QueryDataTable()
        {
            var dt = new DataTable();

            dt.Columns.Add(new DataColumn("SendTime"));
            dt.Rows.Add(dt.NewRow()["SendTime"] = "2020/11/14");

            var where = $" SendTime < #{DateTime.Now.ToString()}#";

            var query = dt.Select(where).CopyToDataTable();
        }

The big pit is right here. Most of the time, the filtering datatable can be written in this way:SendTime < #2020/11/5#However, the customer is in Singapore. The operating system is all English, and the time format is not known. I estimate that the time format contains similar #, and it happens to encounter the pre suffix#, there was an error in splitting, resulting in the classicThe string was not recognized as a valid datetimeException thrown.

This bug is still very simple to change. Just # replace it with ‘i.e.:SendTime < '2020/11/5'If everything goes well, the article should stop here, but God just teased me because it was an emergency bug. The R & D boss & project implementation asked for leave. I’m really not sure which release version I gave to the customer. I don’t want to create complications. In order to solve this problem first, I came up with a good way to decompile and modify, which is the least expensive, It can be done as soon as possible.

2: Using dnspy decompile to modify code

1. Use the editing method mode of dnspy

In order to better understand the modification through dnspy, let’s talk about the most convenient way of modifying DLL by dnspy:Editing method, this method is very convenient and does not need to understand IL code. For demonstration, I give a simple addition operation.

static void Main(string[] args)
        {
            var i = 10;

            var j = 20;

            Console.WriteLine($"{i}+{j}={i + j}");

            Console.ReadLine();
        }

Next willvar i= 10Change tovar i=100The steps are:

  • Right clickEditing method
  • Bullet frame modificationvar i=10 -> var i=100
  • Click the lower right cornercompile
  • CTRL + Shift + s save all
  • Select from the pop-up boxdetermine

The screenshot is as follows:

图片名称

Finally, the EXE in the bin directory was successfully modified. Double click to see your results!

, it’s done. Isn’t it too simple? I feel that there is no threshold for decompilation. Ha ha, is there really no threshold?

If you don’t believe me, let me give an example of an asynchronous method:

class Program
    {
        static void Main(string[] args)
        {
            var query = QueryDataTable().Result;

            Console.WriteLine(JsonConvert.SerializeObject(query));

            Console.ReadLine();
        }

        static async Task QueryDataTable()
        {
            var dt = new DataTable();

            dt.Columns.Add(new DataColumn("SendTime"));
            dt.Rows.Add(dt.NewRow()["SendTime"] = "2020/11/14");

            var where = $" SendTime < #{DateTime.Now.ToString()}#";

            Console.Write(where + "\t");

            var task = await Task.Run(() => { return dt.Select(where).CopyToDataTable(); });

            return task;
        }
    }

Next, decompile:

图片名称

I’ll go, please. Two messages can be seen from the picture:

  • Asynchronous methods will generate state machines. If you use c# mode to see the decompiled code, you can’t see the automatically generated state machine classes. How to modify??? For example, you can find:var where = $" SendTime < #{DateTime.Now.ToString()}#";Are you?

  • fromd__1Class naming format:d__Look, you clickcompileThe button must not pass the compiler.

And that’s exactly what happened to me. It’s too stupid… Therefore, it is impossible not to touch IL in actual decompilation.

2. Edit IL instruction mode using dnspy

Except in dnspyEditing methodIn addition, you can also useEdit IL instruction, this function is powerful. Let’s see how to deal with it? The operation steps are as follows:

  • Switch c# to IL view in dnspy
  • Find the IL code of the class to be modified and right-click to selectEdit IL instruction
  • After editing, clickdetermine

The approximate screenshot is as follows:

图片名称

Then double-click execute exe to see that the modification has been successful.

图片名称

However, there is a bad thing here, that is, there are many places I need to modify this bug, andEdit IL instructionThere is no search function in the window, which is embarrassing and very troublesome to deal with!

3: Decompile and modify code using ILdasm & ILAsm

1. Introduction

This pair is still quite interesting. ILdasm is used to view the IL code in DLL and ILAsm is used to compile IL into DLL, so it’s good to use the two together.

  • ILdasm path: C: \ program files (x86) \ Microsoft SDKs \ windows \ v10.0a \ bin \ netfx 4.8 tools \ ildasm.exe
  • ILAsm path: C: \ windows \ Microsoft. Net \ framework64 \ v4.0.30319 \ ilasm.exe

2. Export the IL file using ILdasm

Open ILdasm, click ‘file’ – > ‘dump’ to generate an IL file. Here I specify the name as my.il, and then you can # change it to ‘in my.il, as shown in the following figure:

图片名称

3. Compile the IL file using ILAsm

Use ILAsm to regenerate my.il into consoleapp2.exe.

E:\net5\ConsoleApp2\ConsoleApp2\bin\Debug>ilasm my.il my.res /output=ConsoleApp2.exe /exe

Microsoft (R) .NET Framework IL Assembler.  Version 4.8.3752.0
Copyright (c) Microsoft Corporation.  All rights reserved.
Assembling 'my.il'  to EXE --> 'ConsoleApp2.exe'
Source file is UTF-8

Assembled method ConsoleApp2.Program?<>c__DisplayClass1_0::.ctor
Assembled method ConsoleApp2.Program?<>c__DisplayClass1_0::b__0
Assembled method ConsoleApp2.Program?d__1::.ctor
Assembled method ConsoleApp2.Program?d__1::MoveNext
Assembled method ConsoleApp2.Program?d__1::SetStateMachine
Assembled method ConsoleApp2.Program::Main
Assembled method ConsoleApp2.Program::QueryDataTable
Assembled method ConsoleApp2.Program::.ctor

Assembling 'my.res'  to EXE --> 'ConsoleApp2.exe'
Source file is UNICODE

Creating PE file

Emitting classes:
Class 1:        ConsoleApp2.Program
Class 2:        ConsoleApp2.Program?>c__DisplayClass1_0
Class 3:        ConsoleApp2.Program?QueryDataTable>d__1

Emitting fields and methods:
Global
Class 1 Methods: 3;
Class 2 Fields: 2;      Methods: 2;
Class 3 Fields: 6;      Methods: 3;
Resolving local member refs: 44 -> 44 defs, 0 refs, 0 unresolved

Emitting events and properties:
Global
Class 1
Class 2
Class 3
Method Implementations (total): 2
Resolving local member refs: 0 -> 0 defs, 0 refs, 0 unresolved
Writing PE file
Operation completed successfully

E:\net5\ConsoleApp2\ConsoleApp2\bin\Debug>ilasm my.il my.res /output=ConsoleApp2.exe /exe

Microsoft (R) .NET Framework IL Assembler.  Version 4.8.3752.0
Copyright (c) Microsoft Corporation.  All rights reserved.
Assembling 'my.il'  to EXE --> 'ConsoleApp2.exe'
Source file is UTF-8

Assembled method ConsoleApp2.Program?<>c__DisplayClass1_0::.ctor
Assembled method ConsoleApp2.Program?<>c__DisplayClass1_0::b__0
Assembled method ConsoleApp2.Program?d__1::.ctor
Assembled method ConsoleApp2.Program?d__1::MoveNext
Assembled method ConsoleApp2.Program?d__1::SetStateMachine
Assembled method ConsoleApp2.Program::Main
Assembled method ConsoleApp2.Program::QueryDataTable
Assembled method ConsoleApp2.Program::.ctor

Assembling 'my.res'  to EXE --> 'ConsoleApp2.exe'
Source file is UNICODE

Creating PE file

Emitting classes:
Class 1:        ConsoleApp2.Program
Class 2:        ConsoleApp2.Program?>c__DisplayClass1_0
Class 3:        ConsoleApp2.Program?QueryDataTable>d__1

Emitting fields and methods:
Global
Class 1 Methods: 3;
Class 2 Fields: 2;      Methods: 2;
Class 3 Fields: 6;      Methods: 3;
Resolving local member refs: 44 -> 44 defs, 0 refs, 0 unresolved

Emitting events and properties:
Global
Class 1
Class 2
Class 3
Method Implementations (total): 2
Resolving local member refs: 0 -> 0 defs, 0 refs, 0 unresolved
Writing PE file
Operation completed successfully

You can see that the final compilation into exe is successful. Double click consoleapp2.exe to see the latest results.

图片名称

4: Summary

This article introduces two ways to modify DLL. In fact, I feel it in practiceildasm & ilasmThe way is more flexible. If you have a better way to decompile and modify, you are welcome to leave a message for discussion!

More high quality dry goods: see my GitHub:dotnetfly

图片名称

Recommended Today

Seven solutions for distributed transactions

1、 What is distributed transaction Distributed transaction means that transaction participants, transaction supporting servers, resource servers and transaction managers are located on different nodes of different distributed systems. A large operation is completed by more than n small operations. These small operations are distributed on different services. For these operations, either all of them are […]