buuctf逆向2

[GXYCTF2019]luck_guy

拿到题目后先查一下壳

ok,没有壳放进工具里反编译

先查看所有字符串

发现一个"get flag"

查看引用它的函数

cpp 复制代码
void get_flag(void)

{
  int iVar1;
  time_t tVar2;
  long in_FS_OFFSET;
  int local_44;
  int local_40;
  char local_38 [40];
  long local_10;
  
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  tVar2 = time((time_t *)0x0);
  srand((uint)tVar2);
  for (local_44 = 0; local_44 < 5; local_44 = local_44 + 1) {
    iVar1 = rand();
    switch(iVar1 % 200) {
    default:
      puts("emmm,you can\'t find flag 23333");
      break;
    case 1:
      puts("OK, it\'s flag:");
      memset(local_38,0,0x28);
      strcat(local_38,f1);
      strcat(local_38,f2);
      printf("%s",local_38);
      break;
    case 2:
      printf("Solar not like you");
      break;
    case 3:
      printf("Solar want a girlfriend");
      break;
    case 4:
      builtin_strncpy(local_38,"icug`of\x7f",9);
      strcat(f2,local_38);
      break;
    case 5:
      for (local_40 = 0; local_40 < 8; local_40 = local_40 + 1) {
        if (local_40 % 2 == 1) {
          f2[local_40] = f2[local_40] + -2;
        }
        else {
          f2[local_40] = f2[local_40] + -1;
        }
      }
    }
  }
  if (local_10 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return;

这段代码是一个典型的概率型逆向题目 。它的核心逻辑在于利用随机数 rand() 来决定程序的执行路径,只有触发了特定的"幸运"路径组合,才能还原出正确的 Flag。

程序循环 5 次,每次根据 rand() % 200 的结果进入不同的分支。我们需要找到对 Flag 有贡献的分支:

分支1:

cpp 复制代码
case 1:
  puts("OK, it\'s flag:");
  memset(local_38,0,0x28);
  strcat(local_38,f1);
  strcat(local_38,f2);
  printf("%s",local_38);
  • 作用 :这是获取 Flag 的唯一出口。它将全局变量 f1f2 拼接后打印。
  • 结论 :Flag = f1 + f2

先查看f1与f2看看有没有预设值

f1:

f2:

f1的值为:47 58 59 7b 64 6f 5f 6e 6f 74 5f 转为ASCII值为:GXY{do_not_

f2的值为空,也就是我们要计算的内容

回顾 get_flag 函数中的逻辑:

  1. Case 4:

    cpp 复制代码
    case 4:
          builtin_strncpy(local_38,"icug`of\x7f",9);
          strcat(f2,local_38);
          break;
    • 这里将字符串 "icug`of\x7f"(注意大小端区别) 赋值给了f2
  2. Case 5:

    cpp 复制代码
    case 5:
          for (local_40 = 0; local_40 < 8; local_40 = local_40 + 1) {
            if (local_40 % 2 == 1) {
              f2[local_40] = f2[local_40] + -2;
            }
            else {
              f2[local_40] = f2[local_40] + -1;
            }

    f2 的前 8 位进行减法混淆。

    • 偶数位减 1,奇数位减 2。
    • 我们需要逆向这个操作来得到真正的 f2

解密代码:

python 复制代码
f1 = 'GXY{do_not_'
f2 = [0x7F, 0x66, 0x6F, 0x60, 0x67, 0x75, 0x63, 0x69][::-1]
s = ''
for i in range(8):
    if i % 2 == 1:
        s = chr(int(f2[i]) - 2)
    else:
        s = chr(int(f2[i]) - 1)
    f1 += s
print(f1)

解出flag为GXY{do_not_hate_me}(记得把头改成flag)

Java逆向解密

打开附件发现是一个.class文件

这就不需要查壳了("壳" 是Windows 可执行文件(EXE/DLL)Linux ELF 文件 特有的概念,指为了保护、加密或混淆程序代码而添加的一层额外保护机制(常见于恶意软件、付费软件)Java 字节码文件(.class) ,由 Java 编译器(javac)生成,运行在 Java 虚拟机(JVM) 中。Java 类文件的结构是固定的 (包含魔数、版本号、常量池、字段、方法、属性等),不存在 "加壳" 或 "脱壳" 的说法。)

直接放进jd-gui反编译

java 复制代码
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!");
    } 
  }
}

通过阅读 Java 源代码,我们可以清晰地看到程序的执行流程:

  1. 输入获取 :程序接收用户输入的字符串,并将其转换为字符数组 char[] arr
  2. 加密/混淆逻辑 :程序遍历字符数组,对每个字符执行以下运算并存入列表:int result = arr[i] + 64 ^ 0x20;
  3. 比对验证 :将计算得到的 Resultlist 与硬编码的 KEYList 进行全等比较。目标数组 KEY 为:
java 复制代码
{ 180, 136, 137, 147, 191, 137, 147, 191, 148, 136, 133, 191, 134, 140, 129, 135, 191, 65 }

还原 Flag,我们需要逆向上述加密公式

解密代码:

python 复制代码
key = [
    180, 136, 137, 147, 191, 137, 147, 191, 148, 136, 
    133, 191, 134, 140, 129, 135, 191, 65
]

flag = ""
for val in key:
    # 逆向公式:Char = (Val ^ 32) - 64
    char_code = (val ^ 32) - 64
    flag += chr(char_code)

print(flag)


#This_is_the_flag_!
相关推荐
hughnz5 小时前
保护偏远地区的石油和天然气作业免受网络攻击:当数字世界崩溃时,物理世界就会崩溃
网络安全·能源
huachaiufo6 小时前
burpsuite代理链实现对google.com 访问
web安全·网络安全
white-persist8 小时前
【渗透测试 红队】Netcat(NC)渗透实战全指南详解
开发语言·数据库·python·sql·算法·web安全·网络安全
CDN3609 小时前
游戏盾 SDK 混淆后失效?豁免规则与打包配置解决方案
运维·游戏·网络安全
童话的守望者13 小时前
应急响应靶机练习-Web1
网络安全
NaclarbCSDN13 小时前
User ID controlled by request parameter, with unpredictable user IDs -Burp 复现
网络·安全·网络安全
鹅天帝14 小时前
20260404网安学习日志——RCE漏洞
学习·安全·网络安全
vortex515 小时前
原创 Burp 插件 | Injector - Path Collector:专攻 URL 路径与 XFF 头部 SQL 注入
数据库·sql·网络安全·渗透测试
虚拟世界AI15 小时前
AI代码审计:机器学习如何重塑漏洞检测
人工智能·网络安全·代码审计