首先用exeinfo打开它,发现是无壳的64位程序。

逆向先静后动,因此先用ida 打开:

main函数代码如下:

int __cdecl main(int argc, const char **argv, const char **envp)
{unsigned __int64 v3; // rbx__int64 v4; // rax__int128 *v5; // rax__int64 v6; // r11__int128 *v7; // r14int v8; // edi__int128 *v9; // rsichar v10; // r10int v11; // edx__int64 v12; // r8unsigned __int64 v13; // rcx__int64 v14; // rcxunsigned __int64 v15; // raxunsigned __int64 i; // rax_BYTE *v17; // raxsize_t v18; // rsi_BYTE *v19; // rbx_BYTE *v20; // r9int v21; // er11char *v22; // r8__int64 v23; // rcxchar v24; // alsigned __int64 v25; // r9__int64 v26; // rdx__int64 v27; // raxsize_t Size; // [rsp+20h] [rbp-48h]__int128 v30; // [rsp+28h] [rbp-40h]int v31; // [rsp+38h] [rbp-30h]int v32; // [rsp+3Ch] [rbp-2Ch]int input_str[4]; // [rsp+40h] [rbp-28h]int v34; // [rsp+50h] [rbp-18h]*(_OWORD *)input_str = 0i64;v34 = 0;sub_1400018C0(std::cin, (__int64)argv, (__int64)input_str);v3 = -1i64;v4 = -1i64;do++v4;while ( *((_BYTE *)input_str + v4) );if ( v4 != 19 )                               // 输入长度为19字节{sub_140001620(std::cout, "error\n");_exit((unsigned __int64)input_str);}v5 = (__int128 *)operator new(5ui64);v6 = *(_QWORD *)&Code;                        // 这个是qwertyuiopa....v7 = v5;v8 = 0;v9 = v5;do{v10 = *((_BYTE *)v9 + (char *)input_str - (char *)v5);v11 = 0;*(_BYTE *)v9 = v10;v12 = 0i64;v13 = -1i64;do++v13;while ( *(_BYTE *)(v6 + v13) );             // v13=code_len-1if ( v13 ){do{if ( v10 == *(_BYTE *)(v6 + v12) )break;++v11;++v12;}while ( v11 < v13 );}v14 = -1i64;do++v14;while ( *(_BYTE *)(v6 + v14) );if ( v11 == v14 )_exit(v6);v9 = (__int128 *)((char *)v9 + 1);       // v5的前4个等于input前四个,并且应该为code中的值}while ( (char *)v9 - (char *)v5 < 4 );*((_BYTE *)v5 + 4) = 0;                       // v5[4]=0do++v3;while ( *((_BYTE *)input_str + v3) );         // v3=input_lenv15 = 0i64;v30 = *v7;while ( *((_BYTE *)&v30 + v15) ){if ( !*((_BYTE *)&v30 + v15 + 1) ){++v15;break;}if ( !*((_BYTE *)&v30 + v15 + 2) ){v15 += 2i64;break;}if ( !*((_BYTE *)&v30 + v15 + 3) ){v15 += 3i64;break;}v15 += 4i64;if ( v15 >= 0x10 )break;}for ( i = v15 + 1; i < 0x10; ++i )*((_BYTE *)&v30 + i) = 0;                   // v30一直到后面持续为0,前面4个字节为 input的前四个字节v17 = sub_140001AB0((__int64)input_str, v3, (unsigned __int8 *)&v30, &Size);// 用19字节的原始输入 加上原始输入的前四个字节 加上len=19 最后返回24字节的输出v18 = Size;v19 = v17;v20 = operator new(Size);v21 = 1;*v20 = v19[2];v22 = v20 + 1;v20[1] = *v19;v20[2] = v19[3];v20[3] = v19[1];v20[4] = v19[6];v20[5] = v19[4];v20[6] = v19[7];v20[7] = v19[5];v20[8] = v19[10];v20[9] = v19[8];v20[10] = v19[11];v20[11] = v19[9];v20[12] = v19[14];v20[13] = v19[12];v20[14] = v19[15];v20[15] = v19[13];v20[16] = v19[18];v20[17] = v19[16];v20[18] = v19[19];v20[19] = v19[17];v20[20] = v19[22];v20[21] = v19[20];v20[22] = v19[23];for ( v20[23] = v19[21]; v21 < v18; ++v22 )   // init: v22=v20+1{v23 = 0i64;if ( v21 / 3 > 0 ){v24 = *v22;do{v24 ^= v20[v23++];*v22 = v24;}while ( v23 < v21 / 3 );}++v21;}*(_QWORD *)&v30 = 0xC0953A7C6B40BCCEi64;v25 = v20 - (_BYTE *)&v30;*((_QWORD *)&v30 + 1) = 0x3502F79120209BEFi64;v26 = 0i64;v31 = 0xC8021823;v32 = 0xFA5656E7;do{if ( *((_BYTE *)&v30 + v26) != *((_BYTE *)&v30 + v26 + v25) )// 右边等于v20+v26_exit(v8 * v8);++v8;++v26;}while ( v26 < 24 );v27 = sub_140001620(std::cout, "You win!");std::basic_ostream<char,std::char_traits<char>>::operator<<(v27, sub_1400017F0);return 0;
}

下面一步一步来分析,下图中,首先是输入,随后通过v4判断是否是19字节,若是19字节,那么就继续,否则就error报错并且退出。 值得注意的是v6指针对应的字符串code,是qwertyui.....字符。这个命名很搞,一开始和input_str是重名的,看了半天看不懂,后来自己修改了变量名字。

往下走就是这一段了,这一段干了啥呢,其实就是检查输入的字符串是否在v6所示的qwertyu...中,其次将输入的前四个字节,存到v5中,并且v5[4]=0。

随后这个v30=*v7。v7是等于v5的,v5刚刚说到,就是input的前四个字节。v30是128位的,因此下面的循环也就是16个字节,最后得到的效果就是v30这个128位的变量,前4个字节是input的输入值,后面的12个字节都是0。

下面的部分很重要,一个是sub_140001AB0函数,函数结束之后,将得到的24字节输出进行调换顺序的操作。

首先研究这个函数,函数还是很复杂的,但是这里有一个关键的数值,0x61C88647,百度搜索了这个数值之后,发现是和tea加密算法相关,最后经过对比,发现是xxtea算法。

贴上tea的代码:

#include <stdio.h>
#include <stdint.h>
#define DELTA 0x9e3779b9
#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))  void btea(uint32_t *v, int n, uint32_t const key[4])
{  uint32_t y, z, sum;  unsigned p, rounds, e;  if (n > 1)            /* Coding Part */  {  rounds = 6 + 52/n;  sum = 0;  z = v[n-1];  do  {  sum += DELTA;  e = (sum >> 2) & 3;  for (p=0; p<n-1; p++)  {  y = v[p+1];  z = v[p] += MX;  }  y = v[0];  z = v[n-1] += MX;  }  while (--rounds);  }  else if (n < -1)      /* Decoding Part */  {  n = -n;  rounds = 6 + 52/n;  sum = rounds*DELTA;  y = v[0];  do  {  e = (sum >> 2) & 3;  for (p=n-1; p>0; p--)  {  z = v[p-1];  y = v[p] -= MX;  }  z = v[n-1];  y = v[0] -= MX;  sum -= DELTA;  }  while (--rounds);  }
}  int main()
{  uint32_t v[2]= {1,2};  uint32_t const k[4]= {2,2,3,4};  int n= 2; //n的绝对值表示v的长度,取正表示加密,取负表示解密  // v为要加密的数据是两个32位无符号整数  // k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位  printf("加密前原始数据:%u %u\n",v[0],v[1]);  btea(v, n, k);  printf("加密后的数据:%u %u\n",v[0],v[1]);  btea(v, -n, k);  printf("解密后的数据:%u %u\n",v[0],v[1]);  return 0;
}  

这个程序就是将19位的输入作为明文,然后将前四个字节作为密钥,使用xxtea进行加密,我们猜测密钥为flag。加密之后。将字符串打乱顺序。随后进入下一步:

上图就是一个简单的异或操作。可以写一个反向操作的函数即可:

最后就是与一个24字节的字符串进行比较。

下面附上用C语言写的脚本,由于是新手,写的比较乱。

#include<stdio.h>
#include<stdlib.h>
#include <stdio.h>
#include <stdint.h>
#define DELTA 0x9e3779b9
#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))
void xxtea(uint32_t* v, int n, uint32_t* key)
{uint32_t y, z, sum;unsigned p, rounds, e;if (n > 1) // encrypt{rounds = 6 + 52 / n;sum = 0;z = v[n - 1];do{sum += DELTA;e = (sum >> 2) & 3;for (p = 0; p < n - 1; p++){y = v[p + 1];z = v[p] += MX;}y = v[0];z = v[n - 1] += MX;} while (--rounds);}else if (n < -1) // decrypt{n = -n;rounds = 6 + 52 / n;sum = rounds * DELTA;y = v[0];do{e = (sum >> 2) & 3;for (p = n - 1; p > 0; p--){z = v[p - 1];y = v[p] -= MX;}z = v[n - 1];y = v[0] -= MX;sum -= DELTA;} while (--rounds);}
}int main() {unsigned char v20[30] = {0xce,0xbc,0x40,0x6b,0x7c,0x3a,0x95,0xc0,0xef,0x9b,0x20,0x20,0x91,0xf7,0x02,0x35,0x23,0x18,0x02,0xc8,0xe7,0x56,0x56,0xfa};unsigned char v19[30] = { 0xce,0xbc,0x40,0xa5,0xb2,0xf4,0xe7,0xb2,0x9d,0xa9,0x12,0x12,0xc8,0xae,0x5b,0x10,0x6,0x3d,0x1d,0xd7,0xf8,0xdc,0xdc,0x70 };int v21 = 1;unsigned char *v22 =v20+ 1;int v23;char v24;
/*for (; v21 < 24; ++v22)   // init: v22=v20+1{   v23 = 0;if (v21 / 3 > 0){v24 = *v22;do{v24 ^= v20[v23++];*v22 = v24;} while (v23 < v21 / 3);}++v21;}*/v21 = 23; v22 = v20 + 23;for (; v21 >= 0; --v22)   // init: v22=v20+1{v23 = 0;if (v21 / 3 > 0){v24 = *v22;do{v24 ^= v20[v23++];*v22 = v24;} while (v23 < v21 / 3);}--v21;}for (int i = 0; i < 24; i++) {printf("0x%x,", v20[i]);}//printf("%x %x %x %x", 'f','l','a','g');v19[2] = *v20;v19[0] = v20[1];v19[3] = v20[2];v19[1] = v20[3];v19[6] = v20[4];v19[4] = v20[5];v19[7] = v20[6];v19[5] = v20[7];v19[10] = v20[8];v19[8] = v20[9];v19[11] = v20[10];v19[9] = v20[11];v19[14] = v20[12];v19[12] = v20[13];v19[15] = v20[14];v19[13] = v20[15];v19[18] = v20[16];v19[16] = v20[17];v19[19] = v20[18];v19[17] = v20[19];v19[22] = v20[20];v19[20] = v20[21];v19[23] = v20[22];v19[21] = v20[23];printf("\n");for (int i = 0; i < 24; i++) {printf("%x,", v19[i]);}// 两个32位无符号整数,即待加密的64bit明文数据uint32_t v[7] = {0x12345678, 0x78563412 };// 四个32位无符号整数,即128bit的keyuint32_t k[4] = {0x67616c66,0,0,0 };//n的绝对值表示v的长度,取正表示加密,取负表示解密for (int i = 0,j=0; i < 6; i++, j = j + 4) {unsigned int tt = (uint32_t)v19[j ] ;unsigned int tt1 = (uint32_t)v19[j + 1] << 8;unsigned int tt2 = (uint32_t)v19[j + 2] << 16;unsigned int tt3 = (uint32_t)v19[j + 3] << 24;v[i] = tt + tt1 + tt2 + tt3;}int n = 6;
//  printf("Data is : %x %x\n", v[0], v[1]);
//  xxtea(v, n, k);
//  printf("Encrypted data is : %x %x\n", v[0], v[1]);xxtea(v, -n, k);printf("\n");printf("Decrypted data is : %x %x %x %x %x %x %x %x\n", v[0], v[1],v[2],v[3],v[4],v[5],v[6],v[7]);printf("\n ");for (int i = 0; i < 6; i++) {char tt = (char)v[i];char tt1 = (uint32_t)v[i] >> 8;char tt2 = (uint32_t)v[i] >> 16;char tt3 = (uint32_t)v[i] >> 24;printf("%c%c%c%c", tt, tt1, tt2, tt3);}printf("\n");}

buu [2019红帽杯]xx1 wp相关推荐

  1. buu [2019红帽杯]childRE wr

    这个题是有一定难度的,它考的知识点不是特别常见,对于萌新来说. 解题步骤: 1. 下载完附件之后先进行查壳 无壳,我们直接拖进ida64中.通过shift+f12查看字符串 找到输出flag的字符串通 ...

  2. [2019红帽杯]easyRE1题解

    迷蒙马背眠,月随残梦天边远,淡淡起茶烟.                                                         --松尾芭蕉 目录 1.查壳 2.拖入64位I ...

  3. [2019红帽杯]easyRE writeup

    很想挑战难题,发现自己连writeup也看不懂 用64bit的ida打开,查找字符 找到函数: signed __int64 sub_4009C6() {signed __int64 result; ...

  4. #2019江苏领航杯部分wp

    关于2019领航杯部分wp 队友的wp 两天前参加了领航杯,奋斗了24小时,做出了十几题. 第一题签到题 base64解码 第三题steganoI 一个简单的隐写,可以用strings查看他的信息 第 ...

  5. BUUCTF-[2019红帽杯]SnakeDig the way

    [2019红帽杯]Snake 题目下载:下载 下载完文件是一个用C#编写的untiy程序,对于这种程序果断用dnSpy查看Assembly-CSharp.dll 找到如下位置 发现这些函数都导入了In ...

  6. 面向萌新的红帽杯2018线上赛wp

    网络安全攻防大赛第二届"红帽杯"网络安全攻防大赛(除了web3 guess id,不会做.没写.) misc2 Not Only Wireshark 下载流量包,wireshark ...

  7. 网络安全培训小白入门课,从buu到红帽的图片隐写

    图片隐写是MISC中的一部分,雨笋教育小编给小白从BUU中找到入门MISC之图片隐写,分享给大家 恢复黑白图片 buuoj 静静听这么好听的歌 由于网上wp只给了代码而且函数非常吓人,因此写了一个新手 ...

  8. 2019 蓝桥杯省赛 B 组模拟赛(一)蒜厂年会

    2019 蓝桥杯省赛 B 组模拟赛(一)蒜厂年会 这题有两种情况 1.最大的和是在0~n-1 2.最大的和越过了首尾 这时候只要用n个数的和 - 0~n-1 的连续的最小和 这是求连续子集最大.最小 ...

  9. [CTFHub] 2021-第四届红帽杯网络安全大赛-Web-find_it

    [CTFHub] 2021-第四届红帽杯网络安全大赛-Web-find_it 看群里说CTFHub上复现了, 我来看看 本来想按照红帽杯的套路来试一下,发现phpinfo里莫得flag了 只能想想其他 ...

最新文章

  1. jQuery学习- 内容选择器
  2. 2021-03-28为什么用SCALA语言优势在哪里 Scala适合服务端、大数据、数据挖掘、NLP、图像识别、机器学习、深度学习…等等开发。
  3. 「打造中国人自己的开放 AI」:清华教授唐杰宣布成立AI新期刊
  4. 青龙羊毛——宝石星球(教程)
  5. 企业网络推广——企业网络推广更注重网站内部链接优化!
  6. mac php安装mysql扩展_(MAC) PHP扩展安装
  7. 华为新系统 鸿蒙,旗舰CPU+鸿蒙OS!华为Mate家族重磅新品来袭
  8. 【Kafka】Elasticsearch 与 Kafka 整合剖析
  9. 一个八卦的AI,嗅到了你和TA之间基情满满
  10. Redis缓存持久化
  11. apache POI技术的使用
  12. 采用Xamarin进行ffmpeg调用视频编解码的方法
  13. java 文件传输_Java开发之如何通过HTTP方式传输文件
  14. 台式电脑连不上wifi怎么办
  15. 杂谈——最好用的数学神器Mathpix Snip,不接受反驳 :)
  16. fsadfsaddfsadfsafsda
  17. 赛特斯艰难上市,“软件定义通信”的路并不好走
  18. 条码追溯系统解决外贸企业进销存管理
  19. UVALive 7308 Tom and Jerry 猫抓老鼠 物理题
  20. java小项目之贪吃蛇项目(图解超详细)

热门文章

  1. 取消win10 f1~f12默认快捷键
  2. 单缝衍射matlab,单缝衍射的matlab讲解.doc
  3. C++简单读写GPS信号
  4. Word文档带有权限密码怎么办?
  5. ZEGO“音视频+”整体化解决方案(二):互动白板
  6. angular,Last few GCs JavaScript heap out of memory
  7. 数据中心制冷系统设计40个问题!
  8. 【精益生产】车间现场管理的八大浪费
  9. STC51单片机36——51单片机简单分两路控制步进电机
  10. 医疗行业如何写软文?附100字优秀的软文范例分析,让你推广效果更好