gpt4 book ai didi

assembly - Shellcoders手册中的汇编指令不一致

转载 作者:行者123 更新时间:2023-12-02 21:47:05 24 4
gpt4 key购买 nike

两年后,我又回来了。试图再次解决shellcoders手册,但是我仍然发现不一致之处。本书提供以下功能:

int triangle (int width, in height){
int array[5] = {0,1,2,3,4};
int area;
area = width * height/2;
return (area);
}


以及该函数的以下反汇编:

0x8048430 <triangle>: push %ebp
0x8048431 <triangle+1>: mov %esp, %ebp
0x8048433 <triangle+3>: push %edi
0x8048434 <triangle+4>: push %esi
0x8048435 <triangle+5>: sub $0x30,%esp
0x8048438 <triangle+8>: lea 0xffffffd8(%ebp), %edi
0x804843b <triangle+11>: mov $0x8049508,%esi
0x8048440 <triangle+16>: cld
0x8048441 <triangle+17>: mov $0x30,%esp
0x8048446 <triangle+22>: repz movsl %ds:( %esi), %es:( %edi)
0x8048448 <triangle+24>: mov 0x8(%ebp),%eax
0x804844b <triangle+27>: mov %eax,%edx
0x804844d <triangle+29>: imul 0xc(%ebp),%edx
0x8048451 <triangle+33>: mov %edx,%eax
0x8048453 <triangle+35>: sar $0x1f,%eax
0x8048456 <triangle+38>: shr $0x1f,%eax
0x8048459 <triangle+41>: lea (%eax, %edx, 1), %eax
0x804845c <triangle+44>: sar %eax
0x804845e <triangle+46>: mov %eax,0xffffffd4(%ebp)
0x8048461 <triangle+49>: mov 0xffffffd4(%ebp),%eax
0x8048464 <triangle+52>: mov %eax,%eax
0x8048466 <triangle+54>: add $0x30,%esp
0x8048469 <triangle+57>: pop %esi
0x804846a <triangle+58>: pop %edi
0x804846b <triangle+59> pop %ebp
0x804846c <triangle+60>: ret


出于学术原因,我试图分解并解释装配的每一行。但是有些事情感觉不对,例如: lea 0xffffffd8(%ebp), %edi,据我了解,第一部分意味着将基本指针乘以0xffffffd8,这似乎是错误的。另一个示例是 mov $0x30, $esp,为什么要将文字值移到堆栈指针寄存器中。我可以理解是否为 mov $0x30, (%ebp),但事实并非如此。我是错了,还是这一切似乎都错了?

最佳答案

但是有些事情感觉不对


对,他们是。一本书有印刷错误并不罕见。通常,当您看到某些会伤脑筋的东西时,应该寻找已发布的勘误清单。出版商的网站和作者的网站都是不错的选择。我不知道这本书的确切名称是什么,所以我自己也无法搜索,但是您应该可以轻松找到它。

当然,可能不是那么简单。信誉较差的出版商的书籍通常不会提供勘误表,而人气较低的书籍通常没有足够的读者来发现错误。您可以通过找到作者的电子邮件地址并通知他们发现的错误来发挥作用。或者,如果您不确定它们是否是错误的,请要求作者进行澄清。 (您不希望作者为您提供个人教程,但是关于他们书中所发表内容的特定问题总是公平的。)


lea 0xffffffd8(%ebp), %edi,据我了解,第一部分意味着将基本指针乘以0xffffffd8,这似乎是不正确的


在这种情况下,您对代码执行的理解是不正确的。我责怪这种痴迷的AT&T语法。转换为英特尔语法为:

lea edi, DWORD [ebp + ffffffd8h]


等效于:

lea edi, DWORD [ebp - 28h]


因此,这实际上等效于:

mov  edi, ebp
sub edi, 28h


现在,您说对了, LEA指令可以进行乘法运算。好吧,有点。它可以按某些常数(例如2、4和8)进行缩放,其作用与乘法相同。但是这种形式并未对乘法进行编码(或者,更准确地说,它是1的小数位)。


mov $0x30, $esp,为什么要将文字值移到堆栈指针寄存器中。我可以理解是否为 mov $0x30, (%ebp),但事实并非如此。


是的,将文字移到堆栈指针中是一件很奇怪的事情。永不说永不,但是应该尖叫“ bug”(或“ typo”)。

但请看下一条指令:


repz movsl  %ds:(%esi), %es:(%edi)



repeat string operation prefixes导致字符串指令(在这种情况下为 MOVSL)被重复执行 ECX寄存器中指定的次数,因此,以前的指令可能应该初始化 ECX。将 ECX初始化为30h是有意义的,因为这是先前在堆栈( subl $0x30, %esp)上分配的空间量。

但是这里还有另一个错误: REPZ(或等效的 REPE)前缀对于 MOVS指令没有意义! [N]Z / [N]E通常意味着将零标志用作辅助终止条件,但是移动没有设置任何标志,因此写 REPZ MOVS没有任何意义!那应该只是 REP MOVS



坦白说,就我而言,整个拆卸过程都是可疑的。我开始怀疑这本书是否值得写。为什么会显示未优化的汇编代码?如果您想学习汇编语言,则不想学习如何编写次优的代码。如果您想学习逆向工程,那么研究未优化的代码就没有意义,因为这不是编译器将生成的内容。漏洞利用也是一样。我想不出为什么要浪费时间在未优化的代码上的充分理由。只有一堆分散注意力的声音并没有告诉您任何有用的东西。

例如,您在一开始就看到未优化代码的明显迹象:没有忽略基本指针( EBP)的初始化。

REPZ MOVS指令(以及相关的必需指令)的目的对我来说也是一个完全的谜。我什至看不到编译器在禁用优化的情况下生成这些代码的原因。

我猜想作者必须关闭优化,因为否则,整个“数组”分配/初始化将被省去。不是最好的例子。

此序列也必须是一个错误:


sar $0x1f, %eax
shr $0x1f, %eax



将无符号右移31是有道理的(将符号位作为2的优化有符号除法的一部分进行隔离),但是在有符号右移之后立即执行则没有意义。 (作为该优化部门的一部分,预期的 sar %eax稍后会出现,采用典型的GAS格式,省略了立即$ 1。)

如果所有(或什至大部分)代码都是这样,我的建议是要么放弃那本书,再去找另一本书,要么自己编译和反汇编C函数。

不间断的C编译器将为该C函数生成以下代码:

    ; Load second parameter from stack into EAX.
movl 8(%esp), %eax

; Multiply that second parameter by the first parameter.
; (Could just as well have used a second movl, and then done a reg-reg imull.)
imull 4(%esp), %eax

; Make a copy of that result in EDX.
movl %eax, %edx

; Optimized signed divide-by-2:
shrl $31, %eax
addl %edx, %eax
sarl $1, %eax ; GAS encodes this as 'sarl %eax', making the $1 implicit

ret


或者,如果禁用了优化(在不同的编译器中这会有更多的可变性,那么查看未优化的代码的另一个原因很愚蠢,但是您可以得到基本的想法):

    ; Set up a stack frame
pushl %ebp
movl %esp, %ebp

; Allocate space on the stack for the pointless "array" array,
; and store the values in that space.
; (Why 32 bytes instead of only 30? To keep the stack pointer aligned.)
subl $32, %esp
movl $0, -24(%ebp)
movl $1, -20(%ebp)
movl $2, -16(%ebp)
movl $3, -12(%ebp)
movl $4, -8(%ebp)

; Get first parameter from the stack.
movl 8(%ebp), %eax

; Multiply it by the second parameter.
imull 12(%ebp), %eax

; Make a copy of the result.
movl %eax, %edx

; Optimized signed divide-by-2 (some compilers will always apply this
; strength-reduction, even when optimizations are disabled; others won't
; and will go ahead and emit the IDIV instruction you might expect):
shrl $31, %edx
addl %edx, %eax
sarl $1, %eax

; Store the result in a temporary location in memory.
movl %eax, -4(%ebp)

; Then load it back into EAX so it can be returned.
movl -4(%ebp), %eax

; Tear down the stack frame and deallocate stack space.
leave

ret

关于assembly - Shellcoders手册中的汇编指令不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43808000/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com