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
Maybe you could post a complete example with standard masm32rt.inc headers, so that people can test it?
ok,here it is
It works :t
But why is the exe size 8.5k?
"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 ?
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)
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"
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
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
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.
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 ?.
I have VS2015 is it in it?
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
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
I launched the program. It displayed a dialog box twice and finished when I click the OK button.