常见算法逆向
Base64 Base64加解密 1 2 3 4 1. 将要加密的字符串变成二进制 2. 二进制重新分组 3. 分组后二进制转十进制 4. 根据十进制查base64编码表
加密步骤
空缺时会有一个补零操作
魔改 base64加密时一般会改base64编码表
比如本来的编码表:
1 origin = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
更改后的编码表:
1 base = 'aUiBDdopSQVOFlfLnTNrv4sj+MJW3g2Cy5IZk6APYt9RGwqm/8H7eKcx1EzbX0hu'
使用更改的编码表进行解码:
1 2 3 4 5 6 7 8 9 10 import base64origin = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' base = 'aUiBDdopSQVOFlfLnTNrv4sj+MJW3g2Cy5IZk6APYt9RGwqm/8H7eKcx1EzbX0hu' c = 'r6lrnKTo27T5FsDxfB+ElZMIlBQZMAS/MB6AlB4klBnelZFeFrTACn==' table = str .maketrans(base, origin) m = str (base64.b64decode(c.translate(table)), encoding='utf-8' ) print (m)
表一般会在程序运行的时候改掉,比如下面的例子
题目 easybase.exe
#### IDA 分析
找到main函数,分析程序逻辑
1 2 printf ("plz_input_your_flag: " );
1 2 Str1 = (char *)base64_encode(v4, 1 );
1 2 3 4 5 if ( !strcmp (Str1, "r6lrnKTo27T5FsDxfB+ElZMIlBQZMAS/MB6AlB4klBnelZFeFrTACn==" ) ) printf ("Right!" ); else printf ("try_again!" );
直接拿去解码是乱码,所以判断应该改了表
先进到base64_encode函数中查看加密逻辑:
在这里没有发现有什么改表操作,是一个常规的base64加密方法
那问题应该在debug()函数
在debug()函数中,最后返回的时候有一个random_shuffle()函数,参数传进了base64编码表,应该是使用随机数种子打乱了编码表。如果程序正常执行不调试,那么随机数种子为0,如果程序在调试模式中运行,那么随机数种子会被设置成114514
所以动态调试的时候跳过IsDebuggerPresent()函数即可,使用随机数种子0获取到打乱后的表,在进行解密就可以了
x64dbg动态调试 感觉x64dbg动态比IDA好用
可以使用IDA快速定位到debug()函数,(主要分析在右侧注释)
在第一个断点处,将ZF位标位1,跳过Seed = 114514,这样就得到了非调试模式下的base64表,表就应该在0x40F020这段内存中
这一段就是修改后的base64编码表,编写一下一段py进行解码
1 2 3 4 5 6 7 8 9 10 import base64origin = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' base = 'aUiBDdopSQVOFlfLnTNrv4sj+MJW3g2Cy5IZk6APYt9RGwqm/8H7eKcx1EzbX0hu' c = 'r6lrnKTo27T5FsDxfB+ElZMIlBQZMAS/MB6AlB4klBnelZFeFrTACn==' table = str .maketrans(base, origin) m = str (base64.b64decode(c.translate(table)), encoding='utf-8' ) print (m)
解出:
RC4 RC4加解密 RC4是对称加密算法,加解密使用同一套秘钥
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 #pragma once #include <windows.h> #include <iostream> #include <stdio.h> #pragma warning (disable:6273) using namespace std ; typedef struct _RC4_KEY { unsigned char S_Box[256 ]; unsigned char T_Box[256 ]; } RC4_KEY, * PRC4_KEY; void RC4Init (PRC4_KEY Context, unsigned char * Key, int KeyLength) { int i = 0 , j = 0 ; unsigned char v1; if (Context == NULL ) { return ; } for (i = 0 ; i < 256 ; i++) { Context->S_Box[i] = i; Context->T_Box[i] = Key[i % KeyLength]; } for (i = 0 ; i < 256 ; i++) { j = (j + Context->S_Box[i] + Context->T_Box[i]) % 256 ; v1 = Context->S_Box[i]; Context->S_Box[i] = Context->S_Box[j]; Context->S_Box[j] = v1; } } void RC4Crypt (unsigned char * Input, unsigned int InputLength, unsigned char * Key, unsigned int KeyLength) { int v1 = 0 , i = 0 , j = 0 , t = 0 ; unsigned char v2; RC4_KEY Context; RC4Init(&Context, Key, KeyLength); for (v1 = 0 ; v1 < InputLength; v1++) { i = (i + 1 ) % 256 ; j = (j + Context.S_Box[i]) % 256 ; v2 = Context.S_Box[i]; Context.S_Box[i] = Context.S_Box[j]; Context.S_Box[j] = v2; t = (Context.S_Box[i] + Context.S_Box[j]) % 256 ; Input[v1] ^= Context.S_Box[t]; } } void RC4UpdateString (unsigned char Input[], unsigned int InputLength) { unsigned char Key[] = "Key" ; RC4Crypt(Input, InputLength, Key, strlen ((const char *)Key)); } int main () { char v1[] = "Hello World!" ; printf ("Before encryption: %s\n" , v1); RC4UpdateString((unsigned char *)v1, strlen (v1)); printf ("After encryption: %x\n" , v1); RC4UpdateString((unsigned char *)v1, strlen (v1)); printf ("After decryption: %s\n" , v1); return 0 ; }
题目TCR0.exe
查一下壳
IDA看一下主要逻辑
直接动调拿出解密之后的flag
调试的时候发现没法调试,应该是有反调试,找main函数里面没有IsDebuggerPresent,猜测可能是使用TlsCallback,
在最下面跳转的语句下一个断点,运行到这里先修改一下ZF标志位
分析一下主函数,v10应该是用户输入的flag,大小为40字节,所以先给input一个40位的输入,过后直接改这40位就好了
v8数组应该是秘钥,这里的密钥加载到内存中,使用小端存储,所以排列起来应该是从右到左,一个字节一个字节来(先转成Hex)
密钥:
1 2 3 71 0b 02 49 73 b4 e1 a3 2f 58 71 85 16 67 b3 ab 1a cf 62 4f 1e 7d 3b 6c 55 58 15 b9 69 36 7e c0 b8 f4 02 42 03 c2 7f 56
main函数的断点下在加解密之前,第24行
查看v10里面存储了40个'a'
使用patch修改这一块的密钥,注意最后一段不要全覆盖掉,只改DWORD64大小的数据
程序过到加密之后,再查看v10
按A键转成字符串就出来了
Flag:NSSCTF{75025d7f6c9f2fbcf746228b4f3d623a}
题目TCR.exe 这个题目没法运行exe,会报错,安装了dll还是会报错,所以直接先查壳再仿写
主要逻辑大概是这样
主要就是上面三段逻辑,密钥、init初始化和加密算法
这是一个魔改的RC4算法,程序有点问题没法动调,所以仿写一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 #include <windows.h> #include <iostream> #include <stdio.h> #pragma warning (disable:6273) using namespace std ; typedef struct _RC4_KEY { unsigned char S_Box[64 ]; unsigned char T_Box[64 ]; } RC4_KEY, * PRC4_KEY; void RC4Init (PRC4_KEY Context, unsigned char * Key, int KeyLength) { int i = 0 , j = 0 ; unsigned char v1; if (Context == NULL ) { return ; } for (i = 0 ; i < 64 ; i++) { Context->S_Box[i] = i; Context->T_Box[i] = Key[i % KeyLength]; } for (i = 0 ; i < 64 ; i++) { j = (j + Context->S_Box[i] + Context->T_Box[i]) % 64 ; v1 = Context->S_Box[i]; Context->S_Box[i] = Context->S_Box[j]; Context->S_Box[j] = v1; } } void RC4Crypt (unsigned char * Input, unsigned int InputLength, unsigned char * Key, unsigned int KeyLength) { int v1 = 0 , i = 0 , j = 0 , t = 0 ; unsigned char v2; RC4_KEY Context; RC4Init(&Context, Key, KeyLength); for (v1 = 0 ; v1 < InputLength; v1++) { i = (i + 1 ) % 64 ; j = (j + Context.S_Box[i]) % 64 ; v2 = Context.S_Box[i]; Context.S_Box[i] = Context.S_Box[j]; Context.S_Box[j] = v2; t = (Context.S_Box[i] + Context.S_Box[j]) % 64 ; Input[v1] ^= Context.S_Box[t] + Context.S_Box[i]; } } void RC4UpdateString (unsigned char Input[], unsigned int InputLength) { unsigned char Key[] = "r4nd0m_k5y" ; RC4Crypt(Input, InputLength, Key, strlen ((const char *)Key)); } void main () { char v1[41 ] = { 0x18 , 0x35 , 0x08 , 0x59 , 0x01 , 0x79 , 0x2D , 0x7D , 0x3D , 0x4C , 0x17 , 0x0A , 0x09 , 0x48 , 0x6D , 0x18 , 0x29 , 0x04 , 0x53 , 0x25 , 0x77 , 0x29 , 0x39 , 0x6B , 0x4E , 0x66 , 0x60 , 0x65 , 0x4A , 0x41 , 0x6F , 0x27 , 0x61 , 0x7A , 0x16 , 0x14 , 0x4c , 0x5a , 0x57 , 0x69 , 0x00 }; RC4UpdateString((unsigned char *)v1, strlen (v1)); for (int i = 0 ; i < strlen (v1); i++) { printf ("%c" , v1[i]); } }
看起来没问题,但是跑不出结果
看一下上面有一个sub_A325
里面有IsDebuggerPresent()
里面有一个对密钥修改的操作:
1 2 ascii('4') xor 0x55 0x34 ^ 0x55 = 0x61 => DEC 97 => 'a' ascii('0') xor 0x5F 0x30 ^ 0x5F = 0x6F => DEC 111 => '0'
所以,key应该是random_k5y
果然算出了答案,但是发现少了一小段,发现少了四个字符的密钥
发现这一串也是密钥的一部分
加上之后,终于算出了正确答案NSSCTF{4af695c7065c5cf6053271d3e3151a2d}
TEA
TEA(Tiny Encryption Algorithm)是一种对称密钥加密算法,由David Wheeler和Roger Needham在1994年提出。TEA的设计目标是简单、高效,并且在实现上尽量减少代码的复杂性。
TEA加解密 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 #include <iostream> #include <vector> #include <algorithm> using namespace std ; #pragma warning (disable:26450) #define UI32 uint32_t #define DELTA 0x9E3779B9 #define ROUND 32 void decrypt (UI32* v, UI32* k) { UI32 v0 = v[0 ], v1 = v[1 ], sum = DELTA * ROUND, i; UI32 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; } void encrypt (UI32* v, UI32* k) { UI32 v0 = v[0 ], v1 = v[1 ], sum = 0 ; for (int i = 0 ; i < 32 ; i++) { sum += DELTA; v0 += ((v1 << 4 ) + k[2 ]) ^ (v1 + sum) ^ ((v1 >> 5 ) + k[1 ]); v1 += ((v0 << 4 ) + k[3 ]) ^ (v0 + sum) ^ ((v0 >> 5 ) + k[0 ]); } v[0 ] = v0; v[1 ] = v1; } int main () { UI32 k[ y ] = { ...... }; UI32 v[ x ] = { ...... }; for (int i = 0 ; i < (x / 2 ); i++) { UI32 f[2 ] = { v[2 * i], v[2 * i + 1 ] }; decrypt(f, k); for (int j = 0 ; j < 2 ; j++) { printf ("%c" , f[j] & 0xff ); printf ("%c" , (f[j] >> 8 ) & 0xff ); printf ("%c" , (f[j] >> 16 ) & 0xff ); printf ("%c" , (f[j] >> 24 ) & 0xff ); } } return 0 ; }
题目 SEA0.txt 题目:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 hint1 = {11,22,33,44} hint2 = {0x7c12e17f,0x43c2b691,0xa8d8d6ce,0x6280ecc8,0xe6e18c6e,0x20d6dfa3,0xf2dd40c,0xb819b77e,0xb9258436,0x5d3e88b6} .text:0000000000401550 ; unsigned int *__fastcall encrypt(unsigned int *, unsigned int *) .text:0000000000401550 public _Z7encryptPjS_ .text:0000000000401550 _Z7encryptPjS_ proc near ; CODE XREF: main+FC↓p .text:0000000000401550 ; DATA XREF: .pdata:000000000040A06C↓o .text:0000000000401550 .text:0000000000401550 var_14= dword ptr -14h .text:0000000000401550 var_10= dword ptr -10h .text:0000000000401550 var_C= dword ptr -0Ch .text:0000000000401550 var_8= dword ptr -8 .text:0000000000401550 var_4= dword ptr -4 .text:0000000000401550 arg_0= qword ptr 10h .text:0000000000401550 arg_8= qword ptr 18h .text:0000000000401550 .text:0000000000401550 55 push rbp .text:0000000000401551 48 89 E5 mov rbp, rsp .text:0000000000401554 48 83 EC 20 sub rsp, 20h .text:0000000000401558 48 89 4D 10 mov [rbp+arg_0], rcx .text:000000000040155C 48 89 55 18 mov [rbp+arg_8], rdx .text:0000000000401560 C7 45 EC B9 79 37 9E mov [rbp+var_14], 9E3779B9h .text:0000000000401567 48 8B 45 10 mov rax, [rbp+arg_0] .text:000000000040156B 8B 00 mov eax, [rax] .text:000000000040156D 89 45 FC mov [rbp+var_4], eax .text:0000000000401570 48 8B 45 10 mov rax, [rbp+arg_0] .text:0000000000401574 8B 40 04 mov eax, [rax+4] .text:0000000000401577 89 45 F8 mov [rbp+var_8], eax .text:000000000040157A C7 45 F4 00 00 00 00 mov [rbp+var_C], 0 .text:0000000000401581 C7 45 F0 00 00 00 00 mov [rbp+var_10], 0 .text:0000000000401581 .text:0000000000401588 .text:0000000000401588 loc_401588: ; CODE XREF: encrypt(uint *,uint *)+B2↓j .text:0000000000401588 83 7D F0 1F cmp [rbp+var_10], 1Fh // DEC = 19 .text:000000000040158C 7F 76 jg short loc_401604 .text:000000000040158C .text:000000000040158E 8B 45 EC mov eax, [rbp+var_14] .text:0000000000401591 01 45 F4 add [rbp+var_C], eax .text:0000000000401594 8B 45 F8 mov eax, [rbp+var_8] .text:0000000000401597 C1 E0 04 shl eax, 4 .text:000000000040159A 89 C2 mov edx, eax .text:000000000040159C 48 8B 45 18 mov rax, [rbp+arg_8] .text:00000000004015A0 8B 00 mov eax, [rax] .text:00000000004015A2 01 C2 add edx, eax .text:00000000004015A4 8B 4D F8 mov ecx, [rbp+var_8] .text:00000000004015A7 8B 45 F4 mov eax, [rbp+var_C] .text:00000000004015AA 01 C8 add eax, ecx .text:00000000004015AC 31 C2 xor edx, eax .text:00000000004015AE 8B 45 F8 mov eax, [rbp+var_8] .text:00000000004015B1 C1 E8 05 shr eax, 5 .text:00000000004015B4 89 C1 mov ecx, eax .text:00000000004015B6 48 8B 45 18 mov rax, [rbp+arg_8] .text:00000000004015BA 48 83 C0 04 add rax, 4 .text:00000000004015BE 8B 00 mov eax, [rax] .text:00000000004015C0 01 C8 add eax, ecx .text:00000000004015C2 31 D0 xor eax, edx .text:00000000004015C4 01 45 FC add [rbp+var_4], eax .text:00000000004015C7 8B 45 FC mov eax, [rbp+var_4] .text:00000000004015CA C1 E0 04 shl eax, 4 .text:00000000004015CD 89 C2 mov edx, eax .text:00000000004015CF 48 8B 45 18 mov rax, [rbp+arg_8] .text:00000000004015D3 48 83 C0 08 add rax, 8 .text:00000000004015D7 8B 00 mov eax, [rax] .text:00000000004015D9 01 C2 add edx, eax .text:00000000004015DB 8B 4D FC mov ecx, [rbp+var_4] .text:00000000004015DE 8B 45 F4 mov eax, [rbp+var_C] .text:00000000004015E1 01 C8 add eax, ecx .text:00000000004015E3 31 C2 xor edx, eax .text:00000000004015E5 8B 45 FC mov eax, [rbp+var_4] .text:00000000004015E8 C1 E8 05 shr eax, 5 .text:00000000004015EB 89 C1 mov ecx, eax .text:00000000004015ED 48 8B 45 18 mov rax, [rbp+arg_8] .text:00000000004015F1 48 83 C0 0C add rax, 0Ch .text:00000000004015F5 8B 00 mov eax, [rax] .text:00000000004015F7 01 C8 add eax, ecx .text:00000000004015F9 31 D0 xor eax, edx .text:00000000004015FB 01 45 F8 add [rbp+var_8], eax .text:00000000004015FE 83 45 F0 01 add [rbp+var_10], 1 .text:0000000000401602 EB 84 jmp short loc_401588 .text:0000000000401602 .text:0000000000401604 ; --------------------------------------------------------------------------- .text:0000000000401604 .text:0000000000401604 loc_401604: ; CODE XREF: encrypt(uint *,uint *)+3C↑j .text:0000000000401604 48 8B 45 10 mov rax, [rbp+arg_0] .text:0000000000401608 8B 55 FC mov edx, [rbp+var_4] .text:000000000040160B 89 10 mov [rax], edx .text:000000000040160D 48 8B 45 10 mov rax, [rbp+arg_0] .text:0000000000401611 48 83 C0 04 add rax, 4 .text:0000000000401615 8B 55 F8 mov edx, [rbp+var_8] .text:0000000000401618 89 10 mov [rax], edx .text:000000000040161A 90 nop .text:000000000040161B 48 83 C4 20 add rsp, 20h .text:000000000040161F 5D pop rbp .text:0000000000401620 C3 retn .text:0000000000401620 .text:0000000000401620 _Z7encryptPjS_ endp
这是一段IDA反编译的汇编代码,Key的长度是4位的一般会想到TEA家族(TEA,XTEA,XXTEA)的加密 再看hint2,是4*10=40位,大概是flag的长度,所以hint2可能是密文,hint1是Key
分析汇编代码:
这是一段完整的TEA加密,发现了mov [rbp+var_14], 9E3779B9h,这里的delta,sub rsp, 20h,这里的20h应该是round = 32
汇编中还有shl eax, 4和shr eax, 5,左移4和右移5,判断应该是标准TEA加密。
所以这一段汇编对应的C代码应该就是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #define UI32 uint32_t #define DELTA 0x9E3779B9 #define ROUND 32 void decrypt (UI32* v, UI32* k) { UI32 v0 = v[0 ], v1 = v[1 ], sum = DELTA * ROUND, i; UI32 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; }
完整解密:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 #include <iostream> #include <vector> #include <algorithm> using namespace std ; #pragma warning (disable:26450) #define UI32 uint32_t #define DELTA 0x9E3779B9 #define ROUND 32 void decrypt (UI32* v, UI32* k) { UI32 v0 = v[0 ], v1 = v[1 ], sum = DELTA * ROUND, i; UI32 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 () { UI32 k[4 ] = { 11 ,22 ,33 ,44 }; UI32 v[12 ] = { 0x7c12e17f ,0x43c2b691 ,0xa8d8d6ce ,0x6280ecc8 , 0xe6e18c6e ,0x20d6dfa3 ,0x0f2dd40c ,0xb819b77e , 0xb9258436 ,0x5d3e88b6 }; for (int i = 0 ; i < 5 ; i++) { UI32 f[2 ] = { v[2 * i], v[2 * i + 1 ] }; decrypt(f, k); for (int j = 0 ; j < 2 ; j++) { printf ("%c" , f[j] & 0xff ); printf ("%c" , (f[j] >> 8 ) & 0xff ); printf ("%c" , (f[j] >> 16 ) & 0xff ); printf ("%c" , (f[j] >> 24 ) & 0xff ); } } return 0 ; }
解密之后的答案为:NSSCTF{5b84a51236d7043fe2480d69d24b37a3}
XTEA XTEA加解密 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 #include <stdio.h> #include <stdint.h> void encipher (unsigned int num_rounds, uint32_t v[2 ], uint32_t const key[4 ]) { unsigned int i; uint32_t v0=v[0 ], v1=v[1 ], sum=0 , delta=0x9E3779B9 ; 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; } void decipher (unsigned int num_rounds, uint32_t v[2 ], uint32_t const key[4 ]) { unsigned int i; uint32_t v0=v[0 ], v1=v[1 ], delta=0x9E3779B9 , sum=delta*num_rounds; for (i=0 ; i < num_rounds; i++) { v1 -= (((v0 << 4 ) ^ (v0 >> 5 )) + v0) ^ (sum + key[(sum>>11 ) & 3 ]); sum -= delta; v0 -= (((v1 << 4 ) ^ (v1 >> 5 )) + v1) ^ (sum + key[sum & 3 ]); } v[0 ]=v0; v[1 ]=v1; } int main () { uint32_t v[2 ]={1 ,2 }; uint32_t const k[4 ]={2 ,2 ,3 ,4 }; unsigned int r=32 ; printf ("加密前原始数据:%u %u\n" ,v[0 ],v[1 ]); encipher(r, v, k); printf ("加密后的数据:%u %u\n" ,v[0 ],v[1 ]); decipher(r, v, k); printf ("解密后的数据:%u %u\n" ,v[0 ],v[1 ]); return 0 ; }
XTEA是TEA的升级版,增加了更多的密钥表,移位和异或操作等,TEA 算法被发现存在缺陷,作为回应,设计者提出了一个 TEA 的升级版本——XTEA(有时也被称为”tean”)。XTEA 跟 TEA 使用了相同的简单运算,但它采用了截然不同的顺序,为了阻止密钥表攻击,四个子密钥(在加密过程中,原 128 位的密钥被拆分为 4 个 32 位的子密钥)采用了一种不太正规的方式进行混合,但速度更慢了。
XXTEA 特点: Corrected Block TEA,原字符串长度可以不是4的倍数了
XXTEA加解密 XXTEA与TEA类似,都是块加密算法,以下是常规的加密和解密方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 #include <stdio.h> #include <stdint.h> #define DELTA 0x9e3779b9 #define MX (((z>>5^y<<2) + (y> >3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z))) void btea (uint32_t *v, int n, uint32_t const key[4 ]) { uint32_t y, z, sum; unsigned p, rounds, e; if (n > 1 ) { rounds = 6 + 52 /n; sum = 0 ; z = v[n-1 ]; do { sum += DELTA; e = (sum >> 2 ) & 3 ; for (p=0 ; p<n-1 ; p++) { y = v[p+1 ]; z = v[p] += MX; } y = v[0 ]; z = v[n-1 ] += MX; } while (--rounds); } else if (n < -1 ) { n = -n; rounds = 6 + 52 /n; sum = rounds*DELTA; y = v[0 ]; do { e = (sum >> 2 ) & 3 ; for (p=n-1 ; p>0 ; p--) { z = v[p-1 ]; y = v[p] -= MX; } z = v[n-1 ]; y = v[0 ] -= MX; sum -= DELTA; } while (--rounds); } } int main () { uint32_t v[2 ]= {1 ,2 }; uint32_t const k[4 ]= {2 ,2 ,3 ,4 }; int n= 2 ; printf ("加密前原始数据:%u %u\n" ,v[0 ],v[1 ]); btea(v, n, k); printf ("加密后的数据:%u %u\n" ,v[0 ],v[1 ]); btea(v, -n, k); printf ("解密后的数据:%u %u\n" ,v[0 ],v[1 ]); return 0 ; }
题目 sec_cython.so main.py
1 2 3 4 5 6 7 8 9 10 11 12 13 import sec_cythonflag = input ('input your flag:' ) m = sec_cython.encrypt(flag) if m != 'wrong' : m = [hex (x.value) for x in m] m = [int (x, 16 ) for x in m] if m != sec_cython.enc: print ('Wrong!' ) else : print ('Correct!' ) else : print ('something wrong!' )
看来主要的加密是在sec_cython里面的
so文件是Linux相当于windows的dll动态链接库,所以放到kali里面
kali里面写一个python文件
1 2 import sec_cythonhelp (sec_cython)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 Help on module sec_cython: NAME sec_cython FUNCTIONS encrypt(v) sea(v) string_to_uint32_bytes(string) DATA DELTA = 2654435769 __test__ = {} enc = [235096951, 4274635695, 1983592480, 2346500962, 4098093858, 1778... k = [1935954450, 825721906, 305287507, 875914545] FILE /root/桌面/sec_cython.so
1 2 3 4 import sec_cythonprint (sec_cython.enc)print (sec_cython.k)print (hex (sec_cython.DELTA))
1 2 3 4 5 [235096951, 4274635695, 1983592480, 2346500962, 4098093858, 1778866619, 2372400532, 839025380, 4012226876, 1286419149] [1935954450, 825721906, 305287507, 875914545] 0x9e3779b9
看到了DELTA = 0x9e3779b9,所以应该也是TEA家族中的一个,第一个是加密字符,第二个是key
IDA分析一下sec_cython.so
在函数表里面直接搜一下之前help中出来的encrypt:
encrypt前面这一大部分是编译so文件时编译上去的,只看结尾这个encrypt就行
找到下面这个东西,名字看起来是SEA,所以进到这个函数里面查看一下
看到这里有些熟悉,v5 = 10,为密钥的长度;v6 = 52,v7 = Divide(v6, v5),这里应该算的就是轮数
以上两段也有非常明显的左移5右移2异或,左移3右移4异或的操作
解密代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 #include <stdio.h> #include <stdint.h> #define DELTA 0x9E3779B9 void decrypt (uint32_t * v, int n, uint32_t * k) { int rounds = 6 + (52 / n); uint32_t sum = rounds * DELTA; uint32_t y = v[0 ]; while (rounds > 0 ) { uint32_t e = (sum >> 2 ) & 3 ; int p = n - 1 ; while (p > 0 ) { uint32_t z = v[p - 1 ]; v[p] -= (((z >> 5 ^ (y << 2 )) + ((y >> 3 ) ^ (z << 4 ))) ^ ((sum ^ y) + (k[(p & 3 ) ^ e] ^ z))); y = v[p]; p--; } uint32_t z = v[n - 1 ]; v[0 ] -= (((z >> 5 ^ (y << 2 )) + ((y >> 3 ) ^ (z << 4 ))) ^ ((sum ^ y) + (k[(p & 3 ) ^ e] ^ z))); y = v[0 ]; sum -= DELTA; rounds--; } } int main () { uint32_t k[4 ] = { 0x73645212 , 0x31378432 , 0x12325153 , 0x34356531 }; uint32_t m[10 ] = { 0xe034b77 , 0xfec9c3af , 0x763b3820 , 0x8bdcc362 , 0xf443f322 , 0x6a0759bb , 0x8d67f594 , 0x320282e4 , 0xef25b93c , 0x4cad32cd }; decrypt(m, sizeof (m) / sizeof (m[0 ]), k); for (int i = 0 ; i < sizeof (m) / sizeof (m[0 ]); i++) { for (int j = 0 ; j < 4 ; j++) { putchar (m[i] & 0xff ); m[i] >>= 8 ; } } return 0 ; }
AES 题目 wheel.exe 打开发现这个程序加了upx壳
用upx -d脱一下壳
IDA已经识别出这是一个aes加密