Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect size for stack-based variables in x86 64bit binaries #6486

Open
0x4b6579 opened this issue May 7, 2024 · 1 comment
Open

Incorrect size for stack-based variables in x86 64bit binaries #6486

0x4b6579 opened this issue May 7, 2024 · 1 comment
Assignees
Labels
Feature: Decompiler Status: Triage Information is being gathered

Comments

@0x4b6579
Copy link

0x4b6579 commented May 7, 2024

Describe the bug
I have a very simple C code, and have a variable with size of 1024 bytes. When I build it as a 64bits executable, Ghidra confuses and thinks it's 1032 bytes. When I build a 32bits executable, the size is detected correctly.

I spotted this behavior in x86 64, but I guess it's not limited to it.

The code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8080
#define MAXLINE 10024

int main() {
    int sockfd;
    char *buffer = malloc(10024);
    struct sockaddr_in servaddr, cliaddr;

    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("socket creation failed");
        //exit(EXIT_FAILURE);
        free(buffer);
        return 1;
    }

    memset(&servaddr, 0, sizeof(servaddr));
    memset(&cliaddr, 0, sizeof(cliaddr));

    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = INADDR_ANY;
    servaddr.sin_port = htons(PORT);

    if (bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    int len, n;
    len = sizeof(cliaddr);

    n = recvfrom(sockfd, buffer, MAXLINE, MSG_WAITALL, (struct sockaddr *)&cliaddr, &len);
    buffer[n] = '\0';
    printf("Client : %s\n", buffer);

    char buff2[1024]; // <- my variable

    strcpy(buff2, buffer);

    close(sockfd);
    return 0;
}

Decompiler result:

undefined8 main(void)

{
  int iVar1;
  undefined8 uVar2;
  ssize_t sVar3;
  long in_FS_OFFSET;
  socklen_t local_44c;
  int local_448;
  int local_444;
  char *local_440;
  sockaddr local_438;
  sockaddr local_428;
  char local_418 [1032]; // <- my variable
  long local_10;

  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  local_440 = (char *)malloc(0x2728);
  local_448 = socket(2,2,0);
  if (local_448 < 0) {
    perror("socket creation failed");
    free(local_440);
    uVar2 = 1;
  }
  else {
    memset(&local_438,0,0x10);
    memset(&local_428,0,0x10);
    local_438.sa_family = 2;
    local_438.sa_data[2] = '\0';
    local_438.sa_data[3] = '\0';
    local_438.sa_data[4] = '\0';
    local_438.sa_data[5] = '\0';
    local_438.sa_data._0_2_ = htons(0x1f90);
    iVar1 = bind(local_448,&local_438,0x10);
    if (iVar1 < 0) {
      perror("bind failed");
                    /* WARNING: Subroutine does not return */
      exit(1);
    }
    local_44c = 0x10;
    sVar3 = recvfrom(local_448,local_440,0x2728,0x100,&local_428,&local_44c);
    local_444 = (int)sVar3;
    local_440[local_444] = '\0';
    printf("Client : %s\n",local_440);
    strcpy(local_418,local_440);
    close(local_448);
    uVar2 = 0;
  }
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return uVar2;
}

To Reproduce
Steps to reproduce the behavior:

  1. Select a 64bit binary (without 32 in names) from compiled.zip
  2. Open the binary in Ghidra
  3. Go to main function
  4. See the size of variable

Expected behavior
Having the correct size of 1024 bytes

Environment (please complete the following information):

  • OS: Linux 6.7
  • Java Version: 17.0.10
  • Ghidra Version: 11.0.3
  • Ghidra Origin: official GitHub distro
@01ChenQing
Copy link

I don't think a decompiler can recover the length of a variable very precisely.
For example, there are several consecutive variables on the stack that are only defined but not used.
In addition, the actual stack size may not match the size of the source code after the code is compiled, because the compiler aligns the stack during compilation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature: Decompiler Status: Triage Information is being gathered
Projects
None yet
Development

No branches or pull requests

4 participants