buuctf-reverse


1

 

reverse3

一进去查看伪代码

 

15-19行 搜image-20220324110632271索算法常量发现是一个检验Destination字符结果的算法

发现24行v4是做了一个base64加密

没有发现有自带的字符串 说明可能是动态加密,而且也没有明显的反调试

于是dbg动调 找到加密完后的字符“e3nifIH9b_C@n@dH”

简单for循环解密再base64就行

#include <stdio.h>
#include <string.h>
signed int v11;
char Destination[108];
int main()
{
  const char *v4 = { "e3nifIH9b_C@n@dH" };
  strncpy(Destination, v4, 0x28u);
  v11 = strlen(Destination);
  for (int j = 0; j < v11; ++j)
  {
      Destination[j] -= j;
  }
  printf("%s", Destination);
}

SimpleRev

查看文件是elf

用ida64打开

伪代码如下

unsigned __int64 Decry()
{
char v1; // [rsp+Fh] [rbp-51h]
int v2; // [rsp+10h] [rbp-50h]
int v3; // [rsp+14h] [rbp-4Ch]
int i; // [rsp+18h] [rbp-48h]
int v5; // [rsp+1Ch] [rbp-44h]
char src[8]; // [rsp+20h] [rbp-40h] BYREF
__int64 v7; // [rsp+28h] [rbp-38h]
int v8; // [rsp+30h] [rbp-30h]
__int64 v9[2]; // [rsp+40h] [rbp-20h] BYREF
int v10; // [rsp+50h] [rbp-10h]
unsigned __int64 v11; // [rsp+58h] [rbp-8h]

v11 = __readfsqword(0x28u);
*(_QWORD *)src = 0x534C43444ELL;
v7 = 0LL;
v8 = 0;
v9[0] = 0x776F646168LL;
v9[1] = 0LL;
v10 = 0;
text = join(key3, (const char *)v9);
strcpy(key, key1);
strcat(key, src);
v2 = 0;
v3 = 0;
getchar();
v5 = strlen(key);
for ( i = 0; i < v5; ++i )
{
  if ( key[v3 % v5] > 64 && key[v3 % v5] <= 90 )
    key[i] = key[v3 % v5] + 32;
  ++v3;
}
printf("Please input your flag:");
while ( 1 )
{
  v1 = getchar();
  if ( v1 == 10 )
    break;
  if ( v1 == 32 )
  {
    ++v2;
  }
  else
  {
    if ( v1 <= '`' || v1 > 'z' )
    {
      if ( v1 > '@' && v1 <= 'Z' )
      {
        str2[v2] = (v1 - 39 - key[v3 % v5] + 97) % 26 + 97;
        ++v3;
      }
    }
    else
    {
      str2[v2] = (v1 - 39 - key[v3 % v5] + 97) % 26 + 97;
      ++v3;
    }
    if ( !(v3 % v5) )
      putchar(32);
    ++v2;
  }
}
if ( !strcmp(text, str2) )
  puts("Congratulation!\n");
else
  puts("Try again!\n");
return __readfsqword(0x28u) ^ v11;
}

伪代码流程解读(正向): 先是用一个自定义函数join来拼接(key3,v9 ),text用来接收拼接字符串,再用strcat拼接(key1,src),放入key中存储

for循环判断大小写,小写转换成大写

接下来就是接收输入,无论是否判断大小写,输入字符都和key做一个加减和取余26

最后再和text作对比

逆向想法过程:

因为key,和text在其中没有变换字符串,约等于他们是常量,然而要去余的逆运算,所以要放大取模倍数,符合大写条件的再打印出来

最后附上解密脚本:

#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <stdint.h>
#include <Windows.h>

char v1; // [rsp+Fh] [rbp-51h]
int v2; // [rsp+10h] [rbp-50h]
int v3; // [rsp+14h] [rbp-4Ch]
int i; // [rsp+18h] [rbp-48h]
int v5; // [rsp+1Ch] [rbp-44h]
__int64 src[1]; // [rsp+20h] [rbp-40h] BYREF
__int64 v7; // [rsp+28h] [rbp-38h]
int v8; // [rsp+30h] [rbp-30h]
__int64 v9[2]; // [rsp+40h] [rbp-20h] BYREF
int v10; // [rsp+50h] [rbp-10h]
unsigned __int64 v11; // [rsp+58h] [rbp-8h]
char key3[6] = { "kills" };
char str2[104];
char* __fastcall join(const char* a1, const char* a2)
{
size_t v2; // rbx
size_t v3; // rax
char* dest; // [rsp+18h] [rbp-18h]

v2 = strlen(a1);
v3 = strlen(a2);
dest = (char*)malloc(v2 + v3 + 1);
if (!dest)
exit(1);
strcpy(dest, a1);
strcat(dest, a2);
return dest;
}
int main()
{

src[0] = 0x534C43444ELL;
v9[0] = 0x776F646168LL;
v9[1] = 0LL;
char* test = join(key3, (const char*)v9);
char key1[] = { "ADSFK" };
char key[128];
strcpy(key, key1);

strcat(key, (const char *)src);

v5 = strlen(key);
char tmp;
char flag[10];

for (i = 0; i < v5; ++i)
{
if (key[v3 % v5] > 64 && key[v3 % v5] <= 90)
key[i] = key[v3 % v5] + 32;
++v3;
}


for (i = 0; i < 10; i++)//放大取模倍数
{
v3 = 10;
for (v2 = 0; v2 < 10; v2++)//十个字符
{
tmp = test[v2] - 97 + i * 26 - 97 + key[v3++ % v5] + 39;
if (tmp >= 65 && tmp <= 90)
flag[v2] = tmp;
                                   
}
}
printf("%s", flag);


}

这题总结:失误点:1.总想着直接逆,没有第一时间仔细看代码逻辑,导致最后浪费时间很多

2.对于这种求余的逆运算带括号的逆运算总是写错,要细心一点

经验:像这种16进制字符串v9[0] = 0x776F646168LL,用__int64(long long)来存储强行转换const char 既不会损失精度,也不会截断

Java逆向解密

jd-gui打开

伪代码如下:

import java.util.ArrayList;
import java.util.Scanner;

public class Reverse {
public static void main(String[] args) {
  Scanner s = new Scanner(System.in);
  System.out.println("Please input the flag :");
  String str = s.next();
  System.out.println("Your input is :");
  System.out.println(str);
  char[] stringArr = str.toCharArray();
  Encrypt(stringArr);
}
 
public static void Encrypt(char[] arr) {
  ArrayList<Integer> Resultlist = new ArrayList<>();
  for (int i = 0; i < arr.length; i++) {
    int result = arr[i] + 64 ^ 0x20;
    Resultlist.add(Integer.valueOf(result));
  }
  int[] KEY = {
      180, 136, 137, 147, 191, 137, 147, 191, 148, 136,
      133, 191, 134, 140, 129, 135, 191, 65 };
  ArrayList<Integer> KEYList = new ArrayList<>();
  for (int j = 0; j < KEY.length; j++)
    KEYList.add(Integer.valueOf(KEY[j]));
  System.out.println("Result:");
  if (Resultlist.equals(KEYList)) {
    System.out.println("Congratulations!");
  } else {
    System.err.println("Error!");
  }
}
}

很简单的每个字符+64^0x20

逆向过程就是-64^0x20

最后附上解密代码


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

int main()
{
  char KEY []= {
    180, 136, 137, 147, 191, 137, 147, 191, 148, 136,
    133, 191, 134, 140, 129, 135, 191, 65 };

    int len = strlen(KEY);
    for (int i = 0; i < len; i++)
    {
      int result = KEY[i] - 64 ^ 0x20;
      printf("%c", result);
    }


}

 

[GXYCTF2019]luck_guy

伪代码如下:

unsigned __int64 get_flag()
{
unsigned int v0; // eax
int i; // [rsp+4h] [rbp-3Ch]
int j; // [rsp+8h] [rbp-38h]
__int64 s; // [rsp+10h] [rbp-30h] BYREF
char v5; // [rsp+18h] [rbp-28h]
unsigned __int64 v6; // [rsp+38h] [rbp-8h]

v6 = __readfsqword(0x28u);
v0 = time(0LL);
srand(v0); //狡猾的骗局
for ( i = 0; i <= 4; ++i )
{
  switch ( rand() % 200 )
  {
    case 1:
      puts("OK, it's flag:");
      memset(&s, 0, 0x28uLL);
      strcat((char *)&s, f1);
      strcat((char *)&s, &f2);
      printf("%s", (const char *)&s);
      break;
    case 2:
      printf("Solar not like you");
      break;
    case 3:
      printf("Solar want a girlfriend");
      break;
    case 4:
      s = 0x7F666F6067756369LL;
      v5 = 0;
      strcat(&f2, (const char *)&s);
      break;
    case 5:
      for ( j = 0; j <= 7; ++j )
      {
        if ( j % 2 == 1 )
          *(&f2 + j) -= 2;
        else
          --*(&f2 + j);
      }
      break;
    default:
      puts("emmm,you can't find flag 23333");
      break;
  }
}
return __readfsqword(0x28u) ^ v6;
}

伪代码流程解读(正向):

先是跳转不同函数给地址赋值字符串

然后给f1和f2依次赋值(其中值得一提的是f1的是明文赋值,f2则要看汇编找到loc_4008CA:这个函数去得到赋值数据)

随机1到5 ,选择1,2,5就是正确的

随后就是很简单的爆破脚本

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

unsigned int v0; // eax
int i; // [rsp+4h] [rbp-3Ch]
int j; // [rsp+8h] [rbp-38h]
__int64 s; // [rsp+10h] [rbp-30h] BYREF
char v5; // [rsp+18h] [rbp-28h]
unsigned __int64 v6; // [rsp+38h] [rbp-8h]
char f1[] = { "GXY{do_not_" };

int check;
int main()
{
  char f2[256] = { 0x69,0x63,0x75,0x67,0x60,0x6F,0x66,0x7F };
  for(int t=0;t<=100;++t){
  for (i = 0; i <= 4; ++i)
  {
      check = rand() % 200;
      if(check==1 || check==4 || check==5)
      switch (check)
      {
      case 1:
          puts("OK, it's flag:");
          memset(&s, 0, 0x28uLL);
          strcat((char*)&s, f1);
          strcat((char*)&s, f2);
          printf("%s", (const char*)&s);
          break;
      case 2:
          printf("Solar not like you");
          break;
      case 3:
          printf("Solar want a girlfriend");
          break;
      case 4:
          s = 0x7F666F6067756369LL;
          v5 = 0;
          strcat((char *)&f2, (const char*)&s);
          break;
      case 5:
          for (j = 0; j <= 7; ++j)
          {
              if (j % 2 == 1)
                  *(f2 + j) -= 2;
              else
                  --* (f2 + j);
          }
          break;
      default:
          puts("emmm,you can't find flag 23333");
          break;
      }
  }
  }
}

[BJDCTF2020]JustRE

观看程序功能 发现一个模块getflag

盲猜getflag这里要动调 于是打开x32dbg

 

找到关键字image-20220326232741645符串 在前面几个关键跳下断点,nop常规操作后

发现flag,输入发现不对,于是打开ida观察

image-20220326232550222

image-20220326233131641

发现简单的把

BJD{199992069a45792d233ac}19999后面加个0就行

得到flag{1999902069a45792d233ac}

[GWCTF 2019]pyre

下载文件观察文件类型是pyc,百度找一个pyc在线反编译

伪代码如下:

#!/usr/bin/env python
# visit https://tool.lu/pyc/ for more information
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 = [
  '\x1f',
  '\x12',
  '\x1d',
  '(',
  '0',
  '4',
  '\x01',
  '\x06',
  '\x14',
  '4',
  ',',
  '\x1b',
  'U',
  '?',
  'o',
  '6',
  '*',
  ':',
  '\x01',
  'D',
  ';',
  '%',
  '\x13']

很简单的加密过程 先取模再和后一位异或

坑点在于其一这个去模要来一手,取模运算规则

运算规则

模运算与基本四则运算有些相似,但是除法例外。其规则如下:

  1. (a + b) % p = (a % p + b % p) % p (1)

 

其二是在于异或要注意伪代码里面的l-1,倒过来得是后面倒数第二位和倒数第三位开始异或解密过程

C语言脚本如下(由于某种特别力量输出flag会出错,暂且不知道原因)

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


int main()
{

  int code[] = {
      '\x1f',
  '\x12',
  '\x1d',
  '(',
  '0',
  '4',
  '\x01',
  '\x06',
  '\x14',
  '4',
  ',',
  '\x1b',
  'U',
  '?',
  'o',
  '6',
  '*',
  ':',
  '\x01',
  'D',
  ';',
  '%',
  '\x13' };
  char num[29];
  int l = 23;




  for (int i = l - 2; i > -1; i--)
  {


      code[i] = code[i] ^ code[i + 1];

  }
  for (int i = 0; i <= l; i++)
  {


      num[i] = (code[i] - i) % 128;

       
  }

  printf("%s", num);
}

rsa

image-20220408152113277

这种题google了一下rsa这种解密文件包的做法,主要就是用linux的openssl来解

题目思路:

pub.key了解一下rsa的文件解密,就会发现他其实是公钥,给E和N的,具体命令

openssl rsa -pubin -text -modulus -in warmup -in pub.key

得到16进制数字

python转换

s=''
int(s,16)

在线网站分解

 

image-20220408152535411

然后python解密

image-20220408152737275

CrackRTF

题目伪代码

int __cdecl main_0(int argc, const char **argv, const char **envp)
{
DWORD v3; // eax
DWORD v4; // eax
char Str[260]; // [esp+4Ch] [ebp-310h] BYREF
int v7; // [esp+150h] [ebp-20Ch]
char String1[260]; // [esp+154h] [ebp-208h] BYREF
char Destination[260]; // [esp+258h] [ebp-104h] BYREF

memset(Destination, 0, sizeof(Destination));
memset(String1, 0, sizeof(String1));
v7 = 0;
printf("pls input the first passwd(1): ");
scanf("%s", Destination);
if ( strlen(Destination) != 6 ) //判断输入的是不是六位
{
printf("Must be 6 characters!\n");
ExitProcess(0);
}
v7 = atoi(Destination);
if ( v7 < 100000 )
ExitProcess(0);
strcat(Destination, "@DBApp");
v3 = strlen(Destination);
sub_40100A((BYTE *)Destination, v3, String1); //sha1加密
if ( !_strcmpi(String1, "6E32D0943418C2C33385BC35A1470250DD8923A9") )//md5加密
{
printf("continue...\n\n");
printf("pls input the first passwd(2): ");
memset(Str, 0, sizeof(Str));
scanf("%s", Str);
if ( strlen(Str) != 6 )
{
printf("Must be 6 characters!\n");
ExitProcess(0);
}
strcat(Str, Destination);
memset(String1, 0, sizeof(String1));
v4 = strlen(Str);
sub_401019((BYTE *)Str, v4, String1);
if ( !_strcmpi("27019e688a4e62a649fd99cadaafdb4e", String1) )
{
if ( !(unsigned __int8)sub_40100F(Str) )
{
printf("Error!!\n");
ExitProcess(0);
}
printf("bye ~~\n");
}
}
return 0;
}

正向流程:

先输入一个6位字符,然后后面加上@DBApp,再把六位字符转换数字一下,判定他是否小于六位,然后一个sha1加密再进行对比

image-20220408153401956

像这种函数呢,google了一下是微软的一些官方加密函数,第二个参数是指运用什么加密算法image-20220408153508055

可以明显看到是sha1

接下来很明显是和一个md5字符串进行对比,但是和之前的截然不同,他是要获取这个rtf这个文件里面的资源文件AAA的头文件字符,然后进行md5加密

逆向过程:

先把sha1爆破出来,因为字符串转数字只能是6位,所以范围是100000,999999

写出爆破脚本,学了下hashlib这个库的用法

import hashlib

flag = "@DBApp"

for i in range(100000,999999):
s = str(i)+flag
x = hashlib.sha1(s.encode())
cnt = x.hexdigest()
if "6e32d0943418c2c" in cnt:
print(cnt)
print(str(i)+flag)

在打开ResourceHacker这个文件提取出rtf里面的aaa资源的头文件字符

因为也是6位,所以只需要截取前六位就好了

sub_401420这个函数里面对他进行了异或,我们照样操作就行

#include <stdio.h>

int main()
{
char enc[] = { 0x05, 0x7D, 0x41, 0x15,0x26,0x01,0x6D,0x53, 0x5D,0x40,0x5B,0x6D,0x21,0x24 };
char enc1[] = { 0x7b,0x5c,0x72,0x74,0x66,0x31 };
for (int i = 0; i <= 10; ++i)
{

enc[i] ^= enc1[i];
}
printf("%s", enc);
}

然后正常运行程序输入字符串就可以在当前文件夹得到一个rtf文件了,里面就有flag

flag{N0_M0re_Free_Bugs}

这道题经验:

先从题目的名字去分析,也不至于后面耗费那么多时间

这道题应该还能去动调直接得到第二个程序运行的结果,因为他先判断这个md5嘛,但是这个md5和题目运算出来的文件和flag并没有关系,所以跳过这个判断md5的应该也能得到flag

[FlareOn4]login

 

image-20220408155330980

经典html,像这种可逆算法(个人觉得如果有异或,多项判断的没有取模的应该都是可逆算法)

直接看下html语法 输入这个比较字符串再打印出来就行了

 

image-20220408155630978

[GUET-CTF2019]re

upx加壳,在仔细了看了看upx壳格式(hgame后遗症)没啥问题后,kali命令

upx -d

image-20220408155912337

伪代码流程图

image-20220408155957875

加密函数,经典方程式加密

直接上z3

要注意的是这里没有第七位,还有image-20220408160049497

16位和17位调换过来了,提取数据的时候要注意

上脚本

from z3 import *

a, c, b = Ints('a c b')
e, f, g = Ints('e f g')
h, i, k = Ints('h i k')
l, m, n = Ints('l m n')
o, p, q = Ints('o p q')
r, s, t = Ints('r s t')
u, v, w = Ints('u v w')
x1, y, z = Ints('x1 y z')
a1, b1, c1 = Ints('a1 b1 c1')
d1, e1, f1 = Ints('d1 e1 f1')


x = Solver()
x.add(a*1629056 == 166163712)
x.add(b*6771600 == 731332800)
x.add(c*10431000 == 1074393000)
x.add(e*3977328 == 489211344)
x.add(f*5138336 == 518971936)
x.add(g*7532250 == 406741500)
x.add(h*5551632 == 294236496)
x.add(i*3409728 == 177305856)
x.add(k*13013670 == 650683500)
x.add(l*6088797 == 298351053)
x.add(m*7884663 == 386348487)
x.add(n*8944053 == 438258597)
x.add(o*5198490 == 249527520)
x.add(p*4544518 == 445362764)
x.add(q*10115280 == 981182160)
x.add(r*3645600 == 174988800)
x.add(s* 9667504 == 493042704)
x.add(t* 5364450 == 257493600)
x.add(u* 13464540 == 767478780)
x.add(v* 5488432 == 312840624)
x.add(w* 14479500== 1404511500)
x.add(x1* 6451830 == 316139670)
x.add(y* 6252576 == 619005024)
x.add(z* 7763364 == 372641472)
x.add(a1* 7327320 == 373693320)
x.add(b1* 8741520 == 498266640)
x.add(c1* 8871876 == 452465676)
x.add(d1* 4086720 == 208422720)
x.add(e1* 9374400 == 515592000)
x.add(f1* 5759124 == 719890500)


check = x.check() //
print(check)
model = x.model()
print(model)
'''[f1 = 125,
e1 = 55,
d1 = 51,
c1 = 51,
b1 = 57,
a1 = 51,
z = 48,
y = 99,
x1 = 49,
w = 97,
v = 57,
u = 57,
t = 48,
s = 51,
r = 48,
q = 97,
p = 98,
o = 48,
n = 49,
m = 49,
l = 49,
k = 50,
i = 52,
h = 53,
g = 54,
f = 101,
e = 123,
c = 103,
b = 108,
a = 102]
'''

flag{e165421110ba03099a1c039337}

第七位爆破即可

[2019红帽杯]easyRE

伪代码流程

__int64 sub_4009C6()
{
__int64 result; // rax
int i; // [rsp+Ch] [rbp-114h]
__int64 v2; // [rsp+10h] [rbp-110h]
__int64 v3; // [rsp+18h] [rbp-108h]
__int64 v4; // [rsp+20h] [rbp-100h]
__int64 v5; // [rsp+28h] [rbp-F8h]
__int64 v6; // [rsp+30h] [rbp-F0h]
__int64 v7; // [rsp+38h] [rbp-E8h]
__int64 v8; // [rsp+40h] [rbp-E0h]
__int64 v9; // [rsp+48h] [rbp-D8h]
__int64 v10; // [rsp+50h] [rbp-D0h]
__int64 v11; // [rsp+58h] [rbp-C8h]
char v12[13]; // [rsp+60h] [rbp-C0h] BYREF
char v13[4]; // [rsp+6Dh] [rbp-B3h] BYREF
char v14[19]; // [rsp+71h] [rbp-AFh] BYREF
char v15[32]; // [rsp+90h] [rbp-90h] BYREF
int v16; // [rsp+B0h] [rbp-70h]
char v17; // [rsp+B4h] [rbp-6Ch]
char v18[72]; // [rsp+C0h] [rbp-60h] BYREF
unsigned __int64 v19; // [rsp+108h] [rbp-18h]

v19 = __readfsqword(0x28u);
qmemcpy(v12, "Iodl>Qnb(ocy", 12);
v12[12] = 127;
qmemcpy(v13, "y.i", 3);
v13[3] = 127;
qmemcpy(v14, "d`3w}wek9{iy=~yL@EC", sizeof(v14));
memset(v15, 0, sizeof(v15));
v16 = 0;
v17 = 0;
sub_4406E0(0LL, v15, 37LL);
v17 = 0;
if ( sub_424BA0(v15) == 36 )
{
  for ( i = 0; i < (unsigned __int64)sub_424BA0(v15); ++i )
  {
    if ( (unsigned __int8)(v15[i] ^ i) != v12[i] )
    {
      result = 4294967294LL;
      goto LABEL_13;
    }
  }
  sub_410CC0("continue!");
  memset(v18, 0, 0x40uLL);
  v18[64] = 0;
  sub_4406E0(0LL, v18, 64LL);
  v18[39] = 0;
  if ( sub_424BA0(v18) == 39 )
  {
    v2 = sub_400E44((__int64)v18);
    v3 = sub_400E44(v2);
    v4 = sub_400E44(v3);
    v5 = sub_400E44(v4);
    v6 = sub_400E44(v5);
    v7 = sub_400E44(v6);
    v8 = sub_400E44(v7);
    v9 = sub_400E44(v8);
    v10 = sub_400E44(v9);
    v11 = sub_400E44(v10);
    if ( !(unsigned int)sub_400360(v11, off_6CC090) )
    {
      sub_410CC0("You found me!!!");
      sub_410CC0("bye bye~");
    }
    result = 0LL;
  }
  else
  {
    result = 4294967293LL;
  }
}
else
{
  result = 0xFFFFFFFFLL;
}
LABEL_13:
if ( __readfsqword(0x28u) != v19 )
  sub_444020();
return result;
}

一开始看上去很简单,不就是一个异或,然后不断地base64加密嘛

直到我看到了这个

image-20220408160628673

然后就开始迷了,因为主函数就这些加密,好像似乎也没了

后来经过学长提醒,看了看elf的执行前运行的段init_array和fini_array段

ctrl+s找到这个段

image-20220408160837578

这才发现真正的加密函数在这里

这里的话

思路:先要推出这前面数组四个字节是“flag”然后进行异或,得到字符串"&YA1"随后再对这个字符串进行异或

解密代码如下

#include <stdio.h>
#include <string.h>
int main()
{
char ida_chars[] =
{ 0x40, 0x35, 0x20, 0x56, 0x5D, 0x18, 0x22, 0x45, 0x17, 0x2F, 0x24, 0x6E, 0x62, 0x3C, 0x27, 0x54, 0x48, 0x6C, 0x24, 0x6E, 0x72, 0x3C, 0x32, 0x45, 0x5B };
char key[] = { 0x40, 0x35, 0x20, 0x56 };
char key1[] = { "flag" };
char key2[6] = {0 };
char flag[26] = { 0 };

for (int i = 0; i < 5; i++)
{
key[i] ^= key1[i];
}

printf("%s\n", key);
for (int j = 0; j <25; j++)
{
flag[j] = ida_chars[j] ^ key[j % 4];

printf("%c", flag[j]);
}


}

经验:

这里乱用了一波strlen,导致乱码,后才发现,这个实际上不是字符串

[SUCTF2019]SignIn

image-20220408173945932

看到数字65547就知道可能是rsa

正向过程:

输入字符串给a1a,转换一波格式,转成数字

然后进行一波rsa加密

最后比较

于是解密脚本

[MRCTF2020]Transform

 

教训:尽量不要用动态数组,这种未初始化的内存空间,对字符的控制挺差的

Youngter-drive

 

SThe quick brown fox jumps over the lazy dog.

#include <stdio.h>
#include <Windows.h>

int main()
{
char output[30] = "TOiZiZtOrYaToUwPnToBsOaOapsyS";

char enc[54] = "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm";
char flag[64] = "0";
char *result;

for (int i = 0; i <= 30; i++)
{
if (i % 2 == 0)
{
flag[i] = output[i];
printf("%c", flag[i]);
}
else
{
if (97 < output[i] || output[i] > 122)
{
result = strstr(enc, output);
result += 96;
printf("%s", result);
}
else
{
result = strstr(enc, output);
result += 38;
printf("%s", result);

}
}

}

}

 

加密函数:

主要是找到output的字符在off_418000里面的位置,再加38和86

hgame fakeShell

直接用ida打开无果,应该是有反调试,因为是新生赛,去ctfwiki看看有什么反反调试方法

68CADA362C99068FB6254F152FAC2AB21EA41F663FAA8646934EB3320F45546253CCCD3BD5A611ABC0C28CD844D24A431601B0294D52D0555B60B812A7F450E6B9388B56A358C74C4B0719BF04631C18205D9B83A8679ABB285F0CB71BAF9C6C8A7DC50B2DA1902E0DED089DE4F9577E88A9DCFCDD806AE17940947FE9FFC826C33EAD751A2342E0CB9F105EDFD15C41A0CF02EF7159F103490A3487097CE861CEBAE3B5A28E27D305F81724519E69D939AEF77BC6FB6EC9EC2BFEBD35B195D4736BDE842282A533143D70EE7285DBEB21D6788992C1EA97E5F33C657AD7960E91E23174BE6F77FDF0C464E7763A4847F2FA3013F6006D981D375AB4818DF5BC00000000000000000051D341B615D274D02CF282FD7F000083EA72F66E55000010A0EBF66E550000E02DF28273750000000000000000000019742658C67F00006161616161616161616161616161616161616161616161616161616161616161002DF282FD7F00002B782658C67F00003E0000000000000020265B58C67F000070F172F66E5500000AC82558C67F000000000000000000000051D341B615D274002DF282FD7F0000D3ED72F66E55000020EE72F66E550000A0E172F66E557375646F0082FD7F00000051D341B615D27420EE72F66E55000040D82058C67F00000100000000000000E82DF282FD7F0000A0CC7D58010000001CED72F66E5500000000000000000000E9F9D17D04FF5871A0E172F66E550000E02DF282FD7F000000000000000000000000000000000000E9F9B1FB05167E24E9F9610EA0A30924000000000000000000000000000000000000000000000000F82DF282FD7F000068E17D58C67F00000B785C58C67F

init arrry

4E616D653A0966616B655368656C6C0A556D61736B3A09303030320A53746174653A0952202872756E6E696E67290A546769643A09333730390A4E6769643A09300A5069643A09333730390A505069643A09333531350A5472616365725069643A0933353B7F00000006AB6EBE74309202

image-20220420230404641

gdb更换ptrace

程序主要逻辑就是两个RC4,然后对比,不过第一个RC4是被init_array赋值转换了key,w0wy0ugot1t,然后再rc4,动调赋值内存数据,得到hgame{s0meth1ng_run_bef0r_m4in?}

[HDCTF2019]Maze

###

这个kali脱壳有点问题,直接自己手动脱壳,这题的坑主要在于ida反汇编不对,因为有花指令的存在,总结了下,这个题应该是跳转到一个无效地址,让函数变成数据了,nop掉,按P框选红色区域就能反汇编成功了

image-20220422155446923

看看各个函数的作用,sw应该是上下,ad应该是左右,加上是70个字符,变量值为7,推测格式为10*7

得出flagflag{ssaaasaassdddw}

[MRCTF2020]Xor

普通的异或

记得加Mimage-20220422162903576

#include <Stdio.h>

int main()
{

char flag[28] = "MSAWB~FXZ:J:`tQJ\"N@ bpdd}8g";
for (int i = 0; i < 27; i++)
{
flag[i] ^= i;
}
printf("%s", flag);
}//MRCTF{@_R3@1ly_E2_R3verse!}

image-20220423161958515

 

[GWCTF 2019]xxor

考点z3

#include <cstdio>


void decode(int* a1)
{
  for (int j = 0; j < 6; j++)
  {
      unsigned int v3; // [rsp+1Ch] [rbp-24h]
      int a2[4] = { 2,2,3,4 };
      unsigned int v4;
      int flag;
      int v5 = 74674557056;
      v3 = a1[j];
      v4 = a1[j+1];
      for (int i = 0; i <= 0x3F; ++i)
      {
          v4 -= (v3 + v5 + 20) ^ ((v3 << 6) + a2[2]) ^ ((v3 >> 9) + a2[3]) ^ 0x10;
          v3 -= (v4 + v5 + 11) ^ ((v4 << 6) + *a2) ^ ((v4 >> 9) + a2[1]) ^ 0x20;
          v5 -= 1166789954;


      }
      a1[j]=v3;
        a1[j+1]=v4;
      j++;
       
  }
}
int main()
{
 
   
    int a1[6];
  a1[2] = 3774025685;
  a1[1] = 550153460;
  a1[5] = -2064448480;
  a1[0] = -548868226;
  a1[3] = 1548802262;
  a1[4] = 2652626477;
  decode(a1);
  for (int i = 0; i < 6; i++)
  {
      printf("%x",a1[i] );
  }
  printf("\n");
  printf("%x", a1[4]);
  printf("%x", a1[5]);
}


[MRCTF2020]hello_world_go

flag以明文存储

不过逆向起来,确实感觉有点难看出来

 

[WUSTCTF2020]level3

 

考点init_array

import base64
import string

str1 = "d2G0ZjLwHjS7DmOzZAY0X2lzX3CoZV9zdNOydO9vZl9yZXZlcnGlfD=="

string1 = "TSRQPONMLKJIHGFEDCBAUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
string2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

a=str1.translate(str.maketrans(string1,string2))#利用密码表还原成正常base64编码后的字符串
#print(str1.translate(str.maketrans(string1,string2)))

print(base64.b64decode(a).decode())#base64解码
#wctf2020{Base64_is_the_start_of_reverse}

[FlareOn4]IgniteMe

image-20220616100646377

加密逻辑就是一开始先异或v4,然后v4再等于字符串的现在遍历的字符,本来是挺简单的,想复杂了....,用了时间久一点

// [WUSTCTF2020]level3.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>

int main()

{
  unsigned char byte_403000[40] = {
  0x0D, 0x26, 0x49, 0x45, 0x2A, 0x17, 0x78, 0x44, 0x2B, 0x6C, 0x5D, 0x5E, 0x45, 0x12, 0x2F, 0x17,
  0x2B, 0x44, 0x6F, 0x6E, 0x56, 0x09, 0x5F, 0x45, 0x47, 0x73, 0x26, 0x0A, 0x0D, 0x13, 0x17, 0x48,
  0x42, 0x01, 0x40, 0x4D, 0x0C, 0x02, 0x69,0x0
  };
  int v4 = 4;
  int v1 = 40;
  char v5;
 
  unsigned char byte_403078[40] = { 0 };
 
  for (int i = v1 - 1; i >=0;-- i)
       
  {
       
      byte_403078 [i] = v4 ^ byte_403000[i];
      v4 = byte_403078[i];
      printf("%c", byte_403078[i]);
     

  }

  for (int i = 0; i < v1 - 1; i++)
  {
      char v5 = byte_403078[i];
      if (v5 != 10 && v5 != 13)
      {
          if (v5)
              byte_403078[i] = v5;
      }
     
  }
  printf("\n");
  printf("flag{");
  for (int i = 0; i < v1 - 1; i++)
  {
      printf("%c", byte_403078[i]);
  }
  printf("}");
  //flag{R_y0u_H0t_3n0ugH_t0_1gn1t3@flare-on.com}
}



[WUSTCTF2020]Cr0ssfun

image-20220617095913103

check是一个经典比较函数

最近学了点cpp就用cpp写了

// [WUSTCTF2020]Cr0ssfun.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

//a1[1] == 99 && a1[25] == 64 && a1[27] == 101;
//a1[4] == 50 && a1[17] == 114 && a1[29] == 102 && a1[17] == 114 && a1[24] == 95
//a1[2] == 116
//&& a1[9] == 99
//&& a1[32] == 125
//&& a1[19] == 118
//&& a1[5] == 48
//&& a1[14] == 110
//a1[15] == 100 && a1[8] == 123 && a1[18] == 51 && a1[28] == 95 && a1[21] == 114
//* a1 == 119 && a1[6] == 50 && a1[22] == 's' && a1[31] == 'n' && a1[12] == '_'
//a1[7] == 48 && a1[16] == 95 && a1[11] == 112 && a1[23] == 101 && a1[30] == 117
//a1[10] == 112 && a1[13] == 64 && a1[3] == 102 && a1[26] == 114 && a1[20] == 101
#include <iostream>

int main()
{
  std::string s1 = { 119,99,116,102, 50,48,50,48,123 ,99,112,112,95,64,110,100,95,114,51,118,101,114,115,101,95,64,114,101,95,102,117,110,125 };
  std::cout << s1 << std::endl;
}
//wctf2020{cpp_@nd_r3verse_@re_fun}



posted @   chis42  阅读(90)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
点击右上角即可分享
微信分享提示