-
-
[原创]看雪CTF.TSRC 2018 团队赛 第六题 追凶者也
-
发表于: 2018-12-11 23:12 2634
-
先试运行了下,果然win10运行不正常,没有退出,CPU立马上来了。
拖进ida,ida自动定位到了WinMain
函数。但是,函数只调用了一个空函数。
事出反常必有妖。因为用户函数比较少,很容易就发现程序使用的tls
回调函数,从exports
中亦能看出。查看回调函数,其中有两个调用,和一个线程函数。
先看smc
函数,明显是修改sub_401280
偏移4字节处的5个字节数据,第一个字节修改为E9
,对应jmp
指令,后面4字节数据当然是跳转偏移,所以是跳到off_414014
指向的函数处。
顺着往下走,看看主函数到底执行了什么。原来指定了窗口的消息回调函数DialogFunc
,ID为1002的控件被点击时的响应函数为sub_401040
。
但sub_401040
除了获取了文本框的输入,最后出了个弹窗,似乎什么都没做。此条线就到此为止了。回到tls回调函数,还有一个函数调用的一个线程函数没有分析。go on,看hook_GetDlgItemTextA
函数。
先是通过get_api_GetDlgItemTextA
函数获取GetDlgItemTextA
的地址,然后修改GetDlgItemTextA
函数偏移32字节处的5字节数据。与上次的smc类似,第一个字节修改为E9
,后4字节为偏移,是jmp
到sub_401A10
的偏移。下面列出了GetDlgItemTextA
的代码,就是将754A6B56
处本来要跳到返回的代码改成了跳到sub_401A10
,也就是hook了GetDlgItemTextA
的返回。
再顺着往下走,看sub_401A10
:
咋一看,有点费事,动态跟下就出来了。基本过程是:
所以检验点就出来了。
那线程函数是干嘛用的呢?
原来是为了下次按键点击时作准备,继续hookGetDlgItemTextA
。
这里的校验有两个,下面的hash
函数其实在取api的时候用过,按道理讲是不可逆的,应该实际上的check只有一个,第一个满足条件了,第二个也应该就满足了。其实还有个隐含条件,就是输入应该是小于20字节的,可以从取输入的地方可以看出来,那第二个条件也可以说是防止多解。看go_check
:
go_check
函数先初始化了一个33的全局数组,再进入check
函数。check
先检查输入长度为偶数,再以2字节步长遍历输入,进入move
对33全局数组进行操作,最后检查全局数组值为1-8,最后为0。
细看move
函数,以遍历的输入2字节的第1字节为控制方向,第2字节为控制对象,进行上下左右的移动,原位置0。仔细一想,这不就是拼图游戏,0为空位,考虑到输入长度的隐含限制,应该是最少步数完成结果,具体步骤如下:
所以最终flag为:d6d8s7s4a1w2a5w6
。
输入试试,果然成功。
我十分好奇,为什么在win10上不能运行。原来秘密藏在api的获取过程中,代码如下,将就用伪代码看看吧。
先取dll基址,具体实现是:通过PEB找到PEB_LDR_DATA指针,再找到InInitializationOrderModuleList双向链表,遍历dll的全路径名称,进行hash计算与预设hash值比对。这里问题就来了,win10和win7 64位环境中user32.dll的全路径名称并不一致,就算基本路径一致,大小写也不一样。程序中预设的全路径名称为C:\Windows\syswow64\USER32.dll
,所以即使是在win7 32位系统中也是运行不正常的,会一直遍历双向链表。要想通用,只能取BaseDllName
,并且hash前统一大小写。
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)