第四届“安洵杯”网络安全挑战赛 re部分详细题解

阅读量    108360 | 评论 1

分享到: QQ空间 新浪微博 微信 QQ facebook twitter

 

signin

一个字:麻烦

先打开程序 发现好像是贪吃蛇

ida跟进sub_40100F,发现有个花指令和SMC,先不管这么多,先把SMC解出来。

image-20211128000157079

用od动态调试,断在0x419054,此为加密完成的位置。然后到0x401d10,重新分析代码后,将整个函数选中右键复制到可执行文件-选择,然后保存到新的文件即可看到逻辑。

image-20211128000848969

解出来发现这是flag的逻辑,这里程序先进行了异或,矩阵变换,然后就是一个魔改的类似TEA思想的算法。

image-20211128105520620

image-20211128105604653

这里的dword_42CA44 未知,但是其 小于256

v5 = dword_42CA44 + 1144219440;

image-20211128105646146

可以注意到加密函数这里sub_401055((int)v5, (int)v4, 32);

v5 虽然是一个int 数组,但是他是从char 赋值来的。所以我们可以爆破dword_42CA44,尝试dword_42CA44解出来是否<256

#include <ctime>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
unsigned char Enc[] = { 0xA5, 0xD8, 0x8E, 0xBF, 0xF9, 0xA9, 0x15, 0xE1, 0x8A, 0xF0,
  0xD3, 0xFC, 0x46, 0x89, 0xBF, 0x8B, 0x62, 0xB1, 0x08, 0xC3,
  0x29, 0xCF, 0x19, 0x2B, 0x56, 0x06, 0x77, 0x7A, 0xBA, 0xE4,
  0xBA, 0xA4, 0xE4, 0x8C, 0x3E, 0x4E, 0xD9, 0xE1, 0xA7, 0x01,
  0x04, 0xCE, 0xE9, 0x75, 0xB9, 0x93, 0xB5, 0x22, 0xB4, 0x42,
  0x77, 0x49, 0xF6, 0x15, 0xEB, 0x24, 0x0E, 0xFF, 0xC2, 0xF2,
  0x39, 0x30, 0x97, 0x47, 0x0D, 0xCA, 0x01, 0xC8, 0x61, 0x58,
  0x12, 0x6A, 0xE8, 0x0B, 0x32, 0x80, 0x47, 0xBD, 0x85, 0x03,
  0xDD, 0x6D, 0xF9, 0x69, 0xD1, 0x90, 0x64, 0xE5, 0x4B, 0xAD,
  0x3C, 0x2D, 0xBE, 0x00, 0x42, 0x2D, 0x79, 0x69, 0xEF, 0x89,
  0x5D, 0x88, 0x91, 0x4A, 0xC7, 0xEB, 0x9D, 0x01, 0x96, 0xFD,
  0xF8, 0x3B, 0x57, 0x25, 0xDD, 0x1B, 0xDD, 0x5F, 0x68, 0xB8,
  0x14, 0x66, 0x22, 0x57, 0x28, 0x5C, 0x58, 0x9F };


DWORD GetMagic1(int time,int x)
{
    DWORD magic = 0x44336730 + x;
    DWORD v8 = 0;
    for(int i = 0 ; i< time ;i++){
        v8 += magic;
    }
    return (v8 >> 2) & 3;
}
DWORD GetMagic2(int time,int x)
{
    DWORD magic = 0x44336730 + x;
    DWORD v8 = 0;
    for (int i = 0; i < time; i++) {
        v8 += magic;
    }
    return v8;
}
int main()
{
    unsigned long ENC[32] = { 0 };

    for (int x = 0;x < 256;x++){
        memcpy(ENC, Enc, 32 * 4);
        DWORD* a1 = (DWORD*)ENC;
        DWORD know[] = { 68,48,103,51 };
        for (int j = 7; j > 0; j--) {
            DWORD v8 = GetMagic2(j,x);
            DWORD v6 = GetMagic1(j,x);
            DWORD v9 = a1[30];
            a1[31] -= ((v9 ^ (know[(v6 ^ 31) & 3])) + (*a1 ^ v8)) ^ (((16 * v9) ^ (*a1 >> 3))
                + ((4 * *a1) ^ (v9 >> 5)));
            for (int i = 30; i >= 0; i--) {
                if (i == 0) {
                    v9 = a1[31];

                }
                else {
                    v9 = a1[i - 1];
                }
                a1[i] -= ((v9 ^ (know[(v6 ^ i) & 3])) + (a1[i + 1] ^ v8)) ^ (((16 * v9) ^ (a1[i + 1] >> 3))
                    + ((4 * a1[i + 1]) ^ (v9 >> 5)));

            }
        }
        if(ENC[0] < 256){
            printf("%d",x);
        }
    }
}

x = 77

然后再逆矩阵变换,我们可以构造一个{1,2,3,4,5,6,7,...}的数组然后进行加密拿到置换表

int j = 0;
int i = 0;
int v1[128] = { 0 };
char table[32] = { 0 };
// DWORD* table = ENC;
// char table[32] = { 0x25,0x4f,0x1d,0x32,0x6b,0x5c,0x3c,0x1d,0x5c,0x6e,0x06,0x42,0x40,0x1a,0x0f,0x15,0x1c,0x2b,0x2b,0x57,0x5c,0x00,0x1a,0x36,0x66,0x44,0x2b,0x00,0x09};
for(int sb = 0;sb<32;sb++){
    table[sb] = sb + 1;
}

while (i < 32)
{
    if (j % 6 >= 3)
        v1[32 * (3 - j % 3) + i] = table[i];
    else
        v1[32 * (j % 3) + i] = table[i];
    ++i;
    ++j;
}
char result[32] = { 0 };
int v7 = 0;
for (i = 0; i < 4; ++i)
{
    for (j = 0; j < 32; ++j)
    {
        if (v1[32 * i + j])
            result[v7++] = (unsigned __int8)v1[32 * i + j];
    }
}
__asm int 3;

然后把提取表,逆置换,再逆异或即可拿到flag

char ConverTable[32] = { 0x1,0x07,0x0d,0x13,0x19,0x1f,0x02,0x06,0x08,0x0c,0x0e,0x12,0x14,0x18,0x1a,0x1e,0x20,0x03,0x05,0x09,0x0b,0x0f,0x11,0x15,0x17,0x1b,0x1d,0x04,0x0a,0x10,0x16,0x1c };
for(int i = 0;i<32;i++){
    ConverTable[i] -= 1; // 这里对应关系要 -1
}
char sb[33] = { 0 };
for(int i = 0;i<32;i++){
    sb[ConverTable[i]] =(char)ENC[i];
}
sb[31] ^= sb[0];

for(int i = 30 ;i>=0;i--){
    // printf("%d", i);
    sb[i] ^= sb[(i + 1) % 32];
}
printf("%s", sb);
Th4_1mp0rtant_th2n9_is_t0_le@rn!

 

virus

主体程序是一个process hollowing

sub_40132C是一个资源提取的函数,这里用0x41解密资源

image-20211128110234293

resource hacker 把 资源节的LOCALIZATIONUNICODE数据提取,然后异或65 即可拿到真正的exe

sub_4010EAprocess hollowing 没有修改释放的程序内容,因此我们可以直接把提取的exe解包。

解包分析:

首先要输入一个key

image-20211128110808613

这里key经过KeyExpand函数生成了128位key,程序验证最后32位是否位Lroo,由于key只有4位,这里我们可以直接爆破。

void __cdecl sub_401790(char* a1, char* a2)
{
    DWORD v2[56]; // [esp+4Ch] [ebp-FCh] BYREF
    int v3; // [esp+12Ch] [ebp-1Ch]
    int v4; // [esp+130h] [ebp-18h]
    int v5; // [esp+134h] [ebp-14h]
    int j; // [esp+138h] [ebp-10h]
    int v7; // [esp+13Ch] [ebp-Ch]
    int v8; // [esp+140h] [ebp-8h]
    int i; // [esp+144h] [ebp-4h]

    for (i = 0; i < 4; ++i)
    {
        v8 = *(char*)(i + a1);
        for (j = 6; j >= 0; --j)
        {
            v2[7 * i + 28 + j] = v8 % 2;
            v8 /= 2;
            v2[7 * i + j] = v2[7 * i + 28 + j];
        }
    }
    v5 = 0;
    v4 = 0;
    for (i = 0; i < 4; ++i)
    {
        for (j = 0; j < 7; ++j)
        {
            v3 = v2[7 * v5 + v4];
            v2[7 * i + 28 + j] = v3;
            v5 = (v5 + 1) % 4;
            v4 = (v4 + 2) % 7;
        }
    }
    for (i = 0; i < 4; ++i)
    {
        v7 = 0;
        for (j = 0; j < 6; ++j)
        {
            v7 = 2 * (v7 + v2[7 * i + 28 + j]);
            if (v2[7 * i + 29 + j] == 1 && j == 5)
                ++v7;
        }
        *(BYTE*)(i + a2) = v7;
    }
}
void baopo()
{
    char table[] = { "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
            "abcdefghijklmnopqrstuvwxyz"
            "0123456789+/_-" };
    char key[5] = { "" };

    for (int a1 = 0; a1 < strlen(table); a1++)
        for (int a2 = 0; a2 < strlen(table); a2++)
            for (int a3 = 0; a3 < strlen(table); a3++)
                for (int a4 = 0; a4 < strlen(table); a4++) {
                    key[0] = table[a1];
                    key[1] = table[a2];
                    key[2] = table[a3];
                    key[3] = table[a4];
                    char test[5] = { 0 };
                    lstrcpynA(test, key, 5);

                    char result[20] = { 0 };
                    for (int i = 0; i < 4; i++) {
                        sub_401790(key, result);
                        lstrcpynA(key, result, 5);
                    }
                    if (!strcmp(key, "Lroo")) {
                        printf("%s", test);
                        system("pause");
                    }
                }
}

key = _shy

这里key 生成了 v11,提取v11

然后是最后的加密函数

void __cdecl sub_4012F0(int a1, int a2, int a3)
{
  int v3[36]; // [esp+4Ch] [ebp-94h] BYREF
  int i; // [esp+DCh] [ebp-4h]

  for ( i = 0; i < 4; ++i )
    pack(a1 + 4 * i, &v3[i]);
  for ( i = 0; i < 32; ++i )
    v3[i + 4] = sub_401005(*(_DWORD *)(a2 + 4 * i + 16) ^ v3[i + 3] ^ v3[i + 2] ^ v3[i + 1]) ^ v3[i];
  for ( i = 0; i < 4; ++i )
    unpack(v3[35 - i], a3 + 4 * i);
}
int __cdecl pack(int a1, int *a2)
{
  int result; // eax
  int i; // [esp+4Ch] [ebp-4h]

  result = (int)a2;
  *a2 = 0;
  for ( i = 0; i < 4; ++i )
  {
    result = *a2 | (*(unsigned __int8 *)(i + a1) << (24 - 8 * i));
    *a2 = result;
  }
  return result;
int __cdecl unpack(unsigned int a1, int a2)
{
  int result; // eax
  int i; // [esp+4Ch] [ebp-4h]

  for ( i = 0; i < 4; ++i )
  {
    *(_BYTE *)(i + a2) = a1 >> (24 - 8 * i);
    result = i + 1;
  }
  return result;
}

sub_40103csub_401019 是大端序的“pack” 和 “unpack” 函数。sub_401005是一个函数,他传入已知参数,得到的返回值与v3[i]异或得到加密值,写exp时需要用到这个函数,但是由于这个函数内部流程稍微比较复杂,这里我们可以用远线程注入的方法调用此函数,拿到返回值。

DWORD GetRemoteCallValue(HANDLE hProcess,DWORD v)
{
    HANDLE hThread = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)0x4011e0, (LPVOID)v, 0, 0);
    WaitForSingleObject(hThread, -1);
    DWORD ret = 0;
    GetExitCodeThread(hThread, &ret);
    CloseHandle(hThread);
    return ret;
}

所以最终的exp如下

#include <windows.h>
#include <stdio.h>
void __cdecl sub_401790(char* a1, char* a2)
{
    DWORD v2[56]; // [esp+4Ch] [ebp-FCh] BYREF
    int v3; // [esp+12Ch] [ebp-1Ch]
    int v4; // [esp+130h] [ebp-18h]
    int v5; // [esp+134h] [ebp-14h]
    int j; // [esp+138h] [ebp-10h]
    int v7; // [esp+13Ch] [ebp-Ch]
    int v8; // [esp+140h] [ebp-8h]
    int i; // [esp+144h] [ebp-4h]

    for (i = 0; i < 4; ++i)
    {
        v8 = *(char*)(i + a1);
        for (j = 6; j >= 0; --j)
        {
            v2[7 * i + 28 + j] = v8 % 2;
            v8 /= 2;
            v2[7 * i + j] = v2[7 * i + 28 + j];
        }
    }
    v5 = 0;
    v4 = 0;
    for (i = 0; i < 4; ++i)
    {
        for (j = 0; j < 7; ++j)
        {
            v3 = v2[7 * v5 + v4];
            v2[7 * i + 28 + j] = v3;
            v5 = (v5 + 1) % 4;
            v4 = (v4 + 2) % 7;
        }
    }
    for (i = 0; i < 4; ++i)
    {
        v7 = 0;
        for (j = 0; j < 6; ++j)
        {
            v7 = 2 * (v7 + v2[7 * i + 28 + j]);
            if (v2[7 * i + 29 + j] == 1 && j == 5)
                ++v7;
        }
        *(BYTE*)(i + a2) = v7;
    }
}
void baopo()
{
    char table[] = { "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
            "abcdefghijklmnopqrstuvwxyz"
            "0123456789+/_-" };
    char key[5] = { "" };

    for (int a1 = 0; a1 < strlen(table); a1++)
        for (int a2 = 0; a2 < strlen(table); a2++)
            for (int a3 = 0; a3 < strlen(table); a3++)
                for (int a4 = 0; a4 < strlen(table); a4++) {
                    key[0] = table[a1];
                    key[1] = table[a2];
                    key[2] = table[a3];
                    key[3] = table[a4];
                    char test[5] = { 0 };
                    lstrcpynA(test, key, 5);

                    char result[20] = { 0 };
                    for (int i = 0; i < 4; i++) {
                        sub_401790(key, result);
                        lstrcpynA(key, result, 5);
                    }
                    if (!strcmp(key, "Lroo")) {
                        printf("%s", test);
                        system("pause");
                    }
                }
}
unsigned char Enc[] = { 0x5C, 0x89, 0xEE, 0xF5, 0x6F, 0xC5, 0x44, 0x92, 0xDB, 0xE3,
       0xAE, 0x9C, 0xB5, 0x4F, 0x4A, 0xF4, 0xE7, 0xA3, 0x5E, 0x0F,
       0xFC, 0x93, 0xFC, 0x76, 0x6C, 0xFB, 0x29, 0xE0, 0x16, 0x2F,
       0xA5, 0x67
};
unsigned long key[] = {
        0xCBD6C588, 0x03F17D27, 0x1C18E9CC, 0xFE024DB3, 0xD71737EB, 0x7B9B1EAB, 0x2776BBA4, 0xBD2018C0,
        0x356D0553, 0x0C825513, 0xCAAFF094, 0x9DFBCBA1, 0x7EB6B878, 0x47630F35, 0x4B494BBE, 0x34FD620A,
        0x14CF85EF, 0xD754E93A, 0x338B4918, 0xC0846091, 0xD526F236, 0xB9CE1FC7, 0xCB537B6A, 0x25FDD8EA,
        0x7221094B, 0xA1F73ABF, 0x2473D8CC, 0x8FA4F2F2, 0x1E7CAC59, 0xEC581806, 0x425D33C3, 0xBEB16ED4,
        0xE5C0CA70, 0x02B60624, 0x3011744F, 0xF73A6E51
};
DWORD pack(const char * a)
{
    int r = 0;
    for(int i = 0;i<4;i++){
        r <<= 8;
        r |= (BYTE)a[i];
    }
    return r;
}

// char* unpack()
// {

// }

DWORD GetRemoteCallValue(HANDLE hProcess,DWORD v)
{
    HANDLE hThread = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)0x4011e0, (LPVOID)v, 0, 0);
    WaitForSingleObject(hThread, -1);
    DWORD ret = 0;
    GetExitCodeThread(hThread, &ret);
    CloseHandle(hThread);
    return ret;
}

int main(void)
{
    for(int x = 0;x<2;x++){
        unsigned v1 = pack((const char*)Enc + 12 + 16 *x);
        unsigned v2 = pack((const char*)Enc + 8 + 16*x);
        unsigned v3 = pack((const char*)Enc + 4 + 16 *x);
        unsigned v4 = pack((const char*)Enc + 16 *x);
        unsigned Temp[36] = { 0 };
        Temp[32] = v1;
        Temp[33] = v2;
        Temp[34] = v3;
        Temp[35] = v4;
        HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 5052); //TODO: 5852为解包出的题目程序运行的pid
        for (int i = 31; i >= 0; i--) {
            Temp[i] = GetRemoteCallValue(hProcess, Temp[i + 1] ^ Temp[i + 2] ^ Temp[i + 3] ^ key[i + 4]) ^ Temp[i + 4];
        }
        for (int i = 0; i < 4; i++) {
            Temp[i] ^= 0x06070607;
        }
        char* sb1 = (char*)Temp;
        for(int i = 0;i<4;i++){
            for(int j = 0 ; j< 4;j++){
                printf("%c", sb1[i * 4 + (3 - j)]);
        }
    }
}
    system("pause");
}
Ho3_I_Exp3cTed_n0_pY_1n_the_Ctf!

maze

一个很简单的迷宫,先算出dWWwwdddWWaawwddsssSaw的解法

但是找不到flag验证函数

然后题目提示 hint:字符串

这里输入了正确迷宫后,用x32dbg查找字符串可以看到变换的base64码表和base64字符串

image-20211128003119897

解出前半部分

import base64
import string

str1 = "QCAmN2sYNGUfR3EvOUMuNWYkW3k1JR=="

string1 = "BADCFEHGJILKNMPORQTSVUXWZYbadcfehgjilknmporqtsvuxwzy1032547698+/"
string2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

print (base64.b64decode(str1.translate(str.maketrans(string1,string2))))

这里是迷宫验证逻辑处

int __cdecl sub_411E30(char a1)
{
  unsigned int v1; // eax
  _BYTE *v2; // eax
  int i; // [esp+D4h] [ebp-40h]
  char v5[36]; // [esp+E0h] [ebp-34h] BYREF
  int v6; // [esp+110h] [ebp-4h]

  v6 = 0;
  sub_411406(v5, (char *)byte_41D94C);
  LOBYTE(v6) = 1;
  for ( i = 0; i < 44; ++i )
  {
    v1 = sub_4113ED(&a1);
    v2 = (_BYTE *)sub_411262(i % v1);
    sub_4114AB(byte_42024C[i] ^ *v2);
  }
  sub_4112C6(std::cout, "Congratulations!!! \nBut more than...");
  Sleep(0x989680u);
  sub_4112C6(std::cout, "Maybe there's something wrong with the front...");
  LOBYTE(v6) = 0;
  sub_41132F(v5);
  v6 = -1;
  return sub_41132F(&a1);
}

题目提示"Maybe there's something wrong with the front...",在验证成功的逻辑上方有个很奇怪的逻辑,因为byte_42024C全是0,但是要异或,而且找不到验证逻辑。但是交叉引用byte_42024C发现这个函数

int sub_411D80()
{
  int v0; // ecx
  int result; // eax
  int i; // [esp+D0h] [ebp-8h]

  for ( i = 1; i < 44; ++i )
    byte_420000[i] = byte_42024B[i] & 0xE0 | byte_42024C[i] & 0x1F;
  v0 = byte_420277 & 0xE0;
  result = v0 | byte_42024C[0] & 0x1F;
  byte_420000[0] = v0 | byte_42024C[0] & 0x1F;
  return result;
}

然而byte_420000 是有数据的,这里就可以求出byte_42024C

from z3 import *
enc = [0x0e,0x5D, 0x7D, 0x7D, 0x5D, 0x4E, 0x4E, 0x4E, 0x5D, 0x7D, 0x6B, 0x4B, 0x5D, 0x5D, 0x4E, 0x4E, 0x59,
0x59, 0x59, 0x59, 0x6B, 0x5D, 0x53, 0x24, 0x7B, 0x34, 0x07, 0x49, 0x01, 0x1B, 0x23, 0x27, 0x7E,
0x35, 0x3F, 0x12, 0x1B, 0x29, 0x32, 0x09, 0x16, 0x12, 0x60, 0x4A]
sb = [BitVec(f"sb[{i}]",8) for i in range(45)]
s = Solver()
for i in range(1,44):
    s.add(sb[i-1] & 0xe0 | sb[i] & 0x1f == enc[i]
print(s.check())
print(s.model())

由于最开始那儿有个异或,我们就可以把解出来的数据和那个地图迷宫路径异或

sb = [0] *44
sb[43] = 10
sb[0] = 64
sb[22] = 51
sb[13] = 93
sb[20] = 75
sb[33] = 53
sb[42] = 64
sb[14] = 78
sb[5] = 78
sb[3] = 93
sb[32] = 62
sb[34] = 31
sb[29] = 59
sb[17] = 89
sb[38] = 18
sb[16] = 89
sb[37] = 41
sb[26] = 71
sb[39] = 9
sb[2] = 125
sb[9] = 125
sb[11] = 75
sb[30] = 35
sb[31] = 103
sb[27] = 9
sb[21] = 93
sb[8] = 125
sb[19] = 121
sb[35] = 18
sb[12] = 93
sb[4] = 93
sb[28] = 1
sb[40] = 22
sb[23] = 100
sb[24] = 59
sb[10] = 75
sb[1] = 125
sb[25] = 20
sb[36] = 59
sb[41] = 114
sb[15] = 78
sb[7] = 78
sb[6] = 78
sb[18] = 89
flag = ""
maze = "dWWwwdddWWaawwddsssSaw"
for i in range(44):
    flag += chr(sb[i] ^ ord(maze[i % len(maze)]))
print(flag)
D0g3{Y0u^Can=So1ve_it!W3lc0me_t0_The_Maze!!}

 

localhost:2333

打开ida 一看start 就知道是UPX,先解开。

打开server_getflag 根据函数名和逻辑猜测此为输入和验证长度

image-20211128004749015

进入MainVM 观察虚拟机结构,发现这是一个基于栈的虚拟机

观察InitVM

image-20211128005117651

观察MainVM 这里根据code 调用了对应的函数

image-20211128005323198

观察每个函数 除了vm___ptr_register__sub_9 以外,F5的伪代码的前半部分完全一样

其实vm___ptr_register__sub_9 为比对算法

唯独最后几句,所以这几句是虚拟机的关键几句

如:vm___ptr_register__sub_2 的最后几句说明这是一个异或

image-20211128005536262

我们这里可以在gdb调试的时候断在此处,根据运算数据猜测加密算法

但是这里只有5个函数,这里的虚拟机指令似乎有8、9种,猜测其他的逻辑被内联了

这里是右移

image-20211128005940271

gdb 断在这些地方

image-20211128112206569

输入"012345678901234567890123456789" gdb 断下:观察寄存器

0-10的加密

image-20211128112709593

image-20211128112811658

>>> hex(0x30^0xff)
'0xcf'
>>> 0xcf - 0

根据多次断点发现RAXindex,下一轮异或值用到了前一轮的结果

10-20:

image-20211128113025944

0x47不知道哪儿来的,但是注意InitVM 初始化了GOL@nD~!!!,实际上就是和这个异或

20-30:

image-20211128113223419

image-20211128113317022

image-20211128113353401

>>> 0x30 >> 3 | (0x30 << 5 & 0xff)
6

exp:

enc = [0x9b, 0xaa, 0xcb, 0xf5, 0x8a, 0xc8, 0xa1, 0x89, 0xe0, 0xa5,
       0x7e, 0x10, 0x3a, 0x0d, 0x31, 0x75, 0x2d, 0x7e, 0x77, 0x64,
       0x4a, 0x2b, 0xeb, 0xac, 0x08, 0x84, 0x2b, 0x24, 0x24, 0xaf]
# xor_key = 0x217E446E404C4F47
xor_key = [0x47, 0x4f, 0x4c, 0x40, 0x6e, 0x44, 0x7e, 0x21, 0x21, 0x21]
magic_key = 0xff
flag = ""
for i in range(0, 10):
    if i == 0:
        magic_key = 0xff
    else:
        magic_key = enc[i - 1]
    raw = (enc[i] + i ^ magic_key)
    flag += chr(raw)
for i in range(10, 20):
    flag += chr(enc[i] ^ xor_key[i - 10])
# >> 3 << 5
for i in range(20, 30):
    flag += chr(enc[i] << 3 & 0xf8 | (enc[i] >> 5) & 0xff)
print(flag)
d0g3{Go1aN9_vM_1S_VERY_e@$Y!!}
分享到: QQ空间 新浪微博 微信 QQ facebook twitter
|推荐阅读
|发表评论
|评论列表
加载更多