[BJDCTF2022]encode(点击下载)
分析
文件带有upx壳,脱壳之后,进入ida分析
根据字符串里面的right字符找到窗口
文件将输入点放在v6数组的第50个地址上面,输入之后判断长度为21.
然后文件进入了sub_8048AC2进行了加密
int __cdecl sub_8048AC2(int a1)
{
int v2; // [esp+8h] [ebp-20h]
int v3; // [esp+Ch] [ebp-1Ch]
int v4; // [esp+10h] [ebp-18h]
int v5; // [esp+18h] [ebp-10h]
int v6; // [esp+1Ch] [ebp-Ch]
v5 = sub_805BBD0(a1);
if ( v5 % 3 )
v2 = 4 * (v5 / 3 + 1);
else
v2 = 4 * (v5 / 3);
v6 = sub_80597A0(v2 + 1);
*(_BYTE *)(v2 + v6) = 0;
v3 = 0;
v4 = 0;
while ( v2 - 2 > v3 )
{
*(_BYTE *)(v6 + v3) = a0123456789Abcd[*(_BYTE *)(v4 + a1) >> 2];
*(_BYTE *)(v6 + v3 + 1) = a0123456789Abcd[(16 * (*(_BYTE *)(v4 + a1) & 3)) | (*(_BYTE *)(v4 + 1 + a1) >> 4)];
*(_BYTE *)(v6 + v3 + 2) = a0123456789Abcd[(4 * (*(_BYTE *)(v4 + 1 + a1) & 0xF)) | (*(_BYTE *)(v4 + 2 + a1) >> 6)];
*(_BYTE *)(v6 + v3 + 3) = a0123456789Abcd[*(_BYTE *)(v4 + 2 + a1) & 0x3F];
v4 += 3;
v3 += 4;
}
if ( v5 % 3 == 1 )
{
*(_BYTE *)(v3 - 2 + v6) = 61;
*(_BYTE *)(v3 - 1 + v6) = 61;
}
else if ( v5 % 3 == 2 )
{
*(_BYTE *)(v3 - 1 + v6) = 61;
}
return v6;
}
根据逻辑发现是Base64
密码表为:
0123456789+/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
sub_80481D0是将base64加密后的数据存到v5 + 18 的地址上面
再使用for循环和v5这串密钥循环异或
最后进入sub_8048E24
unsigned int __cdecl sub_8048E24(int a1, unsigned int a2, int a3, int a4)
{
unsigned int result; // eax
char v5; // [esp+1Bh] [ebp-11Dh]
int v6; // [esp+1Ch] [ebp-11Ch]
int v7; // [esp+20h] [ebp-118h]
unsigned int i; // [esp+24h] [ebp-114h]
char v9[256]; // [esp+2Ch] [ebp-10Ch] BYREF
unsigned int v10; // [esp+12Ch] [ebp-Ch]
v10 = __readgsdword(0x14u);
sub_8048CC2(v9, a3, a4);
LOBYTE(v6) = 0;
LOBYTE(v7) = 0;
for ( i = 0; i < a2; ++i )
{
v6 = (unsigned __int8)(v6 + 1);
v7 = (unsigned __int8)(v9[v6] + v7);
v5 = v9[v6];
v9[v6] = v9[v7];
v9[v7] = v5;
*(_BYTE *)(a1 + i) ^= v9[(unsigned __int8)(v9[v6] + v9[v7])];
}
result = __readgsdword(0x14u) ^ v10;
if ( result )
sub_806FA00();
return result;
}
其中调用了 sub_8048CC2(v9, a3, a4);
unsigned int __cdecl sub_8048CC2(int a1, int a2, unsigned int a3)
{
unsigned int result; // eax
char v4; // [esp+13h] [ebp-115h]
int i; // [esp+14h] [ebp-114h]
int j; // [esp+14h] [ebp-114h]
int v7; // [esp+18h] [ebp-110h]
char v8[256]; // [esp+1Ch] [ebp-10Ch]
unsigned int v9; // [esp+11Ch] [ebp-Ch]
v9 = __readgsdword(0x14u);
for ( i = 0; i <= 255; ++i )
{
*(_BYTE *)(i + a1) = i;
v8[i] = *(_BYTE *)(i % a3 + a2);
}
v7 = 0;
for ( j = 0; j <= 255; ++j )
{
v7 = (*(unsigned __int8 *)(j + a1) + v7 + (unsigned __int8)v8[j]) % 256;
v4 = *(_BYTE *)(j + a1);
*(_BYTE *)(a1 + j) = *(_BYTE *)(v7 + a1);
*(_BYTE *)(a1 + v7) = v4;
}
result = __readgsdword(0x14u) ^ v9;
if ( result )
sub_806FA00();
return result;
}
分析之后发现是rc4加密。
题解:
首先将v6地址上存储的数据进行rc4解密,然后循环异或,最后再使用base64变表解密,就行了。
【注意】
题目中这个v6的字符串,由于ida的原因是分析错误了的。
所以我们需要手动改造一下,我们可以发现这一段语句
if ( sub_805BBD0(&v6[50]) == 21 )
sub_804EAF0(0);
动态调试后发现这个sub_805BBD0是一个获取字符串长的的语句
那么flag长度是21的话,经过base64加密之后应该是28位数,但是v6中存储的却只有49位数字,这是因为这个字符串有些01或者0E被识别成了1和E
正确的enc:
int a[]={
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
};
EXP
直接手撸代码版本
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<map>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<string>
#include<cstring>
#include<list>
#include<stdlib.h>
#include<windows.h>
#include<iostream>
#include<cstring>
#include<bitset>
#include<vector>
#include<stdlib.h>
#include<time.h>
#include<sstream>
#include<cstring>
/*base64.c*/
#include "base64.h"
using namespace std;
//base64.c
#include"base64.h"
char base64char[] = "0123456789+/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
char c;
char* base64_encode(char* binData, char* base64, int binLength)
{
int i = 0;
int j = 0;
int current = 0;
for (i = 0; i < binLength; i += 3) {
//获取第一个6位
current = (*(binData + i) >> 2) & 0x3F;
*(base64 + j++) = base64char[current];
//获取第二个6位的前两位
current = (*(binData + i) << 4) & 0x30;
//如果只有一个字符,那么需要做特殊处理
if (binLength <= (i + 1)) {
*(base64 + j++) = base64char[current];
*(base64 + j++) = '=';
*(base64 + j++) = '=';
break;
}
//获取第二个6位的后四位
current |= (*(binData + i + 1) >> 4) & 0xf;
*(base64 + j++) = base64char[current];
//获取第三个6位的前四位
current = (*(binData + i + 1) << 2) & 0x3c;
if (binLength <= (i + 2)) {
*(base64 + j++) = base64char[current];
*(base64 + j++) = '=';
break;
}
//获取第三个6位的后两位
current |= (*(binData + i + 2) >> 6) & 0x03;
*(base64 + j++) = base64char[current];
//获取第四个6位
current = *(binData + i + 2) & 0x3F;
*(base64 + j++) = base64char[current];
}
*(base64 + j) = '\0';
return base64;
}
char* base64_decode(char const* base64Str, char* debase64Str, int encodeStrLen)
{
int i = 0;
int j = 0;
int k = 0;
char temp[4] = "";
for (i = 0; i < encodeStrLen; i += 4) {
for (j = 0; j < 64; j++) {
if (*(base64Str + i) == base64char[j]) {
temp[0] = j;
}
}
for (j = 0; j < 64; j++) {
if (*(base64Str + i + 1) == base64char[j]) {
temp[1] = j;
}
}
for (j = 0; j < 64; j++) {
if (*(base64Str + i + 2) == base64char[j]) {
temp[2] = j;
}
}
for (j = 0; j < 64; j++) {
if (*(base64Str + i + 3) == base64char[j]) {
temp[3] = j;
}
}
*(debase64Str + k++) = ((temp[0] << 2) & 0xFC) | ((temp[1] >> 4) & 0x03);
if (*(base64Str + i + 2) == '=')
break;
*(debase64Str + k++) = ((temp[1] << 4) & 0xF0) | ((temp[2] >> 2) & 0x0F);
if (*(base64Str + i + 3) == '=')
break;
*(debase64Str + k++) = ((temp[2] << 6) & 0xF0) | (temp[3] & 0x3F);
}
return debase64Str;
}
unsigned int __cdecl sub_8048CC2(unsigned __int8 * a1, char *a2, unsigned int a3)
{
char v4; // [esp+13h] [ebp-115h]
int i; // [esp+14h] [ebp-114h]
int j; // [esp+14h] [ebp-114h]
int v7; // [esp+18h] [ebp-110h]
unsigned __int8 v8[256]; // [esp+1Ch] [ebp-10Ch]
for ( i = 0; i <= 255; ++i )
{
*(i + a1) = i;
v8[i] = *(i % a3 + a2);
}
v7 = 0;
for ( j = 0; j <= 255; ++j )
{
v7 = (*(unsigned __int8 *)(j + a1) + v7 + (unsigned __int8)v8[j]) % 256;
v4 = *(j + a1);
*(a1 + j) = *(v7 + a1);
*(a1 + v7) = v4;
}
return 0;
}
unsigned int __cdecl sub_8048E24(int* a1, unsigned int a2, char * a3, unsigned int a4)
{
char v5; // [esp+1Bh] [ebp-11Dh]
int v6; // [esp+1Ch] [ebp-11Ch]
int v7; // [esp+20h] [ebp-118h]
unsigned int i; // [esp+24h] [ebp-114h]
unsigned __int8 v9[256]; // [esp+2Ch] [ebp-10Ch] BYREF // [esp+12Ch] [ebp-Ch]
sub_8048CC2(v9, a3, a4);
v6 = 0;
v7 = 0;
for ( i = 0; i < a2; ++i )
{
v6 = (unsigned __int8)(v6 + 1);
v7 = (unsigned __int8)(v9[v6] + v7);
v5 = v9[v6];
v9[v6] = v9[v7];
v9[v7] = v5;
*(a1 + i) ^= v9[(unsigned __int8)(v9[v6] + v9[v7])];
}
return 0;
}
int a[]={
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
};
char b[]="Flag{This_a_Flag}";
int main ()
{
char flag[256]="0";
sub_8048E24(a,28,b,17);
for(int i = 0 ; i<28; i ++ )
{
a[i]^=b[i%17];
flag[i]=a[i];
}
char ans[256]={0};
base64_decode(flag,ans,strlen(flag));
cout<<ans<<endl;
}
动态调试获取rc4异或值
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<map>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<string>
#include<cstring>
#include<list>
#include<stdlib.h>
#include<windows.h>
#include<iostream>
#include<cstring>
#include<bitset>
#include<vector>
#include<stdlib.h>
#include<time.h>
#include<sstream>
#include<cstring>
/*base64.c*/
#include "base64.h"
using namespace std;
//base64.c
#include"base64.h"
char base64char[] = "0123456789+/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
char c;
char* base64_encode(char* binData, char* base64, int binLength)
{
int i = 0;
int j = 0;
int current = 0;
for (i = 0; i < binLength; i += 3) {
//获取第一个6位
current = (*(binData + i) >> 2) & 0x3F;
*(base64 + j++) = base64char[current];
//获取第二个6位的前两位
current = (*(binData + i) << 4) & 0x30;
//如果只有一个字符,那么需要做特殊处理
if (binLength <= (i + 1)) {
*(base64 + j++) = base64char[current];
*(base64 + j++) = '=';
*(base64 + j++) = '=';
break;
}
//获取第二个6位的后四位
current |= (*(binData + i + 1) >> 4) & 0xf;
*(base64 + j++) = base64char[current];
//获取第三个6位的前四位
current = (*(binData + i + 1) << 2) & 0x3c;
if (binLength <= (i + 2)) {
*(base64 + j++) = base64char[current];
*(base64 + j++) = '=';
break;
}
//获取第三个6位的后两位
current |= (*(binData + i + 2) >> 6) & 0x03;
*(base64 + j++) = base64char[current];
//获取第四个6位
current = *(binData + i + 2) & 0x3F;
*(base64 + j++) = base64char[current];
}
*(base64 + j) = '\0';
return base64;
}
char* base64_decode(char const* base64Str, char* debase64Str, int encodeStrLen)
{
int i = 0;
int j = 0;
int k = 0;
char temp[4] = "";
for (i = 0; i < encodeStrLen; i += 4) {
for (j = 0; j < 64; j++) {
if (*(base64Str + i) == base64char[j]) {
temp[0] = j;
}
}
for (j = 0; j < 64; j++) {
if (*(base64Str + i + 1) == base64char[j]) {
temp[1] = j;
}
}
for (j = 0; j < 64; j++) {
if (*(base64Str + i + 2) == base64char[j]) {
temp[2] = j;
}
}
for (j = 0; j < 64; j++) {
if (*(base64Str + i + 3) == base64char[j]) {
temp[3] = j;
}
}
*(debase64Str + k++) = ((temp[0] << 2) & 0xFC) | ((temp[1] >> 4) & 0x03);
if (*(base64Str + i + 2) == '=')
break;
*(debase64Str + k++) = ((temp[1] << 4) & 0xF0) | ((temp[2] >> 2) & 0x0F);
if (*(base64Str + i + 3) == '=')
break;
*(debase64Str + k++) = ((temp[2] << 6) & 0xF0) | (temp[3] & 0x3F);
}
return debase64Str;
}
int a[]={
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
};
char b[]="Flag{This_a_Flag}";
int tmp[]={
0xcb,0xcd,0x98,0xc2,0x8f,0x0,0x58,0x36,0x44,0x65,
0x6a,0xc5,0xaf,0xcd,0x89,0xea,0x72,0x4a,0x56,0xc1,
0xa0,0x3d,0x9f,0xd6,0xfd,0xe2,0x4e,0x5c,0x3f,0xd,
0xe,0x47,0x8b,0x8a,0x45,0x39,0xcb,0xa4,0xbf,0xf2,
0x79,0x7c,0x3a,0x6b,0xe8,0x2c,0x8b,0x1a,0x60,0x60,
0x8e,0x7f,0x76,0x83,0x8e,0x1a
};
int main ()
{
char flag[256]="0";
for(int i= 0 ; i< 28; i ++ )
{
a[i]^=tmp[i];
}
for(int i = 0 ; i<28; i ++ )
{
a[i]^=b[i%17];
flag[i]=a[i];
}
char ans[256]={0};
base64_decode(flag,ans,strlen(flag));
cout<<ans<<endl;
}