re學習筆記(26)BUUCTF-re-[2019紅帽杯]xx

[2019紅帽杯]easyRE
新手一枚,如有錯誤(不足)請指正,謝謝!!

個人博客:點擊進入
題目鏈接:BUUCTF-re-[2019紅帽杯]xx
題目下載:點擊下載

IDA64位載入
shift+F12查看字符串
在這裏插入圖片描述
交叉引用找到關鍵代碼
在這裏插入圖片描述
使用findcrypt插件找到加密算法爲tea系列,進函數內部查看知道爲xxtea
在這裏插入圖片描述

__int64 __fastcall sub_1400011A0(__int64 a1, __int64 a2)
{
  unsigned __int64 v2; // rbx
  signed __int64 v3; // rax
  __int128 *v4; // rax
  __int64 v5; // r11
  __int128 *v6; // r14
  int v7; // edi
  __int128 *v8; // rsi
  char v9; // r10
  int v10; // edx
  __int64 v11; // r8
  unsigned __int64 v12; // rcx
  signed __int64 v13; // rcx
  unsigned __int64 v14; // rax
  unsigned __int64 i; // rax
  _BYTE *v16; // rax
  size_t v17; // rsi
  _BYTE *v18; // rbx
  _BYTE *v19; // r9
  signed int v20; // er11
  char *v21; // r8
  signed __int64 v22; // rcx
  char v23; // al
  signed __int64 v24; // r9
  signed __int64 v25; // rdx
  __int64 v26; // rax
  size_t Size; // [rsp+20h] [rbp-48h]
  __int128 v29; // [rsp+28h] [rbp-40h]
  int v30; // [rsp+38h] [rbp-30h]
  int v31; // [rsp+3Ch] [rbp-2Ch]
  int user_input[4]; // [rsp+40h] [rbp-28h]
  int v33; // [rsp+50h] [rbp-18h]

  *(_OWORD *)user_input = 0i64;
  v33 = 0;
  sub_1400018C0(std::cin, a2, user_input);      // 讀取用戶輸入
  v2 = -1i64;
  v3 = -1i64;
  do
    ++v3;
  while ( *((_BYTE *)user_input + v3) );        // 計算user_input的長度,即v3
  if ( v3 != 19 )                               // 輸入的長度要等於19
  {
    sub_140001620(std::cout, "error\n");
    _exit((unsigned __int64)user_input);
  }
  v4 = (__int128 *)sub_140001E5C(5ui64);        // v4爲動態分配出的一塊長度爲5的空間
  v5 = *(_QWORD *)&Code;                        // v5爲內存中存儲的數據
                                                // 爲  "qwertyuiopasdfghjklzxcvbnm1234567890"
  v6 = v4;
  v7 = 0;
  v8 = v4;                                      // v6=v8=v4
  do
  {
    v9 = *((_BYTE *)v8 + (char *)user_input - (char *)v4);// v9 = user_input
    v10 = 0;
    *(_BYTE *)v8 = v9;
    v11 = 0i64;
    v12 = -1i64;
    do
      ++v12;
    while ( *(_BYTE *)(v5 + v12) );             // v12  計算內存中存儲數據的長度
    if ( v12 )
    {
      do
      {
        if ( v9 == *(_BYTE *)(v5 + v11) )       // 輸入的字符,是在內存存儲的數據裏中的一個元素
          break;
        ++v10;
        ++v11;
      }
      while ( v10 < v12 );
    }
    v13 = -1i64;
    do
      ++v13;
    while ( *(_BYTE *)(v5 + v13) );             // v12  計算內存中存儲數據的長度
    if ( v10 == v13 )
      _exit(v5);
    v8 = (__int128 *)((char *)v8 + 1);
  }
  while ( (char *)v8 - (char *)v4 < 4 );        // 54~83行
                                                // 輸入數據的前四個元素能在內存中存儲的數據中找到對應
  *((_BYTE *)v4 + 4) = 0;                       // v4這塊動態分配的內存空間中存放着 輸入的前四個元素和一個0
  do
    ++v2;
  while ( *((_BYTE *)user_input + v2) );        // v2爲輸入字符串的長度
  v14 = 0i64;
  v29 = *v6;                                    // v6等於v4   85行
  while ( *((_BYTE *)&v29 + v14) )
  {
    if ( !*((_BYTE *)&v29 + v14 + 1) )
    {
      ++v14;
      break;
    }
    if ( !*((_BYTE *)&v29 + v14 + 2) )
    {
      v14 += 2i64;
      break;
    }
    if ( !*((_BYTE *)&v29 + v14 + 3) )
    {
      v14 += 3i64;
      break;
    }
    v14 += 4i64;
    if ( v14 >= 16 )
      break;
  }
  for ( i = v14 + 1; i < 16; ++i )
    *((_BYTE *)&v29 + i) = 0;                   // 將四個字符之後的置零
  v16 = sub_140001AB0((__int64)user_input, v2, (unsigned __int8 *)&v29, &Size);                                         //xxtea加密
  v17 = Size;                                   // 加密後的長度
  v18 = v16;
  v19 = sub_140001E5C(Size);                    // 動態分配一塊加密後字符串長度給v19
  v20 = 1;
  *v19 = v18[2];
  v21 = v19 + 1;
  v19[1] = *v18;
  v19[2] = v18[3];
  v19[3] = v18[1];
  v19[4] = v18[6];
  v19[5] = v18[4];
  v19[6] = v18[7];
  v19[7] = v18[5];
  v19[8] = v18[10];
  v19[9] = v18[8];
  v19[10] = v18[11];
  v19[11] = v18[9];
  v19[12] = v18[14];
  v19[13] = v18[12];
  v19[14] = v18[15];
  v19[15] = v18[13];
  v19[16] = v18[18];
  v19[17] = v18[16];
  v19[18] = v18[19];
  v19[19] = v18[17];
  v19[20] = v18[22];
  v19[21] = v18[20];
  v19[22] = v18[23];                            // 排序
  for ( v19[23] = v18[21]; v20 < v17; ++v21 )   // v21=v19+1
  {
    v22 = 0i64;
    if ( v20 / 3 > 0 )
    {
      v23 = *v21;
      do
      {
        v23 ^= v19[v22++];
        *v21 = v23;
      }
      while ( v22 < v20 / 3 );
    }
    ++v20;
  }
  *(_QWORD *)&v29 = 0xC0953A7C6B40BCCEi64;
  v24 = v19 - (_BYTE *)&v29;
  *((_QWORD *)&v29 + 1) = 0x3502F79120209BEFi64;
  v25 = 0i64;
  v30 = 0xC8021823;
  v31 = 0xFA5656E7;
  do
  {
    if ( *((_BYTE *)&v29 + v25) != *((_BYTE *)&v29 + v25 + v24) )
      _exit(v7 * v7);
    ++v7;
    ++v25;
  }
  while ( v25 < 24 );
  v26 = sub_140001620(std::cout, "You win!");
  std::basic_ostream<char,std::char_traits<char>>::operator<<(v26, sub_1400017F0);
  return 0i64;
}

流程爲

  1. 先判斷輸入的字符串是否都在程序實現存儲的數據Code中
  2. 然後取前四個字符作爲xxtea的密鑰,(不滿位數右端補零)
  3. 然後對輸入的字符串進行加密
  4. 之後對加密的字符串打亂順序
  5. 之後異或操作
  6. 再與存儲的數據進行比對

其中第6部存儲的數據爲在這裏插入圖片描述
v29,v29+1,v30,v31在棧上存放的位置相連。小端序存放,需將其反過來寫。

開始寫腳本

在這裏插入圖片描述

data0 = "CEBC406B7C3A95C0EF9B202091F70235231802C8E75656FA"#爲提取出來的v29,v29+1,v30,v31
data = []
for i in range(0,len(data0),2):
    data.append(int(data0[i]+data0[i+1],16))#每兩位爲整體,將16進制轉換爲10進制
print(data)
for i in range(len(data)-1,-1,-1):
    for j in range(i//3):
        data[i] ^= data[j]
        #進行的異或操作
print(data)
biao = [2,0,3,1,6,4,7,5,10,8,11,9,14,12,15,13,18,16,19,17,22,20,23,21]#置換表
shuju = [1]*24
for i in range(24):
    shuju[biao[i]] = data[i]#將其按照一定順序置換
print(shuju)
print(len(shuju))

在這裏插入圖片描述

#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include "encode.h"
int main()
{
	int i,j,data[] = { 188, 165, 206, 64, 244, 178, 178, 231, 169, 18, 157, 18, 174, 16, 200, 91, 61, 215, 6, 29, 220, 112, 248, 220 };
	for (i = 1; i <= 6; i++)//導出加密的數據,將其轉換爲十六進制並用小端序來表示
	{
		printf("0x");
		for (j = i * 4 - 1; j > (i - 1) * 4 - 1; j--)
			printf("%x", data[j]);
		printf(",");
	}
	printf("\n0x");
	int key[] = { 'f','l','a','g' };//導出密鑰,將其轉換爲十六進制並用小端序來表示
	for (i = 3; i >= 0; i--)
		printf("%x", key[i]);
	printf(",");
	for (i = 0; i < 3; i++)//密鑰爲4個32位的數,1個字符4bit,4個字符爲32bit,還差3個32bit的數
		printf("0x0,");
}

在這裏插入圖片描述
解密得到十六進制字符串,這裏用到了我自己寫的頭文件。頭文件所用函數爲

#define xxtea_DELTA 0x9e3779b9
#define xxtea_MX (((xxtea_z>>5^xxtea_y<<2) + (xxtea_y>>3^xxtea_z<<4)) ^ ((xxtea_sum^xxtea_y) + (xxtea_key[(xxtea_p&3)^xxtea_e] ^ xxtea_z)))
void xxtea(uint32_t* xxtea_origin, int xxtea_n, uint32_t const xxtea_key[4])
{
    uint32_t xxtea_y, xxtea_z, xxtea_sum;
    unsigned xxtea_p, xxtea_rounds, xxtea_e;
    if (xxtea_n > 1)            /* Coding Part */
    {
        xxtea_rounds = 6 + 52 / xxtea_n;
        xxtea_sum = 0;
        xxtea_z = xxtea_origin[xxtea_n - 1];
        do
        {
            xxtea_sum += xxtea_DELTA;
            xxtea_e = (xxtea_sum >> 2) & 3;
            for (xxtea_p = 0; xxtea_p < xxtea_n - 1; xxtea_p++)
            {
                xxtea_y = xxtea_origin[xxtea_p + 1];
                xxtea_z = xxtea_origin[xxtea_p] += xxtea_MX;
            }
            xxtea_y = xxtea_origin[0];
            xxtea_z = xxtea_origin[xxtea_n - 1] += xxtea_MX;
        } while (--xxtea_rounds);
    }
    else if (xxtea_n < -1)      /* Decoding Part */
    {
        xxtea_n = -xxtea_n;
        xxtea_rounds = 6 + 52 / xxtea_n;
        xxtea_sum = xxtea_rounds * xxtea_DELTA;
        xxtea_y = xxtea_origin[0];
        do
        {
            xxtea_e = (xxtea_sum >> 2) & 3;
            for (xxtea_p = xxtea_n - 1; xxtea_p > 0; xxtea_p--)
            {
                xxtea_z = xxtea_origin[xxtea_p - 1];
                xxtea_y = xxtea_origin[xxtea_p] -= xxtea_MX;
            }
            xxtea_z = xxtea_origin[xxtea_n - 1];
            xxtea_y = xxtea_origin[0] -= xxtea_MX;
            xxtea_sum -= xxtea_DELTA;
        } while (--xxtea_rounds);
    }
}

因爲用戶輸入的爲19位字符,也就是38位十六進制字符串,而上面生成了40位,所以要去掉最後兩位,也就是去掉13。
最後將生成的十六進制數用小端序表示
在這裏插入圖片描述
得到flag
在這裏插入圖片描述
最後粘貼一下寫的代碼:

#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include "encode.h"
int main()
{
#if 0
	int i,j,data[] = { 188, 165, 206, 64, 244, 178, 178, 231, 169, 18, 157, 18, 174, 16, 200, 91, 61, 215, 6, 29, 220, 112, 248, 220 };
	for (i = 1; i <= 6; i++)//導出加密的數據,將其轉換爲十六進制並用小端序來表示
	{
		printf("0x");
		for (j = i * 4 - 1; j > (i - 1) * 4 - 1; j--)
			printf("%x", data[j]);
		printf(",");
	}
	printf("\n0x");
	int key[] = { 'f','l','a','g' };//導出密鑰,將其轉換爲十六進制並用小端序來表示
	for (i = 3; i >= 0; i--)
		printf("%x", key[i]);
	printf(",");
	for (i = 0; i < 3; i++)//密鑰爲4個32位的數,1個字符4bit,4個字符爲32bit,還差3個32bit的數
		printf("0x0,");

	uint32_t enc[6] = { (unsigned int)0x40cea5bc,(unsigned int)0xe7b2b2f4,(unsigned int)0x129d12a9,(unsigned int)0x5bc810ae,(unsigned int)0x1d06d73d,(unsigned int)0xdcf870dc };
	int n = -6;
	uint32_t const key[4] = { (unsigned int)0x67616c66,(unsigned int)0x0,(unsigned int)0x0,(unsigned int)0x0 };
	btea(enc, n, key);
	for (int i = 0; i < 6; i++)
		printf("%x", enc[i]);
#endif
	char string[] = "67616c665858437b646e615f742b2b5f7d6165";
	int i = 1,j=0;
	for (;i<6;i++)
	{
		for (j = 0; j < 8; j += 2)
		{
			if (j == 0 && i == 5)
				continue;
			printf("%c%c", string[i * 8 - j - 2], string[i * 8 - j - 1]);
		}
	}

}

flag爲flag{CXX_and_++tea}
在這裏插入圖片描述

發佈了50 篇原創文章 · 獲贊 7 · 訪問量 3535
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章