Разопаковане на ExeCryptor 2
Гарантиране, че ExeCryptor Dump работи на различни операционни системи
Ако се опитаме да стартираме коригирания dumped_.exe на различна операционна система, той няма да се стартира. Защо се случва това?
Тук начинът за решаване на този проблем е очевиден. Ако имаме нули в клетките на паметта на раздела за пакетиране, където са записани хешовете на API, тогава програмата ще преизчисли хешовете на API за тази операционна система и програмата ще стартира нормално. В статията си EvOlUtIoN предлага да се направят два дъмпа на разопакованата програма на два компютъра с различни инсталирани операционни системи. След това той предлага да сравни тези изхвърляния и с помощта на специална програма, която е написал, замени хеш стойностите с нули в клетките на областта на паметта на пакета. Този начин според мен е по-тромав, тъй като тази работа може да се извърши много по-лесно. Просто трябва да извадите дъмпа на .prot2 паметта на пакета, преди хеш стойностите на API да бъдат записани в него (когато са записани с начални нули), и да вмъкнете дъмпа на тази област на паметта във файла dumped_.exe.
Зареждаме пакетираната програма в дебъгера и програмата спира на TLS Callback. Секцията за пакетиране, която нарекохме .prot2 в нашия файл dumped_.exe (намиращ се точно под секцията .rsrc), досега е пълна с нули. Премахнете временния BP, зададен от дебъгера, и задайте BMP при запис в този раздел:

Натискаме клавиша F9 и програмата спира тук:
Тук виждаме цикъла за разопаковане на секцията .prot2. На изхода от цикъла за разопаковане задайте BP, премахнете BMP при запис и натиснете клавиша F9. Трябва да се отбележи, че самата процедура за разопаковане за този раздел на пакетера е доста голяма и ако превъртим надолу нейния код,тогава ще видим няколко RETN инструкции, последната от които завършва разопаковането на кода на секцията .prot2:


За да изхвърлите тази област от паметта, изберете я цялата и я запазете за всеки случай, като използвате Hex Workshop с името Recovery_prot2 , както направихме преди:

Сега във втория дебъгер отваряме файла dumped_.exe, разпределяме цялата област на паметта на секцията .prot2 и извършваме двоично вмъкване:

Записваме направените промени във файла и се опитваме да стартираме модифицирания файл dumped_.exe. Получаваме следното съобщение за грешка:

Прихващането за отстраняване на грешки отново проработи. Заредете файла dumped_.exe в програмата за отстраняване на грешки и задайте точката на прекъсване на хардуера при достъп до API на CreateThread. Натискаме клавиша F9, за да стартираме програмата и програмата спира в началото на API CreateThread:
Възниква очевидният въпрос, защо се изпълнява дъмп със записани хешове на API към раздела за пакетиране, но дъмп с ненаписани хешове на API не се стартира? Очевидно все още има някои промени в този раздел, които не ни позволяват да стартираме програмата, но показват откриването на дебъгера - код [305]. Може да се предположи (и ние видяхме това при премахването на защитните потоци), че пакетиращият, когато стартира програмен дъмп със записани хешове на API, замества някои инструкции за защитен поток с RETN инструкцията. Но как да намеря тази RETN инструкция? Реших да го намеря по следния начин. Отворете нашия файл с коригираната секция за пакетиране, отидете на тази секция и изберете командата за търсене на всички RETN инструкции:


Поставете получения списък в Hex Workshop:

Запазваме получения файл с името Listing RETN в коригираната секция на пакета.
Повтаряме същото действие за бунищетоdumped_.exe със секцията за пакетиране без корекции и запишете получения файл с име Listing RETN в секцията за пакетиране без корекции.
Сега зареждаме и двете обяви в инструмента за сравнение на Hex Workshop и ги сравняваме:

Запазваме промените във файла dumped_.exe и програмата стартира нормално както без дебъгера, така и в дебъгера:

За да разреши този проблем, Хагар измисли много добър метод. Зареждаме нашия файл dumped_.exe в програмата за отстраняване на грешки OllyDbg и отиваме в началото на секцията за пакетиране .prot2. Изберете командата „Търсене на всички команди“ и въведете търсенето за следната инструкция:



Запазете промените и стартирайте програмата. Програмата стартира нормално.
Машината ми има втора операционна система, Windows ME. Копирах файла dumped_.exe в програмната папка PrevedSMS, инсталирана на тази операционна система, и го стартирах. Програмата стартира нормално. Следователно можем да приемем, че сме осигурили работата на разопакования файл на всяка операционна система.
6. Как работи ExeCryptor при изпълнение на откраднати инструкции
Както видяхме по-рано, пакетът ExeCryptor краде инструкции от програмния код и ги изпълнява в своя раздел. В този случай пакетиращият краде инструкции не само от областта OEP, но също така краде инструкции от други области на кода. Възниква въпросът - възможно ли е да намерите и възстановите откраднатите инструкции от секцията за опаковки? Този въпрос е доста труден, тъй като кодът на раздела за пакетиране е разбит от огромен брой условни и безусловни скокове и голям брой боклук код, което значително усложнява анализа на защитния код.
Във втората част на статията реконструирахме кода на OEP, използвайки знания за началото на OEP на стандартния компилатор Delphi и стойноститерегистри. Този код беше както следва:

Тук пакетиращият е откраднал три инструкции и нека да видим как пакетиращият емулира изпълнението на тези инструкции. Първо, когато програмата е спряна във входната точка на пакетера, нека напишем стойностите на регистъра, защото пакетиращият, когато пакетира програмата, гарантира, че първоначалните стойности на регистъра са запазени:


Това ще ни позволи да определим какво пише пакетиращият в своя раздел. Натиснете клавиша F9 и вижте какво пише пакера в своята секция.
Пакерът обменя съдържанието на регистъра [EAX] и регистъра EDX.
Преди - [00AE5150] = 00, EDX = 01. Сега: [00AE5150] = 01, EDX = 00.
Ние ще зададем BP на всички инструкции за запис в тази секция на опаковката, тъй като тези инструкции могат да бъдат повторени няколко пъти.
Съдържанието на регистъра [EAX] се възстановява. Беше [00AE5150] = 01. Сега: [00AE5150] = 00.
Стойността на съдържанието [00B28B70] и регистърът EBP се обменят и стойността на регистъра EBP се добавя към стойността на съдържанието [00B28B70].
Преди - [00B28B70] = 64B2, EBP = 01. Сега: [00B28B70] = 64B3, EBP = 64B2.
Преди - [00B28C66] = 00, AH = 01. Сега: [00B28C66] = 01.
Следва група от четири инструкции, където се съхраняват стойностите на регистрите EDX, ECX, EBX и EAX:
Запазването на стойността на регистъра ESP става, като първо се запише в регистъра EAX:
След това стойността на регистъра EAX = ESP се съхранява с помощта на инструкцията:
Стойността на съдържанието на регистъра [ESP] и стойността на регистъра ECX се обменят.
Преди: ECX = 0012FFF0 , [0012FFC0] = 00000000 Сега: ECX = 00000000, [0012FFC0] = 0012FFF0 .
По този начин пакетът емулира инструкцията PUSH EBP.
По този начин пакетът възстанови новата стойност на ESP регистъра.Тук виждаме, че първоначално пакетиращият е последният, който запазва стойността на ESP регистъра, а сега той е първият, който възстановява новата стойност на ESP регистъра. Ако погледнем прозореца на стека, ще видим следното:


Стойността на съдържанието [00B28B70] и регистърът EBP се обменят и стойността на регистъра EBP се добавя към стойността на съдържанието [00B28B70].
Преди - [00B28B70] = 64B3, EBP = 01. Сега: [00B28B70] = 64B4, EBP = 64B3.
Стойността на съдържанието [00B28B70] и регистърът EBP се обменят и стойността на регистъра EBP се добавя към стойността на съдържанието [00B28B70].
Преди - [00B28B70] = 64B4, EBP = 01. Сега: [00B28B70] = 64B5, EBP = 64B4.
И отново цикълът на записване на регистрите се повтаря.
И следващия път, когато натиснете клавиша F9, програмата спира тук (тук задавам точка на прекъсване на хардуера при достъп):

След това се изпълнява основният код на програмата PrevedSMS.
Много е интересно да се види как пакетът възстановява запазените стойности на регистъра. Ако след като запазим регистрите, проследим малко пакета, много бързо ще намерим инструкции, които се използват за възстановяване на запазените стойности на регистъра.

И в прозореца с връзки получаваме:

Можем да зададем BP на всяка инструкция и да спрем програмата, когато възстановим съхранената стойност на който и да е регистър.
Сега разбираме как работи пакетът, когато изпълнява откраднатите инструкции:
Пакерът първо изчислява константа за EBP регистъра с помощта на инструкцията LOCK XCHG DWORD PTR DS:[EAX],EDX (тук в тази статия първоначалната константа за EBP регистъра е 64B2; тя се променя при всяко стартиране на програмата).
След това пакетиращият дешифрира и изпълнява откраднатата инструкция.
Следизпълнявайки откраднатата инструкция, пакетиращият възстановява стойностите на регистъра, които не се променят, когато се изпълни открадната инструкция. Например, за да възстанови стойността на регистъра EDX, опаковчикът използва инструкцията MOV EDX,DWORD PTR DS:[EDX].
След възстановяване на всички стойности на регистъра пакетиращият използва инструкцията MOV BYTE PTR DS:[EAX+B28B80],0, за да продължи със следващата емулирана инструкция
Следователно процесът на ръчно разопаковане, който описах в тази статия, може да бъде полезен при разопаковане на такива програми.
Бих искал да благодаря на модераторите на форума CRACKL@B, които публикуват статиите ми, както и на членовете на форума bronco, RSI, Gideon Vi, kioresk, r99, pavka и всички останали членове на форума за обсъждането на различни аспекти на разопаковането на този криптор.