BUUCTF-reverse wp(二)

2025-01-29 6 0

BUUCTF-reverse wp(一)
萌新学习,大佬轻喷^_^

Java逆向解密

class文件,jd-gui打开:
BUUCTF-reverse wp(二)插图

result = arr[i] + 64 ^ 0x20;

将输入的字符进行了加密。

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

加密的值与key进行比较,如果加密结果与 KEY 完全匹配,打印 Congratulations。否则打印 Error。

脚本

KEY = [180, 136, 137, 147, 191, 137, 147, 191, 148, 136,
       133, 191, 134, 140, 129, 135, 191, 65]

def decrypt(KEY):
    flag = ""
    for key in KEY:
        char = chr((key ^ 0x20) - 64)
        flag += char
    return flag

flag = decrypt(KEY)
print("Flag:", flag)

BUUCTF-reverse wp(二)插图1

JustRE

BUUCTF-reverse wp(二)插图2
BUUCTF-reverse wp(二)插图3
exe文件,查壳:
BUUCTF-reverse wp(二)插图4
丢入IDA:
BUUCTF-reverse wp(二)插图5
Windows 应用程序的主入口函数,未发现特殊字符。
直接shift+f12查看特殊字段:
BUUCTF-reverse wp(二)插图6
跟踪:
BUUCTF-reverse wp(二)插图7
点击x
BUUCTF-reverse wp(二)插图8
f5查看伪代码:
BUUCTF-reverse wp(二)插图9
分析:

sprintf(String, &Format, ++dword_4099F0);
if (dword_4099F0 == 19999)
{
  sprintf(String, " BJD{%d%d2069a45792d233ac}", 19999, 0);
  SetWindowTextA(hWnd, String);
  return 0;
}
SetWindowTextA(hWnd, String);

sprintf(String, " BJD{%d%d2069a45792d233ac}", 19999, 0);第一个%d19999,第二个%d0
此段是指按钮按19999次,将会输出BJD{1999902069a45792d233ac},判断此为flag。

刮开有奖

BUUCTF-reverse wp(二)插图10
exe,查壳:
BUUCTF-reverse wp(二)插图11
丢入IDA:
BUUCTF-reverse wp(二)插图12
shift+f12查看敏感字符:
BUUCTF-reverse wp(二)插图13
根据BCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=字符可判断是base64编码。
跟进:
BUUCTF-reverse wp(二)插图14

if (String[0] == v7[0] + 34 // String[0] == 'Z' + 34 == 'd'
   && String[1] == v10     // String[1] == 'C'
   && 4 * String[2] - 141 == 3 * v8 // 4 * String[2] - 141 == 3 * 83
   && String[3] / 4 == 2 * (v13 / 9) // String[3] / 4 == 2 * (72 / 9)
   && !strcmp(v4, "ak1w")  // 验证第一组结果
   && !strcmp(v5, "V1Ax")) // 验证第二组结果

根据该代码需要编码"ak1w""V1Ax"
BUUCTF-reverse wp(二)插图15
BUUCTF-reverse wp(二)插图16
根据伪代码,String为flag值,应该为8位。
推导过程
String[0] == v7[0] + 34

v7[0] = 3(加密后)。

3 + 34 = 85,ASCII 对应字符为 U
String[1] == v10

v10对应加密后的第五位字符:J
4 * String[2] - 141 == 3 * v8

v8 = 69(加密后的第三位字符E的 ASCII)。
解方程:4 * String[2] = 3 * 69 + 141 = 348String[2] = 87
ASCII 对应字符为 W
String[3] / 4 == 2 * (v13 / 9)

v13对应加密后的倒数第四位字符:Z,ASCII 为90

解方程:String[3] / 4 = 2 * (90 / 9)String[3] = 80

ASCII 对应字符为 P

Flag 第四个字符:P

WP1jMp通过 Base64 解码后的位置已知:
WP1在前,jMp在后

Flag 剩余字符:WP1jMp
完整 Flag

flag{UJWPWP1jMp}

[ACTF新生赛2020]easyre

exe,先查壳:
BUUCTF-reverse wp(二)插图17
存在UPX壳,通过upx.exe -d解壳:
BUUCTF-reverse wp(二)插图18
解壳后~~~~打开看看:
BUUCTF-reverse wp(二)插图19
应该是输入对应的值出现flag,丢入IDA,查看main():
BUUCTF-reverse wp(二)插图20
分析代码:

if \( v6\[0\] \!= 65 \|\| v6\[1\] \!= 67 \|\| v6\[2\] \!= 84 \|\| v6\[3\] \!= 70 \|\| v6\[4\] \!= 123 \|\| v10 \!= 125 \)

65 是字符 'A';67 是字符 'C';84 是字符 'T';70 是字符 'F';123 是字符 '{';125 是字符 '}',继续分析:

v5[0] = v7;
v5[1] = v8;
v5[2] = v9;

for ( i = 0; i <= 11; ++i )
{
  if ( v4[i] != _data_start__[*((char *)v5 + i) - 1] )
    return 0;
}

1、将 v7、v8、v9 的值存储到 v5 中。
2、遍历 v4 的 12 个字节,逐一进行比对:
3、v4[i] 是目标字符串的第 i 个字节。_data_start__[*((char *)v5 + i) - 1] 是从全局数据段_data_start__中获取的字节。
说明:*((char *)v5 + i) 是通过 v5 的偏移获取的索引值,减 1 后作为索引,访问_data_start__
如果有任何一个字节不匹配,则程序直接返回 0,校验失败。

获取_data_start__[]值,双击即可:
BUUCTF-reverse wp(二)插图21

根据data_start推算v4值:
_data_start__[]值为:}|{zyxwvutsrqponmlkjihgfedcba_^][ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)(',27h,'&%$# !"根据for循环和if语句判断可以倒推出v4 = "*F'"N,"(I?+@"换成ASII值:v4[]=[42, 70, 39, 34, 78, 44, 34, 40, 73, 63, 43, 64]确定了v4值,以及加密后的data_start_[]`,现在要做的就是解密后的值与v4对比,如果相同即可。

脚本

根据伪代码编写脚本逆推:

# data 是 _data_start__ 的字符序列,表示可能的字符集
# 注:写脚本时的密文格式  定义名称=‘~密文 ’
data = "~}|{zyxwvutsrqponmlkjihgfedcba`_^]\\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$# !\""

# v4 是 ASCII 值的数组,对应 "*F'\"N,\"(I?+@" 中每个字符的 ASCII 值
v4 = [42, 70, 39, 34, 78, 44, 34, 40, 73, 63, 43, 64]

flag = ''
x = []
# 根据 v4 中的 ASCII 值,找到其在 data 中的索引,并加 1 存入 x
for i in v4:
    x.append(data.find(chr(i)) + 1)

# 将 x 中的每个数值转为对应的字符,并拼接到 flag 中
for i in x:
    flag += chr(i)

print(flag)

BUUCTF-reverse wp(二)插图22
即可得到flag{U9X_1S_W6@T?}

简单注册器

将apk丢入Jadx-gui:
BUUCTF-reverse wp(二)插图23
找到关键代码:

public void onClick(View v) {
                int flag = 1;
                String xx = editview.getText().toString();
                if (xx.length() != 32 || xx.charAt(31) != 'a' || xx.charAt(1) != 'b' || (xx.charAt(0) + xx.charAt(2)) - 48 != 56) {
                    flag = 0;
                }
                if (flag == 1) {
                    char[] x = "dd2940c04462b4dd7c450528835cca15".toCharArray();
                    x[2] = (char) ((x[2] + x[3]) - 50);
                    x[4] = (char) ((x[2] + x[5]) - 48);
                    x[30] = (char) ((x[31] + x[9]) - 48);
                    x[14] = (char) ((x[27] + x[28]) - 97);
                    for (int i = 0; i < 16; i++) {
                        char a = x[31 - i];
                        x[31 - i] = x[i];
                        x[i] = a;
                    }
                    String bbb = String.valueOf(x);
                    textview.setText("flag{" + bbb + "}");
                    return;
                }
                textview.setText("输入注册码错误");
            }
        });
    }

分析:
根据if (xx.length() != 32 || xx.charAt(31) != 'a' || xx.charAt(1) != 'b' || (xx.charAt(0) + xx.charAt(2)) - 48 != 56) { flag = 0; }判断用户输入规则:
1、输入的xx字符串长度为32位
2、第32个字符和第2个字符分别为ab
3、字符1+字符3-48=56
只要flag=1即可输出flag,继续分析下边逻辑:
根据以下代码:

char[] x = "dd2940c04462b4dd7c450528835cca15".toCharArray();
                    x[2] = (char) ((x[2] + x[3]) - 50);
                    x[4] = (char) ((x[2] + x[5]) - 48);
                    x[30] = (char) ((x[31] + x[9]) - 48);
                    x[14] = (char) ((x[27] + x[28]) - 97);
                    for (int i = 0; i < 16; i++) {    //交换前16个字符和后16个字符
                        char a = x[31 - i];
                        x[31 - i] = x[i];
                        x[i] = a;
                    }

脚本

根据代码可以写python脚本:

# 初始字符数组
x = list("dd2940c04462b4dd7c450528835cca15")

# 按逻辑修改 x 的值
x[2] = chr((ord(x[2]) + ord(x[3])) - 50)  # 修改 x[2]
x[4] = chr((ord(x[2]) + ord(x[5])) - 48)  # 修改 x[4]
x[30] = chr((ord(x[31]) + ord(x[9])) - 48)  # 修改 x[30]
x[14] = chr((ord(x[27]) + ord(x[28])) - 97)  # 修改 x[14]

# 翻转数组
for i in range(16):
    x[i], x[31 - i] = x[31 - i], x[i]  # 对称交换

# 最终的结果 bbb
bbb = "".join(x)
print("bbb:", bbb)

计算即可:
BUUCTF-reverse wp(二)插图24

[GWCTF 2019]pyre

pyc文件:.pyc文件不可直接阅读,但可以使用反编译工具将其转换回 .py 文件
通过uncompyle6编译pyc文件:
BUUCTF-reverse wp(二)插图25
即可还原出py文件:
BUUCTF-reverse wp(二)插图26

也可以通过在线解密pyc文件:

#!/usr/bin/env python
# visit https://tool.lu/pyc/ for more information
# Version: Python 2.7

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']

分析:
两个for语句,经过两段加密得到了code,逆推即可还原出加密前的值:

num = ((input1[i] + i) % 128 + 128) % 128
code += num

1、每个字符的 ASCII 值 input1[i] 加上索引 i。
2、对 128 取模,确保结果在 0 到 127 之间。
3、加密后的结果存储到 code 中。

for i in range(l - 1):
    code[i] = code[i] ^ code[i + 1]

每个 code[i] 与下一个字节 code[i + 1] 进行异或操作,进一步扰乱加密结果。

脚本

编写解密脚本:

# 给定的最终 code(字符形式)
code_chars = [
    '\x1f', '\x12', '\x1d', '(', '0', '4', '\x01', '\x06', '\x14', '4',
    ',', '\x1b', 'U', '?', 'o', '6', '*', ':', '\x01', 'D', ';', '%', '\x13'
]

# 将 code 转为 ASCII 值列表
code = [ord(c) for c in code_chars]

# 逆推 XOR 操作,从后向前恢复原始 code
for i in range(len(code) - 2, -1, -1):
    code[i] = code[i] ^ code[i + 1]

# 逆推 input1(字符加索引操作)
input1 = ""
for i, num in enumerate(code):
    # 恢复 input1[i]
    original_char = (num - i + 128) % 128  # 逆推公式
    input1 += chr(original_char)  # 转为字符并添加到结果中

# 输出逆推得到的 flag(即 input1)
print("Flag:", input1)

即可得到flag:~~~~
BUUCTF-reverse wp(二)插图27

findit

apk文件,jadx分析:
BUUCTF-reverse wp(二)插图28
代码分析1:

for (int i = 0; i < 17; i++) {
                    if ((a[i] < 'I' && a[i] >= 'A') || (a[i] < 'i' && a[i] >= 'a')) {
                        x[i] = (char) (a[i] + 18);
                    } else if ((a[i] >= 'A' && a[i] <= 'Z') || (a[i] >= 'a' && a[i] <= 'z')) {
                        x[i] = (char) (a[i] - '\b');
                    } else {
                        x[i] = a[i];
                    }
                }

处理 a,生成 x 并与用户输入比较:
1、若 a[i] 是字母(A-H 或 a-h),则加 18。
2、若 a[i] 是其他字母,则减 8。
3、非字母的字符保持不变。
4、最终生成的 x 转换为字符串,与用户输入 edit 比较。

代码分析2:

String m = String.valueOf(x);
                if (m.equals(edit.getText().toString())) {
                    for (int i2 = 0; i2 < 38; i2++) {
                        if ((b[i2] >= 'A' && b[i2] <= 'Z') || (b[i2] >= 'a' && b[i2] <= 'z')) {
                            y[i2] = (char) (b[i2] + 16);
                            if ((y[i2] > 'Z' && y[i2] < 'a') || y[i2] >= 'z') {
                                y[i2] = (char) (y[i2] - 26);
                            }
                        } else {
                            y[i2] = b[i2];
                        }
                    }
                    String n = String.valueOf(y);
                    text.setText(n);
                    return;
                }

处理 b,生成 y:
1、对于 b[i]:如果是字母(A-Z 或 a-z),则加 16。如果超出字母范围(大于 Z 且小于 a 或大于等于 z),减 26 使其回到字母范围内。非字母保持不变。
2、最终生成的 y 转换为字符串 n,作为输出。

已知
a = ['T', 'h', 'i', 's', 'I', 's', 'T', 'h', 'e', 'F', 'l', 'a', 'g', 'H', 'o', 'm', 'e']
b = ['p', 'v', 'k', 'q', '{', 'm', '1', '6', '4', '6', '7', '5', '2', '6', '2', '0', '3', '3', 'l', '4', 'm', '4', '9', 'l', 'n', 'p', '7', 'p', '9', 'm', 'n', 'k', '2', '8', 'k', '7', '5', '}']

脚本

编写脚本:

# 提供的 a 和 b
a = ['T', 'h', 'i', 's', 'I', 's', 'T', 'h', 'e', 'F', 'l', 'a', 'g', 'H', 'o', 'm', 'e']
b = ['p', 'v', 'k', 'q', '{', 'm', '1', '6', '4', '6', '7', '5', '2', '6', '2', '0', '3', '3',
     'l', '4', 'm', '4', '9', 'l', 'n', 'p', '7', 'p', '9', 'm', 'n', 'k', '2', '8', 'k', '7', '5', '}']

# 逆推 a
x = []
for char in a:
    if 'I' > char >= 'A' or 'i' > char >= 'a':  # 属于 A-H 或 a-h
        x.append(chr(ord(char) + 18))
    elif 'A' <= char <= 'Z' or 'a' <= char <= 'z':  # 属于其他字母
        x.append(chr(ord(char) - 8))
    else:
        x.append(char)  # 非字母字符不变

# 转换 x 为字符串
x_str = ''.join(x)
print("x (用户输入 edit):", x_str)

# 逆推 b
y = []
for char in b:
    if 'A' <= char <= 'Z' or 'a' <= char <= 'z':  # 字符是字母
        temp = ord(char) + 16
        if (temp > ord('Z') and temp < ord('a')) or temp >= ord('z'):  # 超出范围
            temp -= 26
        y.append(chr(temp))
    else:
        y.append(char)  # 非字母字符不变

# 转换 y 为字符串
y_str = ''.join(y)
print("y (输出 text):", y_str)

计算:
BUUCTF-reverse wp(二)插图29

[ACTF新生赛2020]rome

exe,先查壳:
BUUCTF-reverse wp(二)插图30
丢入IDA:
BUUCTF-reverse wp(二)插图31
分析代码:

{
              v1[0] = v7;
              v1[1] = v8;
              v1[2] = v9;
              v1[3] = v10;  //中间部分的 16 个字符(v7 到 v10 组成的 v1 数组)被输入。
              # 接下来会对这些字符进行条件性的位移操作。
              for ( i = 0; i <= 15; ++i )
              {
              # 处理 v1 数组中的每个字符(共 16 个)。
              # 如果字符是大写字母(A-Z,ASCII 范围 65-90)
                if ( *((char *)v1 + i) > 64 && *((char *)v1 + i) <= 90 )
                  *((_BYTE *)v1 + i) = (*((char *)v1 + i) - 51) % 26 + 65;
                  # 如果字符是小写字母(a-z,ASCII 范围 97-122)
                if ( *((char *)v1 + i) > 96 && *((char *)v1 + i) <= 122 )
                  *((_BYTE *)v1 + i) = (*((char *)v1 + i) - 79) % 26 + 97;
              }
              # 最后,对处理后的 v1 的每个字符,与 v12(即 "Qsw3sj_lz4_Ujw@l")逐个对比,如果不匹配则返回错误
              for ( i = 0; i <= 15; ++i )
              {
                result = (unsigned __int8)v12[i];
                if ( *((_BYTE *)v1 + i) != (_BYTE)result )
                  return result;
              }

根据对字符移动获得编码后的值:Qsw3sj_lz4_Ujw@l

脚本

编写脚本:

v12 = "Qsw3sj_lz4_Ujw@l"  # 目标字符数组

# 爆破~~!!^_^~~
flag = ""
for i in range(len(v12)):
    for j in range(32, 127):  # 可见 ASCII 范围
        x = j
        if '@' < chr(x) <= 'Z':  # 大写字母转换
            x = (x - 51) % 26 + 65
        if '`' < chr(x) <= 'z':  # 小写字母转换
            x = (x - 79) % 26 + 97
        if chr(x) == v12[i]:  # 验证是否匹配
            flag += chr(j)
            break

print(f"Flag: {flag}")

BUUCTF-reverse wp(二)插图32

[FlareOn4]login

html文件:

<!DOCTYPE Html />
<html>
    <head>
        <title>FLARE On 2017</title>
    </head>
    <body>
        <input type="text" name="flag"   value="Enter the flag" />
        <input type="button"   value="Click to check the flag" />
        <script type="text/javascript">
            document.getElementById("prompt").onclick = function () {
                var flag = document.getElementById("flag").value;
                var rotFlag = flag.replace(/[a-zA-Z]/g, function(c){return String.fromCharCode((c <= "Z" ? 90 : 122) >= (c = c.charCodeAt(0) + 13) ? c : c - 26);});
                if ("[email protected]" == rotFlag) {
                    alert("Correct flag!");
                } else {
                    alert("Incorrect flag, rot again");
                }
            }
        </script>
    </body>
</html>

分析关键代码:
var rotFlag = flag.replace(/[a-zA-Z]/g, function(c){return String.fromCharCode((c <= "Z" ? 90 : 122) >= (c = c.charCodeAt(0) + 13) ? c : c - 26);});
根据此代码为ROT13编码。
根据if ("[email protected]" == rotFlag) { alert("Correct flag!");只要将"[email protected]"进行rot13解码即可:
BUUCTF-reverse wp(二)插图33

有什么问题欢迎大家提问,后续有时间再更~


4A评测 - 免责申明

本站提供的一切软件、教程和内容信息仅限用于学习和研究目的。

不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。

本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。

如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。敬请谅解!

程序来源网络,不确保不包含木马病毒等危险内容,请在确保安全的情况下或使用虚拟机使用。

侵权违规投诉邮箱:4ablog168#gmail.com(#换成@)

相关文章

2025最新&模拟器微信小程序抓包&小程序反编译
新威胁组织GamaCopy模仿俄罗斯Gamaredon APT,针对俄语目标发起攻击
Windows_xp_win7-驱动编译与双虚拟机调试环境搭建
勒索软件利用隐秘SSH隧道攻击ESXi系统,实现C2通信
[Meachines] [Easy] GoodGames SQLI+Flask SSTI+Docker逃逸权限提升
xss总结

发布评论