BUUCTF reverse wp 51 - 55

news2024/11/25 18:55:05

findKey

在这里插入图片描述

shift + f12 找到一个flag{}字符串, 定位到关键函数, F5无效, 大概率是有花指令, 读一下汇编
在这里插入图片描述
在这里插入图片描述
这里连续push两个byte_428C54很奇怪, nop掉下面那个, 再往上找到函数入口, p设置函数入口, 再F5
在这里插入图片描述

LRESULT __stdcall sub_401640(HWND hWndParent, UINT Msg, WPARAM wParam, LPARAM lParam)
{
  int v5; // eax
  size_t v6; // eax
  DWORD v7; // eax
  int v8; // eax
  int v9; // eax
  CHAR *v10; // [esp+0h] [ebp-44Ch]
  CHAR v11[256]; // [esp+54h] [ebp-3F8h] BYREF
  char v12[7]; // [esp+154h] [ebp-2F8h] BYREF
  __int16 v13; // [esp+15Bh] [ebp-2F1h]
  char v14; // [esp+15Dh] [ebp-2EFh]
  char Str[253]; // [esp+160h] [ebp-2ECh] BYREF
  __int16 v16; // [esp+25Dh] [ebp-1EFh]
  char v17; // [esp+25Fh] [ebp-1EDh]
  CHAR v18[256]; // [esp+260h] [ebp-1ECh] BYREF
  CHAR String[4]; // [esp+360h] [ebp-ECh] BYREF
  int v20; // [esp+364h] [ebp-E8h]
  __int16 v21; // [esp+368h] [ebp-E4h]
  CHAR Text[32]; // [esp+36Ch] [ebp-E0h] BYREF
  struct tagRECT Rect; // [esp+38Ch] [ebp-C0h] BYREF
  CHAR Buffer[100]; // [esp+39Ch] [ebp-B0h] BYREF
  HDC hdc; // [esp+400h] [ebp-4Ch]
  struct tagPAINTSTRUCT Paint; // [esp+404h] [ebp-48h] BYREF
  int v27; // [esp+444h] [ebp-8h]
  int v28; // [esp+448h] [ebp-4h]

  LoadStringA(hInstance, 0x6Au, Buffer, 100);
  if ( Msg > 0x111 )
  {
    if ( Msg == 517 )
    {
      if ( strlen((const char *)String1) > 6 )
        ExitProcess(0);
      if ( strlen((const char *)String1) )
      {
        memset(v18, 0, sizeof(v18));
        v6 = strlen((const char *)String1);
        memcpy(v18, String1, v6);
        v7 = strlen((const char *)String1);
        sub_40101E(String1, v7, v10);
        strcpy(Str, "0kk`d1a`55k222k2a776jbfgd`06cjjb");
        memset(&Str[33], 0, 0xDCu);
        v16 = 0;
        v17 = 0;
        strcpy(v12, "SS");
        *(_DWORD *)&v12[3] = 0;
        v13 = 0;
        v14 = 0;
        v8 = strlen(Str);
        sub_401005(v12, (int)Str, v8);
        if ( _strcmpi((const char *)String1, Str) )
        {
          SetWindowTextA(hWndParent, "flag{}");
          MessageBoxA(hWndParent, "Are you kidding me?", "^_^", 0);
          ExitProcess(0);
        }
        memcpy(v11, &unk_423030, 0x32u);
        v9 = strlen(v11);
        sub_401005(v18, (int)v11, v9);
        MessageBoxA(hWndParent, v11, 0, 0x32u);
      }
      ++dword_428D54;
    }
    else
    {
      if ( Msg != 520 )
        return DefWindowProcA(hWndParent, Msg, wParam, lParam);
      if ( dword_428D54 == 16 )
      {
        strcpy(String, "ctf");
        v20 = 0;
        v21 = 0;
        SetWindowTextA(hWndParent, String);
        strcpy(Text, "Are you kidding me?");
        MessageBoxA(hWndParent, Text, Buffer, 0);
      }
      ++dword_428D54;
    }
  }
  else
  {
    switch ( Msg )
    {
      case 0x111u:
        v28 = (unsigned __int16)wParam;
        v27 = HIWORD(wParam);
        if ( (unsigned __int16)wParam == 104 )
        {
          DialogBoxParamA(hInstance, (LPCSTR)0x67, hWndParent, (DLGPROC)DialogFunc, 0);
        }
        else
        {
          if ( (unsigned __int16)wParam != 105 )
            return DefWindowProcA(hWndParent, Msg, wParam, lParam);
          DestroyWindow(hWndParent);
        }
        break;
      case 2u:
        PostQuitMessage(0);
        break;
      case 0xFu:
        hdc = BeginPaint(hWndParent, &Paint);
        GetClientRect(hWndParent, &Rect);
        v5 = strlen(Buffer);
        DrawTextA(hdc, Buffer, v5, &Rect, 1u);
        EndPaint(hWndParent, &Paint);
        break;
      default:
        return DefWindowProcA(hWndParent, Msg, wParam, lParam);
    }
  }
  return 0;
}

int __cdecl sub_4013A0(BYTE *pbData, DWORD dwDataLen, LPSTR lpString1)
{
  DWORD i; // [esp+4Ch] [ebp-24h]
  CHAR String2[4]; // [esp+50h] [ebp-20h] BYREF
  BYTE v6[16]; // [esp+54h] [ebp-1Ch] BYREF
  DWORD pdwDataLen; // [esp+64h] [ebp-Ch] BYREF
  HCRYPTHASH phHash; // [esp+68h] [ebp-8h] BYREF
  HCRYPTPROV phProv; // [esp+6Ch] [ebp-4h] BYREF

  if ( !CryptAcquireContextA(&phProv, 0, 0, 1u, 0xF0000000) )
    return 0;
  if ( CryptCreateHash(phProv, 0x8003u, 0, 0, &phHash) )
  {
    if ( CryptHashData(phHash, pbData, dwDataLen, 0) )
    {
      CryptGetHashParam(phHash, 2u, v6, &pdwDataLen, 0);
      *lpString1 = 0;
      for ( i = 0; i < pdwDataLen; ++i )
      {
        wsprintfA(String2, "%02X", v6[i]);
        lstrcatA(lpString1, String2);
      }
      CryptDestroyHash(phHash);
      CryptReleaseContext(phProv, 0);
      return 1;
    }
    else
    {
      CryptDestroyHash(phHash);
      CryptReleaseContext(phProv, 0);
      return 0;
    }
  }
  else
  {
    CryptReleaseContext(phProv, 0);
    return 0;
  }
}

发现string1会经过sub_4013A0中的hash处理, 查MSDN的文档
https://docs.microsoft.com/en-us/windows/win32/seccrypto/alg-id?redirectedfrom=MSDN

在这里插入图片描述
猜测是经过md5处理, 返回的值与0kk`d1a`55k222k2a776jbfgd`06cjjb ^ SS的结果比较

s = '0kk`d1a`55k222k2a776jbfgd`06cjjb'
key = 'SS'

md5val = ''
for i in range(len(s)):
    md5val += chr(ord(s[i]) ^ ord(key[i % 2]))

print(md5val)

查MD5, 得到解密真正flag的key == 123321

unsigned int __cdecl sub_401590(LPCSTR lpString, int a2, unsigned int a3)
{
  unsigned int result; // eax
  unsigned int i; // [esp+4Ch] [ebp-Ch]
  unsigned int v5; // [esp+54h] [ebp-4h]

  v5 = lstrlenA(lpString);
  for ( i = 0; ; ++i )
  {
    result = i;
    if ( i >= a3 )
      break;
    *(_BYTE *)(i + a2) ^= lpString[i % v5];
  }
  return result;
}

shift + e导出unk_423030数据, 写逆

enc = [
    87, 94, 82, 84, 73, 95, 1, 109, 105, 70, 
    2, 110, 95, 2, 108, 87, 91, 84, 76
]
key = "123321"
flag = ''

for i in range(len(enc)):
    flag += chr(enc[i] ^ ord(key[i % 6]))

print(flag)

firmware

$ file 51475f91-7b90-41dd-81a3-8b82df4f29d0.bin
51475f91-7b90-41dd-81a3-8b82df4f29d0.bin: firmware 941 v7 TP-LINK Technologies ver. 1.0, version 3.15.36, 4063744 bytes or less, at 0x200 772784 bytes , at 0x100000 2883584 bytes

$ binwalk -e 51475f91-7b90-41dd-81a3-8b82df4f29d0.bin

$ ls _51475f91-7b90-41dd-81a3-8b82df4f29d0.bin.extracted/
120200.squashfs  20400  20400.7z  squashfs-root

包含一个squashfs文件系统镜像, 需要使用firmware-mod-kit工具包内的unsquashfs_all.sh解压文件系统镜像
需要在linux里编译, 而且安装过程也比较坑, 嫌麻烦的直接上kali

git clone https://github.com/mirror/firmware-mod-kit.git
sudo apt-get install build-essential zlib1g-dev libz1zma-dev python-magic
cd firmware-mod-kit/src
./configure && make 

kali执行

sudo apt update
sudo apt upgrade
sudo apt install firmware-mod-kit

apt安装的软件, 可以用dpkg -L xxx显示安装路径, 然后用unsquashfs_all.sh解析文件系统

┌──(kali㉿kali)-[~/Desktop]
└─$ /opt/firmware-mod-kit/trunk/unsquashfs_all.sh 120200.squashfs 
Attempting to extract SquashFS 4.X file system...

Skipping squashfs-2.1-r2 (wrong version)...
Skipping squashfs-3.0 (wrong version)...
Skipping squashfs-3.0-lzma-damn-small-variant (wrong version)...
Skipping others/squashfs-2.0-nb4 (wrong version)...
Skipping others/squashfs-2.2-r2-7z (wrong version)...
Skipping others/squashfs-3.0-e2100 (wrong version)...
Skipping others/squashfs-3.2-r2 (wrong version)...
Skipping others/squashfs-3.2-r2-lzma (wrong version)...
Skipping others/squashfs-3.2-r2-lzma/squashfs3.2-r2/squashfs-tools (wrong version)...
Skipping others/squashfs-3.2-r2-hg612-lzma (wrong version)...
Skipping others/squashfs-3.2-r2-wnr1000 (wrong version)...
Skipping others/squashfs-3.2-r2-rtn12 (wrong version)...
Skipping others/squashfs-3.3 (wrong version)...
Skipping others/squashfs-3.3-lzma/squashfs3.3/squashfs-tools (wrong version)...
Skipping others/squashfs-3.3-grml-lzma/squashfs3.3/squashfs-tools (wrong version)...
Skipping others/squashfs-3.4-cisco (wrong version)...
Skipping others/squashfs-3.4-nb4 (wrong version)...

Trying ./src/others/squashfs-4.2-official/unsquashfs... Parallel unsquashfs: Using 4 processors

Trying ./src/others/squashfs-4.2/unsquashfs... Parallel unsquashfs: Using 4 processors

Trying ./src/others/squashfs-4.0-lzma/unsquashfs-lzma... Parallel unsquashfs: Using 4 processors
480 inodes (523 blocks) to write

[====================================================|        ] 454/523  86%
created 341 files
created 39 directories
created 70 symlinks
created 0 devices
created 0 fifos
File system sucessfully extracted!
MKFS="./src/others/squashfs-4.0-lzma/mksquashfs-lzma"

提取出文件系统中的内容后, 把各个目录翻一遍, 找到backdoor文件
在这里插入图片描述

查壳发现UPX
在这里插入图片描述

直接 kali 脱壳

┌──(kali㉿kali)-[~/Desktop/squashfs-root/tmp]
└─$ upx -d backdoor 
                       Ultimate Packer for eXecutables
                          Copyright (C) 1996 - 2020
UPX 3.96        Markus Oberhumer, Laszlo Molnar & John Reiser   Jan 23rd 2020

        File size         Ratio      Format      Name
   --------------------   ------   -----------   -----------
     54907 <-     19508   35.53%    linux/arm    backdoor

Unpacked 1 file.

拖进IDA

bool initConnection()
{
  char *v0; // r0
  char s[512]; // [sp+4h] [bp-208h] BYREF
  int v3; // [sp+204h] [bp-8h]

  memset(s, 0, sizeof(s));
  if ( mainCommSock )
  {
    close(mainCommSock);
    mainCommSock = 0;
  }
  if ( currentServer )
    ++currentServer;
  else
    currentServer = 0;
  strcpy(s, (&commServer)[currentServer]);
  v3 = 36667;
  if ( strchr(s, 58) )
  {
    v0 = strchr(s, 58);
    v3 = atoi(v0 + 1);
    *strchr(s, 58) = 0;
  }
  mainCommSock = socket(2, 1, 0);
  return connectTimeout(mainCommSock, s, v3, 30) == 0;
}

.data:0001B108 E4 19 01 00                   commServer DCD aEchoByethost51          ; DATA XREF: initConnection+8C↑o
.data:0001B108                                                                       ; .text:off_10C2C↑o
.data:0001B108                                                                       ; "echo.byethost51.com"

initConnection函数中进行链接建立操作, 可以分析出端口和地址

import hashlib

flag = hashlib.md5(b'echo.byethost51.com:36667')
print('flag{' + flag.hexdigest() + '}')

[网鼎杯 2020 青龙组]jocker

在这里插入图片描述

// positive sp value has been detected, the output may be wrong!
int __cdecl main(int argc, const char **argv, const char **envp)
{
  char Str[50]; // [esp+12h] [ebp-96h] BYREF
  char Destination[80]; // [esp+44h] [ebp-64h] BYREF
  DWORD flOldProtect; // [esp+94h] [ebp-14h] BYREF
  size_t v7; // [esp+98h] [ebp-10h]
  int i; // [esp+9Ch] [ebp-Ch]

  __main();
  puts("please input you flag:");
  if ( !VirtualProtect(encrypt, 0xC8u, 4u, &flOldProtect) )
    exit(1);
  scanf("%40s", Str);
  v7 = strlen(Str);
  if ( v7 != 24 )
  {
    puts("Wrong!");
    exit(0);
  }
  strcpy(Destination, Str);
  wrong(Str);
  omg(Str);
  for ( i = 0; i <= 186; ++i )
    *((_BYTE *)encrypt + i) ^= 0x41u;
  if ( encrypt(Destination) )
    finally(Destination);
  return 0;
}

char *__cdecl wrong(char *a1)
{
  char *result; // eax
  int i; // [esp+Ch] [ebp-4h]

  for ( i = 0; i <= 23; ++i )
  {
    result = &a1[i];
    if ( (i & 1) != 0 )
      a1[i] -= i;
    else
      a1[i] ^= i;
  }
  return result;
}

int __cdecl omg(char *str)
{
  int testval[24]; // [esp+18h] [ebp-80h] BYREF
  int i; // [esp+78h] [ebp-20h]
  int success; // [esp+7Ch] [ebp-1Ch]

  success = 1;
  qmemcpy(testval, &unk_4030C0, sizeof(testval));
  for ( i = 0; i <= 23; ++i )
  {
    if ( str[i] != testval[i] )
      success = 0;
  }
  if ( success == 1 )
    return puts("hahahaha_do_you_find_me?");
  else
    return puts("wrong ~~ But seems a little program");
}

wrongomg函数逻辑很简单, 测试的数组也是硬编码的, 不过逆回去之后会发现是假的flag, 所以关键处理逻辑就是encrypt函数了
main函数虽然SP不对, 但是IDA7.7可以直接F5, 大概看一下逻辑也能看懂, 只有encrypt函数不能反编译, 因为上面的for循环是做代码修改的, 可以IDAPython修改回去;
也可以动调然后dump出来
在这里插入图片描述

拿到dump得到exe, 拖进IDA分析encrypt

int __cdecl start(int a1)
{
  int v2[19]; // [esp+1Ch] [ebp-6Ch] BYREF
  int v3; // [esp+68h] [ebp-20h]
  int i; // [esp+6Ch] [ebp-1Ch]

  v3 = 1;
  qmemcpy(v2, &unk_403040, sizeof(v2));
  for ( i = 0; i <= 18; ++i )
  {
    if ( (char)(*(_BYTE *)(i + a1) ^ aHahahahaDoYouF[i]) != v2[i] )
    {
      puts("wrong ~");
      v3 = 0;
      exit(0);
    }
  }
  puts("come here");
  return v3;
}

就是和aHahahahaDoYouF数组进行xor, 直接REV

#include <iostream>
#include <string>
using namespace std;

unsigned char testvals[] =
{
   14,   0,   0,   0,  13,   0,   0,   0,   9,   0, 
    0,   0,   6,   0,   0,   0,  19,   0,   0,   0, 
    5,   0,   0,   0,  88,   0,   0,   0,  86,   0, 
    0,   0,  62,   0,   0,   0,   6,   0,   0,   0, 
   12,   0,   0,   0,  60,   0,   0,   0,  31,   0, 
    0,   0,  87,   0,   0,   0,  20,   0,   0,   0, 
  107,   0,   0,   0,  87,   0,   0,   0,  89,   0, 
    0,   0,  13,   0,   0,   0,   0,   0,   0,   0, 
    0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 
    0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 
    0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 
    0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 
    0,   0,   0,   0,   0,   0,   0,   0, 102,   0, 
    0,   0, 107,   0,   0,   0,  99,   0,   0,   0, 
  100,   0,   0,   0, 127,   0,   0,   0,  97,   0, 
    0,   0, 103,   0,   0,   0, 100,   0,   0,   0, 
   59,   0,   0,   0,  86,   0,   0,   0, 107,   0, 
    0,   0,  97,   0,   0,   0, 123,   0,   0,   0, 
   38,   0,   0,   0,  59,   0,   0,   0,  80,   0, 
    0,   0,  99,   0,   0,   0,  95,   0,   0,   0, 
   77,   0,   0,   0,  90,   0,   0,   0, 113,   0, 
    0,   0,  12,   0,   0,   0,  55,   0,   0,   0, 
  102,   0,   0,   0,   0,   0,   0,   0,   0,   0, 
    0,   0
};

int main() 
{
    char xorvals[] = "hahahaha_do_you_find_me?";
    string flag = "";
    for (int i = 0; i < 19; ++i)
    {
        flag += xorvals[i] ^ testvals[i * 4];
    }

    cout << flag << endl;
}

但是只有19位, 还差5位, 在dump出来的程序中再找找发现sub_40159A函数

int __cdecl sub_40159A(int a1)
{
  unsigned int v1; // eax
  char v3[9]; // [esp+13h] [ebp-15h] BYREF
  int v4; // [esp+1Ch] [ebp-Ch]

  strcpy(v3, "%tp&:");
  v1 = time(0);
  srand(v1);
  v4 = rand() % 100;
  v3[6] = 0;
  *(_WORD *)&v3[7] = 0;
  if ( (v3[(unsigned __int8)v3[5]] != *(_BYTE *)((unsigned __int8)v3[5] + a1)) == v4 )
    return puts("Really??? Did you find it?OMG!!!");
  else
    return puts("I hide the last part, you will not succeed!!!");
}

没啥固定逻辑, 剩下5位就摁猜, 因为知道最后一个字符是}, 然后v3 == "%tp&:", 盲猜也是xor, 而且':' ^ '}' == 71

#include <iostream>
#include <string>
using namespace std;

int main() 
{
    char xorvals[] = "\%tp&:";
    string flag = "flag{d07abccf8a410c";
    for (int i = 0; i < 5; ++i)
    {
        flag += xorvals[i] ^ 71;
    }

    cout << flag << endl;
}

[FlareOn5]Minesweeper Championship Registration

jadx打开, 看到InviteValidator

package defpackage;

import java.awt.Component;
import javax.swing.JOptionPane;

/* renamed from: InviteValidator  reason: default package */
public class InviteValidator {
    public static void main(String[] args) {
        String response = JOptionPane.showInputDialog((Component) null, "Enter your invitation code:", "Minesweeper Championship 2018", 3);
        if (response.equals("GoldenTicket2018@flare-on.com")) {
            JOptionPane.showMessageDialog((Component) null, "Welcome to the Minesweeper Championship 2018!\nPlease enter the following code to the ctfd.flare-on.com website to compete:\n\n" + response, "Success!", -1);
        } else {
            JOptionPane.showMessageDialog((Component) null, "Incorrect invitation code. Please try again next year.", "Failure", 0);
        }
    }
}

[羊城杯 2020]easyre

在这里插入图片描述

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // eax
  int v4; // eax
  int v5; // eax
  char Str[48]; // [rsp+20h] [rbp-60h] BYREF
  char Str1[64]; // [rsp+50h] [rbp-30h] BYREF
  char v9[64]; // [rsp+90h] [rbp+10h] BYREF
  char v10[64]; // [rsp+D0h] [rbp+50h] BYREF
  char Str2[60]; // [rsp+110h] [rbp+90h] BYREF
  int v12; // [rsp+14Ch] [rbp+CCh] BYREF

  _main();
  strcpy(Str2, "EmBmP5Pmn7QcPU4gLYKv5QcMmB3PWHcP5YkPq3=cT6QckkPckoRG");
  puts("Hello, please input your flag and I will tell you whether it is right or not.");
  scanf("%38s", Str);
  if ( strlen(Str) != 38
    || (v3 = strlen(Str), (unsigned int)encode_one(Str, v3, v10, &v12))
    || (v4 = strlen(v10), (unsigned int)encode_two(v10, v4, v9, &v12))
    || (v5 = strlen(v9), (unsigned int)encode_three(v9, v5, Str1, &v12))
    || strcmp(Str1, Str2) )
  {
    printf("Something wrong. Keep going.");
    return 0;
  }
  else
  {
    puts("you are right!");
    return 0;
  }
}

__int64 __fastcall encode_one(char *a1, int a2, char *a3, int *a4)
{
  int v5; // esi
  int v6; // esi
  int v7; // esi
  int v8; // [rsp+34h] [rbp-1Ch]
  int v9; // [rsp+38h] [rbp-18h]
  int v11; // [rsp+48h] [rbp-8h]
  int i; // [rsp+4Ch] [rbp-4h]
  unsigned __int8 *v13; // [rsp+70h] [rbp+20h]

  v13 = (unsigned __int8 *)a1;
  if ( !a1 || !a2 )
    return 0xFFFFFFFFi64;
  v11 = 0;
  if ( a2 % 3 )
    v11 = 3 - a2 % 3;
  v9 = a2 + v11;
  v8 = 8 * (a2 + v11) / 6;
  for ( i = 0; i < v9; i += 3 )
  {
    *a3 = alphabet[(char)*v13 >> 2];
    if ( a2 + v11 - 3 == i && v11 )
    {
      if ( v11 == 1 )
      {
        v5 = (char)cmove_bits(*v13, 6u, 2u);
        a3[1] = alphabet[v5 + (char)cmove_bits(v13[1], 0, 4u)];
        a3[2] = alphabet[(char)cmove_bits(v13[1], 4u, 2u)];
        a3[3] = 61;
      }
      else if ( v11 == 2 )
      {
        a3[1] = alphabet[(char)cmove_bits(*v13, 6u, 2u)];
        a3[2] = 61;
        a3[3] = 61;
      }
    }
    else
    {
      v6 = (char)cmove_bits(*v13, 6u, 2u);
      a3[1] = alphabet[v6 + (char)cmove_bits(v13[1], 0, 4u)];
      v7 = (char)cmove_bits(v13[1], 4u, 2u);
      a3[2] = alphabet[v7 + (char)cmove_bits(v13[2], 0, 6u)];
      a3[3] = alphabet[v13[2] & 0x3F];
    }
    a3 += 4;
    v13 += 3;
  }
  if ( a4 )
    *a4 = v8;
  return 0i64;
}

__int64 __fastcall encode_two(const char *a1, int a2, char *a3, int *a4)
{
  if ( !a1 || !a2 )
    return 0xFFFFFFFFi64;
  strncpy(a3, a1 + 26, 0xDui64);
  strncpy(a3 + 13, a1, 0xDui64);
  strncpy(a3 + 26, a1 + 39, 0xDui64);
  strncpy(a3 + 39, a1 + 13, 0xDui64);
  return 0i64;
}

__int64 __fastcall encode_three(const char *a1, int a2, char *a3, int *a4)
{
  char v5; // [rsp+Fh] [rbp-11h]
  int i; // [rsp+14h] [rbp-Ch]
  const char *v8; // [rsp+30h] [rbp+10h]

  v8 = a1;
  if ( !a1 || !a2 )
    return 0xFFFFFFFFi64;
  for ( i = 0; i < a2; ++i )
  {
    v5 = *v8;
    if ( *v8 <= '@' || v5 > 'Z' )
    {
      if ( v5 <= '`' || v5 > 'z' )
      {
        if ( v5 <= '/' || v5 > '9' )
          *a3 = v5;
        else
          *a3 = (v5 - '0' + 3) % 10 + '0';
      }
      else
      {
        *a3 = (v5 - 'a' + 3) % 26 + 'a';
      }
    }
    else
    {
      *a3 = (v5 - 'A' + 3) % 26 + 'A';
    }
    ++a3;
    ++v8;
  }
  return 0i64;
}

从后往前逆, encode_three是数字和字母移位置换3位, encode_two是每13位数据进行置换, encode_one是base64(看alphabet猜的)
REV

import base64

testval = 'EmBmP5Pmn7QcPU4gLYKv5QcMmB3PWHcP5YkPq3=cT6QckkPckoRG'
print(len(testval))
testval = list(testval)

for i in range(len(testval)):
    tmp = testval[i]
    if not str.isalnum(tmp): 
        continue
    if str.isalpha(tmp):
        if str.isupper(tmp):
            testval[i] = chr(((ord(tmp) - ord('A') - 3) % 26) + ord('A'))
        else:
            testval[i] = chr(((ord(tmp) - ord('a') - 3) % 26) + ord('a'))
    else:
        testval[i] = chr(((ord(tmp) - ord('0') - 3) % 10) + ord('0'))

print(''.join(testval))

tempval = [' ' for _ in range(52)]
tempval[13:26] = testval[39:]
tempval[39:] = testval[26:39]
tempval[:13] = testval[13:26]
tempval[26:39] = testval[:13]

print(tempval)
tempval = ''.join(tempval)
print(tempval)
flag = base64.b64decode(tempval.encode('utf-8'))
print(flag.decode('utf-8'))

注意 - 写脚本时踩的坑:
%的优先级大于+-;
python3解码base64时, 字符都为unicode编码, 而b64decode函数的参数为byte类型, 所以必须先转码.
还有如果用列表的切片赋值, 会出错, 原因在于浅拷贝, 比如

tempval = testval
testval[13:26] = tempval[39:]
testval[39:] = tempval[26:39]
testval[:13] = tempval[13:26]
testval[26:39] = tempval[:13]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1053606.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

顺序表(7.24)

1.线性表 线性表 &#xff08; linear list &#xff09; 是 n 个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构&#xff0c;常见的线性表&#xff1a;顺序表、链表、栈、队列、字符串... 线性表在逻辑上是线性结构&#xff0c;也就说是连续的一…

Docker+K3S搭建集群

本次环境使用的是阿里云资源服务器&#xff0c;Linux版本为Centos&#xff0c;集群需要安装Docker和k3s。 Docker下载&#xff1a;Docker(一) 安装Docker_CV猿码人的博客-CSDN博客 K3S 下载&#xff1a;k3s在线快速安装部署-CSDN博客 一、定制镜像 制作Tomcat镜像&#xff0c…

GeoServer扩展功能之发布矢量瓦片

目录 前言 一、矢量瓦片 VS 栅格瓦片 1、基本对比 2、适量瓦片处理步骤 二、GeoServer矢量瓦片插件配置 1、确定GeoServer版本 2、查找瓦片切片插件 3、下载 并安装插件 三、GeoServer发布矢量瓦片 1、矢量瓦片处理 2、如何进行数据预览 总结 前言 今天是10月1日国庆…

常用数学分布

正态分布&#xff08;高斯分布&#xff09; 若随机变数 X X X 服从一个期望 μ \mu μ&#xff0c;标准差 的正态分布 σ \sigma σ&#xff0c;则记为 X ≈ N ( μ , σ 2 ) X \approx N(\mu,\sigma^2) X≈N(μ,σ2)&#xff0c;其密度函数为&#xff1a; f ( x ) 1 σ …

JAVA 获得特定格式时间

0 背景 我们有时要获取时间&#xff0c;年月日时分秒周几&#xff0c;有时要以特定的格式出现。这时就要借助 SimpleDateFormat 或者 DateTimeFormatter。有时要某个月份有多少天需要借助 Calendar。所以有必要了解一些知识。 1 SimpleDateFormat simpledateFormat 线程不安全…

侯捷 C++ STL标准库和泛型编程 —— 4 分配器 + 5 迭代器

4 分配器 4.1 测试 分配器都是与容器共同使用的&#xff0c;一般分配器参数用默认值即可 list<string, allocator<string>> c1;不建议直接用分配器分配空间&#xff0c;因为其需要在释放内存时也要指明大小 int* p; p allocator<int>().allocate(512,…

图像处理: ImageKit.NET 3.0.10704 Crack

关于 ImageKit.NET3 100% 原生 .NET 图像处理组件。 ImageKit.NET 可让您快速轻松地向 .NET 应用程序添加图像处理功能。从 TWAIN 扫描仪和数码相机检索图像&#xff1b;加载和保存多种格式的图像文件&#xff1b;对图像应用图像滤镜和变换&#xff1b;在显示屏、平移窗口或缩略…

【大家的项目】通用规则引擎——Rush(一)可以自定义的规则引擎,告别发版,快速配置...

前言 很长一段时间在搞过增长和促销的事情&#xff0c;在实现各种活动和玩法时非常心累。每个新的玩法&#xff0c;都需要填一点代码&#xff0c;每次改动都需要走流水线发一次版&#xff0c;烦躁且痛苦。 对于这种&#xff0c;输入不确定&#xff0c;过程不确定&#xff0c;结…

uni-app:官方文档中的canvas实例剖析

效果 代码 <template><view><!-- 创建了一个宽度为300像素&#xff0c;高度为200像素的canvas元素。canvas-id属性被设置为"firstCanvas"&#xff0c;可以用来在JavaScript中获取该canvas元素的上下文对象。 --><canvas style"width: 30…

【python海洋专题三】图像修饰之画布和坐标轴

【python海洋专题三】图像修饰之画布和坐标轴 海洋与大气科学 上期读取nc水深文件&#xff0c;并出图 但是存在一些不完美&#xff0c;本期修饰 本期内容目录 1&#xff1a;改变画布大小 2&#xff1a;改变画布背景色 3&#xff1a;改变画布在显示屏中的显示位置 4&#xf…

建筑能源管理(3)——建筑能源监管

为了全面落实科学发展观&#xff0c;提高建筑能源管理水平&#xff0c;进一步降低能源和水资源消耗、合理利用资源&#xff0c;以政府办公建筑和大型公共建筑的运行节能管理为突破口&#xff0c;建立了既有政府办公建筑和大型公共建筑运行节能监管体系&#xff0c;旨在提高政府…

[python 刷题] 刷题常用函数

[python 刷题] 刷题常用函数 最近直到未来一段时间之内应该都会用 python 刷题了&#xff0c;所以记一下碰到的还蛮好用的方法 按照分区实现&#xff0c;基本上刷一个类型的题&#xff0c;了解一些常用函数&#xff0c;就更新一下 这里假设你对编程语言有一定的了解&#xf…

Python海洋专题七之Cartopy画地形水深图的陆地填充

Python海洋专题七之Cartopy画地形水深图的陆地填充 第一期图 本期&#xff1a; 上期 Cartopy画地形水深图 但是陆地没有填充 如图 本期内容 陆地填充 如图&#xff1a; 详细过程如下 1&#xff1a;陆地填充 land feature.NaturalEarthFeature(‘physical’, ‘land’…

如何在Qt6中引入Network模块

2023年10月1日&#xff0c;周日凌晨 如果用的是CMake find_package(Qt6 COMPONENTS Network REQUIRED) target_link_libraries(mytarget PRIVATE Qt6::Network) 但在实际使用中&#xff0c;我发现有以下几点要注意&#xff1a; 1、要把“mytarget”换成项目名称 2、要去掉…

指针巩固习题

1.该程序输出的结果为 #include<stdio.h> int main() {int arr[]{1,2,3,4,5};short *p(short*)arr;//转化类型int i0;for(i0;i<4;i){*(pi)0;//short型指针1跳过两个字节}for(i0;i<5;i){printf("%d",arr[i]);}return 0;} 2.程序的输出结果为 #include&…

oracle-使用PLSQL工具自行修改用户密码

1、使用PLSQL工具&#xff0c;输入用户名和原密码登录&#xff0c;如下图 2、登录后&#xff0c;在会话下拉菜单中找到”Change password..” 3、在跳出的窗口中配置新密码&#xff0c;修改完成后单击”确认”&#xff0c;后退出PLSQL 4、重新打开PLSQL&#xff0c;使用新密码登…

1. windows安装elasticSearch

目录 1. 下载 2. 安装和启动 1. 下载 下载地址&#xff1a;https://elasticsearch.cn/download/ 下载7.8.0版本&#xff1a; 下载后的elasticsearch-7.8.0-windows-x86_64.zip文件放在本地合适的位置。 2. 安装和启动 解压elasticsearch-7.8.0-windows-x86_64.zip文件&…

蜂蜜配送销售商城小程序的作用是什么

蜂蜜是农产品中重要的一个类目&#xff0c;其受众之广市场需求量大&#xff0c;但由于非人人必需品&#xff0c;因此传统线下门店经营也面临着痛点&#xff0c;线上入驻平台也有很多限制难以打造自有品牌&#xff0c;无法管理销售商品及会员、营销等&#xff0c;缺少自营渠道&a…

DirectX12_Windows_GameDevelop_1:向量代数

引言 向量在计算机图形学、碰撞检测和物理模拟中扮演者关键的角色。因此在游戏开发之前我们必须先了解向量。本章研究向量的使用。 一、向量 如果你对数学中的向量不太熟悉&#xff0c;建议阅读《3D数学基础&#xff1a;图形和游戏开发 第2版》&#xff0c;如果你需要某些PD…

敏感性分析一览

敏感性分析 SobolMorrisFourier Amplitude Sensitivity Test (FAST)Random Balance Designs - Fourier Amplitude Sensitivity Test (RBD-FAST)Delta Moment-Independent MeasureDerivative-based Global Sensitivity Measure (DGSM)Fractional Factorial Sensitivity Analysis…