1.查壳
PE32 无壳
尝试运行
提示输入flag,但是发现输入不进去,程序也没有卡顿,光标闪烁很流畅,猜测是程序内部分代码阻止了输入。
2.IDA逆向分析
题目名为Newbie_calculations,也是一种提示,表示此题与运算相关
打开看到一堆变量定义和一堆函数调用,逆序阅读代码
发现程序最后直接输出flag,其值在数组v120中,并且知道其长度为32。
向上跟踪数组v120
在栈中修改数组长度后,代码变的好看一点了,但还是没能完全解决IDA拆分的问题
首先初始化数组v120[32], 其中32个元素全初始化为1
阅读代码后发现,main函数中没有执行用户输入的函数,
一大堆的函数执行中实际上只有三个函数
sub_731100 ,sub_731000 和sub_731220
分别查看
main函数代码如下:(三个函数已经经过改名)
int __cdecl main(int argc, const char **argv, const char **envp)
{
_DWORD *v3; // eax
_DWORD *v4; // eax
_DWORD *v5; // eax
_DWORD *v6; // eax
_DWORD *v7; // eax
_DWORD *v8; // eax
_DWORD *v9; // eax
_DWORD *v10; // eax
_DWORD *v11; // eax
_DWORD *v12; // eax
_DWORD *v13; // eax
_DWORD *v14; // eax
_DWORD *v15; // eax
_DWORD *v16; // eax
_DWORD *v17; // eax
_DWORD *v18; // eax
_DWORD *v19; // eax
_DWORD *v20; // eax
_DWORD *v21; // eax
_DWORD *v22; // eax
_DWORD *v23; // eax
_DWORD *v24; // eax
_DWORD *v25; // eax
_DWORD *v26; // eax
_DWORD *v27; // eax
_DWORD *v28; // eax
_DWORD *v29; // eax
_DWORD *v30; // eax
_DWORD *v31; // eax
_DWORD *v32; // eax
_DWORD *v33; // eax
_DWORD *v34; // eax
_DWORD *v35; // eax
_DWORD *v36; // eax
_DWORD *v37; // eax
_DWORD *v38; // eax
_DWORD *v39; // eax
_DWORD *v40; // eax
_DWORD *v41; // eax
_DWORD *v42; // eax
_DWORD *v43; // eax
_DWORD *v44; // eax
_DWORD *v45; // eax
_DWORD *v46; // eax
_DWORD *v47; // eax
_DWORD *v48; // eax
_DWORD *v49; // eax
_DWORD *v50; // eax
_DWORD *v51; // eax
_DWORD *v52; // eax
_DWORD *v53; // eax
_DWORD *v54; // eax
_DWORD *v55; // eax
_DWORD *v56; // eax
_DWORD *v57; // eax
_DWORD *v58; // eax
_DWORD *v59; // eax
_DWORD *v60; // eax
_DWORD *v61; // eax
_DWORD *v62; // eax
_DWORD *v63; // eax
_DWORD *v64; // eax
_DWORD *v65; // eax
_DWORD *v66; // eax
_DWORD *v67; // eax
_DWORD *v68; // eax
_DWORD *v69; // eax
_DWORD *v70; // eax
_DWORD *v71; // eax
_DWORD *v72; // eax
_DWORD *v73; // eax
_DWORD *v74; // eax
_DWORD *v75; // eax
_DWORD *v76; // eax
_DWORD *v77; // eax
_DWORD *v78; // eax
_DWORD *v79; // eax
_DWORD *v80; // eax
_DWORD *v81; // eax
_DWORD *v82; // eax
_DWORD *v83; // eax
_DWORD *v84; // eax
_DWORD *v85; // eax
_DWORD *v86; // eax
_DWORD *v87; // eax
_DWORD *v88; // eax
_DWORD *v89; // eax
_DWORD *v90; // eax
_DWORD *v91; // eax
_DWORD *v92; // eax
_DWORD *v93; // eax
_DWORD *v94; // eax
_DWORD *v95; // eax
_DWORD *v96; // eax
_DWORD *v97; // eax
_DWORD *v98; // eax
_DWORD *v99; // eax
_DWORD *v100; // eax
_DWORD *v101; // eax
_DWORD *v102; // eax
_DWORD *v103; // eax
_DWORD *v104; // eax
_DWORD *v105; // eax
_DWORD *v106; // eax
_DWORD *v107; // eax
_DWORD *v108; // eax
_DWORD *v109; // eax
_DWORD *v110; // eax
_DWORD *v111; // eax
_DWORD *v112; // eax
_DWORD *v113; // eax
int v115; // [esp-8h] [ebp-9Ch]
int v116; // [esp-4h] [ebp-98h]
int v117; // [esp-4h] [ebp-98h]
int i; // [esp+4h] [ebp-90h]
int j; // [esp+8h] [ebp-8Ch]
int v120[12]; // [esp+Ch] [ebp-88h] BYREF 由程序代码可知,v120的长度为32,IDA将它拆分了,所以要在栈中修改
int v121; // [esp+3Ch] [ebp-58h] BYREF
int v122; // [esp+40h] [ebp-54h] BYREF
int v123; // [esp+44h] [ebp-50h] BYREF
int v124; // [esp+48h] [ebp-4Ch] BYREF
int v125; // [esp+4Ch] [ebp-48h] BYREF
int v126; // [esp+50h] [ebp-44h] BYREF
int v127; // [esp+54h] [ebp-40h] BYREF
int v128; // [esp+58h] [ebp-3Ch] BYREF
int v129; // [esp+5Ch] [ebp-38h] BYREF
int v130; // [esp+60h] [ebp-34h] BYREF
int v131; // [esp+64h] [ebp-30h] BYREF
int v132; // [esp+68h] [ebp-2Ch] BYREF
int v133; // [esp+6Ch] [ebp-28h] BYREF
int v134; // [esp+70h] [ebp-24h] BYREF
int v135; // [esp+74h] [ebp-20h] BYREF
int v136; // [esp+78h] [ebp-1Ch] BYREF
int v137; // [esp+7Ch] [ebp-18h] BYREF
int v138; // [esp+80h] [ebp-14h] BYREF
int v139; // [esp+84h] [ebp-10h] BYREF
_DWORD v140[2]; // [esp+88h] [ebp-Ch] BYREF
for ( i = 0; i < 32; ++i )
v120[i] = 1; // v120,32个元素全是1
v140[1] = 0;
puts("Your flag is:"); // 执行的一堆函数中,实际上只有三个函数,
// sub_731100,sub_731000,sub_731220
v3 = mul(v120, 1000000000); // 将参数2与参数1相乘并赋值给参数1
v4 = sub(v3, 999999950); // 参数1-参数2后的结果赋给参数1
mul(v4, 2);
v5 = add(&v120[1], 5000000); // 参数1的值与参数2相加后赋值给参数1
v6 = sub(v5, 6666666);
v7 = add(v6, 1666666);
v8 = add(v7, 45);
v9 = mul(v8, 2);
add(v9, 5);
v10 = mul(&v120[2], 1000000000);
v11 = sub(v10, 999999950);
v12 = mul(v11, 2);
add(v12, 2);
v13 = add(&v120[3], 55);
v14 = sub(v13, 3);
v15 = add(v14, 4);
sub(v15, 1);
v16 = mul(&v120[4], 100000000);
v17 = sub(v16, 99999950);
v18 = mul(v17, 2);
add(v18, 2);
v19 = sub(&v120[5], 1);
v20 = mul(v19, 1000000000);
v21 = add(v20, 55);
sub(v21, 3);
v22 = mul(&v120[6], 1000000);
v23 = sub(v22, 999975);
mul(v23, 4);
v24 = add(&v120[7], 55);
v25 = sub(v24, 33);
v26 = add(v25, 44);
sub(v26, 11);
v27 = mul(&v120[8], 10);
v28 = sub(v27, 5);
v29 = mul(v28, 8);
add(v29, 9);
v30 = add(&v120[9], 0);
v31 = sub(v30, 0);
v32 = add(v31, 11);
v33 = sub(v32, 11);
add(v33, 53);
v34 = add(&v120[10], 49);
v35 = sub(v34, 2);
v36 = add(v35, 4);
sub(v36, 2);
v37 = mul(&v120[11], 1000000);
v38 = sub(v37, 999999);
v39 = mul(v38, 4);
add(v39, 50);
v40 = add(&v121, 1);
v41 = add(v40, 1);
v42 = add(v41, 1);
v43 = add(v42, 1);
v44 = add(v43, 1);
v45 = add(v44, 1);
v46 = add(v45, 10);
add(v46, 32);
v47 = mul(&v122, 10);
v48 = sub(v47, 5);
v49 = mul(v48, 8);
v50 = add(v49, 9);
add(v50, 48);
v51 = sub(&v123, 1);
v52 = mul(v51, -294967296);
v53 = add(v52, 55);
sub(v53, 3);
v54 = add(&v124, 1);
v55 = add(v54, 2);
v56 = add(v55, 3);
v57 = add(v56, 4);
v58 = add(v57, 5);
v59 = add(v58, 6);
v60 = add(v59, 7);
add(v60, 20);
v61 = mul(&v125, 10);
v62 = sub(v61, 5);
v63 = mul(v62, 8);
v64 = add(v63, 9);
add(v64, 48);
v65 = add(&v126, 7);
v66 = add(v65, 6);
v67 = add(v66, 5);
v68 = add(v67, 4);
v69 = add(v68, 3);
v70 = add(v69, 2);
v71 = add(v70, 1);
add(v71, 20);
v72 = add(&v127, 7);
v73 = add(v72, 2);
v74 = add(v73, 4);
v75 = add(v74, 3);
v76 = add(v75, 6);
v77 = add(v76, 5);
v78 = add(v77, 1);
add(v78, 20);
v79 = mul(&v128, 1000000);
v80 = sub(v79, 999999);
v81 = mul(v80, 4);
v82 = add(v81, 50);
sub(v82, 1);
v83 = sub(&v129, 1);
v84 = mul(v83, -294967296);
v85 = add(v84, 49);
sub(v85, 1);
v86 = sub(&v130, 1);
v87 = mul(v86, 1000000000);
v88 = add(v87, 54);
v89 = sub(v88, 1);
v90 = add(v89, 1000000000);
sub(v90, 1000000000);
v91 = add(&v131, 49);
v92 = sub(v91, 1);
v93 = add(v92, 2);
sub(v93, 1);
v94 = mul(&v132, 10);
v95 = sub(v94, 5);
v96 = mul(v95, 8);
v97 = add(v96, 9);
add(v97, 48);
v98 = add(&v133, 1);
v99 = add(v98, 3);
v100 = add(v99, 3);
v101 = add(v100, 3);
v102 = add(v101, 6);
v103 = add(v102, 6);
v104 = add(v103, 6);
add(v104, 20);
v105 = add(&v134, 55);
v106 = sub(v105, 33);
v107 = add(v106, 44);
v108 = sub(v107, 11);
add(v108, 42);
add(&v135, v134);
add(&v136, v121);
v115 = v136;
v109 = sub(&v137, 1);
v110 = add(v109, v115);
sub(v110, 1);
v116 = v132;
v111 = sub(&v138, 1);
v112 = mul(v111, 1000000);
add(v112, v116);
v117 = v136;
v113 = add(&v139, 1);
mul(v113, v117);
add(v140, v139);
sub_731C7F("CTF{");
for ( j = 0; j < 32; ++j ) // 输出flag,flag的值在数组v120中,继续向上查看对v120进行处理的函数
sub_731C7F("%c", SLOBYTE(v120[j]));
sub_731C7F("}\n");
return 0;
}
(1)sub_731000()--add
其中有两个循环次数很大的while循环,但我们始终关注v120的值的变化即可,这里有个不常见的知识点——负数作为循环条件,这里补充一些计组知识,在CPU的ALU(算术逻辑单元)中进行计算时,数字通常都是以补码形式进行计算,正数的补码和反码都跟原码相同;负数的原码为除符号位全部取反,补码为反码末位加1,即负数的补码为原码的数值位取反后末位+1。
-1的补码为:0xFFFFFFFF,
负数减正数,实际上转换为补码的加法计算:
[-1]补-[1]补=[-1]补+[-1]补=0xFFFFFFFF+0xFFFFFFFF=0x1FFFFFFFE
而在32位系统中,int型的变量长度为4个字节,上面符号位向前进的那一位1,实际上已经向下溢出,并不存在。
所以由上可知,在循环不断的减1中,被减数持续下溢,逐渐会得到正数,最终得到0,while循环结束。
将函数逻辑简化后,发现其作用就是将参数1和参数2相加后赋值给参数1。
(2)sub_73110()--mul
其中调用了sub_731000()--add
将此函数逻辑简化后:发现其作用就是将参数1和参数2相乘后赋值给参数1。
(3)sub_7317220()--sub
同理将此函数逻辑简化后:发现其作用就是将参数1减去参数2后赋值给参数1。
3.解题
将main函数用python重写后,代码如下:、
def add(a,b):
return a + b
def sub(a,b):
return a - b
def mul(a,b):
return a * b
v120 = [ 1 for i in range(32)]
v121=0
v3 = mul(v120[0], 1000000000)
v4 = sub(v3, 999999950)
v120[0]=mul(v4, 2)
v5 = add( v120[1], 5000000)
v6 = sub(v5, 6666666)
v7 = add(v6, 1666666)
v8 = add(v7, 45)
v9 = mul(v8, 2)
v120[1]=add(v9, 5)
v10 = mul( v120[2], 1000000000)
v11 = sub(v10, 999999950)
v12 = mul(v11, 2)
v120[2]=add(v12, 2)
v13 = add( v120[3], 55)
v14 = sub(v13, 3)
v15 = add(v14, 4)
v120[3]=sub(v15, 1)
v16 = mul( v120[4], 100000000)
v17 = sub(v16, 99999950)
v18 = mul(v17, 2)
v120[4]=add(v18, 2)
v19 = sub( v120[5], 1)
v20 = mul(v19, 1000000000)
v21 = add(v20, 55)
v120[5]=sub(v21, 3)
v22 = mul( v120[6], 1000000)
v23 = sub(v22, 999975)
v120[6]=mul(v23, 4)
v24 = add( v120[7], 55)
v25 = sub(v24, 33)
v26 = add(v25, 44)
v120[7]=sub(v26, 11)
v27 = mul( v120[8], 10)
v28 = sub(v27, 5)
v29 = mul(v28, 8)
v120[8]=add(v29, 9)
v30 = add( v120[9], 0)
v31 = sub(v30, 0)
v32 = add(v31, 11)
v33 = sub(v32, 11)
v120[9]=add(v33, 53)
v34 = add( v120[10], 49)
v35 = sub(v34, 2)
v36 = add(v35, 4)
v120[10]=sub(v36, 2)
v37 = mul( v120[11], 1000000)
v38 = sub(v37, 999999)
v39 = mul(v38, 4)
v120[11]=add(v39, 50)
v40 = add( v120[12], 1)
v41 = add(v40, 1)
v42 = add(v41, 1)
v43 = add(v42, 1)
v44 = add(v43, 1)
v45 = add(v44, 1)
v46 = add(v45, 10)
v120[12]=add(v46, 32)
v47 = mul( v120[13], 10)
v48 = sub(v47, 5)
v49 = mul(v48, 8)
v50 = add(v49, 9)
v120[13]=add(v50, 48)
v51 = sub( v120[14], 1)
v52 = mul(v51, -294967296)
v53 = add(v52, 55)
v120[14]=sub(v53, 3)
v54 = add( v120[15], 1)
v55 = add(v54, 2)
v56 = add(v55, 3)
v57 = add(v56, 4)
v58 = add(v57, 5)
v59 = add(v58, 6)
v60 = add(v59, 7)
v120[15]=add(v60, 20)
v61 = mul( v120[16], 10)
v62 = sub(v61, 5)
v63 = mul(v62, 8)
v64 = add(v63, 9)
v120[16]=add(v64, 48)
v65 = add( v120[17], 7)
v66 = add(v65, 6)
v67 = add(v66, 5)
v68 = add(v67, 4)
v69 = add(v68, 3)
v70 = add(v69, 2)
v71 = add(v70, 1)
v120[17]=add(v71, 20)
v72 = add( v120[18], 7)
v73 = add(v72, 2)
v74 = add(v73, 4)
v75 = add(v74, 3)
v76 = add(v75, 6)
v77 = add(v76, 5)
v78 = add(v77, 1)
v120[18]=add(v78, 20)
v79 = mul( v120[19], 1000000)
v80 = sub(v79, 999999)
v81 = mul(v80, 4)
v82 = add(v81, 50)
v120[19]=sub(v82, 1)
v83 = sub( v120[20], 1)
v84 = mul(v83, -294967296)
v85 = add(v84, 49)
v120[20]=sub(v85, 1)
v86 = sub( v120[21], 1)
v87 = mul(v86, 1000000000)
v88 = add(v87, 54)
v89 = sub(v88, 1)
v90 = add(v89, 1000000000)
v120[21]=sub(v90, 1000000000)
v91 = add( v120[22], 49)
v92 = sub(v91, 1)
v93 = add(v92, 2)
v120[22]=sub(v93, 1)
v94 = mul( v120[23], 10)
v95 = sub(v94, 5)
v96 = mul(v95, 8)
v97 = add(v96, 9)
v120[23]=add(v97, 48)
v98 = add( v120[24], 1)
v99 = add(v98, 3)
v100 = add(v99, 3)
v101 = add(v100, 3)
v102 = add(v101, 6)
v103 = add(v102, 6)
v104 = add(v103, 6)
v120[24]=add(v104, 20)
v105 = add( v120[25], 55)
v106 = sub(v105, 33)
v107 = add(v106, 44)
v108 = sub(v107, 11)
v120[25]=add(v108, 42)
v120[26]=add( v120[26], v120[25])
v120[27]=add( v120[27], v120[12])
v115 = v120[27]
v109 = sub( v120[28], 1)
v110 = add(v109, v115)
v120[28]=sub(v110, 1)
v116 = v120[23]
v111 = sub( v120[29], 1)
v112 = mul(v111, 1000000)
v120[29]=add(v112, v116)
v117 = v120[27]
v113 = add( v120[30], 1)
v120[30]=mul(v113, v117)
v120[31]=add(v120[31], v120[30])
print("CTF{"+"".join(map(chr,v120))+"}")
运行得到flag:
CTF{daf8f4d816261a41a115052a1bc21ade}