用户
搜索
  • TA的每日心情
    郁闷
    昨天 05:15
  • 签到天数: 17 天

    连续签到: 1 天

    [LV.4]经常看看II

    i春秋作家

    Rank: 7Rank: 7Rank: 7

    3

    主题

    4

    帖子

    298

    魔法币
    收听
    0
    粉丝
    0
    注册时间
    2020-8-4
    发表于 2021-5-31 22:42:49 110515
    本帖最后由 a3uRa 于 2021-6-1 10:10 编辑

    [toc]

    从一道ctf学习LD_PRELOAD和ida patch

    https://ctf-wiki.org/reverse/linux/ld_preload/

    这里复现 并且仔细讲解一下wiki的例题
    https://github.com/ctf-wiki/ctf-challenges/blob/master/reverse/linux-re/2014_hitb/hitb_bin100.elf

    分析


    运行起来就张这个样子了
    会不断的输出字符串

    64位
    ida64打开
    shift+f12
    看到
    关键点

    .rodata:0000000000400A5F        0000001F        C        OK YOU WIN. HERE'S YOUR FLAG: 

    双击跳转过来

    定位main函数 f5反编译

    int __cdecl main(int argc, const char **argv, const char **envp)
    {
      char *v3; // rdi
      signed __int64 i; // rcx
      unsigned __int64 v5; // r12
      int v6; // eax
      char v7; // r13
      const char *v8; // r13
      __int64 v9; // r14
      const __int32_t **v10; // rax
      __int64 v11; // rbx
      __int64 v12; // rdx
      char *v13; // rbx
      __int64 v14; // rdx
      __int64 v15; // rbx
      __int64 v16; // rdx
      unsigned __int8 v17; // di
      signed int v19; // [rsp+8h] [rbp-190h]
      int v20; // [rsp+Ch] [rbp-18Ch]
      char v21[36]; // [rsp+10h] [rbp-188h]
      char v22[37]; // [rsp+34h] [rbp-164h]
      char v23[255]; // [rsp+59h] [rbp-13Fh]
      unsigned __int64 v24; // [rsp+158h] [rbp-40h]
    
      qmemcpy(v22, &unk_400A7E, sizeof(v22));
      v24 = __readfsqword(0x28u);
      v3 = v21;
      for ( i = 9LL; i; --i )
      {
        *(_DWORD *)v3 = 0;
        v3 += 4;
      }
      v19 = 201527;
      v20 = time(0LL);
      do
      {
        v11 = 0LL;
        do
        {
          v5 = 0LL;
          v6 = time(0LL);
          srand(233811181 - v20 + v6);
          v7 = v21[v11];
          v21[v11] = rand() ^ v7;
          v8 = (&funny)[v11];
          while ( v5 < strlen(v8) )
          {
            v9 = v8[v5];
            if ( (_BYTE)v9 == 105 )
            {
              v23[(signed int)v5] = 105;
            }
            else
            {
              if ( (_DWORD)v5 && v8[v5 - 1] != 32 )
                v10 = __ctype_toupper_loc();
              else
                v10 = __ctype_tolower_loc();
              v23[(signed int)v5] = (*v10)[v9];
            }
            ++v5;
          }
          v23[(signed int)v5] = 0;
          ++v11;
          __printf_chk(1LL, &unk_400A44, v23);
          sleep(1u);
        }
        while ( v11 != 36 );
        --v19;
      }
      while ( v19 );
      v13 = v21;
      __printf_chk(1LL, "KEY: ", v12);
      do
      {
        v14 = (unsigned __int8)*v13++;
        __printf_chk(1LL, "%02x ", v14);
      }
      while ( v13 != v22 );
      v15 = 0LL;
      putchar(10);
      __printf_chk(1LL, "OK YOU WIN. HERE'S YOUR FLAG: ", v16);
      do
      {
        v17 = v22[v15] ^ v21[v15];
        ++v15;
        putchar(v17);
      }
      while ( v15 != 36 );
      putchar(10);
      return 0;
    }

    全是伪c代码?看不懂?没关系,这里我在放个注释的图


    在结合运行程序的时候的图片
    是格式化输出了
    funny这里

    随机输出

    writeup
    https://ctf-wiki.org/reverse/linux/ld_preload/
    整个代码流程就是不停的输出funny里的句子
    等条件满足输出key 然后进行一些异或运算得到flag
    有些爆破的意思
    那么就考虑让程序爆破的更快
    这里把一些print的操作给nop掉
    print耗时也比较多
    并且注意到程序中还有个sleep函数
    也要考虑把sleep函数给搞掉

    nop print函数

    先去patch print函数
    定位


    就是这里了
    光标定位到这两行的地方


    一直nop

    这里print函数就被搞掉了

    apply patches to input file

    这里我已经备份了

    搞掉sleep函数

    LD_PRELOAD,进阶web的过程中遇到过
    http://www.hausahan.cn/2020/05/24/ctfhub%E6%8A%80%E8%83%BD%E6%A0%91-web%E8%BF%9B%E9%98%B6-wp/

    搞掉sleep函数用的是
    LD_PRELOAD
    Linux 动态加载器ld-linux
    LD_PRELOAD是一个可选的环境变量

    加载器会先于 C 语言运行库之前载入LD_PRELOAD指定的共享链接库,也就是所谓的预装载 (preload)。
    预装载意味着会它的函数会比其他库文件中的同名函数先于调用, 也就使得库函数可以被阻截或替换掉. 多个共享链接库文件的路径可以用冒号或空格进行区分. 显然不会受到LD_PRELOAD影响的也就只有那些静态链接的程序了.
    当然为避免用于恶意攻击, 在ruid != euid的情况下加载器是不会使用LD_PRELOAD进行预装载的.
    更多阅读: https://blog.fpmurphy.com/2012/09/all-about-ld_preload.html#ixzz569cbyze4

    简单说就是 我可以用我自己定义的函数 也叫sleep函数
    也有time函数,然后我使用LD_PRELOAD,让程序先用我自己定义的sleep函数和time函数,而不使用他程序自己的函数

    写个time.c

    static int t = 912312;
    
    void sleep(int sec) {
            t += sec;
    }
    
    int time() {
            return t;
    }

    这里t的取值应该是任意都可以
    wiki上取值是

    我还疑惑 这个0x31337 是从哪来的
    其实任意取值就可以了

    v20 = time(0LL);
    v6 = time(0LL);
    srand(233811181 - v20 + v6);
    v20和v6就抵消了
    gcc --shared time.c -o time.so
    生成动态链接文件
    
    linux在gcc编译时加上 -shared 参数时,目的是使源码编译成动态库 .so 文件
    -o 是指定生成的文件名

    最后运行 得到flag

    $ LD_PRELOAD=./time.so ./hitb_bin100.elf
    指定使用我们构造的time.so 去运行hitb_bin100.elf
    已经patch好的文件

    自己对逆向的一些技巧总结


    七分逆向三分猜
    当然 感觉随着逆向的逐渐深入和熟悉 理解也会越来越深刻,一些函数的写法 用法 能看懂,猜的成分也会逐渐降低
    还有对一些算法 tea rc4 base及其变种的识别 逆向 能看出来是什么算法

    动态调试环境学习 搭建
    。。。

    [md][toc]

    一个小红客a3uRa
    学习了
    使用道具 举报 回复
    发新帖
    您需要登录后才可以回帖 登录 | 立即注册