一次脱单的机会-西南赛区线下赛

本文详细介绍了对一个64位exe程序的逆向分析过程,包括使用IDA Pro进行静态分析,以及利用x64dbg进行动态调试来绕过调试检测。在调试过程中,发现了关键的flag输出部分,通过md5加密的字符串得到了可能的flag。最后,成功解密出可能的两个flag:flag{056a5ae5aa88a2151e96ba83948b83aa}

题目是一个大佬发的,说是西南赛区的一道逆向题目

解压出来是一个exe文件

在这里插入图片描述

运行起来是这样的

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

先看文件信息,没有加壳,64位程序

在这里插入图片描述

用IDA64位打开,分析代码

int __cdecl main(int argc, const char **argv, const char **envp)
{
  unsigned int v3; // eax
  double v4; // xmm1_8
  int v5; // xmm0_4
  int i; // eax
  float v7; // xmm2_4
  const char *v8; // rbx
  __m128i si128; // xmm2
  __int64 v10; // rbx
  unsigned int v11; // eax
  const char *v12; // rbx
  int v14; // [rsp+20h] [rbp-98h] BYREF
  int v15[3]; // [rsp+24h] [rbp-94h] BYREF
  __int128 v16[5]; // [rsp+30h] [rbp-88h]

  v3 = time64(0i64);
  srand(v3);
  v4 = (double)rand() / 100000.0;
  *(float *)&v5 = v4 + 491.0;
  dword_14000563C = v5;
  *(float *)&dword_140005638 = v4 + 10.0;
  if ( IsDebuggerPresent() )
LABEL_22:
    exit(1);
  printf("\n");
  printf("\n");
  printf(asc_140003288);
  printf("\n");
  printf(asc_1400032C8);
  printf("\n");
  printf(asc_1400032F0);
  printf("\n");
  printf(asc_140003318);
  printf("\n");
  printf(asc_140003348);
  printf("\n");
  printf(asc_140003378);
  printf("\n");
  printf(asc_1400033A0);
  printf("\n");
  printf(asc_1400033D0);
  printf("\n");
  printf(asc_140003408);
  printf("\n");
  printf("---------------------------------------------------------------------------\n");
  printf("\n");
  printf(asc_140003490);
  printf("\n");
  printf(asc_1400034A8, dword_14000563C);
  printf("\n");
  printf(asc_1400034C0, dword_140005638);
  printf("\n");
  printf(a1);
  printf("\n");
  printf(a2);
  printf("\n");
  printf(asc_140003510);
  scanf("%d", &v14, 1i64);
  for ( i = v14; v14 == 1; i = v14 )
  {
    printf("\n");
    printf(asc_140003528);
    scanf("%d", v15, 3i64);
    if ( v15[0] > 9 || (v7 = (float)v15[0], (float)v15[0] > (float)(501.0 - *(float *)&dword_14000563C)) )
    {
      v8 = (const char *)&unk_140003540;
    }
    else if ( v15[0] > 0 )
    {
      v8 = (const char *)&unk_140003568;
      *(float *)&dword_14000563C = *(float *)&dword_14000563C + v7;
      *(float *)&dword_140005638 = *(float *)&dword_140005638 - v7;
    }
    else
    {
      v8 = asc_140003558;
    }
    printf("\n");
    printf(v8);
    printf("\n");
    if ( *(float *)&dword_140005638 <= 0.0 )
    {
      if ( IsDebuggerPresent() )
        goto LABEL_22;
      printf("f");
      if ( IsDebuggerPresent() )
        goto LABEL_22;
      printf("l");
      if ( IsDebuggerPresent() )
        goto LABEL_22;
      printf("ag");
      printf("{md5(");
      si128 = _mm_load_si128((const __m128i *)&xmmword_1400035F0);
      v10 = 0i64;
      v11 = _mm_cvtsi128_si32(si128);
      v16[2] = (__int128)_mm_load_si128((const __m128i *)&xmmword_1400035D0);
      v16[1] = (__int128)_mm_load_si128((const __m128i *)&xmmword_1400035E0);
      v16[0] = (__int128)si128;
      v16[3] = (__int128)si128;
      for ( v16[4] = 0i64; v11; v11 = *((_DWORD *)v16 + v10) )
      {
        printf("%c", v11);
        ++v10;
      }
      if ( IsDebuggerPresent() )
        goto LABEL_22;
      printf(")");
      if ( IsDebuggerPresent() )
        goto LABEL_22;
      printf("}");
    }
    printf("---------------------------------------------------------------------------\n");
    printf("\n");
    printf(asc_140003490);
    printf("\n");
    printf(asc_1400034A8, dword_14000563C);
    printf("\n");
    printf(asc_1400034C0, dword_140005638);
    printf("\n");
    printf(a1);
    printf("\n");
    printf(a2);
    printf("\n");
    printf(asc_140003510);
    scanf("%d", &v14, 1i64);
  }
  v12 = (const char *)&unk_140003578;
  if ( i != 2 )
    v12 = asc_140003590;
  printf("\n");
  printf(v12);
  getchar();
  getchar();
  return 0;
}

一点点分析,这里面有好几个检测动态调试的函数

 if ( IsDebuggerPresent() )
LABEL_22:
    exit(1);

这里这段就是输出flag了,跟进查看,也看不出什么,只能用动态调试了

 printf("f");
      if ( IsDebuggerPresent() )
        goto LABEL_22;
      printf("l");
      if ( IsDebuggerPresent() )
        goto LABEL_22;
      printf("ag");
      printf("{md5(");
      si128 = _mm_load_si128((const __m128i *)&xmmword_1400035F0);
      v10 = 0i64;
      v11 = _mm_cvtsi128_si32(si128);
      v16[2] = (__int128)_mm_load_si128((const __m128i *)&xmmword_1400035D0);
      v16[1] = (__int128)_mm_load_si128((const __m128i *)&xmmword_1400035E0);
      v16[0] = (__int128)si128;
      v16[3] = (__int128)si128;
      for ( v16[4] = 0i64; v11; v11 = *((_DWORD *)v16 + v10) )
      {
        printf("%c", v11);
        ++v10;
      }
      if ( IsDebuggerPresent() )
        goto LABEL_22;
      printf(")");
      if ( IsDebuggerPresent() )
        goto LABEL_22;
      printf("}");

x64debug 打开,f8单步运行,运行到这里调用的是main函数

在这里插入图片描述

在这里插入图片描述

f7跟进查看

在这里插入图片描述

这里对应的就是开始的那个检测动态调试的地方

在这里插入图片描述
在这里插入图片描述

然后就是一步步运行分析了,我是分析过的,我就直接说简单方法了:搜索字符串

这里有个输出md5( 的,那么在注释里面应该有这段字符串,直接搜索

在这里插入图片描述

在这里插入图片描述

过滤一下,双击跳转

在这里插入图片描述

在这之前下个断点,记下地址 00007FF73737143F

在这里插入图片描述

执行到这个检测这个debug的地方

在这里插入图片描述

把下面那一句 test eax,eax 改成 jmp 00007FF73737143F,选择剩下字节以nop
填充

在这里插入图片描述

然后直接执行跳到那里就行

在这里插入图片描述

执行结果: ag{md5(女神早已不是女神,这里flag已经出来了,可以不用继续了

在这里插入图片描述

后面这两个检测是否有动态调试的函数,后面的输出也只是把括号补全而已

在这里插入图片描述
在这里插入图片描述

补全后的结果:ag{md5(女神早已不是女神)}

在这里插入图片描述

然后再md5加密一下

md5(女神早已不是女神,32) = 056a5ae5aa88a2151e96ba83948b83aa
md5(女神早已不是女神,16) = aa88a2151e96ba83

最终flag:

flag{056a5ae5aa88a2151e96ba83948b83aa} 或者 flag{aa88a2151e96ba83} (咱也没进到线下赛,也不知道哪个对的)

于2024年4月-2025年9月期间,研究团队在贵州习水国家级自然保护区制定39条样线,涵盖灌木林、常绿阔叶林、针叶林、常绿落叶阔叶混交林、针阔混交林等不同植被类型,每条样线分春夏秋冬4个季节采集样品,用真菌采集软件记录经纬度、海拔、采集地点、时间、生境等信息,使用佳能相机(R6 mark Ⅱ)对大型真菌进行拍照,并采集标本,标本存放于贵州省生物研究所大型真菌标本馆(HGAMF)。 通过形态学初步鉴定,结合分子生物学最终鉴定,参考已]报道的中国毒蘑菇名录开展毒蘑菇的认定。 调查到保护区内有毒真菌7目25科64种,导致中毒的主要类型有急性肾衰竭型、神经精神型和胃肠炎型。最终形成贵州习水国家级自然保护区大型有毒真菌图片数据集,它由以下2个部分组成。 (1)附件1包含78张原始照片(.JPG),照片名字包括了大型有毒真菌的拉丁名和中文名,若无中文名的直接用拉丁名。 (2)附件2是一个压缩文件,包含了2张工作表,其中一张表是大型有毒真菌39条样线的信息,另一张表是大型有毒真菌的中毒类型。 照片采用佳能相机R6 mark Ⅱ拍摄,物种鉴定通过多种文献核实,并经两位以上专家鉴定确认。该数据集可为研究地及周边的普通人识别有毒大型真菌提供参考,通过及时的图片对比,能有效避免误采误食大型有毒真菌,同时为因误食大型真菌可能引发的身体损伤进行了总结,能为患者及时治疗提供参考。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ofo300

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值