(RE)2025 SWPU-NSSCTF 秋季招新入门训练赛

1.Xor

Xor是一種可反編的加密方式

打開ida

828467d7ccf0cd60a7b01bb9ef381510.png

可以看見flag在c語言下做了Xor

5c8d8203477f9fc91a3f3802bf755f6e.png

說明要==enc_0[i]

導出enc_0[i] 的值

bab8208e6375cf6db2f356c51fff0a9f.png

**要先從HEX轉回string 再做Xor , key為0x7A

2.Base64

d90b2674d83a5df2aee11cd1a9ada666.png

一眼就看見了base64 的表和文了

8efc9e6f77d7c5f0e1360f37ca239bba.png

3.ida使用

99a7154adc406f7987a5bc799d650ffb.png

string1: NSSCTF{

在shift+f12就可以在第一行找到string2了

b909c3f5a150e053eb31a9bfa904158d.png

string2:IDA_1s_4_VeRy_Impo

需要debug 查看flag3的值(因為在有一部分在擬偽代碼沒有寫出來的,要轉匯編才能看出來)

在flag() tab 一下在nap 下一個斷點(F2)

e93fb65f74e5e9c9b50296cb2456d825.png a68bf748cb2ef0660fad5977466c0d73.png

可以用R來看data

R之前:

3696371f3475861cc2f21887dc1845d7.png

R之後:

運行程式到斷點位

27e3e89a1180c1ea341a641e4481d92f.png

string3: rTant_t0

string4: rever5e_en8ine3ring} (直接把代碼抄去運行都可以(

0a8b4637d88e87501e94a7d0047e3588.png

看看string4的是要用上patch的功能,

6daca8c7809502ec18ea9ed11f979e06.png

看看左邊有一個print_flag4()函數 , 利用patch method 調用 , 按下print_nothing() + tab 找出flag4 call 的地址

f3ed3c41be1c85401a2ef7eb8b85f443.png

在x86-64架構, call 指令通常使用相對地址, 在ida 中你可以打開opcode查看該部分


看看兩函數的地址的 偏移量 = 目標地址 - (下一條指令的地址)


84ad891a1751360c23775abbbe14f898.png 20caaeb2b198101bb1db33b055f52f35.png
  • 目標地址: 0x7FF733631473** ( print_flag4(void) )**

  • 當前指令地址: 0x7FF73363160D** (print_nothing(void))**

  • 下一條命令的地址: 0x7FF733631612

  • 偏移量 = hex(0x07FF733631473 - 0x7FF733631612 ) = -0x19f

    1
    2
    >>> hex(0x7FF733631473 - 0x7FF733631612 )
    '-0x19f'
  • 下一條指令的地址: 0x7FF73363160D+ 5 (當前指令地址+匯編字節[E8占1字節,** rel32占4字節**])

  • 偏移量 = hex(0x07FF733631473 - (0x7FF73363160D+ 5)) = -0x19f

    1
    2
    >>> hex(0x07FF733631473 - (0x7FF73363160D+ 5))
    '-0x19f'

把-0x19f 補碼 :

1
2
>>> print(hex(-0x19f & 0xffffffff))
0xfffffe61

機械碼: 61feffff

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

def hex_to_machine_code(hex_value):
"""
將十六進位值轉換為機械碼 (little-endian 格式)

Args:
hex_value (int): 十六進位值,例如 0xfffffe61

Returns:
str: 機械碼的十六進位字符串
"""
# 將整數轉換為 4 字節的 bytes (32位, little-endian)
result_bytes = hex_value.to_bytes(4, byteorder='little')
return result_bytes.hex()

# 測試給定的值
if __name__ == "__main__":
test_value = 0xfffffe61
machine_code = hex_to_machine_code(test_value)
print(f"0x{test_value:08x} 的機械碼: {machine_code}")

*我們可以驗算一下本來的地址是否為3E FE FF FF

  • 目標地址:** 0x7FF733631450** ( print_nothing(void) )
  • 下一條命令的地址: 0x7FF733631612
1
2
3
4
>>> print (hex((0x7FF733631450 - 0x7FF733631612)& 0xFFFFFFFF ))
0xfffffe3e

3E FE FF FF

所以是對的 , 這裹是在要下 E8 3E FE FF FF 下斷點 , debug一下

5eaa56a2d99d5bc5b517c596b1f6e68a.png

右鍵patch 把3E 改成 61 , F8一下就出現了

e5835272bc7d00692f0296c9079493c0.png

steing4 : rever5e_en8ine3ring

flag : NSSCTF{rever5e_en8ine3ring}

4.debug

1432811f7ae465fbe334ea7f405998b3.png

下一個斷點 debugger , 找到v4的棧 , 按一下A鍵可在匯編中查看。

5bdda7728018d20de9f7283396b5ff43.png

NSSCTF{you_know_debug!!}

5.RC4

用cyber

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
flag[i] != enc_0[i] int __fastcall main(int argc, const char **argv, const char **envp)
{
unsigned int v3; // eax
unsigned int v4; // eax
char flag[112]; // [rsp+20h] [rbp-60h] BYREF
_BYTE v7[264]; // [rsp+90h] [rbp+10h] BYREF
int i; // [rsp+198h] [rbp+118h]
int v9; // [rsp+19Ch] [rbp+11Ch]

_main(argc, argv, envp);
printf("please input flag:");
scanf("%s", flag);
v3 = strlen("SakuraiCora");
rc4_init(v7, "SakuraiCora", v3);
v4 = strlen(flag);
rc4_crypt(v7, flag, v4);
v9 = 1;
for ( i = 0; i <= 23; ++i )
{
if ( flag[i] != enc_0[i] )
{
v9 = 0;
break;
}
}
if ( v9 )
printf("You get flag!\n");
else
printf("Wrong flag!\n");
return 0;
}

Rc4 key 是 : "SakuraiCora"

看看flag的數據 flag[i] != enc_0[i] 看看enc_0

15be3ff173fde475a71000bb8c8146d8.png

0xe8, 0x2b, 0x33, 0x25, 0xb2, 0x55, 0xe9, 0xd, 0x5d, 0xaa, 0x69, 0xfd, 0x1b, 0x47, 0xd1, 0x7c, 0xa6, 0xff, 0x52, 0xe1, 0x6c, 0xe8, 0x4c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0

在cyber 先 HEX 一下再 RC4

b034e7992f6781e1f8e0039428aef998.png

flag : NSSCTF{y0u_solved_Rc4!}

6.认识asm

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
text:00000001400014A1                 public enc
.text:00000001400014A1 enc proc near
.text:00000001400014A1
.text:00000001400014A1
.text:00000001400014A1 i = dword ptr -14h
.text:00000001400014A1 flag = qword ptr 10h
.text:00000001400014A1
.text:00000001400014A1 push rbp
.text:00000001400014A2 push rbx
.text:00000001400014A3 sub rsp, 38h
.text:00000001400014A7 lea rbp, [rsp+30h]
.text:00000001400014AC mov [rbp+10h+flag], rcx
.text:00000001400014B0 mov [rbp+10h+i], 0
.text:00000001400014B7 jmp short loc_1400014F6
.text:00000001400014B9 ; ---------------------------------------------------------------------------
.text:00000001400014B9
.text:00000001400014B9 loc_1400014B9:
.text:00000001400014B9 mov eax, [rbp+10h+i]
.text:00000001400014BC cdqe
.text:00000001400014BE mov rdx, [rbp+10h+flag]
.text:00000001400014C2 add rax, rdx
.text:00000001400014C5 movzx eax, byte ptr [rax]
.text:00000001400014C8 mov ecx, eax
.text:00000001400014CA mov eax, [rbp+10h+i]
.text:00000001400014CD cdqe
.text:00000001400014CF lea rdx, [rax+1]
.text:00000001400014D3 mov rax, [rbp+10h+flag]
.text:00000001400014D7 add rax, rdx
.text:00000001400014DA movzx eax, byte ptr [rax]
.text:00000001400014DD add eax, 1
.text:00000001400014E0 xor ecx, eax
.text:00000001400014E2 mov edx, ecx
.text:00000001400014E4 mov eax, [rbp+10h+i]
.text:00000001400014E7 cdqe
.text:00000001400014E9 mov rcx, [rbp+10h+flag]
.text:00000001400014ED add rax, rcx
.text:00000001400014F0 mov [rax], dl
.text:00000001400014F2 add [rbp+10h+i], 1
.text:00000001400014F6
.text:00000001400014F6 loc_1400014F6:
.text:00000001400014F6 mov eax, [rbp+10h+i]
.text:00000001400014F9 movsxd rbx, eax
.text:00000001400014FC mov rcx, [rbp+10h+flag] ; Str
.text:0000000140001500 call strlen
.text:0000000140001505 sub rax, 2
.text:0000000140001509 cmp rbx, rax
.text:000000014000150C jb short loc_1400014B9
.text:000000014000150E nop
.text:000000014000150F nop
.text:0000000140001510 add rsp, 38h
.text:0000000140001514 pop rbx
.text:0000000140001515 pop rbp
.text:0000000140001516 retn
.text:0000000140001516 enc endp


enc_flag db 0x1a,0x7,0x17,0x16,0x13,0x3a,0x39,0x15,0x1d,0x2d,0x35,0x1d,0x13,0x3b,0x10,0x4
db 0x11,0x9,0xb,0xc,0xc,0x2a,0x4,0xf,0x1c,0x28,0x6,0xc,0x12,0x8,0x6,0x7e
db 0x7d

補充:

在匯編中,變量名通常為:

1
2
3
[基址+偏移量+變量名]
[rbq+10h+flag] #flag字符串的地址
[rbq+10h+i] #i的值

Windows x64 調用約定(_fastcall):

1
2
3
4
5
6
7
四個整數或指針參數(從左到右)通過 rcx , rdx , r8 , r9 寄存器
例如 func(arg1, arg2 , arg3 , arg4)會將arg1 放入 rcx , arg2 放入 rdx...
多於四個會則其余用棧傳遞。
浮點數參數用 xmm0 , xmm1 , xmm2 , xmm3 寄存器傳遞。
.text:00000001400014FC mov rcx, [rbp+10h+flag] ; Str
.text:0000000140001500 call strlen
.text:0000000140001505 sub rax, 2

可參考:https://www.bilibili.com/video/BV17TaCzJEqp/?spm_id_from=333.1007.top_right_bar_window_default_collection.content.click&vd_source=b128d59725d91ecef706ce0b01795a8f

跳轉邏輯:

1
2
3
4
5
6
7
8
9
10
11
.text:0000000140001509                 cmp     rbx, rax
.text:000000014000150C jb short loc_1400014B9

#j = jump
#e = equal
#z = zero
#a = above (>)
#g = greater (>)
#b = below (<)
#l = less (<)
#n = not

問一問 ai 寫出了python

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
enc_flag = [
0x1a, 0x7, 0x17, 0x16, 0x13, 0x3a, 0x39, 0x15, 0x1d, 0x2d, 0x35, 0x1d, 0x13, 0x3b, 0x10, 0x4,
0x11, 0x9, 0xb, 0xc, 0xc, 0x2a, 0x4, 0xf, 0x1c, 0x28, 0x6, 0xc, 0x12, 0x8, 0x6, 0x7e,
0x7d
]

flag = list(enc_flag)

# 從倒數第二個開始往前解密
for i in range(len(flag) - 3, -1, -1):
flag[i] = flag[i] ^ (flag[i+1] + 1)

# 將解密後的字節轉換為字符串(假設是 ASCII)
flag_str = ''.join(chr(c) for c in flag)

print(flag_str)

flag : NSSCTF{ASM_is_crucial_to_Binary~}