-
Notifications
You must be signed in to change notification settings - Fork 1
unpack reverse
- Категория: Reverse
- Стоимость: 600
- Автор: Алексей Захаров
- Репозиторий
Компания QuasiSecurity опубликовала свою новую разработку — инструмент для защиты программ от взлома. На хакерских форумах активное обсуждение этого продукта началось ещё несколько дней назад.
Как утверждают разработчики, в их решении есть несколько уровней безопасности, изолирующих секретную информацию в программе от пользователя. Любой желающий может удостовериться в надёжности системы: авторы загрузили на свой сайт пример защищённой программы. За нахождение путей обхода защиты обещают серьёзное вознаграждение, однако разработчики уверены, что способов взлома не существует.
При запуске exe-файла из условия пользователю предлагается ввести некоторый PIN-код:
unpack-reverse> protected.exe
Please, complete security check to run this application.
Enter PIN: 1234
Security check failed. Exiting...
Откроем бинарник в IDA. Функция main
состоит из нескольких блоков, в каждом из которых в случае ошибки выводится некоторое сообщение:
.text:00401763 lea eax, [ebp+Buffer]
.text:00401769 mov [esp+4], eax ; lpBuffer
.text:0040176D mov dword ptr [esp], 105h ; nBufferLength
.text:00401774 call _GetTempPathA@8
.text:00401779 sub esp, 8
.text:0040177C test eax, eax
.text:0040177E jnz short loc_40178C
.text:00401780 mov dword ptr [esp], offset aCannotGetTempD ; "Cannot get temp directory"
.text:00401787 call _fail
.text:0040178C ; ---------------------------------------------------------------------------
.text:0040178C
.text:0040178C loc_40178C: ; CODE XREF: _main+34↑j
.text:0040178C lea eax, [ebp+TempFileName]
.text:00401792 mov [esp+0Ch], eax ; lpTempFileName
.text:00401796 mov dword ptr [esp+8], 0 ; uUnique
.text:0040179E mov dword ptr [esp+4], 0 ; lpPrefixString
.text:004017A6 lea eax, [ebp+Buffer]
.text:004017AC mov [esp], eax ; lpPathName
.text:004017AF call _GetTempFileNameA@16
.text:004017B4 sub esp, 10h
.text:004017B7 test eax, eax
.text:004017B9 jnz short loc_4017C7
.text:004017BB mov dword ptr [esp], offset aCannotGetTempF ; "Cannot get temp filename"
.text:004017C2 call _fail
.text:004017C7 ; ---------------------------------------------------------------------------
.text:004017C7
.text:004017C7 loc_4017C7: ; CODE XREF: _main+6F↑j
.text:004017C7 mov dword ptr [esp+4], offset aWb ; "wb"
.text:004017CF lea eax, [ebp+TempFileName]
.text:004017D5 mov [esp], eax ; char *
.text:004017D8 call _fopen
.text:004017DD mov [ebp+var_C], eax
.text:004017E0 cmp [ebp+var_C], 0
.text:004017E4 jnz short loc_4017F2
.text:004017E6 mov dword ptr [esp], offset aCannotOpenTemp ; "Cannot open temp file"
.text:004017ED call _fail
.text:004017F2 ; ---------------------------------------------------------------------------
По содержанию сообщений и вызываемым функциям (GetTempPathA
, GetTempFileNameA
, fopen
в режиме wb
) можно понять, что этот код открывает на запись новый временный файл с именем, которое находится в переменной TempFileName
.
Последний блок в main
содержит вызов ещё нескольких функций:
.text:004017F2 call _deobfuscate
.text:004017F7 mov eax, [ebp+var_C]
.text:004017FA mov [esp+0Ch], eax ; FILE *
.text:004017FE mov dword ptr [esp+8], 4000h ; size_t
.text:00401806 mov dword ptr [esp+4], 1 ; size_t
.text:0040180E mov dword ptr [esp], offset _level2 ; void *
.text:00401815 call _fwrite
.text:0040181A mov eax, [ebp+var_C]
.text:0040181D mov [esp], eax ; FILE *
.text:00401820 call _fclose
.text:00401825 lea eax, [ebp+TempFileName]
.text:0040182B mov [esp], eax ; char *
.text:0040182E call _system
.text:00401833 lea eax, [ebp+TempFileName]
.text:00401839 mov [esp], eax ; lpFileName
.text:0040183C call _DeleteFileA@4
fwrite
записывает в открытый временный файл некоторый набор байт, файл закрывается, а затем запускается на исполнение с помощью функции system
. После этого он удаляется. Но вызов system
- блокирующий, поэтому удаление распакованной программы происходит только после её завершения.
Можно предположить, что все сообщения на консоль выводит именно распакованная программа. При этом она не завершается, пока не введён PIN-код. Тогда для того, чтобы её извлечь, достаточно запустить protected.exe
и найти только что созданный временный файл в папке %TEMP%
.
При открытии нового файла в IDA нам предлагается загрузить его как Microsoft.Net assembly, из чего мы делаем вывод о том, что это программа, написанная с использованием .Net Framework. Получим её код на C# с помощью одного из декомпиляторов, например dotPeek.
Функция Main
в полученном коде начинается с вызова функции Authorize
, в которой введённый PIN-код сравнивается с константой.
private static bool Authorize()
{
Console.WriteLine("Please, complete security check to run this application.");
Console.Write("Enter PIN: ");
long result;
if (long.TryParse(Console.ReadLine(), out result))
return result == 89543436219193903L;
return false;
}
Запустив бинарник повторно и введя нужный PIN, получаем новое сообщение:
unpack-reverse> protected.exe
Please, complete security check to run this application.
Enter PIN: 89543436219193903
Security check complete. Starting application...
Enter your flag:
Продолжив анализ C#-кода, снова видим запись во временный файл и его удаление перед выходом. Однако на этот раз файл не запускается, а загружается как dll-библиотека, из которой затем вызывается функция check
:
IntPtr hModule = Win32.LoadLibrary(tempFileName);
string procedureName = "check";
((Action) Marshal.GetDelegateForFunctionPointer(Win32.GetProcAddress(hModule, procedureName), typeof (Action)))();
Win32.FreeLibrary(hModule);
Скопируем библиотеку из папки %TEMP%
тем же способом, найдя файл, созданный после ввода PIN-кода.
Вновь запустим IDA, откроем dll и перейдём на check
в списке функций. Её код устроен следующим образом:
- с помощью функции
puts
выводится "Enter your flag:", - далее происходит ввод строки с консоли с помощью
fgets
и её анализ, - а в конце печатается одно из двух сообщений: "You are right!" или "You are wrong".
Выбор сообщения происходит в зависимости от значения локальной переменной var_C
:
.text:62D8130B cmp [ebp+var_C], 0
.text:62D8130F jz short loc_62D8131F
.text:62D81311 mov [esp+58h+Str], offset aYouAreRight ; "You are right!"
.text:62D81318 call puts
.text:62D8131D jmp short locret_62D8132B
.text:62D8131F ; ---------------------------------------------------------------------------
.text:62D8131F
.text:62D8131F loc_62D8131F: ; CODE XREF: check+8F↑j
.text:62D8131F mov [esp+58h+Str], offset aYouAreWrong ; "You are wrong"
.text:62D81326 call puts
Для того, чтобы получить "You are right!" нужно, чтобы var_C
была не равна 0. Посмотрим на обращения к этой переменной:
- сразу после ввода пользовательской строки
var_C
выставляется в 1 -
strlen
для неё должна вернуть 39, иначеvar_C
станет нулём:
.text:62D812B9 lea eax, [ebp+Buf]
.text:62D812BC mov [esp+58h+Str], eax ; Str
.text:62D812BF call strlen
.text:62D812C4 cmp eax, 39
.text:62D812C7 jz short loc_62D812D0
.text:62D812C9 mov [ebp+var_C], 0
Нужно заметить, что функция fgets
сохраняет символ \n
. Это означает, что длина самой строки должна быть равна 38.
- кроме того,
var_C
будет выставлена в 0, если на одной из итераций цикла по символам строки результат некоторых вычислений не совпадёт с ожидаемым:
.text:62D812D9 mov eax, [ebp+var_10] ; var_10 - счётчик цикла
.text:62D812DC add eax, offset unk_62D82000
.text:62D812E1 movzx eax, byte ptr [eax]
.text:62D812E4 xor al, [ebp+var_11] ; var_11 = 87h
.text:62D812E7 mov edx, eax
.text:62D812E9 lea ecx, [ebp+Buf] ; Buf - введённая строка
.text:62D812EC mov eax, [ebp+var_10]
.text:62D812EF add eax, ecx
.text:62D812F1 movzx eax, byte ptr [eax]
.text:62D812F4 cmp dl, al
.text:62D812F6 jz short loc_62D812FF
.text:62D812F8 mov [ebp+var_C], 0
Проанализировав этот код, можно понять, что ключевая операция здесь - xor очередного элемента массива unk_62D82000
с ключом, который находится в переменной var_11
(в начале программы этой переменной присваивается значение 87h
). Полученное значение затем сравнивается с соответствующим символом ввода.
Таким образом, чтобы получить флаг, достаточно выполнить xor 38 байтов массива unk_62D82000
с ключом 87h
.