Statistics

Members: 1927
News: 293
Web Links: 1
Visitors: 3962680

Who's Online

We have 2 guests online
Damn Vulnerable LinuxDamn Vulnerable Linux (DVL) is a Linux-based (modified Damn Small Linux) tool for IT-Security & IT-Anti- Security and Attack & Defense. [CLICK HERE FOR MORE INFOS! ]

Featured Conference Video

T16-Recon2006-Joe_Stewart-OllyBonE.gif OllyBone - Semi-Automatic Unpacking on IA-32. View the conference video here!
Home arrow Conference Proceedings arrow Assembly arrow Formatted Numeric Output
Formatted Numeric Output
User Rating: / 0
PoorBest 
Written by Laura Fairhead   


Here I am going to present you with a very useful routine for numeric output. I have been using it myself for sometime and now I think it is almost perfect.

It consists of 2 basic API's. The first (nuconvs), you call when you want to change the parameters of the main routine (nuconv). You simply call it with one DWORD in EAX, this specifies the following:

EAX = SSFFPPRR (hexadecimal value of course) SS size size of the datum you will be calling the main routine with,

                only 3 values are valid:
0=byte
1=word
2=dword
FF    field   size of a field in which to right-justify the number,
if this is = 0 then there is no right-justification you
only get the number
PP    pad     the ASCII value of the character to use to right-justify
the number in the field of output

RR radix the radix to output the number in

Once you've set the control parameters you can call the main routine (nuconv) freely to do the work. You call the main routine with ES:DI set to where the output is to be stored, and the value to be output in AL or AX or EAX (depending on what data size you set).

I use the word 'output' here which might conjure up images of the screen, but in fact what we are doing here is writing all the ASCII to memory. This is much more powerful than incorporating all that OS/application specific nonsense, and it really doesn't cost much overhead at all (in fact this is the way C does it and even though I **HATE** C, here it is right on the mark;)

Here is the code:

================START OF CODE============================================== ;
;nuconvs- set control parameters for 'nuconv' ;
; !! this must be called at least once before calling nuconv ;
;entry: EAX=SSFFPPRR (hex digits)
;

;         where:  SS=data size (0=byte,1=word,2=dword)
;                 FF=field size (0=none)
;                 PP=pad char
;                 RR=radix (2-16)
;
;     !!  these parameters must be set correctly by the application
;     !!  they are not validated in anyway and invalid parameters
;     !!  will cause undefined operation

;
;exit: (all registers preserved)
;

nuconvs PROC NEAR

        MOV DWORD PTR CS:[nuradix],EAX
RET

nuconvs ENDP

;
;control parameters
;
; !! these absolutely must be in the below order due to the way the above ; routine works
;

nuradix DB ?            ;output radix
nupad   DB ?            ;pad character
nufld   DB ?            ;field size
nudsiz  DB ?            ;data size

;
;nuconv- output value in accumalator -> ES:DI ;
; !! see 'nuconvs' header for more information ;
;entry: AL|AX|EAX=value to output
; ES:DI=address to write output data ;

;        size of accumulator that is used depends on what the current data
;        size is ( as specified by a previous call to 'nuconvs' )

;
;
;exit: DI=updated to offset of last character + 1 ;
; (all other registers preserved) ;

nuconv PROC NEAR
;
;all registers are going to be preserved ;

        PUSH DS
PUSH EAX
PUSH EBX
PUSH CX
PUSH EDX

;
;save some CS: overrides
;

        PUSH CS
POP DS

;
;initialise
;
; set EBX =radix
; CX =fieldsize
;
; also we zero pad out the datum passed so it fills EAX ;

XOR EBX,EBX

        CMP BL,BYTE PTR DS:[nudsiz]
JNP SHORT ko1
JS SHORT ko0
MOV AH,0
ko0:    DEC BX
AND EAX,EBX
INC BX

ko1:

        MOV BL,BYTE PTR DS:[nuradix]
MOV CH,0
MOV CL,BYTE PTR DS:[nufld]

;
;calculate digits and push to stack
;
; EAX is divided and modulus taken which is the standard way, ; loop exits when it reaches 0 or the field size is hit ; notice that if CX=0 on entry to this then the field size ; will be effectively unbounded
;
nulop0: XOR EDX,EDX

        DIV EBX
PUSH DX
AND EAX,EAX
LOOPNZ nulop0

;
;'output' the field padding
;
; the number of padding characters is normally the value ; now in CX (ie: fieldsize - digits ). however no pad chars ; should be output if field size = 0. i think the check here ; for this is nice and tight (read the code...) ;

        MOV BX,CX
NEG BX
JNS SHORT ko
MOV AL,BYTE PTR DS:[nupad]
REP STOSB

ko:
;
;'output' all the digits
;
; CX is set to the number of digits on the stack we have to output ; ie: fieldsize - ( fieldsize - digits ) ;

        MOV CH,0
MOV CL,BYTE PTR DS:[nufld]
ADD CX,BX

;
; now we pop off those #CX digits translating into ASCII using a nice ; variation of the traditional speed method ;

MOV BX,OFFSET nudat

nulop1: POP AX

        XLAT
STOSB
LOOP nulop1

;
; restore all registers and exit (in case it wasn't obvious!) ;

        POP EDX
POP CX
POP EBX
POP EAX
POP DS
RET

;
nudat DB "0123456789ABCDEF"
;
nuconv ENDP

==================END OF CODE==============================================