逆向解密
base64
基本概念:
base64根据百度的查询,定义如下:
Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法。
//64个字符为:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=
基本原理:
即把一个3字节的数据转换为4字节的数据存储-----以二进制的形式进行操作。
假设现在要对"abc"这串字符串进行base64加密,首先判断该数据是否为 3的倍数的 字节大小(其中一个字符1字节,一个字节可以用8个二进制表示)
该数据确定为3字节大小的倍数后根据ascii码对应的二进制表示出来
将二进制每6位为一组,然后高位补00,形成8位一组
然后将其二进制对应的base64表中的值去对应相应的base64码
最后就能得到base64加密的字符串
”YWJj"
若加密的数据不足3的倍数的字节的大小,那么就在其 编码过程 中补\x00,补足其位数,补了几个\x00,最后就加上几个'='
现要加密字符'1'//其ascii表对应的二进制为0011 0001(49)
操作如下和正常情况加密相似
base64表如下:
摘自百度
C语言实现
#include<stdio.h>
#include<string.h>
#define MAX 100000
char base64[]={"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="};//base64表
char decode(char flag[]);
int main(){
char text[MAX];
scanf("%s",&text);
int i=0;
int j=0;
long len=strlen(text);
char flag[MAX];
int v4=len%3;
switch(v4){
//字符串是3的倍数长度的情况
case 0:{
len=(strlen(text)/3)*4;
for(i=0;i<len;){
flag[i]=base64[text[j]>>2];//取第一位元素text[0]的前6位
flag[i+1]=base64[ ( ( text[j] & 0x3 ) << 4 ) | ( ( text[j+1] >> 4 ) ) ];//取第一位元素text[0]的后两位和第二元素text[1]的前4位
flag[i+2]=base64[((text[j+1]&0xf)<<2)|((text[j+2]&0xc0)>>6)];//取text[1]的后4位和text[2]的前2位
flag[i+3]=base64[text[j+2]&0x3f];//取text[2]的后六位
i=i+4;
j=j+3;
}
break;
}
//长度比3的倍数多一的情况
case 1:{
len=(strlen(text)/3)*4;
//先对前面3的倍数的长度经行正常规则编码
for(i=0;i<len;){
flag[i]=base64[text[j]>>2];
flag[i+1]=base64[ ( ( text[j] & 3 ) << 4 ) | ( ( text[j+1] >> 4 ) ) ];
flag[i+2]=base64[((text[j+1]&0xf)<<2)|((text[j+2]&0xc0)>>6)];
flag[i+3]=base64[text[j+2]&0x3f];
i=i+4;
j=j+3;
}
//再对多出来的字符以在二进制末尾补充/x00的形式进行编码,末尾填写多少个/x00就在编码末尾添加几个‘=’
flag[i]=base64[text[j]>>2];
flag[i+1]=base64[ ( ( text[j] & 3 ) << 4 ) | ( ( text[j+1] >> 4 ) ) ];
flag[i+2]=base64[strlen(base64)-1];// '='
flag[i+3]=base64[strlen(base64)-1];// '='
break;
}
//长度比3的倍数多2的情况
//编码规则和多1的一样
case 2:{
len=(strlen(text)/3)*4;
for(i=0;i<len;){
flag[i]=base64[text[j]>>2];
flag[i+1]=base64[ ( ( text[j] & 3 ) << 4 ) | ( ( text[j+1] >> 4 ) ) ];
flag[i+2]=base64[((text[j+1]&0xf)<<2)|((text[j+2]&0xc0)>>6)];
flag[i+3]=base64[text[j+2]&0x3f];
i=i+4;
j=j+3;
}
flag[i]=base64[text[j]>>2];
flag[i+1]=base64[ ( ( text[j] & 3 ) << 4 ) | ( ( text[j+1] >> 4 ) ) ];
flag[i+2]=base64[((text[j+1]&0xf)<<2)|((text[j+2]&0xc0)>>6)];
flag[i+3]=base64[strlen(base64)-1];// '='
break;
}
}
printf("%s\n",flag);
decode(flag);//base64的解码
return 0;
}
char decode(char flag[]){
char base64[MAX];
base64['A']=0;
base64['B']=1;
base64['C']=2;
base64['D']=3;
base64['E']=4;
base64['F']=5;
base64['G']=6;
base64['H']=7;
base64['I']=8;
base64['J']=9;
base64['K']=10;
base64['L']=11;
base64['M']=12;
base64['N']=13;
base64['O']=14;
base64['P']=15;
base64['Q']=16;
base64['R']=17;
base64['S']=18;
base64['T']=19;
base64['U']=20;
base64['V']=21;
base64['W']=22;
base64['X']=23;
base64['Y']=24;
base64['Z']=25;
base64['a']=26;
base64['b']=27;
base64['c']=28;
base64['d']=29;
base64['e']=30;
base64['f']=31;
base64['g']=32;
base64['h']=33;
base64['i']=34;
base64['j']=35;
base64['k']=36;
base64['l']=37;
base64['m']=38;
base64['n']=39;
base64['o']=40;
base64['p']=41;
base64['q']=42;
base64['r']=43;
base64['s']=44;
base64['t']=45;
base64['u']=46;
base64['v']=47;
base64['w']=48;
base64['x']=49;
base64['y']=50;
base64['z']=51;
base64['0']=52;
base64['1']=53;
base64['2']=54;
base64['3']=55;
base64['4']=56;
base64['5']=57;
base64['6']=58;
base64['7']=59;
base64['8']=60;
base64['9']=61;
base64['+']=62;
base64['/']=63;
//建立base64表 ,后续根据base64表对应的十进制进行移位操作,到达解码的目的
int i=0;
int j=0;
int len=strlen(flag);
//判断原始明文长度
if(flag[len-1]=='='&&flag[len-2]!='=')
len=len/4*3-1;
else if(flag[len-2]=='=')
len=len/4*3-2;
else
len=len/4*3;
char text[len];
for(i=0;i<len;){
text[i]=(base64[flag[j]]<<2)|((base64[flag[j+1]]<<2)&0x60)>>6;//取flag[0]的后六位和flag[1]的前2位
text[i+1]=(base64[flag[j+1]]<<4)|(base64[flag[j+2]]<<2)>>4;//取flag[1]的后4位和flag[2]的中间4位
text[i+2]=(base64[flag[j+2]]<<6)|base64[flag[j+3]]&0x3f; //取flag[2]的后2位和flag{3]的后6位
i=i+3;
j=j+4;
}
printf("%s",text);
return *text;
}
关于base64的题
BUUCTF-reverse-3
IDA32打开进行分析
没找到main函数,然后打开string window界面,找到”right flag!“字符串跟进去,对该部分函数进行分析
int sub_4156E0()
{
int v0; // eax@6
int v1; // eax@6
size_t v2; // eax@9
char v4; // [sp+0h] [bp-188h]@6
char v5; // [sp+Ch] [bp-17Ch]@1
size_t v6; // [sp+10h] [bp-178h]@3
size_t j; // [sp+DCh] [bp-ACh]@6
size_t i; // [sp+E8h] [bp-A0h]@1
char Dest[108]; // [sp+F4h] [bp-94h]@5
char Str; // [sp+160h] [bp-28h]@6
char v11; // [sp+17Ch] [bp-Ch]@6
unsigned int v12; // [sp+184h] [bp-4h]@1
int savedregs; // [sp+188h] [bp+0h]@1
memset(&v5, 0xCCu, 0x17Cu);
v12 = (unsigned int)&savedregs ^ __security_cookie;
for ( i = 0; (signed int)i < 100; ++i )
{
v6 = i;
if ( i >= 0x64 )
sub_411154();
Dest[v6] = 0;
}
sub_41132F("please enter the flag:", v4);
sub_411375("%20s", &Str); // Str字符串就是flag
v0 = j_strlen(&Str); // V0表示flag的长度
v1 = sub_4110BE((int)&Str, v0, (int)&v11); // 调用函数sub_4110BE进行加密str操作,同时加密后的代码返回给V1
strncpy(Dest, (const char *)v1, 0x28u); // 将加密后的flag也就是v1复制到Dest里面
sub_411127();
i = j_strlen(Dest);
for ( j = 0; (signed int)j < (signed int)i; ++j )// 对加密后的flag也就是Dest中的每个元素加j操作
Dest[j] += j; // Dest[j]=Dest[j]+j;
v2 = j_strlen(Dest);
strncmp(Dest, Str2, v2); // 比较Dest和Str2,也就是说Str2是最终的加密flag
if ( sub_411127() ) // Str2为e3nifIH9b_C@n@dH
sub_41132F("wrong flag!\n", v4);
else
sub_41132F("rigth flag!\n", v4);
sub_41126C(&savedregs, &dword_415890);
sub_411280();
return sub_411127();
}
顺着分析下来,其主要的加密部分为
v1 = sub_4110BE((int)&Str, v0, (int)&v11); // 调用函数sub_4110BE进行加密str操作,同时加密后的代码返回给V1
//和
for ( j = 0; (signed int)j < (signed int)i; ++j )// 对加密后的flag也就是Dest中的每个元素加j操作
Dest[j] += j; // Dest[j]=Dest[j]+j;
主要跟进sub_4110BE函数
这部分代码就是对传进来的字符串进行base64加密,v4判断本次循环的byte_41A144[0][1][2]是否有3字节的大小
然后根据v4的情况进行加密,满足3字节的话,就进第三个判断,正常加密,
不满足3字节的就进行补\x00操作,然后加几个\x00就在末尾添几个'='
从该函数跳出后,加密后的字符串被传给了v1,然后又被copy到Dest上,之后又对Dest修改
for ( j = 0; (signed int)j < (signed int)i; ++j )// 对加密后的flag也就是Dest中的每个元素加j操作
Dest[j] += j; // Dest[j]=Dest[j]+j;
最后Dest只有等于Str2才输出”right flag“
所以就是解题步骤如下:
#include<stdio.h>
#include<windows.h>
#include<string.h>
int main(){
int v4;
char a[20]={"e3nifIH9b_C@n@dH"};
int i;
for(i=0;i<strlen(a);i++){
a[i]=a[i]-i;
}
//memset( &v4,0xCCu,0x100u);
printf("%s\n",a);
system("pause");
return 0;
得原来的base加密后的字符为:e2lfbDB2ZV95b3V9,通过网上的base64解密得flag:
flag{i_l0ve_you}
0x100u);
printf("%s\n",a);
system(“pause”);
return 0;
得原来的base加密后的字符为:==e2lfbDB2ZV95b3V9==,通过网上的base64解密得flag:
flag{i_l0ve_you}