Оригинальный DVD-ROM: eXeL@B DVD !
eXeL@B ВИДЕОКУРС !

ВИДЕОКУРС ВЗЛОМ
выпущен 12 ноября!


УЗНАТЬ БОЛЬШЕ >>
Домой | Статьи | RAR-cтатьи | FAQ | Форум | Скачать | Видеокурс
Новичку | Ссылки | Программирование | Интервью | Архив | Связь

Распаковка Армадилло с IAT Elimination (часть 3)

Обсудить статью на форуме

Хорошая подборка видеоуроков, инструментов крэкера, книг и статей - здесь.

Автор: R.Narvaja / estet / MARcoDEN <--- / estet@hotbox.ru / --->

В этой части мы попробуем найти «магический прыжок», который поможет нам восстановить таблицу импорта. Разработчики armadillo каждый раз усложняют поиск этого заветного места.
Хочу напомнить, что я решаю те проблемы, которые возникают в ходе данного исследования. Это не означает, что подобные ситуации будут во всех программах.

ПОИСК МАГИИ

Попробуем отыскать «магический прыжок» тем же способом, что и раньше. Заодно и проверим, что же придумали разработчики в этот раз.
Мы будем исправлять таблицу в тот момент, когда armadillo ее создает. Как сказано во второй части, нужно скопировать таблицу с исправленными переходами и вызовами в нужное место.
Итак, загрузим программу в отладчик и дойдем до OEP (метод описан в первой части).



Здесь мы видим, что имеется CALL (обращение к таблице) к адресу 3Cxxxx. Давайте посмотрим в дампе этот адрес. Выделяем строку и выбираем FOLLOW IN DUMP-MEMORY ADDRESS.
Оказываемся здесь – 3C8338



Как мы уже выяснили, armadillo меняет указатель на начало таблицы, но ведь можно изменить указатель ;) . Выберем второй по счету редирект:



Ставим Hardware BPX on WRITE и перезапускаем программу.

Так, это неинтересно…



тоже самое…



опять…



В итоге попадем сюда (чтобы сразу попасть в это место, можно написать небольшой скрипт)



Да-а-а, опять не то…



А вот здесь



мы видим таблицу



Это место, где сохраняются хорошие значения таблицы. Поставим BPX ON EXECUTION в этом месте и начнем трейсить этот цикл.



Этот цикл достаточно большой (начинается с адреса DE41F1)



Для себя можно поставить несколько меток, чтобы лучше ориентироваться.



Итак, что же происходит.
Здесь считывается имя API, которое будет сохраняться

 
 00DE4212    8B85 80E8FFFF   MOV EAX,DWORD PTR SS:[EBP-1780]
 
Ниже есть условный прыжок

 
 00DE421D	75 44 			JNZ SHORT 00DE4263
 
Если EAX равен нулю - не прыгаем. В моем случае, это 43. Продолжим.
Снова помещает в EAX имя

 
 00DE4263    8B85 80E8FFFF   MOV EAX,DWORD PTR SS:[EBP-1780]
 
 00DE4269    0FB600          MOVZX EAX,BYTE PTR DS:[EAX]
 
В следующей строке берется первый символ, код которого равен 43. JNZ не выполняет переход, когда первый символ имени - нуль. Потом сравнивается FF с этим символом.

 
 00DE426C 3D FF000000 CMP EAX, 0FF
 0FF 00DE4271 0F85 8A000000 JNZ 00DE4301
 
Снова чтение имени API и сохранение

 
 00DE4301    8B85 80E8FFFF   MOV EAX,DWORD PTR SS:[EBP-1780]
 00DE4307    8985 7CE2FFFF   MOV DWORD PTR SS:[EBP-1D84],EAX
 
Потом идет вызов функции strchr

 
 00DE4315    FF15 C4B2DE00   CALL DWORD PTR DS:[DEB2C4]               ; msvcrt.strchr
 
strchr, wcschr, _mbschr
Поиск символа в строке.
char *strchr( const char *string, int c );
wchar_t *wcschr( const wchar_t *string, wint_t c );
unsigned char *_mbschr( const unsigned char *string, unsigned int c );
Выполняется поиск нуля в строке, т.е. указатель на место, где она заканчивается.
После возврата из функции, EAX содержит указатель на конец строки.
Стоит отметить то, что в этот момент указатель ведет к списку APIs, который он обрабатывает для создания таблицы. Просмотрим дамп:

 
 00FAAFBA  05 00 01 07 27 00 30 30 30 30 30 30 30 30 30 30   . ’.0000000000
 00FAAFCA  30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30  0000000000000000
 00FAAFDA  30 30 30 30 30 30 00 AB AB AB AB AB AB AB AB FE  000000.««««««««&#254;
 00FAAFEA  EE FE EE FE EE FE EE FE EE FE EE FE EE FE 00 00  &#238;&#254;&#238;&#254;&#238;&#254;&#238;&#254;&#238;&#254;&#238;&#254;&#238;&#254;..
 00FAAFFA  00 00 00 00 00 00 22 25 09 00 01 07 1E 00 57 49  ......"%..  .WI
 00FAB00A  4E 4D 4D 2E 64 6C 6C 00 C0 AA 1C 00 01 00 00 00  NMM.dll.&#192;&#170; . ...
 00FAB01A  50 6C 61 79 53 6F 75 6E 64 41 00 00 4C 54 46 49  PlaySoundA..LTFI
 00FAB02A  4C 31 30 4E 2E 44 4C 4C 00 A0 A5 1C 00 07 00 00  L10N.DLL. &#165; ...
 00FAB03A  00 FF 65 00 FF 70 00 FF 68 00 FF 69 00 FF 6A 00  .&#255;e.&#255;p.&#255;h.&#255;i.&#255;j.
 00FAB04A  FF 83 00 FF 64 00 00 4C 54 49 4D 47 31 30 4E 2E  &#255;&#402;.&#255;d..LTIMG10N.
 00FAB05A  64 6C 6C 00 C0 A5 1C 00 0C 00 00 00 FF 7D 00 FF  dll.&#192;&#165; .....&#255;}.&#255;
 00FAB06A  70 00 FF 6A 00 FF 68 00 FF 67 00 FF 69 00 FF 75  p.&#255;j.&#255;h.&#255;g.&#255;i.&#255;u
 00FAB07A  00 FF 7F 00 FF 77 00 FF 6F 00 FF 7A 00 FF 7E 00  .&#255;.&#255;w.&#255;o.&#255;z.&#255;~.
 00FAB08A  00 4C 54 4B 52 4E 31 30 4E 2E 64 6C 6C 00 F4 A5  .LTKRN10N.dll.&#244;&#165;
 00FAB09A  1C 00 16 00 00 00 FF 92 00 FF 6A 00 FF 6C 00 FF   . ...&#255;’.&#255;j.&#255;l.&#255;
 00FAB0AA  6E 00 FF C6 00 FF 7D 00 FF 86 00 FF C5 00 FF 97  n.&#255;&#198;.&#255;}.&#255;†.&#255;&#197;.&#255;—
 00FAB0BA  00 FF 8D 00 FF 8B 00 FF 84 00 FF 64 00 FF 88 00  .&#255;&#141;.&#255;‹.&#255;„.&#255;d.&#255;&#710;.
 00FAB0CA  FF 80 00 FF 73 00 FF 85 00 FF 7C 00 FF 90 00 FF  &#255;€.&#255;s.&#255;….&#255;|.&#255;&#144;.&#255;
 00FAB0DA  96 00 FF 87 00 FF 91 00 00 4C 54 54 57 4E 31 30  –.&#255;‡.&#255;‘..LTTWN10
 00FAB0EA  4E 2E 64 6C 6C 00 50 A6 1C 00 02 00 00 00 FF 67  N.dll.P¦ . ...&#255;g
 00FAB0FA  00 FF 65 00 00 4C 54 44 49 53 31 30 4E 2E 64 6C  .&#255;e..LTDIS10N.dl
 00FAB10A  6C 00 7C A5 1C 00 02 00 00 00 FF 83 00 FF 7A 00  l.|&#165; . ...&#255;&#402;.&#255;z.
 00FAB11A  00 4C 54 44 4C 47 31 30 4E 2E 64 6C 6C 00 88 A5  .LTDLG10N.dll.&#710;&#165;
 00FAB12A  1C 00 03 00 00 00 FF 65 00 FF 68 00 FF 6B 00 00   . ...&#255;e.&#255;h.&#255;k..
 00FAB13A  4C 54 45 46 58 31 30 4E 2E 64 6C 6C 00 98 A5 1C  LTEFX10N.dll.&#732;&#165; 
 00FAB14A  00 01 00 00 00 FF 66 00 00 4B 45 52 4E 45 4C 33  . ...&#255;f..KERNEL3
 00FAB15A  32 2E 64 6C 6C 00 98 A2 1C 00 B8 00 00 00 4C 6F  2.dll.&#732;&#162; .&#184;...Lo
 00FAB16A  63 61 6C 52 65 41 6C 6C 6F 63 00 47 6C 6F 62 61  calReAlloc.Globa
 00FAB17A  6C 46 6C 61 67 73 00 47 65 74 50 72 6F 63 65 73  lFlags.GetProces
 00FAB18A  73 56 65 72 73 69 6F 6E 00 47 65 74 4F 45 4D 43  sVersion.GetOEMC
 00FAB19A  50 00 46 69 6E 64 52 65 73 6F 75 72 63 65 45 78  P.FindResourceEx
 00FAB1AA  41 00 4C 6F 63 61 6C 46 69 6C 65 54 69 6D 65 54  A.LocalFileTimeT
 00FAB1BA  6F 46 69 6C 65 54 69 6D 65 00 53 79 73 74 65 6D  oFileTime.System
 00FAB1CA  54 69 6D 65 54 6F 46 69 6C 65 54 69 6D 65 00 53  TimeToFileTime.S
 00FAB1DA  65 74 45 72 72 6F 72 4D 6F 64 65 00 52 74 6C 55  etErrorMode.RtlU
 
 --------  Пропущено для экономии места
 
 00FAD04A  50 61 6C 65 74 74 65 00 43 72 65 61 74 65 42 69  Palette.CreateBi
 00FAD05A  74 6D 61 70 49 6E 64 69 72 65 63 74 00 47 65 74  tmapIndirect.Get
 00FAD06A  4E 65 61 72 65 73 74 50 61 6C 65 74 74 65 49 6E  NearestPaletteIn
 00FAD07A  64 65 78 00 52 65 73 69 7A 65 50 61 6C 65 74 74  dex.ResizePalett
 00FAD08A  65 00 55 6E 72 65 61 6C 69 7A 65 4F 62 6A 65 63  e.UnrealizeObjec
 00FAD09A  74 00 53 65 74 42 72 75 73 68 4F 72 67 45 78 00  t.SetBrushOrgEx.
 00FAD0AA  43 72 65 61 74 65 48 61 74 63 68 42 72 75 73 68  CreateHatchBrush
 00FAD0BA  00 53 65 74 50 69 78 65 6C 00 47 65 74 44 49 42  .SetPixel.GetDIB
 00FAD0CA  43 6F 6C 6F 72 54 61 62 6C 65 00 47 65 74 45 6E  ColorTable.GetEn
 00FAD0DA  68 4D 65 74 61 46 69 6C 65 48 65 61 64 65 72 00  hMetaFileHeader.
 00FAD0EA  50 6C 61 79 45 6E 68 4D 65 74 61 46 69 6C 65 00  PlayEnhMetaFile.
 00FAD0FA  45 78 74 46 6C 6F 6F 64 46 69 6C 6C 00 50 6F 6C  ExtFloodFill.Pol
 00FAD10A  79 67 6F 6E 00 53 65 74 50 69 78 65 6C 56 00 53  ygon.SetPixelV.S
 00FAD11A  65 74 44 49 42 43 6F 6C 6F 72 54 61 62 6C 65 00  etDIBColorTable.
 00FAD12A  53 65 74 44 49 42 69 74 73 00 4D 6F 76 65 54 6F  SetDIBits.MoveTo
 00FAD13A  45 78 00 00 63 6F 6D 64 6C 67 33 32 2E 64 6C 6C  Ex..comdlg32.dll
 
 --------  Пропущено для экономии места
 
 00FAD84A  FF 04 00 00 4D 53 56 46 57 33 32 2E 64 6C 6C 00  &#255; ..MSVFW32.dll.
 00FAD85A  5C A6 1C 00 05 00 00 00 44 72 61 77 44 69 62 44  \¦ . ...DrawDibD
 00FAD86A  72 61 77 00 44 72 61 77 44 69 62 4F 70 65 6E 00  raw.DrawDibOpen.
 00FAD87A  44 72 61 77 44 69 62 43 6C 6F 73 65 00 44 72 61  DrawDibClose.Dra
 00FAD88A  77 44 69 62 52 65 61 6C 69 7A 65 00 44 72 61 77  wDibRealize.Draw
 00FAD89A  44 69 62 53 65 74 50 61 6C 65 74 74 65 00 00 56  DibSetPalette..V
 00FAD8AA  45 52 53 49 4F 4E 2E 64 6C 6C 00 B0 AA 1C 00 03  ERSION.dll.°&#170; . 
 00FAD8BA  00 00 00 47 65 74 46 69 6C 65 56 65 72 73 69 6F  ...GetFileVersio
 00FAD8CA  6E 49 6E 66 6F 53 69 7A 65 41 00 47 65 74 46 69  nInfoSizeA.GetFi
 00FAD8DA  6C 65 56 65 72 73 69 6F 6E 49 6E 66 6F 41 00 56  leVersionInfoA.V
 00FAD8EA  65 72 51 75 65 72 79 56 61 6C 75 65 41 00 00 00  erQueryValueA...
 00FAD8FA  AD BA 0D F0 AD BA 0D F0 AD BA 0D F0 AD BA 0D F0  ­&#186;.&#240;­&#186;.&#240;­&#186;.&#240;­&#186;.&#240;
 
Та, которая выделена, является CreateHatchBrush,. На вашем компьютере эта может быть другая функция, но в дампе вы должны видеть это имя в списке.

 
 00DE431D 		40 				INC EAX
 00DE431E 		8985 80E8FFFF 		MOV DWORD PTR SS: [EBP-1780], EAX
 
Увеличение EAX на 1, который указывает на следующее имя API (в моем случае, это SetPixel).

 
 00DE43C1 		8B85 7CE2FFFF 		MOV EAX, DWORD PTR SS: [EBP-1D84]
 00DE43C7 		8985 B0CDFFFF 		MOV DWORD PTR SS: [EBP-3250], EAX
 
Здесь вновь возвращается имя API CreateHatchBrush, после чего сохраняется указатель на следующее имя

 
 00DE43CD 		FFB5 B0CDFFFF 		PUSH DWORD PTR SS: [EBP-3250]
 00DE43D3 		FFB5 B8E4FFFF 		PUSH DWORD PTR SS: [EBP-1B48]
 00DE43D9 		E8 A358FEFF 		CALL 00DC9C81
 
Здесь в стек сохраняется базовый адрес библиотеки GDI32.dll, которая содержит вышеуказанные функции.



Заходим в CALL.



Терпеливо трейсим.

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


 00DC9D68 FF15 30B3DE00 CALL DWORD PTR DS: [DEB330]; msvcrt. _ stricmp
Если это не то, что мы ищем,



то продолжаем. Первой он ищет секцию dll, где сохранялись имена APIs, сейчас сравнивает одну с той, что он ищет.



Если имена совпали, то JNZ не выполнит переход. Чтобы ускорить процесс, поставим временный бряк на DC9D74, который прервет выполнение, когда имя совпадет.
Остановились и



смотрим, что происходит дальше.
Ниже отображено количество операций по результатам поиска (по всем APIs, которые сравнивались, в моем случае, это было 40). В итоге, он получает положение API в библиотеке

 
 00DC9D9A    8B4D BC         MOV ECX,DWORD PTR SS:[EBP-44]
 00DC9D9D    03C8            ADD ECX,EAX
 


Вот поганцы, решили запудрить нам мозги ;).

 
 00DE43D9    E8 A358FEFF     CALL 00DC9C81
 
А вот здесь сохраняется «хороший» адрес API

 
 00DE44A5   8908            MOV DWORD PTR DS:[EAX],ECX               ; AQUIIII BUENO
 
Теперь мы знаем, как работает цикл. Сейчас посмотрим, как он обработает «плохое» значение.

Выделенный адрес является тем самым «плохим» значением.



Проверим, поможет ли нам предыдущий адрес 77E5B7FD



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

Итак, сначала ставим Hardware on execution там, где выполняется сохранение хороших значений.



Сохраняется первая «хорошая» API



Первая из списка.

 
 003C8890  7E 4F C4 77 62 8B B0 76  ~O&#196;wb‹°v
 003C8898  A2 42 C5 77 2B A7 DC 00  &#162;B&#197;w+§&#220;.
 003C88A0  02 E2 DC 00 8E 5B DC 77   &#226;&#220;.&#381;[&#220;w
 
Мы можем несколько раз запустить программу, чтобы убедиться в последовательности алгоритма.



Плохо то, что API размещаются в беспорядке, что затруднить поиск момента, когда сохраняется «плохое» значение. Самый простой способ - поставить BPM ON WRITE на всю таблицу и смотреть, где он остановится.

Запускаем (F9) и видим



Хм-м



Это - место, где сохраняется «плохое» значение. Продвигаемся дальше. Видно, что область, где сохраняются «плохие» значения - DE4240 - немного ниже начала цикла (DE41F1), который мы изучали.



Это означает, что есть только два условных прыжка, которые избегают эту область. Хм, интересно.
Ставим Hardware BPX on execution на DE41F1 (начало цикла): так мы сможем изучить оба варианта – «хорошее» и «плохое» значения - и найти различия.



Запускаем (F9) и смотрим, что происходит, одновременно поглядывая на список API выше.



второе «плохое»



другие «хорошие»















Все эти функции (из LTFIL10N.DLL) были записаны в чистом виде dll. А вот сейчас исправленное значение



Хм-м-м, это достаточно подозрительно, т.к. «плохие» значения были нулями, которые отделяют функции одной библиотеки от другой. Особенно подозрительно то, что условием перехода в «плохую» область является равенство первого символа имени API нулю, а противном случае - сохраняется «хорошее» значение.



Мы продолжим в 4-ой части



Автор: Ricardo Narvaja
Перевод: Estet
Редактор: MARcoDEN



Обсуждение статьи: Распаковка Армадилло с IAT Elimination (часть 3) >>>


Материалы находятся на сайте https://exelab.ru



Оригинальный DVD-ROM: eXeL@B DVD !


Вы находитесь на EXELAB.rU
Проект ReactOS