Как получить путь к исполняемому файлу c

Обновлено: 04.07.2024

Принцип всех методов определения файловой системы следующий: на обычном хосте таких файлов и каталогов нет; однако они существуют в определенных виртуальных средах и песочницах. Виртуальная среда может быть обнаружена, если присутствует такой артефакт.

1. Проверить, существуют ли определенные файлы

Этот метод использует разницу в файлах, присутствующих в обычной хост-системе и виртуальной среде. В виртуальных средах присутствует довольно много файловых артефактов, специфичных для таких систем. Эти файлы отсутствуют на обычных хост-системах, где не установлена ​​виртуальная среда.

  • GetFileAttributes // если атрибуты недействительны, то файл не существует

Пример кода

Кредиты для этого примера кода: проект al-khaser

Рекомендации по подписи

Если следующая функция содержит единственный аргумент из столбца таблицы "Путь":

тогда это указывает на то, что приложение пытается использовать метод уклонения.

Таблица обнаружений

< td /> < /tr>
Проверьте, существуют ли следующие файлы:
Обнаружение Путь Подробности (если есть)
[general] c:\[60 случайных шестнадцатеричных символов] файл, уникальный для ПК, используемый для кодирования
c:\take_screenshot.ps1
c:\loaddll.exe < /tr>
c:\email.doc
c:\email.htm
c:\123\email.doc
c:\123\email.docx < /tr>
c:\a\foobar.bmp
c:\a\foobar.doc
c:\a\foobar.jpg
c:\symbols\aagmmc.pdb
Parallels c:\windows\system32\drivers\prleth.sys Сетевой адаптер
c:\windows\system32\drivers\prlfs.sys
c:\windows\system32\drivers \prlmouse.sys Инструмент синхронизации мыши
c:\windows\system32\drivers\prlvideo.sys
c:\windows\system32\drivers\prltime.sys Драйвер синхронизации времени
c:\windows\system32 \drivers\prl_pv32.sys Драйвер паравиртуализации
c:\windows\system32\drivers\prl_paravirt_32.sys Драйвер паравиртуализации
VirtualBox c:\windows\system32\drivers\VBoxMouse.sys
c:\windows\system32\drivers\VBoxGuest.sys
c:\windows\system32\drivers\VBoxSF.sys< /td>
c:\windows\system32\drivers\VBoxVideo.sys
c:\ windows\system32\vboxdisp.dll
c:\windows\system32\vboxhook.dll
c:\windows\system32\vboxmrxnp.dll
c:\windows\system32\vboxogl.dll < /tr>
c:\windows\system32\vboxoglarrayspu.dll
c:\windows\system32\vboxoglcrutil.dll
c:\windows\system32 \vboxoglerrorspu.dll
c:\windows\system32\vboxoglfeedbackspu.dll
c:\windows\system32\vboxoglpackspu.dll
c:\windows\system32\vboxoglpassthroughspu.dll
c:\windows\system32\vboxservice.exe
c:\windows\system32\vboxtray.exe
c:\windows\system32\VBoxControl.exe
VirtualPC c:\windows\system32\drivers\vmsrvc.sys
c:\windows\system32\drivers\vpc-s3.sys
VMware c:\windows\system32\drivers\vmmouse.sys Указание драйвера устройства PS/2
c:\windows\system32\drivers\vmnet.sys
c:\windows\system32\drivers\vmxnet.sys адаптер Ethernet PCI
c:\windows\system32\drivers\vmhgfs.sys HG Драйвер файловой системы FS
c:\windows\system32\drivers\vmx86.sys
c:\windows\system32\ драйверы\hgfs.sys

2. Проверить наличие определенных каталогов

Этот метод использует разницу в каталогах, которые присутствуют в обычной хост-системе и виртуальной среде. В виртуальных средах присутствует довольно много артефактов каталогов, характерных для таких систем. Эти каталоги отсутствуют на обычных хост-системах, где не установлена ​​виртуальная среда.

  • GetFileAttributes // если атрибуты недействительны, то файл не существует

Пример кода

Кредиты для этого примера кода: проект al-khaser

Рекомендации по подписи

Если следующая функция содержит единственный аргумент из столбца таблицы "Путь":

тогда это указывает на то, что приложение пытается использовать метод уклонения.

Таблица обнаружений

Проверьте, существуют ли следующие файлы:
Обнаружение Путь
CWSandbox c:\analysis< /td>
VirtualBox %PROGRAMFILES%\oracle\virtualbox гостевые дополнения\
VMware %PROGRAMFILES%\VMware\

3. Проверить, содержит ли полный путь к исполняемому файлу одну из указанных строк

Этот метод основан на особенностях запуска исполняемых файлов внутри виртуальных сред. В некоторых средах исполняемые файлы запускаются по определенным путям, и образцы вредоносных программ проверяют эти пути.

Функции, используемые для получения пути к исполняемому файлу:

  • ПолучитьИмяФайлаМодуля
  • GetProcessImageFileNameA/W
  • QueryFullProcessImageName

Пример кода (функция GetModuleFileName)

Кредиты для этого примера кода: проект pafish

Пример кода (функция QueryFullProcessImageName)

Нет рекомендаций по подписи

Рекомендации по сигнатурам не предоставляются, так как сложно сказать, почему именно приложение хочет получить свой полный путь. Вызовы функций могут быть перехвачены — и это все, просто общая рекомендация.

Таблица обнаружений

4. Проверить, запускается ли исполняемый файл из определенного каталога

Этот метод основан на особенностях запуска исполняемых файлов внутри виртуальных сред. В некоторых средах исполняемые файлы запускаются из определенных каталогов, и образцы вредоносных программ проверяют эти каталоги.

Это всего лишь частный случай проверки наличия определенных строк в полном пути к приложению. Обратитесь к разделу выше, чтобы ознакомиться с образцом кода и рекомендациями по подписи.

Поскольку этот метод довольно старый и редко используется, для ознакомления с этим методом приводятся ссылки на внешние источники:

  • Пример кода VB
  • пример кода Python
  • приемы защиты от эмуляции
  • заглушка для кода C

Таблица обнаружений

Проверить, содержит ли полный путь к исполняемому файлу одну из следующих строк:
Обнаружение Строка
[ общие] \sample
\virus
песочница
Проверьте, запускается ли исполняемый файл из следующих каталогов:
Обнаружение Путь
Анубис c :\insidetm

5. Проверить наличие исполняемых файлов с определенными именами в корневом каталоге физических дисков

Этот метод основан на особенностях виртуальных сред, в данном случае на наличии определенных файлов в корневых каталогах диска.

  • GetFileAttributes // если атрибуты недействительны, то файл не существует

Пример кода (функция GetModuleFileName)

Кредиты для этого примера кода: проект pafish

Рекомендации по подписи

Если следующая функция содержит единственный аргумент из столбца таблицы "Путь":

тогда это указывает на то, что приложение пытается использовать метод уклонения.

Таблица обнаружений

< th style="text-align:center">Обнаружение
Проверить наличие исполняемых файлов с определенными именами в корне диска:
Путь
[general ] malware.exe
sample.exe

Контрмеры

Перехватывать целевые функции и возвращать соответствующие результаты, если индикаторы (файлы из таблиц) проверены.

Кредиты

Кредиты относятся к проектам с открытым исходным кодом, из которых были взяты образцы кода:

  • проект al-khaser на github
  • проект pafish на github

Хотя инструмент Check Point InviZzzible уже реализовал их все, из-за модульной структуры кода потребовалось бы больше места, чтобы показать пример кода из этого инструмента для тех же целей. Вот почему мы решили использовать другие замечательные проекты с открытым исходным кодом в качестве примеров по всей энциклопедии.

Есть ли функция C++, похожая на getcwd, которая дает вам не
рабочий каталог, а каталог или путь к текущему
исполняемому файлу?

Мне это нужно, потому что я импортирую игру, которая использует относительные пути к
изображениям. Это прекрасно работает, когда игра запускается непосредственно из
каталога, в котором она находится (как в ./game &). Он не работает, когда выполняется
из другого места (как в /root/games/game &)




Существует ли функция C++, похожая на getcwd, которая дает вам не
рабочий каталог, а каталог или путь к текущему
исполняемому файлу?

Мне это нужно, потому что я импортирую игру, которая использует относительные пути к
изображениям. Это прекрасно работает, когда игра запускается непосредственно из
каталога, в котором она находится (как в ./game &). Он не работает, когда выполняется
из другого места (как в /root/games/game &)

Это первый аргумент программы.

Мне это нужно, потому что я импортирую игру, которая использует относительные пути к
изображениям. Это прекрасно работает, когда игра запускается непосредственно из
каталога, в котором она находится (например, ./game &). Он не работает, когда выполняется
из другого места (как в /root/games/game &)

Это первый аргумент программы.

int main(int argc, char* argv[])
std::cout return 0;
>
Помните: это обычный способ, но стандарт не гарантирует < бр />это.

Например, он не работает в ms-dos до версии 3.0, поскольку
операционная система не предоставляет эту информацию. но я не знаю
существуют ли стандартные компиляторы C++, которые создают программы, способные работать
в этих версиях.

Мне это нужно, потому что я импортирую игру, которая использует относительные пути к
изображениям. Это прекрасно работает, когда игра запускается непосредственно из
каталога, в котором она находится (например, ./game &). Он не работает, когда выполняется
из другого места (как в /root/games/game &)

Это первый аргумент программы.

Помните: это обычный способ, но стандарт не гарантирует
его. Да, нет никакой гарантии, что argv[0] содержит что-либо (кроме 0),
вы всегда должны проверять, чтобы argc был равен 0 перед обращением к argv.

На большинстве современных платформ рекомендуется установить argv[0], однако
он может содержать как относительный, так и полный путь.

Существует ли функция C++, похожая на getcwd, которая дает вам не
рабочий каталог, а каталог или путь к текущему
исполняемому файлу?

Мне это нужно, потому что я импортирую игру, которая использует относительные пути к
изображениям. Это прекрасно работает, когда игра запускается непосредственно из
каталога, в котором она находится (как в ./game &). Он не работает, когда выполняется
из другого места (как в /root/games/game &)

Не существует переносимого способа определения полного имени исполняемого файла, а
даже если бы он был, его использование было бы ограниченным. Несистемная программа, включая
или особенно игры, не должна иметь возможности записи в каталог, где
хранятся программы. Программы должны записывать туда данные в
домашний каталог текущего пользователя (или его подкаталог), но обычно не в
системный каталог, ни в /root, ни в c:\winnt или куда-то ещё.

Пусть программа записывает в текущий каталог, возможно, поэтому она
использует относительные пути, или позволяет пользователю указать рабочий каталог в
командной строке, или использует переменную среды, чтобы указать, что директории, но
не предполагайте, что вы можете писать в директорию, где исполняемый файл
хранится на диске. Представьте, что произойдет, если вы запустите программу с
CD-ROM, не говоря уже о том, что могло бы произойти, если бы каждая дурацкая программа могла
создавать файлы повсюду в системе.


Например, он не работает в ms-dos до версии 3.0, поскольку
операционная система не предоставляет эту информацию. но я не знаю
существуют ли стандартные совместимые компиляторы C++, которые создают программы, способные работать
в этих версиях.
Означает ли это, что мы никогда не получим порт игры Патрика для MS-DOS 3.0? :-(

CD-ROM, не говоря уже о том, что могло бы произойти, если бы любая глупая программа могла
создавать файлы повсюду в системе.

Спасибо всем за комментарии. Я так торопился, что не успел
прочитать комментарии раньше.

Я нашел тот же трюк с argv[0], о котором вы упоминали. В итоге я использовал argv[0]
вместе с getcwd и некоторыми манипуляциями со строками, чтобы выяснить
каталог исполняемого файла. Насколько я понимаю, формат этой строки
не указан в стандарте. Однако он отлично работает на определенных
платформах, для которых мне нужно выполнить перенос.

Игра пишет и читает из той же папки, в которой находится исполняемый файл.
Мне это показалось естественным. Это делается для того, чтобы данные,
принадлежащие одному и тому же приложению, хранились вместе в одном месте, а не
разбросаны по системе.

Но вы поднимаете важный вопрос.Я не должен был предполагать, что у меня есть
права на запись в этот каталог, в котором находится исполняемый файл.

Поэтому, если можно предположить, что папка для чтения/выполнения одна и та же, а папка для
записи не может, тогда мне нужен способ настроить другой путь
записи. У меня есть путь чтения/выполнения, и чтобы получить путь записи, я мог бы:

A Жестко запрограммировать путь записи.

B получить рабочий каталог. Я не могу предположить, что рабочим каталогом является
каталог записи из-за проблем с интеграцией (скрипт, который запускает
игру, запускает ее от root, поэтому root будет рабочим каталогом.
Поскольку я не владею платформу, поэтому я не могу изменить способ
работы скрипта.)

C Переменная окружения для конкретной игры. Чтение какой-либо
переменной среды, специфичной для игры, не поможет, потому что, опять же, я
не владею платформой и не могу устанавливать свои собственные
переменные среды, специфичные для игры.

D Использование домашнего каталога пользователя. Выяснение домашнего
каталога текущего пользователя с помощью c++ звучит не очень переносимо. Опять же, id
вероятно, должен прочитать какую-то переменную среды, специфичную для платформы.

E Чтение пути записи из файла. Наличие файла с именем
writePath.txt в той же папке, что и исполняемый файл.

Есть ли способ в C/C++ найти местоположение (полный путь) текущей исполняемой программы?

(Проблема с argv[0] заключается в том, что он не дает полный путь.)

Я не думаю, что есть портативный способ сделать это. Имеет ли argv[0] полный путь, если вы вызываете программу с полным статическим путем? Если это так, вы можете заставить пользователя выполнить двоичный файл как таковой, как это делает sshd.

В этом вопросе ("Как мне найти расположение моей программы в НАСТРОЙКЕ X?") действительно можно было бы использовать тег; сложно искать по ключевым словам!

Верхний ответ в дубликате более исчерпывающий, чем любой или все ответы здесь, хотя это более свежий вопрос. Следовательно, я закрыл это как дубликат этого, а не наоборот, хотя это более старый вопрос, и он обычно получает кивок как основной вопрос по теме.

9 ответов 9

В Unix-системах с /proc действительно прямой и надежный способ:

readlink("/proc/self/exe", buf, bufsize) (Linux)

readlink("/proc/curproc/file", buf, bufsize) (FreeBSD)

readlink("/proc/self/path/a.out", buf, bufsize) (Solaris)

В Unix без /proc (т. е. если вышеперечисленное не работает):

Если argv[0] начинается с "/" (абсолютный путь), это путь.

В противном случае, если argv[0] содержит "/" (относительный путь), добавьте его к cwd (при условии, что он еще не был изменен).

В противном случае выполните поиск исполняемого файла argv[0] в каталогах $PATH.

После этого может быть целесообразно проверить, не является ли исполняемый файл на самом деле символической ссылкой. Если это разрешено относительно каталога символической ссылки.

Этот шаг необязателен для метода /proc (по крайней мере, для Linux). Там символическая ссылка proc указывает непосредственно на исполняемый файл.

Обратите внимание, что правильность установки argv[0] зависит от вызывающего процесса. В большинстве случаев это правильно, однако бывают случаи, когда вызывающему процессу нельзя доверять (например, исполняемый файл setuid).

В Windows: используйте GetModuleFileName(NULL, buf, bufsize)

Все, что зависит от того, что argv[0] является именем программы, ненадежно. Это будет работать в большинстве случаев, но не каждый раз. Эта проблема сложна для Unix без /proc

Не все Unix-системы с proc имеют /proc/self/exe. Макет /proc полностью зависит от ОС, и все они делают это немного по-разному. Например, FreeBSD предоставляет /proc/curproc/file, который работает так же, как /proc/self/exe в Linux. Но другие могут вообще этого не делать.

Обратите внимание, что если кому-то нужно скрыть свои следы, то execl("/home/hacker/.hidden/malicious", "/bin/ls", "-s", (char *)0); оставляет argv[0] с абсолютным путем, который не имеет ничего общего с именем исполняемого файла. Однако другая информация полезна; спасибо.

Неясный случай: метод Linux /proc/self/exe не совсем работает, если исполняемый файл находится в представлении MVFS с прозрачным регистром, поскольку Linux в конечном итоге возвращает расположение исполняемого файла в каталоге хранилища представления, а не /просмотреть квалифицированный путь. Например, для /vbs/bldsupp/linuxamd64/clang/debug/bin/llvm-config /proc/self/exe указывает мне недружественный путь: /home/peeterj/views/peeterj_clang-7.vws/.s/00024/ 8000023250b8f17fllvm-tblgen

Используйте функцию GetModuleFileName(), если вы используете Windows.

Обратите внимание, что следующие комментарии относятся только к Unix.

Педантичный ответ на этот вопрос заключается в том, что не существует общего способа правильно ответить на этот вопрос во всех случаях. Как вы заметили, argv[0] может быть установлен родительским процессом на что угодно, и поэтому он не должен иметь никакого отношения ни к фактическому имени программы, ни к ее местоположению в файловой системе.

Однако часто работает следующая эвристика:

  1. Если argv[0] является абсолютным путем, предполагается, что это полный путь к исполняемому файлу.
  2. Если argv[0] является относительным путем, т. е. содержит / , определите текущий рабочий каталог с помощью getcwd() и затем добавьте к нему argv[0].
  3. Если argv[0] — простое слово, выполните поиск $PATH в поисках argv[0] и добавьте argv[0] в любой каталог, в котором вы его найдете.

Обратите внимание, что все это можно обойти процессом, вызвавшим данную программу. Наконец, вы можете использовать методы, специфичные для Linux, такие как упомянутые в emg-2. Вероятно, в других операционных системах есть аналогичные методы.

Даже если предположить, что приведенные выше шаги дали вам правильное имя пути, у вас все равно может не быть имени пути, которое вам действительно нужно (поскольку я подозреваю, что на самом деле вы хотите найти где-нибудь файл конфигурации). Наличие жестких ссылок означает, что у вас может быть следующая ситуация:

Теперь описанный выше подход (включая, как я подозреваю, /proc/$pid/exe) даст /some/where/else/foo реальный путь к программе. И, по сути, это настоящий путь к программе, только не тот, который вы хотели. Обратите внимание, что эта проблема не возникает с символическими ссылками, которые на практике встречаются гораздо чаще, чем жесткие ссылки.

Несмотря на то, что этот подход в принципе ненадежен, на практике он работает достаточно хорошо для большинства целей.

Получает полный путь к файлу, содержащему указанный модуль. Модуль должен быть загружен текущим процессом.

Чтобы найти файл для модуля, который был загружен другим процессом, используйте функцию GetModuleFileNameEx.

Синтаксис

Параметры

[in, необязательно] hModule

Дескриптор загруженного модуля, путь к которому запрашивается. Если этот параметр имеет значение NULL, GetModuleFileName получает путь к исполняемому файлу текущего процесса.

Функция GetModuleFileName не извлекает пути для модулей, которые были загружены с использованием флага LOAD_LIBRARY_AS_DATAFILE. Дополнительные сведения см. в разделе LoadLibraryEx.

Указатель на буфер, который получает полный путь к модулю. Если длина пути меньше размера, указанного в параметре nSize, функция завершается успешно, и путь возвращается в виде строки с завершающим нулем.

Если длина пути превышает размер, указанный параметром nSize, функция завершается успешно, и строка усекается до символов nSize, включая завершающий нулевой символ.< /p>

Windows XP: строка усекается до nSize символов и не заканчивается нулем.

Возвращаемая строка будет использовать тот же формат, который был указан при загрузке модуля. Поэтому путь может быть длинным или коротким именем файла и может использовать префикс \\?\ . Дополнительную информацию см. в разделе Именование файла.

Размер буфера lpFilename в TCHAR.

Возвращаемое значение

Если функция завершается успешно, возвращаемое значение представляет собой длину строки, которая копируется в буфер, в символах, не включая завершающий нулевой символ. Если буфер слишком мал для хранения имени модуля, строка усекается до nSize символов, включая завершающий нулевой символ, функция возвращает nSize и устанавливает последний ошибка ERROR_INSUFFICIENT_BUFFER.

Windows XP: если буфер слишком мал для хранения имени модуля, функция возвращает значение nSize. Последний код ошибки остается ERROR_SUCCESS. Если nSize равно нулю, возвращаемое значение равно нулю, а последний код ошибки — ERROR_SUCCESS.

Если функция завершается ошибкой, возвращаемое значение равно 0 (ноль). Чтобы получить расширенную информацию об ошибке, вызовите GetLastError.

Примечания

Если DLL загружается в двух процессах, имя ее файла в одном процессе может отличаться от имени файла в другом процессе.

Глобальная переменная _pgmptr автоматически инициализируется полным путем к исполняемому файлу и может использоваться для получения полного пути к исполняемому файлу.

Примеры

Заголовок libloaderapi.h определяет GetModuleFileName как псевдоним, который автоматически выбирает версию этой функции в формате ANSI или Unicode на основе определения константы препроцессора UNICODE. Смешивание использования псевдонима, не зависящего от кодировки, с кодом, который не является нейтральным, может привести к несоответствиям, которые приводят к ошибкам компиляции или выполнения. Дополнительные сведения см. в разделе Соглашения для прототипов функций.

argv[0] ссылается на команду оболочки, вызвавшую загрузку текущего процесса. getcwd() возвращает текущий рабочий каталог. Могу ли я из этой информации построить абсолютный путь к двоичному исполняемому файлу программы? Я не ожидаю, что это сработает, если программа сделала компакт-диск с момента ее первой загрузки.

Текущий рабочий каталог не имеет значения, исполняемый файл ищется в каталогах, перечисленных в переменной среды PATH.Еще больше усложняет ситуацию то, что POSIX определяет функцию fexecve(int fd, char *const argv[], char *const envp), которая «выполняет программу, указанную через файловый дескриптор». Эта библиотечная функция реализована в Linux с использованием файловой системы /proc, а argv[0] содержит что-то вроде «/proc/self/fd/4». На самом деле нет надежного способа получить исполняемый файл, его может и не быть!

@countermode Хотя argv[0] может быть любым, вы можете задокументировать для своей программы требование, чтобы определенные ее функции (возможно, все они) требовали от нее вычисления собственного пути, который (по крайней мере, на некоторых платформах ) требует, чтобы argv[0] был ненулевым и имел разумное значение: путь, возможно, относительно cwd, по которому он был вызван. Любую программу можно использовать неправильно, вопреки документально подтвержденному правильному использованию, с неверными аргументами или в других ситуациях.

2 ответа 2

Внутри интерпретатора языка программирования я использую следующий код для получения пути к себе.

Есть специальный код для Linux, Windows (включая Cygwin), Mac и Solaris:

Тип val, символ nil и функции string и string_utf8 являются внутренними для интерпретатора. convert — это просто макрос, который абстрагирует кастинг. Конечно, некоторые заголовочные файлы необходимы для readlink, realpath и т. д.

Функция getexecname используется в Solaris. Похоже, что по какой-то причине я написал код для обработки относительного пути, и в этом случае текущий каталог должен быть привязан к нему, чтобы получить его абсолютным.

Стратегия отката заключается в том, что если argv[0] из main доступен, то вызывается для него realpath и выполняется с ним. Если argv[0] недоступен, мы полагаемся на жестко заданный путь установки, который берется из переменной Makefile. Например, если программа установлена ​​как /usr/bin/foo , то рецепт Makefile вставляет это в командную строку компилятора как -DHARD_INSTALLATION_PATH=/usr/bin/foo . Конечно, это будет правильно, только если программа установлена ​​по тому пути, для которого она была создана.

Читайте также: