- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我试图弄清楚如何一步一步地进行藏匿粉碎。我已经用过Google了,但我仍然不知道为什么我的EIP没有被覆盖。我有这个示例程序:
1 #include <stdio.h>
2 #include <string.h>
3
4 int main(int argc, char *argv[])
5 {
6 char buf[10];
7
8 strcpy(buf, argv[1]);
9 printf("Done.\n");
10 return 0;
11
12 }
gcc -g -o prog main.c
Program received signal SIGSEGV, Segmentation fault.
0x08048472 in main (argc=<error reading variable: Cannot access memory at address 0x41414141>, argv=<error reading variable: Cannot access memory at address 0x41414145>)
at main.c:12
12 }
(gdb) info reg
eax 0x0 0
ecx 0x41414141 1094795585
edx 0xb7fbb878 -1208240008
ebx 0xb7fba000 -1208246272
esp 0x4141413d 0x4141413d
ebp 0x41414141 0x41414141
esi 0x0 0
edi 0x0 0
eip 0x8048472 0x8048472 <main+71>
eflags 0x10282 [ SF IF RF ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb) disass main
Dump of assembler code for function main:
0x0804842b <+0>: lea 0x4(%esp),%ecx
0x0804842f <+4>: and $0xfffffff0,%esp
0x08048432 <+7>: pushl -0x4(%ecx)
0x08048435 <+10>: push %ebp
0x08048436 <+11>: mov %esp,%ebp
0x08048438 <+13>: push %ecx
0x08048439 <+14>: sub $0x14,%esp
0x0804843c <+17>: mov %ecx,%eax
0x0804843e <+19>: mov 0x4(%eax),%eax
0x08048441 <+22>: add $0x4,%eax
0x08048444 <+25>: mov (%eax),%eax
0x08048446 <+27>: sub $0x8,%esp
0x08048449 <+30>: push %eax
0x0804844a <+31>: lea -0x12(%ebp),%eax
0x0804844d <+34>: push %eax
0x0804844e <+35>: call 0x80482f0 <strcpy@plt>
0x08048453 <+40>: add $0x10,%esp
0x08048456 <+43>: sub $0xc,%esp
0x08048459 <+46>: push $0x8048510
0x0804845e <+51>: call 0x8048300 <puts@plt>
0x08048463 <+56>: add $0x10,%esp
0x08048466 <+59>: mov $0x0,%eax
0x0804846b <+64>: mov -0x4(%ebp),%ecx
0x0804846e <+67>: leave
0x0804846f <+68>: lea -0x4(%ecx),%esp
=> 0x08048472 <+71>: ret
End of assembler dump.
strcpy
完成之后,我没有看到从堆栈中加载返回地址的EIP的那一刻。我尝试了
-fno-stack-protector
,但没有改变任何事情。这可能是什么原因?
# Just below the sp are argc and argv and the sp points to the address
# where RET will be stored
# This one moves the address of argc (which is on the stack) to $ecx
0x0804842b <+0>: lea 0x4(%esp),%ecx
# Move stack pointer down for alignment
0x0804842f <+4>: and $0xfffffff0,%esp
# Push the value to which $sp pointed to before alignment
# It is never used - correct me if I'm wrong
0x08048432 <+7>: pushl -0x4(%ecx)
# Push last used base pointer value (and start creating another frame)
0x08048435 <+10>: push %ebp
# Set current position sp as bp - I think here the main body starts
0x08048436 <+11>: mov %esp,%ebp
# Push the address of argc - it's later used for calculating
# the address of argv[1].
0x08048438 <+13>: push %ecx
# Make some space on the stack (20 bytes - 5 words - first two I'm
# sure for what (alignment and not used here return value?)
# another 3 for buffer[10]
0x08048439 <+14>: sub $0x14,%esp
# Move argc address to $eax
0x0804843c <+17>: mov %ecx,%eax
# Move argv address to $eax
0x0804843e <+19>: mov 0x4(%eax),%eax
# Move past argv - $eax should now point to pointer to first
# argument string
0x08048441 <+22>: add $0x4,%eax
# Move the address of the parameter string to $eax
0x08048444 <+25>: mov (%eax),%eax
# Make space for 2 words
# (probably alignment and return value from strcpy)
0x08048446 <+27>: sub $0x8,%esp
# Push the parameter address
0x08048449 <+30>: push %eax
# Get the address of the local buffer
0x0804844a <+31>: lea -0x12(%ebp),%eax
# Push it
0x0804844d <+34>: push %eax
# Call strcpy
0x0804844e <+35>: call 0x80482f0 <strcpy@plt>
# Remove 4 words - 2 for arguments and 2 for return + alignment
0x08048453 <+40>: add $0x10,%esp
# Make space for 3 words - alignment + return value
0x08048456 <+43>: sub $0xc,%esp
# Push the printf argument address (the string address)
0x08048459 <+46>: push $0x8048510
# Call printf
0x0804845e <+51>: call 0x8048300 <puts@plt>
# Remove 4 words - 1 for parameter and previous 3
0x08048463 <+56>: add $0x10,%esp
# Reset 0x0 just because
0x08048466 <+59>: mov $0x0,%eax
# Load previously saved address of argc
0x0804846b <+64>: mov -0x4(%ebp),%ecx
# not sure about that leave...
0x0804846e <+67>: leave
# Reload $esp starting value
0x0804846f <+68>: lea -0x4(%ecx),%esp
# Pop the RET address - this one should be changed to
# pointer to malicious code
=> 0x08048472 <+71>: ret
最佳答案
免责声明:我在装有gnuwin32的Windows 7系统上使用gcc-4.8.3。 Windows默认情况下似乎没有启用ASLR,因此当我运行此程序时,我得到了可重现的内存地址,这使工作变得更加轻松。同样,如果您遵循此规则,则获得的内存地址很可能会有所不同。
现在考虑这个程序:
#include <string.h>
void copyinput(char* input)
{
char buf[10];
strcpy(buf, input);
}
int main(int argc, char** argv)
{
int a = 5;
copyinput(argv[1]);
a = 7;
return 0;
}
gcc -g -ansi -pedantic -Wall overflow2.c -o overflow
0x0040157a <+0>: push %ebp
0x0040157b <+1>: mov %esp,%ebp
=> 0x0040157d <+3>: and $0xfffffff0,%esp
0x00401580 <+6>: sub $0x20,%esp
0x00401583 <+9>: call 0x401fd0 <__main>
0x00401588 <+14>: movl $0x5,0x1c(%esp)
0x00401590 <+22>: mov 0xc(%ebp),%eax
0x00401593 <+25>: add $0x4,%eax
0x00401596 <+28>: mov (%eax),%eax
0x00401598 <+30>: mov %eax,(%esp)
0x0040159b <+33>: call 0x401560 <copyinput>
0x004015a0 <+38>: movl $0x7,0x1c(%esp)
0x004015a8 <+46>: mov $0x0,%eax
0x004015ad <+51>: leave
0x004015ae <+52>: ret
0x004015af <+53>: nop
copyinput
之后的指令。这将是copyinput
。 (gdb) info reg
eax 0x1 1
ecx 0x752c1162 1965822306
edx 0xa02080 10494080
ebx 0x2 2
esp 0x28fea0 0x28fea0
ebp 0x28fec8 0x28fec8
esi 0xa01858 10491992
edi 0x1f 31
eip 0x401590 0x401590 <main+22>
eflags 0x202 [ IF ]
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x53 83
gs 0x2b 43
copyinput
。 copyinput
,然后逐步进入strcpy
):(gdb) info reg
eax 0x9218b0 9574576
ecx 0x752c1162 1965822306
edx 0x922080 9576576
ebx 0x2 2
esp 0x28fe70 0x28fe70
ebp 0x28fe98 0x28fe98
esi 0x921858 9574488
edi 0x1f 31
eip 0x401566 0x401566 <copyinput+6>
eflags 0x202 [ IF ]
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x53 83
gs 0x2b 43
copyinput
的堆栈框架来自main
的堆栈帧基于0x28fec8。 (gdb) x/88xb 0x28fe70
0x28fe70: 0x50 0x15 0x40 0x00 0xdc 0x00 0x00 0x00
0x28fe78: 0xff 0xff 0xff 0xff 0x30 0x60 0x44 0x00
0x28fe80: 0x03 0x00 0x00 0x00 0x8c 0xfe 0x28 0x00
0x28fe88: 0x00 0x00 0x00 0x00 0x8f 0x17 0x40 0x00
0x28fe90: 0x50 0x1f 0x40 0x00 0x1c 0x50 0x40 0x00
0x28fe98: 0xc8 0xfe 0x28 0x00 0xa0 0x15 0x40 0x00
0x28fea0: 0xb0 0x18 0x92 0x00 0x00 0x50 0x40 0x00
0x28fea8: 0x88 0xff 0x28 0x00 0xae 0x1f 0x40 0x00
0x28feb0: 0x50 0x1f 0x40 0x00 0x60 0x00 0x00 0x40
0x28feb8: 0x1f 0x00 0x00 0x00 0x05 0x00 0x00 0x00
0x28fec0: 0x58 0x17 0x92 0x00 0x1f 0x00 0x00 0x00
0x28fe70: 0x00401550 <- esp for `copyinput`
0x000000dc
0x28fe78: 0xffffffff
0x00446030
0x28fe80: 0x00000003
0x0028fe8c
0x28fe88: 0x00000000
0x0040178f
0x28fe90: 0x00401f50
0x0040501c
0x28fe98: 0x0028fec8 <- stored *ebp* for `main``s stack frame
0x004015a0 <- stored *eip*,
0x28fea0: 0x009218b0 <- esp for `main``s stack frame
0x00405000
(gdb) x/88xb 0x28fe70
0x28fe70: 0x86 0xfe 0x28 0x00 0xb0 0x18 0x92 0x00
0x28fe78: 0xff 0xff 0xff 0xff 0x30 0x60 0x44 0x00
0x28fe80: 0x03 0x00 0x00 0x00 0x8c 0xfe 0x41 0x41
0x28fe88: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0x28fe90: 0x42 0x42 0x42 0x42 0x42 0x42 0x42 0x42
0x28fe98: 0x42 0x42 0x43 0x43 0x43 0x43 0x43 0x43
0x28fea0: 0x43 0x43 0x43 0x43 0x00 0x50 0x40 0x00
0x28fea8: 0x88 0xff 0x28 0x00 0xae 0x1f 0x40 0x00
0x28feb0: 0x50 0x1f 0x40 0x00 0x60 0x00 0x00 0x40
0x28feb8: 0x1f 0x00 0x00 0x00 0x05 0x00 0x00 0x00
0x28fec0: 0x58 0x17 0x92 0x00 0x1f 0x00 0x00 0x00
copyinput
返回时,#include <stdio.h>
#include <string.h>
void copyinput(char* input)
{
char buf[10];
strcpy(buf, input);
}
void testinput()
{
printf("we should never see this\n");
}
int main(int argc, char** argv)
{
int a = 5;
copyinput(argv[1]);
a = 7;
return 0;
}
testinput
函数。但是,如果我们可以将
copyinput
中的返回地址覆盖为0x0040157a(这是
testinput
在我的机器上的位置)的值,我们将能够使该函数执行。
(gdb) disass main
Dump of assembler code for function main:
0x00401560 <+0>: push %ebp
0x00401561 <+1>: mov %esp,%ebp
0x00401563 <+3>: and $0xfffffff0,%esp
0x00401566 <+6>: sub $0x20,%esp
0x00401569 <+9>: call 0x401fc0 <__main>
push %ebp
,
mov %esp, %ebp
和
sub xxx, %esp
的通用模式是函数的通用序言。
(gdb) x/16xb &argv[0]
0xa31830: 0x58 0x18 0xa3 0x00 0x98 0x18 0xa3 0x00
0xa31838: 0x00 0x00 0x00 0x00 0xab 0xab 0xab 0xab
(gdb) x/20cb 0x00a31858
0xa31858: 100 'd' 58 ':' 92 '\\' 117 'u' 115 's' 101 'e' 114 'r' 115 's'
0xa31860: 92 '\\' 103 'g' 104 'h' 117 'u' 98 'b' 101 'e' 114 'r' 92 '\\'
0xa31868: 71 'G' 78 'N' 85 'U' 72 'H'
(gdb) x/20xb 0x00a31898
0xa31898: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xa318a0: 0x41 0x41 0x00 0xab 0xab 0xab 0xab 0xab
0xa318a8: 0xab 0xab 0xab 0xfe
(gdb) print $esp
$4 = (void *) 0x28fea0
(gdb) print $ebp
$5 = (void *) 0x28fec8
(gdb) x/40xb $esp
0x28fea0: 0xb6 0xfe 0x28 0x00 0x98 0x18 0xa3 0x00
0x28fea8: 0x88 0xff 0x28 0x00 0x9e 0x1f 0x40 0x00
0x28feb0: 0x40 0x1f 0x40 0x00 0x60 0x00 0x41 0x41
0x28feb8: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0x28fec0: 0x00 0x17 0xa3 0x00 0x0b 0x00 0x00 0x00
strcpy
进行设置:
0x0040156e <+14>: mov 0xc(%ebp),%eax
0x00401571 <+17>: add $0x4,%eax
0x00401574 <+20>: mov (%eax),%eax
0x00401576 <+22>: mov %eax,0x4(%esp)
0x0040157a <+26>: lea 0x16(%esp),%eax
0x0040157e <+30>: mov %eax,(%esp)
0x00401581 <+33>: call 0x402748 <strcpy>
displacement(base register, offset register, scalar multiplier)
[base register + displacement + offset register * scalar multiplier]
0x0040156e <+14>: mov 0xc(%ebp),%eax
0x00401571 <+17>: add $0x4,%eax
0x00401574 <+20>: mov (%eax),%eax
0x00401576 <+22>: mov %eax,0x4(%esp)
0x08FEC4
的四个字节是
0x00a31830
,它是argv [0]的地址。将eax加4会使eax现在指向argv
1。接下来的两条指令将argv
1的地址有效地移至esp之上的四个字节。
0x0040157a <+26>: lea 0x16(%esp),%eax
0x0040157e <+30>: mov %eax,(%esp)
buf[10]
所在的位置。然后,将此值移至esp所在的位置。此时,我们的堆栈现在看起来像:
~ ~
| |
+------------+
0x28fea4 | 0x00a31898 | remember that this is the address of argv[1][0]
+------------+
0x28fea0 | 0x0028feb6 | remember that this is the address of buf[0]
+------------+
strcpy
的函数原型(prototype)为:
char* strcpy(char* dst, const char* src);
src
首先被压入,然后
dst
其次被压入。因此,编译器不只是将参数推入堆栈,还预留了足够的空间,以便可以将所需的值加载到正确的位置。一切就绪,我们现在可以调用
strcpy
了。
printf
的调用(实际上就是
puts
),我们需要将字符串“Done。\ n”的地址移到堆栈上,然后调用
puts
:
0x00401586 <+38>: movl $0x404024,(%esp)
0x0040158d <+45>: call 0x402750 <puts>
main
。
0x00401592 <+50>: mov $0x0,%eax
0x00401597 <+55>: leave
0x00401598 <+56>: ret
Is the value in line +7 unnecessary? I don't see any use for it, so why is it stored?
In some places sp moves more than it has to - is it due to alignment? (e.g. line +14)
main+14
中,我们从esp中减去20个字节,因此我们分配了20个字节供主函数使用。我们可以争辩说缓冲区中的12个字节已被缓冲区使用(请记住,缓冲区的末尾可能会有两个填充字节,以便存储在堆栈中的下一个值将位于32位字边界处)。
0x08048435 <+10>: push %ebp
0x08048436 <+11>: mov %esp,%ebp
0x08048438 <+13>: push %ecx
0x08048439 <+14>: sub $0x14,%esp
main+10
至
main+14
是正常的功能序言
Is my conclusion over line +71 correct?
call, ret — Subroutine call and return
These instructions implement a subroutine call and return. The call instruction first pushes the current code location onto the hardware supported stack in memory (see the push instruction for details), and then performs an unconditional jump to the code location indicated by the label operand. Unlike the simple jump instructions, the call instruction saves the location to return to when the subroutine completes.
The ret instruction implements a subroutine return mechanism. This instruction > first pops a code location off the hardware supported in-memory stack (see the pop instruction for details). It then performs an unconditional jump to the retrieved code location.
Syntax
call <label>
ret
main+67
上使用)(取自
here):
Releases the stack frame set up by an earlier ENTER instruction. The LEAVE instruction copies the frame pointer (in the EBP register) into the stack pointer register (ESP), which releases the stack space allocated to the stack frame. The old frame pointer (the frame pointer for the calling procedure that was saved by the ENTER instruction) is then popped from the stack into the EBP register, restoring the calling procedure's stack frame.
A RET instruction is commonly executed following a LEAVE instruction to return program control to the calling procedure.
See "Procedure Calls for Block-Structured Languages" in Chapter 6 of the IA-32 Intel Architecture Software Developer's Manual, Volume 1, for detailed information on the use of the ENTER and LEAVE instructions.
set disassembly-flavor att
set disassembly-flavor intel
show disassembly-flavor
#include <stdio.h>
unsigned long find_start(void)
{
__asm__("movl %esp, %eax");
}
int main()
{
printf("0x%x\n", find_start());
return (0);
}
关于c - 如何禁用可能的堆栈破坏保护(未覆盖EIP,而是EBP),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31986411/
我找到了 this excellent question and answer它以 x/y(加上 center x/y 和 degrees/radians)开始并计算旋转- 到 x'/y'。这个计算很
全部: 我已经创建了一个 Windows 窗体和一个按钮。在另一个线程中,我试图更改按钮的文本,但它崩溃了;但是如果我尝试更改按钮的颜色,它肯定会成功。我认为如果您更改任何 Windows 窗体控件属
本网站的另一个问题已证实,C 中没有缩写的字面后缀,并且可以执行以下操作: short Number = (short)1; 但是转换它和不这样做有什么区别: short Number = 1; 您使
我有下表: ID (int) EMAIL (varchar(50)) CAMPAIGNID (int) isSubscribe (bit) isActionByUser (bit) 此表存储了用户对事
也就是说,无需触发Javascript事件即可改变的属性,如何保留我手动选中或取消选中的复选框的状态,然后复制到另一个地方? 运行下面的代码片段并选中或取消选中其中的一些,然后点击“复制”: $('#
我在网上找到的所有关于递增指针导致段错误的示例都涉及指针的取消引用 - 如果我只想递增它(例如在 for 循环的末尾)并且我不在乎它是否最终进入无效内存,因为我不会再使用它。例如,在这个程序中,每次迭
我有一个 Spring MVC REST 服务,它使用 XStream 将消息与 XML 相互转换。 有什么方法可以将请求和响应中的 xml(即正文)打印到普通的 log4j 记录器? 在 Contr
做我的任务有一个很大的挑战,那就是做相互依赖的任务我在这张照片中说的。假设我们有两个任务 A 和 B,执行子任务 A1、A2 和 B1、B2,假设任务 B 依赖于 A。 要理想地执行任务 B,您应该执
通过阅读该网站上的几个答案,我了解到 CoInitialize(Ex) should be called by the creator of a thread 。然后,在该线程中运行的任何代码都可以使
这个问题已经困扰我一段时间了。我以前从未真正使用过 ListViews,也没有使用过 FirebaseListAdapters。我想做的就是通过显示 id 和用户位置来启动列表的基础,但由于某种原因,
我很难解释这两个(看似简单)句子的含义: “受检异常由编译器在编译时检查” 这是什么意思?编译器检查是否捕获了所有已检查的异常(在代码中抛出)? “未经检查的异常在运行时检查,而不是编译时” 这句话中
我有一个包含排除子字符串的文本文件,我想迭代该文件以检查并返回不带排除子字符串的输入项。 这里我使用 python 2.4,因此下面的代码可以实现此目的,因为 with open 和 any 不起作用
Spring 的缓存框架能否了解请求上下文的身份验证状态,或者更容易推出自己的缓存解决方案? 最佳答案 尽管我发现这个用例 super 奇怪,但您可以为几乎任何与 SpEL 配合使用的内容设置缓存条件
我有以下函数模板: template HeldAs* duplicate(MostDerived *original, HeldAs *held) { // error checking omi
如果我的应用程序具有设备管理员/设备所有者权限(未获得 root 权限),我如何才能从我的应用程序中终止(或阻止启动)另一个应用程序? 最佳答案 设备所有者可以阻止应用程序: DevicePolicy
非常简单的问题,但我似乎无法让它正常工作。 我有一个组件,其中有一些 XSLT(用于导航)。它通过 XSLT TBB 使用 XSLT Mediator 发布。 发布后
我正在将一个对象拖动到一个可拖放的对象内,该对象也是可拖动的。放置对象后,它会嵌套在可放置对象内。同样,如果我将对象拖到可放置的外部,它就不再嵌套。 但是,如果我经常拖入和拖出可放置对象,则可拖动对象
我正在尝试为按钮和弹出窗口等多个指令实现“取消选择”功能。也就是说,我希望当用户单击不属于指令模板一部分的元素时触发我的函数。目前,我正在使用以下 JQuery 代码: $('body').click
我从 this question 得到了下面的代码,该脚本用于在 Google tasks 上更改 iframe[src="about:blank"] 内的 CSS使用 Chrome 扩展 Tempe
我有一些 @Mock 对象,但没有指定在该对象上调用方法的返回值。该方法返回 int (不是 Integer)。我很惊讶地发现 Mockito 没有抛出 NPE 并返回 0。这是预期的行为吗? 例如:
我是一名优秀的程序员,十分优秀!