Я не смотрел исходники дабы не плагиатить подсознательно код и делал пакер разбираясь по ходу в коде и заголовке упакованного файла и имея только бинарники.
Для изучения алгоритмов я использовал следующие программы:
IDA Pro - по большей части чисто как дизассемблер
OllyDbg - для дебага
Explorer Suite (CFF Explorer) - для изучения заголовка PE, секций и т.п.
Для начала теория.
Один из вариантов работы пакера/криптора:
- Маппируем исходный фаил в память.
- Вычисляем размер заголовка с файловым выравниванием изначального заголовка.
- Вычисляем реальный размер всех секций.
- Склеивем секции и упаковыем/криптуем их получая новый размер.
- Вычисляем размер кода распаковки/декриптора.
- Складываем все размеры применяя файловое выравнивание которое в заголовке.
- Создаем и маппируем фаил с получившимся размером в 6 пункте.
- Записываем PE заголовок украденный из упаковываемого файла.
- Создаем секции, учитывая размер из упаковываемого файла .
- Исправляем PE заголовок согласно размеру в памяти которые занимают секции.
- Заливаем в фаил криптованные данные.
- Заливаем техническую информацию, размеры, смещения етц.
- Заливаем код декриптора/анпакера.
- Вычисляем новую точку входа и записываем ее в PE заголовок.
- Создаем таблицу импорта с kernel32.dll и для загрузки LoadLibrary и GetProcAdrress.
- Пишем код распаковки/декриптора.
Литература которую было бы неплохо почитать перед написанием кода:
http://wasm.ru/article.php?article=green2red02
http://www.insidepro.com/kk/019/019r.shtml
Итак, куча говнокода, по пунктам:
1. Маппируем исходный фаил в память.
invoke FindFirstFile, offset fileName, offset wfd ; получаем размер файла invoke CreateFile, offset fileName,GENERIC_READ,0, NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0 ; открываем фаил invoke CreateFileMapping, eax, NULL,PAGE_READONLY, 0, DWORD PTR [wfd.nFileSizeLow], NULL ; мапируем в ридонли invoke MapViewOfFile, eax, FILE_MAP_READ, 0, 0, 0 ; делаем проэкцию mov hinfile, eax ; запишем адрес, начала файла invoke checkPE, eax ; проверим, PE это фаил или нет
2. Вычисляем размер заголовка с файловым выравниванием изначального заголовка.
xor ebx, ebx ; обнуляем ebx mov bx, WORD PTR [eax+IMAGE_DOS_HEADER.e_lfanew] ; записываем в bx размер dos заголовка mov dosHSize, ebx ; сохраняем размер dos заголовка в dosHSize, add eax, ebx ; добавляем размер к eax, в котором лежит указатель на начало маппированного файла ; IMAGE FILE HEADER mov ecx, dosHSize ; копируем размер dos заголовка в ecx add ecx, FULL_IMAGE_FILE_HEADER ; прибавляем к ecx размер IMAGE_FILE_HEADER и IMAGE_NT_SIGNATURE add cx, WORD PTR [eax+IMAGE_FILE_HEADER.SizeOfOptionalHeader+4h] ; прибавляем размер опционального заголовка mov pehSize, ecx ; размер PE заголовка сохраняем в pehSize
3.Вычисляем реальный размер всех секций
xor ebx, ebx ; обнулим ebx mov bx, WORD PTR [eax+IMAGE_FILE_HEADER.NumberOfSections+4h] ; скопируем в bx количество секций mov secCount, ebx ; сохраним количество секций в secCount imul ebx, ebx,28h ; размер секции равено 28h умножим ее на количество секций add ecx, ebx ; результат прибавим к размеру заголовка полученному выше ;IMAGE OPTIONAL HEADER add eax, FULL_IMAGE_FILE_HEADER ; в eax находится ссылка на начало IMAGE_OPTIONAL_HEADER прибавим к нему размер IMAGE_OPTIONAL_HEADER mov ebx, DWORD PTR [eax+IMAGE_OPTIONAL_HEADER.FileAlignment] ; получим выравнивание файла mov fAlig, ebx ; запишем его в fAlig invoke GetAlignUp, ecx, ebx ; сделаем выравнивние заголовка согласно файловому выравниванию mov fileSize, eax ; запишем в переменную fileSize mov codeStart, eax ; в codeStart записываем начало кода в файле invoke GetProcessHeap ; получим адрес кучи mov pHeap, eax ; сохраним адрес кучи в pHeap mov eax, secCount ; скопируем в eax количество секций imul eax, eax, SECSTRUCSIZE ; умножим количество секций на размер моей структуры SECSTRUCSIZE invoke HeapAlloc, pHeap,HEAP_ZERO_MEMORY, eax ; выделяем столько места в куче mov secMem, eax ; запишем указатель на выделеное место mov edi, hinfile ; записываем указатель на открытый файл add edi, pehSize ; прибавим к нему PE заголовок без секций mov ecx, secCount ; в счетчик запишем количество секий xor eax, eax ; обнуляем eax mov esi, secMem ; в esi указатель на выделенное место в куче nextsec: mov ebx, DWORD PTR[edi+8h] ; запишем в ebx данные из Virtual Size mov DWORD PTR [esi], ebx ; запишем в структуру SECSTRUCSIZE их add eax, ebx ; прибавим к eax виртуальный размер mov ebx, DWORD PTR[edi+0Ch] ; запишем в ebx Virtual Address mov DWORD PTR [esi+4h], ebx ; запишем в структуру SECSTRUCSIZE их на вторую позицию mov ebx, DWORD PTR[edi+14h] ; запишем в ebx Ra wSize mov DWORD PTR [esi+8h], ebx ; запишеи в структуру SECSTRUCSIZE их на третью позицию add eax, 8h ; прибавим к eax 8байт необходимых для технической информации add edi, 28h ; увеличим указатель на секциях на 28h чтобы перейти ко второй секции add esi, SECSTRUCSIZE ; увеличим указатель в стуктуре SECSTRUCSIZE чтобы перейти ко второй секции loop nextsec ; повторить всю эту бесовщину с метки nextsec
Ну и для начала все, в следующих частях будет описание других пунктов. А в последней части будет ссылка на исходник.
Вторая часть.
Комментариев нет:
Отправить комментарий