Last updated on November 5, 2023 pm
reserve
关于校园官网上一些道题目的讲解
base64
下载发现这是一个PE32位文件,运行之后发现要求我们输入一个字符串,随便输入一个,弹出wrong,于是直接打开IDA发现没有main函数,于是先按shift+f12搜索字符串wrong,顺着这个字符串就能够找到调用他的函数,找到调用的主函数后,分析反编译出来的代码,主函数是将我们输入的字符串经过一个函数加密后,与主函数内的一个字符串进行对比,分析函数,发现其为变种的base64编码,写一个脚本,将对比的那串字符串,根据表,转换成六位二进制,再根据ascii转换成字符串,就能得出flag了。
tree
不难发现这个文件是一个ELF64位文件,在linux里运行,没有弹出提示,将这个文件丢进IDA里,先找主函数,分析主函数并结合题目TREE我们不难发现,这个程序首先是读取标准输入流里的32个字符,并按照层序排列的方式构建一棵二叉树,接着有一个验证函数,他以后序遍历的方式来读取二叉树里面的内容,并与他内置的32个两位十六进制数进行比较,具体过程是这样的,先读取第一个,将其赋值给tmp,tmp与内置第一个两位十六进制数进行比较,相同就++check,并继续比较,不同就退出程序,第二次比较,先将tmp与读取的第二个数进行一个虚假的异或(满足异或的特性但有不同),赋值給读取出的数,再赋值给tmp,并比较是否与第二个十六进制数相等,相等就++check,后面就重复这个过程,当检查完32个字符后,全对就会输出Congratulation!,解题方法也很简单,先用C语言复刻这个程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
| #include <stdio.h> #include <stdlib.h> __int64 __fastcall customXOR(char root, unsigned __int8 tmp) { char v2; char v4; char v5; unsigned __int8 v6;
v2 = 16 * ((((8 * ((((4 * ((((2 * ((((root & 1 ^ ((tmp & 2) != 0)) & 2 | root & 2) != 0) ^ ((tmp & 4) != 0))) & 4 | (root & 1 ^ ((tmp & 2) != 0)) & 4 | root & 4) != 0) ^ ((tmp & 8) != 0))) & 8 | (2 * ((((root & 1 ^ ((tmp & 2) != 0)) & 2 | root & 2) != 0) ^ ((tmp & 4) != 0))) & 8 | (root & 1 ^ ((tmp & 2) != 0)) & 8 | root & 8) != 0) ^ ((tmp & 0x10) != 0))) & 0x10 | (4 * ((((2 * ((((root & 1 ^ ((tmp & 2) != 0)) & 2 | root & 2) != 0) ^ ((tmp & 4) != 0))) & 4 | (root & 1 ^ ((tmp & 2) != 0)) & 4 | root & 4) != 0) ^ ((tmp & 8) != 0))) & 0x10 | (2 * ((((root & 1 ^ ((tmp & 2) != 0)) & 2 | root & 2) != 0) ^ ((tmp & 4) != 0))) & 0x10 | (root & 1 ^ ((tmp & 2) != 0)) & 0x10 | root & 0x10) != 0) ^ ((tmp & 0x20) != 0)); v4 = v2 | (8 * ((((4 * ((((2 * ((((root & 1 ^ ((tmp & 2) != 0)) & 2 | root & 2) != 0) ^ ((tmp & 4) != 0))) & 4 | (root & 1 ^ ((tmp & 2) != 0)) & 4 | root & 4) != 0) ^ ((tmp & 8) != 0))) & 8 | (2 * ((((root & 1 ^ ((tmp & 2) != 0)) & 2 | root & 2) != 0) ^ ((tmp & 4) != 0))) & 8 | (root & 1 ^ ((tmp & 2) != 0)) & 8 | root & 8) != 0) ^ ((tmp & 0x10) != 0))) & 0xEF | (4 * ((((2 * ((((root & 1 ^ ((tmp & 2) != 0)) & 2 | root & 2) != 0) ^ ((tmp & 4) != 0))) & 4 | (root & 1 ^ ((tmp & 2) != 0)) & 4 | root & 4) != 0) ^ ((tmp & 8) != 0))) & 0xE7 | (2 * ((((root & 1 ^ ((tmp & 2) != 0)) & 2 | root & 2) != 0) ^ ((tmp & 4) != 0))) & 0xE3 | root & 1 ^ ((tmp & 2) != 0) | root & 0xE0; v5 = (32 * (((v2 & 0x20 | (8 * ((((4 * ((((2 * ((((root & 1 ^ ((tmp & 2) != 0)) & 2 | root & 2) != 0) ^ ((tmp & 4) != 0))) & 4 | (root & 1 ^ ((tmp & 2) != 0)) & 4 | root & 4) != 0) ^ ((tmp & 8) != 0))) & 8 | (2 * ((((root & 1 ^ ((tmp & 2) != 0)) & 2 | root & 2) != 0) ^ ((tmp & 4) != 0))) & 8 | (root & 1 ^ ((tmp & 2) != 0)) & 8 | root & 8) != 0) ^ ((tmp & 0x10) != 0))) & 0x20 | (4 * ((((2 * ((((root & 1 ^ ((tmp & 2) != 0)) & 2 | root & 2) != 0) ^ ((tmp & 4) != 0))) & 4 | (root & 1 ^ ((tmp & 2) != 0)) & 4 | root & 4) != 0) ^ ((tmp & 8) != 0))) & 0x20 | (2 * ((((root & 1 ^ ((tmp & 2) != 0)) & 2 | root & 2) != 0) ^ ((tmp & 4) != 0))) & 0x20 | (root & 1 ^ ((tmp & 2) != 0)) & 0x20 | root & 0x20) != 0) ^ ((tmp & 0x40) != 0))) | v4 & 0xDF; v6 = (((tmp >> 7) ^ ((v5 & 0x40) != 0)) << 6) | v5 & 0xBF; return (((v6 >> 7) ^ tmp & 1) << 7) | v6 & 0x7Fu; }
unsigned char tmp; int check = 0;
typedef struct TreeNode { unsigned char value; struct TreeNode *left; struct TreeNode *right; } TreeNode;
TreeNode* createNode(unsigned char value) { TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode)); node->value = value; node->left = NULL; node->right = NULL; return node; }
unsigned __int64 __fastcall postorderTraversal(TreeNode* root) { unsigned __int64 result = 0xFE974D705ED41790LL; __int64 v3[5]; v3[0] = 0xC14D242A3480E17DLL; v3[1] = 0x4B4E6AB68979708ELL; v3[2] = 0xFE974D705ED41790LL; v3[3] = 0xC5474CF22F3C924FLL; if (root == NULL) return result; postorderTraversal(root->left); postorderTraversal(root->right); if (check) { int b = *((unsigned char *)v3 + check); unsigned char a = customXOR(b,tmp); root->value= a; printf("%c", a); root->value=customXOR(root->value, tmp); } tmp = root->value; if (tmp != *((unsigned char*)v3+ check)) { printf("不匹配\n"); exit(0); } return ++check; }
TreeNode* createTreeByLevelOrder(unsigned char* values, int size) { if (size == 0) return NULL; TreeNode** nodes = (TreeNode**)malloc(size * sizeof(TreeNode*)); for (int i = 0; i < size; ++i) { nodes[i] = createNode(values[i]); } for (int i = 0; i < size; ++i) { if (2 * i + 1 < size) nodes[i]->left = nodes[2 * i + 1]; if (2 * i + 2 < size) nodes[i]->right = nodes[2 * i + 2]; } TreeNode* root = nodes[0]; free(nodes); return root; }
int main() { unsigned char values[32]="flag{abcdefghijklmnopqrstuvwxyz}"; printf("启动\n"); TreeNode* root = createTreeByLevelOrder(values, 32); postorderTraversal(root);
printf("\n"); if (check == 32) { printf("Congratulation!\n"); } else { printf("wrong"); } return 0; }
|
根据异或运算的结合律,打印出来,在根据二叉树后序遍历的顺序,还原出原来的flag就行了(我这里是直接手画,太丑就不看了),得出flag是flag{15t_A1_u5e_p01n75r5_4_50u1}