News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Illustration of a "filter" for the Win32 console

Started by Larry Hammick, November 09, 2009, 09:05:08 AM

Previous topic - Next topic

Larry Hammick

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

dedndave

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

BlackVortex

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

Larry Hammick

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.

sinsi

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)
Light travels faster than sound, that's why some people seem bright until you hear them.

Larry Hammick

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

sinsi

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
Light travels faster than sound, that's why some people seem bright until you hear them.

RuiLoureiro

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

Larry Hammick

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.