【BJDCTF】encode
收获
- 要求能看出伪代码中的加密算法,本题中的 Base64 和 RC4
思路
先进行常规 upx 脱壳 (脱壳机好像有问题,用 cmd 脱壳,upx -d <文件名>
)
没有 main 函数,shift + F12
查看字符串,发现与 flag 有关的信息
在 IDA View-A 中跟进
进入函数 sub_804887C()
根据经验,将一些函数进行 rename,得到代码如下:
int sub_804887C()
{
int v0; // eax
int result; // eax
unsigned int i; // [esp+Ch] [ebp-FCh]
unsigned int v3; // [esp+10h] [ebp-F8h]
unsigned int v4; // [esp+14h] [ebp-F4h]
char v5[48]; // [esp+1Ah] [ebp-EEh] BYREF
char v6[178]; // [esp+4Ah] [ebp-BEh] BYREF
unsigned int v7; // [esp+FCh] [ebp-Ch]
v7 = __readgsdword(0x14u);
strcpy(v5, "Flag{This_a_Flag}");
v3 = strlen(v5);
strcpy(v6, "E8D8BD91871A1E56F53F4889682F96142AF2AB8FED7ACFD5E");
printf("Please input your flag:");
read(0, &v6[50], 256);
if ( strlen(&v6[50]) != 21 )
exit(0);
v0 = sub_8048AC2(&v6[50]);
strcpy(&v5[18], v0);
v4 = strlen(&v5[18]);
for ( i = 0; i < v4; ++i )
v5[i + 18] ^= v5[i % v3];
sub_8048E24(&v5[18], v4, v5, v3);
if ( !strcmp(&v5[18], v6) )
exit(0);
printf("right!");
result = 0;
if ( __readgsdword(0x14u) != v7 )
sub_806FA00();
return result;
}
那么就只存在两处函数不明确作用,一个是 sub_8048AC2
,一个是 sub_8048E24
查看函数 sub_8048AC2
:
查看 a0123456789Abcd
中的内容:
发现 a0123456789Abcd
是 Base64 加密的码表,根据 sub_8048AC2
函数的结构,可以判断这可能是 Base64 加密的算法
查看函数 sub_8048E24
根据函数调用,查看函数 sub_8048CC2
:
基本可以断定,sub_8048CC2
函数是一个 RC4 算法的加密初始化,那么 sub_8048E24
就是 RC4 加密的算法
得到最终的程序逻辑:
int sub_804887C()
{
int v0; // eax
int result; // eax
unsigned int i; // [esp+Ch] [ebp-FCh]
unsigned int v3; // [esp+10h] [ebp-F8h]
unsigned int v4; // [esp+14h] [ebp-F4h]
char v5[48]; // [esp+1Ah] [ebp-EEh] BYREF
char v6[178]; // [esp+4Ah] [ebp-BEh] BYREF
unsigned int v7; // [esp+FCh] [ebp-Ch]
v7 = __readgsdword(0x14u);
strcpy(v5, "Flag{This_a_Flag}");
v3 = strlen(v5);
strcpy(v6, "E8D8BD91871A1E56F53F4889682F96142AF2AB8FED7ACFD5E");
printf("Please input your flag:");
read(0, &v6[50], 256);
if ( strlen(&v6[50]) != 21 )
exit(0);
v0 = Base64(&v6[50]);
strcmp(&v5[18], v0);
v4 = strlen(&v5[18]);
for ( i = 0; i < v4; ++i )
v5[i + 18] ^= v5[i % v3];
RC4(&v5[18], v4, v5, v3);
if ( !strcmp(&v5[18], v6) )
exit(0);
printf("right!");
result = 0;
if ( __readgsdword(0x14u) != v7 )
sub_806FA00();
return result;
}
经过分析,逻辑就是 rc4(xor(base64(input)))
,key是 Flag{This_a_Flag}
,但最终 cipher 是有点问题的,需要手动 Base16 解密成字节码才能用
脚本
C++
#include <stdio.h>
#include <string.h>
typedef unsigned long ULONG;
void rc4_init(unsigned char *s, unsigned char *key, unsigned long Len) //初始化函数
{
int i =0, j = 0;
char k[256] = {0};
unsigned char tmp = 0;
for (i = 0; i < 256; i++) {
s[i] = i;
k[i] = key[i % Len];
}
for (i = 0; i < 256; i++) {
j=(j + s[i] + k[i]) % 256;
tmp = s[i];
s[i] = s[j]; //交换s[i]和s[j]
s[j] = tmp;
}
}
void rc4_crypt(unsigned char *s, unsigned char *Data, unsigned long Len) //加解密
{
int i = 0, j = 0, t = 0;
unsigned long k = 0;
unsigned char tmp = 0;
for(k = 0;k < Len; k++) {
i=(i + 1) % 256;
j=(j + s[i]) % 256;
tmp = s[i];
s[i] = s[j]; //交换s[x]和s[y]
s[j] = tmp;
t=(s[i] + s[j]) % 256;
Data[k] ^= s[t];
}
}
unsigned int FindIndex(char *string,char c)
{
int i;
for(i = 0; i < strlen(string); i++)
{
if(c == string[i])
return i;
}
}
void base64_decode(unsigned char *input)
{
unsigned char output[256] = {0};
char *string = {"0123456789+/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"};
int index = 0;
int input_length = strlen((char*)input);
int i = 0;
for(i = 0; i < input_length; i += 4)
{
if(i+1 >= input_length) break;
output[index++] = (FindIndex(string,input[i])<<2) + (FindIndex(string,input[i+1])>>4);
if(i+2 >= input_length) break;
output[index++] = (FindIndex(string,input[i+1])<<4) + (FindIndex(string,input[i+2])>>2);
if(i+3 >= input_length) break;
output[index++] = (FindIndex(string,input[i+2])<<6) + (FindIndex(string,input[i+3]));
}
printf("result:");
puts((char*)output);
printf("HEX:");
for(i = 0; i < strlen((char*)output); i++)
{
printf("%x ",output[i]);
}
printf("\n");
}
int main()
{
unsigned char s[257] = {0}; //S-box
int i=0;
unsigned char key[257] = {"Flag{This_a_Flag}\x00"}; //key
unsigned char pData[] = {0xe8,0xd8,0xbd,0x91,0x87,0x1a,0x01,0x0e,0x56,0x0f,0x53,0xf4,0x88,0x96,0x82,0xf9,0x61,0x42,0x0a,0xf2,0xab,0x08,0xfe,0xd7,0xac,0xfd,0x5e,0x00}; //密文
ULONG len = strlen((char*)pData);
rc4_init(s,(unsigned char *)key,strlen((char*)key)); //已经完成了初始化
rc4_crypt(s,(unsigned char *)pData,strlen((char*)pData)); //加密
for(int i = 0; i < strlen((char*)pData); i++)
{
pData[i] ^= key[i % strlen((char*)key)];
}
printf("rc4 decrypt : %s\n",pData);
base64_decode(pData);
return 0;
}
Python
from base64 import b64decode
key = 'Flag{This_a_Flag}'
decode_byte = '23152553081a5938126a3931275b0b1313085c330b356101511f105c'
encode_base64 = ''
lists = []
for i in range(len(decode_byte)//2):
lists.append(int(decode_byte[i*2:(i+1)*2], 16))
print(lists)
for i in range(len(lists)):
encode_base64 += chr(lists[i] ^ ord(key[i % len(key)]))
t = '0123456789+/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ='
table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
table = str.maketrans(t, table)
flag = b64decode(encode_base64.translate(table))
print(flag.decode())
结果
BJD{0v0_Y0u_g07_1T!}
C++
Python
评论