• Welcome to Valhalla Legends Archive.
 

SStrChr and SStrChrR - annotated

Started by iago, May 14, 2004, 08:36 PM

Previous topic - Next topic

iago

Just for fun, here's a couple of simple storm functions:

.text:1503AA50 ; Returns the substring after the first occurance of the specific character in the string.  Returns NULL if the character is not found.
.text:1503AA50
.text:1503AA50 ; char *__fastcall SStrChr(char *str,char c)
.text:1503AA50                 public SStrChr
.text:1503AA50 SStrChr         proc near               ; CODE XREF: SBmpSaveImageEx+6Dp
.text:1503AA50                                         ; SBmpSaveImageEx+7Ap ...
.text:1503AA50                 mov     eax, ecx        ; Move the string into eax
.text:1503AA52                 test    eax, eax        ; Ensure that it's a valid character
.text:1503AA54                 jnz     short SStrChrValidString
.text:1503AA56                 push    ERROR_INVALID_PARAMETER ; dwErrCode
.text:1503AA58                 call    SErrSetLastError
.text:1503AA5D                 xor     eax, eax
.text:1503AA5F                 retn
.text:1503AA60 ; ---------------------------------------------------------------------------
.text:1503AA60
.text:1503AA60 SStrChrValidString:                     ; CODE XREF: SStrChr+4j
.text:1503AA60                 mov     cl, [eax]       ; Move the current character into ecx
.text:1503AA62                 test    cl, cl          ; Check if it's null
.text:1503AA64                 jz      short SStrChrReturn0 ; If it's null, return 0
.text:1503AA66
.text:1503AA66 SStrChrTop:                             ; CODE XREF: SStrChr+20j
.text:1503AA66                 cmp     cl, dl          ; Compare the current character to the character we're looking for
.text:1503AA68                 jz      short SStrChrReturn ; If they're equal, return the rest of the string
.text:1503AA6A                 mov     cl, [eax+1]     ; ecx gets the next character into the string
.text:1503AA6D                 inc     eax             ; eax goes to the next character
.text:1503AA6E                 test    cl, cl          ; Check if the character is null
.text:1503AA70                 jnz     short SStrChrTop
.text:1503AA72
.text:1503AA72 SStrChrReturn0:                         ; CODE XREF: SStrChr+14j
.text:1503AA72                 xor     eax, eax
.text:1503AA74
.text:1503AA74 SStrChrReturn:                          ; CODE XREF: SStrChr+18j
.text:1503AA74                 retn
.text:1503AA74 SStrChr         endp



.text:1503AA80 ; Exported entry 570.
.text:1503AA80 ; Exported entry 572.
.text:1503AA80
.text:1503AA80
.text:1503AA80 ; Returns the address of the final occurance of c within the string str.  If it is not found, NULL is returned.
.text:1503AA80
.text:1503AA80 ; char *__fastcall SStrChrR(const char *str,char c)
.text:1503AA80                 public SStrChrR
.text:1503AA80 SStrChrR        proc near               ; CODE XREF: sub_15001420+82p
.text:1503AA80                                         ; sub_150024C0+D3p ...
.text:1503AA80                 test    ecx, ecx        ; Make sure we have a non-null string
.text:1503AA82                 jnz     short SStrChrValidParameter
.text:1503AA84                 push    ERROR_INVALID_PARAMETER ; dwErrCode
.text:1503AA86                 call    SErrSetLastError
.text:1503AA8B                 xor     eax, eax        ; return 0
.text:1503AA8D                 retn
.text:1503AA8E ; ---------------------------------------------------------------------------
.text:1503AA8E
.text:1503AA8E SStrChrValidParameter:                  ; CODE XREF: SStrChrR+2j
.text:1503AA8E                 push    ebx
.text:1503AA8F                 mov     bl, [ecx]       ; Move the first character in ecx to bl
.text:1503AA91                 push    esi
.text:1503AA92                 xor     esi, esi        ; Clear esi
.text:1503AA94                 test    bl, bl          ; Check if the character is null
.text:1503AA96                 jz      short SStrChrReturnEsi
.text:1503AA98
.text:1503AA98 SStrChrTopLoop:                         ; CODE XREF: SStrChrR+24j
.text:1503AA98                 cmp     bl, dl          ; Compare the character to the character we're searching for
.text:1503AA9A                 jnz     short SStrChrNotEqual
.text:1503AA9C                 mov     esi, ecx        ; If they're equal, move the character here
.text:1503AA9E
.text:1503AA9E SStrChrNotEqual:                        ; CODE XREF: SStrChrR+1Aj
.text:1503AA9E                 mov     bl, [ecx+1]     ; Set the current character to the next character
.text:1503AAA1                 inc     ecx             ; Go to the next character
.text:1503AAA2                 test    bl, bl          ; Loop as long as we aren't at null
.text:1503AAA4                 jnz     short SStrChrTopLoop ; Compare the character to the character we're searching for
.text:1503AAA6
.text:1503AAA6 SStrChrReturnEsi:                       ; CODE XREF: SStrChrR+16j
.text:1503AAA6                 mov     eax, esi
.text:1503AAA8                 pop     esi
.text:1503AAA9                 pop     ebx
.text:1503AAAA                 retn
.text:1503AAAA SStrChrR        endp


One question I have is, why do they each have 2 ords?  Is there some reason for that?
This'll make an interesting test for broken AV:
QuoteX5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*


Eibro

I don't have a lot of experience doing this, but here's my go at converting it to C
char* __fastcall SStrChrR( const char* str, char c ) {

   if ( str == NULL ) {
      SSetLastError( ERROR_INVALID_PARAMETER );
      return NULL;
   }

   char* found = NULL;
   while ( *str != NULL ) {
      if ( c == *str )
         found = str;
   }

   return found;
}

char* __fastcall SStrChr( char* str, char c ) {

   if ( str == NULL ) {
      SSetLastError( ERROR_INVALID_PARAMETER );
      return NULL;
   }
   
   while ( *str != c || *str != NULL ) ++str;

   return str;
}
Eibro of Yeti Lovers.

iago

I believe your while loop in the SStrChr should be &&, not ||
This'll make an interesting test for broken AV:
QuoteX5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*


Moonshine

#3
Quote from: Eibro[yL] on May 14, 2004, 11:28 PM
I don't have a lot of experience doing this, but here's my go at converting it to C
char* __fastcall SStrChrR( const char* str, char c ) {

  if ( str == NULL ) {
     SSetLastError( ERROR_INVALID_PARAMETER );
     return NULL;
  }

  char* found = NULL;
  while ( *str != NULL ) {
     if ( c == *str )
        found = str;
  }

  return found;
}

char* __fastcall SStrChr( char* str, char c ) {

  if ( str == NULL ) {
     SSetLastError( ERROR_INVALID_PARAMETER );
     return NULL;
  }
 
  while ( *str != c || *str != NULL ) ++str;

  return str;
}


You missed the char* incrementation in your first function.

Here's what I got:


char * __fastcall SStrChr( char * str, char ch ) {
  if (!str) {
     //SErrSetLastError(ERROR_INVALID_PARAMETER);
     return (NULL);
  }

  for (int i = 0; *str; i++, *str++)
     if (*str == ch)
        return (str);  

  return (NULL);
}

const char * __fastcall SStrChrR( const char * str, char ch ) {
   if (!str) {
      //SErrSetLastError(ERROR_INVALID_PARAMETER);
      return (NULL);
   }

   int i;
   const char * pRet = NULL;
   for (i = 0; *str; i++, *str++)
      if (*str == ch)
         pRet = str;

   return (pRet);
}



Edit: iago, are you SURE the second function isn't returning a const char*?  It doesn't really make sense otherwise.


Adron

I don't see why a strchr function should return a const char* instead of a char*. Makes much more sense to return a char*.

The found variable going out of scope is not a problem.


Moonshine

#5
I forgot that found was pointing to the parameter itself -- my bad.  Anyways, SStrChrR should definitely be returning a const char * if the parameter is const char *.  Otherwise, you'd need to const_cast<>() it at return, and that's dangerous.

Adron

#6
Quote from: Moonshine on May 15, 2004, 04:32 PM
I forgot that found was pointing to the parameter itself -- my bad.  Anyways, SStrChrR should definitely be returning a const char * if the parameter is const char *.  Otherwise, you'd need to const_cast<>() it at return, and that's dangerous.

Ah. I got confused because you said the second function, and in the C++ post, it's the argument of the first function that is const char *. Either way; I think he put a const on it that shouldn't be there. It's very useful to have strchr and strrchr return a char *.

Maddox

#7
Quote from: Moonshine on May 15, 2004, 04:13 PM
You missed the char* incrementation in your first function.

Here's what I got:


char * __fastcall SStrChr( char * str, char ch ) {
  if (!str) {
     //SErrSetLastError(ERROR_INVALID_PARAMETER);
     return (NULL);
  }

  for (int i = 0; *str; i++, *str++)
     if (*str == ch)
        return (str);  

  return (NULL);
}

const char * __fastcall SStrChrR( const char * str, char ch ) {
   if (!str) {
      //SErrSetLastError(ERROR_INVALID_PARAMETER);
      return (NULL);
   }

   int i;
   const char * pRet = NULL;
   for (i = 0; *str; i++, *str++)
      if (*str == ch)
         pRet = str;

   return (pRet);
}



Edit: iago, are you SURE the second function isn't returning a const char*?  It doesn't really make sense otherwise.



More like

char * __fastcall SStrChr( char * str, char ch ) {
  if (!str) {
     //SErrSetLastError(ERROR_INVALID_PARAMETER);
     return (NULL);
  }

   while(*str) {
       if (*str == ch)
           return (str);
       str++;
   }

  return (NULL);
}
asdf.