objdump
,反汇编了gcc
编译的一些静态链接二进制文件。在反汇编的asm代码中,我发现了这一点:
80ade23: 74 01 je 0x80ade26
80ade25: f0 0f c1 16 lock xadd %edx,(%esi) // lock
80ade29: 89 54 24 14 mov %edx,0x14(%esp)
80ade2d: 8b 54 24 14 mov 0x14(%esp),%edx
80ade31: 3b 15 f0 0e 0f 08 cmp 0x80f0ef0,%edx
80ade37: 73 75 jae 0x80adeae
80ade39: 65 83 3d 0c 00 00 00 cmpl je S_0x80ade26
lock
S_0x80ade26: xadd %edx,(%esi) // lock
x0,%gs:0xc
80ade40: 00
80ade41: 74 01 je 0x80ade44
80ade43: f0 0f c1 0d dc 0e 0f lock xadd %ecx,0x80f0edc // lock
80ade4a: 08
因此,据我所知,基本上
lock
是x86 asm操作码的前缀,在这里是合法的。看来
je
跳到lock
之后的位置。这是我的问题:
objdump
的拆卸结果正确吗?很少见到objdump
会生成这种“跳转到指令”的asm代码。.(无论如何,我是逆向工程的新手,所以... :))然后如何调整它使其重新
我试图以这种方式进行更改,然后使用
gcc
重新进行组装,它可以通过组装过程,但是基本上我真的不知道它是否正确否。
q4312078q
#1 楼
我不会走那么远,指出objdump
提供的输出不正确。没错,线性扫描不能正确处理数据,跳转表和shellcode通常是反汇编错误的根源。但这仍然不是错误。如果仔细看一下代码,您会发现您有
je
。意味着,仅当前一条指令(肯定是cmp
或test
)返回true时,才执行跳转。 x86
ISA(指令集)允许跳转到指令的中间,或者如果需要的话可以跳转到字节流。有时这是用来避免使用某些前缀,例如rep
,...,以及您所需要的lock
。我100%确信所提供的输出是正确的,并且程序员(或编译器) )使用此技巧来避免不必要的附加代码。
#2 楼
实际上,objdump
使用线性扫描算法反汇编可执行文件。这意味着它一步一步地反汇编指令。像这样:首先进入入口并反汇编第一条指令(并获得其大小):
4028c0: 41 57 push %r15
然后,知道前一条指令的大小,就将当前地址更新为下一条指令,并将其反汇编(并重新获得其大小):
4028c2: 41 56 push %r14
然后,一次又一次地迭代(返回2),直到到达当前节的末尾:
4028c4: 41 55 push %r13
4028c6: 41 54 push %r12
4028c8: 55 push %rbp
4028c9: 48 89 f5 mov %rsi,%rbp
4028cc: 53 push %rbx
...
objdump
实现在此简单算法上仅增加了一个小增量,即使它出现在当前反汇编指令的中间,它也会在每个符号上开始。这意味着您可能遇到以下情况(我在研究混淆软件时遇到了这种情况): 4028c0: 41 57 push %r15
4028c2: 41 56 push %r14
4028c4: 41 55 push %r13
4028c6: 41 54 push %r12
4028c8: 55 push %rbp
4028c9: 48 89 f5 mov %rsi,%rbp
4028cc: 48 85 c0 test %rax,%rax
00000000004028cd <.f668>:
4028cd: 85 c0 test %eax,%eax
4028cf: 53 push %rbx
...
反汇编程序首先将
4028cc
作为amd64指令反汇编,但符号是在4028cd
。因此,该算法将重置为该值并从那里重新开始。最后,请注意,线性扫描算法被广泛认为是不正确的。它可能很容易误导。它的主要问题是它没有考虑所有指令的语义,因此当到达动态跳转(
jmp %rax
)时,该算法将无法遵循执行流程。当然,还有很多其他方法可以误导该算法,在这里我不会尝试穷尽所有这些技术(请注意,递归遍历并不是更好)。回到您的原始问题:
线性扫描算法无法跟踪程序的执行流程。如果位于指令中间,则将无法跳过数据。但是,当符号指向该指令在上一条指令的中间跳转的位置时,
objdump
可能是正确的(请参阅我之前描述的情况)。要正确地反汇编此程序,就没有希望了与
objdump
。但是,您可以使用gdb
并通过Python脚本对其进行检测,从而收集执行跟踪。同样,其他反汇编程序也不会被这种简单的布局所欺骗。您可以尝试radare
或Benny建议的IDAPro。我还可以发布一些自己的工具,即Insight框架中的cfgrecovery
(但对于这样一个简单的技巧来说有点过分了。)。#3 楼
我认为您所说的“跳入指令”可能是一种称为反汇编反同步的抗静电分析技术,该技术将数据字节与代码交错,以使反汇编程序混乱。在IDA Pro书籍的第21章(混淆代码分析)中对此技术和其他技术进行了解释。如果您满足以下条件,则使用IDA Pro可以正确地反汇编代码:
使用IDA(免费或专业版)打开二进制文件
将光标放在有问题的一行代码上,在您的情况下,该行位于以下地址:
80ade25
和80ade43
lock xadd %edx,(%esi) // lock
...
lock xadd %ecx,0x80f0edc // lock
单击IDA的“编辑”菜单,然后选择“取消定义”
现在将光标放在跳转指令所指向的地址上是
0x80ade26
和80ade44
再次单击IDA的“编辑”菜单,然后选择“这次编码”。
请注意,已应用此抗静电分析技术在您的代码中两次。因此,您需要两次执行步骤2-5。
更新:但是,在
objdump
输出中没有反汇编反同步,正如Peter Ferrie在下面的注释中指出的那样。跳入指令是提高性能的一种手段。但是,对于那些偶然发现您的问题并且反汇编实际上正遭受失步困扰的人,我保留此答案。评论
原来的拆卸是正确的,答案是错误的。代码正在检查线程数并避免锁定:如果只有一个线程。此操作可以提高性能。
–彼得·弗里
14年7月8日在16:18
@peterferrie感谢您的信息。我之前从未见过这种优化。因此,我认为这是反汇编不同步的情况。我现在想知道如果不动态计算跳转地址,如何不跳过锁?
–本尼
2014年7月8日在16:24
分支和锁定指令是作为一个集合生成的,因此总是je $ + 3 / lock /
–彼得·弗里
2014年7月8日在16:31
评论
谢谢yaspr,所以基本上,我的使用方式(在我的问题底部)是否正确?
– lllllllllllll
2014年7月9日14:13
实际上,您重写它的方式与以前没有什么区别。为什么呢?好吧,在二进制级别,指令之间没有分隔符,因为它们在x86中是可变长度的。而且,您可以在字节流中跳转。
– Yaspr
2014年7月9日14:30