push esi
push 100 ; /size = 100 (256.)
call Chapter7.malloc ; \malloc
mov esi,eax
add esp,4
test esi,esi
je short Chapter7.0040104E
mov eax,dword ptr [esp+C]
cmp eax,100
jg short Chapter7.0040104E
push eax ; /maxlen
mov eax,dword ptr [esp+C] ; |
push eax ; |src
push esi ; |dest
call Chapter7.strncpy ; \strncpy
add esp,0C
Chapter7.0040104E:
mov eax,esipop esi
retn
This function allocates a fixed size buffer (256 bytes long) and copies a user-
supplied string into that buffer. The length of the source buffer is also user-
supplied (through [esp + c]). This is not a typical overflow vulnerability
and is slightly less obvious because the user-supplied length is checked to
make sure that it doesn’t exceed the allocated buffer size (that’s the cmp eax,
100 ). The caveat in this particular sample is the data type of the buffer-length
parameter.
There are two conditional code groups in IA-32 assembly language, signed
and unsigned, each operating on different CPU flags. The conditional code used
in a conditional jump usually exposes the exact data type used in the compari-
son in the original source code. In this particular case, the use of JG(jump if
greater) indicates that the compiler was treating the buffer length parameter as
a signed integer. If the parameter was defined as an unsigned integer or simply
cast to an unsigned integer during the comparison, the compiler would have
generated JA(jump if above) instead of JGfor the comparison. You’ll find more
information on flags and conditional codes in Appendix A.
Signed buffer-length comparisons are dangerous because with the right
input value it is possible to bypass the buffer length check. The idea is quite
simple. Conceptually, buffer lengths are always unsigned values because there
is no such thing as a negative buffer length—a buffer length variable can only
be 0 or some positive integer. When buffer lengths are stored as signed integers
comparisons can produce unexpected results because the condition Signed-
BufferLen <= MAXIMUM_LENwould not only be satisfied when 0 <=
SignedBufferLen <= MAXIMUM_LEN, but also when SignedBufferLen
< 0. Of course, functions that take buffer lengths as input can’t possibly use
negative values, so any negative value is treated as a very large number.
Auditing Program Binaries 257