1

I have never seen something like this before but I assume this is some kind of way C++ allocates dynamic strings. In my decompilation listing in Ghidra I see something like:

  local_14 = DAT_00404004 ^ (uint)&stack0xfffffff0;
  local_70 = 0x2120302e;
  local_90 = 0x636c6557;
  uStack140 = 0x20656d6f;
  uStack136 = 0x45206f74;
  uStack132 = 0x7972636e;
  local_6c = 0xa20;
  local_80 = 0x6f697470;
  uStack124 = 0x694b206e;
  uStack120 = 0x76206172;
  uStack116 = 0x322e342e;
  local_6a = 0;
  local_28 = 0x203a656d;
  plea_str = 0x61656c50;
  uStack60 = 0x69206573;
  uStack56 = 0x7475706e;
  uStack52 = 0x756f7920;
  local_30 = 0x616e726573752072;
  local_24 = 0;
  local_60 = 0x656c500a;
  uStack92 = 0x20657361;
  uStack88 = 0x75706e69;
  uStack84 = 0x6f792074;
  local_48 = 0x3a64726f;
  local_50 = 0x7773736170207275;
  local_20 = 0x656d6f636c65570a;
  local_44 = 0x20;
  local_18 = 0x20;
  local_d0 = 0xa2e6e;
  local_f0 = 0x6f72570a;
  uStack236 = 0x7020676e;
  uStack232 = 0x77737361;
  uStack228 = 0x2e64726f;
  local_e0 = 0x656c5020;
  uStack220 = 0x20657361;
  uStack216 = 0x20797274;
  uStack212 = 0x69616761;
  your_str = 0x72756f59;
  uStack156 = 0x65737520;
  uStack152 = 0x6d616e72;
  uStack148 = 0x203a65;
  local_c0 = 0x72756f59;
  uStack188 = 0x73617020;
  uStack184 = 0x726f7773;
  uStack180 = 0x203a64;
  local_b0 = 0x766e490a;
  uStack172 = 0x64696c61;
  uStack168 = 0x6d616e20;
  uStack164 = 0xa2165;

I am not totally sure what local_14 is doing either. But each of these locals is a string as you can tell from the bytes. Hovering over them gives the string (in reverse). I'd like to find a way to combine these in a way that makes them make more sense but despite my best efforts I cannot type them correct to get ghidra to recognize what they are and their relationship. What is the best way to handle these strings to clean up my decompilation?

2
  • local_14 might be some sort of SEH or cookie handling. The others are probably a single char[] misinterpreted to many ints. Try to change the type of the lowest stack-address to an char array.
    – tkausl
    Apr 30 at 5:22
  • You need some experience for that, but most (if not all) of the individual octets of these values are within the ASCII printable range. Whenever I see this in IDA I try R to validate my assumption and then act accordingly. But with Ghidra I have no idea.
    – 0xC0000022L
    May 5 at 9:40

1 Answer 1

2

This is a standard method for the C and C++ compilers to build static strings directly on the stack. This method will be used by the compiler when compiling this code:

#include <cstdio>

int main() {
    char str1[] = "hello world from some string that is constructed directly on the stack";
    printf("%s\n", str1);                                                                  
    return 0;
}

Result in Ghidra:

undefined8 main(void)

{
    long in_FS_OFFSET;
    long local_58;
    undefined8 uStack80;
    undefined8 uStack72;
    undefined8 uStack64;
    undefined8 uStack56;
    undefined8 uStack48;
    undefined8 uStack40;
    undefined8 uStack32;
    undefined4 uStack24;
    undefined2 uStack20;
    undefined uStack18;
    long lStack16;
    
    lStack16 = *(long *)(in_FS_OFFSET + 0x28);
    local_58 = 0x6f77206f6c6c6568;
    uStack80 = 0x6d6f726620646c72;
    uStack72 = 0x747320656d6f7320;
    uStack64 = 0x61687420676e6972;
    uStack56 = 0x6e6f632073692074;
    uStack48 = 0x6465746375727473;
    uStack40 = 0x6c74636572696420;
    uStack32 = 0x656874206e6f2079;
    uStack24 = 0x61747320;
    uStack20 = 0x6b63;
    uStack18 = 0;
    puts((char *)&local_58);
    if (lStack16 != *(long *)(in_FS_OFFSET + 0x28)) {
                    // WARNING: Subroutine does not return
        __stack_chk_fail();
    }
    return 0;
}

The only way I could find to make the output a little less noisy is to change the type of the variable that holds the beginning of each string to char[N] where N is the size of the string. In I've retyped the local_58 variable to char[71] and I got this:

undefined8 main(void)

{
    long lVar1;
    long in_FS_OFFSET;
    char local_58 [71];
    
    lVar1 = *(long *)(in_FS_OFFSET + 0x28);
    local_58._0_8_ = 0x6f77206f6c6c6568;
    local_58._8_8_ = 0x6d6f726620646c72;
    local_58._16_8_ = 0x747320656d6f7320;
    local_58._24_8_ = 0x61687420676e6972;
    local_58._32_8_ = 0x6e6f632073692074;
    local_58._40_8_ = 0x6465746375727473;
    local_58._48_8_ = 0x6c74636572696420;
    local_58._56_8_ = 0x656874206e6f2079;
    local_58._64_4_ = 0x61747320;
    local_58._68_2_ = 0x6b63;
    local_58[70] = '\0';
    puts(local_58);
    if (lVar1 != *(long *)(in_FS_OFFSET + 0x28)) {
                    // WARNING: Subroutine does not return
        __stack_chk_fail();
    }
    return 0;
}

It's still noisy, but at least now it uses just 1 variable for a string, and it's easier to rename the variables.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.