Rev

asm_re

看汇编,简单转换一下逻辑,大概是这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <stdio.h>
#include <string.h>

int main() {
// Stack allocation
char buffer[256];
char result[256];

// Initialize buffer with a string
strcpy(buffer, "flag{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}");

// Copy buffer to result
memcpy(result, buffer, 256);

// Calculate the length of the string in buffer
int length = strlen(result);

// Loop through each character in result, perform some operations
for (int i = 0; i < length; i++) {
// Some arithmetic operations on each character
result[i] = ((result[i] * 0x50 + 0x14) ^ 0x4D) + 0x1E;
}

// Print result
printf("%s\n", result);

return 0;
}

导出一下密文
2024-05-19T210813
爆破flag

exp

1
2
3
4
5
6
7
8
enc = [0x1FD7, 0x21B7, 0x1E47, 0x2027, 0x26E7, 0x10D7, 0x1127, 0x2007, 0x11C7, 0x1E47, 0x1017, 0x1017, 0x11F7, 0x2007, 0x1037, 0x1107, 0x1F17, 0x10D7, 0x1017, 0x1017, 0x1F67, 0x1017, 0x11C7, 0x11C7, 0x1017, 0x1FD7, 0x1F17, 0x1107, 0x0F47, 0x1127, 0x1037, 0x1E47, 0x1037, 0x1FD7, 0x1107, 0x1FD7, 0x1107, 0x2787]

for i in range(len(enc)):
for j in range(32,128):
if ((j * 0x50 + 0x14) ^ 0x4D) + 0x1E == enc[i]:
print(chr(j), end='')
break
#flag{67e9a228e45b622c2992fb5174a4f5f5}

android_re

主要加密在inspect里面
2024-05-19T211159
key和iv都在native 层JNI里
2024-05-19T211216
都挺复杂的,静态不好分析
2024-05-19T211231
2024-05-19T211240
考虑动态,frida hook梭

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function hook() {
let jni = Java.use("com.example.re11113.jni");

var iv = jni.getiv();
console.log("iv = :" + iv);
var key = jni.getkey();
console.log("key = :" + key);
}
function main() {
Java.perform(function () {
hook();
});
}

setTimeout(main, 200);

结果发现getkey返回值不是Mofified UTF-8,导致程序崩溃
2024-05-19T211334
所以尝试直接hook JNI函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
function hook() {
let jni = Java.use("com.example.re11113.jni");

var res = jni.getiv();
console.log("iv = :" + res);
//var key = jni.getkey();
//console.log("key = :" + key);
// 尝试直接Hook JNI函数
var getkeybase = Module.findExportByName("libSecret_entrance.so", "Java_com_example_re11113_jni_getkey");//获取getkey函数地址
if (getkeybase) {
Interceptor.attach(getkeybase, {//hook getkey函数
onEnter: function(args) {//进入函数时调用
console.log("JNI getkey called");
},
onLeave: function(retval) {//离开函数时调用
if (!retval.isNull()) {//如果返回值不为空/
try {
var result = Memory.readUtf8String(retval);//读取返回值UTF-8字符串
console.log("Reconstructed key = " + result);//打印返回值
retval.replace(ptr(result));//替换返回值
} catch (memError) {
console.log("Memory read error: " + memError.message);//打印错误信息
}
}
}
});

// 调用getkey方法以触发Hook
var key = jni.getkey();
console.log("key = :" + key);//打印key
} else {
console.log("Failed to find the export 'Java_com_example_re11113_jni_getkey'");//打印错误信息无法找到导出
}
}

function main() {
Java.perform(function () {
hook();
});
}

setTimeout(main, 200);

得到

1
2
key = b"A8UdWaeq"  
iv = b"Wf3DLups"

2024-05-19T211437

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import base64
from Crypto.Cipher import DES
from Crypto.Util.Padding import unpad

def decrypt_message(encrypted_message, key, iv):
try:
# 解码 base64 编码的密文
encrypted_bytes = base64.b64decode(encrypted_message)

# 初始化 DES 密码器
cipher = DES.new(key, DES.MODE_CBC, iv)

# 解密并去填充
decrypted_bytes = unpad(cipher.decrypt(encrypted_bytes), DES.block_size)
decrypted_message = decrypted_bytes.decode('utf-8')

return decrypted_message
except (ValueError, KeyError) as e:
# 捕获解密和去填充错误
print(f"Decryption failed: {e}")
return None

if __name__ == "__main__":
encrypted_message = "JqslHrdvtgJrRs2QAp+FEVdwRPNLswrnykD/sZMivmjGRKUMVIC/rw=="
key = b"A8UdWaeq" # 8 字节长的密钥
iv = b"Wf3DLups" # 8 字节长的初始化向量

decrypted_message = decrypt_message(encrypted_message, key, iv)
if decrypted_message:
print("Decrypted message:", decrypted_message)
else:
print("Decryption failed.")
#Decrypted message: 188cba3a5c0fbb2250b5a2e590c391ce
#flag{188cba3a5c0fbb2250b5a2e590c391ce}

rust_baby

看看字符串窗口
2024-05-19T211601
有明显base64表和数据
2024-05-19T211618
跟进一下找到主函数 sub_14000298A
先解看看这数据是什么
2024-05-19T211658

1
2
3
4
5
6
7
8
9
10
{
"henhenaaa!":[1,1,4,5,1,4,1,9,1,9,8,1,0],
"cryforhelp":"igdydo19TVE13ogW1AT5DgjPzHwPDQle1X7kS8TzHK8S5KCu9mnJ0uCnAQ4aV3CSYUl6QycpibWSLmqm2y/GqW6PNJBZ/C2RZuu+DfQFCxvLGHT5goG8BNl1ji2XB3x9GMg9T8Clatc=",
"whatadoor":"1145141919810WTF",
"iwantovisit":"O0PSwantf1agnow1"
}{
"where":"where is your flag?:",
"omg":"correct flag",
"nonono":"nope, wrong flag"
}

大致判断igdydo19TVE13ogW1AT5DgjPzHwPDQle1X7kS8TzHK8S5KCu9mnJ0uCnAQ4aV3CSYUl6QycpibWSLmqm2y/GqW6PNJBZ/C2RZuu+DfQFCxvLGHT5goG8BNl1ji2XB3x9GMg9T8Clatc=是最后的密文
base64解码一下最终密文,可以得知输入长度是104
开始调试,输入长度伪104的字符串,这里对输入进行分组
2024-05-19T211807
355行对数据进行了加密处理,静态看比较复杂
直接看结果,前两位-1然后两位不变,再两位+1,最后两位+2
2024-05-19T211857
然后加密完后每一位异或0x33
中间一大段是用这这两串来进行一系列操作 "whatadoor":"1145141919810WTF", "iwantovisit":"O0PSwantf1agnow1"生成一个串来和输入进行异或
然后对比数据可以发现,输入加密后存在了这里v181这里都是同样的8个一组
2024-05-19T212001
记录下来,后面会用到
2024-05-19T212031
在这往后也是一堆异或操作
往后找,直到这里
2024-05-19T212048
看看src,dump下来
2024-05-19T212102
再往后是一些base64加密
2024-05-19T212650
然后到这里
2024-05-19T212704
在汇编界面运行到这里
2024-05-19T212719
可以得到输入的最后加密结果
2024-05-19T212733
把他base64解密一下,得到的和之前记录的src一样,印证了中间一大串都是base64
2024-05-19T212749
那我们用最初记录下来的8位一组的加密结果与src异或
2024-05-19T212805
然后我们换个输入,同样的做法也会得到相同的值,说明这就是密钥
用这个密钥去异或最后的加密结果,还原出异或前的值
2024-05-19T212821
然后这个值再异或0x33
2024-05-19T212833
就得到一串只要解最开始的前两位-1然后两位不变,再两位+1,最后两位+2就是正确输入的数据了
我们用正确的密文解一下
2024-05-19T212849
写个脚本解一下

exp

1
2
3
4
5
6
7
enc = [0x65,0x6b,0x61,0x67,0x7c,0x37,0x67,0x34,0x33,0x37,0x30,0x62,0x34,0x2e,0x36,0x68,0x2f,0x31,0x2d,0x34,0x64,0x67,0x33,0x2f,0x38,0x61,0x63,0x30,0x2e,0x32,0x34,0x35,0x61,0x36,0x35,0x66,0x3a,0x62,0x3b,0x34,0x31,0x7c,0x45,0x45,0x46,0x46,0x47,0x47,0x44,0x44,0x45,0x45,0x46,0x46,0x47,0x47,0x44,0x44,0x45,0x45,0x46,0x46,0x47,0x47,0x44,0x44,0x45,0x45,0x46,0x46,0x47,0x47,0x44,0x44,0x45,0x45,0x46,0x46,0x47,0x47,0x44,0x44,0x45,0x45,0x46,0x46,0x47,0x47,0x44,0x44,0x45,0x45,0x46,0x46,0x47,0x47,0x44,0x44,0x45,0x45,0x46,0x46,0x47,0x47] 
key = [1,1,0,0,-1,-1,-2,-2]
flag = ""
for i in range(len(enc)):
flag += chr(enc[i] + key[i % len(key)])
print(flag)
#flag{6e2480b3-4f02-4cf1-9bc0-123b75f9a922}EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE

whereThel1b

以为是cython逆向,硬看so,脑子直接炸
后来转念一想,运行脚本看看呢
输入任意三个字符trytry都返回4个数字
2024-05-19T212937
猜测跟base有关或者类似
考虑每次去爆破三个字符,然后补齐剩下的,调用trytry得到返回值去和密文比较
注意so的调用必须是linux 下python 3.10
2024-05-19T212958

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import whereThel1b

enc = [108, 117, 72, 80, 64, 49, 99, 19, 69, 115, 94, 93, 94, 115, 71, 95, 84, 89, 56, 101, 70, 2, 84, 75, 127, 68, 103, 85, 105, 113, 80, 103, 95, 67, 81, 7, 113, 70, 47, 73, 92, 124, 93, 120, 104, 108, 106, 17, 80, 102, 101, 75, 93, 68, 121, 26]
table = list(b'flag{-}abcdefghijklmnopqrstuvwxyz0123456789')

flag = b''
for i in range(0, len(enc), 4):
query = 0
for j in table:
for k in table:
for l in table:
if query == 1: break
else:
c = bytes([j, k, l])
tmp = flag + c
tmp = tmp.ljust(42, b'A')
res = whereThel1b.trytry(tmp)[i:i+4]
if res == enc[i:i+4]:
flag += c
print(flag)
query = 1
#flag{7f9a2d3c-07de-11ef-be5e-cf1e88674c0b}

gdb_debug

种子是固定的
2024-05-19T213051
考虑直接动调,拿异或因子
第一个断点,拿到v20异或因子,只取低两位0xD9
2024-05-19T213114
第二个断点
2024-05-19T213128
然后转到汇编,一直F8运行至这里
2024-05-19T213143
点ptr获得indx值
2024-05-19T213156
第三个断点
2024-05-19T213209
然后转到汇编,在rand()处再下个断点,同样取低两位 0xDE
2024-05-19T213238
最后的数据是静态的byte数组,点进去就行了
2024-05-19T213253

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
key = [0xBF, 0xD7, 0x2E, 0xDA, 0xEE, 0xA8, 0x1A, 0x10, 0x83, 0x73, 0xAC, 0xF1, 0x06, 0xBE, 0xAD, 0x88, 0x04, 0xD7, 0x12, 0xFE, 0xB5, 0xE2, 0x61, 0xB7, 0x3D, 0x07, 0x4A, 0xE8, 0x96, 0xA2, 0x9D, 0x4D, 0xBC, 0x81, 0x8C, 0xE9, 0x88, 0x78]
enc = 'congratulationstoyoucongratulationstoy'
tmp = []
for i in range(len(enc)):
tmp.append(ord(enc[i]) ^ key[i])
print(tmp)
key2 =[0xDE, 0xAA, 0x42, 0xFC, 0x09, 0xE8, 0xB2, 0x06, 0x0D, 0x93, 0x61, 0xF4, 0x24, 0x49, 0x15, 0x01, 0xD7, 0xAB, 0x04, 0x18, 0xCF, 0xE9, 0xD5, 0x96, 0x33, 0xCA, 0xF9, 0x2A, 0x5E, 0xEA, 0x2D, 0x3C, 0x94, 0x6F, 0x38, 0x9D, 0x58, 0xEA]
tmp = [tmp[i] ^ key2[i] for i in range(len(tmp))]

ind = [0x12, 0x0E, 0x1B, 0x1E, 0x11, 0x05, 0x07, 0x01, 0x10, 0x22, 0x06, 0x17, 0x16, 0x08, 0x19, 0x13, 0x04, 0x0F, 0x02, 0x0D, 0x25, 0x0C, 0x03, 0x15, 0x1C, 0x14, 0x0B, 0x1A, 0x18, 0x09, 0x1D, 0x23, 0x1F, 0x20, 0x24, 0x0A, 0x00, 0x21]
v28 = [0] * 38
for i in range(38):
v28[ind[i]] = tmp[i]
v20 = [0xD9, 0x0F, 0x18, 0xBD, 0xC7, 0x16, 0x81, 0xBE, 0xF8, 0x4A, 0x65, 0xF2, 0x5D, 0xAB, 0x2B, 0x33, 0xD4, 0xA5, 0x67, 0x98, 0x9F, 0x7E, 0x2B, 0x5D, 0xC2, 0xAF, 0x8E, 0x3A, 0x4C, 0xA5, 0x75, 0x25, 0xB4, 0x8D, 0xE3, 0x7B, 0xA3, 0x64]
flag = bytes([v20[i] ^ v28[i] for i in range(38)])
print(flag)
#b'flag{78bace5989660ee38f1fd980a4b4fbcd}'