heloo.
how make function GetCL in fasm pleas help me

soory fo my english
Posted on 2005-11-10 02:16:01 by zames
zames,

This is the best I can do for you. I disassembled the MASM32 GetCL function from witin an application and formated it as bare mnemonics. It is still in standard Intel notation so you wil need to modify the notation so it will build in FASM. The procedure has been very reliable but it probably needs a rewrite to modernise it. You can use the reference in the MASM32 help file for how the procedure works and what the return values are.


; ллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл

fn_00401030:

    push ebp
    mov ebp, esp
    add esp, 0FFFFFE7Ch
    push esi
    push edi
    call GetCommandLineA
    mov , eax
    xor ecx, ecx
    mov esi,

  lbl0:
    lodsb
    cmp al, 0
    jz lbl1
    cmp al, 22h
    jnz lbl0
    inc ecx
    jmp lbl0

  lbl1:
    push ecx
    shr ecx, 1
    shl ecx, 1
    pop eax
    cmp eax, ecx
    jz lbl2
    pop edi
    pop esi
    mov eax, 3
    leave
    ret 8

  lbl2:
    mov esi,
    lea edi,

  lbl3:
    lodsb
    cmp al, 0
    jz lbl5
    cmp al, 9
    jnz lbl4
    mov al, 20h

  lbl4:
    stosb
    jmp lbl3

  lbl5:
    stosb
    lea eax,
    mov esi, eax
    mov edi, eax

  lbl6:
    lodsb
    cmp al, 0
    jnz lbl7
    jmp lbl12

  lbl7:
    cmp al, 22h
    jnz lbl8
    stosb
    jmp lbl9

  lbl8:
    stosb
    jmp lbl6

  lbl9:
    lodsb
    cmp al, 20h
    jnz lbl10
    mov al, 0FEh

  lbl10:
    cmp al, 22h
    jnz lbl11
    stosb
    jmp lbl6

  lbl11:
    stosb
    jmp lbl9

  lbl12:
    stosb
    lea eax,
    mov esi, eax
    lea edi,
    mov ecx, 0

  lbl13:
    lodsb
    cmp al, 20h
    jz lbl13

  lbl14:
    cmp ecx,
    jz lbl17
    lodsb
    cmp al, 0
    jz lbl19
    cmp al, 20h
    jnz lbl16

  lbl15:
    lodsb
    cmp al, 20h
    jz lbl15
    inc ecx
    cmp al, 0
    jz lbl19

  lbl16:
    jmp lbl14

  lbl17:
    stosb

  lbl18:
    lodsb
    cmp al, 20h
    jz lbl19
    cmp al, 0
    jz lbl19
    stosb
    jmp lbl18

  lbl19:
    mov al, 0
    stosb
    cmp ecx,
    jnb lbl20
    mov edi,
    mov al, 0
    stosb
    mov eax, 2
    pop edi
    pop esi
    leave
    ret 8

  lbl20:
    lea eax,
    mov esi, eax
    mov edi,

  lbl21:
    lodsb
    cmp al, 0
    jz lbl23
    cmp al, 22h
    jz lbl21
    cmp al, 0FEh
    jnz lbl22
    mov al, 20h

  lbl22:
    stosb
    jmp lbl21

  lbl23:
    stosb
    mov esi,
    lodsb
    cmp al, 0
    jnz lbl24
    pop edi
    pop esi
    mov eax, 4
    leave
    ret 8

  lbl24:
    mov eax, 1
    pop edi
    pop esi
    leave
    ret 8


Regards,

hutch at movsd dot com
Posted on 2005-11-10 22:01:41 by hutch--
zames, unless the bug has been fixed, I would advice against using hutch's GetCL as it has/had known buffer overflow problems.

http://www.masmforum.com/simple/index.php?topic=1443.0
http://www.masmforum.com/simple/index.php?topic=1534.0
Posted on 2005-11-11 02:46:36 by f0dder
It is a mistake to assume poor high level code design with assembler procedures. In terms of primitives a command line parsing algo performs a different task to testing a command line length and/or setting a buffer size and controlling the input length.

The command line buffer is controlled by the OS and late versions of Windows have 32k so all you need to do if you application is being placed where it s subject to potential exploits is to check the LENGTH of the command line and reject it if it is too long for the application's use.

This is how simple it is in MASM32 to test this condition.

main proc

    .if len(rv(GetCommandLine)) > 128
      print "Warning, Some idiot is trying a stack overflow exploit.",13,10
      ret
    .endif

    print "It appears the command line did not exceed the limit",13,10

    ret

main endp

You should have no problems doing the same test with FASM.

The simplicity of assembler code when properly understood saves you from other people slow bloated badly designed C++ code. If and where you do have some serios security concern, it is ALWAYS safer to design the code to block the risk that accept someone elses crappy code design.
Posted on 2005-11-11 17:49:35 by hutch--
Here's a cmdline argument parser that has no silly hardcoded assumptions on commandline buffer string length, nor amount of arguments the user wishes to pass. It doesn't modify the input buffer either; this adds a bit to the complexity of the algorith, but means it will NOT break if Microsoft decides to make the GetCommandLine() memory read-only in a future windows version.

It eliminates whitespace, and supports the usual double-quoted strings. It does NOT perform any expansion of arguments, so _g_cmdline_args[0] is not necessarily the full path to your executable; if somebody types "main blabla" from a console, _g_cmdline_args[0] will be "main", not even "main.exe", thus the routine can easily be adapted to a generic string tokenizer.

The parsing logic is a simple copy-paste of what I use in my C++ code, compiled with optimize-for-size - the assembly code can certainly be improved, but this was written for correct operation, not speed. When used for commandline parsing it's only called once anyway.

The assembly code is written in FASM/NASM style assembly without any macros or highlevel statements, which means it's easy to convert to any assembler of choice. It might hurt readability a bit, so I've included the C++ source it was based on.

If you find any bugs or have suggestions for improvements, please let me know - there's NO excuses for buggy code or kludgy workarounds.

See attached .zip for "the whole package" - I'm posting the main FASM code here, too, for future reference even when attachments are pruned.



format ms coff

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; DATA section
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
section '.data' data
_g_cmdline_block dd 0
_g_cmdline_args dd 0
_g_cmdline_argcount dd 0

PUBLIC _g_cmdline_block
PUBLIC _g_cmdline_args
PUBLIC _g_cmdline_argcount


; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; CODE section
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
section '.code' code

EXTRN _GetProcessHeap@0
EXTRN _HeapAlloc@12

EXTRN _malloc

; internal_alloc: allocates memory, amount of bytes passed in EAX.
internal_alloc:
push eax ; dwBytes
call _GetProcessHeap@0
push dword 0 ; dwFlags
push eax ; hHeap
call _HeapAlloc@12
ret



;
; void __stdcall cmdline_init(const char *input);
;  tokenizes `input', removing whitespace and handling double-quoted arguments.
;  Output: g_cmdline_block contains input in tokenized-and-terminated form,
;          g_cmdline_args is an array of pointers into g_cmdline_block,
; g_cmdline_argcount is the number of pointers in g_cmdline_args.
;
PUBLIC _cmdline_init@4
_cmdline_init@4:
_input$ equ 8
_totalbytes$ equ (-16)
_pushedstart$ equ (-24)

push ebp
mov ebp, esp

push ebx
push esi
push edi
sub esp, 4

xor esi, esi
mov [_g_cmdline_argcount], esi
mov , esi

mov ebx,
cmp byte , 0
je .doneparse

mov eax, ebx

.mainloop:
; skip whitespace
cmp byte , ' '
jne .notws1
.skipws1:
inc esi
cmp byte , ' '
je .skipws1
.notws1:

; if we reached end of string, break
mov al,
test al, al
je .doneparse

; handle quote-delimited args
cmp al, '"'
jne .notquote

; in quotes, consume until endquote
inc esi
mov edi, esi
mov al,
test al, al
je .next_iteration

.find_endquote:
cmp al, '"'
je .consume_done
inc edi
mov al,
test al, al
jne .find_endquote
jmp .consume_done

.notquote:
; not in quotes, consume until quote or whitespace
lea edi,

jmp .consume_loop
.consume:
cmp al, '"'
je .consume_done
cmp al, ' '
je .consume_done
inc edi
.consume_loop:
mov al,
test al, al
jne .consume

.consume_done:
; at this point we have a string to add, or an empty string in cases like
; two doublequotes right next to eachother.
cmp edi, esi
jbe .next_iteration

; push {start, end} pair to stack
; !!!
push edi
push esi
; !!!

; increase totalbytes... +1 because of NUL terminator
mov eax, edi
sub eax, esi
inc eax
add , eax

inc dword [_g_cmdline_argcount]

.next_iteration:
lea esi,
lea eax,
cmp byte , 0
jne .mainloop

.doneparse:

; Allocate memory for the pointers-to-arguments buffer. Exit if no args
; were detected.
mov eax, [_g_cmdline_argcount]
test eax, eax
jz .exit

shl eax, 2
call internal_alloc
mov [_g_cmdline_args], eax

; allocate memory for the tokenized commandline buffer
mov eax,
call internal_alloc
mov [_g_cmdline_block], eax


; now comes the easy part - filling the g_cmdline_args with pointers, and
; at the same time g_cmdline_block with tokenized and NUL-terminated strings;
; copied from the input buffer.
;
mov ecx, [_g_cmdline_argcount]
mov edi, [_g_cmdline_block]

lea ebx,
mov edx, [_g_cmdline_args]
.fill_loop:
; store arg pointer
mov , edi
add edx, 4

; copy string
push ecx
mov eax, ; start-index
mov ecx, ; end-index
sub ecx, eax

mov esi,
add esi, eax
rep movsb
xor al, al
stosb
pop ecx

; process next item
sub ebx, 8
dec ecx
jnz .fill_loop

.exit:
pop edi
pop esi
pop ebx

leave

retn 4

Attachments:
Posted on 2005-11-12 06:12:04 by f0dder
I suggest the member was looking for the simplicity of use when he asked about the GetCL procedure. It was written for win9x 128 byte command line limit in 1999 but its rarely exceeded. When I get around to it I will write one for a 32k limit but tere is no great demand at the moment.

Here is the 2k bloated pig in MASM. Should be very easy to convert to FASM.


; ллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл
    include \masm32\include\masm32rt.inc
; ллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл

comment * -----------------------------------------------------
                        Build this  template with
                      "CONSOLE ASSEMBLE AND LINK"

                        LEANER AND MEANER MASM
        ----------------------------------------------------- *

    .code

start:
 
; ллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл

    call main
    exit

; ллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл

main proc

    LOCAL acnt  :DWORD
    LOCAL pbuf  :DWORD
    LOCAL buffer[128]:BYTE

    mov pbuf, ptr$(buffer)
    cmp len(GetCommandLine),128    ; test command line length
    jle @F

    ret                            ; exit on exploit

  @@:
    mov acnt, 1                    ; set the argument counter

  @@:
    cmp rv(GetCL,acnt,pbuf), 1      ; read each arg into buffer
    jne @F
    print pbuf,13,10                ; display it at the console
    add acnt, 1
    jmp @B
  @@:

    ret

main endp

; ллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллллл

end start
Posted on 2005-11-12 08:25:55 by hutch--
Yay for workarounds to insecure code :)

http://www.asmcommunity.net/board/index.php?topic=22332.msg167787#msg167787 - code works, and doesn't need to be "updated to 32k limit" since it has no assumptions. You could use it on a multi-megabyte string if you wanted to. It's dynamic and it works ^_^
Posted on 2005-11-12 08:35:28 by f0dder
hmmmm,

> Yay for workarounds to insecure code

Knowing the difference between a command line parser and a test for a security issue is the difference between a minimal assembler method of achieving the task versus a far larger bloated C++ style of code. Would you use a sort algorithm to format a hard disk or a search algorithm to display an image on the screen ?

Low level programming involves the use of primitives and in this instance it uses the measurement of the command line length and a command line parser to select each argument and puts the control directly in the hands of the programmer to select the functionaity they require, not what someone else wants to impliment on them complete with the bloat and unused functionality.

It may be normal to treat C++ programmers like idiots but it is not a wise choice with assembler programmers who generally prefer to know what is going on with code instead of someone elses black box.

Regards,

hutch at movsd dot com
Posted on 2005-11-12 17:19:40 by hutch--
Hello Hutch and f0dder,

I am too lazy to argue with you guys.

Hutch,
You are wrong to treat assembly programmers as knowing what they are doing because this is not true. Does all your users of the getcl function know about the potential bugs? All the bugs in the masm32lib that have been pointed out by f0dder were not really announced by you.

f0dder,
let them suffer. Not your problem anyway, the world would not be more secured.
Posted on 2005-11-12 20:22:00 by roticv