2021-newsctf-Re

2021-newsctf

对这个题目的吐槽:我是在做逆向还是misc。。。。
1.第一道为什么加个rot13在后面....还一点提示都没有,真就misc吗。
2.1+1的那道题目,我觉得只有出题人自己觉得那个题逻辑很好,完全是靠猜,
虽然这照应了题目的main函数未写完,连逻辑都连不起来的逆向题,神仙给你把逻辑连起来
(除开那个随机数处理有点价值)。
3.至于两道APK,风格真的很像misc,不过还能勉强接受,逻辑和加密步骤都还好
4.Qsay很扯,那一堆控制流平坦化,究竟是想干什么,结果就只是一个魔改了s盒和CK的SM4,这是考用findcrypt
工具的能力吗,还是说思维的敏捷

一:re-signin

考点:pyc逆向,python代码分析,ROT13加密

pyc反编译成py文件,分析代码

flag = "xxxx{xxxxxxxxxxxxxxxxxx}"
import random
c = [0]*len(flag)
for i in range(len(flag)):
    c[i] = ord(flag[i])
print(c)
t = 0
for i in range(2000):
    num = range(0, 100)
    nums = random.sample(num, 22)
    numss = nums.copy()
    for i in range(len(nums) - 1):
        for j in range(len(nums)-i-1):
            if nums[j] > nums[j+1]:
                nums[j], nums[j+1] = nums[j+1], nums[j]
    if(count==c[t]):#what's count?
        print(numss)
        t += 1
        if(t==24):
            break

显然count就是排序次数,也就是我们的flag的ASCII值

解题脚本:

# _*_ coding: utf-8 _*_
# editor: SYJ
# function: Reversed By SYJ
# describe:
table = [[73, 69, 60, 20, 64, 68, 99, 4, 36, 9, 91, 42, 75, 43, 8, 77, 55, 70, 84, 37, 3, 93],
[85, 46, 47, 99, 58, 35, 83, 3, 57, 18, 52, 17, 97, 16, 6, 51, 84, 62, 1, 41, 88, 87],
[97, 34, 31, 80, 19, 57, 10, 84, 4, 50, 43, 63, 65, 88, 30, 72, 21, 36, 27, 41, 86, 79],
[31, 23, 68, 67, 30, 47, 27, 40, 73, 63, 11, 89, 18, 5, 9, 74, 88, 38, 8, 20, 50, 83],
[88, 5, 85, 82, 36, 74, 6, 15, 40, 55, 95, 8, 84, 47, 96, 33, 25, 29, 77, 67, 26, 39],
[54, 53, 0, 37, 66, 91, 39, 38, 57, 6, 47, 28, 49, 92, 29, 85, 88, 84, 90, 13, 35, 52],
[80, 18, 26, 91, 10, 52, 11, 99, 85, 75, 60, 48, 36, 74, 55, 51, 86, 49, 89, 29, 82, 16],
[35, 70, 42, 44, 18, 65, 84, 71, 26, 14, 38, 28, 21, 86, 20, 54, 30, 11, 66, 10, 69, 77],
[71, 25, 43, 23, 29, 6, 33, 44, 5, 30, 32, 18, 47, 13, 76, 8, 83, 87, 57, 26, 16, 19],
[29, 51, 7, 62, 94, 32, 57, 1, 71, 84, 92, 16, 18, 19, 56, 52, 40, 80, 98, 44, 82, 33],
[67, 14, 93, 91, 78, 80, 7, 37, 10, 82, 38, 83, 23, 27, 17, 76, 74, 18, 66, 24, 99, 43],
[29, 56, 44, 54, 70, 31, 10, 38, 8, 85, 18, 22, 32, 49, 2, 21, 50, 5, 25, 48, 90, 84],
[23, 33, 90, 7, 42, 71, 25, 58, 5, 47, 54, 18, 97, 72, 2, 1, 68, 64, 76, 85, 69, 49],
[77, 67, 52, 31, 35, 6, 56, 94, 81, 23, 78, 50, 15, 10, 28, 69, 43, 91, 82, 72, 99, 38],
[20, 47, 52, 27, 73, 64, 9, 62, 3, 57, 2, 97, 44, 35, 89, 10, 18, 29, 58, 56, 74, 84],
[66, 11, 76, 91, 70, 9, 6, 75, 32, 71, 44, 48, 88, 20, 98, 97, 79, 63, 47, 78, 60, 81],
[43, 13, 70, 23, 31, 69, 52, 30, 2, 78, 0, 37, 73, 93, 18, 1, 51, 62, 25, 68, 65, 87],
[24, 86, 29, 0, 93, 51, 53, 47, 16, 40, 94, 98, 88, 64, 41, 83, 44, 35, 45, 75, 17, 46],
[33, 12, 63, 77, 25, 24, 47, 58, 6, 89, 97, 27, 21, 96, 92, 50, 82, 76, 5, 62, 56, 44],
[12, 36, 16, 44, 19, 62, 43, 80, 58, 98, 69, 97, 1, 7, 49, 26, 70, 34, 53, 13, 65, 48],
[51, 74, 76, 98, 33, 78, 44, 45, 4, 65, 99, 84, 80, 93, 37, 56, 77, 9, 6, 94, 52, 88],
[80, 38, 88, 66, 7, 40, 70, 24, 2, 12, 76, 18, 57, 73, 58, 83, 33, 17, 89, 69, 77, 67],
[18, 53, 14, 24, 94, 42, 61, 75, 62, 60, 73, 2, 65, 48, 80, 23, 44, 91, 7, 0, 31, 71],
[16, 54, 87, 75, 8, 23, 33, 56, 22, 63, 1, 2, 25, 6, 84, 80, 4, 49, 17, 42, 14, 43]]
string = ''
for k in range(len(table)):
    nums = table[k]
    count = 0
    for i in range(len(nums) - 1):  # 将最后的nums排序
        for j in range(len(nums) - i - 1):
            if nums[j] > nums[(j + 1)]:
                nums[j], nums[j + 1] = nums[(j + 1)], nums[j]
                count += 1
    string += chr(count)
import Rot13
print(Rot13.func(string)

二:1+1=?

没有解题过程,乱猜,拼凑起来

解题脚本:

对随机数的理解,这个有一点点意思,不同平台下随机数算法不同,如果种子相同,同平台,生成的随机数序列就是相同的

#include <stdio.h>
#include <stdlib.h>

int main()
{
    unsigned long long int v2=0;
    unsigned long long int v3=0;
    unsigned long long int a1 = 0;    //在不知道对方是否是4字节的时候,多给空间,避免造成数据缺失
    srand(0x535F4D72);                //同平台的随机数生成算法的一样的
    v2=rand();
    v3=rand();
    printf("v2=%#llx\n",v2);
    printf("v3=%#llx\n", v3);
    a1 = 20 * v3 ^ 0x67B7940F53 ^ 0x235FFFA864 ^ v2;
    printf("a1=%#llx\n",a1);
    printf("%c%c%c%c%c\n",*((char*)&a1+4), *((char*)&a1 + 3), *((char*)&a1 + 2), *((char*)&a1 + 1), *((char*)&a1 + 0));
    return 0;
}

得到flag前五个字节

后面的flag是secret函数里面两个secret解开得到的

# _*_ coding: utf-8 _*_
# editor: SYJ
# function: Reversed By SYJ
# describe:
def b58encode(tmp:str) -> str:
    tmp = list(map(ord,tmp))
    temp = tmp[0]
    base58 = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz123456789"
    for i in range(len(tmp)-1):
        temp = temp * 256 + tmp[i+1]
    tmp = []
    while True:
        tmp.insert(0,temp % 58)
        temp = temp // 58
        if temp == 0:
            break
    temp = ""
    for i in tmp:
        temp += base58[i]
    return temp

def b58decode(tmp:str) -> str:
    import binascii
    base58 = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz123456789"
    temp = []
    for i in tmp:
        temp.append(base58.index(i))
    tmp = temp[0]
    for i in range(len(temp)-1):
        tmp = tmp * 58 + temp[i+1]
    return binascii.unhexlify(hex(tmp)[2:].encode("utf-8")).decode("UTF-8")

print("E4sy?")     # 第一个解开的
print(b58decode("ZoJPRqxMfvzxNqu"))  # 解secret1

# 得到变换后的base64表
table = b58decode("BTqHGKfUP69n1YGCyv6GEch9GEeyXiGwHeP8sTJT4V3jFab2AgMyF6noE48Sb6kp2VSg4Xi9Ak6cNBUJMVkMBemp")
str2 = 'ITFDNG5nejSVfUFcfGssbjVcIR=='   # 解secret2(变表base64)
base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
import base64
real_str = ''
for i in range(len(str2)):
    real_str += base[table.find(str2[i])]
print(base64.b64decode(real_str))
# flag{E4sy?_Up_t0_Y0u!!!C0ngr4Tu1atl0n5!!}

三:开门1

在这里插入图片描述

解题脚本:

# _*_ coding: utf-8 _*_
# editor: SYJ
# function: Reversed By SYJ
# describe:
cmp = [0x7A, 0x74, 0x7F, 0x79, 0x85, 0x4F, 74, 76, 71, 72, 77, 75, 74, 73, 76, 74, 76, 77, 76, 0x83]
for i in range(len(cmp)):
    print(chr((cmp[i] ^ 15) - 15), end='')

四:Qsay

Qsay.exe放SM4加密后的数据,key放SM4的key,dll控制流平坦化魔改SM4(改了CK和那个S盒)

对拍解题脚本:

/*
*这道题目更换了s盒
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define u8 unsigned char
#define u32 unsigned long

/* 四字节转换成u32 */
void four_uCh2uLong(u8 *in, u32 *out);
/* u32转换成四字节 */
void uLong2four_uCh(u32 in, u8 *out);
/* 左移,保留丢弃位放置尾部 */
unsigned long move(u32 data, int length);
/* 先使用Sbox进行非线性变化,再将线性变换L置换为L' */
unsigned long func_key(u32 input);
/* 先使用Sbox进行非线性变化,再进行线性变换L */
unsigned long func_data(u32 input);
/* 无符号字符数组转16进制打印 */
void print_hex(u8 *data, int len);
/* 加密函数 */
void encode_fun(u8 len,u8 *key, u8 *input, u8 *output);
/* 解密函数 */
void decode_fun(int len,u8 *key, u8 *input, u8 *output);            //我们知道加密后的数据是32字节直接传入字节数即可,改成int型参数

/* 定义系统参数FK的取值 */
const u32 TBL_SYS_PARAMS[4] = {
	0xa3b1bac6,
	0x56aa3350,
	0x677d9197,
	0xb27022dc
};

/* 定义固定参数CK的取值 */
const u32 TBL_FIX_PARAMS[32] = {
	0x00070e15,0x1c232a31,0x383f464d,0x545b6269,
	0x70777e85,0x8c939aa1,0xa8afb6bd,0xc4cbd2d9,
	0xe0e7eef5,0xfc030a11,0x181f262d,0x343b4249,
	0x50575e65,0x6c737a81,0x888f969d,0xa4abb2b9,
	0xc0c7ced5,0xdce3eaf1,0xf8ff060d,0x141b2229,
	0x30373e45,0x4c535a61,0x686f787d,0x848b9299,
	0xa0a7aeb5,0xbcc3cad1,0xd8dfe6ed,0xf4fb0209,
	0x10171e25,0x2c333a41,0x484f565d,0x646b7279
};

/*S盒参数列表 */
const u8 TBL_SBOX[256] = {
	0xC6,0x90,0xe9,0xfe,0xcc,0xe1,0x3F,0xb7,0x16,0xb6,0x14,0xc2,0x28,0xfb,0x2c,0x05,
	0x2b,0x67,0x9a,0x76,0x2C,0xbe,0x04,0xc3,0xaa,0x44,0x13,0x26,0x49,0x86,0x06,0x99,
	0x9c,0x42,0x50,0xf4,0x91,0xef,0x98,0x7a,0x33,0x54,0x0b,0x43,0xed,0xcf,0xac,0x62,
	0xe4,0xb3,0x1c,0xa9,0xc9,0x08,0xe8,0x95,0x80,0xdf,0x94,0xfa,0x75,0x8f,0x3f,0xa6,
	0x47,0x07,0xa7,0xfc,0xf3,0x73,0x17,0xba,0x83,0x59,0x3c,0x19,0xe6,0x85,0x4f,0xa8,
	0x68,0x6b,0x81,0xb2,0x71,0x64,0xda,0x8b,0xf8,0xeb,0x0f,0x4b,0x70,0x56,0x9d,0x35,
	0x1e,0x24,0x0e,0x5e,0x63,0x58,0xd1,0xa2,0x25,0x22,0x7c,0x3b,0x01,0x21,0x78,0x87,
	0xd4,0x00,0x46,0x57,0x9f,0xd3,0x27,0x52,0x4c,0x36,0x02,0xe7,0xa0,0xc4,0xc8,0x9e,
	0xea,0xbf,0x8a,0xd2,0x40,0xc7,0x38,0xb5,0xa3,0xf7,0xf2,0xce,0xf9,0x61,0x15,0xa1,
	0xe0,0xae,0x5d,0xa4,0x9b,0x34,0x1a,0x55,0xad,0x93,0x32,0x30,0xf5,0x8c,0xb1,0xe3,
	0x1d,0xf6,0xe2,0x2e,0x82,0x66,0xca,0x60,0xc0,0x29,0x23,0xab,0x0d,0x53,0x4e,0x6f,
	0xd5,0xdb,0x37,0x45,0xde,0xfd,0x8e,0x2f,0x03,0xff,0x6a,0x72,0x6d,0x6c,0x5b,0x51,
	0x8d,0x1b,0xaf,0x92,0xbb,0xdd,0xbc,0x7f,0x11,0xd9,0x5c,0x41,0x1f,0x10,0x5a,0xd8,
	0x0a,0xc1,0x31,0x88,0xa5,0xcd,0x7b,0xbd,0x2d,0x74,0xd0,0x12,0xb8,0xe5,0xb4,0xb0,
	0x89,0x69,0x97,0x4a,0x0c,0x96,0x77,0x7e,0x65,0xb9,0xf1,0x09,0xc5,0x6e,0xc6,0x84,
	0x18,0xf0,0x7d,0xec,0x3a,0xdc,0x4d,0x20,0x79,0xee,0x5f,0x3e,0xd7,0xcb,0x39,0x48
};

/* 4字节无符号数组转无符号long型 */
void four_uCh2uLong(u8 *in, u32 *out)
{
	int i = 0;
	*out = 0;
	for (i = 0; i < 4; i++)
		*out = ((u32)in[i] << (24 - i * 8)) ^ *out;
}

/* 无符号long型转4字节无符号数组 */
void uLong2four_uCh(u32 in, u8 *out)
{
	int i = 0;
	//从32位unsigned long的高位开始取
	for (i = 0; i < 4; i++)
		*(out + i) = (u32)(in >> (24 - i * 8));
}

/* 左移,保留丢弃位放置尾部 */
u32 move(u32 data, int length)
{
	u32 result = 0;
	result = (data << length) ^ (data >> (32 - length));

	return result;
}

/* 秘钥处理函数,先使用Sbox进行非线性变化,再将线性变换L置换为L' */
u32 func_key(u32 input)
{
	int i = 0;
	u32 ulTmp = 0;
	u8 ucIndexList[4] = { 0 };
	u8 ucSboxValueList[4] = { 0 };
	uLong2four_uCh(input, ucIndexList);
	for (i = 0; i < 4; i++)
	{
		ucSboxValueList[i] = TBL_SBOX[ucIndexList[i]];
	}
	four_uCh2uLong(ucSboxValueList, &ulTmp);
	ulTmp = ulTmp ^ move(ulTmp, 13) ^ move(ulTmp, 23);

	return ulTmp;
}

/* 加解密数据处理函数,先使用Sbox进行非线性变化,再进行线性变换L */
u32 func_data(u32 input)
{
	int i = 0;
	u32 ulTmp = 0;
	u8 ucIndexList[4] = { 0 };
	u8 ucSboxValueList[4] = { 0 };
	uLong2four_uCh(input, ucIndexList);
	for (i = 0; i < 4; i++)
	{
		ucSboxValueList[i] = TBL_SBOX[ucIndexList[i]];
	}
	four_uCh2uLong(ucSboxValueList, &ulTmp);
	ulTmp = ulTmp ^ move(ulTmp, 2) ^ move(ulTmp, 10) ^ move(ulTmp, 18) ^ move(ulTmp, 24);

	return ulTmp;
}

/* 解密函数(与加密函数基本一致,只是秘钥使用的顺序不同,即把钥匙反着用就是解密) */
//len:数据长度 key:密钥 input:输入的加密后数据 output:输出的解密后数据
void decode_fun(int len,u8 *key, u8 *input, u8 *output)
{
	int i = 0,j=0;
	u32 ulKeyTmpList[4] = { 0 };//存储密钥的u32数据
	u32 ulKeyList[36] = { 0 };  //用于密钥扩展算法与系统参数FK运算后的结果存储
	u32 ulDataList[36] = { 0 }; //用于存放加密数据
    len = 16 * (len / 16) + 16 * ((len % 16) ? 1 : 0);

	/*开始生成子秘钥*/
	four_uCh2uLong(key, &(ulKeyTmpList[0]));
	four_uCh2uLong(key + 4, &(ulKeyTmpList[1]));
	four_uCh2uLong(key + 8, &(ulKeyTmpList[2]));
	four_uCh2uLong(key + 12, &(ulKeyTmpList[3]));

	ulKeyList[0] = ulKeyTmpList[0] ^ TBL_SYS_PARAMS[0];
	ulKeyList[1] = ulKeyTmpList[1] ^ TBL_SYS_PARAMS[1];
	ulKeyList[2] = ulKeyTmpList[2] ^ TBL_SYS_PARAMS[2];
	ulKeyList[3] = ulKeyTmpList[3] ^ TBL_SYS_PARAMS[3];

	for (i = 0; i < 32; i++)             //32次循环迭代运算
	{
		//5-36为32个子秘钥
		ulKeyList[i + 4] = ulKeyList[i] ^ func_key(ulKeyList[i + 1] ^ ulKeyList[i + 2] ^ ulKeyList[i + 3] ^ TBL_FIX_PARAMS[i]);
	}
	/*生成32轮32位长子秘钥结束*/

	for (j = 0; j < len / 16; j++)
	{
		/*开始处理解密数据*/
		four_uCh2uLong(input + 16 * j, &(ulDataList[0]));
		four_uCh2uLong(input + 16 * j + 4, &(ulDataList[1]));
		four_uCh2uLong(input + 16 * j + 8, &(ulDataList[2]));
		four_uCh2uLong(input + 16 * j + 12, &(ulDataList[3]));

		//解密
		for (i = 0; i < 32; i++)
		{
			ulDataList[i + 4] = ulDataList[i] ^ func_data(ulDataList[i + 1] ^ ulDataList[i + 2] ^ ulDataList[i + 3] ^ ulKeyList[35 - i]);//与加密唯一不同的就是轮密钥的使用顺序
		}
		/*将解密后数据输出*/
		uLong2four_uCh(ulDataList[35], output + 16 * j);
		uLong2four_uCh(ulDataList[34], output + 16 * j + 4);
		uLong2four_uCh(ulDataList[33], output + 16 * j + 8);
		uLong2four_uCh(ulDataList[32], output + 16 * j + 12);
	}
}

/* 无符号字符数组转16进制打印 */
void print_hex(u8 *data, int len)
{
	int i = 0;
	char alTmp[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
	for (i = 0; i < len; i++)
	{
		printf("%c", alTmp[data[i] / 16]);
		printf("%c", alTmp[data[i] % 16]);
        putchar(' ');
	}
	putchar('\n');
}

/*在主函数中实现任意字节加密与解密,并且结果正确*/
int main(void)
{
	u8 i;
	u8 encode_Result[50] = {0xAF, 0xD3, 0xD5, 0x71, 0x1F, 0xC6, 0xA3, 0x42, 0xC5, 0x64, 0x53, 0x2E, 0xFE, 0x13, 0xF1, 0xA3, 0x0F, 0x96, 0x0A, 0x0B, 0x1D, 0x3D, 0x83, 0x33, 0x2A, 0x4B, 0x71, 0x98, 0x10, 0xFF, 0x70, 0x43};    //定义加密输出缓存区
	u8 decode_Result[50] = { 0 };    //定义解密输出缓存区
	u8 key[16] = {0x4D,0x4C,0x7B,0x4F,0xAB,0x6B,0x78,0x09,0xE6,0x27,0xFA,0x9D,0xA6,0xC6,0x4E,0x8A}; 	//定义16字节的密钥
	decode_fun(32, key, encode_Result, decode_Result);      //数据解密
	printf("解密后数据:");
	for (i = 0; i < 32; i++)
	{
		if(decode_Result[i] >= 16)
		{
			printf("0x%x ", decode_Result[i]);
		}
		else{
			printf("0x0%x ", decode_Result[i]);
		}
	}
	printf("\n转成字符串:%s\n",decode_Result);
	system("pause");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值