本章我会带来Qctf-Re向的非官方WP

Week 1

test1:8086ASM

加密核心逻辑是循环右移+异或

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
加密核心
ENCRYPT PROC
PUSH AX
PUSH BX
PUSH CX
MOV SI, OFFSET INPUT_BUFFER + 2
MOV BX, OFFSET DATA2
MOV CX, 35
LOOP2:
PUSH CX
MOV CL, 2
MOV AL, [SI]
ROR AL, CL//循环右移2位
POP CX
MOV [SI], AL
MOV AX, WORD PTR[SI]//同时取出两个SI字节,即此次循环右移后的imput[i]和未加密的input[i+1]
XOR AX, WORD PTR[BX]//同上,将AX与两字节的BX异或
MOV WORD PTR[SI], AX
INC SI
ADD BX, 2
CMP BX, OFFSET DATA2 + 10
JNE CASE1
MOV BX, OFFSET DATA2
CASE1:
LOOP LOOP2
POP CX
POP BX
POP AX
RET
ENCRYPT ENDP
循环右移2位的代码实现:x=(x>>2)|(x<<6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
加密脚本
#include <stdio.h>
#include <stdint.h>
int main()
{
unsigned char input[36];
for(int i=0;i<36;i++)
{
scanf("%c",&input[i]);
}
uint16_t key[5]={0x1122, 0x3344, 0x1717, 0x9090, 0xBBCC};
for(int i=0;i<35;i++)
{
input[i]=(input[i]>>2)|(input[i]<<6);
uint16_t temp=(input[i]|input[i+1]<<8);
temp^=key[i%5];
input[i]=temp&0xff;
input[i+1]=temp>>8;
}
for(int i=0;i<36;i++)
{
printf("%#x ",input[i]);
}
}

解密脚本实际上就是加密脚本逆向

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>
#include <stdint.h>
int main()
{
unsigned char input[36]={0xbb,0x1b,0x83,0x8c,0x36,0x19,0xcc,0x97,0x8d,0xe4,0x97,0xcc,0xc,0x48,0xe4,0x1b,0xe,0xd7,0x5b,0x65,0x1b,0x50,0x96,0x6,0x3f,0x19,0xc,0x4f,0x4e,0xf9,0x1b,0xd7,0xc,0x1d,0xa0,0xc6};

uint16_t key[5]={0x1122, 0x3344, 0x1717, 0x9090, 0xBBCC};
for(int i=34;i>=0;i--)
{

uint16_t temp=(input[i]|input[i+1]<<8);
temp^=key[i%5];
input[i]=temp&0xff;
input[i+1]=temp>>8;
input[i]=(input[i]<<2)|(input[i]>>6);
}
for(int i=0;i<36;i++)
{
printf("%c",input[i]);
}
}

test2:PlzDebugMe

进入ida,我们查找flag相关函数
不难看出这个为中心函数
本质是一个加密比较,逆向只要再进行一次相同加密就行了
这里我们采取动调patch的方法
patch掉wrong分支的return 0;设下如图断点
debug
动态调试过程中将密文重新填入输入中
debug
加密32次得到flag
debug

test3:ezCSharp

dnspy打开
发现这题其实是解密完密文后与输入比对
直接动态调试获取flag即可
Cs

test4:ezCalculate

打开ida,是简单的加密和计算
ezc
直接逆向计算即可

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>
int main()
{
unsigned char key[22] = {
0x77, 0x77, 0x71, 0x65, 0x73, 0x73, 0x67, 0x78, 0x73, 0x64, 0x64, 0x6B, 0x61, 0x61, 0x6F, 0x31,
0x32, 0x33, 0x77, 0x6D, 0x73,0x00
};
unsigned char answer[22] = {
0x33, 0x1D, 0x32, 0x44, 0x2A, 0x54, 0x45, 0x2C, 0x2E, 0x74, 0x8C, 0x4B, 0x40, 0x42, 0x43, 0x73,
0x71, 0x82, 0x24, 0x35, 0x10, 0x00,
};
for(int i=0;i<21;i++)
{
answer[i]+=key[i];
}
for(int i=0;i<21;i++)
{

answer[i]=answer[i]^key[i];
}

for(int i=0;i<21;i++)
{
answer[i]-=key[i];
}
printf("%s",answer);

}
1
flag{Add_X0r_and_Sub}

test5:jvav

发现文件是apk格式,使用工具jadx,根据题目提示,我们发现EncKt
jvav
对明文主要处理为这一步
jvav
分别为:base64加密,相加异或取反,右移六位
从外往里逆向计算即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
int main()
{
short enc[]={-89, 96, 102, 118, -89, -122, 103, -103, -125, -95, 114, 117, -116, -102, 114, -115, -125, 108, 110, 118, -91, -83, 101, -115, -116, -114, 124, 114, -123, -87, -87, -114, 121, 108, 124, -114};
short flag[36];
for(int i=0;i<36;i++)
{
flag[i]=enc[(i+31)%36];
}
for(int i=0;i<36;i++)
{
flag[i]=((~flag[i])^11)-32;
}
for(int i=0;i<36;i++)
printf("%c",flag[i]);
}
1
2
ZmxhZ3trb3RsMW5faXNfYWxzb19qYXZhfQ==
flag{kotl1n_is_also_java}