Reverse刷题

[SWPUCTF 2021 新生赛]简简单单的逻辑

题目描述

```#方法1 爆破  只有256个数字
flag = ''
list = [47, 138, 127, 57, 117, 188, 51, 143, 17, 84, 42, 135, 76, 105, 28, 169, 25]
result = ''
key2='bcfba4d0038d48bd4b00f82796d393dfec'
for i in range(len(list)):
    key = (list[i]>>4)+((list[i] & 0xf)<<4)
    for j in range(256):
        char=chr(j)
        if key2[i*2:i*2+2] == str(hex(ord(char)^key))[2:].zfill(2):
            flag+=char
            result+=str(hex(ord(char)^key))[2:].zfill(2)
print(flag)
```flag = ''
list = [47, 138, 127, 57, 117, 188, 51, 143, 17, 84, 42, 135, 76, 105, 28, 169, 25]
result = ''
# for i in range(len(list)):
#     key = (list[i]>>4)+((list[i] & 0xf)<<4)
#     result += str(hex(ord(flag[i])^key))[2:].zfill(2)
# print(result)
# result=bcfba4d0038d48bd4b00f82796d393dfec
result2='bcfba4d0038d48bd4b00f82796d393dfec'
for i in range(len(list)):
    key=(list[i]>>4)+((list[i]&0xf)<<4)
    char=chr(int(result2[i*2:i*2+2],16)^key)
    flag+=char
print(flag)

[SWPUCTF 2021 新生赛]re1

题目描述

1.先查壳,发现无壳,直接丢进ida分析
2.``` c
int __cdecl main(int argc, const char **argv, const char **envp)
{
char Str2[1008]; // [rsp+20h] [rbp-60h] BYREF
char Str1[1000]; // [rsp+410h] [rbp+390h] BYREF
int i; // [rsp+7FCh] [rbp+77Ch]

_main();
strcpy(Str2,{34sy_r3v3rs3});
printf(“please put your flag:);
scanf(%s”, Str1);
for ( i = 0; i <= 665; ++i )
{
if ( Str1[i] == 101 )
Str1[i] = 51;
}
for ( i = 0; i <= 665; ++i )
{
if ( Str1[i] == 97 )
Str1[i] = 52;
}
if ( strcmp(Str1, Str2) )
printf(“you are wrong,see again!”);
else
printf(“you are right!”);
system(“pause”);
return 0;
}
2.发现只是简单的字符替换,编写脚本即可

exp

print('{34sy_r3v3rs3}'.replace(chr(51),chr(101)).replace(chr(52),chr(97)))

[SWPUCTF 2021 新生赛]

题目描述

import base64,urllib.parse
key = "HereIsFlagggg"
flag = "xxxxxxxxxxxxxxxxxxx"

s_box = list(range(256))
j = 0
for i in range(256):
    j = (j + s_box[i] + ord(key[i % len(key)])) % 256
    s_box[i], s_box[j] = s_box[j], s_box[i]
res = []
i = j = 0
for s in flag:
    i = (i + 1) % 256
    j = (j + s_box[i]) % 256
    s_box[i], s_box[j] = s_box[j], s_box[i]
    t = (s_box[i] + s_box[j]) % 256
    k = s_box[t]
    res.append(chr(ord(s) ^ k))
cipher = "".join(res)
crypt = (str(base64.b64encode(cipher.encode('utf-8')), 'utf-8'))
enc = str(base64.b64decode(crypt),'utf-8')
enc = urllib.parse.quote(enc)
print(enc)
# enc = %C2%A6n%C2%87Y%1Ag%3F%C2%A01.%C2%9C%C3%B7%C3%8A%02%C3%80%C2%92W%C3%8C%C3%BA

发现是一个rc4然后进行base64加密再进行url编码,直接逆过来即可

exp

enc = '%C2%A6n%C2%87Y%1Ag%3F%C2%A01.%C2%9C%C3%B7%C3%8A%02%C3%80%C2%92W%C3%8C%C3%BA'
str=urllib.parse.unquote(enc)
flag=''
key = "HereIsFlagggg"
s_box = list(range(256))
j = 0
for i in range(256):
    j = (j + s_box[i] + ord(key[i % len(key)])) % 256
    s_box[i], s_box[j] = s_box[j], s_box[i]
res = []
i = j = 0
for s in str:
    i = (i + 1) % 256
    j = (j + s_box[i]) % 256
    s_box[i], s_box[j] = s_box[j], s_box[i]
    t = (s_box[i] + s_box[j]) % 256
    k = s_box[t]
    res.append(chr(ord(s) ^ k))
flag="".join(res)
print(flag)

[SWPUCTF 2021 新生赛]re2

题目描述

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char Str2[64]; // [rsp+20h] [rbp-90h] BYREF
  char Str[68]; // [rsp+60h] [rbp-50h] BYREF
  int v7; // [rsp+A8h] [rbp-8h]
  int i; // [rsp+ACh] [rbp-4h]

  _main();
  strcpy(Str2, "ylqq]aycqyp{");
  printf(&Format);
  gets(Str);
  v7 = strlen(Str);
  for ( i = 0; i < v7; ++i )
  {
    if ( (Str[i] <= 96 || Str[i] > 98) && (Str[i] <= 64 || Str[i] > 66) )
      Str[i] -= 2;
    else
      Str[i] += 24;
  }
  if ( strcmp(Str, Str2) )
    printf(&byte_404024);
  else
    printf(aBingo);
  system("pause");
  return 0;
}

exp

这题存在多解:
str2 = 'ylqq]aycqyp{'
result = ''

# 遍历字符串中的每个字符
for char in str2:
    # 获取字符的 ASCII 值并加上 2
    temp = ord(char) + 2
    
    # 检查是否超过大写字母范围或小写字母范围
    if ((temp <= 96 or temp > 98) and (temp <= 64 or temp > 66)):
        # 如果超出范围,将修改后的字符添加到结果字符串
        result += chr(temp)
    else:
        # 如果在范围内,将修改后的字符减去 24 并添加到结果字符串
        result += chr(temp - 26)
# 打印修改后的字符串
print(result)

也可暴力枚举

cipher=list("ylqq]aycqyp{")
for i in range(len(cipher)):
    for j in range(33,128):
        if ((j<=96 or j > 98) and (j<=64 or j > 66)):
            if(j-2)==ord(cipher[i]):
                print(chr(j),end="")
                break
        else:
            if(j+24)==ord(cipher[i]):
                print(chr(j),end="")
                break

[HUBUCTF 2022 新生赛]simple_RE

题目描述

//base64编码的反汇编代码,关键是遇到后要根据特征会识别:
__int64 __fastcall sub_401570(const char *a1, _QWORD *a2, int *a3)
{
  int v6; // r15d
  int v7; // r12d
  int v8; // r13d
  __int64 v9; // r14
  _BYTE *v10; // rax
  _BYTE *v11; // r9
  __int64 v12; // r8
  char v13; // cl
  char v14; // r11
  char v15; // r10
  __int64 result; // rax

  v6 = strlen(a1);
  v7 = v6 % 3;
  if ( v6 % 3 )
  {
    v8 = 4 * (v6 / 3) + 4;
    v9 = v8;
    v10 = malloc(v8 + 1i64);
    v10[v8] = 0;
    if ( v6 <= 0 )
      goto LABEL_5;
  }
  else
  {
    v8 = 4 * (v6 / 3);
    v9 = v8;
    v10 = malloc(v8 + 1i64);
    v10[v8] = 0;
    if ( v6 <= 0 )
      goto LABEL_8;
  }
  v11 = v10;
  v12 = 0i64;
  do
  {
    v11 += 4;
    v13 = a1[v12];
    *(v11 - 4) = aQvejafhmuyjbac[v13 >> 2];
    v14 = a1[v12 + 1];
    *(v11 - 3) = aQvejafhmuyjbac[(v14 >> 4) | (16 * v13) & 0x30];
    v15 = a1[v12 + 2];
    v12 += 3i64;
    *(v11 - 2) = aQvejafhmuyjbac[(v15 >> 6) | (4 * v14) & 0x3C];
    *(v11 - 1) = aQvejafhmuyjbac[v15 & 0x3F];
  }
  while ( v6 > (int)v12 );
LABEL_5:
  if ( v7 == 1 )
  {
    v10[v9 - 2] = 61;
    v10[v9 - 1] = 61;
  }
  else if ( v7 == 2 )
  {
    v10[v9 - 1] = 61;
  }
LABEL_8:
  *a2 = v10;
  result = 0i64;
  *a3 = v8;
  return result;
}

exp

import base64
import string
cipher='5Mc58bPHLiAx7J8ocJIlaVUxaJvMcoYMaoPMaOfg15c475tscHfM/8=='
string1='qvEJAfHmUYjBac+u8Ph5n9Od17FrICL/X0gVtM4Qk6T2z3wNSsyoebilxWKGZpRD'
string2='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
print(base64.b64decode(cipher.translate(str.maketrans(string1,string2))))
#b'NSSCTF{a8d4347722800e72e34e1aba3fe914ae}'
  1. str.maketrans(string1, string2): 这个方法创建一个字符映射表,用于将 string1 中的字符替换为相应位置的 string2 中的字符。在这个上下文中,它用于创建一个替代规则,将密文中的字符进行解密。请确保 string1string2 的长度相同,否则会引发 ValueError
  2. cipher.translate(str.maketrans(string1, string2)): 这一行将密文 cipher 中的字符根据先前创建的映射表进行替换,相当于执行解密操作。
  3. base64.b64decode(...): 这一行使用 base64 解码函数来解码由上一步得到的解密后的字符串。b64decode 函数接受一个 base64 编码的字符串,并返回其解码后的原始二进制数据。

以上为关键函数解释。

[SWPUCTF 2021 新生赛]非常简单的逻辑题

题目描述

flag = 'xxxxxxxxxxxxxxxxxxxxx'
s = 'wesyvbniazxchjko1973652048@$+-&*<>'
result = ''
for i in range(len(flag)):
    s1 = ord(flag[i])//17
    s2 = ord(flag[i])%17
    result += s[(s1+i)%34]+s[-(s2+i+1)%34]  #注意!这是生成两个字符并连接
print(result)
# result = 'v0b9n1nkajz@j0c4jjo3oi1h1i937b395i5y5e0e$i'

exp

#不会逆,直接爆破吧
flag = ''
s = 'wesyvbniazxchjko1973652048@$+-&*<>'
result = 'v0b9n1nkajz@j0c4jjo3oi1h1i937b395i5y5e0e$i'
k=0
for i in range(0,len(result),2):
    for j in range(32,127):
        s1=j//17
        s2=j%17
        if(result[i]==s[(s1+k)%34])and (result[i+1]==s[-(s2+k+1)%34]):
            flag+=chr(j)
            k+=1
print(flag)
# NSSCTF{Fake_RERE_QAQ}

[GFCTF 2021]wordy

题目描述(花指令,idapython)

下载附件,查壳,发现没壳,接着拖入到Ida中

打开附件,找主函数发现无法编译,考虑是花指令

可以看到标红的这段有一段代码

loc_1144:
jmp short near ptr loc_1144+1

这串代码并没有实际的作用,看了很多大佬 的wp才知道这 是一种常见的花指令。把这段代码nop掉就可以,即找到机械码为EBFF的,把它改成90(即为no的机械码),但是我们发现下面的数据中含有大量的EBFF机械码,手动nop坑定是很麻烦的,这时就可以使用idapython(file-Script command打开),用上脚本直接把所有的jmp花指令nop掉
其中startaddr时初始地址,endaddr是结束地址,get_wide_byte()函数是常用的命令,含义是get_wide_byte(ea)/get_wide_dword/word(ea)create_data(ea, dataflag, size, tid)转变为数据(byte,word,dword,etc),patch_byte(addr,byte)是设置addr处的一个字节值(其他的ida命令可以参考一位大佬的文章

之后可以直接找到flag

非预期解

exp

# 利用idapython脚本解决重复工作
startaddr = 0x1135
endaddr = 0x3100

for i in range(startaddr,endaddr):
    if get_wide_byte(i) == 0xEB:
        if get_wide_byte(i+1) == 0xFF:
            patch_byte(i,0x90)
            print("[+] Addr {} is patched".format(hex(i)))

[SWPUCTF 2021 新生赛]fakerandom

题目描述(xor,fakerandom)

import random
flag = 'xxxxxxxxxxxxxxxxxxxx'
random.seed(1)
l = []
for i in range(4):
    l.append(random.getrandbits(8))
result=[]
for i in range(len(l)):
    random.seed(l[i])
    for n in range(5):
        result.append(ord(flag[i*5+n])^random.getrandbits(8))
print(result)
# result = [201, 8, 198, 68, 131, 152, 186, 136, 13, 130, 190, 112, 251, 93, 212, 1, 31, 214, 116, 244]

exp

#鼠鼠不会逆,只能根据异或的可逆性把答案给搞出来
import random
flag=[201, 8, 198, 68, 131, 152, 186, 136, 13, 130, 190, 112, 251, 93, 212, 1, 31, 214, 116, 244]
result=[]
random.seed(1)
l = []
for i in range(4):
    l.append(random.getrandbits(8))
result=[]
for i in range(len(l)):
    random.seed(l[i])
    for n in range(5):
        result.append(chr((flag[i*5+n])^random.getrandbits(8)))
print(str(result))
print("".join(result))
#NSSCTF{FakeE_random}

看了一眼标准解法

#本题考查的是python random模块的伪随机数相关的知识。所谓伪随机数就是设定种子之后,生成的随机数序列可以被预测(每次都一样的)。
#random.seed(1) 是 Python 的 randm 模块中的一个函数,用于设置随机生成器的种子值
#random.getrandbits() 是 Pytho 的 random 模块中的一个函数,用于生成定数量的随机位(bit)的整数。
import random

random.seed(1)
l = []
for i in range(4):
l.append(random.getrandbits(8))

print(l)
#l= [34, 145, 216, 205]
key = []
for i in range(len(l)):
random.seed(l[i])
for n in range(5):
key.append(random.getrandbits(8))
print(key)
#key = [135, 91, 149, 7, 215, 222, 193, 206, 108, 233, 219, 53, 164, 47, 181, 111, 123, 185, 25, 137]
result = [201, 8, 198, 68, 131, 152, 186, 136, 13, 130, 190, 112, 251, 93, 212, 1, 31, 214, 116, 244]

flag = ‘’

for i in range(len(key)):
flag+=chr(result[i]^key[i])

[NISACTF 2022]string

题目描述

char *__fastcall flag(char *a1)
{
  char *v1; // rax
  char *v2; // rax
  char *v3; // rax
  int v4; // eax
  char *v6; // [rsp+8h] [rbp-38h]
  int i; // [rsp+1Ch] [rbp-24h]
  int j; // [rsp+20h] [rbp-20h]
  int k; // [rsp+20h] [rbp-20h]
  int v10; // [rsp+24h] [rbp-1Ch]
  int m; // [rsp+28h] [rbp-18h]
  int v12; // [rsp+2Ch] [rbp-14h]
  int v13; // [rsp+34h] [rbp-Ch]

  v6 = a1;
  v12 = (_DWORD)a1 + 1;
  if ( (_DWORD)a1 << 30 )
  {
    while ( 1 )
    {
      v1 = v6++;
      if ( !*v1 )
        break;
      if ( !((_DWORD)v6 << 30) )
        goto LABEL_4;
    }
  }
  else
  {
LABEL_4:
    for ( i = (int)v6; ((i - 16843009) & ~i & 0x80808080) == 0; i = v13 )
    {
      v13 = v6[1];
      v6 += 4;
    }
    v2 = v6++;
    for ( j = *v2; j; j = *v3 )
      v3 = v6++;
  }
  puts("This a magic!");
  v10 = (_DWORD)v6 - v12;
  for ( k = 0; (int)v6 - v12 > k; ++k )
    v10 ^= 0x1Au;
  if ( v10 != 13 )
  {
    puts("error!");
    exit(0);
  }
  puts("The length of flag is 13");
  srand(seed);
  printf("NSSCTF{");
  for ( m = 0; m < 13; ++m )
  {
    v4 = rand();
    printf("%d", (unsigned int)(v4 % 8 + 1));
  }
  putchar(125);
  return &v6[-v12];
}

exp

#include<stdio.h>
#include<string.h>
#include<stdlib.h>

int main(int argc, char const *argv[])
{
int v4 = 0;
int seed = 0x2766;
srand(seed);
for ( int l = 0; l < 13; ++l )
{
v4 = rand();
printf(“%d”, (unsigned int)(v4 % 8 + 1));
}
return 0;
}
//5353316611126

必须要linux写出来的程序得到的才是正确的答案,win的写出来是错的

这个是依赖于libc版本的, 如果libc的rand换了实现, 输出就变了

[NISACTF 2022]sign-ezc++

题目描述

int __cdecl main(int argc, const char **argv, const char **envp)
{
  Man *v3; // rbx
  Human *v4; // rbx
  std::string name; // [rsp+20h] [rbp-20h] BYREF
  char v7; // [rsp+37h] [rbp-9h] BYREF
  Human *m; // [rsp+38h] [rbp-8h]

  _main();
  std::allocator<char>::allocator(&v7);
  std::string::string(&name, "NISACTF", &v7);
  v3 = (Man *)operator new(0x18ui64);
  Man::Man(v3, (std::string)&name, 4);
  m = v3;
  std::string::~string(&name);
  std::allocator<char>::~allocator(&v7);
  (*((void (__fastcall **)(Human *))m->_vptr_Human + 1))(m);
  v4 = m;
  if ( m )
  {
    Human::~Human(m);
    operator delete(v4);
  }
  return 0;
}
//主函数看不懂一点,随便点点看看有没有什么有用信息,可以在human这个类中找到giveflag函数
//点进去一看发现是一个数组与0xA0异或

exp

enc=bytearray.fromhex("445959495E4C717E626379556379554443594B55786F5579636D6477")
print(enc)
for i in enc:
    print(chr(i^0xA),end="")
#NSSCTF{this_is_NISA_re_sign}

[HNCTF 2022 Week1]超级签到

题目描述

int __cdecl main_0(int argc, const char **argv, const char **envp)
{
  char *v3; // rdi
  __int64 i; // rcx
  size_t v5; // rax
  char v7; // [rsp+0h] [rbp-20h] BYREF
  int j; // [rsp+24h] [rbp+4h]
  char Str1[224]; // [rsp+48h] [rbp+28h] BYREF
  __int64 v10; // [rsp+128h] [rbp+108h]

  v3 = &v7;
  for ( i = 82i64; i; --i )
  {
    *(_DWORD *)v3 = -858993460;
    v3 += 4;
  }
  for ( j = 0; ; ++j )
  {
    v10 = j;
    if ( j > j_strlen(Str2) )
      break;
    if ( Str2[j] == 111 )
      Str2[j] = 48;
  }
  sub_1400111D1("input the flag:");
  scanf("%20s", Str1);
  v5 = j_strlen(Str2);
  if ( !strncmp(Str1, Str2, v5) )
    sub_1400111D1("this is the right flag!\n");
  else
    sub_1400111D1("wrong flag\n");
  return 0;
//程序逻辑就是先替换然后再比较,很显然

exp

flag=''
str2='{hello_world}'
for char in str2:
    if(ord(char)==111):
        char=chr(48)
    flag+=char
print(flag)
# {hell0_w0rld}

[LitCTF 2023]ez_XOR

题目描述

__main();
  strcpy(Str2, "E`}J]OrQF[V8zV:hzpV}fVF[t");
  v9 = 0;
  v10 = 0;
  v11 = 0;
  v12 = 0;
  v13 = 0;
  v14 = 0;
  v15 = 0;
  printf("Enter The Right FLAG:");
  scanf("%s", Str1);
  XOR(Str1, 3);
  if ( !strcmp(Str1, Str2) )
  {
    printf("U Saved IT!\n");
    return 0;
  }
  else
  {
    printf("Wrong!Try again!\n");
    return main(v4, v5, v6);
  }
//XOR函数进去看是字符串每个字符异或3**3,逻辑很简单

exp

enc="E`}J]OrQF[V8zV:hzpV}fVF[t"
flag=""
for char in enc:
    i=ord(char)^9
    flag+=chr(i)
print(flag)
# LitCTF{XOR_1s_3asy_to_OR}

[HNCTF 2022 WEEK2]e@sy_flower

题目描述

把爆红的jmp花指令nop掉就能得到主函数的逻辑

v3 = a1 - a2;
  for ( i = 0; i < v3 >> 1; ++i )               // 在循环内部,进行了一些对字符串的字节交换操作:就是奇数位和偶数位交换
  {
    v5 = *(_BYTE *)(a3 + 2 * i - 52);
    *(_BYTE *)(a3 + 2 * i - 52) = *(_BYTE *)(a3 + 2 * i - 51);
    *(_BYTE *)(a3 + 2 * i - 51) = v5;
  }
  for ( j = 0; j < strlen((const char *)(a3 - 52)); ++j )// 在第二个循环内部,对字符串中的每个字节执行异或操作,将其与0x30u(十进制为48)进行异或。
    *(_BYTE *)(a3 + j - 52) ^= 0x30u;
  v7 = strcmp((const char *)(a3 - 52), "c~scvdzKCEoDEZ[^roDICUMC");

exp

enc="c~scvdzKCEoDEZ[^roDICUMC"
a3_=""
for char in enc:
    a3_+=chr(ord(char)^0x30)
print(a3_)
a3=list(a3_)
for i in range(0,len(enc),2):
    a3[i],a3[i+1]=a3[i+1],a3[i]
print("".join(a3))
# SNCSFTJ{su_tujknB_tyse}s
# NSSCTF{Just_junk_Bytess}

[BJDCTF 2020]JustRE

题目描述

shift+f12查找字符串,看到一个BJD开头的像flag的东西,直接交叉引用,来到giveflag的函数

INT_PTR __stdcall DialogFunc(HWND hWnd, UINT a2, WPARAM a3, LPARAM a4)
{
  CHAR String[100]; // [esp+0h] [ebp-64h] BYREF

  if ( a2 != 272 )
  {
    if ( a2 != 273 )
      return 0;
    if ( (_WORD)a3 != 1 && (_WORD)a3 != 2 )
    {
      sprintf(String, &Format, ++dword_4099F0);
      if ( dword_4099F0 == 19999 )
      {
        sprintf(String, " BJD{%d%d2069a45792d233ac}", 19999, 0);//格式化输出
        SetWindowTextA(hWnd, String);
        return 0;
      }
      SetWindowTextA(hWnd, String);
      return 0;
    }
    EndDialog(hWnd, (unsigned __int16)a3);
  }
  return 1;
//可以直接看出flag就是BJD{1999902069a45792d233ac}

[SWPUCTF 2021 新生赛]fakebase

题目描述

flag = 'xxxxxxxxxxxxxxxxxxx'

s_box = 'qwertyuiopasdfghjkzxcvb123456#$'
tmp = ''
for i in flag:
    tmp += str(bin(ord(i)))[2:].zfill(8)
b1 = int(tmp,2)
s = ''
while b1//31 != 0:
    s += s_box[b1%31]
    b1 = b1//31

print(s)

# s = u#k4ggia61egegzjuqz12jhfspfkay

exp

# 回到题目本身我们我肯可以得到s的值,其中s的值都是s_box中取的,因此[b1%31]是可以得知的。
# 类似于十进制转二进制的“除二取余法”,但是循环成立条件为b1//31 != 0,所以缺少最后一个数,需要从0-30间进行爆破,进而得到num,转为flag
from Crypto.Util.number import *
s_box = 'qwertyuiopasdfghjkzxcvb123456#$'
s = 'u#k4ggia61egegzjuqz12jhfspfkay'
tmp=''
num=0
for final in range(31):
    num=final
    for i in s[::-1]:
        num=num*31+s_box.index(i)
    if "CTF" in str(long_to_bytes(num)):
        print(long_to_bytes(num))
#b'NSSCTF{WHAt_BASe31}'

[NISACTF 2022]ezpython

题目描述

pyinstaller是对python打包的第三方库,这个地方是把python程序打包成exe了。。。那我们应该先去拿到原本python源代码。。

  • 拿到pyc字节码文件
python pyinstxtractor.py ez_python.exe
  • 拿到源代码
    这个地方我是直接用uncompyle6就拿到源代码了
uncompyle6 src.py > out.py
# Visit https://www.lddgo.net/string/pyc-compile-decompile for more information
# Version : Python 3.4

import rsa
import base64
key1 = rsa.PrivateKey.load_pkcs1(base64.b64decode('LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcVFJQkFBS0NBUUVBcVJUZ0xQU3BuT0ZDQnJvNHR1K1FBWXFhTjI2Uk42TzY1bjBjUURGRy9vQ1NJSU00ClNBeEVWaytiZHpSN2FucVNtZ1l5MEhRWGhDZTM2U2VGZTF0ejlrd0taL3UzRUpvYzVBSzR1NXZ4UW5QOWY1cTYKYVFsbVAvVjJJTXB5NFFRNlBjbUVoNEtkNm81ZWRJUlB2SHd6V0dWS09OQ3BpL0taQ082V0tWYkpXcWh3WGpEQgpsSDFNVURzZ1gyVUM4b3Bodnk5dXIyek9kTlBocElJZHdIc1o5b0ZaWWtaMUx5Q0lRRXRZRmlKam1GUzJFQ1RVCkNvcU9acnQxaU5jNXVhZnFvZlB4eHlPb2wwYVVoVGhiaHE4cEpXL3FPSFdYd0xJbXdtNk96YXFVeks4NEYyY3UKYWRiRE5zeVNvaElHaHYzd0lBVThNSlFnOEthd1Z3ZHBzRWhlSXdJREFRQUJBb0lCQURBazdwUStjbEZtWHF1Vgp1UEoyRWxZdUJpMkVnVHNMbHZ0c1ltL3cyQnM5dHQ0bEh4QjgxYlNSNUYyMEJ2UlJ4STZ3OXlVZCtWZzdDd1lMCnA5bHhOL3JJdWluVHBkUEhYalNhaGNsOTVOdWNOWEZ4T0dVU05SZy9KNHk4dUt0VHpkV3NITjJORnJRa0o4Y2IKcWF5czNOM3RzWTJ0OUtrUndjbUJGUHNJalNNQzB5UkpQVEE4cmNqOFkranV3SHZjbUJPNHVFWXZXeXh0VHR2UQova0RQelBqdTBuakhkR055RytkSDdkeHVEV2Jxb3VZQnRMdzllZGxXdmIydTJ5YnZzTXl0NWZTOWF1a01NUjNoCnBhaDRMcU1LbC9ETTU3cE44Vms0ZTU3WE1zZUJLWm1hcEptcVNnSGdjajRPNWE2R1RvelN1TEVoTmVGY0l2Tm8KWFczTEFHRUNnWWtBc0J0WDNVcFQ3aUcveE5BZDdSWER2MENOY1k1QnNZOGY4NHQ3dGx0U2pjSWdBKy9nUjFMZQpzb2gxY1RRd1RadUYyRTJXL1hHU3orQmJDTVVySHNGWmh1bXV6aTBkbElNV3ZhU0dvSlV1OGpNODBlUjRiVTRyCmdYQnlLZVZqelkzNVlLejQ5TEVBcFRQcTZRYTVQbzhRYkF6czhuVjZtNXhOQkNPc0pQQ29zMGtCclFQaGo5M0cKOFFKNUFQWEpva0UrMmY3NXZlazZNMDdsaGlEUXR6LzRPYWRaZ1MvUVF0eWRLUmg2V3VEeGp3MytXeXc5ZjNUcAp5OXc0RmtLRzhqNVRpd1RzRmdzem94TGo5TmpSUWpqb3cyVFJGLzk3b2NxMGNwY1orMUtsZTI1cEJ3bk9yRDJBCkVpMUVkMGVEV3dJR2gzaFhGRmlRSzhTOG5remZkNGFMa1ZxK1V3S0JpRXRMSllIamFZY0N2dTd5M0JpbG1ZK0gKbGZIYkZKTkowaXRhazRZZi9XZkdlOUd6R1h6bEhYblBoZ2JrZlZKeEVBU3ZCOE5NYjZ5WkM5THdHY09JZnpLRApiczJQMUhuT29rWnF0WFNxMCt1UnBJdEkxNFJFUzYySDJnZTNuN2dlMzJSS0VCYnVKb3g3YWhBL1k2d3ZscUhiCjFPTEUvNnJRWk0xRVF6RjRBMmpENmdlREJVbHhWTUVDZVFDQjcyUmRoYktNL3M0TSsvMmYyZXI4Y2hwT01SV1oKaU5Hb3l6cHRrby9sSnRuZ1RSTkpYSXdxYVNCMldCcXpndHNSdEhGZnpaNlNyWlJCdTd5Y0FmS3dwSCtUd2tsNQpoS2hoSWFTNG1vaHhwUVNkL21td1JzbTN2NUNDdXEvaFNtNmNXYTdFOVZxc25heGQzV21tQ2VqTnp0MUxQWUZNCkxZMENnWWdKUHhpVTVraGs5cHB6TVAwdWU0clA0Z2YvTENldEdmQjlXMkIyQU03eW9VM2VsMWlCSEJqOEZ3UFQKQUhKUWtCeTNYZEh3SUpGTUV1RUZSSFFzcUFkSTlYVDBzL2V0QTg1Y3grQjhjUmt3bnFHakFseW1PdmJNOVNrMgptMnRwRi8rYm56ZVhNdFA3c0ZoR3NHOXJ5SEZ6UFNLY3NDSDhXWWx0Y1pTSlNDZHRTK21qblAwelArSjMKLS0tLS1FTkQgUlNBIFBSSVZBVEUgS0VZLS0tLS0K'))
key2 = rsa.PublicKey.load_pkcs1(base64.b64decode('LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JSUJDZ0tDQVFFQXFSVGdMUFNwbk9GQ0JybzR0dStRQVlxYU4yNlJONk82NW4wY1FERkcvb0NTSUlNNFNBeEUKVmsrYmR6UjdhbnFTbWdZeTBIUVhoQ2UzNlNlRmUxdHo5a3dLWi91M0VKb2M1QUs0dTV2eFFuUDlmNXE2YVFsbQpQL1YySU1weTRRUTZQY21FaDRLZDZvNWVkSVJQdkh3eldHVktPTkNwaS9LWkNPNldLVmJKV3Fod1hqREJsSDFNClVEc2dYMlVDOG9waHZ5OXVyMnpPZE5QaHBJSWR3SHNaOW9GWllrWjFMeUNJUUV0WUZpSmptRlMyRUNUVUNvcU8KWnJ0MWlOYzV1YWZxb2ZQeHh5T29sMGFVaFRoYmhxOHBKVy9xT0hXWHdMSW13bTZPemFxVXpLODRGMmN1YWRiRApOc3lTb2hJR2h2M3dJQVU4TUpRZzhLYXdWd2Rwc0VoZUl3SURBUUFCCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0K'))

def encrypt1(message):
    crypto_text = rsa.encrypt(message.encode(), key2)
    return crypto_text


def decrypt1(message):
    message_str = rsa.decrypt(message, key1).decode()
    return message_str


def encrypt2(tips, key):
    ltips = len(tips)
    lkey = len(key)
    secret = []
    num = 0
    for each in tips:
        if num >= lkey:
            num = num % lkey
        secret.append(chr(ord(each) ^ ord(key[num])))
        num += 1
    
    return base64.b64encode(''.join(secret).encode()).decode()


def decrypt2(secret, key):
    tips = base64.b64decode(secret.encode()).decode()
    ltips = len(tips)
    lkey = len(key)
    secret = []
    num = 0
    for each in tips:
        if num >= lkey:
            num = num % lkey
        secret.append(chr(ord(each) ^ ord(key[num])))
        num += 1
    
    return ''.join(secret)

flag = 'IAMrG1EOPkM5NRI1cChQDxEcGDZMURptPzgHJHUiN0ASDgUYUB4LGQMUGAtLCQcJJywcFmddNno/PBtQbiMWNxsGLiFuLwpiFlkyP084Ng0lKj8GUBMXcwEXPTJrRDMdNwMiHVkCBFklHgIAWQwgCz8YQhp6E1xUHgUELxMtSh0xXzxBEisbUyYGOx1DBBZWPg1CXFkvJEcxO0ADeBwzChIOQkdwXQRpQCJHCQsaFE4CIjMDcwswTBw4BS9mLVMLLDs8HVgeQkscGBEBFSpQFQQgPTVRAUpvHyAiV1oPE0kyADpDbF8AbyErBjNkPh9PHiY7O1ZaGBADMB0PEVwdCxI+MCcXARZiPhwfH1IfKitGOF42FV8FTxwqPzBPAVUUOAEKAHEEP2QZGjQVV1oIS0QBJgBDLx1jEAsWKGk5Nw03MVgmWSE4Qy5LEghoHDY+OQ9dXE44Th0='
key = 'this is key'

try:
    result = input('please input key: ')
    if result == decrypt2('AAAAAAAAAAAfFwwRSAIWWQ==', key):
        print(decrypt1(base64.b64decode(decrypt2(flag, result))))
    elif result == key:
        print('flag{0e26d898-b454-43de-9c87-eb3d122186bc}')
    else:
        print('key is error.')
except Exception:
    e = None
    
    try:
        pass
    finally:
        e = None
        del e

关键是要逆向出真的key,然后输入真的key得到flag

exp


import base64
def decrypt2(secret, key):
    tips = base64.b64decode(secret.encode()).decode()
    ltips = len(tips)
    lkey = len(key)
    secret = []
    num = 0
    for each in tips:
        if num >= lkey:
            num = num % lkey
        secret.append(chr(ord(each) ^ ord(key[num])))
        num += 1
    
    return ''.join(secret)
key = 'this is key'
print(decrypt2('AAAAAAAAAAAfFwwRSAIWWQ==',key))
#this is true key
#OUTPUT:
#please input key: this is true key
#flag{5236cb7d-f4a7-4080-9bde-8b9e061609ad}

[LitCTF 2023]enbase64

题目描述

换表base64

exp

import base64
enc="GQTZlSqQXZ/ghxxwhju3hbuZ4wufWjujWrhYe7Rce7ju"
code="gJ1BRjQie/FIWhEslq7GxbnL26M4+HXUtcpmVTKaydOP38of5v90ZSwrkYzCAuND"
coder=str.maketrans(code, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789==")
flag=enc.translate(coder)
print(base64.b64decode(flag))
b'LitCTF{B@5E64_l5_tooo0_E3sy!!!!!}'

[HUBUCTF 2022 新生赛]ezPython

题目描述

给了一个pyc文件,直接在线反编译得到源码

# Visit https://www.lddgo.net/string/pyc-compile-decompile for more information
# Version : Python 3.7

from Crypto.Util.number import *
import base64
import base58
password = open('password.txt', 'r').read()
tmp = bytes_to_long(password.encode('utf-8'))
ans = base64.b64encode(base58.b58encode(str(tmp))).decode()
print("I've forgot my password,could you please help me find the password?")
if ans == 'M0hBajFITHVLcWV6R1BOcEM5MTR0R0J3eGZVODV6MTJjZUhGZFNHQw==':
    print('You get the password!')
else:
    print('Wrong! try again')

exp

from Crypto.Util.number import *
import base58
import base64
import hashlib
ans='M0hBajFITHVLcWV6R1BOcEM5MTR0R0J3eGZVODV6MTJjZUhGZFNHQw=='
password=base58.b58decode(base64.b64decode(ans))
print(long_to_bytes(int(password)))#b'HUBUCTF@1405'
flag=hashlib.md5(b'HUBUCTF@1405').hexdigest()
print(flag) #fd78ee3399dd6a3c1d0b637fdca0c075

[SWPUCTF 2021 新生赛]easyapp

题目描述

这个题目是安卓逆向。
根本没有做过这种题目,通过观看别人的wp知道了这题是要用到jadx反编译工具。
下面附带下载链接:
https://blog.csdn.net/weixin_39142112/article/details/80356244
把文件丢进jadx里分析
我们需要找到这三个关键函数
NSSIMAGE
135435
NSSIMAGE
首先查看关键信息,我们在第一个函数中能找到的关键信息就是这一串类似于乱码的字符串
135624
我们在第二个函数中得到的信息是key的值是123456789然后在下面的for循环中看到了异或加密算法,看到这里我大概就懂了,应该就是把那串字符串去异或这个key。
NSSIMAGE
我们再来看看最后一个函数干了什么,这个函数好像把key的值修改了,它把123456789改成了987654321.
NSSIMAGE

exp

enc="棿棢棢棲棥棷棊棐棁棚棨棨棵棢棌"
key=987654321
flag=""
for char in enc:
    flag+=chr((ord(char)^key)%128)  #因为ASCII字符集只有128个字符,所以如果不取模,那么异或运算的结果可能超出ASCII范围,导致无法正确解密。取模128可以保证结果在0到127之间,也就是ASCII字符集的有效范围。
print(flag)
#NSSCTF{apkYYDS}

[GDOUCTF 2023]Check_Your_Luck(z3)

题目描述

#include <iostream>
using namespace std;

void flag_checker(int v, int w,int x,int y,int z); 

int main(){
	int v,w,x,y,z;
	cout << "Input 5 random number and check your luck ;)" << endl;
	cout << "Num1: ";
	cin >> v;
	cout << "Num2: ";
	cin >> w;
	cout << "Num3: ";
	cin >> x;
	cout << "Num4: ";
	cin >> y;
	cout << "Num5: ";
	cin >> z;
	cout << endl;
	flag_checker(v,w,x,y,z);
}


void flag_checker(int v,int w, int x, int y, int z){
	if ((v * 23 + w * -32 + x * 98 + y * 55 + z * 90 == 333322) &&
		(v * 123 + w * -322 + x * 68 + y * 67 + z * 32 == 707724) &&
		(v * 266 + w * -34 + x * 43 + y * 8 + z * 32 == 1272529) &&
		(v * 343 + w * -352 + x * 58 + y * 65 + z * 5 == 1672457) &&
		(v * 231 + w * -321 + x * 938 + y * 555 + z * 970 == 3372367)){
			cout << "Congratulations, Here is your flag:\n";
			cout << "flag{" << v << "_" << w << "_" << x << "_" << y << "_" << z << "}" << endl;
		}
		else{
			cout << "\nSeems your luck is not in favor right now!\nBetter luck next time!" << endl;
		}
}

显然是这是五元一次方程,高斯消元可以求解,这里为了方便直接z3一把梭

exp

from z3 import *

s=Solver()
v,w,x,y,z=Ints('v w x y z')
s.add(v * 23 + w * -32 + x * 98 + y * 55 + z * 90 == 333322)
s.add(v * 123 + w * -322 + x * 68 + y * 67 + z * 32 == 707724)
s.add(v * 266 + w * -34 + x * 43 + y * 8 + z * 32 == 1272529)
s.add(v * 343 + w * -352 + x * 58 + y * 65 + z * 5 == 1672457)
s.add(v * 231 + w * -321 + x * 938 + y * 555 + z * 970 == 3372367)

s.check()
print(s.model())
#[x = 677, w = 123, z = 777, v = 4544, y = 1754]

[HNCTF 2022 Week1]贝斯是什么乐器啊?

题目描述

base64后,加改减就可以

exp

import base64
enc="TlJRQFBBdTs4alsrKFI6MjgwNi5p"
enc_=base64.b64decode(enc.encode())
print(enc_)
flag=""
for i in range(len(enc_)):
    flag+=chr(enc_[i]+i)
print(flag)
#b'NRQ@PAu;8j[+(R:2806.i'
#NSSCTF{B@se64_HAHAHA}

[HNCTF 2022 Week1]X0r

题目描述

简单的异或

exp

arr=[1022,
  1003,
  1003,
  1019,
  996,
  1014,
  979,
  976,
  904,
  970,
  1007,
  905,
  971,
  1007,
  971,
  904,
  1007,
  981,
  985,
  971,
  977,
  973]
flag=""
for i in range(len(arr)):
    char=chr((arr[i]-900)^0x34)
    flag+=char
print(flag) #NSSCTF{x0r_1s_s0_easy}

[BJDCTF 2020]Easy

题目描述

ida pro动态调试,发现_ques函数是输出flag的函数,劫持输出流,设置eip到该函数的入口,直接F9

看命令行界面(要熟练使用ida调试的快捷键)

exp

HACKIT4FUN

[HGAME 2022 week1]easyasm

题目描述

  • 解题大致思路
    16位DOS,只能看汇编
    NSSIMAGE
    开头载入了两个数据dseg、seg001
    往上翻可以找到
    一个是提示字符
    NSSIMAGE
    一个是密文
    NSSIMAGE
    分析一下加密过程
    NSSIMAGE
    把每个数前四位和后四位交换,再与23异或
    构建解密脚本(注意还原后的结果%256,不然打不出来正确的结果)

exp

#每个字节的前四位和后四位交换,再与23异或
from Crypto.Util.number import *
Array=[145,  97,   1, 193,  65, 160,  96,  65, 209,  33, 
   20, 193,  65, 226,  80, 225, 226,  84,  32, 193, 
  226,  96,  20,  48, 209,  81, 192,  23]
flag=b''
for i in Array:
    print(bin(i))
    flag+=long_to_bytes((((i^23)<<4)+((i^23)>>4))%256)
print(flag)
# b'hgame{welc0me_to_4sm_w0rld}\x00'

[HUBUCTF 2022 新生赛]help

题目描述

发现有个CreateMap()函数,在它后面的跳转点打个断点,动态调试
NSSIMAGE
NSSIMAGE
进入CreateMap()按F5找map
NSSIMAGE

在Export data 中提取出来,编辑成16个一行

11111111111111111111111111111111
11000000000011111111111100111111
11001111110011111111111100111111
11001111110011110000001100111111
11001111110011110011001100111111
11001111110000000011001100111111
11001111111111110011001100111111
11001111111111110000001100111111
11001111111111111100111100111111
11001111111111111100111100111111
11000000001111000000001100000011
11111111001111111100111100110011
11111111001111111100111100110011
11000000001111111100111100110000
11001111111111111100000000111111  
11001111111111111111111111111111   (15,1)是起点  
wwdddwwwaaawwwwwwwwwddddssssdddssdsssssssdddwwwwddsssd
NSSIMAGE 在check()函数可以发现步法,以及初始位置(1,15) 那么接下来就只需要找路了 找到之后转md5

exp(迷宫万用脚本dfs)

#可视化
dirs=[(0,1),(1,0),(0,-1),(-1,0)] #当前位置四个方向的偏移量
path=[]              #存找到的路径
 
def mark(maze,pos):  #给迷宫maze的位置pos标"2"表示“倒过了”
    maze[pos[0]][pos[1]]=2
 
def passable(maze, pos):
    rows, cols = len(maze), len(maze[0])
    return 0 <= pos[0] < rows and 0 <= pos[1] < cols and maze[pos[0]][pos[1]] == 0

 
def find_path(maze,pos,end):
    mark(maze,pos)
    if pos==end:
        # print(pos,end=" ")  #已到达出口,输出这个位置。成功结束
        path.append(pos)
        return True
    for i in range(4):      #否则按四个方向顺序检查
        nextp=pos[0]+dirs[i][0],pos[1]+dirs[i][1]
        #考虑下一个可能方向
        if passable(maze,nextp):        #不可行的相邻位置不管
            if find_path(maze,nextp,end):#如果从nextp可达出口,输出这个位置,成功结束
                # print(pos,end="")
                path.append(pos)
                return True
    return False
 
def see_path(maze,path):     
    #使寻找到的路径可视化
    for i in range(len(path)-1, 0, -1):
        current_pos = path[i - 1]
        next_pos = path[i]
        direction = ""
        if current_pos[0] < next_pos[0]:
            direction = "w"  # 向下走
        elif current_pos[0] > next_pos[0]:
            direction = "s"  # 向上走
        elif current_pos[1] < next_pos[1]:
            direction = "a"  # 向右走
        elif current_pos[1] > next_pos[1]:
            direction = "d"  # 向左走
        print(direction, end="")

    for i,p in enumerate(path):
        if i==0:
            maze[p[0]][p[1]] ="E"
        elif i==len(path)-1:
            maze[p[0]][p[1]]="S"
        else:
            maze[p[0]][p[1]] =3
    print("\n")
    for r in maze:
        for c in r:
            if c==3:
                print('\033[0;31m'+"*"+" "+'\033[0m',end="")
            elif c=="S" or c=="E":
                print('\033[0;34m'+c+" " + '\033[0m', end="")
            elif c==2:
                print('\033[0;32m'+"#"+" "+'\033[0m',end="")
            elif c==1:
                print('\033[0;;40m'+" "*2+'\033[0m',end="")
            else:
                print(" "*2,end="")
        print()
 
if __name__ == '__main__':
    maze =[[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],\
    [1,0,0,0,0,0,1,1,1,1,1,1,0,1,1,1],\
    [1,0,1,1,1,0,1,1,1,1,1,1,0,1,1,1],\
    [1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,1],\
    [1,0,1,1,1,0,1,1,0,1,0,1,0,1,1,1],\
    [1,0,1,1,1,0,0,0,0,1,0,1,0,1,1,1],\
    [1,0,1,1,1,1,1,1,0,1,0,1,0,1,1,1],\
    [1,0,1,1,1,1,1,1,0,0,0,1,0,1,1,1],\
    [1,0,1,1,1,1,1,1,1,0,1,1,0,1,1,1],\
    [1,0,1,1,1,1,1,1,1,0,1,1,0,1,1,1],\
    [1,0,0,0,0,1,1,0,0,0,0,1,0,0,0,1],\
    [1,1,1,1,0,1,1,1,1,0,1,1,0,1,0,1],\
    [1,1,1,1,0,1,1,1,1,0,1,1,0,1,0,1],\
    [1,0,0,0,0,1,1,1,1,0,1,1,0,1,0,0],\
    [1,0,1,1,1,1,1,1,1,0,0,0,0,1,1,1],\
    [1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1]]
    start=(15,1)
    end=(13,15)
    path.clear()  # 清空路径列表
    find_path(maze,start,end)
    see_path(maze,path)
 #wwdddwwwaaawwwwwwwwwddddssssdddssdsssssssdddwwwwddsssd

[HNCTF 2022 Week1]你知道什么是Py嘛?

题目描述

s = str(input("please input your flag:"))
arr=[29, 0, 16, 23, 18, 61, 43, 41, 13, 28, 88, 94, 49, 110, 66, 44, 43, 28, 91, 108, 61, 7, 22, 7, 43, 51, 44, 46, 9, 18, 20, 6, 2, 24]
if(len(s)!=35  or s[0]!='N'):
    print("error")
    exit(0)
for i in range(1,len(s)):
    if(ord(s[i-1])^ord(s[i])!=arr[i-1]):
        print("error!")
        exit(0)
print("right!")

exp

arr=[29, 0, 16, 23, 18, 61, 43, 41, 13, 28, 88, 94, 49, 110, 66, 44, 43, 28, 91, 108, 61, 7, 22, 7, 43, 51, 44, 46, 9, 18, 20, 6, 2, 24]
flag=['N']
for i in range(34):
    flag_list=chr(arr[i]^ord(flag[i]))
    flag.append(flag_list)
print("".join(flag))
#NSSCTF{Pyth0n_1s_th3_best_l@nguage}

[NSSRound#3 Team]jump_by_jump_revenge

题目描述

翻一翻,有个地方爆红了,是花指令。
NSSIMAGE
选中红的这里,按’U’,用16进制显示,把"0E90"NOP掉。
NSSIMAGE
重新对main函数反编译,F5可以查看到正常的伪代码。
NSSIMAGE

exp

'''''''''''''''''这是正向流程
for i in range(28):

    k=(i*i+123)%21

    a[i]=(a[i]+a[k]) % 0x60 + 0x20
'''''''''''''''''
a="~4G~M:=WV7iX,zlViGmu4?hJ0H-Q*"
a=list(a)
for i in range(28,-1,-1):
    k=(i*i+123)%21
    for j in range(3):
        x=(ord(a[i])-0x20+j*0x60-ord(a[k]))
        if x>=33 and x<=126:
            a[i]=chr(x)
            break
print("".join(a))

[羊城杯 2020]easyre

题目描述

第二重加密

__int64 __fastcall encode_two(const char *a1, int a2, char *a3, int *a4)
{
  char *Source; // [rsp+40h] [rbp+10h]
  char *v6; // [rsp+50h] [rbp+20h]
  Source = (char *)a1;
  v6 = a3;
  if ( !a1 || !a2 )
    return 0xFFFFFFFFi64;
  strncpy(a3, a1 + 26, 0xDui64);
  strncpy(v6 + 13, Source, 0xDui64);
  strncpy(v6 + 26, Source + 39, 0xDui64);
  strncpy(v6 + 39, Source + 13, 0xDui64);
  return 0i64;
}

encode_two(&v10, v4, &v9, &v12) == 0

根据前面的推断,第三个参数应该是加密后的密文,用一个Source指针指向原来的明文,然后进行strncpy操作

strncpy(a3, a1 + 26, 0xDui64);

strncpy(v6 + 13, Source, 0xDui64);

strncpy(v6 + 26, Source + 39, 0xDui64);

strncpy(v6 + 39, Source + 13, 0xDui64);

就是一个简单的替换加密

第三重加密

__int64 __fastcall encode_three(const char *flag3, int lflag3, char *str1, int *a4)
{
  char v5; // [rsp+Fh] [rbp-11h]
  int i; // [rsp+14h] [rbp-Ch]
  const char *strflag3index; // [rsp+30h] [rbp+10h]

  strflag3index = flag3;
  if ( !flag3 || !lflag3 )
    return 0xFFFFFFFFi64;
  for ( i = 0; i < lflag3; ++i )
  {
    v5 = *strflag3index;
    if ( *strflag3index <= 64 || v5 > 90 )
    {
      if ( v5 <= '`' || v5 > 'z' )
      {
        if ( v5 <= '/' || v5 > '9' )
          *str1 = v5;
        else
          *str1 = (v5 - '0' + 3) % 10 + '0';
      }
      else
      {
        *str1 = (v5 - 'a' + 3) % 26 + 'a';
      }
    }
    else
    {
      *str1 = (v5 - 'A' + 3) % 26 + 'A';
    }
    ++str1;
    ++strflag3index;
  }
  return 0i64;
}

这实际上是右移量为3的凯撒加密算法

exp

'''正向过程
先base64加密
再encode2位交换
再encode3凯撒加密   
'''
import base64
Str1="EmBmP5Pmn7QcPU4gLYKv5QcMmB3PWHcP5YkPq3=cT6QckkPckoRG"
def decrypt_caesar(str,key=3): #解谜函数
    text=""
    for i in str:
        if ord(i) >= 65 and ord(i) <= 90:
            text += chr(65 + ((ord(i) - 65) - key) % 26)
        elif ord(i) >= 97 and ord(i) <= 122:
            text += chr(97 + ((ord(i) - 97) - key) % 26)
        elif ord(i) >= 48 and ord(i) <= 57:
            text += chr(48 + ((ord(i) - 48) - key) % 10)
        else:
            text+=i
    return text
flag3=decrypt_caesar(Str1)
flag2=flag3[13:26]+flag3[39:]+flag3[0:13]+flag3[26:39]
while len(flag2) % 4 != 0:
    flag2 += "="
flag1=base64.b64decode(flag2.encode())
print(flag1) #b'GWHT{672cc4778a38e80cb362987341133ea2}'

[GWCTF 2019]pyre

题目描述

print "Welcome to Re World!"
print "Your input1 is your flag~"
l = len(input1)
for i in range(l):
    num = ((input1[i] + i) % 128 + 128) % 128
    code += num
for i in range(l - 1):
    code[i] = code[i] ^ code[i + 1]
print code
code = [
    "%1f",
    "%12",
    "%1d",
    "(",
    "0",
    "4",
    "%01",
    "%06",
    "%14",
    "4",
    ",",
    "%1b",
    "U",
    "?",
    "o",
    "6",
    "*",
    ":",
    "%01",
    "D",
    ";",
    "%",
    "%13",
]

exp

code = ["\x1f","\x12","\x1d","(","0","4","\x01","\x06","\x14","4",",","\x1b","U","?","o","6","*",":","\x01","D",";","%","\x13",]
l=len(code)
code=[ord(i)for i in code]
for i in range(l-2,-1,-1):
    code[i]=code[i]^code[i+1]
flag=''
for i in range(l):
    for j in range(33,127):
        if code[i] == ((j+i)%128+128)%128:
            flag+=chr(j)
print(flag) #GWHT{Just_Re_1s_Ha66y!}

[广东省大学生攻防大赛 2022]pyre

题目描述

def check():
    a = input("plz input your flag:")
    c = [
    144, 163, 158, 177, 121, 39, 58, 58, 91, 111, 25, 158, 72, 53, 152, 78, 171, 12, 53, 105, 45, 12, 12, 53, 12, 171, 111, 91, 53, 152, 105, 45, 152, 144, 39, 171, 45, 91, 78, 45, 158, 8
]  
    for i in range(len(a)):
        if ord(a[i]) * 33 % b != c[i]:
            print("wrong")
            return None
    print("win")

exp

c = [
    144, 163, 158, 177, 121, 39, 58, 58, 91, 111, 25, 158, 72, 53, 152, 78, 171, 12, 53, 105, 45, 12, 12, 53, 12, 171, 111, 91, 53, 152, 105, 45, 152, 144, 39, 171, 45, 91, 78, 45, 158, 8
]
a=[]
b=2
i=0
while True:
    for i in range(len(c)):
        for j in range(33,127):
            if j*33%b == c[i]:
                a.append(chr(j))
    if 'flag' in "".join(a):
        print("".join(a))#flag{2889e7a3-0d6b-4cbb-b6e9-04c0f26c9dca}
        print(f"{b}")   #179
    b+=1
    a.clear()

[MoeCTF 2022]chicken_soup

题目描述

首先进入查壳,在进入到IDA
发现有两个加密函数
NSSIMAGE
进去看一看
发现互补跳转的花指令
NSSIMAGE
接着手动修改花指令,根据跳转的字节大小(为一个字节),外面将跳转后面的一个字节nop(修改为90)掉就ok了
NSSIMAGE
按p定义函数后按F5就可以看到源代码了:
NSSIMAGE
另一个加密函数同样的方法操作。
接着后面有一个函数点进去看,发现是比较字符串的函数,在内存中找到加密后的密文,注意长度为38.
NSSIMAGE
拿出来用脚本反向解密拿到flag。

exp

Array=[205,  77, 140, 125, 173,  30, 190,  74, 138, 125, 
  188, 124, 252,  46,  42, 121, 157, 106,  26, 204, 
   61,  74, 248,  60, 121, 105,  57, 217, 221, 157, 
  169, 105,  76, 140, 221,  89, 233, 215]
'''正向过程
第一个函数:
flag2[i]=flag[i]+flag[i+1]
第二个函数:
Array[i]=(16*flag2[i])|flag2[i]>>4  前四位后四位互换
'''
flag2=[]
for i in Array:
    flag2.append((((i&0xf0)>>4)|((i&0xf)<<4)))
for i in range(len(Array)-2,-1,-1):
    flag2[i]=flag2[i]-flag2[i+1]
flag2=[chr(i)for i in flag2]
print("".join(flag2))#moectf{p4tch_pr0gr4m_t0_d3c0mpi1e_it!}

[LitCTF 2023]snake(pyc文件头修复)

题目描述

直接反编译发现magic number不对

python 3.7生成的 pyc 文件前32个字节

42 0D 0D 0A
所以拖进010editor修改前4个字节保存再反编译
然后把代码中flag附近的拖出来,转成字符串输出

MagicNumber详解

扒出源码后直接运行出flag的代码

exp

flag = [
        30, 196,
        52, 252, 49, 220, 7, 243,
        3, 241, 24, 224, 40, 230,
        25, 251, 28, 233, 40, 237,
        4, 225, 4, 215, 40, 231,
        22, 237, 14, 251, 10, 169]
for i in range(0, len(flag), 2):
    flag[i] ,flag[i + 1] = flag[i + 1] ^ 136,flag[i] ^ 119
flag=[chr(i)for i in flag]
print("".join(flag)) #LitCTF{python_snake_is_so_easy!}

这个题有个很坑的地方,pycdc反编译好有错误,flag[i] = flag[i + 1] ^ 136 flag[i + 1] = flag[i] ^ 119

uncompyle6才能正确反编译成功flag[i] ,flag[i + 1] = flag[i + 1] ^ 136,flag[i] ^ 119

遇到坑的时候可以两个引擎都试试对照一下

[SWPUCTF 2021 新生赛]astJS(js逆向)

题目描述

使用 npm 包 escodegen 解密

  1. 安装 escodegen
npm i escodegen -g
$ esgenerate 附件.json
(function () {
    function bE(str, key) {
        var arr = str.split('');
        return arr.map(i => {
            return String.fromCharCode(i.charCodeAt() ^ key);
        }).join('');
    }
    console.log(bE('EXXH_Mpjx\x7FBxYnjggrM~eerv', 11));
}());

执行语句即可获得 flag

$ node
Welcome to Node.js v14.13.1.
Type ".help" for more information.
> (function () {
...     function bE(str, key) {
.....         var arr = str.split('');
.....         return arr.map(i => {
.......             return String.fromCharCode(i.charCodeAt() ^ key);
.......         }).join('');
.....     }
...     console.log(bE('EXXH_Mpjx\x7FBxYnjggrM~eerv', 11));
... }());
NSSCTF{astIsReallyFunny}

[GDOUCTF 2023]Tea

题目描述

题目已经告诉我们这个是一个tea加密

查壳,无壳,打开ida找flag,交叉引用到主函数

IDA分析:

通过字符串窗口,我们可以找到字符串"you are right!\n".交叉引用(X键)到相关函数去.

字符串所在函数代码:

__int64 sub_140016230()
{
  char *v0; // rdi
  __int64 i; // rcx
  char v3[32]; // [rsp+0h] [rbp-20h] BYREF
  char v4; // [rsp+20h] [rbp+0h] BYREF
  int v5; // [rsp+24h] [rbp+4h]
  int v6; // [rsp+44h] [rbp+24h]
  int v7[12]; // [rsp+68h] [rbp+48h] BYREF
  _DWORD v8[16]; // [rsp+98h] [rbp+78h] BYREF
  int v9[31]; // [rsp+D8h] [rbp+B8h] BYREF
  int j; // [rsp+154h] [rbp+134h]
  int k; // [rsp+174h] [rbp+154h]
  int m; // [rsp+194h] [rbp+174h]

  v0 = &v4;
  for ( i = 102i64; i; --i )
  {
    *(_DWORD *)v0 = -858993460;
    v0 += 4;
  }
  sub_14001137F(&unk_140023009);
  v5 = 32;
  v6 = 0;
  v7[0] = 1234;
  v7[1] = 5678;
  v7[2] = 9012;
  v7[3] = 3456;
  memset(v8, 0, 0x28ui64);
  v9[15] = 0;
  v9[23] = 0;
  sub_1400113E8();
  for ( j = 0; j < 10; ++j )
    sub_1400111FE("%x", &v8[j]);
  sub_140011339(v7);
  sub_140011145(v8, v9);
  sub_1400112B7(v8, v7);
  v6 = sub_140011352(v8);
  if ( v6 )
  {
    sub_140011195("you are right\n");
    for ( k = 0; k < 10; ++k )
    {
      for ( m = 3; m >= 0; --m )
        sub_140011195("%c", (unsigned __int8)((unsigned int)v9[k] >> (8 * m)));
    }
  }
  else
  {
    sub_140011195("fault!\nYou can go online and learn the tea algorithm!");
  }
  sub_140011311(v3, &unk_14001AE90);
  return 0i64;
}

sub_1400113E8函数

__int64 sub_1400113E8(void)
{
  return sub_140011B00();
}

int sub_140011B00()
{
  sub_14001137F(&unk_140023009);
  printf("This is the input format for you geting of flag hex \n");
  printf("0x12345678 0x12345678 0x12345678 0x12345678 0x12345678 0x12345678 0x12345678\n");
  printf("The end of flag:\nHZCTF{This_is_the_fake_flag}\n");
  return printf("input your get the flag:\n");
}
  • 程序运行时,打印的东西
for ( j = 0; j < 10; ++j )
    scanf("%x", &v8[j]);
  • 对我们的v8数组输入十六进制字符串,因为在上一个函数中,指定了我们要输入字符串的格式为hex

sub_140011339函数

__int64 __fastcall sub_140011339(__int64 a1)
{
  return sub_1400117D0(a1);
}

__int64 __fastcall sub_1400117D0(_DWORD *a1)
{
  char *v1; // rdi
  __int64 i; // rcx
  char v4[32]; // [rsp+0h] [rbp-20h] BYREF
  char v5; // [rsp+20h] [rbp+0h] BYREF
  int v6; // [rsp+28h] [rbp+8h]
  int v7; // [rsp+2Ch] [rbp+Ch]
  int v8; // [rsp+30h] [rbp+10h]
  int v9; // [rsp+34h] [rbp+14h]

  v1 = &v5;
  for ( i = 14i64; i; --i )
  {
    *(_DWORD *)v1 = -858993460;
    v1 += 4;
  }
  sub_14001137F(&unk_140023009);
  v6 = 2233;
  v7 = 4455;
  v8 = 6677;
  v9 = 8899;
  *a1 = 2233;
  a1[1] = v7;
  a1[2] = v8;
  a1[3] = v9;
  return sub_140011311(v4, &unk_14001AD00);
}
  • 传入的参数为v7,但是在函数内部通过指针被改变了值
  • 原来的v7值为1234,5678,9012,3456
  • 改变后的v7值为2233,4455,6677,8899

sub_140011145(v8, v9);

代码如下:

__int64 __fastcall sub_140011145(__int64 a1, __int64 a2)
{
  return sub_140012030(a1, a2);
}

__int64 __fastcall sub_140012030(__int64 a1, __int64 a2)
{
  __int64 result; // rax
  int i; // [rsp+24h] [rbp+4h]

  result = sub_14001137F(&unk_140023009);
  for ( i = 0; i < 10; ++i )
  {
    *(_DWORD *)(a2 + 4i64 * i) = *(_DWORD *)(a1 + 4i64 * i);
    result = (unsigned int)(i + 1);
  }
  return result;
}
  • 传入的是v8,v9数组,实际上只是把v8数组的每个值赋给了v9

sub_1400112B7(v8, v7);

代码如下:

__int64 __fastcall sub_1400112B7(__int64 a1, __int64 a2)
{
  return sub_140011900(a1, a2);
}

__int64 __fastcall sub_140011900(__int64 a1, __int64 key)
{
  __int64 result; // rax
  int v3; // [rsp+44h] [rbp+24h]
  int i; // [rsp+64h] [rbp+44h]
  unsigned int v5; // [rsp+84h] [rbp+64h]
  unsigned int sum; // [rsp+C4h] [rbp+A4h]

  result = sub_14001137F(&unk_140023009);
  for ( i = 0; i <= 8; ++i )
  {
    v5 = 0;
    sum = 0xF462900 * i;                        // sum = delta * i
    v3 = i + 1;
    do
    {
      ++v5;
      *(_DWORD *)(a1 + 4i64 * i) += sum ^ (*(_DWORD *)(a1 + 4i64 * v3)
                                         + ((*(_DWORD *)(a1 + 4i64 * v3) >> 5) ^ (16 * *(_DWORD *)(a1 + 4i64 * v3)))) ^ (sum + *(_DWORD *)(key + 4i64 * (sum & 3)));
      *(_DWORD *)(a1 + 4i64 * v3) += (sum + *(_DWORD *)(key + 4i64 * ((sum >> 11) & 3))) ^ (*(_DWORD *)(a1 + 4i64 * i)
                                                                                          + ((*(_DWORD *)(a1 + 4i64 * i) >> 5) ^ (16 * *(_DWORD *)(a1 + 4i64 * i))));
      sum += 0xF462900;                         // sum += delta
    }
    while ( v5 <= 32 );                         // 循环32次
    result = (unsigned int)(i + 1);
  }
  return result;
}
  • 存在一个变量与一个固定的常数做运算,且常数不受影响,常数为0xF462900
  • 存在移位+异或运算
  • 存在Feistal结构,即把运算后的值相加并且给新的变量
  • do…while循环33次
  • for循环8次

通过上述信息,可以初步判断这个题目是一个魔改的Xtea算法

把加密过程逆过来

exp

key=[2233,4455,6677,8899]
value=[0x1A800BDA,0xF7A6219B,0x491811D8,0xF2013328,0x156C365B,0x3C6EAAD8,0x84D4BF28,0xF11A7EE7,0x3313B252,0xDD9FE279]
def x_tea_decrypt(value,key):
    delta=256256256
    for j in range(8,-1,-1):
        rounds=33
        sum=delta*(33+j) #注意i最大是8,所以还要+1
        for i in range(rounds):
            sum-=delta
            #注意这段逻辑被魔改了,做题的时候要慢慢来分析,&0xfffffff模拟32位
            value[i+1]-=(sum+key[(sum>>11)&3])^(value[i]+((value[i]>>5)^(value[i]<<4)))
            value[i+1]=value[i+1]&0xffffffff
            value[i]-=sum^((value[i+1])+((value[i+1]>>5)^(value[i+1]<<4)))^(sum+key[sum&3])
            value[i]=value[i]&0xffffffff
    return value
value=x_tea_decrypt(value,key)
for i in range(10):
    for j in range(3,-1,-1):
        print(chr((value[i]>>(8*j))&0xff),end="")  #&0xff模拟8位
 #HZCTF{hzCtf_94_re666fingcry5641qq}