系统级编程 lab5 下载本文

内容发布更新时间 : 2024/11/17 16:28:47星期一 下面是文章的全部内容请认真阅读。

Practice1

上周做了,复制过来。前面得key1=3、key2=777

下面我们继续往后面看代码,并且通过提示我们了解到我们需要想办法使程序进入并执行msg2 = extract_message2(start, stride);

但是从正常的程序逻辑上看,我们无法使msg1为空而顺利进入到条件码中。那么我们需要考虑应该在process_keys34中做出调整。我们能否在执行完process_keys34后偷偷的改变msg1的值呢?在看了这段函数的代码后,我们发现这个函数中两个变量的范围相差太大了,一个是全局变量message(msg1的实际指向),一个是局部变量key3。那么我们需要换一个思路,能否让函数在返回的时候直接跳转到目标代码呢?如果要这么做,我们就需要修改程序在运行过程中的栈帧结构中的存储数据了。现在让我们来分析一下程序在调用process_keys34之前的栈帧结构:

从汇编码中我们可以看到在调用之前整个栈帧结构中数据的存储细节。首先是将参数key3、key4压入栈中保存,然后在传入这些参数。然而这些参数的传递都是传地址的,所以我们在process_keys34中可以通过&key3的相对定位来改动调用者的栈帧数据。

在这之前让我们来想想调用时的栈帧结构:

我们可以看到,如果我们能够修改返回地址使它返回到我们期望的位置就可以了。那么我们现在需要确定这个返回地址相对于key3的距离是多少,通过图我们可以看到这个地址就在key3的下面,只需要在key3基础上减一(这个减一是在int下的,实际上在地址层面应该是-4)就好了。所以我们得到了key3的值-1.

另外我们需要感谢出题者,他一直给我们提供充足的相对数据。在这里我们

只需要在原返回地址上面加上一个合适的值就好了。

从上图中,我们可以看到原先的返回地址和我们需要抵达的返回地址0040138e是原先保存在栈帧中的返回地址,而我们期望程序返回时直接到达0x004013bb。这样我们就得到了key4的具体值:

Key4=(0x004013bb-0040138e)/4=45。

所以key1234分别就是 3 777 -1 45。

Practice2 将ebp压入栈顶位置。EIP跳到00951851。栈顶ESP变为00951850 push ebp 0091FD68 将ESP的值赋值给EBP,栈底00951851 movebp,esp EBP变为0091FD68 将ESP的值减小0D8h,变为00951853 sub esp,0D8h 00D2FBF8 00951859 push ebx 将当前的EBX,ESI,EDI值逐个0095185A push esi 压入到栈里。得到ESP为0095185B push edi 00D2FBEC Main() EDI=EBP-0D8h为与栈底相隔0095185C lea edi,[ebp-0D8h] 0D8hbytes的位置 00951862 mov ecx,36h 将ECX赋值为36h. 00951867 mov eax,0CCCCCCCCh 将EAX赋值为0CCCCCCCCh 从EDI的位置开始赋值,每次EDI+4,ECX-1,直到ECX为0为止。执行完后EDI=00D2FCD0、0095186C rep stosdwordptres:[edi] EFL=00000212 0095186E movdwordptr [a],1 将1赋值给a的位置 00951875 movdwordptr [b],2 将2赋值给b的位置 将(b位置中的)2赋值给0095187C moveax,dwordptr [b] EAX=00000002 将EAX放入栈中, ESP变为0095187F push eax 00D2FBE8 将(a位置中的)1赋值给00951880 movecx,dwordptr [a] ECX=00000001 将ecx压入栈顶,ESP变为00951883 push ecx 00D2FBE4 00951884 call swap1 执行swap1函数 (0951307h) 00951889 add esp,8 ESP加8,ESP变为00D2FBEC 将(b位置中的)2赋值给0095188C moveax,dwordptr [b] EAX=00000002 将eax压入栈顶,esp变为0095188F push eax 00D2FBE8 将(a位置中的)1赋值给00951890 movecx,dwordptr [a] ECX=00000001 将ecx压入栈顶,esp变为00951893 push ecx 00D2FBE4 00951894 push 956B30h 调用printf()函数 00951899 call _printf EAX = 00000015 (0951325h) EBX = 7ED8F000 ECX = 0D0AE50D EDX = 5447181C ESI = 00951046 EDI = 00D2FCD0 EIP = 0095189E ESP = 00D2FBE0 EBP = 00D2FCD0 EFL = 00000244 栈顶ESP置为ESP+0Ch,清除之0095189E add esp,0Ch 前放入的形参 009518A1 lea eax,[b] Eax = b(00D2FCBC) 将eax压入栈顶,esp变为009518A4 push eax 00D2FBE8 009518A5 lea ecx,[a] Ecx=a(00D2FCC8) 将ecx压入栈顶,esp变为009518A8 push ecx 00D2FBE4 009518A9 call swap2 跳转执行swap2函数 (0951339h) 栈顶ESP置为ESP+8,清除之前009518AE add esp,8 放入的形参 将(b位置中的)1赋值给009518B1 moveax,dwordptr [b] EAX=00000001 将eax压入栈顶,esp变为009518B4 push eax 00D2FBE8 将(a位置中的)2赋值给009518B5 movecx,dwordptr [a] ECX=00000002 将ecx压入栈顶,esp变为009518B8 push ecx 00D2FBE4 调用printf()函数 EAX = 00000015 EBX = 7ED8F000 ECX = 0D0AE50D EDX = 5447181C ESI = 00951046 EDI = 00D2FCD0 EIP = 009518C3 009518B9 push 956B30h ESP = 00D2FBE0 009518BE call _printf EBP = 00D2FCD0 (0951325h) EFL = 00000244 栈顶ESP置为ESP+0Ch,清除之009518C3 add esp,0Ch 前放入的形参 009518D7 pop eax 栈压出EDI,ESI,EBX以前的值009518D8 pop edx 009518D9 pop edi 009518DA pop esi 009518DB pop ebx 009518DC add esp,0D8h 放入EDI,ESI,EBX中 ESP = ESP+0D8h 比较EBP和ESP 009518E2 cmpebp,esp 009518E4 call __RTC_CheckEsp 检查函数有没有出错 (0951113h) 009518E9 movesp,ebp ESP = EBP 009518EB pop ebp EBP = 栈顶压出的值 跳转执行栈顶压出的值指向的009518EC ret 代码

Practice3

题目中已经说了,“分析这个程序,可以得知,正常情况下,这个函数会在getbuf中,调入getxs函数读入数字对,然后不管任何情况下,都会对test函数返回0x1,”那我们该怎么办了?我们马上可以想到在getbuf这个函数里定义的char buf[16]上做手脚,可以看到在getxs函数里的while循环,结束条件只是以回车或者是eof结束符为判断标准,所以,根本没对char输入的数量做判断!这样的话,我们可以输入多于16个的数,从而缓冲区溢出! 在这里还是提一下帧栈结构,如下: +-------------------------------+高地址 |函数参数 n 个 | +-------------------------------+ |函数参数第 n-1 个 | +-------------------------------+ | ... | | ... | | ... |

+-------------------------------+ |函数参数第1个 |

+-------------------------------+ |return 返回地址 | +-------------------------------+ |ebp指针入栈 |