• 攻防世界 Mine- IDA静调或x64dbg动调 两种方式


    刷攻防世界的最后一道二星题,记录一下,大佬请飘过


     题目


    分析过程

    我很勇,我先双击看看这是什么

    是一个扫雷游戏,第一下运气好没踩雷,发现无法继续输入了;如果运气不好,会输出“您踩雷啦!”

    丢到PE里面

     无壳,64位

    丢到IDA里面,shif+F12查看字符串,追踪可疑字符串,发现main函数

    复制代码
      1 int __cdecl main(int argc, const char **argv, const char **envp)
      2 {
      3   unsigned int v3; // eax
      4   std::ostream *v4; // rax
      5   __int64 v5; // rax
      6   _BYTE *v6; // rax
      7   std::istream *v7; // rax
      8   __int64 v8; // rax
      9   std::ostream *v9; // rax
     10   std::ostream *v10; // rax
     11   __int64 v11; // rax
     12   int v13; // [rsp+28h] [rbp-58h]
     13   int v14; // [rsp+2Ch] [rbp-54h]
     14   int v15; // [rsp+30h] [rbp-50h]
     15   int v16; // [rsp+34h] [rbp-4Ch]
     16   int v17; // [rsp+38h] [rbp-48h]
     17   int v18; // [rsp+3Ch] [rbp-44h]
     18   int v19; // [rsp+40h] [rbp-40h]
     19   int i1; // [rsp+44h] [rbp-3Ch]
     20   int nn; // [rsp+48h] [rbp-38h]
     21   int mm; // [rsp+4Ch] [rbp-34h]
     22   int ll; // [rsp+50h] [rbp-30h]
     23   int i2; // [rsp+54h] [rbp-2Ch]
     24   int kk; // [rsp+58h] [rbp-28h]
     25   int jj; // [rsp+5Ch] [rbp-24h]
     26   int ii; // [rsp+60h] [rbp-20h]
     27   int n; // [rsp+64h] [rbp-1Ch]
     28   int m; // [rsp+68h] [rbp-18h]
     29   int l; // [rsp+6Ch] [rbp-14h]
     30   int k; // [rsp+70h] [rbp-10h]
     31   int v32; // [rsp+74h] [rbp-Ch]
     32   int j; // [rsp+78h] [rbp-8h]
     33   int i; // [rsp+7Ch] [rbp-4h]
     34 
     35   _main();
     36   memset(grid, 0, 0x190ui64);
     37   memset(randMark, 0, 0x9C40ui64);
     38   memset(vis, 0, sizeof(vis));
     39   for ( i = 0; i <= 9; ++i )                    // 第一个循环-------------------------------------------------------------------------------
     40   {
     41     for ( j = 0; j <= 9; ++j )
     42       showUs[100 * i + j] = 42;
     43   }
     44   v3 = time(0i64);
     45   srand(v3);
     46   v32 = 0;
     47   do
     48   {
     49     v19 = rand() % 10;                          // 随机一个0~9
     50     v18 = rand() % 10;
     51     if ( randMark[100 * v19 + v18] != 1 )
     52     {
     53       randMark[100 * v19 + v18] = 1;            // v32不到mine_sum,就一直循环
     54                                                 // 我怀疑这里是布雷
     55                                                 // mine_sum是雷的数量
     56       ++v32;
     57     }
     58   }
     59   while ( v32 != mine_sum );
     60   res = 0;
     61   for ( k = 0; k <= 9; ++k )                    // 第二个循环-------------------------------------------------------------------------------------------
     62   {
     63     for ( l = 0; l <= 9; ++l )
     64     {
     65       if ( randMark[100 * k + l] )
     66         grid[10 * k + l] = -1;
     67     }
     68   }
     69   for ( m = 0; m <= 9; ++m )                    // 第三个循环-----------------------------------------------------------------------------------------------------
     70   {
     71     for ( n = 0; n <= 9; ++n )
     72     {
     73       if ( grid[10 * m + n] != -1 )
     74       {
     75         for ( ii = 0; ii <= 7; ++ii )
     76         {
     77           v17 = *((_DWORD *)&dir + 2 * ii) + m;
     78           v16 = dword_475044[2 * ii] + n;
     79           if ( v17 >= 0 && v17 <= 9 && v16 >= 0 && v16 <= 9 && grid[10 * v17 + v16] == -1 )
     80             ++grid[10 * m + n];
     81         }
     82       }
     83     }
     84   }
     85   for ( jj = 0; jj <= 9; ++jj )                 // 第四个循环--------------------------------------------------------------------------------------------------------
     86   {
     87     for ( kk = 0; kk <= 9; ++kk )
     88     {
     89       v4 = (std::ostream *)std::operator<<char>>(
     90                              refptr__ZSt4cout,
     91                              (unsigned int)showUs[100 * jj + kk]);
     92       std::operator<<char>>(v4, " ");
     93     }
     94     std::ostream::operator<<(refptr__ZSt4cout, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
     95   }
     96 LABEL_42:
     97   v5 = std::operator<<char>>(refptr__ZSt4cout, asc_48B002);// 请输入要翻开的位置的坐标
     98   std::ostream::operator<<(v5, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
     99   while ( 100 - mine_sum != res )               // res是没有雷的地方
    100   {
    101     v7 = (std::istream *)std::istream::operator>>(refptr__ZSt3cin);
    102     std::istream::operator>>(v7);
    103     if ( grid[10 * v14 + v13] == -1 )           // 第一个if---检查是否踩雷
    104     {
    105       v8 = std::operator<<char>>(refptr__ZSt4cout, asc_48B01D);// 您中雷啦
    106       std::ostream::operator<<(v8, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
    107       goto LABEL_69;                            // pause
    108     }
    109     if ( !vis[100 * v14 + v13] && grid[10 * v14 + v13] > 0 )// 第二个if---
    110     {
    111       ++res;
    112       vis[100 * v14 + v13] = 1;
    113       showUs[100 * v14 + v13] = LOBYTE(grid[10 * v14 + v13]) + 48;
    114       system("cls");
    115       for ( ll = 0; ll <= 9; ++ll )
    116       {
    117         for ( mm = 0; mm <= 9; ++mm )
    118         {
    119           v9 = (std::ostream *)std::operator<<char>>(
    120                                  refptr__ZSt4cout,
    121                                  (unsigned int)showUs[100 * ll + mm]);
    122           std::operator<<char>>(v9, " ");
    123         }
    124         std::ostream::operator<<(refptr__ZSt4cout, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
    125       }
    126       goto LABEL_42;
    127     }
    128     if ( !vis[100 * v14 + v13] && !grid[10 * v14 + v13] )// 第三个if---
    129     {
    130       bfs(v14, v13);
    131       system("cls");
    132       for ( nn = 0; nn <= 9; ++nn )
    133       {
    134         for ( i1 = 0; i1 <= 9; ++i1 )
    135         {
    136           v10 = (std::ostream *)std::operator<<char>>(
    137                                   refptr__ZSt4cout,
    138                                   (unsigned int)showUs[100 * nn + i1]);
    139           std::operator<<char>>(v10, " ");
    140         }
    141         std::ostream::operator<<(refptr__ZSt4cout, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
    142       }
    143       v11 = std::operator<<char>>(refptr__ZSt4cout, asc_48B002);// 请输入要翻开的位置的坐标
    144       std::ostream::operator<<(v11, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
    145     }
    146   }                                             // while结束的地方
    147   v15 = std::string::length((std::string *)&ans);
    148   for ( i2 = 0; i2 < v15; ++i2 )
    149   {
    150     v6 = (_BYTE *)std::string::operator[](&ans, i2);
    151     std::operator<<char>>(refptr__ZSt4cout, (unsigned int)(char)((v15 - i2) ^ *v6));// 异或操作!!!!注意!!!!
    152   }
    153   std::ostream::operator<<(refptr__ZSt4cout, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
    154 LABEL_69:
    155   system("pause");
    156   return 0;
    157 }
    复制代码

    一堆循环与if,粗略看看,147行之前都没发现什么表明游戏通关的字符串或者跳转函数

    一直到147行,突然出现一个ans,上来直接就是将它的长度赋给v15,做题有点经验的小伙伴应该会发现,一般能够单开一行赋长度的参数,很有可能是关键之一

    特别是下面还有一个异或操作,简直就是重点怀疑对象


    动态调试(X64dbg)

    输出ans紧接着的是一个循环,我们看看地址与汇编

     x64dbg的基址与IDA是一样的,不用改了——需要改地址的可以看看我之前的博客攻防世界 gametime 使用IDA pro+OD动调 - demo41 - 博客园 (cnblogs.com)

     既然不用改地址,我们直接记下jmz的地址 0000000000401ED2 ,在x64dbg中跳转到

     将jnz改成jz,运行直到出现字符串

    输出结果: 7ii3VecVgof3r6ssiP2g7E3HqwqhM 

    直接拿去提交了,出错了,那应该是加密了

    我试了很多,一直试不出来,还以为自己错了

    后面看了wp,我解题没错,这是一个标准base58

    大部分base58解密网站的字符序都是BTC-base58序列,顺序为123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz

    标准base58的解密序列是123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ

    这里提供一个解密网站:Base58编码/解码 - 一个工具箱 - 好用的在线工具都在这里! (atoolbox.net)


    静态调试(IDA+py脚本)

    我之前查看字符串的时候,还有追踪asc_48B002和asc_48B01D的时候,都发现一个特别可疑的字符串

     追进去看看

    复制代码
     1 int __fastcall __static_initialization_and_destruction_0(int a1, int a2)
     2 {
     3   int result; // eax
     4   char v3[17]; // [rsp+2Fh] [rbp-51h] BYREF
     5 
     6   if ( a1 == 1 && a2 == 0xFFFF )
     7   {
     8     std::ios_base::Init::Init((std::ios_base::Init *)&std::__ioinit);
     9     atexit(_tcf_0);
    10     std::allocator<char>::allocator(v3);
    11     std::string::string(&ans, "*ur)O}t@r{u!c&|}d\\9m>M4NtsrjL", v3);// 放进去吗?
    12     std::allocator<char>::~allocator(v3);
    13     result = atexit(_tcf_1);
    14   }
    15   return result;
    16 }
    复制代码

    竟然和ans联系在一起了,花指令我没查具体意思,七分逆向三分猜,我感觉就是把字符串放进ans里面,反正异或操作不难,脚本很容易写,试试再说

    py脚本

    复制代码
    1 ans="*ur)O}t@r{u!c&|}d\\9m>M4NtsrjL"
    2 v15=len(ans)
    3 str=""
    4 
    5 for i in range(len(ans)):
    6     str+=chr((v15-i)^ord(ans[i]))
    7 
    8 print(str)
    复制代码

    输出结果: 7ii3VecVgof3r6ssiP2g7E3HqwqhM 

    直接拿去提交了,出错了,那应该是加密了

    我试了很多,一直试不出来,还以为自己错了

    后面看了wp,我解题没错,这是一个标准base58

    大部分base58解密网站的字符序都是BTC-base58序列,顺序为123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz

    标准base58的解密序列是123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ

    这里提供一个解密网站:Base58编码/解码 - 一个工具箱 - 好用的在线工具都在这里! (atoolbox.net)


    flag

    flag{h4pp4-M1n3-G4m3}
  • 相关阅读:
    分析Jetpack Compose动画内部是如何实现的
    mybatis中mapper.xml热加载
    idea Springboot闲置物品交易平台VS开发mysql数据库web结构java编程计算机网页源码maven项目
    YOLOv5_Android_USBCamera:支持USB摄像头的YOLOv5Android图像识别项目
    容器编排学习(一)容器技术
    团队协作利器----API接口Eolink
    Trino 与Hive 有差异的函数
    vue项目部署到阿里云服务器(windows),Nginx代理!
    进程的通信 - 剪切板
    学习笔记6--决策与控制技术概述
  • 原文地址:https://www.cnblogs.com/demo41/p/18122439