本题主要考察一些常用的加密方法。
目录
分析
__int64 __fastcall main(int argc, char **argv, char **a3)
{
size_t v3; // rax
char *dest; // ST18_8
size_t length; // rax
char *v6; // rax
char *v7; // rax
const char *v8; // ST18_8
if ( argc != 2 )
{
puts("./dec_dec_dec flag_string_is_here ");
exit(0);
}
v3 = strlen(argv[1]);
dest = (char *)malloc(v3 + 1);
length = strlen(argv[1]);
strncpy(dest, argv[1], length);
v6 = base64_encode(dest);
v7 = rot13(v6);
v8 = mapping_table(v7);
if ( !strcmp(v8, s2) )
puts("correct :)");
else
puts("incorrect :(");
return 0LL;
}
程序总共有三次加密,加密完成和字符串@1DE!440S9W9,2T%Y07=%<W!Z.3!:1T%S2S-),7-$/3T
(s2)进行比较,只要比较成功即可,前两次加密很容易就能分析出来,一个是base64
加密,一个是rot13
加密。最后一个加密函数是我没见过的,其反汇编如下:
mapping_table
char *__fastcall mapping_table(const char *a1)
{
unsigned int v1; // ST1C_4
_BYTE *v2; // rax
_BYTE *v3; // rax
char v4; // dl
_BYTE *v5; // rax
char v6; // cl
_BYTE *v7; // rax
char v8; // cl
_BYTE *v9; // rax
char v10; // dl
_BYTE *v11; // rax
char v12; // dl
char *v13; // rax
char v14; // dl
_BYTE *v15; // rax
char v16; // cl
_BYTE *v17; // rax
char v18; // cl
_BYTE *v19; // rax
char v20; // dl
char *s; // [rsp+8h] [rbp-88h]
unsigned int i; // [rsp+10h] [rbp-80h]
signed int v24; // [rsp+14h] [rbp-7Ch]
unsigned int v25; // [rsp+18h] [rbp-78h]
signed __int64 v26; // [rsp+20h] [rbp-70h]
signed __int64 v27; // [rsp+20h] [rbp-70h]
signed __int64 v28; // [rsp+20h] [rbp-70h]
signed __int64 v29; // [rsp+20h] [rbp-70h]
char *v30; // [rsp+20h] [rbp-70h]
signed __int64 v31; // [rsp+20h] [rbp-70h]
signed __int64 v32; // [rsp+20h] [rbp-70h]
signed __int64 v33; // [rsp+20h] [rbp-70h]
char *v34; // [rsp+28h] [rbp-68h]
s = (char *)a1;
v1 = strlen(a1);
v34 = (char *)malloc(4 * v1 / 3 + 1);
v26 = (signed __int64)v34;
for ( i = v1; i > 0x2D; i -= 45 )
{
v2 = (_BYTE *)v26++;
*v2 = 77;
v24 = 0;
while ( v24 <= 44 )
{
v3 = (_BYTE *)v26;
v27 = v26 + 1;
if ( *s >> 2 )
v4 = ((unsigned __int8)*s >> 2) + 32;
else
v4 = 32;
*v3 = v4;
v5 = (_BYTE *)v27;
v28 = v27 + 1;
if ( 16 * *s & 0x30 )
v6 = (16 * *s & 0x30) + 32;
else
v6 = 32;
*v5 = v6 | ((unsigned __int8)s[1] >> 4);
v7 = (_BYTE *)v28;
v29 = v28 + 1;
if ( 4 * s[1] & 0x3C )
v8 = (4 * s[1] & 0x3C) + 32;
else
v8 = 32;
*v7 = v8 | ((unsigned __int8)s[2] >> 6);
v9 = (_BYTE *)v29;
v26 = v29 + 1;
if ( s[2] & 0x3F )
v10 = (s[2] & 0x3F) + 32;
else
v10 = 32;
*v9 = v10;
v24 += 3;
s += 3;
}
}
v11 = (_BYTE *)v26;
v30 = (char *)(v26 + 1);
if ( i )
v12 = (i & 0x3F) + 32;
else
v12 = 32;
*v11 = v12;
v25 = 0;
while ( v25 < i )
{
v13 = v30;
v31 = (signed __int64)(v30 + 1);
if ( *s >> 2 )
v14 = ((unsigned __int8)*s >> 2) + 32;
else
v14 = 32;
*v13 = v14;
v15 = (_BYTE *)v31;
v32 = v31 + 1;
if ( 16 * *s & 0x30 )
v16 = (16 * *s & 0x30) + 32;
else
v16 = 32;
*v15 = v16 | ((unsigned __int8)s[1] >> 4);
v17 = (_BYTE *)v32;
v33 = v32 + 1;
if ( 4 * s[1] & 0x3C )
v18 = (4 * s[1] & 0x3C) + 32;
else
v18 = 32;
*v17 = v18 | ((unsigned __int8)s[2] >> 6);
v19 = (_BYTE *)v33;
v30 = (char *)(v33 + 1);
if ( s[2] & 0x3F )
v20 = (s[2] & 0x3F) + 32;
else
v20 = 32;
*v19 = v20;
v25 += 3;
s += 3;
}
*v30 = 0;
return v34;
}
首先猜测该函数是一个一一映射的函数,再根据v34 = (char *)malloc(4 * v1 / 3 + 1);
猜测是一个3字节
向4字节
的映射规则,然后再利用mapping_table
函数进行分析。
提取出来的代码:
#define _BYTE char
#define __int64 long long
#define __int8 char
char *mapping_table(const char *a1)
{
unsigned int v1; // ST1C_4
_BYTE *v2; // rax
_BYTE *v3; // rax
char v4; // dl
_BYTE *v5; // rax
char v6; // cl
_BYTE *v7; // rax
char v8; // cl
_BYTE *v9; // rax
char v10; // dl
_BYTE *v11; // rax
char v12; // dl
char *v13; // rax
char v14; // dl
_BYTE *v15; // rax
char v16; // cl
_BYTE *v17; // rax
char v18; // cl
_BYTE *v19; // rax
char v20; // dl
char *s; // [rsp+8h] [rbp-88h]
unsigned int i; // [rsp+10h] [rbp-80h]
signed int v24; // [rsp+14h] [rbp-7Ch]
unsigned int v25; // [rsp+18h] [rbp-78h]
signed __int64 v26; // [rsp+20h] [rbp-70h]
signed __int64 v27; // [rsp+20h] [rbp-70h]
signed __int64 v28; // [rsp+20h] [rbp-70h]
signed __int64 v29; // [rsp+20h] [rbp-70h]
char *v30; // [rsp+20h] [rbp-70h]
signed __int64 v31; // [rsp+20h] [rbp-70h]
signed __int64 v32; // [rsp+20h] [rbp-70h]
signed __int64 v33; // [rsp+20h] [rbp-70h]
char *v34; // [rsp+28h] [rbp-68h]
s = (char *)a1;
v1 = strlen(a1);
v34 = (char *)malloc(4 * v1 / 3 + 1);
v26 = (signed __int64)v34;
for (i = v1; i > 0x2D; i -= 45)
{
v2 = (_BYTE *)v26++;
*v2 = 77;
v24 = 0;
while (v24 <= 44)
{
v3 = (_BYTE *)v26;
v27 = v26 + 1;
if (*s >> 2)
v4 = ((unsigned __int8)*s >> 2) + 32;
else
v4 = 32;
*v3 = v4;
v5 = (_BYTE *)v27;
v28 = v27 + 1;
if (16 * *s & 0x30)
v6 = (16 * *s & 0x30) + 32;
else
v6 = 32;
*v5 = v6 | ((unsigned __int8)s[1] >> 4);
v7 = (_BYTE *)v28;
v29 = v28 + 1;
if (4 * s[1] & 0x3C)
v8 = (4 * s[1] & 0x3C) + 32;
else
v8 = 32;
*v7 = v8 | ((unsigned __int8)s[2] >> 6);
v9 = (_BYTE *)v29;
v26 = v29 + 1;
if (s[2] & 0x3F)
v10 = (s[2] & 0x3F) + 32;
else
v10 = 32;
*v9 = v10;
v24 += 3;
s += 3;
}
}
v11 = (_BYTE *)v26;
v30 = (char *)(v26 + 1);
if (i)
v12 = (i & 0x3F) + 32;
else
v12 = 32;
*v11 = v12;
v25 = 0;
while (v25 < i)
{
v13 = v30;
v31 = (signed __int64)(v30 + 1);
if (*s >> 2)
v14 = ((unsigned __int8)*s >> 2) + 32;
else
v14 = 32;
*v13 = v14;
v15 = (_BYTE *)v31;
v32 = v31 + 1;
if (16 * *s & 0x30)
v16 = (16 * *s & 0x30) + 32;
else
v16 = 32;
*v15 = v16 | ((unsigned __int8)s[1] >> 4);
v17 = (_BYTE *)v32;
v33 = v32 + 1;
if (4 * s[1] & 0x3C)
v18 = (4 * s[1] & 0x3C) + 32;
else
v18 = 32;
*v17 = v18 | ((unsigned __int8)s[2] >> 6);
v19 = (_BYTE *)v33;
v30 = (char *)(v33 + 1);
if (s[2] & 0x3F)
v20 = (s[2] & 0x3F) + 32;
else
v20 = 32;
*v19 = v20;
v25 += 3;
s += 3;
}
*v30 = 0;
return v34;
}#define _BYTE char
#define __int64 long long
#define __int8 char
char *mapping_table(const char *a1)
{
unsigned int v1; // ST1C_4
_BYTE *v2; // rax
_BYTE *v3; // rax
char v4; // dl
_BYTE *v5; // rax
char v6; // cl
_BYTE *v7; // rax
char v8; // cl
_BYTE *v9; // rax
char v10; // dl
_BYTE *v11; // rax
char v12; // dl
char *v13; // rax
char v14; // dl
_BYTE *v15; // rax
char v16; // cl
_BYTE *v17; // rax
char v18; // cl
_BYTE *v19; // rax
char v20; // dl
char *s; // [rsp+8h] [rbp-88h]
unsigned int i; // [rsp+10h] [rbp-80h]
signed int v24; // [rsp+14h] [rbp-7Ch]
unsigned int v25; // [rsp+18h] [rbp-78h]
signed __int64 v26; // [rsp+20h] [rbp-70h]
signed __int64 v27; // [rsp+20h] [rbp-70h]
signed __int64 v28; // [rsp+20h] [rbp-70h]
signed __int64 v29; // [rsp+20h] [rbp-70h]
char *v30; // [rsp+20h] [rbp-70h]
signed __int64 v31; // [rsp+20h] [rbp-70h]
signed __int64 v32; // [rsp+20h] [rbp-70h]
signed __int64 v33; // [rsp+20h] [rbp-70h]
char *v34; // [rsp+28h] [rbp-68h]
s = (char *)a1;
v1 = strlen(a1);
v34 = (char *)malloc(4 * v1 / 3 + 1);
v26 = (signed __int64)v34;
for (i = v1; i > 0x2D; i -= 45)
{
v2 = (_BYTE *)v26++;
*v2 = 77;
v24 = 0;
while (v24 <= 44)
{
v3 = (_BYTE *)v26;
v27 = v26 + 1;
if (*s >> 2)
v4 = ((unsigned __int8)*s >> 2) + 32;
else
v4 = 32;
*v3 = v4;
v5 = (_BYTE *)v27;
v28 = v27 + 1;
if (16 * *s & 0x30)
v6 = (16 * *s & 0x30) + 32;
else
v6 = 32;
*v5 = v6 | ((unsigned __int8)s[1] >> 4);
v7 = (_BYTE *)v28;
v29 = v28 + 1;
if (4 * s[1] & 0x3C)
v8 = (4 * s[1] & 0x3C) + 32;
else
v8 = 32;
*v7 = v8 | ((unsigned __int8)s[2] >> 6);
v9 = (_BYTE *)v29;
v26 = v29 + 1;
if (s[2] & 0x3F)
v10 = (s[2] & 0x3F) + 32;
else
v10 = 32;
*v9 = v10;
v24 += 3;
s += 3;
}
}
v11 = (_BYTE *)v26;
v30 = (char *)(v26 + 1);
if (i)
v12 = (i & 0x3F) + 32;
else
v12 = 32;
*v11 = v12;
v25 = 0;
while (v25 < i)
{
v13 = v30;
v31 = (signed __int64)(v30 + 1);
if (*s >> 2)
v14 = ((unsigned __int8)*s >> 2) + 32;
else
v14 = 32;
*v13 = v14;
v15 = (_BYTE *)v31;
v32 = v31 + 1;
if (16 * *s & 0x30)
v16 = (16 * *s & 0x30) + 32;
else
v16 = 32;
*v15 = v16 | ((unsigned __int8)s[1] >> 4);
v17 = (_BYTE *)v32;
v33 = v32 + 1;
if (4 * s[1] & 0x3C)
v18 = (4 * s[1] & 0x3C) + 32;
else
v18 = 32;
*v17 = v18 | ((unsigned __int8)s[2] >> 6);
v19 = (_BYTE *)v33;
v30 = (char *)(v33 + 1);
if (s[2] & 0x3F)
v20 = (s[2] & 0x3F) + 32;
else
v20 = 32;
*v19 = v20;
v25 += 3;
s += 3;
}
*v30 = 0;
return v34;
}
具体分析代码如下:
mapping_table.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern char *mapping_table(const char *a1);
int main(int argc, char const *argv[])
{
puts(mapping_table(argv[1]));
return 0;
}
运行结果:
ex@Ex:~/test$ gcc -O3 mapping_table.c -o mapping_table
ex@Ex:~/test$ ./mapping_table abc
#86)C
ex@Ex:~/test$ ./mapping_table abcabc
&86)C86)C
ex@Ex:~/test$ ./mapping_table abcabcabc
)86)C86)C86)C
ex@Ex:~/test$ ./mapping_table abcabcabc123
,86)C86)C86)C,3(S
ex@Ex:~/test$ ./mapping_table abcabcabc123123
/86)C86)C86)C,3(S,3(S
虽然不知道第一个字符有什么用,但是不影响我们还原字符串,然后利用该函数生成对应的映射表,进行反向查询就可以还原原来的字符。
解密
creat_mapping_table.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern char *mapping_table(const char *a1);
int main(int argc, char const *argv[])
{
char *table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int table_length = 64;
char buf[4];
int store;
char *temp;
puts("[\n");
for (int i = 0; i < table_length; i++)
{
buf[0] = table[i];
for (int ii = 0; ii < table_length; ii++)
{
buf[1] = table[ii];
for (int iii = 0; iii < table_length; iii++)
{
buf[2] = table[iii];
buf[3] = '\0';
temp = mapping_table(buf);
store = *(int *)buf;
printf("{\"%s\":\t\"%s\"},\n", temp + 1, (char *)&store);
free(temp);
}
}
}
puts("]\n");
return 0;
}
运行结果:
ex@Ex:~/test$ gcc -O3 creat_mapping_table.c -o creat_mapping_table
ex@Ex:~/test$ ./creat_mapping_table > table
生成了映射文件table
,在把我们的字符串@1DE!440S9W9,2T%Y07=%<W!Z.3!:1T%S2S-),7-$/3T
带到映射表中去查找(注意第一个字符是要被舍去的),虽然最后四个字符/3T
在映射表中找不到,但是不影响我们拿flag,查找完之后得到字符串FIAQD3gvLKAyAwEspz90ZGAsK3I1sD
,进行rot13解密得到字符串SVNDQ3tiYXNlNjRfcm90MTNfX3V1fQ
。然后进行base64解密即可拿到flag。
原本想直接生成json文件放到Python里面处理,但是由于文件有太多的非常字符要处理,所以就只能手动查找,鉴于要查找的字符串不长,所以花的时间也不多。
ex@Ex:~/test$ echo -n SVNDQ3tiYXNlNjRfcm90MTNfX3V1fQ | base64 -d
ISCC{base64_rot13__uu}base64: invalid input
总结
主要是对一些常用的加密算法要了解,一些不常用的加密算法也是比较容易进行还原的,因为逆向的很多加密算法遵循一一对应的原则,所以我们即使我们不知道加密的具体原理,但是只要我们能生成对照表,就能通过对照表进行还原。