скрыть

скрыть

  Форум  

Delphi FAQ - Часто задаваемые вопросы

| Базы данных | Графика и Игры | Интернет и Сети | Компоненты и Классы | Мультимедиа |
| ОС и Железо | Программа и Интерфейс | Рабочий стол | Синтаксис | Технологии | Файловая система |



Google  
 

Armadillo и CopyMem II



Автор: Hex

Я не люблю всякие анпакеры, потому что они приучают лениться. А потом автор анпакера пропадет куда-нить и все - фиг чего-то сделаешь. Т.к. не знаешь как оно работает. Вот и к анпакеру Armkiller у меня такое же отношение. Поэтому опишу как ловить армадилину раскриптовку при CopyMem II.

Для тех кто в танке:

Armadillo работает так: запускает себя в двух экземплярах.

1) Этот тот что вызвали мы. Это типа сервер
2) Созданный серевером. (клиент)

Так вот сервер запускает клиента в режиме отладки и помере происходящих DebugEvents он его разжимает, делает импорт и т.д. и потом запускает. CopyMem II: это такая фича у сервера. Когда она включена сервер динамически раскриптовывает секцию кода клиента блоками по 1000h байт. После выполненния кода этой страницы - закриптовывает назад. Т.е. сервер следит за Page Fault. И когда оно происходит - раскриптовывает недостающий блок и ставит все на место. Так вот, наша цель: заставить сервер распаковать прогу полностью и больше не закриптовывать.

Инструменты: Softice, IDA.

Для примера беру сам Armadillo 2.61 Public build 2000. Он является последним к моменту написания статьи и в нем используется CopyMem II.

Загружаем Armadillo 2.61 в IDA пусть дизасмится. Запускаем армадилу жмем Basic и больше никуда не лезем. Теперь ставим bpx Writeprocessmemory и жмем "Protection" - "Edit Project". Вылезет айс. Делаем bd * и жмем 3 раза F12. Видим вот это (я тут уже поподписывал):


_text1:0044D6BD push 0 ; EnCryptBit - если 1 - закриптовать, 0 - раскриптовать
_text1:0044D6BF mov esi, [ebp+PageNumber]
_text1:0044D6C5 shl esi, 4
_text1:0044D6C8 mov eax, [ebp+PageNumber]
_text1:0044D6CE and eax, 80000007h
_text1:0044D6D3 jns short loc_0_44D6DA
_text1:0044D6D5 dec eax
_text1:0044D6D6 or eax, 0FFFFFFF8h
_text1:0044D6D9 inc eax
_text1:0044D6DA 
_text1:0044D6DA loc_0_44D6DA: ; CODE XREF: sub_0_44C5FD+10D6j
_text1:0044D6DA xor ecx, ecx
_text1:0044D6DC mov cl, byte ptr ds:unk_0_4591E0[eax]
_text1:0044D6E2 mov edx, [ebp+PageNumber]
_text1:0044D6E8 and edx, 80000007h
_text1:0044D6EE jns short loc_0_44D6F5
_text1:0044D6F0 dec edx
_text1:0044D6F1 or edx, 0FFFFFFF8h
_text1:0044D6F4 inc edx
_text1:0044D6F5 
_text1:0044D6F5 loc_0_44D6F5: ; CODE XREF: sub_0_44C5FD+10F1j
_text1:0044D6F5 xor eax, eax
_text1:0044D6F7 mov al, byte ptr ds:unk_0_4591E1[edx]
_text1:0044D6FD mov edi, ds:dword_0_456238[ecx*4]
_text1:0044D704 xor edi, ds:dword_0_456238[eax*4]
_text1:0044D70B mov ecx, [ebp+PageNumber]
_text1:0044D711 and ecx, 80000007h
_text1:0044D717 jns short loc_0_44D71E
_text1:0044D719 dec ecx
_text1:0044D71A or ecx, 0FFFFFFF8h
_text1:0044D71D inc ecx
_text1:0044D71E 
_text1:0044D71E loc_0_44D71E: ; CODE XREF: sub_0_44C5FD+111Aj
_text1:0044D71E xor edx, edx
_text1:0044D720 mov dl, byte ptr ds:unk_0_4591E2[ecx]
_text1:0044D726 xor edi, ds:dword_0_456238[edx*4]
_text1:0044D72D mov eax, [ebp+PageNumber]
_text1:0044D733 cdq
_text1:0044D734 mov ecx, 1Ch
_text1:0044D739 idiv ecx
_text1:0044D73B mov ecx, edx
_text1:0044D73D shr edi, cl
_text1:0044D73F and edi, 0Fh
_text1:0044D742 add esi, edi
_text1:0044D744 
_text1:0044D744 DeCrypting:
_text1:0044D744 mov edx, ds:dword_0_459A74
_text1:0044D74A lea eax, [edx+esi*4]
_text1:0044D74D push eax ; hHash
_text1:0044D74E mov ecx, [ebp+PageNumber]
_text1:0044D754 push ecx ; PageNumber - номер страницы для раскриптовки.
_text1:0044D755 call ArmaCryptDecrypt
_text1:0044D75A add esp, 0Ch
_text1:0044D75D and eax, 0FFh
_text1:0044D762 test eax, eax
_text1:0044D764 jz short loc_0_44D770

Все что идет от _text1:0044D6BF до _text1:0044D74D - это просто вычисление кодов для раскриптовки указаной страницы. Чтобы раскриптовать нужную страницу нужно после выполнения _text1:0044D75A add esp, 0Ch загнать в [ebp+PageNumber] номер нужной страницы и прыгнуть к _text1:0044D6BD push 0 Таким образом можно прямо в айсе написать небольшой цикл который раскриптует все страницы. Как используются номера страниц? Номер страницы*1000+401000 = адрес, куда будет записан раскриптованый кусок. Таким образом чтобы узнать сколько у нас страниц смотрим в PE: Rva секции .text = 1000, Rva следующей секции(.rdata) = 2A000 т.е. число страниц = ((2A000 - 1000 ) / 1000) - 1 = 28h штук (-1 это я опытным путем выявил :) Но перед тем как писать цикл такой нужно обратить внимание еще на 1 особенность. Внутри ArmaCryptDecrypt есть еще 2 разных вызова одной и той же процедуры:

Раз:


_text1:0044E3FF push 0 ; Decrypt...
_text1:0044E401 mov ecx, [ebp+hHash]
_text1:0044E404 push ecx
_text1:0044E405 mov edx, [ebp+PageNumber]
_text1:0044E408 push edx
_text1:0044E409 call Crypting
_text1:0044E40E add esp, 0Ch

Два:


_text1:0044E48F push 1 ; Crypt...
...............
_text1:0044E542 mov edx, ds:dword_0_459A74
_text1:0044E548 lea eax, [edx+esi*4]
_text1:0044E54B push eax ; Crypting...
_text1:0044E54C mov ecx, ds:dword_0_459A88
_text1:0044E552 mov edx, ds:dword_0_459A8C
_text1:0044E558 mov eax, [edx+ecx*4]
_text1:0044E55B push eax
_text1:0044E55C call Crypting
_text1:0044E561 add esp, 0Ch

Первая всегда раскриптовывает, а вторая закриптовывает и удаляет страницу из памяти (т.е. ставит No_access) Нам на удаление страниц совсем не нужно, поэтому оставим только первый вызов, а второй CALL происходит если _text1:0044E47C jle loc_0_44E57C не прыгает.

Таким образом чтоб раскриптовать секцию кода нужно пропатчить _text1:0044E47C jle loc_0_44E57C на _text1:0044E47C jmp loc_0_44E57C И сделать цикл про который я говорил ранее. Потом просто делаем дамп раскриптованной секции кода. Найти OEP проще всего если поставить BPX SetProcessWorkingsetSize там буквально через 20 строчек OEP. Дальше делаем дамп на OEP, вставляем в него полученную секцию кода. Восстанавливаем импорт(лучше под NT/2k, но и в 98 его тоже не проблема восстановить). И долбаемся с остатками лицензирования...

Что еще можно сказать... Если глянуть по адресам 44D60B и 44D57B то увидим такие же куски кода с двумя отличиями:


_text1:0044D57B push 1 - Криптовать!
...............
_text1:0044D5E8 mov eax, [ebp+PageNumber]
_text1:0044D5EE sub eax, 1 - Предидущая страница
_text1:0044D5F1 push eax ; PageNumber
_text1:0044D5F2 call ArmaCryptDecrypt

и


_text1:0044D60B push 1 - Криптовать!
.........................
_text1:0044D678 mov eax, [ebp+PageNumber]
_text1:0044D67E add eax, 1 - Следующая страница
_text1:0044D681 push eax ; PageNumber
_text1:0044D682 call ArmaCryptDecrypt

Т.е. перед раскриптовкой новой станицы он криптует предидущую и следующую. В Armadillo 2.61 Public build 2000 это не используется но нужно иметь в виду :)






Copyright © 2004-2016 "Delphi Sources". Delphi World FAQ




Группа ВКонтакте   Ссылка на Twitter   Группа на Facebook