第一次听说二进制反汇编时,我以为它可以被称为汇编代码的完美反编译工具,但我仍然不明白为什么不是这样。我以为汇编操作码可以直接转换为二进制序列,也可以直接从二进制序列转换回操作码,但后来我听说了一些可能将代码和数据混合在一起的事情,还有可能使我想到可以分解任何二进制文件然后将其重新组装以重新创建相同的二进制文件。请不要立即对我投反对票。我对逆向工程几乎一无所知,我正在考虑开始进行逆向冒险。您能否在某些示例中让我简单些,为什么事情像它们一样?

#1 楼

首先,欢迎进入逆向工程领域,如果真的有一个像完美的反汇编程序这样的工具,那么整个堆栈交换论坛甚至都不会成立。我想开始谈论反转的真正含义以及它的含义,因为我认为这是解决问题的一种更合适的方法。从两种意义上讲,我的意思是说,二进制的转储似乎是一个非常大的零和一序列,实际上是您最喜欢的视频游戏或驱动程序。 br />老实说,这个序列可以是文本文件,程序,驱动程序,图像,音乐,视频,木马等任何东西。假设您知道上述内容之一,那么您仍然不知道如何解释它,如果是某种媒体,它是什么格式(png,mp3,avi ...)?
如果它是一个针对哪个平台(Windows / Linux)的程序,甚至更糟糕的是,它甚至针对(x86,ARM,PowerPC,MSP430 ...)的CPU体系结构,以及该CPU的版本是什么对于?。等待,但是如果已加密怎么办?这是什么加密方式?我相信您现在已经明白了。特别是关于代码反汇编。反汇编正是将不同的二进制序列转换为原始操作码的过程,但是,当您获得一个程序并假设您知道平台/ CPU /版本等时。

并且,假设操作码不能不能混在一起。例如,假设0101(指令a),0011(b)是操作码,假设还有更长的不同操作码01010011(c)和00110101(d)。给定序列0101001100110101
您如何知道如何解释代码(abba,cd,cab ..)? (扰流板:通常,ISA的设计方式是不可能发生此类冲突)

太好了,我们现在应该有一个完美的反汇编程序,现在我们希望更进一步,并获得原始代码。问题来了

以下面的代码为例:将edx转换为eax,然后切换其内容),现在,生成原始代码的简单方法如下:

.loop:
    xadd eax, edx
    loop .loop


但是,智能逆向工程师可以将其翻译为这样:

for (int i = n; i > 0; i--)
{
    a += b;
    switch(a, b);
}


当eax和edx从0和1开始时

类似地,恶意软件中的一系列随机命令可能会翻译成“ makeAntivirusNotNotice”函数或在其他合法程序中对于特殊情况是非常有效的算法。

因此,编程在编写代码时也有意图,因此当您尝试反向执行同一代码时还是如前所述,根据上下文,许多高级代码替代方案,看似混乱的字节序列可能具有不同的含义,并且在撰写本文时,还没有一种工具可以还可以预测原始程序员的意图。最好的反编译器和反向工具(如Radare和IDA)试图更好地分析和模仿此类功能,但现在这是反向工程师的任务。

评论


另一个免费且易于使用的出色反编译器是retdec.com

– savram
18年5月16日在2:39

#2 楼

考虑阅读《计算机系统:程序员的观点》的第1、2和3章。它解释了一切。在深入研究逆向工程之前,力求对计算机体系结构和编程语言的基本概念有所了解。




第一次听说二进制反汇编时,我认为这是可以称为汇编代码的完美反编译工具的东西,但我仍然不明白为什么它不是。了解反编译和反汇编。



编译是语言到语言的转换,其中保留了原始含义。通常,与计算机体系结构无关的语言(例如C)会转换为特定于体系结构的语言(例如x86汇编语言),该语言针对Intel i386家族CPU。

这是一个如此高的示例,使用GCC将语言从低级语言转换为低级语言:

源C“ hello_world.c”文件(ASCII文本):


#include <stdio.h>

int main(void) {
  printf("Hello, world.\n");
  return 0;
}



编译器输出(使用-S标志生成的x86汇编ASCII文本):


$ gcc -m32 -S hello_world.c 
$ cat hello_world.s
  .file   "hello_world.c"
  .section    .rodata
.LC0:
  .string "Hello, world."
  .text
  .globl  main
  .type   main, @function
main:
.LFB0:
  .cfi_startproc
  pushl   %ebp
  .cfi_def_cfa_offset 8
  .cfi_offset 5, -8
  movl    %esp, %ebp
  .cfi_def_cfa_register 5
  andl    $-16, %esp
  subl    , %esp
  movl    $.LC0, (%esp)
  call    puts
  movl    
 0804841d <main>:
 804841d: 55                      push   %ebp
 804841e: 89 e5                   mov    %esp,%ebp
 8048420: 83 e4 f0                and    q4312078qxfffffff0,%esp
 8048423: 83 ec 10                sub    q4312078qx10,%esp
 8048426: c7 04 24 d0 84 04 08    movl   q4312078qx80484d0,(%esp)
 804842d: e8 be fe ff ff          call   80482f0 <puts@plt>
 8048432: b8 00 00 00 00          mov    q4312078qx0,%eax
 8048437: c9                      leave  
 8048438: c3                      ret    
 8048439: 66 90                   xchg   %ax,%ax
 804843b: 66 90                   xchg   %ax,%ax
 804843d: 66 90                   xchg   %ax,%ax
 804843f: 90                      nop
, %eax leave .cfi_restore 5 .cfi_def_cfa 4, 4 ret .cfi_endproc .LFE0: .size main, .-main .ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.4) 4.8.4" .section .note.GNU-stack,"",@progbits



您可以看到,这都是ASCII文本。这里没有机器代码。为了使CPU执行此代码,还需要执行一个附加步骤。

以上以ASCII编码的x86汇编语言被转换为符合目标CPU指令集规范的二进制值序列通过汇编程序。汇编器将汇编语言作为输入,然后汇编语言将生成CPU可以执行的机器语言。机器语言不是用ASCII编码的,并且不可读。

反汇编程序的作用是将机器语言操作代码显示为人类可读的助记符。以下输出是x86机器语言的反汇编:


q4312078q


左侧是机器语言操作代码的十六进制值,右侧是与机器语言操作代码相对应的助记符。


反编译可以通过以下方式理解:


反编译器或反向编译器是试图执行反过程的程序。编译器的定义:给定以任何高级语言编译的可执行程序,其目的是产生一种高级语言程序,该程序执行与可执行程序相同的功能。因此,输入依赖于机器,而
输出依赖于语言。独立的语言(例如C)。反汇编和反编译是完全不同的概念,不应混淆。





我认为汇编操作码可以直接转换为二进制序列,然后直接从二进制序列返回到操作码,但后来我听说了诸如混合代码和数据的可能性之类的事情,还有可能使我想到可以分解任何二进制并将其反汇编以重新创建同一二进制的某些事情。


当您说“汇编操作码”时,您的意思是对应于机器语言操作码的汇编语言助记符。尽管汇编语言和机器语言之间存在很强的关系,但是这种关系不一定是一对一的。看看为什么没有反汇编程序可以生成可重新组装的asm代码?。

评论


问题“为什么没有任何反汇编程序可以生成可重新组装的汇编代码?”。是我想知道的。感谢您指出了这一点

–达罗
18年5月15日在20:56

#3 楼

反汇编会产生人类可读的助记符形式,即十六进制字节数

处理器可以理解0和1的二进制数

如果需要指示处理器移动1来注册eax
,则需要将其编码为0b1011100000000001000000000000000000000000
,将其转换为十六进制(基数为16,而不是16)上面的基数2)
将变为> 0xb801000000

反汇编器将其> 0xb801000000将此十六进制字节解释并分发为mov eax,1

高级语言不了解寄存器
您将编写类似

int a = 1的代码;

这可以转换为mov eax,1或mov ebx,1或mov [addr],1

,因此无法将几种形式之一转换回原始总是