这个题真的是1星的难度吗?

注:下面的过程都是抄的。

image-20231017193447816

进来首先看到off_FA88。

由于off_FA88 = (char *)sub_6314((unsigned int)v24, k, (unsigned int)m, v12);

得知off_FA88 是sub_6314()这个函数的返回值。

image-20231017193816866

sub_6314()函数的返回值是==byte_104C8.

byte_104C8是dword_E120得到的。

byte_104C8 = dword_E120[a3 - 5] & 0x7F;

dword_E120是通过异或sub_62B5()这个函数的返回值得到的

dword_E120[a3 - 5] ^= sub_62B5();

image-20231017194122823

sub_62B5()这个函数是由于dword_E1E8这个得到的。

image-20231017194348141

dword_E1E8 += printf("\x1B[1;37mYou have nyaned for %d times!\x1B[J\x1B[0m", (unsigned int)++dword_108E0);

dword_E1E8是通过printf函数的返回值得到的。

printf的返回值:和这个dword_108E0这个有关系。

根据printf输出的字符数修改,测试可得 42 + log(count)

通过:如下进行测试

1
printf("\n%d",printf("\x1B[1;37mYou have nyaned for %d times!\x1B[J\x1B[0m",1));

发现这样是42,再多试几个就试出来规律了。

最后总结一下,main函数所有相关值的修改顺序是off_FA88->dword_108E0->dword_E1E8。解题exp也遵循这个规律,先处理dword_E120(flag,off_FA88),再是dword_E1E8(count),最后dword_E1E8。后面的for循环只不过是将稍微修正一下flag的值而已,总体完全等同于题目逻辑

真写不来,最后找了Wp:

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
60
61
62
63
64
65
#include<stdio.h>
#include<string.h>
//在ida里面点开dword_E1E8会发现初始值为dword_E1E8
int dword_E1E8 = 0x1106;
//同理,ida里也能看到dword_E120的初始值
int dword_E120[50]={0x27fb, 0x27a4, 0x464e, 0x0e36, 0x7b70, 0x5e7a, 0x1a4a, 0x45c1, 0x2bdf, 0x23bd, 0x3a15, 0x5b83, 0x1e15, 0x5367, 0x50b8, 0x20ca, 0x41f5, 0x57d1, 0x7750, 0x2adf, 0x11f8, 0x09bb, 0x5724, 0x7374, 0x3ce6, 0x646e, 0x010c, 0x6e10, 0x64f4, 0x3263, 0x3137, 0x00b8, 0x229c, 0x7bcd, 0x73bd, 0x480c, 0x14db, 0x68b9, 0x5c8a, 0x1b61, 0x6c59, 0x5707, 0x09e6, 0x1fb9, 0x2ad3, 0x76d4, 0x3113, 0x7c7e, 0x11e0, 0x6c70};
//原封不动抄下来就好了
int sub_62B5()
{
dword_E1E8 = 1103515245 * dword_E1E8 + 12345;
return (dword_E1E8 >> 10) & 0x7FFF;
}
//这块是拿来算输出数字n需要多少个字符的。个位数0,十位数1,百位数2……以此类推。至于为什么和一般理解的不一样,我也不太清楚,自己做了个实验发现的
int llog(int n){
int a = 0;
while(n /= 10)a++;
return a;
}
//这个函数我没有特别放出来,反正这里也是照抄的
int sub_62E3(char a1)
{
int result; // rax

if ( (a1 & 0x7Fu) <= 0x7E )
result = (a1 & 0x7Fu) > 0x20;
else
result = 0LL;
return result;
}

int main(){
//count代表那个不停自增的dword_108E0
int count = 0;
while(1){
//这里结合 函数,本来应该是dword_E120[a3-5]。a3对应到main函数的调用是循环索引l,还挺麻烦的。其实只需要把鼠标悬停在dword_E120上,就能发现它的大小是50,直接这么设定就好了。一个偷懒的方法,很多情况还是要动调确定
for(int i = 0; i < 50; i++){
dword_E120[i]^=sub_62B5();
}
count++;
//计算printf的返回值,更改dword_E1E8,每10倍增加一个位数
dword_E1E8+=42+llog(count);
if(count % 1000000 == 0 ){
printf("Count:%d\n",count);
}
//flag代表off_FA88
unsigned char flag[51]={0};
for(int i = 0; i < 50; i++){
//根据出题人所说,出题时循环次数为705980581,但是线性同余随机数算法出现了循环导致在100427942就出现了flag,若只考虑数组的最低字节,能在100001958得到flag
// Loop: 100427942
// if((dword_E120[i] & 0xff00)){
// break;
// }
// Loop: 100001958
if(!sub_62E3(dword_E120[i])){
break;
}
flag[i]=dword_E120[i]&0xff;
}
if(memcmp("CatCTF",flag,6) == 0){
puts(flag);
printf("Count:%d\n",count);
break;
}
}
}
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
#include<stdio.h>
#include<string.h>
int dword_E1E8 = 0x1106;
int dword_E120[50]={0x27fb, 0x27a4, 0x464e, 0x0e36, 0x7b70, 0x5e7a, 0x1a4a, 0x45c1, 0x2bdf, 0x23bd, 0x3a15, 0x5b83, 0x1e15, 0x5367, 0x50b8, 0x20ca, 0x41f5, 0x57d1, 0x7750, 0x2adf, 0x11f8, 0x09bb, 0x5724, 0x7374, 0x3ce6, 0x646e, 0x010c, 0x6e10, 0x64f4, 0x3263, 0x3137, 0x00b8, 0x229c, 0x7bcd, 0x73bd, 0x480c, 0x14db, 0x68b9, 0x5c8a, 0x1b61, 0x6c59, 0x5707, 0x09e6, 0x1fb9, 0x2ad3, 0x76d4, 0x3113, 0x7c7e, 0x11e0, 0x6c70};
int sub_62B5()
{
dword_E1E8 = 1103515245 * dword_E1E8 + 12345;
return (dword_E1E8 >> 10) & 0x7FFF;
}

int llog(int n){
int a = 0;
while(n /= 10)a++;
return a;
}

int sub_62E3(char a1)
{
int result; // rax

if ( (a1 & 0x7Fu) <= 0x7E )
result = (a1 & 0x7Fu) > 0x20;
else
result = 0LL;
return result;
}

int main(){
int count = 0;
while(1){
for(int i = 0; i < 50; i++){
dword_E120[i]^=sub_62B5();
}
count++;
dword_E1E8+=42+llog(count);
if(count % 1000000 == 0 ){
printf("Count:%d\n",count);
}
unsigned char flag[51]={0};
for(int i = 0; i < 50; i++){
// Loop: 100427942
// if((dword_E120[i] & 0xff00)){
// break;
// }
// Loop: 100001958
if(!sub_62E3(dword_E120[i])){
break;
}
flag[i]=dword_E120[i]&0xff;
}
if(memcmp("CatCTF",flag,6) == 0){
puts(flag);
printf("Count:%d\n",count);
break;
}
}
}