Hard-coded passwords and `strings`

Today I came across this post that states that it is not possible to get a hard-coded password out of a binary by using the strings command.
But a while back I also remember reading another article saying that it is indeed possible.

So, is it?

I grabbed the code from the linked article, compiled it and executed strings on the binary only to get the same results as the original author.

$ strings pass
yomaf <---  

If you look closely the string is kind of there as the yomaf string shows, instead of the whole yomama. But that does not do it for us.
But, hey! I remember doing this very test and getting the password out clean with strings. Maybe it is due to the string being declared as a char [] instead of an explicit size char array?
I went ahead and declared the password string as char[10] and... ta-da! I got my password out correctly.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char **argv) {  
  char password[10] = "yomama";

  if(argc < 2) {
    printf("Usage: %s <password>\n", argv[0]);

  if(strncmp(argv[1], password, strlen(password))) {
  } else {

return(0); // never reached :)  
strings pass | grep yo  

So, what is happening? IDA to the rescue!

Analyzing the code

The real question here is: how does the compiler work and how are the strings being stored?
I assumed that the string was being stored in the .rodata section, as it is the section for the read-only data. But this assumption was wrong. (Notice that for this test I changed the yomama string for the less offensive bingo).

We can clearly see how, instead of referring to the string as a pointer to the .rodata section, it is loading hard-coded constant binary values into the register. And for that it is using the eax register, which is a 32-bit register; meaning that the longer it can hold it's 4 ASCII characters.

Now, what is the difference with the char[10] code?

This one is using the rax register, which is a 64-bit register, thereof capable of holding 8 characters at most, and thereof capable of moving the whole bingo string in a single mov.

Why the difference?

Because if you declare a string as char [] the compiler will automatically fill in between the [] with the appropriate string size, for bingo this is 5 + 1 = 6 bytes. If we write to that stack memory zone using rax we will write 8 bytes, thereof writting past the end of the stack memory allocated for the string. If we declare the buffer as >8 bytes there is no problem whatsoever using rax.
You can double check this with the couple movs below the mov qword ptr [rbp+s], rax. They are there because we have declared the string as char[10].

mov     qword ptr [rbp+s], rax <-- moves 8 bytes  
mov     [rbp+var_18], 0        <-- moves 1 byte  
mov     [rbp+var_10], 0        <-- moves 1 byte  

So it is moving 10 bytes in total.

Declaring it as static

Declaring the variable as static (static char password[10] = "yomama";) makes the compiler move the string to the .rodata section and reference it on the code. Thus, the string will be stored sequentially and you will always be able to get it out using strings.

$ strings pass_static | grep bin