Menu

#9 Binary Replace and NULL Characters

open
nobody
None
5
2014-08-16
2009-10-25
Theo
No

PROBLEM
When performing binary replaces on files which contain the \0character (NULL) or when performing binary replaces using a search string that contains the \0 character (NULL) the replace can fail because the \0 is interpreted as the end of the string.

For example, create a file whose contents are A\0A\0 and attempt to replace A\0A\0 with B\0B\0. The replace will succeed. Now create a file whose contents are \0A\0A\0 and attempt to replace A\0A\0 with B\0B\0. The replace will fail because the first \0 is considered the end of the string.

SOLUTION
The cause of the failure is the use of the strstr function in the _fart function. The strstr function finds an instance of a string within another string, but is designed such that both the input and the search strings must be NULL terminated, which makes it binary incompatible.

To address this problem I wrote a function called strnstrn that determines string lengths based on provided character counts rather than \0 characters embedded in strings.

char *strnstrn(const char *str, const int nStrLen, const char *strSearch, const int nStrSearchLen)
{
// Declare
int bMatchFailed = 0;

// Input string sanity check
if ((str == NULL) || (nStrLen == 0))
return NULL;

// Search string sanity check
if ((strSearch == NULL) || (nStrSearchLen == 0))
return NULL;

// Loop over str
for (int i=0; i<nStrLen; i++)
{
// Look for first character in the string
if(str[i] == strSearch[0])
{
// Setup loop
bMatchFailed = 0;
for (int j=0; j<nStrSearchLen; j++)
{
if(str[i+j] != strSearch[j])
{
bMatchFailed = 1;
break;
}
}

// Check result of match
if (bMatchFailed == 0)
return (char *)(&(str[i]));
}
}

// Return
return NULL;
}

Add the strnstrn function above to the fart.cpp file above the _fart function. Then change the following code in the _fart function:

const char *t = strstr(bp,FindString);

with

const char *t = strnstrn(bp, MAXSTRING, FindString, FindLength);

Presto, problem solved!

Discussion

  • Theo

    Theo - 2009-10-25

    Need to check for that we don't exceed the original string boundaries when comparing strings, so replace

    if(str[i+j] != strSearch[j])
    {
    bMatchFailed = 1;
    break;
    }

    with

    if ((i+j)>=nStrLen)
    {
    bMatchFailed = 1;
    break;
    }
    else if(str[i+j] != strSearch[j])
    {
    bMatchFailed = 1;
    break;
    }

     
  • Theo

    Theo - 2009-10-25

    An additional problem that results in corruption of EXE files occurs because of the use of the fgets and fputs functions, which are also not binary compatible and hence cannot handle strings with /0.

    So in the _fart function, we need to check if the file is binary, and then decide which input and output functions to use:

    1. Declare new variable bytes_read as unsigned long

    2. Replace
    if (!fgets( fart_buf, MAXSTRING, f1 ))
    break;

    with

    if (!_Binary)
    {
    if (!fgets( fart_buf, MAXSTRING, f1 )
    break;
    }
    else
    {
    if ((bytes_read = fread( fart_buf, 1, MAXSTRING, f1 ))==0)
    break;
    }

    3. Replace the sequence below twice. Replace:

    fputs( fart_buf+(bp-b), f2 );

    with

    if(!_Binary)
    {
    fputs( fart_buf+(bp-b), f2 );
    }
    else
    {
    fwrite(fart_buf+(bp-b), 1, bytes_read - (bp-b), f2);
    }

    This fixes the EXE corruption issue.

     

Log in to post a comment.

MongoDB Logo MongoDB