吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 3586|回复: 6
收起左侧

[CTF] 【reverse】buu-[Zer0pts2020]easy_strcmp——main函数的启动过程+IDA动态调试ELF

  [复制链接]
hans7 发表于 2022-9-12 10:15
本帖最后由 hans7 于 2022-9-12 10:23 编辑

依赖

  1. IDA7.7
  2. Ubuntu20.04

作者:hans774882968以及hans774882968以及hans774882968

本文52pojie:https://www.52pojie.cn/thread-1686873-1-1.html

本文juejin:https://juejin.cn/post/7142310602067673124

本文csdn:https://blog.csdn.net/hans774882968/article/details/126813906

思路

64位ELF。用IDA打开即可看到main函数:

__int64 __fastcall main(int a1, char **a2, char **a3)
{
  if ( a1 > 1 )
  {
    if ( !strcmp(a2[1], "zer0pts{********CENSORED********}") )
      puts("Correct!");
    else
      puts("Wrong!");
  }
  else
  {
    printf("Usage: %s <FLAG>\n", *a2);
  }
  return 0LL;
}

会这么简单嘛?我们应该关注a2[1]是否被修改了。因此看看start函数:

// positive sp value has been detected, the output may be wrong!
void __fastcall __noreturn start(__int64 a1, __int64 a2, void (*a3)(void))
{
  __int64 v3; // rax
  int v4; // esi
  __int64 v5; // [rsp-8h] [rbp-8h] BYREF
  char *retaddr; // [rsp+0h] [rbp+0h] BYREF

  v4 = v5;
  v5 = v3;
  _libc_start_main(main, v4, &retaddr, init, fini, a3, &v5);
  __halt();
}

查阅_libc_start_main的资料(参考链接1)可知init函数会在main函数之前被调用。

void __fastcall init(unsigned int a1, __int64 a2, __int64 a3)
{
  signed __int64 v4; // rbp
  __int64 i; // rbx

  v4 = &off_200DF0 - &funcs_889;
  init_proc();
  if ( v4 )
  {
    for ( i = 0LL; i != v4; ++i )
      ((void (__fastcall *)(_QWORD, __int64, __int64))*(&funcs_889 + i))(a1, a2, a3);
  }
}

有这些函数被调用了:

.init_array:0000000000200DE0 E0 06 00 00 00 00 00 00       funcs_889 dq offset sub_6E0 
.init_array:0000000000200DE8 95 07 00 00 00 00 00 00       dq offset sub_795

看了看sub_6E0啥也没有,那重点肯定是sub_795了:

// write access to const memory has been detected, the output may be wrong!
int (**sub_795())(const char *s1, const char *s2)
{
  int (**result)(const char *, const char *); // rax

  result = &strcmp;
  qword_201090 = (__int64)&strcmp;
  off_201028 = sub_6EA;
  return result;
}

点击查看off_201028,发现是strcmp函数的地址,也就是说off_201028 = sub_6EAstrcmp的地址篡改为sub_6EA的地址。因此main函数调用strcmp的时候会调用sub_6EA

__int64 __fastcall sub_6EA(__int64 a1, __int64 a2)
{
  int i; // [rsp+18h] [rbp-8h]
  int v4; // [rsp+18h] [rbp-8h]
  int j; // [rsp+1Ch] [rbp-4h]

  for ( i = 0; *(_BYTE *)(i + a1); ++i )
    ;
  v4 = (i >> 3) + 1;
  for ( j = 0; j < v4; ++j )
    *(_QWORD *)(8 * j + a1) -= qword_201060[j];
  return qword_201090(a1, a2);
}

这里a1, a2类型不对,应该是const char *。回忆一下sub_795这句qword_201090 = (__int64)&strcmp,可知qword_201090(a1, a2)就是调用原有的strcmp函数。至此我们已经知道a2[1]被修改的过程。

总结:一种hook,很有趣。

代码

CPP实现

考虑到这里要把字符串当_QWORD使用,python不方便实现,因此我们用IDA安装目录下可找到的defs.h,赋能cpp,打出一套组合👊。

#include <bits/stdc++.h>
#include "defs.h"
using namespace std;
typedef long long LL;
#define rep(i,a,b) for(int i = (a);i <= (b);++i)
#define re_(i,a,b) for(int i = (a);i < (b);++i)
#define dwn(i,a,b) for(int i = (a);i >= (b);--i)

void dbg() {
    puts ("");
}
template<typename T, typename... R>void dbg (const T &f, const R &... r) {
    cout << f << " ";
    dbg (r...);
}

int main() {
    char a1[40] = "zer0pts{********CENSORED********}";
    _QWORD qword_201060[4] = {0, 0x410A4335494A0942, 0x0B0EF2F50BE619F0, 0x4F0A3A064A35282B};
    int v4 = strlen (a1);
    re_ (j, 0, 4) {
        * (_QWORD *) (8 * j + a1) += qword_201060[j];
    }
    dbg (a1);
    return 0;
}
Python+libnum库

libnum可以让我们方便地把char数组当成整数来进行内存操作,同时支持一些基本的数论操作(如:求逆元、分解质因数)。安装libnum(注意:只支持python3):

pip config set global.index-url https://pypi.douban.com/simple # 注意现在pip只支持https的源了
pip install libnum

代码

from libnum import s2n, n2s

def main():
    key = [0, 0x410A4335494A0942, 0x0B0EF2F50BE619F0, 0x4F0A3A064A35282B]
    a = b'zer0pts{********CENSORED********}'
    ans = b''
    for i in range(4):
        j = s2n(a[i * 8: i * 8 + 8][::-1]) + key[i]
        ans += n2s(j)[::-1]
    ans += b'}'
    print(ans)

if __name__ == "__main__":
    main()

IDA动态调试

IDA动态调试配置戳这里qwq

动调时sub_795main函数长这样(因为没有去掉ASLR):

// write access to const memory has been detected, the output may be wrong!
__int64 (__fastcall *sub_561199200795())()
{
  __int64 (__fastcall *result)(); // rax

  result = sub_5611992005C6;
  qword_561199401090 = (__int64)sub_5611992005C6;
  off_561199401028 = sub_5611992006EA;
  return result;
}

__int64 __fastcall sub_5588DE0007C7(int a1, __int64 a2)
{
  if ( a1 > 1 )
  {
    if ( (unsigned int)sub_5588DE0005C0(*(_QWORD *)(a2 + 8), "zer0pts{********CENSORED********}") )
      sub_5588DE0005A0("Wrong!");
    else
      sub_5588DE0005A0("Correct!");
  }
  else
  {
    sub_5588DE0005B0("Usage: %s <FLAG>\n", *(const char **)a2);
  }
  return 0LL;
}

即使不知道sub_795hook了strcmp也没关系,我们断点断在main函数,然后“步进”strcmp函数也能找到关键代码。

sub_6ea点击a1变量,可以定位输入字符串,进而看到它被修改的过程。


1-a1变量的地址.JPG
金句.jpg

免费评分

参与人数 3吾爱币 +10 热心值 +2 收起 理由
Hmily + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
小朋友呢 + 2 + 1 我很赞同!
酷柠 + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

zgdtianya 发表于 2022-9-13 08:41
不懂爱,学习了
16713720339 发表于 2022-9-13 08:37
wang1440544971 发表于 2022-9-20 17:02
最后可说的是大实话,之前别人付出的那么多心血,瞬间被工具降低了门槛,不过真正懂的多深的也是可以搞一些事情做的
 楼主| hans7 发表于 2022-9-22 00:02
wang1440544971 发表于 2022-9-20 17:02
最后可说的是大实话,之前别人付出的那么多心血,瞬间被工具降低了门槛,不过真正懂的多深的也是可以搞一些 ...

唉,我感觉学会能跨越工具的那些知识比学会各种搬砖工具会好一些吧
wang1440544971 发表于 2022-9-23 11:43
hans7 发表于 2022-9-22 00:02
唉,我感觉学会能跨越工具的那些知识比学会各种搬砖工具会好一些吧

那是肯定的啊,你懂的更底层学的更好更深就能做别人不知道没见过的,玩的就花啊
 楼主| hans7 发表于 2022-9-23 23:56
wang1440544971 发表于 2022-9-23 11:43
那是肯定的啊,你懂的更底层学的更好更深就能做别人不知道没见过的,玩的就花啊

理是这么个理,但是学会一丁点底层知识比掌握搬砖工具难太多了……
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-12-24 10:38

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表