;---------------------------------------------------------------------; ; ; ; EXE-2-BAT CONVERTER STUB - AWARE CREW - AWARENETWORK.ORG ; ; ; ; nasm -f bin -o B64.COM B64.ASM ; ; ; ;---------------------------------------------------------------------; section .text org 100H ;---------------------------------------------------------------------; ; ; We expect to be called B64.COM SOURCEFILE.BAT OUTFILE.EXE with ; exactly these two commandline parameters in this exact order. ; Then, SOURCEFILE.BAT is parsed until :EOF is encountered. After ; that keyword, this stub expects CR-LF terminated lines of length ; 76 which form the base64-encode of OUTFILE.EXE. The file will be ; decoded and written to OUTFILE.EXE. ; ;--------------------------------;------------------------------------; XOR CX,CX ; zero out CX MOV CL, [BYTE DS:80H] ; size of our commandline MOV DI, CX ; set DI to the entire length ADD DI, 81H ; plus the offset MOV [BYTE DS:DI], BYTE 0 ; place a zero at end of input SPACEFIND: ; DEC DI ; now crawl for the space and CMP [BYTE DS:DI], BYTE 20H ; replace that one with a nullbyte. JNE SPACEFIND ; MOV [BYTE DS:DI], BYTE 0 ; There we have it. MOV DX, DI ; Offset of second parameter INC DX ; just off by one. ;--------------------------------;------------------------------------; MOV AH,3CH ; create a file MOV CX,2H ; hidden file at that INT 021H ; go for it JC NOEXEFILE ; no file for us, panic MOV DI,AX ; destination file handle ;--------------------------------;------------------------------------; MOV AX,3D00H ; open a file: MOV DX,082H ; the batch file. INT 21H ; here we go ... JC NOSRCFILE ; wtf? panic. MOV SI,AX ; source file handle ;--------------------------------;------------------------------------; XOR AX,AX ; zero out AX MOV BX,AX ; and BX MOV DX,SP ; destination is SUB DX,4 ; 4 bytes below current stack MOV CX,1 ; one byte at a time will be read FASTFORWARD: ; PUSH BX ; we will store the last 4 bytes PUSH AX ; of file data as BX:AX MOV AH,3FH ; read, MOV BX,SI ; from the source file, INT 21H ; yes do it. POP AX ; get the data back POP BX ; pop doesn't affect flags so ... JC FILEERROR ; check for file read error CMP AX,4F46H ; BX:AX = **OF ? JNE FORWARD ; if not, read some more CMP BX,3A45H ; BX:AX = :EOF ? JE DECODE ; if yes, decoding is on FORWARD: ; MOV BH,BL ; BH:BL:AH:AL -> BH:BH:AH:AL MOV BL,AH ; -> BH:AH:AH:AL MOV AH,AL ; -> BH:AH:AL:AL JMP FASTFORWARD ; spin it ;--------------------------------;------------------------------------; DECODE: ; Before we can decode the next MOV AX,4201H ; line, seek over the linebreak. MOV BX,SI ; source file XOR CX,CX ; no high word, MOV DX,2 ; seek two bytes ahead INT 21H ; there we go ... JC FILEERROR ; MOV CX, 13H ; 76 bytes of yummy base64 to read ;--------------------------------;------------------------------------; READLINE: ; PUSH CX ; save our counter to the stack SUB SP, 4 ; 4 byte buffer on the stack MOV AH, 3FH ; read from MOV BX, SI ; our beloved source file MOV CX, 4 ; a whole 4 bytes. MOV DX, SP ; to the stack, as mentioned earlier INT 21H ; and here we go. JC FILEERROR ; TEST AX,AX ; maybe we are EOF already JZ PARTYTIME ; if we are, time to get goin' JMP dcd ; otherwise do the decode BACK: ; MOV AH, 40H ; time to write the binary data MOV BX, DI ; to the destination file MOV DX, SP ; and it's right there on the stack! INT 21H ; off it goes JC FILEERROR ; ADD SP, 4 ; back on track with tha stack POP CX ; counter to the counter register LOOP READLINE ; and lewp JMP DECODE ; one more time? ;--------------------------------;------------------------------------; PARTYTIME: ; MOV CX, 4C00H ; errorcode JMP FILECLOSE ; go on with cleanup NOEXEFILE: ; MOV CX, 4C01H ; exe file didn't even open right JMP EXIT ; we can just quit FILEERROR: ; MOV CX, 4C01H ; =(( JMP FILECLOSE ; some file error NOSRCFILE: ; MOV CX, 4C01H ; no source file? JMP FILECLOSE2 ; close the other one and leave FILECLOSE: ; MOV AX, 3EH ; close the ... MOV BX, DI ; ... exe file! INT 21H ; FILECLOSE2: ; MOV AX, 3EH ; and now ... MOV BX, SI ; ... the other one! INT 21H ; ;--------------------------------;------------------------------------; EXIT: ; MOV AX,CX ; it was fun while it lasted. INT 21H ; ;--------------------------------;------------------------------------; ; ; ## , ; ####a ,d###########m, ,##', a# ; ###']#i a##".#"`# "####a,## #' .##' ; ##P' "" .d#P'.# .I "#:##:aaad##' ; ##P' ,ama, .aa, .ama.g mmm d#P' # .I' ##:#####" ; ###' d#I,`#..a#"PI ,#I"## I##' d## ]IaI' d#[ ; ###' ]P ""m#mP#']P .#I #" d##' `" .## ; ##I ]P[ .I'.# ##' # I[ ,##P ,ama ,ama, d#[ .ama.g ; 8##' I#, .I' ]#, ,##B d# aI (##',##"#) d#I,`#. ## ,#I"## ; 8## `####" '####" "##""#m" I## ### #[ ]P ""m#m##[.#I #" ; 8##, _,aaaaaa,_ I## #" # ]P[ .I' ## ##' # I[ ; ###a,. .,add##########bma. )##, .]I I#, .I' )##a#B d# aI ; ########""' `#""""""# "#####P" `####" `###""##""#m" ; ;--------------------------------;------------------------------------; ; dcd function ; decode DWORD from stack to stack. ; ; CX contains number of bytes ;--------------------------------;------------------------------------; dcd: ; POP BX ; Input is in AX:BX in reverse order POP AX ; XOR DX,DX ; Output will be in DX:CL MOV CX,DX ; CL serves as loop counter (CL<4) dcd_PARSE: ; CMP BL,60H ; JG dcd_SMALL ; is it a small letter? CMP BL,40H ; JG dcd_BIG ; or a capital letter? CMP BL,2BH ; JE dcd_62 ; maybe it's a PLUS? CMP BL,2FH ; JE dcd_63 ; or a slash! CMP BL,3DH ; JE dcd_EQUAL ; could be an equal sign. ADD BL,4 ; JMP dcd_DECODED ; ok, it's a number. done. dcd_BIG: ; SUB BL,41H ; -----------------------------------; JMP dcd_DECODED ; dcd_SMALL: ; All these decodes follow naturally SUB BL,47H ; from the base64 encoding standard JMP dcd_DECODED ; alphabet. Just give it a look if dcd_62: ; you are truly interested. MOV BL,03EH ; JMP dcd_DECODED ; -----------------------------------; dcd_63: ; MOV BL,03FH ; JMP dcd_DECODED ; dcd_DECODED: ; PUSH CX ; save our counter onto the stack SHL DX,6 ; now, shift DX by 6 SHR CX,2 ; shift CX by 2, eliminating CL OR DL,CH ; insert upper 6 bits at end of DX OR BL,CL ; insert lower 2 bits at top of BL POP CX ; get original CX from stack MOV CH,BL ; glue BL over CH, all done ;--------------------------------; MOV BL,BH ; now we will shift AX:BX MOV BH,AL ; byte by byte MOV AL,AH ; INC CL ; loop again if ++CL < 4 CMP CL, 4 ; otherwise be done JNE dcd_PARSE ; JMP dcd_DONE ; -----------------------------------; dcd_EQUAL: ; Buffer padding: CMP CX,2 ; Get length of padding JNE D1 ; MOV DH,DL ; padding of length 2, means we MOV DL,CH ; shift by 8 SHL DX,4 ; then shift by 4 JMP D2 ; and be done D1: ; SHL DX,6 ; padding of length 1, means we SHL CL,2 ; do one shift by 6 bits. SHR CX,2 ; OR DL,CL ; D2: ; XCHG DL,DH ; switch byte order XOR AX,AX ; PUSH AX ; on Stack: PUSH DX ; DH-DL-00-00 JMP dcd_RETURN ; dcd_DONE: ; MOV AL,CH ; XOR AH,AH ; PUSH AX ; onto stack: CH-00 XCHG DL,DH ; PUSH DX ; onto stack: DH-DL-CH-00 dcd_RETURN: ; XOR CH,CH ; zero out high byte of CX DEC CX ; number of bytes JMP BACK ; all done! ;--------------------------------;-------------------------[ .aware ]-;