News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Avoiding Buffer Overruns

Started by TouEnMasm, December 05, 2015, 08:24:33 PM

Previous topic - Next topic

TouEnMasm

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

Fa is a musical note to play with CL

jj2007

Maybe you could post a complete example with standard masm32rt.inc headers, so that people can test it?

TouEnMasm

Fa is a musical note to play with CL

jj2007

It works :t

But why is the exe size 8.5k?

TouEnMasm

"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 ?

Fa is a musical note to play with CL

jj2007


TouEnMasm


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"

Fa is a musical note to play with CL

TouEnMasm

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

Fa is a musical note to play with CL

jj2007

Here is a complete example. It seems to work, but it throws an exception for LIMITE_TAMP=18000. See here for possible reasons (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

Grincheux

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.
Kenavo (Bye)
----------------------
Help me if you can, I'm feeling down...

TouEnMasm


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 ?.

Fa is a musical note to play with CL

Grincheux

Kenavo (Bye)
----------------------
Help me if you can, I'm feeling down...

Grincheux

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
Kenavo (Bye)
----------------------
Help me if you can, I'm feeling down...

TouEnMasm

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
Fa is a musical note to play with CL

Grincheux

I launched the program. It displayed a dialog box twice and finished when I click the OK button.
Kenavo (Bye)
----------------------
Help me if you can, I'm feeling down...