首页
社区
课程
招聘
[原创]2019看雪CTF晋级赛Q1-第七题writeup
发表于: 2019-3-18 23:16 5628

[原创]2019看雪CTF晋级赛Q1-第七题writeup

2019-3-18 23:16
5628

题目描述为“算法题+轻度ANTI”,说明程序中有反调试。将程序用ida打开,在字符串中发现了“6BigNum”,说明程序中可能有大数结构和运算。

找到main函数,发现程序中有很多花指令,并且.text:004B8E55 call sub_401F58后的数据无法转换为代码,猜测程序中可能有SMC,动态调试程序,看执行完call sub_401F58后程序会在哪执行,单步跟踪函数sub_401F58,发现函数sub_401F58在执行到.text:00402129 retn后会跳转到004B8E5F处执行,且004B8E5A处的一大段数据并没有被修改,说明只是作者在这里插入了一些数据来扰乱ida的分析。

将004B8E5F处的数据转化为代码,并将上面的垃圾数据nop掉。

通过观察程序中代码,发现花指令主要有以下4种模式:

可以通过如下的idapython脚本去除花指令,有部分花指令没有识别到,任然需要自己手动nop掉。

在.text:004B8DF3处创建函数并修改函数结尾为.text:004B9827,F5后得到该函数的代码如下:

函数sub_401F58的花指令要更复杂一些,去除花指令后执行的汇编代码如下:

伪C代码如下:

该函数一共被调用了三次,函数有三个参数,第一个参数是返回地址,后面两个参数是依次传入的,例如第一次调用时参数为(0x4b8e5a,0,0x25a),第二次调用的参数为(0x4029C6,0x4025D3,0xF0),第三次调用的参数为(0x4025F2,0x401F58,0x68)。该函数的作用是进行代码检验,防止patch代码和下int 3断点,然后跳到返回地址加5处执行。例如第一次执行时就是检验0x4b8e5f到0x4b97c7处的代码,然后将结果填入到(0x4BC080+0)处,第二次检验0x4025D8到0x402998处的代码,然后将结果填入到(0x4BC080+4)处,第三次检验0x401F5d到0x4020fd处的代码,然后将结果填入到(0x4BC080+0x9d)处。
通过动态调试得知函数4B5240是获取用户输入的,输入只能为16进制数且只能为1-F,然后会转化为10进制数据,转化规则如下:
例如输入为123AF,表示数据为0xfa321,转化为10进制为1024801,在程序里表示为1084201(从右到左依次为高位到低位)。

函数004017A0是初始化大数的,大数的数据可以在
.text:00401665 1014 mov edx, [ebp+ecx4+var_100C]处下断点,然后查看ebp+ecx4+var_100C处的数据,就是大数的值,即0xc23f6401c93adb,即54675844241111771。

注意004BC080处的数据是根据代码校验后的值填入的,可以附加程序,得到此处真正的值。
然后计算了两个大数的乘积,即0xc23f6401c93adb*0xeedcea3743d03a263af94f386de1=0xb53e8f2b7b1a5b4d53c1bc6b32c8b6a5d9b4d3f97b

函数4016B6和4018DE十分重要,分别是根据下标取大数的数据和根据下标写大数中写入数据。
通过在.text:004B9533 call set_index_data处和.text:004B91BE call set_index_data处下断点,可以得到输入的数据和乘积的数据是怎么插入大数中的。

[0x2,0x3,0xA,0xF,0x12,0x17,0x19,0x1c,0x20,0x21,0x24,0x2a,0x2e,0x2f,0x34,0x37,0x39,0x3c,0x3f,0x46,0x4c,0x4d]是乘积依次插入大数的下标

[0x0,0x1,0x4,0x5,0x6,0x7,0x8,0x9,0xb,0xc,0xd,0xe,0x10,0x11,0x13,0x14,0x15,0x16,0x18,0x1a,0x1b,0x1d,0x1e,0x1f,0x22,0x23,0x25,0x26,0x27,0x28,0x29,0x2b,0x2c,0x2d,0x30,0x31,0x32,0x33,0x35,0x36,0x38,0x3a,0x3b,0x3d,0x3e,0x40,0x41,0x42,0x43,0x44,0x45,0x47,0x48,0x49,0x4a,0x4b,0x4e,0x4f]是输入的数据依次插入大数的下标

查看set_index_data函数和get_index_data函数的调用可以得到变换的算法就是查找表,根据表中的值作为大数的下标,取大数数据后,乘9后异或0x37,交换大数中的数据。

根据length为0x1f1a,可以推导出v59为79。
然后在.text:004B975C call sub_402950和.text:004B9768 cmp [ebp+var_2BBC], 144h处下断点,查看比较的下标跟数据。
得到依次比较的下标为
r1=[0x2,0x3,0xA,0xF,0x12,0x17,0x19,0x1c,0x20,0x21,0x24,0x2a,0x2e,0x2f,0x34,0x37,0x39,0x3c,0x3f,0x46,0x4c,0x4d]
和r2=[0x27,0x42,0x13,0x22,0x25,0x1,0xb,0x2c,0x31,0xc,0x5,0xd,0xe,0x29,0x33,0x10,0x9,0x0,0x11,0x14,0x2b,0x2d,0x1b,0x30,0x32,0x23,0x1a,0x7,0x4,0x6,0x8,0x18,0x3d,0x44,0x3b,0x4e,0x45,0x3e,0x47,0x35,0x48,0x36,0x38,0x3a,0x28,0x1e,0x1f,0x1d,0x26,0x41,0x15,0x16,0x43,0x40,0x49,0x4a,0x4b,0x4f]
比较的值依次为
result1=[7,9,3,4,9,5,6,8,2,3,6,1,3,5,4,5,1,7,2,8,3,5]
和result2=[0x3,0x5,0x1,0x5,0x5,0x6,0x2,0x2,0x1,0x1,0x8,0x6,0x7,0x8,0x9,0x8,0x5,0x4,0x9,0x8,0x2,0x7,0x1,0x8,0x6,0x7,0x3,0x2,0x3,0x1,0x5,0x7,0x6,0x9,0x2,0x4,0x3,0x7,0x8,0x3,0x9,0x4,0x8,0x9,0x4,0x6,0x9,0x4,0x9,0x4,0x2,0x4,0x6,0x1,0x6,0x7,0x2,0x1]

三次调用sub_401F58,修改了后面计算用到的数据,在特定位置下断点和修改代码,都会导致值变化,从而得不到正确的结果,特别是第三次调用是在反调试函数数组的第一个,如果直接patch掉.text:004B9398 call eax,会导致0x4BC11D处的数据错误。
这三处数据的值可通过附加程序和下内存断点得到,三处数据的正确数值为如下所示:

.text:004B9398 call eax处的返回值并不固定,patch时,会出现问题,导致后面比较的数据和下标不对,可以通过修改00402BEE处的代码为00402BEE | EB FE | jmp dancing1.402BEE ,即死循环,然后附加程序,修改回原来的代码,然后在比较的地方下断点,得到正确的结果。


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2019-3-18 23:24 被新手慢慢来编辑 ,原因:
上传的附件:
收藏
免费 3
支持
分享
最新回复 (2)
雪    币: 6051
活跃值: (1441)
能力值: ( LV15,RANK:1473 )
在线值:
发帖
回帖
粉丝
2
核心算法是对数独采用DancingLinks求解,对数据变换仅仅在转圈圈,是不是很简单
2019-3-25 17:19
0
雪    币: 10845
活跃值: (1054)
能力值: (RANK:190 )
在线值:
发帖
回帖
粉丝
3
出题 设计巧妙
破解 干净直接
2019-3-25 17:49
0
游客
登录 | 注册 方可回帖
返回
//