日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

CatFly【汇编代码还原】

發布時間:2023/12/24 windows 30 coder
生活随笔 收集整理的這篇文章主要介紹了 CatFly【汇编代码还原】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

CatFly【難度:1】

題目界面

下載附件,發現是dll文件,放到linux中運行一下,運行界面如圖所示:

從上圖中可以看到兩處字符串,上面的字符串不斷滾動,下方字符串在次數上不斷累加,猜測上方字符串與flag相關。

靜態調試

  • 打開IDA,找到main函數

    方便分析,此處只粘貼關鍵部分代碼(源代碼的后半部分)

      time(&timer);
      v13 = 1;
      v24 = 0LL;
      v23 = 0;
      v22 = 0;
      v12 = off_FA88;
      while ( v13 )
      {
        if ( dword_E104 )
          printf("\x1B[H");
        else
          printf("\x1B[u");
        for ( k = dword_E1EC; k < dword_E1F0; ++k )
        {
          for ( m = dword_E1F4; m < dword_E1F8; ++m )
          {
            if ( k <= 23 || k > 42 || m >= 0 )
            {
              if ( m >= 0 && (unsigned int)k <= 0x3F && m <= 63 )
              {
    
                v19 = off_FA20[v24][k][m];
                off_FA88 = sub_6314((unsigned int)v24, k, m, (__int64)v12);
              }
              else
              {
                v19 = 44;
              }
            }
            else
            {
              v18 = (2 - m) % 16 / 8;
              if ( ((v24 >> 1) & 1) != 0 )
                v18 = 1 - v18;
              s[128] = (__int64)",,>>&&&+++###==;;;,,";
              v19 = asc_BFE3[v18 - 23 + k];
              if ( !v19 )
                v19 = 44;
            }
            if ( v25 )
            {
              printf("%s", *((const char **)&unk_FCC0 + v19));
            }
            else if ( v19 == v22 || !*((_QWORD *)&unk_FCC0 + v19) )
            {
              printf("%s", off_FA88);
            }
            else
            {
              v22 = v19;
              printf("%s%s", *((const char **)&unk_FCC0 + v19), off_FA88);
            }
          }
          sub_65E2(1LL);
        }
        if ( dword_E100 )
        {
          time(&time1);
          v11 = difftime(time1, timer);
          v10 = sub_63FF((unsigned int)(int)v11);
          for ( n = (dword_E1FC - 29 - v10) / 2; n > 0; --n )
            putchar(32);
          dword_E1E8 += printf("\x1B[1;37mYou have nyaned for %d times!\x1B[J\x1B[0m", (unsigned int)++dword_108E0);
        }
        v22 = 0;
        ++v23;
        if ( dword_104C4 && v23 == dword_104C4 )
          sub_6471();
        if ( !off_FA20[++v24] )
          v24 = 0LL;
        usleep(1000 * v27);
      }
      return 0LL;
    

    因為flag可能與屏幕上滾動的字符串有關,所以此處需要格外關注printf函數。從上述關鍵代碼中,可以看到off_FA88最可能與flag有關,因為其他的printf函數打印的基本是一個確定的值。

  • 查看目標的交叉引用路徑

    確定了off_FA88后,開始查找與其相關的函數。

    • 第一處是469行中的對off_FA88的賦值操作

      off_FA88的值是sub_6314()函數的返回值。

    • 接下來進入sub_6314()函數

      函數偽代碼如下圖所示:

      其功能為:當a2!=18,a3≤4||a3>54時off_FA88不變(v12的值就是off_FA88),所以此處相當于是k=18(一次)且m∈(4,53)時會執行sub_6314函數,即循環執行50次。該函數的返回值是byte_104C8的地址,byte_104C8的值與dword_E120[a3-5],dword_E120[a3-5]的值又與sub_62B5()函數的返回值有關。這里還有個sub_62E3作為邏輯判斷的條件。將此處邏輯進行還原,還原代碼如下:

      for (int i = 0; i < 50; i++) {
           dword_E120[i] ^= sub_62B5();
       }
      
    • 查看sub_62B5()函數

      函數偽代碼如下圖所示:

      可以看到該函數的返回值與dword_E1E8相關,查看dword_E1E8的交叉引用,可以看到只在main函數中有一次自增操作:

    • 總結整個流程

  • 還原關鍵匯編代碼

    此處使用大佬wp給的代碼進行分析,基本都給了解析:

    #include<stdio.h>
    #include<string.h>
    //在ida里面點開dword_E1E8會發現初始值為0x1106
    int dword_E1E8 = 0x1106;
    //同理,ida里也能看到dword_E120的初始值
    int dword_E120[50] = { 0x27fb, 0x27a4, 0x464e, 0x0e36, 0x7b70, 0x5e7a, 0x1a4a, 0x45c1, 0x2bdf, 0x23bd, 0x3a15, 0x5b83, 0x1e15, 0x5367, 0x50b8, 0x20ca, 0x41f5, 0x57d1, 0x7750, 0x2adf, 0x11f8, 0x09bb, 0x5724, 0x7374, 0x3ce6, 0x646e, 0x010c, 0x6e10, 0x64f4, 0x3263, 0x3137, 0x00b8, 0x229c, 0x7bcd, 0x73bd, 0x480c, 0x14db, 0x68b9, 0x5c8a, 0x1b61, 0x6c59, 0x5707, 0x09e6, 0x1fb9, 0x2ad3, 0x76d4, 0x3113, 0x7c7e, 0x11e0, 0x6c70 };
    //原封不動抄下來就好了
    int sub_62B5()
    {
        dword_E1E8 = 1103515245 * dword_E1E8 + 12345;
        return (dword_E1E8 >> 10) & 0x7FFF;
    }
    //這塊是拿來算輸出數字n需要多少個字符的。
    //因為main函數中的dword_E1E8需要接收printf函數的返回值
    //而printf函數的返回值是打印的字符長度
    int llog(int n) {
        int a = 0;
        while (n /= 10)a++;
        return a;
    }
    //這個函數我沒有特別放出來,反正這里也是照抄的
    int sub_62E3(char a1)
    {
        int result; // rax
    
        if ((a1 & 0x7Fu) <= 0x7E)
            result = (a1 & 0x7Fu) > 0x20;
        else
            result = 0LL;
        return result;
    }
    
    int main() {
        //count代表那個不停自增的dword_108E0
        int count = 0;
        while (1) {
            for (int i = 0; i < 50; i++) {
                dword_E120[i] ^= sub_62B5();
            }
            count++;
            //計算printf的返回值,更改dword_E1E8,每10倍增加一個位數
            dword_E1E8 += 42 + llog(count);
            if (count % 1000000 == 0) {
                printf("Count:%d\n", count);
            }
            //flag代表off_FA88
            unsigned char flag[51] = { 0 };
            for (int i = 0; i < 50; i++) {
                //根據出題人所說,出題時循環次數為705980581,但是線性同余隨機數算法出現了循環導致在100427942就出現了flag,若只考慮數組的最低字節,能在100001958得到flag
                // Loop: 100427942
                // if((dword_E120[i] & 0xff00)){
                //     break;
                // }
                // Loop: 100001958
                if (!sub_62E3(dword_E120[i])) {
                    break;
                }
                flag[i] = dword_E120[i] & 0xff;
            }
            if (memcmp("CatCTF", flag, 6) == 0) {
                puts(flag);
                printf("Count:%d\n", count);
                break;
            }
        }
    }
    
  • 運行代碼,得到flag

總結

以上是生活随笔為你收集整理的CatFly【汇编代码还原】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。