How do I check the program for viruses

Introduction

The reason for writing this article was a dialogue in one telegram chat. Someone posted a program to “unique” files by changing the MD5 hash, and another vigilant chat participant checked it on Virustotal and, due to two positive (and 68 negative) results, accused the program of having undeclared functions, including even stealing passwords from various accounts, and all those who installed it – in the “surplus” of the mind. His exhortations and the story about possible false positives did not give the desired result, the conversation ceased to be constructive and died out.

virustotal
virustotal

But I (as one of the participants in that dispute) lost my peace, sleep and appetite, because on the one hand, if the antivirus swears, then there is no reason not to believe it and you should be careful. On the other hand, two not the most popular antiviruses, it would be something to worry about. But the most important thing – and if there were 0 detections at all, does this give reason to be confident in the program? And how to be in that case? Well, in addition, it was interesting – but how, in fact, does MD5 change, just by adding extra bytes (the most obvious way) or somehow smartly?

I decided to check, and at the same time tell the algorithm of my thoughts and actions, perhaps it will be useful to someone. I don’t pretend to be an expert, we’ll dig deeper purely at the household level.

Exploring the program

So, there is a MD5_Hash_Changer.exe file, which we suspect has some hidden functions. First, let’s see it with PEiD:

PEID
PEID

The line about C#/.NET suggests that the program is written in Sharpe, which in some cases can make it possible to do without a disassembler. Download the free JetBrains dotPeek program, which allows you to get C# code from an exe file (provided, of course, that the program was originally written in C#), and set it on the file under study:

See the program in dotPeek
See the program in dotPeek

To begin with, you should look at the Metadata section, in which the first thing you need to pay attention to is the strings used, which may contain interesting names, paths, IP addresses, and so on.

String resources in dotPeek
String resources in dotPeek

If necessary, you can immediately see where exactly an interesting string is used, if there is one. In my case, nothing suspicious was found and I moved on to the code section. As it turned out, the program source code contains two classes, Program and MainForm, while the Program class is quite standard and contains only the code for launching the main application window:

using System; using System.Windows.Forms;
namespace MD5_Hash_Changer {
  internal static class Program {
    [STAThread] private static void Main() { 
      Application.EnableVisualStyles(); 
      Application.SetCompatibleTextRenderingDefault(false);
      Application.Run((Form) new MainForm()); 
    } 
  } 
}

The MainForm class will be looser, and we should dwell on it in more detail:

Application code
Application Code

As you can see, when the form is launched, the InitializeComponent () function is launched, but nothing interesting happens in it, the usual interface settings, setting fonts and button names, and other routine. I had to look at the entire code, but no hints of network activity or attempts to access files “unnecessary” for the program were found, everything is very transparent and naive. Well, since no malicious functionality was found, then at least take a look at the algorithm itself in order to understand how the program modifies files.

The function is responsible for this.

private void changeMD5(string[] fileNames) {
  Random random = new Random();
  Thread.Sleep(1000);
  this.Invoke((Delegate) (() => this.btnStartMD5.Enabled = true));
  for (int i = 0; i < fileNames.Length; ++i) {
    if (!this.running) {
      this.Invoke((Delegate) (() => {
        this.btnStartMD5.Text = "Start Change MD5";
        this.running = false; 
      }));
      break; 
    } 
    int length1 = random.Next(2, 7);
    byte[] buffer = new byte[length1];
    for (int index = 0; index < length1; ++index)
      buffer[index] = (byte) 0;
    long length2 = new FileInfo(fileNames[i]).Length;
    if (length2 == 0L) {
      this.Invoke((Delegate) (() => this.dgvMD5.Rows[i].Cells[3].Value = (object) "Empty")); 
    } 
    else {
      using (FileStream fileStream = new FileStream(fileNames[i], FileMode.Append)) 
        fileStream.Write(buffer, 0, buffer.Length);
      int bufferSize = length2 > 1048576L ? 1048576 : 4096;
      string md5hash = "";
      using (MD5 md5 = MD5.Create()) {
        using (FileStream inputStream = new FileStream(fileNames[i], FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize)) 
          md5hash = BitConverter.ToString(md5.ComputeHash((Stream) inputStream)).Replace("-", ""); 
      } 
      this.Invoke((Delegate) (() => { 
        if (this.dgvMD5.Rows[i].Cells[2].Value.ToString() != "") 
          this.dgvMD5.Rows[i].Cells[1].Value = this.dgvMD5.Rows[i].Cells[2].Value;
        this.labelItem.Text = (i + 1).ToString();
        this.progressBarStatus.Value = i + 1;
        this.dgvMD5.Rows[i].Cells[2].Value = (object) md5hash;
        this.dgvMD5.Rows[i].Cells[3].Value = (object) "OK"; 
      })); 
    } 
  } 
  this.Invoke((Delegate) (() => { 
    this.btnStartMD5.Text = "Start Change MD5"; this.running = false; 
  }));
}

As input, the function receives a list of files that should be processed, and runs through it in a loop. For each file, a random length buffer is generated in the range from 2 to 7 bytes and filled with zeros:

int length1 = random.Next(2, 7);
byte[] buffer = new byte[length1];
for (int index = 0; index < length1; ++index) 
  buffer[index] = (byte) 0;

This buffer is then simply appended to the end of the file.

using (FileStream fileStream = new FileStream(fileNames[i], FileMode.Append))
  fileStream.Write(buffer, 0, buffer.Length);

and again the MD5 hash is calculated for the modified file:

using (FileStream inputStream = new FileStream(fileNames[i], FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize))
  md5hash = BitConverter.ToString(md5.ComputeHash((Stream) inputStream)).Replace("-", "");

That’s it, nothing else interesting happens here. As you can see, the program is very trivial and this kind of “uniqueization” of course formally changes the hash of the file, but … You can judge how suitable it is for solving your problems.

And finally, you should probably check in practice what happens to the files. Let’s take the first picture from this article as an example and set the program on it, and then compare the files before and after processing.

Compare files
Compare files

Firstly, the file size after processing increased by 6 bytes, and secondly, as can be seen from the screenshot, 6 zero bytes appeared at the end of the file. Obviously, this corresponds to the algorithm established during the study of the source code.

Important addition

In addition, I consider it necessary to note that the verification algorithm described by me does not allow us to make an unambiguous conclusion about the presence of malicious functionality in the program, because there are ways to inject into the exe file at a lower level, so we should not neglect the analysis of possible network traffic after running in ” sandbox”, and a more detailed study of the actual executable code, however, this requires some kind of qualification and experience, and the algorithm described by me is quite accessible even to an unprepared and far from reverse user.

Links

Similar Posts

Leave a Reply