The MASM Forum Archive 2004 to 2012

General Forums => The Laboratory => Topic started by: Larry Hammick on November 09, 2009, 09:05:08 AM

Title: Illustration of a "filter" for the Win32 console
Post by: Larry Hammick on November 09, 2009, 09:05:08 AM
By a "filter", I mean a program that takes a file for input, and outputs another ("filtered") file.
;DUMP.EXE for the Win32 console, illustrative standard-IO filter.
;Also illustrates buffered file input and output.

comment~ Sample build file:
@echo off
\masm32\bin\ml /c /coff dump.asm
if errorlevel 1 goto end
\masm32\bin\polink /SUBSYSTEM:CONSOLE /STACK:4096,4096 /HEAP:4096,4096 dump.obj
del dump.obj
dir dump.exe
:end
~
comment~ When it's assembled, enter e.g.
dump<sometextfile
or
echo some text|dump
or
type sometextfile|dump
and you will see a hex dump of the input. The output may be redirected
to a file or device, just as in DOS.

Filters of this kind can be chained together, as in:
type sometextfile | caps.exe | ltrim.exe
where "caps" and "ltrim" are st-IO filters.
~

.586
.model flat, stdcall
option casemap:none

include \masm32\include\kernel32.inc
includelib \masm32\lib\kernel32.lib

ReadBuff_ equ 200h     ;buffer sizes
WriteBuff_ equ 200h

.data
ExitAddress  dd ?
hRead        dd ?    ;file handle
ReadBuff     dd ?    ;address of a buffer in the stack
amtReadBuff  dd 0    ;number of bytes of data remaining in the buffer
ptrReadBuff  dd ?    ;address of the next byte to get
hWrite       dd ?    ;file handle
WriteBuff    dd ?    ;address of a buffer in the stack
amtWriteBuff dd WriteBuff_    ;number of bytes of space remaining in the buffer
ptrWriteBuff dd ?    ;address to which to put the next byte
bytesperline equ 16
countdown dd bytesperline

.code
Start:
    pop ExitAddress    ;an alternative to ExitProcess or ExitThread
    sub esp,ReadBuff_  ;heap instead of stack could be used for these buffers
    mov ReadBuff,esp
    sub esp,WriteBuff_
    mov WriteBuff,esp
    mov ptrWriteBuff,esp
    invoke GetStdHandle,-10   ; -10 = STD_INPUT_HANDLE
    mov hRead,eax
    invoke GetStdHandle,-11   ; -11 = STD_OUTPUT_HANDLE
    mov hWrite,eax
MainLoop:
    call GetByte
    js InputExhausted
    push eax
    mov al," "
    call PutByte
    pop eax
    call AL2hexAX
    push eax
    call PutByte
    pop eax
    mov al,ah
    call PutByte
    dec countdown
    jnz MainLoop
    mov countdown,bytesperline
    call PutCRLF
    jmp MainLoop
InputExhausted:
    cmp countdown,bytesperline
    je short @F
    call PutCRLF
@@: call FlushWrite
    xor eax,eax
    jmp ExitAddress

GetByte:  ;returns a byte in AL, from the read handle, or SF if end-of-file.
    mov esi,offset amtReadBuff
    dec dword ptr[esi]
    jns short @F   ;if read buffer is empty, read more of the input
    invoke ReadFile,hRead,ReadBuff,ReadBuff_,esi,0
    mov eax,[esi]
    dec eax
    js short AnyRet
    mov [esi],eax
    mov eax,ReadBuff
    mov ptrReadBuff,eax
@@: mov esi,ptrReadBuff
    lodsb
    mov ptrReadBuff,esi
AnyRet: ret

PutCRLF:
    mov al,13
    call PutByte
    mov al,10
PutByte:      ;input is al
    mov edi,ptrWriteBuff
    stosb
    mov ptrWriteBuff,edi
    dec amtWriteBuff
    jnz short AnyRet   ;if write buffer is now full, write what is there
FlushWrite:
    mov eax,ptrWriteBuff
    mov edx,WriteBuff
    sub eax,edx
    invoke WriteFile,hWrite,edx,eax,addr amtWriteBuff,0
    mov amtWriteBuff,WriteBuff_
    mov eax,WriteBuff
    mov ptrWriteBuff,eax
    ret

AL2hexAX:
    mov ah,al
    shr ah,4
    call nibble2hexAL
    xchg al,ah
  nibble2hexAL:
    and al,0Fh
    cmp al,0Ah
    sbb al,69h
    das
    ret

end Start
Title: Re: Illustration of a "filter" for the Win32 console
Post by: dedndave on November 09, 2009, 09:14:20 AM
very cool
Mike (Slugsnack) was playing with this a while back
he was using piping to run one app under another in GUI mode - you might find it interesting
Title: Re: Illustration of a "filter" for the Win32 console
Post by: BlackVortex on November 10, 2009, 02:47:51 AM
Lol, why on earth do you save the calling address from the CreateProcess api and jmp to that ? Weirdness.

I thought people using RET instead of exitprocess was weird, but this ...   :green
Title: Re: Illustration of a "filter" for the Win32 console
Post by: Larry Hammick on November 10, 2009, 05:15:42 AM
I like to be different. Who else would use POP as the very first instruction in a program? :eek But really now, jumping to ExitAddress is available from anywhere in the program, whereas RET isn't, and it makes for one fewer symbol in the import table.
Title: Re: Illustration of a "filter" for the Win32 console
Post by: sinsi on November 10, 2009, 05:32:29 AM
Quote from: Larry Hammick on November 10, 2009, 05:15:42 AM
Who else would use POP as the very first instruction in a program?
malware/virus writers? (no accusations here, just an observation  :bg)
Title: Re: Illustration of a "filter" for the Win32 console
Post by: Larry Hammick on November 10, 2009, 06:41:30 AM
A small subroutine may well start with a pop instruction, e.g.
sz_copy@8:      ;(lpDest,lpSrc)  returns eax pointing at the terminator in the destination
    pop eax
    pop edx      ;dest
    pop ecx      ;src
    push eax
    sub edx,ecx
@@: mov al,[ecx]
    mov [ecx+edx],al
    inc ecx
    test al,al
    jnz short @B
    lea eax,[ecx+edx-1]
    ret  ;stack is clean
Title: Re: Illustration of a "filter" for the Win32 console
Post by: sinsi on November 10, 2009, 07:21:10 AM
For sure, but that's a subroutine, not the first instruction. I've also seen it in exe packers and 'no import' win32 exe's.
So you aren't so different after all  :P
Title: Re: Illustration of a "filter" for the Win32 console
Post by: RuiLoureiro on November 10, 2009, 09:17:38 PM
Quote from: sinsi on November 10, 2009, 05:32:29 AM
Quote from: Larry Hammick on November 10, 2009, 05:15:42 AM
Who else would use POP as the very first instruction in a program?
malware/virus writers? (no accusations here, just an observation  :bg)
I use it a lot of times inside procs and i never write a malware or virus  :bg
Rui
Title: Re: Illustration of a "filter" for the Win32 console
Post by: Larry Hammick on November 11, 2009, 11:31:14 AM
A "varargs" routine that cleans its own stack is likely to be begin by popping the return address. Simple illustration:
add_em_all:      ;takes a zero-terminated list of dwords on the stack
    pop edx
    xor eax,eax
@@: pop ecx
    add eax,ecx
    test ecx,ecx
    jnz short @B
    jmp edx

I've written my own partial substitute for wsprintf that cleans its own stack. Not very hard.