;************************************************************************************* ; MODULE: BASE64.ASM DATE: JANUARY 27,1997 ; AUTHOR: SEAN M. KESSLER ; TARGET: 32 BIT FLAT MODEL ; FUNCTION : BASE64 DECODER ;************************************************************************************* .386 .MODEL FLAT INCLUDE devioctl.inc HANDLE STRUC PHANDLE TYPEDEF FAR PTR HANDLE HANDLE@@mHandle DD <0> HANDLE ENDS INVALID_HANDLE equ 0FFFFFFFFh STRSTR MACRO szStringOne,szStringTwo push offset szStringTwo ; save string one push offset szStringOne ; save string two call _strstr ; call standard library strstr add esp,08h ; reset stack frame ENDM STRCHR MACRO szString,charByte push charByte ; save charByte push offset szString ; save string call _strchr ; call standard library strchr add esp,08h ; reset stack frame ENDM STRLEN MACRO szData push edi ; save destination index register push ecx ; save ecx register mov edi,offset szData ; get string to destination index register mov ecx,0FFFFh ; move 65535 to ecx register xor eax,eax ; clear eax register repnz scasb ; scan string mov eax,0FFFFh ; move 65535 to eax sub eax,ecx ; subtract number of bytes scanned dec eax ; decrement result pop ecx ; restore ecx register pop edi ; restore destination index register ENDM MEMCPY MACRO szDstData,szSrcData,lengthCopy push esi ; save source index register push edi ; save destination index register mov esi,offset szSrcData ; move source data to source index register mov edi,offset szDstData ; move destination data to destination index register mov ecx,lengthCopy ; move number of bytes to copy to ecx register rep movsb ; copy data pop edi ; restore destination index register pop esi ; restore source index register ENDM STRCMP MACRO szStringOne,szStringTwo LOCAL @@STRCMPnotEqual,@@STRCMPequal,@@STRCMPexit push ecx ; save ecx register push edi ; save destination index register push esi ; save source index register mov edi,offset szStringOne ; move string one to destination index register mov esi,offset szStringTwo ; move string two to source index register STRLEN szStringOne ; get length of string one mov ecx,eax ; save length to ecx register STRLEN szStringTwo ; get length of string two cmp ecx,eax ; compare lengths jne @@STRCMPnotEqual ; if lengths differ, strings are not equal @@STRCMPloop: ; loop control mov al,byte ptr[esi] ; get byte from string two cmp al,byte ptr[edi] ; compare with byte from string one jne @@STRCMPnotEqual ; if bytes differ then we're done loop @@STRCMPloop ; iterate through string length @@STRCMPequal: ; equality control mov eax,0001h ; set return code jmp @@STRCMPexit ; we're done @@STRCMPnotEqual: ; inequality control xor eax,eax ; set return code @@STRCMPexit: ; exit sync address pop esi ; restore source index register pop edi ; restore destination index register pop ecx ; restore ecx register ENDM STRNCMP MACRO szStringOne,szStringTwo LOCAL @@STRNCMPloop,@@STRNCMPequal,@@STRNCMPnotEqual,@@STRNCMPexit push ecx ; save ecx register push edi ; save edi register push esi ; save source index register mov edi,offset szStringOne ; move string one to destination index register mov esi,offset szStringTwo ; move string two to source index register STRLEN szStringOne ; get length of string one mov ecx,eax ; save length to ecx register STRLEN szStringTwo ; get length of string two cmp ecx,eax ; compare the lengths jle @@STRNCMPloop ; string one is less equal to string two mov ecx,eax ; string two is less, so use it's length @@STRNCMPloop: ; loop control mov al,byte ptr[esi] ; get byte from string one cmp al,byte ptr[edi] ; compare with byte from string two jne @@STRNCMPnotEqual ; if byte are unequal, strings are unequal inc edi ; increment along string two inc esi ; increment along string one loop @@STRNCMPloop ; keep going @@STRNCMPequal: ; string equal sync address mov eax,0001h ; set return code jmp @@STRNCMPexit ; we're done @@STRNCMPnotEqual: ; string unequal sync address xor eax,eax ; set return code @@STRNCMPexit: ; exit sync address pop esi ; restore source index register pop edi ; restore destination index register pop ecx ; restore ecx register ENDM CREATEFILE MACRO pathFileName,access,share,open,attribute push 0000h ; save handle to template (null) push attribute ; save attributes push open ; save creation flags push 0000h ; save security attributes push share ; save share mode push access ; save acess mode push pathFileName ; save path file name call dword ptr __imp__CreateFileA@28 ; call create ENDM READFILE MACRO hFileHandle,szBuffer,sizeBuffer sub esp,04h ; create bytesRead on stack mov eax,esp ; move bytesRead address to eax push 0000h ; save overlapped structure address push eax ; save pointer to bytesRead push sizeBuffer ; save length of buffer push offset szBuffer ; save address of read buffer push hFileHandle ; save file handle call dword ptr __imp__ReadFile@20 ; call read mov eax,[esp] ; move bytesRead value to eax add esp,04h ; remove bytesRead variable from stack ENDM WRITEFILE MACRO hFileHandle,szBuffer,sizeBuffer sub esp,04h ; create bytesWritten variable on stack mov eax,esp ; move bytesWritten address to eax push 0000h ; save overlapped structure address push eax ; save bytesWritten address push sizeBuffer ; save write length push offset szBuffer ; save address of write buffer push hFileHandle ; save file handle call dword ptr __imp__WriteFile@20 ; call write mov eax,[esp] ; move number of bytes written to eax add esp,04h ; remove bytesWritten variable from stack ENDM CLOSEHANDLE MACRO handle push handle ; save file handle call dword ptr __imp__CloseHandle@4 ; call close ENDM FREAD MACRO sFileInfo,ptrByte LOCAL @@FREADreadError,@@FREADsimpleRead,@@FREADdone cmp sFileInfo.FileInfo@@mBufferIndex,00h ; is buffer index zero jne @@FREADsimpleRead ; if not then just grab next byte READFILE sFileInfo.FileInfo@@mhFileHandle,sFileInfo.FileInfo@@mszBuffer,MaxLength ; otherwise we fill the read buffer cmp eax,0000h ; did we read any data ? je @@FREADreadError ; if not then we're done mov sFileInfo.FileInfo@@mBufferIndex,eax ; move number of bytes read to buffer index mov eax,offset sFileInfo.FileInfo@@mszBuffer ; move address of buffer to eax mov sFileInfo.FileInfo@@mlpBufferPointer,eax ; move address of buffer to lpBufferPointer jmp @@FREADsimpleRead ; grab next byte @@FREADreadError: ; read error sync address xor eax,eax ; set return code jmp @@FREADdone ; we're done @@FREADsimpleRead: ; simple read sync address mov eax,sFileInfo.FileInfo@@mlpBufferPointer ; move address of buffer to eax mov al,byte ptr[eax] ; move byte value to al mov byte ptr[ptrByte],al ; move byte value to user buffer inc sFileInfo.FileInfo@@mlpBufferPointer ; increment along lpBufferPointer dec sFileInfo.FileInfo@@mBufferIndex ; decrement the buffer index mov eax,01h ; set the return code @@FREADdone: ; done reading sync ENDM FWRITE MACRO sFileInfo,ptrByte LOCAL @@FWRITEsimpleWrite,@@FWRITEuseBuffer cmp sFileInfo.FileInfo@@mBufferIndex,MaxLength ; compare buffer index to MaxLength jl @@FWRITEsimpleWrite ; if it's less then insert char into buffer WRITEFILE sFileInfo.FileInfo@@mhFileHandle,sFileInfo.FileInfo@@mszBuffer,MaxLength ; other wise mov sFileInfo.FileInfo@@mBufferIndex,0000h ; set buffer index to zero mov eax,offset sFileInfo.FileInfo@@mszBuffer ; move address of buffer to eax mov sFileInfo.FileInfo@@mlpBufferPointer,eax ; move address of buffer to lpBufferPointer @@FWRITEsimpleWrite: ; simple write sync address cmp sFileInfo.FileInfo@@mlpBufferPointer,0000h ; is buffer pointer null? jne @@FWRITEuseBuffer ; if not then just use it mov eax,offset sFileInfo.FileInfo@@mszBuffer ; move address of buffer to eax mov sFileInfo.FileInfo@@mlpBufferPointer,eax ; move address of buffer to lpBufferPointer @@FWRITEuseBuffer: ; use buffer sync address mov cl,byte ptr[ptrByte] ; move byte to write to cl mov eax,sFileInfo.FileInfo@@mlpBufferPointer ; move address of buffer to eax mov byte ptr[eax],cl ; move byte into buffer inc sFileInfo.FileInfo@@mlpBufferPointer ; increment buffer pointer inc sFileInfo.FileInfo@@mBufferIndex ; increment buffer index mov eax,01h ; set return code ENDM FFLUSH MACRO sFileInfo WRITEFILE sFileInfo.FileInfo@@mhFileHandle,sFileInfo.FileInfo@@mszBuffer,sFileInfo.FileInfo@@mBufferIndex ; write buffer to disk mov sFileInfo.FileInfo@@mBufferIndex,0000h ; set buffer index to zero mov eax,offset sFileInfo.FileInfo@@mszBuffer ; move address of buffer to eax mov sFileInfo.FileInfo@@mlpBufferPointer,eax ; move address of buffer to lpBufferPointer ENDM FGETS MACRO sFileInfo,szBuffer LOCAL @@FGETScont,@@FGETexit,@@FGETsetError,@@FGETScrlf push esi ; save source index register mov esi,offset szBuffer ; move address of buffer into esi @@FGETScont: ; loop control FREAD sFileInfo,esi ; read a byte cmp eax,0000h ; was our read successful? je @@FGETexit ; if not we're done cmp byte ptr[esi],0Dh ; is the byte a carriage return? je @@FGETScrlf ; if yes then jump to handler inc esi ; increment along esi jmp @@FGETScont ; keep reading @@FGETScrlf: ; carriage return control mov byte ptr[esi],00h ; move null into line data sub esp,04h ; create temp var on stack mov esi,esp ; esi points to temp var FREAD sFileInfo,esi ; read line-feed into temp var add esp,04h ; restore stack @@FGETexit: ; exit sync address pop esi ; restore source index register ENDM FileInfo STRUC MaxLength equ 800h FileInfo@@mhFileHandle HANDLE <0> FileInfo@@mszBuffer DB MaxLength DUP(0) FileInfo@@mBufferIndex DD (0) FileInfo@@mlpBufferPointer DD (0) FileInfo ENDS .DATA inputFile FileInfo <<0>> outputFile FileInfo <<0>> lineData DB 400h DUP(0) szDefaultOutputPathFileName DB 'IMAGE.JPG',00h szOutputPathFileName DB 0FFh DUP(0) szFileNameLiteral DB 'filename=',00h szOutBytes DB 04h DUP(0) szInputPathFileName DD ? szBase64ID DB '/9j/',00h szBase64Vector DB 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',00h num DD ? lineLength DD ? itemIndex DD ? numIndex DD ? valueItem DD ? .CODE _decodeBase64 proc near ; WORD decodeBase64(const char *szPathFileName) push ebp ; save stack frame mov ebp,esp ; create new frame push esi ; save source index register push edi ; save destination index register push [ebp+8] ; save pathFileName pop szInputPathFileName ; restore into inputPathFileName cmp szInputPathFileName,0000h ; is the file na null je @@error ; if so then we've got an error CREATEFILE szInputPathFileName,GENERIC_READ,FILE_SHARE_READ,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL mov inputFile.FileInfo@@mhFileHandle,eax ; store the handle cmp inputFile.FileInfo@@mhFileHandle,INVALID_HANDLE ; do we have a valid handle ? je @@error ; if the handle is invalid then we've got an error STRLEN szDefaultOutputPathFileName ; get the length of the default file name MEMCPY szOutputPathFileName,szDefaultOutputPathFileName,eax ; set output file name to default @@search: ; search sync address FGETS inputFile,lineData ; get input line cmp eax,0000h ; did we read anything je @@end ; if not we're done STRSTR lineData,szFileNameLiteral ; look for "filename=" literal cmp eax,0000h ; did we find it jne @@nameFile ; if so then extract the filename STRNCMP szBase64ID,lineData ; compare line to base64 identifier cmp eax,0001h ; if we've got it then we start decoding je @@beginDecode ; jump to decode handler jmp @@search ; keep going @@nameFile: ; nameFile sync address push eax ; save address of filename literal push offset szOutputPathFileName ; save address of filename buffer call _nameFile ; extract the file name add esp,08h ; reset stack frame jmp @@search ; keep going @@beginDecode: ; begin decode sync address CREATEFILE offset szOutputPathFileName,GENERIC_WRITE,FILE_SHARE_READ,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL mov outputFile.FileInfo@@mhFileHandle,eax ; save handle @@continueDecode: ; continue decode sync address STRLEN lineData ; get length of lineData dec eax ; decrement line length mov lineLength,eax ; move line length into lineLength mov itemIndex,0000h ; set itemIndex to zero @@itemLoop: ; itemLoop sync address mov valueItem,0000h ; set valueItem to zero mov esi,offset lineData ; move ptr lineData to esi register add esi,itemIndex ; add itemIndex to address cmp byte ptr[esi+02h],'=' ; is pChar[2] equal to '='? je @@assignOne ; if so then num=1 cmp byte ptr[esi+03h],'=' ; else if pChar[3]='=' je @@assignTwo ; then num=2 mov num,0003h ; otherwise num=3 jmp @@assignContinue ; continue @@assignOne: ; assignment sync address mov num,0001h ; assign 1 to num jmp @@assignContinue ; continue @@assignTwo: ; assignment sync address mov num,0002h ; assign two to num jmp @@assignContinue ; continue @@assignContinue: ; end assignment sync address mov numIndex,0000h ; set numIndex to zero @@numLoop: ; numIndex loop sync address xor eax,eax ; clear out eax mov edi,numIndex ; move numIndex into destination index mov al,byte ptr[esi+edi] ; get the byte at pChar[numIndex] STRCHR szBase64Vector,eax ; ::strchar(szBase64Vector,pChar[numIndex]) cmp eax,0000h ; did we find the token je @@end ; if not then we've got an error mov edi,eax ; move address of found token to edi (pTok) sub edi,offset szBase64Vector ; perform (pTok-szBase64Vector) result to edi mov eax,0003h ; move 3 into eax sub eax,numIndex ; perform (3-numIndex) result to eax mov edx,0006h ; move 6 into edx imul eax,edx ; perform (3-numIndex)*6 result to eax mov cl,al ; move shift value into cl register shl edi,cl ; perform (pTok-smszVec)<<((3-numIndex)*6) result to edi add valueItem,edi ; valueItem+=(pTok-smszVec)<<((3-numIndex)*6) inc numIndex ; increment numIndex mov eax,numIndex ; move numIndex into eax register cmp eax,num ; compare numIndex to num jle @@numLoop ; loop through <= operation mov numIndex,0002h ; set numIndex to 2 @@nextNumLoop: ; next numLoop sync address mov esi,offset szOutBytes ; move szOutBytes address into esi mov edi,numIndex ; move numIndex into edi mov eax,valueItem ; move valueItem into eax register and eax,000000FFh ; apply bit mask mov byte ptr[esi+edi],al ; set byte in szOutBytes shr valueItem,08h ; shift valueItem right 8 bytes dec numIndex ; decrement numIndex cmp numIndex,0000h ; compare numIndex to zero jge @@nextNumLoop ; if >=0 keep going mov esi,offset szOutBytes ; move szOutBytes to esi xor edi,edi ; clear edi @@writeLoop: ; writeLoop sync address FWRITE outputFile,byte ptr[esi+edi] ; write out the byte inc edi ; increment edi cmp edi,num ; compare edi to num jl @@writeLoop ; if it's less then keep going add itemIndex,0004h ; increment itemIndex by four mov eax,itemIndex ; move itemIndex to eax cmp eax,lineLength ; compare itemIndex to lineLength jl @@itemLoop ; if it's less that keep going FGETS inputFile,lineData ; get another line cmp eax,0000h ; did we get a line? je @@end ; if not then we're done jmp @@continueDecode ; otherwise keep going @@end: ; end sync address FFLUSH outputFile ; flush the output file CLOSEHANDLE outputFile.FileInfo@@mhFileHandle ; close output file CLOSEHANDLE inputFile.FileInfo@@mhFileHandle ; close input file @@error: ; error sync address pop edi ; restore destination index register pop esi ; restore source index register pop ebp ; restore prior stack frame retn ; return near to caller _decodeBase64 endp _nameFile proc near push ebp ; save stack frame mov ebp,esp ; create new frame push esi ; save source index register push edi ; save destination index register mov edi,[ebp+8] ; move dest string to destination index register mov esi,[ebp+0Ch] ; move source string to source index register @@NAMEFILEquoteLoop: ; first quote loop control mov al,byte ptr[esi] ; move byte into al cmp al,00h ; is it null? je @@NAMEFILEerror ; if it's null then we've got an error cmp al,'"' ; is it the first quote ? je @@NAMEFILEreadFile ; if so then get the filename inc esi ; increment along esi jmp @@NAMEFILEquoteLoop ; keep going @@NAMEFILEreadFile: ; read file name sync address inc esi ; skip past the first quote mov al,byte ptr[esi] ; read from file name cmp al,'"' ; is the byte the closing quote? je @@NAMEFILEreadEnd ; if so then we're done cmp al,00h ; is the byte a null byte? je @@NAMEFILEreadEnd ; if so then we're done mov byte ptr[edi],al ; store the byte in destination inc edi ; increment along destination jmp @@NAMEFILEreadFile ; keep going @@NAMEFILEreadEnd: ; read end sync address mov byte ptr[edi],00h ; null terminate the string mov eax,0001h ; set return code jmp @@NAMEFILEend ; we're done @@NAMEFILEerror: ; error sync address xor eax,eax ; set error return @@NAMEFILEend: ; end proc sync address pop edi ; restore destination index register pop esi ; restore source index register pop ebp ; restore prior stack frame retn ; return near to caller _nameFile endp public _decodeBase64 extrn __imp__WriteFile@20:near extrn __imp__CloseHandle@4:near extrn __imp__CreateFileA@28:near extrn __imp__GetLastError@0:near extrn __imp__ReadFile@20:near extrn __imp__WriteFile@20:near extrn _strstr:near extrn _strchr:near END