目标 |
手段 |
被利用代码 |
1.返回地址 |
覆盖 |
ret |
2.返回地址上面的ebp |
覆盖
带加0功能的字符串函数(比如strncat) ebp被提高到局部变量的位置 反正你知道ebp下面是返回地址就ok
|
mov esp,ebp ret
|
3.再上面的seh指针 |
覆盖 |
make异常 |
题外:ida搜索
有符号比较 ja jb
jae jbe
jna jnb
无符号比较 jg jl
jge jle
memcpy使用无符号长度,所以你传个-1进去你就知道错
e.x.e.x 得到很多 mov eax,[eax+edx*4+xxh]之类的内存访问 说不定有你需要的内存段操作代码
详细归纳 格式化字符串
printf(s),如果s是受你输入控制的 你就准备好直接靠输入读写该进程的地址空间吧
首先堆栈是这个样子 低<- ......调用printf的地址......(调用printf的函数的)各个局部变量......ebp 返回地址 ->高
1.如果你输入abcd它自然就显示abcd 没意思。
看法
2.你要输入%08x它就显示 堆栈里调用printf的地址 下面的DWORD的内容。所以你不停的输入%08x%08x%08x它就把堆栈里的东西看完了
3.这时候你突然冒出个%s就可以把堆栈里相应位置的DWORD作指针指向的“字符串”看了
写法
4.首先你要确定什么时候能看到你自己的输入串 位于堆栈的哪里,一个%08x其实就是25 30 38 78,当你看到显示的全是这个DWORD的时候意味着已经到你的控制领域了 (当然你可以在输入%08x之前输入你喜欢的任何暗号)
有了这个基础结合3你可以看到进程地址空间里的几乎任何“字符串”!人造地址可以这样输入"\x01\x02\x03\x04",配上%s便可看到04030201地址的“字符串”,很遗憾人造地址不得包含\x00
5.%n可以写入当前输入字符的数量到人造地址,比如".......\x04\xf0\xfd\x7f......%n",对准了哦,
虽然一次写的是一个DWORD但是你可以相当于每次写一个BYTE写四次,从低地址到高地址每次递增一字节,
比如"......
\x04\xf0\xfd\x7f
\x05\xf0\xfd\x7f
\x06\xf0\xfd\x7f
\x07\xf0\xfd\x7f......%n%n%n%n",这样也把0x7ffdf004地址的4个BYTE写成了一样的数值
6.要写入你想要的数据,靠%xxu可以增加“字符串长度”,xx是数字。而且为了对齐,在四个相邻地址之间夹三个临时的任意DWORD
比如"......
\x04\xf0\xfd\x7f
\x41\x41\x41\x41\x05\xf0\xfd\x7f
\x41\x41\x41\x41\x06\xf0\xfd\x7f
\x41\x41\x41\x41\x07\xf0\xfd\x7f......
%152u%n
%64u%n
%191u%n
%256u%n"
勒误:因为\x01这个转义字符是编译前就被变成了BYTE01了,所以以上的自造地址之类的无法直接输入,只能靠重定向输入或者你用alt+小键盘数字键(10进制),后者似乎容易出问题
过两天再回顾堆溢出的问题 谢谢大家观赏 转载请注明出处