[WUSTCTF 2020](病假回归)
[WUSTCTF 2020]level1
下载下来后有俩文件,先看level1
查壳,无壳64位,拖入IDA中
看到其中的i&1,为按位与运算,取2进制整数 i 的最低位,如果最低位是1 则得1,如果最低位是0 则得0。 奇数 i 的最低位 是1,偶数i 的最低位 是0。
再看到output文件,里面有
198,232,816,200,1536,300,6144,984,51200,570,92160,1200,565248,756,1474560,800,6291456,1782,65536000
那么就可以编写脚本了
flag = [0,198,232,816,200,1536,300,6144,984,51200,570,92160,1200,565248,756,1474560,800,6291456,1782,65536000]
for i in range(1,20):
if(i & 1) != 0:
flag[i] = flag[i] >> i
else:
flag[i] = flag[i] // i
print(''.join([chr(i)for(i)in(flag)]))
[WUSTCTF 2020]level2
根据题目叙述,有UPX壳,查壳看看,UPX壳32位
脱个壳玩玩,一定要注意文件位置的命名不能带有'[]'这个东西!
打开看看
[WUSTCTF 2020]level3
查壳,拖入IDA中
看到了加密后的码,再找找码表,shift12看看
但发现只有63个字母少了,前面应该还有A
因为它提示换表且有交叉引用的考点,所以点进base函数看看,交叉引用base64_table
看到了LookAtYou,跟进
是个换表题,编写脚本
#include<stdio.h>
#include<stdlib.h>
int main() {
char v1;
int i;
int result;
char base[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
for (i = 0; i <= 9; ++i)
{
v1 = base[i];
base[i] = base[19 - i];
result = 19 - i;
base[result] = v1;
}
printf("%s", base);
return 0;
}
放到赛博橱子里看看
[WUSTCTF 2020]level4
查壳,无壳64位
拖进IDA中
有init(),type1(),type2()这三个函数值得查看
init()
有个赋值操作,字符串为'I{_}Af2700ih_secTS2Et_wr'
type1()
type2()
下面两个是递归函数,但我不能更好地理解...
查看wp后发现要动态调试,也可以拖入kali中运行,因为这个文件是ELF文件
根据wp和运行可知,这是在考察二叉树的前、中、后序遍历
所以说init函数里的就是总的字符串,为'I{_}Af2700ih_secTS2Et_wr'
type1为中序,type2为后序,而中后序遍历的结果就为上图所示
至于如何判断的前中后序:
前序:根左右
中序:左根右
后序:左右根
所以脚本为(以后遇到二叉树可以套模)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct TreeNode
{
char val;
struct TreeNode* left;//左子树
struct TreeNode* right;//右子树
};
struct TreeNode* buildTree(char* inorder, int inStart, int inEnd, char* postorder, int postStart, int postEnd)
{
if (inStart > inEnd || postStart > postEnd) //如果大于最大长度就结束
{
return NULL;
}
struct TreeNode* root = (struct TreeNode*)malloc(sizeof(struct TreeNode));//创建一个动态结构体数组
root->val = postorder[postEnd];//指向后序中的根字符
int i;
for (i = inStart; i <= inEnd; i++) //计算中序的左子树长度
{
if (inorder[i] == postorder[postEnd]) //如果中序的字符与后序最后一个字符相等就结束计算,也就是最终的根
{
break;
}
}
//开始构建树
root->left = buildTree(inorder, inStart, i - 1, postorder, postStart, postStart + i - inStart - 1);
root->right = buildTree(inorder, i + 1, inEnd, postorder, postStart + i - inStart, postEnd - 1);
return root;
}
void preOrder(struct TreeNode* root)
{
if (!root)
{
return;
}
printf("%c", root->val);
preOrder(root->left);
preOrder(root->right);
}
int main()
{
char inorderStr[] = "2f0t02T{hcsiI_SwA__r7Ee}";//已知中序
char postorderStr[] = "20f0Th{2tsIS_icArE}e7__w";//已知后序
int n = strlen(inorderStr);
struct TreeNode* root = buildTree(inorderStr, 0, n - 1, postorderStr, 0, n - 1);
printf("前序遍历结果为: ");
preOrder(root);
return 0;
}
此题还有一种解法,那就是画图
这个遍历顺序问题画图解决最直观,但要注意别找错了,要不烦死
当然,你也可以在线工具直接一波带走
[WUSTCTF 2020]Cr0ssfun
查壳,无壳64位
拖进IDA中查看
应该是check函数进行了加密,点进去看看,一路跟进
跟进完后,发现是明文flag,直接脚本操作
#include<stdio.h>
int main()
{
char a1[33];
a1[10] = 'p';
a1[13] = '@';
a1[3] = 'f';
a1[26] = 'r';
a1[20] = 'e';
a1[7] = '0';
a1[16] = '_';
a1[11] = 'p';
a1[23] = 'e';
a1[30] = 'u';
a1[0] = 'w';
a1[6] = '2';
a1[22] = 's';
a1[31] = 'n';
a1[12] = '_';
a1[15] = 'd';
a1[8] = '{';
a1[18] = '3';
a1[28] = '_';
a1[21] = 'r';
a1[2] = 't';
a1[9] = 'c';
a1[32] = '}';
a1[19] = 'v';
a1[5] = '0';
a1[14] = 'n';
a1[4] = '2';
a1[17] = 'r';
a1[29] = 'f';
a1[17] = 'r';
a1[24] = '_';
a1[1] = 'c';
a1[25] = '@';
a1[27] = 'e';
printf("%s", a1);
}