内容简介:记录DDCTF中一道非常需要耐心的逆向题
这题出现在DDCTF的level8,题目给了两张图片和一段文字,稍后我会提供附件。
挑战:《Crack me if you can》
赛题背景:图片信息隐藏与数字水印技术一直是安全研究领域的热门话题之一,本挑战结合了图片内嵌、算法逆向等知识点,考察了挑战者的综合技术素养。
赛题描述:本题是一张图片,请试分析图片中隐藏的内嵌文件,逆向 Crack me 算法并得到 DDCTF-65f9 输入所对应的密钥。
评分标准:密钥正确则可进入下一题。
图片1:
图片2(名字crackme.png,关键附件,请从下文中下载原图):
附件下载: http://pan.baidu.com/s/1jIMaBum 密码:5cah
从图片到程序
首先由名字crackme,我们知道了这是一道re题,但他给了一张图片。
我们用010editor打开他。
emmm,标准的jpg文件头,果然png的后缀名是假的,jpg的文件结尾标志是FFD9,ctrl+F查找
发现后面附加了一段数据,把这段数据先单独存下来。
不知是不是直觉,我猜这段数据是zlib的压缩数据,用 python 写脚本解压一下。
import zlib enc = open('dump','rb').read() dec = zlib.decompress(enc) print dec
输出了一段base64,由于数据过长,就不贴了。我把他base64解码后写到文件。
import zlib enc = open('dump','rb').read() dec = zlib.decompress(enc).decode('base64') open('dump_base64','wb').write(dec)
再用010editor打开,发现我们熟悉的zip文件头PK被改成了KP(滑稽)
改过来以后得到压缩包 dump.zip
。
然而解压需要密码。
结合题目提供的第一张图,这是一个除零错误。
试一试就知道了。
Traceback (most recent call last): File "C:\Users\veritas501\Desktop\study\test.py", line 1, in <module> 2/0 ZeroDivisionError: integer division or modulo by zero [Finished in 0.1s]
所以压缩密码是 integer division or modulo by zero
。
成功得到 crackme.exe
!!
IDA加OD动静态分析
OD里下 GetDlgItemTextA
断点,来到获取输入的地址 0x00**1EE4
,IDA也相应的来到 0x00**1EE4
。
接下来在IDA中疯狂整理代码逻辑和变量名。这段辛酸过程省略,不想整理的话我上面的附件里也提供了我当时做题时整理好的idb文件,直接载入也行。
首先程序里有一段240bytes长的char * head,作为常量,结合输入的password(即mail)进行大量的运算,所得的值1和输入的uasename通过某种运算的到的值2相等。
整理一下逻辑。
username题目告诉我们了,因为用了strcat,所以key可以推出,key到IV3由于是正向计算,直接在OD中动态跟一下结果IV3也就出来了。又因为IV2和IV3是相等的关系,所以IV2也可以直接得到。head到hash是正向算法,hash也可以直接动态跟出来。
head->hash\ IV1\ mail_mid->pwd/ IV2\ head/ equal!! username->key->IV3/ username:DDCTF-65f9 IV3:IV2:'e8d8e2ceaf9de076a0f211f5a1895352'.encode('hex') len IV2,IV3 = 16 hash: 7DEC14283116611B3CBD497513843B3B304D171BF021FF0C9E8D4692307EBC7AE8223FB03CE6FE1C6EC09B6C957C40A49D8D2CC63F13953F8973EDF80CD3B7775C5DE5D0BE87E7B62AD148729F60649E3D059704628685678A0AEC8BC80ED5F70AB1B095042BFD3FCDA94906961437F5A8009DBC70D01C4591D583A6FE967A9992CF10E197BDBAAD3BE159E448393F08DAC047366783936D408B2DA876AFB530CAA6F54FAD0AF83A6F860B9E8B40EC1D len hash :0xB0
所以现在的关键是需要对IV12IV3这个算法求逆,由IV2和head推出IV1。然后再对hash2IV1这个函数求逆,由IV1和hash推出pwd。然后pwd直接encode_hex就能得到mail_mid。
分析IV12IV2
又是一段艰苦的逆向,最后发现就是一个稍微变化过的aes解码函数。。。
当然逆向这东西,事后看看都觉得简单,只有自己逆过才懂得艰辛。
用python写出加密和解密函数:
head = '4E5332303137434D2D44444354462D006469646963687578696E672E636F6D00E3E22A86D2D569CBFF912D88ABD70088795A7C0A1A320972735C6E5C1033035C7E73C8AAACA6A16153378CE9F8E08C61B0FD53F4AACF5A86D99334DAC9A037861090A478BC360519EF0189F017E105912C5455E7869B0F615F083BBB96A80C3DDD94FDCB61A2F8D28EA37122994274B3434E26BBC5D529DA9ADD12610C751E5C0DB91FCF6C1BE71DE2B8963F7BFAE28CAF1526946AC00F4EF01D1D2FFC680373A928A37DC5334460278BD25F5C7130D34D8C69C6274C6688D7517BA72B3978D4CBAF95E70E9CD187291703D87566330B'.decode('hex') box = 'E2D681A62AFEC53CBDAF540A75D85120E9BBED7A92EE48A46E03B56DB8A5597DDF4A391A4DD3C722EC50DEFCF3C95CC8899183D7F4438874C06A5896020837720C7C0DA92F7E6980684C352D40BE9A36F72C8FC6B6DBCE09BCEB04D0A8C411B20552B1D415A2972E90642963318AE8CA873E762321D20B257824E034A1D90EAC8D0060E4AA5D0FEA3827BA7FA3703216FB66DA06653DBF3B2871E162F8AD9F4E9D42F2CF1285A04F672B93F0824B01561C9CE513C2FAFFDC9B9498E3F684EF77E76B10465EB386B0F9176F73D1AE7B446CAB1ED55B9E265FC33A14181B3F79F1FD8EB7C1CC55F5455357A747958BCD6149198C1F305A99411D33B4E6CB07DDB9'.decode('hex') inv_box = [0]*256 inv_a = [3,1,1,2] a = [9,0xe,0xb,0xd] int_1 = 14 def AddRoundKey(tmp,head,k): for j in range(4): tmp[j] ^= ord(head[16*k+4*j]) tmp[j+4] ^= ord(head[16*k+4*j+1]) tmp[j+8] ^= ord(head[16*k+4*j+2]) tmp[j+12] ^= ord(head[16*k+4*j+3]) return tmp def ShiftRows(tmp): for i in range(1,4): for j in range(i): v3 = tmp[4*i+3] for k in range(3,0,-1): tmp[4*i+k] = tmp[4*i+k-1] tmp[4*i] = v3 return tmp def inv_ShiftRows(tmp): for i in range(1,4): for j in range(i): v3 = tmp[4*i] for k in range(0,3): tmp[4*i+k] = tmp[4*i+k+1] tmp[4*i+3] = v3 return tmp def SubBytes(tmp): for i in range(4): for j in range(4): tmp[4*i+j] = ord(box[16 * (tmp[4*i+j] & 0xF) + (( tmp[4*i+j] & 0xF0) >> 4)]) return tmp def inv_SubBytes(tmp): for i in range(256): inv_box[ord(box[i])] = i for i in range(4): for j in range(4): tmp[4*i+j] = inv_box[tmp[4*i+j]] tmp[4*i+j] = 16 * (tmp[4*i+j] & 0xF) + (( tmp[4*i+j] & 0xF0) >> 4) return tmp def mix_single_column(v6): d = [0]*4 d[0] = gmult(a[0],v6[0])^gmult(a[3],v6[1])^gmult(a[2],v6[2])^gmult(a[1],v6[3]); d[1] = gmult(a[1],v6[0])^gmult(a[0],v6[1])^gmult(a[3],v6[2])^gmult(a[2],v6[3]); d[2] = gmult(a[2],v6[0])^gmult(a[1],v6[1])^gmult(a[0],v6[2])^gmult(a[3],v6[3]); d[3] = gmult(a[3],v6[0])^gmult(a[2],v6[1])^gmult(a[1],v6[2])^gmult(a[0],v6[3]); return d def gmult(aa,bb): p=0 hbs=0 for i in range(8): if (bb&1): p ^= aa hbs=aa&0x80 aa<<=1 aa = aa&0xff if hbs: aa ^= 0x1b bb>>=1 return p def mix_columns(tmp): v6 = [0]*4 for i in range(4): for j in range(4): v6[j] = tmp[4*j+i] v6 = mix_single_column(v6) for j in range(4): tmp[4*j+i] = v6[j] return tmp def inv_mix_columns(tmp): v6 = [0]*4 for i in range(4): for j in range(4): v6[j] = tmp[4*j+i] v6 = inv_mix_single_column(v6) for j in range(4): tmp[4*j+i] = v6[j] return tmp def inv_mix_single_column(v6): d = [0]*4 d[0] = gmult(inv_a[0],v6[0])^gmult(inv_a[3],v6[1])^gmult(inv_a[2],v6[2])^gmult(inv_a[1],v6[3]); d[1] = gmult(inv_a[1],v6[0])^gmult(inv_a[0],v6[1])^gmult(inv_a[3],v6[2])^gmult(inv_a[2],v6[3]); d[2] = gmult(inv_a[2],v6[0])^gmult(inv_a[1],v6[1])^gmult(inv_a[0],v6[2])^gmult(inv_a[3],v6[3]); d[3] = gmult(inv_a[3],v6[0])^gmult(inv_a[2],v6[1])^gmult(inv_a[1],v6[2])^gmult(inv_a[0],v6[3]); return d def print_iv(iv): out='' for i in range(len(iv)): out += chr(iv[i]) print out.encode('hex') def enc(iv1): print iv1 iv1 = list(iv1.decode('hex')) for i in range(len(iv1)): iv1[i] = ord(iv1[i]) tmp=[0]*16 iv2=[0]*16 for i in range(4): for j in range(4): tmp[4*i+j] = iv1[4*j+i] tmp = AddRoundKey(tmp,head,int_1) for k in range(int_1-1,0,-1): tmp = ShiftRows(tmp) tmp = SubBytes(tmp) tmp = AddRoundKey(tmp,head,k) tmp = mix_columns(tmp) tmp = ShiftRows(tmp) tmp = SubBytes(tmp) tmp = AddRoundKey(tmp,head,0) for i in range(4): for j in range(4): iv2[4*j+i] = tmp[4*i+j] for i in range(len(iv2)): iv2[i] = chr(iv2[i]) iv2 = ''.join(iv2) iv2 = iv2.encode('hex') return iv2 def dec(iv1): print iv1 iv1 = list(iv1.decode('hex')) for i in range(len(iv1)): iv1[i] = ord(iv1[i]) tmp=[0]*16 iv2=[0]*16 for i in range(4): for j in range(4): tmp[4*i+j] = iv1[4*j+i] tmp = AddRoundKey(tmp,head,0) tmp = inv_SubBytes(tmp) tmp = inv_ShiftRows(tmp) for k in range(1,int_1): tmp = inv_mix_columns(tmp) tmp = AddRoundKey(tmp,head,k) tmp = inv_SubBytes(tmp) tmp = inv_ShiftRows(tmp) tmp = AddRoundKey(tmp,head,int_1) for i in range(4): for j in range(4): iv2[4*j+i] = tmp[4*i+j] for i in range(len(iv2)): iv2[i] = chr(iv2[i]) iv2 = ''.join(iv2) iv2 = iv2.encode('hex') return iv2 iv2 = 'e8d8e2ceaf9de076a0f211f5a1895352' iv1 = dec(iv2) print iv1
得到 iv1:e3c8f0eb7ad23ff182c8d87383f44918
分析hash2IV1函数
又是一阵疯狂的逆向加整理。
如果你直接在ida里按f5的话,你会得到这样的代码:
int __cdecl hash2IV1(char *hash, char *pwd, char *IV1) { unsigned int v3; // ST14_4@3 unsigned int v4; // ST24_4@3 char *v5; // ST18_4@3 unsigned int v6; // ST0C_4@3 int v7; // ST14_4@3 int v8; // ST0C_4@4 int v9; // ST24_4@4 int result; // eax@4 int xxx4; // [sp+Ch] [bp-20h]@1 int xxx1; // [sp+10h] [bp-1Ch]@1 char *v13; // [sp+18h] [bp-14h]@1 int xxx3; // [sp+1Ch] [bp-10h]@1 int xxx2; // [sp+24h] [bp-8h]@1 unsigned int i; // [sp+28h] [bp-4h]@1 xxx2 = *((_DWORD *)pwd + 1); xxx4 = *((_DWORD *)pwd + 3); xxx3 = *((_DWORD *)pwd + 2) - *((_DWORD *)hash + 0x2B); xxx1 = *(_DWORD *)pwd - *((_DWORD *)hash + 0x2A); v13 = hash + 0xA4; for ( i = 0; i < 0x14; ++i ) { v3 = ((unsigned int)(xxx1 * (2 * xxx3 + 1)) >> 25) | (xxx1 * (2 * xxx3 + 1) << 7); v4 = v3 ^ (((unsigned int)(xxx2 - *(_DWORD *)v13) >> (32 - ((unsigned int)(xxx3 * (2 * xxx1 + 1)) >> 23))) | ((xxx2 - *(_DWORD *)v13) << ((unsigned int)(xxx3 * (2 * xxx1 + 1)) >> 23))); v5 = v13 - 4; v6 = (((unsigned int)(xxx3 * (2 * xxx1 + 1)) >> 23) | (xxx3 * (2 * xxx1 + 1) << 9)) ^ (((unsigned int)(xxx4 - *(_DWORD *)v5) >> (32 - (32 - v3))) | ((xxx4 - *(_DWORD *)v5) << (32 - v3))); v13 = v5 - 4; v7 = v6; xxx4 = xxx3; xxx3 = v4; xxx2 = xxx1; xxx1 = v7; } v8 = xxx4 - *(_DWORD *)v13; v9 = xxx2 - *((_DWORD *)v13 - 1); *((_DWORD *)IV1 + 3) = xxx1; *(_DWORD *)IV1 = v9; *((_DWORD *)IV1 + 1) = xxx3; result = v8; *((_DWORD *)IV1 + 2) = v8; return result; }
这种代码你想写逆算法根本是不可能的,我们要先对这段代码进行整理和改编。
由于用了一些不同数据长度的类型的转换,所以这里我用 c语言 来写。
include <stdio.h> #include<stdlib.h> #include<iostream> using namespace std; typedef unsigned char byte; typedef unsigned int uint; byte pwd[] = { 0x59 ,0x43 ,0x29 ,0x31 ,0x19 ,0xA8 ,0x45 ,0xE9 ,0xBB ,0xDB ,0xDE ,0x5A ,0x36 ,0x9C ,0x1F ,0x50 }; byte iv1[] = { 0xe3 ,0xc8 ,0xf0 ,0xeb ,0x7a ,0xd2 ,0x3f ,0xf1 ,0x82 ,0xc8 ,0xd8 ,0x73 ,0x83 ,0xf4 ,0x49 ,0x18 }; byte out[] = { 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 }; byte hashcode[] = { 0x7D,0xEC,0x14,0x28,0x31,0x16,0x61,0x1B,0x3C,0xBD,0x49,0x75,0x13,0x84,0x3B,0x3B,0x30,0x4D,0x17,0x1B,0xF0,0x21,0xFF,0x0C,0x9E,0x8D,0x46,0x92,0x30,0x7E,0xBC,0x7A,0xE8,0x22,0x3F,0xB0,0x3C,0xE6,0xFE,0x1C,0x6E,0xC0,0x9B,0x6C,0x95,0x7C,0x40,0xA4,0x9D,0x8D,0x2C,0xC6,0x3F,0x13,0x95,0x3F,0x89,0x73,0xED,0xF8,0x0C,0xD3,0xB7,0x77,0x5C,0x5D,0xE5,0xD0,0xBE,0x87,0xE7,0xB6,0x2A,0xD1,0x48,0x72,0x9F,0x60,0x64,0x9E,0x3D,0x05,0x97,0x04,0x62,0x86,0x85,0x67,0x8A,0x0A,0xEC,0x8B,0xC8,0x0E,0xD5,0xF7,0x0A,0xB1,0xB0,0x95,0x04,0x2B,0xFD,0x3F,0xCD,0xA9,0x49,0x06,0x96,0x14,0x37,0xF5,0xA8,0x00,0x9D,0xBC,0x70,0xD0,0x1C,0x45,0x91,0xD5,0x83,0xA6,0xFE,0x96,0x7A,0x99,0x92,0xCF,0x10,0xE1,0x97,0xBD,0xBA,0xAD,0x3B,0xE1,0x59,0xE4,0x48,0x39,0x3F,0x08,0xDA,0xC0,0x47,0x36,0x67,0x83,0x93,0x6D,0x40,0x8B,0x2D,0xA8,0x76,0xAF,0xB5,0x30,0xCA,0xA6,0xF5,0x4F,0xAD,0x0A,0xF8,0x3A,0x6F,0x86,0x0B,0x9E,0x8B,0x40,0xEC,0x1D }; void printout(byte* pout){ int unequal = 0; for (int i = 0; i < 16; i++) { unequal |= (pwd[i] ^ pout[i]); printf("%x,", pout[i]); } printf("\n\n"); if (!unequal) { printf("true!!!\n"); } else { printf("FALSE\n"); } } inlineuintrol(uint a, uint off){ return (a << off) | (a >> (32 - off)); } inlineuintror(uint a, uint off){ return (a << (32 - off)) | (a >> off); } void enc(byte* in_pwd){ uint xxx1, xxx2, xxx3, xxx4; byte * v13; uint a, b, c, d; xxx1 = *((uint*)in_pwd) - *((uint*)hashcode + 0x2a); xxx2 = *((uint*)in_pwd + 1); xxx3 = *((uint*)in_pwd + 2) - *((uint*)hashcode + 0x2b); xxx4 = *((uint*)in_pwd + 3); for (int i = 0; i < 0x14; ++i) { v13 = hashcode + 0xa4 - i * 8; a = rol(xxx1 * (2 * xxx3 + 1), 7); b = rol(xxx2 - *(uint *)v13, ((xxx3 * (2 * xxx1 + 1)) >> 23)); c = rol(xxx3 * (2 * xxx1 + 1), 9); d = ror(xxx4 - *(uint *)(v13 - 4), a); xxx4 = xxx3; xxx3 = a^b; xxx2 = xxx1; xxx1 = c^d; } *(uint *)out = xxx2 - *((uint *)hashcode); *((uint *)out + 1) = xxx3; *((uint *)out + 2) = xxx4 - *(uint *)(hashcode + 4); *((uint *)out + 3) = xxx1; }
从这改编过的代码中,我们可以明显看出轮加密的痕迹,也就是Feistel网络结构。
那逆算法就好写了。
include <stdio.h> #include<stdlib.h> #include<iostream> using namespace std; typedef unsigned char byte; typedef unsigned int uint; byte pwd[] = { 0x59 ,0x43 ,0x29 ,0x31 ,0x19 ,0xA8 ,0x45 ,0xE9 ,0xBB ,0xDB ,0xDE ,0x5A ,0x36 ,0x9C ,0x1F ,0x50 }; byte iv1[] = { 0xe3 ,0xc8 ,0xf0 ,0xeb ,0x7a ,0xd2 ,0x3f ,0xf1 ,0x82 ,0xc8 ,0xd8 ,0x73 ,0x83 ,0xf4 ,0x49 ,0x18 }; byte out[] = { 0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 }; byte hashcode[] = { 0x7D,0xEC,0x14,0x28,0x31,0x16,0x61,0x1B,0x3C,0xBD,0x49,0x75,0x13,0x84,0x3B,0x3B,0x30,0x4D,0x17,0x1B,0xF0,0x21,0xFF,0x0C,0x9E,0x8D,0x46,0x92,0x30,0x7E,0xBC,0x7A,0xE8,0x22,0x3F,0xB0,0x3C,0xE6,0xFE,0x1C,0x6E,0xC0,0x9B,0x6C,0x95,0x7C,0x40,0xA4,0x9D,0x8D,0x2C,0xC6,0x3F,0x13,0x95,0x3F,0x89,0x73,0xED,0xF8,0x0C,0xD3,0xB7,0x77,0x5C,0x5D,0xE5,0xD0,0xBE,0x87,0xE7,0xB6,0x2A,0xD1,0x48,0x72,0x9F,0x60,0x64,0x9E,0x3D,0x05,0x97,0x04,0x62,0x86,0x85,0x67,0x8A,0x0A,0xEC,0x8B,0xC8,0x0E,0xD5,0xF7,0x0A,0xB1,0xB0,0x95,0x04,0x2B,0xFD,0x3F,0xCD,0xA9,0x49,0x06,0x96,0x14,0x37,0xF5,0xA8,0x00,0x9D,0xBC,0x70,0xD0,0x1C,0x45,0x91,0xD5,0x83,0xA6,0xFE,0x96,0x7A,0x99,0x92,0xCF,0x10,0xE1,0x97,0xBD,0xBA,0xAD,0x3B,0xE1,0x59,0xE4,0x48,0x39,0x3F,0x08,0xDA,0xC0,0x47,0x36,0x67,0x83,0x93,0x6D,0x40,0x8B,0x2D,0xA8,0x76,0xAF,0xB5,0x30,0xCA,0xA6,0xF5,0x4F,0xAD,0x0A,0xF8,0x3A,0x6F,0x86,0x0B,0x9E,0x8B,0x40,0xEC,0x1D }; void printout(byte* pout){ int unequal = 0; for (int i = 0; i < 16; i++) { unequal |= (pwd[i] ^ pout[i]); printf("%x,", pout[i]); } printf("\n\n"); if (!unequal) { printf("true!!!\n"); } else { printf("FALSE\n"); } } inlineuintrol(uint a, uint off){ return (a << off) | (a >> (32 - off)); } inlineuintror(uint a, uint off){ return (a << (32 - off)) | (a >> off); } void enc(byte* in_pwd){ uint xxx1, xxx2, xxx3, xxx4; byte * v13; uint a, b, c, d; xxx1 = *((uint*)in_pwd) - *((uint*)hashcode + 0x2a); xxx2 = *((uint*)in_pwd + 1); xxx3 = *((uint*)in_pwd + 2) - *((uint*)hashcode + 0x2b); xxx4 = *((uint*)in_pwd + 3); for (int i = 0; i < 0x14; ++i) { v13 = hashcode + 0xa4 - i * 8; a = rol(xxx1 * (2 * xxx3 + 1), 7); b = rol(xxx2 - *(uint *)v13, ((xxx3 * (2 * xxx1 + 1)) >> 23)); c = rol(xxx3 * (2 * xxx1 + 1), 9); d = ror(xxx4 - *(uint *)(v13 - 4), a); xxx4 = xxx3; xxx3 = a^b; xxx2 = xxx1; xxx1 = c^d; } *(uint *)out = xxx2 - *((uint *)hashcode); *((uint *)out + 1) = xxx3; *((uint *)out + 2) = xxx4 - *(uint *)(hashcode + 4); *((uint *)out + 3) = xxx1; } void dec(byte* in_iv){ uint xxx1, xxx1_up, xxx2, xxx2_up, xxx3, xxx3_up, xxx4, xxx4_up; byte * v13; uint a, b, c, d; xxx2 = *(uint *)in_iv + *((uint *)hashcode); xxx3 = *((uint *)in_iv + 1); xxx4 = *((uint *)in_iv + 2) + *(uint *)(hashcode + 4);; xxx1 = *((uint *)in_iv + 3); for (int i = 0x13; i >= 0; --i) { v13 = hashcode + 0xa4 - i * 8; xxx1_up = xxx2; xxx3_up = xxx4; a = rol(xxx1_up * (2 * xxx3_up + 1), 7); c = rol(xxx3_up * (2 * xxx1_up + 1), 9); b = xxx3^a; d = xxx1^c; xxx2_up = ror(b, ((xxx3_up * (2 * xxx1_up + 1)) >> 23)) + *(uint *)v13; xxx4_up = rol(d, a) + *(uint *)(v13 - 4); xxx4 = xxx4_up; xxx3 = xxx3_up; xxx2 = xxx2_up; xxx1 = xxx1_up; } *((uint*)out) = xxx1 + *((uint*)hashcode + 0x2a); *((uint*)out + 1) = xxx2; *((uint*)out + 2) = xxx3 + *((uint*)hashcode + 0x2b); *((uint*)out + 3) = xxx4; } int main(void){ dec(iv1); printout(out); system("pause"); return 0; }
从而得到 pwd:93c65c807c3800b15f3600d449c64692
收尾
由格式知,我们的password(也就是mail)为 DDCTF-93c65c807c3800b15f3600d449c64692@didichuxing.com
总结这道题,不说前面的非re部分,难点主要在于求这两个的逆函数上。对此应当对常见的加密算法模式有比较透彻的理解。
而且从头到尾彻彻底底的写了一遍AES加密算法和AES的解密算法还真TM赤鸡呢!
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。