1.0 Введение
Хоть компания Adobe и ушла из России, но потребность в их софте всё ещё остаётся. Решают её по-разному: кто-то использует другие аккаунты, кто-то использует ключи, а кто-то одевает повязку и спускает на воду свой цифровой фрегат.На последнем мы как раз и остановимся. В этой статье проанализируем Adobe GenP.
Adobe GenP — это патчер, предназначенный для активации продуктов Adobe Creative Cloud, начиная с версий 2019 года и до текущих релизов. Он позволяет устанавливать и использовать приложения Adobe: Photoshop, Illustrator, Premiere Pro и другие, без необходимости приобретения лицензии.
Патчер — это программа, предназначенная для модификации программного обеспечения. Чаще всего используемая для обхода проверки лицензий и других защитных механизмов.
В отличие от многих других патчеров у него есть даже
Ссылка скрыта от гостей
!Кстати, помимо основного сообщества рекомендую обратить внимание на Community bookmarks. Там много полезных туториалов и дополнительной информации.
План статьи:
1.0 Введение
2.0 Файлы
3.0 Установка Creative Cloud и первый запуск
3.1 Про установку Adobe
3.2 Запуск GenP
4.0 Разбираемся в исходном коде4.1 Начало скрипта
4.2 Основной цикл патчера
4.2.1. Обработчик кнопки поиска
4.2.2. Обработчик кнопки выбора папки
4.2.3. Обработчик кнопки выбора/отмены всех элементов
4.2.4. Обработчик кнопки Pop-up
4.2.5. Обработчик кнопки "Patch CC" и как работает эта магия
4.2.5.1. Весь цикл поиска и патчинга кратко
4.2.5.2. Вернёмся к обработчику кнопки "Patch CC"
4.2.5.3. Сравниваем пропатченные байты с оригинальными и ищем их
4.2.6. Обработчик кнопки "Restore"
4.2.7. Обработчик кнопки "Patch"
5.0 Изучаем патчи из INI-файла5.1. Секция CustomPatterns
5.2. Секция DefaultPatterns
5.3. Оставшиеся патчи
6.0 Вывод2.0 Файлы
Архив с GenP, который будет разбирать, был загружен с Reddit.Его контрольные суммы:
iz3lne.zip
MD5:
6b104ba9deb749a6b6ce88b9c6997dae
SHA1:
19d9b52477606b78bdce568235c0acb9321c1bc4
SHA256:
14ce93ae01d50b9d2ff3c36c3edd574a9f8bcec56451f3a865fcc210c617a77b
Архив с GenP состоит из следующих частей:
Исполняемый файл и исходник со всем необходимым, если мы хотим собрать патчер сами. Исходник написан в виде скрипта для
Ссылка скрыта от гостей
.3.0 Установка Creative Cloud и первый запуск
3.1 Про установку Adobe
Установщик для Creative Cloud (далее CC) загружаем с
Ссылка скрыта от гостей
. На момент написания статьи его MD5: 0011ec2b0f49f83ccf67aa706a638ccc
. Но и с более новыми версиями всё работает (дата проверки 27.09.2024).ОБЯЗАТЕЛЬНО снимаем тут галочку, чтобы патчи не слетали. Должно быть так, как на скрине.
3.2 Запуск GenP
После установки видим магазин приложений, где нам предлагают купить софт.Попробуем запустить GenP.
Он предлагает повысить привилегии GenP, чтобы нормально пропатчить XD и UWP-приложения. Откажемся.
Патчинг происходит таким образом:
- Патчим Adobe Creative Cloud, чтобы скачивать приложения - кнопка "Patch CC"
- Патчим отдельные приложения - кнопки "Search" и "Patch".
Нажмём "Patch CC".
Все приложения Adobe CC закрываются. Выводится лог патча: какой файл патчится и что в нём ищется/заменяется - это первая/вторая строка после названия файла. Попробуем запустить Adobe CC.
Появилась возможность скачивать любое приложение, как будто у нас есть подписка. Скачаем и запустим Adobe Audition для теста.
Нас просят купить подписку. Вернёмся в GenP и выполним поиск.
Пропатчим. Перед этим желательно закрыть Audition.
Нам вывелся лог патча. Попробуем запустить снова программу.
Теперь можем спокойно использовать софт. Также есть возможность заблокировать всплывающие окна (pop-up's). Adobe Illustrator также успешно патчится.
Более того, мы можем восстановить оригинальные файлы до патча через кнопку "Restore".
4.0 Разбираемся в исходном коде
Код представлен в виде скрипта для AutoIt.Читается как многие скриптовые языки вроде того же Python.
4.1 Начало скрипта
Первые две строчки кода указывают, что в трее не будет иконки от скрипта и то что он выполняется с правами админа.
Visual Basic:
#NoTrayIcon
#RequireAdmin
Затем идут настройки конкретно для AutoIT.
Visual Basic:
#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Icon=ICONS/Logo.ico
#AutoIt3Wrapper_Outfile_x64=GenP-3.4.14.1.exe
#AutoIt3Wrapper_Res_Comment=GenP v3.4.14.1
#AutoIt3Wrapper_Res_Description=GenP v3.4.14.1
#AutoIt3Wrapper_Res_Fileversion=3.4.14.1
#AutoIt3Wrapper_Res_ProductName=GenP v3.4.14.1
#AutoIt3Wrapper_Res_ProductVersion=3.4.14.1
#AutoIt3Wrapper_Res_CompanyName=GenP
#AutoIt3Wrapper_Res_LegalCopyright=GenP
#AutoIt3Wrapper_Res_LegalTradeMarks=GenP
#AutoIt3Wrapper_Res_requestedExecutionLevel=asInvoker
#AutoIt3Wrapper_Run_Au3Stripper=y
#Au3Stripper_Parameters=/pe /sf /sv /rm
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
#NoTrayIcon
- отключает иконку в системном трее для этого скрипта.#RequireAdmin
- требует права администратора для выполнения скрипта.#AutoIt3Wrapper_Icon=ICONS/Logo.ico
- задает иконку для исполняемого файла.#AutoIt3Wrapper_Outfile_x64=GenP-3.4.14.1.exe
- указывает имя выходного файла для 64-битной системы.#AutoIt3Wrapper_Res_*
- различные настройки ресурсов, такие как комментарии, описание, версия файла и продукта, имя компании, авторские права и торговые марки.#AutoIt3Wrapper_Res_requestedExecutionLevel=asInvoker
- устанавливает уровень выполнения для исполняемого файла (в данном случае, как вызывающий).#AutoIt3Wrapper_Run_Au3Stripper=y
- включает использование Au3Stripper, инструмента для уменьшения размера скрипта.#Au3Stripper_Parameters=/pe /sf /sv /rm
- параметры для Au3Stripper, которые включают удаление комментариев, пустых строк и других ненужных элементов.
Visual Basic:
#include <ProgressConstants.au3>
#include <WindowsConstants.au3>
#include <GUIConstantsEx.au3>
#include <EditConstants.au3>
#include <GuiListView.au3>
#include <WinAPIProc.au3>
#include <Constants.au3>
#include <String.au3>
#include <WinAPI.au3>
#include <Misc.au3>
Далее небольшой блок кода:
Visual Basic:
AutoItSetOption("GUICloseOnESC", 0) ;1=ESC closes, 0=ESC won't close
Global Const $g_AppWndTitle = "GenP v3.4.14.1", $g_AppVersion = "Original version by uncia/CGP - GenP Community Edition - v3.4.14.1"
If _Singleton($g_AppWndTitle, 1) = 0 Then
Exit
EndIf
Первая строка указывает, что при нажатии ESC окно программы не будет закрываться. Вторая строка указывает заголовок приложения и дополнительную информацию о приложении.
Блок
if
служит для запуска только одного экземпляра приложения.Затем объявляются глобальные переменные:
Visual Basic:
Global $MyLVGroupIsExpanded = True
Global $fInterrupt = 0
Global $FilesToPatch[0][1], $FilesToPatchNull[0][1]
Global $FilesToRestore[0][1], $fFilesListed = 0
Global $MyhGUI, $hTab, $hMainTab, $hLogTab, $idMsg, $idListview, $g_idListview, $idButtonSearch, $idButtonStop
Global $idButtonCustomFolder, $idBtnCure, $idBtnDeselectAll, $ListViewSelectFlag = 1
Global $idBtnBlockPopUp, $idBtnPatchCC, $idMemo, $timestamp, $idLog, $idBtnRestore, $idBtnCopyLog
Далее идёт проверка наличия
config.ini
. Если его нет, то он создаётся по указанному пути.
Visual Basic:
Global $sINIPath = @ScriptDir & "\config.ini"
If Not FileExists($sINIPath) Then
FileInstall("config.ini", @ScriptDir & "\config.ini")
EndIf
Этот конфиг-файл выглядит так:
Часть контента скрыл, чтобы скрин поместился на экран. Этот файл важен для работы патчера, так как содержит названия файлов, что будет искать патчер, сами патчи и указания, какие конкретно патчи к чему применяются.
- Секция
[Default]
:- Содержит ключ Path, который указывает путь по умолчанию до папки с программами Adobe.
- Секция
[TargetFiles]
:- Содержит список файлов, которые будет искать патчер.
- Секция
[DefaultPatterns]
:- Содержит ключ Values с набором имён применяемых патчей. Используется для тех программ, что нет в [CustomPatterns].
- Секция
[CustomPatterns]
:- Содержит ключи для различных файлов и их соответствующие имена патчей.
- Секция
[Patches]
:- Содержит ключи (имена патчей) и значения (сами патчи в виде искомых и заменяемых байт).
"C:\Program Files\Adobe"
. Также мы пишем этот путь в INI-файл.
Visual Basic:
Global $MyDefPath = IniRead($sINIPath, "Default", "Path", "C:\Program Files\Adobe")
If Not FileExists($MyDefPath) Or Not StringInStr(FileGetAttrib($MyDefPath), "D") Then
IniWrite($sINIPath, "Default", "Path", "C:\Program Files\Adobe")
$MyDefPath = "C:\Program Files\Adobe"
EndIf
Далее идёт работа с Nsudo - инструмент, позволяющий запускать процессы с правами System или TrustedInstaller. По описанию она нужна для корректной работы Adobe XD и приложений UWP.
Вот краткое объяснение функции:
Сначала происходит копирование файла
NSudoLG.exe
во временную директорию (обычно C:\Users\<Имя_Пользователя>\AppData\Local\Temp
). Далее проверка.Если скрипт не запущен от имени
SYSTEM
и файл NSudoLG.exe
существует:Выводится диалоговое окно с вопросом о повышении привилегий до TrustedInstaller.
Если пользователь соглашается, скрипт перезапускается с повышенными привилегиями.
Если условия не выполнены:Проверяется существование директории
"C:\Windows\System32\config\systemprofile\Desktop"
. Нужна для нормальной работы приложений, чьи привилегии были повышены.Если директория не существует, она создаётся.
В конце удаление временного файла NSudoLG.exe
.Затем снова объявляются глобальные переменные:
Visual Basic:
Global $MyRegExpGlobalPatternSearchCount = 0, $Count = 0, $idProgressBar
Global $aOutHexGlobalArray[0], $aNullArray[0], $aInHexArray[0]
Global $MyFileToParse = "", $MyFileToParsSweatPea = "", $MyFileToParseEaclient = ""
Global $sz_type, $bFoundAcro32 = False, $bFoundLrARM = False, $bFoundCCARM = False, $bFoundPsARM = False, $bFoundGenericARM = False, $aSpecialFiles, $sSpecialFiles = "|"
Global $ProgressFileCountScale, $FileSearchedCount
Далее идёт код, что читает содержимое секций
TargetFiles
и CustomPatterns
из config.ini
.
Visual Basic:
Local $tTargetFileList_Adobe = IniReadSection($sINIPath, "TargetFiles")
Global $TargetFileList_Adobe[0]
If Not @error Then
ReDim $TargetFileList_Adobe[$tTargetFileList_Adobe[0][0]]
For $i = 1 To $tTargetFileList_Adobe[0][0]
$TargetFileList_Adobe[$i - 1] = StringReplace($tTargetFileList_Adobe[$i][1], '"', "")
Next
EndIf
;_ArrayDisplay($TargetFileList_Adobe, "TargetFileList_Adobe")
$aSpecialFiles = IniReadSection($sINIPath, "CustomPatterns")
;_ArrayDisplay($aSpecialFiles)
For $i = 1 To UBound($aSpecialFiles) - 1
$sSpecialFiles = $sSpecialFiles & $aSpecialFiles[$i][0] & "|"
Next
;MsgBox(0, "", $sSpecialFiles)
Тут есть даже отладочный код. Можно убрать комментарии и запустить скрипт с ним. Для дальнейшего понимания патчера важно запомнить, что:
$TargetFileList_Adobe
- TargetFiles
из конфига.$sSpecialFiles
- CustomPatterns
из конфига.Затем идёт блок кода для настройки GUI-части:
Visual Basic:
GUIRegisterMsg($WM_COMMAND, "WM_COMMAND")
MainGui()
Функция
MainGui
находится в самом скрипте и создает графический интерфейс для приложения: табы, ListView, кнопки для выбора пути, поиска, патчинга, блокировки всплывающих окон и восстановления файлов, а также прогресс-бар и лог активности.После этого идёт главный код в цикле
While 1
.4.2 Основной цикл патчера
Visual Basic:
$idMsg = GUIGetMsg()
Select
Case $idMsg = $GUI_EVENT_CLOSE
GUIDelete($MyhGUI)
Exit
Case $idMsg = $GUI_EVENT_RESIZED
ContinueCase
Case $idMsg = $GUI_EVENT_RESTORE
ContinueCase
Case $idMsg = $GUI_EVENT_MAXIMIZE
Local $iWidth
Local $aGui = WinGetPos($MyhGUI)
Local $aRect = _GUICtrlListView_GetViewRect($g_idListview)
If ($aRect[2] > $aGui[2]) Then
$iWidth = $aGui[2] - 75
Else
$iWidth = $aRect[2] - 25
EndIf
GUICtrlSendMsg($idListview, $LVM_SETCOLUMNWIDTH, 1, $iWidth)
Этот фрагмент настраивает закрытие окна, изменение его размера и максимизацию. Далее идёт обработка кнопки "Stop" в поиске.
Далее в коде будет обработка событий для кнопки "Search".
4.2.1. Обработчик кнопки поиска
В самом начале идёт настройка списка файлов (вListView
) под вывод и появление надписи, что нам нужно подождать:
Visual Basic:
Case $idMsg = $idButtonSearch
$fInterrupt = 0
GUICtrlSetState($idButtonSearch, $GUI_HIDE)
GUICtrlSetState($idButtonStop, $GUI_SHOW)
ToggleLog(0)
GUICtrlSetState($idBtnDeselectAll, 128)
GUICtrlSetState($idBtnBlockPopUp, 128)
GUICtrlSetState($idListview, 128)
GUICtrlSetState($idBtnCure, 128)
GUICtrlSetState($idButtonCustomFolder, 128)
GUICtrlSetState($idBtnPatchCC, 128)
;Search through all files and folders in directory and fill ListView
_GUICtrlListView_DeleteAllItems($g_idListview)
_GUICtrlListView_SetExtendedListViewStyle($idListview, BitOR($LVS_EX_FULLROWSELECT, $LVS_EX_GRIDLINES, $LVS_EX_DOUBLEBUFFER))
_GUICtrlListView_AddItem($idListview, "", 0)
_GUICtrlListView_AddItem($idListview, "", 1)
_GUICtrlListView_AddItem($idListview, "", 2)
_GUICtrlListView_AddItem($idListview, "", 2)
_GUICtrlListView_RemoveAllGroups($idListview)
_GUICtrlListView_InsertGroup($idListview, -1, 1, "", 1) ; Group 1
_GUICtrlListView_SetGroupInfo($idListview, 1, "Info", 1, $LVGS_COLLAPSIBLE)
_GUICtrlListView_AddSubItem($idListview, 0, "", 1)
_GUICtrlListView_AddSubItem($idListview, 1, "Preparing...", 1)
_GUICtrlListView_AddSubItem($idListview, 2, "", 1)
_GUICtrlListView_AddSubItem($idListview, 3, "Be patient, please.", 1)
_GUICtrlListView_SetItemGroupID($idListview, 0, 1)
_GUICtrlListView_SetItemGroupID($idListview, 1, 1)
_GUICtrlListView_SetItemGroupID($idListview, 2, 1)
_GUICtrlListView_SetItemGroupID($idListview, 3, 1)
_Expand_All_Click()
_GUICtrlListView_SetGroupInfo($idListview, 1, "Info", 1, $LVGS_COLLAPSIBLE)
Функция
_Expand_All_Click
самописная:
Visual Basic:
Func _Expand_All_Click()
Local $aInfo, $aCount = _GUICtrlListView_GetGroupCount($idListview) ; Group Count
If $aCount > 0 Then
; Change group information
For $i = 1 To 28
$aInfo = _GUICtrlListView_GetGroupInfo($idListview, $i)
_GUICtrlListView_SetGroupInfo($idListview, $i, $aInfo[0], $aInfo[1], $LVGS_NORMAL)
_GUICtrlListView_SetGroupInfo($idListview, $i, $aInfo[0], $aInfo[1], $LVGS_COLLAPSIBLE)
Next
EndIf
EndFunc ;==>_Expand_All_Click
Также есть обратная функция:
Visual Basic:
Func _Collapse_All_Click()
Local $aInfo, $aCount = _GUICtrlListView_GetGroupCount($idListview) ; Group Count
If $aCount > 0 Then
If $MyLVGroupIsExpanded = 1 Then
; Change group information
For $i = 1 To 28
$aInfo = _GUICtrlListView_GetGroupInfo($idListview, $i)
_GUICtrlListView_SetGroupInfo($idListview, $i, $aInfo[0], $aInfo[1], $LVGS_COLLAPSED)
Next
Else
_Expand_All_Click()
EndIf
$MyLVGroupIsExpanded = Not $MyLVGroupIsExpanded
EndIf
EndFunc ;==>_Collapse_All_Click
_Expand_All_Click
: Раскрывает все группы в ListView, делая их видимыми и сворачиваемыми._Collapse_All_Click
: Сворачивает все группы, если они были раскрыты, и наоборот, раскрывает все группы, если они были свернуты.Далее идут подготовительные блоки:
Visual Basic:
; Clear previous results
$FilesToPatch = $FilesToPatchNull
$FilesToRestore = $FilesToPatchNull
$timestamp = TimerInit()
Очищаем предыдущие результаты и настраиваем таймер. Затем идёт блок, что ищет файлы, считает их количество, настраивает прогресс-бар и некоторые переменные.
Visual Basic:
Local $FileCount
Local $aSize = DirGetSize($MyDefPath, $DIR_EXTENDED) ; extended mode
If UBound($aSize) >= 2 Then
$FileCount = $aSize[1]
$ProgressFileCountScale = 100 / $FileCount
$FileSearchedCount = 0
ProgressWrite(0)
RecursiveFileSearch($MyDefPath, 0, $FileCount) ;Search through all files and folders
Sleep(100)
ProgressWrite(0)
EndIf
Параметр
$MyDefPath
в этот момент содержит содержимое секции [Default]
из INI-файла:
INI:
[Default]
Path=C:\Program Files\Adobe
Функция
RecursiveFileSearch
самописная:
Visual Basic:
Func RecursiveFileSearch($INSTARTDIR, $DEPTH, $FileCount)
;_FileListToArrayEx
_GUICtrlListView_SetItemText($idListview, 1, "Searching for files.", 1)
;_GUICtrlListView_SetItemGroupID($idListview, 0, 1)
Local $RecursiveFileSearch_MaxDeep = 6
; Local $RecursiveFileSearch_WhenFoundRaiseToLevel = 0 ;0 to disable raising
If $DEPTH > $RecursiveFileSearch_MaxDeep Then Return
Local $STARTDIR = $INSTARTDIR & "\"
$FileSearchedCount += 1
Local $HSEARCH = FileFindFirstFile($STARTDIR & "*.*")
If @error Then Return
Local $NEXT, $IPATH, $isDir
While $fInterrupt = 0
$NEXT = FileFindNextFile($HSEARCH)
$FileSearchedCount += 1
If @error Then ExitLoop
$isDir = StringInStr(FileGetAttrib($STARTDIR & $NEXT), "D")
If $isDir Then
Local $targetDepth
$targetDepth = RecursiveFileSearch($STARTDIR & $NEXT, $DEPTH + 1, $FileCount)
; raise up in recursion to wanted level
;~ if ( $targetDepth > 0 ) and _
;~ ( $targetDepth < $DEPTH ) Then _
;~ Return $targetDepth
Else
$IPATH = $STARTDIR & $NEXT
Local $FileNameCropped
If (IsArray($TargetFileList_Adobe)) Then
For $AdobeFileTarget In $TargetFileList_Adobe
$FileNameCropped = StringSplit(StringLower($IPATH), StringLower($AdobeFileTarget), $STR_ENTIRESPLIT)
If @error <> 1 Then
If Not StringInStr($IPATH, ".bak") Then
;_ArrayAdd( $FilesToPatch, $DEPTH & " - " & $IPATH )
If StringInStr($IPATH, "Adobe") Or StringInStr($IPATH, "Acrobat") Then
If StringInStr($IPATH, "4.js") And Not StringInStr($IPATH, "UXP\com.adobe.ccx.start\js\4.js") Then
Return
EndIf
If StringInStr($IPATH, "manifest.json") And Not StringInStr($IPATH, "UXP\com.adobe.ccx.start\manifest.json") Then
Return
EndIf
_ArrayAdd($FilesToPatch, $IPATH)
EndIf
Else
_ArrayAdd($FilesToRestore, $IPATH)
EndIf
; File Found and stored - Quit search in current dir
;~ return $RecursiveFileSearch_WhenFoundRaiseToLevel
EndIf
Next
EndIf
EndIf
WEnd
;Lazy screenupdates
If 1 = Random(0, 10, 1) Then
MemoWrite(@CRLF & "Searching in " & $FileCount & " files" & @TAB & @TAB & "Found : " & UBound($FilesToPatch) & @CRLF & _
"---" & @CRLF & _
"Level: " & $DEPTH & " Time elapsed : " & Round(TimerDiff($timestamp) / 1000, 0) & " second(s)" & @TAB & @TAB & "Excluded because of *.bak: " & UBound($FilesToRestore) & @CRLF & _
"---" & @CRLF & _
$INSTARTDIR _
)
ProgressWrite($ProgressFileCountScale * $FileSearchedCount)
EndIf
FileClose($HSEARCH)
EndFunc ;==>RecursiveFileSearch
Она выполняет поиск файлов из
$TargetFileList_Adobe
(секция [TargetFiles]
в INI) и добавляет пути до них в массив $FilesToPatch
- файла для патчинга, которые нашлись из [TargetFiles]
. Также если где-то нашлись бекапы оригинальных файлов (с постфиксом .bak
), то они добавляются в $FilesToRestore
.Для теста можно добавить вывод массива в процессе работы.
Или так:
Также в логах выводится дополнительная информация.
Далее в обработчике кнопки поиска идёт блок, который также ищет файлы, но в заранее определённых директориях Adobe (по умолчанию). Оба блока нужны, чтобы обработать случаи, когда путь до файлов Adobe стандартный (по умолчанию) и кастомный.
Visual Basic:
If $MyDefPath = "C:\Program Files" Or $MyDefPath = "C:\Program Files\Adobe" Then
Local $sProgramFiles = EnvGet('ProgramFiles(x86)') & "\Common Files\Adobe"
$aSize = DirGetSize($sProgramFiles, $DIR_EXTENDED) ; extended mode
If UBound($aSize) >= 2 Then
$FileCount = $aSize[1]
RecursiveFileSearch($sProgramFiles, 0, $FileCount) ;Search through all files and folders
ProgressWrite(0)
EndIf
EndIf
Затем идёт вывод найденных файлов через самописную функцию
FillListViewWithFiles
:
Visual Basic:
Func FillListViewWithFiles()
_GUICtrlListView_DeleteAllItems($g_idListview)
_GUICtrlListView_SetExtendedListViewStyle($idListview, BitOR($LVS_EX_FULLROWSELECT, $LVS_EX_GRIDLINES, $LVS_EX_DOUBLEBUFFER, $LVS_EX_CHECKBOXES))
; Two column load
If UBound($FilesToPatch) > 0 Then
Global $aItems[UBound($FilesToPatch)][2]
For $i = 0 To UBound($aItems) - 1
$aItems[$i][0] = $i
$aItems[$i][1] = $FilesToPatch[$i][0]
Next
_GUICtrlListView_AddArray($idListview, $aItems)
MemoWrite(@CRLF & UBound($FilesToPatch) & " File(s) were found in " & Round(TimerDiff($timestamp) / 1000, 0) & " second(s) at:" & @CRLF & "---" & @CRLF & $MyDefPath & @CRLF & "---" & @CRLF & "Press the 'Patch Files'")
LogWrite(1, UBound($FilesToPatch) & " File(s) were found in " & Round(TimerDiff($timestamp) / 1000, 0) & " second(s)" & @CRLF)
;_ArrayDisplay($FilesToPatch)
$fFilesListed = 1
Else
MemoWrite(@CRLF & "Nothing was found in" & @CRLF & "---" & @CRLF & $MyDefPath & @CRLF & "---" & @CRLF & "waiting for user action")
LogWrite(1, "Nothing was found in " & $MyDefPath)
$fFilesListed = 0
EndIf
EndFunc ;==>FillListViewWithFiles
Информация выводится в логах. В конце обработчика кнопки будет настройка GUI-частей.
Также есть такие небольшие функции:
Visual Basic:
; Write a line to the memo control
Func MemoWrite($sMessage)
GUICtrlSetData($idMemo, $sMessage)
EndFunc ;==>MemoWrite
Func LogWrite($bTS, $sMessage)
GUICtrlSetDataEx($idLog, $sMessage, $bTS)
EndFunc ;==>LogWrite
Func ToggleLog($bShow)
If $bShow = 1 Then
GUICtrlSetState($idMemo, $GUI_HIDE)
GUICtrlSetState($idLog, $GUI_SHOW)
Else
GUICtrlSetState($idLog, $GUI_HIDE)
GUICtrlSetState($idMemo, $GUI_SHOW)
EndIf
EndFunc ;==>ToggleLog
Func SendToClipBoard()
If BitAND(GUICtrlGetState($idMemo), $GUI_HIDE) = $GUI_HIDE Then
ClipPut(GUICtrlRead($idLog))
Else
ClipPut(GUICtrlRead($idMemo))
EndIf
EndFunc ;==>SendToClipBoard
Краткое описание этих функций:
MemoWrite
записывает строку текста в элемент управленияMemo
(текстовое поле для многострочного ввода).LogWrite
записывает строку текста в элемент управленияLog
(журнал) со временной меткой к сообщению или без неё.ToggleLog
переключает видимость между элементами управленияMemo
иLog
.SendToClipBoard
копирует текст из видимого элемента управления (либоMemo
, либоLog
) в буфер обмена. Если элементMemo
скрыт, копируется текст изLog
, иначе копируется текст изMemo
.
GUICtrlSetDataEx
. Её код прилагается:
Visual Basic:
Func GUICtrlSetDataEx($hWnd, $sText, $bTS)
If Not IsHWnd($hWnd) Then $hWnd = GUICtrlGetHandle($hWnd)
Local $iLength = DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", $hWnd, "uint", 0x000E, "wparam", 0, "lparam", 0)
DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", $hWnd, "uint", 0xB1, "wparam", $iLength[0], "lparam", $iLength[0]) ; $EM_SETSEL
If $bTS = 1 Then
Local $iData = @CRLF & @YEAR & "-" & @MON & "-" & @MDAY & " " & @HOUR & ":" & @MIN & ":" & @SEC & "." & @MSEC & " " & $sText
Else
Local $iData = $sText
EndIf
DllCall("user32.dll", "lresult", "SendMessageW", "hwnd", $hWnd, "uint", 0xC2, "wparam", True, "wstr", $iData) ; $EM_REPLACESEL
EndFunc ;==>GUICtrlSetDataEx
Она выполняет запись текста в элемент управления (например, текстовое поле) с возможностью добавления временной метки.
4.2.2. Обработчик кнопки выбора папки
Далее идёт обработчик выбора своей папки с программами Adobe вместо стандартной.
Visual Basic:
Case $idMsg = $idButtonCustomFolder ; Select Custom Path
ToggleLog(0)
MyFileOpenDialog()
_Expand_All_Click()
If $fFilesListed = 0 Then
GUICtrlSetState($idBtnCure, 128)
GUICtrlSetState($idBtnDeselectAll, 128)
GUICtrlSetState($idButtonSearch, 64)
GUICtrlSetState($idButtonSearch, 256) ; Set focus
Else
GUICtrlSetState($idButtonSearch, 128)
GUICtrlSetState($idBtnDeselectAll, 64)
GUICtrlSetState($idBtnCure, 64)
GUICtrlSetState($idBtnCure, 256) ; Set focus
EndIf
Функция
MyFileOpenDialog
самописная.
Visual Basic:
Func MyFileOpenDialog()
; Create a constant variable in Local scope of the message to display in FileOpenDialog.
Local Const $sMessage = "Select a Path"
; Display an open dialog to select a file.
FileSetAttrib("C:\Program Files\WindowsApps", "-H")
Local $MyTempPath = FileSelectFolder($sMessage, $MyDefPath, 0, $MyDefPath, $MyhGUI)
If @error Then
; Display the error message.
;MsgBox($MB_SYSTEMMODAL, "", "No folder was selected.")
FileSetAttrib("C:\Program Files\WindowsApps", "+H")
MemoWrite(@CRLF & "Path" & @CRLF & "---" & @CRLF & $MyDefPath & @CRLF & "---" & @CRLF & "waiting for user action")
Else
GUICtrlSetState($idBtnCure, 128)
$MyDefPath = $MyTempPath
IniWrite($sINIPath, "Default", "Path", $MyDefPath)
_GUICtrlListView_DeleteAllItems($g_idListview)
_GUICtrlListView_SetExtendedListViewStyle($idListview, BitOR($LVS_EX_GRIDLINES, $LVS_EX_FULLROWSELECT, $LVS_EX_SUBITEMIMAGES))
_GUICtrlListView_AddItem($idListview, "", 0)
_GUICtrlListView_AddItem($idListview, "", 1)
_GUICtrlListView_AddItem($idListview, "", 2)
_GUICtrlListView_AddItem($idListview, "", 3)
_GUICtrlListView_AddItem($idListview, "", 4)
_GUICtrlListView_AddItem($idListview, "", 5)
_GUICtrlListView_AddItem($idListview, "", 6)
_GUICtrlListView_AddSubItem($idListview, 0, "", 1)
_GUICtrlListView_AddSubItem($idListview, 1, "Path:", 1)
_GUICtrlListView_AddSubItem($idListview, 2, " " & $MyDefPath, 1)
_GUICtrlListView_AddSubItem($idListview, 3, "Step 1:", 1)
_GUICtrlListView_AddSubItem($idListview, 4, " Press 'Search Files' - wait until GenP finds all files", 1)
_GUICtrlListView_AddSubItem($idListview, 5, "Step 2:", 1)
_GUICtrlListView_AddSubItem($idListview, 6, " Press 'Patch Files' - wait until GenP will do it's job", 1)
_GUICtrlListView_SetItemGroupID($idListview, 0, 1)
_GUICtrlListView_SetItemGroupID($idListview, 1, 1)
_GUICtrlListView_SetItemGroupID($idListview, 2, 1)
_GUICtrlListView_SetItemGroupID($idListview, 3, 1)
_GUICtrlListView_SetItemGroupID($idListview, 4, 1)
_GUICtrlListView_SetItemGroupID($idListview, 5, 1)
_GUICtrlListView_SetItemGroupID($idListview, 6, 1)
_GUICtrlListView_SetGroupInfo($idListview, 1, "Info", 1, $LVGS_COLLAPSIBLE)
FileSetAttrib("C:\Program Files\WindowsApps", "+H")
MemoWrite(@CRLF & "Path" & @CRLF & "---" & @CRLF & $MyDefPath & @CRLF & "---" & @CRLF & "Press the Search button")
; Display the selected folder.
;MsgBox($MB_SYSTEMMODAL, "", "You chose the following folder:" & @CRLF & $MyDefPath)
GUICtrlSetState($idBtnBlockPopUp, $GUI_SHOW)
GUICtrlSetState($idBtnRestore, $GUI_HIDE)
$fFilesListed = 0
EndIf
EndFunc ;==>MyFileOpenDialog
Она отображает диалоговое окно для выбора папки и снимает скрытый атрибут с папки
C:\Program Files\WindowsApps
. Если папка выбрана, обновляет путь, сохраняет его в INI-файле, очищает и обновляет ListView
с новыми элементами, восстанавливает скрытый атрибут и выводит сообщение с инструкцией.4.2.3. Обработчик кнопки выбора/отмены всех элементов
Затем идёт обработчик для выбора или отмены выбора всех элементов:
Visual Basic:
Case $idMsg = $idBtnDeselectAll ; Deselect-Select All
ToggleLog(0)
If $ListViewSelectFlag = 1 Then
For $i = 0 To _GUICtrlListView_GetItemCount($idListview) - 1
_GUICtrlListView_SetItemChecked($idListview, $i, 0)
Next
$ListViewSelectFlag = 0 ; Set Flag to Deselected State
Else
For $i = 0 To _GUICtrlListView_GetItemCount($idListview) - 1
_GUICtrlListView_SetItemChecked($idListview, $i, 1)
Next
$ListViewSelectFlag = 1 ; Set Flag to Selected State
EndIf
4.2.4. Обработчик кнопки Pop-up
Следующий обработчик для кнопки "Pop-up":
Visual Basic:
Case $idMsg = $idBtnBlockPopUp ; Pop-up button
ToggleLog(0)
BlockPopUp()
Функцию
BlockPopUp
нам нужно разобрать.
Visual Basic:
Func BlockPopUp()
GUICtrlSetState($hLogTab, $GUI_SHOW)
GUICtrlSetState($idBtnBlockPopUp, 128)
MemoWrite(@CRLF & "Checking for an active internet connection..." & @CRLF & "" & @CRLF & "")
Local $sCmdInfo = """C:\Windows\System32\WindowsPowerShell\v1.0\PowerShell.exe"" -Command ""Test-Connection 8.8.8.8 -Count 1 -Quiet"""
Local $iPID = Run($sCmdInfo, "", @SW_HIDE, BitOR($STDERR_CHILD, $STDOUT_CHILD))
Local $sOutput = ""
While 1
$sOutput &= StdoutRead($iPID)
If @error Then ExitLoop
WEnd
ProcessWaitClose($iPID)
If StringReplace($sOutput, @CRLF, "") = "True" Then
Тут происходит настройка GUI и проверка наличия интернет-соединения через Powershell-команду:
Bash:
Test-Connection 8.8.8.8 -Count 1 -Quiet
Она вернёт нам True, если интернет есть.
Затем идёт блок кода для разрешения IP-адресов доменов
adobe.io
и 3u6k9as4bj.adobestats.io
.
Visual Basic:
If StringReplace($sOutput, @CRLF, "") = "True" Then
MemoWrite(@CRLF & "Resolving ip-addresses..." & @CRLF & "" & @CRLF & "")
$sCmdInfo = ; Powershell-скрипт
$iPID = Run($sCmdInfo, "", @SW_HIDE, BitOR($STDERR_CHILD, $STDOUT_CHILD))
$sOutput = ""
While 1
$sOutput &= StdoutRead($iPID)
If @error Then ExitLoop
WEnd
ProcessWaitClose($iPID)
If StringInStr($sOutput, "False") Then
MemoWrite(@CRLF & "Failed to resolve ip-addresses, try using a VPN..." & @CRLF & "" & @CRLF & "")
Sleep(2000)
Else
...
Разрешение IP-адресов (или "резолвинг" IP-адресов) — это процесс преобразования доменного имени (например,
example.com
) в его соответствующий IP-адрес (например, 101.34.200.8
).В функции выполняется PowerShell-скрипт для разрешения IP-адресов доменов
adobe.io
и 3u6k9as4bj.adobestats.io
:- Читается вывод скрипта в переменную
$sOutput
. - Если в выводе содержится "False", записывает сообщение о неудаче в журнал и предлагает использовать VPN.
- Иначе добавляется правило в брандмауэр Windows для блокировки IP-адресов. Это разберём далее.
Bash:
$currentDate = Get-Date
$ipAddresses = @()
try {
$SOA = (Resolve-DnsName -Name adobe.io -Type SOA -ErrorAction Stop).PrimaryServer
} catch {
$SOA = $null
}
if ($SOA) {
Do {
if ((New-TimeSpan -Start $currentDate -End (Get-Date)).TotalSeconds -gt 5) {
if ($ipAddresses.Count -eq 0) {
$ipAddresses += 'False'
}
break
}
try {
$ipAddress = (Resolve-DnsName -Name adobe.io -Server $SOA -ErrorAction Stop).IPAddress
} catch {
$ipAddress = $null
}
if ($ipAddress) {
$ipAddresses += $ipAddress
}
$ipAddresses = $ipAddresses | Select -Unique | Sort-Object
} While ($ipAddresses.Count -lt 8)
} else {
$ipAddresses += 'False'
}
Do {
if ((New-TimeSpan -Start $currentDate -End (Get-Date)).TotalSeconds -gt 5 -or $ipAddresses[0] -eq 'False') {
break
}
try {
$ipAddress = (Resolve-DnsName -Name 3u6k9as4bj.adobestats.io -ErrorAction Stop).IPAddress
} catch {
$ipAddress = $null
}
if ($ipAddress) {
$ipAddresses += $ipAddress
}
$ipAddresses = $ipAddresses | Select -Unique | Sort-Object
} While ($ipAddresses.Count -lt 12 -and $ipAddresses[0] -ne 'False')
$ipAddresses = $ipAddresses -ne 'False' | Select -Unique | Sort-Object
$ipAddressList = if ($ipAddresses.Count -eq 0) { 'False' } else { $ipAddresses -join ',' }
$ipAddressList
Скрипт определяет авторитетный сервер (SOA) для домена
adobe.io
. Затем собирает уникальные IP-адреса для доменов adobe.io
и 3u6k9as4bj.adobestats.io
.В итоге мы получим список уникальных IP-адресов такого вида:
Код:
107.22.247.231,18.207.85.246,23.22.254.206...
Затем идёт блок Else, что добавляет правило в брандмауэр Windows для блокировки IP-адресов:
Visual Basic:
If StringInStr($sOutput, "False") Then
MemoWrite(@CRLF & "Failed to resolve ip-addresses, try using a VPN..." & @CRLF & "" & @CRLF & "")
Sleep(2000)
Else
MemoWrite(@CRLF & "Adding Windows Firewall rule..." & @CRLF & "" & @CRLF & "")
$sCmdInfo = "netsh advfirewall firewall delete rule name=""Adobe Unlicensed Pop-up"""
$iPID = Run($sCmdInfo, "", @SW_HIDE, BitOR($STDERR_CHILD, $STDOUT_CHILD))
ProcessWaitClose($iPID)
$sCmdInfo = "netsh advfirewall firewall add rule name=""Adobe Unlicensed Pop-up"" dir=out action=block remoteip=""" & StringReplace($sOutput, @CRLF, "") & """"
$iPID = Run($sCmdInfo, "", @SW_HIDE, BitOR($STDERR_CHILD, $STDOUT_CHILD))
ProcessWaitClose($iPID)
EndIf
Данный код удаляет старое правило в брандмауэре, если оно было:
Bash:
netsh advfirewall firewall delete rule name="Adobe Unlicensed Pop-up"
Затем уже добавляет своё:
Bash:
netsh advfirewall firewall add rule name="Adobe Unlicensed Pop-up" dir=out action=block remoteip="..."
Вместо "..." подставятся IP из прошлого ps-скрипта. Получим команду подобного вида:
Bash:
netsh advfirewall firewall add rule name="Adobe Unlicensed Pop-up" dir=out action=block
remoteip="107.22.247.231,18.207.85.246,23.22.254.206..."
Далее идёт блок кода, что работает с файлом
hosts
.
Visual Basic:
MemoWrite(@CRLF & "Blocking Hosts..." & @CRLF & "" & @CRLF & "")
$sCmdInfo = ; Powershell-скрипт
$iPID = Run($sCmdInfo, "", @SW_HIDE, $STDOUT_CHILD)
$sOutput = ""
While 1
$sLine = StdoutRead($iPID)
If @error Then ExitLoop
$sOutput &= $sLine
WEnd
If StringInStr($sOutput, "Script execution complete.") Then
MemoWrite(@CRLF & "All Hosts blocked." & @CRLF & "" & @CRLF & "")
Else
MemoWrite(@CRLF & "Failed to block Hosts, try using a VPN..." & @CRLF & "" & @CRLF & "")
EndIf
Тут снова используется Powershell-скрипт:
Bash:
try {
if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Write-Host 'Script execution failed...'
return
}
$hostsPath = 'C:\Windows\System32\drivers\etc\hosts'
$bakPath = $hostsPath + '.bak'
if (-not (Test-Path $bakPath)) {
Copy-Item -Path $hostsPath -Destination $bakPath
}
$webContent = (Invoke-RestMethod -Uri 'https://a.dove.isdumb.one/list.txt' -UseBasicParsing).Split($([char]0x0A)) | ForEach-Object { $_.Trim() }
$currentHostsContent = Get-Content -Path $hostsPath
$startMarker = '# <GenP>'
$endMarker = '# </GenP>'
$blockStart = $currentHostsContent.IndexOf($startMarker)
$blockEnd = $currentHostsContent.IndexOf($endMarker)
if ($blockStart -eq -1 -or $blockEnd -eq -1) {
$currentHostsContent += $startMarker
$currentHostsContent += $endMarker
$blockStart = $currentHostsContent.IndexOf($startMarker)
$blockEnd = $currentHostsContent.IndexOf($endMarker)
}
$newBlock = @($startMarker) + $webContent + $endMarker
$newHostsContent = $currentHostsContent[0..($blockStart - 1)] + $newBlock + $currentHostsContent[($blockEnd + 1)..$currentHostsContent.Length]
Set-Content -Path $hostsPath -Value $newHostsContent
Write-Host 'Script execution complete.'
} catch {
Write-Host 'Script execution failed...'
}
Данный скрипт выполняет предварительные действия:
- Проверка наличие прав администратора. Если нет, то завершает выполнение.
- Создание резервной копии файла
hosts
:C:\Windows\System32\drivers\etc\hosts.bak
- Загрузка файла
https://a.dove.isdumb.one/list.txt
и разделяет загруженный контент по строкам и удаляет пробелы в начале и конце каждой строки.
list.txt
можно взять из этого репозитория: GitHub - ignaciocastro/a-dove-is-dumb: Easily block Adobe telemetry checking domains. Continuously Updated. Useful for HostsMan / SwitchHosts / Pi-hole users А далее происходит работа с файлом
hosts
. Мы записываем содержимое list.txt
между строками <GenP>
.До выполнения скрипта:
Код:
127.0.0.1 localhost
После:
Код:
127.0.0.1 localhost
# <GenP>
# Данные из list.txt
# </GenP>
Таким образом, функция
BlockPopUp
просто добавляет правила в брандмауэр и записи в файл hosts
. Теперь настало время самого интересного - начинаем разбор патчинга Creative Cloud и программ Adobe.4.2.5. Обработчик кнопки "Patch CC" и как работает эта магия
Обработкой кнопки "Patch CC" занимается вот этот обработчик:
Visual Basic:
Case $idMsg = $idBtnPatchCC ; Patch Creative Cloud button
Global $appsPanelFile
Global $containerBLFile
Global $adobeDesktopServiceFile
...
Первое, что патчит код - это
AppsPanelBL.dll
.
Visual Basic:
If FileExists("C:\Program Files\Common Files\Adobe\Adobe Desktop Common\AppsPanel\AppsPanelBL.dll") Then
$appsPanelFile = "C:\Program Files\Common Files\Adobe\Adobe Desktop Common\AppsPanel\AppsPanelBL.dll"
ElseIf FileExists("C:\Program Files (x86)\Common Files\Adobe\Adobe Desktop Common\AppsPanel\AppsPanelBL.dll") Then
$appsPanelFile = "C:\Program Files (x86)\Common Files\Adobe\Adobe Desktop Common\AppsPanel\AppsPanelBL.dll"
Else
$appsPanelFile = FileOpenDialog("Select a File", @ScriptDir, "AppsPanelBL.dll (AppsPanelBL.dll)")
EndIf
ProgressWrite(0)
If FileExists($appsPanelFile) Then
MyGlobalPatternSearch($appsPanelFile)
Sleep(100)
MemoWrite(@CRLF & "File Path:" & @CRLF & "" & @CRLF & $appsPanelFile & @CRLF & "" & @CRLF & "")
Sleep(100)
MyGlobalPatternPatch($appsPanelFile, $aOutHexGlobalArray)
Sleep(500)
EndIf
Выполняется проверка на существование файла. А затем в нём ищутся паттерны, которые будут взяты из INI-файла через
MyGlobalPatternSearch
.
Visual Basic:
Func MyGlobalPatternSearch($MyFileToParse)
;ConsoleWrite($MyFileToParse & @CRLF)
$aInHexArray = $aNullArray ; Nullifay Array that will contain Hex later
$aOutHexGlobalArray = $aNullArray ; Nullifay Array that will contain Hex later
ProgressWrite(0)
$MyRegExpGlobalPatternSearchCount = 0
$Count = 15
Local $sFileName = StringRegExpReplace($MyFileToParse, "^.*\\", "")
Local $sExt = StringRegExpReplace($sFileName, "^.*\.", "")
MemoWrite(@CRLF & $MyFileToParse & @CRLF & "---" & @CRLF & "Preparing to Analyze" & @CRLF & "---" & @CRLF & "*****")
LogWrite(1, "Checking File: " & $sFileName & " ")
;MsgBox($MB_SYSTEMMODAL,"","$sFileName = " & $sFileName & @CRLF & "$sExt = " & $sExt)
If $sExt = "exe" Then
_ProcessCloseEx("""" & $sFileName & """")
EndIf
If $sFileName = "AppsPanelBL.dll" Or $sFileName = "ContainerBL.dll" Or $sFileName = "Adobe Desktop Service.exe" Then
_ProcessCloseEx("""Creative Cloud.exe""")
_ProcessCloseEx("""Adobe Desktop Service.exe""")
Sleep(100)
EndIf
If StringInStr($sSpecialFiles, $sFileName) Then
;MsgBox($MB_SYSTEMMODAL, "", "Special File: " & $sFileName)
LogWrite(0, " - using Custom Patterns")
ExecuteSearchPatterns($sFileName, 0, $MyFileToParse)
Else
LogWrite(0, " - using Default Patterns")
ExecuteSearchPatterns($sFileName, 1, $MyFileToParse)
;MsgBox($MB_SYSTEMMODAL, "", "File: " & $sFileName & @CRLF & "Not in Special Files")
EndIf
Sleep(100)
EndFunc ;==>MyGlobalPatternSearch
Функции передаётся путь до файла. Затем из него извлекается:
- Имя файла вместе с расширением;
- Отдельно расширение файла.
Visual Basic:
If $sExt = "exe" Then
_ProcessCloseEx("""" & $sFileName & """")
EndIf
If $sFileName = "AppsPanelBL.dll" Or $sFileName = "ContainerBL.dll" Or $sFileName = "Adobe Desktop Service.exe" Then
_ProcessCloseEx("""Creative Cloud.exe""")
_ProcessCloseEx("""Adobe Desktop Service.exe""")
Sleep(100)
EndIf
Затем закрываются процессы Creative Cloud, чтобы успешно пропатчить нужный файл. В конце функции вызывается
ExecuteSearchPatterns
в зависимости от того, есть ли искомый файл в $sSpecialFiles
- это секция [CustomPatterns]
в INI-файле.Для дальнейшего понимания патчера важно запомнить, что:
$TargetFileList_Adobe
- TargetFiles
из конфига.$sSpecialFiles
- CustomPatterns
из конфига.Если такой файл есть, то вызывается
ExecuteSearchPatterns($sFileName, 0, $MyFileToParse)
.Иначе -
ExecuteSearchPatterns($sFileName, 1, $MyFileToParse)
.Сейчас как раз разберём её.
Visual Basic:
Func ExecuteSearchPatterns($FileName, $DefaultPatterns, $MyFileToParse)
Local $aPatterns, $sPattern, $sData, $aArray, $sSearch, $sReplace, $iPatternLength
If $DefaultPatterns = 0 Then
$aPatterns = IniReadArray($sINIPath, "CustomPatterns", $FileName, "")
Else
$aPatterns = IniReadArray($sINIPath, "DefaultPatterns", "Values", "")
EndIf
;_ArrayDisplay($aPatterns, "Patterns for " & $FileName)
For $i = 0 To UBound($aPatterns) - 1
$sPattern = $aPatterns[$i]
$sData = IniRead($sINIPath, "Patches", $sPattern, "")
If StringInStr($sData, "|") Then
$aArray = StringSplit($sData, "|")
If UBound($aArray) = 3 Then
$sSearch = StringReplace($aArray[1], '"', '')
$sReplace = StringReplace($aArray[2], '"', '')
$iPatternLength = StringLen($sSearch)
If $iPatternLength <> StringLen($sReplace) Or Mod($iPatternLength, 2) <> 0 Then
MsgBox($MB_SYSTEMMODAL, "Error", "Pattern Error in config.ini:" & $sPattern & @CRLF & $sSearch & @CRLF & $sReplace)
Exit
EndIf
;MsgBox(0,0, $MyFileToParse & @CRLF & $sSearch & @CRLF & $aReplace & @CRLF & $sPattern )
LogWrite(1, "Searching for: " & $sPattern & ": " & $sSearch)
MyRegExpGlobalPatternSearch($MyFileToParse, $sSearch, $sReplace, $sPattern)
;Exit ; STOP AT FIRST VALUE - COMMENT OUT TO CONTINUE
EndIf
;Exit
EndIf
Next
EndFunc ;==>ExecuteSearchPatterns
$FileName
- имя файла$DefaultPatterns
- 1 или 0 (True или False)$MyFileToParse
- путь до файлаЕсли передаётся 0, то используется
[CustomPatterns]
. Иначе - [DefaultPatterns]
. Затем начинается основной цикл, где происходит обработка данных из INI-файла и передача в MyRegExpGlobalPatternSearch
.4.2.5.1. Весь цикл поиска и патчинга кратко
Рассмотрим работу всего цикла поиска и патчинга, забегая немного вперёд. Посмотрим на INI-файл:
INI:
...
[DefaultPatterns]
Values="ProfileExpired1","ProfileExpired3","ProfileExpired4","ProfileExpired5","ProfileExpired6","ValidateLicense1","ValidateLicense2","ValidateLicense3","CmpEax61","CmpEax62","CmpEax63","CmpEax64","Profile1","Profile2","Banner1","Banner2","InstantShutdown1"
[CustomPatterns]
Acrobat.dll="Acrobat3","Acrobat5"
acrodistdll.dll="Acrodist2","Acrodist3","Acrodist4","Acrodist5","AcroRegistry1","AcroNew1"
acrotray.exe="AcroTray2","AcroTray3","AcroTray4","AcroTray5","AcroRegistry1","AcroNew1"
AppsPanelBL.dll="CreativeCloud1","CreativeCloud2"
ContainerBL.dll="CreativeCloud3"
...
[Patches]
CreativeCloud1="8378????0F84????????8378????0F84????????8378????0F84????????33C0"|"C640????0F84????????C640????0F84????????C640????0F84????????33C0"
CreativeCloud2="E8????????85C00F85????????83EC??8BCC89"|"E8????????FEC00F85????????83EC??8BCC89"
CreativeCloud3="??????0F85890300"|"??????E98A030000"
Acrobat1="488BCFE8????????85C00F84????????488D??????????488BCFE8????????85C075??8D"|"488BCFE8????????FFC00F84????????488D??????????488BCFE8????????31C075??8D"
Acrobat2="6685C0740FE8????????6685C07405BB01000000"|"6685C07400E8????????6685C07400BB01000000"
Acrobat3="6685C0741A6685??0F85??020000"|"6685C090906685??0F85??020000"
...
В секции
[CustomPatterns]
есть ключи, имена которых - это имена файлов для патчинга. У имён-файлов (ключей) есть значения. Значения используются в секции [Patches]
, которая содержит байты для поиска и патчинга.Например, если патчится файл
AppsPanelBL.dll
, то используются патчи "CreativeCloud1"
,"CreativeCloud2"
(из-за прямого указания в строке AppsPanelBL.dll="CreativeCloud1","CreativeCloud2"
):В секции патчей это будет:
INI:
CreativeCloud1="8378????0F84????????8378????0F84????????8378????0F84????????33C0"|"C640????0F84????????C640????0F84????????C640????0F84????????33C0"
CreativeCloud2="E8????????85C00F85????????83EC??8BCC89"|"E8????????FEC00F85????????83EC??8BCC89"
Байты для поиска и замены разделены символов
|
. Для CreativeCloud1
будут искаться байты "8378????0F84????????8378????0F84????????8378????0F84????????33C0"
, а заменой им будет "C640????0F84????????C640????0F84????????C640????0F84????????33C0"
.Затем поиск и замена будут выполнены для
CreativeCloud2
. До знаков вопроса в патчах мы сейчас дойдём. Для понимания нам нужно изучить MyRegExpGlobalPatternSearch
. Вот так она вызывается в MyRegExpGlobalPatternSearch
:
Visual Basic:
MyRegExpGlobalPatternSearch($MyFileToParse, $sSearch, $sReplace, $sPattern)
$MyFileToParse
- путь до файла$sSearch
- байты, которые ищутся (до символа | в секции с патчами)$sReplace
- байты, на которые произойдёт замена (после символа | в секции с патчами)$sPattern
- значение ключа из набора в секции [CustomPatterns]
(CreativeCloud1
, CreativeCloud2
и другие).Функция
MyRegExpGlobalPatternSearch
:
Visual Basic:
Func MyRegExpGlobalPatternSearch($FileToParse, $PatternToSearch, $PatternToReplace, $PatternName) ; Path to a file to parse
;MsgBox($MB_SYSTEMMODAL, "Path", $FileToParse)
;ConsoleWrite($FileToParse & @CRLF)
Local $hFileOpen = FileOpen($FileToParse, $FO_READ + $FO_BINARY)
FileSetPos($hFileOpen, 60, 0)
$sz_type = FileRead($hFileOpen, 4)
FileSetPos($hFileOpen, Number($sz_type) + 4, 0)
$sz_type = FileRead($hFileOpen, 2)
If $sz_type = "0x4C01" And StringInStr($FileToParse, "Acrobat", 2) > 0 Then ; Acrobat x86 won't work with this script
MemoWrite(@CRLF & $FileToParse & @CRLF & "---" & @CRLF & "File is 32bit. Aborting..." & @CRLF & "---")
FileClose($hFileOpen)
Sleep(100)
$bFoundAcro32 = True
ElseIf $sz_type = "0x64AA" Then ; AArch64 (ARM64) and ~~AArch32 (ARM32) architectures~~ (big-endian). only exist as photoshop, lightroom, and ccdesktop at time of writing
If StringInStr($FileToParse, "Lightroom", 2) > 0 Then ; Lightroom ARM
MemoWrite(@CRLF & $FileToParse & @CRLF & "---" & @CRLF & "Lightroom is ARM. Aborting..." & @CRLF & "---")
FileClose($hFileOpen)
Sleep(100)
$bFoundLrARM = True
ElseIf StringInStr($FileToParse, "AppsPanelBL.dll", 2) Or StringInStr($FileToParse, "ContainerBL.dll", 2) Or StringInStr($FileToParse, "Adobe Desktop Service.exe", 2) > 0 Then ; CC Desktop ARM
MemoWrite(@CRLF & $FileToParse & @CRLF & "---" & @CRLF & "Creative Cloud is ARM. Aborting..." & @CRLF & "---")
FileClose($hFileOpen)
Sleep(100)
$bFoundCCARM = True
ElseIf StringInStr($FileToParse, "Photoshop", 2) > 0 Then ; Photoshop ARM
MemoWrite(@CRLF & $FileToParse & @CRLF & "---" & @CRLF & "Photoshop is ARM. Aborting..." & @CRLF & "---")
FileClose($hFileOpen)
Sleep(100)
$bFoundPsARM = True
Else ; Other ARM
MemoWrite(@CRLF & $FileToParse & @CRLF & "---" & @CRLF & "File is ARM. Aborting..." & @CRLF & "---")
FileClose($hFileOpen)
Sleep(100)
$bFoundGenericARM = True
EndIf
Else
FileSetPos($hFileOpen, 0, 0)
Local $sFileRead = FileRead($hFileOpen)
Local $GeneQuestionMark, $AnyNumOfBytes, $OutStringForRegExp
For $i = 256 To 1 Step -2 ; limiting to 256 -?-
$GeneQuestionMark = _StringRepeat("??", $i / 2) ; Repeat the string -??- $i/2 times.
$AnyNumOfBytes = "(.{" & $i & "})"
$OutStringForRegExp = StringReplace($PatternToSearch, $GeneQuestionMark, $AnyNumOfBytes)
$PatternToSearch = $OutStringForRegExp
Next
Local $sSearchPattern = $OutStringForRegExp ;string
Local $aReplacePattern = $PatternToReplace ;string
Local $sWildcardSearchPattern = "", $sWildcardReplacePattern = "", $sFinalReplacePattern = ""
Local $aInHexTempArray[0]
Local $sSearchCharacter = "", $sReplaceCharacter = ""
$aInHexTempArray = $aNullArray
$aInHexTempArray = StringRegExp($sFileRead, $sSearchPattern, $STR_REGEXPARRAYGLOBALFULLMATCH, 1)
For $i = 0 To UBound($aInHexTempArray) - 1
$aInHexArray = $aNullArray
$sSearchCharacter = ""
$sReplaceCharacter = ""
$sWildcardSearchPattern = ""
$sWildcardReplacePattern = ""
$sFinalReplacePattern = ""
$aInHexArray = $aInHexTempArray[$i]
;_ArrayDisplay($aInHexArray)
If @error = 0 Then
$sWildcardSearchPattern = $aInHexArray[0] ; full founded Search Pattern index 0
$sWildcardReplacePattern = $aReplacePattern
;MsgBox(-1,"",$sWildcardSearchPattern & @CRLF & $sWildcardReplacePattern) ; full search and full patch with ?? symbols
If StringInStr($sWildcardReplacePattern, "?") Then
;MsgBox($MB_SYSTEMMODAL, "Found ? symbol", "Constructing new Replace string")
For $j = 1 To StringLen($sWildcardReplacePattern) + 1
; Retrieve a characters from the $jth position in each string.
$sSearchCharacter = StringMid($sWildcardSearchPattern, $j, 1)
$sReplaceCharacter = StringMid($sWildcardReplacePattern, $j, 1)
If $sReplaceCharacter <> "?" Then
$sFinalReplacePattern &= $sReplaceCharacter
Else
$sFinalReplacePattern &= $sSearchCharacter
EndIf
Next
Else
$sFinalReplacePattern = $sWildcardReplacePattern
EndIf
_ArrayAdd($aOutHexGlobalArray, $sWildcardSearchPattern)
_ArrayAdd($aOutHexGlobalArray, $sFinalReplacePattern)
ConsoleWrite($PatternName & "---" & @TAB & $sWildcardSearchPattern & " " & @CRLF)
ConsoleWrite($PatternName & "R" & "--" & @TAB & $sFinalReplacePattern & " " & @CRLF)
MemoWrite(@CRLF & $FileToParse & @CRLF & "---" & @CRLF & $PatternName & @CRLF & "---" & @CRLF & $sWildcardSearchPattern & @CRLF & $sFinalReplacePattern)
LogWrite(1, "Replacing with: " & $sFinalReplacePattern)
Else
ConsoleWrite($PatternName & "---" & @TAB & "No" & " " & @CRLF)
MemoWrite(@CRLF & $FileToParse & @CRLF & "---" & @CRLF & $PatternName & "---" & "No")
EndIf
$MyRegExpGlobalPatternSearchCount += 1
Next
FileClose($hFileOpen)
$sFileRead = ""
ProgressWrite(Round($MyRegExpGlobalPatternSearchCount / $Count * 100))
Sleep(100)
EndIf ;==>If $sz_type = "0x4C01"
EndFunc ;==>MyRegExpGlobalPatternSearch
Первое, что проверяет функция - патчим ли мы Adobe Acrobat с архитектурой x32. Если да, то функция завершается, так как скрипт не может обработать такой случай. Далее проверяется, используем ли мы файл с архитектурой ARM. Если да, то снова завершение функции. GenP рассчитан в основном на x64.
Далее функция читает файл, путь до которого был ей передан, и находит точные байты в нём (без знаков ?), добавляя их в массив
$aOutHexGlobalArray
:
Visual Basic:
_ArrayAdd($aOutHexGlobalArray, $sWildcardSearchPattern)
_ArrayAdd($aOutHexGlobalArray, $sFinalReplacePattern)
В первый элемент массива будут добавлены точные байты, которые были найдены в файле.
Во второй элемент массива будут добавлены точные байты, на которые произойдёт замена.
Функция заменяет знаки
??
на байты из самого файла, чтобы получились "точные байты". Забегая вперёд, потом благодаря массиву $aOutHexGlobalArray
функция MyGlobalPatternPatch
просто пропатчит точные искомые байты на точные заменяемые. Но перед этим создаст резервную копию.Рассмотрим схематично замену байтов в файле. Значения
CreativeCloud1
для файла AppsPanelBL.dll
:
INI:
CreativeCloud1="8378????0F84????????8378????0F84????????8378????0F84????????33C0"|"C640????0F84????????C640????0F84????????C640????0F84????????33C0"
Более понятная запись:
INI:
"8378????0F84????????8378????0F84????????8378????0F84????????33C0" ; байты, которые ищем
"C640????0F84????????C640????0F84????????C640????0F84????????33C0" ; байты, на которые заменяем
2 знака вопроса выступают в роли одного любого байта, который не будет изменён. Или по-другому это часть регулярного выражения. Отсюда и Reg в названии функции.
INI:
"83 78 ?? ?? 0F 84 ?? ?? ?? ?? 83 78 ?? ?? 0F 84 ..." ; байты, которые ищем
"C6 40 ?? ?? 0F 84 ?? ?? ?? ?? C6 40 ?? ?? 0F 84..." ; байты, на которые заменяем
Вот так записано более понятно. Функция
MyRegExpGlobalPatternSearch
сделает из вопросов точные байты:
INI:
"83 78 FF FF 0F 84 FF FF FF FF 83 78 FF FF 0F 84 ..." ; байты, которые ищем
"C6 40 FF FF 0F 84 FF FF FF FF C6 40 FF FF 0F 84..." ; байты, на которые заменяем
Для примера представим, что в самом файле на месте вопросов были байты 0xFF.
Байт 0x83 заменится на 0xC6,
Байт 0x78 заменится на 0x40,
Байт 0xFF заменится на 0xFF,
Байт 0xFF заменится на 0xFF,
Байт 0x0F заменится на 0x0F,
Байт 0x84 заменится на 0x84,
и так далее
4.2.5.2. Вернёмся к обработчику кнопки "Patch CC"
Теперь снова вернёмся к обработчику нажатия кнопки "Patch CC".
Visual Basic:
If FileExists("C:\Program Files\Common Files\Adobe\Adobe Desktop Common\AppsPanel\AppsPanelBL.dll") Then
$appsPanelFile = "C:\Program Files\Common Files\Adobe\Adobe Desktop Common\AppsPanel\AppsPanelBL.dll"
ElseIf FileExists("C:\Program Files (x86)\Common Files\Adobe\Adobe Desktop Common\AppsPanel\AppsPanelBL.dll") Then
$appsPanelFile = "C:\Program Files (x86)\Common Files\Adobe\Adobe Desktop Common\AppsPanel\AppsPanelBL.dll"
Else
$appsPanelFile = FileOpenDialog("Select a File", @ScriptDir, "AppsPanelBL.dll (AppsPanelBL.dll)")
EndIf
ProgressWrite(0)
If FileExists($appsPanelFile) Then
MyGlobalPatternSearch($appsPanelFile)
Sleep(100)
MemoWrite(@CRLF & "File Path:" & @CRLF & "" & @CRLF & $appsPanelFile & @CRLF & "" & @CRLF & "")
Sleep(100)
MyGlobalPatternPatch($appsPanelFile, $aOutHexGlobalArray)
Sleep(500)
EndIf
После того как вызов
MyGlobalPatternSearch
пропатчит файл, запустится функция MyGlobalPatternPatch
.
Visual Basic:
Func MyGlobalPatternPatch($MyFileToPatch, $MyArrayToPatch)
;MsgBox($MB_SYSTEMMODAL, "", $MyFileToPatch)
;_ArrayDisplay($MyArrayToPatch)
ProgressWrite(0)
;MemoWrite("Current path" & @CRLF & "---" & @CRLF & $MyFileToPatch & @CRLF & "---" & @CRLF & "medication :)")
Local $iRows = UBound($MyArrayToPatch) ; Total number of rows
MsgBox(0, "q", $MyArrayToPatch)
MsgBox(0, "q", $iRows)
If $iRows > 0 Then
MemoWrite(@CRLF & "Path" & @CRLF & "---" & @CRLF & $MyFileToPatch & @CRLF & "---" & @CRLF & "medication :)")
Local $hFileOpen = FileOpen($MyFileToPatch, $FO_READ + $FO_BINARY)
Local $sFileRead = FileRead($hFileOpen)
Local $sStringOut
For $i = 0 To $iRows - 1 Step 2
MsgBox(0, "q", $MyArrayToPatch[$i])
MsgBox(0, "q", $MyArrayToPatch[$i+1])
$sStringOut = StringReplace($sFileRead, $MyArrayToPatch[$i], $MyArrayToPatch[$i + 1], 0, 1)
$sFileRead = $sStringOut
$sStringOut = $sFileRead
ProgressWrite(Round($i / $iRows * 100))
Next
;MsgBox($MB_SYSTEMMODAL, "", "binary: " & Binary($sStringOut))
FileClose($hFileOpen)
FileMove($MyFileToPatch, $MyFileToPatch & ".bak", $FC_OVERWRITE)
Local $hFileOpen1 = FileOpen($MyFileToPatch, $FO_OVERWRITE + $FO_BINARY)
FileWrite($hFileOpen1, Binary($sStringOut))
FileClose($hFileOpen1)
ProgressWrite(0)
Sleep(100)
;MemoWrite1(@CRLF & "---" & @CRLF & "Waitng for your command :)" & @CRLF & "---")
LogWrite(1, "File patched." & @CRLF)
Else
;Empty array - > no search-replace patterns
;File is already patched or no patterns were found .
MemoWrite(@CRLF & "No patterns were found" & @CRLF & "---" & @CRLF & "or" & @CRLF & "---" & @CRLF & "file is already patched.")
Sleep(100)
LogWrite(1, "No patterns were found or file already patched." & @CRLF)
EndIf
;Sleep(100)
;MemoWrite2("***")
EndFunc ;==>MyGlobalPatternPatch
Данная функция открывает файл и благодаря глобальному массиву
$aOutHexGlobalArray
ищет точные байты в файле и заменяет их на точные нужные. Передачу этого массива, как аргумента, можно найти в обработчике. Перед записью изменения создаётся бекап файла с расширением .bak
, чтобы в случае чего его можно было бы восстановить. Таким образом, MyGlobalPatternSearch
и все функции, что вызываются внутри неё, ищут точные байты в файле для замены и на основе них создают точные байты, на которые произойдёт замена. Саму замену байтов выполняет MyGlobalPatternPatch
. Связаны 2 эти функции через $aOutHexGlobalArray
.Таким образом, во всём обработчике "Patch CC" прослеживается общий шаблон:
Код:
1. Проверка, существует ли обрабатываемый файл в Program Files (x86) или в Program Files. Иначе выбираем сами.
2. Функцией MyGlobalPatternSearch ищутся точные исходные и заменяемые байты и записываются в глобальный массив $aOutHexGlobalArray.
3. Функция MyGlobalPatternPatch использует $aOutHexGlobalArray и заменяет точные искомые байты на точные заменяемые. Также создаёт бекап исходного файла.
В коде это:
Visual Basic:
If FileExists("C:\Program Files\Common Files\Adobe\Adobe Desktop Common\AppsPanel\AppsPanelBL.dll") Then
$appsPanelFile = "C:\Program Files\Common Files\Adobe\Adobe Desktop Common\AppsPanel\AppsPanelBL.dll"
ElseIf FileExists("C:\Program Files (x86)\Common Files\Adobe\Adobe Desktop Common\AppsPanel\AppsPanelBL.dll") Then
$appsPanelFile = "C:\Program Files (x86)\Common Files\Adobe\Adobe Desktop Common\AppsPanel\AppsPanelBL.dll"
Else
$appsPanelFile = FileOpenDialog("Select a File", @ScriptDir, "AppsPanelBL.dll (AppsPanelBL.dll)")
EndIf
ProgressWrite(0)
If FileExists($appsPanelFile) Then
MyGlobalPatternSearch($appsPanelFile)
Sleep(100)
MemoWrite(@CRLF & "File Path:" & @CRLF & "" & @CRLF & $appsPanelFile & @CRLF & "" & @CRLF & "")
Sleep(100)
MyGlobalPatternPatch($appsPanelFile, $aOutHexGlobalArray)
Sleep(500)
EndIf
ProgressWrite(0)
If $bFoundCCARM = False Then
If FileExists("C:\Program Files\Common Files\Adobe\Adobe Desktop Common\ADS\ContainerBL.dll") Then
$containerBLFile = "C:\Program Files\Common Files\Adobe\Adobe Desktop Common\ADS\ContainerBL.dll"
ElseIf FileExists("C:\Program Files (x86)\Common Files\Adobe\Adobe Desktop Common\ADS\ContainerBL.dll") Then
$containerBLFile = "C:\Program Files (x86)\Common Files\Adobe\Adobe Desktop Common\ADS\ContainerBL.dll"
Else
$containerBLFile = FileOpenDialog("Select a File", @ScriptDir, "ContainerBL.dll (ContainerBL.dll)")
EndIf
ProgressWrite(0)
If FileExists($containerBLFile) Then
MyGlobalPatternSearch($containerBLFile)
Sleep(100)
MemoWrite(@CRLF & "File Path:" & @CRLF & "" & @CRLF & $containerBLFile & @CRLF & "" & @CRLF & "")
Sleep(100)
MyGlobalPatternPatch($containerBLFile, $aOutHexGlobalArray)
Sleep(500)
EndIf
ProgressWrite(0)
If FileExists("C:\Program Files\Common Files\Adobe\Adobe Desktop Common\ADS\Adobe Desktop Service.exe") Then
$adobeDesktopServiceFile = "C:\Program Files\Common Files\Adobe\Adobe Desktop Common\ADS\Adobe Desktop Service.exe"
ElseIf FileExists("C:\Program Files (x86)\Common Files\Adobe\Adobe Desktop Common\ADS\Adobe Desktop Service.exe") Then
$adobeDesktopServiceFile = "C:\Program Files (x86)\Common Files\Adobe\Adobe Desktop Common\ADS\Adobe Desktop Service.exe"
Else
$adobeDesktopServiceFile = FileOpenDialog("Select a File", @ScriptDir, "Adobe Desktop Service.exe (Adobe Desktop Service.exe)")
EndIf
If FileExists($adobeDesktopServiceFile) Then
MyGlobalPatternSearch($adobeDesktopServiceFile)
Sleep(100)
MemoWrite(@CRLF & "File Path:" & @CRLF & "" & @CRLF & $adobeDesktopServiceFile & @CRLF & "" & @CRLF & "")
Sleep(100)
MyGlobalPatternPatch($adobeDesktopServiceFile, $aOutHexGlobalArray)
Sleep(500)
EndIf
ProgressWrite(0)
MemoWrite(@CRLF & "All files patched." & @CRLF & "" & @CRLF & "")
Кроме этого проверяется, что мы не используем ARM-версии файлов. Ну и всё пишется в лог
Теперь посмотрим, какие именно изменения вносятся. Как мы узнали, меняются эти файлы:
Код:
C:\Program Files\Common Files\Adobe\Adobe Desktop Common\AppsPanel\AppsPanelBL.dll
C:\Program Files\Common Files\Adobe\Adobe Desktop Common\ADS\ContainerBL.dll
C:\Program Files\Common Files\Adobe\Adobe Desktop Common\ADS\Adobe Desktop Service.exe
Вместо
Program Files
может быть Program Files (x86)
. У меня как раз этот случай. Патчинг этих файлов позволяет скачивать платные программы Adobe из Creative Cloud.До патча:
После патча:
Экспериментально у себя я выяснил, что для достижения такого результата обязательно нужно пропатчить
ContainerBL.dll
и AppsPanelBL.dll
. Вероятно, патчинг Adobe Desktop Service.exe
нужен для подстраховки.4.2.5.3. Сравниваем пропатченные байты с оригинальными и ищем их
Мы сравним файл до патча и после патча. Я буду делать это через IDA. Но сначала нужно найти точные байты.Это можно сделать этой утилитой на C++:
C++:
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <sstream>
#include <iomanip>
#include <exception>
#include <locale>
struct Pattern {
std::string name;
std::vector<std::pair<std::string, std::string>> patterns;
};
// Функция для парсинга паттернов
std::vector<Pattern> parsePatterns() {
std::vector<Pattern> patterns = {
{"CreativeCloud1", {{"8378????0F84????????8378????0F84????????8378????0F84????????33C0", "C640????0F84????????C640????0F84????????C640????0F84????????33C0"}}},
{"CreativeCloud2", {{"E8????????85C00F85????????83EC??8BCC89", "E8????????FEC00F85????????83EC??8BCC89"}}},
{"CreativeCloud3", {{"??????0F85890300", "??????E98A030000"}}},
{"Acrobat1", {{"488BCFE8????????85C00F84????????488D??????????488BCFE8????????85C075??8D", "488BCFE8????????FFC00F84????????488D??????????488BCFE8????????31C075??8D"}}},
{"Acrobat2", {{"6685C0740FE8????????6685C07405BB01000000", "6685C07400E8????????6685C07400BB01000000"}}},
{"Acrobat3", {{"6685C0741A6685??0F85??020000", "6685C090906685??0F85??020000"}}},
{"Acrobat4", {{"00E8????E7FF66893D??????03381D??????03751F4533C0488D15??????02488D0D??????02E8????E7FF6685C00F84BAFEFFFF8BDFE9B3FEFFFFB801000000", "00E8????E7FF66893D??????03381D??????03EB1F4533C0488D15??????02488D0D??????02E8????E7FF6685C00F84BAFEFFFF8BDFE9B3FEFFFFB801000000"}}},
{"Acrobat5", {{"753FE8????????6685C0740933C9E8????????EB25488D05????????48894424204C8D0D????????33D2448D423C488D0D??????00E8????????66893D????????381D????????75", "EB3FE8????????6685C0740933C9E8????????EB25488D05????????48894424204C8D0D????????33D2448D423C488D0D??????00E8????????66893D????????381D????????EB"}}},
{"Acrodist1", {{"85C00F84????????E8????????85C00F85????????E8", "85C00F84????????E8????????FFC00F85????????E8"}}},
{"Acrodist2", {{"00908BC8E8??????00CCCCCCCCCCCC48895C24104889", "00908BC8E8??????00CCCCCCCCCCCC31C0C324104889"}}},
{"Acrodist3", {{"5E5B5DC3CCCCCCCCCCCCCCCCCCCCCCCCCCCCCC4055535657415441554156415748", "5E5B5DC3CCCCCCCCCCCCCCCCCCCCCCCCCCCCCC31C0C35657415441554156415748"}}},
{"Acrodist4", {{"00005072696E745F447269766572", "0000B001906E745F447269766572"}}},
{"Acrodist5", {{"51??????????????????????????????48895C????????????????????????55", "51??????????????????????????????33C0C3????????????????????????55"}}},
{"AcroNew1", {{"C3488BC1C3CC48895C24084889??2410", "C3488BC1C3CCC3895C24084889??2410"}}},
{"AcroRegistry1", {{"0FB6C3488B5C2458????????????????895C", "B801000000909090????????????????895C"}}},
{"AcroTray1", {{"E8????????84C074??E8????????84C075??33DB", "E8????????FEC074??E8????????FEC075??33DB"}}},
{"AcroTray2", {{"0F8459030000803D??????00000F8545030000", "E95A03000090803D??????0000E94603000090"}}},
{"AcroTray3", {{"0F85A302000048397C24400F84", "E9A40200009048397C24400F85"}}},
{"AcroTray4", {{"244884DB0F84C70100", "244884DB0F85C70100"}}},
{"AcroTray5", {{"????????E86791D9FFE862B2D8FF????", "????????9090909090B801000000????"}}},
{"DesktopService1", {{"68008B40148985CCFEFFFF85C0", "68008B40148985CCFEFFFF33C0"}}},
{"Banner1", {{"72656C6174696F6E7368697050726F66696C65", "78656C6174696F6E7368697050726F66696C65"}}},
{"Banner2", {{"000000000000000072656C6174696F6E", "000000000000000078656C6174696F6E"}}},
{"BridgeCamRaw1", {{"84C074??8B??83??0174??83??0174??83??01", "84C074??8B??83??01EB??83??0174??83??01"}}},
{"BridgeCamRaw2", {{"4084??0F85????????4084??0F84", "4084??0F85????????40FEC60F85"}}},
{"CmpEax61", {{"8B??85C074??83F80674????83????007D", "C7??0300000083F8067400??83????00EB"}}},
{"CmpEax62", {{"8B??85C074??83F80674????83??????007D", "C7??0300000083F8067400??83??????00EB"}}},
{"CmpEax63", {{"8B????85C074??83F80674????83????007D", "C7????0300000083F8067400??83????00EB"}}},
{"CmpEax64", {{"8B????85C074??83F80674????83??????007D", "C7????0300000083F8067400??83??????00EB"}}},
{"HevcMpegEnabler1", {{"FF50100FB6", "FFC0900FB6"}}},
{"HevcMpegEnabler2", {{"FF5010??0FB6", "FFC090??0FB6"}}},
{"HevcMpegEnabler3", {{"FF50??0FB6", "FFC0900FB6"}}},
{"HevcMpegEnabler4", {{"FF50????0FB6", "FFC090??0FB6"}}},
{"Profile1", {{"00007504488D4850", "00007500488D4850"}}},
{"Profile2", {{"00007504488D5050", "00007500488D5050"}}},
{"ProfileExpired1", {{"85C075??????????75??B892010000E9", "31C075004883FF0F7500B800000000E9"}}},
{"ProfileExpired2", {{"85C075??B892010000E9", "85C07500B800000000E9"}}},
{"ProfileExpired3", {{"85C075????????75??B892010000E9", "31C075????????7500B800000000E9"}}},
{"ProfileExpired4", {{"488D4D??483B??0F??????000048????4889??4885C9", "488D4D??483B??C700000000004831C94889??4885C9"}}},
{"ProfileExpired5", {{"488B0B4889034885C974??BA04000000E8????????B00148", "C7000000000048890348C7C1000000000F1F440000B00148"}}},
{"ProfileExpired6", {{"4885C974??BA04000000E8????????4C8D5C", "C700000000004889034831C90F1F004C8D5C"}}},
{"TeamProjectEnabler1", {{"488379????740A488379????7403B001C332C0C3", "488379????740A488379????7403B001C3B001C3"}}},
{"ValidateLicense1", {{"83F80175??BA94010000", "83F80175??BA00000000"}}},
{"ValidateLicense2", {{"83F8040F95C281C293010000", "83F8040F95C2BA0000000090"}}},
{"ValidateLicense3", {{"83F8040F95C181C193010000", "83F8040F95C1B90000000090"}}},
{"InstantShutdown1", {{"00??????????E875000000????????C0", "00??????????9090909090????????C0"}}},
{"PluginVerification1", {{"5F5E????????????????????????????48895C2410??8974", "5F5E????????????????????????????C390909090??8974"}}},
{"LoginVerification1", {{"4C8B??????????????????????????????????????742C48", "4C8B??????????????????????????????????????EB2C48"}}},
{"JS1", {{"52656C6174696F6E7368697050726F66696C653A612E??2E6F7074696F6E616C", "58656C6174696F6E7368697050726F66696C653A612E??2E6F7074696F6E616C"}}},
{"JS2", {{"52656C6174696F6E7368697050726F66696C652E66696E6428653D3E652E75736564466F724C656761637950726F66696C65293B72657475726E20692E6D61696E53746F7265", "58656C6174696F6E7368697050726F66696C652E66696E6428653D3E652E75736564466F724C656761637950726F66696C65293B72657475726E20692E6D61696E53746F7265"}}},
{"JS3", {{"52656C6174696F6E7368697050726F66696C652E66696E6428653D3E652E75736564466F724C656761637950726F66696C65297D7D2929", "58656C6174696F6E7368697050726F66696C652E66696E6428653D3E652E75736564466F724C656761637950726F66696C65297D7D2929"}}},
{"JS4", {{"52656C6174696F6E7368697050726F66696C65297C7C766F696420303D3D3D69", "58656C6174696F6E7368697050726F66696C65297C7C766F696420303D3D3D69"}}},
{"Version", {{"6363782E7374617274222C0A20202276657273696F6E223A2022372E", "6363782E7374617274222C0A20202276657273696F6E223A2022392E"}}}
};
return patterns;
}
// Функция для преобразования паттерна в байтовый массив и маску
void parseHexPattern(const std::string& pattern, std::vector<uint8_t>& bytes, std::vector<uint8_t>& mask) {
for (size_t i = 0; i < pattern.size(); i += 2) {
if (pattern[i] == '?' || pattern[i+1] == '?') {
bytes.push_back(0);
mask.push_back(0);
} else {
std::string byteString = pattern.substr(i, 2);
try {
uint8_t byte = static_cast<uint8_t>(std::stoi(byteString, nullptr, 16));
bytes.push_back(byte);
mask.push_back(0xFF);
} catch (const std::invalid_argument& e) {
std::cerr << "Invalid pattern: " << byteString << std::endl;
throw;
}
}
}
}
// Функция для поиска паттерна в файле
bool matchPattern(const std::vector<uint8_t>& data, const std::vector<uint8_t>& pattern, const std::vector<uint8_t>& mask, size_t pos) {
for (size_t i = 0; i < pattern.size(); ++i) {
if ((data[pos + i] & mask[i]) != (pattern[i] & mask[i])) {
return false;
}
}
return true;
}
bool searchAndPrintPattern(const std::vector<uint8_t>& data, const std::vector<uint8_t>& pattern, const std::vector<uint8_t>& mask, const std::string& patternType, bool& headerPrinted, const std::string& patternName) {
bool found = false;
for (size_t i = 0; i <= data.size() - pattern.size(); ++i) {
if (matchPattern(data, pattern, mask, i)) {
if (!headerPrinted) {
std::cout << "<========= " << patternName << " =========>" << std::endl;
headerPrinted = true;
}
found = true;
std::cout << patternType << ": ";
std::cout << std::hex << std::setfill('0');
for (size_t j = 0; j < pattern.size(); ++j) {
std::cout << std::setw(2) << static_cast<int>(data[i + j]) << " ";
}
std::cout << std::endl;
}
}
return found;
}
int main(int argc, char* argv[]) {
setlocale(LC_ALL, "Rus");
if (argc < 2) {
std::cerr << "Использование: " << argv[0] << " <файл>" << std::endl;
return 1;
}
std::ifstream file(argv[1], std::ios::binary);
if (!file.is_open()) {
std::cerr << "Не получается открыть файл: " << argv[1] << std::endl;
return 1;
}
std::vector<uint8_t> data((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
auto patterns = parsePatterns();
for (const auto& pattern : patterns) {
bool anyFound = false;
bool headerPrinted = false;
for (const auto& [searchPattern, replacePattern] : pattern.patterns) {
std::vector<uint8_t> searchBytes, searchMask;
parseHexPattern(searchPattern, searchBytes, searchMask);
std::vector<uint8_t> replaceBytes, replaceMask;
parseHexPattern(replacePattern, replaceBytes, replaceMask);
if (searchAndPrintPattern(data, searchBytes, searchMask, "Искомый ", headerPrinted, pattern.name)) {
anyFound = true;
}
if (searchAndPrintPattern(data, replaceBytes, replaceMask, "Заменяемый", headerPrinted, pattern.name)) {
anyFound = true;
}
}
if (anyFound) {
std::cout << std::endl;
}
}
return 0;
}
Пример запуска:
Код:
C:\Users\fff\Desktop>search.exe AppsPanelBL.dll
<========= CreativeCloud1 =========>
Искомый : 83 78 2c 00 0f 84 95 01 00 00 83 78 44 00 0f 84 8b 01 00 00 83 78 5c 00 0f 84 81 01 00 00 33 c0
<========= CreativeCloud2 =========>
Искомый : e8 76 47 10 00 85 c0 0f 85 9d 00 00 00 83 ec 18 8b cc 89
Искомый : e8 01 a9 0e 00 85 c0 0f 85 8f 02 00 00 83 ec 18 8b cc 89
Искомый : e8 09 b7 02 00 85 c0 0f 85 1f 02 00 00 83 ec 18 8b cc 89
Искомый : e8 83 fd ff ff 85 c0 0f 85 bd 04 00 00 83 ec 18 8b cc 89
Искомый : e8 f2 f7 ff ff 85 c0 0f 85 74 01 00 00 83 ec 18 8b cc 89
Искомый : e8 ef f5 ff ff 85 c0 0f 85 76 02 00 00 83 ec 18 8b cc 89
Искомый : e8 cf f2 ff ff 85 c0 0f 85 76 02 00 00 83 ec 18 8b cc 89
<========= CreativeCloud3 =========>
Искомый : ff 84 c0 0f 85 89 03 00
Искомый : ff 84 c0 0f 85 89 03 00
Искомый : 74 24 38 0f 85 89 03 00
Заменяемый: ff 32 c0 e9 8a 03 00 00
Заменяемый: 0a 01 00 e9 8a 03 00 00
Только иногда она находит лишние байты. Но нам нужно искать только те, что патчатся. Для
AppsPanelBL.dll
это будет CreativeCloud1
и CreativeCloud2
. На CreativeCloud3
просто не смотрим.
INI:
AppsPanelBL.dll="CreativeCloud1","CreativeCloud2"
Далее файл нужно открыть в IDA, нажать ALT+B и ввести первые 5-10 найденных байт:
Нажимаем 2 раза на запись.
Попали сюда. Теперь отобразим опкоды инструкций.
Таким образом можно сравнивать файлы до патча и после. Так мы посмотрим, как поменяются инструкции.
Так как GenP делает бекапы (.bak), то можно сравнивать бекапы с пропатченными файлами.
C:\Program Files\Common Files\Adobe\Adobe Desktop Common\ADS\Adobe Desktop Service.exe
DesktopService1
Слева я буду располагать файл до патча, а справа после. Если хотите перейти в режим листинга IDA (как на скрине), нажмите пробел. И снова в настройках включите отображение опкодов.
C:\Program Files\Common Files\Adobe\Adobe Desktop Common\AppsPanel\AppsPanelBL.dll
CreativeCloud1
CreativeCloud2
C:\Program Files\Common Files\Adobe\Adobe Desktop Common\ADS\ContainerBL.dll
CreativeCloud3
Проанализировав различия между этими файлами, видим, что ничего вредоносного в них он не добавляет. Просто меняет ход выполнения программы. Где-то через замену инструкций условных переходов, где-то через замену инструкций перед ними. Можно даже сделать всё это вручную и получить тот же результат.
Далее нам нужно будет рассмотреть, как работает обработчик патчинга файлов самих программ Adobe. Но перед этим рассмотрим обработчик кнопки восстановления оригинального файла - "Restore".
4.2.6. Обработчик кнопки "Restore"
Она появляется, если после поиска файлов для патча (кнопка "Search") мы выберем какой-либо или какие-либо из них, и есть файл.bak
для выбранного.Начало его обработчика:
Visual Basic:
Case $idMsg = $idBtnRestore
GUICtrlSetData($idLog, "Activity Log" & @CRLF)
ToggleLog(0)
GUICtrlSetState($idListview, 128)
GUICtrlSetState($idBtnDeselectAll, 128)
GUICtrlSetState($idButtonSearch, 128)
GUICtrlSetState($idBtnCure, 128)
Основная функция там - это
RestoreFile
:
Visual Basic:
If _GUICtrlListView_GetItemChecked($idListview, $i) = True Then
_GUICtrlListView_SetItemSelected($idListview, $i)
$ItemFromList = _GUICtrlListView_GetItemText($idListview, $i, 1)
$iCheckedItems = _GUICtrlListView_GetSelectedCount($idListview)
$iProgress = 100 / $iCheckedItems
ProgressWrite(0)
RestoreFile($ItemFromList)
ProgressWrite($iProgress)
Sleep(100)
MemoWrite(@CRLF & "Path" & @CRLF & "---" & @CRLF & $ItemFromList & @CRLF & "---" & @CRLF & "restoring :)")
Sleep(100)
; Scroll control 10 pixels - 1 line
_GUICtrlListView_Scroll($idListview, 0, 10)
_GUICtrlListView_EnsureVisible($idListview, $i, 0)
Sleep(100)
EndIf
Этой функции передаётся путь до файла. Её код:
Visual Basic:
Func RestoreFile($MyFileToDelete)
If FileExists($MyFileToDelete & ".bak") Then
FileDelete($MyFileToDelete)
FileMove($MyFileToDelete & ".bak", $MyFileToDelete, $FC_OVERWRITE)
Sleep(100)
MemoWrite(@CRLF & "File restored" & @CRLF & "---" & @CRLF & $MyFileToDelete)
LogWrite(1, $MyFileToDelete)
LogWrite(1, "File restored.")
Else
Sleep(100)
MemoWrite(@CRLF & "No backup file found" & @CRLF & "---" & @CRLF & $MyFileToDelete)
LogWrite(1, $MyFileToDelete)
LogWrite(1, "No backup file found.")
EndIf
EndFunc ;==>RestoreFile
Тут всё просто
Удаляем пропатченный файл и переименовываем
.bak-файл
в файл без постфикса .bak
. Конечно же, если бекап этого файла существует.4.2.7. Обработчик кнопки "Patch"
Ну а теперь переходим к обработчику кнопки "Patch", что доступна после "Search".
Visual Basic:
Case $idMsg = $idBtnCure
ToggleLog(0)
GUICtrlSetState($idListview, 128)
GUICtrlSetState($idBtnDeselectAll, 128)
GUICtrlSetState($idButtonSearch, 128)
GUICtrlSetState($idBtnCure, 128)
GUICtrlSetState($idBtnBlockPopUp, 128)
GUICtrlSetState($idBtnRestore, 128)
GUICtrlSetState($idButtonCustomFolder, 128)
GUICtrlSetState($idBtnPatchCC, 128)
_Expand_All_Click()
_GUICtrlListView_EnsureVisible($idListview, 0, 0)
...
Это начало кода функции.
Visual Basic:
For $i = 0 To _GUICtrlListView_GetItemCount($idListview) - 1
If _GUICtrlListView_GetItemChecked($idListview, $i) = True Then
_GUICtrlListView_SetItemSelected($idListview, $i)
$ItemFromList = _GUICtrlListView_GetItemText($idListview, $i, 1)
MyGlobalPatternSearch($ItemFromList)
ProgressWrite(0)
Sleep(100)
MemoWrite(@CRLF & "Path" & @CRLF & "---" & @CRLF & $ItemFromList & @CRLF & "---" & @CRLF & "medication :)")
LogWrite(1, $ItemFromList)
Sleep(100)
MyGlobalPatternPatch($ItemFromList, $aOutHexGlobalArray)
; Scroll control 10 pixels - 1 line
_GUICtrlListView_Scroll($idListview, 0, 10)
_GUICtrlListView_EnsureVisible($idListview, $i, 0)
Sleep(100)
EndIf
При выборе какого-либо элемента и при нажатии кнопки "Patch" в функцию
MyGlobalPatternSearch
передаётся путь до файла. В MyGlobalPatternSearch
, как мы помним, решается, что брать из INI-файла для этого искомого файла, затем проверяется сам файл и уже далее ищутся байты в нём.После поиска нужных байт и занесения их в
$aOutHexGlobalArray
, вызывается MyGlobalPatternPatch
. Тут всё, как в патчинге самого Creative Cloud. Но отличие в том, что при патчинге Creative Cloud искомые файлы были в секции [CustomPatterns]
:
INI:
[CustomPatterns]
...
AppsPanelBL.dll="CreativeCloud1","CreativeCloud2"
ContainerBL.dll="CreativeCloud3"
Adobe Desktop Service.exe="DesktopService1"
...
Но теперь нам нужно пропатчить сами программы, а не Creative Cloud. Вот полный список файлов, что будет искать GenP:
INI:
[TargetFiles]
1="acrobat.dll"
2="acrodistdll.dll"
3="acrotray.exe"
4="aero.exe"
5="afterfxlib.dll"
6="animate.exe"
7="animator.exe"
8="animator (beta).exe"
9="auui.dll"
10="adobe bridge.exe"
11="designer.exe"
12="dreamweaver.exe"
13="dvaappsupport.dll"
14="encoder.exe"
15="encoder (beta).exe"
16="euclid-core"
17="gemini_uwp_bridge.dll"
18="illustrator.exe"
19="lightroom.exe"
20="lightroomcc.exe"
21="modeler.exe"
22="modeler beta.exe"
23="ngl-lib.dll"
24="painter.exe"
25="photoshop.exe"
26="public.dll"
27="registration.dll"
28="sampler.exe"
29="sampler beta.exe"
30="stager.exe"
31="sweetpeasupport.dll"
32="xd.exe"
33="appframework.rpln"
34="objectmodel.dll"
35="4.js"
36="manifest.json"
А вот список специальных файлов:
INI:
[CustomPatterns]
Acrobat.dll="Acrobat3","Acrobat5"
acrodistdll.dll="Acrodist2","Acrodist3","Acrodist4","Acrodist5","AcroRegistry1","AcroNew1"
acrotray.exe="AcroTray2","AcroTray3","AcroTray4","AcroTray5","AcroRegistry1","AcroNew1"
AppsPanelBL.dll="CreativeCloud1","CreativeCloud2"
ContainerBL.dll="CreativeCloud3"
Adobe Bridge.exe="ProfileExpired1","ValidateLicense1","ValidateLicense2","ValidateLicense3","CmpEax61","CmpEax62","CmpEax63","CmpEax64","Profile1","Profile2","Banner1","BridgeCamRaw1","BridgeCamRaw2","InstantShutdown1"
dvaappsupport.dll="TeamProjectEnabler1"
SweetPeaSupport.dll="HevcMpegEnabler3","HevcMpegEnabler4"
AppFramework.rpln="LoginVerification1"
ObjectModel.dll="PluginVerification1"
Adobe Desktop Service.exe="DesktopService1"
4.js="JS1","JS2","JS3","JS4"
manifest.json="Version"
Файлов из
TargetFiles
явно больше. Как быть с теми, что не в секции со специальными файлами?В таком случае используется набор патчей из секции
[DefaultPatterns]
:
INI:
[DefaultPatterns]
Values="ProfileExpired1","ProfileExpired3","ProfileExpired4","ProfileExpired5","ProfileExpired6","ValidateLicense1","ValidateLicense2","ValidateLicense3","CmpEax61","CmpEax62","CmpEax63","CmpEax64","Profile1","Profile2","Banner1","Banner2","InstantShutdown1"
Патчи по умолчанию применяются для всех файлов, что не находятся в секции
[CustomPatterns]
. В функции MyGlobalPatternSearch
и ExecuteSearchPatterns
как раз можно это увидеть:
Visual Basic:
Func MyGlobalPatternSearch($MyFileToParse)
...
If StringInStr($sSpecialFiles, $sFileName) Then
;MsgBox($MB_SYSTEMMODAL, "", "Special File: " & $sFileName)
LogWrite(0, " - using Custom Patterns")
ExecuteSearchPatterns($sFileName, 0, $MyFileToParse)
Else
LogWrite(0, " - using Default Patterns")
ExecuteSearchPatterns($sFileName, 1, $MyFileToParse)
;MsgBox($MB_SYSTEMMODAL, "", "File: " & $sFileName & @CRLF & "Not in Special Files")
EndIf
...
Visual Basic:
Func ExecuteSearchPatterns($FileName, $DefaultPatterns, $MyFileToParse)
Local $aPatterns, $sPattern, $sData, $aArray, $sSearch, $sReplace, $iPatternLength
If $DefaultPatterns = 0 Then
$aPatterns = IniReadArray($sINIPath, "CustomPatterns", $FileName, "")
Else
$aPatterns = IniReadArray($sINIPath, "DefaultPatterns", "Values", "")
EndIf
...
Явно видно, что в случае если
$DefaultPatterns
равен 1, то читается значение ключа Values
из секции [DefaultPatterns]
. А если же файл будет из секции CustomPatterns
, то и использоваться будут те байты, что указаны в этой секции. Например, как с Acrobat.dll
:
INI:
[CustomPatterns]
Acrobat.dll="Acrobat3","Acrobat5"
5.0 Изучаем патчи из INI-файла
Теперь рассмотрим патчи из секции[Patches]
. Как и с файлами Creative Cloud, слева на скринах будет файл до патча, а справа - после. Сначала рассмотрим оставшиеся значения для ключей из [CustomPatterns]
, а затем из [DefaultPatterns]
. Важно учесть то, что не все значения для ключей будут найдены и применены. Некоторые останутся ненайденными и байты из них не будут использоваться для патча. Скорее всего, они использовались у некоторых старых версий приложений. Я покажу в IDA только то, что нашлось у меня. Также в файлах могут встречаться байты из других. Дубликаты я буду пропускать.5.1. Секция CustomPatterns
C:\Program Files\Adobe\Acrobat DC\Acrobat\Acrobat.dll
Acrobat3
Acrobat5
C:\Program Files\Adobe\Acrobat DC\Acrobat\acrodistdll.dll
Acrodist4
AcroRegistry1
AcroNew1
C:\Program Files\Adobe\Acrobat DC\Acrobat\acrotray.exe
Новых нет.
C:\Program Files\Adobe\Adobe Bridge 2024\Adobe Bridge.exe
Banner1
BridgeCamRaw2
CmpEax63
Profile2
ProfileExpired1
ValidateLicense2
C:\Program Files\Adobe\Adobe After Effects 2024\Support Files\dvaappsupport.dll
TeamProjectEnabler1
C:\Program Files\Adobe\Adobe After Effects 2024\Support Files\SweetPeaSupport.dll
HevcMpegEnabler3
HevcMpegEnabler4
C:\Program Files\Adobe\Adobe Photoshop 2024\Required\UXP\com.adobe.ccx.start\js\4.js
JS1
JS2
JS3
JS4
C:\Program Files\Adobe\Adobe Photoshop 2024\Required\UXP\com.adobe.ccx.start\manifest.json
Version
5.2. Секция DefaultPatterns
C:\Program Files\Adobe\Adobe Photoshop 2024\Photoshop.exe
Banner2
Profile1
ProfileExpired4
C:\Program Files\Adobe\Adobe Illustrator 2024\Support Files\Contents\Windows\Illustrator.exe
ProfileExpired6
C:\Program Files\Adobe\Adobe Substance 3D Designer\Adobe Substance 3D Designer.exe
ProfileExpired5
C:\Program Files\Adobe\Adobe Dreamweaver 2021\Dreamweaver.exe
ValidateLicense3
5.3. Оставшиеся патчи
После анализа всех программ у меня остались нетронутыми такие байты:
INI:
Acrobat1="488BCFE8????????85C00F84????????488D??????????488BCFE8????????85C075??8D"|"488BCFE8????????FFC00F84????????488D??????????488BCFE8????????31C075??8D"
Acrobat2="6685C0740FE8????????6685C07405BB01000000"|"6685C07400E8????????6685C07400BB01000000"
Acrobat4="00E8????E7FF66893D??????03381D??????03751F4533C0488D15??????02488D0D??????02E8????E7FF6685C00F84BAFEFFFF8BDFE9B3FEFFFFB801000000"|"00E8????E7FF66893D??????03381D??????03EB1F4533C0488D15??????02488D0D??????02E8????E7FF6685C00F84BAFEFFFF8BDFE9B3FEFFFFB801000000"
Acrodist1="85C00F84????????E8????????85C00F85????????E8"|"85C00F84????????E8????????FFC00F85????????E8"
Acrodist2="00908BC8E8??????00CCCCCCCCCCCC48895C24104889"|"00908BC8E8??????00CCCCCCCCCCCC31C0C324104889"
Acrodist3="5E5B5DC3CCCCCCCCCCCCCCCCCCCCCCCCCCCCCC4055535657415441554156415748"|"5E5B5DC3CCCCCCCCCCCCCCCCCCCCCCCCCCCCCC31C0C35657415441554156415748"
Acrodist5="51??????????????????????????????48895C????????????????????????55"|"51??????????????????????????????33C0C3????????????????????????55"
AcroTray1="E8????????84C074??E8????????84C075??33DB"|"E8????????FEC074??E8????????FEC075??33DB"
AcroTray2="0F8459030000803D??????00000F8545030000"|"E95A03000090803D??????0000E94603000090"
AcroTray3="0F85A302000048397C24400F84"|"E9A40200009048397C24400F85"
AcroTray4="244884DB0F84C70100"|"244884DB0F85C70100"
AcroTray5="????????E86791D9FFE862B2D8FF????"|"????????9090909090B801000000????"
BridgeCamRaw1="84C074??8B??83??0174??83??0174??83??01"|"84C074??8B??83??01EB??83??0174??83??01"
CmpEax61="8B??85C074??83F80674????83????007D"|"C7??0300000083F8067400??83????00EB"
CmpEax62="8B??85C074??83F80674????83??????007D"|"C7??0300000083F8067400??83??????00EB"
CmpEax64="8B????85C074??83F80674????83??????007D"|"C7????0300000083F8067400??83??????00EB"
HevcMpegEnabler1="FF50100FB6"|"FFC0900FB6"
HevcMpegEnabler2="FF5010??0FB6"|"FFC090??0FB6"
ProfileExpired2="85C075??B892010000E9"|"85C07500B800000000E9"
ProfileExpired3="85C075????????75??B892010000E9"|"31C075????????7500B800000000E9"
ValidateLicense1="83F80175??BA94010000"|"83F80175??BA00000000"
InstantShutdown1="00??????????E875000000????????C0"|"00??????????9090909090????????C0"
PluginVerification1="5F5E????????????????????????????48895C2410??8974"|"5F5E????????????????????????????C390909090??8974"
LoginVerification1="4C8B??????????????????????????????????????742C48"|"4C8B??????????????????????????????????????EB2C48"
В этом случае можно поступить по-другому: мы используем онлайн-дизассемблер (
Ссылка скрыта от гостей
). Передадим в него искомые и заменяемые байты, чтобы сравнить. Знаки ??
я заменю 00
вот так:
Ссылка скрыта от гостей
Этот способ даст не на 100% точный вывод дизассемблера, а приблизительный. Но точный нам тут и не нужен. Для проверки того, вредоносен ли патч, хватит и приблизительного вывода. К тому же изменения в патчах маленькие, обычно меняют инструкции перед условным переходом, сам условный переход или что-то заменяют чем-то. Это всё не будет вредоносным.
Acrobat1
Acrobat2
Acrobat4
Acrodist1
Acrodist2
Acrodist3
Acrodist5
AcroTray1
AcroTray2
AcroTray3
AcroTray4
AcroTray5
BridgeCamRaw1
CmpEax61
CmpEax62
CmpEax64
HevcMpegEnabler1
HevcMpegEnabler2
ProfileExpired2
ProfileExpired3
ValidateLicense1
InstantShutdown1
PluginVerification1
LoginVerification1
6.0 Вывод
Мы вместе с вами изучили этот патчер и не нашли ничего особо вредоносного внутри него. Даже рассмотрели все патчи и все функции. Но важный момент - мы работали с исходником GenP. Помимо исходника в архиве идёт ещё и EXE-файл. Насчёт его ничего сказать не могу, так как ещё не ревёрсил его. Поэтому если вы хотите тоже его изучить, для безопасности ЗАГРУЖАЙТЕ AutoIt С ОФИЦИАЛЬНОГО САЙТА И СОБИРАЙТЕ СВОЙ EXE ИЗ ИСХОДНИКА! Также обращайте внимание на версию GenP. Ниже я прикреплю контрольные суммы файлов, что были рассмотрены в статье.Архив с GenP:
iz3lne.zip
MD5:
6b104ba9deb749a6b6ce88b9c6997dae
SHA1:
19d9b52477606b78bdce568235c0acb9321c1bc4
SHA256:
14ce93ae01d50b9d2ff3c36c3edd574a9f8bcec56451f3a865fcc210c617a77b
GenP-3.4.14.1.au3
MD5:
42c434f0a040132e37eddb5b1d886f8e
SHA1:
3e94d309d3c1dbd4dd9077082e9caf5926bc0fde
SHA256:
3dd6cf96e38768110c8f0e64ae8c698e43931ff9fb57b4a1476b63f4e5d45554
config.ini
MD5:
add427035968bc6f8bcdf0c5d7580495
SHA1:
7c1d13771b0546c31b87b36d1f158665ba9f793b
SHA256:
66232a4d8677cd50612eaebc664b2f2f3556b497d5bf8657967c259ef4723b68
Последнее редактирование: