续BUUCTF-reverse wp(一)
萌新学习,大佬轻喷^_^
Java逆向解密
class文件,jd-gui打开:
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)
JustRE
exe文件,查壳:
丢入IDA:
Windows 应用程序的主入口函数,未发现特殊字符。
直接shift+f12
查看特殊字段:
跟踪:
点击x
f5
查看伪代码:
分析:
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);
第一个%d
为19999
,第二个%d
为0
。
此段是指按钮按19999次,将会输出BJD{1999902069a45792d233ac}
,判断此为flag。
刮开有奖
exe,查壳:
丢入IDA:shift+f12
查看敏感字符:
根据BCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=
字符可判断是base64编码。
跟进:
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"
:
根据伪代码,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 = 348
→String[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
。
WP1
和jMp
通过 Base64 解码后的位置已知:WP1
在前,jMp
在后。
Flag 剩余字符:WP1jMp
。
完整 Flag
flag{UJWPWP1jMp}
[ACTF新生赛2020]easyre
exe,先查壳:
存在UPX壳,通过upx.exe -d
解壳:
解壳后~~~~打开看看:
应该是输入对应的值出现flag,丢入IDA,查看main():
分析代码:
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__[]
值,双击即可:
根据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)
即可得到flag{U9X_1S_W6@T?}
简单注册器
将apk丢入Jadx-gui:
找到关键代码:
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个字符分别为a
和b
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)
计算即可:
[GWCTF 2019]pyre
pyc文件:.pyc
文件不可直接阅读,但可以使用反编译工具将其转换回 .py 文件
通过uncompyle6
编译pyc文件:
即可还原出py文件:
也可以通过在线解密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:~~~~
findit
apk文件,jadx分析:
代码分析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)
计算:
[ACTF新生赛2020]rome
exe,先查壳:
丢入IDA:
分析代码:
{
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}")
[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解码即可:
有什么问题欢迎大家提问,后续有时间再更~
4A评测 - 免责申明
本站提供的一切软件、教程和内容信息仅限用于学习和研究目的。
不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。
本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。
如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。敬请谅解!
程序来源网络,不确保不包含木马病毒等危险内容,请在确保安全的情况下或使用虚拟机使用。
侵权违规投诉邮箱:4ablog168#gmail.com(#换成@)