前言:最近打了这两个比赛,赛后就把一些题复现了一下,还是学到很多吧。

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加密