C 其中Aleph one';s的shell代码正在改变自身?
我正在读Aleph one写的《为了乐趣和利润而砸书堆》, 到了这个地方,C 其中Aleph one';s的shell代码正在改变自身?,c,assembly,stack-overflow,C,Assembly,Stack Overflow,我正在读Aleph one写的《为了乐趣和利润而砸书堆》, 到了这个地方, jmp 0x2a # 2 bytes popl %esi # 1 byte movl %esi,0x8(%esi) # 3 bytes movb $0x0,0x7(%esi) # 4 bytes movl $0x0,0xc(%esi)
jmp 0x2a # 2 bytes
popl %esi # 1 byte
movl %esi,0x8(%esi) # 3 bytes
movb $0x0,0x7(%esi) # 4 bytes
movl $0x0,0xc(%esi) # 7 bytes
movl $0xb,%eax # 5 bytes
movl %esi,%ebx # 2 bytes
leal 0x8(%esi),%ecx # 3 bytes
leal 0xc(%esi),%edx # 3 bytes
int $0x80 # 2 bytes
movl $0x1, %eax # 5 bytes
movl $0x0, %ebx # 5 bytes
int $0x80 # 2 bytes
call -0x2f # 5 bytes
.string \"/bin/sh\" # 8 bytes
------------------------------------------------------------------------------
Looks good. To make sure it works correctly we must compile it and run it.
**But there is a problem. Our code modifies itself**, but most operating system
mark code pages read-only.
我的问题是这段代码在哪里(以及如何)修改自己?[我不太清楚]
谢谢 第一条指令跳转到代码末尾的
调用
,该调用调用第二条指令,该指令弹出调用
放在堆栈上的返回地址。因此,esi
指向末尾的字符串。如您所见,接下来的3条指令相对于esi
写入内存,设置参数指针,并以零结束字符串和参数列表。这就是自我修改所指的。这有点误导,因为它不是修改代码,只是修改数据。在独立测试期间,数据是.text
部分的一部分,该部分通常是只读的,但可以轻松编写。请注意,在实际使用过程中,这将在堆栈中,该堆栈是可写的,但不可执行的,因此您可能会遇到不同的问题。第一条指令跳转到代码末尾的调用
,该调用将返回到第二条指令,该指令将弹出调用
放在堆栈上的返回地址。因此,esi
指向末尾的字符串。如您所见,接下来的3条指令相对于esi
写入内存,设置参数指针,并以零结束字符串和参数列表。这就是自我修改所指的。这有点误导,因为它不是修改代码,只是修改数据。在独立测试期间,数据是.text
部分的一部分,该部分通常是只读的,但可以轻松编写。请注意,在实际使用过程中,这将在堆栈中,该堆栈是可写的,但不可执行的,因此您可能会遇到不同的问题。第一条指令跳转到代码末尾的调用
,该调用将返回到第二条指令,该指令将弹出调用
放在堆栈上的返回地址。因此,esi
指向末尾的字符串。如您所见,接下来的3条指令相对于esi
写入内存,设置参数指针,并以零结束字符串和参数列表。这就是自我修改所指的。这有点误导,因为它不是修改代码,只是修改数据。在独立测试期间,数据是.text
部分的一部分,该部分通常是只读的,但可以轻松编写。请注意,在实际使用过程中,这将在堆栈中,该堆栈是可写的,但不可执行的,因此您可能会遇到不同的问题。第一条指令跳转到代码末尾的调用
,该调用将返回到第二条指令,该指令将弹出调用
放在堆栈上的返回地址。因此,esi
指向末尾的字符串。如您所见,接下来的3条指令相对于esi
写入内存,设置参数指针,并以零结束字符串和参数列表。这就是自我修改所指的。这有点误导,因为它不是修改代码,只是修改数据。在独立测试期间,数据是.text
部分的一部分,该部分通常是只读的,但可以轻松编写。请注意,在实际使用过程中,这将位于堆栈中,该堆栈是可写的,但不可执行的,因此您将遇到不同的问题。谢谢,我得到了它:-)后续问题:void main(){int*ret;ret=(int*)&ret+2;(*ret)=(int)外壳代码;}想象一下现在代码段中的外壳代码(全局)数组。我想执行它。在main的最后一行中,我们将外壳代码的地址复制到“ret”指针。我的问题是:它前面的行(主要)在做什么?为什么是“+2”?我的意思是,我们不应该希望外壳代码的地址覆盖main的返回地址,它比当前的“ret”指针位置早8个字节。[为什么我认为是8字节:4字节[传递*int]+4字节[传递帧指针]=8字节。]谢谢!下次请单独提问。+2
取决于C指针算法的工作方式,它将根据4
的项目大小进行缩放。因此,+2
实际上是8
的字节偏移量。请注意,编译器可以使用任何堆栈布局,因此返回地址可能不超过8个字节。谢谢,我得到了:-)后续问题:void main(){int*ret;ret=(int*)&ret+2;(*ret=(int)外壳代码;}想象一下现在代码段中的外壳代码(全局)数组。我想执行它。在main的最后一行中,我们将外壳代码的地址复制到“ret”指针。我的问题是:它前面的行(主要)在做什么?为什么是“+2”?我的意思是,我们不应该希望外壳代码的地址覆盖main的返回地址,它比当前的“ret”指针位置早8个字节。[为什么我认为是8字节:4字节[传递*int]+4字节[传递帧指针]=8字节。]谢谢!下次请单独提问。+2
取决于C指针算法的工作方式,它将根据4
的项目大小进行缩放。因此,+2
实际上是8
的字节偏移量。请注意,编译器可以使用任何堆栈布局,因此返回地址可能不超过8个字节。谢谢,我得到了:-)后续问题:void main(){int*ret;ret=(int*)&ret+2;(*ret=(int)外壳代码;}想象一下现在代码段中的外壳代码(全局)数组。我想执行它。在main的最后一行中,我们将外壳代码的地址复制到“ret”指针。我的问题是:它前面的行(主要)在做什么?为什么是“+2”?我的意思是,我们不应该希望外壳代码的地址覆盖main的返回地址,它比当前的“ret”指针位置早8个字节。[为什么我认为是8字节:4字节[传递*int]+4字节[传递帧指针]=8字节。