我需要从可执行文件中恢复我的源代码

ayt*_*e17 4 c disassembly

现在是半夜,我不小心打字覆盖了我所有的工作

gcc source.c -o source.c
Run Code Online (Sandbox Code Playgroud)

我仍然拥有原始的二进制文件,我唯一的希望是对其进行反汇编,但我不知道如何或使用什么最好的工具来获得最易读的结果。我知道这可能不是发帖的正确位置,但我很紧张。有人可以帮我吗?

Igo*_*sky 5

感谢您上传文件。正如我所怀疑的那样,它没有被剥离,所以函数名称仍然存在。除了标准样板代码之外,我还可以识别函数main, register_broker, connect_exchange(未使用和空的)和handle_requests.

我在 IDA Pro 上花了一些时间,恢复该main()功能并不太难。首先,这是main()来自 IDA 的未经修改的原始列表:http : //pastebin.com/sBxhRJMM

要继续,您需要熟悉AMD64 调用约定。总而言之,前四个参数在 RDI(EDI)、RSI(ESI)、RDX(EDX) 和 RCX(ECX) 中传递。其余部分在堆栈上传递,但所有调用main()最多只使用四个参数,因此我们无需担心。

IDA 有用地标记了标准 C 函数的参数,甚至重命名了一些局部变量。但是,它可以进一步改进和评论。例如,因为我们在 中main(),我们知道argc(第一个参数)来自 EDI(因为它是一个int32 位的含义,它只使用 RDI 的低半部分)并且argv来自 RSI(它是一个指针,所以它使用完整的8 个字节的寄存器)。因此,我们可以重命名 EDI 和 RSI 复制到的局部变量:

mov     [rbp+argc], edi
mov     [rbp+argv], rsi
Run Code Online (Sandbox Code Playgroud)

接下来是一个简单的条件块:

mov     [rbp+argc], edi
mov     [rbp+argv], rsi
Run Code Online (Sandbox Code Playgroud)

这里我们将 argc 与 2 进行比较,如果相等,则在代码中进一步跳转。如果相等,我们调用fwrite()。它的第一个参数是 in rdi,并且rdi是从 加载的rax,它保存着一个常量字符串“Usage”的地址。第二个参数是 inesi并且是 1,第三个 inedx并且是 5,第四个 in rcx,从rdx它加载的值为stderr@@GLIBC_2_2_5,这基本上是对stderr来自 libc的变量的奇特引用。把它们串起来,我们得到:

fwrite("Usage", 1, 5, stderr);
Run Code Online (Sandbox Code Playgroud)

根据我的经验,我可以说它很可能是一个 inlined fprintf,因为 5 正是字符串的长度。即原始代码可能是:

fprintf(stderr, "Usage");
Run Code Online (Sandbox Code Playgroud)

下一个调用是一个简单的exit(1);. 将两者与比较相结合,我们得到:

if ( argc != 2 )
{
  fprintf(stderr, "Usage");
  exit(1);
}
Run Code Online (Sandbox Code Playgroud)

继续这样,我们可以识别他们使用的其他调用和变量。描述这一切有点乏味,所以我上传了反汇编的注释版本,我试图在其中显示每个调用的等效 C 代码。你可以在这里看到它:http : //pastebin.com/p5sRSwgQ

从那个评论版本不难想象可能的版本main()

int main(int argc, char **argv)
{
  if ( argc != 2 )
  {
    fprintf(stderr, "Usage");
    exit(1);
  }
  char name[256];
  gethostname(name, sizeof(name));
  struct hostent* _hostent = gethostbyname(name);
  struct in_addr *_addr0 = (struct in_addr *)(_hostent->h_addr_list[0]);
  struct sockaddr_in addr;
  addr.sin_family = AF_INET;
  addr.sin_port = htons(0);
  addr.sin_addr.s_addr = _addr0->s_addr;
  char *tmp = (char *)malloc(6);
  sprintf(tmp, "%d", addr.sin_port);
  char *ip_str = inet_ntoa(*_addr0);
  char *newbuf = (char *)malloc(strlen(argv[1]) + strlen(ip_str) + strlen(tmp) + 5);
  strcpy(newbuf, "r");
  strcat(newbuf, " ");
  strcat(newbuf, argv[1]);
  strcat(newbuf, " ");
  strcat(newbuf, ip_str);
  strcat(newbuf, " ");
  strcat(newbuf, tmp);
  register_broker(newbuf);
  int fd = socket(PF_INET, SOCK_STREAM, 0);
  if ( fd < 0 )
  {
    perror("Error creating socket");
    exit(1);
  }
  if ( bind(fd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
  {
    perror("Error binding socket");
    exit(1);
  }
  if ( listen(fd, 0x80) != 0 )
  {
    perror("Error listening on socket");
    exit(1);
  }
  handle_requests(fd);
}
Run Code Online (Sandbox Code Playgroud)

恢复其他两个函数留给读者练习:)