繁体   English   中英

从汇编中逆向工程C源代码

[英]Reverse engineering C-source code from assembly

我想知道是否有人可以帮助我解决我在学校参加的入门讲习班中的一个讲座幻灯片时遇到的问题。 我遇到的问题是不了解程序集,它是如何根据程序集对C源代码进行排序的。 我将发布我正在讨论的片段,也许我会更清楚地谈论我的内容。

C来源:

int arith(int x, int y, int z)
{ 
   int t1 = x+y;
   int t2 = z+t1;
   int t3 = x+4;
   int t4 = y * 48; 
   int t5 = t3 + t4;
   int rval = t2 * t5;
   return rval;
}

大会给出:

arith:
pushl %ebp
movl %esp,%ebp

movl 8(%ebp),%eax
movl 12(%ebp),%edx
leal (%edx,%eax),%ecx
leal (%edx,%edx,2),%edx
sall $4,%edx
addl 16(%ebp),%ecx
leal 4(%edx,%eax),%eax
imull %ecx,%eax

movl %ebp,%esp
popl %ebp
ret

我只是很困惑,我应该能够辨别出例如在第二行(在源代码中)中添加z + t1z + x + y )时,在汇编之后它出现在汇编代码中的y * 48或者例如x + 4是汇编时的第3行,它本身甚至不是一行,它与最后一个leal语句混合在一起。 当我有源代码时对我有意义但是我应该能够重现测试的源代码并且我确实理解编译器优化了一些东西但是如果有人有办法考虑可以帮助我的逆向工程如果他们能够引导我完成思考过程,我将不胜感激。

谢谢。

我已经分解了反汇编,以显示如何从C源生成程序集。

8(%ebp) = x12(%ebp) = y16(%ebp) = z

arith:

创建堆栈框架:

pushl %ebp
movl %esp,%ebp


x移动到eaxy转换为edx

 movl 8(%ebp),%eax movl 12(%ebp),%edx 


t1 = x + y leal (加载有效地址)将添加edxeaxt1将在ecx

 leal (%edx,%eax),%ecx 


int t4 = y * 48; 在下面的两个步骤中,乘以3,再乘以16. t4最终将在edx

edx乘以2,并将edx添加到结果中,即。 edx = edx * 3

 leal (%edx,%edx,2),%edx 

向左移4位,即。 乘以16:

 sall $4,%edx 


int t2 = z+t1; ecx 最初持有t1z16(%ebp) ,在指令结束时ecx将持有t2

 addl 16(%ebp),%ecx 


int t5 = t3 + t4; t3只是x + 4 ,而非计算并存储t3 ,表达t3被内嵌放置。 该指令必不可少(x+4) + t4 ,与t3 + t4相同。 它添加了edxt4 )和eaxx ),并添加了4作为偏移量来实现该结果。

 leal 4(%edx,%eax),%eax 

int rval = t2 * t5; 相当直截了当; ecx代表t2eax代表t5 返回值通过eax传递回调用者。

 imull %ecx,%eax 


销毁堆栈帧并恢复espebp

 movl %ebp,%esp popl %ebp 


从例行程序返回:

 ret 


从这个例子中你可以看到结果是一样的,但结构有点不同。 很可能这个代码是通过某种优化编译的,或者有人自己编写这样的代码来证明这一点。

正如其他人所说,你无法从反汇编中完全回到源头。 这取决于阅读程序集的人的解释,以提出等效的C代码。


为了帮助学习汇编和理解C程序的反汇编,您可以在Linux上执行以下操作:

编译调试信息( -g ),它将嵌入源:

 gcc -c -g arith.c 

如果您使用的是64位计算机,则可以告诉编译器使用-m32标志创建一个32位二进制文​​件(我在下面的示例中这样做了)。


使用objdump转储目标文件,其源交错:

gcc -c -g arith.c

-d =反汇编, -S =显示源。 您可以添加-M intel-mnemonic以使用Intel ASM语法,如果您更喜欢使用您的示例使用的AT&T语法。

输出:

objdump -d -S arith.o

如您所见,没有优化,编译器会生成比您拥有的示例更大的二进制文件。 您可以使用它并在编译时添加编译器优化标志(即-O1-O2-O3 )。 优化级别越高,反汇编看起来就越抽象。

例如,只有1级优化( gcc -c -g -O1 -m32 arith.c1 ),生成的汇编代码要短得多:

arith.o:     file format elf32-i386


Disassembly of section .text:

00000000 <arith>:
int arith(int x, int y, int z)
{ 
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   83 ec 20                sub    $0x20,%esp
   int t1 = x+y;
   6:   8b 45 0c                mov    0xc(%ebp),%eax
   9:   8b 55 08                mov    0x8(%ebp),%edx
   c:   01 d0                   add    %edx,%eax
   e:   89 45 fc                mov    %eax,-0x4(%ebp)
   int t2 = z+t1;
  11:   8b 45 fc                mov    -0x4(%ebp),%eax
  14:   8b 55 10                mov    0x10(%ebp),%edx
  17:   01 d0                   add    %edx,%eax
  19:   89 45 f8                mov    %eax,-0x8(%ebp)
   int t3 = x+4;
  1c:   8b 45 08                mov    0x8(%ebp),%eax
  1f:   83 c0 04                add    $0x4,%eax
  22:   89 45 f4                mov    %eax,-0xc(%ebp)
   int t4 = y * 48; 
  25:   8b 55 0c                mov    0xc(%ebp),%edx
  28:   89 d0                   mov    %edx,%eax
  2a:   01 c0                   add    %eax,%eax
  2c:   01 d0                   add    %edx,%eax
  2e:   c1 e0 04                shl    $0x4,%eax
  31:   89 45 f0                mov    %eax,-0x10(%ebp)
   int t5 = t3 + t4;
  34:   8b 45 f0                mov    -0x10(%ebp),%eax
  37:   8b 55 f4                mov    -0xc(%ebp),%edx
  3a:   01 d0                   add    %edx,%eax
  3c:   89 45 ec                mov    %eax,-0x14(%ebp)
   int rval = t2 * t5;
  3f:   8b 45 f8                mov    -0x8(%ebp),%eax
  42:   0f af 45 ec             imul   -0x14(%ebp),%eax
  46:   89 45 e8                mov    %eax,-0x18(%ebp)
   return rval;
  49:   8b 45 e8                mov    -0x18(%ebp),%eax
}
  4c:   c9                      leave  
  4d:   c3                      ret

您无法重现原始来源,您只能重现等效来源。

在您的情况下, t2的计算可以出现在t1之后和retval之前的任何地方。

源可能只是一个表达式:

return (x+y+z) * ((x+4) + (y * 48));

逆向工程时,你不关心原始源代码,你关心它的作用。 副作用是你看到代码的作用,而不是程序员想要的代码。

反编译并不是完全可以实现的:当从源代码(其中注释和名称给出了原始程序员的意图的线索)到二进制机器代码(其中指令将由处理器执行)时,存在一些知识损失。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM