Patch the. NET program without source code"

Source: Internet
Author: User
Tags mscorlib reflector

The company writes a registration machine for a web application. The basic principle is that after the user runs the software, he gets an application code and the company gives the corresponding registration code based on the application code, the Web software can be used normally only after matching. There is no problem on another machine, but after I run the software on the machine, the application code is not generated and no error is reported. People who develop this program have no idea who it is and no source code, so they have to analyze what causes it by themselves. If it is a program problem, they hope to patch the program ", it is accurate to say that it is relatively Elementary. netReverse EngineeringTo inject the required patch code. The following are the ideas and main operations (the unnecessary code is omitted in the Code ).

1.

Open it with reflector and find that it is A. Net program without confusion. This is easy to do. Because the program code is relatively small, let's look at the event functions of a few buttons in reflector, and read it almost.Basic IdeasYes. Since no application code is generated in the text box of the application code, you need to find the statement that assigns a value to the application box to see if there is any problem with the statement. To find this statement, first, you need to find the ID number in the application box in the program.

2.

Enter the registration code in the program and click the Registration button. Then, the "Registration Code error" message is displayed:

Codeprivate void registerbut_click (Object sender, eventargs e) {If (this. sanswercode (this. requestcode. text) = This. answercode. text) {This. setregstr (this. answercode. text); MessageBox. show ("registered successfully. ");} Else {MessageBox. Show (" incorrect registration code! ");}}

Obviously, requestcode is the textbox of the application code, and answercode is the textbox of the registration code.

3.

Then, find the statement that assigns a value to requestcode:

codeprivate static void Main(){    Application.EnableVisualStyles();    Application.SetCompatibleTextRenderingDefault(false);    Application.Run(new SystemSet());}public SystemSet(){   ………  this.requestCode.Text = this.CpuID();   ………}private string CpuID(){   string text2 = "";        try         {         ManagementObjectSearcher managementObjectSearcher = new ManagementObjectSearcher("SELECT * FROM Win32_Processor");         ManagementObjectCollection managementObjectCollection = managementObjectSearcher.Get();            using (ManagementObjectCollection.ManagementObjectEnumerator enumerator = managementObjectCollection.GetEnumerator())            {               .....            }               .....          }        catch          {                          }        return text2;}

It can be seen that the cpuid method is used to generate the application code, which should be generated based on hardware information such as CPU, which can generate different application codes for each computer. After processing, the returned text2 is the application code. the try-catch code block is used to ignore all possible errors. No wonder the application code is missing, but no error is reported ~~~

4.

Run the cpuid method in Vs of my local machine (system. management must be referenced). An error is returned. Check whether the exception thrown by catch is called.Searcher.Get()The error message is as follows:
 
{System. runtime. interopservices. comexception (0x80070422 ):Unable to start serviceThe reason may be that the device has been disabled or is not started. (Exception from hresult: 0x80070422)
In system. runtime. interopservices. Marshal. throwexceptionforhrinternal (int32 errorcode, intptr errorinfo)
In system. Management. managementscope. initializeguts (Object O)
In system. Management. managementscope. initialize ()
In system. Management. managementobjectsearcher. initialize ()
In system. Management. managementobjectsearcher. Get ()

Maybe a service in my machine is not started, but the get method uses this service. The smart prompt of get is:

"Asynchronous callWMIQuery and bind it to an observer to pass the results ."
This is clear. I went to the service and looked at it. My Windows Management Instrumentation did not start. It was closed when I optimized the system. I didn't expect it to be used here. After the service is started, the program runs normally and an application code can be generated.

5.

Although I know this is the problem, what if the same problem occurs on the machine that uses this software in the future? There is always no way to configure a special manual, so it would be best if you could make a small patch. However, because there is no source code, in principleThe fewer changes, the better.Instead of pursuing perfect patching.
For convenience, I only want to add a prompt statement in the catch of the cpuid method:
MessageBox. Show ("the application code cannot be generated. Please make sure that the system WMI Service is started normally! ");
This is definitely not rigorous enough. Not all exceptions are caused by the failure of WMI, because it is troublesome to modify Il. Here we will try to minimize the Modification Principle and find other problems later.
The procedure is as follows:
  • Obtain the Il code of the program;
  • Inject the Il code of the required prompt information;
  • Decompile the program;
  • Test whether the program runs properly.
(1)
First, use ildasm (. NET's il disassembly program, which comes with the Framework) to open this program, and thenDumpIts Il and Its Related Files (here I dump it as programil and generate a total of four files, one il suffix, two resources suffixes, and one res suffix ).
 
(2)
Open the file suffixed with IL in the text editor and find the Il code segment of cpuid. You can see the following:
Code. method private hidebysig instance string cpuid () cel managed {...... omit catch [mscorlib] system. object {il_00b2: Pop il_00b3: Leave. s il_00b5} // end handler il_00b5: ldloc.1 il_00b6: Ret} // end of method systemset: cpuid

 
We can see that in the catch of Il, nothing is actually done, and the jump goes out directly. I need to add the above prompt information here. The modified code is:
Codemethod private hidebysig instance string cpuid () cel managed {...... omit catch [mscorlib] system. object {il_00b2: Pop il_00b3: NOP il_00b4: ldstr "the application code cannot be generated. Check that the WMI Service of the system is started normally! "Il_00b9: Call valuetype [system. windows. forms] system. windows. forms. dialogresult [system. windows. forms] system. windows. forms. messageBox: Show (string) il_00be: Pop il_00c0: NOP il_00c1: NOP il_00c2: NOP il_00c3: Leave. s il_00c5} // end handler il_00c5: ldloc.1 il_00c6: Ret} // end of method systemset: cpuid

 
Here is a brief description of the added Il:
  • Ldstr at the location of il_00b4, which means to push the object reference of the subsequent string to the stack;
  • Then the call of il_00b9 calls the MessageBox. Show method. Of course, the above string will be passed in as a parameter;
  • Finally, execute pop at il_00be to bring up the string reference that was just pressed at the top from the stack;

After the stack is pressed, called, and out of the stack, our custom code is injected into the stack, and the stack status is restored before modification, so the stack balance is not affected. Here, I would like to emphasize that the above il statement is not unique. For example, we can completely "the application code cannot be generated. Please make sure that the system WMI Service starts normally !" Use the following code instead:

Bytearray (E0 65 D5 6C 1f 75 10 62 33 75 F7 8B 01 78 0C FF F7 8B 6e 78 A4 8B FB 7C DF 7E 57 00 4D 00 49 00 0d 67 A1 52 2f 54 a8 52 63 6B 38 5E 01 ff)

The code in bytearray is the Unicode code of Chinese characters.

Note that:

  • For the convenience of code calculation, some NOP commands are inserted to fill the space when the operation code is patched;
  • Because some code is inserted, the address of Il needs to be changed. The address of the source il code after the code is inserted should be pushed back, that is, the catch will jump out from il_00b3, now it is changed to il_00c3 to exit. The difference is 16 (hexadecimal );
  • Since the address of all the code changes from il_00b3 to the end, if there is code jump to the code before, you need to modify it accordingly! This program has a place, that is, if the try does not report an error, it will skip the catch section and directly go to the original il_00c5 (leave. s il_00b5), so I can change it to il_00c5.
(3)
Use ilasm (. NET's il assembler, which comes with the Framework) to compile the modified il into an application. This only provides the command line version.
Run the following command to compile this ililiter into newprogram.exe. There are many parameters that can be referenced by the ilasm connection;
 
The execution process is omitted. The following are some statistics:
 
It can be seen that no error occurs and the compilation is successful.
 
(4)
Run the new program. When the WMI service is stopped, the message is displayed:
 
After other tests, the previous functions of the program are not affected, and the modification is successful.
 
Summary:
  1. As a program to protect other software, if the registration server is not well protected, we still need to talk about how to protect other software. At least the decompilation measures still need to be done;
  2. Try-catch should be a mechanism established to solve software exceptions, rather than ignoring problems and saving things. At least to prevent users from getting confused, in order for the software to effectively feedback and update bugs after discovering them, it is also good to give some tips or make a log;
  3. Coding and testing are very lacking, especially the Code related to the system environment. On the one hand, coding should give some constructive suggestions (for example, WMI Service is not started, please start the service ), on the other hand, the testing environment should not be limited to development machines;
  4. Microsoft's il intermediate language is still very powerful. It is easier to get started than assembly. Of course, it is more difficult to get started;
  5. Do not optimize system services ~;
  6. Later, Zhuge Liang, maybe I will make the same mistake. use others' mistakes to improve myself :)

Refer:

Msil assembler msil disassembly program msil Opcodes Field

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.