HECTFreverse部分writeup

因为期中考试(寄)所以很多题目没来得及复现,汇编也没学,感觉自己又变菜了qwq

hard

直接扔进Ida64查字符串/查汇编/查代码都可以得到flag:HECTF{HElLo_RRRRe}

baby_upx

尝试用指令脱壳失败,本来打算手动脱壳,但是后来偶然发现了upx-3.9.6封装好的一个脱壳软件,居然给脱出来了。

反编译得到源代码:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  unsigned int v3; // eax
  char String[26]; // [esp+1Eh] [ebp-46h] BYREF
  int v6; // [esp+38h] [ebp-2Ch]
  _DWORD v7[5]; // [esp+3Ch] [ebp-28h] BYREF
  char *v8; // [esp+50h] [ebp-14h]
  const char *v9; // [esp+54h] [ebp-10h]
  char i; // [esp+5Bh] [ebp-9h]
  int v11; // [esp+5Ch] [ebp-8h]

  sub_401AD0();
  v7[0] = 2099915543;
  v7[1] = 120201498;
  v7[2] = 269490557;
  v7[3] = 67837461;
  v7[4] = 271401;
  v9 = (const char *)v7;
  puts("Similarly, this is also a challenge for beginners");
  *(_DWORD *)String = 0;
  v6 = 0;
  v3 = 0;
  do
  {
    *(_DWORD *)&String[v3 + 2] = 0;
    v3 += 4;
  }
  while ( v3 < ((String - &String[2] + 30) & 0xFFFFFFFC) );
  printf("Now, please enter your flag: ");
  scanf("%30s", String);
  v11 = 0;
  v8 = strtok(String, "{");
  if ( strcmp(v8, "HECTF") )
    goto LABEL_10;
  v8 = strtok(0, "}");
  if ( !v8 )
    goto LABEL_10;
  for ( i = v8[v11]; i; i = v8[v11] )
  {
    i ^= String[(v11 ^ (rand() + 10086)) % 5];
    v8[v11++] = i;
  }
  if ( !strcmp(v8, v9) )
    puts("Success!");
  else
LABEL_10:
    puts("Wrong!");
  return 0;
}

首先查询strtok函数的用法,发现是把HECTF{}这几个字符给去掉。
发现输入语句之前的都是初始化,可以不用管,关键代码如下:

for ( i = v8[v11]; i; i = v8[v11] )
  {
    i ^= String[(v11 ^ (rand() + 10086)) % 5];
    v8[v11++] = i;
  }

我们发现v11是递增的

i ^= String[(v11 ^ (rand() + 10086)) % 5];
v8[v11++] = i;

其实就是v9[v11]=v8[v11]^string(v11^(rand()+10086))%5]
那么v8[v11]=v9[v11]^string(v11^(rand()+10086))%5]
可以发现有个rand()函数,这是一个假随机数,只要种子是一样的rand出来的数就是一样的,可以预处理出rand数组。
然后发现v8数组在通过这个循环结构后变成了v9,而v9直接copy源代码即可得到,由此得出exp:

#include<bits/stdc++.h>
#define I inline
using namespace std;
unsigned int v7[6];
const char *v9;
char *v8;
char hectf[7]="HECTF{";
char flag[30];
int random[55];
int len;

I void make_rand(){for(int i=0;i<=50;i++)random[i]=rand();}

int main()
{
    v7[0]=2099915543;
    v7[1]=120201498;
    v7[2]=269490557;
    v7[3]=67837461;
    v7[4]=271401;
    v9=(const char *)v7;
    make_rand();
    for(int i=0;i<=18;i++)
    {
        flag[i]=v9[i]^hectf[(i^(random[i]+10086))%5];
    }
    for(int i=0;i<=18;i++)cout<<flag[i];
}

得到flag:
HECTF{Thi5_iiS5_UUPX_LalA}

baby_pp

查壳发现用python打包的。

用pyinstxtractor进行解包:

得到main.pyc,用uncompyle6反编译(在线反编译出锅,比赛的时候反编译出来少了很多东西,后来用uncompyle6就可以了)

查看python源代码:

# uncompyle6 version 3.8.0
# Python bytecode 3.8.0 (3413)
# Decompiled from: Python 3.8.0 (tags/v3.8.0:fa919fd, Oct 14 2019, 19:37:50) [MSC v.1916 64 bit (AMD64)]
# Embedded file name: main.py
import random
ens = '742641edefb6770733ab5932325106b3a5fa75222791d09e451161c46f15504402b32737362443d4df7d136145cd970b54116669c230'

def encode(s, nuum):
    step = len(s) // nuum
    ens = ''
    for i in range(step):
        ens += s[i::step]
    else:
        return ens


def main():
    random.seed(10085)
    u_input = input(': ')
    t = ''
    for i in u_input:
        t += '%02x' % (ord(i) ^ random.randint(0, 127))
    else:
        eni = encode(t, 6)
        if eni == ens:
            print('Success!')
        else:
            print('Failed!')


if __name__ == '__main__':
    main()

首先分析encode函数:

ens = '742641edefb6770733ab5932325106b3a5fa75222791d09e451161c46f15504402b32737362443d4df7d136145cd970b54116669c230'
def encode(s, nuum):
    step = len(s) // nuum #ens长度为108,返回值得到eni=ens,同时该函数并没有对字符串长度进行改变,推出len(s)=108,nuum=6,step=18
    ens = ''
    for i in range(step):
        ens += s[i::step] #每隔18位从s中选一个值(这里的ens和全局变量ens应该不是一个),那么也就相当于ens中的
                          #前0-5分别对应s中的0,0+18-1,0+2*18-1...
                          #前6-11分别对应s中的1,1+18-1,1+2*18-1...
    else:
        return ens

由此可以有ens(全局)decode出eni:

str = '742641edefb6770733ab5932325106b3a5fa75222791d09e451161c46f15504402b32737362443d4df7d136145cd970b54116669c230'
eni= ''
for i in range(0,6):
    eni+= str[i::6]
print("eni="+eni)

得到eni=7e7a3b794c5b3d1c564d7b23515403643d492e055a2d16422d691c6f7915201f474f17124b330f29610347406316326a7e15273d5b60
注意到源代码中这一句:

for i in u_input:
        t += '%02x' % (ord(i) ^ random.randint(0, 127))

'%02x'是把t转成两位16进制之后进行异或运算,最后得到eni,再encode得到ens。
此时我们已经得到了eni,应该是一个两位16进制数,手动转码之后异或写出exp:

import random
random.seed(10085)
ens = [0x7e,0x7a,0x3b,0x79,0x4c,0x5b,0x3d,0x1c,0x56,0x4d,0x7b,0x23,0x51,0x54,0x03,0x64,0x3d,0x49,0x2e,0x05,0x5a,0x2d,0x16,0x42,0x2d,0x69,0x1c,0x6f,0x79,0x15,0x20,0x1f,0x47,0x4f,0x17,0x12,0x4b,0x33,0x0f,0x29,0x61,0x03,0x47,0x40,0x63,0x16,0x32,0x6a,0x7e,0x15,0x27,0x3d,0x5b,0x60]
t = ''
for i in range(len(ens)):
    t +=chr(ens[i] ^ random.randint(0, 127))
else:
    print(t)

得到虚假的flag:HECTF{decrypt(80410840840842108808881088408084210842)}
最后是某crypto大佬一眼看出云影密码(01248密码),当场学习一波(白嫖一份解密脚本)

a="80410840840842108808881088408084210842"
a=a.split("0")
flag=''
for i in range(0,len(a)):
     str = a[i]
     list=[]
     sum=0
     for j in str:
        list.append(j)
        length = len(list)
     for k in range(0,length):
        sum+=int(list[k])
     flag+=chr(sum+64)
print(flag)

运行得到flag:HELLOPYTHON

原文地址:https://www.cnblogs.com/THRANDUil/p/15591486.html