Путь К Исполняемому Файлу. Скопировать Себя (С++ Без WinApi)
Задача — получить путь к исполняемому файлу, скопировать исполняемый файл. Среда Visual C++ (в прочем подходит любая другая среда или компилятор).
Самый простой способ решения указанных задач — использование функций WinApi. Без труда можно получить путь до бинарника (самого себя) и скопировать себя в любое место на ПК. Но мы пойдем другим путем — решим указанную выше задачу без WinApi.
Далее — что-то вроде лабораторной работы. На полноту раскрытия темы не претендуем, только любопытная информация. Если нужно — этого должно хватить, чтобы найти правильный путь решения задач типа работы с файлами без WinApi.
Путь к исполняемому файлу
Создадим каркас нашей программы:
#include <iostream> using namespace std; int main(int argc, char* argv[]){ cout << "Hello, World" << endl; return 0; }
Ничего сложного. Здесь только подключаемый заголовочный файл iostream (для вывода сообщения на экран), объявляется основная функция main с типом int и вывод на экран строчки.
Нас интересует следующий код
int argc, char* argv[]
Это параметры канонадой строки. Обратим внимание на массив argv (argument vector). Здесь аргументы запуска нашей программы. В нем и содержится путь до бинарника. Изменим наш код
cout << argv[0] << endl;
Результат — на экране отобразится полный путь до исполняемого файла с именем и расширением. И все без WinApi!
Копировать себя
Будем использовать только функции, которые прописаны в стандартных заголовочных файлах.
Подключим еще один заголовочный файл fstream и добавим несколько строчек:
#include <iostream> #include <fstream> using namespace std; int main(int argc, char* argv[]){ char buf[256]; ifstream myFile; ofstream exeFile; myFile.open(argv[0],ios_base::binary); exeFile.open("file.exe",ios_base::binary); return 0; }
Здесь мы объявляем массив. Создаем два объекта — myFile(класс ifstream, чтение самого себя) и exeFile (класс ofstream, запись нового бинарника).
Открываем исполняемый файл с помощью метода open():
myFile.open(argv[0],ios_base::binary);
Параметр ios_base::binary означает, что мы будем работать с бинарным файлом (можно обойтись и без этого параметра).
exeFile.open("file.exe",ios_base::binary);
Открываем (создаем) новый файл в текущей директории.
Добавим еще несколько строк:
while(1){ myFile.read(buf,sizeof(buf)); if(myFile.eof())break; exeFile.write(buf, sizeof(buf)); }
Здесь создается бесконечный цикл, в ходе которого считываем самого себя до тех пор, пока не доходим до конца:
if(myFile.eof())break;
Этот код позволяет выйти из цикла как только доходим до конца.
С помощью метода read() читаем себя.
С помощью метода write() записываем прочитанные символы во вновь созданный файл.
В конце зарываем оба файла с помощью метода close().
myFile.close(); exeFile.close();
Этого достаточно чтобы скопировать себя без WinApi.
Добавим еще несколько строк — полезная нагрузка. Добавляем заголовочный файл cstdlib (с помощью описанных в нем методов получим функцию пауза):
cout << "hello world" << endl; system("pause");
То есть после исполнения программа отобразит на экране строчку и будет ожидать нажатия клавиш (чтобы окно программы не закрылось).
Все вместе:
#include <iostream> #include <fstream> #include <cstdlib> using namespace std; int main(int argc, char* argv[]){ char buf[256]; ifstream myFile; ofstream exeFile; myFile.open(argv[0],ios_base::binary); exeFile.open("C:\\File\\1.exe",ios_base::binary); while(1){ myFile.read(buf,sizeof(buf)); if(myFile.eof())break; exeFile.write(buf, sizeof(buf)); } myFile.close(); exeFile.close(); cout << "hello, world" << endl; system("pause"); return 0; }
Необычный эффект
Указанный код тестировался в Visual C++. Если просто запустить приложение через редактор, то исполняемый файл копируется лишь частично. Причем то, что копировалось будет называться встроенным защитником Windows как троянская программа. Поэтому компилируем код и запускаем двойным щелчком по бинарнику. Вероятно, что на определенном этапе чтения-записи полученный код в новом файле содержит сигнатуру, близкую к вредоносной программе.