📜 ⬆️ ⬇️

Removing .NET programs from registration using the example of BEM

Not so long ago, I decided to study, and at the same time try to fix one library, freeing the program working on this library from the license.

It all started with the fact that somehow I got into the hands of a program for financial statements, a kind of budget option 1C. As the developers of this program assured that it is almost the most secure and resistant to hacking. It was this boasting that pushed to refute the overconfidence of the developers.

Having rummaged in the program through Reflector , I found out that all the main libraries of the program were written by a third-party company, moreover, they were written not for a specific project, but were a whole Framework. The framework was written just for accounting programs. For this kind of focus of the Framework, an unusually large amount of unnecessary functionality was pushed into it (for example, working with FTP). An incredible number of system namespaces have been redefined.

As well as in one of the libraries of this Framework, a namespace was defined, the classes of which were responsible for checking the correctness of the license. In this regard, I decided to google to search for information and documentation for this Framework. After a couple of minutes of searching, it became clear that this Framework is closed. Why closed? - yes, because it is distributed according to unknown criteria, at least I have not found information on this subject on the developer’s website . Also on the developer’s site it was not possible to find reference information on this Framework. I was looking for all this information on the fact that as mentioned above, it was this Framework that was responsible for licensing the program, a part of the soul naively thought to find the keygen for this Framework, because the license system for all programs based on this Framework is uniform. This meant that someone for one of the programs on this Framework made a keygen. But, alas, the searches were not crowned with success.
')
By the way the name NetDec Framework.

Also, an analysis of the library in which the classes responsible for checking the license were located showed that part of the classes were obfuscated, including the entire namespace responsible for the license. There was no desire to bother with deobfuscation and subsequent recompilation, especially since the goal was to write a license generator or patcher.



The method responsible for checking the license was found very quickly, it was necessary only to track the handler for clicking the OK button in the license input form.



For the convenience of analyzing the code, I still had to look for an analogue of the Reflector with only a deobfuscator on board. That was DisSharp .

As you can see the license in the program is a digital signature on the DSA algorithm. To create a digital signature, the so-called computer code is taken (as they called it, it did not go into the generation of this code), the computer code is connected to the serial number, and in the DSACryptoServiceProvider :: VerifyData method are verified with a digital signature.

An XML string is passed to the method in text1 to restore the DSA object. After a little digging, an XML file was found, in which was the object to restore the DSA. The first thing was a look at the search for a private key (well, what the hell is not joking), alas, of course, the developers got rid of it. The XML file itself was embedded in the library resources. First of all, attempts were made to generate your DSA object and insert the resulting XML into the library resources, replacing the old one.

I didn’t have to deal with anything like this before, so the search for a program for replacing resources did not produce results. Yes, and I wanted to make a fully automated solution to activate the program. Of course, it was possible to patch this for such programs with similar programs, and then just replace the standard one with a patcher, but somehow it is not aesthetically pleasing. I wanted to make a fully automated solution in order to send it for evaluation to the developers of this product.

The search for replacing resources programmatically with an adequate solution was not given. Hands like that let go. Although in principle I have already proved that it is possible to bypass a license by stitching your DSA object into a library, and to make a license generator on the same object.
At the time, I had to throw the whole thing in a distant box, and take up work. After some time, someone told me again about this program and its security. Again took up the analysis.

After sitting for a while thinking about it, remembering that the IL compiler does not compile strings, an idea came up to my mind (which would seem to many very primitive and stupid) to look at the insides of the library through a simple notebook. Yes, build a notepad. Searching for the keyword DSAKeyValue immediately brought me an XML data DSA object. An idea immediately occurred to the head on the regular expression of programmatically replacing this object with its own. I started coding, having realized my plans, faced with the fact that the library refused to work at all. Expecting a similar result, before a complete replacement, I tried a partial replacement of the object, after which the library worked fine, but did not even eat the official license.

Previously, I checked the length of the official DSA object in the XML file and mine (by length is meant the number of characters), the dimensions are completely the same.

Then I simply programmatically read the entire library into an array of bytes, fixed the first and last entry in xml of the dsa object when reading it, replaced these bytes with my own, and saved it back to a file.
I forgot to say that the DSA object was generated on the fly, and when it is generated in the xml line, you can specify whether to add a private key to the data or not, I set this value to false, because it does not exist in the original signature. Immediately when the DSA object was initialized, a digital signature with a serial number was created, which was saved to a license file.

Having done the above steps, my xml DSA object should have been reflected in the reflector. It only remained to try to run the program. Squared and tried to run the program. As expected, the program was launched without any license issues.

After some time, I found an article in Habré, about MSIL code injections into third-party assemblies using the Mono.Cecil library. After a couple of minutes, a code was made that adds a simple return to the beginning of the license verification method, thereby confirming the license successfully!

private void Injector(string path) { var assembly = AssemblyDefinition.ReadAssembly (path); foreach (var typeDef in assembly.MainModule.Types) { foreach (var method in typeDef.Methods) { string mp = "("; for (int i = 0; i < method.Parameters.Count; i++) { mp += method.Parameters[i].ParameterType+","; } mp = mp.Trim(' '); mp = mp.Trim(','); mp += ")"; if (mp == "(System.Byte[],System.String,System.String)") { var ilProc = method.Body.GetILProcessor(); Instruction badInstruction = Instruction.Create (OpCodes.No); Instruction firstInstruction = ilProc.Body.Instructions [0]; ilProc.InsertBefore (firstInstruction, Instruction.Create (OpCodes.Ret, firstInstruction)); ilProc.InsertBefore (firstInstruction, badInstruction); } } } assembly.Write(path); } 


This method works because the principle of license verification in this Framework is incredibly simple. In the method that calls the method of checking the license, an exception handler is installed, if an exception occurs in the license checking method, then the license is incorrect or not at all, if there are no exceptions, everything can be started.

Since all methods are obfuscated, it does not make sense to look for a method by name via Mono.Cecil. Looking in the reflector, I noticed that in this library there is no one with the same arguments, with the same type and sequence. Therefore, it was decided to distinguish the method by arguments:

 if (mp == "(System.Byte[],System.String,System.String)"){ //… } 


That's basically it.

PS This article was not intended in any way for cracking aids or the like. You do not need to be a guru in programming in order to understand that the actions performed above are primitive, and sometimes even ridiculous in their implementation.

Source: https://habr.com/ru/post/111330/


All Articles