Introduction to Anti-Virus engine design
1. Introduction
The main content of this article is as follows: Design and compile an advanced anti-virus engine. First, we need to explain the word "advanced". What is "advanced "? As we all know, traditional anti-virus software uses static Scanning Technology Based on signatures, that is, to find a specific hexadecimal string in a file. If it is found, it can be determined that the file is infected with a virus. However, this method does not play a very good role in today's rapid development of virus technology. The reason is described in the following sections. Therefore, this article will not analyze the signature scanning and virus code clearing modules in the Anti-Virus engine. We will discuss the two major anti-virus technologies necessary to cope with Advanced virus technologies-virtual machines and real-time monitoring technologies. I will give a detailed introduction to what is virtual machine and what is real-time monitoring. Although these two technologies have been embodied in previous work (used by some advanced anti-virus manufacturers at home and abroad), they are for commercial purposes, these technologies are not completely disclosed, so you cannot find any insider information about these technologies from books or online materials. I will analyze a large number of program source codes in relevant chapters (mainly a complete virtual machine source code in section 2.4) or Reverse Engineering Code (three real-time monitoring drivers for a well-known anti-virus software in my reverse engineering in section 3.3.3 and 3.4.3 and the disassembly code of the customer Program ), at the same time, I also published some undisclosed mechanisms and data structures in the operating system I personally mined. Start to enter the topic.
Directory
1.1 Background
1.2 Development of today's virus Technology
1.2.1 system core virus
1.2.2 resident Virus
1.2.3 interception of system operations
1.2.4 encryption and deformation Virus
1.2.5 anti-tracking/anti-virtual execution Virus
1.2.6 direct API call
1.2.7 virus hiding
1.2.8 special virus infection Method
1.1 Background
The two main technologies involved in this article are two of the most advanced technologies used in today's anti-virus industry. What exactly is it? First, let's talk about the virtual machine technology, which is mainly designed to kill encryption and deformation viruses. Simply put, the so-called virtual machine is not a virtual machine. It is more appropriate to say that it should be a virtual CPU (a CPU implemented by software), but it is only called in the virus field. It is mainly used to simulate the work process of INTEL X86 CPU to explain the execution of executable code. Like a real CPU, it can get the finger, decode and execute the operations specified by the corresponding machine commands. Of course, what are encryption and deformation viruses, why they need to be virtualized, and how to perform them are answered in the appropriate chapter. In addition, the real-time monitoring technology, another major concern, is more widely used than virus detection and removal. There are also many objects to be monitored in real time, such as Intmon, Pfmon, and Diskmon. Anti-Virus Monitoring mainly targets file access. When you want to access a file, real-time monitoring first checks whether the file is a virus-infected file. If yes, the user selects whether to clear the virus or cancel the operation request. This gives users a relatively secure execution environment. But at the same time, real-time monitoring will reduce the system performance. Many anti-virus software users complain that their real-time monitoring has made the system extremely slow and unstable. This puts forward a higher requirement for our design, that is, how to accurately intercept file operations while allowing real-time monitoring to consume less system resources. I will discuss this issue in the real-time virus Monitoring Section. These two technologies are used in products of advanced anti-virus manufacturers at home and abroad. Although their source code is not disclosed, we can still peat their design ideas through reverse engineering. In fact, if you use a hexadecimal editor to open their executable files, you may see some unstripped debugging symbols, variable names, or output information, these clues are helpful for understanding the intent of the Code. At the same time, in the installation directory of the anti-virus software, the suffix is. VXD or. SYS, which is the driver for real-time monitoring. you can reverse it (see my discussion in driver source code analysis later ). I believe that we have a general understanding of these two technologies. We will go deep into the technical details later.
1.2 Development of today's virus Technology
To discuss anti-virus, you must start with the discussion of virus technology. It is the so-called "know yourself, know yourself, and know what you want ". In fact, I think there are huge drawbacks in the study of virus technologies that are illegal. It is hard to imagine that a person without any virus writing experience will become a antivirus expert. As far as I know, the R & D teams of some well-known anti-virus software companies in China do not lack virus writing skills. However, they use the same technology on the main road and attack the virus with the poison '. Therefore, I hope this paper will serve as a reference and expect more people to introduce the virus technology to the public. Today's viruses are different from those in the DOS and WIN3.1 era in terms of technology. I think the biggest change is that the boot zone virus is reduced, and the script virus is spreading. The reason is that it is difficult to directly rewrite the boot zone of the disk in today's operating system (DOS is not protected, and INT13 can be called to directly write the disk), and the changes in the boot zone are easily discovered, as a result, few people write it again. Script viruses are favored by virus writers for their high transmission efficiency and ease of writing. Of course, because these two viruses can be detected and killed using the static Scanning Technology Based on signatures I mentioned above, we will not discuss them here. The technologies I will discuss mainly come from binary shell viruses (Virus Infected with files). Most of these technologies are related to the underlying mechanism of the operating system or the protection mode of more than 386 CPUs, so it is worth studying. As we all know, shell viruses in DOS are mainly infected with 16-bit COM or EXE files. Because DOS is not protected, they can easily reside and reduce available memory (by modifying the MCB chain ), modify the system code to block system services or interruptions. In the WIN9X and WINNT/2000 era, it is not easy to write a 32-bit WINDOWS virus. Because of page protection, you cannot modify the system code page. Because of the rules in the I/O license bitmap, you cannot directly access the port. In WINDOWS, you cannot intercept all file operations by intercepting INT21H as in DOS. In short, if you run the program as a user, your behavior will be strictly controlled by the operating system, and it is impossible to do whatever you like in DOS. It is also worth mentioning that the executable file format used in WINDOWS is very different from the EXE in DOS (the common program adopts the PE format and the driver uses LE ), therefore, it is more difficult to infect files with viruses (PE and LE are complicated, and there are several sections in the middle. If the infection is wrong, the file cannot be executed again ). Because there are too many new technologies of today's virus, I cannot discuss them in detail one by one, so I chose some important and representative sections to discuss in this chapter.
1.2.1 system core virus
It is necessary to discuss the concept of the core State and the user State before introducing what is the system core State virus. In fact, as long as you open a textbook about the Compilation Program Design of The 386 protection model, you can find a description of these two concepts. 386 or more CPUs implement four privileged-level modes (only two of them are used in WINDOWS). The privileged-level 0 (Ring0) is reserved for the operating system code and the device driver code, they work in the core state of the system, while privileged 3 (Ring3) is used by common user programs and they work in the user State. The code running on the core state of the processor is unrestricted and can freely access any valid address for direct port access. Code running in the user State is subject to a lot of checks by the processor. They can only access the virtual addresses that can access the page in the user State specified in the page table items mapped to their address space, and only the I/O permit Bitmap (I/O Permission Bitmap) in the task status segment (TSS) can be) (In this case, the IOPL In the processor status and Control Mark register EFLAGS is usually 0, indicating that the lowest privilege level for direct I/O is Ring0 ). The above discussion is only limited to operating systems in protection mode. Real-mode operating systems such as DOS do not have these concepts, and all the code can be seen as running in the core state. Since running in the core State has so many advantages, the virus certainly has no reason not to get Ring0. The switch from Ring3 to Ring0 in processor mode occurs when the control is transferred. There are two situations: the long transfer command CALL of the Access CALL door, And the INT command of the access interrupt door or trap door. The transfer details involve complex protection checks and stack switching. For more information, see relevant materials. Modern Operating systems usually use the interrupt gate to provide system services, and execute a command to switch the mode. on INTEL X86, this command is INT, for example, in WIN9X, It is INT30 (protection mode callback), INT80 in LINUX, and INT2E in WINNT/2000. User-mode service programs (such as system DLL) request system services by executing an INTXX, and then the processor mode switches to the core state, the corresponding system code working on the core State serves this request and sends the result to the user program. The following example shows how a virus enters the core state of the system.
In the process virtual address space mapped to the shared system code section (3g--4g) in WIN9X, except for the top 4 m page table with page protection, it can be read and written by the user program. If you use the PAGE command of Softice (system-level debugger) to view the PAGE properties of these addresses, you will be surprised to find the u rw bit, this indicates that these addresses can be read or written directly from the user State. This means that any user program can maliciously or unintentionally damage the operating system code page during its operation. Thus, the virus can construct a gate descriptor in GDT (Global Descriptor Table) and LDT (Local Descriptor Table) and enter the core state. Of course, it is not necessary to use the door description. There are still many ways to get Ring0. As far as I know, there are no more than 10 methods, such as calling Gate, Intgate, Trapgate, and Fault ), interrupt request (IRQs), Port (Ports), virtual machine Manager (VMM), Callback (Callback), form conversion (Thunks), device IO control (DeviceIOControl ), API function (SetThreadContext) to interrupt the 2E Service (NTKERN. vxD ). Due to space limitations, I cannot clearly describe all the methods one by one. Here I only select a piece of code starting with the most representative CIH virus version 1.5.
It is often said that CIH uses VXD (Virtual Device Driver) technology, but it is not VXD itself. However, it uses the WIN9X vulnerability to construct a DPL (segment privileged level) in IDT (Interrupt Descriptor Table) it is a 3 interrupt gate (meaning that the INT command to access the interrupt gate can be executed under Ring3), and enables the descriptor to point to a function address that needs to work under Ring0 in its own private address space. In this way, CIH can simply execute an INTXX command (CIH chooses to use INT3 to make the system debugger Softice with the same INT3 unable to work properly for the purpose of anti-tracking) enter the system core State to call the system's VMM and VXD services. Below is the source code of a piece of CIH1.5 I noted:
;*************************************; * Modify the IDT to obtain the core State privilege level *; * *********************************** push eax sidt [esp-02h]; obtain the base address of the IDT table pop ebx add ebx, HookExceptionNumber * 08 h + 04 h; ZF = 0 cli; Disable mov ebp, [ebx] mov bp, [ebx-04h]; get the original interrupt entry address lea esi, MyExceptionHook-@ 1 [ecx]; get the offset address of the function that needs to work in Ring0 push esi mov [ebx-04h], si shr esi, 16 mov [ebx + 02 h], si; set as the new interrupt entry address pop esi; *************************************; * An exception is generated to enter Ring0 *; * *********************************** int HookExceptionNumber; generate an exception |
Of course, there will be code to restore the original interrupt entry address and Exception Handling frame.
The technology just discussed is limited to WIN9X. It is not so easy to enter Ring0 in WINNT/2000. The main reason is that WINNT/2000 does not have the above vulnerabilities, and their system code pages (2G--4G) have good page protection. Virtual addresses greater than 0x80000000 are invisible to user programs. If you use the Softice PAGE command to view the PAGE properties of these addresses, you will find S-bit, which means these addresses can only be accessed from the core state. Therefore, if you want to construct a descriptor in IDT and GDT at will, you cannot modify the kernel at runtime. All you can do is load a driver and use it to do what you cannot do in ring3. Viruses can modify the internal code in their drivers or create a calling portal for the virus itself (using the undisclosed system service kei?allocategdtselectors, kei=setgdtselector, and kei=releasegdtselectors exported by ntoskrnl.exe ). For example, funlovevirus uses a driver to modify the system file (ntoskrnl.exe, Ntldr) to bypass security checks. However, there are two problems. One is where the driver comes from. Modern Viruses generally use a technology called "Drop, that is, when the virus body contains the binary code of the driver (which can be compressed or the file header can be dynamically constructed), the driver is dynamically generated and thrown to the disk when the virus needs to be used, then, register in the SCM (Service Control Manager) and call StartService to run the driver. The other is to load a driver as an administrator, an ordinary account will return a failure when calling the above loading function (the security subsystem should check whether the user's access Token (Token) has the SeLoadDriverPrivilege privilege ), however, most users log on as administrators most of the time. Otherwise, the real-time virus monitoring driver cannot be loaded, so there are still many opportunities for viruses.
1.2.2 resident Virus
Resident virus refers to the existence of virus code that finds appropriate pages in the memory and copies the virus itself to it, and can always be maintained during system operation. Resident viruses are more concealed than Direct-action viruses. They usually intercept certain system operations to spread the virus. A virus in the core State can use system services for this purpose. For example, CIH uses VMMCALL_PageAllocate, a service exported by VMM, to allocate a page space on an address greater than 0xC0000000. It seems impossible for a user-State program to resident the code after the program exits in the memory, because no matter what memory the user program allocates, it will be part of the resources occupied by the process, once the process ends, the occupied resources will be released immediately. So what we need to do is allocate a piece of memory that can be maintained after the process exits.
GriYo, a member of the virus writing team 29A, is very creative about applying to open the file ing again in the address space of CreateFileMappingA ghost. Quit.
In addition, you can modify the system dynamic connection module (DLL) to stay. System DLL (such as Kernel32.dll ing to BFF70000) in WIN9X is in the system shared area (2G-3G ), if you write a small piece of virus code in the gap between the code segments, it can affect all other processes. However, the code segment of Kernel32.dll can only be read and cannot be written in the user State. Therefore, you must first modify the page protection attribute through special means. In WINNT/2000, the page where the system DLL is located is mapped to the private space of the process (for example, Kernel32.dll ing to 77ED0000, when a process tries to write data to the page, all processes share the page. When a process tries to write data to the page, the system page error handling code will receive an exception from the processor and check that this exception is not an access violation. At the same time, it is assigned to a new page for the process that causes the exception, copy the original page content on it and update the page table of the process to point to the newly allocated page. This optimization of shared memory brings a certain amount of trouble to virus writing. The virus cannot modify only one code in Kernel32.dll as it does in WIN9X. It needs to use WriteProcessMemory to write virus code to the address mapped to Kernel32.dll for each process, so that each process will get a copy of the virus body, this is known in the virus community as multi-Process resident or Per-Process resident ).
1.2.3 interception of system operations
Intercepting system operations is a common virus trick. In the DOS era, WINDOWS is no exception. In DOS, viruses intercept DOS system services by modifying the INT21H entry address in the interrupt vector table (DOS uses INT21H to provide system calls, including a large number of file operations ). Most of the boot zone viruses are connected to INT13H (BIOS interruptions that provide disk operation services) to control disk access. The virus in WINDOWS also finds a way to hook up system services. For example, CIH virus uses IFSMGR. VXD provides a system-level file hook to intercept all file operations in the system. I will discuss this issue in detail in the relevant sections, this service is also used for real-time monitoring in WIN9X. In addition, there are other methods. But the effect is not as good as the system-level file hook, mainly because the underlying layer is not enough and some file operations will be lost.
One method is to use APIHOOK to hook up API functions. In fact, there is no ready-made service in the system. There is a SetWindowsHookEx that can hook the mouse message, but it is powerless to intercept API functions. What we can do is construct such a HOOK by ourselves. The method is actually very simple: for example, if you want to intercept the CreateFile function exported by Kernel32.dll, you only need to add a jump command at the beginning of the Function Code (BFF7XXXX) to the entry of your hook function, jump back after your function is executed. As shown in:
; Target Function (Target Function to be intercepted )...... TargetFunction: (the entry to the target function to be intercepted) jmp DetourFunction (jump to the hook function, a jump command of 5 bytes) TargetFunction + 5: push edi ...... ; Trampoline (your hook function )...... TrampolineFunction: (the place where your hook function returns the original function after execution) push ebp mov ebp, esp push ebx push esi (the above lines are several commands at the entrance of the original function, 5 bytes in total) jmp TargetFunction + 5 (jumping back to the original function )...... |
However, this method intercepts only a small part of file opening operations.
There is also a little-known method to intercept File Operations Under WIN9X, which should be regarded as a large backdoor of WIN9X. It is an undisclosed API function named VxdCall0 in Kernel32.dll. The code for disassembly of this function is as follows:
Mov eax, dword ptr [esp + 00000004 h]; get service code pop dword ptr [esp]; stack correction call fword ptr cs: [BFFC9004]; call code somewhere in Section 3B through a call door |
If we continue tracking, we will see:
This is a protection mode callback for VWIN32.VXD.
For more information about VxdCall, see Matt Pietrek's Windows 95 System Programming Secrets.
When the service code is 0X002A0010, the protection mode callback will fall into a service called VWIN32_Int21Dispatch in VWIN32.VXD. This shows that WIN9X is still dependent on MSDos, although Microsoft claims that WIN9X is no longer dependent on MSDos. The Calling rules are as follows:
My_int21h: push ecx push eax; push 002A0010h call dword ptr [ebp + a_VxDCall] ret similar to the function number passed in maxcompute of INT21H in DOS |
We can set the user State writable address BFFC9004 in the Kernel32.dll Data Segment accessed by the third Remote Call command at the entrance of the VxdCall0 function above? The six bytes of fword' point to the address of our own hook function, and check the input service number and function number in the hook to determine whether it is a file service in the request VWIN32_Int21Dispatch. The famous HPS virus uses this technology to directly intercept file operations in the system in the user mode. However, this method only intercepts a small part of file operations.
1.2.4 encryption and deformation Virus
The encryption and deformation virus is the focus of the Virtual Machine chapter, which will be introduced in the relevant chapter.
1.2.5 anti-tracking/anti-virtual execution Virus
The anti-tracking/anti-virtual execution virus is closely related to the virtual machine, so it will be introduced in the relevant chapter.
1.2.6 direct API call
Direct API calling is a common method of WIN32 Viruses today. It refers to a technology that allows viruses to directly locate the API function's entry address in the memory during runtime and then call it. When a common program calls an API, the compiler compiles an API call statement into several parameter pressure stack commands followed by an indirect call Statement (this refers to the Microsoft compiler, Borland compiler uses JMP ).
Dword ptr [XXXXXXXXh]): push arg1 push arg2 ...... Call dword ptr [XXXXXXXXh] |
The address XXXXXXXXh is in the Import Section of the program image. When the program is loaded and running, the loader adds the address of the API function to the program, this is the so-called Dynamic Link Mechanism. Virus because in order to avoid being infected with an executable file, the link information of the API used in the virus body code is constructed in the File Import segment, it chooses to use the code that directly locates the API function address at runtime. In fact, these function addresses are relatively fixed for a certain version of the operating system, but the virus cannot depend on this. Currently, it is more popular to first locate the base address of the dynamic connection library containing the API functions, and then find the required API address in its Export Section (Export Section. The next step is almost no difficulty, as long as you are familiar with the export segment structure. The key lies in the first step-determine the DLL loading address. In fact, the base address for system DLL loading is also fixed for a certain version of the operating system, but the virus still cannot rely on this to ensure its stability. Currently, most viruses use a technology called structured exception processing to capture exceptions caused by viruses. In this way, the virus can search for the specified DLL within a certain range of memory (the DLL uses the PE format and the header has a fixed mark), without worrying about being killed by the operating system due to page errors.
As exception handling is closely related to the subsequent anti-virtual execution technology, the following is a simple explanation of structured exception handling:
There are two types of exception handling: Final Exception Handling and Exception Handling per Thread.
1. Final Exception Handling
When any thread in your process encounters an exception, the operating system will call the Exception Processing Function created by SetUnhandledExceptionFilter in the main thread. You do not need to remove the processing code you installed when you exit. The system will automatically clear the code for you.
PUSH OFFSET FINAL_HANDLER CALL SetUnhandledExceptionFilter …… CALL ExitProcess ;************************************ FINAL_HANDLER: …… ;(eax=-1 reload context and continue) MOV EAX,1 RET ;program entry point …… ;code covered by final handler …… ;code to provide a polite exit …… ;eax=1 stops display of closure box ;eax=0 enables display of the box |
Second: Exception Handling per Thread
The value in FS is a sixteen-bit selector that points to the data structure TIB and thread information block that contains important thread information. Its first double byte points to the structure we call ERR:
1st dword + 0 pointer to next err structure (pointer of the next err structure) 2nd dword + 4 pointer to own exception handler (address of the current level of exception handling function) |
Therefore, exception handling is like training. If your own processing function captures and handles this exception, when your program encounters an exception, the operating system will not call its default processing function, so it will not have a Red Cross that is annoying to execute illegal operations.
The following is the exception section of cih:
MyVirusStart: push ebp lea eax, [esp-04h * 2] xor ebx, ebx xchg eax, fs: [ebx]; Switch the address of the current err structure and the previous one; eax = address of the previous structure; fs: [0] = Current err structure pointer (on the stack) call @ 0 @ 0: pop ebx lea ecx, stopToRunVirusCode-@ 0 [ebx]; your exception handling function offset push ecx; your exception handling function offset pressure stack push eax; the address pressure stack of the previous err structure; construct the err structure and note that the esp (err structure pointer) at this time is esp0 ...... StopToRunVirusCode: @ 1 = StopToRunVirusCode xor ebx, ebx; when an exception occurs, the system adds an err structure before your practice. Therefore, you must first find the original structure address mov eax, fs: [ebx]; obtain the current err structure address eax mov esp, [eax]; remove a structure address: eps0 to esp RestoreSE :; if no exception occurs, the esp is esp0 pop dword ptr fs: [ebx]. The address of the original structure is pop-up to fs: 0 pop eax; pop up your exception handling address, just flat the stack |
1.2.7 virus hiding
Hiding an implementation process or module is a required feature of a successful virus. In WIN9X, Kernel32.dll has an export function, RegisterServiceProcess, which can cause the process to disappear from the Process Manager Process List. However, it cannot cause viruses to escape from the monitoring of some process browsing tools. But when you know how these tools enumerate processes, you will also find a way to deal with these tools. In WIN9X, most process browsing tools use Process32First and Process32Next functions in a dynamic connection library called ToolHelp32.dll to implement process enumeration. In WINNT/2000, PSAPI is also used. the EnumProcess exported by DLL can be used to implement the same function. Therefore, you can consider modifying part of the code of these public functions so that the information of specific processes cannot be returned to hide the virus.
However, it is far less simple than imagined. As the saying goes, "It's a little too high, it's a little too high. Due to the efforts of many reverse engineering engineers, many secrets that Microsoft tries to hide have been gradually mined. Of course, this includes the management process used by the WINDOWS Kernel and the internal data structure and code of the module. For example, WINNT/2000describe all active processes in the system using the Eprocess block bidirectional linked list of the Process pointed to by the kernel variable PsInitialSystemProcess exported by ntoskrnl.exe. If the process browsing tool reads the data from the system kernel space directly with the help of the driver to enumerate the process, no virus can escape from it.
For detailed structure and functions of Eprocess, see the third edition of David A. Solomon and Mark E. Russinovich's "Inside Windows2000.
1.2.8 special virus infection Method
People who have a little knowledge about viruses know that common viruses add themselves to the tail of the host (as a result, the host size increases ), modify the program entry point to activate the virus. But now many viruses use special infection techniques to keep the size of the host and the entry points on the host file head unchanged.
The virus code is appended, but the infected file size does not change. In fact, it uses the characteristics of the PE file format: each section of the PE file contains holes aligned by cluster size. If the virus is small enough, you can divide itself into several parts and insert them into the gaps at the end of each section, in this way, you do not need to add an additional section, so the file size remains unchanged. The famous CIH virus is a typical example of using this technology (it is about 1 K in size ).
It is not easy for a virus to gain control without modifying the file header entry point: the entry point remains unchanged, meaning that the program is executed from the entry code of the original program, A virus must change one of the original program code to a jump command directed to the virus entry. This is the principle, but there are still many discussions, such as where to insert this jump command in the original program code. Some anti-virus tools scan the entry point domain of the executable file header. If it is found that it points to an abnormal place, that is, it is not in the Code section but in the resource section or the relocation section, there is reason to suspect that the file is infected with a virus. So we just discussed that the technology known as EPO (Fuzzy entry point) in the virus community can well deal with such scanning, and it is also an important means of anti-virtual execution.
It is also worth mentioning that many viruses now support infection of compressed files. For example, Win32.crypto can infect ZIP, ARJ, RAR, ACE, CAB, and many other types of compressed files. These virus codes contain code segments that extract and compress specific compressed file types. You can first extract the content from the compressed file and then infect the appropriate file, at last, compress the infected file back and modify the checksum of the compressed file header. At present, many anti-virus software supports querying compressed files in multiple formats, but some infected compressed files cannot be deleted. I think the reason may be that, for some reason, such as decompression or compression errors and incorrect checksum and calculation, the format of the compressed file after cleanup is damaged. The virus does not take responsibility for file corruption, so there is no such worry.
References
David A. Solomon, Mark Russinovich Inside Microsoft Windows 2000 September 2000
David A. Solomon Inside Windows NT May 1998
Prasad Dabak, Sandeep Phadke, Milind Borate "untitled ented Windows NT" October 1999
Matt Pietrek Windows 95 System Programming Secrets March 1996
Walter Oney System Programming for Windows 95 March 1996
Walter Oney "Programming the Windows Driver Model" 1999
Lu Lin WINDOWS9X file read/write Internal 2001
Original article: http://tech.ccidnet.com/pub/article/c1101_a80391_p1.html