Virus Basic Series by Hume / Cold Rain Delivery: There is nothing terrible in viruses, and it is not like the complexity of imagination, if you have no virus, if you have seen a virus? It is just white live ... virus is like Double-edged sword, malicious use will bring evil, I am deeply sick for such behavior! We have not to destroy but for knowing yourself, and there are also many high-top skills in different viruses worth learning, this is our purpose. I don't have the intention of the crime of people and I am far from my horizontal.
There are several basic knowledge before studying the virus: 1) Ring0 acquisition, see a RING0 article I translated, there are many information on the Internet. 2) SEH's knowledge, please refer to I write << SEHIN ASM Research >> 3) Knowledge of the PE structure, Zoudan Heroes, ICZelion's PE teaching and LuevelSmey "PE file format", the most important! 4) The basic knowledge of document read and write, mainly CreateFilea, Readfile Files such as Writefile, CreateFilemapping ... If you still don't understand, it is best to learn Win32ASM's basics. 5) PolyEngine ... Metamorphism and other basic concepts 6) Some concepts of Anti-debug 7) MBR, FAT and other knowledge is useful for some old Virus.
Some of the TIPs I have below may be helpful to understand the virus. In addition, these technologies are also common in changing software.
TIP1: Acquisition of API Function Address
This is an old topic. If we don't have any introduction library, can I call the API function in the program? Of course! There are a lot of ways, you may know, if you have already understood, you will hit it. Don't know this technology. In addition, this is also one of the skills of virus, if you are interested in viruses, then look down.
Here, you understand the basic structure of PE, if you don't understand, find some information to see, everywhere.
In the beginning of almost every virus, use the following statement: Call Deltadelta: POP EBP SUB EBP, OFFSET DELTA MOV DWORD PTR [EBP OFFSET AppBase], EBP Let us consider the execution of the program, if the following code is compiled by the compiler Automatically compile connection, the base address performed by the program is generally 400000h. If it is executed in NT, the base address may be different, such as starting from 100000h, don't worry, the Loader of the operating system will automatically relocate. But here stopped Let's take a look, if you want to attach this code to the back of other programs and want it to be executed correctly, because your code may be executed from 555588h, but not get a host Under the circumstance of the program license, it is impossible to correct the offset error. Since there is a very purpose, you have to pay strength, you can get a weight position. And the above code is first get the EIP pointer, and Delta is The actual offset of the program is executed, then minus the offset of the Pier to Delta to get the true base address of your code, and the back to the offset should be subject to this real offset. This is what you look If you don't understand, let's think about it, Nothing Difficult! The following example demonstrates this, not all relocation, because this is just a technical demonstration.
Now returning to the official content of this article, to get the address of the API, first get the base address such as kernel32.dll, user32.dll, and then find a real function address. How to get the base and function addresses? Method 1) Search the introduction table of the host to get the getModuleHandlea function and the address of the getProcAddress, then return to the base address of the system DLL. Because many programs use these two functions, so in some cases, if the host Didn't use GetProcaddress, then you have to search for the export table. 2) Get the base address of kernel32.dll directly, then search the Export table to get the address of GetProcaddress and LoadLibrarya, and then we can get any function addresses you want to call. ) The hard-encoded call function, such as the address of 9X The first and third methods have compatibility problems. If the host does not call getModuleHandlea, then you can't get the base address, don't even think about it ... hard-coded problems are larger, the operating system cannot be run. For example, under the 9X may be normal on some computers, but must not run under NT / 2K ... The second method is more compatible, so it is described. One point background: In Pe Loader, the address of the stack top after PE Loader is started, it is the return address of the program, and it is sure in Kernel! So we can get this address, then reduce the verification of the low address until the start address of the module, the verification condition is the PE header cannot be greater than 4096bytes, the imagebase value of Pe header should be equal, 嘿, simple, and compatibility not bad. To get the address of the API, you should get the address of getModuleHandle, LoadLibrarya, getProcAddress, which is achieved by searching the export table. The specific principle is the structure of the Pe Export table. If you understand the PE structure is very simple. I have added it below. Note, no optimization code is for easy understanding. Ok, this part is over! This is an example. It does not use any pre-introduced functions, adding an invoke initcommonControls to run normally in 2k, otherwise you can't load it in 2k! Program gets the address of the MessageBoxa and then display a message box, the purpose is to demonstrate, The important part has been added, very well understood. Note the /section: Terxt ,RWE option when connecting. .586.Model flat, StdCallOption Casemap: None; Case SensitiveInClude C: /HD/HD.HINCLUDE C: /HD/Mac.h ;;; -------------- Getapia Proto: DWORD,: DWORD ;; --------------. CodeAppBase DD? K32Base DD? LPAPIADDRS Label Near DD Offset SgetModuleHandle Dd Offset SgetProcaddress DD Offset SexitProcess DD Offset Sloadlibrary DD 0 SgetModuleHandle DB "getModuleHandlea", 0SGetProcaddress DB "getProcaddress", 0sexitProcess DB "EXITPROCESS", 0SLOADLIBRARY DB "LoadLibrarya", 0 SMESSAGEBOXA DB "MessageBoxa", 0 AgetModuleHandle DD 0AGETPROCADDRESS DD 0AEXITPROCADDRESS DD 0AExitProcess DD 0AloadLibrary DD 0amessageBoxa DD 0U32 DB "User32.dll", 0K32 DB "kernel32.dll", 0 Sztit DB "BY HUME, 2002", 0Szmsg0 DB "Hey, Hope U Enjoy it!", 0 ;; -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --------------- __Start: InvokeinitCommonControls Call Deltadelta: POP EBP; get Delta Address Sub EBP, Offset Delta; Because the base address in other programs may not be the default, it is necessary to relocate MOV DWORD PTR [EBP Offset AppBase], EBP; huh, I think about MOV ECX, [ESP]; Return Address XOR EDX, EDXGETK32BASE: DEC ECX; Characterization Compare Verification MOV DX, Word PTR [ECX Image_DOS_HEADER.E_LFANEW]; ECX 3ch Test DX, 0F000H; DOS Header Stub is not too large, more than 4096byte jnz getK32Base; accelerated test cmp ecx, dword ptr [ecx edx IMAGE_NT_HEADERS.OptionalHeader.ImageBase] jnz getK32Base; see whether the value is equal to ecx i.e. Image_Base module start value, mov [ebp offset k32Base], ecx; If so, think of finding the Base value of Kernel32 Lea EDI, [EBP Offset AgetModuleHandle] Lea ESI, [EBP Offset LPAPIADDRS] LOP_GET: LODSD CMP EAX, 0 jz end_get pu sh eax push dword ptr [ebp offset k32Base] callGetApiA; an API address stosd jmp lop_getEnd_Get: push offset u32 call dword ptr [ebp offset aLoadLibrary]; User32.dll lea EDX program loading space, [EBP OFFSET sMessageBoxA] push EDX PUSH EAX MOV EAX, DWORD PTR [EBP AGETPROCADDRESS]; Get the address of Messageboxa with GetProcaddress Call Eax; call getProcAddress PUSH 40H 1000H; Style Push Offset Szmsg0; Message Content Push 0 Call Eax; A message box is generated ... 嘿嘿; reason we are happy, because we don't pre-introduced @@:; these functions Push 0 Call [EBP AEXITPROCESS]; -------------------------------------------------------------------------------------------------------------------------------------------------------------- K32_api_retrieve proc Base: DWORD, sApi: DWORDpush edx; save edx xor eax, eax; case esi = sApiNext_Api:; edi = AddressOfNames mov esi, sApi xor edx, edx dec edxMatch_Api_name: mov bl, byte ptr [esi] inc esi cmp BL, 0 JZ Foundit Inc EDX Push Eax Mov Eax, [EDI EAX * 4]; AdredmentOfnames pointer, incrementing add eax, base; Note is RVA, must add Base value Cmp BL, Byte PTR [EAX EDX]; Character comparison POP EAX JZ MATCH_API_NAME Continue to search for Inc Eax; do not match, the next API loop next_api jmp no_exist; EDX EAX]; EAX Returns the pointer Retno_exist: Pop Edx XOR Eax, EAX RETK32_API_RETRIEVE ENDP; ------------------------------------------------------------------------------------ ------------- GetApiA proc Base: DWORD, sApi: DWORD local ADDRofFun: DWORD pushad mov edi, Base add edi, IMAGE_DOS_HEADER.e_lfanew mov edi, [edi]; now edi = off PE_HEADER add edi, Base; IMAGE_NT_HEADERS obtained offset mov ebx, edi mov edi, [edi IMAGE_NT_HEADERS.OptionalHeader.DataDirectory.VirtualAddress] add edi, Base; give edi = IMAGE_EXPORT_DIRECTORY inlet mov eax, [edi 1ch]; AddressOfFunctions address add eax, Base mov ADDRofFun, eax; ecx = NumberOfNames mov ecx , [EDI 18H] MOV EDX, [EDI 24h] Add Edx, Base; EDX = AddressOfnameRDINALS MOV EDI, [EDI 20H] Add Edi, Base; EDI = addressofnames invoke52_api_retrieve, base, SAPI MOV EBX, Addroffun SHL EAX, 2; * 4 to get offset Add Eax, EBX MOV EAX, [EAX] Add Eax, Base; plus Base! MOV [ESP 7 * 4], EAX; EAX Returns API Address Popad RetGetApia ENDP ; ----------------------------------------- End__start; ----------------------------------------- End All