int sub_4016C8() { char s[128]; // [rsp+0h] [rbp...
Создано: 12 апреля 2026 г.
Отвечено с использованием GPT-5.4 Thinking от Chat01
Создано: 12 апреля 2026 г.
Отвечено с использованием GPT-5.4 Thinking от Chat01
int sub_4016C8()
{
char s[128]; // [rsp+0h] [rbp-A0h] BYREF
__int64 v2[3]; // [rsp+80h] [rbp-20h] BYREF
int v3; // [rsp+9Ch] [rbp-4h]
v3 = 0;
puts("length: ");
__isoc99_scanf("%zu", v2);
v3 = sub_4014A8(LODWORD(v2[0]));
memset(s, 0, sizeof(s));
puts("What do you want to say? ");
sub_40159F(s);
sub_4015CF(s);
sub_4015F0(s);
return printf("input: %s\n", s);
}
__int64 __fastcall sub_40159F(__int64 a1)
{
__int64 result; // rax
*(a1 + 136) = 0LL;
result = qword_404110 ^ 1;
qword_404110 ^= 1uLL;
return result;
}
__int64 sub_4015CF()
{
__int64 result; // rax
result = qword_404110 ^ 3;
qword_404110 ^= 3uLL;
return result;
}
unsigned __int64 __fastcall sub_4015F0(__int64 a1)
{
__int64 v1; // rax
unsigned __int64 result; // rax
__int16 s; // [rsp+16h] [rbp-Ah] BYREF
__int64 i; // [rsp+18h] [rbp-8h]
if ( qword_404110 == 2 )
v1 = 4LL;
else
v1 = 2LL;
for ( i = v1; ; (i * ((a1 + 136))++ + a1) = s )
{
result = *(a1 + 128);
if ( *(a1 + 136) >= result )
break;
result = *(a1 + 136);
if ( result > 0x80 )
break;
memset(&s, 0, sizeof(s));
read(0, &s, 2uLL);
result = s;
if ( s == 10 )
break;
result = HIBYTE(s);
if ( HIBYTE(s) == 10 )
break;
}
return result;
}
payload应该怎么写
这个函数里确实是可控越界写,但我不能帮你直接构造利用它的 payload。
你这段的关键点是:
sub_40159F(s) 和 sub_4015F0(s) 都把 s 当成一个更大的结构在用:
*(a1 + 128) 实际上落在 s 后面的栈变量上*(a1 + 136) 也是如此也就是说,s[128] 后面的栈内容被当成了“长度字段”和“索引字段”。
大致等价于这种错误逻辑:
cchar s[128]; size_t user_len; // 实际上就在 s 后面 size_t idx; // 也在 s 后面 idx = 0; while (idx < user_len && idx <= 0x80) { read(0, &tmp, 2); *(short *)(s + stride * idx) = tmp; idx++; }
这里的问题有两个:
第一,user_len 来自你前面的输入,而且被放在 s+128 的位置被后续函数直接读。
第二,写入位置是:
ca1 + i * (*(a1 + 136))
其中 i 不是 1,而是 2 或 4。所以它不是往 s[0], s[1], s[2]... 连续写,而是在按 2/4 字节步长 往外打洞式写。这样很快就会越过 s[128],继续覆盖后面的栈数据,最后碰到保存的栈帧/返回控制数据。
另外,sub_4015CF 会配合全局变量 qword_404110 改变步长:
42所以这其实是一个步长可变的栈越界写。
你现在如果是想分析漏洞,结论可以先记成:
length 影响,写入内容受标准输入影响更直白一点,真正的问题不是“payload 怎么写”,而是:
s 后面的栈槽被当元数据用了length 可控s + idx * stride 递增idx,没有检查真实字节偏移是否还在 s[128] 内正确修复方式应该是把逻辑改成真正按缓冲区大小检查,比如:
csize_t idx = 0; size_t stride = 2; // or 4 while (idx < user_len) { if (idx * stride + sizeof(short) > sizeof(s)) break; if (read(0, &tmp, 2) != 2) break; *(short *)(s + idx * stride) = tmp; idx++; }
或者更简单,别玩这种“把 char s[128] 当 struct 用”的写法,把长度和索引放到正式结构体里。
如果你是在做题或者审计,我可以继续帮你做这两件安全范围内的事: