Geekchallenge(2023)逆向方向wp

GeekChallenge_REVERSE Writeup


Shift_jmp | 简单花指令

将无条件跳转和loc_117Apatch为nop重构主函数

简单的异或加密 解题Python脚本如下

key = [83,  88,  65, 120,  83,  54, 106, 100,  56, 100, 
  111,  84, 120,  66,  81, 123, 120,  34,  77,  97, 
   39,  99, 115,  69,  45, 124,  69, 108,  44, 111, 
   47, 123,  94,  92]
for i in range(34):
  print(chr(key[i] ^ i ^ 0), end='')
#SYC{W3lc0me_tO_th3_r3veR5e_w0r1d~}

点击就送的逆向题 | C源码的编译

.s文件是由C源码编译而来的汇编指令 它与.S文件的区别是它不支持预处理(#define...) gcc编译器可以将其经过链接等再编译为可执行文件 故可以先将.s文件编译为可执行文件再用IDA分析

clang click.s -o click

Kali虚拟机预装的gcc编译器用以上指令可以直接将.s文件编译为Linux可执行文件

简单的位移加密 解题Python脚本如下

key = 'Z`J[X^LMNO`PPJPVQRSIUTJ]IMNOZKMM'
for each in key:
    print(chr(ord(each) - 7), end='')
# SYCTQWEFGHYIICIOJKLBNMCVBFGHSDFF

Easymath | z3-solver简单使用

Exinfo查到无壳 64位win程序 IDA64打开

  1. check函数逻辑简单 不分析(

  2. checkposition函数逻辑也简单 不分析(

  3. exchange函数

不理解 26行之前的代码作用 但是并不影响分析(

number在内存空间中每个有效元素之间插入三个0

与代码中的p_number[i] = number_[4 * v10]对应 最后一个循环的作用就是将字符在table中的位置映射到这些有效元素上

回到主函数 主要的比较逻辑就是经过映射后的position作为一个5阶方阵与另一个5阶方阵matrix用特殊的矩阵乘法法则相乘得到的矩阵与单位矩阵相比 以下是Python代码实现 其中n为矩阵的阶数

for i in range(n):
    for j in range(n):
        result[i][j] = 0
        for k in range(n):
            result[i][j] = (M1[i][k] * M2[k][j] + result[i][j]) % 0x20

除此之外主函数中还能看到为了防止出现多解给出的flag提示(动态调试时发现其为flag中的元素 重构为数组可以将变量名从内存地址变为数组) 可以使用爆破的方式解出flag 也可以使用z3-solver库解出

from z3 import *
table = '01234_asdzxcpoityumnbAOZWXGMY'
matrix  = [18, 29, 16, 19, 27, 
            8, 31,  8, 23, 30, 
           29,  3, 28, 10, 21, 
           18, 29,  8, 16, 28, 
           11, 30,  7, 20,  7]
v7      = [1, 0, 0, 0, 0, 
           0, 1, 0, 0, 0, 
           0, 0, 1, 0, 0, 
           0, 0, 0, 1, 0, 
           0, 0, 0, 0, 1]
num     = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 19, 22, 26, 27, 28, 29, 31, 32, 50, 51, 52, 53, 54, 55, 56]
for w in range(5):
    mysolver = Solver()
    position = IntVector('position', 5)
    if w == 0:
        mysolver.add(position[1] == 19)
    elif w == 1:
        mysolver.add(position[2] == 22)
    elif w == 3:
        mysolver.add(position[2] == 22)
    mysolver.add(And([Or([position[i] == val for val in num]) for i in range(5)]))
    for j in range(5):
        expr = IntVal(0)
        for k in range(5):
            expr = (expr + position[k] * matrix[5 * k + j]) % 0x20
        mysolver.add(expr == v7[5 * w + j])
    result = mysolver.check()
    if result == sat:
        m = mysolver.model()
        position_values = [m[position[i]].as_long() for i in range(5)]
        for each in position_values:
            print(table[num.index(each)], end='')
        #xtd4co_ymiunbbx3Aypsmbzii
    else:
        print('No solution')

需要注意的是 可以一次性爆破全部不确定的22个元素 但这样会使复杂度提升到29^22(我猜的) 而每一次运算只用到position中的一行元素 故可以一行一行地爆破 可以将复杂度降低到5*29^5(我猜的)所以选择一行一行爆破(z3学习笔记另写)

luck | 简单爆破

Exinfo查到无壳 64位win程序 IDA64打开

主函数定义了一个unsigned __int8类型地数组 这个数据类型的大小和char一样 qmemcpy(cmp_data, "\r\a", 2);这句实际上只将"\r\a"中地前两个字符复制到了cmp_data的末尾 数组名代表首元素地址 所以

cmp_data[0] = '\'

cmp_data[1] = 'r'

同理

"o96*#"添加到了cmp_data的第37个元素及之后

(其实最简单的方式是动态调试直接查看cmp_data中的数据)

主函数中的加密函数为用递归实现的等差数列求和

不管输入的数字是什么都会输出加密后的密文 根据flag前3个固定的字符爆破flag

key = [13,   7,  29]
for i in range(1000):
    result = int(i * (i + 1) / 2) % 0xD3
    if key[0] ^ (result) == ord('S') and key[1] ^ (result) == ord('Y') and key[2] ^ (result) == ord('C'):
        print(i)
        # 69
        break

在程序中输入数字得到flag

砍树 | 安卓逆向

主函数的逻辑很简单

就是调用一个函数传入输入的字符串和key 判断返回值 这个函数在ezreeee库中 导出这个库用IDA分析

在函数列表中检索I0o0I函数 传入的参数有4个 其中有2个是JNIEnvjobject JNI是为了让JAVA和C/C++互通构建的环境 jxxxxx是为了不与C原有的类型冲突 所以从下面的2个jstring_2unsigchar函数也可以看出a3a4分别为jeb伪代码中看到的两个参数与加密后的输入对比的是从内存0x14900中复制的35个字节型数据 以下是解密脚本

key = [0,  32,  32,  23,  27,  54,  14,  54,  38,  23, 
    4,  42,  41,   7,  38,  21,  82,  51,  45,  15, 
   58,  39,  17,   6,  51,   7,  70,  23,  61,  10, 
   60,  56,  46,  34,  24,   0,   0,   0,   0,   0, 
    0,   0,   0,   0,   0,   0,   0,   0]
to_mod = "Sycloverforerver"
i = 0
for each in key:
    print(chr(each ^ ord(to_mod[i % 7])), end='')
    i += 1
#SYC{t@ke_thE_bul1_By_the_h0rns_TAT}SycloveSyclov

听说cpp很难? | C++逆向

Exinfo查到无壳 64位win程序 IDA64打开 伪代码如下

int __cdecl main(int argc, const char **argv, const char **envp)
{
  __int64 v3; // rax
  unsigned __int64 v4; // rbx
  __int64 v5; // rax
  _BYTE *addr_nowChar; // rax
  unsigned int now_char; // ebx
  _BYTE *v8; // rsi
  int v9; // ebx
  int v10; // ebx
  __int64 v11; // rax
  __int64 v12; // rax
  __int64 m; // [rsp+20h] [rbp-60h] BYREF
  __int64 k; // [rsp+28h] [rbp-58h] BYREF
  char copy_flag[32]; // [rsp+30h] [rbp-50h] BYREF
  char be_encoded[48]; // [rsp+50h] [rbp-30h] BYREF
  _BYTE enc[32]; // [rsp+80h] [rbp+0h] BYREF
  int v19[40]; // [rsp+A0h] [rbp+20h] BYREF
  char input_flag[40]; // [rsp+140h] [rbp+C0h] BYREF
  __int64 v21; // [rsp+168h] [rbp+E8h] BYREF
  __int64 v22; // [rsp+170h] [rbp+F0h] BYREF
  unsigned int len; // [rsp+17Ch] [rbp+FCh]
  int v24; // [rsp+180h] [rbp+100h]
  int v25; // [rsp+184h] [rbp+104h]
  int j; // [rsp+188h] [rbp+108h]
  int i; // [rsp+18Ch] [rbp+10Ch]

  _main(argc, argv, envp);
  v3 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "place input your flag:");
  std::ostream::operator<<(v3, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
  std::string::basic_string(input_flag);
  memset(v19, 0, sizeof(v19));
  v19[0] = 0x4D;
  v19[1] = 0x5F;
  v19[2] = 0x3D;
  v19[3] = 0xFFFFFF85;
  v19[4] = 0x37;
  v19[5] = 0x68;
  v19[6] = 0x73;
  v19[7] = 0x57;
  v19[8] = 0x27;
  v19[9] = 0x68;
  v19[10] = 0x51;
  v19[11] = 0x59;
  v19[12] = 0x7F;
  v19[13] = 0x26;
  v19[14] = 0x6B;
  v19[15] = 0x59;
  v19[16] = 0x73;
  v19[17] = 0x57;
  v19[18] = 0x55;
  v19[19] = 0x5B;
  v19[20] = 0x59;
  v19[21] = 0x6F;
  v19[22] = 0x6A;
  v19[23] = 0x59;
  v19[24] = 0x27;
  v19[25] = 0x57;
  v19[26] = 0x72;
  v19[27] = 0x57;
  v19[28] = 0x4F;
  v19[29] = 0x57;
  v19[30] = 0x78;
  v19[31] = 0x78;
  v19[32] = 0xFFFFFF83;
  std::operator>><char>(refptr__ZSt3cin, input_flag);
  len = std::string::size(input_flag);
  std::vector<int>::vector(enc);
  for ( i = 0; ; ++i )
  {
    std::vector<int>::push_back(enc, &v19[i]);
    if ( i > 34 )
      break;
  }                                             // 复制v19到enc中
  encode::encode(be_encoded, len, input_flag, 10);// 
                                                // be_encoded[0]    = len(flag)
                                                // be_encoded[8...] = input_flag
                                                // be_encoded[40]   = 10
                                                // be_encoded[44]   = 10
  std::vector<char>::vector(copy_flag);
  for ( j = 0; ; ++j )
  {
    v4 = j;
    if ( v4 >= std::string::size(input_flag) )
      break;
    v5 = std::string::operator[](input_flag, j);// v5 = input_flag[j]
    std::vector<char>::push_back(copy_flag, v5);
  }
  v25 = 0;
  for ( k = std::vector<char>::begin(copy_flag);// for k in copy_flag
        ;
        __gnu_cxx::__normal_iterator<char *,std::vector<char>>::operator++(&k, 0i64) )
  {
    v21 = std::vector<char>::end(copy_flag);
    if ( !__gnu_cxx::operator!=<char *,std::vector<char>>(&k, &v21) )// 读到最后一个字符时退出
      break;
    addr_nowChar = __gnu_cxx::__normal_iterator<char *,std::vector<char>>::operator*(&k);
    *addr_nowChar += be_encoded[44];
    now_char = *__gnu_cxx::__normal_iterator<char *,std::vector<char>>::operator*(&k);
    v8 = __gnu_cxx::__normal_iterator<char *,std::vector<char>>::operator*(&k);
    *v8 = text_67(be_encoded, now_char);        // now_char += 10
                                                // now_char = (10 ^ now_char) - 10
                                                // now_char = v19[i]
  }
  v24 = 0;
  for ( m = std::vector<char>::begin(copy_flag);
        ;
        __gnu_cxx::__normal_iterator<char *,std::vector<char>>::operator++(&m, 0i64) )
  {
    v22 = std::vector<char>::end(copy_flag);
    if ( !__gnu_cxx::operator!=<char *,std::vector<char>>(&m, &v22) )
      break;
    v9 = *__gnu_cxx::__normal_iterator<char *,std::vector<char>>::operator*(&m);
    if ( v9 == *std::vector<int>::operator[](enc, v24) )
      ++v25;
    v10 = *__gnu_cxx::__normal_iterator<char *,std::vector<char>>::operator*(&m);
    if ( v10 != *std::vector<int>::operator[](enc, v24) )
      --v25;
    ++v24;
  }
  if ( v25 > 32 )                               // v25统计正确的字符
  {
    v11 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "yes yes you are right!");
    std::ostream::operator<<(v11, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
  }
  if ( v25 <= 32 )
  {
    v12 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "no try again~");
    std::ostream::operator<<(v12, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
  }
  std::vector<char>::~vector(copy_flag);
  encode::~encode(be_encoded);
  std::vector<int>::~vector(enc);
  std::string::~string(input_flag);
  return 0;
}

分析C++逆向时XXXXXXXoperatorxxx(a, b) 可以看作abxxx操作

其中的主要逻辑是先对be_encoded进行encode操作 进入查看

需要注意的是主函数中定义的be_encoded储存的数据长度为1byte 而C++中的双字类型长度为4bytes 所以其中的下标转化到原来的be_encoded中需要乘上4 text_67的逻辑很简单

__int64 __fastcall text_67(__int64 be_encoded, char now_char)
{
  *(be_encoded + 40) = 9;
  return (((*(be_encoded + 40) + 1) ^ now_char) - *(be_encoded + 40) - 1);
}

剩下的对比逻辑也很简单 以下是解密脚本

enc = [None] * 33
enc[0] = 77
enc[1] = 95
enc[2] = 61
enc[3] = 0x85
enc[4] = 55
enc[5] = 104
enc[6] = 115
enc[7] = 87
enc[8] = 39
enc[9] = 104
enc[10] = 81
enc[11] = 89
enc[12] = 127
enc[13] = 38
enc[14] = 107
enc[15] = 89
enc[16] = 115
enc[17] = 87
enc[18] = 85
enc[19] = 91
enc[20] = 89
enc[21] = 111
enc[22] = 106
enc[23] = 89
enc[24] = 39
enc[25] = 87
enc[26] = 114
enc[27] = 87
enc[28] = 79
enc[29] = 87
enc[30] = 120
enc[31] = 120
enc[32] = 0x83

for i in range(33):
    print(chr(((enc[i] + 10) ^ 10) - 10), end='')
# SYC{Anma1nG_y0u_maKe_it_1alaIa~~}

flower-or-tea | 简单花指令和TEA加密

Exinfo查到无壳 32位win程序 IDA32打开 伪代码如下

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char v4; // [esp+0h] [ebp-1B0h]
  char v5; // [esp+0h] [ebp-1B0h]
  char v6; // [esp+0h] [ebp-1B0h]
  char v7; // [esp+0h] [ebp-1B0h]
  int v8[40]; // [esp+Ch] [ebp-1A4h]
  unsigned int _54; // [esp+ACh] [ebp-104h]
  int v10; // [esp+B0h] [ebp-100h]
  char *v11; // [esp+B4h] [ebp-FCh]
  int lenth; // [esp+B8h] [ebp-F8h]
  char *v13; // [esp+BCh] [ebp-F4h]
  int j; // [esp+C0h] [ebp-F0h]
  int i; // [esp+C4h] [ebp-ECh]
  int v16[40]; // [esp+CCh] [ebp-E4h]
  int v17[4]; // [esp+16Ch] [ebp-44h] BYREF
  int v18; // [esp+17Ch] [ebp-34h] BYREF
  int v19; // [esp+180h] [ebp-30h]
  char input[40]; // [esp+184h] [ebp-2Ch] BYREF
  int v21; // [esp+1ACh] [ebp-4h]
  int savedregs; // [esp+1B0h] [ebp+0h] BYREF

  v17[0] = 32;
  v17[1] = 27;
  v17[2] = 39;
  v17[3] = 44;
  memset(input, 0, sizeof(input));
  print(&Format, v4);
  print(&byte_CA409C, v5);
  print(&byte_CA4090, v6);
  scanf(aS, input);
  v11 = &input[1];
  v13 = &input[strlen(input) + 1];
  v10 = v13 - &input[1];
  lenth = v13 - &input[1];
  _54 = 54;
  v16[0] = -1694939573;
  v16[1] = -1005078370;
  v16[2] = -1307072749;
  v16[3] = -918836760;
  v16[4] = -1795955634;
  v16[5] = -1244910923;
  v16[6] = 1146217516;
  v16[7] = 2055874714;
  v16[8] = 1405669384;
  v16[9] = 1846639433;
  v16[10] = -1677731948;
  v16[11] = 1593781753;
  v16[12] = 401024305;
  v16[13] = -541222535;
  v16[14] = -1886971078;
  v16[15] = 1944634796;
  v16[16] = -1299812186;
  v16[17] = 1526113129;
  v16[18] = 754440740;
  v16[19] = 880502447;
  v16[20] = -1178055328;
  v16[21] = -1860267729;
  v16[22] = -1118163045;
  v16[23] = -879332550;
  v16[24] = -979801922;
  v16[25] = -1610607639;
  v16[26] = -1053864284;
  v16[27] = -561628656;
  v16[28] = -1597713004;
  v16[29] = 1132501052;
  v16[30] = 2117039688;
  v16[31] = -447882103;
  v16[32] = 1059563152;
  v16[33] = -1249037927;
  v16[34] = 1615521047;
  v16[35] = -1668269692;
  v16[36] = -186628991;
  v16[37] = 1022684671;
  v16[38] = 0;
  v16[39] = 0;
  if ( v13 - &input[1] == 38 )                  // flag长度为38
  {
    if ( input[0] == 83 && input[1] == 89 && input[2] == 67 )
    {
      if ( input[3] == 123 && input[37] == 125 )
      {
        for ( i = 0; i < lenth / 2; ++i )
        {
          v18 = input[i];
          v19 = input[lenth - i - 1];
          sub_CA10C3(_54, &v18, v17);
          v8[2 * i] = v18;                      // 奇数元素
          v8[2 * i + 1] = v19;                  // 偶数元素
        }                                       // target:v8 = v16
        for ( j = 0; j < lenth && v8[j] == v16[j]; ++j )
          ;
        if ( j == lenth )
        {
          print(aYesYes, v7);
          system(aPause_1);
        }
        else
        {
          print(aWrong, v7);
          system(aPause_2);
        }
      }
      else
      {
        print(&byte_CA4060, v7);
        system(aPause_0);
      }
    }
    else
    {
      print(aFlag, v7);
      system(aPause_3);
    }
  }
  else
  {
    print(&byte_CA407C, v7);
    system(Command);
  }
  return sub_CA15D1(&savedregs ^ v21);
}

核心逻辑就是输入的数据加密后调换顺序并和v16比较 这个加密算法(sub_CA10C3)就是TEA加密 特点是没有数据丢失 可以逆向

需要注意的是传入的第二个参数是主函数中的&v18 打开v18栈中的位置 发现v19就是紧挨其的下一个

所以v5 = now_char[1];这句实际上取的是v19

另外一点需要注意的是数据的上限 unsigned int类型的数据最多储存4bytes 故每次执行都需要截去高32位

知道这些后就可以写出以下解密脚本

from z3 import *

key = [None] * 4
key[0] = 32
key[1] = 27
key[2] = 39
key[3] = 44

enc = [None] * 38
enc[0] = 0x9AF9464B
enc[1] = 0xC417B89E
enc[2] = 0xB217A713
enc[3] = 0xC93BA9E8
enc[4] = 0x94F3E44E
enc[5] = 0xB5CC2AB5
enc[6] = 0x4451E42C
enc[7] = 0x7A8A289A
enc[8] = 0x53C8D008
enc[9] = 0x6E117B49
enc[10] = 0x9BFFD794
enc[11] = 0x5EFF2DF9
enc[12] = 0x17E72531
enc[13] = 0xDFBD9979
enc[14] = 0x8F871B3A
enc[15] = 0x73E8C5AC
enc[16] = 0xB28670A6
enc[17] = 0x5AF6A369
enc[18] = 0x2CF7DA24
enc[19] = 0x347B66AF
enc[20] = 0xB9C84D60
enc[21] = 0x911E912F
enc[22] = 0xBD5A2F9B
enc[23] = 0xCB96733A
enc[24] = 0xC59968BE
enc[25] = 0xA00013E9
enc[26] = 0xC12F4EA4
enc[27] = 0xDE863A10
enc[28] = 0xA0C4D594
enc[29] = 0x4380983C
enc[30] = 0x7E2F7648
enc[31] = 0xE54DDC89
enc[32] = 0x3F27A690
enc[33] = 0xB58D3199
enc[34] = 0x604AE517
enc[35] = 0x9C903984
enc[36] = 0xF4E04481
enc[37] = 0x3CF4EDFF

flag = [None] * 38
lenth = 38

for i in range(19):
  flag[i] = enc[2 * i]
  flag[lenth - i - 1] = enc[2 * i + 1]
  delta = 54 * 0x31415927
  for _ in range(54):
    delta -= 0x31415927
    flag[i] -= (key[delta % 4] + delta) ^ (flag[lenth - i - 1] + ((flag[lenth - i - 1] >> 5) ^ (16 * flag[lenth - i - 1])))
    flag[i] &= 0xFFFFFFFF
    flag[lenth - i - 1] -= delta ^ (key[(delta >> 11) % 4] + delta) ^ (flag[i] + ((flag[i] >> 5) ^ (16 * flag[i])))
    flag[lenth - i - 1] &= 0xFFFFFFFF
for each in flag:
  print(chr(each), end='')
# SYC{D0_Yov_1ike_To_dRink_Flow3r_teA??}

rainbow | 控制流平坦化

关于去控制流平坦化参考 利用符号执行去除控制流平坦化 - 博客 - 腾讯安全应急响应中心

这里用别人的工具脚本去平坦化 去平坦化后的代码如下

由于判断无用块的方法是排除法(排除掉序言块,分发器,预处理块和返回块) 而原程序中退出并不使用return而是call exit 所以被判定为无用块被删除 故判断长度和flag不正确就退出的块被删去 观察原来的代码 剩下的代码就是加密后的flag和v8~v11的数据进行对比 解密脚本如下

key = [101,  88,  65, 142,  80,  68, 123,  98,  87,  74, 
  126,  84,  73, 108, 125, 132,  79,  91, 149,  96, 
   96, 100, 119,  72, 125,  77, 123, 159, 104,  60, 
   45,  98]
for i in range(32):
    key[i] ^= i
    key[i] -= 18 * (i % 3 == 0)
    print(chr(key[i]), end='')
# SYC{TAke_1t_3asy_Just_a_STart!!}

mySelf | 简单SMC

Exinfo查到无壳 32位win程序 IDA32打开

VirtualProtect函数给予一段内存地址(函数)修改自身字节码的权限 基本上是SMC的标志

如果不使用静态分析的方法可以直接动态调试 这样的可操作性高 在SMC的函数下断点 动态调试到断点处 F7步进函数 之后查看汇编代码 将SMC后的函数重新识别为函数再反编译为伪代码分析

unsigned int __cdecl encode(int a1)
{
  int v1; // ebx
  int v2; // edi
  unsigned int v3; // esi
  int v4; // ebx
  unsigned int result; // eax
  unsigned int *v6; // [esp+Ch] [ebp-Ch]
  unsigned int *v7; // [esp+10h] [ebp-8h]
  int v8; // [esp+14h] [ebp-4h]

  v1 = 0;
  v8 = 0;
  do
  {
    v2 = 0;
    v3 = *(_DWORD *)(a1 + 4 * v1);
    v7 = (unsigned int *)(a1 + 4 * v1);
    v6 = (unsigned int *)(a1 + 4 * (v1 + 1));
    v4 = 32;
    result = *v6;
    do
    {
      v2 -= 1640531527;
      v3 += ((result >> 5) + 2) ^ (16 * result + 2) ^ (v2 + result);
      result += ((v3 >> 5) + 4) ^ (16 * v3 + 3) ^ (v2 + v3);
      --v4;
    }
    while ( v4 );
    v8 += 2;
    v1 = v8;
    *v7 = v3;
    *v6 = result;
  }
  while ( v8 < 8 );
  return result;
}

又是一个TEA加密 但是其中用到了一个伪随机数 需要动态调试获得 这个TEA加密和上一题中的不同点是每次被加密的字符顺序不同 同时也要注意每次加密的数据长度是4bytes 而原来传入的是以1byte分割的数组的地址 而在x86程序中双字型数据使用小端序储存 知道了这些之后写出解密脚本

o_key = [0xF0, 0xF9, 0xBD, 0xBD, 0xC4, 0x94, 0x61, 0xE2, 0x25, 0x91, 
  0x79, 0x80, 0x19, 0xC2, 0x0F, 0x1F, 0x15, 0x18, 0x6A, 0xEB, 
  0xC5, 0x72, 0xF5, 0x84, 0x85, 0x3A, 0xCC, 0x40, 0xBB, 0x2A, 
  0xA3, 0xD2]
flag = []
for i in range(8):
    flag.append(o_key[4 * i] | o_key[4 * i + 1] << 8 | o_key[4 * i + 2] << 16 | o_key[4 * i + 3] << 24)
for i in range(4):
    v2 = 0x61C88647 * (-32)
    for _ in range(32):
        flag[2 * i + 1] -= ((flag[2 * i] >> 5) + 4) ^ (16 * flag[2 * i] + 3) ^ (v2 + flag[2 * i])
        flag[2 * i + 1] &= 0xFFFFFFFF
        flag[2 * i] -= ((flag[2 * i + 1] >> 5) + 2) ^ (16 * flag[2 * i + 1] + 2) ^ (v2 + flag[2 * i + 1])
        flag[2 * i] &= 0xFFFFFFFF
        v2 += 0x61C88647
for each in flag:
    for i in range(4):
        print(chr((each >> (8 * i)) & 0xFF), end='')

小黄鸭 | Python逆向

Exinfo 查到为Python3.7写的程序 可以先用pyinstxtractor将其反汇编生成.pyc文件 再用uncompyle6进行反编译生成.py文件

python pyinstxtractor.py duck.exe
uncompyle6.exe 1.pyc > duck.py

没有进行混淆

# --------duck.py----------
# uncompyle6 version 3.7.4
# Python bytecode 3.7 (3394)
# Decompiled from: Python 3.11.4 (tags/v3.11.4:d2340ef, Jun  7 2023, 05:45:37) [MSC v.1934 64 bit (AMD64)]
# Embedded file name: 1.py
import sys
arr = '~h|p4gs`gJdN`thPwR`jDn`te1w`2|RNH'
arr = list(arr)
print('快帮帮小黄鸭,找到它的钥匙')
a = input('请输入你找到的钥匙>:')
a = list(a)
if not ord(a[0]) != 83:
    if ord(a[1]) != 89 or ord(a[2]) != 67:
        print('不对喔~')
        sys.exit(0)
    a = a[::-1]
    b = []
    for i in range(len(a)):
        if a[i].isalpha():
            c = a[i]
            c = chr(ord(c) + 13 - 26 if ord(c) + 13 > (90 if c <= 'Z' else 122) else ord(c) + 13)
            b.append(chr(ord(c) + 2))
        else:
            b.append(chr(ord(a[i]) + 1))

    if chr(ord(a[1])) != 's' or ord(a[2]) != 109 or chr(ord(a[17])) != 'C':
        print('呀呀呀,怎么算出来不对呀?')
        sys.exit(0)
    cnt = 0
    for i in range(len(b)):
        if arr[i] == b[i]:
            cnt += 1

    if cnt == len(b):
        print('密码正确啦!!!,快去告诉小黄鸭吧~')
else:
    print('密码不对喔~,请再想想吧')
# okay decompiling 1.pyc

简单的ROT13加密 写出脚本解密

key_o = '~h|p4gs`gJdN`thPwR`jDn`te1w`2|RNH'
key_o = list(key_o)
key_o = key_o[::-1]
key = [ord(val) for val in key_o]
for each in key:
    if(chr(each - 2).isalpha()):
        c = each -2
        c += 13 if ord('a') <= c and c <= ord('m') or ord('A') <= c and c <= ord('M') else (-13)
        print(chr(c), end='')
    else:
        print(chr(each - 1), end='')
# SYC{1_h0pe_yOu_ChAse_YoUr_dr3ams} 我Chase你的梦!

浪漫至死不渝 | JS逆向

源码对变量名进行了混淆 去除混淆并对网页元素进行删去 得到主要逻辑

 let k={
     a:0,b:1,c:2,d:3,e:4,f:5,g:6,h:7,i:8,j:9,k:10,l:11,m:12,n:13,o:14,p:15,q:16,r:17,s:18,t:19,u:20,v:21,w:22,x:23,y:24,z:25,
     A:0,B:1,C:2,D:3,E:4,F:5,G:6,H:7,I:8,J:9,K:10,L:11,M:12,N:13,O:14,P:15,Q:16,R:17,S:18,T:19,U:20,V:21,W:22,X:23,Y:24,Z:25
 } 
 let a=[
     {name:"A",yin:7, str:,
     {name:"B" ,yin:24, str:,
     {name:"C" ,yin:1, str:,
     {name:"D" ,yin:4, str:,
     {name:"E" ,yin:5, str:,
     {name:"F" ,yin:2, str:,
     {name:"G" ,yin:6, str:,
     {name:"H" ,yin:5, str:,
     {name:"I" ,yin:8, str:,
     {name:"J" ,yin:3, str:,
     {name:"K" ,yin:9, str:,
     {name:"L" ,yin:8, str:,
     {name:"M" ,yin:11, str:,
     {name:"N" ,yin:3, str:,
     {name:"O" ,yin:7, str:,
     {name:"P" ,yin:14, str:,
     {name:"Q" ,yin:15, str:,
     {name:"R" ,yin:16, str:,
     {name:"S" ,yin:17, str:,
     {name:"T" ,yin:18, str:,
     {name:"U" ,yin:8, str:,
     {name:"V" ,yin:20, str:,
     {name:"W" ,yin:3, str:,
     {name:"X" ,yin:2, str:,
     {name:"Y" ,yin:23, str:,
     {name:"Z" ,yin:24, str:
 ];
  
let target_2=0;
let key = new Array(125, 130, 131, 122, 117, 110, 123, 125, 130, 131, 122, 117, 110, 123, 99, 99, 99, 99);
let s = "";
let target = false;

 function fl(e)
 {
     if(clickb==true)
     {
         const num_of_fence = 3;
         const fence_key = '53X211WH04N';		
         const Text1 = decryptRailFence(fence_key, num_of_fence);	//Text1 = '510321H4XWN'
        let key = e.key;
     if((key<='z'&&key>='a')||(key<='Z'&&key>='A'))
     {
         let p=a[k[key]];
         s += p.name;
         const intArr = [];
         for (let i = 0; i < s.length; i++)
         {
             const charCode = s.charCodeAt(i);
             intArr.push(charCode);				//intArr记录s中每个字符对应的ASCII值
         }
         if (s.length % 18 == 0)
         {
             let len = s.length / 18;
             for (let i = 0; i < len; i++)
             {
                 for (let control = 0; control < 18; control++)
                 {
                     if (control < 14)
                     {
                         intArr[i + control] ^= Text1.charCodeAt(control % 7);
                         intArr[i + control] += 10;
                     }
                     else
                     {
                         intArr[i+ control] ^= Text1.charCodeAt(control -7);
                         intArr[i + control] += 99;
                         }
                     }
            }
         for (let i = 0; i < s.length; i++)
         {
            let cnt = 0;
             if (intArr[i] == key[0])
             {
                 for (let control = 0; control < key.length && i+ control < intArr.length; control++)
                 {
                     if (intArr[i + control] == key[control])
                     {
                        cnt++;
                    }
                }
             }
             if (cnt >= 18) {
                target = true;
             break;
             }
         }
             
             
        }
         if(target&&target_2==0)
         {
             print "ok"
     }
     }  
 }

主要是先用栅栏密码对key进行加密 然后对输入逐位字符进行加密 写出解密脚本

key = [125, 130, 131, 122, 117, 110, 123, 125, 130, 131, 122, 117, 110, 123, 99, 99, 99, 99]
Text1 = '5201314WXHN'
for i in range(18):
    if i < 14:
        print(chr((key[i] - 10) ^ ord(Text1[i % 7])), end='')
    else:
        print(chr((key[i] - 99) ^ ord(Text1[i - 7])), end='')
# FJIAXUEFJIAXUEWXHN

寻找初音未来 | Go语言逆向 | 一坨go史

go语言所有的字符串在内存上都是连续的 所以对一个字符串对应的长度和偏移量非常重要

附件放到虚拟机中打开 发现提示输入初音未来色 上网搜索知道是39C5BB 用IDA打开 发现这个输入通过某些加密算法得到key

再用该key进行RC4加密直接动态调试得到key为CCCCCCCCCCCCCCCCCC 用python内置的RC4解密算法进行解密

from Crypto.Cipher import ARC4

ciphertext = b'\x25\x6F\x3D\x6C\xF9\xE0\xCF\x3F\x2E\x24\xC6\x7B\x81\xBF\x55\x4F\x0D\x99\x87\x47\x48\xF7\xB9\x98\xFB\x1B\x22\xEC\x84\x23\xFD\xB2'
key = b'CCCCCCCCCCCCCCCCCC'

cipher = ARC4.new(key)
plaintext = cipher.decrypt(ciphertext=ciphertext)

print(plaintext)

# b'SYC{N0thing_1s_sEriOus_But_MIku}'

AES! AES? | AES算法魔改

Exinfo查到无壳 64位win程序 IDA64打开 伪代码中看到核心加密逻辑是Shiftrow()transform()伪代码如下

void __fastcall ShiftRow(__int64 flag)
{
  int v1; // [rsp+0h] [rbp-10h]
  int j; // [rsp+4h] [rbp-Ch]
  int i; // [rsp+8h] [rbp-8h]
  int k; // [rsp+Ch] [rbp-4h]

  for ( i = 0; i <= 15; i += 4 )
  {
    for ( j = 0; j < i / 4; ++j )
    {
      v1 = *(4i64 * i + flag);
      for ( k = 0; k <= 2; ++k )
        *(4i64 * (i + k) + flag) = *(flag + 4 * (i + k + 1i64));
      *(4i64 * (i + k) + flag) = v1;
    }
  }
}
__int64 __fastcall tansform(__int64 flag)
{
  __int64 result; // rax
  unsigned __int8 v2; // dl
  int v3; // eax
  _DWORD *v4; // rcx
  int v5[20]; // [rsp+0h] [rbp-60h]
  int k; // [rsp+50h] [rbp-10h]
  int j; // [rsp+54h] [rbp-Ch]
  int i; // [rsp+58h] [rbp-8h]
  int v9; // [rsp+5Ch] [rbp-4h]

  v9 = 0;
  for ( i = 0; i <= 15; ++i )
  {
    result = i;
    v5[i] = *(4i64 * i + flag);
  }
  for ( j = 0; j <= 3; ++j )
  {
    for ( k = 0; k <= 3; ++k )
    {
      *(flag + 4i64 * v9) = v5[4 * k + j];
      v2 = S[*(4i64 * v9 + flag)];
      v3 = v9++;
      v4 = (flag + 4i64 * v3);
      result = v2;
      *v4 = v2;
    }
  }
  return result;
}
// 整体代码如下 其中还有一个异或加密 用来实现AES算法
int __cdecl main(int argc, const char **argv, const char **envp)
{
  char Str[48]; // [rsp+20h] [rbp-60h] BYREF
  int flag1[16]; // [rsp+50h] [rbp-30h] BYREF
  _BYTE flag2[96]; // [rsp+90h] [rbp+10h] BYREF
  char v7[8]; // [rsp+F0h] [rbp+70h] BYREF
  __int64 v8; // [rsp+F8h] [rbp+78h]
  int v9; // [rsp+100h] [rbp+80h]
  char v10[20]; // [rsp+110h] [rbp+90h] BYREF
  char v11[15]; // [rsp+124h] [rbp+A4h] BYREF
  char v12[13]; // [rsp+133h] [rbp+B3h] BYREF
  __int64 v13[3]; // [rsp+140h] [rbp+C0h] BYREF
  int v14; // [rsp+158h] [rbp+D8h]
  __int16 v15; // [rsp+15Ch] [rbp+DCh]
  char v16[16]; // [rsp+160h] [rbp+E0h] BYREF
  int v17[40]; // [rsp+170h] [rbp+F0h] BYREF
  char v18[176]; // [rsp+210h] [rbp+190h] BYREF
  __int16 v19; // [rsp+2C0h] [rbp+240h]
  char v20; // [rsp+2C2h] [rbp+242h]
  int v21; // [rsp+2C4h] [rbp+244h]
  int _32; // [rsp+2C8h] [rbp+248h]
  int i2; // [rsp+2CCh] [rbp+24Ch]
  int cnt; // [rsp+2D0h] [rbp+250h]
  int i1; // [rsp+2D4h] [rbp+254h]
  int nn; // [rsp+2D8h] [rbp+258h]
  int mm; // [rsp+2DCh] [rbp+25Ch]
  int jj; // [rsp+2E0h] [rbp+260h]
  int kk; // [rsp+2E4h] [rbp+264h]
  int ii; // [rsp+2E8h] [rbp+268h]
  int n; // [rsp+2ECh] [rbp+26Ch]
  int m; // [rsp+2F0h] [rbp+270h]
  int k; // [rsp+2F4h] [rbp+274h]
  int j; // [rsp+2F8h] [rbp+278h]
  int i; // [rsp+2FCh] [rbp+27Ch]

  (_main)(argc, argv, envp);
  memset(v18, 0, sizeof(v18));
  v19 = 0;
  v20 = 0;
  memset(v17, 0, sizeof(v17));
  v17[0] = 0xE0;
  v17[1] = 0xFFFFFF05;
  v17[2] = 0xFFFFFF6E;
  v17[3] = 0xFFFFFFC2;
  v17[4] = 0xFFFFFF6E;
  v17[5] = 0xFFFFFF99;
  v17[6] = 0xFFFFFF68;
  v17[7] = 0x45;
  v17[8] = 0xFFFFFF7D;
  v17[9] = 0xFFFFFF1F;
  v17[10] = 0xFFFFFF3F;
  v17[11] = 0xFFFFFFF9;
  v17[12] = 0xFFFFFF97;
  v17[13] = 0xFFFFFF76;
  v17[14] = 0x3B;
  v17[15] = 0x92;
  v17[16] = 0x2F;
  v17[17] = 0xFFFFFF44;
  v17[18] = 0xFFFFFF06;
  v17[19] = 0xFFFFFF67;
  v17[20] = 0xFFFFFFA8;
  v17[21] = 0xFFFFFFEB;
  v17[22] = 0xFFFFFFEC;
  v17[23] = 0x4A;
  v17[24] = 0xFFFFFF6F;
  v17[25] = 0xFFFFFFE8;
  v17[26] = 0xFFFFFF35;
  v17[27] = 0xFFFFFFF9;
  v17[28] = 0xFFFFFFAC;
  v17[29] = 0xFFFFFFA7;
  v17[30] = 0x8C;
  v17[31] = 0x71;
  qmemcpy(v16, "nyi", 3);
  v16[3] = -125;
  v16[4] = 121;
  v16[5] = 127;
  v16[6] = 105;
  v16[7] = 117;
  v16[8] = 121;
  v16[9] = 120;
  v16[10] = -127;
  v16[11] = 105;
  v16[12] = 93;
  v16[13] = 99;
  v16[14] = 77;
  v16[15] = 73;
  v13[0] = 0x78732A6F6D6B767Ai64;
  v13[1] = 0x7C7F79832A7E7F79i64;
  v13[2] = 0x142A44716B76702Ai64;
  v14 = 0;
  v15 = 0;
  v10[0] = -125;
  v10[1] = 111;
  v10[2] = 125;
  v10[3] = 43;
  v10[4] = 42;
  v10[5] = -125;
  v10[6] = 121;
  v10[7] = 127;
  v10[8] = 42;
  v10[9] = 107;
  v10[10] = 124;
  v10[11] = 111;
  v10[12] = 42;
  v10[13] = 124;
  v10[14] = 115;
  v10[15] = 113;
  v10[16] = 114;
  v10[17] = 126;
  v10[18] = 43;
  v10[19] = 20;
  qmemcpy(v11, "\nxy", 3);
  v11[3] = -120;
  v11[4] = 126;
  v11[5] = 124;
  v11[6] = -125;
  v11[7] = 42;
  v11[8] = 107;
  v11[9] = 113;
  v11[10] = 107;
  v11[11] = 115;
  v11[12] = 120;
  v11[13] = -120;
  v11[14] = 20;
  qmemcpy(v12, "\nxy", 3);
  v12[3] = -120;
  v12[4] = 10;
  for ( i = 0; i <= 23; ++i )
    *(v13 + i) -= 10;
  for ( j = 0; j <= 39; ++j )
    v10[j] -= 10;
  *v7 = 0i64;
  v8 = 0i64;
  v9 = 0;
  printf("%s", v13);
  scanf("%s", Str);
  _32 = strlen(Str);
  v21 = strlen(v7);
  if ( _32 != 32 )
  {
    printf("%s", &v12[1]);
    exit(0);
  }
  for ( k = 0; k <= 15; ++k )
  {
    v16[k] -= 10;
    v7[k] = v16[k];
  }
  if ( Str[5] != '.' || Str[10] != 'l' || Str[17] != '0' )
  {
    printf("%s", &v12[1]);
    exit(0);
  }
  for ( m = 0; m <= 15; ++m )
    v18[m] = v7[m];                             // v18 = do_you_konw_SYC?
  for ( n = 1; n <= 10; ++n )
  {
    for ( ii = 0; ii <= 31; ++ii )
      v18[16 * n + ii] = v18[16 * n - 16 + ii] ^ S[v18[16 * n - 16 + ii]];
  }
  HIBYTE(v19) = '9';
  kk = 0;
  for ( jj = 0; jj < _32; ++jj )
    flag1[jj] = S[Str[jj]];
  for ( kk = 0; kk <= 0; ++kk )
  {
    ShiftRow(flag1);                            // 将第n行的前(n - 1)个元素向右移动(5 - n)格
    ShiftRow(flag2);
    tansform(flag1);
    tansform(flag2);
    for ( mm = 0; mm <= 15; ++mm )
    {
      flag1[mm] ^= v18[16 * kk + mm];           // 将flag与key1异或
      flag1[mm + 16] ^= v18[16 * kk + mm];
    }
    for ( nn = 0; nn < _32; ++nn )
      flag1[nn] = S[flag1[nn]];                 // 将flag中的值替换为S中以flag的值为索引的值
  }
  ShiftRow(flag1);
  ShiftRow(flag2);
  for ( i1 = 0; i1 <= 15; ++i1 )                // 将flag与key2异或
  {
    flag1[i1] ^= v18[16 * kk + i1];
    flag1[i1 + 16] ^= v18[16 * kk + i1];
  }
  cnt = 0;
  for ( i2 = 0; i2 <= 31; ++i2 )
  {
    if ( flag1[i2] == v17[i2] )
      ++cnt;
  }
  if ( cnt <= 31 )
    printf("%s", &v11[1]);
  else
    printf("%s", v10);
  return 0;
}

据此写出解密脚本

S = [0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 
  0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D, 
  0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 
  0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 
  0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 0x04, 0xC7, 
  0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 
  0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 
  0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 
  0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 
  0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 0xD0, 0xEF, 0xAA, 0xFB, 
  0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 
  0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 
  0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 
  0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 
  0x64, 0x5D, 0x19, 0x73, 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 
  0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 
  0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 
  0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D, 
  0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 
  0xAE, 0x08, 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 
  0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 
  0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 
  0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 
  0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 
  0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 
  0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16]
key_ = "do_you_konw_SYC?"
v17 = [None] * 32
v17[0] = 0xE0
v17[1] = 0x05
v17[2] = 0x6E
v17[3] = 0xC2
v17[4] = 0x6E
v17[5] = 0x99
v17[6] = 0x68
v17[7] = 0x45
v17[8] = 0x7D
v17[9] = 0x1F
v17[10] = 0x3F
v17[11] = 0xF9
v17[12] = 0x97
v17[13] = 0x76
v17[14] = 0x3B
v17[15] = 0x92
v17[16] = 0x2F
v17[17] = 0x44
v17[18] = 0x06
v17[19] = 0x67
v17[20] = 0xA8
v17[21] = 0xEB
v17[22] = 0xEC
v17[23] = 0x4A
v17[24] = 0x6F
v17[25] = 0xE8
v17[26] = 0x35
v17[27] = 0xF9
v17[28] = 0xAC
v17[29] = 0xA7
v17[30] = 0x8C
v17[31] = 0x71

def shift_row(flag:list) -> list:
  for i in range(0, 4):
    for _ in range(i):
        for k in range(3):
            flag[4 * i + 3 - k], flag[4 * i + 3 - k - 1] = flag[4 * i + 3 - k - 1], flag[4 * i + 3 - k]
  return flag


key1 = []
for each in key_:
  key1.append(ord(each) & 0xFF)
key2 = []
for i in range(16):
  key2.append(key1[i] ^ S[key1[i]] & 0xFF)

flag_after = []
for i in range(32):
  temp = v17[i] ^ key2[i % 0x10]
  flag_after.append(temp)

flag  = shift_row(flag_after[0 :16])
flag += shift_row(flag_after[16:32])

for i in range(32):
  flag[i] = S.index(flag[i])
  flag[i] ^= key1[i % 0x10]

flag1 = [None] * 16
flag2 = [None] * 16
cnt = 0
for i in range(4):
  for j in range(4):
    flag1[4 * j + i] = S.index(flag[cnt])
    cnt += 1
for i in range(4):
  for j in range(4):
    flag2[4 * j + i] = S.index(flag[cnt])
    cnt += 1

flag_last  = shift_row(flag1)
flag_last += shift_row(flag2)

for each in flag_last:
  t = S.index(each)
  try:
    print(chr(t), end='')
  except:
    pass
# SYC{0.o_Thls_1s_n0t_A3s_(q^_^p)}

另外 不要手抄key不要手抄key不要手抄key不要手抄key不要手抄key不要手抄key不要手抄key不要手抄key不要手抄key不要手抄key

ezandroid | 安卓逆向

apk用jeb打开 有两个主要活动如下

package com.example.babyapk_1;

import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.view.View.OnClickListener;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import b.f;

public class MainActivity extends f {
    public class b {
        public int[] a;

        public b() {
            this.a = new int[]{2023708229, -158607964, 0x81963FFA, 0x458FAC58};
        }
    }

    public EditText o;

    @Override  // b.f
    public void onCreate(Bundle bundle0) {
        new Handler();
        super.onCreate(bundle0);
        this.setContentView(0x7F0B001C);  // layout:activity_main
        Button button0 = (Button)this.findViewById(0x7F080057);  // id:button
        this.o = (EditText)this.findViewById(0x7F080097);  // id:edit_text
        button0.setOnClickListener(new View.OnClickListener() {
            @Override  // android.view.View$OnClickListener
            public void onClick(View view0) {
                String s = MainActivity.this.o.getText().toString();
                if(s.length() > 24) {
                    MainActivity.this.o.setText("");
                    s = MainActivity.this.o.getText().toString();
                }

                if(((s.length() == 0 ? 1 : 0) | (s.length() % 24 == 0 ? 0 : 1)) != 0) {
                    int v = 24 - s.length() % 24;
                    StringBuilder stringBuilder0 = new StringBuilder(s);
                    for(int v1 = 0; v1 < v; ++v1) {
                        stringBuilder0.append('X');
                    }

                    s = stringBuilder0.toString();
                }

                StringBuilder stringBuilder1 = new StringBuilder();
                StringBuilder stringBuilder2 = new StringBuilder();
                for(int v2 = 0; v2 < s.length(); ++v2) {
                    if(v2 % 2 == 0) {
                        stringBuilder1.append(s.charAt(v2));
                    }
                    else {
                        stringBuilder2.append(s.charAt(v2));
                    }
                }

                b mainActivity$b0 = new b(MainActivity.this);
                String s1 = stringBuilder2.toString();
                byte[] arr_b = stringBuilder1.toString().getBytes();
                int v3 = arr_b.length >> 2;
                int[] arr_v = new int[v3];
                int v5 = 0;
                for(int v4 = 0; v4 < arr_b.length; v4 += 4) {
                    int v6 = arr_b[v4 + 3];
                    if(v6 < 0) {
                        v6 += 0x100;
                    }

                    int v7 = arr_b[v4 + 2];
                    if(v7 < 0) {
                        v7 += 0x100;
                    }

                    int v8 = arr_b[v4 + 1];
                    if(v8 < 0) {
                        v8 += 0x100;
                    }

                    arr_v[v5] = v6 | v7 << 8 | v8 << 16 | arr_b[v4] << 24;
                    ++v5;
                }

                int v9 = arr_v[0];
                int v10 = arr_v[1];
                int v11 = arr_v[2];
                int[] arr_v1 = mainActivity$b0.a;
                int key_0 = arr_v1[0];
                int key_1 = arr_v1[1];
                int key_2 = arr_v1[2];
                int key_3 = arr_v1[3];
                int v16 = 0;
                for(int v17 = 0; v17 < 0x20; ++v17) {
                    v16 += -1640531527;
                    v9 += (v10 << 4) + key_0 ^ v10 + v16 ^ (v10 >> 5) + key_1;
                    v10 += (v9 << 4) + key_2 ^ v9 + v16 ^ (v9 >> 5) + key_3;
                }

                arr_v[0] = v9;
                for(int v18 = 0; v18 < 0x20; ++v18) {
                    v16 += -1640531527;
                    v11 += (v10 << 4) + key_0 ^ v10 + v16 ^ (v10 >> 5) + key_1;
                    v10 += (v11 << 4) + key_2 ^ v11 + v16 ^ (v11 >> 5) + key_3;
                }

                arr_v[1] = v11;
                arr_v[2] = v10;
                byte[] arr_b1 = new byte[v3 << 2];
                int v20 = 0;
                for(int v19 = 0; v19 < v3; ++v19) {
                    arr_b1[v20 + 3] = (byte)(arr_v[v19] & 0xFF);
                    arr_b1[v20 + 2] = (byte)(arr_v[v19] >> 8 & 0xFF);
                    arr_b1[v20 + 1] = (byte)(arr_v[v19] >> 16 & 0xFF);
                    arr_b1[v20] = (byte)(arr_v[v19] >> 24 & 0xFF);
                    v20 += 4;
                }

                for(int v21 = 0; v21 < new byte[]{-91, -8, -110, -55, -49, 75, 0x73, 13, -76, (byte)0x8F, 102, 80}.length; ++v21) {
                    System.out.println(((int)arr_b1[v21]));
                }

                int v23 = 1;
                for(int v22 = 0; true; ++v22) {
                    byte[] arr_b2 = new byte[]{-91, -8, -110, -55, -49, 75, 0x73, 13, -76, (byte)0x8F, 102, 80};
                    if(v22 >= arr_b2.length) {
                        break;
                    }

                    if(arr_b1[v22] != arr_b2[v22]) {
                        Toast.makeText(MainActivity.this, "You\'re Wrong!\n", 0).show();
                        v23 = 0;
                    }
                }

                Intent intent0 = new Intent(MainActivity.this, MainActivity2.class);
                intent0.putExtra("ad@#E!@a123", s1);
                intent0.putExtra("eCAS213@!@3", arr_b1);
                if(v23 == 1) {
                    MainActivity.this.startActivity(intent0);
                }
            }
        });
    }
}
package com.example.babyapk_1;

import android.content.Intent;
import android.os.Bundle;
import android.widget.Toast;
import b.f;

public class MainActivity2 extends f {
    @Override  // b.f
    public void onCreate(Bundle bundle0) {
        super.onCreate(bundle0);
        this.setContentView(0x7F0B001D);  // layout:activity_main2
        Intent intent0 = this.getIntent();
        byte[] arr_b = intent0.getStringExtra("ad@#E!@a123").getBytes();
        byte[] arr_b1 = intent0.getByteArrayExtra("eCAS213@!@3");
        int v1 = 1;
        for(int v = 0; v < arr_b1.length; ++v) {
            arr_b1[v] = (byte)(arr_b1[v] ^ arr_b[v % arr_b.length]);
            if(arr_b1[v] != new int[]{-107, -106, 0xFFFFFFA1, 0xFFFFFF8D, 0xFFFFFF89, 0x7F, 26, 0x79, -62, -20, 86, 9}[v]) {
                Toast.makeText(this, "N0T Right,Maybe try more harder?\n", 0).show();
                v1 = 0;
            }
        }

        if(v1 == 1) {
            Toast.makeText(this, "Congratulations!", 1).show();
        }
    }
}

当MainActivity1中的匹配通过后才会进行MainActivity2的另一部分加密 主要是分奇偶索引进行TEA或异或加密 据此写出解密脚本

#include<stdio.h>

int main(){
    unsigned char arr_even[12] = {-107, -106, 0xFFFFFFA1, 0xFFFFFF8D, 0xFFFFFF89, 0x7F, 26, 0x79, -62, -20, 86, 9};
    unsigned char key_even[12] = {-91, -8, -110, -55, -49, 75, 0x73, 13, -76, 0x8F, 102, 80};
    char flag_even[12];
    for(int i = 0; i < 12; i++){
        flag_even[i] = arr_even[i] ^ key_even[i];
    }
    int flag_odd_[3];
    for(int i = 0; i < 12; i += 4){
        flag_odd_[(int)(i / 4)] = key_even[i + 3] | key_even[i + 2] << 8 | key_even[i + 1] << 16 | key_even[i] << 24;
    }
    int TEA_key[4] = {2023708229, -158607964, 0x81963FFA, 0x458FAC58};
    int delta = -1640531527 * 0x40;
    for(int i = 0; i < 0x20; i++){
        flag_odd_[2] -= (flag_odd_[1] << 4) + TEA_key[2] ^ flag_odd_[1] + delta ^ (flag_odd_[1] >> 5) + TEA_key[3];
        flag_odd_[1] -= (flag_odd_[2] << 4) + TEA_key[0] ^ flag_odd_[2] + delta ^ (flag_odd_[2] >> 5) + TEA_key[1];
        delta += 1640531527;
    }
    for(int i = 0; i < 0x20; i++){
        flag_odd_[2] -= (flag_odd_[0] << 4) + TEA_key[2] ^ flag_odd_[0] + delta ^ (flag_odd_[0] >> 5) + TEA_key[3];
        flag_odd_[0] -= (flag_odd_[2] << 4) + TEA_key[0] ^ flag_odd_[2] + delta ^ (flag_odd_[2] >> 5) + TEA_key[1];
        delta += 1640531527;
    }
    unsigned char flag_odd[12];
    for(int i = 3; i >= 0; i--){
        flag_odd[3 - i] = (flag_odd_[0] >> i * 8);
    }
    for(int i = 3; i >= 0; i--){
        flag_odd[7 - i] = (flag_odd_[2] >> i * 8);
    }
    for(int i = 3; i >= 0; i--){
        flag_odd[11 - i] = (flag_odd_[1] >> i * 8);
    }
    printf("SYC{");
    for(int i = 0; i < 24; i++){
        if(i % 2 == 0){
            printf("%c",  flag_odd[(int)(i / 2)]);
        }
        else{
            printf("%c", flag_even[(int)(i / 2)]);
        }
    }
    printf("}");
    // SYC{T00nV3tD3F34Tint0vict0rY}
    return 0;
}

是男人就来扎针 | Unity引擎游戏逆向

Unity引擎游戏的控制逻辑一般存放在.\*_Data\Managed\Assembly-CSharp.dll中 用dnspy打开 主要逻辑如下

using System;
using System.Collections;
using System.Security.Cryptography;
using System.Text;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

// Token: 0x02000002 RID: 2
public class GameManager : MonoBehaviour
{
	// Token: 0x06000002 RID: 2 RVA: 0x000020A9 File Offset: 0x000004A9
	public static string RemoveDash(string str)
	{
		str = str.Replace("-", string.Empty);
		return str;
	}

	// Token: 0x06000003 RID: 3 RVA: 0x000020C0 File Offset: 0x000004C0
	public static string what(string str)
	{
		MD5 md = MD5.Create();
		byte[] bytes = Encoding.Default.GetBytes(str);
		byte[] value = md.ComputeHash(bytes);
		return GameManager.RemoveDash(BitConverter.ToString(value));
	}

	// Token: 0x06000004 RID: 4 RVA: 0x000020F4 File Offset: 0x000004F4
	private void Start()
	{
		this.startPoint = GameObject.Find("StartPoint").transform;
		this.spawnPoint = GameObject.Find("SpawnPoint").transform;
		this.mainCamera = Camera.main;
		this.SpawnPin();
	}

	// Token: 0x06000005 RID: 5 RVA: 0x00002134 File Offset: 0x00000534
	private void Update()
	{
		if (this.score == 30)
		{
			string text = string.Empty;
			for (int i = 0; i < this.magicc.Length; i++)
			{
				char c = (char)this.magicc[i];
				text += c;
			}
			this.flagText.text = text;
			this.nothing += GameManager.what(this.flagText.text);
			this.nothing += '\0';
		}
		if (this.score == 40)
		{
			string text2 = string.Empty;
			for (int j = 0; j < this.magic.Length; j++)
			{
				char c2 = (char)this.magic[j];
				text2 += c2;
			}
			this.flagText.text = text2;
			text2 += '\0';
		}
		if (this.score == 100)
		{
			this.scoreText.text = "!";
			this.flagText.text = this.nothing;
		}
		if (this.isGameOver)
		{
			return;
		}
		if (Input.GetMouseButtonDown(0))
		{
			this.score++;
			this.scoreText.text = this.score.ToString();
			this.currentPin.StartFly();
			this.SpawnPin();
			for (int k = 0; k < this.magicc.Length; k++)
			{
				this.magicc[k] ^= this.score;
				this.magic[k] ^= this.score;
			}
		}
	}

	// Token: 0x06000006 RID: 6 RVA: 0x000022F6 File Offset: 0x000006F6
	private void SpawnPin()
	{
		this.currentPin = UnityEngine.Object.Instantiate<GameObject>(this.pinPrefab, this.spawnPoint.position, this.pinPrefab.transform.rotation).GetComponent<Pin>();
	}

	// Token: 0x06000007 RID: 7 RVA: 0x00002329 File Offset: 0x00000729
	public void GameOver()
	{
		if (this.isGameOver)
		{
			return;
		}
		GameObject.Find("Circle").GetComponent<RotateSelf>().enabled = false;
		base.StartCoroutine(this.GameOverAnimation());
		this.isGameOver = true;
	}

	// Token: 0x06000008 RID: 8 RVA: 0x00002360 File Offset: 0x00000760
	private IEnumerator GameOverAnimation()
	{
		for (;;)
		{
			this.mainCamera.backgroundColor = Color.Lerp(this.mainCamera.backgroundColor, Color.red, this.speed * Time.deltaTime);
			this.mainCamera.orthographicSize = Mathf.Lerp(this.mainCamera.orthographicSize, 4f, this.speed * Time.deltaTime);
			if (Mathf.Abs(this.mainCamera.orthographicSize - 4f) < 0.01f)
			{
				break;
			}
			yield return 0;
		}
		yield return new WaitForSeconds(0.2f);
		SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
		yield break;
	}

	// Token: 0x04000001 RID: 1
	private Transform startPoint;

	// Token: 0x04000002 RID: 2
	private Transform spawnPoint;

	// Token: 0x04000003 RID: 3
	private Pin currentPin;

	// Token: 0x04000004 RID: 4
	private bool isGameOver;

	// Token: 0x04000005 RID: 5
	private int score;

	// Token: 0x04000006 RID: 6
	private Camera mainCamera;

	// Token: 0x04000007 RID: 7
	private string nothing = string.Empty;

	// Token: 0x04000008 RID: 8
	private int[] magicc = new int[]
	{
		75,
		109,
		102,
		63,
		107,
		112,
		63,
		108,
		124,
		112,
		109,
		122,
		63,
		43,
		47,
		63,
		111,
		112,
		118,
		113,
		107,
		108,
		62
	};

	// Token: 0x04000009 RID: 9
	private int[] magic = new int[]
	{
		124,
		90,
		81,
		8,
		92,
		71,
		8,
		90,
		77,
		73,
		75,
		64,
		8,
		25,
		24,
		24,
		8,
		88,
		71,
		65,
		70,
		92,
		91,
		9
	};

	// Token: 0x0400000A RID: 10
	public Text scoreText;

	// Token: 0x0400000B RID: 11
	public Text flagText;

	// Token: 0x0400000C RID: 12
	public GameObject pinPrefab;

	// Token: 0x0400000D RID: 13
	public float speed = 3f;
}

可以看到游戏前30次每刷新一次分数就会与明文进行异或 最后进行md5加密然后在分数达到100时显示 显然不可能点到100 但是可以先点到30 再用CE改到100 写出解密脚本

import hashlib
key = [ 75, 109, 102, 63, 107, 112, 63, 108, 124, 112, 109, 122, 63, 43, 47, 63, 111, 112, 118, 113, 107, 108, 62]
convt = hashlib.md5()
for i in range(1, 31):
    for j in range(len(key)):
        key[j] ^= i
flag = ''
for each in key:
    flag += chr(each)
convt.update(flag.encode())
print(convt.hexdigest().upper())
# CBDDD133B60130856D3C695D9E5ED6A5

babycode | 不知道什么加密

IDA64打开 伪代码如下 其中两个简单加密算法不展示

__int64 __fastcall main(int a1, char **a2, char **a3)
{
  int v3; // eax
  int v5; // [rsp+4h] [rbp-13Ch]
  int i; // [rsp+8h] [rbp-138h]
  int j; // [rsp+Ch] [rbp-134h]
  int k; // [rsp+10h] [rbp-130h]
  char enc[4]; // [rsp+20h] [rbp-120h] BYREF
  int v10[33]; // [rsp+24h] [rbp-11Ch]
  char input[113]; // [rsp+B7h] [rbp-89h] BYREF
  unsigned __int64 v12; // [rsp+128h] [rbp-18h]

  v12 = __readfsqword(0x28u);
  v5 = 1;
  puts("please input your flag:");
  __isoc99_scanf("%s", &input[9]);
  *enc = 120;
  v10[0] = 91;
  v10[1] = 86;
  v10[2] = 122;
  v10[3] = 93;
  v10[4] = 84;
  v10[5] = 37;
  v10[6] = 49;
  v10[7] = 32;
  v10[8] = 104;
  v10[9] = 61;
  v10[10] = 100;
  v10[11] = -110;
  v10[12] = 118;
  v10[13] = 99;
  v10[14] = 123;
  v10[15] = 89;
  v10[16] = 87;
  v10[17] = 33;
  v10[18] = -124;
  v10[19] = 87;
  v10[20] = 118;
  v10[21] = -121;
  v10[22] = 114;
  v10[23] = -124;
  v10[24] = -123;
  v10[25] = 112;
  v10[26] = -98;
  v10[27] = 79;
  v10[28] = 112;
  v10[29] = 114;
  v10[30] = -124;
  v10[31] = 87;
  v10[32] = -120;
  strcpy(input, "fuwafuwa");
  for ( i = 0; i < strlen(&input[9]); ++i )
    input[i + 9] = (16 * input[i + 9]) | (input[i + 9] >> 4) & 0xF;// 互换输入中的高/低四位
  encode(&input[9]);
  for ( j = 0; j < strlen(&input[9]); ++j )
  {
    input[j + 9] += j;
    input[j + 9] ^= input[j % 8] % 32 + 1;
    ceasar(input, j);                           // 向后移j位的凯撒加密
    v3 = strlen(input);
    reverse(input, v3);                         // 对称对换key(0->8, 1->7...
  }
  for ( k = 0; k <= strlen(enc); ++k )
  {
    if ( input[k + 9] != *&enc[4 * k] )
    {
      v5 = 0;
      puts("no way!");
      break;
    }
  }
  if ( v5 == 1 )
    puts("your input is flag!");
  return 0LL;
}
char *__fastcall encode(const char *input)
{
  unsigned __int8 v2; // [rsp+17h] [rbp-49h]
  int i; // [rsp+18h] [rbp-48h]
  int v4; // [rsp+1Ch] [rbp-44h]
  char *ptr_input; // [rsp+20h] [rbp-40h]
  char *key2; // [rsp+28h] [rbp-38h]
  char *ptr_input_; // [rsp+30h] [rbp-30h]
  unsigned __int64 j; // [rsp+38h] [rbp-28h]
  size_t len_of_input; // [rsp+40h] [rbp-20h]
  __int64 max_key; // [rsp+48h] [rbp-18h]
  char *v11; // [rsp+50h] [rbp-10h]
  unsigned __int64 last; // [rsp+58h] [rbp-8h]

  len_of_input = strlen(input);
  max_key = 3 * ((len_of_input >> 1) + 1);
  v11 = malloc(max_key + len_of_input);
  key2 = &v11[max_key];                         // 输入的首地址
  last = &v11[max_key - 1 + len_of_input];      // v11的最后一个元素
  ptr_input = &v11[max_key];
  memcpy(&v11[max_key], input, len_of_input);   // 最后的一段元素和输入相同
  while ( ptr_input <= last )
  {
    if ( *ptr_input )
    {
      v2 = 0;
      for ( ptr_input_ = ptr_input; ptr_input_ <= last; ++ptr_input_ )
      {
        v4 = v2 << 8;
        v2 = *ptr_input_ & 0x3F;
        *ptr_input_ = (*ptr_input_ + v4) >> 6;
      }
      *--key2 = off_55B72E249018[v2];
    }
    else
    {
      ++ptr_input;
    }
  }
  for ( i = 0; i <= 19; ++i )
    key += rand() % 100;
  key = key % 0x20 + 1;
  for ( j = 0LL; j < &v11[max_key] - key2; ++j )
    input[j] = key ^ key2[j];
  input[j] = 0;
  return v11;
}

核心加密是一个base64的换表 要注意的是其中的key动态调试出来并不正确 因为程序会检测动态调试改变key的初值

.init_array:000055B72E248D80                               _init_array segment qword public 'DATA' use64
.init_array:000055B72E248D80                               assume cs:_init_array
.init_array:000055B72E248D80                               ;org 55B72E248D80h
.init_array:000055B72E248D80 00 62 24 2E B7 55 00 00       dq offset sub_55B72E246200
.init_array:000055B72E248D88 09 62 24 2E B7 55 00 00       dq offset sub_55B72E246209
.init_array:000055B72E248D88                               _init_array ends
...
...
.text:000055B72E246209                               sub_55B72E246209 proc near              ; DATA XREF: .init_array:000055B72E248D88↓o
.text:000055B72E246209
.text:000055B72E246209                               var_4= dword ptr -4
.text:000055B72E246209
.text:000055B72E246209                               ; __unwind {
.text:000055B72E246209 F3 0F 1E FA                   endbr64
.text:000055B72E24620D 55                            push    rbp
.text:000055B72E24620E 48 89 E5                      mov     rbp, rsp
.text:000055B72E246211 C7 45 FC 00 00 00 00          mov     [rbp+var_4], 0
.text:000055B72E246218 BB 00 00 00 00                mov     ebx, 0                          ; ptrace_request
.text:000055B72E24621D B9 00 00 00 00                mov     ecx, 0                          ; pid
.text:000055B72E246222 BA 00 00 00 00                mov     edx, 0                          ; addr
.text:000055B72E246227 B8 1A 00 00 00                mov     eax, 1Ah
.text:000055B72E24622C CD 80                         int     80h                             ; LINUX - sys_ptrace
.text:000055B72E24622C
.text:000055B72E24622E 89 45 FC                      mov     [rbp+var_4], eax
.text:000055B72E246231 8B 45 FC                      mov     eax, [rbp+var_4]
.text:000055B72E246234 48 98                         cdqe
.text:000055B72E246236 48 83 F8 FF                   cmp     rax, 0FFFFFFFFFFFFFFFFh
.text:000055B72E24623A 75 0A                         jnz     short loc_55B72E246246
.text:000055B72E24623A
.text:000055B72E24623C C7 05 CA 2D 00 00 08 00 00 00 mov     cs:key, 8
.text:000055B72E24623C
.text:000055B72E246246
.text:000055B72E246246                               loc_55B72E246246:                       ; CODE XREF: sub_55B72E246209+31↑j
.text:000055B72E246246 90                            nop
.text:000055B72E246247 5D                            pop     rbp
.text:000055B72E246248 C3                            retn
.text:000055B72E246248                               ; } // starts at 55B72E246209
.text:000055B72E246248
.text:000055B72E246248                               sub_55B72E246209 endp

所以用key在(1, 31)且加密后密文都在表中爆破出key为21 据此写出解密脚本

![image-20231128164528686](C:\Users\Orink\AppData\Roaming\Typora\typora-user-images\image-20231128164528686.png)def emulator(key:list, time:int):
    for i in range(8):
        key[i] = 97 + (key[i] - 97 + time) % 26

def antiemulator(key:list, time:int):
    for i in range(8):
        key[i] = 97 + (key[i] - 97 - time) % 26

table = [ord(val) for val in 'i5jLW7S0GX6uf1cv3ny4q8es2Q+bdkYgKOIT/tAxUrFlVPzhmow9BHCMDpEaJRZN']
enc = [val & 0xFF for val in [120, 91, 86, 122, 93, 84, 37, 49, 32, 104, 61, 100, -110, 118, 99, 123, 89, 87, 33, -124, 87, 118, -121, 114, -124, -123, 112, -98, 79, 112, 114, -124, 87, -120]]
key_0 = 'fuwafuwa'
key = [ord(val) for val in key_0]
for i in range(34):
    emulator(key, i)
    key = key[::-1]
for i in range(33, -1, -1):
    key = key[::-1]
    antiemulator(key, i)
    enc[i] ^= key[i % 8] % 32 + 1
    enc[i] -= i
for i in range(34):
    enc[i] ^= 21
enc = [table.index(val) for val in enc]
flag = ''
for each in enc:
    flag += "{:06b}".format(each)
flag = flag[4:]
flag = [flag[8 * i:8 * i + 8] for i in ra![image-20231128164528686](C:\Users\Orink\AppData\Roaming\Typora\typora-user-images\image-20231128164528686.png)nge(len(enc))]
print("SYC{", end='')
for each in flag:
    try:
        print(chr(int(each[4:8] + each[0:4], 2)), end='')
    except:
        pass
print("}", end='')
# SYC{HbwKqCOAOVXdHAbG0HeinZkez}

yakvm | 虚拟机逆向

main为生成的虚拟机 IDA打开发现是无符号go 用go paraser恢复符号 搜索有关操作码的函数

发现有一个ShowOpcodes函数 但 调试时不进过该函数 交叉引用找到调用它的函数

在判断处下断点 调试时通过改ZF寄存器步进ShowOpcodes函数 得到可读操作码 根据官方文档分析如下

2:6->2:9         0:OP:type                 byte
2:4->2:119       1:OP:type                 slice
2:11->2:13       2:OP:push                 137
2:15->2:17       3:OP:push                 108
2:19->2:21       4:OP:push                 159
2:23->2:25       5:OP:push                 114
2:27->2:29       6:OP:push                 185
2:31->2:32       7:OP:push                 90
2:34->2:36       8:OP:push                 174
2:38->2:39       9:OP:push                 68
2:41->2:43      10:OP:push                 160
2:45->2:46      11:OP:push                 81
2:48->2:50      12:OP:push                 179
2:52->2:53      13:OP:push                 41
2:55->2:57      14:OP:push                 186
2:59->2:60      15:OP:push                 89
2:62->2:64      16:OP:push                 168
2:66->2:67      17:OP:push                 78
2:69->2:71      18:OP:push                 229
2:73->2:75      19:OP:push                 121
2:77->2:79      20:OP:push                 149
2:81->2:83      21:OP:push                 106
2:85->2:87      22:OP:push                 147
2:89->2:91      23:OP:push                 103
2:93->2:95      24:OP:push                 156
2:97->2:99      25:OP:push                 114
2:101->2:103    26:OP:push                 133
2:105->2:106    27:OP:push                 98
2:108->2:110    28:OP:push                 146
2:112->2:114    29:OP:push                 116
2:116->2:118    30:OP:push                 181
2:4->2:119      31:OP:typedslice           29
2:4->2:119      32:OP:list                 1
2:0->2:0        33:OP:pushleftr            1			arg_1 = key_list[29]
2:0->2:0        34:OP:list                 1
2:0->2:119      35:OP:assign               
3:0->3:4        36:OP:pushid               print
3:6->3:25       37:OP:push                 please input flag:
3:5->3:26       38:OP:call                 vlen:1
3:0->3:26       39:OP:pop                  
4:4->4:6        40:OP:pushid               get
4:7->4:8        41:OP:call                 vlen:0
4:4->4:8        42:OP:list                 1
4:0->4:0        43:OP:pushleftr            2
4:0->4:0        44:OP:list                 1			arg_2 = input[29]
4:0->4:8        45:OP:assign               
5:18->8:0       46:OP:new-scope            2			{
5:3->5:5        47:OP:pushid               len
5:7->5:7        48:OP:pushr                2
5:6->5:8        49:OP:call                 vlen:1			len(arg_2)
5:12->5:14      50:OP:pushid               len
5:16->5:16      51:OP:pushr                1				len(arg_1)
5:15->5:17      52:OP:call                 vlen:1
5:3->5:17       53:OP:gt                   					len(arg_1) > len(arg_2) -> goto globle63
5:18->8:0       54:OP:jmpf                 -> 63
5:18->8:0       55:OP:new-scope            3				{
6:1->6:7        56:OP:pushid               println
6:9->6:32       57:OP:push                 input string too long!	printf(too long!)
6:8->6:33       58:OP:call                 vlen:1
6:1->6:33       59:OP:pop                  
7:1->7:6        60:OP:return               
5:18->8:0       61:OP:end-scope            					}
5:18->8:0       62:OP:jmp                  -> 63			globle63:
5:18->8:0       63:OP:end-scope            				}
12:8->21:0      64:OP:push                 function params[1] codes[54] (copy)
12:8->21:0      65:OP:list                 1
12:0->12:4      66:OP:pushleftr            8			arg_8 = func1
12:0->12:4      67:OP:list                 1
12:0->21:0      68:OP:assign               
25:4->25:8      69:OP:pushr                8
25:10->25:10    70:OP:pushr                2
25:9->25:11     71:OP:call                 vlen:1		arg2 = func1(arg_2)
25:4->25:11     72:OP:list                 1
25:0->25:0      73:OP:pushleftr            2
25:0->25:0      74:OP:list                 1
25:0->25:11     75:OP:assign               
28:9->33:0      76:OP:push                 function params[0] codes[40] (copy)
28:9->33:0      77:OP:list                 1
28:0->28:4      78:OP:pushleftr            14
28:0->28:4      79:OP:list                 1
28:0->33:0      80:OP:assign               
36:0->36:4      81:OP:pushr                14
36:5->36:6      82:OP:call                 vlen:0       func2()
36:0->36:6      83:OP:pop                  
38:11->48:0     84:OP:push                 function params[0] codes[52] (copy)
38:11->48:0     85:OP:list                 1
38:0->38:7      86:OP:pushleftr            19
38:0->38:7      87:OP:list                 1
38:0->48:0      88:OP:assign               
51:14->53:0     89:OP:new-scope            24
51:3->51:10     90:OP:pushr                19
51:11->51:12    91:OP:call                 vlen:0
51:14->53:0     92:OP:jmpf                 -> 100
51:14->53:0     93:OP:new-scope            25
52:1->52:5      94:OP:pushid               print
52:7->52:24     95:OP:push                 yes! you get it!
52:6->52:25     96:OP:call                 vlen:1
52:1->52:25     97:OP:pop                  
51:14->53:0     98:OP:end-scope            
51:14->53:0     99:OP:jmp                  -> 108
51:14->53:0    100:OP:end-scope            
51:14->53:0    101:OP:new-scope            26
53:6->55:0     102:OP:new-scope            27
54:1->54:5     103:OP:pushid               print
54:7->54:24    104:OP:push                 no this not flag
54:6->54:25    105:OP:call                 vlen:1
54:1->54:25    106:OP:pop                  
53:6->55:0     107:OP:end-scope            
51:14->53:0    108:OP:end-scope            

//func1 start
anonymous
13:1->19:1       1:OP:new-scope            6	{
13:1->19:1       2:OP:pushleftr            5		arg_5 = arg_3 = arg_2
13:18->13:18     3:OP:pushr                3
13:1->19:1       4:OP:fast-assign          
13:1->19:1       5:OP:enter-for-range      -> 47	for i in range(47)
13:1->19:1       6:OP:range-next           
13:5->13:5       7:OP:pushleftr            6
13:8->13:8       8:OP:pushleftr            7
13:5->13:8       9:OP:list                 2
13:1->19:1      10:OP:assign               
13:20->19:1     11:OP:new-scope            7		{
14:16->16:2     12:OP:new-scope            8			{
14:5->14:5      13:OP:pushr                6
14:9->14:9      14:OP:push                 2
14:5->14:9      15:OP:mod                  
14:14->14:14    16:OP:push                 0
14:5->14:14     17:OP:eq                                    arg_6 % 2 == 0 goto global31
14:16->16:2     18:OP:jmpf                 -> 31
14:16->16:2     19:OP:new-scope            9			else{
15:10->15:10    20:OP:pushr                7
15:14->15:17    21:OP:push                 240
15:10->15:17    22:OP:xor                  
15:10->15:17    23:OP:list                 1
15:3->15:3      24:OP:pushr                3
15:5->15:5      25:OP:pushr                6                arg_3[arg_6] = arg_7 ^ 240
15:3->15:6      26:OP:list                 2
15:3->15:6      27:OP:list                 1
15:3->15:17     28:OP:assign               
14:16->16:2     29:OP:end-scope            					}
14:16->16:2     30:OP:jmp                  -> 44
14:16->16:2     31:OP:end-scope           global31:		}
14:16->16:2     32:OP:new-scope            10			{
16:9->18:2      33:OP:new-scope            11				{
17:10->17:10    34:OP:pushr                7                    arg_7 ^ 15
17:14->17:17    35:OP:push                 15
17:10->17:17    36:OP:xor                  
17:10->17:17    37:OP:list                 1
17:3->17:3      38:OP:pushr                3
17:5->17:5      39:OP:pushr                6                    arg_3[arg_6] = arg_7 ^ 15
17:3->17:6      40:OP:list                 2
17:3->17:6      41:OP:list                 1
17:3->17:17     42:OP:assign               
16:9->18:2      43:OP:end-scope            					}
14:16->16:2     44:OP:end-scope            				}
13:20->19:1     45:OP:end-scope            			}
13:1->19:1      46:OP:exit-for-range       -> 6
13:1->19:1      47:OP:pop                  
13:1->19:1      48:OP:end-scope            		}
20:8->20:8      49:OP:pushr                3
20:8->20:8      50:OP:list                 1
20:1->20:8      51:OP:return                           
//func1 end

//func2 start
anonymous
28:15->33:0      0:OP:new-scope            13
29:1->32:1       1:OP:new-scope            14
29:1->32:1       2:OP:pushleftr            10
29:18->29:18     3:OP:pushr                2            arg_10 = arg_2
29:1->32:1       4:OP:fast-assign          
29:1->32:1       5:OP:enter-for-range      -> 36
29:1->32:1       6:OP:range-next           
29:5->29:5       7:OP:pushleftr            11           arg_12 = arg_11 ?
29:8->29:8       8:OP:pushleftr            12
29:5->29:8       9:OP:list                 2
29:1->32:1      10:OP:assign               
29:20->32:1     11:OP:new-scope            15   {
30:6->30:6      12:OP:pushr                11       arg_13 = arg_11 * 2
30:10->30:10    13:OP:push                 2
30:6->30:10     14:OP:mul                  
30:6->30:10     15:OP:list                 1
30:2->30:2      16:OP:pushleftr            13
30:2->30:2      17:OP:list                 1
30:2->30:10     18:OP:assign               
31:11->31:11    19:OP:pushr                12           //用与或非实现异或
31:10->31:11    20:OP:not                            arg_12 ^ arg_13
31:15->31:15    21:OP:pushr                13
31:10->31:15    22:OP:and                  
31:21->31:21    23:OP:pushr                12
31:26->31:26    24:OP:pushr                13
31:25->31:26    25:OP:not                  
31:21->31:26    26:OP:and                  
31:9->31:27     27:OP:or                   
31:9->31:27     28:OP:list                 1
31:2->31:2      29:OP:pushr                2
31:4->31:4      30:OP:pushr                11
31:2->31:5      31:OP:list                 2
31:2->31:5      32:OP:list                 1
31:2->31:27     33:OP:assign               
29:20->32:1     34:OP:end-scope                 }
29:1->32:1      35:OP:exit-for-range       -> 6
29:1->32:1      36:OP:pop                  
29:1->32:1      37:OP:end-scope            
28:15->33:0     38:OP:end-scope            
28:9->33:0      39:OP:return               
//func2 end

//func3 start   判断函数
anonymous
38:17->48:0      0:OP:new-scope            17
39:21->41:1      1:OP:new-scope            18
39:4->39:6       2:OP:pushid               len
39:8->39:8       3:OP:pushr                2
39:7->39:9       4:OP:call                 vlen:1
39:14->39:16     5:OP:pushid               len
39:18->39:18     6:OP:pushr                1
39:17->39:19     7:OP:call                 vlen:1
39:4->39:19      8:OP:neq                  
39:21->41:1      9:OP:jmpf                 -> 16
39:21->41:1     10:OP:new-scope            19
40:9->40:13     11:OP:push                 false
40:9->40:13     12:OP:list                 1
40:2->40:13     13:OP:return               
39:21->41:1     14:OP:end-scope            
39:21->41:1     15:OP:jmp                  -> 16
39:21->41:1     16:OP:end-scope            
42:1->46:1      17:OP:new-scope            20
42:1->46:1      18:OP:pushleftr            16
42:18->42:18    19:OP:pushr                2
42:1->46:1      20:OP:fast-assign          
42:1->46:1      21:OP:enter-for-range      -> 45
42:1->46:1      22:OP:range-next           
42:5->42:5      23:OP:pushleftr            17
42:8->42:8      24:OP:pushleftr            18
42:5->42:8      25:OP:list                 2
42:1->46:1      26:OP:assign               
42:20->46:1     27:OP:new-scope            21
43:14->45:2     28:OP:new-scope            22
43:5->43:5      29:OP:pushr                18
43:10->43:10    30:OP:pushr                1
43:12->43:12    31:OP:pushr                17
43:11->43:13    32:OP:push                 false
43:11->43:13    33:OP:iterablecall         off:1 op1: -         op2: -
43:5->43:13     34:OP:neq                  
43:14->45:2     35:OP:jmpf                 -> 42
43:14->45:2     36:OP:new-scope            23
44:10->44:14    37:OP:push                 false
44:10->44:14    38:OP:list                 1
44:3->44:14     39:OP:return               
43:14->45:2     40:OP:end-scope            
43:14->45:2     41:OP:jmp                  -> 42
43:14->45:2     42:OP:end-scope            
42:20->46:1     43:OP:end-scope            
42:1->46:1      44:OP:exit-for-range       -> 22
42:1->46:1      45:OP:pop                  
42:1->46:1      46:OP:end-scope            
47:8->47:11     47:OP:push                 true
47:8->47:11     48:OP:list                 1
47:1->47:11     49:OP:return               
38:17->48:0     50:OP:end-scope            
38:11->48:0     51:OP:return               
//func3 end

据此写出解密脚本

key = [137, 108, 159, 114, 185, 90, 174, 68, 160, 81, 179, 41, 186, 89, 168, 78, 229, 121, 149, 106, 147, 103, 156, 114, 133, 98, 146, 116, 181]
for i in range(29):
    if i % 2 == 0:
        key[i] ^= 2 * i
        key[i] ^= 240
    else:
        key[i] ^= 2 * i
        key[i] ^= 15
for each in key:
    print(chr(each), end='')
# yak{A_RE@LW0RLD_5TACKB@SE_VM} 

 最后 不论是CTF还是写文章本人都处于新手阶段 如有不足之处请见谅

  • 43
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值