-
-
[讨论]25KCTF-初窥门径
-
发表于: 2025-8-18 05:48 3995
-
25KCTF-初窥门径
IDA反编译main函数,可以看到第一个条件,要求输入长度>0x70(112)。
图 1
Dbg跟进到sub_0070129E,这个就是验证函数,但由于程序是通过Shellcode的方式间接调用到验证函数,IDA识别不出该函数有关的调用,所以会出现如图 3所示的未定义情况。解决方案是在0070129E的位置上按下P键,创建函数定义。此时IDA便可进行F5反编译函数,效果如图 4所示。
图 2
先梳理一下验证流程,首先是要求输入长度>0x70,其次是要求sub_0070129E的返回值为1。
根据返回值回溯第一个条件,通过动态调试确定符号信息,v19是某个index,v24-1是输入字符串的最后一个index;dword_703020是张映射表,映射关系是80 * v18 + 10 * v18 + 10 * v15 + v21,关系涉及到三个变量,分别为v18、v15、v21。映射值为8114时即走向验证成功。
if ( v19 == v24 - 1 && dword_703020[80 * v18 + 10 * v18 + 10 * v15 + v21] == 8114 )
return 1;
第二个条件如下表所示,v23是某个index,v24是输入字符串的长度;与dword_703020相关的映射关系和第一个条件是相同的;a11为栈ESP、a11为栈ESP+4。
经验之谈,一般ESP寄存器值的bit高4位是0001,地址与19FE 2000相像。所以a11<2、a12<2、a11 == a12是假条件,永不成立。最终我们需要关注的是v23 < v24 && (!sub_7011C0(dword_703020[80 * v18 + 10 * v18 + 10 * v15 + v21], &a11, &a12)和abs32(v21 - v26) + abs32(v15 - v27) + abs32(v18 - v28) != 1 )。
if ( v23 < v24
&& (!sub_7011C0(dword_703020[80 * v18 + 10 * v18 + 10 * v15 + v21], &a11, &a12)
|| a11 < 2
|| a12 < 2
|| a11 == a12)
|| abs32(v21 - v26) + abs32(v15 - v27) + abs32(v18 - v28) != 1 )
{
return 0;
}
由于v23是某个index,v24是输入字符串的长度,猜测v23一直小于24,即在条件当中恒为1。
这就要求!sub_7011C0的值为0,即sub_7011C0的返回值为1,使得1 && !sub_7011C0的结果为0。这样就不会走向return 0。其次是abs32(v21 - v26) + abs32(v15 - v27) + abs32(v18 - v28) != 1 ),要求表达式的值为1,这样不会走向return 0,涉及到六个变量,分别为v18、v15、v21和v28、v27、v26。我们要做的,就是搞清楚俩组变量之间的关系。
第三个条件如下表所示,v20 是某个 index,要求dword_703020的映射值为11278,否则走向验证失败。
if ( v20 == 1 && dword_703020[80 * v18 + 10 * v18 + 10 * v15 + v21] != 11278 )
return 0;
第四个条件如下表所示,v23为某个index,v24-1为输入字符串的最后一个index,要求其为最后一个index同时dword_703020的映射值为8114,否则走向验证失败。
if ( v23 == v24 - 1 && dword_703020[80 * v18 + 10 * v18 + 10 * v15 + v21] != 8114 )
return 0;
V14为当前的index,v14 & 1 != 0,取当前index的最低位与1做与运算,即每当v14位偶数时触发验证。同时也意味着输入字符串2字节为一组。
if ( (v14 & 1) != 0 )
{
// 开始条件验证
}
接下来是6个变量的关系,可以发现后一组的三个变量保存着上一次index的值。前一组变量都根据v13计算,而v13的值根据byte_7020F9表和input[index]映射出。
if ( (v14 & 1) != 0 )
{
v21 = v13 % 12;
if ( v13 >= 12 )
v18 = (v13 >= 24) + 1;
else
v18 = 0;
}
else{
v15 = v13 % 12;
}
// 验证后
v26 = v21;
v27 = v15;
v28 = v18;
v13 根据表byte_7020F9和input[index]映射出
输入条件根据80 * v18 + 10 * v18 + 10 * v15 + v21推出变量的范围,最终通过打表的方式得到一张完整的合法输入表(input_unit)。
v21 = v13 % 12; (v12恒小于12)
v15 = v13 % 12; (v15恒小于12)
v18恒小于2,根据dword_703020[index] == 8114的index得出,index为269,当v17>3时,80 * 3 + 10 * 3 = 270,必然走向验证失败
// 由于idb丢了,所以实际算法与理论存在符号偏差
for (size_t v17 = 0; v17 <= 2; v17++)
{
for (size_t v14 = 0; v14 < 12; v14++)
{
for (size_t v20 = 0; v20 < 12; v20++)
{
int f = sub_7011C0(dword_703020[table_offset], &a10, &a11);
if (f == 1)
{
char left = str_table[v14];
char right = str_table[v17 * 12 + v20];
Unit unit;
unit.v17 = v17;
unit.v14 = v14;
unit.v20 = v20;
unit.left = left;
unit.right = right;
input_unit.push_back(unit);
}
赞赏
- [求助]我很痛苦 1148
- [讨论]25KCTF-初窥门径 3996
- [讨论]关于我对未来的看法 915
- [讨论]25KCTF-废材少年觉醒 271
- [讨论]关于高利贷的设计问题 776