The MASM Forum

General => The Laboratory => Topic started by: TouEnMasm on December 05, 2015, 08:24:33 PM

Title: Avoiding Buffer Overruns
Post by: TouEnMasm on December 05, 2015, 08:24:33 PM
The Dynamic Allocation of Memory is a solution to do this.
But it can be slow.
Here is a solution for static buffer.

A macro (SECURE) create the needed data in .data and .data?.
A function (EcritTamp) replace lstrcpy and lstrcat in secure form.
It's not possible to made an Overrun with it.




;************* Avoiding Buffer Overruns ********************************
.const
SECURETAMPON STRUCT
ptampon  dd ?
Tailletampon dd ?
decale dd ? ;si zero,ecrit en debut tampon
SECURETAMPON ENDS

LIMITE_TAMP equ 600h

;--------------- SECURE abuffer,db LIMITE_TAMP dup (?) ----------------------------------
SECURE MACRO nombuffer:REQ,quoted_text:VARARG
local declaretampon,declaredata
declaretampon CATSTR <nombuffer>,<_s >,<SECURETAMPON >,<<offset nombuffer,sizeof nombuffer,0>>
declaredata CATSTR <nombuffer>,< >,<quoted_text>
.data?
declaredata
.data
declaretampon
ENDM
.data
SECURE abuffer,db LIMITE_TAMP dup (?) ;create abuffer_s in data and abuffer in data?
;-------------- data to write ----------------
szinclude db "Include Myfile.txt",0
mot1   db " ;Just a sample to concatene text",0
retourligne db 13,10,0
OneBuffer_s SECURETAMPON <>
.code
;---------- write in the buffer ----------------------------------------
EcritTamp PROC uses esi edi ebx init:DWORD,psecuretamp:DWORD,psubchain:DWORD,lenchain:DWORD
Local taille:DWORD,retour
mov retour,0
mov ebx,psecuretamp

.if init == 1
mov [ebx].SECURETAMPON.decale,0 ;init
.elseif init == 2
;init tampon local,need lea to get it's adress
mov eax,psubchain ;utilisé pour passer l'adresse du tampon
mov [ebx].SECURETAMPON.ptampon,eax
mov eax,lenchain ;utilisé pour passer la taille du tampon
mov [ebx].SECURETAMPON.Tailletampon,eax
mov [ebx].SECURETAMPON.decale,0
.endif
.if lenchain == 0
invoke lstrlen,psubchain
.else
mov eax,lenchain
.endif
mov taille,eax
;----------------------------
mov ecx,[ebx].SECURETAMPON.decale
add ecx,taille
.if ecx < [ebx].SECURETAMPON.Tailletampon
mov edi,[ebx].SECURETAMPON.ptampon
add edi,[ebx].SECURETAMPON.decale
mov esi,psubchain
mov ecx,taille
and ecx,3
.if ecx != 0
rep movsb
.endif
mov ecx,taille
and ecx,0fffffffch
shr ecx,2 ;divise 4
.if ecx != 0
rep movsd
.endif

mov byte ptr [edi],0
mov eax,taille
add [ebx].SECURETAMPON.decale,eax
mov retour,1
.else
invoke MessageBox,NULL,psubchain,TXT("EcritTamp Overflow"),MB_OK
.endif
mov eax,retour
ret
EcritTamp ENDP
Protect_Local_Buffer PROC
Local OneBuffer[LIMITE_TAMP]:BYTE
;Couldn't use the macro here
;The OneBuffer_s must be declared in data : OneBuffer_s SECURETAMPON <>
;The parametre 2 init all
invoke EcritTamp,2,addr OneBuffer_s,addr OneBuffer,sizeof OneBuffer ;init
;.......
Protect_Local_Buffer ENDP
;----------------- usage  ---------------------------------
start:
;----------------- Same usage as lstrcpy and lstrcat in secure form -------------
;1=Init task + copy
invoke EcritTamp,1,addr abuffer_s,addr szinclude,0 ;init +chercher la longueur
;0=add the chain to the tamp
invoke EcritTamp,0,addr abuffer_s,addr mot1,0
invoke EcritTamp,0,addr abuffer_s,addr retourligne,0
.if eax != 0 ;-- write operations are successfull
invoke MessageBox,NULL,addr abuffer,TXT("pragma"),MB_OK
mov retour,1
.endif


end start

Title: Re: Avoiding Buffer Overruns
Post by: jj2007 on December 05, 2015, 09:39:55 PM
Maybe you could post a complete example with standard masm32rt.inc headers, so that people can test it?
Title: Re: Avoiding Buffer Overruns
Post by: TouEnMasm on December 05, 2015, 10:25:47 PM

ok,here it is
Title: Re: Avoiding Buffer Overruns
Post by: jj2007 on December 06, 2015, 02:57:09 AM
It works :t

But why is the exe size 8.5k?
Title: Re: Avoiding Buffer Overruns
Post by: TouEnMasm on December 06, 2015, 05:20:12 AM
"But why is the exe size 8.5k?"
That's the good question,I haven't answer,It's not big,but can be decrease with release version.

What can be better is a macro for local buffer.
Any idea ?

Title: Re: Avoiding Buffer Overruns
Post by: jj2007 on December 06, 2015, 06:03:40 AM
Quote from: ToutEnMasm on December 06, 2015, 05:20:12 AMWhat can be better is a macro for local buffer.

StackBuffer? (http://www.webalice.it/jj2006/MasmBasicQuickReference.htm#Mb1255)
Title: Re: Avoiding Buffer Overruns
Post by: TouEnMasm on December 06, 2015, 07:38:34 PM

Not,
a SECURE_LOCAL macro who create the needed data in local memory.
The problem is that the word Local is a reserved word for the MACRO.
This to avoid the init operation for local buffer.
"   invoke EcritTamp,2,addr OneBuffer_s,addr OneBuffer,sizeof OneBuffer ;init"

Title: Re: Avoiding Buffer Overruns
Post by: TouEnMasm on December 06, 2015, 08:31:13 PM
Found,
can be used at the end of locals variables

Quote
SECURE_LOCAL MACRO nombuffer:REQ,quoted_text:VARARG
   local declaretampon,declaredata,securebuffer
   securebuffer CATSTR <nombuffer>,<_s>
   declaretampon CATSTR <LOCAL nombuffer>,<_s>,<:SECURETAMPON >
   declaredata CATSTR <LOCAL nombuffer>,<quoted_text>
      declaredata    
   lea eax,securebuffer
   lea edx,nombuffer
   mov [eax].SECURETAMPON.ptampon,edx
   mov [eax].SECURETAMPON.Tailletampon,sizeof nombuffer
   mov [eax].SECURETAMPON.decale,0
ENDM


Protect_Local_Buffer PROC
SECURE_LOCAL OneBuffer,[LIMITE_TAMP]:BYTE
invoke EcritTamp,1,addr OneBuffer_s,addr szinclude,0
overrunlocal:
invoke EcritTamp,0,addr OneBuffer_s,addr mot1,0
invoke EcritTamp,0,addr OneBuffer_s,addr retourligne,0
.if eax == 0 ;-- write operations failed
invoke MessageBox,NULL,addr abuffer,TXT("STOP local Buffer"),MB_OK
.else
jmp overrunlocal
.endif
ret
Protect_Local_Buffer ENDP

Title: Re: Avoiding Buffer Overruns
Post by: jj2007 on December 06, 2015, 08:57:54 PM
Here is a complete example. It seems to work, but it throws an exception for LIMITE_TAMP=18000. See here for possible reasons (http://masm32.com/board/index.php?topic=94.msg26592#msg26592) (last line before the EDIT).

include \masm32\include\masm32rt.inc

LIMITE_TAMP=16000 ; try 18000

SECURE_LOCAL MACRO nombuffer:REQ,quoted_text:VARARG
   local declaretampon,declaredata,securebuffer
   securebuffer CATSTR <nombuffer>,<_s>
   declaretampon CATSTR <LOCAL nombuffer>,<_s>,<:SECURETAMPON >
   declaredata CATSTR <LOCAL nombuffer>,<quoted_text>
      declaredata   
   lea eax,securebuffer
   lea edx,nombuffer
   mov [eax].SECURETAMPON.ptampon,edx
   mov [eax].SECURETAMPON.Tailletampon,sizeof nombuffer
   mov [eax].SECURETAMPON.decale,0
ENDM

.data
MyArray db LIMITE_TAMP dup("x"), 0

.code

;************* Avoiding Buffer Overruns ********************************
.const
SECURETAMPON STRUCT
ptampon  dd ?
Tailletampon dd ?
decale dd ? ;si zero,ecrit en debut tampon
SECURETAMPON ENDS

; LIMITE_TAMP equ 600h

;--------------- SECURE abuffer,db LIMITE_TAMP dup (?) ----------------------------------
SECURE MACRO nombuffer:REQ,quoted_text:VARARG
local declaretampon,declaredata
declaretampon CATSTR <nombuffer>,<_s >,<SECURETAMPON >,<<offset nombuffer,sizeof nombuffer,0>>
declaredata CATSTR <nombuffer>,< >,<quoted_text>
.data?
declaredata
.data
declaretampon
ENDM
.data
SECURE abuffer,db LIMITE_TAMP dup (?) ;create abuffer_s in data and abuffer in data?
;-------------- data to write ----------------
szinclude db "Include Myfile.txt",0
mot1   db " ;Just a sample to concatene text",0
retourligne db 13,10,0
OneBuffer_s SECURETAMPON <>
.code
;---------- write in the buffer ----------------------------------------
EcritTamp PROC uses esi edi ebx init:DWORD,psecuretamp:DWORD,psubchain:DWORD,lenchain:DWORD
Local taille:DWORD,retour
mov retour,0
mov ebx,psecuretamp

.if init == 1
mov [ebx].SECURETAMPON.decale,0 ;init
.elseif init == 2
;init tampon local,need lea to get it's adress
mov eax,psubchain ;utilisé pour passer l'adresse du tampon
mov [ebx].SECURETAMPON.ptampon,eax
mov eax,lenchain ;utilisé pour passer la taille du tampon
mov [ebx].SECURETAMPON.Tailletampon,eax
mov [ebx].SECURETAMPON.decale,0
.endif
.if lenchain == 0
invoke lstrlen,psubchain
.else
mov eax,lenchain
.endif
mov taille,eax
;----------------------------
mov ecx,[ebx].SECURETAMPON.decale
add ecx,taille
.if ecx < [ebx].SECURETAMPON.Tailletampon
mov edi,[ebx].SECURETAMPON.ptampon
add edi,[ebx].SECURETAMPON.decale
mov esi,psubchain
mov ecx,taille
and ecx,3
.if ecx != 0
rep movsb
.endif
mov ecx,taille
and ecx,0fffffffch
shr ecx,2 ;divise 4
.if ecx != 0
rep movsd
.endif

mov byte ptr [edi],0
mov eax,taille
add [ebx].SECURETAMPON.decale,eax
mov retour,1
.else
invoke MessageBox,NULL,psubchain,chr$("EcritTamp Overflow"),MB_OK
.endif
mov eax,retour
ret
EcritTamp ENDP

Protect_Local_Buffer PROC
SECURE_LOCAL OneBuffer,[LIMITE_TAMP]:BYTE
invoke EcritTamp,1,addr OneBuffer_s,addr szinclude,0
overrunlocal:
invoke EcritTamp,0,addr OneBuffer_s,addr mot1,0
invoke EcritTamp,0,addr OneBuffer_s,addr retourligne,0
.if eax == 0 ;-- write operations failed
invoke MessageBox,NULL,addr abuffer,chr$("STOP local Buffer"),MB_OK
.else
jmp overrunlocal
.endif
ret
Protect_Local_Buffer ENDP

.code
start:
  call Protect_Local_Buffer
  MsgBox 0, "All is fine", "Hi", MB_OK
  exit

end start
Title: Re: Avoiding Buffer Overruns
Post by: Grincheux on December 07, 2015, 01:02:27 AM
It is ok to make secure macro but you use a unsecured function : lstrlen

QuoteUsing this function incorrectly can compromise the security of your application. lstrlen assumes that lpString is a null-terminated string, or NULL. If it is not, this could lead to a buffer overrun or a denial of service attack against your application.
Consider using one of the following alternatives: StringCbLength or StringCchLength.
Title: Re: Avoiding Buffer Overruns
Post by: TouEnMasm on December 07, 2015, 03:24:30 AM

18000 must be max size of segment stack for the proc ,there is need to increase it

StringCbLength is an inline function (code in .h) and need a compiled Library with inline functions.
Have you it ?.

Title: Re: Avoiding Buffer Overruns
Post by: Grincheux on December 07, 2015, 04:46:23 AM
I have VS2015 is it in it?
Title: Re: Avoiding Buffer Overruns
Post by: Grincheux on December 07, 2015, 04:54:52 AM
Try this one from Agner Frog


;**************************  strlen32.asm  **********************************
; Author:           Agner Fog
; Date created:     2008-07-06
; Last modified:    2008-07-06
; Syntax:           MASM/ML 6.x, 32 bit
; Operating system: Windows, Linux, BSD or Mac, 32-bit x86
; Instruction set:  80386
; Description:
; Standard strlen function:
; size_t strlen(const char *str);
; Finds the length of a zero-terminated string of bytes, optimized for speed.
; Uses 32-bit registers to check four bytes at a time, all memory reads aligned.
;
; Alternatives:
; In 64-bit systems or when SSE2 is available, use strlenSSE2.asm
; More versions are available in www.agner.org/optimize/asmlib.zip
;
; The latest version of this file is available at:
; www.agner.org/optimize/asmexamples.zip
; Copyright (c) 2008 GNU General Public License www.gnu.org/copyleft/gpl.html
;******************************************************************************
.386
.model flat

.code

_strlen PROC    NEAR
; extern "C" int strlen (const char * s);
; Works in all 32-bit systems
; In Linux, remove the underscore from the function name.

        push    ebx
        mov     ecx, [esp+8]           ; get pointer to string
        mov     eax, ecx               ; copy pointer
        and     ecx, 3                 ; lower 2 bits of address, check alignment
        jz      L2                     ; string is aligned by 4. Go to loop
        and     eax, -4                ; align pointer by 4
        mov     ebx, [eax]             ; read from nearest preceding boundary
        shl     ecx, 3                 ; mul by 8 = displacement in bits
        mov     edx, -1
        shl     edx, cl                ; make byte mask
        not     edx                    ; mask = 0FFH for false bytes
        or      ebx, edx               ; mask out false bytes

        ; check first four bytes for zero
        lea     ecx, [ebx-01010101H]   ; subtract 1 from each byte
        not     ebx                    ; invert all bytes
        and     ecx, ebx               ; and these two
        and     ecx, 80808080H         ; test all sign bits
        jnz     L3                     ; zero-byte found
       
        ; Main loop, read 4 bytes aligned
L1:     add     eax, 4                 ; increment pointer by 4
L2:     mov     ebx, [eax]             ; read 4 bytes of string
        lea     ecx, [ebx-01010101H]   ; subtract 1 from each byte
        not     ebx                    ; invert all bytes
        and     ecx, ebx               ; and these two
        and     ecx, 80808080H         ; test all sign bits
        jz      L1                     ; no zero bytes, continue loop
       
L3:     bsf     ecx, ecx               ; find right-most 1-bit
        shr     ecx, 3                 ; divide by 8 = byte index
        sub     eax, [esp+8]           ; subtract start address
        add     eax, ecx               ; add index to byte
        pop     ebx
        ret
_strlen ENDP

END
Title: Re: Avoiding Buffer Overruns
Post by: TouEnMasm on December 07, 2015, 05:37:16 AM
I have solved the problem for Windows 10
I have added the strsafe inline functions at the crt inline function
The new crt10_32.lib is in the package
This allow to use the StringCbLength in the sample (translated sdk + msvcrt.lib)
The strsafe.h is in the sdk 10 or less
Title: Re: Avoiding Buffer Overruns
Post by: Grincheux on December 07, 2015, 06:03:56 AM
I launched the program. It displayed a dialog box twice and finished when I click the OK button.