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;
}