avast / retdec

RetDec is a retargetable machine-code decompiler based on LLVM.
https://retdec.com/
MIT License
7.97k stars 942 forks source link

retdec does not find functions set to function pointers #1039

Open probinso opened 2 years ago

probinso commented 2 years ago

I have a program with a list of named function pointers that are searched for execution. The functions that I place in this list do not appear in the decompiled code. In the example below, aexit does not appear at all in the decompiled code, and it's storage list builtins is assigned a memory address.

$ retdec-decompiler --version
RetDec version :  v4.0-378-g59deef20
Commit hash    :  59deef2049b8e5118402c7c86b44f9d6bbc5a437
Build date     :  2021-11-01T17:48:51Z

Makefile

SHELL:=/bin/bash -O globstar

CC=clang
CFLAGS=-g -O0 -I.
PROG=a.out
DEC=retdec-decompiler
DECOMPILED=decompiled

$(PROG): main.c
    $(CC) -o $(PROG) $(CFLAGS) $<

$(DECOMPILED).c: $(PROG)
    $(DEC) $(PROG) --output $@ --cleanup --backend-var-renamer address

clean:
    rm -f *~ *.o *.core *.gch *.{bc,config.json,dsm,ll,config.json,dsm,ll,json} fact_files

veryclean: clean
    rm -rf $(DECOMPILED).c{,.json} $(PROG)

main.c

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

typedef int (*funcptr)(char**, int);
struct list
{
  char* command;
  funcptr mycommand;
  struct list* next;
};
typedef struct list item;

int aexit(char** argv, int argc);
int aenvset(char ** argv, int argc);

void insert(item* node,char* command,funcptr mycommand);
funcptr find(item* node,char* command);

item builtins = {"exit", aexit, NULL};

int aexit(char** argv, int argc)
{
  if (argc > 1)
    exit((int)atoi(argv[1]));
  exit(0);
  return 1;
}

funcptr find(item* node,char* command)
{
  if (node == NULL)
    return NULL;
  else if (strcmp(command,node->command)==0)
    return node->mycommand;
  else
    return find(node->next,command);
}

int main(int argc, char **argv)
{
    funcptr execute = find(&builtins, "exit");
    return execute(argv, argc);
}

decompiled.c

//
// This file was generated by the Retargetable Decompiler
// Website: https://retdec.com
//

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

// ------------------- Function Prototypes --------------------

int32_t (*find(int32_t * node, char * command))(char **, int32_t);

// --------------------- Global Variables ---------------------

int64_t builtins = 0x402004; // 0x404040

// ------------------------ Functions -------------------------

// From module:   /opt/home/git/retdec-fail/main.c
// Address range: 0x401190 - 0x401201
// Line range:    32 - 40
int32_t (*find(int32_t * node, char * command))(char **, int32_t) {
    // 0x401190
    if (node == NULL) {
        // 0x4011f7
        return NULL;
    }
    int64_t v1 = (int64_t)node;
    int32_t (*v2)(char **, int32_t); // 0x401190
    if (strcmp(command, command) != 0) {
        // 0x4011e2
        v2 = find((int32_t *)*(int64_t *)(v1 + 16), command);
    } else {
        // 0x4011d1
        v2 = (int32_t (*)(char **, int32_t))*(int64_t *)(v1 + 8);
    }
    // 0x4011f7
    return v2;
}

// From module:   /opt/home/git/retdec-fail/main.c
// Address range: 0x401210 - 0x401256
// Line range:    43 - 46
int main(int argc, char ** argv) {
    // 0x401210
    return (int64_t)find((int32_t *)&builtins, "exit");
}

// --------------- Dynamically Linked Functions ---------------

// int strcmp(const char * s1, const char * s2);

// --------------------- Meta-Information ---------------------

// Detected compiler/packer: llvm (10.0.0)
// Detected functions: 2
Heilce commented 2 years ago

I encountered the same bug. Do you have any ideas to solve it?