前言:最近打了这两个比赛,赛后就把一些题复现了一下,还是学到很多吧。
nepctf
hardcsharp
文件是用C#写的,用
aes解密,网上解密即可dnSpy打开
先获得key
#include<stdio.h>
#include<windows.h>
//badbadwomen!!!!!!!!!!!!!!!!!!!!!
int main()
{
int a[32]={81,82,87,81,82,87,68,92,94,86,93,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18};
int i;
for(i=0;i<32;i++)
{
printf("%x",a[i]^51);
}
}
//key=626164626164776f6d656e212121212121212121212121212121212121212121
然后网上解密就行了
easy_mips
反编译出来,找到加密在这个函数里面,并且对第1,6,7进行了随机数。
根据题目提示,改一下一些字符就行了
#include<stdio.h>
int main(void)
{
char a[]="3_isjA0UeQZcNa\\`\\Vf";
int i, m=5;
for(i=0;i<19;i++)
{
a[i]=a[i]+(m++);
}
a[0]='N';
a[5]='o';
a[6]='l';
printf("%s",a);
}
//Nep{solar_is_sotql}
password
一道APK题目,魔改rc4加密,然后key是一个变表的base64加密,在so文件里面。
先来看key
python解出key
import base64
import string
str1 = "73g6L2PWL2PXFmR+7ise7iq=="
string1 = "abcdefghijklmnopqrstuvwxyz0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZ"
string2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
print (base64.b64decode(str1.translate(str.maketrans(string1,string2))))
//th1s_1s_k3y!!!!!
在来看apk文件,jeb打开,加密过程在Encrypt
rc4解密
#include<stdio.h>
#include<string.h>
#include <wchar.h>
typedef unsigned longULONG;
/*初始化函数*/
void rc4_init(unsigned char*s, unsigned char*key, unsigned long Len)
{
int i = 0, j = 0;
char k[256] = { 0 };
unsigned char tmp = 0;
for (i = 0; i<256; i++)
{
s[i] = 256-i;
k[i] = key[i%Len];
}
for (i = 0; i<256; i++)
{
j = (j + s[i] + k[i]) % 256;
tmp = s[i];
s[i] = s[j];//交换s[i]和s[j]
s[j] = tmp;
}
}
/*加解密*/
void rc4_crypt(unsigned char*s, unsigned char*Data, unsigned long Len)
{
int i = 0, j = 0, t = 0;
unsigned long k = 0;
unsigned char tmp;
for (k = 0; k<Len; k++)
{
i = (i + 1) % 256;
j = (j + s[i]) % 256;
tmp = s[i];
s[i] = s[j];//交换s[x]和s[y]
s[j] = tmp;
t = (s[i] + s[j]) % 256;
Data[k] ^= s[t];
}
}
int main()
{
unsigned char s[256] = { 0 }, s2[256] = { 0 };//S-box
char key[256] ="th1s_1s_k3y!!!!!";
char pData[256] = { '\x8b','\xd2','\xd9','\x5d','\x95','\xff','\x7e','\x5f','\x29','\x56','\x12','\xb9','\xef','\xec','\x8b','\xd0','\x45'};
//char pData[256]="\x8b\xd2\xd9\x5d\x95\xff\x7e\x5f\x29\x56\x12\xb9\xef\xec\x8b\xd0\x45";
unsigned long len = strlen(pData);
int i;
printf("pData=%s\n", pData);
printf("key=%s,length=%d\n\n", key, strlen(key));
rc4_init(s, (unsigned char*)key, strlen(key));//已经完成了初始化
printf("\n");
for (i = 0; i<256; i++)//用s2[i]暂时保留经过初始化的s[i],很重要的!!!
{
s2[i] = s[i];
}
rc4_crypt(s2, (unsigned char*)pData, len);//解密
printf("pData=%s\n\n", pData);
for(i=0;i<20;i++)
{
printf("%d ",pData[i]);
}
return 0;
}
//Y0uG3tTheP4ssw0rd
然后用这个去解压缩包,得到Nep{4c89261f-4d09-4bbf-be6c-9303128a143c}
二十六进制
这道题应该做起了的,可能因为自己手动算时打错数了,最后得到的数错了。
先得到26进制的数
#include<stdio.h>
#include<windows.h>
//2163qwe)(*&^%489$!057@#><A
//25 6 18 19 15 17 1
int main()
{
int table[26]={'2', '1', '6', '3', 'q', 'w', 'e', ')', '(', '*', '&', '^', '%', '4', '8', '9', '$', '!', '0', '5', '7', '@', '#', '>', '<', 'A'};
int a[7]={'F', 'b', '7', '2', '>', '&', '6'};
int i,j;
for(i=0;i<7;i++)
{
a[i]=a[i]^7;
printf("%c,",a[i]);
}
printf("\n");
for(i=0;i<7;i++)
{
for(j=0;j<=32;j++)
{
if(a[i]==table[j])
{
printf("%d ",j);
break;
}
}
}
}
由于是正向存入的数,所以转10进制时要倒着来。
python脚本
l=[1,17,15,19,18,6,25]
num=0
for i in l:
if(i==25):
num=num+i
break;
num=(num+i)*26
print(num)
//518100101
然后md5加密得到Nep{967fa25cbea166ded43127f141cff31a}
worrrrms
文件应该是go语言写的,但是不用脚本也可以看,sm4的ECB模式加密加密,wp说动调可以调出来,能力有限,试了很多次,每次都调飞了,然后根据解题的一些数据来找到相关位置吧。
分析一下
进入sm4加密函数看看
key是base64解密后的,然后转16进制
#include<stdio.h>
int main(void)
{
int code[20]={2, 23, 137, 200, 217, 218, 251, 229, 14, 71, 140, 137, 76, 29,
122, 185};
char key[17]="icantelluasimple";
int i;
printf("key=");
for(i=0;i<16;i++)
{
printf("%02x",key[i]);
}
printf("\ncode=");
for(i=0;i<16;i++)
{
printf("%02x",code[i]);
}
//key=6963616e74656c6c756173696d706c65
//code=021789c8d9dafbe50e478c894c1d7ab9
}
网上python脚本如下
SBOX = ['d6', '90', 'e9', 'fe', 'cc', 'e1', '3d', 'b7', '16', 'b6', '14', 'c2', '28', 'fb', '2c', '05',
'2b', '67', '9a', '76', '2a', 'be', '04', 'c3', 'aa', '44', '13', '26', '49', '86', '06', '99',
'9c', '42', '50', 'f4', '91', 'ef', '98', '7a', '33', '54', '0b', '43', 'ed', 'cf', 'ac', '62',
'e4', 'b3', '1c', 'a9', 'c9', '08', 'e8', '95', '80', 'df', '94', 'fa', '75', '8f', '3f', 'a6',
'47', '07', 'a7', 'fc', 'f3', '73', '17', 'ba', '83', '59', '3c', '19', 'e6', '85', '4f', 'a8',
'68', '6b', '81', 'b2', '71', '64', 'da', '8b', 'f8', 'eb', '0f', '4b', '70', '56', '9d', '35',
'1e', '24', '0e', '5e', '63', '58', 'd1', 'a2', '25', '22', '7c', '3b', '01', '21', '78', '87',
'd4', '00', '46', '57', '9f', 'd3', '27', '52', '4c', '36', '02', 'e7', 'a0', 'c4', 'c8', '9e',
'ea', 'bf', '8a', 'd2', '40', 'c7', '38', 'b5', 'a3', 'f7', 'f2', 'ce', 'f9', '61', '15', 'a1',
'e0', 'ae', '5d', 'a4', '9b', '34', '1a', '55', 'ad', '93', '32', '30', 'f5', '8c', 'b1', 'e3',
'1d', 'f6', 'e2', '2e', '82', '66', 'ca', '60', 'c0', '29', '23', 'ab', '0d', '53', '4e', '6f',
'd5', 'db', '37', '45', 'de', 'fd', '8e', '2f', '03', 'ff', '6a', '72', '6d', '6c', '5b', '51',
'8d', '1b', 'af', '92', 'bb', 'dd', 'bc', '7f', '11', 'd9', '5c', '41', '1f', '10', '5a', 'd8',
'0a', 'c1', '31', '88', 'a5', 'cd', '7b', 'bd', '2d', '74', 'd0', '12', 'b8', 'e5', 'b4', 'b0',
'89', '69', '97', '4a', '0c', '96', '77', '7e', '65', 'b9', 'f1', '09', 'c5', '6e', 'c6', '84',
'18', 'f0', '7d', 'ec', '3a', 'dc', '4d', '20', '79', 'ee', '5f', '3e', 'd7', 'cb', '39', '48',]
FK = ['a3b1bac6', '56aa3350', '677d9197', 'b27022dc']
CK = ['00070e15', '1c232a31', '383f464d', '545b6269',
'70777e85', '8c939aa1', 'a8afb6bd', 'c4cbd2d9',
'e0e7eef5', 'fc030a11', '181f262d', '343b4249',
'50575e65', '6c737a81', '888f969d', 'a4abb2b9',
'c0c7ced5', 'dce3eaf1', 'f8ff060d', '141b2229',
'30373e45', '4c535a61', '686f767d', '848b9299',
'a0a7aeb5', 'bcc3cad1', 'd8dfe6ed', 'f4fb0209',
'10171e25', '2c333a41', '484f565d', '646b7279']
def left(list,n):
return list[n:] + list[:n]
def group(list, n):
for i in range(0, len(list), n):
yield list[i:i + n]
def xor(a,b):
a1 = int(a,16)
b1 = int(b,16)
if a == b:
A = '{:032x}'.format(int(a1^b1))
else:
A = '{:08x}'.format(int(a1^b1))
return A
def round_function(k0,k1,k2,k3,rk,mod):
k = xor(xor(xor(k1,k2),k3),rk)
Tr = T(k,mod)
rki = xor(k0,Tr)
return rki
def T(A,mod):
T = linear(S(A),mod)
return T
def S(A):
A1 = []
A2 = [0,0,0,0]
for i in group(A,2):
A1.append(i)
for i in range(4):
l = int(A1[i],16)
A2[i] = '{:02x}'.format(int(SBOX[l],16))
A2 = ''.join(A2)
return A2
def linear(B,mod):
B1 = list(B)
for i in range(8):
B1[i] = '{:04b}'.format(int(B1[i],16))
B1 = ''.join(B1)
B1_2= left(B1,2)
B1_10 = left(B1,10)
B1_18 = left(B1,18)
B1_24 = left(B1,24)
B1_13 = left(B1,13)
B1_23 = left(B1,23)
if mod == 'enc' or mod == 'dec':
BX = xor(xor(xor(xor(B1,B1_2),B1_10),B1_18),B1_24)
elif mod == 'extend':
BX = xor(xor(B1,B1_13),B1_23)
else:
return "模式输入错误"
BX = '%x'%int(BX, 2)
return BX
def get_key(key):
MK = []
for i in group(key,8):
MK.append(i)
key0 = xor(MK[0],FK[0])
key1 = xor(MK[1],FK[1])
key2 = xor(MK[2],FK[2])
key3 = xor(MK[3],FK[3])
keylist = [key0,key1,key2,key3]
rk = []
for i in range(32):
a = round_function(keylist[i],keylist[i+1],keylist[i+2],keylist[i+3],CK[i],mod='extend')
keylist.append(a)
rk.append(a)
return rk
def get_sm4_ecb(key,input_data,mod):
data = []
rk = get_key(key)
for i in group(input_data,8):
data.append(i)
for i in range(32):
if mod == 'enc':
ldata = round_function(data[i],data[i+1],data[i+2],data[i+3],rk[i],mod)
else:
ldata = round_function(data[i],data[i+1],data[i+2],data[i+3],rk[31-i],mod)
data.append(ldata)
out_data = [data[35],data[34],data[33],data[32]]
out_data = ''.join(out_data)
return out_data
s=''
s=get_sm4_ecb(key = '6963616e74656c6c756173696d706c65', input_data = '021789c8d9dafbe50e478c894c1d7ab9', mod = 'dec')
y = bytearray.fromhex(s)
print(y)
//we1come_2_nepCTF
得到Nep{we1come_2_nepCTF}
dasctf
drinkSomeTea
这道题吃了不会文件知识的亏吧,太菜的我居然用提数据来做,真是sb,而且数据处理还有一些地方存在问题,导致自己用解密后的数据生成的png文件不对。
先说一说考点吧,思路还是很简单,要先去花指令才能看到tea加密,然后这个tea加密是int的,大概过程就是将一个png文件两个int,两个int的加密。
先去花。
再来看主要过程
然后写脚本就ok了
#include <stdio.h>
void decrypt (int* v, int* k)
{
int v0=v[0], v1=v[1], sum=0xC6EF3720, i;
int delta=0x9e3779b9;
int k0=k[0], k1=k[1], k2=k[2], k3=k[3];
for (i=0; i<32; i++)
{
v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
sum -= delta;
}
v[0]=v0; v[1]=v1;
}
int main()
{
int v[14656]={0},k[4]={0x67616C66, 0x6B61667B, 0x6C665F65, 0x7D216761};
FILE *p1 = fopen("./tea.png.out", "rb");
fread(&v, 4, 14656, p1);
fclose(p1);
for(int i=0;i<14656;i+=2)
{
decrypt(&v[i], k);
}
FILE *p2 = fopen("./tea.png", "wb");
fwrite(&v, 4, 14656, p2);
fclose(p2);
return 0;
}
这里就写一些关于文件读写的函数吧。
fopen
fopen函数是打开一个文件,FILE *FP的这个fp是一个流
FILE *fp;
fp=fopen("file a","r");
其意义是在当前目录下打开文件file a,只允许进行“读”操作,并使fp指向该文件。
FILE *fphzk
fphzk=fopen("c:\\hzk16","rb");
其意义是打开C驱动器磁盘的根目录下的文件hzk16,按二进制方式进行读操作。两个反斜线“\\ ”中的第一个表示转义字符,第二个表示根目录。
fclose
fopen函数是关闭一个流
fclose是一个函数名,功能是关闭一个流。注意:使用fclose()函数就可以把缓冲区内最后剩余的数据输出到内核缓冲区,并释放文件指针和有关的缓冲区。
函数原型:int fclose( FILE *fp );
返回值:如果流成功关闭,fclose 返回 0,否则返回EOF(-1)。(如果流为NULL,而且程序可以继续执行,fclose设定error number给EINVAL,并返回EOF。)
fwrite
从给定输入流stream读取最多count个对象到数组buffer中(相当于对每个对象调用size次fgetc),把buffer当作unsigned char数组并顺序保存结果。
fread( void *buffer, // 指向要读取的数组中首个对象的指针
size_t size, //每个对象的大小(单位是字节)
size_t count, // 要读取的对象个数
FILE *stream //输入流
)
fwrite
fwrite() 是 C 语言标准库中的一个文件处理函数,功能是向指定的文件中写入若干数据块,如成功执行则返回实际写入的数据块数目。该函数以二进制形式对文件进行操作,不局限于文本文件。
size_t fwrite(
const void *ptr, // 是一个指针,对fwrite来说,是要获取数据的地址;
size_t size, // 要写入内容的单字节数;
size_t nmemb, // 要进行写入size字节的数据项的个数;
FILE *stream // 目标文件指针,流
)
Enjoyit-1
考点就是变表的base64,和改了delta的xtea算法吧。
变表base64
c函数
python脚本
import base64
import string
str1 = 'yQXHyBvN3g/81gv51QXG1QTBxRr/yvXK1hC='
string1 = "abcdefghijklmnopqrstuvwxyz0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZ"
string2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
print(base64.b64decode(str1.translate(str.maketrans(string1, string2))))
//b'combustible_oolong_tea_plz'
得到flag要27h,显然不可能等,继续看后面过程
先得到xtea加密后的array
#include <stdio.h>
void encipher(unsigned int num_rounds, unsigned int v[2], unsigned int key[4]) {
unsigned int i;
unsigned int v0=v[0], v1=v[1], sum=0, delta=2654435464U;
for (i=0; i < num_rounds; i++) {
v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
sum += delta;
v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
}
v[ 0]=v0; v[1]=v1;
}
int main()
{
unsigned int v[2]={288,369};
unsigned int k[4]={0x63,0x6f,0x6d,0x62};
unsigned int r=32;
encipher(r, v, k);
printf("加密后的数据:%x %x\n",v[0],v[1]);
return 0;
}
//6308fe34b7fe6fdb
再进行异或
#include <stdio.h>
int main(void)
{
int flag[]={2,5,4,13,3,84,11,4,87,3,86,3,80,7,83,3,0,4,83,94,7,84,4,0,1,83,3,84,6,83,5,80};
char key[17]="6308fe34b7fe6fdb";
int i;
printf("flag{");
for(i=0;i<32;i++)
{
flag[i]=flag[i]^key[i%16];
printf("%c",flag[i]);
}
printf("}");
}
得到flag{4645e180540ffa7a67cfa174cde105a2}
方法2,得到解密后的base64字符串后,直接跳过等待。
继续跑得到flag
replace
看了wp后,这道题比较惊艳到我的地方还是那个栅栏加密,充分利用了int型变量有4个字节,而char型变量只有1个字节。然后用win32的一些函数和花指令将真正的加密函数给隐藏了。通过动调来更能理解这个程序干了什么,什么函数是有用的。
下面先ida载入看看主函数逻辑
然后看看修改IsDebuggerPresent()函数地址的sub_401925函数
然后现在来去花
真正的加密函数
不得不说这种栅栏加密还是第一次见,通过动调来理解或许会好一些。所以说解密思路就是,先进行栅栏解密,然后再去进行5轮换盒。
exp
#include<stdio.h>
int main()
{
char a[6][4]={65, 111, 107, 17,
101, 73, 67, 92,
44, 15, 17, 67,
23, 67, 57, 2,
61, 77, 76, 15,
24, 62, 120, 40};
int b[24];
int table[128]={0x80,0x65,0x2F,0x34,0x12,0x37,0x7D,0x40,0x26,0x16,0x4B,0x4D,0x55,0x43,0x5C,0x17,0x3F,0x69,0x79,0x53,0x18,0x02,0x06,0x61,0x27,0x08,0x49,0x4A,0x64,0x23,0x56,0x5B,0x6F,0x11,0x4F,0x14,0x04,0x1E,0x5E,0x2D,0x2A,0x32,0x2B,0x6C,0x74,0x09,0x6E,0x42,0x70,0x5A,0x71,0x1C,0x7B,0x2C,0x75,0x54,0x30,0x7E,0x5F,0x0E,0x01,0x46,0x1D,0x20,0x3C,0x66,0x6B,0x76,0x63,0x47,0x6A,0x29,0x25,0x4E,0x31,0x13,0x50,0x51,0x33,0x59,0x1A,0x5D,0x44,0x3E,0x28,0x0F,0x19,0x2E,0x05,0x62,0x4C,0x3A,0x21,0x45,0x1F,0x38,0x7F,0x57,0x3D,0x1B,0x3B,0x24,0x41,0x77,0x6D,0x7A,0x52,0x73,0x07,0x10,0x35,0x0A,0x0D,0x03,0x0B,0x48,0x67,0x15,0x78,0x0C,0x60,0x39,0x36,0x22,0x7C,0x58,0x72,0x68};
int i,j,n,c=0;
for(i=0;i<4;i++)
{
for(j=0;j<6;j++)
{
b[c]=a[j][i];
// printf("%d ",b[c]);
c++;
}
}
printf("\n");
for(n=0;n<5;n++)
{
for(i=0;i<24;i++)
{
for(j=0;j<128;j++)
{
if(b[i]==table[j])
{
b[i]=j;
break;
}
}
}
}
for(i=0;i<24;i++)
{
printf("%c",b[i]);
}
}
得到flag{Sh1t_you_dec0d3_it},然后md5加密